/****** * HFTSniff simple sniffer using pcap * xorg62@gmail.com ******/ #include #include #include #include #include #include #include #include #include #include #include #include /* Macros */ #define LEN(x) (sizeof(x) / sizeof(*x)) /* Using ANSI escape codes to use bold in simple text mode */ #define IP_SRCDEST(src, psrc, dest, pdest) \ do { \ printf("%s:\e[1m%d\e[0m ==> %s:\e[1m%d\e[0m\n", \ src, psrc, dest, pdest); \ } while(/* CONSTCOND */ 0); #define DISP_PROTO(s) \ do { \ printf("( \e[1m%s\e[0m ) ", s); \ } while(/* CONSTCOND */ 0); #define DISP_PAYLOAD(p, l) \ do { \ int i = 0; \ for(; i < (l) && (p); ++i, ++(p)) \ if(isprint(*(p))) \ putchar((char)*(p)); \ } while(/* CONSTCOND */ 0); #define BYE(s, er) \ do { \ fprintf(stderr, s": (%s)\n", er); \ exit(EXIT_FAILURE); \ } while(/* CONSTCOND */ 0); #define PKT_ERROR(r, s, a) \ do { \ fprintf(stderr, " PKT_ERROR: %s (%u)\n", s, a); \ return r; \ } while(/* CONSTCOND */ 0); \ /* Option const */ #define FILTER "ip" #define TIMEOUT (10) #define SNAPLEN (SHRT_MAX) /* * Ethernet packet format */ #define ETHERNET_SIZE (14) #define ETHERNET_ALEN (6) struct ethernet_header { unsigned char ether_dhost[ETHERNET_ALEN]; /* Destination ethernet address */ unsigned char ether_shost[ETHERNET_ALEN]; /* Source ethernet adress */ unsigned short ether_type; /* Packet type, id field */ }; /* * Ip packet format (tcpdump way) */ #define IP_V(ip) (((ip)->ip_vhl & 0xf0) >> 4) #define IP_HL(ip) ((ip)->ip_vhl & 0x0f) #define IP_DF (0x4000) /* Dont fragment flag */ #define IP_MF (0x2000) /* More fragments flag */ #define IP_OFFMASK (0x1fff) /* Mask for fragmenting bits */ struct ip_header { unsigned char ip_vhl; /* Header length, version */ unsigned char ip_tos; /* Type of service */ unsigned short ip_len; /* Total length */ unsigned short ip_id; /* Identification */ unsigned short ip_off; /* Fragment offset field */ unsigned char ip_ttl; /* Time to live */ unsigned char ip_p; /* Protocol */ unsigned short ip_sum; /* Checksum */ struct in_addr ip_src, ip_dst; /* Source and dest address */ }; /* * TCP packet format */ #define TH_OFF(th) (((th)->th_offx2 & 0xf0) >> 4) #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 (0xf7) /* TH_* */ struct tcp_header { unsigned short th_sport; /* Source port */ unsigned short th_dport; /* Destination port */ unsigned int th_seq; /* Sequence number */ unsigned int th_ack; /* Acknowledgement number */ unsigned char th_offx2; /* Data offset, rsvd */ unsigned char th_flags; /* Flags bitfield */ unsigned short th_win; /* Window */ unsigned short th_sum; /* Checksum */ unsigned short th_urp; /* Urgent pointer */ }; /* Function protos */ int pkt_tcp_handle(void *, void *); /* Usefull things */ const struct { unsigned int p; int (*f)(void *, void*); char name[32]; } protos[] = { { IPPROTO_IP, NULL, "IP" }, /* _IP 0 */ { IPPROTO_ICMP, NULL, "ICMP" }, /* _ICMP 1 */ { IPPROTO_TCP, pkt_tcp_handle, "TCP" }, /* _TCP 6 */ { IPPROTO_UDP, NULL, "UDP" }, /* _UDP 17 */ { -1, NULL, ""} }; /* As defined in man: */ char errbuf[PCAP_ERRBUF_SIZE]; /* * Handle TCP packets */ int pkt_tcp_handle(void *pkt, void *prev_pkt) { const struct tcp_header *tcp; const struct ip_header *ip; int len; ip = (struct ip_header*)prev_pkt; tcp = (struct tcp_header*)(pkt + ETHERNET_SIZE + (IP_HL(ip) << 2)); if((len = TH_OFF(tcp) << 2) < 20) PKT_ERROR(0, "Invalid IP header length:", len); IP_SRCDEST(inet_ntoa(ip->ip_src), ntohs(tcp->th_sport), /* src */ inet_ntoa(ip->ip_dst), ntohs(tcp->th_dport)); /* dest */ return len; } /* * Handle every packet, point it to corresponding pkt_proto_handle */ void pkt_handle(unsigned char *args, const struct pcap_pkthdr *header, const unsigned char *packet) { struct ethernet_header *eth; struct ip_header *ip; const unsigned char *payload; int len, plen, paylen, i = 0; bool pfound = false; /* Translate ethernet pkt */ eth = (struct ethernet_header*)packet; /* Translate ip pkt */ ip = (struct ip_header*)(packet + ETHERNET_SIZE); /* Check ipv4 */ if((len = IP_HL(ip) << 2) < 20) PKT_ERROR(, "Invalid IP header length:", len); /* Protocol */ for(; i < LEN(protos); ++i) if(ip->ip_p == protos[i].p) { DISP_PROTO(protos[i].name); if(protos[i].f) plen = protos[i].f((void*)packet, (void*)ip); pfound = true; break; } /* Unknown protocol */ if(!pfound) { DISP_PROTO("unknown"); IP_SRCDEST(inet_ntoa(ip->ip_src), -1, /* src */ inet_ntoa(ip->ip_dst), -1); /* dest */ puts("\n"); return; } /* Get / Display payload */ payload = (unsigned char*)(packet + ETHERNET_SIZE + len + plen); if((paylen = ntohs(ip->ip_len) - (len + plen)) > 0) DISP_PAYLOAD(payload, paylen); puts("\n"); return; } int main(int argc, char **argv) { char *dev; bpf_u_int32 mask; bpf_u_int32 netip; pcap_t *descr; struct bpf_program bpf; if(argc < 2) { fprintf(stderr, "%s usage: %s \n", argv[0], argv[0]); exit(EXIT_FAILURE); } /* Find adress & mask */ if(pcap_lookupnet(argv[1], &netip, &mask, errbuf) < 0) { fprintf(stderr, "Can't find Adress or Mask: (%s)\n", errbuf); netip = mask = 0; } /* Open device and reaaad */ if(!(descr = pcap_open_live(argv[1], SNAPLEN, true, TIMEOUT, errbuf))) BYE("Fail at opening and reading device", errbuf); /* Check if packet is from ethernet device */ if(pcap_datalink(descr) != DLT_EN10MB) BYE("Device is not an Ethernet", dev); /* Parse & set pcap with option expression */ if(pcap_compile(descr, &bpf, FILTER, 0, netip) < 0) BYE("Option parse error", pcap_geterr(descr)); if(pcap_setfilter(descr, &bpf) < 0) BYE("Can't use option", pcap_geterr(descr)); printf("%d\n", 1<<1); pcap_loop(descr, 10, pkt_handle, NULL); pcap_freecode(&bpf); pcap_close(descr); return 0; }