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
|