wireshark插件 - 用自己做的插件,来简单分析ARP协议

前言

最近要调试chromium工程,感到自己的开发机台渣了。借着这个理由,换个新的开发机,安慰自己一下。要是没找到理由,自己会惭愧的,还真说服不了自己换新计算机。

将内存升到64GB, 用起来好爽。主板上还有4个内存插槽,还能加4个单条的16GB内存。等下一步,再找个理由(估计很难),升到128GB. 华硕主板做的是真强。

上午在捣鼓新开发机,将旧开发机的ssd和机械硬盘加到新开发机上了。装开发环境。

想起上周,想做的wireshark的arp分析插件。就拿这个工程来试试刀,看看编译和调试的感觉是不是好很多。
有以前做好的虚拟机,wireshark开发环境都是好的。这回,给虚拟机分配32GB内存,CPU只能分2x2.
开始做wireshark-arp分析插件。

ARP协议简单. 做的时候,要接管wireshark的内建的ARP分析(不要改wireshark源码,只由插件代码来接管), 这个实验了好久. 去围观和调试了wireshark的arp协议分析的实现, 抄代码挺爽的, 能边做边学。

插件主实现下载

从上一个插件代码实验的博文,将主实现拷贝下来做实验,发现每行结尾的回车换行都变了. 应该是csdn博客的bug, 以前有拷贝代码的按钮,拷贝下来和原始代码一样,现在没这个按钮了, 拷贝下来都变形了. 特别是Makefile.

packet-foo-arp.c

ARP协议下载

在网上找了一份将ARP协议的ppt
protocol_arp_rarp.pdf

运行效果

wireshark插件 - 用自己做的插件,来简单分析ARP协议_第1张图片
通过对ARP问答包的分别分析,可以看出,ARP发送者是多播,ARP回答者是单播.

ARP protocol parse by foo plugin
    TAG_ARP_HEADER.hardware_type = Ethernet (0x0001)
    TAG_ARP_HEADER.protocol_type = IPv4 (0x0800)
    TAG_ARP_HEADER.hardware_size = 6
    TAG_ARP_HEADER.protocol_size = 4
    TAG_ARP_HEADER.opt_code = request (0x0001)
    sender mac = 8C:F2:28:4B:E3:2C
    sender ip = 192.168.2.2
    request mac = 00:00:00:00:00:00
    request ip = 192.168.2.66
    nice, parse ok
ARP protocol parse by foo plugin
    TAG_ARP_HEADER.hardware_type = Ethernet (0x0001)
    TAG_ARP_HEADER.protocol_type = IPv4 (0x0800)
    TAG_ARP_HEADER.hardware_size = 6
    TAG_ARP_HEADER.protocol_size = 4
    TAG_ARP_HEADER.opt_code = reply (0x0002)
    sender mac = 4C:ED:FB:CB:44:1C
    sender ip = 192.168.2.66
    request mac = 8C:F2:28:4B:E3:2C
    request ip = 192.168.2.2
    nice, parse ok

通过分析,可以看出这对ARP应答, 是我的路由器(网关)在问我的新开发机的mac和IP对应关系. 他为啥要问呢? 已经连接了好久。

arp协议分析简单实现-主实现预览

wireshark插件要配好一套开发环境,单是主实现,编译不出能用的插件。
配插件环境,太折腾了,不想每个实验都搞一个新插件工程。如果不是正式工程,不想整新插件工程了。
将环境搭好了,配好一个foo插件工程, 在这个工程中作各种协议分析的实验。

// @file packet-foo.c
// @brief the foo plugin parse ARP protocol
// @ref http://www.dgtech.com/foo/sys/www/docs/html/
//      https://www.wireshark.org/docs/wsdg_html_chunked/
//      https://www.wireshark.org/docs/wsdg_html_chunked/PartDevelopment.html
//      https://www.wireshark.org/docs/wsdg_html_chunked/ChDissectAdd.html#idm1589259872

// @note how to use foo plugin
// open a pcap file or capture any packet, select a tcp frame(have payload), Decode as ... => foo => ok

#include 
#include 
#include 
#include 

#include "config.h"

#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 

#include "packet-foo.h"

#define PROTOCOL_FULL_NAME_FOO "ARP protocol parse by foo plugin"
#define PROTOCOL_SHORT_NAME_FOO "foo"
#define PROTOCOL_DISPLAY_FILTER_NAME_FOO PROTOCOL_SHORT_NAME_FOO

// interface declare for plugin.c (plugin dll interface plugin_register(), plugin_reg_handoff())
void proto_register_foo(void);
void proto_reg_handoff_foo(void);

static dissector_handle_t dissector_handle_foo = NULL;

static int protocol_handle_foo = -1;
static int proto_arp = 1;

// hf means "header field name"
static int hf_foo_message = -1;
static int hf_foo_pdu_type = -1;

