diff --git a/flow_db.c b/flow_db.c index 2a7a82b..b2b9971 100644 --- a/flow_db.c +++ b/flow_db.c @@ -96,6 +96,10 @@ static unsigned int hash_5tuple(struct af_6tuple af_6tuple) hash1 = hashf(&af_6tuple.ip1.v4, 4, hash1); hash1 = hashf(&af_6tuple.ip2.v4, 4, hash1); break; + case AF_INET6: + hash1 = hashf(&af_6tuple.ip1.v6, 16, hash1); + hash1 = hashf(&af_6tuple.ip2.v6, 16, hash1); + break; } if (af_6tuple.port1) hash1 = hashf(&af_6tuple.port1, 2, hash1); @@ -107,6 +111,10 @@ static unsigned int hash_5tuple(struct af_6tuple af_6tuple) hash2 = hashf(&af_6tuple.ip2.v4, 4, hash2); hash2 = hashf(&af_6tuple.ip1.v4, 4, hash2); break; + case AF_INET6: + hash2 = hashf(&af_6tuple.ip2.v6, 16, hash2); + hash2 = hashf(&af_6tuple.ip1.v6, 16, hash2); + break; } if (af_6tuple.port2) hash2 = hashf(&af_6tuple.port2, 2, hash2); @@ -137,6 +145,16 @@ static int compare_5tuple(struct af_6tuple af1, struct af_6tuple af2) af1.port1 == af2.port2 && af1.port2 == af2.port1) return 1; break; + case AF_INET6: + if (memcmp(&af1.ip1.v6, &af2.ip1.v6, sizeof(af1.ip1.v6)) == 0 && + memcmp(&af1.ip2.v6, &af2.ip2.v6, sizeof(af1.ip2.v6)) == 0 && + af1.port1 == af2.port1 && af1.port2 == af2.port2) + return 1; + if (memcmp(&af1.ip1.v6, &af2.ip2.v6, sizeof(af1.ip1.v6)) == 0 && + memcmp(&af1.ip2.v6, &af2.ip1.v6, sizeof(af1.ip2.v6)) == 0 && + af1.port1 == af2.port2 && af1.port2 == af2.port1) + return 1; + break; } return 0; diff --git a/pkt2flow.c b/pkt2flow.c index 12d5304..6b59451 100644 --- a/pkt2flow.c +++ b/pkt2flow.c @@ -33,7 +33,9 @@ #include #include #include +#include #include +#include #include #include #include @@ -241,6 +243,60 @@ static int pcap_handle_ipv4(struct af_6tuple *af_6tuple, const u_char *bytes, return pcap_handle_layer4(af_6tuple, bytes, len, iphdr->ip_p); } +static int pcap_handle_ipv6(struct af_6tuple *af_6tuple, const u_char *bytes, + size_t len) +{ + struct ip6_hdr *iphdr; + struct ip6_opt *opthdr; + int curheader = 255; + uint8_t nexthdr; + + while (1) { + switch (curheader) { + case 255: + if (len < sizeof(*iphdr)) + return -1; + iphdr = (struct ip6_hdr *)bytes; + bytes += sizeof(*iphdr); + len -= sizeof(*iphdr); + nexthdr = iphdr->ip6_ctlun.ip6_un1.ip6_un1_nxt; + + af_6tuple->af_family = AF_INET6; + af_6tuple->ip1.v6 = iphdr->ip6_src; + af_6tuple->ip2.v6 = iphdr->ip6_dst; + break; + case IPPROTO_HOPOPTS: + case IPPROTO_ROUTING: + case IPPROTO_DSTOPTS: + if (len < sizeof(*opthdr)) + return -1; + nexthdr = bytes[0]; + + opthdr = (struct ip6_opt *)bytes; + if (len < ((1u + opthdr->ip6o_len) * 8u)) + return -1; + bytes += (1u + opthdr->ip6o_len) * 8u; + len -= (1u + opthdr->ip6o_len) * 8u; + break; + case IPPROTO_FRAGMENT: + if (len < 1) + return -1; + nexthdr = bytes[0]; + if (len < 8) + return -1; + bytes += 8; + len -= 8; + break; + case IPPROTO_NONE: + return -1; + default: + return pcap_handle_layer4(af_6tuple, bytes, len, + nexthdr); + }; + curheader = nexthdr; + } +} + static int pcap_handle_ip(struct af_6tuple *af_6tuple, const u_char *bytes, size_t len) { @@ -251,6 +307,9 @@ static int pcap_handle_ip(struct af_6tuple *af_6tuple, const u_char *bytes, if ((bytes[0] >> 4) == 4) return pcap_handle_ipv4(af_6tuple, bytes, len); + if ((bytes[0] >> 4) == 6) + return pcap_handle_ipv6(af_6tuple, bytes, len); + return -1; } @@ -269,7 +328,8 @@ static int pcap_handle_ethernet(struct af_6tuple *af_6tuple, len -= sizeof(*ethhdr); bytes += sizeof(*ethhdr); - if (ntohs(ethhdr->ether_type) != ETHERTYPE_IP) + if (ntohs(ethhdr->ether_type) != ETHERTYPE_IP && + ntohs(ethhdr->ether_type) != ETHERTYPE_IPV6) return -1; return pcap_handle_ip(af_6tuple, bytes, len); diff --git a/pkt2flow.h b/pkt2flow.h index ef9bd05..5663e9b 100644 --- a/pkt2flow.h +++ b/pkt2flow.h @@ -33,6 +33,7 @@ #include #include +#include #define __SOURCE_VERSION__ "1.2" #define __AUTHOR__ "X. Chen (chenxm35@gmail.com)" @@ -68,6 +69,7 @@ struct pkt_dump_file { union ip_address { struct in_addr v4; + struct in6_addr v6; }; struct af_6tuple { diff --git a/utilities.c b/utilities.c index fe89dac..1911297 100644 --- a/utilities.c +++ b/utilities.c @@ -41,8 +41,8 @@ char *new_file_name(struct af_6tuple af_6tuple, unsigned long timestamp) { char *fname; - char src_ip_str[INET_ADDRSTRLEN]; - char dst_ip_str[INET_ADDRSTRLEN]; + char src_ip_str[INET6_ADDRSTRLEN]; + char dst_ip_str[INET6_ADDRSTRLEN]; int ret; switch (af_6tuple.af_family) { @@ -50,6 +50,10 @@ char *new_file_name(struct af_6tuple af_6tuple, unsigned long timestamp) inet_ntop(AF_INET, &af_6tuple.ip1.v4, src_ip_str, INET_ADDRSTRLEN); inet_ntop(AF_INET, &af_6tuple.ip2.v4, dst_ip_str, INET_ADDRSTRLEN); break; + case AF_INET6: + inet_ntop(AF_INET6, &af_6tuple.ip1.v6, src_ip_str, INET6_ADDRSTRLEN); + inet_ntop(AF_INET6, &af_6tuple.ip2.v6, dst_ip_str, INET6_ADDRSTRLEN); + break; } ret = asprintf(&fname, "%s_%"PRIu16"_%s_%"PRIu16"_%lu.pcap",