1244769Sglebius/*- 2126258Smlaier * The authors of this code are John Ioannidis (ji@tla.org), 3240233Sglebius * Angelos D. Keromytis (kermit@csd.uch.gr) and 4126258Smlaier * Niels Provos (provos@physnet.uni-hamburg.de). 5126258Smlaier * 6240233Sglebius * This code was written by John Ioannidis for BSD/OS in Athens, Greece, 7126258Smlaier * in November 1995. 8126258Smlaier * 9126258Smlaier * Ported to OpenBSD and NetBSD, with additional transforms, in December 1996, 10126258Smlaier * by Angelos D. Keromytis. 11126258Smlaier * 12126258Smlaier * Additional transforms and features in 1997 and 1998 by Angelos D. Keromytis 13126258Smlaier * and Niels Provos. 14126258Smlaier * 15126258Smlaier * Copyright (C) 1995, 1996, 1997, 1998 by John Ioannidis, Angelos D. Keromytis 16126258Smlaier * and Niels Provos. 17126258Smlaier * Copyright (c) 2001, Angelos D. Keromytis, Niels Provos. 18126258Smlaier * 19126258Smlaier * Permission to use, copy, and modify this software with or without fee 20126258Smlaier * is hereby granted, provided that this entire notice is included in 21126258Smlaier * all copies of any software which is or includes a copy or 22240233Sglebius * modification of this software. 23126258Smlaier * You may use this code under the GNU public license if you so wish. Please 24126258Smlaier * contribute changes back to the authors under this freer than GPL license 25126258Smlaier * so that we may further the use of strong encryption without limitations to 26126258Smlaier * all. 27126258Smlaier * 28126258Smlaier * THIS SOFTWARE IS BEING PROVIDED "AS IS", WITHOUT ANY EXPRESS OR 29126258Smlaier * IMPLIED WARRANTY. IN PARTICULAR, NONE OF THE AUTHORS MAKES ANY 30126258Smlaier * REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING THE 31126258Smlaier * MERCHANTABILITY OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR 32126258Smlaier * PURPOSE. 33244769Sglebius * 34244769Sglebius * $OpenBSD: if_pflog.c,v 1.26 2007/10/18 21:58:18 mpf Exp $ 35126258Smlaier */ 36126258Smlaier 37240233Sglebius#include <sys/cdefs.h> 38240233Sglebius__FBSDID("$FreeBSD: stable/10/sys/netpfil/pf/if_pflog.c 310094 2016-12-14 21:30:35Z kp $"); 39240233Sglebius 40126261Smlaier#include "opt_inet.h" 41126261Smlaier#include "opt_inet6.h" 42126261Smlaier#include "opt_bpf.h" 43126261Smlaier#include "opt_pf.h" 44153110Sru 45126258Smlaier#include <sys/param.h> 46240233Sglebius#include <sys/kernel.h> 47126258Smlaier#include <sys/mbuf.h> 48240233Sglebius#include <sys/module.h> 49171168Smlaier#include <sys/proc.h> 50126258Smlaier#include <sys/socket.h> 51126261Smlaier#include <sys/sockio.h> 52126258Smlaier 53240233Sglebius#include <net/bpf.h> 54126258Smlaier#include <net/if.h> 55130933Sbrooks#include <net/if_clone.h> 56240233Sglebius#include <net/if_pflog.h> 57126258Smlaier#include <net/if_types.h> 58240233Sglebius#include <net/pfvar.h> 59126258Smlaier 60221132Sbz#if defined(INET) || defined(INET6) 61221132Sbz#include <netinet/in.h> 62221132Sbz#endif 63126258Smlaier#ifdef INET 64126258Smlaier#include <netinet/in_var.h> 65126258Smlaier#include <netinet/ip.h> 66126258Smlaier#endif 67126258Smlaier 68126258Smlaier#ifdef INET6 69221132Sbz#include <netinet6/in6_var.h> 70126258Smlaier#include <netinet6/nd6.h> 71126258Smlaier#endif /* INET6 */ 72126258Smlaier 73193900Sbz#ifdef INET 74171168Smlaier#include <machine/in_cksum.h> 75223637Sbz#endif /* INET */ 76126261Smlaier 77126258Smlaier#define PFLOGMTU (32768 + MHLEN + MLEN) 78126258Smlaier 79126258Smlaier#ifdef PFLOGDEBUG 80126258Smlaier#define DPRINTF(x) do { if (pflogdebug) printf x ; } while (0) 81126258Smlaier#else 82126258Smlaier#define DPRINTF(x) 83126258Smlaier#endif 84126258Smlaier 85249925Sglebiusstatic int pflogoutput(struct ifnet *, struct mbuf *, 86249925Sglebius const struct sockaddr *, struct route *); 87240233Sglebiusstatic void pflogattach(int); 88240233Sglebiusstatic int pflogioctl(struct ifnet *, u_long, caddr_t); 89240233Sglebiusstatic void pflogstart(struct ifnet *); 90240233Sglebiusstatic int pflog_clone_create(struct if_clone *, int, caddr_t); 91240233Sglebiusstatic void pflog_clone_destroy(struct ifnet *); 92241610Sglebiusstatic struct if_clone *pflog_cloner; 93126258Smlaier 94241610Sglebiusstatic const char pflogname[] = "pflog"; 95171168Smlaier 96171168Smlaierstruct ifnet *pflogifs[PFLOGIFS_MAX]; /* for fast access */ 97171168Smlaier 98240233Sglebiusstatic void 99171168Smlaierpflogattach(int npflog) 100126261Smlaier{ 101171168Smlaier int i; 102171168Smlaier for (i = 0; i < PFLOGIFS_MAX; i++) 103171168Smlaier pflogifs[i] = NULL; 104241610Sglebius pflog_cloner = if_clone_simple(pflogname, pflog_clone_create, 105241610Sglebius pflog_clone_destroy, 1); 106126261Smlaier} 107126261Smlaier 108128209Sbrooksstatic int 109171168Smlaierpflog_clone_create(struct if_clone *ifc, int unit, caddr_t param) 110126261Smlaier{ 111141584Smlaier struct ifnet *ifp; 112126261Smlaier 113171168Smlaier if (unit >= PFLOGIFS_MAX) 114171168Smlaier return (EINVAL); 115171168Smlaier 116240233Sglebius ifp = if_alloc(IFT_PFLOG); 117147256Sbrooks if (ifp == NULL) { 118147256Sbrooks return (ENOSPC); 119147256Sbrooks } 120241610Sglebius if_initname(ifp, pflogname, unit); 121141584Smlaier ifp->if_mtu = PFLOGMTU; 122141584Smlaier ifp->if_ioctl = pflogioctl; 123141584Smlaier ifp->if_output = pflogoutput; 124141584Smlaier ifp->if_start = pflogstart; 125141584Smlaier ifp->if_snd.ifq_maxlen = ifqmaxlen; 126141584Smlaier ifp->if_hdrlen = PFLOG_HDRLEN; 127141584Smlaier if_attach(ifp); 128126261Smlaier 129141584Smlaier bpfattach(ifp, DLT_PFLOG, PFLOG_HDRLEN); 130126261Smlaier 131171168Smlaier pflogifs[unit] = ifp; 132171168Smlaier 133141584Smlaier return (0); 134126261Smlaier} 135171168Smlaier 136171168Smlaierstatic void 137171168Smlaierpflog_clone_destroy(struct ifnet *ifp) 138126258Smlaier{ 139240233Sglebius int i; 140126258Smlaier 141240233Sglebius for (i = 0; i < PFLOGIFS_MAX; i++) 142240233Sglebius if (pflogifs[i] == ifp) 143240233Sglebius pflogifs[i] = NULL; 144126258Smlaier 145171168Smlaier bpfdetach(ifp); 146171168Smlaier if_detach(ifp); 147171168Smlaier if_free(ifp); 148126258Smlaier} 149126258Smlaier 150126258Smlaier/* 151126258Smlaier * Start output on the pflog interface. 152126258Smlaier */ 153240233Sglebiusstatic void 154126258Smlaierpflogstart(struct ifnet *ifp) 155126258Smlaier{ 156126258Smlaier struct mbuf *m; 157126258Smlaier 158126258Smlaier for (;;) { 159130475Smlaier IF_LOCK(&ifp->if_snd); 160130475Smlaier _IF_DROP(&ifp->if_snd); 161130475Smlaier _IF_DEQUEUE(&ifp->if_snd, m); 162171168Smlaier IF_UNLOCK(&ifp->if_snd); 163171168Smlaier 164126258Smlaier if (m == NULL) 165126258Smlaier return; 166126258Smlaier else 167126258Smlaier m_freem(m); 168126258Smlaier } 169126258Smlaier} 170126258Smlaier 171240233Sglebiusstatic int 172249925Sglebiuspflogoutput(struct ifnet *ifp, struct mbuf *m, const struct sockaddr *dst, 173223637Sbz struct route *rt) 174126258Smlaier{ 175126258Smlaier m_freem(m); 176126258Smlaier return (0); 177126258Smlaier} 178126258Smlaier 179126258Smlaier/* ARGSUSED */ 180240233Sglebiusstatic int 181126258Smlaierpflogioctl(struct ifnet *ifp, u_long cmd, caddr_t data) 182126258Smlaier{ 183126258Smlaier switch (cmd) { 184126258Smlaier case SIOCSIFFLAGS: 185126258Smlaier if (ifp->if_flags & IFF_UP) 186148887Srwatson ifp->if_drv_flags |= IFF_DRV_RUNNING; 187126258Smlaier else 188148887Srwatson ifp->if_drv_flags &= ~IFF_DRV_RUNNING; 189126258Smlaier break; 190126258Smlaier default: 191223637Sbz return (ENOTTY); 192126258Smlaier } 193126258Smlaier 194126258Smlaier return (0); 195126258Smlaier} 196126258Smlaier 197240233Sglebiusstatic int 198130613Smlaierpflog_packet(struct pfi_kif *kif, struct mbuf *m, sa_family_t af, u_int8_t dir, 199126258Smlaier u_int8_t reason, struct pf_rule *rm, struct pf_rule *am, 200240233Sglebius struct pf_ruleset *ruleset, struct pf_pdesc *pd, int lookupsafe) 201126258Smlaier{ 202126258Smlaier struct ifnet *ifn; 203126258Smlaier struct pfloghdr hdr; 204126258Smlaier 205171168Smlaier if (kif == NULL || m == NULL || rm == NULL || pd == NULL) 206223637Sbz return ( 1); 207126258Smlaier 208171168Smlaier if ((ifn = pflogifs[rm->logif]) == NULL || !ifn->if_bpf) 209171168Smlaier return (0); 210171168Smlaier 211130613Smlaier bzero(&hdr, sizeof(hdr)); 212126258Smlaier hdr.length = PFLOG_REAL_HDRLEN; 213126258Smlaier hdr.af = af; 214126258Smlaier hdr.action = rm->action; 215126258Smlaier hdr.reason = reason; 216130613Smlaier memcpy(hdr.ifname, kif->pfik_name, sizeof(hdr.ifname)); 217126258Smlaier 218126258Smlaier if (am == NULL) { 219126258Smlaier hdr.rulenr = htonl(rm->nr); 220310094Skp hdr.subrulenr = -1; 221126258Smlaier } else { 222126258Smlaier hdr.rulenr = htonl(am->nr); 223126258Smlaier hdr.subrulenr = htonl(rm->nr); 224145836Smlaier if (ruleset != NULL && ruleset->anchor != NULL) 225145836Smlaier strlcpy(hdr.ruleset, ruleset->anchor->name, 226126258Smlaier sizeof(hdr.ruleset)); 227126258Smlaier } 228240233Sglebius /* 229240233Sglebius * XXXGL: we avoid pf_socket_lookup() when we are holding 230240233Sglebius * state lock, since this leads to unsafe LOR. 231240233Sglebius * These conditions are very very rare, however. 232240233Sglebius */ 233240233Sglebius if (rm->log & PF_LOG_SOCKET_LOOKUP && !pd->lookup.done && lookupsafe) 234240233Sglebius pd->lookup.done = pf_socket_lookup(dir, pd, m); 235240233Sglebius if (pd->lookup.done > 0) 236171168Smlaier hdr.uid = pd->lookup.uid; 237240233Sglebius else 238171168Smlaier hdr.uid = UID_MAX; 239240233Sglebius hdr.pid = NO_PID; 240171168Smlaier hdr.rule_uid = rm->cuid; 241171168Smlaier hdr.rule_pid = rm->cpid; 242126258Smlaier hdr.dir = dir; 243126258Smlaier 244126258Smlaier#ifdef INET 245126258Smlaier if (af == AF_INET && dir == PF_OUT) { 246126258Smlaier struct ip *ip; 247126258Smlaier 248126258Smlaier ip = mtod(m, struct ip *); 249126258Smlaier ip->ip_sum = 0; 250126258Smlaier ip->ip_sum = in_cksum(m, ip->ip_hl << 2); 251126258Smlaier } 252126258Smlaier#endif /* INET */ 253126258Smlaier 254171168Smlaier ifn->if_opackets++; 255171168Smlaier ifn->if_obytes += m->m_pkthdr.len; 256171168Smlaier BPF_MTAP2(ifn, &hdr, PFLOG_HDRLEN, m); 257126258Smlaier 258126258Smlaier return (0); 259126258Smlaier} 260126261Smlaier 261126261Smlaierstatic int 262126261Smlaierpflog_modevent(module_t mod, int type, void *data) 263126261Smlaier{ 264126261Smlaier int error = 0; 265126261Smlaier 266126261Smlaier switch (type) { 267126261Smlaier case MOD_LOAD: 268171168Smlaier pflogattach(1); 269240233Sglebius PF_RULES_WLOCK(); 270155337Smlaier pflog_packet_ptr = pflog_packet; 271240233Sglebius PF_RULES_WUNLOCK(); 272126261Smlaier break; 273126261Smlaier case MOD_UNLOAD: 274240233Sglebius PF_RULES_WLOCK(); 275155337Smlaier pflog_packet_ptr = NULL; 276240233Sglebius PF_RULES_WUNLOCK(); 277241610Sglebius if_clone_detach(pflog_cloner); 278126261Smlaier break; 279126261Smlaier default: 280126261Smlaier error = EINVAL; 281126261Smlaier break; 282126261Smlaier } 283126261Smlaier 284126261Smlaier return error; 285126261Smlaier} 286126261Smlaier 287241610Sglebiusstatic moduledata_t pflog_mod = { pflogname, pflog_modevent, 0 }; 288126261Smlaier 289126261Smlaier#define PFLOG_MODVER 1 290126261Smlaier 291226532SbzDECLARE_MODULE(pflog, pflog_mod, SI_SUB_PSEUDO, SI_ORDER_ANY); 292126261SmlaierMODULE_VERSION(pflog, PFLOG_MODVER); 293155337SmlaierMODULE_DEPEND(pflog, pf, PF_MODVER, PF_MODVER, PF_MODVER); 294