From 99c814703327b6230b0a5900feb76565a499c7f5 Mon Sep 17 00:00:00 2001 From: Steffen Vogel Date: Sun, 31 May 2015 19:09:53 +0200 Subject: [PATCH] improved parser and bugfixes --- session5/sniff/sniff.c | 190 +++++++++++++++++++++++++++++++---------- 1 file changed, 147 insertions(+), 43 deletions(-) diff --git a/session5/sniff/sniff.c b/session5/sniff/sniff.c index b16fb58..7d7beae 100644 --- a/session5/sniff/sniff.c +++ b/session5/sniff/sniff.c @@ -6,6 +6,7 @@ #include #include #include +#include #include #include @@ -14,26 +15,26 @@ #include #include +#include #include #include -#include #include +#include #include #include #include -#define SNAPLEN 65536 -#define INTERFACE "eth1" +#define SNAPLEN 1024 const char* icmp_type_str[] = { [ 0 ] = "Echo Reply", - [ 1 ... 2 ] = NULL, + [ 1 ... 2 ] = NULL, [ 3 ] = "Destination Unreachable", [ 4 ] = "Source Quench", [ 5 ] = "Redirect", [ 6 ] = "Alternate Host Address", - [ 7 ] = NULL, + [ 7 ] = NULL, [ 8 ] = "Echo", [ 9 ] = "Router Advertisement", [ 10 ] = "Router Solicitation", @@ -47,61 +48,161 @@ const char* icmp_type_str[] = { [ 18 ] = "Address Mask Reply" }; -int hexdump(void *buf, size_t len) +int hexdump(char *buf, size_t len) { uint16_t *data = (uint16_t *) buf; - - for (size_t i = 0; i < len; i += 2) { - if (i % 16 == 0 && i != 0) + size_t i; + for (i = 0; i < len; i += 2) { + /* ASCII */ + if (i % 16 == 0 && i != 0) { + printf("\t"); + for (size_t j = i-16; j < i; j++) + printf("%c", isprint(buf[j]) ? buf[j] : '.'); printf("\n"); + } + /* Address offset */ + if (i % 16 == 0) + printf("\t\t%#06x:\t", i); printf("%04hx ", ntohs(data[i/2])); } + + printf("\t"); + for (; i < len; i++) + printf("%c", isprint(buf[i]) ? buf[i] : '.'); printf("\n"); } -int parse_packet(uint8_t *data, size_t len) +int parse_packet(char *data, size_t len) { - /* Parse Ethertype */ + int protocol; + char *next_hdr; + static int cnt; + + printf("%5d >>> Received packet with %u bytes:\n", cnt++, len); + +layer2: { struct ethhdr *eth = (struct ethhdr*) data; - - printf("ether_src: %s ", ether_ntoa((const struct ether_addr*) eth->h_source)); - printf("ether_dst: %s ", ether_ntoa((const struct ether_addr*) eth->h_dest)); - printf("ether_type: %#04x ", eth->h_proto); - - if (eth->h_proto == ETH_P_IP) { - /* Parse IP protocol */ - struct iphdr *ip = (struct iphdr*) (eth+1); + printf("\tEthernet src: %s dst: %s type: %#04x\n", + ether_ntoa((const struct ether_addr*) eth->h_source), + ether_ntoa((const struct ether_addr*) eth->h_dest), + ntohs(eth->h_proto) + ); + + protocol = ntohs(eth->h_proto); + next_hdr = (char *) (eth + 1); +} + + +layer3: switch (protocol) { + case ETH_P_IP: { + /* Parse IP protocol */ + struct iphdr *ip = (struct iphdr*) next_hdr; + char buf[32]; - printf("ip_version: %u ", ip->version); - printf("ip_ihl: %u ", ip->ihl); - printf("ip_ttl: %u ", ip->ttl); - printf("ip_protocol: %u ", ip->protocol); - printf("ip_src: %u ", *((struct in_addr*) &ip->saddr)); - printf("ip_dst: %u ", *((struct in_addr*) &ip->daddr)); + printf("\tIP version: %u ihl: %u ttl: %u protocol: %u src: %s dst %s\n", + ip->version, + ip->ihl, + ip->ttl, + ip->protocol, + inet_ntop(AF_INET, &ip->saddr, buf, sizeof(buf)), + inet_ntop(AF_INET, &ip->daddr, buf, sizeof(buf)) + ); + + protocol = ip->protocol; + next_hdr = (char*) ip + ip->ihl * 4; + goto layer4; + } - if (ip->protocol == IPPROTO_ICMP) { + case ETH_P_IPV6: { + struct ip6_hdr *ip6 = (struct ip6_hdr*) next_hdr; + char buf[32]; + + printf("\tIP version: %u class: %u flow: %u hlim: %u: next: %u src: %s dst %s\n", + ip6->ip6_vfc >> 4, + ip6->ip6_vfc & 0xf, + ip6->ip6_flow, + ip6->ip6_hlim, + ip6->ip6_nxt, + inet_ntop(AF_INET6, &ip6->ip6_src, buf, sizeof(buf)), + inet_ntop(AF_INET6, &ip6->ip6_dst, buf, sizeof(buf)) + ); + + protocol = ip6->ip6_nxt; + next_hdr = (char*) (ip6 + 1); + goto layer4; + } + + case ETH_P_ARP: + printf("\tARP\n"); + goto dump; + + default: + goto end; + } + +layer4: switch (protocol) { + case IPPROTO_ICMP: { /* Parse ICMP */ - struct icmphdr *icmp = (struct icmphdr*) ((char*) ip + ip->ihl * 4); - - printf("icmp_type: %u (%s) "); - printf("icmp_code: %u "); + struct icmphdr *icmp = (struct icmphdr*) next_hdr; + + printf("\tICMP type: %u (%s) code: %u\n", + icmp->type, + icmp_type_str[icmp->type], + icmp->code + ); + + goto dump; } - else if (ip->protocol == IPPROTO_UDP) { + + case IPPROTO_UDP: { /* Parse UDP */ - struct udphdr *udp = (struct udphdr*) ((char*) ip + ip->ihl * 4); - - printf("udp_port: %u "); + struct udphdr *udp = (struct udphdr*) next_hdr; + + printf("\tUDP src: %u dst: %u len: %u\n", + ntohs(udp->source), + ntohs(udp->dest), + ntohl(udp->len) + ); + goto layer5; } - else if (ip->protocol == IPPROTO_TCP) { + + case IPPROTO_TCP: { /* Parse TCP */ - struct tcphdr *tcp = (struct tcphdr*) ((char*) ip + ip->ihl * 4); - - printf("tcp_port: %u "); + struct tcphdr *tcp = (struct tcphdr*) next_hdr; + + printf("\tTCP src: %u dst: %u seq: %u win: %u ", + ntohs(tcp->source), + ntohs(tcp->dest), + ntohl(tcp->seq), + ntohs(tcp->window) + ); + + if (tcp->fin) printf("FIN "); + if (tcp->syn) printf("SYN "); + if (tcp->rst) printf("RST "); + if (tcp->ack) printf("ACK "); + + printf("\n"); + + if (tcp->fin || tcp->syn || tcp->rst) + goto end; + else + goto layer5; } + + default: + goto end; } +dump: +layer5: + hexdump(next_hdr, len - (next_hdr - data)); + +end: printf("\n"); + + return 0; } int main (int argc, char *argv[]) @@ -111,7 +212,10 @@ int main (int argc, char *argv[]) struct ifreq ifr; struct sockaddr_ll sll; - sd = socket(AF_INET, SOCK_RAW, htons(ETH_P_ALL)); + if (argc != 2) + error(-1, 0, "Usage %s INTERFACE", argv[0]); + + sd = socket(AF_PACKET, SOCK_RAW, htons(ETH_P_ALL)); if (sd < 0) error(-1, errno, "Failed to create socket"); @@ -120,7 +224,7 @@ int main (int argc, char *argv[]) error(-1, errno, "Failed to set socket option: SO_REUSEADDR"); /* Get interface flags */ - strncpy(ifr.ifr_name, INTERFACE, IFNAMSIZ); + strncpy(ifr.ifr_name, argv[1], IFNAMSIZ); if (ioctl(sd, SIOCGIFFLAGS, &ifr)) error(-1, errno, "Failed to get interface flags"); @@ -135,6 +239,7 @@ int main (int argc, char *argv[]) /* Bind socket to interface */ memset(&sll, 0, sizeof(sll)); + sll.sll_family = AF_PACKET; sll.sll_protocol = htons(ETH_P_ALL); sll.sll_ifindex = ifr.ifr_ifindex; @@ -143,15 +248,14 @@ int main (int argc, char *argv[]) printf("Successfully put interface %s (%u) into promiscuous mode!\n", ifr.ifr_name, ifr.ifr_ifindex); - printf("The socket is now bound/listening on interface %s", ifr.ifr_name); + printf("The socket is now bound/listening on interface %s\n", ifr.ifr_name); while (1) { ssize_t bytes = recv(sd, packet, sizeof(packet), 0); if (bytes == -1) error(-1, errno, "Failed to recv"); - printf("Received %u bytes\n", bytes); - parse_packet(packet, sizeof(packet)); + parse_packet(packet, bytes); } close(sd);