In this lesson we will take code from the previous lessons and use these pieces to build a more useful program. the main purpose of the current program is to show how the protocol headers of a captured packet can be parsed and interpreted. The resulting application, called UDPdump, prints a summary of the UDP traffic on our network.
We have chosen to parse and display the UDP protocol because it is more accessible than other protocols such as TCP and consequently is an excellent initial example. Let's look at the code:
/* * Copyright (c) 1999 - 2005 NetGroup, Politecnico di Torino (Italy) * Copyright (c) 2005 - 2006 CACE Technologies, Davis (California) * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. Neither the name of the Politecnico di Torino, CACE Technologies * nor the names of its contributors may be used to endorse or promote * products derived from this software without specific prior written * permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * */ #include "pcap.h" /* 4 bytes IP address */ typedef struct ip_address{ u_char byte1; u_char byte2; u_char byte3; u_char byte4; }ip_address; /* IPv4 header */ typedef struct ip_header{ u_char ver_ihl; // Version (4 bits) + Internet header length (4 bits) u_char tos; // Type of service u_short tlen; // Total length u_short identification; // Identification u_short flags_fo; // Flags (3 bits) + Fragment offset (13 bits) u_char ttl; // Time to live u_char proto; // Protocol u_short crc; // Header checksum ip_address saddr; // Source address ip_address daddr; // Destination address u_int op_pad; // Option + Padding }ip_header; /* UDP header*/ typedef struct udp_header{ u_short sport; // Source port u_short dport; // Destination port u_short len; // Datagram length u_short crc; // Checksum }udp_header; /* prototype of the packet handler */ void packet_handler(u_char *param, const struct pcap_pkthdr *header, const u_char *pkt_data); main() { pcap_if_t *alldevs; pcap_if_t *d; int inum; int i=0; pcap_t *adhandle; char errbuf[PCAP_ERRBUF_SIZE]; u_int netmask; char packet_filter[] = "ip and udp"; struct bpf_program fcode; /* Retrieve the device list */ if (pcap_findalldevs_ex(PCAP_SRC_IF_STRING, NULL, &alldevs, errbuf) == -1) { fprintf(stderr,"Error in pcap_findalldevs: %s\n", errbuf); exit(1); } /* Print the list */ for(d=alldevs; d; d=d->next) { printf("%d. %s", ++i, d->name); if (d->description) printf(" (%s)\n", d->description); else printf(" (No description available)\n"); } if(i==0) { printf("\nNo interfaces found! Make sure WinPcap is installed.\n"); return -1; } printf("Enter the interface number (1-%d):",i); scanf("%d", &inum); if(inum < 1 || inum > i) { printf("\nInterface number out of range.\n"); /* Free the device list */ pcap_freealldevs(alldevs); return -1; } /* Jump to the selected adapter */ for(d=alldevs, i=0; i< inum-1 ;d=d->next, i++); /* Open the adapter */ if ( (adhandle= pcap_open(d->name, // name of the device 65536, // portion of the packet to capture. // 65536 grants that the whole packet will be captured on all the MACs. PCAP_OPENFLAG_PROMISCUOUS, // promiscuous mode 1000, // read timeout NULL, // remote authentication errbuf // error buffer ) ) == NULL) { fprintf(stderr,"\nUnable to open the adapter. %s is not supported by WinPcap\n"); /* Free the device list */ pcap_freealldevs(alldevs); return -1; } /* Check the link layer. We support only Ethernet for simplicity. */ if(pcap_datalink(adhandle) != DLT_EN10MB) { fprintf(stderr,"\nThis program works only on Ethernet networks.\n"); /* Free the device list */ pcap_freealldevs(alldevs); return -1; } if(d->addresses != NULL) /* Retrieve the mask of the first address of the interface */ netmask=((struct sockaddr_in *)(d->addresses->netmask))->sin_addr.S_un.S_addr; else /* If the interface is without addresses we suppose to be in a C class network */ netmask=0xffffff; //compile the filter if (pcap_compile(adhandle, &fcode, packet_filter, 1, netmask) <0 ) { fprintf(stderr,"\nUnable to compile the packet filter. Check the syntax.\n"); /* Free the device list */ pcap_freealldevs(alldevs); return -1; } //set the filter if (pcap_setfilter(adhandle, &fcode)<0) { fprintf(stderr,"\nError setting the filter.\n"); /* Free the device list */ pcap_freealldevs(alldevs); return -1; } printf("\nlistening on %s...\n", d->description); /* At this point, we don't need any more the device list. Free it */ pcap_freealldevs(alldevs); /* start the capture */ pcap_loop(adhandle, 0, packet_handler, NULL); return 0; } /* Callback function invoked by libpcap for every incoming packet */ void packet_handler(u_char *param, const struct pcap_pkthdr *header, const u_char *pkt_data) { struct tm *ltime; char timestr[16]; ip_header *ih; udp_header *uh; u_int ip_len; u_short sport,dport; time_t local_tv_sec; /* convert the timestamp to readable format */ local_tv_sec = header->ts.tv_sec; ltime=localtime(&local_tv_sec); strftime( timestr, sizeof timestr, "%H:%M:%S", ltime); /* print timestamp and length of the packet */ printf("%s.%.6d len:%d ", timestr, header->ts.tv_usec, header->len); /* retireve the position of the ip header */ ih = (ip_header *) (pkt_data + 14); //length of ethernet header /* retireve the position of the udp header */ ip_len = (ih->ver_ihl & 0xf) * 4; uh = (udp_header *) ((u_char*)ih + ip_len); /* convert from network byte order to host byte order */ sport = ntohs( uh->sport ); dport = ntohs( uh->dport ); /* print ip addresses and udp ports */ printf("%d.%d.%d.%d.%d -> %d.%d.%d.%d.%d\n", ih->saddr.byte1, ih->saddr.byte2, ih->saddr.byte3, ih->saddr.byte4, sport, ih->daddr.byte1, ih->daddr.byte2, ih->daddr.byte3, ih->daddr.byte4, dport); }
00001 /* 00002 * Copyright (c) 1999 - 2005 NetGroup, Politecnico di Torino (Italy) 00003 * Copyright (c) 2005 - 2006 CACE Technologies, Davis (California) 00004 * All rights reserved. 00005 * 00006 * Redistribution and use in source and binary forms, with or without 00007 * modification, are permitted provided that the following conditions 00008 * are met: 00009 * 00010 * 1. Redistributions of source code must retain the above copyright 00011 * notice, this list of conditions and the following disclaimer. 00012 * 2. Redistributions in binary form must reproduce the above copyright 00013 * notice, this list of conditions and the following disclaimer in the 00014 * documentation and/or other materials provided with the distribution. 00015 * 3. Neither the name of the Politecnico di Torino, CACE Technologies 00016 * nor the names of its contributors may be used to endorse or promote 00017 * products derived from this software without specific prior written 00018 * permission. 00019 * 00020 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 00021 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 00022 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 00023 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 00024 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 00025 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 00026 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 00027 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 00028 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 00029 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 00030 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 00031 * 00032 */ 00033 00034 #include "pcap.h" 00035 00036 /* 4 bytes IP address */ 00037 typedef struct ip_address{ 00038 u_char byte1; 00039 u_char byte2; 00040 u_char byte3; 00041 u_char byte4; 00042 }ip_address; 00043 00044 /* IPv4 header */ 00045 typedef struct ip_header{ 00046 u_char ver_ihl; // Version (4 bits) + Internet header length (4 bits) 00047 u_char tos; // Type of service 00048 u_short tlen; // Total length 00049 u_short identification; // Identification 00050 u_short flags_fo; // Flags (3 bits) + Fragment offset (13 bits) 00051 u_char ttl; // Time to live 00052 u_char proto; // Protocol 00053 u_short crc; // Header checksum 00054 ip_address saddr; // Source address 00055 ip_address daddr; // Destination address 00056 u_int op_pad; // Option + Padding 00057 }ip_header; 00058 00059 /* UDP header*/ 00060 typedef struct udp_header{ 00061 u_short sport; // Source port 00062 u_short dport; // Destination port 00063 u_short len; // Datagram length 00064 u_short crc; // Checksum 00065 }udp_header; 00066 00067 /* prototype of the packet handler */ 00068 void packet_handler(u_char *param, const struct pcap_pkthdr *header, const u_char *pkt_data); 00069 00070 00071 main() 00072 { 00073 pcap_if_t *alldevs; 00074 pcap_if_t *d; 00075 int inum; 00076 int i=0; 00077 pcap_t *adhandle; 00078 char errbuf[PCAP_ERRBUF_SIZE]; 00079 u_int netmask; 00080 char packet_filter[] = "ip and udp"; 00081 struct bpf_program fcode; 00082 00083 /* Retrieve the device list */ 00084 if (pcap_findalldevs_ex(PCAP_SRC_IF_STRING, NULL, &alldevs, errbuf) == -1) 00085 { 00086 fprintf(stderr,"Error in pcap_findalldevs: %s\n", errbuf); 00087 exit(1); 00088 } 00089 00090 /* Print the list */ 00091 for(d=alldevs; d; d=d->next) 00092 { 00093 printf("%d. %s", ++i, d->name); 00094 if (d->description) 00095 printf(" (%s)\n", d->description); 00096 else 00097 printf(" (No description available)\n"); 00098 } 00099 00100 if(i==0) 00101 { 00102 printf("\nNo interfaces found! Make sure WinPcap is installed.\n"); 00103 return -1; 00104 } 00105 00106 printf("Enter the interface number (1-%d):",i); 00107 scanf("%d", &inum); 00108 00109 if(inum < 1 || inum > i) 00110 { 00111 printf("\nInterface number out of range.\n"); 00112 /* Free the device list */ 00113 pcap_freealldevs(alldevs); 00114 return -1; 00115 } 00116 00117 /* Jump to the selected adapter */ 00118 for(d=alldevs, i=0; i< inum-1 ;d=d->next, i++); 00119 00120 /* Open the adapter */ 00121 if ( (adhandle= pcap_open(d->name, // name of the device 00122 65536, // portion of the packet to capture. 00123 // 65536 grants that the whole packet will be captured on all the MACs. 00124 PCAP_OPENFLAG_PROMISCUOUS, // promiscuous mode 00125 1000, // read timeout 00126 NULL, // remote authentication 00127 errbuf // error buffer 00128 ) ) == NULL) 00129 { 00130 fprintf(stderr,"\nUnable to open the adapter. %s is not supported by WinPcap\n"); 00131 /* Free the device list */ 00132 pcap_freealldevs(alldevs); 00133 return -1; 00134 } 00135 00136 /* Check the link layer. We support only Ethernet for simplicity. */ 00137 if(pcap_datalink(adhandle) != DLT_EN10MB) 00138 { 00139 fprintf(stderr,"\nThis program works only on Ethernet networks.\n"); 00140 /* Free the device list */ 00141 pcap_freealldevs(alldevs); 00142 return -1; 00143 } 00144 00145 if(d->addresses != NULL) 00146 /* Retrieve the mask of the first address of the interface */ 00147 netmask=((struct sockaddr_in *)(d->addresses->netmask))->sin_addr.S_un.S_addr; 00148 else 00149 /* If the interface is without addresses we suppose to be in a C class network */ 00150 netmask=0xffffff; 00151 00152 00153 //compile the filter 00154 if (pcap_compile(adhandle, &fcode, packet_filter, 1, netmask) <0 ) 00155 { 00156 fprintf(stderr,"\nUnable to compile the packet filter. Check the syntax.\n"); 00157 /* Free the device list */ 00158 pcap_freealldevs(alldevs); 00159 return -1; 00160 } 00161 00162 //set the filter 00163 if (pcap_setfilter(adhandle, &fcode)<0) 00164 { 00165 fprintf(stderr,"\nError setting the filter.\n"); 00166 /* Free the device list */ 00167 pcap_freealldevs(alldevs); 00168 return -1; 00169 } 00170 00171 printf("\nlistening on %s...\n", d->description); 00172 00173 /* At this point, we don't need any more the device list. Free it */ 00174 pcap_freealldevs(alldevs); 00175 00176 /* start the capture */ 00177 pcap_loop(adhandle, 0, packet_handler, NULL); 00178 00179 return 0; 00180 } 00181 00182 /* Callback function invoked by libpcap for every incoming packet */ 00183 void packet_handler(u_char *param, const struct pcap_pkthdr *header, const u_char *pkt_data) 00184 { 00185 struct tm *ltime; 00186 char timestr[16]; 00187 ip_header *ih; 00188 udp_header *uh; 00189 u_int ip_len; 00190 u_short sport,dport; 00191 time_t local_tv_sec; 00192 00193 /* convert the timestamp to readable format */ 00194 local_tv_sec = header->ts.tv_sec; 00195 ltime=localtime(&local_tv_sec); 00196 strftime( timestr, sizeof timestr, "%H:%M:%S", ltime); 00197 00198 /* print timestamp and length of the packet */ 00199 printf("%s.%.6d len:%d ", timestr, header->ts.tv_usec, header->len); 00200 00201 /* retireve the position of the ip header */ 00202 ih = (ip_header *) (pkt_data + 00203 14); //length of ethernet header 00204 00205 /* retireve the position of the udp header */ 00206 ip_len = (ih->ver_ihl & 0xf) * 4; 00207 uh = (udp_header *) ((u_char*)ih + ip_len); 00208 00209 /* convert from network byte order to host byte order */ 00210 sport = ntohs( uh->sport ); 00211 dport = ntohs( uh->dport ); 00212 00213 /* print ip addresses and udp ports */ 00214 printf("%d.%d.%d.%d.%d -> %d.%d.%d.%d.%d\n", 00215 ih->saddr.byte1, 00216 ih->saddr.byte2, 00217 ih->saddr.byte3, 00218 ih->saddr.byte4, 00219 sport, 00220 ih->daddr.byte1, 00221 ih->daddr.byte2, 00222 ih->daddr.byte3, 00223 ih->daddr.byte4, 00224 dport); 00225 }
First of all, we set the filter to "ip and udp". In this way we are sure that packet_handler() will receive only UDP packets over IPv4: this simplifies the parsing and increases the efficiency of the program.
We have also created a couple of structs that describe the IP and UDP headers. These structs are used by packet_handler() to properly locate the various header fields.
packet_handler(), although limited to a single protocol dissector (UDP over IPv4), shows how complex "sniffers" like tcpdump/WinDump decode the network traffic. Since we aren't interested in the MAC header, we skip it. For simplicity and before starting the capture, we check the MAC layer with pcap_datalink() to make sure that we are dealing with an Ethernet network. This way we can be sure that the MAC header is exactly 14 bytes.
The IP header is located just after the MAC header. We will extract the IP source and destination addresses from the IP header.
Reaching the UDP header is a bit more complicated, because the IP header doesn't have a fixed length. Therefore, we use the IP header's length field to know its size. Once we know the location of the UDP header, we extract the source and destination ports.
The extracted values are printed on the screen, and the result is something like:
1. \Device\Packet_{A7FD048A-5D4B-478E-B3C1-34401AC3B72F} (Xircom t 10/100 Adapter)
Enter the interface number (1-2):1
listening on Xircom CardBus Ethernet 10/100 Adapter...
16:13:15.312784 len:87 130.192.31.67.2682 -> 130.192.3.21.53
16:13:15.314796 len:137 130.192.3.21.53 -> 130.192.31.67.2682
16:13:15.322101 len:78 130.192.31.67.2683 -> 130.192.3.21.53
Each of the final 3 lines represents a different packet.
documentation. Copyright (c) 2002-2005 Politecnico di Torino. Copyright (c) 2005-2006
CACE Technologies. All rights reserved.