1 /* $OpenBSD: if_pflow.c,v 1.10 2009/02/27 11:09:36 gollo Exp $ */ 2 3 /* 4 * Copyright (c) 2008 Henning Brauer <henning@openbsd.org> 5 * Copyright (c) 2008 Joerg Goltermann <jg@osn.de> 6 * 7 * Permission to use, copy, modify, and distribute this software for any 8 * purpose with or without fee is hereby granted, provided that the above 9 * copyright notice and this permission notice appear in all copies. 10 * 11 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 12 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 13 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 14 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 15 * WHATSOEVER RESULTING FROM LOSS OF MIND, USE, DATA OR PROFITS, WHETHER IN 16 * AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT 17 * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 18 */ 19 20 #include <sys/types.h> 21 #include <sys/malloc.h> 22 #include <sys/param.h> 23 #include <sys/mbuf.h> 24 #include <sys/socket.h> 25 #include <sys/ioctl.h> 26 #include <sys/kernel.h> 27 #include <sys/sysctl.h> 28 #include <dev/rndvar.h> 29 30 #include <net/if.h> 31 #include <net/if_types.h> 32 #include <net/bpf.h> 33 #include <net/route.h> 34 #include <netinet/in.h> 35 #include <netinet/if_ether.h> 36 #include <netinet/tcp.h> 37 38 #ifdef INET 39 #include <netinet/in.h> 40 #include <netinet/in_var.h> 41 #include <netinet/in_systm.h> 42 #include <netinet/ip.h> 43 #include <netinet/ip_var.h> 44 #include <netinet/udp.h> 45 #include <netinet/udp_var.h> 46 #include <netinet/in_pcb.h> 47 #endif /* INET */ 48 49 #include <net/pfvar.h> 50 #include <net/if_pflow.h> 51 52 #include "bpfilter.h" 53 #include "pflow.h" 54 55 #define PFLOW_MINMTU \ 56 (sizeof(struct pflow_header) + sizeof(struct pflow_flow)) 57 58 #ifdef PFLOWDEBUG 59 #define DPRINTF(x) do { printf x ; } while (0) 60 #else 61 #define DPRINTF(x) 62 #endif 63 64 SLIST_HEAD(, pflow_softc) pflowif_list; 65 struct pflowstats pflowstats; 66 67 void pflowattach(int); 68 int pflow_clone_create(struct if_clone *, int); 69 int pflow_clone_destroy(struct ifnet *); 70 void pflow_setmtu(struct pflow_softc *, int); 71 int pflowoutput(struct ifnet *, struct mbuf *, struct sockaddr *, 72 struct rtentry *); 73 int pflowioctl(struct ifnet *, u_long, caddr_t); 74 void pflowstart(struct ifnet *); 75 76 struct mbuf *pflow_get_mbuf(struct pflow_softc *); 77 int pflow_sendout(struct pflow_softc *); 78 int pflow_sendout_mbuf(struct pflow_softc *, struct mbuf *); 79 void pflow_timeout(void *); 80 void copy_flow_data(struct pflow_flow *, struct pflow_flow *, 81 struct pf_state *, int, int); 82 int pflow_pack_flow(struct pf_state *, struct pflow_softc *); 83 int pflow_get_dynport(void); 84 int export_pflow_if(struct pf_state*, struct pflow_softc *); 85 int copy_flow_to_m(struct pflow_flow *flow, struct pflow_softc *sc); 86 87 struct if_clone pflow_cloner = 88 IF_CLONE_INITIALIZER("pflow", pflow_clone_create, 89 pflow_clone_destroy); 90 91 /* from in_pcb.c */ 92 extern int ipport_hifirstauto; 93 extern int ipport_hilastauto; 94 95 /* from kern/kern_clock.c; incremented each clock tick. */ 96 extern int ticks; 97 98 void 99 pflowattach(int npflow) 100 { 101 SLIST_INIT(&pflowif_list); 102 if_clone_attach(&pflow_cloner); 103 } 104 105 int 106 pflow_clone_create(struct if_clone *ifc, int unit) 107 { 108 struct ifnet *ifp; 109 struct pflow_softc *pflowif; 110 111 if ((pflowif = malloc(sizeof(*pflowif), 112 M_DEVBUF, M_NOWAIT|M_ZERO)) == NULL) 113 return (ENOMEM); 114 115 pflowif->sc_sender_ip.s_addr = INADDR_ANY; 116 pflowif->sc_sender_port = pflow_get_dynport(); 117 118 pflowif->sc_imo.imo_membership = malloc( 119 (sizeof(struct in_multi *) * IP_MIN_MEMBERSHIPS), M_IPMOPTS, 120 M_WAITOK|M_ZERO); 121 pflowif->sc_imo.imo_max_memberships = IP_MIN_MEMBERSHIPS; 122 pflowif->sc_receiver_ip.s_addr = 0; 123 pflowif->sc_receiver_port = 0; 124 pflowif->sc_sender_ip.s_addr = INADDR_ANY; 125 pflowif->sc_sender_port = pflow_get_dynport(); 126 ifp = &pflowif->sc_if; 127 snprintf(ifp->if_xname, sizeof ifp->if_xname, "pflow%d", unit); 128 ifp->if_softc = pflowif; 129 ifp->if_ioctl = pflowioctl; 130 ifp->if_output = pflowoutput; 131 ifp->if_start = pflowstart; 132 ifp->if_type = IFT_PFLOW; 133 ifp->if_snd.ifq_maxlen = ifqmaxlen; 134 ifp->if_hdrlen = PFLOW_HDRLEN; 135 ifp->if_flags = IFF_UP; 136 ifp->if_flags &= ~IFF_RUNNING; /* not running, need receiver */ 137 pflow_setmtu(pflowif, ETHERMTU); 138 timeout_set(&pflowif->sc_tmo, pflow_timeout, pflowif); 139 if_attach(ifp); 140 if_alloc_sadl(ifp); 141 142 #if NBPFILTER > 0 143 bpfattach(&pflowif->sc_if.if_bpf, ifp, DLT_RAW, 0); 144 #endif 145 146 /* Insert into list of pflows */ 147 SLIST_INSERT_HEAD(&pflowif_list, pflowif, sc_next); 148 return (0); 149 } 150 151 int 152 pflow_clone_destroy(struct ifnet *ifp) 153 { 154 struct pflow_softc *sc = ifp->if_softc; 155 int s; 156 157 s = splnet(); 158 pflow_sendout(sc); 159 #if NBPFILTER > 0 160 bpfdetach(ifp); 161 #endif 162 if_detach(ifp); 163 SLIST_REMOVE(&pflowif_list, sc, pflow_softc, sc_next); 164 free(sc->sc_imo.imo_membership, M_IPMOPTS); 165 free(sc, M_DEVBUF); 166 splx(s); 167 return (0); 168 } 169 170 /* 171 * Start output on the pflow interface. 172 */ 173 void 174 pflowstart(struct ifnet *ifp) 175 { 176 struct mbuf *m; 177 int s; 178 179 for (;;) { 180 s = splnet(); 181 IF_DROP(&ifp->if_snd); 182 IF_DEQUEUE(&ifp->if_snd, m); 183 splx(s); 184 185 if (m == NULL) 186 return; 187 m_freem(m); 188 } 189 } 190 191 int 192 pflowoutput(struct ifnet *ifp, struct mbuf *m, struct sockaddr *dst, 193 struct rtentry *rt) 194 { 195 m_freem(m); 196 return (0); 197 } 198 199 /* ARGSUSED */ 200 int 201 pflowioctl(struct ifnet *ifp, u_long cmd, caddr_t data) 202 { 203 struct proc *p = curproc; 204 struct pflow_softc *sc = ifp->if_softc; 205 struct ifreq *ifr = (struct ifreq *)data; 206 struct pflowreq pflowr; 207 int s, error; 208 209 switch (cmd) { 210 case SIOCSIFADDR: 211 case SIOCAIFADDR: 212 case SIOCSIFDSTADDR: 213 case SIOCSIFFLAGS: 214 if ((ifp->if_flags & IFF_UP) && 215 sc->sc_receiver_ip.s_addr != 0 && 216 sc->sc_receiver_port != 0) { 217 ifp->if_flags |= IFF_RUNNING; 218 sc->sc_gcounter=pflowstats.pflow_flows; 219 } else 220 ifp->if_flags &= ~IFF_RUNNING; 221 break; 222 case SIOCSIFMTU: 223 if (ifr->ifr_mtu < PFLOW_MINMTU) 224 return (EINVAL); 225 if (ifr->ifr_mtu > MCLBYTES) 226 ifr->ifr_mtu = MCLBYTES; 227 s = splnet(); 228 if (ifr->ifr_mtu < ifp->if_mtu) 229 pflow_sendout(sc); 230 pflow_setmtu(sc, ifr->ifr_mtu); 231 splx(s); 232 break; 233 234 case SIOCGETPFLOW: 235 bzero(&pflowr, sizeof(pflowr)); 236 237 pflowr.sender_ip = sc->sc_sender_ip; 238 pflowr.receiver_ip = sc->sc_receiver_ip; 239 pflowr.receiver_port = sc->sc_receiver_port; 240 241 if ((error = copyout(&pflowr, ifr->ifr_data, 242 sizeof(pflowr)))) 243 return (error); 244 break; 245 246 case SIOCSETPFLOW: 247 if ((error = suser(p, p->p_acflag)) != 0) 248 return (error); 249 if ((error = copyin(ifr->ifr_data, &pflowr, 250 sizeof(pflowr)))) 251 return (error); 252 253 s = splnet(); 254 pflow_sendout(sc); 255 splx(s); 256 257 if (pflowr.addrmask & PFLOW_MASK_DSTIP) 258 sc->sc_receiver_ip = pflowr.receiver_ip; 259 if (pflowr.addrmask & PFLOW_MASK_DSTPRT) 260 sc->sc_receiver_port = pflowr.receiver_port; 261 if (pflowr.addrmask & PFLOW_MASK_SRCIP) 262 sc->sc_sender_ip.s_addr = pflowr.sender_ip.s_addr; 263 264 if ((ifp->if_flags & IFF_UP) && 265 sc->sc_receiver_ip.s_addr != 0 && 266 sc->sc_receiver_port != 0) { 267 ifp->if_flags |= IFF_RUNNING; 268 sc->sc_gcounter=pflowstats.pflow_flows; 269 } else 270 ifp->if_flags &= ~IFF_RUNNING; 271 272 break; 273 274 default: 275 return (ENOTTY); 276 } 277 return (0); 278 } 279 280 void 281 pflow_setmtu(struct pflow_softc *sc, int mtu_req) 282 { 283 int mtu; 284 285 if (sc->sc_pflow_ifp && sc->sc_pflow_ifp->if_mtu < mtu_req) 286 mtu = sc->sc_pflow_ifp->if_mtu; 287 else 288 mtu = mtu_req; 289 290 sc->sc_maxcount = (mtu - sizeof(struct pflow_header) - 291 sizeof (struct udpiphdr)) / sizeof(struct pflow_flow); 292 if (sc->sc_maxcount > PFLOW_MAXFLOWS) 293 sc->sc_maxcount = PFLOW_MAXFLOWS; 294 sc->sc_if.if_mtu = sizeof(struct pflow_header) + 295 sizeof (struct udpiphdr) + 296 sc->sc_maxcount * sizeof(struct pflow_flow); 297 } 298 299 struct mbuf * 300 pflow_get_mbuf(struct pflow_softc *sc) 301 { 302 struct pflow_header h; 303 struct mbuf *m; 304 305 MGETHDR(m, M_DONTWAIT, MT_DATA); 306 if (m == NULL) { 307 pflowstats.pflow_onomem++; 308 return (NULL); 309 } 310 311 MCLGET(m, M_DONTWAIT); 312 if ((m->m_flags & M_EXT) == 0) { 313 m_free(m); 314 pflowstats.pflow_onomem++; 315 return (NULL); 316 } 317 318 m->m_len = m->m_pkthdr.len = 0; 319 m->m_pkthdr.rcvif = NULL; 320 321 /* populate pflow_header */ 322 h.reserved1 = 0; 323 h.reserved2 = 0; 324 h.count = 0; 325 h.version = htons(PFLOW_VERSION); 326 h.flow_sequence = htonl(sc->sc_gcounter); 327 h.engine_type = PFLOW_ENGINE_TYPE; 328 h.engine_id = PFLOW_ENGINE_ID; 329 m_copyback(m, 0, PFLOW_HDRLEN, &h); 330 331 sc->sc_count = 0; 332 timeout_add_sec(&sc->sc_tmo, PFLOW_TIMEOUT); 333 return (m); 334 } 335 336 void 337 copy_flow_data(struct pflow_flow *flow1, struct pflow_flow *flow2, 338 struct pf_state *st, int src, int dst) 339 { 340 struct pf_state_key *sk = st->key[PF_SK_WIRE]; 341 342 flow1->src_ip = flow2->dest_ip = sk->addr[src].v4.s_addr; 343 flow1->src_port = flow2->dest_port = sk->port[src]; 344 flow1->dest_ip = flow2->src_ip = sk->addr[dst].v4.s_addr; 345 flow1->dest_port = flow2->src_port = sk->port[dst]; 346 347 flow1->dest_as = flow2->src_as = 348 flow1->src_as = flow2->dest_as = 0; 349 flow1->if_index_out = flow2->if_index_in = 350 flow1->if_index_in = flow2->if_index_out = 0; 351 flow1->dest_mask = flow2->src_mask = 352 flow1->src_mask = flow2->dest_mask = 0; 353 354 flow1->flow_packets = htonl(st->packets[0]); 355 flow2->flow_packets = htonl(st->packets[1]); 356 flow1->flow_octets = htonl(st->bytes[0]); 357 flow2->flow_octets = htonl(st->bytes[1]); 358 359 flow1->flow_start = flow2->flow_start = htonl(st->creation * 1000); 360 flow1->flow_finish = flow2->flow_finish = htonl(time_second * 1000); 361 flow1->tcp_flags = flow2->tcp_flags = 0; 362 flow1->protocol = flow2->protocol = sk->proto; 363 flow1->tos = flow2->tos = st->rule.ptr->tos; 364 } 365 366 int 367 export_pflow(struct pf_state *st) 368 { 369 struct pflow_softc *sc = NULL; 370 struct pf_state_key *sk = st->key[PF_SK_WIRE]; 371 372 if (sk->af != AF_INET) 373 return (0); 374 375 SLIST_FOREACH(sc, &pflowif_list, sc_next) { 376 export_pflow_if(st, sc); 377 } 378 379 return (0); 380 } 381 382 int 383 export_pflow_if(struct pf_state *st, struct pflow_softc *sc) 384 { 385 struct pf_state pfs_copy; 386 struct ifnet *ifp = &sc->sc_if; 387 u_int64_t bytes[2]; 388 int ret = 0; 389 390 if (!(ifp->if_flags & IFF_RUNNING)) 391 return (0); 392 393 if ((st->bytes[0] < (u_int64_t)PFLOW_MAXBYTES) 394 && (st->bytes[1] < (u_int64_t)PFLOW_MAXBYTES)) 395 return (pflow_pack_flow(st, sc)); 396 397 /* flow > PFLOW_MAXBYTES need special handling */ 398 bcopy(st, &pfs_copy, sizeof(pfs_copy)); 399 bytes[0] = pfs_copy.bytes[0]; 400 bytes[1] = pfs_copy.bytes[1]; 401 402 while (bytes[0] > PFLOW_MAXBYTES) { 403 pfs_copy.bytes[0] = PFLOW_MAXBYTES; 404 pfs_copy.bytes[1] = 0; 405 406 if ((ret = pflow_pack_flow(&pfs_copy, sc)) != 0) 407 return (ret); 408 if ((bytes[0] - PFLOW_MAXBYTES) > 0) 409 bytes[0] -= PFLOW_MAXBYTES; 410 } 411 412 while (bytes[1] > (u_int64_t)PFLOW_MAXBYTES) { 413 pfs_copy.bytes[1] = PFLOW_MAXBYTES; 414 pfs_copy.bytes[0] = 0; 415 416 if ((ret = pflow_pack_flow(&pfs_copy, sc)) != 0) 417 return (ret); 418 if ((bytes[1] - PFLOW_MAXBYTES) > 0) 419 bytes[1] -= PFLOW_MAXBYTES; 420 } 421 422 pfs_copy.bytes[0] = bytes[0]; 423 pfs_copy.bytes[1] = bytes[1]; 424 425 return (pflow_pack_flow(&pfs_copy, sc)); 426 } 427 428 int 429 copy_flow_to_m(struct pflow_flow *flow, struct pflow_softc *sc) 430 { 431 int s, ret = 0; 432 433 s = splnet(); 434 if (sc->sc_mbuf == NULL) { 435 if ((sc->sc_mbuf = pflow_get_mbuf(sc)) == NULL) { 436 splx(s); 437 return (ENOBUFS); 438 } 439 } 440 m_copyback(sc->sc_mbuf, PFLOW_HDRLEN + 441 (sc->sc_count * sizeof (struct pflow_flow)), 442 sizeof (struct pflow_flow), flow); 443 444 if (pflowstats.pflow_flows == sc->sc_gcounter) 445 pflowstats.pflow_flows++; 446 sc->sc_gcounter++; 447 sc->sc_count++; 448 449 if (sc->sc_count >= sc->sc_maxcount) 450 ret = pflow_sendout(sc); 451 452 splx(s); 453 return(ret); 454 } 455 456 int 457 pflow_pack_flow(struct pf_state *st, struct pflow_softc *sc) 458 { 459 struct pflow_flow flow1; 460 struct pflow_flow flow2; 461 int ret = 0; 462 463 bzero(&flow1, sizeof(flow1)); 464 bzero(&flow2, sizeof(flow2)); 465 466 if (st->direction == PF_OUT) 467 copy_flow_data(&flow1, &flow2, st, 1, 0); 468 else 469 copy_flow_data(&flow1, &flow2, st, 0, 1); 470 471 if (st->bytes[0] != 0) /* first flow from state */ 472 ret = copy_flow_to_m(&flow1, sc); 473 474 if (st->bytes[1] != 0) /* second flow from state */ 475 ret = copy_flow_to_m(&flow2, sc); 476 477 return (ret); 478 } 479 480 void 481 pflow_timeout(void *v) 482 { 483 struct pflow_softc *sc = v; 484 int s; 485 486 s = splnet(); 487 pflow_sendout(sc); 488 splx(s); 489 } 490 491 /* This must be called in splnet() */ 492 int 493 pflow_sendout(struct pflow_softc *sc) 494 { 495 struct mbuf *m = sc->sc_mbuf; 496 struct pflow_header *h; 497 struct ifnet *ifp = &sc->sc_if; 498 499 timeout_del(&sc->sc_tmo); 500 501 if (m == NULL) 502 return (0); 503 504 sc->sc_mbuf = NULL; 505 if (!(ifp->if_flags & IFF_RUNNING)) { 506 m_freem(m); 507 return (0); 508 } 509 510 pflowstats.pflow_packets++; 511 h = mtod(m, struct pflow_header *); 512 h->count = htons(sc->sc_count); 513 514 /* populate pflow_header */ 515 h->uptime_ms = htonl(time_uptime * 1000); 516 h->time_sec = htonl(time_second); 517 h->time_nanosec = htonl(ticks); 518 519 return (pflow_sendout_mbuf(sc, m)); 520 } 521 522 int 523 pflow_sendout_mbuf(struct pflow_softc *sc, struct mbuf *m) 524 { 525 struct udpiphdr *ui; 526 u_int16_t len = m->m_pkthdr.len; 527 struct ifnet *ifp = &sc->sc_if; 528 struct ip *ip; 529 int err; 530 531 /* UDP Header*/ 532 M_PREPEND(m, sizeof(struct udpiphdr), M_DONTWAIT); 533 if (m == NULL) { 534 pflowstats.pflow_onomem++; 535 return (ENOBUFS); 536 } 537 538 ui = mtod(m, struct udpiphdr *); 539 ui->ui_pr = IPPROTO_UDP; 540 ui->ui_src = sc->sc_sender_ip; 541 ui->ui_sport = sc->sc_sender_port; 542 ui->ui_dst = sc->sc_receiver_ip; 543 ui->ui_dport = sc->sc_receiver_port; 544 ui->ui_ulen = htons(sizeof (struct udphdr) + len); 545 546 ip = (struct ip *)ui; 547 ip->ip_v = IPVERSION; 548 ip->ip_hl = sizeof(struct ip) >> 2; 549 ip->ip_id = htons(ip_randomid()); 550 ip->ip_off = htons(IP_DF); 551 ip->ip_tos = IPTOS_LOWDELAY; 552 ip->ip_ttl = IPDEFTTL; 553 ip->ip_len = htons(sizeof (struct udpiphdr) + len); 554 555 /* 556 * Compute the pseudo-header checksum; defer further checksumming 557 * until ip_output() or hardware (if it exists). 558 */ 559 m->m_pkthdr.csum_flags |= M_UDPV4_CSUM_OUT; 560 ui->ui_sum = in_cksum_phdr(ui->ui_src.s_addr, 561 ui->ui_dst.s_addr, htons(len + sizeof(struct udphdr) + 562 IPPROTO_UDP)); 563 564 #if NBPFILTER > 0 565 if (ifp->if_bpf) { 566 ip->ip_sum = in_cksum(m, ip->ip_hl << 2); 567 bpf_mtap(ifp->if_bpf, m, BPF_DIRECTION_OUT); 568 } 569 #endif 570 571 sc->sc_if.if_opackets++; 572 sc->sc_if.if_obytes += m->m_pkthdr.len; 573 574 if ((err = ip_output(m, NULL, NULL, IP_RAWOUTPUT, &sc->sc_imo, NULL))) { 575 pflowstats.pflow_oerrors++; 576 sc->sc_if.if_oerrors++; 577 } 578 return (err); 579 } 580 581 int 582 pflow_get_dynport(void) 583 { 584 u_int16_t tmp, low, high, cut; 585 586 low = ipport_hifirstauto; /* sysctl */ 587 high = ipport_hilastauto; 588 589 cut = arc4random_uniform(1 + high - low) + low; 590 591 for (tmp = cut; tmp <= high; ++(tmp)) { 592 if (!in_baddynamic(tmp, IPPROTO_UDP)) 593 return (htons(tmp)); 594 } 595 596 for (tmp = cut - 1; tmp >= low; --(tmp)) { 597 if (!in_baddynamic(tmp, IPPROTO_UDP)) 598 return (htons(tmp)); 599 } 600 601 return (htons(ipport_hilastauto)); /* XXX */ 602 } 603 604 int 605 pflow_sysctl(int *name, u_int namelen, void *oldp, size_t *oldlenp, 606 void *newp, size_t newlen) 607 { 608 if (namelen != 1) 609 return (ENOTDIR); 610 611 switch (name[0]) { 612 case NET_PFLOW_STATS: 613 if (newp != NULL) 614 return (EPERM); 615 return (sysctl_struct(oldp, oldlenp, newp, newlen, 616 &pflowstats, sizeof(pflowstats))); 617 default: 618 return (EOPNOTSUPP); 619 } 620 return (0); 621 } 622