// 要注册的字段信息数组, use use proto_register_field_array to register
static hf_register_info hf[] = {
    { &hf_foo_message,
    {
        "FOO message", // field name
        "foo.msg", // field short name
        FT_STRING, // field type, see ftypes.h
        BASE_NONE, // data base type, see proto.h field_display_e
        NULL, // value_string
        0x0, // bitmask
        NULL, // Brief description of field
        HFILL // info fill by proto routines
    }
    },

    { &hf_foo_pdu_type,
    {
        "FOO PDU Type", // field name
        "foo.type", // field short name
        FT_UINT8, // field type, see ftypes.h
        BASE_DEC, // data base type, see proto.h field_display_e
        NULL, // value_string
        0x0, // bitmask
        NULL, // Brief description of field
        HFILL // info fill by proto routines
    }
    }
};

static gint ett_foo = -1;
static gint ett_foo_subtree_1 = -1;

// ett means "protocol subtree array"
static gint *ett[] = {
    &ett_foo,
    &ett_foo_subtree_1
};

const value_string arp_hrd_vals[] = {
    { ARPHRD_NETROM,             "NET/ROM pseudo" },
    { ARPHRD_ETHER,              "Ethernet" },
    { ARPHRD_EETHER,             "Experimental Ethernet" },
    { ARPHRD_AX25,               "AX.25" },
    { ARPHRD_PRONET,             "ProNET" },
    { ARPHRD_CHAOS,              "Chaos" },
    { ARPHRD_IEEE802,            "IEEE 802" },
    { ARPHRD_ARCNET,             "ARCNET" },
    { ARPHRD_HYPERCH,            "Hyperchannel" },
    { ARPHRD_LANSTAR,            "Lanstar" },
    { ARPHRD_AUTONET,            "Autonet Short Address" },
    { ARPHRD_LOCALTLK,           "Localtalk" },
    { ARPHRD_LOCALNET,           "LocalNet" },
    { ARPHRD_ULTRALNK,           "Ultra link" },
    { ARPHRD_SMDS,               "SMDS" },
    { ARPHRD_DLCI,               "Frame Relay DLCI" },
    { ARPHRD_ATM,                "ATM" },
    { ARPHRD_HDLC,               "HDLC" },
    { ARPHRD_FIBREC,             "Fibre Channel" },
    { ARPHRD_ATM2225,            "ATM (RFC 2225)" },
    { ARPHRD_SERIAL,             "Serial Line" },
    { ARPHRD_ATM2,               "ATM" },
    { ARPHRD_MS188220,           "MIL-STD-188-220" },
    { ARPHRD_METRICOM,           "Metricom STRIP" },
    { ARPHRD_IEEE1394,           "IEEE 1394.1995" },
    { ARPHRD_MAPOS,              "MAPOS" },
    { ARPHRD_TWINAX,             "Twinaxial" },
    { ARPHRD_EUI_64,             "EUI-64" },
    { ARPHRD_HIPARP,             "HIPARP" },
    { ARPHRD_IP_ARP_ISO_7816_3,  "IP and ARP over ISO 7816-3" },
    { ARPHRD_ARPSEC,             "ARPSec" },
    { ARPHRD_IPSEC_TUNNEL,       "IPsec tunnel" },
    { ARPHRD_INFINIBAND,         "InfiniBand" },
    { ARPHRD_TIA_102_PRJ_25_CAI, "TIA-102 Project 25 CAI" },
    { ARPHRD_WIEGAND_INTERFACE,  "Wiegand Interface" },
    { ARPHRD_PURE_IP,            "Pure IP" },
    { ARPHDR_HW_EXP1,            "Experimental 1" },
    { ARPHDR_HFI,                "HFI" },
    { ARPHDR_HW_EXP2,            "Experimental 2" },
    /* Virtual ARP types for non ARP hardware used in Linux cooked mode. */
    { ARPHRD_LOOPBACK,           "Loopback" },
    { ARPHRD_IPGRE,              "GRE over IP" },
    { ARPHRD_NETLINK,            "Netlink" },
    { 0, NULL } };

