1 1.22 thorpej /* $NetBSD: if_pflog.c,v 1.22 2020/01/29 05:52:27 thorpej Exp $ */ 2 1.12 yamt /* $OpenBSD: if_pflog.c,v 1.24 2007/05/26 17:13:30 jason Exp $ */ 3 1.12 yamt 4 1.1 itojun /* 5 1.1 itojun * The authors of this code are John Ioannidis (ji (at) tla.org), 6 1.1 itojun * Angelos D. Keromytis (kermit (at) csd.uch.gr) and 7 1.1 itojun * Niels Provos (provos (at) physnet.uni-hamburg.de). 8 1.1 itojun * 9 1.1 itojun * This code was written by John Ioannidis for BSD/OS in Athens, Greece, 10 1.1 itojun * in November 1995. 11 1.1 itojun * 12 1.1 itojun * Ported to OpenBSD and NetBSD, with additional transforms, in December 1996, 13 1.1 itojun * by Angelos D. Keromytis. 14 1.1 itojun * 15 1.1 itojun * Additional transforms and features in 1997 and 1998 by Angelos D. Keromytis 16 1.1 itojun * and Niels Provos. 17 1.1 itojun * 18 1.1 itojun * Copyright (C) 1995, 1996, 1997, 1998 by John Ioannidis, Angelos D. Keromytis 19 1.1 itojun * and Niels Provos. 20 1.1 itojun * Copyright (c) 2001, Angelos D. Keromytis, Niels Provos. 21 1.1 itojun * 22 1.1 itojun * Permission to use, copy, and modify this software with or without fee 23 1.1 itojun * is hereby granted, provided that this entire notice is included in 24 1.1 itojun * all copies of any software which is or includes a copy or 25 1.1 itojun * modification of this software. 26 1.1 itojun * You may use this code under the GNU public license if you so wish. Please 27 1.1 itojun * contribute changes back to the authors under this freer than GPL license 28 1.1 itojun * so that we may further the use of strong encryption without limitations to 29 1.1 itojun * all. 30 1.1 itojun * 31 1.1 itojun * THIS SOFTWARE IS BEING PROVIDED "AS IS", WITHOUT ANY EXPRESS OR 32 1.1 itojun * IMPLIED WARRANTY. IN PARTICULAR, NONE OF THE AUTHORS MAKES ANY 33 1.1 itojun * REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING THE 34 1.1 itojun * MERCHANTABILITY OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR 35 1.1 itojun * PURPOSE. 36 1.1 itojun */ 37 1.1 itojun 38 1.11 lukem #include <sys/cdefs.h> 39 1.22 thorpej __KERNEL_RCSID(0, "$NetBSD: if_pflog.c,v 1.22 2020/01/29 05:52:27 thorpej Exp $"); 40 1.11 lukem 41 1.2 itojun #ifdef _KERNEL_OPT 42 1.2 itojun #include "opt_inet.h" 43 1.2 itojun #endif 44 1.2 itojun 45 1.1 itojun #include "pflog.h" 46 1.1 itojun 47 1.1 itojun #include <sys/param.h> 48 1.1 itojun #include <sys/systm.h> 49 1.1 itojun #include <sys/mbuf.h> 50 1.12 yamt #include <sys/proc.h> 51 1.1 itojun #include <sys/socket.h> 52 1.1 itojun #include <sys/ioctl.h> 53 1.1 itojun 54 1.1 itojun #include <net/if.h> 55 1.1 itojun #include <net/if_types.h> 56 1.1 itojun #include <net/route.h> 57 1.1 itojun #include <net/bpf.h> 58 1.1 itojun 59 1.1 itojun #ifdef INET 60 1.1 itojun #include <netinet/in.h> 61 1.1 itojun #include <netinet/in_var.h> 62 1.1 itojun #include <netinet/in_systm.h> 63 1.1 itojun #include <netinet/ip.h> 64 1.1 itojun #endif 65 1.1 itojun 66 1.1 itojun #ifdef INET6 67 1.1 itojun #ifndef INET 68 1.1 itojun #include <netinet/in.h> 69 1.1 itojun #endif 70 1.1 itojun #include <netinet6/nd6.h> 71 1.1 itojun #endif /* INET6 */ 72 1.1 itojun 73 1.1 itojun #include <net/pfvar.h> 74 1.1 itojun #include <net/if_pflog.h> 75 1.1 itojun 76 1.19 christos #include "ioconf.h" 77 1.19 christos 78 1.1 itojun #define PFLOGMTU (32768 + MHLEN + MLEN) 79 1.1 itojun 80 1.1 itojun #ifdef PFLOGDEBUG 81 1.1 itojun #define DPRINTF(x) do { if (pflogdebug) printf x ; } while (0) 82 1.1 itojun #else 83 1.1 itojun #define DPRINTF(x) 84 1.1 itojun #endif 85 1.1 itojun 86 1.18 ahoka #ifdef _MODULE 87 1.18 ahoka void pflogdetach(void); 88 1.18 ahoka #endif /* _MODULE */ 89 1.9 dyoung int pflogoutput(struct ifnet *, struct mbuf *, const struct sockaddr *, 90 1.20 ozaki const struct rtentry *); 91 1.10 christos int pflogioctl(struct ifnet *, u_long, void *); 92 1.1 itojun void pflogstart(struct ifnet *); 93 1.12 yamt int pflog_clone_create(struct if_clone *, int); 94 1.12 yamt int pflog_clone_destroy(struct ifnet *); 95 1.12 yamt 96 1.12 yamt LIST_HEAD(, pflog_softc) pflogif_list; 97 1.12 yamt struct if_clone pflog_cloner = 98 1.12 yamt IF_CLONE_INITIALIZER("pflog", pflog_clone_create, pflog_clone_destroy); 99 1.1 itojun 100 1.12 yamt struct ifnet *pflogifs[PFLOGIFS_MAX]; /* for fast access */ 101 1.1 itojun 102 1.1 itojun void 103 1.8 christos pflogattach(int npflog) 104 1.1 itojun { 105 1.1 itojun int i; 106 1.1 itojun 107 1.12 yamt LIST_INIT(&pflogif_list); 108 1.12 yamt for (i = 0; i < PFLOGIFS_MAX; i++) 109 1.12 yamt pflogifs[i] = NULL; 110 1.12 yamt if_clone_attach(&pflog_cloner); 111 1.1 itojun } 112 1.1 itojun 113 1.18 ahoka #ifdef _MODULE 114 1.18 ahoka void 115 1.18 ahoka pflogdetach(void) 116 1.18 ahoka { 117 1.18 ahoka int i; 118 1.18 ahoka 119 1.18 ahoka for (i = 0; i < PFLOGIFS_MAX; i++) { 120 1.18 ahoka if (pflogifs[i] != NULL) 121 1.18 ahoka pflog_clone_destroy(pflogifs[i]); 122 1.18 ahoka } 123 1.18 ahoka if_clone_detach(&pflog_cloner); 124 1.18 ahoka } 125 1.18 ahoka #endif /* _MODULE */ 126 1.18 ahoka 127 1.12 yamt int 128 1.12 yamt pflog_clone_create(struct if_clone *ifc, int unit) 129 1.12 yamt { 130 1.12 yamt struct ifnet *ifp; 131 1.12 yamt struct pflog_softc *pflogif; 132 1.12 yamt int s; 133 1.12 yamt 134 1.12 yamt if (unit >= PFLOGIFS_MAX) 135 1.12 yamt return (EINVAL); 136 1.12 yamt 137 1.14 cegger if ((pflogif = malloc(sizeof(*pflogif), M_DEVBUF, M_NOWAIT|M_ZERO)) == NULL) 138 1.12 yamt return (ENOMEM); 139 1.12 yamt 140 1.12 yamt pflogif->sc_unit = unit; 141 1.12 yamt ifp = &pflogif->sc_if; 142 1.12 yamt snprintf(ifp->if_xname, sizeof ifp->if_xname, "pflog%d", unit); 143 1.12 yamt ifp->if_softc = pflogif; 144 1.12 yamt ifp->if_mtu = PFLOGMTU; 145 1.12 yamt ifp->if_ioctl = pflogioctl; 146 1.12 yamt ifp->if_output = pflogoutput; 147 1.12 yamt ifp->if_start = pflogstart; 148 1.12 yamt ifp->if_type = IFT_PFLOG; 149 1.12 yamt #ifndef __NetBSD__ 150 1.12 yamt ifp->if_snd.ifq_maxlen = ifqmaxlen; 151 1.12 yamt #endif /* !__NetBSD__ */ 152 1.12 yamt ifp->if_hdrlen = PFLOG_HDRLEN; 153 1.12 yamt if_attach(ifp); 154 1.12 yamt if_alloc_sadl(ifp); 155 1.12 yamt 156 1.12 yamt #ifdef __NetBSD__ 157 1.17 joerg bpf_attach(ifp, DLT_PFLOG, PFLOG_HDRLEN); 158 1.12 yamt #else 159 1.12 yamt bpfattach(&pflogif->sc_if.if_bpf, ifp, DLT_PFLOG, PFLOG_HDRLEN); 160 1.12 yamt #endif /* !__NetBSD__ */ 161 1.12 yamt 162 1.12 yamt s = splnet(); 163 1.12 yamt LIST_INSERT_HEAD(&pflogif_list, pflogif, sc_list); 164 1.12 yamt pflogifs[unit] = ifp; 165 1.12 yamt splx(s); 166 1.12 yamt 167 1.12 yamt return (0); 168 1.3 itojun } 169 1.12 yamt 170 1.12 yamt int 171 1.12 yamt pflog_clone_destroy(struct ifnet *ifp) 172 1.12 yamt { 173 1.12 yamt struct pflog_softc *pflogif = ifp->if_softc; 174 1.12 yamt int s; 175 1.12 yamt 176 1.12 yamt s = splnet(); 177 1.12 yamt pflogifs[pflogif->sc_unit] = NULL; 178 1.12 yamt LIST_REMOVE(pflogif, sc_list); 179 1.12 yamt splx(s); 180 1.12 yamt 181 1.17 joerg bpf_detach(ifp); 182 1.12 yamt if_detach(ifp); 183 1.12 yamt free(pflogif, M_DEVBUF); 184 1.12 yamt return (0); 185 1.12 yamt } 186 1.3 itojun 187 1.1 itojun /* 188 1.1 itojun * Start output on the pflog interface. 189 1.1 itojun */ 190 1.1 itojun void 191 1.1 itojun pflogstart(struct ifnet *ifp) 192 1.1 itojun { 193 1.1 itojun struct mbuf *m; 194 1.1 itojun int s; 195 1.1 itojun 196 1.1 itojun for (;;) { 197 1.2 itojun s = splnet(); 198 1.1 itojun IF_DROP(&ifp->if_snd); 199 1.1 itojun IF_DEQUEUE(&ifp->if_snd, m); 200 1.1 itojun splx(s); 201 1.1 itojun 202 1.1 itojun if (m == NULL) 203 1.1 itojun return; 204 1.1 itojun else 205 1.1 itojun m_freem(m); 206 1.1 itojun } 207 1.1 itojun } 208 1.1 itojun 209 1.1 itojun int 210 1.8 christos pflogoutput(struct ifnet *ifp, struct mbuf *m, 211 1.20 ozaki const struct sockaddr *dst, const struct rtentry *rt) 212 1.1 itojun { 213 1.1 itojun m_freem(m); 214 1.1 itojun return (0); 215 1.1 itojun } 216 1.1 itojun 217 1.1 itojun /* ARGSUSED */ 218 1.1 itojun int 219 1.10 christos pflogioctl(struct ifnet *ifp, u_long cmd, void *data) 220 1.1 itojun { 221 1.13 dyoung int error = 0; 222 1.13 dyoung 223 1.1 itojun switch (cmd) { 224 1.13 dyoung case SIOCSIFFLAGS: 225 1.13 dyoung if ((error = ifioctl_common(ifp, cmd, data)) != 0) 226 1.13 dyoung break; 227 1.13 dyoung /*FALLTHROUGH*/ 228 1.13 dyoung case SIOCINITIFADDR: 229 1.1 itojun case SIOCAIFADDR: 230 1.1 itojun case SIOCSIFDSTADDR: 231 1.1 itojun if (ifp->if_flags & IFF_UP) 232 1.1 itojun ifp->if_flags |= IFF_RUNNING; 233 1.1 itojun else 234 1.1 itojun ifp->if_flags &= ~IFF_RUNNING; 235 1.1 itojun break; 236 1.1 itojun default: 237 1.13 dyoung error = ifioctl_common(ifp, cmd, data); 238 1.1 itojun } 239 1.1 itojun 240 1.13 dyoung return error; 241 1.1 itojun } 242 1.1 itojun 243 1.1 itojun int 244 1.1 itojun pflog_packet(struct pfi_kif *kif, struct mbuf *m, sa_family_t af, u_int8_t dir, 245 1.1 itojun u_int8_t reason, struct pf_rule *rm, struct pf_rule *am, 246 1.12 yamt struct pf_ruleset *ruleset, struct pf_pdesc *pd) 247 1.1 itojun { 248 1.1 itojun struct ifnet *ifn; 249 1.1 itojun struct pfloghdr hdr; 250 1.1 itojun 251 1.12 yamt if (kif == NULL || m == NULL || rm == NULL || pd == NULL) 252 1.1 itojun return (-1); 253 1.1 itojun 254 1.12 yamt if ((ifn = pflogifs[rm->logif]) == NULL || !ifn->if_bpf) 255 1.12 yamt return (0); 256 1.12 yamt 257 1.1 itojun bzero(&hdr, sizeof(hdr)); 258 1.1 itojun hdr.length = PFLOG_REAL_HDRLEN; 259 1.1 itojun hdr.af = af; 260 1.1 itojun hdr.action = rm->action; 261 1.1 itojun hdr.reason = reason; 262 1.1 itojun memcpy(hdr.ifname, kif->pfik_name, sizeof(hdr.ifname)); 263 1.1 itojun 264 1.1 itojun if (am == NULL) { 265 1.1 itojun hdr.rulenr = htonl(rm->nr); 266 1.1 itojun hdr.subrulenr = -1; 267 1.1 itojun } else { 268 1.1 itojun hdr.rulenr = htonl(am->nr); 269 1.1 itojun hdr.subrulenr = htonl(rm->nr); 270 1.5 yamt if (ruleset != NULL && ruleset->anchor != NULL) 271 1.5 yamt strlcpy(hdr.ruleset, ruleset->anchor->name, 272 1.1 itojun sizeof(hdr.ruleset)); 273 1.1 itojun } 274 1.12 yamt if (rm->log & PF_LOG_SOCKET_LOOKUP && !pd->lookup.done) 275 1.12 yamt pd->lookup.done = pf_socket_lookup(dir, pd); 276 1.12 yamt if (pd->lookup.done > 0) { 277 1.12 yamt hdr.uid = pd->lookup.uid; 278 1.12 yamt hdr.pid = pd->lookup.pid; 279 1.12 yamt } else { 280 1.12 yamt hdr.uid = UID_MAX; 281 1.12 yamt hdr.pid = NO_PID; 282 1.12 yamt } 283 1.12 yamt hdr.rule_uid = rm->cuid; 284 1.12 yamt hdr.rule_pid = rm->cpid; 285 1.1 itojun hdr.dir = dir; 286 1.1 itojun 287 1.1 itojun #ifdef INET 288 1.1 itojun if (af == AF_INET && dir == PF_OUT) { 289 1.1 itojun struct ip *ip; 290 1.1 itojun 291 1.1 itojun ip = mtod(m, struct ip *); 292 1.1 itojun ip->ip_sum = 0; 293 1.1 itojun ip->ip_sum = in_cksum(m, ip->ip_hl << 2); 294 1.1 itojun } 295 1.1 itojun #endif /* INET */ 296 1.1 itojun 297 1.22 thorpej #ifdef __NetBSD__ 298 1.22 thorpej if_statadd2(ifn, if_opackets, 1, if_obytes, m->m_pkthdr.len); 299 1.22 thorpej #else 300 1.12 yamt ifn->if_opackets++; 301 1.12 yamt ifn->if_obytes += m->m_pkthdr.len; 302 1.22 thorpej #endif /* __NetBSD__ */ 303 1.1 itojun 304 1.12 yamt #ifdef __NetBSD__ 305 1.21 msaitoh bpf_mtap2(ifn->if_bpf, &hdr, PFLOG_HDRLEN, m, BPF_D_OUT); 306 1.12 yamt #else 307 1.12 yamt bpf_mtap_hdr(ifn->if_bpf, (char *)&hdr, PFLOG_HDRLEN, m, 308 1.12 yamt BPF_DIRECTION_OUT); 309 1.12 yamt #endif /* !__NetBSD__ */ 310 1.1 itojun 311 1.1 itojun 312 1.1 itojun return (0); 313 1.1 itojun } 314