1f92d9b1aSKristof Provost /* $OpenBSD: if_pflow.c,v 1.100 2023/11/09 08:53:20 mvs Exp $ */ 2f92d9b1aSKristof Provost 3f92d9b1aSKristof Provost /* 4f92d9b1aSKristof Provost * Copyright (c) 2023 Rubicon Communications, LLC (Netgate) 5f92d9b1aSKristof Provost * Copyright (c) 2011 Florian Obser <florian@narrans.de> 6f92d9b1aSKristof Provost * Copyright (c) 2011 Sebastian Benoit <benoit-lists@fb12.de> 7f92d9b1aSKristof Provost * Copyright (c) 2008 Henning Brauer <henning@openbsd.org> 8f92d9b1aSKristof Provost * Copyright (c) 2008 Joerg Goltermann <jg@osn.de> 9f92d9b1aSKristof Provost * 10f92d9b1aSKristof Provost * Permission to use, copy, modify, and distribute this software for any 11f92d9b1aSKristof Provost * purpose with or without fee is hereby granted, provided that the above 12f92d9b1aSKristof Provost * copyright notice and this permission notice appear in all copies. 13f92d9b1aSKristof Provost * 14f92d9b1aSKristof Provost * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 15f92d9b1aSKristof Provost * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 16f92d9b1aSKristof Provost * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 17f92d9b1aSKristof Provost * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 18f92d9b1aSKristof Provost * WHATSOEVER RESULTING FROM LOSS OF MIND, USE, DATA OR PROFITS, WHETHER IN 19f92d9b1aSKristof Provost * AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT 20f92d9b1aSKristof Provost * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 21f92d9b1aSKristof Provost */ 22f92d9b1aSKristof Provost 23f92d9b1aSKristof Provost #include <sys/cdefs.h> 24f92d9b1aSKristof Provost #include <sys/param.h> 25f92d9b1aSKristof Provost #include <sys/bus.h> 26f92d9b1aSKristof Provost #include <sys/callout.h> 27f92d9b1aSKristof Provost #include <sys/endian.h> 28f92d9b1aSKristof Provost #include <sys/interrupt.h> 2983641335SKristof Provost #include <sys/jail.h> 30f92d9b1aSKristof Provost #include <sys/kernel.h> 31f92d9b1aSKristof Provost #include <sys/malloc.h> 32f92d9b1aSKristof Provost #include <sys/module.h> 33f92d9b1aSKristof Provost #include <sys/mbuf.h> 34f92d9b1aSKristof Provost #include <sys/socket.h> 35f92d9b1aSKristof Provost #include <sys/socketvar.h> 36f92d9b1aSKristof Provost #include <sys/sockio.h> 37f92d9b1aSKristof Provost #include <sys/sysctl.h> 38f92d9b1aSKristof Provost #include <sys/systm.h> 39f92d9b1aSKristof Provost #include <sys/priv.h> 40f92d9b1aSKristof Provost 41f92d9b1aSKristof Provost #include <net/if.h> 42f92d9b1aSKristof Provost #include <net/if_types.h> 43f92d9b1aSKristof Provost #include <net/bpf.h> 44f92d9b1aSKristof Provost #include <net/route.h> 45f92d9b1aSKristof Provost #include <netinet/in.h> 46f92d9b1aSKristof Provost #include <netinet/if_ether.h> 47f92d9b1aSKristof Provost #include <netinet/tcp.h> 48f92d9b1aSKristof Provost 49f92d9b1aSKristof Provost #include <netinet/ip.h> 50f92d9b1aSKristof Provost #include <netinet/ip_icmp.h> 51f92d9b1aSKristof Provost #include <netinet/ip_var.h> 52f92d9b1aSKristof Provost #include <netinet/udp.h> 53f92d9b1aSKristof Provost #include <netinet/udp_var.h> 54f92d9b1aSKristof Provost #include <netinet/in_pcb.h> 55f92d9b1aSKristof Provost 56f92d9b1aSKristof Provost #include <netlink/netlink.h> 57f92d9b1aSKristof Provost #include <netlink/netlink_ctl.h> 58f92d9b1aSKristof Provost #include <netlink/netlink_generic.h> 59f92d9b1aSKristof Provost #include <netlink/netlink_message_writer.h> 60f92d9b1aSKristof Provost 61f92d9b1aSKristof Provost #include <net/pfvar.h> 62f92d9b1aSKristof Provost #include <net/pflow.h> 63f92d9b1aSKristof Provost #include "net/if_var.h" 64f92d9b1aSKristof Provost 65f92d9b1aSKristof Provost #define PFLOW_MINMTU \ 66f92d9b1aSKristof Provost (sizeof(struct pflow_header) + sizeof(struct pflow_flow)) 67f92d9b1aSKristof Provost 68f92d9b1aSKristof Provost #ifdef PFLOWDEBUG 69f92d9b1aSKristof Provost #define DPRINTF(x) do { printf x ; } while (0) 70f92d9b1aSKristof Provost #else 71f92d9b1aSKristof Provost #define DPRINTF(x) 72f92d9b1aSKristof Provost #endif 73f92d9b1aSKristof Provost 74fc6e5069SKristof Provost enum pflow_family_t { 75fc6e5069SKristof Provost PFLOW_INET, 76fc6e5069SKristof Provost PFLOW_INET6, 77fc6e5069SKristof Provost PFLOW_NAT4, 78fc6e5069SKristof Provost }; 79fc6e5069SKristof Provost 80f92d9b1aSKristof Provost static void pflow_output_process(void *); 81f92d9b1aSKristof Provost static int pflow_create(int); 82f92d9b1aSKristof Provost static int pflow_destroy(int, bool); 83f92d9b1aSKristof Provost static int pflow_calc_mtu(struct pflow_softc *, int, int); 84f92d9b1aSKristof Provost static void pflow_setmtu(struct pflow_softc *, int); 85f92d9b1aSKristof Provost static int pflowvalidsockaddr(const struct sockaddr *, int); 86f92d9b1aSKristof Provost 87f92d9b1aSKristof Provost static struct mbuf *pflow_get_mbuf(struct pflow_softc *, u_int16_t); 88f92d9b1aSKristof Provost static void pflow_flush(struct pflow_softc *); 89f92d9b1aSKristof Provost static int pflow_sendout_v5(struct pflow_softc *); 90fc6e5069SKristof Provost static int pflow_sendout_ipfix(struct pflow_softc *, enum pflow_family_t); 91f92d9b1aSKristof Provost static int pflow_sendout_ipfix_tmpl(struct pflow_softc *); 92f92d9b1aSKristof Provost static int pflow_sendout_mbuf(struct pflow_softc *, struct mbuf *); 932be6f757SKristof Provost static int sysctl_pflowstats(SYSCTL_HANDLER_ARGS); 94f92d9b1aSKristof Provost static void pflow_timeout(void *); 95f92d9b1aSKristof Provost static void pflow_timeout6(void *); 96f92d9b1aSKristof Provost static void pflow_timeout_tmpl(void *); 97fc6e5069SKristof Provost static void pflow_timeout_nat4(void *); 98f92d9b1aSKristof Provost static void copy_flow_data(struct pflow_flow *, struct pflow_flow *, 99baf9b6d0SKristof Provost const struct pf_kstate *, struct pf_state_key *, int, int); 100f92d9b1aSKristof Provost static void copy_flow_ipfix_4_data(struct pflow_ipfix_flow4 *, 101baf9b6d0SKristof Provost struct pflow_ipfix_flow4 *, const struct pf_kstate *, struct pf_state_key *, 102f92d9b1aSKristof Provost struct pflow_softc *, int, int); 103f92d9b1aSKristof Provost static void copy_flow_ipfix_6_data(struct pflow_ipfix_flow6 *, 104baf9b6d0SKristof Provost struct pflow_ipfix_flow6 *, const struct pf_kstate *, struct pf_state_key *, 105f92d9b1aSKristof Provost struct pflow_softc *, int, int); 106baf9b6d0SKristof Provost static int pflow_pack_flow(const struct pf_kstate *, struct pf_state_key *, 107f92d9b1aSKristof Provost struct pflow_softc *); 108baf9b6d0SKristof Provost static int pflow_pack_flow_ipfix(const struct pf_kstate *, struct pf_state_key *, 109f92d9b1aSKristof Provost struct pflow_softc *); 110baf9b6d0SKristof Provost static void export_pflow(const struct pf_kstate *); 111baf9b6d0SKristof Provost static int export_pflow_if(const struct pf_kstate*, struct pf_state_key *, 112f92d9b1aSKristof Provost struct pflow_softc *); 113f92d9b1aSKristof Provost static int copy_flow_to_m(struct pflow_flow *flow, struct pflow_softc *sc); 114f92d9b1aSKristof Provost static int copy_flow_ipfix_4_to_m(struct pflow_ipfix_flow4 *flow, 115f92d9b1aSKristof Provost struct pflow_softc *sc); 116f92d9b1aSKristof Provost static int copy_flow_ipfix_6_to_m(struct pflow_ipfix_flow6 *flow, 117f92d9b1aSKristof Provost struct pflow_softc *sc); 118fc6e5069SKristof Provost static int copy_nat_ipfix_4_to_m(struct pflow_ipfix_nat4 *, 119fc6e5069SKristof Provost const struct pf_kstate *, struct pflow_softc *, 120fc6e5069SKristof Provost uint8_t, uint64_t); 121f92d9b1aSKristof Provost 122f92d9b1aSKristof Provost static const char pflowname[] = "pflow"; 123f92d9b1aSKristof Provost 1242be6f757SKristof Provost enum pflowstat_counters { 1252be6f757SKristof Provost pflow_flows, 1262be6f757SKristof Provost pflow_packets, 1272be6f757SKristof Provost pflow_onomem, 1282be6f757SKristof Provost pflow_oerrors, 1292be6f757SKristof Provost pflow_ncounters, 1302be6f757SKristof Provost }; 1312be6f757SKristof Provost struct pflowstats_ctr { 1322be6f757SKristof Provost counter_u64_t c[pflow_ncounters]; 1332be6f757SKristof Provost }; 1342be6f757SKristof Provost 135f92d9b1aSKristof Provost /** 136f92d9b1aSKristof Provost * Locking concept 137f92d9b1aSKristof Provost * 138f92d9b1aSKristof Provost * The list of pflow devices (V_pflowif_list) is managed through epoch. 139f92d9b1aSKristof Provost * It is safe to read the list without locking (while in NET_EPOCH). 140f92d9b1aSKristof Provost * There may only be one simultaneous modifier, hence we need V_pflow_list_mtx 141f92d9b1aSKristof Provost * on every add/delete. 142f92d9b1aSKristof Provost * 143f92d9b1aSKristof Provost * Each pflow interface protects its own data with the sc_lock mutex. 144f92d9b1aSKristof Provost * 145f92d9b1aSKristof Provost * We do not require any pf locks, and in fact expect to be called without 146f92d9b1aSKristof Provost * hashrow locks held. 147f92d9b1aSKristof Provost **/ 148f92d9b1aSKristof Provost 149f92d9b1aSKristof Provost VNET_DEFINE(struct unrhdr *, pflow_unr); 150f92d9b1aSKristof Provost #define V_pflow_unr VNET(pflow_unr) 151f92d9b1aSKristof Provost VNET_DEFINE(CK_LIST_HEAD(, pflow_softc), pflowif_list); 152f92d9b1aSKristof Provost #define V_pflowif_list VNET(pflowif_list) 153f92d9b1aSKristof Provost VNET_DEFINE(struct mtx, pflowif_list_mtx); 154f92d9b1aSKristof Provost #define V_pflowif_list_mtx VNET(pflowif_list_mtx) 1552be6f757SKristof Provost VNET_DEFINE(struct pflowstats_ctr, pflowstat); 1565dea523bSKristof Provost #define V_pflowstats VNET(pflowstat) 157f92d9b1aSKristof Provost 158f92d9b1aSKristof Provost #define PFLOW_LOCK(_sc) mtx_lock(&(_sc)->sc_lock) 159f92d9b1aSKristof Provost #define PFLOW_UNLOCK(_sc) mtx_unlock(&(_sc)->sc_lock) 160f92d9b1aSKristof Provost #define PFLOW_ASSERT(_sc) mtx_assert(&(_sc)->sc_lock, MA_OWNED) 161f92d9b1aSKristof Provost 1625dea523bSKristof Provost SYSCTL_NODE(_net, OID_AUTO, pflow, CTLFLAG_RW | CTLFLAG_MPSAFE, 0, 1635dea523bSKristof Provost "PFLOW"); 1642be6f757SKristof Provost SYSCTL_PROC(_net_pflow, OID_AUTO, stats, CTLTYPE_OPAQUE | CTLFLAG_RD | CTLFLAG_MPSAFE, 1652be6f757SKristof Provost 0, 0, sysctl_pflowstats, "S,pflowstats", 1665dea523bSKristof Provost "PFLOW statistics (struct pflowstats, net/if_pflow.h)"); 1675dea523bSKristof Provost 1682be6f757SKristof Provost static inline void 1692be6f757SKristof Provost pflowstat_inc(enum pflowstat_counters c) 1702be6f757SKristof Provost { 1712be6f757SKristof Provost counter_u64_add(V_pflowstats.c[c], 1); 1722be6f757SKristof Provost } 1732be6f757SKristof Provost 174f92d9b1aSKristof Provost static void 175f92d9b1aSKristof Provost vnet_pflowattach(void) 176f92d9b1aSKristof Provost { 177f92d9b1aSKristof Provost CK_LIST_INIT(&V_pflowif_list); 178f92d9b1aSKristof Provost mtx_init(&V_pflowif_list_mtx, "pflow interface list mtx", NULL, MTX_DEF); 179f92d9b1aSKristof Provost 18063a5fe83SKristof Provost V_pflow_unr = new_unrhdr(0, PFLOW_MAX_ENTRIES - 1, &V_pflowif_list_mtx); 1812be6f757SKristof Provost 1822be6f757SKristof Provost for (int i = 0; i < pflow_ncounters; i++) 1832be6f757SKristof Provost V_pflowstats.c[i] = counter_u64_alloc(M_WAITOK); 184f92d9b1aSKristof Provost } 185f92d9b1aSKristof Provost VNET_SYSINIT(vnet_pflowattach, SI_SUB_PROTO_FIREWALL, SI_ORDER_ANY, 186f92d9b1aSKristof Provost vnet_pflowattach, NULL); 187f92d9b1aSKristof Provost 18883641335SKristof Provost static int 18983641335SKristof Provost pflow_jail_remove(void *obj, void *data __unused) 190f92d9b1aSKristof Provost { 19183641335SKristof Provost #ifdef VIMAGE 19283641335SKristof Provost const struct prison *pr = obj; 19383641335SKristof Provost #endif 194f92d9b1aSKristof Provost struct pflow_softc *sc; 195f92d9b1aSKristof Provost 19683641335SKristof Provost CURVNET_SET(pr->pr_vnet); 197f92d9b1aSKristof Provost CK_LIST_FOREACH(sc, &V_pflowif_list, sc_next) { 198f92d9b1aSKristof Provost pflow_destroy(sc->sc_id, false); 199f92d9b1aSKristof Provost } 20083641335SKristof Provost CURVNET_RESTORE(); 201f92d9b1aSKristof Provost 20283641335SKristof Provost return (0); 20383641335SKristof Provost } 20483641335SKristof Provost 20583641335SKristof Provost static void 20683641335SKristof Provost vnet_pflowdetach(void) 20783641335SKristof Provost { 20883641335SKristof Provost 20983641335SKristof Provost /* Should have been done by pflow_jail_remove() */ 210f92d9b1aSKristof Provost MPASS(CK_LIST_EMPTY(&V_pflowif_list)); 211f92d9b1aSKristof Provost delete_unrhdr(V_pflow_unr); 212f92d9b1aSKristof Provost mtx_destroy(&V_pflowif_list_mtx); 2132be6f757SKristof Provost 2142be6f757SKristof Provost for (int i = 0; i < pflow_ncounters; i++) 2152be6f757SKristof Provost counter_u64_free(V_pflowstats.c[i]); 216f92d9b1aSKristof Provost } 217f92d9b1aSKristof Provost VNET_SYSUNINIT(vnet_pflowdetach, SI_SUB_PROTO_FIREWALL, SI_ORDER_FOURTH, 218f92d9b1aSKristof Provost vnet_pflowdetach, NULL); 219f92d9b1aSKristof Provost 220f92d9b1aSKristof Provost static void 221f92d9b1aSKristof Provost vnet_pflow_finalise(void) 222f92d9b1aSKristof Provost { 223f92d9b1aSKristof Provost /* 224f92d9b1aSKristof Provost * Ensure we've freed all interfaces, and do not have pending 225f92d9b1aSKristof Provost * epoch cleanup calls. 226f92d9b1aSKristof Provost */ 227f92d9b1aSKristof Provost NET_EPOCH_DRAIN_CALLBACKS(); 228f92d9b1aSKristof Provost } 229f92d9b1aSKristof Provost VNET_SYSUNINIT(vnet_pflow_finalise, SI_SUB_PROTO_FIREWALL, SI_ORDER_THIRD, 230f92d9b1aSKristof Provost vnet_pflow_finalise, NULL); 231f92d9b1aSKristof Provost 232f92d9b1aSKristof Provost static void 233f92d9b1aSKristof Provost pflow_output_process(void *arg) 234f92d9b1aSKristof Provost { 235f92d9b1aSKristof Provost struct mbufq ml; 236f92d9b1aSKristof Provost struct pflow_softc *sc = arg; 237f92d9b1aSKristof Provost struct mbuf *m; 238f92d9b1aSKristof Provost 239f92d9b1aSKristof Provost mbufq_init(&ml, 0); 240f92d9b1aSKristof Provost 241f92d9b1aSKristof Provost PFLOW_LOCK(sc); 242f92d9b1aSKristof Provost mbufq_concat(&ml, &sc->sc_outputqueue); 243f92d9b1aSKristof Provost PFLOW_UNLOCK(sc); 244f92d9b1aSKristof Provost 245f92d9b1aSKristof Provost CURVNET_SET(sc->sc_vnet); 246f92d9b1aSKristof Provost while ((m = mbufq_dequeue(&ml)) != NULL) { 247f92d9b1aSKristof Provost pflow_sendout_mbuf(sc, m); 248f92d9b1aSKristof Provost } 249f92d9b1aSKristof Provost CURVNET_RESTORE(); 250f92d9b1aSKristof Provost } 251f92d9b1aSKristof Provost 252f92d9b1aSKristof Provost static int 253f92d9b1aSKristof Provost pflow_create(int unit) 254f92d9b1aSKristof Provost { 255f92d9b1aSKristof Provost struct pflow_softc *pflowif; 256f92d9b1aSKristof Provost int error; 257f92d9b1aSKristof Provost 258f92d9b1aSKristof Provost pflowif = malloc(sizeof(*pflowif), M_DEVBUF, M_WAITOK|M_ZERO); 259f92d9b1aSKristof Provost mtx_init(&pflowif->sc_lock, "pflowlk", NULL, MTX_DEF); 260f92d9b1aSKristof Provost pflowif->sc_version = PFLOW_PROTO_DEFAULT; 26185b71dcfSKristof Provost pflowif->sc_observation_dom = PFLOW_ENGINE_TYPE; 262f92d9b1aSKristof Provost 263f92d9b1aSKristof Provost /* ipfix template init */ 264f92d9b1aSKristof Provost bzero(&pflowif->sc_tmpl_ipfix,sizeof(pflowif->sc_tmpl_ipfix)); 265f92d9b1aSKristof Provost pflowif->sc_tmpl_ipfix.set_header.set_id = 266f92d9b1aSKristof Provost htons(PFLOW_IPFIX_TMPL_SET_ID); 267f92d9b1aSKristof Provost pflowif->sc_tmpl_ipfix.set_header.set_length = 268f92d9b1aSKristof Provost htons(sizeof(struct pflow_ipfix_tmpl)); 269f92d9b1aSKristof Provost 270f92d9b1aSKristof Provost /* ipfix IPv4 template */ 271f92d9b1aSKristof Provost pflowif->sc_tmpl_ipfix.ipv4_tmpl.h.tmpl_id = 272f92d9b1aSKristof Provost htons(PFLOW_IPFIX_TMPL_IPV4_ID); 273f92d9b1aSKristof Provost pflowif->sc_tmpl_ipfix.ipv4_tmpl.h.field_count 274f92d9b1aSKristof Provost = htons(PFLOW_IPFIX_TMPL_IPV4_FIELD_COUNT); 275f92d9b1aSKristof Provost pflowif->sc_tmpl_ipfix.ipv4_tmpl.src_ip.field_id = 276f92d9b1aSKristof Provost htons(PFIX_IE_sourceIPv4Address); 277f92d9b1aSKristof Provost pflowif->sc_tmpl_ipfix.ipv4_tmpl.src_ip.len = htons(4); 278f92d9b1aSKristof Provost pflowif->sc_tmpl_ipfix.ipv4_tmpl.dest_ip.field_id = 279f92d9b1aSKristof Provost htons(PFIX_IE_destinationIPv4Address); 280f92d9b1aSKristof Provost pflowif->sc_tmpl_ipfix.ipv4_tmpl.dest_ip.len = htons(4); 281f92d9b1aSKristof Provost pflowif->sc_tmpl_ipfix.ipv4_tmpl.if_index_in.field_id = 282f92d9b1aSKristof Provost htons(PFIX_IE_ingressInterface); 283f92d9b1aSKristof Provost pflowif->sc_tmpl_ipfix.ipv4_tmpl.if_index_in.len = htons(4); 284f92d9b1aSKristof Provost pflowif->sc_tmpl_ipfix.ipv4_tmpl.if_index_out.field_id = 285f92d9b1aSKristof Provost htons(PFIX_IE_egressInterface); 286f92d9b1aSKristof Provost pflowif->sc_tmpl_ipfix.ipv4_tmpl.if_index_out.len = htons(4); 287f92d9b1aSKristof Provost pflowif->sc_tmpl_ipfix.ipv4_tmpl.packets.field_id = 288f92d9b1aSKristof Provost htons(PFIX_IE_packetDeltaCount); 289f92d9b1aSKristof Provost pflowif->sc_tmpl_ipfix.ipv4_tmpl.packets.len = htons(8); 290f92d9b1aSKristof Provost pflowif->sc_tmpl_ipfix.ipv4_tmpl.octets.field_id = 291f92d9b1aSKristof Provost htons(PFIX_IE_octetDeltaCount); 292f92d9b1aSKristof Provost pflowif->sc_tmpl_ipfix.ipv4_tmpl.octets.len = htons(8); 293f92d9b1aSKristof Provost pflowif->sc_tmpl_ipfix.ipv4_tmpl.start.field_id = 294f92d9b1aSKristof Provost htons(PFIX_IE_flowStartMilliseconds); 295f92d9b1aSKristof Provost pflowif->sc_tmpl_ipfix.ipv4_tmpl.start.len = htons(8); 296f92d9b1aSKristof Provost pflowif->sc_tmpl_ipfix.ipv4_tmpl.finish.field_id = 297f92d9b1aSKristof Provost htons(PFIX_IE_flowEndMilliseconds); 298f92d9b1aSKristof Provost pflowif->sc_tmpl_ipfix.ipv4_tmpl.finish.len = htons(8); 299f92d9b1aSKristof Provost pflowif->sc_tmpl_ipfix.ipv4_tmpl.src_port.field_id = 300f92d9b1aSKristof Provost htons(PFIX_IE_sourceTransportPort); 301f92d9b1aSKristof Provost pflowif->sc_tmpl_ipfix.ipv4_tmpl.src_port.len = htons(2); 302f92d9b1aSKristof Provost pflowif->sc_tmpl_ipfix.ipv4_tmpl.dest_port.field_id = 303f92d9b1aSKristof Provost htons(PFIX_IE_destinationTransportPort); 304f92d9b1aSKristof Provost pflowif->sc_tmpl_ipfix.ipv4_tmpl.dest_port.len = htons(2); 305f92d9b1aSKristof Provost pflowif->sc_tmpl_ipfix.ipv4_tmpl.tos.field_id = 306f92d9b1aSKristof Provost htons(PFIX_IE_ipClassOfService); 307f92d9b1aSKristof Provost pflowif->sc_tmpl_ipfix.ipv4_tmpl.tos.len = htons(1); 308f92d9b1aSKristof Provost pflowif->sc_tmpl_ipfix.ipv4_tmpl.protocol.field_id = 309f92d9b1aSKristof Provost htons(PFIX_IE_protocolIdentifier); 310f92d9b1aSKristof Provost pflowif->sc_tmpl_ipfix.ipv4_tmpl.protocol.len = htons(1); 311f92d9b1aSKristof Provost 312f92d9b1aSKristof Provost /* ipfix IPv6 template */ 313f92d9b1aSKristof Provost pflowif->sc_tmpl_ipfix.ipv6_tmpl.h.tmpl_id = 314f92d9b1aSKristof Provost htons(PFLOW_IPFIX_TMPL_IPV6_ID); 315f92d9b1aSKristof Provost pflowif->sc_tmpl_ipfix.ipv6_tmpl.h.field_count = 316f92d9b1aSKristof Provost htons(PFLOW_IPFIX_TMPL_IPV6_FIELD_COUNT); 317f92d9b1aSKristof Provost pflowif->sc_tmpl_ipfix.ipv6_tmpl.src_ip.field_id = 318f92d9b1aSKristof Provost htons(PFIX_IE_sourceIPv6Address); 319f92d9b1aSKristof Provost pflowif->sc_tmpl_ipfix.ipv6_tmpl.src_ip.len = htons(16); 320f92d9b1aSKristof Provost pflowif->sc_tmpl_ipfix.ipv6_tmpl.dest_ip.field_id = 321f92d9b1aSKristof Provost htons(PFIX_IE_destinationIPv6Address); 322f92d9b1aSKristof Provost pflowif->sc_tmpl_ipfix.ipv6_tmpl.dest_ip.len = htons(16); 323f92d9b1aSKristof Provost pflowif->sc_tmpl_ipfix.ipv6_tmpl.if_index_in.field_id = 324f92d9b1aSKristof Provost htons(PFIX_IE_ingressInterface); 325f92d9b1aSKristof Provost pflowif->sc_tmpl_ipfix.ipv6_tmpl.if_index_in.len = htons(4); 326f92d9b1aSKristof Provost pflowif->sc_tmpl_ipfix.ipv6_tmpl.if_index_out.field_id = 327f92d9b1aSKristof Provost htons(PFIX_IE_egressInterface); 328f92d9b1aSKristof Provost pflowif->sc_tmpl_ipfix.ipv6_tmpl.if_index_out.len = htons(4); 329f92d9b1aSKristof Provost pflowif->sc_tmpl_ipfix.ipv6_tmpl.packets.field_id = 330f92d9b1aSKristof Provost htons(PFIX_IE_packetDeltaCount); 331f92d9b1aSKristof Provost pflowif->sc_tmpl_ipfix.ipv6_tmpl.packets.len = htons(8); 332f92d9b1aSKristof Provost pflowif->sc_tmpl_ipfix.ipv6_tmpl.octets.field_id = 333f92d9b1aSKristof Provost htons(PFIX_IE_octetDeltaCount); 334f92d9b1aSKristof Provost pflowif->sc_tmpl_ipfix.ipv6_tmpl.octets.len = htons(8); 335f92d9b1aSKristof Provost pflowif->sc_tmpl_ipfix.ipv6_tmpl.start.field_id = 336f92d9b1aSKristof Provost htons(PFIX_IE_flowStartMilliseconds); 337f92d9b1aSKristof Provost pflowif->sc_tmpl_ipfix.ipv6_tmpl.start.len = htons(8); 338f92d9b1aSKristof Provost pflowif->sc_tmpl_ipfix.ipv6_tmpl.finish.field_id = 339f92d9b1aSKristof Provost htons(PFIX_IE_flowEndMilliseconds); 340f92d9b1aSKristof Provost pflowif->sc_tmpl_ipfix.ipv6_tmpl.finish.len = htons(8); 341f92d9b1aSKristof Provost pflowif->sc_tmpl_ipfix.ipv6_tmpl.src_port.field_id = 342f92d9b1aSKristof Provost htons(PFIX_IE_sourceTransportPort); 343f92d9b1aSKristof Provost pflowif->sc_tmpl_ipfix.ipv6_tmpl.src_port.len = htons(2); 344f92d9b1aSKristof Provost pflowif->sc_tmpl_ipfix.ipv6_tmpl.dest_port.field_id = 345f92d9b1aSKristof Provost htons(PFIX_IE_destinationTransportPort); 346f92d9b1aSKristof Provost pflowif->sc_tmpl_ipfix.ipv6_tmpl.dest_port.len = htons(2); 347f92d9b1aSKristof Provost pflowif->sc_tmpl_ipfix.ipv6_tmpl.tos.field_id = 348f92d9b1aSKristof Provost htons(PFIX_IE_ipClassOfService); 349f92d9b1aSKristof Provost pflowif->sc_tmpl_ipfix.ipv6_tmpl.tos.len = htons(1); 350f92d9b1aSKristof Provost pflowif->sc_tmpl_ipfix.ipv6_tmpl.protocol.field_id = 351f92d9b1aSKristof Provost htons(PFIX_IE_protocolIdentifier); 352f92d9b1aSKristof Provost pflowif->sc_tmpl_ipfix.ipv6_tmpl.protocol.len = htons(1); 353f92d9b1aSKristof Provost 354fc6e5069SKristof Provost /* NAT44 create template */ 355fc6e5069SKristof Provost pflowif->sc_tmpl_ipfix.nat44_tmpl.h.tmpl_id = 356fc6e5069SKristof Provost htons(PFLOW_IPFIX_TMPL_NAT44_ID); 357fc6e5069SKristof Provost pflowif->sc_tmpl_ipfix.nat44_tmpl.h.field_count = 358fc6e5069SKristof Provost htons(PFLOW_IPFIX_TMPL_NAT44_FIELD_COUNT); 359fc6e5069SKristof Provost pflowif->sc_tmpl_ipfix.nat44_tmpl.timestamp.field_id = 360fc6e5069SKristof Provost htons(PFIX_IE_timeStamp); 361fc6e5069SKristof Provost pflowif->sc_tmpl_ipfix.nat44_tmpl.timestamp.len = 362fc6e5069SKristof Provost htons(8); 363fc6e5069SKristof Provost pflowif->sc_tmpl_ipfix.nat44_tmpl.nat_event.field_id = 364fc6e5069SKristof Provost htons(PFIX_IE_natEvent); 365fc6e5069SKristof Provost pflowif->sc_tmpl_ipfix.nat44_tmpl.nat_event.len = 366fc6e5069SKristof Provost htons(1); 367fc6e5069SKristof Provost pflowif->sc_tmpl_ipfix.nat44_tmpl.protocol.field_id = 368fc6e5069SKristof Provost htons(PFIX_IE_protocolIdentifier); 369fc6e5069SKristof Provost pflowif->sc_tmpl_ipfix.nat44_tmpl.protocol.len = htons(1); 370fc6e5069SKristof Provost pflowif->sc_tmpl_ipfix.nat44_tmpl.src_ip.field_id = 371fc6e5069SKristof Provost htons(PFIX_IE_sourceIPv4Address); 372fc6e5069SKristof Provost pflowif->sc_tmpl_ipfix.nat44_tmpl.src_ip.len = 373fc6e5069SKristof Provost htons(4); 374fc6e5069SKristof Provost pflowif->sc_tmpl_ipfix.nat44_tmpl.src_port.field_id = 375fc6e5069SKristof Provost htons(PFIX_IE_sourceTransportPort); 376fc6e5069SKristof Provost pflowif->sc_tmpl_ipfix.nat44_tmpl.src_port.len = htons(2); 377fc6e5069SKristof Provost pflowif->sc_tmpl_ipfix.nat44_tmpl.postnat_src_ip.field_id = 378fc6e5069SKristof Provost htons(PFIX_IE_postNATSourceIPv4Address); 379fc6e5069SKristof Provost pflowif->sc_tmpl_ipfix.nat44_tmpl.postnat_src_ip.len = 380fc6e5069SKristof Provost htons(4); 381fc6e5069SKristof Provost pflowif->sc_tmpl_ipfix.nat44_tmpl.postnat_src_port.field_id = 382fc6e5069SKristof Provost htons(PFIX_IE_postNAPTSourceTransportPort); 383fc6e5069SKristof Provost pflowif->sc_tmpl_ipfix.nat44_tmpl.postnat_src_port.len = 384fc6e5069SKristof Provost htons(2); 385fc6e5069SKristof Provost pflowif->sc_tmpl_ipfix.nat44_tmpl.dst_ip.field_id = 386fc6e5069SKristof Provost htons(PFIX_IE_destinationIPv4Address); 387fc6e5069SKristof Provost pflowif->sc_tmpl_ipfix.nat44_tmpl.dst_ip.len = 388fc6e5069SKristof Provost htons(4); 389fc6e5069SKristof Provost pflowif->sc_tmpl_ipfix.nat44_tmpl.dst_port.field_id = 390fc6e5069SKristof Provost htons(PFIX_IE_destinationTransportPort); 391fc6e5069SKristof Provost pflowif->sc_tmpl_ipfix.nat44_tmpl.dst_port.len = htons(2); 392fc6e5069SKristof Provost pflowif->sc_tmpl_ipfix.nat44_tmpl.postnat_dst_ip.field_id = 393fc6e5069SKristof Provost htons(PFIX_IE_postNATDestinationIPv4Address); 394fc6e5069SKristof Provost pflowif->sc_tmpl_ipfix.nat44_tmpl.postnat_dst_ip.len = 395fc6e5069SKristof Provost htons(4); 396fc6e5069SKristof Provost pflowif->sc_tmpl_ipfix.nat44_tmpl.postnat_dst_port.field_id = 397fc6e5069SKristof Provost htons(PFIX_IE_postNAPTDestinationTransportPort); 398fc6e5069SKristof Provost pflowif->sc_tmpl_ipfix.nat44_tmpl.postnat_dst_port.len = 399fc6e5069SKristof Provost htons(2); 400fc6e5069SKristof Provost 401f92d9b1aSKristof Provost pflowif->sc_id = unit; 402f92d9b1aSKristof Provost pflowif->sc_vnet = curvnet; 403f92d9b1aSKristof Provost 404f92d9b1aSKristof Provost mbufq_init(&pflowif->sc_outputqueue, 8192); 405f92d9b1aSKristof Provost pflow_setmtu(pflowif, ETHERMTU); 406f92d9b1aSKristof Provost 407f92d9b1aSKristof Provost callout_init_mtx(&pflowif->sc_tmo, &pflowif->sc_lock, 0); 408f92d9b1aSKristof Provost callout_init_mtx(&pflowif->sc_tmo6, &pflowif->sc_lock, 0); 409fc6e5069SKristof Provost callout_init_mtx(&pflowif->sc_tmo_nat4, &pflowif->sc_lock, 0); 410f92d9b1aSKristof Provost callout_init_mtx(&pflowif->sc_tmo_tmpl, &pflowif->sc_lock, 0); 411f92d9b1aSKristof Provost 412f92d9b1aSKristof Provost error = swi_add(&pflowif->sc_swi_ie, pflowname, pflow_output_process, 413f92d9b1aSKristof Provost pflowif, SWI_NET, INTR_MPSAFE, &pflowif->sc_swi_cookie); 414f92d9b1aSKristof Provost if (error) { 415f92d9b1aSKristof Provost free(pflowif, M_DEVBUF); 416f92d9b1aSKristof Provost return (error); 417f92d9b1aSKristof Provost } 418f92d9b1aSKristof Provost 419f92d9b1aSKristof Provost /* Insert into list of pflows */ 420f92d9b1aSKristof Provost mtx_lock(&V_pflowif_list_mtx); 421f92d9b1aSKristof Provost CK_LIST_INSERT_HEAD(&V_pflowif_list, pflowif, sc_next); 422f92d9b1aSKristof Provost mtx_unlock(&V_pflowif_list_mtx); 423f92d9b1aSKristof Provost 424baf9b6d0SKristof Provost V_pflow_export_state_ptr = export_pflow; 425baf9b6d0SKristof Provost 426f92d9b1aSKristof Provost return (0); 427f92d9b1aSKristof Provost } 428f92d9b1aSKristof Provost 429f92d9b1aSKristof Provost static void 430f92d9b1aSKristof Provost pflow_free_cb(struct epoch_context *ctx) 431f92d9b1aSKristof Provost { 432f92d9b1aSKristof Provost struct pflow_softc *sc; 433f92d9b1aSKristof Provost 434f92d9b1aSKristof Provost sc = __containerof(ctx, struct pflow_softc, sc_epoch_ctx); 435f92d9b1aSKristof Provost 436f92d9b1aSKristof Provost free(sc, M_DEVBUF); 437f92d9b1aSKristof Provost } 438f92d9b1aSKristof Provost 439f92d9b1aSKristof Provost static int 440f92d9b1aSKristof Provost pflow_destroy(int unit, bool drain) 441f92d9b1aSKristof Provost { 442f92d9b1aSKristof Provost struct pflow_softc *sc; 443f92d9b1aSKristof Provost int error __diagused; 444f92d9b1aSKristof Provost 445f92d9b1aSKristof Provost mtx_lock(&V_pflowif_list_mtx); 446f92d9b1aSKristof Provost CK_LIST_FOREACH(sc, &V_pflowif_list, sc_next) { 447f92d9b1aSKristof Provost if (sc->sc_id == unit) 448f92d9b1aSKristof Provost break; 449f92d9b1aSKristof Provost } 450f92d9b1aSKristof Provost if (sc == NULL) { 451f92d9b1aSKristof Provost mtx_unlock(&V_pflowif_list_mtx); 452f92d9b1aSKristof Provost return (ENOENT); 453f92d9b1aSKristof Provost } 454f92d9b1aSKristof Provost CK_LIST_REMOVE(sc, sc_next); 455baf9b6d0SKristof Provost if (CK_LIST_EMPTY(&V_pflowif_list)) 456baf9b6d0SKristof Provost V_pflow_export_state_ptr = NULL; 457f92d9b1aSKristof Provost mtx_unlock(&V_pflowif_list_mtx); 458f92d9b1aSKristof Provost 459f92d9b1aSKristof Provost sc->sc_dying = 1; 460f92d9b1aSKristof Provost 461f92d9b1aSKristof Provost if (drain) { 462f92d9b1aSKristof Provost /* Let's be sure no one is using this interface any more. */ 463f92d9b1aSKristof Provost NET_EPOCH_DRAIN_CALLBACKS(); 464f92d9b1aSKristof Provost } 465f92d9b1aSKristof Provost 466f92d9b1aSKristof Provost error = swi_remove(sc->sc_swi_cookie); 467f92d9b1aSKristof Provost MPASS(error == 0); 468f92d9b1aSKristof Provost error = intr_event_destroy(sc->sc_swi_ie); 469f92d9b1aSKristof Provost MPASS(error == 0); 470f92d9b1aSKristof Provost 471f92d9b1aSKristof Provost callout_drain(&sc->sc_tmo); 472f92d9b1aSKristof Provost callout_drain(&sc->sc_tmo6); 473fc6e5069SKristof Provost callout_drain(&sc->sc_tmo_nat4); 474f92d9b1aSKristof Provost callout_drain(&sc->sc_tmo_tmpl); 475f92d9b1aSKristof Provost 476f92d9b1aSKristof Provost m_freem(sc->sc_mbuf); 477f92d9b1aSKristof Provost m_freem(sc->sc_mbuf6); 478fc6e5069SKristof Provost m_freem(sc->sc_mbuf_nat4); 479f92d9b1aSKristof Provost 480f92d9b1aSKristof Provost PFLOW_LOCK(sc); 481f92d9b1aSKristof Provost mbufq_drain(&sc->sc_outputqueue); 482f92d9b1aSKristof Provost if (sc->so != NULL) { 483f92d9b1aSKristof Provost soclose(sc->so); 484f92d9b1aSKristof Provost sc->so = NULL; 485f92d9b1aSKristof Provost } 486f92d9b1aSKristof Provost if (sc->sc_flowdst != NULL) 487f92d9b1aSKristof Provost free(sc->sc_flowdst, M_DEVBUF); 488f92d9b1aSKristof Provost if (sc->sc_flowsrc != NULL) 489f92d9b1aSKristof Provost free(sc->sc_flowsrc, M_DEVBUF); 490f92d9b1aSKristof Provost PFLOW_UNLOCK(sc); 491f92d9b1aSKristof Provost 492f92d9b1aSKristof Provost mtx_destroy(&sc->sc_lock); 493f92d9b1aSKristof Provost 494f92d9b1aSKristof Provost free_unr(V_pflow_unr, unit); 495f92d9b1aSKristof Provost 496f92d9b1aSKristof Provost NET_EPOCH_CALL(pflow_free_cb, &sc->sc_epoch_ctx); 497f92d9b1aSKristof Provost 498f92d9b1aSKristof Provost return (0); 499f92d9b1aSKristof Provost } 500f92d9b1aSKristof Provost 501f92d9b1aSKristof Provost static int 502f92d9b1aSKristof Provost pflowvalidsockaddr(const struct sockaddr *sa, int ignore_port) 503f92d9b1aSKristof Provost { 504f92d9b1aSKristof Provost const struct sockaddr_in6 *sin6; 505f92d9b1aSKristof Provost const struct sockaddr_in *sin; 506f92d9b1aSKristof Provost 507f92d9b1aSKristof Provost if (sa == NULL) 508f92d9b1aSKristof Provost return (0); 509f92d9b1aSKristof Provost switch(sa->sa_family) { 510f92d9b1aSKristof Provost case AF_INET: 511f92d9b1aSKristof Provost sin = (const struct sockaddr_in *)sa; 512f92d9b1aSKristof Provost return (sin->sin_addr.s_addr != INADDR_ANY && 513f92d9b1aSKristof Provost (ignore_port || sin->sin_port != 0)); 514f92d9b1aSKristof Provost case AF_INET6: 515f92d9b1aSKristof Provost sin6 = (const struct sockaddr_in6 *)sa; 516f92d9b1aSKristof Provost return (!IN6_IS_ADDR_UNSPECIFIED(&sin6->sin6_addr) && 517f92d9b1aSKristof Provost (ignore_port || sin6->sin6_port != 0)); 518f92d9b1aSKristof Provost default: 519f92d9b1aSKristof Provost return (0); 520f92d9b1aSKristof Provost } 521f92d9b1aSKristof Provost } 522f92d9b1aSKristof Provost 52385b71dcfSKristof Provost int 524f92d9b1aSKristof Provost pflow_calc_mtu(struct pflow_softc *sc, int mtu, int hdrsz) 525f92d9b1aSKristof Provost { 526fc6e5069SKristof Provost size_t min; 527f92d9b1aSKristof Provost 528f92d9b1aSKristof Provost sc->sc_maxcount4 = (mtu - hdrsz - 529f92d9b1aSKristof Provost sizeof(struct udpiphdr)) / sizeof(struct pflow_ipfix_flow4); 530f92d9b1aSKristof Provost sc->sc_maxcount6 = (mtu - hdrsz - 531f92d9b1aSKristof Provost sizeof(struct udpiphdr)) / sizeof(struct pflow_ipfix_flow6); 532fc6e5069SKristof Provost sc->sc_maxcount_nat4 = (mtu - hdrsz - 533fc6e5069SKristof Provost sizeof(struct udpiphdr)) / sizeof(struct pflow_ipfix_nat4); 534f92d9b1aSKristof Provost if (sc->sc_maxcount4 > PFLOW_MAXFLOWS) 535f92d9b1aSKristof Provost sc->sc_maxcount4 = PFLOW_MAXFLOWS; 536f92d9b1aSKristof Provost if (sc->sc_maxcount6 > PFLOW_MAXFLOWS) 537f92d9b1aSKristof Provost sc->sc_maxcount6 = PFLOW_MAXFLOWS; 538fc6e5069SKristof Provost if (sc->sc_maxcount_nat4 > PFLOW_MAXFLOWS) 539fc6e5069SKristof Provost sc->sc_maxcount_nat4 = PFLOW_MAXFLOWS; 540fc6e5069SKristof Provost 541fc6e5069SKristof Provost min = MIN(sc->sc_maxcount4 * sizeof(struct pflow_ipfix_flow4), 542fc6e5069SKristof Provost sc->sc_maxcount6 * sizeof(struct pflow_ipfix_flow6)); 543fc6e5069SKristof Provost min = MIN(min, sc->sc_maxcount_nat4 * sizeof(struct pflow_ipfix_nat4)); 544fc6e5069SKristof Provost 545fc6e5069SKristof Provost return (hdrsz + sizeof(struct udpiphdr) + min); 546f92d9b1aSKristof Provost } 547f92d9b1aSKristof Provost 548f92d9b1aSKristof Provost static void 549f92d9b1aSKristof Provost pflow_setmtu(struct pflow_softc *sc, int mtu_req) 550f92d9b1aSKristof Provost { 551f92d9b1aSKristof Provost int mtu; 552f92d9b1aSKristof Provost 553f92d9b1aSKristof Provost mtu = mtu_req; 554f92d9b1aSKristof Provost 555f92d9b1aSKristof Provost switch (sc->sc_version) { 556f92d9b1aSKristof Provost case PFLOW_PROTO_5: 557f92d9b1aSKristof Provost sc->sc_maxcount = (mtu - sizeof(struct pflow_header) - 558f92d9b1aSKristof Provost sizeof(struct udpiphdr)) / sizeof(struct pflow_flow); 559f92d9b1aSKristof Provost if (sc->sc_maxcount > PFLOW_MAXFLOWS) 560f92d9b1aSKristof Provost sc->sc_maxcount = PFLOW_MAXFLOWS; 561f92d9b1aSKristof Provost break; 562f92d9b1aSKristof Provost case PFLOW_PROTO_10: 563f92d9b1aSKristof Provost pflow_calc_mtu(sc, mtu, sizeof(struct pflow_v10_header)); 564f92d9b1aSKristof Provost break; 565f92d9b1aSKristof Provost default: /* NOTREACHED */ 566f92d9b1aSKristof Provost break; 567f92d9b1aSKristof Provost } 568f92d9b1aSKristof Provost } 569f92d9b1aSKristof Provost 570f92d9b1aSKristof Provost static struct mbuf * 571f92d9b1aSKristof Provost pflow_get_mbuf(struct pflow_softc *sc, u_int16_t set_id) 572f92d9b1aSKristof Provost { 573f92d9b1aSKristof Provost struct pflow_set_header set_hdr; 574f92d9b1aSKristof Provost struct pflow_header h; 575f92d9b1aSKristof Provost struct mbuf *m; 576f92d9b1aSKristof Provost 577f92d9b1aSKristof Provost MGETHDR(m, M_NOWAIT, MT_DATA); 578f92d9b1aSKristof Provost if (m == NULL) { 5792be6f757SKristof Provost pflowstat_inc(pflow_onomem); 580f92d9b1aSKristof Provost return (NULL); 581f92d9b1aSKristof Provost } 582f92d9b1aSKristof Provost 583f92d9b1aSKristof Provost MCLGET(m, M_NOWAIT); 584f92d9b1aSKristof Provost if ((m->m_flags & M_EXT) == 0) { 585f92d9b1aSKristof Provost m_free(m); 5862be6f757SKristof Provost pflowstat_inc(pflow_onomem); 587f92d9b1aSKristof Provost return (NULL); 588f92d9b1aSKristof Provost } 589f92d9b1aSKristof Provost 590f92d9b1aSKristof Provost m->m_len = m->m_pkthdr.len = 0; 591f92d9b1aSKristof Provost 592f92d9b1aSKristof Provost if (sc == NULL) /* get only a new empty mbuf */ 593f92d9b1aSKristof Provost return (m); 594f92d9b1aSKristof Provost 595f92d9b1aSKristof Provost switch (sc->sc_version) { 596f92d9b1aSKristof Provost case PFLOW_PROTO_5: 597f92d9b1aSKristof Provost /* populate pflow_header */ 598f92d9b1aSKristof Provost h.reserved1 = 0; 599f92d9b1aSKristof Provost h.reserved2 = 0; 600f92d9b1aSKristof Provost h.count = 0; 601f92d9b1aSKristof Provost h.version = htons(PFLOW_PROTO_5); 602f92d9b1aSKristof Provost h.flow_sequence = htonl(sc->sc_gcounter); 603f92d9b1aSKristof Provost h.engine_type = PFLOW_ENGINE_TYPE; 604f92d9b1aSKristof Provost h.engine_id = PFLOW_ENGINE_ID; 605f92d9b1aSKristof Provost m_copyback(m, 0, PFLOW_HDRLEN, (caddr_t)&h); 606f92d9b1aSKristof Provost 607f92d9b1aSKristof Provost sc->sc_count = 0; 608f92d9b1aSKristof Provost callout_reset(&sc->sc_tmo, PFLOW_TIMEOUT * hz, 609f92d9b1aSKristof Provost pflow_timeout, sc); 610f92d9b1aSKristof Provost break; 611f92d9b1aSKristof Provost case PFLOW_PROTO_10: 612f92d9b1aSKristof Provost /* populate pflow_set_header */ 613f92d9b1aSKristof Provost set_hdr.set_length = 0; 614f92d9b1aSKristof Provost set_hdr.set_id = htons(set_id); 615f92d9b1aSKristof Provost m_copyback(m, 0, PFLOW_SET_HDRLEN, (caddr_t)&set_hdr); 616f92d9b1aSKristof Provost break; 617f92d9b1aSKristof Provost default: /* NOTREACHED */ 618f92d9b1aSKristof Provost break; 619f92d9b1aSKristof Provost } 620f92d9b1aSKristof Provost 621f92d9b1aSKristof Provost return (m); 622f92d9b1aSKristof Provost } 623f92d9b1aSKristof Provost 624f92d9b1aSKristof Provost static void 625f92d9b1aSKristof Provost copy_flow_data(struct pflow_flow *flow1, struct pflow_flow *flow2, 626baf9b6d0SKristof Provost const struct pf_kstate *st, struct pf_state_key *sk, int src, int dst) 627f92d9b1aSKristof Provost { 628f92d9b1aSKristof Provost flow1->src_ip = flow2->dest_ip = sk->addr[src].v4.s_addr; 629f92d9b1aSKristof Provost flow1->src_port = flow2->dest_port = sk->port[src]; 630f92d9b1aSKristof Provost flow1->dest_ip = flow2->src_ip = sk->addr[dst].v4.s_addr; 631f92d9b1aSKristof Provost flow1->dest_port = flow2->src_port = sk->port[dst]; 632f92d9b1aSKristof Provost 633f92d9b1aSKristof Provost flow1->dest_as = flow2->src_as = 634f92d9b1aSKristof Provost flow1->src_as = flow2->dest_as = 0; 635f92d9b1aSKristof Provost flow1->if_index_in = htons(st->if_index_in); 636f92d9b1aSKristof Provost flow1->if_index_out = htons(st->if_index_out); 637f92d9b1aSKristof Provost flow2->if_index_in = htons(st->if_index_out); 638f92d9b1aSKristof Provost flow2->if_index_out = htons(st->if_index_in); 639f92d9b1aSKristof Provost flow1->dest_mask = flow2->src_mask = 640f92d9b1aSKristof Provost flow1->src_mask = flow2->dest_mask = 0; 641f92d9b1aSKristof Provost 642f92d9b1aSKristof Provost flow1->flow_packets = htonl(st->packets[0]); 643f92d9b1aSKristof Provost flow2->flow_packets = htonl(st->packets[1]); 644f92d9b1aSKristof Provost flow1->flow_octets = htonl(st->bytes[0]); 645f92d9b1aSKristof Provost flow2->flow_octets = htonl(st->bytes[1]); 646f92d9b1aSKristof Provost 647f92d9b1aSKristof Provost /* 648f92d9b1aSKristof Provost * Pretend the flow was created or expired when the machine came up 649f92d9b1aSKristof Provost * when creation is in the future of the last time a package was seen 650f92d9b1aSKristof Provost * or was created / expired before this machine came up due to pfsync. 651f92d9b1aSKristof Provost */ 652f92d9b1aSKristof Provost flow1->flow_start = flow2->flow_start = st->creation < 0 || 65304932601SKristof Provost st->creation > st->expire ? htonl(0) : htonl(st->creation); 654f92d9b1aSKristof Provost flow1->flow_finish = flow2->flow_finish = st->expire < 0 ? htonl(0) : 65504932601SKristof Provost htonl(st->expire); 656f92d9b1aSKristof Provost flow1->tcp_flags = flow2->tcp_flags = 0; 657f92d9b1aSKristof Provost flow1->protocol = flow2->protocol = sk->proto; 658e5c64b26SKajetan Staszkiewicz flow1->tos = flow2->tos = st->rule->tos; 659f92d9b1aSKristof Provost } 660f92d9b1aSKristof Provost 661f92d9b1aSKristof Provost static void 662f92d9b1aSKristof Provost copy_flow_ipfix_4_data(struct pflow_ipfix_flow4 *flow1, 663baf9b6d0SKristof Provost struct pflow_ipfix_flow4 *flow2, const struct pf_kstate *st, 664f92d9b1aSKristof Provost struct pf_state_key *sk, struct pflow_softc *sc, int src, int dst) 665f92d9b1aSKristof Provost { 666f92d9b1aSKristof Provost flow1->src_ip = flow2->dest_ip = sk->addr[src].v4.s_addr; 667f92d9b1aSKristof Provost flow1->src_port = flow2->dest_port = sk->port[src]; 668f92d9b1aSKristof Provost flow1->dest_ip = flow2->src_ip = sk->addr[dst].v4.s_addr; 669f92d9b1aSKristof Provost flow1->dest_port = flow2->src_port = sk->port[dst]; 670f92d9b1aSKristof Provost 671f92d9b1aSKristof Provost flow1->if_index_in = htonl(st->if_index_in); 672f92d9b1aSKristof Provost flow1->if_index_out = htonl(st->if_index_out); 673f92d9b1aSKristof Provost flow2->if_index_in = htonl(st->if_index_out); 674f92d9b1aSKristof Provost flow2->if_index_out = htonl(st->if_index_in); 675f92d9b1aSKristof Provost 676f92d9b1aSKristof Provost flow1->flow_packets = htobe64(st->packets[0]); 677f92d9b1aSKristof Provost flow2->flow_packets = htobe64(st->packets[1]); 678f92d9b1aSKristof Provost flow1->flow_octets = htobe64(st->bytes[0]); 679f92d9b1aSKristof Provost flow2->flow_octets = htobe64(st->bytes[1]); 680f92d9b1aSKristof Provost 681f92d9b1aSKristof Provost /* 682f92d9b1aSKristof Provost * Pretend the flow was created when the machine came up when creation 683f92d9b1aSKristof Provost * is in the future of the last time a package was seen due to pfsync. 684f92d9b1aSKristof Provost */ 685f92d9b1aSKristof Provost if (st->creation > st->expire) 686f92d9b1aSKristof Provost flow1->flow_start = flow2->flow_start = htobe64((time_second - 687f92d9b1aSKristof Provost time_uptime)*1000); 688f92d9b1aSKristof Provost else 68904932601SKristof Provost flow1->flow_start = flow2->flow_start = htobe64((pf_get_time() - 69004932601SKristof Provost (pf_get_uptime() - st->creation))); 69104932601SKristof Provost flow1->flow_finish = flow2->flow_finish = htobe64((pf_get_time() - 69204932601SKristof Provost (pf_get_uptime() - st->expire))); 693f92d9b1aSKristof Provost 694f92d9b1aSKristof Provost flow1->protocol = flow2->protocol = sk->proto; 695e5c64b26SKajetan Staszkiewicz flow1->tos = flow2->tos = st->rule->tos; 696f92d9b1aSKristof Provost } 697f92d9b1aSKristof Provost 698f92d9b1aSKristof Provost static void 699f92d9b1aSKristof Provost copy_flow_ipfix_6_data(struct pflow_ipfix_flow6 *flow1, 700baf9b6d0SKristof Provost struct pflow_ipfix_flow6 *flow2, const struct pf_kstate *st, 701f92d9b1aSKristof Provost struct pf_state_key *sk, struct pflow_softc *sc, int src, int dst) 702f92d9b1aSKristof Provost { 703f92d9b1aSKristof Provost bcopy(&sk->addr[src].v6, &flow1->src_ip, sizeof(flow1->src_ip)); 704f92d9b1aSKristof Provost bcopy(&sk->addr[src].v6, &flow2->dest_ip, sizeof(flow2->dest_ip)); 705f92d9b1aSKristof Provost flow1->src_port = flow2->dest_port = sk->port[src]; 706f92d9b1aSKristof Provost bcopy(&sk->addr[dst].v6, &flow1->dest_ip, sizeof(flow1->dest_ip)); 707f92d9b1aSKristof Provost bcopy(&sk->addr[dst].v6, &flow2->src_ip, sizeof(flow2->src_ip)); 708f92d9b1aSKristof Provost flow1->dest_port = flow2->src_port = sk->port[dst]; 709f92d9b1aSKristof Provost 710f92d9b1aSKristof Provost flow1->if_index_in = htonl(st->if_index_in); 711f92d9b1aSKristof Provost flow1->if_index_out = htonl(st->if_index_out); 712f92d9b1aSKristof Provost flow2->if_index_in = htonl(st->if_index_out); 713f92d9b1aSKristof Provost flow2->if_index_out = htonl(st->if_index_in); 714f92d9b1aSKristof Provost 715f92d9b1aSKristof Provost flow1->flow_packets = htobe64(st->packets[0]); 716f92d9b1aSKristof Provost flow2->flow_packets = htobe64(st->packets[1]); 717f92d9b1aSKristof Provost flow1->flow_octets = htobe64(st->bytes[0]); 718f92d9b1aSKristof Provost flow2->flow_octets = htobe64(st->bytes[1]); 719f92d9b1aSKristof Provost 720f92d9b1aSKristof Provost /* 721f92d9b1aSKristof Provost * Pretend the flow was created when the machine came up when creation 722f92d9b1aSKristof Provost * is in the future of the last time a package was seen due to pfsync. 723f92d9b1aSKristof Provost */ 724f92d9b1aSKristof Provost if (st->creation > st->expire) 725f92d9b1aSKristof Provost flow1->flow_start = flow2->flow_start = htobe64((time_second - 726f92d9b1aSKristof Provost time_uptime)*1000); 727f92d9b1aSKristof Provost else 72804932601SKristof Provost flow1->flow_start = flow2->flow_start = htobe64((pf_get_time() - 72904932601SKristof Provost (pf_get_uptime() - st->creation))); 73004932601SKristof Provost flow1->flow_finish = flow2->flow_finish = htobe64((pf_get_time() - 73104932601SKristof Provost (pf_get_uptime() - st->expire))); 732f92d9b1aSKristof Provost 733f92d9b1aSKristof Provost flow1->protocol = flow2->protocol = sk->proto; 734e5c64b26SKajetan Staszkiewicz flow1->tos = flow2->tos = st->rule->tos; 735f92d9b1aSKristof Provost } 736f92d9b1aSKristof Provost 737baf9b6d0SKristof Provost static void 738fc6e5069SKristof Provost copy_nat_ipfix_4_data(struct pflow_ipfix_nat4 *nat1, 739fc6e5069SKristof Provost struct pflow_ipfix_nat4 *nat2, const struct pf_kstate *st, 740fc6e5069SKristof Provost struct pf_state_key *sk, struct pflow_softc *sc, int src, int dst) 741fc6e5069SKristof Provost { 742fc6e5069SKristof Provost nat1->src_ip = nat2->dest_ip = st->key[PF_SK_STACK]->addr[src].v4.s_addr; 743fc6e5069SKristof Provost nat1->src_port = nat2->dest_port = st->key[PF_SK_STACK]->port[src]; 744fc6e5069SKristof Provost nat1->dest_ip = nat2->src_ip = st->key[PF_SK_STACK]->addr[dst].v4.s_addr; 745fc6e5069SKristof Provost nat1->dest_port = nat2->src_port = st->key[PF_SK_STACK]->port[dst]; 746fc6e5069SKristof Provost nat1->postnat_src_ip = nat2->postnat_dest_ip = st->key[PF_SK_WIRE]->addr[src].v4.s_addr; 747fc6e5069SKristof Provost nat1->postnat_src_port = nat2->postnat_dest_port = st->key[PF_SK_WIRE]->port[src]; 748fc6e5069SKristof Provost nat1->postnat_dest_ip = nat2->postnat_src_ip = st->key[PF_SK_WIRE]->addr[dst].v4.s_addr; 749fc6e5069SKristof Provost nat1->postnat_dest_port = nat2->postnat_src_port = st->key[PF_SK_WIRE]->port[dst]; 750fc6e5069SKristof Provost nat1->protocol = nat2->protocol = sk->proto; 751fc6e5069SKristof Provost 752fc6e5069SKristof Provost /* 753fc6e5069SKristof Provost * Because we have to generate a create and delete event we'll fill out the 754fc6e5069SKristof Provost * timestamp and nat_event fields when we transmit. As opposed to doing this 755fc6e5069SKristof Provost * work a second time. 756fc6e5069SKristof Provost */ 757fc6e5069SKristof Provost } 758fc6e5069SKristof Provost 759fc6e5069SKristof Provost static void 760baf9b6d0SKristof Provost export_pflow(const struct pf_kstate *st) 761f92d9b1aSKristof Provost { 762f92d9b1aSKristof Provost struct pflow_softc *sc = NULL; 763f92d9b1aSKristof Provost struct pf_state_key *sk; 764f92d9b1aSKristof Provost 765f92d9b1aSKristof Provost NET_EPOCH_ASSERT(); 766f92d9b1aSKristof Provost 767221d459fSKristof Provost /* e.g. if pf_state_key_attach() fails. */ 768221d459fSKristof Provost if (st->key[PF_SK_STACK] == NULL || st->key[PF_SK_WIRE] == NULL) 769221d459fSKristof Provost return; 770221d459fSKristof Provost 771f92d9b1aSKristof Provost sk = st->key[st->direction == PF_IN ? PF_SK_WIRE : PF_SK_STACK]; 772f92d9b1aSKristof Provost 773f92d9b1aSKristof Provost CK_LIST_FOREACH(sc, &V_pflowif_list, sc_next) { 774f92d9b1aSKristof Provost PFLOW_LOCK(sc); 775f92d9b1aSKristof Provost switch (sc->sc_version) { 776f92d9b1aSKristof Provost case PFLOW_PROTO_5: 777f92d9b1aSKristof Provost if (sk->af == AF_INET) 778f92d9b1aSKristof Provost export_pflow_if(st, sk, sc); 779f92d9b1aSKristof Provost break; 780f92d9b1aSKristof Provost case PFLOW_PROTO_10: 781f92d9b1aSKristof Provost if (sk->af == AF_INET || sk->af == AF_INET6) 782f92d9b1aSKristof Provost export_pflow_if(st, sk, sc); 783f92d9b1aSKristof Provost break; 784f92d9b1aSKristof Provost default: /* NOTREACHED */ 785f92d9b1aSKristof Provost break; 786f92d9b1aSKristof Provost } 787f92d9b1aSKristof Provost PFLOW_UNLOCK(sc); 788f92d9b1aSKristof Provost } 789f92d9b1aSKristof Provost } 790f92d9b1aSKristof Provost 791f92d9b1aSKristof Provost static int 792baf9b6d0SKristof Provost export_pflow_if(const struct pf_kstate *st, struct pf_state_key *sk, 793f92d9b1aSKristof Provost struct pflow_softc *sc) 794f92d9b1aSKristof Provost { 795f92d9b1aSKristof Provost struct pf_kstate pfs_copy; 796f92d9b1aSKristof Provost u_int64_t bytes[2]; 797f92d9b1aSKristof Provost int ret = 0; 798f92d9b1aSKristof Provost 799f92d9b1aSKristof Provost if (sc->sc_version == PFLOW_PROTO_10) 800f92d9b1aSKristof Provost return (pflow_pack_flow_ipfix(st, sk, sc)); 801f92d9b1aSKristof Provost 802f92d9b1aSKristof Provost /* PFLOW_PROTO_5 */ 803f92d9b1aSKristof Provost if ((st->bytes[0] < (u_int64_t)PFLOW_MAXBYTES) 804f92d9b1aSKristof Provost && (st->bytes[1] < (u_int64_t)PFLOW_MAXBYTES)) 805f92d9b1aSKristof Provost return (pflow_pack_flow(st, sk, sc)); 806f92d9b1aSKristof Provost 807f92d9b1aSKristof Provost /* flow > PFLOW_MAXBYTES need special handling */ 808f92d9b1aSKristof Provost bcopy(st, &pfs_copy, sizeof(pfs_copy)); 809f92d9b1aSKristof Provost bytes[0] = pfs_copy.bytes[0]; 810f92d9b1aSKristof Provost bytes[1] = pfs_copy.bytes[1]; 811f92d9b1aSKristof Provost 812f92d9b1aSKristof Provost while (bytes[0] > PFLOW_MAXBYTES) { 813f92d9b1aSKristof Provost pfs_copy.bytes[0] = PFLOW_MAXBYTES; 814f92d9b1aSKristof Provost pfs_copy.bytes[1] = 0; 815f92d9b1aSKristof Provost 816f92d9b1aSKristof Provost if ((ret = pflow_pack_flow(&pfs_copy, sk, sc)) != 0) 817f92d9b1aSKristof Provost return (ret); 818f92d9b1aSKristof Provost if ((bytes[0] - PFLOW_MAXBYTES) > 0) 819f92d9b1aSKristof Provost bytes[0] -= PFLOW_MAXBYTES; 820f92d9b1aSKristof Provost } 821f92d9b1aSKristof Provost 822f92d9b1aSKristof Provost while (bytes[1] > (u_int64_t)PFLOW_MAXBYTES) { 823f92d9b1aSKristof Provost pfs_copy.bytes[1] = PFLOW_MAXBYTES; 824f92d9b1aSKristof Provost pfs_copy.bytes[0] = 0; 825f92d9b1aSKristof Provost 826f92d9b1aSKristof Provost if ((ret = pflow_pack_flow(&pfs_copy, sk, sc)) != 0) 827f92d9b1aSKristof Provost return (ret); 828f92d9b1aSKristof Provost if ((bytes[1] - PFLOW_MAXBYTES) > 0) 829f92d9b1aSKristof Provost bytes[1] -= PFLOW_MAXBYTES; 830f92d9b1aSKristof Provost } 831f92d9b1aSKristof Provost 832f92d9b1aSKristof Provost pfs_copy.bytes[0] = bytes[0]; 833f92d9b1aSKristof Provost pfs_copy.bytes[1] = bytes[1]; 834f92d9b1aSKristof Provost 835f92d9b1aSKristof Provost return (pflow_pack_flow(&pfs_copy, sk, sc)); 836f92d9b1aSKristof Provost } 837f92d9b1aSKristof Provost 838f92d9b1aSKristof Provost static int 839f92d9b1aSKristof Provost copy_flow_to_m(struct pflow_flow *flow, struct pflow_softc *sc) 840f92d9b1aSKristof Provost { 841f92d9b1aSKristof Provost int ret = 0; 842f92d9b1aSKristof Provost 843f92d9b1aSKristof Provost PFLOW_ASSERT(sc); 844f92d9b1aSKristof Provost 845f92d9b1aSKristof Provost if (sc->sc_mbuf == NULL) { 846f92d9b1aSKristof Provost if ((sc->sc_mbuf = pflow_get_mbuf(sc, 0)) == NULL) 847f92d9b1aSKristof Provost return (ENOBUFS); 848f92d9b1aSKristof Provost } 849f92d9b1aSKristof Provost m_copyback(sc->sc_mbuf, PFLOW_HDRLEN + 850f92d9b1aSKristof Provost (sc->sc_count * sizeof(struct pflow_flow)), 851f92d9b1aSKristof Provost sizeof(struct pflow_flow), (caddr_t)flow); 852f92d9b1aSKristof Provost 8532be6f757SKristof Provost pflowstat_inc(pflow_flows); 854f92d9b1aSKristof Provost sc->sc_gcounter++; 855f92d9b1aSKristof Provost sc->sc_count++; 856f92d9b1aSKristof Provost 857f92d9b1aSKristof Provost if (sc->sc_count >= sc->sc_maxcount) 858f92d9b1aSKristof Provost ret = pflow_sendout_v5(sc); 859f92d9b1aSKristof Provost 860f92d9b1aSKristof Provost return(ret); 861f92d9b1aSKristof Provost } 862f92d9b1aSKristof Provost 863f92d9b1aSKristof Provost static int 864f92d9b1aSKristof Provost copy_flow_ipfix_4_to_m(struct pflow_ipfix_flow4 *flow, struct pflow_softc *sc) 865f92d9b1aSKristof Provost { 866f92d9b1aSKristof Provost int ret = 0; 867f92d9b1aSKristof Provost 868f92d9b1aSKristof Provost PFLOW_ASSERT(sc); 869f92d9b1aSKristof Provost 870f92d9b1aSKristof Provost if (sc->sc_mbuf == NULL) { 871f92d9b1aSKristof Provost if ((sc->sc_mbuf = 872f92d9b1aSKristof Provost pflow_get_mbuf(sc, PFLOW_IPFIX_TMPL_IPV4_ID)) == NULL) { 873f92d9b1aSKristof Provost return (ENOBUFS); 874f92d9b1aSKristof Provost } 875f92d9b1aSKristof Provost sc->sc_count4 = 0; 876f92d9b1aSKristof Provost callout_reset(&sc->sc_tmo, PFLOW_TIMEOUT * hz, 877f92d9b1aSKristof Provost pflow_timeout, sc); 878f92d9b1aSKristof Provost } 879f92d9b1aSKristof Provost m_copyback(sc->sc_mbuf, PFLOW_SET_HDRLEN + 880f92d9b1aSKristof Provost (sc->sc_count4 * sizeof(struct pflow_ipfix_flow4)), 881f92d9b1aSKristof Provost sizeof(struct pflow_ipfix_flow4), (caddr_t)flow); 882f92d9b1aSKristof Provost 8832be6f757SKristof Provost pflowstat_inc(pflow_flows); 884f92d9b1aSKristof Provost sc->sc_gcounter++; 885f92d9b1aSKristof Provost sc->sc_count4++; 886f92d9b1aSKristof Provost 887f92d9b1aSKristof Provost if (sc->sc_count4 >= sc->sc_maxcount4) 888fc6e5069SKristof Provost ret = pflow_sendout_ipfix(sc, PFLOW_INET); 889f92d9b1aSKristof Provost return(ret); 890f92d9b1aSKristof Provost } 891f92d9b1aSKristof Provost 892f92d9b1aSKristof Provost static int 893f92d9b1aSKristof Provost copy_flow_ipfix_6_to_m(struct pflow_ipfix_flow6 *flow, struct pflow_softc *sc) 894f92d9b1aSKristof Provost { 895f92d9b1aSKristof Provost int ret = 0; 896f92d9b1aSKristof Provost 897f92d9b1aSKristof Provost PFLOW_ASSERT(sc); 898f92d9b1aSKristof Provost 899f92d9b1aSKristof Provost if (sc->sc_mbuf6 == NULL) { 900f92d9b1aSKristof Provost if ((sc->sc_mbuf6 = 901f92d9b1aSKristof Provost pflow_get_mbuf(sc, PFLOW_IPFIX_TMPL_IPV6_ID)) == NULL) { 902f92d9b1aSKristof Provost return (ENOBUFS); 903f92d9b1aSKristof Provost } 904f92d9b1aSKristof Provost sc->sc_count6 = 0; 905f92d9b1aSKristof Provost callout_reset(&sc->sc_tmo6, PFLOW_TIMEOUT * hz, 906f92d9b1aSKristof Provost pflow_timeout6, sc); 907f92d9b1aSKristof Provost } 908f92d9b1aSKristof Provost m_copyback(sc->sc_mbuf6, PFLOW_SET_HDRLEN + 909f92d9b1aSKristof Provost (sc->sc_count6 * sizeof(struct pflow_ipfix_flow6)), 910f92d9b1aSKristof Provost sizeof(struct pflow_ipfix_flow6), (caddr_t)flow); 911f92d9b1aSKristof Provost 9122be6f757SKristof Provost pflowstat_inc(pflow_flows); 913f92d9b1aSKristof Provost sc->sc_gcounter++; 914f92d9b1aSKristof Provost sc->sc_count6++; 915f92d9b1aSKristof Provost 916f92d9b1aSKristof Provost if (sc->sc_count6 >= sc->sc_maxcount6) 917fc6e5069SKristof Provost ret = pflow_sendout_ipfix(sc, PFLOW_INET6); 918fc6e5069SKristof Provost 919fc6e5069SKristof Provost return(ret); 920fc6e5069SKristof Provost } 921fc6e5069SKristof Provost 922fc6e5069SKristof Provost int 923fc6e5069SKristof Provost copy_nat_ipfix_4_to_m(struct pflow_ipfix_nat4 *nat, const struct pf_kstate *st, 924fc6e5069SKristof Provost struct pflow_softc *sc, uint8_t event, uint64_t timestamp) 925fc6e5069SKristof Provost { 926fc6e5069SKristof Provost int ret = 0; 927fc6e5069SKristof Provost 928fc6e5069SKristof Provost PFLOW_ASSERT(sc); 929fc6e5069SKristof Provost 930fc6e5069SKristof Provost if (sc->sc_mbuf_nat4 == NULL) { 931fc6e5069SKristof Provost if ((sc->sc_mbuf_nat4 = 932fc6e5069SKristof Provost pflow_get_mbuf(sc, PFLOW_IPFIX_TMPL_NAT44_ID)) == NULL) { 933fc6e5069SKristof Provost return (ENOBUFS); 934fc6e5069SKristof Provost } 935fc6e5069SKristof Provost sc->sc_count_nat4 = 0; 936fc6e5069SKristof Provost callout_reset(&sc->sc_tmo, PFLOW_TIMEOUT * hz, 937fc6e5069SKristof Provost pflow_timeout_nat4, sc); 938fc6e5069SKristof Provost } 939fc6e5069SKristof Provost 940fc6e5069SKristof Provost nat->nat_event = event; 941fc6e5069SKristof Provost nat->timestamp = htobe64(pf_get_time() - (pf_get_uptime() - timestamp)); 942fc6e5069SKristof Provost m_copyback(sc->sc_mbuf_nat4, PFLOW_SET_HDRLEN + 943fc6e5069SKristof Provost (sc->sc_count_nat4 * sizeof(struct pflow_ipfix_nat4)), 944fc6e5069SKristof Provost sizeof(struct pflow_ipfix_nat4), (caddr_t)nat); 945fc6e5069SKristof Provost sc->sc_count_nat4++; 946fc6e5069SKristof Provost 9472be6f757SKristof Provost pflowstat_inc(pflow_flows); 948fc6e5069SKristof Provost sc->sc_gcounter++; 9492be6f757SKristof Provost 950fc6e5069SKristof Provost if (sc->sc_count_nat4 >= sc->sc_maxcount_nat4) 951fc6e5069SKristof Provost ret = pflow_sendout_ipfix(sc, PFLOW_NAT4); 952f92d9b1aSKristof Provost 953f92d9b1aSKristof Provost return (ret); 954f92d9b1aSKristof Provost } 955f92d9b1aSKristof Provost 956f92d9b1aSKristof Provost static int 957baf9b6d0SKristof Provost pflow_pack_flow(const struct pf_kstate *st, struct pf_state_key *sk, 958f92d9b1aSKristof Provost struct pflow_softc *sc) 959f92d9b1aSKristof Provost { 960f92d9b1aSKristof Provost struct pflow_flow flow1; 961f92d9b1aSKristof Provost struct pflow_flow flow2; 962f92d9b1aSKristof Provost int ret = 0; 963f92d9b1aSKristof Provost 964f92d9b1aSKristof Provost bzero(&flow1, sizeof(flow1)); 965f92d9b1aSKristof Provost bzero(&flow2, sizeof(flow2)); 966f92d9b1aSKristof Provost 967f92d9b1aSKristof Provost if (st->direction == PF_OUT) 968f92d9b1aSKristof Provost copy_flow_data(&flow1, &flow2, st, sk, 1, 0); 969f92d9b1aSKristof Provost else 970f92d9b1aSKristof Provost copy_flow_data(&flow1, &flow2, st, sk, 0, 1); 971f92d9b1aSKristof Provost 972f92d9b1aSKristof Provost if (st->bytes[0] != 0) /* first flow from state */ 973f92d9b1aSKristof Provost ret = copy_flow_to_m(&flow1, sc); 974f92d9b1aSKristof Provost 975f92d9b1aSKristof Provost if (st->bytes[1] != 0) /* second flow from state */ 976f92d9b1aSKristof Provost ret = copy_flow_to_m(&flow2, sc); 977f92d9b1aSKristof Provost 978f92d9b1aSKristof Provost return (ret); 979f92d9b1aSKristof Provost } 980f92d9b1aSKristof Provost 981fc6e5069SKristof Provost static bool 982fc6e5069SKristof Provost pflow_is_natd(const struct pf_kstate *st) 983fc6e5069SKristof Provost { 984fc6e5069SKristof Provost /* If ports or addresses are different we've been NAT-ed. */ 985fc6e5069SKristof Provost return (memcmp(st->key[PF_SK_WIRE], st->key[PF_SK_STACK], 986fc6e5069SKristof Provost sizeof(struct pf_addr) * 2 + sizeof(uint16_t) * 2) != 0); 987fc6e5069SKristof Provost } 988fc6e5069SKristof Provost 989f92d9b1aSKristof Provost static int 990baf9b6d0SKristof Provost pflow_pack_flow_ipfix(const struct pf_kstate *st, struct pf_state_key *sk, 991f92d9b1aSKristof Provost struct pflow_softc *sc) 992f92d9b1aSKristof Provost { 993f92d9b1aSKristof Provost struct pflow_ipfix_flow4 flow4_1, flow4_2; 994fc6e5069SKristof Provost struct pflow_ipfix_nat4 nat4_1, nat4_2; 995f92d9b1aSKristof Provost struct pflow_ipfix_flow6 flow6_1, flow6_2; 996f92d9b1aSKristof Provost int ret = 0; 997fc6e5069SKristof Provost bool nat = false; 998fc6e5069SKristof Provost 99908b53c6eSKristof Provost switch (sk->af) { 100008b53c6eSKristof Provost case AF_INET: 1001f92d9b1aSKristof Provost bzero(&flow4_1, sizeof(flow4_1)); 1002f92d9b1aSKristof Provost bzero(&flow4_2, sizeof(flow4_2)); 1003f92d9b1aSKristof Provost 1004fc6e5069SKristof Provost nat = pflow_is_natd(st); 1005fc6e5069SKristof Provost 1006f92d9b1aSKristof Provost if (st->direction == PF_OUT) 1007f92d9b1aSKristof Provost copy_flow_ipfix_4_data(&flow4_1, &flow4_2, st, sk, sc, 1008f92d9b1aSKristof Provost 1, 0); 1009f92d9b1aSKristof Provost else 1010f92d9b1aSKristof Provost copy_flow_ipfix_4_data(&flow4_1, &flow4_2, st, sk, sc, 1011f92d9b1aSKristof Provost 0, 1); 1012f92d9b1aSKristof Provost 1013fc6e5069SKristof Provost if (nat) 1014fc6e5069SKristof Provost copy_nat_ipfix_4_data(&nat4_1, &nat4_2, st, sk, sc, 1, 0); 1015fc6e5069SKristof Provost 1016fc6e5069SKristof Provost if (st->bytes[0] != 0) /* first flow from state */ { 1017f92d9b1aSKristof Provost ret = copy_flow_ipfix_4_to_m(&flow4_1, sc); 1018f92d9b1aSKristof Provost 1019fc6e5069SKristof Provost if (ret == 0 && nat) { 1020fc6e5069SKristof Provost ret = copy_nat_ipfix_4_to_m(&nat4_1, st, sc, 1021fc6e5069SKristof Provost PFIX_NAT_EVENT_SESSION_CREATE, st->creation); 1022fc6e5069SKristof Provost ret |= copy_nat_ipfix_4_to_m(&nat4_1, st, sc, 1023fc6e5069SKristof Provost PFIX_NAT_EVENT_SESSION_DELETE, st->expire); 1024fc6e5069SKristof Provost } 1025fc6e5069SKristof Provost } 1026fc6e5069SKristof Provost 1027fc6e5069SKristof Provost if (st->bytes[1] != 0) /* second flow from state */ { 1028f92d9b1aSKristof Provost ret = copy_flow_ipfix_4_to_m(&flow4_2, sc); 1029fc6e5069SKristof Provost 1030fc6e5069SKristof Provost if (ret == 0 && nat) { 1031fc6e5069SKristof Provost ret = copy_nat_ipfix_4_to_m(&nat4_2, st, sc, 1032fc6e5069SKristof Provost PFIX_NAT_EVENT_SESSION_CREATE, st->creation); 1033fc6e5069SKristof Provost ret |= copy_nat_ipfix_4_to_m(&nat4_2, st, sc, 1034fc6e5069SKristof Provost PFIX_NAT_EVENT_SESSION_DELETE, st->expire); 1035fc6e5069SKristof Provost } 1036fc6e5069SKristof Provost } 103708b53c6eSKristof Provost break; 103808b53c6eSKristof Provost case AF_INET6: 1039f92d9b1aSKristof Provost bzero(&flow6_1, sizeof(flow6_1)); 1040f92d9b1aSKristof Provost bzero(&flow6_2, sizeof(flow6_2)); 1041f92d9b1aSKristof Provost 1042f92d9b1aSKristof Provost if (st->direction == PF_OUT) 1043f92d9b1aSKristof Provost copy_flow_ipfix_6_data(&flow6_1, &flow6_2, st, sk, sc, 1044f92d9b1aSKristof Provost 1, 0); 1045f92d9b1aSKristof Provost else 1046f92d9b1aSKristof Provost copy_flow_ipfix_6_data(&flow6_1, &flow6_2, st, sk, sc, 1047f92d9b1aSKristof Provost 0, 1); 1048f92d9b1aSKristof Provost 1049f92d9b1aSKristof Provost if (st->bytes[0] != 0) /* first flow from state */ 1050f92d9b1aSKristof Provost ret = copy_flow_ipfix_6_to_m(&flow6_1, sc); 1051f92d9b1aSKristof Provost 1052f92d9b1aSKristof Provost if (st->bytes[1] != 0) /* second flow from state */ 1053f92d9b1aSKristof Provost ret = copy_flow_ipfix_6_to_m(&flow6_2, sc); 105408b53c6eSKristof Provost break; 1055f92d9b1aSKristof Provost } 1056f92d9b1aSKristof Provost return (ret); 1057f92d9b1aSKristof Provost } 1058f92d9b1aSKristof Provost 1059f92d9b1aSKristof Provost static void 1060f92d9b1aSKristof Provost pflow_timeout(void *v) 1061f92d9b1aSKristof Provost { 1062f92d9b1aSKristof Provost struct pflow_softc *sc = v; 1063f92d9b1aSKristof Provost 1064f92d9b1aSKristof Provost PFLOW_ASSERT(sc); 1065f92d9b1aSKristof Provost CURVNET_SET(sc->sc_vnet); 1066f92d9b1aSKristof Provost 1067f92d9b1aSKristof Provost switch (sc->sc_version) { 1068f92d9b1aSKristof Provost case PFLOW_PROTO_5: 1069f92d9b1aSKristof Provost pflow_sendout_v5(sc); 1070f92d9b1aSKristof Provost break; 1071f92d9b1aSKristof Provost case PFLOW_PROTO_10: 1072fc6e5069SKristof Provost pflow_sendout_ipfix(sc, PFLOW_INET); 1073f92d9b1aSKristof Provost break; 1074f92d9b1aSKristof Provost default: /* NOTREACHED */ 1075f92d9b1aSKristof Provost panic("Unsupported version %d", sc->sc_version); 1076f92d9b1aSKristof Provost break; 1077f92d9b1aSKristof Provost } 1078f92d9b1aSKristof Provost 1079f92d9b1aSKristof Provost CURVNET_RESTORE(); 1080f92d9b1aSKristof Provost } 1081f92d9b1aSKristof Provost 1082f92d9b1aSKristof Provost static void 1083f92d9b1aSKristof Provost pflow_timeout6(void *v) 1084f92d9b1aSKristof Provost { 1085f92d9b1aSKristof Provost struct pflow_softc *sc = v; 1086f92d9b1aSKristof Provost 1087f92d9b1aSKristof Provost PFLOW_ASSERT(sc); 1088f92d9b1aSKristof Provost 1089f92d9b1aSKristof Provost if (sc->sc_version != PFLOW_PROTO_10) 1090f92d9b1aSKristof Provost return; 1091f92d9b1aSKristof Provost 1092f92d9b1aSKristof Provost CURVNET_SET(sc->sc_vnet); 1093fc6e5069SKristof Provost pflow_sendout_ipfix(sc, PFLOW_INET6); 1094f92d9b1aSKristof Provost CURVNET_RESTORE(); 1095f92d9b1aSKristof Provost } 1096f92d9b1aSKristof Provost 1097f92d9b1aSKristof Provost static void 1098f92d9b1aSKristof Provost pflow_timeout_tmpl(void *v) 1099f92d9b1aSKristof Provost { 1100f92d9b1aSKristof Provost struct pflow_softc *sc = v; 1101f92d9b1aSKristof Provost 1102f92d9b1aSKristof Provost PFLOW_ASSERT(sc); 1103f92d9b1aSKristof Provost 1104f92d9b1aSKristof Provost if (sc->sc_version != PFLOW_PROTO_10) 1105f92d9b1aSKristof Provost return; 1106f92d9b1aSKristof Provost 1107f92d9b1aSKristof Provost CURVNET_SET(sc->sc_vnet); 1108f92d9b1aSKristof Provost pflow_sendout_ipfix_tmpl(sc); 1109f92d9b1aSKristof Provost CURVNET_RESTORE(); 1110f92d9b1aSKristof Provost } 1111f92d9b1aSKristof Provost 1112f92d9b1aSKristof Provost static void 1113fc6e5069SKristof Provost pflow_timeout_nat4(void *v) 1114fc6e5069SKristof Provost { 1115fc6e5069SKristof Provost struct pflow_softc *sc = v; 1116fc6e5069SKristof Provost 1117fc6e5069SKristof Provost PFLOW_ASSERT(sc); 1118fc6e5069SKristof Provost 1119fc6e5069SKristof Provost if (sc->sc_version != PFLOW_PROTO_10) 1120fc6e5069SKristof Provost return; 1121fc6e5069SKristof Provost 1122fc6e5069SKristof Provost CURVNET_SET(sc->sc_vnet); 1123fc6e5069SKristof Provost pflow_sendout_ipfix(sc, PFLOW_NAT4); 1124fc6e5069SKristof Provost CURVNET_RESTORE(); 1125fc6e5069SKristof Provost } 1126fc6e5069SKristof Provost 1127fc6e5069SKristof Provost static void 1128f92d9b1aSKristof Provost pflow_flush(struct pflow_softc *sc) 1129f92d9b1aSKristof Provost { 1130f92d9b1aSKristof Provost PFLOW_ASSERT(sc); 1131f92d9b1aSKristof Provost 1132f92d9b1aSKristof Provost switch (sc->sc_version) { 1133f92d9b1aSKristof Provost case PFLOW_PROTO_5: 1134f92d9b1aSKristof Provost pflow_sendout_v5(sc); 1135f92d9b1aSKristof Provost break; 1136f92d9b1aSKristof Provost case PFLOW_PROTO_10: 1137fc6e5069SKristof Provost pflow_sendout_ipfix(sc, PFLOW_INET); 1138fc6e5069SKristof Provost pflow_sendout_ipfix(sc, PFLOW_INET6); 1139fc6e5069SKristof Provost pflow_sendout_ipfix(sc, PFLOW_NAT4); 1140f92d9b1aSKristof Provost break; 1141f92d9b1aSKristof Provost default: /* NOTREACHED */ 1142f92d9b1aSKristof Provost break; 1143f92d9b1aSKristof Provost } 1144f92d9b1aSKristof Provost } 1145f92d9b1aSKristof Provost 1146f92d9b1aSKristof Provost static int 1147f92d9b1aSKristof Provost pflow_sendout_v5(struct pflow_softc *sc) 1148f92d9b1aSKristof Provost { 1149f92d9b1aSKristof Provost struct mbuf *m = sc->sc_mbuf; 1150f92d9b1aSKristof Provost struct pflow_header *h; 1151f92d9b1aSKristof Provost struct timespec tv; 1152f92d9b1aSKristof Provost 1153f92d9b1aSKristof Provost PFLOW_ASSERT(sc); 1154f92d9b1aSKristof Provost 1155f92d9b1aSKristof Provost if (m == NULL) 1156f92d9b1aSKristof Provost return (0); 1157f92d9b1aSKristof Provost 1158f92d9b1aSKristof Provost sc->sc_mbuf = NULL; 1159f92d9b1aSKristof Provost 11602be6f757SKristof Provost pflowstat_inc(pflow_packets); 1161f92d9b1aSKristof Provost h = mtod(m, struct pflow_header *); 1162f92d9b1aSKristof Provost h->count = htons(sc->sc_count); 1163f92d9b1aSKristof Provost 1164f92d9b1aSKristof Provost /* populate pflow_header */ 1165f92d9b1aSKristof Provost h->uptime_ms = htonl(time_uptime * 1000); 1166f92d9b1aSKristof Provost 1167f92d9b1aSKristof Provost getnanotime(&tv); 1168f92d9b1aSKristof Provost h->time_sec = htonl(tv.tv_sec); /* XXX 2038 */ 1169f92d9b1aSKristof Provost h->time_nanosec = htonl(tv.tv_nsec); 1170f92d9b1aSKristof Provost if (mbufq_enqueue(&sc->sc_outputqueue, m) == 0) 1171f92d9b1aSKristof Provost swi_sched(sc->sc_swi_cookie, 0); 1172f92d9b1aSKristof Provost 1173f92d9b1aSKristof Provost return (0); 1174f92d9b1aSKristof Provost } 1175f92d9b1aSKristof Provost 1176f92d9b1aSKristof Provost static int 1177fc6e5069SKristof Provost pflow_sendout_ipfix(struct pflow_softc *sc, enum pflow_family_t af) 1178f92d9b1aSKristof Provost { 1179f92d9b1aSKristof Provost struct mbuf *m; 1180f92d9b1aSKristof Provost struct pflow_v10_header *h10; 1181f92d9b1aSKristof Provost struct pflow_set_header *set_hdr; 1182f92d9b1aSKristof Provost u_int32_t count; 1183f92d9b1aSKristof Provost int set_length; 1184f92d9b1aSKristof Provost 1185f92d9b1aSKristof Provost PFLOW_ASSERT(sc); 1186f92d9b1aSKristof Provost 1187f92d9b1aSKristof Provost switch (af) { 1188fc6e5069SKristof Provost case PFLOW_INET: 1189f92d9b1aSKristof Provost m = sc->sc_mbuf; 1190f92d9b1aSKristof Provost callout_stop(&sc->sc_tmo); 1191f92d9b1aSKristof Provost if (m == NULL) 1192f92d9b1aSKristof Provost return (0); 1193f92d9b1aSKristof Provost sc->sc_mbuf = NULL; 1194f92d9b1aSKristof Provost count = sc->sc_count4; 1195f92d9b1aSKristof Provost set_length = sizeof(struct pflow_set_header) 1196f92d9b1aSKristof Provost + sc->sc_count4 * sizeof(struct pflow_ipfix_flow4); 1197f92d9b1aSKristof Provost break; 1198fc6e5069SKristof Provost case PFLOW_INET6: 1199f92d9b1aSKristof Provost m = sc->sc_mbuf6; 1200f92d9b1aSKristof Provost callout_stop(&sc->sc_tmo6); 1201f92d9b1aSKristof Provost if (m == NULL) 1202f92d9b1aSKristof Provost return (0); 1203f92d9b1aSKristof Provost sc->sc_mbuf6 = NULL; 1204f92d9b1aSKristof Provost count = sc->sc_count6; 1205f92d9b1aSKristof Provost set_length = sizeof(struct pflow_set_header) 1206f92d9b1aSKristof Provost + sc->sc_count6 * sizeof(struct pflow_ipfix_flow6); 1207f92d9b1aSKristof Provost break; 1208fc6e5069SKristof Provost case PFLOW_NAT4: 1209fc6e5069SKristof Provost m = sc->sc_mbuf_nat4; 1210fc6e5069SKristof Provost callout_stop(&sc->sc_tmo_nat4); 1211fc6e5069SKristof Provost if (m == NULL) 1212fc6e5069SKristof Provost return (0); 1213fc6e5069SKristof Provost sc->sc_mbuf_nat4 = NULL; 1214fc6e5069SKristof Provost count = sc->sc_count_nat4; 1215fc6e5069SKristof Provost set_length = sizeof(struct pflow_set_header) 1216fc6e5069SKristof Provost + sc->sc_count_nat4 * sizeof(struct pflow_ipfix_nat4); 1217fc6e5069SKristof Provost break; 1218f92d9b1aSKristof Provost default: 1219f92d9b1aSKristof Provost panic("Unsupported AF %d", af); 1220f92d9b1aSKristof Provost } 1221f92d9b1aSKristof Provost 12222be6f757SKristof Provost pflowstat_inc(pflow_packets); 12232be6f757SKristof Provost 1224f92d9b1aSKristof Provost set_hdr = mtod(m, struct pflow_set_header *); 1225f92d9b1aSKristof Provost set_hdr->set_length = htons(set_length); 1226f92d9b1aSKristof Provost 1227f92d9b1aSKristof Provost /* populate pflow_header */ 1228f92d9b1aSKristof Provost M_PREPEND(m, sizeof(struct pflow_v10_header), M_NOWAIT); 1229f92d9b1aSKristof Provost if (m == NULL) { 12302be6f757SKristof Provost pflowstat_inc(pflow_onomem); 1231f92d9b1aSKristof Provost return (ENOBUFS); 1232f92d9b1aSKristof Provost } 1233f92d9b1aSKristof Provost h10 = mtod(m, struct pflow_v10_header *); 1234f92d9b1aSKristof Provost h10->version = htons(PFLOW_PROTO_10); 1235f92d9b1aSKristof Provost h10->length = htons(PFLOW_IPFIX_HDRLEN + set_length); 1236f92d9b1aSKristof Provost h10->time_sec = htonl(time_second); /* XXX 2038 */ 1237f92d9b1aSKristof Provost h10->flow_sequence = htonl(sc->sc_sequence); 1238f92d9b1aSKristof Provost sc->sc_sequence += count; 123985b71dcfSKristof Provost h10->observation_dom = htonl(sc->sc_observation_dom); 1240f92d9b1aSKristof Provost if (mbufq_enqueue(&sc->sc_outputqueue, m) == 0) 1241f92d9b1aSKristof Provost swi_sched(sc->sc_swi_cookie, 0); 1242f92d9b1aSKristof Provost 1243f92d9b1aSKristof Provost return (0); 1244f92d9b1aSKristof Provost } 1245f92d9b1aSKristof Provost 1246f92d9b1aSKristof Provost static int 1247f92d9b1aSKristof Provost pflow_sendout_ipfix_tmpl(struct pflow_softc *sc) 1248f92d9b1aSKristof Provost { 1249f92d9b1aSKristof Provost struct mbuf *m; 1250f92d9b1aSKristof Provost struct pflow_v10_header *h10; 1251f92d9b1aSKristof Provost 1252f92d9b1aSKristof Provost PFLOW_ASSERT(sc); 1253f92d9b1aSKristof Provost 1254f92d9b1aSKristof Provost m = pflow_get_mbuf(sc, 0); 1255f92d9b1aSKristof Provost if (m == NULL) 1256f92d9b1aSKristof Provost return (0); 1257f92d9b1aSKristof Provost m_copyback(m, 0, sizeof(struct pflow_ipfix_tmpl), 1258f92d9b1aSKristof Provost (caddr_t)&sc->sc_tmpl_ipfix); 1259f92d9b1aSKristof Provost 12602be6f757SKristof Provost pflowstat_inc(pflow_packets); 1261f92d9b1aSKristof Provost 1262f92d9b1aSKristof Provost /* populate pflow_header */ 1263f92d9b1aSKristof Provost M_PREPEND(m, sizeof(struct pflow_v10_header), M_NOWAIT); 1264f92d9b1aSKristof Provost if (m == NULL) { 12652be6f757SKristof Provost pflowstat_inc(pflow_onomem); 1266f92d9b1aSKristof Provost return (ENOBUFS); 1267f92d9b1aSKristof Provost } 1268f92d9b1aSKristof Provost h10 = mtod(m, struct pflow_v10_header *); 1269f92d9b1aSKristof Provost h10->version = htons(PFLOW_PROTO_10); 1270f92d9b1aSKristof Provost h10->length = htons(PFLOW_IPFIX_HDRLEN + sizeof(struct 1271f92d9b1aSKristof Provost pflow_ipfix_tmpl)); 1272f92d9b1aSKristof Provost h10->time_sec = htonl(time_second); /* XXX 2038 */ 1273f92d9b1aSKristof Provost h10->flow_sequence = htonl(sc->sc_sequence); 127485b71dcfSKristof Provost h10->observation_dom = htonl(sc->sc_observation_dom); 1275f92d9b1aSKristof Provost 1276f92d9b1aSKristof Provost callout_reset(&sc->sc_tmo_tmpl, PFLOW_TMPL_TIMEOUT * hz, 1277f92d9b1aSKristof Provost pflow_timeout_tmpl, sc); 1278f92d9b1aSKristof Provost if (mbufq_enqueue(&sc->sc_outputqueue, m) == 0) 1279f92d9b1aSKristof Provost swi_sched(sc->sc_swi_cookie, 0); 1280f92d9b1aSKristof Provost 1281f92d9b1aSKristof Provost return (0); 1282f92d9b1aSKristof Provost } 1283f92d9b1aSKristof Provost 1284f92d9b1aSKristof Provost static int 1285f92d9b1aSKristof Provost pflow_sendout_mbuf(struct pflow_softc *sc, struct mbuf *m) 1286f92d9b1aSKristof Provost { 1287f92d9b1aSKristof Provost if (sc->so == NULL) { 1288f92d9b1aSKristof Provost m_freem(m); 1289f92d9b1aSKristof Provost return (EINVAL); 1290f92d9b1aSKristof Provost } 1291f92d9b1aSKristof Provost return (sosend(sc->so, sc->sc_flowdst, NULL, m, NULL, 0, curthread)); 1292f92d9b1aSKristof Provost } 1293f92d9b1aSKristof Provost 1294f92d9b1aSKristof Provost static int 12952be6f757SKristof Provost sysctl_pflowstats(SYSCTL_HANDLER_ARGS) 12962be6f757SKristof Provost { 12972be6f757SKristof Provost struct pflowstats pflowstats; 12982be6f757SKristof Provost 12992be6f757SKristof Provost pflowstats.pflow_flows = 13002be6f757SKristof Provost counter_u64_fetch(V_pflowstats.c[pflow_flows]); 13012be6f757SKristof Provost pflowstats.pflow_packets = 13022be6f757SKristof Provost counter_u64_fetch(V_pflowstats.c[pflow_packets]); 13032be6f757SKristof Provost pflowstats.pflow_onomem = 13042be6f757SKristof Provost counter_u64_fetch(V_pflowstats.c[pflow_onomem]); 13052be6f757SKristof Provost pflowstats.pflow_oerrors = 13062be6f757SKristof Provost counter_u64_fetch(V_pflowstats.c[pflow_oerrors]); 13072be6f757SKristof Provost 13082be6f757SKristof Provost return (sysctl_handle_opaque(oidp, &pflowstats, sizeof(pflowstats), req)); 13092be6f757SKristof Provost } 13102be6f757SKristof Provost 13112be6f757SKristof Provost static int 1312f92d9b1aSKristof Provost pflow_nl_list(struct nlmsghdr *hdr, struct nl_pstate *npt) 1313f92d9b1aSKristof Provost { 1314f92d9b1aSKristof Provost struct epoch_tracker et; 1315f92d9b1aSKristof Provost struct pflow_softc *sc = NULL; 1316f92d9b1aSKristof Provost struct nl_writer *nw = npt->nw; 1317f92d9b1aSKristof Provost int error = 0; 1318f92d9b1aSKristof Provost 1319f92d9b1aSKristof Provost hdr->nlmsg_flags |= NLM_F_MULTI; 1320f92d9b1aSKristof Provost 1321f92d9b1aSKristof Provost NET_EPOCH_ENTER(et); 1322f92d9b1aSKristof Provost CK_LIST_FOREACH(sc, &V_pflowif_list, sc_next) { 1323f92d9b1aSKristof Provost if (!nlmsg_reply(nw, hdr, sizeof(struct genlmsghdr))) { 1324f92d9b1aSKristof Provost error = ENOMEM; 1325f92d9b1aSKristof Provost goto out; 1326f92d9b1aSKristof Provost } 1327f92d9b1aSKristof Provost 1328f92d9b1aSKristof Provost struct genlmsghdr *ghdr_new = nlmsg_reserve_object(nw, struct genlmsghdr); 1329f92d9b1aSKristof Provost ghdr_new->cmd = PFLOWNL_CMD_LIST; 1330f92d9b1aSKristof Provost ghdr_new->version = 0; 1331f92d9b1aSKristof Provost ghdr_new->reserved = 0; 1332f92d9b1aSKristof Provost 1333f92d9b1aSKristof Provost nlattr_add_u32(nw, PFLOWNL_L_ID, sc->sc_id); 1334f92d9b1aSKristof Provost 1335f92d9b1aSKristof Provost if (! nlmsg_end(nw)) { 1336f92d9b1aSKristof Provost error = ENOMEM; 1337f92d9b1aSKristof Provost goto out; 1338f92d9b1aSKristof Provost } 1339f92d9b1aSKristof Provost } 1340f92d9b1aSKristof Provost 1341f92d9b1aSKristof Provost out: 1342f92d9b1aSKristof Provost NET_EPOCH_EXIT(et); 1343f92d9b1aSKristof Provost 1344f92d9b1aSKristof Provost if (error != 0) 1345f92d9b1aSKristof Provost nlmsg_abort(nw); 1346f92d9b1aSKristof Provost 1347f92d9b1aSKristof Provost return (error); 1348f92d9b1aSKristof Provost } 1349f92d9b1aSKristof Provost 1350f92d9b1aSKristof Provost static int 1351f92d9b1aSKristof Provost pflow_nl_create(struct nlmsghdr *hdr, struct nl_pstate *npt) 1352f92d9b1aSKristof Provost { 1353f92d9b1aSKristof Provost struct nl_writer *nw = npt->nw; 1354f92d9b1aSKristof Provost int error = 0; 1355f92d9b1aSKristof Provost int unit; 1356f92d9b1aSKristof Provost 1357f92d9b1aSKristof Provost if (! nlmsg_reply(nw, hdr, sizeof(struct genlmsghdr))) { 1358f92d9b1aSKristof Provost return (ENOMEM); 1359f92d9b1aSKristof Provost } 1360f92d9b1aSKristof Provost 1361f92d9b1aSKristof Provost struct genlmsghdr *ghdr_new = nlmsg_reserve_object(nw, struct genlmsghdr); 1362f92d9b1aSKristof Provost ghdr_new->cmd = PFLOWNL_CMD_CREATE; 1363f92d9b1aSKristof Provost ghdr_new->version = 0; 1364f92d9b1aSKristof Provost ghdr_new->reserved = 0; 1365f92d9b1aSKristof Provost 1366f92d9b1aSKristof Provost unit = alloc_unr(V_pflow_unr); 136763a5fe83SKristof Provost if (unit == -1) { 136863a5fe83SKristof Provost nlmsg_abort(nw); 136963a5fe83SKristof Provost return (ENOMEM); 137063a5fe83SKristof Provost } 1371f92d9b1aSKristof Provost 1372f92d9b1aSKristof Provost error = pflow_create(unit); 1373f92d9b1aSKristof Provost if (error != 0) { 1374f92d9b1aSKristof Provost free_unr(V_pflow_unr, unit); 1375f92d9b1aSKristof Provost nlmsg_abort(nw); 1376f92d9b1aSKristof Provost return (error); 1377f92d9b1aSKristof Provost } 1378f92d9b1aSKristof Provost 1379f92d9b1aSKristof Provost nlattr_add_s32(nw, PFLOWNL_CREATE_ID, unit); 1380f92d9b1aSKristof Provost 1381f92d9b1aSKristof Provost if (! nlmsg_end(nw)) { 1382f92d9b1aSKristof Provost pflow_destroy(unit, true); 1383f92d9b1aSKristof Provost return (ENOMEM); 1384f92d9b1aSKristof Provost } 1385f92d9b1aSKristof Provost 1386f92d9b1aSKristof Provost return (0); 1387f92d9b1aSKristof Provost } 1388f92d9b1aSKristof Provost 1389f92d9b1aSKristof Provost struct pflow_parsed_del { 1390f92d9b1aSKristof Provost int id; 1391f92d9b1aSKristof Provost }; 1392f92d9b1aSKristof Provost #define _OUT(_field) offsetof(struct pflow_parsed_del, _field) 1393f92d9b1aSKristof Provost static const struct nlattr_parser nla_p_del[] = { 1394f92d9b1aSKristof Provost { .type = PFLOWNL_DEL_ID, .off = _OUT(id), .cb = nlattr_get_uint32 }, 1395f92d9b1aSKristof Provost }; 1396f92d9b1aSKristof Provost #undef _OUT 1397*e9255dafSGleb Smirnoff NL_DECLARE_PARSER(del_parser, struct genlmsghdr, nlf_p_empty, nla_p_del); 1398f92d9b1aSKristof Provost 1399f92d9b1aSKristof Provost static int 1400f92d9b1aSKristof Provost pflow_nl_del(struct nlmsghdr *hdr, struct nl_pstate *npt) 1401f92d9b1aSKristof Provost { 1402f92d9b1aSKristof Provost struct pflow_parsed_del d = {}; 1403f92d9b1aSKristof Provost int error; 1404f92d9b1aSKristof Provost 1405f92d9b1aSKristof Provost error = nl_parse_nlmsg(hdr, &del_parser, npt, &d); 1406f92d9b1aSKristof Provost if (error != 0) 1407f92d9b1aSKristof Provost return (error); 1408f92d9b1aSKristof Provost 1409f92d9b1aSKristof Provost error = pflow_destroy(d.id, true); 1410f92d9b1aSKristof Provost 1411f92d9b1aSKristof Provost return (error); 1412f92d9b1aSKristof Provost } 1413f92d9b1aSKristof Provost 1414f92d9b1aSKristof Provost struct pflow_parsed_get { 1415f92d9b1aSKristof Provost int id; 1416f92d9b1aSKristof Provost }; 1417f92d9b1aSKristof Provost #define _OUT(_field) offsetof(struct pflow_parsed_get, _field) 1418f92d9b1aSKristof Provost static const struct nlattr_parser nla_p_get[] = { 1419f92d9b1aSKristof Provost { .type = PFLOWNL_GET_ID, .off = _OUT(id), .cb = nlattr_get_uint32 }, 1420f92d9b1aSKristof Provost }; 1421f92d9b1aSKristof Provost #undef _OUT 1422*e9255dafSGleb Smirnoff NL_DECLARE_PARSER(get_parser, struct genlmsghdr, nlf_p_empty, nla_p_get); 1423f92d9b1aSKristof Provost 1424f92d9b1aSKristof Provost static bool 1425f92d9b1aSKristof Provost nlattr_add_sockaddr(struct nl_writer *nw, int attr, const struct sockaddr *s) 1426f92d9b1aSKristof Provost { 1427f92d9b1aSKristof Provost int off = nlattr_add_nested(nw, attr); 1428f92d9b1aSKristof Provost if (off == 0) 1429f92d9b1aSKristof Provost return (false); 1430f92d9b1aSKristof Provost 1431f92d9b1aSKristof Provost nlattr_add_u8(nw, PFLOWNL_ADDR_FAMILY, s->sa_family); 1432f92d9b1aSKristof Provost 1433f92d9b1aSKristof Provost switch (s->sa_family) { 1434f92d9b1aSKristof Provost case AF_INET: { 1435f92d9b1aSKristof Provost const struct sockaddr_in *in = (const struct sockaddr_in *)s; 1436f92d9b1aSKristof Provost nlattr_add_u16(nw, PFLOWNL_ADDR_PORT, in->sin_port); 1437f92d9b1aSKristof Provost nlattr_add_in_addr(nw, PFLOWNL_ADDR_IP, &in->sin_addr); 1438f92d9b1aSKristof Provost break; 1439f92d9b1aSKristof Provost } 1440f92d9b1aSKristof Provost case AF_INET6: { 1441f92d9b1aSKristof Provost const struct sockaddr_in6 *in6 = (const struct sockaddr_in6 *)s; 1442f92d9b1aSKristof Provost nlattr_add_u16(nw, PFLOWNL_ADDR_PORT, in6->sin6_port); 1443f92d9b1aSKristof Provost nlattr_add_in6_addr(nw, PFLOWNL_ADDR_IP6, &in6->sin6_addr); 1444f92d9b1aSKristof Provost break; 1445f92d9b1aSKristof Provost } 1446f92d9b1aSKristof Provost default: 1447f92d9b1aSKristof Provost panic("Unknown address family %d", s->sa_family); 1448f92d9b1aSKristof Provost } 1449f92d9b1aSKristof Provost 1450f92d9b1aSKristof Provost nlattr_set_len(nw, off); 1451f92d9b1aSKristof Provost return (true); 1452f92d9b1aSKristof Provost } 1453f92d9b1aSKristof Provost 1454f92d9b1aSKristof Provost static int 1455f92d9b1aSKristof Provost pflow_nl_get(struct nlmsghdr *hdr, struct nl_pstate *npt) 1456f92d9b1aSKristof Provost { 1457f92d9b1aSKristof Provost struct epoch_tracker et; 1458f92d9b1aSKristof Provost struct pflow_parsed_get g = {}; 1459f92d9b1aSKristof Provost struct pflow_softc *sc = NULL; 1460f92d9b1aSKristof Provost struct nl_writer *nw = npt->nw; 1461f92d9b1aSKristof Provost struct genlmsghdr *ghdr_new; 1462f92d9b1aSKristof Provost int error; 1463f92d9b1aSKristof Provost 1464f92d9b1aSKristof Provost error = nl_parse_nlmsg(hdr, &get_parser, npt, &g); 1465f92d9b1aSKristof Provost if (error != 0) 1466f92d9b1aSKristof Provost return (error); 1467f92d9b1aSKristof Provost 1468f92d9b1aSKristof Provost NET_EPOCH_ENTER(et); 1469f92d9b1aSKristof Provost CK_LIST_FOREACH(sc, &V_pflowif_list, sc_next) { 1470f92d9b1aSKristof Provost if (sc->sc_id == g.id) 1471f92d9b1aSKristof Provost break; 1472f92d9b1aSKristof Provost } 1473f92d9b1aSKristof Provost if (sc == NULL) { 1474f92d9b1aSKristof Provost error = ENOENT; 1475f92d9b1aSKristof Provost goto out; 1476f92d9b1aSKristof Provost } 1477f92d9b1aSKristof Provost 1478f92d9b1aSKristof Provost if (! nlmsg_reply(nw, hdr, sizeof(struct genlmsghdr))) { 1479f92d9b1aSKristof Provost nlmsg_abort(nw); 1480f92d9b1aSKristof Provost error = ENOMEM; 1481f92d9b1aSKristof Provost goto out; 1482f92d9b1aSKristof Provost } 1483f92d9b1aSKristof Provost 1484f92d9b1aSKristof Provost ghdr_new = nlmsg_reserve_object(nw, struct genlmsghdr); 1485f92d9b1aSKristof Provost if (ghdr_new == NULL) { 1486f92d9b1aSKristof Provost nlmsg_abort(nw); 1487f92d9b1aSKristof Provost error = ENOMEM; 1488f92d9b1aSKristof Provost goto out; 1489f92d9b1aSKristof Provost } 1490f92d9b1aSKristof Provost 1491f92d9b1aSKristof Provost ghdr_new->cmd = PFLOWNL_CMD_GET; 1492f92d9b1aSKristof Provost ghdr_new->version = 0; 1493f92d9b1aSKristof Provost ghdr_new->reserved = 0; 1494f92d9b1aSKristof Provost 1495f92d9b1aSKristof Provost nlattr_add_u32(nw, PFLOWNL_GET_ID, sc->sc_id); 1496f92d9b1aSKristof Provost nlattr_add_u16(nw, PFLOWNL_GET_VERSION, sc->sc_version); 1497f92d9b1aSKristof Provost if (sc->sc_flowsrc) 1498f92d9b1aSKristof Provost nlattr_add_sockaddr(nw, PFLOWNL_GET_SRC, sc->sc_flowsrc); 1499f92d9b1aSKristof Provost if (sc->sc_flowdst) 1500f92d9b1aSKristof Provost nlattr_add_sockaddr(nw, PFLOWNL_GET_DST, sc->sc_flowdst); 150185b71dcfSKristof Provost nlattr_add_u32(nw, PFLOWNL_GET_OBSERVATION_DOMAIN, 150285b71dcfSKristof Provost sc->sc_observation_dom); 1503e95025edSKristof Provost nlattr_add_u8(nw, PFLOWNL_GET_SOCKET_STATUS, sc->so != NULL); 1504f92d9b1aSKristof Provost 1505f92d9b1aSKristof Provost if (! nlmsg_end(nw)) { 1506f92d9b1aSKristof Provost nlmsg_abort(nw); 1507f92d9b1aSKristof Provost error = ENOMEM; 1508f92d9b1aSKristof Provost } 1509f92d9b1aSKristof Provost 1510f92d9b1aSKristof Provost out: 1511f92d9b1aSKristof Provost NET_EPOCH_EXIT(et); 1512f92d9b1aSKristof Provost 1513f92d9b1aSKristof Provost return (error); 1514f92d9b1aSKristof Provost } 1515f92d9b1aSKristof Provost 1516f92d9b1aSKristof Provost struct pflow_sockaddr { 1517f92d9b1aSKristof Provost union { 1518f92d9b1aSKristof Provost struct sockaddr_in in; 1519f92d9b1aSKristof Provost struct sockaddr_in6 in6; 1520f92d9b1aSKristof Provost struct sockaddr_storage storage; 1521f92d9b1aSKristof Provost }; 1522f92d9b1aSKristof Provost }; 1523f92d9b1aSKristof Provost static bool 1524f92d9b1aSKristof Provost pflow_postparse_sockaddr(void *parsed_args, struct nl_pstate *npt __unused) 1525f92d9b1aSKristof Provost { 1526f92d9b1aSKristof Provost struct pflow_sockaddr *s = (struct pflow_sockaddr *)parsed_args; 1527f92d9b1aSKristof Provost 1528f92d9b1aSKristof Provost if (s->storage.ss_family == AF_INET) 1529f92d9b1aSKristof Provost s->storage.ss_len = sizeof(struct sockaddr_in); 1530f92d9b1aSKristof Provost else if (s->storage.ss_family == AF_INET6) 1531f92d9b1aSKristof Provost s->storage.ss_len = sizeof(struct sockaddr_in6); 1532f92d9b1aSKristof Provost else 1533f92d9b1aSKristof Provost return (false); 1534f92d9b1aSKristof Provost 1535f92d9b1aSKristof Provost return (true); 1536f92d9b1aSKristof Provost } 1537f92d9b1aSKristof Provost 1538f92d9b1aSKristof Provost #define _OUT(_field) offsetof(struct pflow_sockaddr, _field) 1539f92d9b1aSKristof Provost static struct nlattr_parser nla_p_sockaddr[] = { 1540f92d9b1aSKristof Provost { .type = PFLOWNL_ADDR_FAMILY, .off = _OUT(in.sin_family), .cb = nlattr_get_uint8 }, 1541f92d9b1aSKristof Provost { .type = PFLOWNL_ADDR_PORT, .off = _OUT(in.sin_port), .cb = nlattr_get_uint16 }, 1542f92d9b1aSKristof Provost { .type = PFLOWNL_ADDR_IP, .off = _OUT(in.sin_addr), .cb = nlattr_get_in_addr }, 1543f92d9b1aSKristof Provost { .type = PFLOWNL_ADDR_IP6, .off = _OUT(in6.sin6_addr), .cb = nlattr_get_in6_addr }, 1544f92d9b1aSKristof Provost }; 1545f92d9b1aSKristof Provost NL_DECLARE_ATTR_PARSER_EXT(addr_parser, nla_p_sockaddr, pflow_postparse_sockaddr); 1546f92d9b1aSKristof Provost #undef _OUT 1547f92d9b1aSKristof Provost 1548f92d9b1aSKristof Provost struct pflow_parsed_set { 1549f92d9b1aSKristof Provost int id; 1550f92d9b1aSKristof Provost uint16_t version; 1551f92d9b1aSKristof Provost struct sockaddr_storage src; 1552f92d9b1aSKristof Provost struct sockaddr_storage dst; 155385b71dcfSKristof Provost uint32_t observation_dom; 1554f92d9b1aSKristof Provost }; 1555f92d9b1aSKristof Provost #define _OUT(_field) offsetof(struct pflow_parsed_set, _field) 1556f92d9b1aSKristof Provost static const struct nlattr_parser nla_p_set[] = { 1557f92d9b1aSKristof Provost { .type = PFLOWNL_SET_ID, .off = _OUT(id), .cb = nlattr_get_uint32 }, 1558f92d9b1aSKristof Provost { .type = PFLOWNL_SET_VERSION, .off = _OUT(version), .cb = nlattr_get_uint16 }, 1559f92d9b1aSKristof Provost { .type = PFLOWNL_SET_SRC, .off = _OUT(src), .arg = &addr_parser, .cb = nlattr_get_nested }, 1560f92d9b1aSKristof Provost { .type = PFLOWNL_SET_DST, .off = _OUT(dst), .arg = &addr_parser, .cb = nlattr_get_nested }, 156185b71dcfSKristof Provost { .type = PFLOWNL_SET_OBSERVATION_DOMAIN, .off = _OUT(observation_dom), .cb = nlattr_get_uint32 }, 1562f92d9b1aSKristof Provost }; 1563f92d9b1aSKristof Provost #undef _OUT 1564*e9255dafSGleb Smirnoff NL_DECLARE_PARSER(set_parser, struct genlmsghdr, nlf_p_empty, nla_p_set); 1565f92d9b1aSKristof Provost 1566f92d9b1aSKristof Provost static int 1567f92d9b1aSKristof Provost pflow_set(struct pflow_softc *sc, const struct pflow_parsed_set *pflowr, struct ucred *cred) 1568f92d9b1aSKristof Provost { 1569f92d9b1aSKristof Provost struct thread *td; 1570f92d9b1aSKristof Provost struct socket *so; 1571f92d9b1aSKristof Provost int error = 0; 1572f92d9b1aSKristof Provost 1573f92d9b1aSKristof Provost td = curthread; 1574f92d9b1aSKristof Provost 1575f92d9b1aSKristof Provost PFLOW_ASSERT(sc); 1576f92d9b1aSKristof Provost 1577f92d9b1aSKristof Provost if (pflowr->version != 0) { 1578f92d9b1aSKristof Provost switch(pflowr->version) { 1579f92d9b1aSKristof Provost case PFLOW_PROTO_5: 1580f92d9b1aSKristof Provost case PFLOW_PROTO_10: 1581f92d9b1aSKristof Provost break; 1582f92d9b1aSKristof Provost default: 1583f92d9b1aSKristof Provost return(EINVAL); 1584f92d9b1aSKristof Provost } 1585f92d9b1aSKristof Provost } 1586f92d9b1aSKristof Provost 1587f92d9b1aSKristof Provost pflow_flush(sc); 1588f92d9b1aSKristof Provost 1589f92d9b1aSKristof Provost if (pflowr->dst.ss_len != 0) { 1590f92d9b1aSKristof Provost if (sc->sc_flowdst != NULL && 1591f92d9b1aSKristof Provost sc->sc_flowdst->sa_family != pflowr->dst.ss_family) { 1592f92d9b1aSKristof Provost free(sc->sc_flowdst, M_DEVBUF); 1593f92d9b1aSKristof Provost sc->sc_flowdst = NULL; 1594f92d9b1aSKristof Provost if (sc->so != NULL) { 1595f92d9b1aSKristof Provost soclose(sc->so); 1596f92d9b1aSKristof Provost sc->so = NULL; 1597f92d9b1aSKristof Provost } 1598f92d9b1aSKristof Provost } 1599f92d9b1aSKristof Provost 1600f92d9b1aSKristof Provost switch (pflowr->dst.ss_family) { 1601f92d9b1aSKristof Provost case AF_INET: 1602f92d9b1aSKristof Provost if (sc->sc_flowdst == NULL) { 1603f92d9b1aSKristof Provost if ((sc->sc_flowdst = malloc( 1604f92d9b1aSKristof Provost sizeof(struct sockaddr_in), 1605f92d9b1aSKristof Provost M_DEVBUF, M_NOWAIT)) == NULL) 1606f92d9b1aSKristof Provost return (ENOMEM); 1607f92d9b1aSKristof Provost } 1608f92d9b1aSKristof Provost memcpy(sc->sc_flowdst, &pflowr->dst, 1609f92d9b1aSKristof Provost sizeof(struct sockaddr_in)); 1610f92d9b1aSKristof Provost sc->sc_flowdst->sa_len = sizeof(struct 1611f92d9b1aSKristof Provost sockaddr_in); 1612f92d9b1aSKristof Provost break; 1613f92d9b1aSKristof Provost case AF_INET6: 1614f92d9b1aSKristof Provost if (sc->sc_flowdst == NULL) { 1615f92d9b1aSKristof Provost if ((sc->sc_flowdst = malloc( 1616f92d9b1aSKristof Provost sizeof(struct sockaddr_in6), 1617f92d9b1aSKristof Provost M_DEVBUF, M_NOWAIT)) == NULL) 1618f92d9b1aSKristof Provost return (ENOMEM); 1619f92d9b1aSKristof Provost } 1620f92d9b1aSKristof Provost memcpy(sc->sc_flowdst, &pflowr->dst, 1621f92d9b1aSKristof Provost sizeof(struct sockaddr_in6)); 1622f92d9b1aSKristof Provost sc->sc_flowdst->sa_len = sizeof(struct 1623f92d9b1aSKristof Provost sockaddr_in6); 1624f92d9b1aSKristof Provost break; 1625f92d9b1aSKristof Provost default: 1626f92d9b1aSKristof Provost break; 1627f92d9b1aSKristof Provost } 1628f92d9b1aSKristof Provost } 1629f92d9b1aSKristof Provost 1630f92d9b1aSKristof Provost if (pflowr->src.ss_len != 0) { 1631f92d9b1aSKristof Provost if (sc->sc_flowsrc != NULL) 1632f92d9b1aSKristof Provost free(sc->sc_flowsrc, M_DEVBUF); 1633f92d9b1aSKristof Provost sc->sc_flowsrc = NULL; 1634f92d9b1aSKristof Provost if (sc->so != NULL) { 1635f92d9b1aSKristof Provost soclose(sc->so); 1636f92d9b1aSKristof Provost sc->so = NULL; 1637f92d9b1aSKristof Provost } 1638f92d9b1aSKristof Provost switch(pflowr->src.ss_family) { 1639f92d9b1aSKristof Provost case AF_INET: 1640f92d9b1aSKristof Provost if ((sc->sc_flowsrc = malloc( 1641f92d9b1aSKristof Provost sizeof(struct sockaddr_in), 1642f92d9b1aSKristof Provost M_DEVBUF, M_NOWAIT)) == NULL) 1643f92d9b1aSKristof Provost return (ENOMEM); 1644f92d9b1aSKristof Provost memcpy(sc->sc_flowsrc, &pflowr->src, 1645f92d9b1aSKristof Provost sizeof(struct sockaddr_in)); 1646f92d9b1aSKristof Provost sc->sc_flowsrc->sa_len = sizeof(struct 1647f92d9b1aSKristof Provost sockaddr_in); 1648f92d9b1aSKristof Provost break; 1649f92d9b1aSKristof Provost case AF_INET6: 1650f92d9b1aSKristof Provost if ((sc->sc_flowsrc = malloc( 1651f92d9b1aSKristof Provost sizeof(struct sockaddr_in6), 1652f92d9b1aSKristof Provost M_DEVBUF, M_NOWAIT)) == NULL) 1653f92d9b1aSKristof Provost return (ENOMEM); 1654f92d9b1aSKristof Provost memcpy(sc->sc_flowsrc, &pflowr->src, 1655f92d9b1aSKristof Provost sizeof(struct sockaddr_in6)); 1656f92d9b1aSKristof Provost sc->sc_flowsrc->sa_len = sizeof(struct 1657f92d9b1aSKristof Provost sockaddr_in6); 1658f92d9b1aSKristof Provost break; 1659f92d9b1aSKristof Provost default: 1660f92d9b1aSKristof Provost break; 1661f92d9b1aSKristof Provost } 1662f92d9b1aSKristof Provost } 1663f92d9b1aSKristof Provost 1664f92d9b1aSKristof Provost if (sc->so == NULL) { 1665f92d9b1aSKristof Provost if (pflowvalidsockaddr(sc->sc_flowdst, 0)) { 1666f92d9b1aSKristof Provost error = socreate(sc->sc_flowdst->sa_family, 1667f92d9b1aSKristof Provost &so, SOCK_DGRAM, IPPROTO_UDP, cred, td); 1668f92d9b1aSKristof Provost if (error) 1669f92d9b1aSKristof Provost return (error); 1670f92d9b1aSKristof Provost if (pflowvalidsockaddr(sc->sc_flowsrc, 1)) { 1671f92d9b1aSKristof Provost error = sobind(so, sc->sc_flowsrc, td); 1672f92d9b1aSKristof Provost if (error) { 1673f92d9b1aSKristof Provost soclose(so); 1674f92d9b1aSKristof Provost return (error); 1675f92d9b1aSKristof Provost } 1676f92d9b1aSKristof Provost } 1677f92d9b1aSKristof Provost sc->so = so; 1678f92d9b1aSKristof Provost } 1679f92d9b1aSKristof Provost } else if (!pflowvalidsockaddr(sc->sc_flowdst, 0)) { 1680f92d9b1aSKristof Provost soclose(sc->so); 1681f92d9b1aSKristof Provost sc->so = NULL; 1682f92d9b1aSKristof Provost } 1683f92d9b1aSKristof Provost 168485b71dcfSKristof Provost if (pflowr->observation_dom != 0) 168585b71dcfSKristof Provost sc->sc_observation_dom = pflowr->observation_dom; 168685b71dcfSKristof Provost 1687f92d9b1aSKristof Provost /* error check is above */ 1688f92d9b1aSKristof Provost if (pflowr->version != 0) 1689f92d9b1aSKristof Provost sc->sc_version = pflowr->version; 1690f92d9b1aSKristof Provost 1691f92d9b1aSKristof Provost pflow_setmtu(sc, ETHERMTU); 1692f92d9b1aSKristof Provost 1693f92d9b1aSKristof Provost switch (sc->sc_version) { 1694f92d9b1aSKristof Provost case PFLOW_PROTO_5: 1695f92d9b1aSKristof Provost callout_stop(&sc->sc_tmo6); 1696f92d9b1aSKristof Provost callout_stop(&sc->sc_tmo_tmpl); 1697f92d9b1aSKristof Provost break; 1698f92d9b1aSKristof Provost case PFLOW_PROTO_10: 1699f92d9b1aSKristof Provost callout_reset(&sc->sc_tmo_tmpl, PFLOW_TMPL_TIMEOUT * hz, 1700f92d9b1aSKristof Provost pflow_timeout_tmpl, sc); 1701f92d9b1aSKristof Provost break; 1702f92d9b1aSKristof Provost default: /* NOTREACHED */ 1703f92d9b1aSKristof Provost break; 1704f92d9b1aSKristof Provost } 1705f92d9b1aSKristof Provost 1706f92d9b1aSKristof Provost return (0); 1707f92d9b1aSKristof Provost } 1708f92d9b1aSKristof Provost 1709f92d9b1aSKristof Provost static int 1710f92d9b1aSKristof Provost pflow_nl_set(struct nlmsghdr *hdr, struct nl_pstate *npt) 1711f92d9b1aSKristof Provost { 1712f92d9b1aSKristof Provost struct epoch_tracker et; 1713f92d9b1aSKristof Provost struct pflow_parsed_set s = {}; 1714f92d9b1aSKristof Provost struct pflow_softc *sc = NULL; 1715f92d9b1aSKristof Provost int error; 1716f92d9b1aSKristof Provost 1717f92d9b1aSKristof Provost error = nl_parse_nlmsg(hdr, &set_parser, npt, &s); 1718f92d9b1aSKristof Provost if (error != 0) 1719f92d9b1aSKristof Provost return (error); 1720f92d9b1aSKristof Provost 1721f92d9b1aSKristof Provost NET_EPOCH_ENTER(et); 1722f92d9b1aSKristof Provost CK_LIST_FOREACH(sc, &V_pflowif_list, sc_next) { 1723f92d9b1aSKristof Provost if (sc->sc_id == s.id) 1724f92d9b1aSKristof Provost break; 1725f92d9b1aSKristof Provost } 1726f92d9b1aSKristof Provost if (sc == NULL) { 1727f92d9b1aSKristof Provost error = ENOENT; 1728f92d9b1aSKristof Provost goto out; 1729f92d9b1aSKristof Provost } 1730f92d9b1aSKristof Provost 1731f92d9b1aSKristof Provost PFLOW_LOCK(sc); 1732f92d9b1aSKristof Provost error = pflow_set(sc, &s, nlp_get_cred(npt->nlp)); 1733f92d9b1aSKristof Provost PFLOW_UNLOCK(sc); 1734f92d9b1aSKristof Provost 1735f92d9b1aSKristof Provost out: 1736f92d9b1aSKristof Provost NET_EPOCH_EXIT(et); 1737f92d9b1aSKristof Provost return (error); 1738f92d9b1aSKristof Provost } 1739f92d9b1aSKristof Provost 1740f92d9b1aSKristof Provost static const struct genl_cmd pflow_cmds[] = { 1741f92d9b1aSKristof Provost { 1742f92d9b1aSKristof Provost .cmd_num = PFLOWNL_CMD_LIST, 1743f92d9b1aSKristof Provost .cmd_name = "LIST", 1744f92d9b1aSKristof Provost .cmd_cb = pflow_nl_list, 1745f92d9b1aSKristof Provost .cmd_flags = GENL_CMD_CAP_DO | GENL_CMD_CAP_DUMP | GENL_CMD_CAP_HASPOL, 1746f92d9b1aSKristof Provost .cmd_priv = PRIV_NETINET_PF, 1747f92d9b1aSKristof Provost }, 1748f92d9b1aSKristof Provost { 1749f92d9b1aSKristof Provost .cmd_num = PFLOWNL_CMD_CREATE, 1750f92d9b1aSKristof Provost .cmd_name = "CREATE", 1751f92d9b1aSKristof Provost .cmd_cb = pflow_nl_create, 1752f92d9b1aSKristof Provost .cmd_flags = GENL_CMD_CAP_DO | GENL_CMD_CAP_DUMP | GENL_CMD_CAP_HASPOL, 1753f92d9b1aSKristof Provost .cmd_priv = PRIV_NETINET_PF, 1754f92d9b1aSKristof Provost }, 1755f92d9b1aSKristof Provost { 1756f92d9b1aSKristof Provost .cmd_num = PFLOWNL_CMD_DEL, 1757f92d9b1aSKristof Provost .cmd_name = "DEL", 1758f92d9b1aSKristof Provost .cmd_cb = pflow_nl_del, 1759f92d9b1aSKristof Provost .cmd_flags = GENL_CMD_CAP_DO | GENL_CMD_CAP_DUMP | GENL_CMD_CAP_HASPOL, 1760f92d9b1aSKristof Provost .cmd_priv = PRIV_NETINET_PF, 1761f92d9b1aSKristof Provost }, 1762f92d9b1aSKristof Provost { 1763f92d9b1aSKristof Provost .cmd_num = PFLOWNL_CMD_GET, 1764f92d9b1aSKristof Provost .cmd_name = "GET", 1765f92d9b1aSKristof Provost .cmd_cb = pflow_nl_get, 1766f92d9b1aSKristof Provost .cmd_flags = GENL_CMD_CAP_DUMP | GENL_CMD_CAP_HASPOL, 1767f92d9b1aSKristof Provost .cmd_priv = PRIV_NETINET_PF, 1768f92d9b1aSKristof Provost }, 1769f92d9b1aSKristof Provost { 1770f92d9b1aSKristof Provost .cmd_num = PFLOWNL_CMD_SET, 1771f92d9b1aSKristof Provost .cmd_name = "SET", 1772f92d9b1aSKristof Provost .cmd_cb = pflow_nl_set, 1773f92d9b1aSKristof Provost .cmd_flags = GENL_CMD_CAP_DO | GENL_CMD_CAP_DUMP | GENL_CMD_CAP_HASPOL, 1774f92d9b1aSKristof Provost .cmd_priv = PRIV_NETINET_PF, 1775f92d9b1aSKristof Provost }, 1776f92d9b1aSKristof Provost }; 1777f92d9b1aSKristof Provost 1778f92d9b1aSKristof Provost static const struct nlhdr_parser *all_parsers[] = { 1779f92d9b1aSKristof Provost &del_parser, 1780f92d9b1aSKristof Provost &get_parser, 1781f92d9b1aSKristof Provost &set_parser, 1782f92d9b1aSKristof Provost }; 1783f92d9b1aSKristof Provost 178483641335SKristof Provost static unsigned pflow_do_osd_jail_slot; 178583641335SKristof Provost 1786f92d9b1aSKristof Provost static int 1787f92d9b1aSKristof Provost pflow_init(void) 1788f92d9b1aSKristof Provost { 1789f92d9b1aSKristof Provost bool ret; 1790f92d9b1aSKristof Provost int family_id __diagused; 1791f92d9b1aSKristof Provost 1792f92d9b1aSKristof Provost NL_VERIFY_PARSERS(all_parsers); 1793f92d9b1aSKristof Provost 179483641335SKristof Provost static osd_method_t methods[PR_MAXMETHOD] = { 179583641335SKristof Provost [PR_METHOD_REMOVE] = pflow_jail_remove, 179683641335SKristof Provost }; 179783641335SKristof Provost pflow_do_osd_jail_slot = osd_jail_register(NULL, methods); 179883641335SKristof Provost 1799f92d9b1aSKristof Provost family_id = genl_register_family(PFLOWNL_FAMILY_NAME, 0, 2, PFLOWNL_CMD_MAX); 1800f92d9b1aSKristof Provost MPASS(family_id != 0); 180129f61502SGleb Smirnoff ret = genl_register_cmds(PFLOWNL_FAMILY_NAME, pflow_cmds, 180229f61502SGleb Smirnoff nitems(pflow_cmds)); 1803f92d9b1aSKristof Provost 1804f92d9b1aSKristof Provost return (ret ? 0 : ENODEV); 1805f92d9b1aSKristof Provost } 1806f92d9b1aSKristof Provost 1807f92d9b1aSKristof Provost static void 1808f92d9b1aSKristof Provost pflow_uninit(void) 1809f92d9b1aSKristof Provost { 181083641335SKristof Provost osd_jail_deregister(pflow_do_osd_jail_slot); 1811f92d9b1aSKristof Provost genl_unregister_family(PFLOWNL_FAMILY_NAME); 1812f92d9b1aSKristof Provost } 1813f92d9b1aSKristof Provost 1814f92d9b1aSKristof Provost static int 1815f92d9b1aSKristof Provost pflow_modevent(module_t mod, int type, void *data) 1816f92d9b1aSKristof Provost { 1817f92d9b1aSKristof Provost int error = 0; 1818f92d9b1aSKristof Provost 1819f92d9b1aSKristof Provost switch (type) { 1820f92d9b1aSKristof Provost case MOD_LOAD: 1821f92d9b1aSKristof Provost error = pflow_init(); 1822f92d9b1aSKristof Provost break; 1823f92d9b1aSKristof Provost case MOD_UNLOAD: 1824f92d9b1aSKristof Provost pflow_uninit(); 1825f92d9b1aSKristof Provost break; 1826f92d9b1aSKristof Provost default: 1827f92d9b1aSKristof Provost error = EINVAL; 1828f92d9b1aSKristof Provost break; 1829f92d9b1aSKristof Provost } 1830f92d9b1aSKristof Provost 1831f92d9b1aSKristof Provost return (error); 1832f92d9b1aSKristof Provost } 1833f92d9b1aSKristof Provost 1834f92d9b1aSKristof Provost static moduledata_t pflow_mod = { 1835f92d9b1aSKristof Provost pflowname, 1836f92d9b1aSKristof Provost pflow_modevent, 1837f92d9b1aSKristof Provost 0 1838f92d9b1aSKristof Provost }; 1839f92d9b1aSKristof Provost 1840f92d9b1aSKristof Provost DECLARE_MODULE(pflow, pflow_mod, SI_SUB_PROTO_FIREWALL, SI_ORDER_ANY); 1841f92d9b1aSKristof Provost MODULE_VERSION(pflow, 1); 1842f92d9b1aSKristof Provost MODULE_DEPEND(pflow, pf, PF_MODVER, PF_MODVER, PF_MODVER); 1843