// epan/etypes.h export etype_vals
// WS_DLL_PUBLIC const value_string etype_vals[]; but it have not array size
const value_string my_etype_vals[] = {
    { ETHERTYPE_IP,                   "IPv4" },
    { ETHERTYPE_IPv6,                 "IPv6" },
    { ETHERTYPE_VLAN,                 "802.1Q Virtual LAN" },
    { ETHERTYPE_ARP,                  "ARP" },
    { ETHERTYPE_WLCCP,                "Cisco Wireless Lan Context Control Protocol" },
    { ETHERTYPE_MINT,                 "Motorola Media Independent Network Transport" },
    { ETHERTYPE_CENTRINO_PROMISC,     "IEEE 802.11 (Centrino promiscuous)" },
    { ETHERTYPE_XNS_IDP,              "XNS Internet Datagram Protocol" },
    { ETHERTYPE_X25L3,                "X.25 Layer 3" },
    { ETHERTYPE_WOL,                  "Wake on LAN" },
    { ETHERTYPE_WMX_M2M,              "WiMax Mac-to-Mac" },
    { ETHERTYPE_EPL_V1,               "EPL_V1" },
    { ETHERTYPE_REVARP,               "RARP" },
    { ETHERTYPE_DEC_LB,               "DEC LanBridge" },
    { ETHERTYPE_ATALK,                "Appletalk" },
    { ETHERTYPE_SNA,                  "SNA-over-Ethernet" },
    { ETHERTYPE_DLR,                  "EtherNet/IP Device Level Ring" },
    { ETHERTYPE_AARP,                 "AARP" },
    { ETHERTYPE_IPX,                  "Netware IPX/SPX" },
    { ETHERTYPE_VINES_IP,             "Vines IP" },
    { ETHERTYPE_VINES_ECHO,           "Vines Echo" },
    { ETHERTYPE_TRAIN,                "Netmon Train" },
    /* Ethernet Loopback */
    { ETHERTYPE_LOOP,                 "Loopback" },
    { ETHERTYPE_FOUNDRY,              "Foundry proprietary" },
    { ETHERTYPE_WCP,                  "Wellfleet Compression Protocol" },
    { ETHERTYPE_STP,                  "Spanning Tree Protocol" },
    /* for ISMP, see RFC 2641, RFC 2642, RFC 2643 */
    { ETHERTYPE_ISMP,                 "Cabletron Interswitch Message Protocol" },
    { ETHERTYPE_ISMP_TBFLOOD,         "Cabletron SFVLAN 1.8 Tag-Based Flood" },
    /* In www.iana.org/assignments/ethernet-numbers, 8203-8205 description is
    * Quantum Software.  Now the company is called QNX Software Systems. */
    { ETHERTYPE_QNX_QNET6,            "QNX 6 QNET protocol" },
    { ETHERTYPE_PPPOED,               "PPPoE Discovery" },
    { ETHERTYPE_PPPOES,               "PPPoE Session" },
    { ETHERTYPE_LINK_CTL,             "HomePNA, wlan link local tunnel" },
    { ETHERTYPE_INTEL_ANS,            "Intel ANS probe" },
    { ETHERTYPE_MS_NLB_HEARTBEAT,     "MS NLB heartbeat" },
    { ETHERTYPE_JUMBO_LLC,            "Jumbo LLC" },
    { ETHERTYPE_HOMEPLUG,             "Homeplug" },
    { ETHERTYPE_HOMEPLUG_AV,          "Homeplug AV" },
    { ETHERTYPE_MRP,                  "MRP" },
    { ETHERTYPE_IEEE_802_1AD,         "802.1ad Provider Bridge (Q-in-Q)" },
    { ETHERTYPE_MACSEC,               "802.1AE (MACsec)" },
    { ETHERTYPE_IEEE_802_1AH,         "802.1ah Provider Backbone Bridge (mac-in-mac)" },
    { ETHERTYPE_IEEE_802_1BR,         "802.1br Bridge Port Extension E-Tag" },
    { ETHERTYPE_EAPOL,                "802.1X Authentication" },
    { ETHERTYPE_RSN_PREAUTH,          "802.11i Pre-Authentication" },
    { ETHERTYPE_MPLS,                 "MPLS label switched packet" },
    { ETHERTYPE_MPLS_MULTI,           "MPLS multicast label switched packet" },
    { ETHERTYPE_3C_NBP_DGRAM,         "3Com NBP Datagram" },
    { ETHERTYPE_DEC,                  "DEC proto" },
    { ETHERTYPE_DNA_DL,               "DEC DNA Dump/Load" },
    { ETHERTYPE_DNA_RC,               "DEC DNA Remote Console" },
    { ETHERTYPE_DNA_RT,               "DEC DNA Routing" },
    { ETHERTYPE_LAT,                  "DEC LAT" },
    { ETHERTYPE_DEC_DIAG,             "DEC Diagnostics" },
    { ETHERTYPE_DEC_CUST,             "DEC Customer use" },
    { ETHERTYPE_DEC_SCA,              "DEC LAVC/SCA" },
    { ETHERTYPE_DEC_LAST,             "DEC LAST" },
    { ETHERTYPE_ETHBRIDGE,            "Transparent Ethernet bridging" },
    { ETHERTYPE_CGMP,                 "Cisco Group Management Protocol" },
    { ETHERTYPE_GIGAMON,              "Gigamon Header" },
    { ETHERTYPE_MSRP,                 "802.1Qat Multiple Stream Reservation Protocol" },
    { ETHERTYPE_MMRP,                 "802.1ak Multiple Mac Registration Protocol" },
    { ETHERTYPE_NSH,                  "Network Service Header" },
    { ETHERTYPE_AVBTP,                "IEEE 1722 Audio Video Bridging Transport Protocol" },
    { ETHERTYPE_ROHC,                 "Robust Header Compression(RoHC)" },
    { ETHERTYPE_TRILL,                "TRansparent Interconnection of Lots of Links" },
    { ETHERTYPE_L2ISIS,               "Intermediate System to Intermediate System" },
    { ETHERTYPE_MAC_CONTROL,          "MAC Control" },
    { ETHERTYPE_SLOW_PROTOCOLS,       "Slow Protocols" },
    { ETHERTYPE_RTMAC,                "Real-Time Media Access Control" },
    { ETHERTYPE_RTCFG,                "Real-Time Configuration Protocol" },
    { ETHERTYPE_CDMA2000_A10_UBS,     "CDMA2000 A10 Unstructured byte stream" },
    { ETHERTYPE_ATMOE,                "ATM over Ethernet" },
    { ETHERTYPE_PROFINET,             "PROFINET" },
    { ETHERTYPE_REALTEK,              "Realtek Layer 2 Protocols" },
    { ETHERTYPE_AOE,                  "ATA over Ethernet" },
    { ETHERTYPE_ECATF,                "EtherCAT frame" },
    { ETHERTYPE_TELKONET,             "Telkonet powerline" },
    { ETHERTYPE_EPL_V2,               "ETHERNET Powerlink v2" },
    { ETHERTYPE_XIMETA,               "XiMeta Technology" },
    { ETHERTYPE_CSM_ENCAPS,           "CSM_ENCAPS Protocol" },
    { ETHERTYPE_EXPERIMENTAL_ETH1,    "Local Experimental Ethertype 1" },
    { ETHERTYPE_EXPERIMENTAL_ETH2,    "Local Experimental Ethertype 2" },
    { ETHERTYPE_IEEE802_OUI_EXTENDED, "IEEE 802a OUI Extended Ethertype" },
    { ETHERTYPE_IEC61850_GOOSE,       "IEC 61850/GOOSE" },
    { ETHERTYPE_IEC61850_GSE,         "IEC 61850/GSE management services" },
    { ETHERTYPE_IEC61850_SV,          "IEC 61850/SV (Sampled Value Transmission" },
    { ETHERTYPE_TIPC,                 "Transparent Inter Process Communication" },
    { ETHERTYPE_LLDP,                 "802.1 Link Layer Discovery Protocol (LLDP)" },
    { ETHERTYPE_3GPP2,                "CDMA2000 A10 3GPP2 Packet" },
    { ETHERTYPE_TTE_PCF,              "TTEthernet Protocol Control Frame" },
    { ETHERTYPE_CESOETH,              "Circuit Emulation Services over Ethernet (MEF8)" },
    { ETHERTYPE_LLTD,                 "Link Layer Topology Discovery (LLTD)" },
    { ETHERTYPE_WSMP,                 "(WAVE) Short Message Protocol (WSM)" },
    { ETHERTYPE_VMLAB,                "VMware Lab Manager" },
    { ETHERTYPE_COBRANET,             "Cirrus Cobranet Packet" },
    { ETHERTYPE_NSRP,                 "Juniper Netscreen Redundant Protocol" },
    /*
    * NDISWAN on Windows translates Ethernet frames from higher-level
    * protocols into PPP frames to hand to the PPP driver, and translates
    * PPP frames from the PPP driver to hand to the higher-level protocols.
    *
    * Apparently the PPP driver, on at least some versions of Windows,
    * passes frames for internal-to-PPP protocols up through NDISWAN;
    * the protocol type field appears to be passed through unchanged
    * (unlike what's done with, for example, the protocol type field
    * for IP, which is mapped from its PPP value to its Ethernet value).
    *
    * This means that we may see, on Ethernet captures, frames for
    * protocols internal to PPP, so we list as "Ethernet" protocol
    * types the PPP protocol types we've seen.
    */
    { PPP_IPCP,                       "PPP IP Control Protocol" },
    { PPP_LCP,                        "PPP Link Control Protocol" },
    { PPP_PAP,                        "PPP Password Authentication Protocol" },
    { PPP_CCP,                        "PPP Compression Control Protocol" },
    { ETHERTYPE_LLT,                  "Veritas Low Latency Transport (not officially registered)" },
    { ETHERTYPE_CFM,                  "IEEE 802.1ag Connectivity Fault Management (CFM) protocol" },
    { ETHERTYPE_DCE,                  "Data Center Ethernet (DCE) protocol(Cisco)" },
    { ETHERTYPE_FCOE,                 "Fibre Channel over Ethernet" },
    { ETHERTYPE_IEEE80211_DATA_ENCAP, "IEEE 802.11 data encapsulation" },
    { ETHERTYPE_LINX,                 "LINX IPC Protocol" },
    { ETHERTYPE_FIP,                  "FCoE Initialization Protocol" },
    { ETHERTYPE_MIH,                  "Media Independent Handover Protocol" },
    { ETHERTYPE_ELMI,                 "Ethernet Local Management Interface (MEF16)" },
    { ETHERTYPE_PTP,                  "PTPv2 over Ethernet (IEEE1588)" },
    { ETHERTYPE_NCSI,                 "Network Controller Sideband Interface" },
    { ETHERTYPE_PRP,                  "Parallel Redundancy Protocol (PRP) and HSR Supervision (IEC62439 Part 3)" },
    { ETHERTYPE_FLIP,                 "Flow Layer Internal Protocol" },
    { ETHERTYPE_ROCE,                 "RDMA over Converged Ethernet" },
    { ETHERTYPE_TDMOE,                "Digium TDM over Ethernet Protocol" },
    { ETHERTYPE_WAI,                  "WAI Authentication Protocol" },
    { ETHERTYPE_VNTAG,                "VN-Tag" },
    { ETHERTYPE_SEL_L2,               "Schweitzer Engineering Labs Layer 2 Protocol" },
    { ETHERTYPE_HSR,                  "High-availability Seamless Redundancy (IEC62439 Part 3)" },
    { ETHERTYPE_BPQ,                  "AX.25" },
    { ETHERTYPE_CMD,                  "CiscoMetaData" },
    { ETHERTYPE_XIP,                  "eXpressive Internet Protocol" },
    { ETHERTYPE_NWP,                  "Neighborhood Watch Protocol" },
    { ETHERTYPE_BLUECOM,              "bluecom Protocol" },
    { ETHERTYPE_QINQ_OLD,             "QinQ: old non-standard 802.1ad" },
    { 0, NULL }
};

