GPSBots.com
Home :: [Photos] : [Tutorials] : [Projects] : [Resources] : [About Us]

Linux Tutorial: Sniff TCP/UDP Packets

sniff_packets.c - Download Source Code
By using the PCAP library, sniffing network traffic is quite easy. The following code was compiled successfully under Slackware 10 on a Mini-ITX board.
To Compile: g++ sniff_packets.c -g -o sniff_packets -O3 -lpcap
-g to allow gdb to work
-o sniff_packets is the output name
-O3 is the optimization level
-lpcap includes the pcap library

#include <stdlib.h>      // exit
#include <unistd.h>      // exit
#include <pcap.h>      // packet capture
#include <arpa/inet.h>      // inet_ntoa
#include <netinet/if_ether.h>      // ETHER_ADDR_LEN

#define DEVICE "eth0"
#define PORTS "udp port 3000 or udp port 3001"

struct ip_header {      // Internet Protocol header
     #if BYTE_ORDER == LITTLE_ENDIAN
     u_int ip_hl:4, ip_v:4;
     #endif
     #if BYTE_ORDER == BIG_ENDIAN
     u_int ip_v:4, ip_hl:4;
     #endif
     u_char ip_tos;      // type of service
     u_short ip_len;      // total length
     u_short ip_id;      // identification
     u_short ip_off;      // fragment offset field
     #define IP_RF 0x8000      // reserved fragment flag
     #define IP_DF 0x4000      // dont fragment flag
     #define IP_MF 0x2000      // more fragments flag
     #define IP_OFFMASK 0x1fff      // mask for fragmenting bits
     u_char ip_ttl;      // time to live
     u_char ip_p;      // protocol
     u_short ip_sum;      // checksum
          // source and destination address
     struct in_addr ip_src, ip_dst;
};

struct tcp_header {      // Transport Control Protocol header
     u_short th_sport;      // source port
     u_short th_dport;      // destination port
     int th_seq;      // sequence number - 32 bits
     int th_ack;      // ack number - 32 bits
          // unused and data offset !
     #if BYTE_ORDER == LITTLE_ENDIAN
     u_int th_x2:4, th_off:4;
     #endif
     #if BYTE_ORDER == BIG_ENDIAN
     u_int th_off:4, th_x2:4;
     #endif
          // Control bits, 6 bits [from left to right]
     u_char th_flags;
     #define TH_FIN 0x01
     #define TH_SYN 0x02
     #define TH_RST 0x04
     #define TH_PUSH 0x08
     #define TH_ACK 0x10
     #define TH_URG 0x20
     #define TH_ECE 0x40
     #define TH_CWR 0x80
     #define TH_FLAGS (TH_FIN|TH_SYN|TH_RST|TH_ACK|TH_URG|TH_ECE|TH_CWR)
     u_short th_win;      // window
     u_short th_sum;      // checksum
     u_short th_urp;      // urgent pointer
};

struct udp_header {      // Transport Control Protocol header
     u_short th_sport;      // source port
     u_short th_dport;      // destination port
     u_short th_len;      // length
     u_short th_sum;      // checksum
};

struct ethernet_header {      // Ethernet Header
     u_char ether_dhost[ETHER_ADDR_LEN];      // destination address
     u_char ether_shost[ETHER_ADDR_LEN];      // source address
     u_short ether_type;      // type of packet
};


void diep(char *s) { perror(s); exit(1); }
void pcap_handler2(u_char *args, const struct pcap_pkthdr *header, const u_char *packet);

int main(void) {
     struct pcap *handle;      // handle to the pcap object
     char errbuf[PCAP_ERRBUF_SIZE];      // pcap puts its error messages in here
     bpf_u_int32 mask, net;
     pcap_lookupnet(DEVICE, &net, &mask, errbuf);
     handle = pcap_open_live(DEVICE, 8096, 1, 1000, errbuf);
     if ((handle = pcap_open_live(DEVICE, 8096, 1, 1000, errbuf)) == NULL) { perror("Error: Can't open device"); _exit(0); }
     struct bpf_program filter;      // filter to apply to pcap, ie "udp port 4020 or udp port 4030"
     pcap_compile(handle, &filter, PORTS, 0, net);      // assign the filter
     pcap_setfilter(handle, &filter);      // activate filter
     unsigned char packet[65535];

     printf("\n** logging: ready to recieve packets, ctrl-c to exit **\n");
     while (1) {
          pcap_loop(handle, 10, pcap_handler2, packet);      // callback pcap_handler2 on new packet
          usleep(1);
     }

     pcap_close(handle);
     return 0;
}



void pcap_handler2(u_char *args, const struct pcap_pkthdr *header, const u_char *packet) {
     const struct ethernet_header *ethernet;
     const struct ip_header *ip;
     const struct tcp_header *tcp;
     const struct udp_header *udp;
     const char *payload = NULL;
     int port = 0;

          // Define data position
     ethernet = (struct ethernet_header *)(packet);
     ip = (struct ip_header*)(packet + sizeof(struct ethernet_header));

     if (ip->ip_p == IPPROTO_TCP) {
          tcp = (struct tcp_header*)(packet + sizeof(struct ethernet_header) + sizeof(struct ip_header));
          payload = (const char*)(packet + sizeof(struct ethernet_header) + sizeof(struct ip_header) + sizeof(struct tcp_header));
          port = ntohs(udp->th_dport);
          printf("TCP:%s:%d > %s:%d = %s\n", inet_ntoa(ip->ip_src), ntohs(tcp->th_sport), inet_ntoa(ip->ip_dst), ntohs(tcp->th_dport), payload);

     } else if (ip->ip_p == IPPROTO_UDP) {
          udp = (struct udp_header*)(packet + sizeof(struct ethernet_header) + sizeof(struct ip_header));
          payload = (const char*)(packet + sizeof(struct ethernet_header) + sizeof(struct ip_header) + sizeof(struct udp_header));
          payload[ntohs(udp->th_len)-8] = 0;      // null terminate (weird bug)
          port = ntohs(udp->th_dport);
          printf("UDP:%s:%d > %s:%d = %s\n", inet_ntoa(ip->ip_src), ntohs(udp->th_sport), inet_ntoa(ip->ip_dst), ntohs(udp->th_dport), payload);
     }
}

Sample Output:

Use transmit_udp to send a test packet.
UDP:10.1.1.90:32774 > 10.1.1.90:3000 = Test UDP Packet