From: Guy Harris Date: Wed, 29 Feb 2012 09:51:27 +0000 (-0800) Subject: Add DLT_PFSYNC support. X-Git-Tag: tcpdump-4.3.0~28 X-Git-Url: https://git.tcpdump.org/tcpdump/commitdiff_plain/0d2d222ffb8fdca529963a11624f4390d1c15297 Add DLT_PFSYNC support. From FreeBSD PR bin/124825: tcpdump(8) does not support pfsync(4) data, which in turn was ported over from OpenBSD. We already have CARP support, so we did not port that part over. --- diff --git a/Makefile.in b/Makefile.in index aefd3a47..d75140a6 100644 --- a/Makefile.in +++ b/Makefile.in @@ -245,6 +245,7 @@ EXTRA_DIST = \ mkdep \ packetdat.awk \ pcap_dump_ftell.c \ + pf_print_state.c \ print-babel.c \ print-dhcp6.c \ print-frag6.c \ @@ -255,6 +256,7 @@ EXTRA_DIST = \ print-netbios.c \ print-ospf6.c \ print-pflog.c \ + print-pfsync.c \ print-ripng.c \ print-rt6.c \ print-smb.c \ diff --git a/addrtoname.c b/addrtoname.c index d77f27b0..eb7b4501 100644 --- a/addrtoname.c +++ b/addrtoname.c @@ -156,6 +156,7 @@ struct enamemem { static struct enamemem enametable[HASHNAMESIZE]; static struct enamemem nsaptable[HASHNAMESIZE]; static struct enamemem bytestringtable[HASHNAMESIZE]; +static const char *ipprototable[256]; struct protoidmem { u_int32_t p_oui; @@ -717,6 +718,12 @@ ipxsap_string(u_short port) return (tp->name); } +const char * +ipproto_string(u_int proto) +{ + return ipprototable[proto & 0xff]; +} + static void init_servarray(void) { @@ -748,6 +755,25 @@ init_servarray(void) endservent(); } +static void +init_ipprotoarray(void) +{ + int i; + char buf[sizeof("000")]; + struct protoent *pr; + + if (!nflag) { + while ((pr = getprotoent()) != NULL) + ipprototable[pr->p_proto & 0xff] = strdup(pr->p_name); + endprotoent(); + } + for (i = 0; i < 256; i++) + if (ipprototable[i] == NULL) { + (void)snprintf(buf, sizeof(buf), "%d", i); + ipprototable[i] = strdup(buf); + } +} + /* in libpcap.a (nametoaddr.c) */ #if defined(WIN32) && !defined(USE_STATIC_LIBPCAP) __declspec(dllimport) @@ -1137,6 +1163,7 @@ init_addrtoname(u_int32_t localnet, u_int32_t mask) f_localnet = localnet; f_netmask = mask; } + init_ipprotoarray(); if (nflag) /* * Simplest way to suppress names. diff --git a/addrtoname.h b/addrtoname.h index cd5c41f4..c0cd0333 100644 --- a/addrtoname.h +++ b/addrtoname.h @@ -38,6 +38,7 @@ extern const char *le64addr_string(const u_char *); extern const char *etherproto_string(u_short); extern const char *tcpport_string(u_short); extern const char *udpport_string(u_short); +extern const char *ipproto_string(u_int); extern const char *getname(const u_char *); #ifdef INET6 extern const char *getname6(const u_char *); diff --git a/configure b/configure index f481d333..5ba60711 100755 --- a/configure +++ b/configure @@ -4190,7 +4190,7 @@ fi done if test "$ac_cv_header_net_pfvar_h" = yes; then - LOCALSRC="print-pflog.c $LOCALSRC" + LOCALSRC="print-pflog.c print-pfsync.c pf_print_state.c $LOCALSRC" fi for ac_header in netinet/if_ether.h diff --git a/configure.in b/configure.in index 4ac664ec..49fd4e8c 100644 --- a/configure.in +++ b/configure.in @@ -34,7 +34,7 @@ AC_CHECK_HEADERS(net/pfvar.h, , , [#include #include #include ]) if test "$ac_cv_header_net_pfvar_h" = yes; then - LOCALSRC="print-pflog.c $LOCALSRC" + LOCALSRC="print-pflog.c print-pfsync.c pf_print_state.c $LOCALSRC" fi AC_CHECK_HEADERS(netinet/if_ether.h, , , [#include #include ]) diff --git a/interface.h b/interface.h index 18668a21..563c4cb5 100644 --- a/interface.h +++ b/interface.h @@ -183,6 +183,8 @@ extern void dvmrp_print(const u_char *, u_int); extern void egp_print(const u_char *, u_int); extern u_int enc_if_print(const struct pcap_pkthdr *, const u_char *); extern u_int pflog_if_print(const struct pcap_pkthdr *, const u_char *); +extern u_int pfsync_if_print(const struct pcap_pkthdr *, const u_char *); +extern void pfsync_ip_print(const u_char *, u_int, const u_char *); extern u_int arcnet_if_print(const struct pcap_pkthdr *, const u_char *); extern u_int arcnet_linux_if_print(const struct pcap_pkthdr *, const u_char *); extern u_int token_print(const u_char *, u_int, u_int); diff --git a/pf_print_state.c b/pf_print_state.c new file mode 100644 index 00000000..602874a6 --- /dev/null +++ b/pf_print_state.c @@ -0,0 +1,289 @@ +/* $OpenBSD: pf_print_state.c,v 1.3 2005/11/04 08:24:15 mcbride Exp $ */ + +/* + * Copyright (c) 2001 Daniel Hartmeier + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * - Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials provided + * with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + */ + +#include +#include +#include +#define TCPSTATES +#include +#include +#include +#include + +#include +#include + +#include "pfctl_parser.h" +#include "pfctl.h" +#include "addrtoname.h" + +#include +#define betoh64(x) (unsigned long long)be64toh(x) + +void print_name(struct pf_addr *, sa_family_t); + +void +print_addr(struct pf_addr_wrap *addr, sa_family_t af, int verbose) +{ + switch (addr->type) { + case PF_ADDR_DYNIFTL: + printf("(%s", addr->v.ifname); + if (addr->iflags & PFI_AFLAG_NETWORK) + printf(":network"); + if (addr->iflags & PFI_AFLAG_BROADCAST) + printf(":broadcast"); + if (addr->iflags & PFI_AFLAG_PEER) + printf(":peer"); + if (addr->iflags & PFI_AFLAG_NOALIAS) + printf(":0"); + if (verbose) { + if (addr->p.dyncnt <= 0) + printf(":*"); + else + printf(":%d", addr->p.dyncnt); + } + printf(")"); + break; + case PF_ADDR_TABLE: + if (verbose) + if (addr->p.tblcnt == -1) + printf("<%s:*>", addr->v.tblname); + else + printf("<%s:%d>", addr->v.tblname, + addr->p.tblcnt); + else + printf("<%s>", addr->v.tblname); + return; + case PF_ADDR_ADDRMASK: + if (PF_AZERO(&addr->v.a.addr, AF_INET6) && + PF_AZERO(&addr->v.a.mask, AF_INET6)) + printf("any"); + else { + char buf[48]; + + if (inet_ntop(af, &addr->v.a.addr, buf, + sizeof(buf)) == NULL) + printf("?"); + else + printf("%s", buf); + } + break; + case PF_ADDR_NOROUTE: + printf("no-route"); + return; + default: + printf("?"); + return; + } + if (! PF_AZERO(&addr->v.a.mask, af)) { + int bits = unmask(&addr->v.a.mask, af); + + if (bits != (af == AF_INET ? 32 : 128)) + printf("/%d", bits); + } +} + +void +print_name(struct pf_addr *addr, sa_family_t af) +{ + const char *host; + + switch (af) { + case AF_INET: + host = getname((const char *)&addr->v4); + break; + case AF_INET6: + host = getname6((const char *)&addr->v6); + break; + default: + host = "?"; + break; + } + printf("%s", host); +} + +void +print_host(struct pf_state_host *h, sa_family_t af, int opts) +{ + u_int16_t p = ntohs(h->port); + + if (opts & PF_OPT_USEDNS) + print_name(&h->addr, af); + else { + struct pf_addr_wrap aw; + + memset(&aw, 0, sizeof(aw)); + aw.v.a.addr = h->addr; + if (af == AF_INET) + aw.v.a.mask.addr32[0] = 0xffffffff; + else { + memset(&aw.v.a.mask, 0xff, sizeof(aw.v.a.mask)); + af = AF_INET6; + } + print_addr(&aw, af, opts & PF_OPT_VERBOSE2); + } + + if (p) { + if (af == AF_INET) + printf(":%u", p); + else + printf("[%u]", p); + } +} + +void +print_seq(struct pf_state_peer *p) +{ + if (p->seqdiff) + printf("[%u + %u](+%u)", p->seqlo, p->seqhi - p->seqlo, + p->seqdiff); + else + printf("[%u + %u]", p->seqlo, p->seqhi - p->seqlo); +} + +void +print_state(struct pf_state *s, int opts) +{ + struct pf_state_peer *src, *dst; + int min, sec; + + if (s->direction == PF_OUT) { + src = &s->src; + dst = &s->dst; + } else { + src = &s->dst; + dst = &s->src; + } + printf("%s ", s->u.ifname); + printf("%s ", ipproto_string(s->proto)); + if (PF_ANEQ(&s->lan.addr, &s->gwy.addr, s->af) || + (s->lan.port != s->gwy.port)) { + print_host(&s->lan, s->af, opts); + if (s->direction == PF_OUT) + printf(" -> "); + else + printf(" <- "); + } + print_host(&s->gwy, s->af, opts); + if (s->direction == PF_OUT) + printf(" -> "); + else + printf(" <- "); + print_host(&s->ext, s->af, opts); + + printf(" "); + if (s->proto == IPPROTO_TCP) { + if (src->state <= TCPS_TIME_WAIT && + dst->state <= TCPS_TIME_WAIT) + printf("\n %s:%s", tcpstates[src->state], + tcpstates[dst->state]); + else if (src->state == PF_TCPS_PROXY_SRC || + dst->state == PF_TCPS_PROXY_SRC) + printf("\n PROXY:SRC"); + else if (src->state == PF_TCPS_PROXY_DST || + dst->state == PF_TCPS_PROXY_DST) + printf("\n PROXY:DST"); + else + printf("\n ", + src->state, dst->state); + if (opts & PF_OPT_VERBOSE) { + printf("\n "); + print_seq(src); + if (src->wscale && dst->wscale) + printf(" wscale %u", + src->wscale & PF_WSCALE_MASK); + printf(" "); + print_seq(dst); + if (src->wscale && dst->wscale) + printf(" wscale %u", + dst->wscale & PF_WSCALE_MASK); + } + } else if (s->proto == IPPROTO_UDP && src->state < PFUDPS_NSTATES && + dst->state < PFUDPS_NSTATES) { + const char *states[] = PFUDPS_NAMES; + + printf(" %s:%s", states[src->state], states[dst->state]); + } else if (s->proto != IPPROTO_ICMP && src->state < PFOTHERS_NSTATES && + dst->state < PFOTHERS_NSTATES) { + /* XXX ICMP doesn't really have state levels */ + const char *states[] = PFOTHERS_NAMES; + + printf(" %s:%s", states[src->state], states[dst->state]); + } else { + printf(" %u:%u", src->state, dst->state); + } + + if (opts & PF_OPT_VERBOSE) { + sec = s->creation % 60; + s->creation /= 60; + min = s->creation % 60; + s->creation /= 60; + printf("\n age %.2u:%.2u:%.2u", s->creation, min, sec); + sec = s->expire % 60; + s->expire /= 60; + min = s->expire % 60; + s->expire /= 60; + printf(", expires in %.2u:%.2u:%.2u", s->expire, min, sec); + printf(", %llu:%llu pkts, %llu:%llu bytes", + s->packets[0], s->packets[1], s->bytes[0], s->bytes[1]); + if (s->anchor.nr != -1) + printf(", anchor %u", s->anchor.nr); + if (s->rule.nr != -1) + printf(", rule %u", s->rule.nr); + if (s->src_node != NULL) + printf(", source-track"); + if (s->nat_src_node != NULL) + printf(", sticky-address"); + } + if (opts & PF_OPT_VERBOSE2) { + printf("\n id: %016llx creatorid: %08x", + betoh64(s->id), ntohl(s->creatorid)); + } +} + +int +unmask(struct pf_addr *m, sa_family_t af) +{ + int i = 31, j = 0, b = 0; + u_int32_t tmp; + + while (j < 4 && m->addr32[j] == 0xffffffff) { + b += 32; + j++; + } + if (j < 4) { + tmp = ntohl(m->addr32[j]); + for (i = 31; tmp & (1 << i); --i) + b++; + } + return (b); +} diff --git a/print-ip.c b/print-ip.c index c0c91888..a7d95eb9 100644 --- a/print-ip.c +++ b/print-ip.c @@ -477,6 +477,14 @@ again: } break; +#ifdef HAVE_NET_PFVAR_H + case IPPROTO_PFSYNC: + pfsync_ip_print(ipds->cp, + (int)(snapend - (u_char *)ipds->ip) - IP_HL(ipds->ip) * 4, + (const u_char *)ipds->ip); + break; +#endif + case IPPROTO_PGM: pgm_print(ipds->cp, ipds->len, (const u_char *)ipds->ip); break; diff --git a/print-pfsync.c b/print-pfsync.c new file mode 100644 index 00000000..27999803 --- /dev/null +++ b/print-pfsync.c @@ -0,0 +1,248 @@ +/* $OpenBSD: print-pfsync.c,v 1.32 2007/10/07 16:41:05 deraadt Exp $ */ + +/* + * Copyright (c) 2002 Michael Shalayeff + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR OR HIS RELATIVES BE LIABLE FOR ANY DIRECT, + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF MIND, USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef lint +static const char rcsid[] = + "@(#) $Id: print-pfsync.c,v 1.32 2007/10/07 16:41:05 deraadt Exp $"; +#endif + +#include +#include +#include +#include +#include +#include + +#ifdef __STDC__ +struct rtentry; +#endif +#include + +#include +#include +#include + +#include +#include + +#include +#include +#include +#include +#include +#include + +#include "interface.h" +#include "addrtoname.h" +#include "pfctl_parser.h" +#include "pfctl.h" + +#include +#define betoh64(x) (unsigned long long)be64toh(x) + +const char *pfsync_acts[] = { PFSYNC_ACTIONS }; + +void pfsync_print(struct pfsync_header *, int); + +u_int +pfsync_if_print(const struct pcap_pkthdr *h, const u_char *p) +{ + u_int caplen = h->caplen; + u_int hdrlen; + + if (caplen < PFSYNC_HDRLEN) { + printf("[|pfsync]"); + goto out; + } + + pfsync_print((struct pfsync_header *)p, + caplen - sizeof(struct pfsync_header)); +out: + return (PFSYNC_HDRLEN); +} + +void +pfsync_ip_print(const u_char *bp, u_int len, const u_char *bp2) +{ + struct pfsync_header *hdr = (struct pfsync_header *)bp; + struct ip *ip = (struct ip *)bp2; + + if (vflag) + printf("%s > %s: ", ipaddr_string(&ip->ip_src), + ipaddr_string(&ip->ip_dst)); + else + printf("%s: ", ipaddr_string(&ip->ip_src)); + + if (len < PFSYNC_HDRLEN) + printf("[|pfsync]"); + else + pfsync_print(hdr, (len - sizeof(struct pfsync_header))); + putchar('\n'); +} + +void +pfsync_print(struct pfsync_header *hdr, int len) +{ + struct pfsync_state *s; + struct pfsync_state_upd *u; + struct pfsync_state_del *d; + struct pfsync_state_clr *c; + struct pfsync_state_upd_req *r; + struct pfsync_state_bus *b; +#ifdef PFSYNC_TDB + struct pfsync_tdb *t; +#endif + int i, flags = 0, min, sec; + u_int64_t id; + + if (eflag) + printf("PFSYNCv%d count %d: ", + hdr->version, hdr->count); + + if (hdr->action < PFSYNC_ACT_MAX) + printf("%s:", pfsync_acts[hdr->action]); + else + printf("%d?:", hdr->action); + if (vflag) + flags |= PF_OPT_VERBOSE; + if (vflag > 1) + flags |= PF_OPT_VERBOSE2; + if (!nflag) + flags |= PF_OPT_USEDNS; + + switch (hdr->action) { + case PFSYNC_ACT_CLR: + if (sizeof(*c) <= len) { + c = (void *)((char *)hdr + PFSYNC_HDRLEN); + printf("\n\tcreatorid: %08x", htonl(c->creatorid)); + if (c->ifname[0] != '\0') + printf(" interface: %s", c->ifname); + } + case PFSYNC_ACT_INS: + case PFSYNC_ACT_UPD: + case PFSYNC_ACT_DEL: + for (i = 1, s = (void *)((char *)hdr + PFSYNC_HDRLEN); + i <= hdr->count && i * sizeof(*s) <= len; i++, s++) { + struct pf_state st; + + bzero(&st, sizeof(st)); + bcopy(&s->id, &st.id, sizeof(st.id)); + + strlcpy(st.u.ifname, s->ifname, sizeof(st.u.ifname)); + pf_state_host_ntoh(&s->lan, &st.lan); + pf_state_host_ntoh(&s->gwy, &st.gwy); + pf_state_host_ntoh(&s->ext, &st.ext); + pf_state_peer_ntoh(&s->src, &st.src); + pf_state_peer_ntoh(&s->dst, &st.dst); + st.rule.nr = ntohl(s->rule); + st.nat_rule.nr = ntohl(s->nat_rule); + st.anchor.nr = ntohl(s->anchor); + bcopy(&s->rt_addr, &st.rt_addr, sizeof(st.rt_addr)); + st.creation = ntohl(s->creation); + st.expire = ntohl(s->expire); + pf_state_counter_ntoh(s->packets[0], st.packets[0]); + pf_state_counter_ntoh(s->packets[1], st.packets[1]); + pf_state_counter_ntoh(s->bytes[0], st.bytes[0]); + pf_state_counter_ntoh(s->bytes[1], st.bytes[1]); + st.creatorid = s->creatorid; + st.af = s->af; + st.proto = s->proto; + st.direction = s->direction; + st.log = s->log; + st.timeout = s->timeout; + st.allow_opts = s->allow_opts; + st.sync_flags = s->sync_flags; + + putchar('\n'); + print_state(&st, flags); + if (vflag > 1 && hdr->action == PFSYNC_ACT_UPD) + printf(" updates: %d", s->updates); + } + break; + case PFSYNC_ACT_UPD_C: + for (i = 1, u = (void *)((char *)hdr + PFSYNC_HDRLEN); + i <= hdr->count && i * sizeof(*u) <= len; i++, u++) { + bcopy(&u->id, &id, sizeof(id)); + printf("\n\tid: %016llx creatorid: %08x", + betoh64(id), ntohl(u->creatorid)); + if (vflag > 1) + printf(" updates: %d", u->updates); + } + break; + case PFSYNC_ACT_DEL_C: + for (i = 1, d = (void *)((char *)hdr + PFSYNC_HDRLEN); + i <= hdr->count && i * sizeof(*d) <= len; i++, d++) { + bcopy(&d->id, &id, sizeof(id)); + printf("\n\tid: %016llx creatorid: %08x", + betoh64(id), ntohl(d->creatorid)); + } + break; + case PFSYNC_ACT_UREQ: + for (i = 1, r = (void *)((char *)hdr + PFSYNC_HDRLEN); + i <= hdr->count && i * sizeof(*r) <= len; i++, r++) { + bcopy(&r->id, &id, sizeof(id)); + printf("\n\tid: %016llx creatorid: %08x", + betoh64(id), ntohl(r->creatorid)); + } + break; + case PFSYNC_ACT_BUS: + if (sizeof(*b) <= len) { + b = (void *)((char *)hdr + PFSYNC_HDRLEN); + printf("\n\tcreatorid: %08x", htonl(b->creatorid)); + sec = b->endtime % 60; + b->endtime /= 60; + min = b->endtime % 60; + b->endtime /= 60; + printf(" age %.2u:%.2u:%.2u", b->endtime, min, sec); + switch (b->status) { + case PFSYNC_BUS_START: + printf(" status: start"); + break; + case PFSYNC_BUS_END: + printf(" status: end"); + break; + default: + printf(" status: ?"); + break; + } + } + break; +#ifdef PFSYNC_TDB + case PFSYNC_ACT_TDB_UPD: + for (i = 1, t = (void *)((char *)hdr + PFSYNC_HDRLEN); + i <= hdr->count && i * sizeof(*t) <= len; i++, t++) + printf("\n\tspi: %08x rpl: %u cur_bytes: %llu", + htonl(t->spi), htonl(t->rpl), + betoh64(t->cur_bytes)); + /* XXX add dst and sproto? */ + break; +#endif + default: + break; + } +} diff --git a/tcpdump.c b/tcpdump.c index 587ed321..5427182d 100644 --- a/tcpdump.c +++ b/tcpdump.c @@ -209,6 +209,9 @@ static struct printer printers[] = { #if defined(DLT_PFLOG) && defined(HAVE_NET_PFVAR_H) { pflog_if_print, DLT_PFLOG }, #endif +#if defined(DLT_PFSYNC) && defined(HAVE_NET_PFVAR_H) + { pfsync_if_print, DLT_PFSYNC }, +#endif #ifdef DLT_FR { fr_if_print, DLT_FR }, #endif