/* ARP / RARP structs and definitions */
#ifndef ARPOP_REQUEST
#define ARPOP_REQUEST  1       /* ARP request.  */
#endif
#ifndef ARPOP_REPLY
#define ARPOP_REPLY    2       /* ARP reply.  */
#endif
/* Some OSes have different names, or don't define these at all */
#ifndef ARPOP_RREQUEST
#define ARPOP_RREQUEST 3       /* RARP request.  */
#endif
#ifndef ARPOP_RREPLY
#define ARPOP_RREPLY   4       /* RARP reply.  */
#endif

/*Additional parameters as per http://www.iana.org/assignments/arp-parameters*/
#ifndef ARPOP_DRARPREQUEST
#define ARPOP_DRARPREQUEST 5   /* DRARP request.  */
#endif

#ifndef ARPOP_DRARPREPLY
#define ARPOP_DRARPREPLY 6     /* DRARP reply.  */
#endif

#ifndef ARPOP_DRARPERROR
#define ARPOP_DRARPERROR 7     /* DRARP error.  */
#endif

#ifndef ARPOP_IREQUEST
#define ARPOP_IREQUEST 8       /* Inverse ARP (RFC 1293) request.  */
#endif
#ifndef ARPOP_IREPLY
#define ARPOP_IREPLY   9       /* Inverse ARP reply.  */
#endif
#ifndef ATMARPOP_NAK
#define ATMARPOP_NAK   10      /* ATMARP NAK.  */
#endif

