961 lines
25 KiB
Plaintext
961 lines
25 KiB
Plaintext
$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 <net/slip.h>
|
||
#endif /* !defined(osf1) */
|
||
-#include <netinet/if_fddi.h>
|
||
+#include <net/if_fddi.h>
|
||
#include <net/if_llc.h>
|
||
#endif /* !defined(sun) */
|
||
|
||
@@ -108,6 +108,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 +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);
|
||
|