diff options
Diffstat (limited to 'sys/net/if_pflog.c')
| -rw-r--r-- | sys/net/if_pflog.c | 125 |
1 files changed, 91 insertions, 34 deletions
diff --git a/sys/net/if_pflog.c b/sys/net/if_pflog.c index f389a99aae5..f8ae8be545d 100644 --- a/sys/net/if_pflog.c +++ b/sys/net/if_pflog.c @@ -1,4 +1,4 @@ -/* $OpenBSD: if_pflog.c,v 1.43 2011/09/28 17:15:45 bluhm Exp $ */ +/* $OpenBSD: if_pflog.c,v 1.44 2011/10/13 18:23:39 claudio Exp $ */ /* * The authors of this code are John Ioannidis (ji@tla.org), * Angelos D. Keromytis (kermit@csd.uch.gr) and @@ -63,6 +63,7 @@ #ifndef INET #include <netinet/in.h> #endif +#include <netinet/ip6.h> #include <netinet6/nd6.h> #include <netinet/icmp6.h> #endif /* INET6 */ @@ -91,7 +92,7 @@ struct if_clone pflog_cloner = IF_CLONE_INITIALIZER("pflog", pflog_clone_create, pflog_clone_destroy); struct ifnet *pflogifs[PFLOGIFS_MAX]; /* for fast access */ -struct mbuf *mfake = NULL; +struct mbuf *pflog_mhdr = NULL, *pflog_mptr = NULL; void pflogattach(int npflog) @@ -100,8 +101,12 @@ pflogattach(int npflog) LIST_INIT(&pflogif_list); for (i = 0; i < PFLOGIFS_MAX; i++) pflogifs[i] = NULL; - if (mfake == NULL) - mfake = m_get(M_DONTWAIT, MT_HEADER); + if (pflog_mhdr == NULL) + if ((pflog_mhdr = m_get(M_DONTWAIT, MT_HEADER)) == NULL) + panic("pflogattach: no mbuf"); + if (pflog_mptr == NULL) + if ((pflog_mptr = m_get(M_DONTWAIT, MT_DATA)) == NULL) + panic("pflogattach: no mbuf"); if_clone_attach(&pflog_cloner); } @@ -225,7 +230,6 @@ pflog_packet(struct pf_pdesc *pd, u_int8_t reason, struct pf_rule *rm, bzero(&hdr, sizeof(hdr)); hdr.length = PFLOG_REAL_HDRLEN; - hdr.af = pd->af; hdr.action = rm->action; hdr.reason = reason; memcpy(hdr.ifname, pd->kif->pfik_name, sizeof(hdr.ifname)); @@ -253,8 +257,10 @@ pflog_packet(struct pf_pdesc *pd, u_int8_t reason, struct pf_rule *rm, hdr.rule_pid = rm->cpid; hdr.dir = pd->dir; - PF_ACPY(&hdr.saddr, &pd->nsaddr, pd->af); - PF_ACPY(&hdr.daddr, &pd->ndaddr, pd->af); + PF_ACPY(&hdr.saddr, &pd->nsaddr, pd->naf); + PF_ACPY(&hdr.daddr, &pd->ndaddr, pd->naf); + hdr.af = pd->af; + hdr.naf = pd->naf; hdr.sport = pd->nsport; hdr.dport = pd->ndport; @@ -270,11 +276,12 @@ pflog_packet(struct pf_pdesc *pd, u_int8_t reason, struct pf_rule *rm, void pflog_bpfcopy(const void *src_arg, void *dst_arg, size_t len) { - const struct mbuf *m; + struct mbuf *m, *mp, *mhdr, *mptr; struct pfloghdr *pfloghdr; u_int count; - u_char *dst; + u_char *dst, *mdst, *cp; u_short action, reason; + int afto, hlen, mlen, off; union pf_headers { struct tcphdr tcp; struct udphdr udp; @@ -290,14 +297,18 @@ pflog_bpfcopy(const void *src_arg, void *dst_arg, size_t len) struct pf_addr osaddr, odaddr; u_int16_t osport = 0, odport = 0; - m = src_arg; + m = (struct mbuf *)src_arg; dst = dst_arg; + mhdr = pflog_mhdr; + mptr = pflog_mptr; + if (m == NULL) panic("pflog_bpfcopy got no mbuf"); /* first mbuf holds struct pfloghdr */ pfloghdr = mtod(m, struct pfloghdr *); + afto = pfloghdr->af != pfloghdr->naf; count = min(m->m_len, len); bcopy(pfloghdr, dst, count); pfloghdr = (struct pfloghdr *)dst; @@ -305,36 +316,72 @@ pflog_bpfcopy(const void *src_arg, void *dst_arg, size_t len) len -= count; m = m->m_next; - /* second mbuf is pkthdr */ - if (len > 0) { - if (m == NULL) - panic("no second mbuf"); - bcopy(m, mfake, sizeof(*mfake)); - mfake->m_flags &= ~(M_EXT|M_CLUSTER); - mfake->m_next = NULL; - mfake->m_nextpkt = NULL; - mfake->m_data = dst; - mfake->m_len = len; - } else + if (len <= 0) return; - while (len > 0) { - if (m == 0) - panic("bpf_mcopy"); - count = min(m->m_len, len); - bcopy(mtod(m, caddr_t), (caddr_t)dst, count); - m = m->m_next; - dst += count; - len -= count; + /* second mbuf is pkthdr */ + if (m == NULL) + panic("no second mbuf"); + + /* + * temporary mbuf will hold an ip/ip6 header and 8 bytes + * of the protocol header + */ + m_inithdr(mhdr); + mhdr->m_len = 0; /* XXX not done in m_inithdr() */ + + /* offset for a new header */ + if (afto && pfloghdr->af == AF_INET) + mhdr->m_data += sizeof(struct ip6_hdr) - + sizeof(struct ip); + + mdst = mtod(mhdr, char *); + switch (pfloghdr->af) { + case AF_INET: { + struct ip *h; + + m_copydata(m, 0, sizeof(*h), mdst); + h = (struct ip *)mdst; + hlen = h->ip_hl << 2; + if (hlen > sizeof(*h)) + m_copydata(m, sizeof(*h), hlen - sizeof(*h), + mdst + sizeof(*h)); + break; + } + case AF_INET6: { + hlen = sizeof(struct ip6_hdr); + m_copydata(m, 0, hlen, mdst); + break; + } + default: + /* shouldn't happen ever :-) */ + m_copydata(m, 0, len, dst); + return; } - if (mfake->m_flags & M_PKTHDR) - mfake->m_pkthdr.len = min(mfake->m_pkthdr.len, mfake->m_len); + /* copy 8 bytes of the protocol header */ + m_copydata(m, hlen, 8, mdst + hlen); + + mhdr->m_len += hlen + 8; + mhdr->m_pkthdr.len = mhdr->m_len; + + /* create a chain mhdr -> mptr, mptr->m_data = (m->m_data+hlen+8) */ + mp = m_getptr(m, hlen + 8, &off); + if (mp != NULL) { + bcopy(mp, mptr, sizeof(*mptr)); + cp = mtod(mp, char *); + mptr->m_data += off; + mptr->m_len -= off; + mptr->m_flags &= ~M_PKTHDR; + mhdr->m_next = mptr; + mhdr->m_pkthdr.len += m->m_pkthdr.len - (hlen + 8); + } /* rewrite addresses if needed */ if (pf_setup_pdesc(&pd, &pdhdrs, pfloghdr->af, pfloghdr->dir, NULL, - &mfake, &action, &reason) == -1) + &mhdr, &action, &reason) == -1) return; + pd.naf = pfloghdr->naf; PF_ACPY(&osaddr, pd.src, pd.af); PF_ACPY(&odaddr, pd.dst, pd.af); @@ -346,11 +393,21 @@ pflog_bpfcopy(const void *src_arg, void *dst_arg, size_t len) if ((pfloghdr->rewritten = pf_translate(&pd, &pfloghdr->saddr, pfloghdr->sport, &pfloghdr->daddr, pfloghdr->dport, 0, pfloghdr->dir))) { - m_copyback(pd.m, pd.off, min(pd.m->m_len - pd.off, - pd.hdrlen), pd.hdr.any, M_NOWAIT); + m_copyback(pd.m, pd.off, min(pd.m->m_len - pd.off, pd.hdrlen), + pd.hdr.any, M_NOWAIT); + if (afto) { + PF_ACPY(&pd.nsaddr, &pfloghdr->saddr, pd.naf); + PF_ACPY(&pd.ndaddr, &pfloghdr->daddr, pd.naf); + } PF_ACPY(&pfloghdr->saddr, &osaddr, pd.af); PF_ACPY(&pfloghdr->daddr, &odaddr, pd.af); pfloghdr->sport = osport; pfloghdr->dport = odport; } + + if (afto) + pf_translate_af(&pd); + + mlen = min(pd.m->m_pkthdr.len, len); + m_copydata(pd.m, 0, mlen, dst); } |