/*Additional parameters as per http://www.iana.org/assignments/arp-parameters*/
#ifndef ARPOP_MARS_REQUEST
#define ARPOP_MARS_REQUEST   11       /*MARS request message. */
#endif

#ifndef ARPOP_MARS_MULTI
#define ARPOP_MARS_MULTI   12       /*MARS-Multi message. */
#endif

#ifndef ARPOP_MARS_MSERV
#define ARPOP_MARS_MSERV   13       /*MARS-Mserv message. */
#endif

#ifndef ARPOP_MARS_JOIN
#define ARPOP_MARS_JOIN  14       /*MARS-Join request. */
#endif

#ifndef ARPOP_MARS_LEAVE
#define ARPOP_MARS_LEAVE   15       /*MARS Leave request. */
#endif

#ifndef ARPOP_MARS_NAK
#define ARPOP_MARS_NAK   16       /*MARS nak message.*/
#endif

#ifndef ARPOP_MARS_UNSERV
#define ARPOP_MARS_UNSERV   17       /*MARS Unserv message. */
#endif

#ifndef ARPOP_MARS_SJOIN
#define ARPOP_MARS_SJOIN   18       /*MARS Sjoin message. */
#endif

#ifndef ARPOP_MARS_SLEAVE
#define ARPOP_MARS_SLEAVE   19       /*MARS Sleave message. */
#endif

#ifndef ARPOP_MARS_GROUPLIST_REQUEST
#define ARPOP_MARS_GROUPLIST_REQUEST   20       /*MARS Grouplist request message. */
#endif

#ifndef ARPOP_MARS_GROUPLIST_REPLY
#define ARPOP_MARS_GROUPLIST_REPLY   21       /*MARS Grouplist reply message. */
#endif

#ifndef ARPOP_MARS_REDIRECT_MAP
#define ARPOP_MARS_REDIRECT_MAP   22       /*MARS Grouplist request message. */
#endif

#ifndef ARPOP_MAPOS_UNARP
#define ARPOP_MAPOS_UNARP   23 /*MAPOS UNARP*/
#endif

#ifndef ARPOP_EXP1
#define ARPOP_EXP1     24      /* Experimental 1 */
#endif
#ifndef ARPOP_EXP2
#define ARPOP_EXP2     25      /* Experimental 2 */
#endif

#ifndef ARPOP_RESERVED1
#define ARPOP_RESERVED1         0  /*Reserved opcode 1*/
#endif

#ifndef ARPOP_RESERVED2
#define ARPOP_RESERVED2         65535 /*Reserved opcode 2*/
#endif

#ifndef DRARPERR_RESTRICTED
#define DRARPERR_RESTRICTED      1
#endif

#ifndef DRARPERR_NOADDRESSES
#define DRARPERR_NOADDRESSES     2
#endif

#ifndef DRARPERR_SERVERDOWN
#define DRARPERR_SERVERDOWN     3
#endif

#ifndef DRARPERR_MOVED
#define DRARPERR_MOVED     4
#endif

#ifndef DRARPERR_FAILURE
#define DRARPERR_FAILURE     5
#endif

