1 /* $OpenBSD: if_pflog.c,v 1.86 2019/10/17 11:23:49 millert 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 #include <net/bpf.h> 52 53 #include <netinet/in.h> 54 #include <netinet/ip.h> 55 #include <netinet/ip_icmp.h> 56 #include <netinet/tcp.h> 57 #include <netinet/udp.h> 58 59 #ifdef INET6 60 #include <netinet/ip6.h> 61 #include <netinet/icmp6.h> 62 #endif /* INET6 */ 63 64 #include <net/pfvar.h> 65 #include <net/pfvar_priv.h> 66 #include <net/if_pflog.h> 67 68 #define PFLOGMTU (32768 + MHLEN + MLEN) 69 70 #ifdef PFLOGDEBUG 71 #define DPRINTF(x) do { if (pflogdebug) printf x ; } while (0) 72 #else 73 #define DPRINTF(x) 74 #endif 75 76 void pflogattach(int); 77 int pflogifs_resize(size_t); 78 int pflogoutput(struct ifnet *, struct mbuf *, struct sockaddr *, 79 struct rtentry *); 80 int pflogioctl(struct ifnet *, u_long, caddr_t); 81 void pflogstart(struct ifnet *); 82 int pflog_clone_create(struct if_clone *, int); 83 int pflog_clone_destroy(struct ifnet *); 84 void pflog_mtap(caddr_t, struct pfloghdr *, struct mbuf *); 85 86 struct if_clone pflog_cloner = 87 IF_CLONE_INITIALIZER("pflog", pflog_clone_create, pflog_clone_destroy); 88 89 int npflogifs = 0; 90 struct ifnet **pflogifs = NULL; /* for fast access */ 91 struct mbuf *pflog_mhdr = NULL, *pflog_mptr = NULL; 92 93 void 94 pflogattach(int npflog) 95 { 96 if (pflog_mhdr == NULL) 97 if ((pflog_mhdr = m_get(M_DONTWAIT, MT_HEADER)) == NULL) 98 panic("pflogattach: no mbuf"); 99 if (pflog_mptr == NULL) 100 if ((pflog_mptr = m_get(M_DONTWAIT, MT_DATA)) == NULL) 101 panic("pflogattach: no mbuf"); 102 if_clone_attach(&pflog_cloner); 103 } 104 105 int 106 pflogifs_resize(size_t n) 107 { 108 struct ifnet **p; 109 int i; 110 111 NET_ASSERT_LOCKED(); 112 113 if (n > SIZE_MAX / sizeof(*p)) 114 return (EINVAL); 115 if (n == 0) 116 p = NULL; 117 else 118 if ((p = mallocarray(n, sizeof(*p), M_DEVBUF, 119 M_NOWAIT|M_ZERO)) == NULL) 120 return (ENOMEM); 121 for (i = 0; i < n; i++) 122 if (i < npflogifs) 123 p[i] = pflogifs[i]; 124 else 125 p[i] = NULL; 126 127 free(pflogifs, M_DEVBUF, npflogifs * sizeof(*pflogifs)); 128 pflogifs = p; 129 npflogifs = n; 130 return (0); 131 } 132 133 int 134 pflog_clone_create(struct if_clone *ifc, int unit) 135 { 136 struct ifnet *ifp; 137 struct pflog_softc *pflogif; 138 139 pflogif = malloc(sizeof(*pflogif), M_DEVBUF, M_WAITOK|M_ZERO); 140 pflogif->sc_unit = unit; 141 ifp = &pflogif->sc_if; 142 snprintf(ifp->if_xname, sizeof ifp->if_xname, "pflog%d", unit); 143 ifp->if_softc = pflogif; 144 ifp->if_mtu = PFLOGMTU; 145 ifp->if_ioctl = pflogioctl; 146 ifp->if_output = pflogoutput; 147 ifp->if_start = pflogstart; 148 ifp->if_xflags = IFXF_CLONED; 149 ifp->if_type = IFT_PFLOG; 150 IFQ_SET_MAXLEN(&ifp->if_snd, IFQ_MAXLEN); 151 ifp->if_hdrlen = PFLOG_HDRLEN; 152 if_attach(ifp); 153 if_alloc_sadl(ifp); 154 155 #if NBPFILTER > 0 156 bpfattach(&pflogif->sc_if.if_bpf, ifp, DLT_PFLOG, PFLOG_HDRLEN); 157 #endif 158 159 NET_LOCK(); 160 if (unit + 1 > npflogifs && pflogifs_resize(unit + 1) != 0) { 161 NET_UNLOCK(); 162 return (ENOMEM); 163 } 164 pflogifs[unit] = ifp; 165 NET_UNLOCK(); 166 167 return (0); 168 } 169 170 int 171 pflog_clone_destroy(struct ifnet *ifp) 172 { 173 struct pflog_softc *pflogif = ifp->if_softc; 174 int i; 175 176 NET_LOCK(); 177 pflogifs[pflogif->sc_unit] = NULL; 178 for (i = npflogifs; i > 0 && pflogifs[i - 1] == NULL; i--) 179 ; /* nothing */ 180 if (i < npflogifs) 181 pflogifs_resize(i); /* error harmless here */ 182 NET_UNLOCK(); 183 184 if_detach(ifp); 185 free(pflogif, M_DEVBUF, sizeof(*pflogif)); 186 return (0); 187 } 188 189 /* 190 * Start output on the pflog interface. 191 */ 192 void 193 pflogstart(struct ifnet *ifp) 194 { 195 IFQ_PURGE(&ifp->if_snd); 196 } 197 198 int 199 pflogoutput(struct ifnet *ifp, struct mbuf *m, struct sockaddr *dst, 200 struct rtentry *rt) 201 { 202 m_freem(m); /* drop packet */ 203 return (EAFNOSUPPORT); 204 } 205 206 int 207 pflogioctl(struct ifnet *ifp, u_long cmd, caddr_t data) 208 { 209 switch (cmd) { 210 case SIOCSIFFLAGS: 211 if (ifp->if_flags & IFF_UP) 212 ifp->if_flags |= IFF_RUNNING; 213 else 214 ifp->if_flags &= ~IFF_RUNNING; 215 break; 216 default: 217 return (ENOTTY); 218 } 219 220 return (0); 221 } 222 223 int 224 pflog_packet(struct pf_pdesc *pd, u_int8_t reason, struct pf_rule *rm, 225 struct pf_rule *am, struct pf_ruleset *ruleset, struct pf_rule *trigger) 226 { 227 #if NBPFILTER > 0 228 struct ifnet *ifn; 229 caddr_t if_bpf; 230 struct pfloghdr hdr; 231 232 if (rm == NULL || pd == NULL || pd->kif == NULL || pd->m == NULL) 233 return (-1); 234 if (trigger == NULL) 235 trigger = rm; 236 237 if (trigger->logif >= npflogifs) 238 return (0); 239 ifn = pflogifs[trigger->logif]; 240 if (ifn == NULL) 241 return (0); 242 if_bpf = ifn->if_bpf; 243 if (!if_bpf) 244 return (0); 245 246 bzero(&hdr, sizeof(hdr)); 247 hdr.length = PFLOG_REAL_HDRLEN; 248 hdr.action = rm->action; 249 hdr.reason = reason; 250 memcpy(hdr.ifname, pd->kif->pfik_name, sizeof(hdr.ifname)); 251 252 if (am == NULL) { 253 hdr.rulenr = htonl(rm->nr); 254 hdr.subrulenr = -1; 255 } else { 256 hdr.rulenr = htonl(am->nr); 257 hdr.subrulenr = htonl(rm->nr); 258 if (ruleset != NULL && ruleset->anchor != NULL) 259 strlcpy(hdr.ruleset, ruleset->anchor->name, 260 sizeof(hdr.ruleset)); 261 } 262 if (trigger->log & PF_LOG_SOCKET_LOOKUP && !pd->lookup.done) 263 pd->lookup.done = pf_socket_lookup(pd); 264 if (pd->lookup.done > 0) { 265 hdr.uid = pd->lookup.uid; 266 hdr.pid = pd->lookup.pid; 267 } else { 268 hdr.uid = -1; 269 hdr.pid = NO_PID; 270 } 271 hdr.rule_uid = rm->cuid; 272 hdr.rule_pid = rm->cpid; 273 hdr.dir = pd->dir; 274 275 pf_addrcpy(&hdr.saddr, &pd->nsaddr, pd->naf); 276 pf_addrcpy(&hdr.daddr, &pd->ndaddr, pd->naf); 277 hdr.af = pd->af; 278 hdr.naf = pd->naf; 279 hdr.sport = pd->nsport; 280 hdr.dport = pd->ndport; 281 282 ifn->if_opackets++; 283 ifn->if_obytes += pd->m->m_pkthdr.len; 284 285 pflog_mtap(if_bpf, &hdr, pd->m); 286 #endif 287 288 return (0); 289 } 290 291 void 292 pflog_mtap(caddr_t if_bpf, struct pfloghdr *pfloghdr, struct mbuf *m) 293 { 294 struct mbuf *mp, *mhdr, *mptr; 295 u_char *mdst; 296 int afto, hlen, off; 297 298 struct pf_pdesc pd; 299 struct pf_addr osaddr, odaddr; 300 u_int16_t osport = 0, odport = 0; 301 u_int8_t proto = 0; 302 303 mhdr = pflog_mhdr; 304 mptr = pflog_mptr; 305 306 afto = pfloghdr->af != pfloghdr->naf; 307 308 /* 309 * temporary mbuf will hold an ip/ip6 header and 8 bytes 310 * of the protocol header 311 */ 312 m_inithdr(mhdr); 313 mhdr->m_len = 0; /* XXX not done in m_inithdr() */ 314 315 #ifdef INET6 316 /* offset for a new header */ 317 if (afto && pfloghdr->af == AF_INET) 318 mhdr->m_data += sizeof(struct ip6_hdr) - 319 sizeof(struct ip); 320 #endif /* INET6 */ 321 322 mdst = mtod(mhdr, char *); 323 switch (pfloghdr->af) { 324 case AF_INET: { 325 struct ip *h; 326 327 if (m->m_pkthdr.len < sizeof(*h)) 328 goto copy; 329 m_copydata(m, 0, sizeof(*h), mdst); 330 h = (struct ip *)mdst; 331 hlen = h->ip_hl << 2; 332 if (hlen > sizeof(*h) && (m->m_pkthdr.len >= hlen)) 333 m_copydata(m, sizeof(*h), hlen - sizeof(*h), 334 mdst + sizeof(*h)); 335 break; 336 } 337 #ifdef INET6 338 case AF_INET6: { 339 struct ip6_hdr *h; 340 341 if (m->m_pkthdr.len < sizeof(*h)) 342 goto copy; 343 hlen = sizeof(struct ip6_hdr); 344 m_copydata(m, 0, hlen, mdst); 345 h = (struct ip6_hdr *)mdst; 346 proto = h->ip6_nxt; 347 break; 348 } 349 #endif /* INET6 */ 350 default: 351 /* shouldn't happen ever :-) */ 352 goto copy; 353 } 354 355 if (m->m_pkthdr.len < hlen + 8 && proto != IPPROTO_NONE) 356 goto copy; 357 else if (proto != IPPROTO_NONE) { 358 /* copy 8 bytes of the protocol header */ 359 m_copydata(m, hlen, 8, mdst + hlen); 360 hlen += 8; 361 } 362 363 mhdr->m_len += hlen; 364 mhdr->m_pkthdr.len = mhdr->m_len; 365 366 /* create a chain mhdr -> mptr, mptr->m_data = (m->m_data+hlen) */ 367 mp = m_getptr(m, hlen, &off); 368 if (mp != NULL) { 369 bcopy(mp, mptr, sizeof(*mptr)); 370 mptr->m_data += off; 371 mptr->m_len -= off; 372 mptr->m_flags &= ~M_PKTHDR; 373 mhdr->m_next = mptr; 374 mhdr->m_pkthdr.len += m->m_pkthdr.len - hlen; 375 } 376 377 /* 378 * Rewrite addresses if needed. Reason pointer must be NULL to avoid 379 * counting the packet here again. 380 */ 381 if (pf_setup_pdesc(&pd, pfloghdr->af, pfloghdr->dir, NULL, 382 mhdr, NULL) != PF_PASS) 383 goto copy; 384 pd.naf = pfloghdr->naf; 385 386 pf_addrcpy(&osaddr, pd.src, pd.af); 387 pf_addrcpy(&odaddr, pd.dst, pd.af); 388 if (pd.sport) 389 osport = *pd.sport; 390 if (pd.dport) 391 odport = *pd.dport; 392 393 if (pd.virtual_proto != PF_VPROTO_FRAGMENT && 394 (pfloghdr->rewritten = pf_translate(&pd, &pfloghdr->saddr, 395 pfloghdr->sport, &pfloghdr->daddr, pfloghdr->dport, 0, 396 pfloghdr->dir))) { 397 m_copyback(pd.m, pd.off, min(pd.m->m_len - pd.off, pd.hdrlen), 398 &pd.hdr, M_NOWAIT); 399 #ifdef INET6 400 if (afto) { 401 pf_addrcpy(&pd.nsaddr, &pfloghdr->saddr, pd.naf); 402 pf_addrcpy(&pd.ndaddr, &pfloghdr->daddr, pd.naf); 403 } 404 #endif /* INET6 */ 405 pf_addrcpy(&pfloghdr->saddr, &osaddr, pd.af); 406 pf_addrcpy(&pfloghdr->daddr, &odaddr, pd.af); 407 pfloghdr->sport = osport; 408 pfloghdr->dport = odport; 409 } 410 411 pd.tot_len -= pd.m->m_data - pd.m->m_pktdat; 412 413 #ifdef INET6 414 if (afto && pfloghdr->rewritten) 415 pf_translate_af(&pd); 416 #endif /* INET6 */ 417 418 m = pd.m; 419 copy: 420 bpf_mtap_hdr(if_bpf, pfloghdr, sizeof(*pfloghdr), m, 421 BPF_DIRECTION_OUT); 422 } 423