1 /* $OpenBSD: if_pflog.c,v 1.91 2020/08/28 12:01:48 mvs Exp $ */ 2 /* 3 * The authors of this code are John Ioannidis (ji@tla.org), 4 * Angelos D. Keromytis (kermit@csd.uch.gr) and 5 * Niels Provos (provos@physnet.uni-hamburg.de). 6 * 7 * This code was written by John Ioannidis for BSD/OS in Athens, Greece, 8 * in November 1995. 9 * 10 * Ported to OpenBSD and NetBSD, with additional transforms, in December 1996, 11 * by Angelos D. Keromytis. 12 * 13 * Additional transforms and features in 1997 and 1998 by Angelos D. Keromytis 14 * and Niels Provos. 15 * 16 * Copyright (C) 1995, 1996, 1997, 1998 by John Ioannidis, Angelos D. Keromytis 17 * and Niels Provos. 18 * Copyright (c) 2001, Angelos D. Keromytis, Niels Provos. 19 * Copyright (c) 2002 - 2010 Henning Brauer 20 * 21 * Permission to use, copy, and modify this software with or without fee 22 * is hereby granted, provided that this entire notice is included in 23 * all copies of any software which is or includes a copy or 24 * modification of this software. 25 * You may use this code under the GNU public license if you so wish. Please 26 * contribute changes back to the authors under this freer than GPL license 27 * so that we may further the use of strong encryption without limitations to 28 * all. 29 * 30 * THIS SOFTWARE IS BEING PROVIDED "AS IS", WITHOUT ANY EXPRESS OR 31 * IMPLIED WARRANTY. IN PARTICULAR, NONE OF THE AUTHORS MAKES ANY 32 * REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING THE 33 * MERCHANTABILITY OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR 34 * PURPOSE. 35 */ 36 37 #include "bpfilter.h" 38 #include "pflog.h" 39 40 #include <sys/param.h> 41 #include <sys/systm.h> 42 #include <sys/mbuf.h> 43 #include <sys/proc.h> 44 #include <sys/socket.h> 45 #include <sys/stdint.h> 46 #include <sys/ioctl.h> 47 48 #include <net/if.h> 49 #include <net/if_var.h> 50 #include <net/if_types.h> 51 #if NBPFILTER > 0 52 #include <net/bpf.h> 53 #endif 54 55 #include <netinet/in.h> 56 #include <netinet/ip.h> 57 #include <netinet/ip_icmp.h> 58 #include <netinet/tcp.h> 59 #include <netinet/udp.h> 60 61 #ifdef INET6 62 #include <netinet/ip6.h> 63 #include <netinet/icmp6.h> 64 #endif /* INET6 */ 65 66 #include <net/pfvar.h> 67 #include <net/pfvar_priv.h> 68 #include <net/if_pflog.h> 69 70 #define PFLOGMTU (32768 + MHLEN + MLEN) 71 72 #ifdef PFLOGDEBUG 73 #define DPRINTF(x) do { if (pflogdebug) printf x ; } while (0) 74 #else 75 #define DPRINTF(x) 76 #endif 77 78 void pflogattach(int); 79 int pflogifs_resize(size_t); 80 int pflogoutput(struct ifnet *, struct mbuf *, struct sockaddr *, 81 struct rtentry *); 82 int pflogioctl(struct ifnet *, u_long, caddr_t); 83 void pflogstart(struct ifnet *); 84 int pflog_clone_create(struct if_clone *, int); 85 int pflog_clone_destroy(struct ifnet *); 86 void pflog_mtap(caddr_t, struct pfloghdr *, struct mbuf *); 87 88 struct if_clone pflog_cloner = 89 IF_CLONE_INITIALIZER("pflog", pflog_clone_create, pflog_clone_destroy); 90 91 int npflogifs = 0; 92 struct ifnet **pflogifs = NULL; /* for fast access */ 93 94 void 95 pflogattach(int npflog) 96 { 97 if_clone_attach(&pflog_cloner); 98 } 99 100 int 101 pflogifs_resize(size_t n) 102 { 103 struct ifnet **p; 104 int i; 105 106 NET_ASSERT_LOCKED(); 107 108 if (n > SIZE_MAX / sizeof(*p)) 109 return (EINVAL); 110 if (n == 0) 111 p = NULL; 112 else 113 if ((p = mallocarray(n, sizeof(*p), M_DEVBUF, 114 M_NOWAIT|M_ZERO)) == NULL) 115 return (ENOMEM); 116 for (i = 0; i < n; i++) 117 if (i < npflogifs) 118 p[i] = pflogifs[i]; 119 else 120 p[i] = NULL; 121 122 free(pflogifs, M_DEVBUF, npflogifs * sizeof(*pflogifs)); 123 pflogifs = p; 124 npflogifs = n; 125 return (0); 126 } 127 128 int 129 pflog_clone_create(struct if_clone *ifc, int unit) 130 { 131 struct ifnet *ifp; 132 struct pflog_softc *pflogif; 133 134 pflogif = malloc(sizeof(*pflogif), M_DEVBUF, M_WAITOK|M_ZERO); 135 pflogif->sc_unit = unit; 136 ifp = &pflogif->sc_if; 137 snprintf(ifp->if_xname, sizeof ifp->if_xname, "pflog%d", unit); 138 ifp->if_softc = pflogif; 139 ifp->if_mtu = PFLOGMTU; 140 ifp->if_ioctl = pflogioctl; 141 ifp->if_output = pflogoutput; 142 ifp->if_start = pflogstart; 143 ifp->if_xflags = IFXF_CLONED; 144 ifp->if_type = IFT_PFLOG; 145 ifp->if_hdrlen = PFLOG_HDRLEN; 146 if_attach(ifp); 147 if_alloc_sadl(ifp); 148 149 #if NBPFILTER > 0 150 bpfattach(&pflogif->sc_if.if_bpf, ifp, DLT_PFLOG, PFLOG_HDRLEN); 151 #endif 152 153 NET_LOCK(); 154 if (unit + 1 > npflogifs && pflogifs_resize(unit + 1) != 0) { 155 NET_UNLOCK(); 156 return (ENOMEM); 157 } 158 pflogifs[unit] = ifp; 159 NET_UNLOCK(); 160 161 return (0); 162 } 163 164 int 165 pflog_clone_destroy(struct ifnet *ifp) 166 { 167 struct pflog_softc *pflogif = ifp->if_softc; 168 int i; 169 170 NET_LOCK(); 171 pflogifs[pflogif->sc_unit] = NULL; 172 for (i = npflogifs; i > 0 && pflogifs[i - 1] == NULL; i--) 173 ; /* nothing */ 174 if (i < npflogifs) 175 pflogifs_resize(i); /* error harmless here */ 176 NET_UNLOCK(); 177 178 if_detach(ifp); 179 free(pflogif, M_DEVBUF, sizeof(*pflogif)); 180 return (0); 181 } 182 183 /* 184 * Start output on the pflog interface. 185 */ 186 void 187 pflogstart(struct ifnet *ifp) 188 { 189 ifq_purge(&ifp->if_snd); 190 } 191 192 int 193 pflogoutput(struct ifnet *ifp, struct mbuf *m, struct sockaddr *dst, 194 struct rtentry *rt) 195 { 196 m_freem(m); /* drop packet */ 197 return (EAFNOSUPPORT); 198 } 199 200 int 201 pflogioctl(struct ifnet *ifp, u_long cmd, caddr_t data) 202 { 203 switch (cmd) { 204 case SIOCSIFFLAGS: 205 if (ifp->if_flags & IFF_UP) 206 ifp->if_flags |= IFF_RUNNING; 207 else 208 ifp->if_flags &= ~IFF_RUNNING; 209 break; 210 default: 211 return (ENOTTY); 212 } 213 214 return (0); 215 } 216 217 int 218 pflog_packet(struct pf_pdesc *pd, u_int8_t reason, struct pf_rule *rm, 219 struct pf_rule *am, struct pf_ruleset *ruleset, struct pf_rule *trigger) 220 { 221 #if NBPFILTER > 0 222 struct ifnet *ifn; 223 caddr_t if_bpf; 224 struct pfloghdr hdr; 225 226 if (rm == NULL || pd == NULL || pd->kif == NULL || pd->m == NULL) 227 return (-1); 228 if (trigger == NULL) 229 trigger = rm; 230 231 if (trigger->logif >= npflogifs) 232 return (0); 233 ifn = pflogifs[trigger->logif]; 234 if (ifn == NULL) 235 return (0); 236 if_bpf = ifn->if_bpf; 237 if (!if_bpf) 238 return (0); 239 240 bzero(&hdr, sizeof(hdr)); 241 hdr.length = PFLOG_REAL_HDRLEN; 242 hdr.action = rm->action; 243 hdr.reason = reason; 244 memcpy(hdr.ifname, pd->kif->pfik_name, sizeof(hdr.ifname)); 245 246 if (am == NULL) { 247 hdr.rulenr = htonl(rm->nr); 248 hdr.subrulenr = -1; 249 } else { 250 hdr.rulenr = htonl(am->nr); 251 hdr.subrulenr = htonl(rm->nr); 252 if (ruleset != NULL && ruleset->anchor != NULL) 253 strlcpy(hdr.ruleset, ruleset->anchor->name, 254 sizeof(hdr.ruleset)); 255 } 256 if (trigger->log & PF_LOG_SOCKET_LOOKUP && !pd->lookup.done) 257 pd->lookup.done = pf_socket_lookup(pd); 258 if (pd->lookup.done > 0) { 259 hdr.uid = pd->lookup.uid; 260 hdr.pid = pd->lookup.pid; 261 } else { 262 hdr.uid = -1; 263 hdr.pid = NO_PID; 264 } 265 hdr.rule_uid = rm->cuid; 266 hdr.rule_pid = rm->cpid; 267 hdr.dir = pd->dir; 268 269 pf_addrcpy(&hdr.saddr, &pd->nsaddr, pd->naf); 270 pf_addrcpy(&hdr.daddr, &pd->ndaddr, pd->naf); 271 hdr.af = pd->af; 272 hdr.naf = pd->naf; 273 hdr.sport = pd->nsport; 274 hdr.dport = pd->ndport; 275 276 ifn->if_opackets++; 277 ifn->if_obytes += pd->m->m_pkthdr.len; 278 279 pflog_mtap(if_bpf, &hdr, pd->m); 280 #endif 281 282 return (0); 283 } 284 285 void 286 pflog_mtap(caddr_t if_bpf, struct pfloghdr *pfloghdr, struct mbuf *m) 287 { 288 struct mbuf mhdr; 289 struct m_hdr mptr; 290 struct mbuf *mp; 291 u_char *mdst; 292 int afto, hlen, off; 293 294 struct pf_pdesc pd; 295 struct pf_addr osaddr, odaddr; 296 u_int16_t osport = 0, odport = 0; 297 u_int8_t proto = 0; 298 299 afto = pfloghdr->af != pfloghdr->naf; 300 301 /* 302 * temporary mbuf will hold an ip/ip6 header and 8 bytes 303 * of the protocol header 304 */ 305 m_inithdr(&mhdr); 306 mhdr.m_len = 0; /* XXX not done in m_inithdr() */ 307 308 #ifdef INET6 309 /* offset for a new header */ 310 if (afto && pfloghdr->af == AF_INET) 311 mhdr.m_data += sizeof(struct ip6_hdr) - 312 sizeof(struct ip); 313 #endif /* INET6 */ 314 315 mdst = mtod(&mhdr, char *); 316 switch (pfloghdr->af) { 317 case AF_INET: { 318 struct ip *h; 319 320 if (m->m_pkthdr.len < sizeof(*h)) 321 goto copy; 322 m_copydata(m, 0, sizeof(*h), mdst); 323 h = (struct ip *)mdst; 324 hlen = h->ip_hl << 2; 325 if (hlen > sizeof(*h) && (m->m_pkthdr.len >= hlen)) 326 m_copydata(m, sizeof(*h), hlen - sizeof(*h), 327 mdst + sizeof(*h)); 328 break; 329 } 330 #ifdef INET6 331 case AF_INET6: { 332 struct ip6_hdr *h; 333 334 if (m->m_pkthdr.len < sizeof(*h)) 335 goto copy; 336 hlen = sizeof(struct ip6_hdr); 337 m_copydata(m, 0, hlen, mdst); 338 h = (struct ip6_hdr *)mdst; 339 proto = h->ip6_nxt; 340 break; 341 } 342 #endif /* INET6 */ 343 default: 344 /* shouldn't happen ever :-) */ 345 goto copy; 346 } 347 348 if (m->m_pkthdr.len < hlen + 8 && proto != IPPROTO_NONE) 349 goto copy; 350 else if (proto != IPPROTO_NONE) { 351 /* copy 8 bytes of the protocol header */ 352 m_copydata(m, hlen, 8, mdst + hlen); 353 hlen += 8; 354 } 355 356 mhdr.m_len = hlen; 357 mhdr.m_pkthdr.len = hlen; 358 359 /* create a chain mhdr -> mptr, mptr->m_data = (m->m_data+hlen) */ 360 mp = m_getptr(m, hlen, &off); 361 if (mp != NULL) { 362 mptr.mh_flags = 0; 363 mptr.mh_data = mp->m_data + off; 364 mptr.mh_len = mp->m_len - off; 365 mptr.mh_next = mp->m_next; 366 367 mhdr.m_next = (struct mbuf *)&mptr; 368 } 369 370 /* 371 * Rewrite addresses if needed. Reason pointer must be NULL to avoid 372 * counting the packet here again. 373 */ 374 if (pf_setup_pdesc(&pd, pfloghdr->af, pfloghdr->dir, NULL, 375 &mhdr, NULL) != PF_PASS) 376 goto copy; 377 pd.naf = pfloghdr->naf; 378 379 pf_addrcpy(&osaddr, pd.src, pd.af); 380 pf_addrcpy(&odaddr, pd.dst, pd.af); 381 if (pd.sport) 382 osport = *pd.sport; 383 if (pd.dport) 384 odport = *pd.dport; 385 386 if (pd.virtual_proto != PF_VPROTO_FRAGMENT && 387 (pfloghdr->rewritten = pf_translate(&pd, &pfloghdr->saddr, 388 pfloghdr->sport, &pfloghdr->daddr, pfloghdr->dport, 0, 389 pfloghdr->dir))) { 390 m_copyback(pd.m, pd.off, min(pd.m->m_len - pd.off, pd.hdrlen), 391 &pd.hdr, M_NOWAIT); 392 #ifdef INET6 393 if (afto) { 394 pf_addrcpy(&pd.nsaddr, &pfloghdr->saddr, pd.naf); 395 pf_addrcpy(&pd.ndaddr, &pfloghdr->daddr, pd.naf); 396 } 397 #endif /* INET6 */ 398 pf_addrcpy(&pfloghdr->saddr, &osaddr, pd.af); 399 pf_addrcpy(&pfloghdr->daddr, &odaddr, pd.af); 400 pfloghdr->sport = osport; 401 pfloghdr->dport = odport; 402 } 403 404 pd.tot_len -= pd.m->m_data - pd.m->m_pktdat; 405 406 #ifdef INET6 407 if (afto && pfloghdr->rewritten) 408 pf_translate_af(&pd); 409 #endif /* INET6 */ 410 411 m = pd.m; 412 KASSERT(m == &mhdr); 413 copy: 414 #if NBPFILTER > 0 415 bpf_mtap_hdr(if_bpf, pfloghdr, sizeof(*pfloghdr), m, 416 BPF_DIRECTION_OUT); 417 #endif 418 return; 419 } 420