static const value_string op_vals[] = {
    { ARPOP_REQUEST,                "request" },
    { ARPOP_REPLY,                  "reply" },
    { ARPOP_RREQUEST,               "reverse request" },
    { ARPOP_RREPLY,                 "reverse reply" },
    { ARPOP_DRARPREQUEST,           "drarp request" },
    { ARPOP_DRARPREPLY,             "drarp reply" },
    { ARPOP_DRARPERROR,             "drarp error" },
    { ARPOP_IREQUEST,               "inverse request" },
    { ARPOP_IREPLY,                 "inverse reply" },
    { ATMARPOP_NAK,                 "arp nak" },
    { ARPOP_MARS_REQUEST,           "mars request" },
    { ARPOP_MARS_MULTI,             "mars multi" },
    { ARPOP_MARS_MSERV,             "mars mserv" },
    { ARPOP_MARS_JOIN,              "mars join" },
    { ARPOP_MARS_LEAVE,             "mars leave" },
    { ARPOP_MARS_NAK,               "mars nak" },
    { ARPOP_MARS_UNSERV,            "mars unserv" },
    { ARPOP_MARS_SJOIN,             "mars sjoin" },
    { ARPOP_MARS_SLEAVE,            "mars sleave" },
    { ARPOP_MARS_GROUPLIST_REQUEST, "mars grouplist request" },
    { ARPOP_MARS_GROUPLIST_REPLY,   "mars gruoplist reply" },
    { ARPOP_MARS_REDIRECT_MAP,      "mars redirect map" },
    { ARPOP_MAPOS_UNARP,            "mapos unarp" },
    { ARPOP_EXP1,                   "experimental 1" },
    { ARPOP_EXP2,                   "experimental 2" },
    { ARPOP_RESERVED1,              "reserved" },
    { ARPOP_RESERVED2,              "reserved" },
    { 0, NULL } };

static const char* get_arp_hardware_type_string(gushort type);
static const char* get_arp_protocol_type_string(gushort type);
static const char* get_arp_optcode_type_string(gushort type);
static gboolean buf_to_mac_addr(const char* psz_buf, int buf_len, /*INOUT*/char* psz_rc, int rc_len);
static gboolean buf_to_ip(const char* psz_buf, int buf_len, /*INOUT*/char* psz_rc, int rc_len);
static int dissect_proc_foo(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree _U_, void *data _U_);

void proto_register_foo(void)
{
    protocol_handle_foo = proto_register_protocol(
        PROTOCOL_FULL_NAME_FOO,
        PROTOCOL_SHORT_NAME_FOO,
        PROTOCOL_DISPLAY_FILTER_NAME_FOO);

    proto_register_field_array(protocol_handle_foo, hf, array_length(hf));
    proto_register_subtree_array(ett, array_length(ett));

    dissector_handle_foo = register_dissector(PROTOCOL_SHORT_NAME_FOO, dissect_proc_foo, protocol_handle_foo);
}

void proto_reg_handoff_foo(void)
{
    // 只有注册了协议分析器要处理的协议, wireshark才会回调到dissector_handle_foo
    dissector_add_uint("ethertype", ETHERTYPE_ARP, dissector_handle_foo);
//  dissector_add_uint("ethertype", ETHERTYPE_REVARP, dissector_handle_foo);
}

// https://stackoverflow.com/questions/20247551/icmp-echo-checksum
// http://www.faqs.org/rfcs/rfc1071.html
static guint16 calc_check_sum(const guint8* data, int len)
{
    guint32 sum = 0;
    guint16 tmp = 0;
    int i = 0;

    do {
        if ((NULL == data) || (len <= 0) || (0 != (len % 8))) {
            break;
        }

        for (i = 0; i < len; i += 2) {
            tmp = (guint16)g_ntohs(*(guint16*)(data + i)); // BE data
            if (0 == i) {
                sum = tmp;
                continue;
            }
            else if (2 == i) {
                // this is check sum, need skip it
                continue;
            }
            else {
                sum += tmp;
            }
        }

        // add carry bit !
        while (sum >> 16) {
            sum = (sum & 0xffff) + (sum >> 16);
        };

        sum = ~sum;
    } while (0);

    return (guint16)sum;
}

// wireshark工程由vs2015编译器设置成默认字节对齐(8字节)
// Projects-Properties-Configuration Properties-C/C++-Code generation-Struct Member Alignment, 如果没有修改过,则默认值是Default,即8字节对齐。

typedef struct _tag_arp_header {
    // these data type all BE
    gushort hardware_type; // Hardware type : Ethernet(1)
    gushort protocol_type; // Protocol type: IPv4 (0x0800)
    guchar hardware_size; // Hardware size: 6
    guchar protocol_size; // Protocol size: 4
    gushort opt_code; // Opcode: request (1)
} TAG_ARP_HEADER;

