summaryrefslogtreecommitdiffstats
path: root/sys/net/if_pflog.c
diff options
context:
space:
mode:
Diffstat (limited to 'sys/net/if_pflog.c')
-rw-r--r--sys/net/if_pflog.c125
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);
}