예제 #1
0
void
pflog_bpfcopy(const void *src_arg, void *dst_arg, size_t len)
{
	struct mbuf		*m, *mp, *mhdr, *mptr;
	struct pfloghdr		*pfloghdr;
	u_int			 count;
	u_char			*dst, *mdst;
	int			 afto, hlen, mlen, off;
	union pf_headers {
		struct tcphdr		tcp;
		struct udphdr		udp;
		struct icmp		icmp;
#ifdef INET6
		struct icmp6_hdr	icmp6;
		struct mld_hdr		mld;
		struct nd_neighbor_solicit nd_ns;
#endif /* INET6 */
	} pdhdrs;

	struct pf_pdesc		 pd;
	struct pf_addr		 osaddr, odaddr;
	u_int16_t		 osport = 0, odport = 0;
	u_int8_t		 proto = 0;

	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;
	dst += count;
	len -= count;
	m = m->m_next;

	if (len <= 0)
		return;

	/* 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() */

#if INET && INET6
	/* offset for a new header */
	if (afto && pfloghdr->af == AF_INET)
		mhdr->m_data += sizeof(struct ip6_hdr) -
		    sizeof(struct ip);
#endif /* INET && INET6 */

	mdst = mtod(mhdr, char *);
	switch (pfloghdr->af) {
	case AF_INET: {
		struct ip	*h;

		if (m->m_pkthdr.len < sizeof(*h))
			goto copy;
		m_copydata(m, 0, sizeof(*h), mdst);
		h = (struct ip *)mdst;
		hlen = h->ip_hl << 2;
		if (hlen > sizeof(*h) && (m->m_pkthdr.len >= hlen))
			m_copydata(m, sizeof(*h), hlen - sizeof(*h),
			    mdst + sizeof(*h));
		break;
	    }
#ifdef INET6
	case AF_INET6: {
		struct ip6_hdr	*h;

		if (m->m_pkthdr.len < sizeof(*h))
			goto copy;
		hlen = sizeof(struct ip6_hdr);
		m_copydata(m, 0, hlen, mdst);
		h = (struct ip6_hdr *)mdst;
		proto = h->ip6_nxt;
		break;
	    }
#endif /* INET6 */
	default:
		/* shouldn't happen ever :-) */
		goto copy;
	}

	if (m->m_pkthdr.len < hlen + 8 && proto != IPPROTO_NONE)
		goto copy;
	else if (proto != IPPROTO_NONE) {
		/* copy 8 bytes of the protocol header */
		m_copydata(m, hlen, 8, mdst + hlen);
		hlen += 8;
	}

	mhdr->m_len += hlen;
	mhdr->m_pkthdr.len = mhdr->m_len;

	/* create a chain mhdr -> mptr, mptr->m_data = (m->m_data+hlen) */
	mp = m_getptr(m, hlen, &off);
	if (mp != NULL) {
		bcopy(mp, mptr, sizeof(*mptr));
		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;
	}

	/*
	 * Rewrite addresses if needed. Reason pointer must be NULL to avoid
	 * counting the packet here again.
	 */
	if (pf_setup_pdesc(&pd, &pdhdrs, pfloghdr->af, pfloghdr->dir, NULL,
	    mhdr, NULL) != PF_PASS)
		goto copy;
	pd.naf = pfloghdr->naf;

	PF_ACPY(&osaddr, pd.src, pd.af);
	PF_ACPY(&odaddr, pd.dst, pd.af);
	if (pd.sport)
		osport = *pd.sport;
	if (pd.dport)
		odport = *pd.dport;

	if (pd.virtual_proto != PF_VPROTO_FRAGMENT &&
	    (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);
#if INET && INET6
		if (afto) {
			PF_ACPY(&pd.nsaddr, &pfloghdr->saddr, pd.naf);
			PF_ACPY(&pd.ndaddr, &pfloghdr->daddr, pd.naf);
		}
#endif /* INET && INET6 */
		PF_ACPY(&pfloghdr->saddr, &osaddr, pd.af);
		PF_ACPY(&pfloghdr->daddr, &odaddr, pd.af);
		pfloghdr->sport = osport;
		pfloghdr->dport = odport;
	}

	pd.tot_len = min(pd.tot_len, len);
	pd.tot_len -= pd.m->m_data - pd.m->m_pktdat;

#if INET && INET6
	if (afto && pfloghdr->rewritten)
		pf_translate_af(&pd);
#endif /* INET && INET6 */

	m = pd.m;
 copy:
	mlen = min(m->m_pkthdr.len, len);
	m_copydata(m, 0, mlen, dst);
	len -= mlen;
	if (len > 0)
		bzero(dst + mlen, len);
}
예제 #2
0
void
pflog_bpfcopy(const void *src_arg, void *dst_arg, size_t len)
{
	const struct mbuf	*m;
	struct pfloghdr		*pfloghdr;
	u_int			 count;
	u_char			*dst;
	u_short			 action, reason;
	int			 off = 0, hdrlen = 0;
	union {
		struct tcphdr		tcp;
		struct udphdr		udp;
		struct icmp		icmp;
#ifdef INET6
		struct icmp6_hdr	icmp6;
#endif /* INET6 */
	} pf_hdrs;

	struct pf_pdesc		 pd;
	struct pf_addr		 osaddr, odaddr;
	u_int16_t		 osport = 0, odport = 0;

	m = src_arg;
	dst = dst_arg;

	if (m == NULL)
		panic("pflog_bpfcopy got no mbuf");

	/* first mbuf holds struct pfloghdr */
	pfloghdr = mtod(m, struct pfloghdr *);
	count = min(m->m_len, len);
	bcopy(pfloghdr, dst, count);
	pfloghdr = (struct pfloghdr *)dst;
	dst += count;
	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
		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;
	}

	if (mfake->m_flags & M_PKTHDR)
		mfake->m_pkthdr.len = min(mfake->m_pkthdr.len, mfake->m_len);

	/* rewrite addresses if needed */
	memset(&pd, 0, sizeof(pd));
	pd.hdr.any = &pf_hdrs;
	if (pf_setup_pdesc(pfloghdr->af, pfloghdr->dir, &pd, mfake, &action,
	    &reason, NULL, NULL, NULL, NULL, &off, &hdrlen) == -1)
		return;

	PF_ACPY(&osaddr, pd.src, pd.af);
	PF_ACPY(&odaddr, pd.dst, pd.af);
	if (pd.sport)
		osport = *pd.sport;
	if (pd.dport)
		odport = *pd.dport;

	if ((pfloghdr->rewritten = pf_translate(&pd, &pfloghdr->saddr,
	    pfloghdr->sport, &pfloghdr->daddr, pfloghdr->dport, 0,
	    pfloghdr->dir))) {
		m_copyback(mfake, off, min(mfake->m_len - off, hdrlen),
		    pd.hdr.any, M_NOWAIT);
		PF_ACPY(&pfloghdr->saddr, &osaddr, pd.af);
		PF_ACPY(&pfloghdr->daddr, &odaddr, pd.af);
		pfloghdr->sport = osport;
		pfloghdr->dport = odport;
	}
}