static int dissect_proc_foo(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree _U_, void *data _U_)
{
    bool b_pasre_ok = false;
    TAG_ARP_HEADER hdr_arp;

    char sz_buf[4096] = { '\0' };
    proto_item* item = NULL;
    proto_item* item_tmp = NULL;
    proto_tree* sub_tree_foo = NULL;

    guint captured_length = tvb_captured_length(tvb);
    guint data_len_left = captured_length; // 要处理的数据长度
    guint data_offset = 0; // 从起始数据开始偏移多少
    const guint8* data_left = NULL; // 要处理的数据
    const guint8* data_org = NULL; // 要处理的原始数据
    guint16 tmp_u16 = 0;

    // set col.5 = "Protocol" 's content to 'foo'
    col_set_str(pinfo->cinfo, COL_PROTOCOL, "ARP");

    // set col.7 = "Info" 's content to empty, else will display by tcp info
    col_clear(pinfo->cinfo, COL_INFO);

    item = proto_tree_add_item(tree, protocol_handle_foo, tvb, 0, -1, ENC_NA);

    do {
        // 在节点下增加子树, 此时子树还没有显示出来
        sub_tree_foo = proto_item_add_subtree(item, ett_foo);
        if (NULL == sub_tree_foo) {
            break;
        }

        // save data and data len
        data_org = tvb_get_ptr(tvb, 0, -1);
        data_left = data_org;
        data_offset = 0;

        // ready read header
        if (data_len_left < sizeof(TAG_ARP_HEADER)) {
            break;
        }

        memcpy(&hdr_arp, data_left, sizeof(TAG_ARP_HEADER));
        data_left += sizeof(TAG_ARP_HEADER);
        data_len_left -= sizeof(TAG_ARP_HEADER);
        data_offset += sizeof(TAG_ARP_HEADER);

        // show hdr_arp.hardware_type
        item_tmp = proto_tree_add_string_format_value(sub_tree_foo, hf_foo_message, tvb, 
            offsetof(TAG_ARP_HEADER, hardware_type), sizeof(hdr_arp.hardware_type),
            NULL, // 可选
            NULL,
            -1);

        tmp_u16 = g_ntohs(hdr_arp.hardware_type);
        proto_item_set_text(item_tmp, "TAG_ARP_HEADER.hardware_type = %s (0x%4.4X)", get_arp_hardware_type_string(tmp_u16), tmp_u16);

        // show hdr_arp.protocol_type
        item_tmp = proto_tree_add_string_format_value(sub_tree_foo, hf_foo_message, tvb,
            offsetof(TAG_ARP_HEADER, protocol_type), sizeof(hdr_arp.protocol_type),
            NULL, // 可选
            NULL,
            -1);

        tmp_u16 = g_ntohs(hdr_arp.protocol_type);
        proto_item_set_text(item_tmp, "TAG_ARP_HEADER.protocol_type = %s (0x%4.4X)", get_arp_protocol_type_string(tmp_u16), tmp_u16);

        // show hdr_arp.hardware_size
        item_tmp = proto_tree_add_string_format_value(sub_tree_foo, hf_foo_message, tvb,
            offsetof(TAG_ARP_HEADER, hardware_size), sizeof(hdr_arp.hardware_size),
            NULL, // 可选
            NULL,
            -1);

        tmp_u16 = hdr_arp.hardware_size;
        proto_item_set_text(item_tmp, "TAG_ARP_HEADER.hardware_size = %d", tmp_u16);

        // show hdr_arp.protocol_size
        item_tmp = proto_tree_add_string_format_value(sub_tree_foo, hf_foo_message, tvb,
            offsetof(TAG_ARP_HEADER, protocol_size), sizeof(hdr_arp.protocol_size),
            NULL, // 可选
            NULL,
            -1);

        tmp_u16 = hdr_arp.protocol_size;
        proto_item_set_text(item_tmp, "TAG_ARP_HEADER.protocol_size = %d", tmp_u16);

        // show hdr_arp.opt_code
        item_tmp = proto_tree_add_string_format_value(sub_tree_foo, hf_foo_message, tvb,
            offsetof(TAG_ARP_HEADER, opt_code), sizeof(hdr_arp.opt_code),
            NULL, // 可选
            NULL,
            -1);

        tmp_u16 = g_ntohs(hdr_arp.opt_code);
        proto_item_set_text(item_tmp, "TAG_ARP_HEADER.opt_code = %s (0x%4.4X)", get_arp_optcode_type_string(tmp_u16), tmp_u16);

        tmp_u16 = (hdr_arp.hardware_size + hdr_arp.protocol_size) * 2;
        if (data_len_left < (tmp_u16)) {
            break;
        }

        // show sender mac
        item_tmp = proto_tree_add_string_format_value(sub_tree_foo, hf_foo_message, tvb,
            data_offset, hdr_arp.hardware_size,
            NULL, // 可选
            NULL,
            -1);

        memset(sz_buf, 0, sizeof(sz_buf));
        buf_to_mac_addr(data_left, hdr_arp.hardware_size, sz_buf, sizeof(sz_buf));
        data_left += hdr_arp.hardware_size;
        data_len_left -= hdr_arp.hardware_size;
        data_offset += hdr_arp.hardware_size;

        proto_item_set_text(item_tmp, "sender mac = %s", sz_buf);

        // show send ip
        item_tmp = proto_tree_add_string_format_value(sub_tree_foo, hf_foo_message, tvb,
            data_offset, hdr_arp.protocol_size,
            NULL, // 可选
            NULL,
            -1);

        memset(sz_buf, 0, sizeof(sz_buf));
        buf_to_ip(data_left, hdr_arp.protocol_size, sz_buf, sizeof(sz_buf));
        data_left += hdr_arp.protocol_size;
        data_len_left -= hdr_arp.protocol_size;
        data_offset += hdr_arp.protocol_size;

        proto_item_set_text(item_tmp, "sender ip = %s", sz_buf);

        // show request mac
        item_tmp = proto_tree_add_string_format_value(sub_tree_foo, hf_foo_message, tvb,
            data_offset, hdr_arp.hardware_size,
            NULL, // 可选
            NULL,
            -1);

        memset(sz_buf, 0, sizeof(sz_buf));
        buf_to_mac_addr(data_left, hdr_arp.hardware_size, sz_buf, sizeof(sz_buf));
        data_left += hdr_arp.hardware_size;
        data_len_left -= hdr_arp.hardware_size;
        data_offset += hdr_arp.hardware_size;

        proto_item_set_text(item_tmp, "request mac = %s", sz_buf);

        // show request ip
        item_tmp = proto_tree_add_string_format_value(sub_tree_foo, hf_foo_message, tvb,
            data_offset, hdr_arp.protocol_size,
            NULL, // 可选
            NULL,
            -1);

        memset(sz_buf, 0, sizeof(sz_buf));
        buf_to_ip(data_left, hdr_arp.protocol_size, sz_buf, sizeof(sz_buf));
        data_left += hdr_arp.protocol_size;
        data_len_left -= hdr_arp.protocol_size;
        data_offset += hdr_arp.protocol_size;

        proto_item_set_text(item_tmp, "request ip = %s", sz_buf);

        b_pasre_ok = true;
    } while (0);

    if (NULL != sub_tree_foo) {
        // show END message, parse ok or error
        item_tmp = proto_tree_add_string_format_value(sub_tree_foo, hf_foo_message, tvb, 0, -1,
            NULL, // 可选
            NULL,
            -1);

        proto_item_set_text(item_tmp, b_pasre_ok ? "nice, parse ok" : "error, please connect developer");
    }

    return captured_length; // return data length by process
}

