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