/* packet-lwres.c * Routines for light weight reslover (lwres, part of BIND9) packet disassembly * * Copyright (c) 2003 by Oleg Terletsky * * Wireshark - Network traffic analyzer * By Gerald Combs * Copyright 1999 Gerald Combs * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ #include "config.h" #include #include #include #include "packet-dns.h" void proto_register_lwres(void); void proto_reg_handoff_lwres(void); #define LWRES_LWPACKET_LENGTH (4 * 5 + 2 * 4) #define LWRES_LWPACKETFLAG_RESPONSE 0x0001U /* if set, pkt is a response */ #define LWRES_LWPACKETVERSION_0 0 #define LW_LENGTH_OFFSET 0 #define LW_VERSION_OFFSET 4 #define LW_PKTFLASG_OFFSET 6 #define LW_SERIAL_OFFSET 8 #define LW_OPCODE_OFFSET 12 #define LW_RESULT_OFFSET 16 #define LW_RECVLEN_OFFSET 20 #define LW_AUTHTYPE_OFFSET 24 #define LW_AUTHLEN_OFFSET 26 #define LWRES_OPCODE_NOOP 0x00000000U #define LWRES_OPCODE_GETADDRSBYNAME 0x00010001U #define LWRES_OPCODE_GETNAMEBYADDR 0x00010002U #define LWRES_OPCODE_GETRDATABYNAME 0x00010003U static const value_string opcode_values[] = { { LWRES_OPCODE_NOOP, "Noop" }, { LWRES_OPCODE_GETADDRSBYNAME, "getaddrbyname" }, { LWRES_OPCODE_GETNAMEBYADDR, "getnamebyaddr" }, { LWRES_OPCODE_GETRDATABYNAME, "getrdatabyname" }, { 0, NULL }, }; #define LWRES_R_SUCCESS 0 #define LWRES_R_NOMEMORY 1 #define LWRES_R_TIMEOUT 2 #define LWRES_R_NOTFOUND 3 #define LWRES_R_UNEXPECTEDEND 4 /* unexpected end of input */ #define LWRES_R_FAILURE 5 /* generic failure */ #define LWRES_R_IOERROR 6 #define LWRES_R_NOTIMPLEMENTED 7 #define LWRES_R_UNEXPECTED 8 #define LWRES_R_TRAILINGDATA 9 #define LWRES_R_INCOMPLETE 10 #define LWRES_R_RETRY 11 #define LWRES_R_TYPENOTFOUND 12 #define LWRES_R_TOOLARGE 13 #define T_A 1 #define T_NS 2 #define T_MX 15 #define T_SRV 33 static const value_string t_types[] = { { T_A, "T_A" }, { T_NS, "T_NS" }, { T_MX, "T_MX" }, { T_SRV, "T_SRV" }, { 0, NULL }, }; static const value_string result_values[] = { { LWRES_R_SUCCESS, "Success" }, { LWRES_R_NOMEMORY, "No memory" }, { LWRES_R_TIMEOUT, "Timeout" }, { LWRES_R_NOTFOUND, "Not found" }, { LWRES_R_UNEXPECTEDEND, "Unexpected end of input" }, { LWRES_R_FAILURE, "Generic failure" }, { LWRES_R_IOERROR, "I/O Error" }, { LWRES_R_UNEXPECTED, "Unexpected" }, { LWRES_R_TRAILINGDATA, "Trailing data" }, { LWRES_R_INCOMPLETE, "Incomplete" }, { LWRES_R_RETRY, "Retry" }, { LWRES_R_TYPENOTFOUND, "Type not found" }, { LWRES_R_TOOLARGE, "Too large" }, { 0, NULL }, }; static int hf_length = -1; static int hf_version = -1; static int hf_flags = -1; static int hf_serial = -1; static int hf_opcode = -1; static int hf_result = -1; static int hf_recvlen = -1; static int hf_authtype = -1; static int hf_authlen = -1; static int hf_rflags = -1; static int hf_rdclass = -1; static int hf_rdtype = -1; static int hf_namelen = -1; static int hf_req_name = -1; static int hf_ttl = -1; static int hf_nrdatas = -1; static int hf_nsigs = -1; static int hf_realnamelen = -1; static int hf_realname = -1; static int hf_a_record = -1; static int hf_a_rec_len = -1; static int hf_srv_prio = -1; static int hf_srv_weight = -1; static int hf_srv_port = -1; static int hf_srv_dname = -1; static int hf_adn_flags = -1; static int hf_adn_addrtype = -1; static int hf_adn_namelen = -1; static int hf_adn_name = -1; static int hf_adn_realname = -1; static int hf_adn_aliasname = -1; static int hf_adn_naddrs = -1; static int hf_adn_naliases = -1; static int hf_adn_family = -1; static int hf_adn_addr_len = -1; static int hf_adn_addr_addr = -1; static int hf_ns_dname = -1; static int ett_lwres = -1; static int ett_rdata_req = -1; static int ett_rdata_resp = -1; static int ett_a_rec = -1; static int ett_a_rec_addr = -1; static int ett_srv_rec = -1; static int ett_srv_rec_item = -1; static int ett_adn_request = -1; static int ett_adn_resp = -1; static int ett_adn_alias = -1; static int ett_adn_addr = -1; static int ett_nba_request = -1; static int ett_nba_resp = -1; static int ett_noop = -1; static int ett_mx_rec = -1; static int ett_mx_rec_item = -1; static int ett_ns_rec = -1; static int ett_ns_rec_item = -1; #define LWRES_UDP_PORT 921 /* Not IANA registered */ /* Define the lwres proto */ static int proto_lwres = -1; /* Define many many headers for mgcp */ static const value_string message_types_values[] = { { 1, "REQUEST " }, { 2, "RESPONSE" }, { 0, NULL }, }; static void dissect_getnamebyaddr_request(tvbuff_t* tvb, proto_tree* lwres_tree) { guint32 flags,family; guint addrlen, slen; const char* addrs; proto_tree* nba_request_tree; flags = tvb_get_ntohl(tvb, LWRES_LWPACKET_LENGTH); family = tvb_get_ntohl(tvb, LWRES_LWPACKET_LENGTH + 4); addrlen = tvb_get_ntohs(tvb, LWRES_LWPACKET_LENGTH + 8); addrs = tvb_ip_to_str(tvb, LWRES_LWPACKET_LENGTH + 10); slen = (int)strlen(addrs); if (lwres_tree == NULL) return; nba_request_tree = proto_tree_add_subtree(lwres_tree,tvb,LWRES_LWPACKET_LENGTH,LWRES_LWPACKET_LENGTH+14, ett_nba_request,NULL,"getnamebyaddr parameters"); proto_tree_add_uint(nba_request_tree, hf_adn_flags, tvb, LWRES_LWPACKET_LENGTH, 4, flags); proto_tree_add_uint(nba_request_tree, hf_adn_family, tvb, LWRES_LWPACKET_LENGTH + 4, 4, family); proto_tree_add_uint(nba_request_tree, hf_adn_addr_len, tvb, LWRES_LWPACKET_LENGTH + 8, 2, addrlen); proto_tree_add_string(nba_request_tree, hf_adn_addr_addr, tvb, LWRES_LWPACKET_LENGTH + 10, slen, addrs); } static void dissect_getnamebyaddr_response(tvbuff_t* tvb, proto_tree* lwres_tree) { guint32 i, offset; guint16 naliases,realnamelen,aliaslen; gchar *aliasname; proto_tree* nba_resp_tree; proto_tree* alias_tree; if(lwres_tree == NULL) return; nba_resp_tree = proto_tree_add_subtree(lwres_tree, tvb, LWRES_LWPACKET_LENGTH, 10, ett_nba_resp, NULL, "getnamebyaddr records"); naliases = tvb_get_ntohs(tvb, LWRES_LWPACKET_LENGTH + 4); realnamelen = tvb_get_ntohs(tvb,LWRES_LWPACKET_LENGTH + 4 + 2); proto_tree_add_item(nba_resp_tree, hf_adn_flags, tvb, LWRES_LWPACKET_LENGTH, 4, ENC_BIG_ENDIAN); proto_tree_add_item(nba_resp_tree, hf_adn_naliases, tvb, LWRES_LWPACKET_LENGTH + 4, 2, ENC_BIG_ENDIAN); proto_tree_add_item(nba_resp_tree, hf_adn_namelen, tvb, LWRES_LWPACKET_LENGTH + 6, 2, ENC_BIG_ENDIAN); proto_tree_add_item(nba_resp_tree, hf_adn_realname, tvb, LWRES_LWPACKET_LENGTH + 8, realnamelen, ENC_ASCII|ENC_NA); offset=LWRES_LWPACKET_LENGTH + 8 + realnamelen; if(naliases) { for(i=0; icinfo, COL_PROTOCOL, "lw_res"); length = tvb_get_ntohl(tvb, LW_LENGTH_OFFSET); version = tvb_get_ntohs(tvb, LW_VERSION_OFFSET); flags = tvb_get_ntohs(tvb, LW_PKTFLASG_OFFSET); serial = tvb_get_ntohl(tvb, LW_SERIAL_OFFSET); opcode = tvb_get_ntohl(tvb,LW_OPCODE_OFFSET); result = tvb_get_ntohl(tvb, LW_RESULT_OFFSET); recvlength = tvb_get_ntohl(tvb, LW_RECVLEN_OFFSET); authtype = tvb_get_ntohs(tvb, LW_AUTHTYPE_OFFSET); authlength = tvb_get_ntohs(tvb, LW_AUTHLEN_OFFSET); message_type = (flags & LWRES_LWPACKETFLAG_RESPONSE) ? 2 : 1; if(flags & LWRES_LWPACKETFLAG_RESPONSE) { col_add_fstr(pinfo->cinfo, COL_INFO, "%s, opcode=%s, serial=0x%x, result=%s", val_to_str_const((guint32)message_type,message_types_values,"unknown"), val_to_str_const(opcode, opcode_values, "unknown"), serial, val_to_str_const(result,result_values,"unknown")); } else { col_add_fstr(pinfo->cinfo, COL_INFO, "%s, opcode=%s, serial=0x%x", val_to_str_const((guint32)message_type,message_types_values,"unknown"), val_to_str_const(opcode, opcode_values, "unknown"), serial); } if(tree == NULL) return tvb_captured_length(tvb); lwres_item = proto_tree_add_item(tree,proto_lwres, tvb,0, -1, ENC_NA); lwres_tree = proto_item_add_subtree(lwres_item, ett_lwres); proto_tree_add_uint(lwres_tree, hf_length, tvb, LW_LENGTH_OFFSET, sizeof(guint32), length); proto_tree_add_uint(lwres_tree, hf_version, tvb, LW_VERSION_OFFSET, sizeof(guint16), version); proto_tree_add_uint(lwres_tree, hf_flags, tvb, LW_PKTFLASG_OFFSET, sizeof(guint16), flags); proto_tree_add_uint(lwres_tree, hf_serial, tvb, LW_SERIAL_OFFSET, sizeof(guint32), serial); proto_tree_add_uint(lwres_tree, hf_opcode, tvb, LW_OPCODE_OFFSET, sizeof(guint32), opcode); proto_tree_add_uint(lwres_tree, hf_result, tvb, LW_RESULT_OFFSET, sizeof(guint32), result); proto_tree_add_uint(lwres_tree, hf_recvlen, tvb, LW_RECVLEN_OFFSET, sizeof(guint32), recvlength); proto_tree_add_uint(lwres_tree, hf_authtype, tvb, LW_AUTHTYPE_OFFSET, sizeof(guint16), authtype); proto_tree_add_uint(lwres_tree, hf_authlen, tvb, LW_AUTHLEN_OFFSET, sizeof(guint16), authlength); if(!result) { switch(opcode) { case LWRES_OPCODE_NOOP: dissect_noop(tvb, lwres_tree); break; case LWRES_OPCODE_GETADDRSBYNAME: dissect_getaddrsbyname(tvb, lwres_tree, message_type); break; case LWRES_OPCODE_GETNAMEBYADDR: dissect_getnamebyaddr(tvb, lwres_tree, message_type); break; case LWRES_OPCODE_GETRDATABYNAME: dissect_getrdatabyname(tvb, lwres_tree, message_type); break; } } return tvb_captured_length(tvb); } void proto_register_lwres(void) { static hf_register_info hf[] = { { &hf_length, { "Length", "lwres.length", FT_UINT32, BASE_DEC, NULL, 0x0, "lwres length", HFILL }}, { &hf_version, { "Version", "lwres.version", FT_UINT16, BASE_DEC, NULL, 0x0, "lwres version", HFILL }}, { &hf_flags, { "Packet Flags", "lwres.flags", FT_UINT16, BASE_HEX, NULL, 0x0, "lwres flags", HFILL }}, { &hf_serial, { "Serial", "lwres.serial", FT_UINT32, BASE_HEX, NULL, 0x0, "lwres serial", HFILL }}, { &hf_opcode, { "Operation code", "lwres.opcode", FT_UINT32, BASE_DEC, VALS(opcode_values), 0x0, "lwres opcode", HFILL }}, { &hf_result, { "Result", "lwres.result", FT_UINT32, BASE_DEC, VALS(result_values), 0x0, "lwres result", HFILL }}, { &hf_recvlen, { "Received length", "lwres.recvlen", FT_UINT32, BASE_DEC, NULL, 0x0, "lwres recvlen", HFILL }}, { &hf_authtype, { "Auth. type", "lwres.authtype", FT_UINT16, BASE_DEC, NULL, 0x0, "lwres authtype", HFILL }}, { &hf_authlen, { "Auth. length", "lwres.authlen", FT_UINT16, BASE_DEC, NULL, 0x0, "lwres authlen", HFILL }}, { &hf_rflags, { "Flags", "lwres.rflags", FT_UINT32, BASE_HEX, NULL, 0x0, "lwres rflags", HFILL }}, { &hf_rdclass, { "Class", "lwres.class", FT_UINT16, BASE_DEC, NULL, 0x0, "lwres class", HFILL }}, { &hf_rdtype, { "Type", "lwres.type", FT_UINT16, BASE_DEC, VALS(t_types), 0x0, "lwres type", HFILL }}, { &hf_namelen, { "Name length", "lwres.namelen", FT_UINT16, BASE_DEC, NULL, 0x0, "lwres namelen", HFILL }}, { &hf_req_name, { "Domain name", "lwres.reqdname", FT_STRING, BASE_NONE, NULL, 0x0, "lwres reqdname", HFILL }}, { &hf_ttl, { "Time To Live", "lwres.ttl", FT_UINT32, BASE_DEC, NULL, 0x0, "lwres ttl", HFILL }}, { &hf_nrdatas, { "Number of rdata records", "lwres.nrdatas", FT_UINT16, BASE_DEC, NULL, 0x0, "lwres nrdatas", HFILL }}, { &hf_nsigs, { "Number of signature records", "lwres.nsigs", FT_UINT16, BASE_DEC, NULL, 0x0, "lwres nsigs", HFILL }}, { &hf_realnamelen, { "Real name length", "lwres.realnamelen", FT_UINT16, BASE_DEC, NULL, 0x0, "lwres realnamelen", HFILL }}, { &hf_realname, { "Real doname name", "lwres.realname", FT_STRING, BASE_NONE, NULL, 0x0, "lwres realname", HFILL }}, { &hf_a_record, { "IPv4 Address", "lwres.arecord", FT_UINT32, BASE_DEC, NULL, 0x0, "lwres arecord", HFILL }}, { &hf_a_rec_len, { "Length", "lwres.areclen", FT_UINT16, BASE_DEC, NULL, 0x0, "lwres areclen", HFILL }}, { &hf_srv_prio, { "Priority", "lwres.srv.priority", FT_UINT16, BASE_DEC, NULL, 0x0, "lwres srv prio", HFILL }}, { &hf_srv_weight, { "Weight", "lwres.srv.weight", FT_UINT16, BASE_DEC, NULL, 0x0, "lwres srv weight", HFILL }}, { &hf_srv_port, { "Port" , "lwres.srv.port", FT_UINT16, BASE_DEC, NULL, 0x0, "lwres srv port", HFILL }}, { &hf_srv_dname, { "DNAME" , "lwres.srv.dname", FT_STRING, BASE_NONE, NULL, 0x0, NULL, HFILL }}, { &hf_adn_flags, { "Flags", "lwres.adn.flags", FT_UINT32, BASE_HEX, NULL, 0x0, "lwres adn flags", HFILL }}, { &hf_adn_addrtype, { "Address type", "lwres.adn.addrtype", FT_UINT32, BASE_DEC, NULL, 0x0, "lwres adn addrtype", HFILL }}, { &hf_adn_namelen, { "Name length", "lwres.adn.namelen", FT_UINT16, BASE_DEC, NULL, 0x0, "lwres adn namelen", HFILL }}, { &hf_adn_name, { "Name", "lwres.adn.name", FT_STRING, BASE_NONE, NULL, 0x0, "lwres adn name", HFILL }}, { &hf_adn_naliases, { "Number of aliases", "lwres.adn.naliases", FT_UINT16, BASE_DEC, NULL, 0x0, "lwres adn naliases", HFILL }}, { &hf_adn_naddrs, { "Number of addresses", "lwres.adn.naddrs", FT_UINT16, BASE_DEC, NULL, 0x0, "lwres adn naddrs", HFILL }}, { &hf_adn_realname, { "Real name", "lwres.adn.realname", FT_STRING, BASE_NONE, NULL, 0x0, "lwres adn realname", HFILL }}, { &hf_adn_aliasname, { "Alias name", "lwres.adn.aliasname", FT_STRING, BASE_NONE, NULL, 0x0, "lwres adn aliasname", HFILL }}, { &hf_adn_family, { "Address family", "lwres.adn.addr.family", FT_UINT32, BASE_DEC, NULL, 0x0, "lwres adn addr family", HFILL }}, { &hf_adn_addr_len, { "Address length", "lwres.adn.addr.length", FT_UINT16, BASE_DEC, NULL, 0x0, "lwres adn addr length", HFILL }}, { &hf_adn_addr_addr, { "IP Address", "lwres.adn.addr.addr", FT_STRING, BASE_NONE, NULL, 0x0, "lwres adn addr addr", HFILL }}, { &hf_ns_dname, { "Name" , "lwres.ns.dname", FT_STRING, BASE_NONE, NULL, 0x0, NULL, HFILL }}, /* Add more fields here */ }; static gint *ett[] = { &ett_lwres, &ett_rdata_req, &ett_rdata_resp, &ett_a_rec, &ett_a_rec_addr, &ett_srv_rec, &ett_srv_rec_item, &ett_adn_request, &ett_adn_resp, &ett_adn_alias, &ett_adn_addr, &ett_nba_request, &ett_nba_resp, &ett_mx_rec, &ett_mx_rec_item, &ett_ns_rec, &ett_ns_rec_item, &ett_noop, }; proto_lwres = proto_register_protocol("Light Weight DNS RESolver (BIND9)", "LWRES", "lwres"); proto_register_field_array(proto_lwres, hf, array_length(hf)); proto_register_subtree_array(ett, array_length(ett)); } /* The registration hand-off routine */ void proto_reg_handoff_lwres(void) { dissector_handle_t lwres_handle; lwres_handle = create_dissector_handle(dissect_lwres, proto_lwres); dissector_add_uint_with_preference("udp.port", LWRES_UDP_PORT, lwres_handle); } /* * Editor modelines - http://www.wireshark.org/tools/modelines.html * * Local variables: * c-basic-offset: 4 * tab-width: 8 * indent-tabs-mode: nil * End: * * vi: set shiftwidth=4 tabstop=8 expandtab: * :indentSize=4:tabSize=8:noTabs=true: */