openbsd-ports/net/tcpdpriv/patches/patch-tcpdpriv_c
naddy 7d6157a211 * Cope with FDDI removal.
* Just use arc4random() instead of incredible contortions to gather
some randomness from the system.
2013-10-31 17:47:14 +00:00

987 lines
25 KiB
Plaintext
Raw Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

$OpenBSD: patch-tcpdpriv_c,v 1.3 2013/10/31 17:47:14 naddy Exp $
--- tcpdpriv.c.orig Thu Aug 28 02:07:55 1997
+++ tcpdpriv.c Thu Oct 31 18:37:26 2013
@@ -93,7 +93,6 @@ static char rcsid[] =
#if !defined(osf1)
#include <net/slip.h>
#endif /* !defined(osf1) */
-#include <netinet/if_fddi.h>
#include <net/if_llc.h>
#endif /* !defined(sun) */
@@ -108,6 +107,10 @@ static char rcsid[] =
#include <signal.h>
#include <pcap.h>
+#include <net/if_pflog.h>
+#include <netinet/ip_icmp.h>
+#include <netinet/ip6.h>
+#include <netinet/icmp6.h>
/*
* deal with systems in which bpf_int32 and bpf_u_int32 are not defined
@@ -205,10 +208,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 +252,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 +286,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 +337,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,
@@ -402,7 +446,9 @@ pcap_t *pc; /* our input file */
static long
rand32()
{
-#if defined(SVR4)
+#if defined(ARC4RANDOM)
+ return arc4random();
+#elif defined(SVR4)
return ((lrand48()&0xffff)<<15)|(lrand48()&0xfff);
#else /* defined(SVR4) */
return ((random()&0xffff)<<16)|(random()&0xffff);
@@ -436,6 +482,7 @@ rand_accum(unsigned prev, unsigned *px, int ints)
static void
rand_start(void)
{
+#if !defined(ARC4RANDOM)
struct {
struct timeval tv;
struct timezone tz;
@@ -538,6 +585,7 @@ rand_start(void)
#else /* defined(SVR4) */
srandom(sum);
#endif /* defined(SVR4) */
+#endif /* defined(ARC4RANDOM */
}
/*
@@ -575,6 +623,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 +830,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 +889,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 +964,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 +1221,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 +1316,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 +1387,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 +1578,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 +1590,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 +1606,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 +1629,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 +1918,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 +1935,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 +2099,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 +2142,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 +2170,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 +2241,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 +2254,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 +2266,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);