$OpenBSD: patch-tcpdpriv_c,v 1.2 2010/05/23 16:57:29 espie Exp $ --- tcpdpriv.c.orig Thu Aug 28 02:07:55 1997 +++ tcpdpriv.c Sun May 23 18:56:10 2010 @@ -93,7 +93,7 @@ static char rcsid[] = #if !defined(osf1) #include #endif /* !defined(osf1) */ -#include +#include #include #endif /* !defined(sun) */ @@ -108,6 +108,10 @@ static char rcsid[] = #include #include +#include +#include +#include +#include /* * deal with systems in which bpf_int32 and bpf_u_int32 are not defined @@ -205,10 +209,15 @@ typedef u_int bpf_u_int32; #endif /* (BYTE_ORDER == LITTLE_ENDIAN) */ #endif /* !defined(NTOHL) */ + +/* a macro to handle v6 address in 32-bit fields */ +#define IN6ADDR32(a, i) (*(u_int32_t *)(&(a)->s6_addr[(i)<<2])) + /* * function prototypes */ +static void usage(char *); /* macros for ansi/non-ansi compatibility */ #ifndef __P #if defined(_USE_PROTOTYPES) && (defined(__STDC__) || defined(__cplusplus)) @@ -244,6 +253,10 @@ int statfs __P((const char *, struct statfs *)); #if defined(sun) /* why not defined in Solaris? */ int gettimeofday __P((struct timeval *, struct timezone *)); #endif /* defined(sun) */ + +static u_char *dumpip(u_char *p, int caplen, int length); +static u_char *dumpip6(u_char *p, int caplen, int length); + /* * typedefs... @@ -274,6 +287,32 @@ struct nodehdr { #define NH_FL_RANDOM_PROPAGATE 1 /* propagate random number down */ #define NH_FL_COUNTER 2 /* bump a counter */ + +/* 128 bit version for IPv6 addresses */ +typedef struct node6 node6_t, *node6_p; /* type of a tree node */ + +struct node6 { + struct in6_addr + input, /* input value */ + output; /* output value */ + node6_p + down[2]; /* children */ +}; + +typedef struct node6hdr node6hdr_t, *node6hdr_p; /* type of a tree */ + +struct node6hdr { + u_long + flags, /* see below */ + addr_mask, /* for ipv6, mask is used to preserve high oder bits */ + counter, /* for NH_FL_COUNTER */ + bump; /* amount by which to bump counter */ + struct in6_addr + cur_input; /* what address is currently being masked */ + node6_p + head; +}; + /* * globally scoped variables @@ -299,6 +338,12 @@ nodehdr_t addr_byte_2 = { NH_FL_COUNTER, 0x0000ff00, 0 }, addr_byte_3 = { NH_FL_COUNTER, 0x000000ff, 0 }; +/* trees for IPv6 addresses */ +/* currently, we preserve first 16 bits of original addresses */ +node6hdr_t + addr6_propagate = { NH_FL_RANDOM_PROPAGATE, 0xffff0000, 0 }, + addr6_whole = { NH_FL_COUNTER, 0xffff0000, 0 }; + /* trees for tcp ports */ nodehdr_t tcpport_whole, @@ -575,6 +620,77 @@ bi_ffs(u_long value) return add+bvals[value&0xf]; } +int +is_normal_ipaddr(u_long addr) +{ + if (addr == INADDR_ANY || addr == INADDR_BROADCAST) + return (0); + + /* + * check private address range + * 10.0.0.0 - 10.255.255.255 + * 172.16.0.0 - 172.31.255.255 + * 192.168.0.0 - 192.168.255.255 + */ + if ((addr & 0xff000000) == 0x0a000000 || + (addr & 0xfff00000) == 0xac100000 || + (addr & 0xffff0000) == 0xc0a80000) + return (0); + + /* check localloop */ + if ((addr & 0xff000000) == 0x7f000000) + return (0); + + /* check multicast */ + if (opt_mcastaddr >= 99 && IN_MULTICAST(addr)) + return (0); + + return (1); +} + +int +bi_ffs6(struct in6_addr *addr) +{ + int value, i; + + for (i = 0; i < 4; i++) { + value = bi_ffs(ntohl(IN6ADDR32(addr, i))); + if (value != 0) + return (i*32 + value); + } + return (0); +} + +int +extract_bit6(struct in6_addr *addr, int bitno) +{ + int value, bit, i; + + for (i = 0, bit = bitno; i < 4; i++, bit -= 32) + if (bit <= 32) { + value = ntohl(IN6ADDR32(addr, i)); + return ((value >> (32 - bit)) & 1); + } + return (0); +} + +int +is_normal_ip6addr(struct in6_addr *addr) +{ + if (IN6_IS_ADDR_UNSPECIFIED(addr)) + return (0); + + /* check localloop */ + if (IN6_IS_ADDR_LOOPBACK(addr)) + return (0); + + /* check multicast */ + if (opt_mcastaddr >= 99 && IN6_IS_ADDR_MULTICAST(addr)) + return (0); + + return (1); +} + /* * Subtract a quantity from a standard IP checksum (network order) * @@ -711,6 +827,36 @@ freetree(node_p node) node = next; } } + +static node6_p +newnode6(void) +{ + node6_p node; + + node = (node6_p) malloc(sizeof *node); + + if (node == 0) { + fprintf(stderr, "malloc failed %s:%d\n", __FILE__, __LINE__); + exit(2); + } + return node; +} + +static void +freetree6(node6_p node) +{ + node6_p next; + + while (node) { + next = node->down[0]; + if (node->down[1]){ + freetree6(node->down[1]); + } + free(node); + node = next; + } +} + /* * M A S K I N G @@ -740,11 +886,17 @@ make_output(u_long value, int flip, nodehdr_p hdr) * bit flip: flip bit (XOR with 1) in value * bits (flip+1)-32: random */ - if (flip == 32) { - return value^1; - } else { /* get left AND flipped bit */ - return ((((value>>(32-flip))^1)<<(32-flip)) | - ((rand32()&0x7fffffff)>>flip)); /* and get right part */ + int retry = 0; + while (1) { + if (flip == 32) { + return value^1; + } else { /* get left AND flipped bit */ + value = ((((value>>(32-flip))^1)<<(32-flip)) | + ((rand32()&0x7fffffff)>>flip)); + if (retry > 10 || is_normal_ipaddr(value)) + return (value); + } + retry++; } } else if (hdr->flags&NH_FL_COUNTER) { hdr->counter += hdr->bump; @@ -809,6 +961,127 @@ make_peer(u_long input, node_p old, nodehdr_p hdr) return down[bitvalue]; } + +/* + * 128 bit version of make_output() + * note: ipv6 addresses are in network byte order. + */ +static void +make_output6(struct in6_addr *old, int flip, node6hdr_p hdr, + struct in6_addr *new) +{ + u_int32_t value; + int i, swivel; + + if (hdr->flags&NH_FL_RANDOM_PROPAGATE) { + int retry = 0; + /* + * the output is: + * bits 1-(flip-1): copied from value + * bit flip: flip bit (XOR with 1) in value + * bits (flip+1)-128: random + */ + while (1) { + for (i = 0, swivel = flip; i < 4; i++, swivel -= 32) { + if (swivel > 32) { + /* + * flip bit is below this 32 bits. + * just copy the original value. + */ + IN6ADDR32(new, i) = IN6ADDR32(old, i); + } else if (swivel < 0) { + /* + * flip bit is above this 32 bits. + * scramble the entire 32 bits. + */ + IN6ADDR32(new, i) = rand32(); + } else { + /* flip bit is in this 32 bits */ + value = ntohl(IN6ADDR32(old, i)); + if (swivel == 32) { + value = value ^ 1; + } else { /* get left AND flipped bit */ + value = (((value >> (32-swivel)) ^ 1) << (32-swivel)) | + ((rand32() & 0x7fffffff) >> swivel); + } + IN6ADDR32(new, i) = htonl(value); + } + } + if (retry > 10 || is_normal_ip6addr(new)) + return; + retry++; + } + } else if (hdr->flags&NH_FL_COUNTER) { + /* we support only Level 0 (interger) mapping */ + hdr->counter += hdr->bump; + IN6ADDR32(new, 0) = IN6ADDR32(new, 1) = IN6ADDR32(new, 2) = 0; + IN6ADDR32(new, 3) = htonl(hdr->counter); + } else { + fprintf(stderr, "unknown flags field %s:%d\n", __FILE__, __LINE__); + exit(2); + } +} + +static node6_p +make_peer6(struct in6_addr *input, node6_p old, node6hdr_p hdr) +{ + node6_p down[2]; + int swivel, bitvalue, i; + struct in6_addr tmp; + + /* + * become a peer + * algo: create two nodes, the two peers. leave orig node as + * the parent of the two new ones. + */ + + down[0] = newnode6(); + down[1] = newnode6(); + + for (i = 0; i < 4; i++) + IN6ADDR32(&tmp, i) = IN6ADDR32(input, i) ^ IN6ADDR32(&old->input, i); + swivel = bi_ffs6(&tmp); + bitvalue = extract_bit6(input, swivel); + + down[bitvalue]->input = *input; + down[bitvalue]->down[0] = down[bitvalue]->down[1] = 0; + make_output6(&old->output, swivel, hdr, &down[bitvalue]->output); + + /* + * heuristics for ipv6 address readability: + * 1. copy the high order bits from the original + * (16 bits are specified at the initialization of the tree head) + * 2. when address is randamized, preserve 0x00 and 0xff octet + * in the original address + */ + if (hdr->addr_mask) { + IN6ADDR32(&down[bitvalue]->output, 0) = + (IN6ADDR32(input, 0) & htonl(hdr->addr_mask)) | + (IN6ADDR32(&down[bitvalue]->output, 0) & ~htonl(hdr->addr_mask)); + } + if (hdr->flags & NH_FL_RANDOM_PROPAGATE) { + int i, bit; + + for (i = 0, bit = swivel; i < 16; i++, bit -= 8) + if (bit < 0) { + /* this octet is below the flip bit and randamized */ + if (input->s6_addr[i] == 0x00) + down[bitvalue]->output.s6_addr[i] = 0x00; + else if (input->s6_addr[i] == 0xff) + down[bitvalue]->output.s6_addr[i] = 0xff; + } + } + + *down[1-bitvalue] = *old; /* copy orig node down one level */ + + old->input = down[1]->input; /* NB: 1s to the right (0s to the left) */ + old->output = down[1]->output; + old->down[0] = down[0]; /* point to children */ + old->down[1] = down[1]; + + return down[bitvalue]; +} + /* * L O O K U P @@ -945,6 +1218,86 @@ dumptable(node_p node, int level) } } #endif /* DEBUG */ + +static void +lookup_init6(node6hdr_p hdr) +{ + node6_p node; + + if (hdr->head) { + freetree6(hdr->head); + hdr->head = 0; + } + + hdr->head = newnode6(); + node = hdr->head; + memset(&node->input, 0, sizeof(struct in6_addr)); + + hdr->bump = 1; /* level 0 counter only */ + if (hdr->flags == NH_FL_COUNTER) { + IN6ADDR32(&node->output, 0) = 0; + IN6ADDR32(&node->output, 1) = 0; + IN6ADDR32(&node->output, 2) = 0; + IN6ADDR32(&node->output, 3) = hdr->bump; + } else { + IN6ADDR32(&node->output, 0) = rand32(); + IN6ADDR32(&node->output, 1) = rand32(); + IN6ADDR32(&node->output, 2) = rand32(); + IN6ADDR32(&node->output, 3) = rand32(); + } + if (opt_class) { + IN6ADDR32(&node->input, 0) = htonl(hdr->addr_mask); + IN6ADDR32(&node->output, 0) |= htonl(hdr->addr_mask); + } else { + hdr->addr_mask = 0; + } + node->down[0] = node->down[1] = 0; +} + +void +lookup6(struct in6_addr *input, node6hdr_p hdr, struct in6_addr *output) +{ + node6_p node; + int swivel, i; + struct in6_addr tmp; + + node = hdr->head; /* non-zero, 'cause lookup_init() already called */ + if (hdr->head == 0) { /* (but...) */ + fprintf(stderr, "unexpected zero head %s:%d\n", __FILE__, __LINE__); + } + + while (node) { + if (IN6_ARE_ADDR_EQUAL(input, &node->input)) { + /* we found our node! */ + *output = node->output; + return; + } + if (node->down[0] == 0) { /* need to descend, but can't */ + node = make_peer6(input, node, hdr); /* create a peer */ + } else { + /* swivel is the first bit the left and right children differ in */ + for (i = 0; i < 4; i++) + IN6ADDR32(&tmp, i) = IN6ADDR32(&node->down[0]->input, i) + ^ IN6ADDR32(&node->down[1]->input, i); + swivel = bi_ffs6(&tmp); + for (i = 0; i < 4; i++) + IN6ADDR32(&tmp, i) = IN6ADDR32(input, i) + ^ IN6ADDR32(&node->input, i); + if (bi_ffs6(&tmp) < swivel) {/* input differs earlier */ + node = make_peer6(input, node, hdr); /* make a peer */ + } else if (extract_bit6(input, swivel)) { + node = node->down[1]; /* NB: 1s to the right */ + } else { + node = node->down[0]; /* NB: 0s to the left */ + } + } + } + + /* ??? should not occur! */ + fprintf(stderr, "unexpected loop termination %s:%d\n", __FILE__, __LINE__); + exit(1); +} + /* * H I D I N G @@ -960,6 +1313,9 @@ hide_addr(u_long addr, u_int ttl) return addr; } + if (!is_normal_ipaddr(addr)) + return (addr); + switch (opt_ipaddr) { case 0: addr_whole.cur_input = addr; @@ -1028,6 +1384,62 @@ hide_udpport(u_short udpport) return hide_port(udpport, &udpport_whole, &udpport_byte_0, &udpport_byte_1, opt_udpports); } + +void +hide_addr6(struct in6_addr *inaddr, struct in6_addr *outaddr, u_int hlimit) +{ + + if (!is_normal_ip6addr(inaddr)) { + /* no conversion */ + *outaddr = *inaddr; + + /* + * special case for solicited-node multicast address that is + * formed by taking the low-order 24 bits of the address + * (unicast or anycast) and appending those bits to the prefix + * FF02:0:0:0:0:1:FF00::/104 + * + * we just clear the low-order 24 bits for now. + */ + if (opt_mcastaddr >= 99 && IN6_IS_ADDR_MULTICAST(outaddr) && + outaddr->s6_addr[1] == 0x02 && + outaddr->s6_addr[2] == 0 && outaddr->s6_addr[3] == 0 && + outaddr->s6_addr[4] == 0 && outaddr->s6_addr[5] == 0 && + outaddr->s6_addr[6] == 0 && outaddr->s6_addr[7] == 0 && + outaddr->s6_addr[8] == 0 && outaddr->s6_addr[9] == 0 && + outaddr->s6_addr[10] == 0 && outaddr->s6_addr[11] == 0x01 && + outaddr->s6_addr[12] == 0xff) { + outaddr->s6_addr[13] = outaddr->s6_addr[14] = + outaddr->s6_addr[15] = 0; + } + + return; + } + + switch (opt_ipaddr) { + case 0: + addr6_whole.cur_input = *inaddr; + lookup6(inaddr, &addr6_whole, outaddr); + break; + case 1: + case 2: + fprintf(stderr, "we don't support -A1 and -A2 for IPv6\n"); + exit(1); + case 50: + addr6_propagate.cur_input = *inaddr; + lookup6(inaddr, &addr6_propagate, outaddr); + break; + case 99: + *outaddr = *inaddr; + break; + default: + fprintf(stderr, "unknown opt_ipaddr %s:%d\n", __FILE__, __LINE__); + exit(1); + } + + return; +} + /* * T C P @@ -1163,6 +1575,7 @@ dumpudp(u_char *p, int caplen, int length, u_long phof { u_short inport, outport; struct udphdr *udp = (struct udphdr *)p; + u_short sport = 0, dport = 0; /* source port */ if (caplen < 2) { @@ -1174,7 +1587,10 @@ dumpudp(u_char *p, int caplen, int length, u_long phof phoffset = cksum_subtract(phoffset, udp->uh_sport); udp->uh_sport = htons(outport); phoffset = cksum_add(phoffset, udp->uh_sport); + } else { + sport = inport; } + caplen -= 2; length -= 2; p += 2; /* destination port */ @@ -1187,7 +1603,10 @@ dumpudp(u_char *p, int caplen, int length, u_long phof phoffset = cksum_subtract(phoffset, udp->uh_dport); udp->uh_dport = htons(outport); phoffset = cksum_add(phoffset, udp->uh_dport); + } else { + dport = inport; } + caplen -= 2; length -= 2; p += 2; /* length */ @@ -1207,11 +1626,187 @@ dumpudp(u_char *p, int caplen, int length, u_long phof } caplen -= 2; length -= 2; p += 2; + if (caplen < 2) + return p+caplen; + /* don't return any UDP data */ return p; } /* + * I C M P + */ + + +/* + * dump an icmp packet. + * + * Input: + * p location of first byte of ICMP header + * caplen bytes (from p) captured + * length bytes (from p) in current datagram (may not be captured) + * phoffset how much pseudo header checksum changed during + * IP munging + * + * Output: + * pointer to byte *past* last byte munged + */ + +static u_char * +dumpicmp(u_char *p, int caplen, int length, u_long phoffset) +{ + struct icmp *dp = (struct icmp *)p; + int len = 4; + + if (caplen < 4) { + return p+caplen; + } + + switch (dp->icmp_type) { + case ICMP_REDIRECT: + case ICMP_UNREACH: + case ICMP_TIMXCEED: + if (dp->icmp_type == ICMP_REDIRECT && caplen >= 8) { + /* hide gateway address */ + u_long inaddr, outaddr; + u_short offset = 0; + + inaddr = ntohl(dp->icmp_gwaddr.s_addr); + outaddr = hide_addr(dp->icmp_gwaddr.s_addr, 255); + if (inaddr != outaddr) { + offset = cksum_subtract(offset, dp->icmp_gwaddr.s_addr); + dp->icmp_gwaddr.s_addr = htonl(outaddr); + offset = cksum_add(offset, dp->icmp_gwaddr.s_addr); + if (offset) + dp->icmp_cksum = cksum_adjust(dp->icmp_cksum, offset); + } + } + if (caplen <= 8) { + len = caplen; + break; + } + /* + * recursively call dumpip + * todo: we have to update icmp checksum. + */ + if (caplen >= 8 + sizeof(struct ip)) { + u_char *np; + np = dumpip(p + 8, caplen - 8, length - 8); + len = np - p; + } + break; + case ICMP_ECHO: + case ICMP_ECHOREPLY: + len = 8; + break; + case ICMP_MASKREPLY: + len = 12; + break; + case ICMP_TSTAMP: + case ICMP_TSTAMPREPLY: + len = 20; + default: + len = 4; + } + + len = MIN(caplen, len); + caplen -= len; length -= len; p += len; + + /* don't return any ICMP data */ + return p; +} + +static u_char * +dumpicmp6(u_char *p, int caplen, int length, u_long phoffset) +{ + struct icmp6_hdr *dp = (struct icmp6_hdr *)p; + int i, len = 4; + struct in6_addr inaddr, outaddr, *addrp; + + if (caplen < 4) { + return p+caplen; + } + + switch (dp->icmp6_type) { + case ICMP6_DST_UNREACH: + case ICMP6_PACKET_TOO_BIG: + case ICMP6_TIME_EXCEEDED: + case ICMP6_PARAM_PROB: + if (caplen <= 8) { + len = caplen; + break; + } + /* + * recursively call dumpip6 + * todo: we have to update icmp6 checksum. + */ + if (caplen >= 8 + sizeof(struct ip6_hdr)) { + u_char *np; + np = dumpip6(p + 8, caplen - 8, length - 8); + len = np - p; + } + break; + case ICMP6_ECHO_REQUEST: + case ICMP6_ECHO_REPLY: + len = 8; + break; + case ICMP6_MEMBERSHIP_QUERY: + case ICMP6_MEMBERSHIP_REPORT: + case ICMP6_MEMBERSHIP_REDUCTION: + len = 24; + break; + case ND_ROUTER_SOLICIT: + case ND_ROUTER_ADVERT: + len = 8; + break; + case ND_NEIGHBOR_SOLICIT: + case ND_NEIGHBOR_ADVERT: + case ND_REDIRECT: + /* + * neighbor sol and adv has 1 ipv6 address below the icmp6 header. + * redirect has 2 addresses. + */ + len = 8; + addrp = (struct in6_addr *)(dp + 1); + again: + if (addrp + 1 > (struct in6_addr *)(p + caplen)) + break; + inaddr = *addrp; + hide_addr6(&inaddr, &outaddr, 255); + if (!IN6_ARE_ADDR_EQUAL(&inaddr, &outaddr)) { + /* need to redo checksum */ + for (i = 0; i < 4; i++) + phoffset = cksum_subtract(phoffset, IN6ADDR32(&inaddr, i)); + *addrp = outaddr; + for (i = 0; i < 4; i++) + phoffset = cksum_add(phoffset, IN6ADDR32(&outaddr, i)); + } + len += sizeof(*addrp); + if (dp->icmp6_type == ND_REDIRECT && len == 8 + sizeof(*addrp)) { + addrp++; + goto again; + } + break; + default: + len = 4; + } + + /* + * icm6 checksum includes ipv6 pseudo header (it's a different policy + * from icmp4). + */ + if (phoffset) + dp->icmp6_cksum = cksum_adjust(dp->icmp6_cksum, phoffset); + + len = MIN(caplen, len); + caplen -= len; length -= len; p += len; + + /* don't return any ICMP6 data */ + return p; +} + + +/* * I P */ @@ -1320,8 +1915,16 @@ dumpip(u_char *p, int caplen, int length) #define IPPROTO_IPIP 4 #endif /* ndef IPPROTO_IPIP */ case IPPROTO_IPIP: - p = dumpip(p, caplen, length); + if (caplen >= sizeof(struct ip)) + p = dumpip(p, caplen, length); break; + case IPPROTO_ICMP: + p = dumpicmp(p, caplen, length, phoffset); + break; + case IPPROTO_IPV6: + if (caplen >= sizeof(struct ip6_hdr)) + p = dumpip6(p, caplen, length); + break; default: break; } @@ -1329,6 +1932,109 @@ dumpip(u_char *p, int caplen, int length) return p; } + +/* + * this is an IPv6 packet --- output it securely. + * + * Input: + * p location of first byte of IPv6 header + * caplen bytes (from p) captured + * length bytes (from p) in current datagram (may not be captured) + * + * Output: + * pointer to byte *past* last byte munged (so, first byte of + * IPv6 payload not munged by dumpip6() or any of its "children") + */ +static u_char * +dumpip6(u_char *p, int caplen, int length) +{ + struct ip6_hdr *ip6; + struct in6_addr inaddr, outaddr; + u_short phoffset = 0; + u_int8_t nxt; + int i, len; + /* structure for ipsec and ipv6 option header template */ + struct _opt6 { + u_int8_t opt6_nxt; /* next header */ + u_int8_t opt6_hlen; /* header extension length */ + u_int16_t _pad; + u_int32_t ah_spi; /* security parameter index + for authentication header */ + } *opt6; + + if (caplen < sizeof (struct ip6_hdr)) { + tooshort++; + return p; + } + + ip6 = (struct ip6_hdr *)p; + + inaddr = ip6->ip6_src; + hide_addr6(&inaddr, &outaddr, ip6->ip6_hlim); + if (!IN6_ARE_ADDR_EQUAL(&inaddr, &outaddr)) { + /* need to redo checksum for TCP and UDP */ + for (i = 0; i < 4; i++) + phoffset = cksum_subtract(phoffset, IN6ADDR32(&ip6->ip6_src, i)); + ip6->ip6_src = outaddr; + for (i = 0; i < 4; i++) + phoffset = cksum_add(phoffset, IN6ADDR32(&ip6->ip6_src, i)); + } + + inaddr = ip6->ip6_dst; + hide_addr6(&inaddr, &outaddr, ip6->ip6_hlim); + if (!IN6_ARE_ADDR_EQUAL(&inaddr, &outaddr)) { + /* need to redo checksum for TCP and UDP */ + for (i = 0; i < 4; i++) + phoffset = cksum_subtract(phoffset, IN6ADDR32(&ip6->ip6_dst, i)); + ip6->ip6_dst = outaddr; + for (i = 0; i < 4; i++) + phoffset = cksum_add(phoffset, IN6ADDR32(&ip6->ip6_dst, i)); + } + + caplen -= sizeof *ip6; + length -= sizeof *ip6; + p += sizeof *ip6; + + nxt = ip6->ip6_nxt; + while (caplen > 0) { + switch (ip6->ip6_nxt) { + case IPPROTO_TCP: + p = dumptcp(p, caplen, length, phoffset); + return (p); + case IPPROTO_UDP: + p = dumpudp(p, caplen, length, phoffset); + return (p); + case IPPROTO_ICMPV6: + p = dumpicmp6(p, caplen, length, phoffset); + return (p); + case IPPROTO_IPV4: /* ipv4 over ipv6 */ + if (caplen >= sizeof(struct ip)) + p = dumpip(p, caplen, length); + return (p); + case IPPROTO_HOPOPTS: + case IPPROTO_ROUTING: + case IPPROTO_DSTOPTS: + /* get next header and header length */ + opt6 = (struct _opt6 *)p; + nxt = opt6->opt6_nxt; + len = (opt6->opt6_hlen + 1) * 8; + /* clear the option contents */ + memset(opt6 + 1, 0, len - sizeof(*opt6)); + + /* goto the next header */ + caplen -= len; + length -= len; + p += len; + break; + default: + /* unknown option header. stop dumping */ + return (p); + } + } + + return p; +} + /* * D U M P E R @@ -1390,6 +2096,8 @@ dumper(u_char *user, const struct pcap_pkthdr *inh, co ether_type = ntohs(ep->ether_type); if (ether_type == 0x800) { /* oh, good! */ p = dumpip(p, caplen, length); + } else if (ether_type == ETHERTYPE_IPV6) { + p = dumpip6(p, caplen, length); } else { uncoded++; return; @@ -1431,6 +2139,11 @@ dumper(u_char *user, const struct pcap_pkthdr *inh, co length -= (sizeof SNAPHDR+2); p += (sizeof SNAPHDR+2); p = dumpip(p, caplen, length); + } else if (ether_type == ETHERTYPE_IPV6) { + caplen -= (sizeof SNAPHDR+2); + length -= (sizeof SNAPHDR+2); + p += (sizeof SNAPHDR+2); + p = dumpip6(p, caplen, length); } else { uncoded++; return; @@ -1454,6 +2167,39 @@ dumper(u_char *user, const struct pcap_pkthdr *inh, co caplen -= NULL_HDRLEN; p = dumpip(p, caplen, length); break; + case DLT_PFLOG: + if (caplen < PFLOG_HDRLEN) { + tooshort++; + return; + } + length -= PFLOG_HDRLEN; + p += PFLOG_HDRLEN; + caplen -= PFLOG_HDRLEN; + p = dumpip(p, caplen, length); + break; + case DLT_ATM_RFC1483: + if (caplen < 8) { + tooshort++; + return; + } + if (p[0] != 0xaa || p[1] != 0xaa || p[2] != 0x03) { + /* unknown format! */ + uncoded++; + return; + } + ether_type = p[6] << 8 | p[7]; + length -= 8; + caplen -= 8; + p += 8; + if (ether_type == ETHERTYPE_IP) { + p = dumpip(p, caplen, length); + } else if (ether_type == ETHERTYPE_IPV6) { + p = dumpip6(p, caplen, length); + } else { + uncoded++; + return; + } + break; default: fprintf(stderr, "unknown DLT %d\n", pcap_dlt); exit(1); @@ -1492,6 +2238,10 @@ dlt_hdrlen(int dlt) #endif /* defined(FDDI_HDRLEN) */ case DLT_NULL: return NULL_HDRLEN; + case DLT_PFLOG: + return PFLOG_HDRLEN; + case DLT_ATM_RFC1483: + return 8; default: fprintf(stderr, "unknown DLT %d\n", dlt); exit(1); @@ -1501,8 +2251,6 @@ dlt_hdrlen(int dlt) static void verify_and_print_args(char *cmd) { - static void usage(char *cmd); - lookup_init(&addr_propagate); lookup_init(&addr_whole); @@ -1515,6 +2263,10 @@ verify_and_print_args(char *cmd) lookup_init(&addr_byte_2); lookup_init(&addr_byte_3); + lookup_init6(&addr6_propagate); + + lookup_init6(&addr6_whole); + tcpport_whole.flags = NH_FL_COUNTER; lookup_init(&tcpport_whole);