static const char* get_arp_hardware_type_string(gushort type)
{
    int i = 0;
    int ary_size = sizeof(arp_hrd_vals) / sizeof(arp_hrd_vals[0]);
    const char* rc = NULL;

    for (i = 0; i < ary_size; i++) {
        if (type == arp_hrd_vals[i].value) {
            rc = arp_hrd_vals[i].strptr;
            break;
        }
    }

    if (NULL == rc) {
        rc = "unknown";
    }

    return rc;
}

static const char* get_arp_protocol_type_string(gushort type)
{
    int i = 0;

    int ary_size = sizeof(my_etype_vals) / sizeof(my_etype_vals[0]);
    const char* rc = NULL;

    for (i = 0; i < ary_size; i++) {
        if (type == my_etype_vals[i].value) {
            rc = my_etype_vals[i].strptr;
            break;
        }
    }

    if (NULL == rc) {
        rc = "unknown";
    }

    return rc;
}

static const char* get_arp_optcode_type_string(gushort type)
{
    int i = 0;
    int ary_size = sizeof(op_vals) / sizeof(op_vals[0]);
    const char* rc = NULL;

    for (i = 0; i < ary_size; i++) {
        if (type == op_vals[i].value) {
            rc = op_vals[i].strptr;
            break;
        }
    }

    if (NULL == rc) {
        rc = "unknown";
    }

    return rc;
}

static gboolean buf_to_mac_addr(const char* psz_buf, int buf_len, /*INOUT*/char* psz_rc, int rc_len)
{
    gboolean rc = FALSE;
    int i = 0;
    char buf[4] = { '\0' };
    guchar tmp_uc = 0;

    do {
        if ((NULL == psz_buf) 
            || (NULL == psz_rc)
            || (rc_len < (buf_len * 2 + buf_len - 1))) {
            break;
        }

        memset(psz_rc, 0, rc_len);
        for (i = 0; i < buf_len; i++) {
            memset(buf, 0, sizeof(buf));
            tmp_uc = *(psz_buf + i);
            sprintf(buf, "%2.2X", tmp_uc);
            strcat(psz_rc, buf);
            if (i != (buf_len - 1)) {
                strcat(psz_rc, ":");
            }
        }
    } while (0);

    return rc;
}

static gboolean buf_to_ip(const char* psz_buf, int buf_len, /*INOUT*/char* psz_rc, int rc_len)
{
    gboolean rc = FALSE;
    int i = 0;
    char buf[4] = { '\0' };
    guchar tmp_uc = 0;

    do {
        if ((NULL == psz_buf)
            || (NULL == psz_rc)
            || (rc_len < (buf_len * 3 + buf_len - 1))) {
            break;
        }

        memset(psz_rc, 0, rc_len);
        for (i = 0; i < buf_len; i++) {
            memset(buf, 0, sizeof(buf));
            tmp_uc = *(psz_buf + i);
            sprintf(buf, "%d", tmp_uc);
            strcat(psz_rc, buf);
            if (i != (buf_len - 1)) {
                strcat(psz_rc, ".");
            }
        }
    } while (0);

    return rc;
}

你可能感兴趣的:(wireshark插件 - 用自己做的插件,来简单分析ARP协议)