1d8aa10ccSGleb Smirnoff /*- 24d846d26SWarner Losh * SPDX-License-Identifier: (BSD-2-Clause AND ISC) 3fe267a55SPedro F. Giffuni * 43b3a8eb9SGleb Smirnoff * Copyright (c) 2002 Michael Shalayeff 5d8aa10ccSGleb Smirnoff * Copyright (c) 2012 Gleb Smirnoff <glebius@FreeBSD.org> 63b3a8eb9SGleb Smirnoff * All rights reserved. 73b3a8eb9SGleb Smirnoff * 83b3a8eb9SGleb Smirnoff * Redistribution and use in source and binary forms, with or without 93b3a8eb9SGleb Smirnoff * modification, are permitted provided that the following conditions 103b3a8eb9SGleb Smirnoff * are met: 113b3a8eb9SGleb Smirnoff * 1. Redistributions of source code must retain the above copyright 123b3a8eb9SGleb Smirnoff * notice, this list of conditions and the following disclaimer. 133b3a8eb9SGleb Smirnoff * 2. Redistributions in binary form must reproduce the above copyright 143b3a8eb9SGleb Smirnoff * notice, this list of conditions and the following disclaimer in the 153b3a8eb9SGleb Smirnoff * documentation and/or other materials provided with the distribution. 163b3a8eb9SGleb Smirnoff * 173b3a8eb9SGleb Smirnoff * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 183b3a8eb9SGleb Smirnoff * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 193b3a8eb9SGleb Smirnoff * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 203b3a8eb9SGleb Smirnoff * IN NO EVENT SHALL THE AUTHOR OR HIS RELATIVES BE LIABLE FOR ANY DIRECT, 213b3a8eb9SGleb Smirnoff * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 223b3a8eb9SGleb Smirnoff * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 233b3a8eb9SGleb Smirnoff * SERVICES; LOSS OF MIND, USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 243b3a8eb9SGleb Smirnoff * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, 253b3a8eb9SGleb Smirnoff * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING 263b3a8eb9SGleb Smirnoff * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF 273b3a8eb9SGleb Smirnoff * THE POSSIBILITY OF SUCH DAMAGE. 283b3a8eb9SGleb Smirnoff */ 293b3a8eb9SGleb Smirnoff 30d8aa10ccSGleb Smirnoff /*- 313b3a8eb9SGleb Smirnoff * Copyright (c) 2009 David Gwynne <dlg@openbsd.org> 323b3a8eb9SGleb Smirnoff * 333b3a8eb9SGleb Smirnoff * Permission to use, copy, modify, and distribute this software for any 343b3a8eb9SGleb Smirnoff * purpose with or without fee is hereby granted, provided that the above 353b3a8eb9SGleb Smirnoff * copyright notice and this permission notice appear in all copies. 363b3a8eb9SGleb Smirnoff * 373b3a8eb9SGleb Smirnoff * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 383b3a8eb9SGleb Smirnoff * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 393b3a8eb9SGleb Smirnoff * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 403b3a8eb9SGleb Smirnoff * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 413b3a8eb9SGleb Smirnoff * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 423b3a8eb9SGleb Smirnoff * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 433b3a8eb9SGleb Smirnoff * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 443b3a8eb9SGleb Smirnoff */ 453b3a8eb9SGleb Smirnoff 463b3a8eb9SGleb Smirnoff /* 47d8aa10ccSGleb Smirnoff * $OpenBSD: if_pfsync.c,v 1.110 2009/02/24 05:39:19 dlg Exp $ 48d8aa10ccSGleb Smirnoff * 493b3a8eb9SGleb Smirnoff * Revisions picked from OpenBSD after revision 1.110 import: 509ff7e6e9SGleb Smirnoff * 1.119 - don't m_copydata() beyond the len of mbuf in pfsync_input() 513b3a8eb9SGleb Smirnoff * 1.118, 1.124, 1.148, 1.149, 1.151, 1.171 - fixes to bulk updates 523b3a8eb9SGleb Smirnoff * 1.120, 1.175 - use monotonic time_uptime 533b3a8eb9SGleb Smirnoff * 1.122 - reduce number of updates for non-TCP sessions 54fed76350SGleb Smirnoff * 1.125, 1.127 - rewrite merge or stale processing 553b3a8eb9SGleb Smirnoff * 1.128 - cleanups 563b3a8eb9SGleb Smirnoff * 1.146 - bzero() mbuf before sparsely filling it with data 573b3a8eb9SGleb Smirnoff * 1.170 - SIOCSIFMTU checks 583b3a8eb9SGleb Smirnoff * 1.126, 1.142 - deferred packets processing 593b3a8eb9SGleb Smirnoff * 1.173 - correct expire time processing 603b3a8eb9SGleb Smirnoff */ 613b3a8eb9SGleb Smirnoff 623b3a8eb9SGleb Smirnoff #include <sys/cdefs.h> 633b3a8eb9SGleb Smirnoff #include "opt_inet.h" 643b3a8eb9SGleb Smirnoff #include "opt_inet6.h" 653b3a8eb9SGleb Smirnoff #include "opt_pf.h" 663b3a8eb9SGleb Smirnoff 673b3a8eb9SGleb Smirnoff #include <sys/param.h> 683b3a8eb9SGleb Smirnoff #include <sys/bus.h> 693b3a8eb9SGleb Smirnoff #include <sys/endian.h> 703b3a8eb9SGleb Smirnoff #include <sys/interrupt.h> 713b3a8eb9SGleb Smirnoff #include <sys/kernel.h> 723b3a8eb9SGleb Smirnoff #include <sys/lock.h> 733b3a8eb9SGleb Smirnoff #include <sys/mbuf.h> 743b3a8eb9SGleb Smirnoff #include <sys/module.h> 753b3a8eb9SGleb Smirnoff #include <sys/mutex.h> 76813c5b75SLuiz Amaral #include <sys/nv.h> 773b3a8eb9SGleb Smirnoff #include <sys/priv.h> 784fc65bcbSKristof Provost #include <sys/smp.h> 793b3a8eb9SGleb Smirnoff #include <sys/socket.h> 803b3a8eb9SGleb Smirnoff #include <sys/sockio.h> 813b3a8eb9SGleb Smirnoff #include <sys/sysctl.h> 8266c00e9eSBjoern A. Zeeb #include <sys/syslog.h> 833b3a8eb9SGleb Smirnoff 843b3a8eb9SGleb Smirnoff #include <net/bpf.h> 853b3a8eb9SGleb Smirnoff #include <net/if.h> 8676039bc8SGleb Smirnoff #include <net/if_var.h> 873b3a8eb9SGleb Smirnoff #include <net/if_clone.h> 883d0d5b21SJustin Hibbits #include <net/if_private.h> 893b3a8eb9SGleb Smirnoff #include <net/if_types.h> 9076039bc8SGleb Smirnoff #include <net/vnet.h> 913b3a8eb9SGleb Smirnoff #include <net/pfvar.h> 926fc7fc2dSLuiz Amaral #include <net/route.h> 933b3a8eb9SGleb Smirnoff #include <net/if_pfsync.h> 943b3a8eb9SGleb Smirnoff 953b3a8eb9SGleb Smirnoff #include <netinet/if_ether.h> 963b3a8eb9SGleb Smirnoff #include <netinet/in.h> 973b3a8eb9SGleb Smirnoff #include <netinet/in_var.h> 986fc7fc2dSLuiz Amaral #include <netinet6/in6_var.h> 993b3a8eb9SGleb Smirnoff #include <netinet/ip.h> 1006fc7fc2dSLuiz Amaral #include <netinet/ip6.h> 1013b3a8eb9SGleb Smirnoff #include <netinet/ip_carp.h> 1023b3a8eb9SGleb Smirnoff #include <netinet/ip_var.h> 1033b3a8eb9SGleb Smirnoff #include <netinet/tcp.h> 1043b3a8eb9SGleb Smirnoff #include <netinet/tcp_fsm.h> 1053b3a8eb9SGleb Smirnoff #include <netinet/tcp_seq.h> 1063b3a8eb9SGleb Smirnoff 1079a1cab6dSKristof Provost #include <netinet/ip6.h> 1089a1cab6dSKristof Provost #include <netinet6/ip6_var.h> 1096fc7fc2dSLuiz Amaral #include <netinet6/scope6_var.h> 1109a1cab6dSKristof Provost 111813c5b75SLuiz Amaral #include <netpfil/pf/pfsync_nv.h> 1123b3a8eb9SGleb Smirnoff 113ad6562ecSKajetan Staszkiewicz #define DPFPRINTF(n, x) if (V_pf_status.debug >= (n)) printf x 114ad6562ecSKajetan Staszkiewicz 1154fc65bcbSKristof Provost struct pfsync_bucket; 1169a1cab6dSKristof Provost struct pfsync_softc; 1174fc65bcbSKristof Provost 118813c5b75SLuiz Amaral union inet_template { 119813c5b75SLuiz Amaral struct ip ipv4; 1206fc7fc2dSLuiz Amaral struct ip6_hdr ipv6; 121813c5b75SLuiz Amaral }; 122813c5b75SLuiz Amaral 123813c5b75SLuiz Amaral #define PFSYNC_MINPKT ( \ 124813c5b75SLuiz Amaral sizeof(union inet_template) + \ 125813c5b75SLuiz Amaral sizeof(struct pfsync_header) + \ 126813c5b75SLuiz Amaral sizeof(struct pfsync_subheader) ) 127813c5b75SLuiz Amaral 128211cddf9SKristof Provost static int pfsync_upd_tcp(struct pf_kstate *, struct pfsync_state_peer *, 1293b3a8eb9SGleb Smirnoff struct pfsync_state_peer *); 1304bf98559SKajetan Staszkiewicz static int pfsync_in_clr(struct mbuf *, int, int, int, int); 1314bf98559SKajetan Staszkiewicz static int pfsync_in_ins(struct mbuf *, int, int, int, int); 1324bf98559SKajetan Staszkiewicz static int pfsync_in_iack(struct mbuf *, int, int, int, int); 1334bf98559SKajetan Staszkiewicz static int pfsync_in_upd(struct mbuf *, int, int, int, int); 1344bf98559SKajetan Staszkiewicz static int pfsync_in_upd_c(struct mbuf *, int, int, int, int); 1354bf98559SKajetan Staszkiewicz static int pfsync_in_ureq(struct mbuf *, int, int, int, int); 1364bf98559SKajetan Staszkiewicz static int pfsync_in_del_c(struct mbuf *, int, int, int, int); 1374bf98559SKajetan Staszkiewicz static int pfsync_in_bus(struct mbuf *, int, int, int, int); 1384bf98559SKajetan Staszkiewicz static int pfsync_in_tdb(struct mbuf *, int, int, int, int); 1394bf98559SKajetan Staszkiewicz static int pfsync_in_eof(struct mbuf *, int, int, int, int); 1404bf98559SKajetan Staszkiewicz static int pfsync_in_error(struct mbuf *, int, int, int, int); 1413b3a8eb9SGleb Smirnoff 1424bf98559SKajetan Staszkiewicz static int (*pfsync_acts[])(struct mbuf *, int, int, int, int) = { 1433b3a8eb9SGleb Smirnoff pfsync_in_clr, /* PFSYNC_ACT_CLR */ 1444bf98559SKajetan Staszkiewicz pfsync_in_ins, /* PFSYNC_ACT_INS_1301 */ 1453b3a8eb9SGleb Smirnoff pfsync_in_iack, /* PFSYNC_ACT_INS_ACK */ 1464bf98559SKajetan Staszkiewicz pfsync_in_upd, /* PFSYNC_ACT_UPD_1301 */ 1473b3a8eb9SGleb Smirnoff pfsync_in_upd_c, /* PFSYNC_ACT_UPD_C */ 1483b3a8eb9SGleb Smirnoff pfsync_in_ureq, /* PFSYNC_ACT_UPD_REQ */ 149cdc231bdSKajetan Staszkiewicz pfsync_in_error, /* PFSYNC_ACT_DEL */ 1503b3a8eb9SGleb Smirnoff pfsync_in_del_c, /* PFSYNC_ACT_DEL_C */ 1513b3a8eb9SGleb Smirnoff pfsync_in_error, /* PFSYNC_ACT_INS_F */ 1523b3a8eb9SGleb Smirnoff pfsync_in_error, /* PFSYNC_ACT_DEL_F */ 1533b3a8eb9SGleb Smirnoff pfsync_in_bus, /* PFSYNC_ACT_BUS */ 1543b3a8eb9SGleb Smirnoff pfsync_in_tdb, /* PFSYNC_ACT_TDB */ 1554bf98559SKajetan Staszkiewicz pfsync_in_eof, /* PFSYNC_ACT_EOF */ 1564bf98559SKajetan Staszkiewicz pfsync_in_ins, /* PFSYNC_ACT_INS_1400 */ 1574bf98559SKajetan Staszkiewicz pfsync_in_upd, /* PFSYNC_ACT_UPD_1400 */ 1583b3a8eb9SGleb Smirnoff }; 1593b3a8eb9SGleb Smirnoff 1603b3a8eb9SGleb Smirnoff struct pfsync_q { 161211cddf9SKristof Provost void (*write)(struct pf_kstate *, void *); 1623b3a8eb9SGleb Smirnoff size_t len; 1633b3a8eb9SGleb Smirnoff u_int8_t action; 1643b3a8eb9SGleb Smirnoff }; 1653b3a8eb9SGleb Smirnoff 1664bf98559SKajetan Staszkiewicz /* We have the following sync queues */ 1674bf98559SKajetan Staszkiewicz enum pfsync_q_id { 1684bf98559SKajetan Staszkiewicz PFSYNC_Q_INS_1301, 1694bf98559SKajetan Staszkiewicz PFSYNC_Q_INS_1400, 1704bf98559SKajetan Staszkiewicz PFSYNC_Q_IACK, 1714bf98559SKajetan Staszkiewicz PFSYNC_Q_UPD_1301, 1724bf98559SKajetan Staszkiewicz PFSYNC_Q_UPD_1400, 1734bf98559SKajetan Staszkiewicz PFSYNC_Q_UPD_C, 1744bf98559SKajetan Staszkiewicz PFSYNC_Q_DEL_C, 1754bf98559SKajetan Staszkiewicz PFSYNC_Q_COUNT, 1764bf98559SKajetan Staszkiewicz }; 1774bf98559SKajetan Staszkiewicz 1784bf98559SKajetan Staszkiewicz /* Functions for building messages for given queue */ 1794bf98559SKajetan Staszkiewicz static void pfsync_out_state_1301(struct pf_kstate *, void *); 1804bf98559SKajetan Staszkiewicz static void pfsync_out_state_1400(struct pf_kstate *, void *); 181211cddf9SKristof Provost static void pfsync_out_iack(struct pf_kstate *, void *); 182211cddf9SKristof Provost static void pfsync_out_upd_c(struct pf_kstate *, void *); 183cdc231bdSKajetan Staszkiewicz static void pfsync_out_del_c(struct pf_kstate *, void *); 1843b3a8eb9SGleb Smirnoff 1854bf98559SKajetan Staszkiewicz /* Attach those functions to queue */ 1863b3a8eb9SGleb Smirnoff static struct pfsync_q pfsync_qs[] = { 1874bf98559SKajetan Staszkiewicz { pfsync_out_state_1301, sizeof(struct pfsync_state_1301), PFSYNC_ACT_INS_1301 }, 1884bf98559SKajetan Staszkiewicz { pfsync_out_state_1400, sizeof(struct pfsync_state_1400), PFSYNC_ACT_INS_1400 }, 1893b3a8eb9SGleb Smirnoff { pfsync_out_iack, sizeof(struct pfsync_ins_ack), PFSYNC_ACT_INS_ACK }, 1904bf98559SKajetan Staszkiewicz { pfsync_out_state_1301, sizeof(struct pfsync_state_1301), PFSYNC_ACT_UPD_1301 }, 1914bf98559SKajetan Staszkiewicz { pfsync_out_state_1400, sizeof(struct pfsync_state_1400), PFSYNC_ACT_UPD_1400 }, 1923b3a8eb9SGleb Smirnoff { pfsync_out_upd_c, sizeof(struct pfsync_upd_c), PFSYNC_ACT_UPD_C }, 193cdc231bdSKajetan Staszkiewicz { pfsync_out_del_c, sizeof(struct pfsync_del_c), PFSYNC_ACT_DEL_C } 1943b3a8eb9SGleb Smirnoff }; 1953b3a8eb9SGleb Smirnoff 1964bf98559SKajetan Staszkiewicz /* Map queue to pf_kstate->sync_state */ 1974bf98559SKajetan Staszkiewicz static u_int8_t pfsync_qid_sstate[] = { 1984bf98559SKajetan Staszkiewicz PFSYNC_S_INS, /* PFSYNC_Q_INS_1301 */ 1994bf98559SKajetan Staszkiewicz PFSYNC_S_INS, /* PFSYNC_Q_INS_1400 */ 2004bf98559SKajetan Staszkiewicz PFSYNC_S_IACK, /* PFSYNC_Q_IACK */ 2014bf98559SKajetan Staszkiewicz PFSYNC_S_UPD, /* PFSYNC_Q_UPD_1301 */ 2024bf98559SKajetan Staszkiewicz PFSYNC_S_UPD, /* PFSYNC_Q_UPD_1400 */ 2034bf98559SKajetan Staszkiewicz PFSYNC_S_UPD_C, /* PFSYNC_Q_UPD_C */ 2044bf98559SKajetan Staszkiewicz PFSYNC_S_DEL_C, /* PFSYNC_Q_DEL_C */ 2054bf98559SKajetan Staszkiewicz }; 2064bf98559SKajetan Staszkiewicz 2074bf98559SKajetan Staszkiewicz /* Map pf_kstate->sync_state to queue */ 2084bf98559SKajetan Staszkiewicz static enum pfsync_q_id pfsync_sstate_to_qid(u_int8_t); 2094bf98559SKajetan Staszkiewicz 2104bf98559SKajetan Staszkiewicz static void pfsync_q_ins(struct pf_kstate *, int sync_state, bool); 211211cddf9SKristof Provost static void pfsync_q_del(struct pf_kstate *, bool, struct pfsync_bucket *); 2123b3a8eb9SGleb Smirnoff 213211cddf9SKristof Provost static void pfsync_update_state(struct pf_kstate *); 2149a1cab6dSKristof Provost static void pfsync_tx(struct pfsync_softc *, struct mbuf *); 2153b3a8eb9SGleb Smirnoff 2163b3a8eb9SGleb Smirnoff struct pfsync_upd_req_item { 2173b3a8eb9SGleb Smirnoff TAILQ_ENTRY(pfsync_upd_req_item) ur_entry; 2183b3a8eb9SGleb Smirnoff struct pfsync_upd_req ur_msg; 2193b3a8eb9SGleb Smirnoff }; 2203b3a8eb9SGleb Smirnoff 2213b3a8eb9SGleb Smirnoff struct pfsync_deferral { 2223b3a8eb9SGleb Smirnoff struct pfsync_softc *pd_sc; 2233b3a8eb9SGleb Smirnoff TAILQ_ENTRY(pfsync_deferral) pd_entry; 2243b3a8eb9SGleb Smirnoff struct callout pd_tmo; 2253b3a8eb9SGleb Smirnoff 226211cddf9SKristof Provost struct pf_kstate *pd_st; 2273b3a8eb9SGleb Smirnoff struct mbuf *pd_m; 2283b3a8eb9SGleb Smirnoff }; 2293b3a8eb9SGleb Smirnoff 2304fc65bcbSKristof Provost struct pfsync_bucket 2314fc65bcbSKristof Provost { 2324fc65bcbSKristof Provost int b_id; 2334fc65bcbSKristof Provost struct pfsync_softc *b_sc; 2344fc65bcbSKristof Provost struct mtx b_mtx; 2354fc65bcbSKristof Provost struct callout b_tmo; 2364fc65bcbSKristof Provost int b_flags; 2374fc65bcbSKristof Provost #define PFSYNCF_BUCKET_PUSH 0x00000001 2384fc65bcbSKristof Provost 2394fc65bcbSKristof Provost size_t b_len; 2404bf98559SKajetan Staszkiewicz TAILQ_HEAD(, pf_kstate) b_qs[PFSYNC_Q_COUNT]; 2414fc65bcbSKristof Provost TAILQ_HEAD(, pfsync_upd_req_item) b_upd_req_list; 2424fc65bcbSKristof Provost TAILQ_HEAD(, pfsync_deferral) b_deferrals; 2434fc65bcbSKristof Provost u_int b_deferred; 244caccf6d3SKristof Provost uint8_t *b_plus; 2454fc65bcbSKristof Provost size_t b_pluslen; 2464fc65bcbSKristof Provost 2474fc65bcbSKristof Provost struct ifaltq b_snd; 2484fc65bcbSKristof Provost }; 2494fc65bcbSKristof Provost 2503b3a8eb9SGleb Smirnoff struct pfsync_softc { 2513b3a8eb9SGleb Smirnoff /* Configuration */ 2523b3a8eb9SGleb Smirnoff struct ifnet *sc_ifp; 2533b3a8eb9SGleb Smirnoff struct ifnet *sc_sync_if; 2543b3a8eb9SGleb Smirnoff struct ip_moptions sc_imo; 2556fc7fc2dSLuiz Amaral struct ip6_moptions sc_im6o; 256813c5b75SLuiz Amaral struct sockaddr_storage sc_sync_peer; 2573b3a8eb9SGleb Smirnoff uint32_t sc_flags; 2583b3a8eb9SGleb Smirnoff uint8_t sc_maxupdates; 259813c5b75SLuiz Amaral union inet_template sc_template; 2603b3a8eb9SGleb Smirnoff struct mtx sc_mtx; 2614bf98559SKajetan Staszkiewicz uint32_t sc_version; 2623b3a8eb9SGleb Smirnoff 2633b3a8eb9SGleb Smirnoff /* Queued data */ 2644fc65bcbSKristof Provost struct pfsync_bucket *sc_buckets; 2653b3a8eb9SGleb Smirnoff 2663b3a8eb9SGleb Smirnoff /* Bulk update info */ 2673b3a8eb9SGleb Smirnoff struct mtx sc_bulk_mtx; 2683b3a8eb9SGleb Smirnoff uint32_t sc_ureq_sent; 2693b3a8eb9SGleb Smirnoff int sc_bulk_tries; 2703b3a8eb9SGleb Smirnoff uint32_t sc_ureq_received; 2713b3a8eb9SGleb Smirnoff int sc_bulk_hashid; 2723b3a8eb9SGleb Smirnoff uint64_t sc_bulk_stateid; 2733b3a8eb9SGleb Smirnoff uint32_t sc_bulk_creatorid; 2743b3a8eb9SGleb Smirnoff struct callout sc_bulk_tmo; 2753b3a8eb9SGleb Smirnoff struct callout sc_bulkfail_tmo; 2763b3a8eb9SGleb Smirnoff }; 2773b3a8eb9SGleb Smirnoff 2783b3a8eb9SGleb Smirnoff #define PFSYNC_LOCK(sc) mtx_lock(&(sc)->sc_mtx) 2793b3a8eb9SGleb Smirnoff #define PFSYNC_UNLOCK(sc) mtx_unlock(&(sc)->sc_mtx) 2803b3a8eb9SGleb Smirnoff #define PFSYNC_LOCK_ASSERT(sc) mtx_assert(&(sc)->sc_mtx, MA_OWNED) 2813b3a8eb9SGleb Smirnoff 2824fc65bcbSKristof Provost #define PFSYNC_BUCKET_LOCK(b) mtx_lock(&(b)->b_mtx) 2834fc65bcbSKristof Provost #define PFSYNC_BUCKET_UNLOCK(b) mtx_unlock(&(b)->b_mtx) 2844fc65bcbSKristof Provost #define PFSYNC_BUCKET_LOCK_ASSERT(b) mtx_assert(&(b)->b_mtx, MA_OWNED) 2854fc65bcbSKristof Provost 2863b3a8eb9SGleb Smirnoff #define PFSYNC_BLOCK(sc) mtx_lock(&(sc)->sc_bulk_mtx) 2873b3a8eb9SGleb Smirnoff #define PFSYNC_BUNLOCK(sc) mtx_unlock(&(sc)->sc_bulk_mtx) 2883b3a8eb9SGleb Smirnoff #define PFSYNC_BLOCK_ASSERT(sc) mtx_assert(&(sc)->sc_bulk_mtx, MA_OWNED) 2893b3a8eb9SGleb Smirnoff 2906983b986SKristof Provost #define PFSYNC_DEFER_TIMEOUT 20 2916983b986SKristof Provost 29242a58907SGleb Smirnoff static const char pfsyncname[] = "pfsync"; 29342a58907SGleb Smirnoff static MALLOC_DEFINE(M_PFSYNC, pfsyncname, "pfsync(4) data"); 2945f901c92SAndrew Turner VNET_DEFINE_STATIC(struct pfsync_softc *, pfsyncif) = NULL; 2953b3a8eb9SGleb Smirnoff #define V_pfsyncif VNET(pfsyncif) 2965f901c92SAndrew Turner VNET_DEFINE_STATIC(void *, pfsync_swi_cookie) = NULL; 2973b3a8eb9SGleb Smirnoff #define V_pfsync_swi_cookie VNET(pfsync_swi_cookie) 298cecfaf9bSKristof Provost VNET_DEFINE_STATIC(struct intr_event *, pfsync_swi_ie); 299cecfaf9bSKristof Provost #define V_pfsync_swi_ie VNET(pfsync_swi_ie) 3005f901c92SAndrew Turner VNET_DEFINE_STATIC(struct pfsyncstats, pfsyncstats); 3013b3a8eb9SGleb Smirnoff #define V_pfsyncstats VNET(pfsyncstats) 3025f901c92SAndrew Turner VNET_DEFINE_STATIC(int, pfsync_carp_adj) = CARP_MAXSKEW; 3033b3a8eb9SGleb Smirnoff #define V_pfsync_carp_adj VNET(pfsync_carp_adj) 304476f6121SKristof Provost VNET_DEFINE_STATIC(unsigned int, pfsync_defer_timeout) = PFSYNC_DEFER_TIMEOUT; 305476f6121SKristof Provost #define V_pfsync_defer_timeout VNET(pfsync_defer_timeout) 3063b3a8eb9SGleb Smirnoff 3073b3a8eb9SGleb Smirnoff static void pfsync_timeout(void *); 3084fc65bcbSKristof Provost static void pfsync_push(struct pfsync_bucket *); 3094fc65bcbSKristof Provost static void pfsync_push_all(struct pfsync_softc *); 3103b3a8eb9SGleb Smirnoff static void pfsyncintr(void *); 3113b3a8eb9SGleb Smirnoff static int pfsync_multicast_setup(struct pfsync_softc *, struct ifnet *, 3126fc7fc2dSLuiz Amaral struct in_mfilter *, struct in6_mfilter *); 3133b3a8eb9SGleb Smirnoff static void pfsync_multicast_cleanup(struct pfsync_softc *); 3147b6fbb73SGleb Smirnoff static void pfsync_pointers_init(void); 3157b6fbb73SGleb Smirnoff static void pfsync_pointers_uninit(void); 3163b3a8eb9SGleb Smirnoff static int pfsync_init(void); 3173b3a8eb9SGleb Smirnoff static void pfsync_uninit(void); 3183b3a8eb9SGleb Smirnoff 3194fc65bcbSKristof Provost static unsigned long pfsync_buckets; 3204fc65bcbSKristof Provost 32110b49b23SPawel Biernacki SYSCTL_NODE(_net, OID_AUTO, pfsync, CTLFLAG_RW | CTLFLAG_MPSAFE, 0, 32210b49b23SPawel Biernacki "PFSYNC"); 3236df8a710SGleb Smirnoff SYSCTL_STRUCT(_net_pfsync, OID_AUTO, stats, CTLFLAG_VNET | CTLFLAG_RW, 3243b3a8eb9SGleb Smirnoff &VNET_NAME(pfsyncstats), pfsyncstats, 3253b3a8eb9SGleb Smirnoff "PFSYNC statistics (struct pfsyncstats, net/if_pfsync.h)"); 326654c1b8eSLuiz Amaral SYSCTL_INT(_net_pfsync, OID_AUTO, carp_demotion_factor, CTLFLAG_VNET | CTLFLAG_RW, 3273b3a8eb9SGleb Smirnoff &VNET_NAME(pfsync_carp_adj), 0, "pfsync's CARP demotion factor adjustment"); 3284fc65bcbSKristof Provost SYSCTL_ULONG(_net_pfsync, OID_AUTO, pfsync_buckets, CTLFLAG_RDTUN, 3294fc65bcbSKristof Provost &pfsync_buckets, 0, "Number of pfsync hash buckets"); 3306983b986SKristof Provost SYSCTL_UINT(_net_pfsync, OID_AUTO, defer_delay, CTLFLAG_VNET | CTLFLAG_RW, 331476f6121SKristof Provost &VNET_NAME(pfsync_defer_timeout), 0, "Deferred packet timeout (in ms)"); 3323b3a8eb9SGleb Smirnoff 3333b3a8eb9SGleb Smirnoff static int pfsync_clone_create(struct if_clone *, int, caddr_t); 3343b3a8eb9SGleb Smirnoff static void pfsync_clone_destroy(struct ifnet *); 3353b3a8eb9SGleb Smirnoff static int pfsync_alloc_scrub_memory(struct pfsync_state_peer *, 3363b3a8eb9SGleb Smirnoff struct pf_state_peer *); 33747e8d432SGleb Smirnoff static int pfsyncoutput(struct ifnet *, struct mbuf *, 33847e8d432SGleb Smirnoff const struct sockaddr *, struct route *); 3393b3a8eb9SGleb Smirnoff static int pfsyncioctl(struct ifnet *, u_long, caddr_t); 3403b3a8eb9SGleb Smirnoff 341211cddf9SKristof Provost static int pfsync_defer(struct pf_kstate *, struct mbuf *); 3423b3a8eb9SGleb Smirnoff static void pfsync_undefer(struct pfsync_deferral *, int); 34353247cdfSKristof Provost static void pfsync_undefer_state_locked(struct pf_kstate *, int); 344211cddf9SKristof Provost static void pfsync_undefer_state(struct pf_kstate *, int); 3453b3a8eb9SGleb Smirnoff static void pfsync_defer_tmo(void *); 3463b3a8eb9SGleb Smirnoff 3473b3a8eb9SGleb Smirnoff static void pfsync_request_update(u_int32_t, u_int64_t); 348211cddf9SKristof Provost static bool pfsync_update_state_req(struct pf_kstate *); 3493b3a8eb9SGleb Smirnoff 3505f75cd39SKristof Provost static void pfsync_drop_all(struct pfsync_softc *); 3515f75cd39SKristof Provost static void pfsync_drop(struct pfsync_softc *, int); 3524fc65bcbSKristof Provost static void pfsync_sendout(int, int); 3533b3a8eb9SGleb Smirnoff static void pfsync_send_plus(void *, size_t); 3543b3a8eb9SGleb Smirnoff 3553b3a8eb9SGleb Smirnoff static void pfsync_bulk_start(void); 3563b3a8eb9SGleb Smirnoff static void pfsync_bulk_status(u_int8_t); 3573b3a8eb9SGleb Smirnoff static void pfsync_bulk_update(void *); 3583b3a8eb9SGleb Smirnoff static void pfsync_bulk_fail(void *); 3593b3a8eb9SGleb Smirnoff 360fbbf436dSKristof Provost static void pfsync_detach_ifnet(struct ifnet *); 361813c5b75SLuiz Amaral 362813c5b75SLuiz Amaral static int pfsync_pfsyncreq_to_kstatus(struct pfsyncreq *, 363813c5b75SLuiz Amaral struct pfsync_kstatus *); 364813c5b75SLuiz Amaral static int pfsync_kstatus_to_softc(struct pfsync_kstatus *, 365813c5b75SLuiz Amaral struct pfsync_softc *); 366813c5b75SLuiz Amaral 3673b3a8eb9SGleb Smirnoff #ifdef IPSEC 3683b3a8eb9SGleb Smirnoff static void pfsync_update_net_tdb(struct pfsync_tdb *); 3693b3a8eb9SGleb Smirnoff #endif 3704fc65bcbSKristof Provost static struct pfsync_bucket *pfsync_get_bucket(struct pfsync_softc *, 371211cddf9SKristof Provost struct pf_kstate *); 3724fc65bcbSKristof Provost 3733b3a8eb9SGleb Smirnoff #define PFSYNC_MAX_BULKTRIES 12 3743b3a8eb9SGleb Smirnoff 37542a58907SGleb Smirnoff VNET_DEFINE(struct if_clone *, pfsync_cloner); 3763b3a8eb9SGleb Smirnoff #define V_pfsync_cloner VNET(pfsync_cloner) 3773b3a8eb9SGleb Smirnoff 3786fc7fc2dSLuiz Amaral const struct in6_addr in6addr_linklocal_pfsync_group = 3796fc7fc2dSLuiz Amaral {{{ 0xff, 0x12, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 3806fc7fc2dSLuiz Amaral 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf0 }}}; 3813b3a8eb9SGleb Smirnoff static int 3823b3a8eb9SGleb Smirnoff pfsync_clone_create(struct if_clone *ifc, int unit, caddr_t param) 3833b3a8eb9SGleb Smirnoff { 3843b3a8eb9SGleb Smirnoff struct pfsync_softc *sc; 3853b3a8eb9SGleb Smirnoff struct ifnet *ifp; 3864fc65bcbSKristof Provost struct pfsync_bucket *b; 3874bf98559SKajetan Staszkiewicz int c; 3884bf98559SKajetan Staszkiewicz enum pfsync_q_id q; 3893b3a8eb9SGleb Smirnoff 3903b3a8eb9SGleb Smirnoff if (unit != 0) 3913b3a8eb9SGleb Smirnoff return (EINVAL); 3923b3a8eb9SGleb Smirnoff 3934fc65bcbSKristof Provost if (! pfsync_buckets) 3944fc65bcbSKristof Provost pfsync_buckets = mp_ncpus * 2; 3954fc65bcbSKristof Provost 3963b3a8eb9SGleb Smirnoff sc = malloc(sizeof(struct pfsync_softc), M_PFSYNC, M_WAITOK | M_ZERO); 3976a8ee0f7SKristof Provost sc->sc_flags |= PFSYNCF_OK; 3983b3a8eb9SGleb Smirnoff sc->sc_maxupdates = 128; 3994bf98559SKajetan Staszkiewicz sc->sc_version = PFSYNC_MSG_VERSION_DEFAULT; 4003b3a8eb9SGleb Smirnoff 4013b3a8eb9SGleb Smirnoff ifp = sc->sc_ifp = if_alloc(IFT_PFSYNC); 40242a58907SGleb Smirnoff if_initname(ifp, pfsyncname, unit); 4033b3a8eb9SGleb Smirnoff ifp->if_softc = sc; 4043b3a8eb9SGleb Smirnoff ifp->if_ioctl = pfsyncioctl; 4053b3a8eb9SGleb Smirnoff ifp->if_output = pfsyncoutput; 4063b3a8eb9SGleb Smirnoff ifp->if_type = IFT_PFSYNC; 4073b3a8eb9SGleb Smirnoff ifp->if_hdrlen = sizeof(struct pfsync_header); 4083b3a8eb9SGleb Smirnoff ifp->if_mtu = ETHERMTU; 40942a58907SGleb Smirnoff mtx_init(&sc->sc_mtx, pfsyncname, NULL, MTX_DEF); 4103b3a8eb9SGleb Smirnoff mtx_init(&sc->sc_bulk_mtx, "pfsync bulk", NULL, MTX_DEF); 4113b3a8eb9SGleb Smirnoff callout_init_mtx(&sc->sc_bulk_tmo, &sc->sc_bulk_mtx, 0); 4123b3a8eb9SGleb Smirnoff callout_init_mtx(&sc->sc_bulkfail_tmo, &sc->sc_bulk_mtx, 0); 4133b3a8eb9SGleb Smirnoff 4143b3a8eb9SGleb Smirnoff if_attach(ifp); 4153b3a8eb9SGleb Smirnoff 4163b3a8eb9SGleb Smirnoff bpfattach(ifp, DLT_PFSYNC, PFSYNC_HDRLEN); 4173b3a8eb9SGleb Smirnoff 4184fc65bcbSKristof Provost sc->sc_buckets = mallocarray(pfsync_buckets, sizeof(*sc->sc_buckets), 4194fc65bcbSKristof Provost M_PFSYNC, M_ZERO | M_WAITOK); 4204fc65bcbSKristof Provost for (c = 0; c < pfsync_buckets; c++) { 4214fc65bcbSKristof Provost b = &sc->sc_buckets[c]; 422812483c4SKristof Provost mtx_init(&b->b_mtx, "pfsync bucket", NULL, MTX_DEF); 4234fc65bcbSKristof Provost 4244fc65bcbSKristof Provost b->b_id = c; 4254fc65bcbSKristof Provost b->b_sc = sc; 4264fc65bcbSKristof Provost b->b_len = PFSYNC_MINPKT; 4274fc65bcbSKristof Provost 4284bf98559SKajetan Staszkiewicz for (q = 0; q < PFSYNC_Q_COUNT; q++) 4294fc65bcbSKristof Provost TAILQ_INIT(&b->b_qs[q]); 4304fc65bcbSKristof Provost 4314fc65bcbSKristof Provost TAILQ_INIT(&b->b_upd_req_list); 4324fc65bcbSKristof Provost TAILQ_INIT(&b->b_deferrals); 4334fc65bcbSKristof Provost 4344fc65bcbSKristof Provost callout_init(&b->b_tmo, 1); 4354fc65bcbSKristof Provost 4364fc65bcbSKristof Provost b->b_snd.ifq_maxlen = ifqmaxlen; 4374fc65bcbSKristof Provost } 4384fc65bcbSKristof Provost 4393b3a8eb9SGleb Smirnoff V_pfsyncif = sc; 4403b3a8eb9SGleb Smirnoff 4413b3a8eb9SGleb Smirnoff return (0); 4423b3a8eb9SGleb Smirnoff } 4433b3a8eb9SGleb Smirnoff 4443b3a8eb9SGleb Smirnoff static void 4453b3a8eb9SGleb Smirnoff pfsync_clone_destroy(struct ifnet *ifp) 4463b3a8eb9SGleb Smirnoff { 4473b3a8eb9SGleb Smirnoff struct pfsync_softc *sc = ifp->if_softc; 4484fc65bcbSKristof Provost struct pfsync_bucket *b; 44901194da2SKristof Provost int c, ret; 4503b3a8eb9SGleb Smirnoff 4514fc65bcbSKristof Provost for (c = 0; c < pfsync_buckets; c++) { 4524fc65bcbSKristof Provost b = &sc->sc_buckets[c]; 4533b3a8eb9SGleb Smirnoff /* 4543b3a8eb9SGleb Smirnoff * At this stage, everything should have already been 4553b3a8eb9SGleb Smirnoff * cleared by pfsync_uninit(), and we have only to 4563b3a8eb9SGleb Smirnoff * drain callouts. 4573b3a8eb9SGleb Smirnoff */ 45801194da2SKristof Provost PFSYNC_BUCKET_LOCK(b); 4594fc65bcbSKristof Provost while (b->b_deferred > 0) { 4604fc65bcbSKristof Provost struct pfsync_deferral *pd = 4614fc65bcbSKristof Provost TAILQ_FIRST(&b->b_deferrals); 4623b3a8eb9SGleb Smirnoff 46301194da2SKristof Provost ret = callout_stop(&pd->pd_tmo); 46401194da2SKristof Provost PFSYNC_BUCKET_UNLOCK(b); 46501194da2SKristof Provost if (ret > 0) { 46601194da2SKristof Provost pfsync_undefer(pd, 1); 4673b3a8eb9SGleb Smirnoff } else { 4683b3a8eb9SGleb Smirnoff callout_drain(&pd->pd_tmo); 46901194da2SKristof Provost } 47001194da2SKristof Provost PFSYNC_BUCKET_LOCK(b); 4713b3a8eb9SGleb Smirnoff } 47201194da2SKristof Provost MPASS(b->b_deferred == 0); 47301194da2SKristof Provost MPASS(TAILQ_EMPTY(&b->b_deferrals)); 47401194da2SKristof Provost PFSYNC_BUCKET_UNLOCK(b); 4753b3a8eb9SGleb Smirnoff 47681debbd6SKristof Provost free(b->b_plus, M_PFSYNC); 47781debbd6SKristof Provost b->b_plus = NULL; 478caccf6d3SKristof Provost b->b_pluslen = 0; 47981debbd6SKristof Provost 4804fc65bcbSKristof Provost callout_drain(&b->b_tmo); 4814fc65bcbSKristof Provost } 4824fc65bcbSKristof Provost 4833b3a8eb9SGleb Smirnoff callout_drain(&sc->sc_bulkfail_tmo); 4843b3a8eb9SGleb Smirnoff callout_drain(&sc->sc_bulk_tmo); 4853b3a8eb9SGleb Smirnoff 4863b3a8eb9SGleb Smirnoff if (!(sc->sc_flags & PFSYNCF_OK) && carp_demote_adj_p) 4873b3a8eb9SGleb Smirnoff (*carp_demote_adj_p)(-V_pfsync_carp_adj, "pfsync destroy"); 4883b3a8eb9SGleb Smirnoff bpfdetach(ifp); 4893b3a8eb9SGleb Smirnoff if_detach(ifp); 4903b3a8eb9SGleb Smirnoff 4915f75cd39SKristof Provost pfsync_drop_all(sc); 4923b3a8eb9SGleb Smirnoff 4933b3a8eb9SGleb Smirnoff if_free(ifp); 4943b3a8eb9SGleb Smirnoff pfsync_multicast_cleanup(sc); 4953b3a8eb9SGleb Smirnoff mtx_destroy(&sc->sc_mtx); 4963b3a8eb9SGleb Smirnoff mtx_destroy(&sc->sc_bulk_mtx); 4974fc65bcbSKristof Provost 4984fc65bcbSKristof Provost free(sc->sc_buckets, M_PFSYNC); 4993b3a8eb9SGleb Smirnoff free(sc, M_PFSYNC); 5003b3a8eb9SGleb Smirnoff 5013b3a8eb9SGleb Smirnoff V_pfsyncif = NULL; 5023b3a8eb9SGleb Smirnoff } 5033b3a8eb9SGleb Smirnoff 5043b3a8eb9SGleb Smirnoff static int 5053b3a8eb9SGleb Smirnoff pfsync_alloc_scrub_memory(struct pfsync_state_peer *s, 5063b3a8eb9SGleb Smirnoff struct pf_state_peer *d) 5073b3a8eb9SGleb Smirnoff { 5083b3a8eb9SGleb Smirnoff if (s->scrub.scrub_flag && d->scrub == NULL) { 5093b3a8eb9SGleb Smirnoff d->scrub = uma_zalloc(V_pf_state_scrub_z, M_NOWAIT | M_ZERO); 5103b3a8eb9SGleb Smirnoff if (d->scrub == NULL) 5113b3a8eb9SGleb Smirnoff return (ENOMEM); 5123b3a8eb9SGleb Smirnoff } 5133b3a8eb9SGleb Smirnoff 5143b3a8eb9SGleb Smirnoff return (0); 5153b3a8eb9SGleb Smirnoff } 5163b3a8eb9SGleb Smirnoff 5173b3a8eb9SGleb Smirnoff static int 5184bf98559SKajetan Staszkiewicz pfsync_state_import(union pfsync_state_union *sp, int flags, int msg_version) 5193b3a8eb9SGleb Smirnoff { 5203b3a8eb9SGleb Smirnoff struct pfsync_softc *sc = V_pfsyncif; 5218ff2bd98SGleb Smirnoff #ifndef __NO_STRICT_ALIGNMENT 5228ff2bd98SGleb Smirnoff struct pfsync_state_key key[2]; 5238ff2bd98SGleb Smirnoff #endif 5248ff2bd98SGleb Smirnoff struct pfsync_state_key *kw, *ks; 525211cddf9SKristof Provost struct pf_kstate *st = NULL; 5263b3a8eb9SGleb Smirnoff struct pf_state_key *skw = NULL, *sks = NULL; 527e86bddeaSKristof Provost struct pf_krule *r = NULL; 528320c1116SKristof Provost struct pfi_kkif *kif; 529ad6562ecSKajetan Staszkiewicz struct pfi_kkif *rt_kif = NULL; 530ad6562ecSKajetan Staszkiewicz struct pf_kpooladdr *rpool_first; 5313b3a8eb9SGleb Smirnoff int error; 532ad6562ecSKajetan Staszkiewicz uint8_t rt = 0; 5333b3a8eb9SGleb Smirnoff 5343b3a8eb9SGleb Smirnoff PF_RULES_RASSERT(); 5353b3a8eb9SGleb Smirnoff 5364bf98559SKajetan Staszkiewicz if (sp->pfs_1301.creatorid == 0) { 537b69d74e8SGleb Smirnoff if (V_pf_status.debug >= PF_DEBUG_MISC) 5383b3a8eb9SGleb Smirnoff printf("%s: invalid creator id: %08x\n", __func__, 5394bf98559SKajetan Staszkiewicz ntohl(sp->pfs_1301.creatorid)); 5403b3a8eb9SGleb Smirnoff return (EINVAL); 5413b3a8eb9SGleb Smirnoff } 5423b3a8eb9SGleb Smirnoff 5434bf98559SKajetan Staszkiewicz if ((kif = pfi_kkif_find(sp->pfs_1301.ifname)) == NULL) { 5443b3a8eb9SGleb Smirnoff if (V_pf_status.debug >= PF_DEBUG_MISC) 5453b3a8eb9SGleb Smirnoff printf("%s: unknown interface: %s\n", __func__, 5464bf98559SKajetan Staszkiewicz sp->pfs_1301.ifname); 5473b3a8eb9SGleb Smirnoff if (flags & PFSYNC_SI_IOCTL) 5483b3a8eb9SGleb Smirnoff return (EINVAL); 5493b3a8eb9SGleb Smirnoff return (0); /* skip this state */ 5503b3a8eb9SGleb Smirnoff } 5513b3a8eb9SGleb Smirnoff 5523b3a8eb9SGleb Smirnoff /* 5533b3a8eb9SGleb Smirnoff * If the ruleset checksums match or the state is coming from the ioctl, 5543b3a8eb9SGleb Smirnoff * it's safe to associate the state with the rule of that number. 5553b3a8eb9SGleb Smirnoff */ 5564bf98559SKajetan Staszkiewicz if (sp->pfs_1301.rule != htonl(-1) && sp->pfs_1301.anchor == htonl(-1) && 5574bf98559SKajetan Staszkiewicz (flags & (PFSYNC_SI_IOCTL | PFSYNC_SI_CKSUM)) && ntohl(sp->pfs_1301.rule) < 5583b3a8eb9SGleb Smirnoff pf_main_ruleset.rules[PF_RULESET_FILTER].active.rcount) 5593b3a8eb9SGleb Smirnoff r = pf_main_ruleset.rules[ 5604bf98559SKajetan Staszkiewicz PF_RULESET_FILTER].active.ptr_array[ntohl(sp->pfs_1301.rule)]; 5613b3a8eb9SGleb Smirnoff else 5623b3a8eb9SGleb Smirnoff r = &V_pf_default_rule; 5633b3a8eb9SGleb Smirnoff 564ad6562ecSKajetan Staszkiewicz /* 565ad6562ecSKajetan Staszkiewicz * Check routing interface early on. Do it before allocating memory etc. 566ad6562ecSKajetan Staszkiewicz * because there is a high chance there will be a lot more such states. 567ad6562ecSKajetan Staszkiewicz */ 568ad6562ecSKajetan Staszkiewicz switch (msg_version) { 569ad6562ecSKajetan Staszkiewicz case PFSYNC_MSG_VERSION_1301: 570ad6562ecSKajetan Staszkiewicz /* 571ad6562ecSKajetan Staszkiewicz * On FreeBSD <= 13 the routing interface and routing operation 572ad6562ecSKajetan Staszkiewicz * are not sent over pfsync. If the ruleset is identical, 573ad6562ecSKajetan Staszkiewicz * though, we might be able to recover the routing information 574ad6562ecSKajetan Staszkiewicz * from the local ruleset. 575ad6562ecSKajetan Staszkiewicz */ 576ad6562ecSKajetan Staszkiewicz if (r != &V_pf_default_rule) { 577*0972294eSKristof Provost struct pf_kpool *pool = &r->route; 578*0972294eSKristof Provost 579*0972294eSKristof Provost /* Backwards compatibility. */ 580*0972294eSKristof Provost if (TAILQ_EMPTY(&pool->list)) 581*0972294eSKristof Provost pool = &r->rdr; 582*0972294eSKristof Provost 583ad6562ecSKajetan Staszkiewicz /* 584ad6562ecSKajetan Staszkiewicz * The ruleset is identical, try to recover. If the rule 585ad6562ecSKajetan Staszkiewicz * has a redirection pool with a single interface, there 586ad6562ecSKajetan Staszkiewicz * is a chance that this interface is identical as on 587ad6562ecSKajetan Staszkiewicz * the pfsync peer. If there's more than one interface, 588ad6562ecSKajetan Staszkiewicz * give up, as we can't be sure that we will pick the 589ad6562ecSKajetan Staszkiewicz * same one as the pfsync peer did. 590ad6562ecSKajetan Staszkiewicz */ 591*0972294eSKristof Provost rpool_first = TAILQ_FIRST(&(pool->list)); 592ad6562ecSKajetan Staszkiewicz if ((rpool_first == NULL) || 593ad6562ecSKajetan Staszkiewicz (TAILQ_NEXT(rpool_first, entries) != NULL)) { 594ad6562ecSKajetan Staszkiewicz DPFPRINTF(PF_DEBUG_MISC, 595ad6562ecSKajetan Staszkiewicz ("%s: can't recover routing information " 596ad6562ecSKajetan Staszkiewicz "because of empty or bad redirection pool\n", 597ad6562ecSKajetan Staszkiewicz __func__)); 598ad6562ecSKajetan Staszkiewicz return ((flags & PFSYNC_SI_IOCTL) ? EINVAL : 0); 599ad6562ecSKajetan Staszkiewicz } 600ad6562ecSKajetan Staszkiewicz rt = r->rt; 601ad6562ecSKajetan Staszkiewicz rt_kif = rpool_first->kif; 602ad6562ecSKajetan Staszkiewicz } else if (!PF_AZERO(&sp->pfs_1301.rt_addr, sp->pfs_1301.af)) { 603ad6562ecSKajetan Staszkiewicz /* 604ad6562ecSKajetan Staszkiewicz * Ruleset different, routing *supposedly* requested, 605ad6562ecSKajetan Staszkiewicz * give up on recovering. 606ad6562ecSKajetan Staszkiewicz */ 607ad6562ecSKajetan Staszkiewicz DPFPRINTF(PF_DEBUG_MISC, 608ad6562ecSKajetan Staszkiewicz ("%s: can't recover routing information " 609ad6562ecSKajetan Staszkiewicz "because of different ruleset\n", __func__)); 610ad6562ecSKajetan Staszkiewicz return ((flags & PFSYNC_SI_IOCTL) ? EINVAL : 0); 611ad6562ecSKajetan Staszkiewicz } 612ad6562ecSKajetan Staszkiewicz break; 613ad6562ecSKajetan Staszkiewicz case PFSYNC_MSG_VERSION_1400: 614ad6562ecSKajetan Staszkiewicz /* 615ad6562ecSKajetan Staszkiewicz * On FreeBSD 14 and above we're not taking any chances. 616ad6562ecSKajetan Staszkiewicz * We use the information synced to us. 617ad6562ecSKajetan Staszkiewicz */ 618ad6562ecSKajetan Staszkiewicz if (sp->pfs_1400.rt) { 619ad6562ecSKajetan Staszkiewicz rt_kif = pfi_kkif_find(sp->pfs_1400.rt_ifname); 620ad6562ecSKajetan Staszkiewicz if (rt_kif == NULL) { 621ad6562ecSKajetan Staszkiewicz DPFPRINTF(PF_DEBUG_MISC, 622ad6562ecSKajetan Staszkiewicz ("%s: unknown route interface: %s\n", 623ad6562ecSKajetan Staszkiewicz __func__, sp->pfs_1400.rt_ifname)); 624ad6562ecSKajetan Staszkiewicz return ((flags & PFSYNC_SI_IOCTL) ? EINVAL : 0); 625ad6562ecSKajetan Staszkiewicz } 626ad6562ecSKajetan Staszkiewicz rt = sp->pfs_1400.rt; 627ad6562ecSKajetan Staszkiewicz } 628ad6562ecSKajetan Staszkiewicz break; 629ad6562ecSKajetan Staszkiewicz } 630ad6562ecSKajetan Staszkiewicz 63148278b88SGleb Smirnoff if ((r->max_states && 63248278b88SGleb Smirnoff counter_u64_fetch(r->states_cur) >= r->max_states)) 6333b3a8eb9SGleb Smirnoff goto cleanup; 6343b3a8eb9SGleb Smirnoff 6353b3a8eb9SGleb Smirnoff /* 6363b3a8eb9SGleb Smirnoff * XXXGL: consider M_WAITOK in ioctl path after. 6373b3a8eb9SGleb Smirnoff */ 638803dfe3dSMateusz Guzik st = pf_alloc_state(M_NOWAIT); 639803dfe3dSMateusz Guzik if (__predict_false(st == NULL)) 6403b3a8eb9SGleb Smirnoff goto cleanup; 6413b3a8eb9SGleb Smirnoff 6423b3a8eb9SGleb Smirnoff if ((skw = uma_zalloc(V_pf_state_key_z, M_NOWAIT)) == NULL) 6433b3a8eb9SGleb Smirnoff goto cleanup; 6443b3a8eb9SGleb Smirnoff 6458ff2bd98SGleb Smirnoff #ifndef __NO_STRICT_ALIGNMENT 6464bf98559SKajetan Staszkiewicz bcopy(&sp->pfs_1301.key, key, sizeof(struct pfsync_state_key) * 2); 6478ff2bd98SGleb Smirnoff kw = &key[PF_SK_WIRE]; 6488ff2bd98SGleb Smirnoff ks = &key[PF_SK_STACK]; 6498ff2bd98SGleb Smirnoff #else 6504bf98559SKajetan Staszkiewicz kw = &sp->pfs_1301.key[PF_SK_WIRE]; 6514bf98559SKajetan Staszkiewicz ks = &sp->pfs_1301.key[PF_SK_STACK]; 6528ff2bd98SGleb Smirnoff #endif 6538ff2bd98SGleb Smirnoff 6544bf98559SKajetan Staszkiewicz if (PF_ANEQ(&kw->addr[0], &ks->addr[0], sp->pfs_1301.af) || 6554bf98559SKajetan Staszkiewicz PF_ANEQ(&kw->addr[1], &ks->addr[1], sp->pfs_1301.af) || 6568ff2bd98SGleb Smirnoff kw->port[0] != ks->port[0] || 6578ff2bd98SGleb Smirnoff kw->port[1] != ks->port[1]) { 6583b3a8eb9SGleb Smirnoff sks = uma_zalloc(V_pf_state_key_z, M_NOWAIT); 6593b3a8eb9SGleb Smirnoff if (sks == NULL) 6603b3a8eb9SGleb Smirnoff goto cleanup; 6613b3a8eb9SGleb Smirnoff } else 6623b3a8eb9SGleb Smirnoff sks = skw; 6633b3a8eb9SGleb Smirnoff 6643b3a8eb9SGleb Smirnoff /* allocate memory for scrub info */ 6654bf98559SKajetan Staszkiewicz if (pfsync_alloc_scrub_memory(&sp->pfs_1301.src, &st->src) || 6664bf98559SKajetan Staszkiewicz pfsync_alloc_scrub_memory(&sp->pfs_1301.dst, &st->dst)) 6673b3a8eb9SGleb Smirnoff goto cleanup; 6683b3a8eb9SGleb Smirnoff 6698ff2bd98SGleb Smirnoff /* Copy to state key(s). */ 6708ff2bd98SGleb Smirnoff skw->addr[0] = kw->addr[0]; 6718ff2bd98SGleb Smirnoff skw->addr[1] = kw->addr[1]; 6728ff2bd98SGleb Smirnoff skw->port[0] = kw->port[0]; 6738ff2bd98SGleb Smirnoff skw->port[1] = kw->port[1]; 6744bf98559SKajetan Staszkiewicz skw->proto = sp->pfs_1301.proto; 6754bf98559SKajetan Staszkiewicz skw->af = sp->pfs_1301.af; 6763b3a8eb9SGleb Smirnoff if (sks != skw) { 6778ff2bd98SGleb Smirnoff sks->addr[0] = ks->addr[0]; 6788ff2bd98SGleb Smirnoff sks->addr[1] = ks->addr[1]; 6798ff2bd98SGleb Smirnoff sks->port[0] = ks->port[0]; 6808ff2bd98SGleb Smirnoff sks->port[1] = ks->port[1]; 6814bf98559SKajetan Staszkiewicz sks->proto = sp->pfs_1301.proto; 6824bf98559SKajetan Staszkiewicz sks->af = sp->pfs_1301.af; 6833b3a8eb9SGleb Smirnoff } 6843b3a8eb9SGleb Smirnoff 6853b3a8eb9SGleb Smirnoff /* copy to state */ 686c49c9da2SKajetan Staszkiewicz bcopy(&sp->pfs_1301.rt_addr, &st->act.rt_addr, sizeof(st->act.rt_addr)); 68704932601SKristof Provost st->creation = (time_uptime - ntohl(sp->pfs_1301.creation)) * 1000; 68804932601SKristof Provost st->expire = pf_get_uptime(); 6894bf98559SKajetan Staszkiewicz if (sp->pfs_1301.expire) { 6903b3a8eb9SGleb Smirnoff uint32_t timeout; 6913b3a8eb9SGleb Smirnoff 6924bf98559SKajetan Staszkiewicz timeout = r->timeout[sp->pfs_1301.timeout]; 6933b3a8eb9SGleb Smirnoff if (!timeout) 6944bf98559SKajetan Staszkiewicz timeout = V_pf_default_rule.timeout[sp->pfs_1301.timeout]; 6953b3a8eb9SGleb Smirnoff 6963b3a8eb9SGleb Smirnoff /* sp->expire may have been adaptively scaled by export. */ 69704932601SKristof Provost st->expire -= (timeout - ntohl(sp->pfs_1301.expire)) * 1000; 6983b3a8eb9SGleb Smirnoff } 6993b3a8eb9SGleb Smirnoff 7004bf98559SKajetan Staszkiewicz st->direction = sp->pfs_1301.direction; 7016b4ed16dSKajetan Staszkiewicz st->act.log = sp->pfs_1301.log; 7024bf98559SKajetan Staszkiewicz st->timeout = sp->pfs_1301.timeout; 70339282ef3SKajetan Staszkiewicz 704ad6562ecSKajetan Staszkiewicz st->act.rt = rt; 705ad6562ecSKajetan Staszkiewicz st->act.rt_kif = rt_kif; 706ad6562ecSKajetan Staszkiewicz 7074bf98559SKajetan Staszkiewicz switch (msg_version) { 7084bf98559SKajetan Staszkiewicz case PFSYNC_MSG_VERSION_1301: 7094bf98559SKajetan Staszkiewicz st->state_flags = sp->pfs_1301.state_flags; 7104bf98559SKajetan Staszkiewicz /* 7114bf98559SKajetan Staszkiewicz * In FreeBSD 13 pfsync lacks many attributes. Copy them 7124bf98559SKajetan Staszkiewicz * from the rule if possible. If rule can't be matched 7134bf98559SKajetan Staszkiewicz * clear any set options as we can't recover their 7144bf98559SKajetan Staszkiewicz * parameters. 7154bf98559SKajetan Staszkiewicz */ 71639282ef3SKajetan Staszkiewicz if (r == &V_pf_default_rule) { 71739282ef3SKajetan Staszkiewicz st->state_flags &= ~PFSTATE_SETMASK; 71839282ef3SKajetan Staszkiewicz } else { 7194bf98559SKajetan Staszkiewicz /* 7204bf98559SKajetan Staszkiewicz * Similar to pf_rule_to_actions(). This code 7214bf98559SKajetan Staszkiewicz * won't set the actions properly if they come 7224bf98559SKajetan Staszkiewicz * from multiple "match" rules as only rule 7234bf98559SKajetan Staszkiewicz * creating the state is send over pfsync. 7244bf98559SKajetan Staszkiewicz */ 7256b4ed16dSKajetan Staszkiewicz st->act.qid = r->qid; 7266b4ed16dSKajetan Staszkiewicz st->act.pqid = r->pqid; 7276b4ed16dSKajetan Staszkiewicz st->act.rtableid = r->rtableid; 72839282ef3SKajetan Staszkiewicz if (r->scrub_flags & PFSTATE_SETTOS) 7296b4ed16dSKajetan Staszkiewicz st->act.set_tos = r->set_tos; 7306b4ed16dSKajetan Staszkiewicz st->act.min_ttl = r->min_ttl; 7316b4ed16dSKajetan Staszkiewicz st->act.max_mss = r->max_mss; 7324bf98559SKajetan Staszkiewicz st->state_flags |= (r->scrub_flags & 7334bf98559SKajetan Staszkiewicz (PFSTATE_NODF|PFSTATE_RANDOMID| 7344bf98559SKajetan Staszkiewicz PFSTATE_SETTOS|PFSTATE_SCRUB_TCP| 7354bf98559SKajetan Staszkiewicz PFSTATE_SETPRIO)); 7364bf98559SKajetan Staszkiewicz if (r->dnpipe || r->dnrpipe) { 7374bf98559SKajetan Staszkiewicz if (r->free_flags & PFRULE_DN_IS_PIPE) 7384bf98559SKajetan Staszkiewicz st->state_flags |= PFSTATE_DN_IS_PIPE; 7394bf98559SKajetan Staszkiewicz else 7404bf98559SKajetan Staszkiewicz st->state_flags &= ~PFSTATE_DN_IS_PIPE; 7414bf98559SKajetan Staszkiewicz } 7426b4ed16dSKajetan Staszkiewicz st->act.dnpipe = r->dnpipe; 7436b4ed16dSKajetan Staszkiewicz st->act.dnrpipe = r->dnrpipe; 7444bf98559SKajetan Staszkiewicz } 7454bf98559SKajetan Staszkiewicz break; 7464bf98559SKajetan Staszkiewicz case PFSYNC_MSG_VERSION_1400: 7474bf98559SKajetan Staszkiewicz st->state_flags = ntohs(sp->pfs_1400.state_flags); 7486b4ed16dSKajetan Staszkiewicz st->act.qid = ntohs(sp->pfs_1400.qid); 7496b4ed16dSKajetan Staszkiewicz st->act.pqid = ntohs(sp->pfs_1400.pqid); 7506b4ed16dSKajetan Staszkiewicz st->act.dnpipe = ntohs(sp->pfs_1400.dnpipe); 7516b4ed16dSKajetan Staszkiewicz st->act.dnrpipe = ntohs(sp->pfs_1400.dnrpipe); 7526b4ed16dSKajetan Staszkiewicz st->act.rtableid = ntohl(sp->pfs_1400.rtableid); 7536b4ed16dSKajetan Staszkiewicz st->act.min_ttl = sp->pfs_1400.min_ttl; 7546b4ed16dSKajetan Staszkiewicz st->act.set_tos = sp->pfs_1400.set_tos; 7556b4ed16dSKajetan Staszkiewicz st->act.max_mss = ntohs(sp->pfs_1400.max_mss); 7566b4ed16dSKajetan Staszkiewicz st->act.set_prio[0] = sp->pfs_1400.set_prio[0]; 7576b4ed16dSKajetan Staszkiewicz st->act.set_prio[1] = sp->pfs_1400.set_prio[1]; 7584bf98559SKajetan Staszkiewicz break; 7594bf98559SKajetan Staszkiewicz default: 7604bf98559SKajetan Staszkiewicz panic("%s: Unsupported pfsync_msg_version %d", 7614bf98559SKajetan Staszkiewicz __func__, msg_version); 76239282ef3SKajetan Staszkiewicz } 7633b3a8eb9SGleb Smirnoff 7644bf98559SKajetan Staszkiewicz st->id = sp->pfs_1301.id; 7654bf98559SKajetan Staszkiewicz st->creatorid = sp->pfs_1301.creatorid; 7664bf98559SKajetan Staszkiewicz pf_state_peer_ntoh(&sp->pfs_1301.src, &st->src); 7674bf98559SKajetan Staszkiewicz pf_state_peer_ntoh(&sp->pfs_1301.dst, &st->dst); 7683b3a8eb9SGleb Smirnoff 769e5c64b26SKajetan Staszkiewicz st->rule = r; 770e5c64b26SKajetan Staszkiewicz st->nat_rule = NULL; 771e5c64b26SKajetan Staszkiewicz st->anchor = NULL; 7723b3a8eb9SGleb Smirnoff 7733b3a8eb9SGleb Smirnoff st->pfsync_time = time_uptime; 7743b3a8eb9SGleb Smirnoff st->sync_state = PFSYNC_S_NONE; 7753b3a8eb9SGleb Smirnoff 7763b3a8eb9SGleb Smirnoff if (!(flags & PFSYNC_SI_IOCTL)) 7773b3a8eb9SGleb Smirnoff st->state_flags |= PFSTATE_NOSYNC; 7783b3a8eb9SGleb Smirnoff 779d0fdf2b2SKristof Provost if ((error = pf_state_insert(kif, kif, skw, sks, st)) != 0) 7803b3a8eb9SGleb Smirnoff goto cleanup_state; 78148278b88SGleb Smirnoff 78248278b88SGleb Smirnoff /* XXX when we have nat_rule/anchors, use STATE_INC_COUNTERS */ 78348278b88SGleb Smirnoff counter_u64_add(r->states_cur, 1); 78448278b88SGleb Smirnoff counter_u64_add(r->states_tot, 1); 7853b3a8eb9SGleb Smirnoff 7863b3a8eb9SGleb Smirnoff if (!(flags & PFSYNC_SI_IOCTL)) { 7873b3a8eb9SGleb Smirnoff st->state_flags &= ~PFSTATE_NOSYNC; 7883b3a8eb9SGleb Smirnoff if (st->state_flags & PFSTATE_ACK) { 7890ed5f66cSKristof Provost struct pfsync_bucket *b = pfsync_get_bucket(sc, st); 7900ed5f66cSKristof Provost PFSYNC_BUCKET_LOCK(b); 791aa8c6a6dSMarcel Moolenaar pfsync_q_ins(st, PFSYNC_S_IACK, true); 7920ed5f66cSKristof Provost PFSYNC_BUCKET_UNLOCK(b); 7930ed5f66cSKristof Provost 7944fc65bcbSKristof Provost pfsync_push_all(sc); 7953b3a8eb9SGleb Smirnoff } 7963b3a8eb9SGleb Smirnoff } 7973b3a8eb9SGleb Smirnoff st->state_flags &= ~PFSTATE_ACK; 7983b3a8eb9SGleb Smirnoff PF_STATE_UNLOCK(st); 7993b3a8eb9SGleb Smirnoff 8003b3a8eb9SGleb Smirnoff return (0); 8013b3a8eb9SGleb Smirnoff 8023b3a8eb9SGleb Smirnoff cleanup: 8033b3a8eb9SGleb Smirnoff error = ENOMEM; 804ad6562ecSKajetan Staszkiewicz 8053b3a8eb9SGleb Smirnoff if (skw == sks) 8063b3a8eb9SGleb Smirnoff sks = NULL; 8073b3a8eb9SGleb Smirnoff uma_zfree(V_pf_state_key_z, skw); 8083b3a8eb9SGleb Smirnoff uma_zfree(V_pf_state_key_z, sks); 8093b3a8eb9SGleb Smirnoff 8103b3a8eb9SGleb Smirnoff cleanup_state: /* pf_state_insert() frees the state keys. */ 8113b3a8eb9SGleb Smirnoff if (st) { 81269ce6ae2SMateusz Guzik st->timeout = PFTM_UNLINKED; /* appease an assert */ 813803dfe3dSMateusz Guzik pf_free_state(st); 8143b3a8eb9SGleb Smirnoff } 8153b3a8eb9SGleb Smirnoff return (error); 8163b3a8eb9SGleb Smirnoff } 8173b3a8eb9SGleb Smirnoff 818813c5b75SLuiz Amaral #ifdef INET 8198f5a8818SKevin Lo static int 8208f5a8818SKevin Lo pfsync_input(struct mbuf **mp, int *offp __unused, int proto __unused) 8213b3a8eb9SGleb Smirnoff { 8223b3a8eb9SGleb Smirnoff struct pfsync_softc *sc = V_pfsyncif; 8238f5a8818SKevin Lo struct mbuf *m = *mp; 8243b3a8eb9SGleb Smirnoff struct ip *ip = mtod(m, struct ip *); 8253b3a8eb9SGleb Smirnoff struct pfsync_header *ph; 8263b3a8eb9SGleb Smirnoff struct pfsync_subheader subh; 8273b3a8eb9SGleb Smirnoff 828485be979SLuiz Amaral int offset, len, flags = 0; 8293b3a8eb9SGleb Smirnoff int rv; 8303b3a8eb9SGleb Smirnoff uint16_t count; 8313b3a8eb9SGleb Smirnoff 832455969d3SKristof Provost PF_RULES_RLOCK_TRACKER; 833455969d3SKristof Provost 8348f5a8818SKevin Lo *mp = NULL; 8353b3a8eb9SGleb Smirnoff V_pfsyncstats.pfsyncs_ipackets++; 8363b3a8eb9SGleb Smirnoff 8373b3a8eb9SGleb Smirnoff /* Verify that we have a sync interface configured. */ 8383b3a8eb9SGleb Smirnoff if (!sc || !sc->sc_sync_if || !V_pf_status.running || 8393b3a8eb9SGleb Smirnoff (sc->sc_ifp->if_drv_flags & IFF_DRV_RUNNING) == 0) 8403b3a8eb9SGleb Smirnoff goto done; 8413b3a8eb9SGleb Smirnoff 8423b3a8eb9SGleb Smirnoff /* verify that the packet came in on the right interface */ 8433b3a8eb9SGleb Smirnoff if (sc->sc_sync_if != m->m_pkthdr.rcvif) { 8443b3a8eb9SGleb Smirnoff V_pfsyncstats.pfsyncs_badif++; 8453b3a8eb9SGleb Smirnoff goto done; 8463b3a8eb9SGleb Smirnoff } 8473b3a8eb9SGleb Smirnoff 8482a6009bfSGleb Smirnoff if_inc_counter(sc->sc_ifp, IFCOUNTER_IPACKETS, 1); 8492a6009bfSGleb Smirnoff if_inc_counter(sc->sc_ifp, IFCOUNTER_IBYTES, m->m_pkthdr.len); 8503b3a8eb9SGleb Smirnoff /* verify that the IP TTL is 255. */ 8513b3a8eb9SGleb Smirnoff if (ip->ip_ttl != PFSYNC_DFLTTL) { 8523b3a8eb9SGleb Smirnoff V_pfsyncstats.pfsyncs_badttl++; 8533b3a8eb9SGleb Smirnoff goto done; 8543b3a8eb9SGleb Smirnoff } 8553b3a8eb9SGleb Smirnoff 8563b3a8eb9SGleb Smirnoff offset = ip->ip_hl << 2; 8573b3a8eb9SGleb Smirnoff if (m->m_pkthdr.len < offset + sizeof(*ph)) { 8583b3a8eb9SGleb Smirnoff V_pfsyncstats.pfsyncs_hdrops++; 8593b3a8eb9SGleb Smirnoff goto done; 8603b3a8eb9SGleb Smirnoff } 8613b3a8eb9SGleb Smirnoff 8623b3a8eb9SGleb Smirnoff if (offset + sizeof(*ph) > m->m_len) { 8633b3a8eb9SGleb Smirnoff if (m_pullup(m, offset + sizeof(*ph)) == NULL) { 8643b3a8eb9SGleb Smirnoff V_pfsyncstats.pfsyncs_hdrops++; 8658f5a8818SKevin Lo return (IPPROTO_DONE); 8663b3a8eb9SGleb Smirnoff } 8673b3a8eb9SGleb Smirnoff ip = mtod(m, struct ip *); 8683b3a8eb9SGleb Smirnoff } 8693b3a8eb9SGleb Smirnoff ph = (struct pfsync_header *)((char *)ip + offset); 8703b3a8eb9SGleb Smirnoff 8713b3a8eb9SGleb Smirnoff /* verify the version */ 8723b3a8eb9SGleb Smirnoff if (ph->version != PFSYNC_VERSION) { 8733b3a8eb9SGleb Smirnoff V_pfsyncstats.pfsyncs_badver++; 8743b3a8eb9SGleb Smirnoff goto done; 8753b3a8eb9SGleb Smirnoff } 8763b3a8eb9SGleb Smirnoff 8779ff7e6e9SGleb Smirnoff len = ntohs(ph->len) + offset; 8789ff7e6e9SGleb Smirnoff if (m->m_pkthdr.len < len) { 8794c794f5cSGleb Smirnoff V_pfsyncstats.pfsyncs_badlen++; 8809ff7e6e9SGleb Smirnoff goto done; 8819ff7e6e9SGleb Smirnoff } 8829ff7e6e9SGleb Smirnoff 8833b3a8eb9SGleb Smirnoff /* 8843b3a8eb9SGleb Smirnoff * Trusting pf_chksum during packet processing, as well as seeking 8853b3a8eb9SGleb Smirnoff * in interface name tree, require holding PF_RULES_RLOCK(). 8863b3a8eb9SGleb Smirnoff */ 8873b3a8eb9SGleb Smirnoff PF_RULES_RLOCK(); 8883b3a8eb9SGleb Smirnoff if (!bcmp(&ph->pfcksum, &V_pf_status.pf_chksum, PF_MD5_DIGEST_LENGTH)) 889485be979SLuiz Amaral flags = PFSYNC_SI_CKSUM; 8903b3a8eb9SGleb Smirnoff 8913b3a8eb9SGleb Smirnoff offset += sizeof(*ph); 8929ff7e6e9SGleb Smirnoff while (offset <= len - sizeof(subh)) { 8933b3a8eb9SGleb Smirnoff m_copydata(m, offset, sizeof(subh), (caddr_t)&subh); 8943b3a8eb9SGleb Smirnoff offset += sizeof(subh); 8953b3a8eb9SGleb Smirnoff 8963b3a8eb9SGleb Smirnoff if (subh.action >= PFSYNC_ACT_MAX) { 8973b3a8eb9SGleb Smirnoff V_pfsyncstats.pfsyncs_badact++; 8983b3a8eb9SGleb Smirnoff PF_RULES_RUNLOCK(); 8993b3a8eb9SGleb Smirnoff goto done; 9003b3a8eb9SGleb Smirnoff } 9013b3a8eb9SGleb Smirnoff 9023b3a8eb9SGleb Smirnoff count = ntohs(subh.count); 9033b3a8eb9SGleb Smirnoff V_pfsyncstats.pfsyncs_iacts[subh.action] += count; 9044bf98559SKajetan Staszkiewicz rv = (*pfsync_acts[subh.action])(m, offset, count, flags, subh.action); 9053b3a8eb9SGleb Smirnoff if (rv == -1) { 9063b3a8eb9SGleb Smirnoff PF_RULES_RUNLOCK(); 9078f5a8818SKevin Lo return (IPPROTO_DONE); 9083b3a8eb9SGleb Smirnoff } 9093b3a8eb9SGleb Smirnoff 9103b3a8eb9SGleb Smirnoff offset += rv; 9113b3a8eb9SGleb Smirnoff } 9123b3a8eb9SGleb Smirnoff PF_RULES_RUNLOCK(); 9133b3a8eb9SGleb Smirnoff 9143b3a8eb9SGleb Smirnoff done: 9153b3a8eb9SGleb Smirnoff m_freem(m); 9168f5a8818SKevin Lo return (IPPROTO_DONE); 9173b3a8eb9SGleb Smirnoff } 918813c5b75SLuiz Amaral #endif 9193b3a8eb9SGleb Smirnoff 9206fc7fc2dSLuiz Amaral #ifdef INET6 9216fc7fc2dSLuiz Amaral static int 9226fc7fc2dSLuiz Amaral pfsync6_input(struct mbuf **mp, int *offp __unused, int proto __unused) 9236fc7fc2dSLuiz Amaral { 9246fc7fc2dSLuiz Amaral struct pfsync_softc *sc = V_pfsyncif; 9256fc7fc2dSLuiz Amaral struct mbuf *m = *mp; 9266fc7fc2dSLuiz Amaral struct ip6_hdr *ip6 = mtod(m, struct ip6_hdr *); 9276fc7fc2dSLuiz Amaral struct pfsync_header *ph; 9286fc7fc2dSLuiz Amaral struct pfsync_subheader subh; 9296fc7fc2dSLuiz Amaral 9306fc7fc2dSLuiz Amaral int offset, len, flags = 0; 9316fc7fc2dSLuiz Amaral int rv; 9326fc7fc2dSLuiz Amaral uint16_t count; 9336fc7fc2dSLuiz Amaral 9346fc7fc2dSLuiz Amaral PF_RULES_RLOCK_TRACKER; 9356fc7fc2dSLuiz Amaral 9366fc7fc2dSLuiz Amaral *mp = NULL; 9376fc7fc2dSLuiz Amaral V_pfsyncstats.pfsyncs_ipackets++; 9386fc7fc2dSLuiz Amaral 9396fc7fc2dSLuiz Amaral /* Verify that we have a sync interface configured. */ 9406fc7fc2dSLuiz Amaral if (!sc || !sc->sc_sync_if || !V_pf_status.running || 9416fc7fc2dSLuiz Amaral (sc->sc_ifp->if_drv_flags & IFF_DRV_RUNNING) == 0) 9426fc7fc2dSLuiz Amaral goto done; 9436fc7fc2dSLuiz Amaral 9446fc7fc2dSLuiz Amaral /* verify that the packet came in on the right interface */ 9456fc7fc2dSLuiz Amaral if (sc->sc_sync_if != m->m_pkthdr.rcvif) { 9466fc7fc2dSLuiz Amaral V_pfsyncstats.pfsyncs_badif++; 9476fc7fc2dSLuiz Amaral goto done; 9486fc7fc2dSLuiz Amaral } 9496fc7fc2dSLuiz Amaral 9506fc7fc2dSLuiz Amaral if_inc_counter(sc->sc_ifp, IFCOUNTER_IPACKETS, 1); 9516fc7fc2dSLuiz Amaral if_inc_counter(sc->sc_ifp, IFCOUNTER_IBYTES, m->m_pkthdr.len); 9526fc7fc2dSLuiz Amaral /* verify that the IP TTL is 255. */ 9536fc7fc2dSLuiz Amaral if (ip6->ip6_hlim != PFSYNC_DFLTTL) { 9546fc7fc2dSLuiz Amaral V_pfsyncstats.pfsyncs_badttl++; 9556fc7fc2dSLuiz Amaral goto done; 9566fc7fc2dSLuiz Amaral } 9576fc7fc2dSLuiz Amaral 9586fc7fc2dSLuiz Amaral 9596fc7fc2dSLuiz Amaral offset = sizeof(*ip6); 9606fc7fc2dSLuiz Amaral if (m->m_pkthdr.len < offset + sizeof(*ph)) { 9616fc7fc2dSLuiz Amaral V_pfsyncstats.pfsyncs_hdrops++; 9626fc7fc2dSLuiz Amaral goto done; 9636fc7fc2dSLuiz Amaral } 9646fc7fc2dSLuiz Amaral 9656fc7fc2dSLuiz Amaral if (offset + sizeof(*ph) > m->m_len) { 9666fc7fc2dSLuiz Amaral if (m_pullup(m, offset + sizeof(*ph)) == NULL) { 9676fc7fc2dSLuiz Amaral V_pfsyncstats.pfsyncs_hdrops++; 9686fc7fc2dSLuiz Amaral return (IPPROTO_DONE); 9696fc7fc2dSLuiz Amaral } 9706fc7fc2dSLuiz Amaral ip6 = mtod(m, struct ip6_hdr *); 9716fc7fc2dSLuiz Amaral } 9726fc7fc2dSLuiz Amaral ph = (struct pfsync_header *)((char *)ip6 + offset); 9736fc7fc2dSLuiz Amaral 9746fc7fc2dSLuiz Amaral /* verify the version */ 9756fc7fc2dSLuiz Amaral if (ph->version != PFSYNC_VERSION) { 9766fc7fc2dSLuiz Amaral V_pfsyncstats.pfsyncs_badver++; 9776fc7fc2dSLuiz Amaral goto done; 9786fc7fc2dSLuiz Amaral } 9796fc7fc2dSLuiz Amaral 9806fc7fc2dSLuiz Amaral len = ntohs(ph->len) + offset; 9816fc7fc2dSLuiz Amaral if (m->m_pkthdr.len < len) { 9826fc7fc2dSLuiz Amaral V_pfsyncstats.pfsyncs_badlen++; 9836fc7fc2dSLuiz Amaral goto done; 9846fc7fc2dSLuiz Amaral } 9856fc7fc2dSLuiz Amaral 9866fc7fc2dSLuiz Amaral /* 9876fc7fc2dSLuiz Amaral * Trusting pf_chksum during packet processing, as well as seeking 9886fc7fc2dSLuiz Amaral * in interface name tree, require holding PF_RULES_RLOCK(). 9896fc7fc2dSLuiz Amaral */ 9906fc7fc2dSLuiz Amaral PF_RULES_RLOCK(); 9916fc7fc2dSLuiz Amaral if (!bcmp(&ph->pfcksum, &V_pf_status.pf_chksum, PF_MD5_DIGEST_LENGTH)) 9926fc7fc2dSLuiz Amaral flags = PFSYNC_SI_CKSUM; 9936fc7fc2dSLuiz Amaral 9946fc7fc2dSLuiz Amaral offset += sizeof(*ph); 9956fc7fc2dSLuiz Amaral while (offset <= len - sizeof(subh)) { 9966fc7fc2dSLuiz Amaral m_copydata(m, offset, sizeof(subh), (caddr_t)&subh); 9976fc7fc2dSLuiz Amaral offset += sizeof(subh); 9986fc7fc2dSLuiz Amaral 9996fc7fc2dSLuiz Amaral if (subh.action >= PFSYNC_ACT_MAX) { 10006fc7fc2dSLuiz Amaral V_pfsyncstats.pfsyncs_badact++; 10016fc7fc2dSLuiz Amaral PF_RULES_RUNLOCK(); 10026fc7fc2dSLuiz Amaral goto done; 10036fc7fc2dSLuiz Amaral } 10046fc7fc2dSLuiz Amaral 10056fc7fc2dSLuiz Amaral count = ntohs(subh.count); 10066fc7fc2dSLuiz Amaral V_pfsyncstats.pfsyncs_iacts[subh.action] += count; 10076fc7fc2dSLuiz Amaral rv = (*pfsync_acts[subh.action])(m, offset, count, flags, subh.action); 10086fc7fc2dSLuiz Amaral if (rv == -1) { 10096fc7fc2dSLuiz Amaral PF_RULES_RUNLOCK(); 10106fc7fc2dSLuiz Amaral return (IPPROTO_DONE); 10116fc7fc2dSLuiz Amaral } 10126fc7fc2dSLuiz Amaral 10136fc7fc2dSLuiz Amaral offset += rv; 10146fc7fc2dSLuiz Amaral } 10156fc7fc2dSLuiz Amaral PF_RULES_RUNLOCK(); 10166fc7fc2dSLuiz Amaral 10176fc7fc2dSLuiz Amaral done: 10186fc7fc2dSLuiz Amaral m_freem(m); 10196fc7fc2dSLuiz Amaral return (IPPROTO_DONE); 10206fc7fc2dSLuiz Amaral } 10216fc7fc2dSLuiz Amaral #endif 10226fc7fc2dSLuiz Amaral 10233b3a8eb9SGleb Smirnoff static int 10244bf98559SKajetan Staszkiewicz pfsync_in_clr(struct mbuf *m, int offset, int count, int flags, int action) 10253b3a8eb9SGleb Smirnoff { 10263b3a8eb9SGleb Smirnoff struct pfsync_clr *clr; 10273b3a8eb9SGleb Smirnoff struct mbuf *mp; 10283b3a8eb9SGleb Smirnoff int len = sizeof(*clr) * count; 10293b3a8eb9SGleb Smirnoff int i, offp; 10303b3a8eb9SGleb Smirnoff u_int32_t creatorid; 10313b3a8eb9SGleb Smirnoff 10323b3a8eb9SGleb Smirnoff mp = m_pulldown(m, offset, len, &offp); 10333b3a8eb9SGleb Smirnoff if (mp == NULL) { 10343b3a8eb9SGleb Smirnoff V_pfsyncstats.pfsyncs_badlen++; 10353b3a8eb9SGleb Smirnoff return (-1); 10363b3a8eb9SGleb Smirnoff } 10373b3a8eb9SGleb Smirnoff clr = (struct pfsync_clr *)(mp->m_data + offp); 10383b3a8eb9SGleb Smirnoff 10393b3a8eb9SGleb Smirnoff for (i = 0; i < count; i++) { 10403b3a8eb9SGleb Smirnoff creatorid = clr[i].creatorid; 10413b3a8eb9SGleb Smirnoff 10423b3a8eb9SGleb Smirnoff if (clr[i].ifname[0] != '\0' && 1043320c1116SKristof Provost pfi_kkif_find(clr[i].ifname) == NULL) 10443b3a8eb9SGleb Smirnoff continue; 10453b3a8eb9SGleb Smirnoff 1046271f1469SKristof Provost for (int i = 0; i <= V_pf_hashmask; i++) { 10473b3a8eb9SGleb Smirnoff struct pf_idhash *ih = &V_pf_idhash[i]; 1048211cddf9SKristof Provost struct pf_kstate *s; 10493b3a8eb9SGleb Smirnoff relock: 10503b3a8eb9SGleb Smirnoff PF_HASHROW_LOCK(ih); 10513b3a8eb9SGleb Smirnoff LIST_FOREACH(s, &ih->states, entry) { 10523b3a8eb9SGleb Smirnoff if (s->creatorid == creatorid) { 10533b3a8eb9SGleb Smirnoff s->state_flags |= PFSTATE_NOSYNC; 10548f3d786cSMateusz Guzik pf_unlink_state(s); 10553b3a8eb9SGleb Smirnoff goto relock; 10563b3a8eb9SGleb Smirnoff } 10573b3a8eb9SGleb Smirnoff } 10583b3a8eb9SGleb Smirnoff PF_HASHROW_UNLOCK(ih); 10593b3a8eb9SGleb Smirnoff } 10603b3a8eb9SGleb Smirnoff } 10613b3a8eb9SGleb Smirnoff 10623b3a8eb9SGleb Smirnoff return (len); 10633b3a8eb9SGleb Smirnoff } 10643b3a8eb9SGleb Smirnoff 10653b3a8eb9SGleb Smirnoff static int 10664bf98559SKajetan Staszkiewicz pfsync_in_ins(struct mbuf *m, int offset, int count, int flags, int action) 10673b3a8eb9SGleb Smirnoff { 10683b3a8eb9SGleb Smirnoff struct mbuf *mp; 10694bf98559SKajetan Staszkiewicz union pfsync_state_union *sa, *sp; 107050edc630SKajetan Staszkiewicz int i, offp, total_len, msg_version, msg_len; 10714bf98559SKajetan Staszkiewicz 10724bf98559SKajetan Staszkiewicz switch (action) { 10734bf98559SKajetan Staszkiewicz case PFSYNC_ACT_INS_1301: 107450edc630SKajetan Staszkiewicz msg_len = sizeof(struct pfsync_state_1301); 107550edc630SKajetan Staszkiewicz total_len = msg_len * count; 10764bf98559SKajetan Staszkiewicz msg_version = PFSYNC_MSG_VERSION_1301; 10774bf98559SKajetan Staszkiewicz break; 10784bf98559SKajetan Staszkiewicz case PFSYNC_ACT_INS_1400: 107950edc630SKajetan Staszkiewicz msg_len = sizeof(struct pfsync_state_1400); 108050edc630SKajetan Staszkiewicz total_len = msg_len * count; 10814bf98559SKajetan Staszkiewicz msg_version = PFSYNC_MSG_VERSION_1400; 10824bf98559SKajetan Staszkiewicz break; 10834bf98559SKajetan Staszkiewicz default: 10844bf98559SKajetan Staszkiewicz V_pfsyncstats.pfsyncs_badact++; 10854bf98559SKajetan Staszkiewicz return (-1); 10864bf98559SKajetan Staszkiewicz } 10873b3a8eb9SGleb Smirnoff 108850edc630SKajetan Staszkiewicz mp = m_pulldown(m, offset, total_len, &offp); 10893b3a8eb9SGleb Smirnoff if (mp == NULL) { 10903b3a8eb9SGleb Smirnoff V_pfsyncstats.pfsyncs_badlen++; 10913b3a8eb9SGleb Smirnoff return (-1); 10923b3a8eb9SGleb Smirnoff } 10934bf98559SKajetan Staszkiewicz sa = (union pfsync_state_union *)(mp->m_data + offp); 10943b3a8eb9SGleb Smirnoff 10953b3a8eb9SGleb Smirnoff for (i = 0; i < count; i++) { 109650edc630SKajetan Staszkiewicz sp = (union pfsync_state_union *)((char *)sa + msg_len * i); 10973b3a8eb9SGleb Smirnoff 10983b3a8eb9SGleb Smirnoff /* Check for invalid values. */ 10994bf98559SKajetan Staszkiewicz if (sp->pfs_1301.timeout >= PFTM_MAX || 11004bf98559SKajetan Staszkiewicz sp->pfs_1301.src.state > PF_TCPS_PROXY_DST || 11014bf98559SKajetan Staszkiewicz sp->pfs_1301.dst.state > PF_TCPS_PROXY_DST || 11024bf98559SKajetan Staszkiewicz sp->pfs_1301.direction > PF_OUT || 11034bf98559SKajetan Staszkiewicz (sp->pfs_1301.af != AF_INET && 11044bf98559SKajetan Staszkiewicz sp->pfs_1301.af != AF_INET6)) { 11053b3a8eb9SGleb Smirnoff if (V_pf_status.debug >= PF_DEBUG_MISC) 11063b3a8eb9SGleb Smirnoff printf("%s: invalid value\n", __func__); 11073b3a8eb9SGleb Smirnoff V_pfsyncstats.pfsyncs_badval++; 11083b3a8eb9SGleb Smirnoff continue; 11093b3a8eb9SGleb Smirnoff } 11103b3a8eb9SGleb Smirnoff 11114bf98559SKajetan Staszkiewicz if (pfsync_state_import(sp, flags, msg_version) == ENOMEM) 11123b3a8eb9SGleb Smirnoff /* Drop out, but process the rest of the actions. */ 11133b3a8eb9SGleb Smirnoff break; 11143b3a8eb9SGleb Smirnoff } 11153b3a8eb9SGleb Smirnoff 111650edc630SKajetan Staszkiewicz return (total_len); 11173b3a8eb9SGleb Smirnoff } 11183b3a8eb9SGleb Smirnoff 11193b3a8eb9SGleb Smirnoff static int 11204bf98559SKajetan Staszkiewicz pfsync_in_iack(struct mbuf *m, int offset, int count, int flags, int action) 11213b3a8eb9SGleb Smirnoff { 11223b3a8eb9SGleb Smirnoff struct pfsync_ins_ack *ia, *iaa; 1123211cddf9SKristof Provost struct pf_kstate *st; 11243b3a8eb9SGleb Smirnoff 11253b3a8eb9SGleb Smirnoff struct mbuf *mp; 11263b3a8eb9SGleb Smirnoff int len = count * sizeof(*ia); 11273b3a8eb9SGleb Smirnoff int offp, i; 11283b3a8eb9SGleb Smirnoff 11293b3a8eb9SGleb Smirnoff mp = m_pulldown(m, offset, len, &offp); 11303b3a8eb9SGleb Smirnoff if (mp == NULL) { 11313b3a8eb9SGleb Smirnoff V_pfsyncstats.pfsyncs_badlen++; 11323b3a8eb9SGleb Smirnoff return (-1); 11333b3a8eb9SGleb Smirnoff } 11343b3a8eb9SGleb Smirnoff iaa = (struct pfsync_ins_ack *)(mp->m_data + offp); 11353b3a8eb9SGleb Smirnoff 11363b3a8eb9SGleb Smirnoff for (i = 0; i < count; i++) { 11373b3a8eb9SGleb Smirnoff ia = &iaa[i]; 11383b3a8eb9SGleb Smirnoff 11393b3a8eb9SGleb Smirnoff st = pf_find_state_byid(ia->id, ia->creatorid); 11403b3a8eb9SGleb Smirnoff if (st == NULL) 11413b3a8eb9SGleb Smirnoff continue; 11423b3a8eb9SGleb Smirnoff 11433b3a8eb9SGleb Smirnoff if (st->state_flags & PFSTATE_ACK) { 11443b3a8eb9SGleb Smirnoff pfsync_undefer_state(st, 0); 11453b3a8eb9SGleb Smirnoff } 11463b3a8eb9SGleb Smirnoff PF_STATE_UNLOCK(st); 11473b3a8eb9SGleb Smirnoff } 11483b3a8eb9SGleb Smirnoff /* 11493b3a8eb9SGleb Smirnoff * XXX this is not yet implemented, but we know the size of the 11503b3a8eb9SGleb Smirnoff * message so we can skip it. 11513b3a8eb9SGleb Smirnoff */ 11523b3a8eb9SGleb Smirnoff 11533b3a8eb9SGleb Smirnoff return (count * sizeof(struct pfsync_ins_ack)); 11543b3a8eb9SGleb Smirnoff } 11553b3a8eb9SGleb Smirnoff 11563b3a8eb9SGleb Smirnoff static int 1157211cddf9SKristof Provost pfsync_upd_tcp(struct pf_kstate *st, struct pfsync_state_peer *src, 11583b3a8eb9SGleb Smirnoff struct pfsync_state_peer *dst) 11593b3a8eb9SGleb Smirnoff { 1160f18ab0ffSGleb Smirnoff int sync = 0; 11613b3a8eb9SGleb Smirnoff 11623b3a8eb9SGleb Smirnoff PF_STATE_LOCK_ASSERT(st); 11633b3a8eb9SGleb Smirnoff 11643b3a8eb9SGleb Smirnoff /* 11653b3a8eb9SGleb Smirnoff * The state should never go backwards except 11663b3a8eb9SGleb Smirnoff * for syn-proxy states. Neither should the 11673b3a8eb9SGleb Smirnoff * sequence window slide backwards. 11683b3a8eb9SGleb Smirnoff */ 1169f18ab0ffSGleb Smirnoff if ((st->src.state > src->state && 11703b3a8eb9SGleb Smirnoff (st->src.state < PF_TCPS_PROXY_SRC || 1171f18ab0ffSGleb Smirnoff src->state >= PF_TCPS_PROXY_SRC)) || 1172fed76350SGleb Smirnoff 1173fed76350SGleb Smirnoff (st->src.state == src->state && 1174fed76350SGleb Smirnoff SEQ_GT(st->src.seqlo, ntohl(src->seqlo)))) 1175f18ab0ffSGleb Smirnoff sync++; 1176f18ab0ffSGleb Smirnoff else 11773b3a8eb9SGleb Smirnoff pf_state_peer_ntoh(src, &st->src); 11783b3a8eb9SGleb Smirnoff 1179fed76350SGleb Smirnoff if ((st->dst.state > dst->state) || 1180fed76350SGleb Smirnoff 1181f18ab0ffSGleb Smirnoff (st->dst.state >= TCPS_SYN_SENT && 1182f18ab0ffSGleb Smirnoff SEQ_GT(st->dst.seqlo, ntohl(dst->seqlo)))) 1183f18ab0ffSGleb Smirnoff sync++; 1184f18ab0ffSGleb Smirnoff else 1185f18ab0ffSGleb Smirnoff pf_state_peer_ntoh(dst, &st->dst); 1186f18ab0ffSGleb Smirnoff 1187f18ab0ffSGleb Smirnoff return (sync); 11883b3a8eb9SGleb Smirnoff } 11893b3a8eb9SGleb Smirnoff 11903b3a8eb9SGleb Smirnoff static int 11914bf98559SKajetan Staszkiewicz pfsync_in_upd(struct mbuf *m, int offset, int count, int flags, int action) 11923b3a8eb9SGleb Smirnoff { 11933b3a8eb9SGleb Smirnoff struct pfsync_softc *sc = V_pfsyncif; 11944bf98559SKajetan Staszkiewicz union pfsync_state_union *sa, *sp; 1195211cddf9SKristof Provost struct pf_kstate *st; 11963b3a8eb9SGleb Smirnoff struct mbuf *mp; 119750edc630SKajetan Staszkiewicz int sync, offp, i, total_len, msg_len, msg_version; 11984bf98559SKajetan Staszkiewicz 11994bf98559SKajetan Staszkiewicz switch (action) { 12004bf98559SKajetan Staszkiewicz case PFSYNC_ACT_UPD_1301: 120150edc630SKajetan Staszkiewicz msg_len = sizeof(struct pfsync_state_1301); 120250edc630SKajetan Staszkiewicz total_len = msg_len * count; 12034bf98559SKajetan Staszkiewicz msg_version = PFSYNC_MSG_VERSION_1301; 12044bf98559SKajetan Staszkiewicz break; 12054bf98559SKajetan Staszkiewicz case PFSYNC_ACT_UPD_1400: 120650edc630SKajetan Staszkiewicz msg_len = sizeof(struct pfsync_state_1400); 120750edc630SKajetan Staszkiewicz total_len = msg_len * count; 12084bf98559SKajetan Staszkiewicz msg_version = PFSYNC_MSG_VERSION_1400; 12094bf98559SKajetan Staszkiewicz break; 12104bf98559SKajetan Staszkiewicz default: 12114bf98559SKajetan Staszkiewicz V_pfsyncstats.pfsyncs_badact++; 12124bf98559SKajetan Staszkiewicz return (-1); 12134bf98559SKajetan Staszkiewicz } 12143b3a8eb9SGleb Smirnoff 121550edc630SKajetan Staszkiewicz mp = m_pulldown(m, offset, total_len, &offp); 12163b3a8eb9SGleb Smirnoff if (mp == NULL) { 12173b3a8eb9SGleb Smirnoff V_pfsyncstats.pfsyncs_badlen++; 12183b3a8eb9SGleb Smirnoff return (-1); 12193b3a8eb9SGleb Smirnoff } 12204bf98559SKajetan Staszkiewicz sa = (union pfsync_state_union *)(mp->m_data + offp); 12213b3a8eb9SGleb Smirnoff 12223b3a8eb9SGleb Smirnoff for (i = 0; i < count; i++) { 122350edc630SKajetan Staszkiewicz sp = (union pfsync_state_union *)((char *)sa + msg_len * i); 12243b3a8eb9SGleb Smirnoff 12253b3a8eb9SGleb Smirnoff /* check for invalid values */ 12264bf98559SKajetan Staszkiewicz if (sp->pfs_1301.timeout >= PFTM_MAX || 12274bf98559SKajetan Staszkiewicz sp->pfs_1301.src.state > PF_TCPS_PROXY_DST || 12284bf98559SKajetan Staszkiewicz sp->pfs_1301.dst.state > PF_TCPS_PROXY_DST) { 12293b3a8eb9SGleb Smirnoff if (V_pf_status.debug >= PF_DEBUG_MISC) { 12303b3a8eb9SGleb Smirnoff printf("pfsync_input: PFSYNC_ACT_UPD: " 12313b3a8eb9SGleb Smirnoff "invalid value\n"); 12323b3a8eb9SGleb Smirnoff } 12333b3a8eb9SGleb Smirnoff V_pfsyncstats.pfsyncs_badval++; 12343b3a8eb9SGleb Smirnoff continue; 12353b3a8eb9SGleb Smirnoff } 12363b3a8eb9SGleb Smirnoff 12374bf98559SKajetan Staszkiewicz st = pf_find_state_byid(sp->pfs_1301.id, sp->pfs_1301.creatorid); 12383b3a8eb9SGleb Smirnoff if (st == NULL) { 12393b3a8eb9SGleb Smirnoff /* insert the update */ 12404bf98559SKajetan Staszkiewicz if (pfsync_state_import(sp, flags, msg_version)) 12413b3a8eb9SGleb Smirnoff V_pfsyncstats.pfsyncs_badstate++; 12423b3a8eb9SGleb Smirnoff continue; 12433b3a8eb9SGleb Smirnoff } 12443b3a8eb9SGleb Smirnoff 12453b3a8eb9SGleb Smirnoff if (st->state_flags & PFSTATE_ACK) { 12463b3a8eb9SGleb Smirnoff pfsync_undefer_state(st, 1); 12473b3a8eb9SGleb Smirnoff } 12483b3a8eb9SGleb Smirnoff 1249f18ab0ffSGleb Smirnoff if (st->key[PF_SK_WIRE]->proto == IPPROTO_TCP) 12504bf98559SKajetan Staszkiewicz sync = pfsync_upd_tcp(st, &sp->pfs_1301.src, &sp->pfs_1301.dst); 12513b3a8eb9SGleb Smirnoff else { 1252f18ab0ffSGleb Smirnoff sync = 0; 1253f18ab0ffSGleb Smirnoff 12543b3a8eb9SGleb Smirnoff /* 12553b3a8eb9SGleb Smirnoff * Non-TCP protocol state machine always go 12563b3a8eb9SGleb Smirnoff * forwards 12573b3a8eb9SGleb Smirnoff */ 12584bf98559SKajetan Staszkiewicz if (st->src.state > sp->pfs_1301.src.state) 1259f18ab0ffSGleb Smirnoff sync++; 1260f18ab0ffSGleb Smirnoff else 12614bf98559SKajetan Staszkiewicz pf_state_peer_ntoh(&sp->pfs_1301.src, &st->src); 12624bf98559SKajetan Staszkiewicz if (st->dst.state > sp->pfs_1301.dst.state) 1263f18ab0ffSGleb Smirnoff sync++; 1264f18ab0ffSGleb Smirnoff else 12654bf98559SKajetan Staszkiewicz pf_state_peer_ntoh(&sp->pfs_1301.dst, &st->dst); 12663b3a8eb9SGleb Smirnoff } 1267f18ab0ffSGleb Smirnoff if (sync < 2) { 12684bf98559SKajetan Staszkiewicz pfsync_alloc_scrub_memory(&sp->pfs_1301.dst, &st->dst); 12694bf98559SKajetan Staszkiewicz pf_state_peer_ntoh(&sp->pfs_1301.dst, &st->dst); 127004932601SKristof Provost st->expire = pf_get_uptime(); 12714bf98559SKajetan Staszkiewicz st->timeout = sp->pfs_1301.timeout; 1272f18ab0ffSGleb Smirnoff } 1273f18ab0ffSGleb Smirnoff st->pfsync_time = time_uptime; 12743b3a8eb9SGleb Smirnoff 1275f18ab0ffSGleb Smirnoff if (sync) { 12763b3a8eb9SGleb Smirnoff V_pfsyncstats.pfsyncs_stale++; 12773b3a8eb9SGleb Smirnoff 12783b3a8eb9SGleb Smirnoff pfsync_update_state(st); 12793b3a8eb9SGleb Smirnoff PF_STATE_UNLOCK(st); 12804fc65bcbSKristof Provost pfsync_push_all(sc); 12813b3a8eb9SGleb Smirnoff continue; 12823b3a8eb9SGleb Smirnoff } 12833b3a8eb9SGleb Smirnoff PF_STATE_UNLOCK(st); 12843b3a8eb9SGleb Smirnoff } 12853b3a8eb9SGleb Smirnoff 128650edc630SKajetan Staszkiewicz return (total_len); 12873b3a8eb9SGleb Smirnoff } 12883b3a8eb9SGleb Smirnoff 12893b3a8eb9SGleb Smirnoff static int 12904bf98559SKajetan Staszkiewicz pfsync_in_upd_c(struct mbuf *m, int offset, int count, int flags, int action) 12913b3a8eb9SGleb Smirnoff { 12923b3a8eb9SGleb Smirnoff struct pfsync_softc *sc = V_pfsyncif; 12933b3a8eb9SGleb Smirnoff struct pfsync_upd_c *ua, *up; 1294211cddf9SKristof Provost struct pf_kstate *st; 12953b3a8eb9SGleb Smirnoff int len = count * sizeof(*up); 1296f18ab0ffSGleb Smirnoff int sync; 12973b3a8eb9SGleb Smirnoff struct mbuf *mp; 12983b3a8eb9SGleb Smirnoff int offp, i; 12993b3a8eb9SGleb Smirnoff 13003b3a8eb9SGleb Smirnoff mp = m_pulldown(m, offset, len, &offp); 13013b3a8eb9SGleb Smirnoff if (mp == NULL) { 13023b3a8eb9SGleb Smirnoff V_pfsyncstats.pfsyncs_badlen++; 13033b3a8eb9SGleb Smirnoff return (-1); 13043b3a8eb9SGleb Smirnoff } 13053b3a8eb9SGleb Smirnoff ua = (struct pfsync_upd_c *)(mp->m_data + offp); 13063b3a8eb9SGleb Smirnoff 13073b3a8eb9SGleb Smirnoff for (i = 0; i < count; i++) { 13083b3a8eb9SGleb Smirnoff up = &ua[i]; 13093b3a8eb9SGleb Smirnoff 13103b3a8eb9SGleb Smirnoff /* check for invalid values */ 13113b3a8eb9SGleb Smirnoff if (up->timeout >= PFTM_MAX || 13123b3a8eb9SGleb Smirnoff up->src.state > PF_TCPS_PROXY_DST || 13133b3a8eb9SGleb Smirnoff up->dst.state > PF_TCPS_PROXY_DST) { 13143b3a8eb9SGleb Smirnoff if (V_pf_status.debug >= PF_DEBUG_MISC) { 13153b3a8eb9SGleb Smirnoff printf("pfsync_input: " 13163b3a8eb9SGleb Smirnoff "PFSYNC_ACT_UPD_C: " 13173b3a8eb9SGleb Smirnoff "invalid value\n"); 13183b3a8eb9SGleb Smirnoff } 13193b3a8eb9SGleb Smirnoff V_pfsyncstats.pfsyncs_badval++; 13203b3a8eb9SGleb Smirnoff continue; 13213b3a8eb9SGleb Smirnoff } 13223b3a8eb9SGleb Smirnoff 13233b3a8eb9SGleb Smirnoff st = pf_find_state_byid(up->id, up->creatorid); 13243b3a8eb9SGleb Smirnoff if (st == NULL) { 13253b3a8eb9SGleb Smirnoff /* We don't have this state. Ask for it. */ 13264fc65bcbSKristof Provost PFSYNC_BUCKET_LOCK(&sc->sc_buckets[0]); 13273b3a8eb9SGleb Smirnoff pfsync_request_update(up->creatorid, up->id); 13284fc65bcbSKristof Provost PFSYNC_BUCKET_UNLOCK(&sc->sc_buckets[0]); 13293b3a8eb9SGleb Smirnoff continue; 13303b3a8eb9SGleb Smirnoff } 13313b3a8eb9SGleb Smirnoff 13323b3a8eb9SGleb Smirnoff if (st->state_flags & PFSTATE_ACK) { 13333b3a8eb9SGleb Smirnoff pfsync_undefer_state(st, 1); 13343b3a8eb9SGleb Smirnoff } 13353b3a8eb9SGleb Smirnoff 1336f18ab0ffSGleb Smirnoff if (st->key[PF_SK_WIRE]->proto == IPPROTO_TCP) 1337f18ab0ffSGleb Smirnoff sync = pfsync_upd_tcp(st, &up->src, &up->dst); 13383b3a8eb9SGleb Smirnoff else { 1339f18ab0ffSGleb Smirnoff sync = 0; 1340f18ab0ffSGleb Smirnoff 13413b3a8eb9SGleb Smirnoff /* 1342f18ab0ffSGleb Smirnoff * Non-TCP protocol state machine always go 1343f18ab0ffSGleb Smirnoff * forwards 13443b3a8eb9SGleb Smirnoff */ 13453b3a8eb9SGleb Smirnoff if (st->src.state > up->src.state) 1346f18ab0ffSGleb Smirnoff sync++; 1347f18ab0ffSGleb Smirnoff else 1348f18ab0ffSGleb Smirnoff pf_state_peer_ntoh(&up->src, &st->src); 1349f18ab0ffSGleb Smirnoff if (st->dst.state > up->dst.state) 1350f18ab0ffSGleb Smirnoff sync++; 1351f18ab0ffSGleb Smirnoff else 1352f18ab0ffSGleb Smirnoff pf_state_peer_ntoh(&up->dst, &st->dst); 13533b3a8eb9SGleb Smirnoff } 1354f18ab0ffSGleb Smirnoff if (sync < 2) { 1355f18ab0ffSGleb Smirnoff pfsync_alloc_scrub_memory(&up->dst, &st->dst); 1356f18ab0ffSGleb Smirnoff pf_state_peer_ntoh(&up->dst, &st->dst); 135704932601SKristof Provost st->expire = pf_get_uptime(); 1358f18ab0ffSGleb Smirnoff st->timeout = up->timeout; 1359f18ab0ffSGleb Smirnoff } 1360f18ab0ffSGleb Smirnoff st->pfsync_time = time_uptime; 13613b3a8eb9SGleb Smirnoff 1362f18ab0ffSGleb Smirnoff if (sync) { 13633b3a8eb9SGleb Smirnoff V_pfsyncstats.pfsyncs_stale++; 13643b3a8eb9SGleb Smirnoff 13653b3a8eb9SGleb Smirnoff pfsync_update_state(st); 13663b3a8eb9SGleb Smirnoff PF_STATE_UNLOCK(st); 13674fc65bcbSKristof Provost pfsync_push_all(sc); 13683b3a8eb9SGleb Smirnoff continue; 13693b3a8eb9SGleb Smirnoff } 13703b3a8eb9SGleb Smirnoff PF_STATE_UNLOCK(st); 13713b3a8eb9SGleb Smirnoff } 13723b3a8eb9SGleb Smirnoff 13733b3a8eb9SGleb Smirnoff return (len); 13743b3a8eb9SGleb Smirnoff } 13753b3a8eb9SGleb Smirnoff 13763b3a8eb9SGleb Smirnoff static int 13774bf98559SKajetan Staszkiewicz pfsync_in_ureq(struct mbuf *m, int offset, int count, int flags, int action) 13783b3a8eb9SGleb Smirnoff { 13793b3a8eb9SGleb Smirnoff struct pfsync_upd_req *ur, *ura; 13803b3a8eb9SGleb Smirnoff struct mbuf *mp; 13813b3a8eb9SGleb Smirnoff int len = count * sizeof(*ur); 13823b3a8eb9SGleb Smirnoff int i, offp; 13833b3a8eb9SGleb Smirnoff 1384211cddf9SKristof Provost struct pf_kstate *st; 13853b3a8eb9SGleb Smirnoff 13863b3a8eb9SGleb Smirnoff mp = m_pulldown(m, offset, len, &offp); 13873b3a8eb9SGleb Smirnoff if (mp == NULL) { 13883b3a8eb9SGleb Smirnoff V_pfsyncstats.pfsyncs_badlen++; 13893b3a8eb9SGleb Smirnoff return (-1); 13903b3a8eb9SGleb Smirnoff } 13913b3a8eb9SGleb Smirnoff ura = (struct pfsync_upd_req *)(mp->m_data + offp); 13923b3a8eb9SGleb Smirnoff 13933b3a8eb9SGleb Smirnoff for (i = 0; i < count; i++) { 13943b3a8eb9SGleb Smirnoff ur = &ura[i]; 13953b3a8eb9SGleb Smirnoff 13963b3a8eb9SGleb Smirnoff if (ur->id == 0 && ur->creatorid == 0) 13973b3a8eb9SGleb Smirnoff pfsync_bulk_start(); 13983b3a8eb9SGleb Smirnoff else { 13993b3a8eb9SGleb Smirnoff st = pf_find_state_byid(ur->id, ur->creatorid); 14003b3a8eb9SGleb Smirnoff if (st == NULL) { 14013b3a8eb9SGleb Smirnoff V_pfsyncstats.pfsyncs_badstate++; 14023b3a8eb9SGleb Smirnoff continue; 14033b3a8eb9SGleb Smirnoff } 14043b3a8eb9SGleb Smirnoff if (st->state_flags & PFSTATE_NOSYNC) { 14053b3a8eb9SGleb Smirnoff PF_STATE_UNLOCK(st); 14063b3a8eb9SGleb Smirnoff continue; 14073b3a8eb9SGleb Smirnoff } 14083b3a8eb9SGleb Smirnoff 14093b3a8eb9SGleb Smirnoff pfsync_update_state_req(st); 14103b3a8eb9SGleb Smirnoff PF_STATE_UNLOCK(st); 14113b3a8eb9SGleb Smirnoff } 14123b3a8eb9SGleb Smirnoff } 14133b3a8eb9SGleb Smirnoff 14143b3a8eb9SGleb Smirnoff return (len); 14153b3a8eb9SGleb Smirnoff } 14163b3a8eb9SGleb Smirnoff 14173b3a8eb9SGleb Smirnoff static int 14184bf98559SKajetan Staszkiewicz pfsync_in_del_c(struct mbuf *m, int offset, int count, int flags, int action) 14193b3a8eb9SGleb Smirnoff { 14203b3a8eb9SGleb Smirnoff struct mbuf *mp; 14213b3a8eb9SGleb Smirnoff struct pfsync_del_c *sa, *sp; 1422211cddf9SKristof Provost struct pf_kstate *st; 14233b3a8eb9SGleb Smirnoff int len = count * sizeof(*sp); 14243b3a8eb9SGleb Smirnoff int offp, i; 14253b3a8eb9SGleb Smirnoff 14263b3a8eb9SGleb Smirnoff mp = m_pulldown(m, offset, len, &offp); 14273b3a8eb9SGleb Smirnoff if (mp == NULL) { 14283b3a8eb9SGleb Smirnoff V_pfsyncstats.pfsyncs_badlen++; 14293b3a8eb9SGleb Smirnoff return (-1); 14303b3a8eb9SGleb Smirnoff } 14313b3a8eb9SGleb Smirnoff sa = (struct pfsync_del_c *)(mp->m_data + offp); 14323b3a8eb9SGleb Smirnoff 14333b3a8eb9SGleb Smirnoff for (i = 0; i < count; i++) { 14343b3a8eb9SGleb Smirnoff sp = &sa[i]; 14353b3a8eb9SGleb Smirnoff 14363b3a8eb9SGleb Smirnoff st = pf_find_state_byid(sp->id, sp->creatorid); 14373b3a8eb9SGleb Smirnoff if (st == NULL) { 14383b3a8eb9SGleb Smirnoff V_pfsyncstats.pfsyncs_badstate++; 14393b3a8eb9SGleb Smirnoff continue; 14403b3a8eb9SGleb Smirnoff } 14413b3a8eb9SGleb Smirnoff 14423b3a8eb9SGleb Smirnoff st->state_flags |= PFSTATE_NOSYNC; 14438f3d786cSMateusz Guzik pf_unlink_state(st); 14443b3a8eb9SGleb Smirnoff } 14453b3a8eb9SGleb Smirnoff 14463b3a8eb9SGleb Smirnoff return (len); 14473b3a8eb9SGleb Smirnoff } 14483b3a8eb9SGleb Smirnoff 14493b3a8eb9SGleb Smirnoff static int 14504bf98559SKajetan Staszkiewicz pfsync_in_bus(struct mbuf *m, int offset, int count, int flags, int action) 14513b3a8eb9SGleb Smirnoff { 14523b3a8eb9SGleb Smirnoff struct pfsync_softc *sc = V_pfsyncif; 14533b3a8eb9SGleb Smirnoff struct pfsync_bus *bus; 14543b3a8eb9SGleb Smirnoff struct mbuf *mp; 14553b3a8eb9SGleb Smirnoff int len = count * sizeof(*bus); 14563b3a8eb9SGleb Smirnoff int offp; 14573b3a8eb9SGleb Smirnoff 14583b3a8eb9SGleb Smirnoff PFSYNC_BLOCK(sc); 14593b3a8eb9SGleb Smirnoff 14603b3a8eb9SGleb Smirnoff /* If we're not waiting for a bulk update, who cares. */ 14613b3a8eb9SGleb Smirnoff if (sc->sc_ureq_sent == 0) { 14623b3a8eb9SGleb Smirnoff PFSYNC_BUNLOCK(sc); 14633b3a8eb9SGleb Smirnoff return (len); 14643b3a8eb9SGleb Smirnoff } 14653b3a8eb9SGleb Smirnoff 14663b3a8eb9SGleb Smirnoff mp = m_pulldown(m, offset, len, &offp); 14673b3a8eb9SGleb Smirnoff if (mp == NULL) { 14683b3a8eb9SGleb Smirnoff PFSYNC_BUNLOCK(sc); 14693b3a8eb9SGleb Smirnoff V_pfsyncstats.pfsyncs_badlen++; 14703b3a8eb9SGleb Smirnoff return (-1); 14713b3a8eb9SGleb Smirnoff } 14723b3a8eb9SGleb Smirnoff bus = (struct pfsync_bus *)(mp->m_data + offp); 14733b3a8eb9SGleb Smirnoff 14743b3a8eb9SGleb Smirnoff switch (bus->status) { 14753b3a8eb9SGleb Smirnoff case PFSYNC_BUS_START: 14763b3a8eb9SGleb Smirnoff callout_reset(&sc->sc_bulkfail_tmo, 4 * hz + 14773b3a8eb9SGleb Smirnoff V_pf_limits[PF_LIMIT_STATES].limit / 14783b3a8eb9SGleb Smirnoff ((sc->sc_ifp->if_mtu - PFSYNC_MINPKT) / 14794bf98559SKajetan Staszkiewicz sizeof(union pfsync_state_union)), 14803b3a8eb9SGleb Smirnoff pfsync_bulk_fail, sc); 14813b3a8eb9SGleb Smirnoff if (V_pf_status.debug >= PF_DEBUG_MISC) 14823b3a8eb9SGleb Smirnoff printf("pfsync: received bulk update start\n"); 14833b3a8eb9SGleb Smirnoff break; 14843b3a8eb9SGleb Smirnoff 14853b3a8eb9SGleb Smirnoff case PFSYNC_BUS_END: 14863b3a8eb9SGleb Smirnoff if (time_uptime - ntohl(bus->endtime) >= 14873b3a8eb9SGleb Smirnoff sc->sc_ureq_sent) { 14883b3a8eb9SGleb Smirnoff /* that's it, we're happy */ 14893b3a8eb9SGleb Smirnoff sc->sc_ureq_sent = 0; 14903b3a8eb9SGleb Smirnoff sc->sc_bulk_tries = 0; 14913b3a8eb9SGleb Smirnoff callout_stop(&sc->sc_bulkfail_tmo); 14923b3a8eb9SGleb Smirnoff if (!(sc->sc_flags & PFSYNCF_OK) && carp_demote_adj_p) 14933b3a8eb9SGleb Smirnoff (*carp_demote_adj_p)(-V_pfsync_carp_adj, 14943b3a8eb9SGleb Smirnoff "pfsync bulk done"); 14953b3a8eb9SGleb Smirnoff sc->sc_flags |= PFSYNCF_OK; 14963b3a8eb9SGleb Smirnoff if (V_pf_status.debug >= PF_DEBUG_MISC) 14973b3a8eb9SGleb Smirnoff printf("pfsync: received valid " 14983b3a8eb9SGleb Smirnoff "bulk update end\n"); 14993b3a8eb9SGleb Smirnoff } else { 15003b3a8eb9SGleb Smirnoff if (V_pf_status.debug >= PF_DEBUG_MISC) 15013b3a8eb9SGleb Smirnoff printf("pfsync: received invalid " 15023b3a8eb9SGleb Smirnoff "bulk update end: bad timestamp\n"); 15033b3a8eb9SGleb Smirnoff } 15043b3a8eb9SGleb Smirnoff break; 15053b3a8eb9SGleb Smirnoff } 15063b3a8eb9SGleb Smirnoff PFSYNC_BUNLOCK(sc); 15073b3a8eb9SGleb Smirnoff 15083b3a8eb9SGleb Smirnoff return (len); 15093b3a8eb9SGleb Smirnoff } 15103b3a8eb9SGleb Smirnoff 15113b3a8eb9SGleb Smirnoff static int 15124bf98559SKajetan Staszkiewicz pfsync_in_tdb(struct mbuf *m, int offset, int count, int flags, int action) 15133b3a8eb9SGleb Smirnoff { 15143b3a8eb9SGleb Smirnoff int len = count * sizeof(struct pfsync_tdb); 15153b3a8eb9SGleb Smirnoff 15163b3a8eb9SGleb Smirnoff #if defined(IPSEC) 15173b3a8eb9SGleb Smirnoff struct pfsync_tdb *tp; 15183b3a8eb9SGleb Smirnoff struct mbuf *mp; 15193b3a8eb9SGleb Smirnoff int offp; 15203b3a8eb9SGleb Smirnoff int i; 15213b3a8eb9SGleb Smirnoff int s; 15223b3a8eb9SGleb Smirnoff 15233b3a8eb9SGleb Smirnoff mp = m_pulldown(m, offset, len, &offp); 15243b3a8eb9SGleb Smirnoff if (mp == NULL) { 15253b3a8eb9SGleb Smirnoff V_pfsyncstats.pfsyncs_badlen++; 15263b3a8eb9SGleb Smirnoff return (-1); 15273b3a8eb9SGleb Smirnoff } 15283b3a8eb9SGleb Smirnoff tp = (struct pfsync_tdb *)(mp->m_data + offp); 15293b3a8eb9SGleb Smirnoff 15303b3a8eb9SGleb Smirnoff for (i = 0; i < count; i++) 15313b3a8eb9SGleb Smirnoff pfsync_update_net_tdb(&tp[i]); 15323b3a8eb9SGleb Smirnoff #endif 15333b3a8eb9SGleb Smirnoff 15343b3a8eb9SGleb Smirnoff return (len); 15353b3a8eb9SGleb Smirnoff } 15363b3a8eb9SGleb Smirnoff 15373b3a8eb9SGleb Smirnoff #if defined(IPSEC) 15383b3a8eb9SGleb Smirnoff /* Update an in-kernel tdb. Silently fail if no tdb is found. */ 15393b3a8eb9SGleb Smirnoff static void 15403b3a8eb9SGleb Smirnoff pfsync_update_net_tdb(struct pfsync_tdb *pt) 15413b3a8eb9SGleb Smirnoff { 15423b3a8eb9SGleb Smirnoff struct tdb *tdb; 15433b3a8eb9SGleb Smirnoff int s; 15443b3a8eb9SGleb Smirnoff 15453b3a8eb9SGleb Smirnoff /* check for invalid values */ 15463b3a8eb9SGleb Smirnoff if (ntohl(pt->spi) <= SPI_RESERVED_MAX || 15473b3a8eb9SGleb Smirnoff (pt->dst.sa.sa_family != AF_INET && 15483b3a8eb9SGleb Smirnoff pt->dst.sa.sa_family != AF_INET6)) 15493b3a8eb9SGleb Smirnoff goto bad; 15503b3a8eb9SGleb Smirnoff 15513b3a8eb9SGleb Smirnoff tdb = gettdb(pt->spi, &pt->dst, pt->sproto); 15523b3a8eb9SGleb Smirnoff if (tdb) { 15533b3a8eb9SGleb Smirnoff pt->rpl = ntohl(pt->rpl); 15543b3a8eb9SGleb Smirnoff pt->cur_bytes = (unsigned long long)be64toh(pt->cur_bytes); 15553b3a8eb9SGleb Smirnoff 15563b3a8eb9SGleb Smirnoff /* Neither replay nor byte counter should ever decrease. */ 15573b3a8eb9SGleb Smirnoff if (pt->rpl < tdb->tdb_rpl || 15583b3a8eb9SGleb Smirnoff pt->cur_bytes < tdb->tdb_cur_bytes) { 15593b3a8eb9SGleb Smirnoff goto bad; 15603b3a8eb9SGleb Smirnoff } 15613b3a8eb9SGleb Smirnoff 15623b3a8eb9SGleb Smirnoff tdb->tdb_rpl = pt->rpl; 15633b3a8eb9SGleb Smirnoff tdb->tdb_cur_bytes = pt->cur_bytes; 15643b3a8eb9SGleb Smirnoff } 15653b3a8eb9SGleb Smirnoff return; 15663b3a8eb9SGleb Smirnoff 15673b3a8eb9SGleb Smirnoff bad: 15683b3a8eb9SGleb Smirnoff if (V_pf_status.debug >= PF_DEBUG_MISC) 15693b3a8eb9SGleb Smirnoff printf("pfsync_insert: PFSYNC_ACT_TDB_UPD: " 15703b3a8eb9SGleb Smirnoff "invalid value\n"); 15713b3a8eb9SGleb Smirnoff V_pfsyncstats.pfsyncs_badstate++; 15723b3a8eb9SGleb Smirnoff return; 15733b3a8eb9SGleb Smirnoff } 15743b3a8eb9SGleb Smirnoff #endif 15753b3a8eb9SGleb Smirnoff 15763b3a8eb9SGleb Smirnoff static int 15774bf98559SKajetan Staszkiewicz pfsync_in_eof(struct mbuf *m, int offset, int count, int flags, int action) 15783b3a8eb9SGleb Smirnoff { 15793b3a8eb9SGleb Smirnoff /* check if we are at the right place in the packet */ 15809ff7e6e9SGleb Smirnoff if (offset != m->m_pkthdr.len) 15819ff7e6e9SGleb Smirnoff V_pfsyncstats.pfsyncs_badlen++; 15823b3a8eb9SGleb Smirnoff 15833b3a8eb9SGleb Smirnoff /* we're done. free and let the caller return */ 15843b3a8eb9SGleb Smirnoff m_freem(m); 15853b3a8eb9SGleb Smirnoff return (-1); 15863b3a8eb9SGleb Smirnoff } 15873b3a8eb9SGleb Smirnoff 15883b3a8eb9SGleb Smirnoff static int 15894bf98559SKajetan Staszkiewicz pfsync_in_error(struct mbuf *m, int offset, int count, int flags, int action) 15903b3a8eb9SGleb Smirnoff { 15913b3a8eb9SGleb Smirnoff V_pfsyncstats.pfsyncs_badact++; 15923b3a8eb9SGleb Smirnoff 15933b3a8eb9SGleb Smirnoff m_freem(m); 15943b3a8eb9SGleb Smirnoff return (-1); 15953b3a8eb9SGleb Smirnoff } 15963b3a8eb9SGleb Smirnoff 15973b3a8eb9SGleb Smirnoff static int 159847e8d432SGleb Smirnoff pfsyncoutput(struct ifnet *ifp, struct mbuf *m, const struct sockaddr *dst, 15993b3a8eb9SGleb Smirnoff struct route *rt) 16003b3a8eb9SGleb Smirnoff { 16013b3a8eb9SGleb Smirnoff m_freem(m); 16023b3a8eb9SGleb Smirnoff return (0); 16033b3a8eb9SGleb Smirnoff } 16043b3a8eb9SGleb Smirnoff 16053b3a8eb9SGleb Smirnoff /* ARGSUSED */ 16063b3a8eb9SGleb Smirnoff static int 16073b3a8eb9SGleb Smirnoff pfsyncioctl(struct ifnet *ifp, u_long cmd, caddr_t data) 16083b3a8eb9SGleb Smirnoff { 16093b3a8eb9SGleb Smirnoff struct pfsync_softc *sc = ifp->if_softc; 16103b3a8eb9SGleb Smirnoff struct ifreq *ifr = (struct ifreq *)data; 16113b3a8eb9SGleb Smirnoff struct pfsyncreq pfsyncr; 1612813c5b75SLuiz Amaral size_t nvbuflen; 16133b3a8eb9SGleb Smirnoff int error; 16144fc65bcbSKristof Provost int c; 16153b3a8eb9SGleb Smirnoff 16163b3a8eb9SGleb Smirnoff switch (cmd) { 16173b3a8eb9SGleb Smirnoff case SIOCSIFFLAGS: 16183b3a8eb9SGleb Smirnoff PFSYNC_LOCK(sc); 16197b6fbb73SGleb Smirnoff if (ifp->if_flags & IFF_UP) { 16203b3a8eb9SGleb Smirnoff ifp->if_drv_flags |= IFF_DRV_RUNNING; 16217b6fbb73SGleb Smirnoff PFSYNC_UNLOCK(sc); 16227b6fbb73SGleb Smirnoff pfsync_pointers_init(); 16237b6fbb73SGleb Smirnoff } else { 16243b3a8eb9SGleb Smirnoff ifp->if_drv_flags &= ~IFF_DRV_RUNNING; 16253b3a8eb9SGleb Smirnoff PFSYNC_UNLOCK(sc); 16267b6fbb73SGleb Smirnoff pfsync_pointers_uninit(); 16277b6fbb73SGleb Smirnoff } 16283b3a8eb9SGleb Smirnoff break; 16293b3a8eb9SGleb Smirnoff case SIOCSIFMTU: 16303b3a8eb9SGleb Smirnoff if (!sc->sc_sync_if || 16313b3a8eb9SGleb Smirnoff ifr->ifr_mtu <= PFSYNC_MINPKT || 16323b3a8eb9SGleb Smirnoff ifr->ifr_mtu > sc->sc_sync_if->if_mtu) 16333b3a8eb9SGleb Smirnoff return (EINVAL); 16343b3a8eb9SGleb Smirnoff if (ifr->ifr_mtu < ifp->if_mtu) { 16354fc65bcbSKristof Provost for (c = 0; c < pfsync_buckets; c++) { 16364fc65bcbSKristof Provost PFSYNC_BUCKET_LOCK(&sc->sc_buckets[c]); 16374fc65bcbSKristof Provost if (sc->sc_buckets[c].b_len > PFSYNC_MINPKT) 16384fc65bcbSKristof Provost pfsync_sendout(1, c); 16394fc65bcbSKristof Provost PFSYNC_BUCKET_UNLOCK(&sc->sc_buckets[c]); 16404fc65bcbSKristof Provost } 16413b3a8eb9SGleb Smirnoff } 16423b3a8eb9SGleb Smirnoff ifp->if_mtu = ifr->ifr_mtu; 16433b3a8eb9SGleb Smirnoff break; 16443b3a8eb9SGleb Smirnoff case SIOCGETPFSYNC: 16453b3a8eb9SGleb Smirnoff bzero(&pfsyncr, sizeof(pfsyncr)); 16463b3a8eb9SGleb Smirnoff PFSYNC_LOCK(sc); 16473b3a8eb9SGleb Smirnoff if (sc->sc_sync_if) { 16483b3a8eb9SGleb Smirnoff strlcpy(pfsyncr.pfsyncr_syncdev, 16493b3a8eb9SGleb Smirnoff sc->sc_sync_if->if_xname, IFNAMSIZ); 16503b3a8eb9SGleb Smirnoff } 1651813c5b75SLuiz Amaral pfsyncr.pfsyncr_syncpeer = ((struct sockaddr_in *)&sc->sc_sync_peer)->sin_addr; 16523b3a8eb9SGleb Smirnoff pfsyncr.pfsyncr_maxupdates = sc->sc_maxupdates; 16535f5bf889SKristof Provost pfsyncr.pfsyncr_defer = sc->sc_flags; 16543b3a8eb9SGleb Smirnoff PFSYNC_UNLOCK(sc); 1655541d96aaSBrooks Davis return (copyout(&pfsyncr, ifr_data_get_ptr(ifr), 1656541d96aaSBrooks Davis sizeof(pfsyncr))); 16573b3a8eb9SGleb Smirnoff 1658813c5b75SLuiz Amaral case SIOCGETPFSYNCNV: 1659813c5b75SLuiz Amaral { 1660813c5b75SLuiz Amaral nvlist_t *nvl_syncpeer; 1661813c5b75SLuiz Amaral nvlist_t *nvl = nvlist_create(0); 1662813c5b75SLuiz Amaral 1663813c5b75SLuiz Amaral if (nvl == NULL) 1664813c5b75SLuiz Amaral return (ENOMEM); 1665813c5b75SLuiz Amaral 1666813c5b75SLuiz Amaral if (sc->sc_sync_if) 1667813c5b75SLuiz Amaral nvlist_add_string(nvl, "syncdev", sc->sc_sync_if->if_xname); 1668813c5b75SLuiz Amaral nvlist_add_number(nvl, "maxupdates", sc->sc_maxupdates); 1669813c5b75SLuiz Amaral nvlist_add_number(nvl, "flags", sc->sc_flags); 16704bf98559SKajetan Staszkiewicz nvlist_add_number(nvl, "version", sc->sc_version); 1671813c5b75SLuiz Amaral if ((nvl_syncpeer = pfsync_sockaddr_to_syncpeer_nvlist(&sc->sc_sync_peer)) != NULL) 1672813c5b75SLuiz Amaral nvlist_add_nvlist(nvl, "syncpeer", nvl_syncpeer); 1673813c5b75SLuiz Amaral 1674813c5b75SLuiz Amaral void *packed = NULL; 1675813c5b75SLuiz Amaral packed = nvlist_pack(nvl, &nvbuflen); 1676813c5b75SLuiz Amaral if (packed == NULL) { 1677813c5b75SLuiz Amaral free(packed, M_NVLIST); 1678813c5b75SLuiz Amaral nvlist_destroy(nvl); 1679813c5b75SLuiz Amaral return (ENOMEM); 1680813c5b75SLuiz Amaral } 1681813c5b75SLuiz Amaral 1682813c5b75SLuiz Amaral if (nvbuflen > ifr->ifr_cap_nv.buf_length) { 1683813c5b75SLuiz Amaral ifr->ifr_cap_nv.length = nvbuflen; 1684813c5b75SLuiz Amaral ifr->ifr_cap_nv.buffer = NULL; 1685813c5b75SLuiz Amaral free(packed, M_NVLIST); 1686813c5b75SLuiz Amaral nvlist_destroy(nvl); 1687813c5b75SLuiz Amaral return (EFBIG); 1688813c5b75SLuiz Amaral } 1689813c5b75SLuiz Amaral 1690813c5b75SLuiz Amaral ifr->ifr_cap_nv.length = nvbuflen; 1691813c5b75SLuiz Amaral error = copyout(packed, ifr->ifr_cap_nv.buffer, nvbuflen); 1692813c5b75SLuiz Amaral 1693813c5b75SLuiz Amaral nvlist_destroy(nvl); 1694813c5b75SLuiz Amaral nvlist_destroy(nvl_syncpeer); 1695813c5b75SLuiz Amaral free(packed, M_NVLIST); 1696813c5b75SLuiz Amaral break; 1697813c5b75SLuiz Amaral } 1698813c5b75SLuiz Amaral 16993b3a8eb9SGleb Smirnoff case SIOCSETPFSYNC: 17003b3a8eb9SGleb Smirnoff { 1701813c5b75SLuiz Amaral struct pfsync_kstatus status; 17023b3a8eb9SGleb Smirnoff 17033b3a8eb9SGleb Smirnoff if ((error = priv_check(curthread, PRIV_NETINET_PF)) != 0) 17043b3a8eb9SGleb Smirnoff return (error); 1705541d96aaSBrooks Davis if ((error = copyin(ifr_data_get_ptr(ifr), &pfsyncr, 1706541d96aaSBrooks Davis sizeof(pfsyncr)))) 17073b3a8eb9SGleb Smirnoff return (error); 17083b3a8eb9SGleb Smirnoff 1709813c5b75SLuiz Amaral memset((char *)&status, 0, sizeof(struct pfsync_kstatus)); 1710813c5b75SLuiz Amaral pfsync_pfsyncreq_to_kstatus(&pfsyncr, &status); 17113b3a8eb9SGleb Smirnoff 1712813c5b75SLuiz Amaral error = pfsync_kstatus_to_softc(&status, sc); 17133b3a8eb9SGleb Smirnoff return (error); 17143b3a8eb9SGleb Smirnoff } 1715813c5b75SLuiz Amaral case SIOCSETPFSYNCNV: 1716813c5b75SLuiz Amaral { 1717813c5b75SLuiz Amaral struct pfsync_kstatus status; 1718813c5b75SLuiz Amaral void *data; 1719813c5b75SLuiz Amaral nvlist_t *nvl; 1720813c5b75SLuiz Amaral 1721813c5b75SLuiz Amaral if ((error = priv_check(curthread, PRIV_NETINET_PF)) != 0) 1722813c5b75SLuiz Amaral return (error); 1723813c5b75SLuiz Amaral if (ifr->ifr_cap_nv.length > IFR_CAP_NV_MAXBUFSIZE) 1724813c5b75SLuiz Amaral return (EINVAL); 1725813c5b75SLuiz Amaral 1726813c5b75SLuiz Amaral data = malloc(ifr->ifr_cap_nv.length, M_TEMP, M_WAITOK); 1727813c5b75SLuiz Amaral 1728813c5b75SLuiz Amaral if ((error = copyin(ifr->ifr_cap_nv.buffer, data, 1729813c5b75SLuiz Amaral ifr->ifr_cap_nv.length)) != 0) { 1730813c5b75SLuiz Amaral free(data, M_TEMP); 1731813c5b75SLuiz Amaral return (error); 17323b3a8eb9SGleb Smirnoff } 17333b3a8eb9SGleb Smirnoff 1734813c5b75SLuiz Amaral if ((nvl = nvlist_unpack(data, ifr->ifr_cap_nv.length, 0)) == NULL) { 1735813c5b75SLuiz Amaral free(data, M_TEMP); 1736813c5b75SLuiz Amaral return (EINVAL); 1737813c5b75SLuiz Amaral } 17383b3a8eb9SGleb Smirnoff 1739813c5b75SLuiz Amaral memset((char *)&status, 0, sizeof(struct pfsync_kstatus)); 1740813c5b75SLuiz Amaral pfsync_nvstatus_to_kstatus(nvl, &status); 17413b3a8eb9SGleb Smirnoff 1742813c5b75SLuiz Amaral nvlist_destroy(nvl); 1743813c5b75SLuiz Amaral free(data, M_TEMP); 1744813c5b75SLuiz Amaral 1745813c5b75SLuiz Amaral error = pfsync_kstatus_to_softc(&status, sc); 1746813c5b75SLuiz Amaral return (error); 17473b3a8eb9SGleb Smirnoff } 17483b3a8eb9SGleb Smirnoff default: 17493b3a8eb9SGleb Smirnoff return (ENOTTY); 17503b3a8eb9SGleb Smirnoff } 17513b3a8eb9SGleb Smirnoff 17523b3a8eb9SGleb Smirnoff return (0); 17533b3a8eb9SGleb Smirnoff } 17543b3a8eb9SGleb Smirnoff 17550fa4aaa7SGleb Smirnoff static void 17564bf98559SKajetan Staszkiewicz pfsync_out_state_1301(struct pf_kstate *st, void *buf) 17573b3a8eb9SGleb Smirnoff { 17584bf98559SKajetan Staszkiewicz union pfsync_state_union *sp = buf; 17593b3a8eb9SGleb Smirnoff 17604bf98559SKajetan Staszkiewicz pfsync_state_export(sp, st, PFSYNC_MSG_VERSION_1301); 17614bf98559SKajetan Staszkiewicz } 17624bf98559SKajetan Staszkiewicz 17634bf98559SKajetan Staszkiewicz static void 17644bf98559SKajetan Staszkiewicz pfsync_out_state_1400(struct pf_kstate *st, void *buf) 17654bf98559SKajetan Staszkiewicz { 17664bf98559SKajetan Staszkiewicz union pfsync_state_union *sp = buf; 17674bf98559SKajetan Staszkiewicz 17684bf98559SKajetan Staszkiewicz pfsync_state_export(sp, st, PFSYNC_MSG_VERSION_1400); 17693b3a8eb9SGleb Smirnoff } 17703b3a8eb9SGleb Smirnoff 17710fa4aaa7SGleb Smirnoff static void 1772211cddf9SKristof Provost pfsync_out_iack(struct pf_kstate *st, void *buf) 17733b3a8eb9SGleb Smirnoff { 17740fa4aaa7SGleb Smirnoff struct pfsync_ins_ack *iack = buf; 17753b3a8eb9SGleb Smirnoff 17763b3a8eb9SGleb Smirnoff iack->id = st->id; 17773b3a8eb9SGleb Smirnoff iack->creatorid = st->creatorid; 17783b3a8eb9SGleb Smirnoff } 17793b3a8eb9SGleb Smirnoff 17800fa4aaa7SGleb Smirnoff static void 1781211cddf9SKristof Provost pfsync_out_upd_c(struct pf_kstate *st, void *buf) 17823b3a8eb9SGleb Smirnoff { 17830fa4aaa7SGleb Smirnoff struct pfsync_upd_c *up = buf; 17843b3a8eb9SGleb Smirnoff 17853b3a8eb9SGleb Smirnoff bzero(up, sizeof(*up)); 17863b3a8eb9SGleb Smirnoff up->id = st->id; 17873b3a8eb9SGleb Smirnoff pf_state_peer_hton(&st->src, &up->src); 17883b3a8eb9SGleb Smirnoff pf_state_peer_hton(&st->dst, &up->dst); 17893b3a8eb9SGleb Smirnoff up->creatorid = st->creatorid; 17903b3a8eb9SGleb Smirnoff up->timeout = st->timeout; 17913b3a8eb9SGleb Smirnoff } 17923b3a8eb9SGleb Smirnoff 17930fa4aaa7SGleb Smirnoff static void 1794cdc231bdSKajetan Staszkiewicz pfsync_out_del_c(struct pf_kstate *st, void *buf) 17953b3a8eb9SGleb Smirnoff { 17960fa4aaa7SGleb Smirnoff struct pfsync_del_c *dp = buf; 17973b3a8eb9SGleb Smirnoff 17983b3a8eb9SGleb Smirnoff dp->id = st->id; 17993b3a8eb9SGleb Smirnoff dp->creatorid = st->creatorid; 18003b3a8eb9SGleb Smirnoff st->state_flags |= PFSTATE_NOSYNC; 18013b3a8eb9SGleb Smirnoff } 18023b3a8eb9SGleb Smirnoff 18033b3a8eb9SGleb Smirnoff static void 18045f75cd39SKristof Provost pfsync_drop_all(struct pfsync_softc *sc) 18055f75cd39SKristof Provost { 18065f75cd39SKristof Provost struct pfsync_bucket *b; 18075f75cd39SKristof Provost int c; 18085f75cd39SKristof Provost 18095f75cd39SKristof Provost for (c = 0; c < pfsync_buckets; c++) { 18105f75cd39SKristof Provost b = &sc->sc_buckets[c]; 18115f75cd39SKristof Provost 18125f75cd39SKristof Provost PFSYNC_BUCKET_LOCK(b); 18135f75cd39SKristof Provost pfsync_drop(sc, c); 18145f75cd39SKristof Provost PFSYNC_BUCKET_UNLOCK(b); 18155f75cd39SKristof Provost } 18165f75cd39SKristof Provost } 18175f75cd39SKristof Provost 18185f75cd39SKristof Provost static void 18195f75cd39SKristof Provost pfsync_drop(struct pfsync_softc *sc, int c) 18203b3a8eb9SGleb Smirnoff { 1821211cddf9SKristof Provost struct pf_kstate *st, *next; 18223b3a8eb9SGleb Smirnoff struct pfsync_upd_req_item *ur; 18234fc65bcbSKristof Provost struct pfsync_bucket *b; 18244bf98559SKajetan Staszkiewicz enum pfsync_q_id q; 18253b3a8eb9SGleb Smirnoff 18264fc65bcbSKristof Provost b = &sc->sc_buckets[c]; 18275f75cd39SKristof Provost PFSYNC_BUCKET_LOCK_ASSERT(b); 18285f75cd39SKristof Provost 18294bf98559SKajetan Staszkiewicz for (q = 0; q < PFSYNC_Q_COUNT; q++) { 18304fc65bcbSKristof Provost if (TAILQ_EMPTY(&b->b_qs[q])) 18313b3a8eb9SGleb Smirnoff continue; 18323b3a8eb9SGleb Smirnoff 18334fc65bcbSKristof Provost TAILQ_FOREACH_SAFE(st, &b->b_qs[q], sync_list, next) { 18344bf98559SKajetan Staszkiewicz KASSERT(st->sync_state == pfsync_qid_sstate[q], 18355f75cd39SKristof Provost ("%s: st->sync_state %d == q %d", 18365f75cd39SKristof Provost __func__, st->sync_state, q)); 18373b3a8eb9SGleb Smirnoff st->sync_state = PFSYNC_S_NONE; 18383b3a8eb9SGleb Smirnoff pf_release_state(st); 18393b3a8eb9SGleb Smirnoff } 18404fc65bcbSKristof Provost TAILQ_INIT(&b->b_qs[q]); 18413b3a8eb9SGleb Smirnoff } 18423b3a8eb9SGleb Smirnoff 18434fc65bcbSKristof Provost while ((ur = TAILQ_FIRST(&b->b_upd_req_list)) != NULL) { 18444fc65bcbSKristof Provost TAILQ_REMOVE(&b->b_upd_req_list, ur, ur_entry); 18453b3a8eb9SGleb Smirnoff free(ur, M_PFSYNC); 18463b3a8eb9SGleb Smirnoff } 18473b3a8eb9SGleb Smirnoff 18484fc65bcbSKristof Provost b->b_len = PFSYNC_MINPKT; 184981debbd6SKristof Provost free(b->b_plus, M_PFSYNC); 18504fc65bcbSKristof Provost b->b_plus = NULL; 1851caccf6d3SKristof Provost b->b_pluslen = 0; 18524fc65bcbSKristof Provost } 18533b3a8eb9SGleb Smirnoff 18543b3a8eb9SGleb Smirnoff static void 18554fc65bcbSKristof Provost pfsync_sendout(int schedswi, int c) 18563b3a8eb9SGleb Smirnoff { 18573b3a8eb9SGleb Smirnoff struct pfsync_softc *sc = V_pfsyncif; 18583b3a8eb9SGleb Smirnoff struct ifnet *ifp = sc->sc_ifp; 18593b3a8eb9SGleb Smirnoff struct mbuf *m; 18603b3a8eb9SGleb Smirnoff struct pfsync_header *ph; 18613b3a8eb9SGleb Smirnoff struct pfsync_subheader *subh; 1862211cddf9SKristof Provost struct pf_kstate *st, *st_next; 18633b3a8eb9SGleb Smirnoff struct pfsync_upd_req_item *ur; 18644fc65bcbSKristof Provost struct pfsync_bucket *b = &sc->sc_buckets[c]; 1865bd802636SMark Johnston size_t len; 18664bf98559SKajetan Staszkiewicz int aflen, offset, count = 0; 18674bf98559SKajetan Staszkiewicz enum pfsync_q_id q; 18683b3a8eb9SGleb Smirnoff 18693b3a8eb9SGleb Smirnoff KASSERT(sc != NULL, ("%s: null sc", __func__)); 18704fc65bcbSKristof Provost KASSERT(b->b_len > PFSYNC_MINPKT, 18714fc65bcbSKristof Provost ("%s: sc_len %zu", __func__, b->b_len)); 18724fc65bcbSKristof Provost PFSYNC_BUCKET_LOCK_ASSERT(b); 18733b3a8eb9SGleb Smirnoff 18742671bde9SZhenlei Huang if (!bpf_peers_present(ifp->if_bpf) && sc->sc_sync_if == NULL) { 18755f75cd39SKristof Provost pfsync_drop(sc, c); 18763b3a8eb9SGleb Smirnoff return; 18773b3a8eb9SGleb Smirnoff } 18783b3a8eb9SGleb Smirnoff 18794fc65bcbSKristof Provost m = m_get2(max_linkhdr + b->b_len, M_NOWAIT, MT_DATA, M_PKTHDR); 18803b3a8eb9SGleb Smirnoff if (m == NULL) { 18812a6009bfSGleb Smirnoff if_inc_counter(sc->sc_ifp, IFCOUNTER_OERRORS, 1); 18823b3a8eb9SGleb Smirnoff V_pfsyncstats.pfsyncs_onomem++; 18833b3a8eb9SGleb Smirnoff return; 18843b3a8eb9SGleb Smirnoff } 18853b3a8eb9SGleb Smirnoff m->m_data += max_linkhdr; 1886bd802636SMark Johnston bzero(m->m_data, b->b_len); 1887bd802636SMark Johnston 1888bd802636SMark Johnston len = b->b_len; 18893b3a8eb9SGleb Smirnoff 18903b3a8eb9SGleb Smirnoff /* build the ip header */ 1891813c5b75SLuiz Amaral switch (sc->sc_sync_peer.ss_family) { 1892813c5b75SLuiz Amaral #ifdef INET 1893813c5b75SLuiz Amaral case AF_INET: 1894813c5b75SLuiz Amaral { 1895813c5b75SLuiz Amaral struct ip *ip; 1896813c5b75SLuiz Amaral 1897813c5b75SLuiz Amaral ip = mtod(m, struct ip *); 1898813c5b75SLuiz Amaral bcopy(&sc->sc_template.ipv4, ip, sizeof(*ip)); 1899813c5b75SLuiz Amaral aflen = offset = sizeof(*ip); 19003b3a8eb9SGleb Smirnoff 1901bd802636SMark Johnston len -= sizeof(union inet_template) - sizeof(struct ip); 1902bd802636SMark Johnston ip->ip_len = htons(len); 19036d947416SGleb Smirnoff ip_fillid(ip); 1904813c5b75SLuiz Amaral break; 1905813c5b75SLuiz Amaral } 1906813c5b75SLuiz Amaral #endif 19076fc7fc2dSLuiz Amaral #ifdef INET6 19086fc7fc2dSLuiz Amaral case AF_INET6: 19096fc7fc2dSLuiz Amaral { 19106fc7fc2dSLuiz Amaral struct ip6_hdr *ip6; 19116fc7fc2dSLuiz Amaral 19126fc7fc2dSLuiz Amaral ip6 = mtod(m, struct ip6_hdr *); 19136fc7fc2dSLuiz Amaral bcopy(&sc->sc_template.ipv6, ip6, sizeof(*ip6)); 19146fc7fc2dSLuiz Amaral aflen = offset = sizeof(*ip6); 19156fc7fc2dSLuiz Amaral 1916bd802636SMark Johnston len -= sizeof(union inet_template) - sizeof(struct ip6_hdr); 1917bd802636SMark Johnston ip6->ip6_plen = htons(len); 19186fc7fc2dSLuiz Amaral break; 19196fc7fc2dSLuiz Amaral } 19206fc7fc2dSLuiz Amaral #endif 1921813c5b75SLuiz Amaral default: 192248767d87SKristof Provost m_freem(m); 19235f75cd39SKristof Provost pfsync_drop(sc, c); 1924813c5b75SLuiz Amaral return; 1925813c5b75SLuiz Amaral } 1926bd802636SMark Johnston m->m_len = m->m_pkthdr.len = len; 1927813c5b75SLuiz Amaral 19283b3a8eb9SGleb Smirnoff /* build the pfsync header */ 19293b3a8eb9SGleb Smirnoff ph = (struct pfsync_header *)(m->m_data + offset); 19303b3a8eb9SGleb Smirnoff offset += sizeof(*ph); 19313b3a8eb9SGleb Smirnoff 19323b3a8eb9SGleb Smirnoff ph->version = PFSYNC_VERSION; 1933bd802636SMark Johnston ph->len = htons(len - aflen); 19343b3a8eb9SGleb Smirnoff bcopy(V_pf_status.pf_chksum, ph->pfcksum, PF_MD5_DIGEST_LENGTH); 19353b3a8eb9SGleb Smirnoff 19363b3a8eb9SGleb Smirnoff /* walk the queues */ 19374bf98559SKajetan Staszkiewicz for (q = 0; q < PFSYNC_Q_COUNT; q++) { 19384fc65bcbSKristof Provost if (TAILQ_EMPTY(&b->b_qs[q])) 19393b3a8eb9SGleb Smirnoff continue; 19403b3a8eb9SGleb Smirnoff 19413b3a8eb9SGleb Smirnoff subh = (struct pfsync_subheader *)(m->m_data + offset); 19423b3a8eb9SGleb Smirnoff offset += sizeof(*subh); 19433b3a8eb9SGleb Smirnoff 19443b3a8eb9SGleb Smirnoff count = 0; 19454fc65bcbSKristof Provost TAILQ_FOREACH_SAFE(st, &b->b_qs[q], sync_list, st_next) { 19464bf98559SKajetan Staszkiewicz KASSERT(st->sync_state == pfsync_qid_sstate[q], 19473b3a8eb9SGleb Smirnoff ("%s: st->sync_state == q", 19483b3a8eb9SGleb Smirnoff __func__)); 19493b3a8eb9SGleb Smirnoff /* 19503b3a8eb9SGleb Smirnoff * XXXGL: some of write methods do unlocked reads 19513b3a8eb9SGleb Smirnoff * of state data :( 19523b3a8eb9SGleb Smirnoff */ 19530fa4aaa7SGleb Smirnoff pfsync_qs[q].write(st, m->m_data + offset); 19540fa4aaa7SGleb Smirnoff offset += pfsync_qs[q].len; 19553b3a8eb9SGleb Smirnoff st->sync_state = PFSYNC_S_NONE; 19563b3a8eb9SGleb Smirnoff pf_release_state(st); 19573b3a8eb9SGleb Smirnoff count++; 19583b3a8eb9SGleb Smirnoff } 19594fc65bcbSKristof Provost TAILQ_INIT(&b->b_qs[q]); 19603b3a8eb9SGleb Smirnoff 19613b3a8eb9SGleb Smirnoff subh->action = pfsync_qs[q].action; 19623b3a8eb9SGleb Smirnoff subh->count = htons(count); 19633b3a8eb9SGleb Smirnoff V_pfsyncstats.pfsyncs_oacts[pfsync_qs[q].action] += count; 19643b3a8eb9SGleb Smirnoff } 19653b3a8eb9SGleb Smirnoff 19664fc65bcbSKristof Provost if (!TAILQ_EMPTY(&b->b_upd_req_list)) { 19673b3a8eb9SGleb Smirnoff subh = (struct pfsync_subheader *)(m->m_data + offset); 19683b3a8eb9SGleb Smirnoff offset += sizeof(*subh); 19693b3a8eb9SGleb Smirnoff 19703b3a8eb9SGleb Smirnoff count = 0; 19714fc65bcbSKristof Provost while ((ur = TAILQ_FIRST(&b->b_upd_req_list)) != NULL) { 19724fc65bcbSKristof Provost TAILQ_REMOVE(&b->b_upd_req_list, ur, ur_entry); 19733b3a8eb9SGleb Smirnoff 19743b3a8eb9SGleb Smirnoff bcopy(&ur->ur_msg, m->m_data + offset, 19753b3a8eb9SGleb Smirnoff sizeof(ur->ur_msg)); 19763b3a8eb9SGleb Smirnoff offset += sizeof(ur->ur_msg); 19773b3a8eb9SGleb Smirnoff free(ur, M_PFSYNC); 19783b3a8eb9SGleb Smirnoff count++; 19793b3a8eb9SGleb Smirnoff } 19803b3a8eb9SGleb Smirnoff 19813b3a8eb9SGleb Smirnoff subh->action = PFSYNC_ACT_UPD_REQ; 19823b3a8eb9SGleb Smirnoff subh->count = htons(count); 19833b3a8eb9SGleb Smirnoff V_pfsyncstats.pfsyncs_oacts[PFSYNC_ACT_UPD_REQ] += count; 19843b3a8eb9SGleb Smirnoff } 19853b3a8eb9SGleb Smirnoff 19863b3a8eb9SGleb Smirnoff /* has someone built a custom region for us to add? */ 19874fc65bcbSKristof Provost if (b->b_plus != NULL) { 19884fc65bcbSKristof Provost bcopy(b->b_plus, m->m_data + offset, b->b_pluslen); 19894fc65bcbSKristof Provost offset += b->b_pluslen; 19903b3a8eb9SGleb Smirnoff 199181debbd6SKristof Provost free(b->b_plus, M_PFSYNC); 19924fc65bcbSKristof Provost b->b_plus = NULL; 1993caccf6d3SKristof Provost b->b_pluslen = 0; 19943b3a8eb9SGleb Smirnoff } 19953b3a8eb9SGleb Smirnoff 19963b3a8eb9SGleb Smirnoff subh = (struct pfsync_subheader *)(m->m_data + offset); 19973b3a8eb9SGleb Smirnoff offset += sizeof(*subh); 19983b3a8eb9SGleb Smirnoff 19993b3a8eb9SGleb Smirnoff subh->action = PFSYNC_ACT_EOF; 20003b3a8eb9SGleb Smirnoff subh->count = htons(1); 20013b3a8eb9SGleb Smirnoff V_pfsyncstats.pfsyncs_oacts[PFSYNC_ACT_EOF]++; 20023b3a8eb9SGleb Smirnoff 20033b3a8eb9SGleb Smirnoff /* we're done, let's put it on the wire */ 20042671bde9SZhenlei Huang if (bpf_peers_present(ifp->if_bpf)) { 2005813c5b75SLuiz Amaral m->m_data += aflen; 2006bd802636SMark Johnston m->m_len = m->m_pkthdr.len = len - aflen; 20072671bde9SZhenlei Huang bpf_mtap(ifp->if_bpf, m); 2008813c5b75SLuiz Amaral m->m_data -= aflen; 2009bd802636SMark Johnston m->m_len = m->m_pkthdr.len = len; 20103b3a8eb9SGleb Smirnoff } 20113b3a8eb9SGleb Smirnoff 20123b3a8eb9SGleb Smirnoff if (sc->sc_sync_if == NULL) { 20134fc65bcbSKristof Provost b->b_len = PFSYNC_MINPKT; 20143b3a8eb9SGleb Smirnoff m_freem(m); 20153b3a8eb9SGleb Smirnoff return; 20163b3a8eb9SGleb Smirnoff } 20173b3a8eb9SGleb Smirnoff 20182a6009bfSGleb Smirnoff if_inc_counter(sc->sc_ifp, IFCOUNTER_OPACKETS, 1); 20192a6009bfSGleb Smirnoff if_inc_counter(sc->sc_ifp, IFCOUNTER_OBYTES, m->m_pkthdr.len); 20204fc65bcbSKristof Provost b->b_len = PFSYNC_MINPKT; 20213b3a8eb9SGleb Smirnoff 20224fc65bcbSKristof Provost if (!_IF_QFULL(&b->b_snd)) 20234fc65bcbSKristof Provost _IF_ENQUEUE(&b->b_snd, m); 20243b3a8eb9SGleb Smirnoff else { 20253b3a8eb9SGleb Smirnoff m_freem(m); 20262a6009bfSGleb Smirnoff if_inc_counter(sc->sc_ifp, IFCOUNTER_OQDROPS, 1); 20273b3a8eb9SGleb Smirnoff } 20283b3a8eb9SGleb Smirnoff if (schedswi) 20293b3a8eb9SGleb Smirnoff swi_sched(V_pfsync_swi_cookie, 0); 20303b3a8eb9SGleb Smirnoff } 20313b3a8eb9SGleb Smirnoff 20323b3a8eb9SGleb Smirnoff static void 2033211cddf9SKristof Provost pfsync_insert_state(struct pf_kstate *st) 20343b3a8eb9SGleb Smirnoff { 20353b3a8eb9SGleb Smirnoff struct pfsync_softc *sc = V_pfsyncif; 20364fc65bcbSKristof Provost struct pfsync_bucket *b = pfsync_get_bucket(sc, st); 20373b3a8eb9SGleb Smirnoff 20383b3a8eb9SGleb Smirnoff if (st->state_flags & PFSTATE_NOSYNC) 20393b3a8eb9SGleb Smirnoff return; 20403b3a8eb9SGleb Smirnoff 2041e5c64b26SKajetan Staszkiewicz if ((st->rule->rule_flag & PFRULE_NOSYNC) || 20423b3a8eb9SGleb Smirnoff st->key[PF_SK_WIRE]->proto == IPPROTO_PFSYNC) { 20433b3a8eb9SGleb Smirnoff st->state_flags |= PFSTATE_NOSYNC; 20443b3a8eb9SGleb Smirnoff return; 20453b3a8eb9SGleb Smirnoff } 20463b3a8eb9SGleb Smirnoff 20473b3a8eb9SGleb Smirnoff KASSERT(st->sync_state == PFSYNC_S_NONE, 2048f8aa4447SGleb Smirnoff ("%s: st->sync_state %u", __func__, st->sync_state)); 20493b3a8eb9SGleb Smirnoff 20504fc65bcbSKristof Provost PFSYNC_BUCKET_LOCK(b); 20514fc65bcbSKristof Provost if (b->b_len == PFSYNC_MINPKT) 20524fc65bcbSKristof Provost callout_reset(&b->b_tmo, 1 * hz, pfsync_timeout, b); 20533b3a8eb9SGleb Smirnoff 2054aa8c6a6dSMarcel Moolenaar pfsync_q_ins(st, PFSYNC_S_INS, true); 20554fc65bcbSKristof Provost PFSYNC_BUCKET_UNLOCK(b); 20563b3a8eb9SGleb Smirnoff 20573b3a8eb9SGleb Smirnoff st->sync_updates = 0; 20583b3a8eb9SGleb Smirnoff } 20593b3a8eb9SGleb Smirnoff 20603b3a8eb9SGleb Smirnoff static int 2061211cddf9SKristof Provost pfsync_defer(struct pf_kstate *st, struct mbuf *m) 20623b3a8eb9SGleb Smirnoff { 20633b3a8eb9SGleb Smirnoff struct pfsync_softc *sc = V_pfsyncif; 20643b3a8eb9SGleb Smirnoff struct pfsync_deferral *pd; 206543020350SKristof Provost struct pfsync_bucket *b; 20663b3a8eb9SGleb Smirnoff 20673b3a8eb9SGleb Smirnoff if (m->m_flags & (M_BCAST|M_MCAST)) 20683b3a8eb9SGleb Smirnoff return (0); 20693b3a8eb9SGleb Smirnoff 207027bd812cSKristof Provost if (sc == NULL) 207127bd812cSKristof Provost return (0); 207227bd812cSKristof Provost 207343020350SKristof Provost b = pfsync_get_bucket(sc, st); 207443020350SKristof Provost 20753b3a8eb9SGleb Smirnoff PFSYNC_LOCK(sc); 20763b3a8eb9SGleb Smirnoff 20777b02a551SKristof Provost if (!(sc->sc_ifp->if_drv_flags & IFF_DRV_RUNNING) || 20783b3a8eb9SGleb Smirnoff !(sc->sc_flags & PFSYNCF_DEFER)) { 20793b3a8eb9SGleb Smirnoff PFSYNC_UNLOCK(sc); 20803b3a8eb9SGleb Smirnoff return (0); 20813b3a8eb9SGleb Smirnoff } 20823b3a8eb9SGleb Smirnoff 208341c4f198SKristof Provost PFSYNC_BUCKET_LOCK(b); 208441c4f198SKristof Provost PFSYNC_UNLOCK(sc); 208541c4f198SKristof Provost 20864fc65bcbSKristof Provost if (b->b_deferred >= 128) 20874fc65bcbSKristof Provost pfsync_undefer(TAILQ_FIRST(&b->b_deferrals), 0); 20883b3a8eb9SGleb Smirnoff 20893b3a8eb9SGleb Smirnoff pd = malloc(sizeof(*pd), M_PFSYNC, M_NOWAIT); 209041c4f198SKristof Provost if (pd == NULL) { 209141c4f198SKristof Provost PFSYNC_BUCKET_UNLOCK(b); 20923b3a8eb9SGleb Smirnoff return (0); 209341c4f198SKristof Provost } 20944fc65bcbSKristof Provost b->b_deferred++; 20953b3a8eb9SGleb Smirnoff 20963b3a8eb9SGleb Smirnoff m->m_flags |= M_SKIP_FIREWALL; 20973b3a8eb9SGleb Smirnoff st->state_flags |= PFSTATE_ACK; 20983b3a8eb9SGleb Smirnoff 20993b3a8eb9SGleb Smirnoff pd->pd_sc = sc; 21003b3a8eb9SGleb Smirnoff pd->pd_st = st; 21013b3a8eb9SGleb Smirnoff pf_ref_state(st); 21023b3a8eb9SGleb Smirnoff pd->pd_m = m; 21033b3a8eb9SGleb Smirnoff 21044fc65bcbSKristof Provost TAILQ_INSERT_TAIL(&b->b_deferrals, pd, pd_entry); 21054fc65bcbSKristof Provost callout_init_mtx(&pd->pd_tmo, &b->b_mtx, CALLOUT_RETURNUNLOCKED); 2106476f6121SKristof Provost callout_reset(&pd->pd_tmo, (V_pfsync_defer_timeout * hz) / 1000, 21076983b986SKristof Provost pfsync_defer_tmo, pd); 21083b3a8eb9SGleb Smirnoff 21094fc65bcbSKristof Provost pfsync_push(b); 211041c4f198SKristof Provost PFSYNC_BUCKET_UNLOCK(b); 21113b3a8eb9SGleb Smirnoff 21123b3a8eb9SGleb Smirnoff return (1); 21133b3a8eb9SGleb Smirnoff } 21143b3a8eb9SGleb Smirnoff 21153b3a8eb9SGleb Smirnoff static void 21163b3a8eb9SGleb Smirnoff pfsync_undefer(struct pfsync_deferral *pd, int drop) 21173b3a8eb9SGleb Smirnoff { 21183b3a8eb9SGleb Smirnoff struct pfsync_softc *sc = pd->pd_sc; 21193b3a8eb9SGleb Smirnoff struct mbuf *m = pd->pd_m; 2120211cddf9SKristof Provost struct pf_kstate *st = pd->pd_st; 21214fc65bcbSKristof Provost struct pfsync_bucket *b = pfsync_get_bucket(sc, st); 21223b3a8eb9SGleb Smirnoff 21234fc65bcbSKristof Provost PFSYNC_BUCKET_LOCK_ASSERT(b); 21243b3a8eb9SGleb Smirnoff 21254fc65bcbSKristof Provost TAILQ_REMOVE(&b->b_deferrals, pd, pd_entry); 21264fc65bcbSKristof Provost b->b_deferred--; 21273b3a8eb9SGleb Smirnoff pd->pd_st->state_flags &= ~PFSTATE_ACK; /* XXX: locking! */ 21283b3a8eb9SGleb Smirnoff free(pd, M_PFSYNC); 21293b3a8eb9SGleb Smirnoff pf_release_state(st); 21303b3a8eb9SGleb Smirnoff 21313b3a8eb9SGleb Smirnoff if (drop) 21323b3a8eb9SGleb Smirnoff m_freem(m); 21333b3a8eb9SGleb Smirnoff else { 21344fc65bcbSKristof Provost _IF_ENQUEUE(&b->b_snd, m); 21354fc65bcbSKristof Provost pfsync_push(b); 21363b3a8eb9SGleb Smirnoff } 21373b3a8eb9SGleb Smirnoff } 21383b3a8eb9SGleb Smirnoff 21393b3a8eb9SGleb Smirnoff static void 21403b3a8eb9SGleb Smirnoff pfsync_defer_tmo(void *arg) 21413b3a8eb9SGleb Smirnoff { 2142ef1bd1e5SKristof Provost struct epoch_tracker et; 21433b3a8eb9SGleb Smirnoff struct pfsync_deferral *pd = arg; 21443b3a8eb9SGleb Smirnoff struct pfsync_softc *sc = pd->pd_sc; 21453b3a8eb9SGleb Smirnoff struct mbuf *m = pd->pd_m; 2146211cddf9SKristof Provost struct pf_kstate *st = pd->pd_st; 2147271f1469SKristof Provost struct pfsync_bucket *b; 2148271f1469SKristof Provost 2149271f1469SKristof Provost CURVNET_SET(sc->sc_ifp->if_vnet); 2150271f1469SKristof Provost 2151271f1469SKristof Provost b = pfsync_get_bucket(sc, st); 21523b3a8eb9SGleb Smirnoff 21534fc65bcbSKristof Provost PFSYNC_BUCKET_LOCK_ASSERT(b); 21543b3a8eb9SGleb Smirnoff 215527b23cdeSKristof Provost TAILQ_REMOVE(&b->b_deferrals, pd, pd_entry); 215627b23cdeSKristof Provost b->b_deferred--; 215727b23cdeSKristof Provost pd->pd_st->state_flags &= ~PFSTATE_ACK; /* XXX: locking! */ 2158844ad282SKristof Provost PFSYNC_BUCKET_UNLOCK(b); 215927b23cdeSKristof Provost free(pd, M_PFSYNC); 216027b23cdeSKristof Provost 216127b23cdeSKristof Provost if (sc->sc_sync_if == NULL) { 216227b23cdeSKristof Provost pf_release_state(st); 216327b23cdeSKristof Provost m_freem(m); 2164271f1469SKristof Provost CURVNET_RESTORE(); 2165fd02192cSKristof Provost return; 2166844ad282SKristof Provost } 2167fd02192cSKristof Provost 2168ef1bd1e5SKristof Provost NET_EPOCH_ENTER(et); 21693b3a8eb9SGleb Smirnoff 21709a1cab6dSKristof Provost pfsync_tx(sc, m); 21713b3a8eb9SGleb Smirnoff 21723b3a8eb9SGleb Smirnoff pf_release_state(st); 21733b3a8eb9SGleb Smirnoff 21743b3a8eb9SGleb Smirnoff CURVNET_RESTORE(); 2175ef1bd1e5SKristof Provost NET_EPOCH_EXIT(et); 21763b3a8eb9SGleb Smirnoff } 21773b3a8eb9SGleb Smirnoff 21783b3a8eb9SGleb Smirnoff static void 217953247cdfSKristof Provost pfsync_undefer_state_locked(struct pf_kstate *st, int drop) 21803b3a8eb9SGleb Smirnoff { 21813b3a8eb9SGleb Smirnoff struct pfsync_softc *sc = V_pfsyncif; 21823b3a8eb9SGleb Smirnoff struct pfsync_deferral *pd; 21834fc65bcbSKristof Provost struct pfsync_bucket *b = pfsync_get_bucket(sc, st); 21843b3a8eb9SGleb Smirnoff 218553247cdfSKristof Provost PFSYNC_BUCKET_LOCK_ASSERT(b); 21863b3a8eb9SGleb Smirnoff 21874fc65bcbSKristof Provost TAILQ_FOREACH(pd, &b->b_deferrals, pd_entry) { 21883b3a8eb9SGleb Smirnoff if (pd->pd_st == st) { 21897c4676ddSRandall Stewart if (callout_stop(&pd->pd_tmo) > 0) 21903b3a8eb9SGleb Smirnoff pfsync_undefer(pd, drop); 21914fc65bcbSKristof Provost 21923b3a8eb9SGleb Smirnoff return; 21933b3a8eb9SGleb Smirnoff } 21943b3a8eb9SGleb Smirnoff } 21953b3a8eb9SGleb Smirnoff 21963b3a8eb9SGleb Smirnoff panic("%s: unable to find deferred state", __func__); 21973b3a8eb9SGleb Smirnoff } 21983b3a8eb9SGleb Smirnoff 219953247cdfSKristof Provost static void 220053247cdfSKristof Provost pfsync_undefer_state(struct pf_kstate *st, int drop) 220153247cdfSKristof Provost { 220253247cdfSKristof Provost struct pfsync_softc *sc = V_pfsyncif; 220353247cdfSKristof Provost struct pfsync_bucket *b = pfsync_get_bucket(sc, st); 220453247cdfSKristof Provost 220553247cdfSKristof Provost PFSYNC_BUCKET_LOCK(b); 220653247cdfSKristof Provost pfsync_undefer_state_locked(st, drop); 220753247cdfSKristof Provost PFSYNC_BUCKET_UNLOCK(b); 220853247cdfSKristof Provost } 220953247cdfSKristof Provost 22104fc65bcbSKristof Provost static struct pfsync_bucket* 2211211cddf9SKristof Provost pfsync_get_bucket(struct pfsync_softc *sc, struct pf_kstate *st) 22124fc65bcbSKristof Provost { 22134fc65bcbSKristof Provost int c = PF_IDHASH(st) % pfsync_buckets; 22144fc65bcbSKristof Provost return &sc->sc_buckets[c]; 22154fc65bcbSKristof Provost } 22164fc65bcbSKristof Provost 22173b3a8eb9SGleb Smirnoff static void 2218211cddf9SKristof Provost pfsync_update_state(struct pf_kstate *st) 22193b3a8eb9SGleb Smirnoff { 22203b3a8eb9SGleb Smirnoff struct pfsync_softc *sc = V_pfsyncif; 2221aa8c6a6dSMarcel Moolenaar bool sync = false, ref = true; 22224fc65bcbSKristof Provost struct pfsync_bucket *b = pfsync_get_bucket(sc, st); 22233b3a8eb9SGleb Smirnoff 22243b3a8eb9SGleb Smirnoff PF_STATE_LOCK_ASSERT(st); 22254fc65bcbSKristof Provost PFSYNC_BUCKET_LOCK(b); 22263b3a8eb9SGleb Smirnoff 22273b3a8eb9SGleb Smirnoff if (st->state_flags & PFSTATE_ACK) 222853247cdfSKristof Provost pfsync_undefer_state_locked(st, 0); 22293b3a8eb9SGleb Smirnoff if (st->state_flags & PFSTATE_NOSYNC) { 22303b3a8eb9SGleb Smirnoff if (st->sync_state != PFSYNC_S_NONE) 22314fc65bcbSKristof Provost pfsync_q_del(st, true, b); 22324fc65bcbSKristof Provost PFSYNC_BUCKET_UNLOCK(b); 22333b3a8eb9SGleb Smirnoff return; 22343b3a8eb9SGleb Smirnoff } 22353b3a8eb9SGleb Smirnoff 22364fc65bcbSKristof Provost if (b->b_len == PFSYNC_MINPKT) 22374fc65bcbSKristof Provost callout_reset(&b->b_tmo, 1 * hz, pfsync_timeout, b); 22383b3a8eb9SGleb Smirnoff 22393b3a8eb9SGleb Smirnoff switch (st->sync_state) { 22403b3a8eb9SGleb Smirnoff case PFSYNC_S_UPD_C: 22413b3a8eb9SGleb Smirnoff case PFSYNC_S_UPD: 22423b3a8eb9SGleb Smirnoff case PFSYNC_S_INS: 22433b3a8eb9SGleb Smirnoff /* we're already handling it */ 22443b3a8eb9SGleb Smirnoff 22453b3a8eb9SGleb Smirnoff if (st->key[PF_SK_WIRE]->proto == IPPROTO_TCP) { 22463b3a8eb9SGleb Smirnoff st->sync_updates++; 22473b3a8eb9SGleb Smirnoff if (st->sync_updates >= sc->sc_maxupdates) 2248aa8c6a6dSMarcel Moolenaar sync = true; 22493b3a8eb9SGleb Smirnoff } 22503b3a8eb9SGleb Smirnoff break; 22513b3a8eb9SGleb Smirnoff 22523b3a8eb9SGleb Smirnoff case PFSYNC_S_IACK: 22534fc65bcbSKristof Provost pfsync_q_del(st, false, b); 2254aa8c6a6dSMarcel Moolenaar ref = false; 2255aa8c6a6dSMarcel Moolenaar /* FALLTHROUGH */ 2256aa8c6a6dSMarcel Moolenaar 22573b3a8eb9SGleb Smirnoff case PFSYNC_S_NONE: 2258aa8c6a6dSMarcel Moolenaar pfsync_q_ins(st, PFSYNC_S_UPD_C, ref); 22593b3a8eb9SGleb Smirnoff st->sync_updates = 0; 22603b3a8eb9SGleb Smirnoff break; 22613b3a8eb9SGleb Smirnoff 22623b3a8eb9SGleb Smirnoff default: 22633b3a8eb9SGleb Smirnoff panic("%s: unexpected sync state %d", __func__, st->sync_state); 22643b3a8eb9SGleb Smirnoff } 22653b3a8eb9SGleb Smirnoff 22663b3a8eb9SGleb Smirnoff if (sync || (time_uptime - st->pfsync_time) < 2) 22674fc65bcbSKristof Provost pfsync_push(b); 22683b3a8eb9SGleb Smirnoff 22694fc65bcbSKristof Provost PFSYNC_BUCKET_UNLOCK(b); 22703b3a8eb9SGleb Smirnoff } 22713b3a8eb9SGleb Smirnoff 22723b3a8eb9SGleb Smirnoff static void 22733b3a8eb9SGleb Smirnoff pfsync_request_update(u_int32_t creatorid, u_int64_t id) 22743b3a8eb9SGleb Smirnoff { 22753b3a8eb9SGleb Smirnoff struct pfsync_softc *sc = V_pfsyncif; 22764fc65bcbSKristof Provost struct pfsync_bucket *b = &sc->sc_buckets[0]; 22773b3a8eb9SGleb Smirnoff struct pfsync_upd_req_item *item; 22783b3a8eb9SGleb Smirnoff size_t nlen = sizeof(struct pfsync_upd_req); 22793b3a8eb9SGleb Smirnoff 22804fc65bcbSKristof Provost PFSYNC_BUCKET_LOCK_ASSERT(b); 22813b3a8eb9SGleb Smirnoff 22823b3a8eb9SGleb Smirnoff /* 2283aa955cb5SGleb Smirnoff * This code does a bit to prevent multiple update requests for the 2284aa955cb5SGleb Smirnoff * same state being generated. It searches current subheader queue, 2285aa955cb5SGleb Smirnoff * but it doesn't lookup into queue of already packed datagrams. 22863b3a8eb9SGleb Smirnoff */ 22874fc65bcbSKristof Provost TAILQ_FOREACH(item, &b->b_upd_req_list, ur_entry) 2288aa955cb5SGleb Smirnoff if (item->ur_msg.id == id && 2289aa955cb5SGleb Smirnoff item->ur_msg.creatorid == creatorid) 2290aa955cb5SGleb Smirnoff return; 2291aa955cb5SGleb Smirnoff 22923b3a8eb9SGleb Smirnoff item = malloc(sizeof(*item), M_PFSYNC, M_NOWAIT); 22933b3a8eb9SGleb Smirnoff if (item == NULL) 22943b3a8eb9SGleb Smirnoff return; /* XXX stats */ 22953b3a8eb9SGleb Smirnoff 22963b3a8eb9SGleb Smirnoff item->ur_msg.id = id; 22973b3a8eb9SGleb Smirnoff item->ur_msg.creatorid = creatorid; 22983b3a8eb9SGleb Smirnoff 22994fc65bcbSKristof Provost if (TAILQ_EMPTY(&b->b_upd_req_list)) 23003b3a8eb9SGleb Smirnoff nlen += sizeof(struct pfsync_subheader); 23013b3a8eb9SGleb Smirnoff 23024fc65bcbSKristof Provost if (b->b_len + nlen > sc->sc_ifp->if_mtu) { 23039f2e5184SThomas Kurschel pfsync_sendout(0, 0); 23043b3a8eb9SGleb Smirnoff 23053b3a8eb9SGleb Smirnoff nlen = sizeof(struct pfsync_subheader) + 23063b3a8eb9SGleb Smirnoff sizeof(struct pfsync_upd_req); 23073b3a8eb9SGleb Smirnoff } 23083b3a8eb9SGleb Smirnoff 23094fc65bcbSKristof Provost TAILQ_INSERT_TAIL(&b->b_upd_req_list, item, ur_entry); 23104fc65bcbSKristof Provost b->b_len += nlen; 23119f2e5184SThomas Kurschel 23129f2e5184SThomas Kurschel pfsync_push(b); 23133b3a8eb9SGleb Smirnoff } 23143b3a8eb9SGleb Smirnoff 23154fc65bcbSKristof Provost static bool 2316211cddf9SKristof Provost pfsync_update_state_req(struct pf_kstate *st) 23173b3a8eb9SGleb Smirnoff { 23183b3a8eb9SGleb Smirnoff struct pfsync_softc *sc = V_pfsyncif; 23194fc65bcbSKristof Provost bool ref = true, full = false; 23204fc65bcbSKristof Provost struct pfsync_bucket *b = pfsync_get_bucket(sc, st); 23213b3a8eb9SGleb Smirnoff 23223b3a8eb9SGleb Smirnoff PF_STATE_LOCK_ASSERT(st); 23234fc65bcbSKristof Provost PFSYNC_BUCKET_LOCK(b); 23243b3a8eb9SGleb Smirnoff 23253b3a8eb9SGleb Smirnoff if (st->state_flags & PFSTATE_NOSYNC) { 23263b3a8eb9SGleb Smirnoff if (st->sync_state != PFSYNC_S_NONE) 23274fc65bcbSKristof Provost pfsync_q_del(st, true, b); 23284fc65bcbSKristof Provost PFSYNC_BUCKET_UNLOCK(b); 23294fc65bcbSKristof Provost return (full); 23303b3a8eb9SGleb Smirnoff } 23313b3a8eb9SGleb Smirnoff 23323b3a8eb9SGleb Smirnoff switch (st->sync_state) { 23333b3a8eb9SGleb Smirnoff case PFSYNC_S_UPD_C: 23343b3a8eb9SGleb Smirnoff case PFSYNC_S_IACK: 23354fc65bcbSKristof Provost pfsync_q_del(st, false, b); 2336aa8c6a6dSMarcel Moolenaar ref = false; 2337aa8c6a6dSMarcel Moolenaar /* FALLTHROUGH */ 2338aa8c6a6dSMarcel Moolenaar 23393b3a8eb9SGleb Smirnoff case PFSYNC_S_NONE: 2340aa8c6a6dSMarcel Moolenaar pfsync_q_ins(st, PFSYNC_S_UPD, ref); 23414fc65bcbSKristof Provost pfsync_push(b); 23423b3a8eb9SGleb Smirnoff break; 23433b3a8eb9SGleb Smirnoff 23443b3a8eb9SGleb Smirnoff case PFSYNC_S_INS: 23453b3a8eb9SGleb Smirnoff case PFSYNC_S_UPD: 2346cdc231bdSKajetan Staszkiewicz case PFSYNC_S_DEL_C: 23473b3a8eb9SGleb Smirnoff /* we're already handling it */ 23483b3a8eb9SGleb Smirnoff break; 23493b3a8eb9SGleb Smirnoff 23503b3a8eb9SGleb Smirnoff default: 23513b3a8eb9SGleb Smirnoff panic("%s: unexpected sync state %d", __func__, st->sync_state); 23523b3a8eb9SGleb Smirnoff } 23533b3a8eb9SGleb Smirnoff 23544bf98559SKajetan Staszkiewicz if ((sc->sc_ifp->if_mtu - b->b_len) < sizeof(union pfsync_state_union)) 23554fc65bcbSKristof Provost full = true; 23564fc65bcbSKristof Provost 23574fc65bcbSKristof Provost PFSYNC_BUCKET_UNLOCK(b); 23584fc65bcbSKristof Provost 23594fc65bcbSKristof Provost return (full); 23603b3a8eb9SGleb Smirnoff } 23613b3a8eb9SGleb Smirnoff 23623b3a8eb9SGleb Smirnoff static void 2363211cddf9SKristof Provost pfsync_delete_state(struct pf_kstate *st) 23643b3a8eb9SGleb Smirnoff { 23653b3a8eb9SGleb Smirnoff struct pfsync_softc *sc = V_pfsyncif; 23664fc65bcbSKristof Provost struct pfsync_bucket *b = pfsync_get_bucket(sc, st); 2367aa8c6a6dSMarcel Moolenaar bool ref = true; 23683b3a8eb9SGleb Smirnoff 23694fc65bcbSKristof Provost PFSYNC_BUCKET_LOCK(b); 23703b3a8eb9SGleb Smirnoff if (st->state_flags & PFSTATE_ACK) 237153247cdfSKristof Provost pfsync_undefer_state_locked(st, 1); 23723b3a8eb9SGleb Smirnoff if (st->state_flags & PFSTATE_NOSYNC) { 23733b3a8eb9SGleb Smirnoff if (st->sync_state != PFSYNC_S_NONE) 23744fc65bcbSKristof Provost pfsync_q_del(st, true, b); 23754fc65bcbSKristof Provost PFSYNC_BUCKET_UNLOCK(b); 23763b3a8eb9SGleb Smirnoff return; 23773b3a8eb9SGleb Smirnoff } 23783b3a8eb9SGleb Smirnoff 23794fc65bcbSKristof Provost if (b->b_len == PFSYNC_MINPKT) 23804fc65bcbSKristof Provost callout_reset(&b->b_tmo, 1 * hz, pfsync_timeout, b); 23813b3a8eb9SGleb Smirnoff 23823b3a8eb9SGleb Smirnoff switch (st->sync_state) { 23833b3a8eb9SGleb Smirnoff case PFSYNC_S_INS: 23843b3a8eb9SGleb Smirnoff /* We never got to tell the world so just forget about it. */ 23854fc65bcbSKristof Provost pfsync_q_del(st, true, b); 23863b3a8eb9SGleb Smirnoff break; 23873b3a8eb9SGleb Smirnoff 23883b3a8eb9SGleb Smirnoff case PFSYNC_S_UPD_C: 23893b3a8eb9SGleb Smirnoff case PFSYNC_S_UPD: 23903b3a8eb9SGleb Smirnoff case PFSYNC_S_IACK: 23914fc65bcbSKristof Provost pfsync_q_del(st, false, b); 2392aa8c6a6dSMarcel Moolenaar ref = false; 2393aa8c6a6dSMarcel Moolenaar /* FALLTHROUGH */ 23943b3a8eb9SGleb Smirnoff 23953b3a8eb9SGleb Smirnoff case PFSYNC_S_NONE: 2396cdc231bdSKajetan Staszkiewicz pfsync_q_ins(st, PFSYNC_S_DEL_C, ref); 23973b3a8eb9SGleb Smirnoff break; 23983b3a8eb9SGleb Smirnoff 23993b3a8eb9SGleb Smirnoff default: 24003b3a8eb9SGleb Smirnoff panic("%s: unexpected sync state %d", __func__, st->sync_state); 24013b3a8eb9SGleb Smirnoff } 2402d6d35f15SMarcel Moolenaar 24034fc65bcbSKristof Provost PFSYNC_BUCKET_UNLOCK(b); 24043b3a8eb9SGleb Smirnoff } 24053b3a8eb9SGleb Smirnoff 24063b3a8eb9SGleb Smirnoff static void 24073b3a8eb9SGleb Smirnoff pfsync_clear_states(u_int32_t creatorid, const char *ifname) 24083b3a8eb9SGleb Smirnoff { 24093b3a8eb9SGleb Smirnoff struct { 24103b3a8eb9SGleb Smirnoff struct pfsync_subheader subh; 24113b3a8eb9SGleb Smirnoff struct pfsync_clr clr; 24123b3a8eb9SGleb Smirnoff } __packed r; 24133b3a8eb9SGleb Smirnoff 24143b3a8eb9SGleb Smirnoff bzero(&r, sizeof(r)); 24153b3a8eb9SGleb Smirnoff 24163b3a8eb9SGleb Smirnoff r.subh.action = PFSYNC_ACT_CLR; 24173b3a8eb9SGleb Smirnoff r.subh.count = htons(1); 24183b3a8eb9SGleb Smirnoff V_pfsyncstats.pfsyncs_oacts[PFSYNC_ACT_CLR]++; 24193b3a8eb9SGleb Smirnoff 24203b3a8eb9SGleb Smirnoff strlcpy(r.clr.ifname, ifname, sizeof(r.clr.ifname)); 24213b3a8eb9SGleb Smirnoff r.clr.creatorid = creatorid; 24223b3a8eb9SGleb Smirnoff 24233b3a8eb9SGleb Smirnoff pfsync_send_plus(&r, sizeof(r)); 24243b3a8eb9SGleb Smirnoff } 24253b3a8eb9SGleb Smirnoff 24264bf98559SKajetan Staszkiewicz static enum pfsync_q_id 24274bf98559SKajetan Staszkiewicz pfsync_sstate_to_qid(u_int8_t sync_state) 24283b3a8eb9SGleb Smirnoff { 24293b3a8eb9SGleb Smirnoff struct pfsync_softc *sc = V_pfsyncif; 24304bf98559SKajetan Staszkiewicz 24314bf98559SKajetan Staszkiewicz switch (sync_state) { 24324bf98559SKajetan Staszkiewicz case PFSYNC_S_INS: 24334bf98559SKajetan Staszkiewicz switch (sc->sc_version) { 24344bf98559SKajetan Staszkiewicz case PFSYNC_MSG_VERSION_1301: 24354bf98559SKajetan Staszkiewicz return PFSYNC_Q_INS_1301; 24364bf98559SKajetan Staszkiewicz case PFSYNC_MSG_VERSION_1400: 24374bf98559SKajetan Staszkiewicz return PFSYNC_Q_INS_1400; 24384bf98559SKajetan Staszkiewicz } 24394bf98559SKajetan Staszkiewicz break; 24404bf98559SKajetan Staszkiewicz case PFSYNC_S_IACK: 24414bf98559SKajetan Staszkiewicz return PFSYNC_Q_IACK; 24424bf98559SKajetan Staszkiewicz case PFSYNC_S_UPD: 24434bf98559SKajetan Staszkiewicz switch (sc->sc_version) { 24444bf98559SKajetan Staszkiewicz case PFSYNC_MSG_VERSION_1301: 24454bf98559SKajetan Staszkiewicz return PFSYNC_Q_UPD_1301; 24464bf98559SKajetan Staszkiewicz case PFSYNC_MSG_VERSION_1400: 24474bf98559SKajetan Staszkiewicz return PFSYNC_Q_UPD_1400; 24484bf98559SKajetan Staszkiewicz } 24494bf98559SKajetan Staszkiewicz break; 24504bf98559SKajetan Staszkiewicz case PFSYNC_S_UPD_C: 24514bf98559SKajetan Staszkiewicz return PFSYNC_Q_UPD_C; 24524bf98559SKajetan Staszkiewicz case PFSYNC_S_DEL_C: 24534bf98559SKajetan Staszkiewicz return PFSYNC_Q_DEL_C; 24544bf98559SKajetan Staszkiewicz default: 24554bf98559SKajetan Staszkiewicz panic("%s: Unsupported st->sync_state 0x%02x", 24564bf98559SKajetan Staszkiewicz __func__, sync_state); 24574bf98559SKajetan Staszkiewicz } 24584bf98559SKajetan Staszkiewicz 24594bf98559SKajetan Staszkiewicz panic("%s: Unsupported pfsync_msg_version %d", 24604bf98559SKajetan Staszkiewicz __func__, sc->sc_version); 24614bf98559SKajetan Staszkiewicz } 24624bf98559SKajetan Staszkiewicz 24634bf98559SKajetan Staszkiewicz static void 24644bf98559SKajetan Staszkiewicz pfsync_q_ins(struct pf_kstate *st, int sync_state, bool ref) 24654bf98559SKajetan Staszkiewicz { 24664bf98559SKajetan Staszkiewicz enum pfsync_q_id q = pfsync_sstate_to_qid(sync_state); 24674bf98559SKajetan Staszkiewicz struct pfsync_softc *sc = V_pfsyncif; 24683b3a8eb9SGleb Smirnoff size_t nlen = pfsync_qs[q].len; 24694fc65bcbSKristof Provost struct pfsync_bucket *b = pfsync_get_bucket(sc, st); 24703b3a8eb9SGleb Smirnoff 24714fc65bcbSKristof Provost PFSYNC_BUCKET_LOCK_ASSERT(b); 24723b3a8eb9SGleb Smirnoff 24733b3a8eb9SGleb Smirnoff KASSERT(st->sync_state == PFSYNC_S_NONE, 2474f8aa4447SGleb Smirnoff ("%s: st->sync_state %u", __func__, st->sync_state)); 24754fc65bcbSKristof Provost KASSERT(b->b_len >= PFSYNC_MINPKT, ("pfsync pkt len is too low %zu", 24764fc65bcbSKristof Provost b->b_len)); 24773b3a8eb9SGleb Smirnoff 24784fc65bcbSKristof Provost if (TAILQ_EMPTY(&b->b_qs[q])) 24793b3a8eb9SGleb Smirnoff nlen += sizeof(struct pfsync_subheader); 24803b3a8eb9SGleb Smirnoff 24814fc65bcbSKristof Provost if (b->b_len + nlen > sc->sc_ifp->if_mtu) { 24824fc65bcbSKristof Provost pfsync_sendout(1, b->b_id); 24833b3a8eb9SGleb Smirnoff 24843b3a8eb9SGleb Smirnoff nlen = sizeof(struct pfsync_subheader) + pfsync_qs[q].len; 24853b3a8eb9SGleb Smirnoff } 24863b3a8eb9SGleb Smirnoff 24874fc65bcbSKristof Provost b->b_len += nlen; 24884bf98559SKajetan Staszkiewicz st->sync_state = pfsync_qid_sstate[q]; 24895f75cd39SKristof Provost TAILQ_INSERT_TAIL(&b->b_qs[q], st, sync_list); 2490aa8c6a6dSMarcel Moolenaar if (ref) 24913b3a8eb9SGleb Smirnoff pf_ref_state(st); 24923b3a8eb9SGleb Smirnoff } 24933b3a8eb9SGleb Smirnoff 24943b3a8eb9SGleb Smirnoff static void 2495211cddf9SKristof Provost pfsync_q_del(struct pf_kstate *st, bool unref, struct pfsync_bucket *b) 24963b3a8eb9SGleb Smirnoff { 24974bf98559SKajetan Staszkiewicz enum pfsync_q_id q; 24983b3a8eb9SGleb Smirnoff 24994fc65bcbSKristof Provost PFSYNC_BUCKET_LOCK_ASSERT(b); 25003b3a8eb9SGleb Smirnoff KASSERT(st->sync_state != PFSYNC_S_NONE, 25013b3a8eb9SGleb Smirnoff ("%s: st->sync_state != PFSYNC_S_NONE", __func__)); 25023b3a8eb9SGleb Smirnoff 25034bf98559SKajetan Staszkiewicz q = pfsync_sstate_to_qid(st->sync_state); 25044fc65bcbSKristof Provost b->b_len -= pfsync_qs[q].len; 25054fc65bcbSKristof Provost TAILQ_REMOVE(&b->b_qs[q], st, sync_list); 25063b3a8eb9SGleb Smirnoff st->sync_state = PFSYNC_S_NONE; 2507aa8c6a6dSMarcel Moolenaar if (unref) 25083b3a8eb9SGleb Smirnoff pf_release_state(st); 25093b3a8eb9SGleb Smirnoff 25104fc65bcbSKristof Provost if (TAILQ_EMPTY(&b->b_qs[q])) 25114fc65bcbSKristof Provost b->b_len -= sizeof(struct pfsync_subheader); 25123b3a8eb9SGleb Smirnoff } 25133b3a8eb9SGleb Smirnoff 25143b3a8eb9SGleb Smirnoff static void 25153b3a8eb9SGleb Smirnoff pfsync_bulk_start(void) 25163b3a8eb9SGleb Smirnoff { 25173b3a8eb9SGleb Smirnoff struct pfsync_softc *sc = V_pfsyncif; 25183b3a8eb9SGleb Smirnoff 25193b3a8eb9SGleb Smirnoff if (V_pf_status.debug >= PF_DEBUG_MISC) 25203b3a8eb9SGleb Smirnoff printf("pfsync: received bulk update request\n"); 25213b3a8eb9SGleb Smirnoff 25223b3a8eb9SGleb Smirnoff PFSYNC_BLOCK(sc); 25233b3a8eb9SGleb Smirnoff 25243b3a8eb9SGleb Smirnoff sc->sc_ureq_received = time_uptime; 25253b3a8eb9SGleb Smirnoff sc->sc_bulk_hashid = 0; 25263b3a8eb9SGleb Smirnoff sc->sc_bulk_stateid = 0; 25273b3a8eb9SGleb Smirnoff pfsync_bulk_status(PFSYNC_BUS_START); 25283b3a8eb9SGleb Smirnoff callout_reset(&sc->sc_bulk_tmo, 1, pfsync_bulk_update, sc); 25293b3a8eb9SGleb Smirnoff PFSYNC_BUNLOCK(sc); 25303b3a8eb9SGleb Smirnoff } 25313b3a8eb9SGleb Smirnoff 25323b3a8eb9SGleb Smirnoff static void 25333b3a8eb9SGleb Smirnoff pfsync_bulk_update(void *arg) 25343b3a8eb9SGleb Smirnoff { 25353b3a8eb9SGleb Smirnoff struct pfsync_softc *sc = arg; 2536211cddf9SKristof Provost struct pf_kstate *s; 2537fb48e998SDimitry Andric int i; 25383b3a8eb9SGleb Smirnoff 25393b3a8eb9SGleb Smirnoff PFSYNC_BLOCK_ASSERT(sc); 25403b3a8eb9SGleb Smirnoff CURVNET_SET(sc->sc_ifp->if_vnet); 25413b3a8eb9SGleb Smirnoff 25423b3a8eb9SGleb Smirnoff /* 25433b3a8eb9SGleb Smirnoff * Start with last state from previous invocation. 25443b3a8eb9SGleb Smirnoff * It may had gone, in this case start from the 25453b3a8eb9SGleb Smirnoff * hash slot. 25463b3a8eb9SGleb Smirnoff */ 25473b3a8eb9SGleb Smirnoff s = pf_find_state_byid(sc->sc_bulk_stateid, sc->sc_bulk_creatorid); 25483b3a8eb9SGleb Smirnoff 25493b3a8eb9SGleb Smirnoff if (s != NULL) 25503b3a8eb9SGleb Smirnoff i = PF_IDHASH(s); 25513b3a8eb9SGleb Smirnoff else 25523b3a8eb9SGleb Smirnoff i = sc->sc_bulk_hashid; 25533b3a8eb9SGleb Smirnoff 2554271f1469SKristof Provost for (; i <= V_pf_hashmask; i++) { 25553b3a8eb9SGleb Smirnoff struct pf_idhash *ih = &V_pf_idhash[i]; 25563b3a8eb9SGleb Smirnoff 25573b3a8eb9SGleb Smirnoff if (s != NULL) 25583b3a8eb9SGleb Smirnoff PF_HASHROW_ASSERT(ih); 25593b3a8eb9SGleb Smirnoff else { 25603b3a8eb9SGleb Smirnoff PF_HASHROW_LOCK(ih); 25613b3a8eb9SGleb Smirnoff s = LIST_FIRST(&ih->states); 25623b3a8eb9SGleb Smirnoff } 25633b3a8eb9SGleb Smirnoff 25643b3a8eb9SGleb Smirnoff for (; s; s = LIST_NEXT(s, entry)) { 25654fc65bcbSKristof Provost if (s->sync_state == PFSYNC_S_NONE && 25664fc65bcbSKristof Provost s->timeout < PFTM_MAX && 25674fc65bcbSKristof Provost s->pfsync_time <= sc->sc_ureq_received) { 25684fc65bcbSKristof Provost if (pfsync_update_state_req(s)) { 25693b3a8eb9SGleb Smirnoff /* We've filled a packet. */ 25703b3a8eb9SGleb Smirnoff sc->sc_bulk_hashid = i; 25713b3a8eb9SGleb Smirnoff sc->sc_bulk_stateid = s->id; 25723b3a8eb9SGleb Smirnoff sc->sc_bulk_creatorid = s->creatorid; 25733b3a8eb9SGleb Smirnoff PF_HASHROW_UNLOCK(ih); 25743b3a8eb9SGleb Smirnoff callout_reset(&sc->sc_bulk_tmo, 1, 25753b3a8eb9SGleb Smirnoff pfsync_bulk_update, sc); 25763b3a8eb9SGleb Smirnoff goto full; 25773b3a8eb9SGleb Smirnoff } 25783b3a8eb9SGleb Smirnoff } 25793b3a8eb9SGleb Smirnoff } 25803b3a8eb9SGleb Smirnoff PF_HASHROW_UNLOCK(ih); 25813b3a8eb9SGleb Smirnoff } 25823b3a8eb9SGleb Smirnoff 25833b3a8eb9SGleb Smirnoff /* We're done. */ 25843b3a8eb9SGleb Smirnoff pfsync_bulk_status(PFSYNC_BUS_END); 25853b3a8eb9SGleb Smirnoff full: 25863b3a8eb9SGleb Smirnoff CURVNET_RESTORE(); 25873b3a8eb9SGleb Smirnoff } 25883b3a8eb9SGleb Smirnoff 25893b3a8eb9SGleb Smirnoff static void 25903b3a8eb9SGleb Smirnoff pfsync_bulk_status(u_int8_t status) 25913b3a8eb9SGleb Smirnoff { 25923b3a8eb9SGleb Smirnoff struct { 25933b3a8eb9SGleb Smirnoff struct pfsync_subheader subh; 25943b3a8eb9SGleb Smirnoff struct pfsync_bus bus; 25953b3a8eb9SGleb Smirnoff } __packed r; 25963b3a8eb9SGleb Smirnoff 25973b3a8eb9SGleb Smirnoff struct pfsync_softc *sc = V_pfsyncif; 25983b3a8eb9SGleb Smirnoff 25993b3a8eb9SGleb Smirnoff bzero(&r, sizeof(r)); 26003b3a8eb9SGleb Smirnoff 26013b3a8eb9SGleb Smirnoff r.subh.action = PFSYNC_ACT_BUS; 26023b3a8eb9SGleb Smirnoff r.subh.count = htons(1); 26033b3a8eb9SGleb Smirnoff V_pfsyncstats.pfsyncs_oacts[PFSYNC_ACT_BUS]++; 26043b3a8eb9SGleb Smirnoff 26053b3a8eb9SGleb Smirnoff r.bus.creatorid = V_pf_status.hostid; 26063b3a8eb9SGleb Smirnoff r.bus.endtime = htonl(time_uptime - sc->sc_ureq_received); 26073b3a8eb9SGleb Smirnoff r.bus.status = status; 26083b3a8eb9SGleb Smirnoff 26093b3a8eb9SGleb Smirnoff pfsync_send_plus(&r, sizeof(r)); 26103b3a8eb9SGleb Smirnoff } 26113b3a8eb9SGleb Smirnoff 26123b3a8eb9SGleb Smirnoff static void 26133b3a8eb9SGleb Smirnoff pfsync_bulk_fail(void *arg) 26143b3a8eb9SGleb Smirnoff { 26153b3a8eb9SGleb Smirnoff struct pfsync_softc *sc = arg; 26164fc65bcbSKristof Provost struct pfsync_bucket *b = &sc->sc_buckets[0]; 26173b3a8eb9SGleb Smirnoff 26183b3a8eb9SGleb Smirnoff CURVNET_SET(sc->sc_ifp->if_vnet); 26193b3a8eb9SGleb Smirnoff 26203b3a8eb9SGleb Smirnoff PFSYNC_BLOCK_ASSERT(sc); 26213b3a8eb9SGleb Smirnoff 26223b3a8eb9SGleb Smirnoff if (sc->sc_bulk_tries++ < PFSYNC_MAX_BULKTRIES) { 26233b3a8eb9SGleb Smirnoff /* Try again */ 26243b3a8eb9SGleb Smirnoff callout_reset(&sc->sc_bulkfail_tmo, 5 * hz, 26253b3a8eb9SGleb Smirnoff pfsync_bulk_fail, V_pfsyncif); 26264fc65bcbSKristof Provost PFSYNC_BUCKET_LOCK(b); 26273b3a8eb9SGleb Smirnoff pfsync_request_update(0, 0); 26284fc65bcbSKristof Provost PFSYNC_BUCKET_UNLOCK(b); 26293b3a8eb9SGleb Smirnoff } else { 26303b3a8eb9SGleb Smirnoff /* Pretend like the transfer was ok. */ 26313b3a8eb9SGleb Smirnoff sc->sc_ureq_sent = 0; 26323b3a8eb9SGleb Smirnoff sc->sc_bulk_tries = 0; 26333b3a8eb9SGleb Smirnoff PFSYNC_LOCK(sc); 26343b3a8eb9SGleb Smirnoff if (!(sc->sc_flags & PFSYNCF_OK) && carp_demote_adj_p) 26353b3a8eb9SGleb Smirnoff (*carp_demote_adj_p)(-V_pfsync_carp_adj, 26363b3a8eb9SGleb Smirnoff "pfsync bulk fail"); 26373b3a8eb9SGleb Smirnoff sc->sc_flags |= PFSYNCF_OK; 26383b3a8eb9SGleb Smirnoff PFSYNC_UNLOCK(sc); 26393b3a8eb9SGleb Smirnoff if (V_pf_status.debug >= PF_DEBUG_MISC) 26403b3a8eb9SGleb Smirnoff printf("pfsync: failed to receive bulk update\n"); 26413b3a8eb9SGleb Smirnoff } 26423b3a8eb9SGleb Smirnoff 26433b3a8eb9SGleb Smirnoff CURVNET_RESTORE(); 26443b3a8eb9SGleb Smirnoff } 26453b3a8eb9SGleb Smirnoff 26463b3a8eb9SGleb Smirnoff static void 26473b3a8eb9SGleb Smirnoff pfsync_send_plus(void *plus, size_t pluslen) 26483b3a8eb9SGleb Smirnoff { 26493b3a8eb9SGleb Smirnoff struct pfsync_softc *sc = V_pfsyncif; 26504fc65bcbSKristof Provost struct pfsync_bucket *b = &sc->sc_buckets[0]; 2651caccf6d3SKristof Provost uint8_t *newplus; 26523b3a8eb9SGleb Smirnoff 26534fc65bcbSKristof Provost PFSYNC_BUCKET_LOCK(b); 26543b3a8eb9SGleb Smirnoff 26554fc65bcbSKristof Provost if (b->b_len + pluslen > sc->sc_ifp->if_mtu) 26564fc65bcbSKristof Provost pfsync_sendout(1, b->b_id); 26573b3a8eb9SGleb Smirnoff 2658caccf6d3SKristof Provost newplus = malloc(pluslen + b->b_pluslen, M_PFSYNC, M_NOWAIT); 2659caccf6d3SKristof Provost if (newplus == NULL) 266081debbd6SKristof Provost goto out; 266181debbd6SKristof Provost 2662caccf6d3SKristof Provost if (b->b_plus != NULL) { 2663caccf6d3SKristof Provost memcpy(newplus, b->b_plus, b->b_pluslen); 2664caccf6d3SKristof Provost free(b->b_plus, M_PFSYNC); 2665caccf6d3SKristof Provost } else { 2666caccf6d3SKristof Provost MPASS(b->b_pluslen == 0); 2667caccf6d3SKristof Provost } 2668caccf6d3SKristof Provost memcpy(newplus + b->b_pluslen, plus, pluslen); 2669caccf6d3SKristof Provost 2670caccf6d3SKristof Provost b->b_plus = newplus; 2671caccf6d3SKristof Provost b->b_pluslen += pluslen; 2672caccf6d3SKristof Provost b->b_len += pluslen; 26733b3a8eb9SGleb Smirnoff 26744fc65bcbSKristof Provost pfsync_sendout(1, b->b_id); 267581debbd6SKristof Provost 267681debbd6SKristof Provost out: 26774fc65bcbSKristof Provost PFSYNC_BUCKET_UNLOCK(b); 26783b3a8eb9SGleb Smirnoff } 26793b3a8eb9SGleb Smirnoff 26803b3a8eb9SGleb Smirnoff static void 26813b3a8eb9SGleb Smirnoff pfsync_timeout(void *arg) 26823b3a8eb9SGleb Smirnoff { 26834fc65bcbSKristof Provost struct pfsync_bucket *b = arg; 26843b3a8eb9SGleb Smirnoff 26854fc65bcbSKristof Provost CURVNET_SET(b->b_sc->sc_ifp->if_vnet); 26864fc65bcbSKristof Provost PFSYNC_BUCKET_LOCK(b); 26874fc65bcbSKristof Provost pfsync_push(b); 26884fc65bcbSKristof Provost PFSYNC_BUCKET_UNLOCK(b); 26893b3a8eb9SGleb Smirnoff CURVNET_RESTORE(); 26903b3a8eb9SGleb Smirnoff } 26913b3a8eb9SGleb Smirnoff 26923b3a8eb9SGleb Smirnoff static void 26934fc65bcbSKristof Provost pfsync_push(struct pfsync_bucket *b) 26943b3a8eb9SGleb Smirnoff { 26953b3a8eb9SGleb Smirnoff 26964fc65bcbSKristof Provost PFSYNC_BUCKET_LOCK_ASSERT(b); 26973b3a8eb9SGleb Smirnoff 26984fc65bcbSKristof Provost b->b_flags |= PFSYNCF_BUCKET_PUSH; 26993b3a8eb9SGleb Smirnoff swi_sched(V_pfsync_swi_cookie, 0); 27003b3a8eb9SGleb Smirnoff } 27013b3a8eb9SGleb Smirnoff 27023b3a8eb9SGleb Smirnoff static void 27034fc65bcbSKristof Provost pfsync_push_all(struct pfsync_softc *sc) 27044fc65bcbSKristof Provost { 27054fc65bcbSKristof Provost int c; 27064fc65bcbSKristof Provost struct pfsync_bucket *b; 27074fc65bcbSKristof Provost 27084fc65bcbSKristof Provost for (c = 0; c < pfsync_buckets; c++) { 27094fc65bcbSKristof Provost b = &sc->sc_buckets[c]; 27104fc65bcbSKristof Provost 27114fc65bcbSKristof Provost PFSYNC_BUCKET_LOCK(b); 27124fc65bcbSKristof Provost pfsync_push(b); 27134fc65bcbSKristof Provost PFSYNC_BUCKET_UNLOCK(b); 27144fc65bcbSKristof Provost } 27154fc65bcbSKristof Provost } 27164fc65bcbSKristof Provost 27174fc65bcbSKristof Provost static void 27189a1cab6dSKristof Provost pfsync_tx(struct pfsync_softc *sc, struct mbuf *m) 27199a1cab6dSKristof Provost { 27209a1cab6dSKristof Provost struct ip *ip; 2721f52ca3dfSKristof Provost int af, error = 0; 27229a1cab6dSKristof Provost 27239a1cab6dSKristof Provost ip = mtod(m, struct ip *); 27249a1cab6dSKristof Provost MPASS(ip->ip_v == IPVERSION || ip->ip_v == (IPV6_VERSION >> 4)); 27259a1cab6dSKristof Provost 27269a1cab6dSKristof Provost af = ip->ip_v == IPVERSION ? AF_INET : AF_INET6; 27279a1cab6dSKristof Provost 27289a1cab6dSKristof Provost /* 27299a1cab6dSKristof Provost * We distinguish between a deferral packet and our 27309a1cab6dSKristof Provost * own pfsync packet based on M_SKIP_FIREWALL 27319a1cab6dSKristof Provost * flag. This is XXX. 27329a1cab6dSKristof Provost */ 27339a1cab6dSKristof Provost switch (af) { 27349a1cab6dSKristof Provost #ifdef INET 27359a1cab6dSKristof Provost case AF_INET: 27369a1cab6dSKristof Provost if (m->m_flags & M_SKIP_FIREWALL) { 27379a1cab6dSKristof Provost error = ip_output(m, NULL, NULL, 0, 27389a1cab6dSKristof Provost NULL, NULL); 27399a1cab6dSKristof Provost } else { 27409a1cab6dSKristof Provost error = ip_output(m, NULL, NULL, 27419a1cab6dSKristof Provost IP_RAWOUTPUT, &sc->sc_imo, NULL); 27429a1cab6dSKristof Provost } 27439a1cab6dSKristof Provost break; 27449a1cab6dSKristof Provost #endif 27459a1cab6dSKristof Provost #ifdef INET6 27469a1cab6dSKristof Provost case AF_INET6: 27479a1cab6dSKristof Provost if (m->m_flags & M_SKIP_FIREWALL) { 27489a1cab6dSKristof Provost error = ip6_output(m, NULL, NULL, 0, 27499a1cab6dSKristof Provost NULL, NULL, NULL); 27509a1cab6dSKristof Provost } else { 27516fc7fc2dSLuiz Amaral error = ip6_output(m, NULL, NULL, 0, 27526fc7fc2dSLuiz Amaral &sc->sc_im6o, NULL, NULL); 27539a1cab6dSKristof Provost } 27549a1cab6dSKristof Provost break; 27559a1cab6dSKristof Provost #endif 27569a1cab6dSKristof Provost } 27579a1cab6dSKristof Provost 27589a1cab6dSKristof Provost if (error == 0) 27599a1cab6dSKristof Provost V_pfsyncstats.pfsyncs_opackets++; 27609a1cab6dSKristof Provost else 27619a1cab6dSKristof Provost V_pfsyncstats.pfsyncs_oerrors++; 27629a1cab6dSKristof Provost 27639a1cab6dSKristof Provost } 27649a1cab6dSKristof Provost 27659a1cab6dSKristof Provost static void 27663b3a8eb9SGleb Smirnoff pfsyncintr(void *arg) 27673b3a8eb9SGleb Smirnoff { 2768ef1bd1e5SKristof Provost struct epoch_tracker et; 27693b3a8eb9SGleb Smirnoff struct pfsync_softc *sc = arg; 27704fc65bcbSKristof Provost struct pfsync_bucket *b; 27713b3a8eb9SGleb Smirnoff struct mbuf *m, *n; 27729a1cab6dSKristof Provost int c; 27733b3a8eb9SGleb Smirnoff 2774ef1bd1e5SKristof Provost NET_EPOCH_ENTER(et); 27753b3a8eb9SGleb Smirnoff CURVNET_SET(sc->sc_ifp->if_vnet); 27763b3a8eb9SGleb Smirnoff 27774fc65bcbSKristof Provost for (c = 0; c < pfsync_buckets; c++) { 27784fc65bcbSKristof Provost b = &sc->sc_buckets[c]; 27794fc65bcbSKristof Provost 27804fc65bcbSKristof Provost PFSYNC_BUCKET_LOCK(b); 27814fc65bcbSKristof Provost if ((b->b_flags & PFSYNCF_BUCKET_PUSH) && b->b_len > PFSYNC_MINPKT) { 27824fc65bcbSKristof Provost pfsync_sendout(0, b->b_id); 27834fc65bcbSKristof Provost b->b_flags &= ~PFSYNCF_BUCKET_PUSH; 27843b3a8eb9SGleb Smirnoff } 27854fc65bcbSKristof Provost _IF_DEQUEUE_ALL(&b->b_snd, m); 27864fc65bcbSKristof Provost PFSYNC_BUCKET_UNLOCK(b); 27873b3a8eb9SGleb Smirnoff 27883b3a8eb9SGleb Smirnoff for (; m != NULL; m = n) { 27893b3a8eb9SGleb Smirnoff n = m->m_nextpkt; 27903b3a8eb9SGleb Smirnoff m->m_nextpkt = NULL; 27913b3a8eb9SGleb Smirnoff 27929a1cab6dSKristof Provost pfsync_tx(sc, m); 27933b3a8eb9SGleb Smirnoff } 27944fc65bcbSKristof Provost } 27953b3a8eb9SGleb Smirnoff CURVNET_RESTORE(); 2796ef1bd1e5SKristof Provost NET_EPOCH_EXIT(et); 27973b3a8eb9SGleb Smirnoff } 27983b3a8eb9SGleb Smirnoff 27993b3a8eb9SGleb Smirnoff static int 280059854ecfSHans Petter Selasky pfsync_multicast_setup(struct pfsync_softc *sc, struct ifnet *ifp, 28016fc7fc2dSLuiz Amaral struct in_mfilter* imf, struct in6_mfilter* im6f) 28023b3a8eb9SGleb Smirnoff { 280377c9e608SKristof Provost #ifdef INET 28043b3a8eb9SGleb Smirnoff struct ip_moptions *imo = &sc->sc_imo; 280577c9e608SKristof Provost #endif 280677c9e608SKristof Provost #ifdef INET6 28076fc7fc2dSLuiz Amaral struct ip6_moptions *im6o = &sc->sc_im6o; 28086fc7fc2dSLuiz Amaral struct sockaddr_in6 *syncpeer_sa6 = NULL; 280977c9e608SKristof Provost #endif 28103b3a8eb9SGleb Smirnoff 28113b3a8eb9SGleb Smirnoff if (!(ifp->if_flags & IFF_MULTICAST)) 28123b3a8eb9SGleb Smirnoff return (EADDRNOTAVAIL); 28133b3a8eb9SGleb Smirnoff 2814813c5b75SLuiz Amaral switch (sc->sc_sync_peer.ss_family) { 2815813c5b75SLuiz Amaral #ifdef INET 2816813c5b75SLuiz Amaral case AF_INET: 2817813c5b75SLuiz Amaral { 281877c9e608SKristof Provost int error; 281977c9e608SKristof Provost 2820813c5b75SLuiz Amaral ip_mfilter_init(&imo->imo_head); 28213b3a8eb9SGleb Smirnoff imo->imo_multicast_vif = -1; 28226fc7fc2dSLuiz Amaral if ((error = in_joingroup(ifp, 282377c9e608SKristof Provost &((struct sockaddr_in *)&sc->sc_sync_peer)->sin_addr, NULL, 282477c9e608SKristof Provost &imf->imf_inm)) != 0) 28253b3a8eb9SGleb Smirnoff return (error); 282659854ecfSHans Petter Selasky 282759854ecfSHans Petter Selasky ip_mfilter_insert(&imo->imo_head, imf); 28283b3a8eb9SGleb Smirnoff imo->imo_multicast_ifp = ifp; 28293b3a8eb9SGleb Smirnoff imo->imo_multicast_ttl = PFSYNC_DFLTTL; 28303b3a8eb9SGleb Smirnoff imo->imo_multicast_loop = 0; 2831813c5b75SLuiz Amaral break; 2832813c5b75SLuiz Amaral } 2833813c5b75SLuiz Amaral #endif 28346fc7fc2dSLuiz Amaral #ifdef INET6 28356fc7fc2dSLuiz Amaral case AF_INET6: 28366fc7fc2dSLuiz Amaral { 283777c9e608SKristof Provost int error; 283877c9e608SKristof Provost 28396fc7fc2dSLuiz Amaral syncpeer_sa6 = (struct sockaddr_in6 *)&sc->sc_sync_peer; 28406fc7fc2dSLuiz Amaral if ((error = in6_setscope(&syncpeer_sa6->sin6_addr, ifp, NULL))) 28416fc7fc2dSLuiz Amaral return (error); 284277c9e608SKristof Provost 28436fc7fc2dSLuiz Amaral ip6_mfilter_init(&im6o->im6o_head); 28446fc7fc2dSLuiz Amaral if ((error = in6_joingroup(ifp, &syncpeer_sa6->sin6_addr, NULL, 28456fc7fc2dSLuiz Amaral &(im6f->im6f_in6m), 0)) != 0) 28466fc7fc2dSLuiz Amaral return (error); 28476fc7fc2dSLuiz Amaral 28486fc7fc2dSLuiz Amaral ip6_mfilter_insert(&im6o->im6o_head, im6f); 28496fc7fc2dSLuiz Amaral im6o->im6o_multicast_ifp = ifp; 28506fc7fc2dSLuiz Amaral im6o->im6o_multicast_hlim = PFSYNC_DFLTTL; 28516fc7fc2dSLuiz Amaral im6o->im6o_multicast_loop = 0; 28526fc7fc2dSLuiz Amaral break; 28536fc7fc2dSLuiz Amaral } 28546fc7fc2dSLuiz Amaral #endif 285577c9e608SKristof Provost } 28563b3a8eb9SGleb Smirnoff 28573b3a8eb9SGleb Smirnoff return (0); 28583b3a8eb9SGleb Smirnoff } 28593b3a8eb9SGleb Smirnoff 28603b3a8eb9SGleb Smirnoff static void 28613b3a8eb9SGleb Smirnoff pfsync_multicast_cleanup(struct pfsync_softc *sc) 28623b3a8eb9SGleb Smirnoff { 286377c9e608SKristof Provost #ifdef INET 28643b3a8eb9SGleb Smirnoff struct ip_moptions *imo = &sc->sc_imo; 286559854ecfSHans Petter Selasky struct in_mfilter *imf; 28663b3a8eb9SGleb Smirnoff 286759854ecfSHans Petter Selasky while ((imf = ip_mfilter_first(&imo->imo_head)) != NULL) { 286859854ecfSHans Petter Selasky ip_mfilter_remove(&imo->imo_head, imf); 286959854ecfSHans Petter Selasky in_leavegroup(imf->imf_inm, NULL); 287059854ecfSHans Petter Selasky ip_mfilter_free(imf); 287159854ecfSHans Petter Selasky } 28723b3a8eb9SGleb Smirnoff imo->imo_multicast_ifp = NULL; 287377c9e608SKristof Provost #endif 287477c9e608SKristof Provost 287577c9e608SKristof Provost #ifdef INET6 287677c9e608SKristof Provost struct ip6_moptions *im6o = &sc->sc_im6o; 287777c9e608SKristof Provost struct in6_mfilter *im6f; 28786fc7fc2dSLuiz Amaral 28796fc7fc2dSLuiz Amaral while ((im6f = ip6_mfilter_first(&im6o->im6o_head)) != NULL) { 28806fc7fc2dSLuiz Amaral ip6_mfilter_remove(&im6o->im6o_head, im6f); 28816fc7fc2dSLuiz Amaral in6_leavegroup(im6f->im6f_in6m, NULL); 28826fc7fc2dSLuiz Amaral ip6_mfilter_free(im6f); 28836fc7fc2dSLuiz Amaral } 28846fc7fc2dSLuiz Amaral im6o->im6o_multicast_ifp = NULL; 288577c9e608SKristof Provost #endif 28863b3a8eb9SGleb Smirnoff } 28873b3a8eb9SGleb Smirnoff 2888fbbf436dSKristof Provost void 2889fbbf436dSKristof Provost pfsync_detach_ifnet(struct ifnet *ifp) 2890fbbf436dSKristof Provost { 2891fbbf436dSKristof Provost struct pfsync_softc *sc = V_pfsyncif; 2892fbbf436dSKristof Provost 2893fbbf436dSKristof Provost if (sc == NULL) 2894fbbf436dSKristof Provost return; 2895fbbf436dSKristof Provost 2896fbbf436dSKristof Provost PFSYNC_LOCK(sc); 2897fbbf436dSKristof Provost 2898fbbf436dSKristof Provost if (sc->sc_sync_if == ifp) { 2899fbbf436dSKristof Provost /* We don't need mutlicast cleanup here, because the interface 2900fbbf436dSKristof Provost * is going away. We do need to ensure we don't try to do 2901fbbf436dSKristof Provost * cleanup later. 2902fbbf436dSKristof Provost */ 290359854ecfSHans Petter Selasky ip_mfilter_init(&sc->sc_imo.imo_head); 2904fbbf436dSKristof Provost sc->sc_imo.imo_multicast_ifp = NULL; 29056fc7fc2dSLuiz Amaral sc->sc_im6o.im6o_multicast_ifp = NULL; 2906fbbf436dSKristof Provost sc->sc_sync_if = NULL; 2907fbbf436dSKristof Provost } 2908fbbf436dSKristof Provost 2909fbbf436dSKristof Provost PFSYNC_UNLOCK(sc); 2910fbbf436dSKristof Provost } 2911fbbf436dSKristof Provost 2912813c5b75SLuiz Amaral static int 2913813c5b75SLuiz Amaral pfsync_pfsyncreq_to_kstatus(struct pfsyncreq *pfsyncr, struct pfsync_kstatus *status) 2914813c5b75SLuiz Amaral { 2915813c5b75SLuiz Amaral struct sockaddr_storage sa; 2916813c5b75SLuiz Amaral status->maxupdates = pfsyncr->pfsyncr_maxupdates; 2917813c5b75SLuiz Amaral status->flags = pfsyncr->pfsyncr_defer; 2918813c5b75SLuiz Amaral 2919813c5b75SLuiz Amaral strlcpy(status->syncdev, pfsyncr->pfsyncr_syncdev, IFNAMSIZ); 2920813c5b75SLuiz Amaral 2921813c5b75SLuiz Amaral memset(&sa, 0, sizeof(sa)); 2922813c5b75SLuiz Amaral if (pfsyncr->pfsyncr_syncpeer.s_addr != 0) { 2923813c5b75SLuiz Amaral struct sockaddr_in *in = (struct sockaddr_in *)&sa; 2924813c5b75SLuiz Amaral in->sin_family = AF_INET; 2925813c5b75SLuiz Amaral in->sin_len = sizeof(*in); 2926813c5b75SLuiz Amaral in->sin_addr.s_addr = pfsyncr->pfsyncr_syncpeer.s_addr; 2927813c5b75SLuiz Amaral } 2928813c5b75SLuiz Amaral status->syncpeer = sa; 2929813c5b75SLuiz Amaral 2930813c5b75SLuiz Amaral return 0; 2931813c5b75SLuiz Amaral } 2932813c5b75SLuiz Amaral 2933813c5b75SLuiz Amaral static int 2934813c5b75SLuiz Amaral pfsync_kstatus_to_softc(struct pfsync_kstatus *status, struct pfsync_softc *sc) 2935813c5b75SLuiz Amaral { 2936813c5b75SLuiz Amaral struct ifnet *sifp; 29376fc7fc2dSLuiz Amaral struct in_mfilter *imf = NULL; 29386fc7fc2dSLuiz Amaral struct in6_mfilter *im6f = NULL; 2939813c5b75SLuiz Amaral int error; 2940813c5b75SLuiz Amaral int c; 2941813c5b75SLuiz Amaral 2942813c5b75SLuiz Amaral if ((status->maxupdates < 0) || (status->maxupdates > 255)) 2943813c5b75SLuiz Amaral return (EINVAL); 2944813c5b75SLuiz Amaral 2945813c5b75SLuiz Amaral if (status->syncdev[0] == '\0') 2946813c5b75SLuiz Amaral sifp = NULL; 2947813c5b75SLuiz Amaral else if ((sifp = ifunit_ref(status->syncdev)) == NULL) 2948813c5b75SLuiz Amaral return (EINVAL); 2949813c5b75SLuiz Amaral 29506fc7fc2dSLuiz Amaral switch (status->syncpeer.ss_family) { 295177c9e608SKristof Provost #ifdef INET 29526fc7fc2dSLuiz Amaral case AF_UNSPEC: 29536fc7fc2dSLuiz Amaral case AF_INET: { 295477c9e608SKristof Provost struct sockaddr_in *status_sin; 29556fc7fc2dSLuiz Amaral status_sin = (struct sockaddr_in *)&(status->syncpeer); 29566fc7fc2dSLuiz Amaral if (sifp != NULL) { 29576fc7fc2dSLuiz Amaral if (status_sin->sin_addr.s_addr == 0 || 2958813c5b75SLuiz Amaral status_sin->sin_addr.s_addr == 29596fc7fc2dSLuiz Amaral htonl(INADDR_PFSYNC_GROUP)) { 29606fc7fc2dSLuiz Amaral status_sin->sin_family = AF_INET; 29616fc7fc2dSLuiz Amaral status_sin->sin_len = sizeof(*status_sin); 29626fc7fc2dSLuiz Amaral status_sin->sin_addr.s_addr = 29636fc7fc2dSLuiz Amaral htonl(INADDR_PFSYNC_GROUP); 29646fc7fc2dSLuiz Amaral } 29656fc7fc2dSLuiz Amaral 29666fc7fc2dSLuiz Amaral if (IN_MULTICAST(ntohl(status_sin->sin_addr.s_addr))) { 2967813c5b75SLuiz Amaral imf = ip_mfilter_alloc(M_WAITOK, 0, 0); 29686fc7fc2dSLuiz Amaral } 29696fc7fc2dSLuiz Amaral } 29706fc7fc2dSLuiz Amaral break; 29716fc7fc2dSLuiz Amaral } 297277c9e608SKristof Provost #endif 297377c9e608SKristof Provost #ifdef INET6 29746fc7fc2dSLuiz Amaral case AF_INET6: { 297577c9e608SKristof Provost struct sockaddr_in6 *status_sin6; 29766fc7fc2dSLuiz Amaral status_sin6 = (struct sockaddr_in6*)&(status->syncpeer); 29776fc7fc2dSLuiz Amaral if (sifp != NULL) { 29786fc7fc2dSLuiz Amaral if (IN6_IS_ADDR_UNSPECIFIED(&status_sin6->sin6_addr) || 29796fc7fc2dSLuiz Amaral IN6_ARE_ADDR_EQUAL(&status_sin6->sin6_addr, 29806fc7fc2dSLuiz Amaral &in6addr_linklocal_pfsync_group)) { 29816fc7fc2dSLuiz Amaral status_sin6->sin6_family = AF_INET6; 29826fc7fc2dSLuiz Amaral status_sin6->sin6_len = sizeof(*status_sin6); 29836fc7fc2dSLuiz Amaral status_sin6->sin6_addr = 29846fc7fc2dSLuiz Amaral in6addr_linklocal_pfsync_group; 29856fc7fc2dSLuiz Amaral } 29866fc7fc2dSLuiz Amaral 29876fc7fc2dSLuiz Amaral if (IN6_IS_ADDR_MULTICAST(&status_sin6->sin6_addr)) { 29886fc7fc2dSLuiz Amaral im6f = ip6_mfilter_alloc(M_WAITOK, 0, 0); 29896fc7fc2dSLuiz Amaral } 29906fc7fc2dSLuiz Amaral } 29916fc7fc2dSLuiz Amaral break; 29926fc7fc2dSLuiz Amaral } 299377c9e608SKristof Provost #endif 29946fc7fc2dSLuiz Amaral } 2995813c5b75SLuiz Amaral 2996813c5b75SLuiz Amaral PFSYNC_LOCK(sc); 29974bf98559SKajetan Staszkiewicz 29984bf98559SKajetan Staszkiewicz switch (status->version) { 29994bf98559SKajetan Staszkiewicz case PFSYNC_MSG_VERSION_UNSPECIFIED: 30004bf98559SKajetan Staszkiewicz sc->sc_version = PFSYNC_MSG_VERSION_DEFAULT; 30014bf98559SKajetan Staszkiewicz break; 30024bf98559SKajetan Staszkiewicz case PFSYNC_MSG_VERSION_1301: 30034bf98559SKajetan Staszkiewicz case PFSYNC_MSG_VERSION_1400: 30044bf98559SKajetan Staszkiewicz sc->sc_version = status->version; 30054bf98559SKajetan Staszkiewicz break; 30064bf98559SKajetan Staszkiewicz default: 30074bf98559SKajetan Staszkiewicz PFSYNC_UNLOCK(sc); 30084bf98559SKajetan Staszkiewicz return (EINVAL); 30094bf98559SKajetan Staszkiewicz } 30104bf98559SKajetan Staszkiewicz 30116fc7fc2dSLuiz Amaral switch (status->syncpeer.ss_family) { 30126fc7fc2dSLuiz Amaral case AF_INET: { 30136fc7fc2dSLuiz Amaral struct sockaddr_in *status_sin = (struct sockaddr_in *)&(status->syncpeer); 3014813c5b75SLuiz Amaral struct sockaddr_in *sc_sin = (struct sockaddr_in *)&sc->sc_sync_peer; 3015813c5b75SLuiz Amaral sc_sin->sin_family = AF_INET; 3016813c5b75SLuiz Amaral sc_sin->sin_len = sizeof(*sc_sin); 3017813c5b75SLuiz Amaral if (status_sin->sin_addr.s_addr == 0) { 3018813c5b75SLuiz Amaral sc_sin->sin_addr.s_addr = htonl(INADDR_PFSYNC_GROUP); 3019813c5b75SLuiz Amaral } else { 3020813c5b75SLuiz Amaral sc_sin->sin_addr.s_addr = status_sin->sin_addr.s_addr; 3021813c5b75SLuiz Amaral } 30226fc7fc2dSLuiz Amaral break; 30236fc7fc2dSLuiz Amaral } 30246fc7fc2dSLuiz Amaral case AF_INET6: { 30256fc7fc2dSLuiz Amaral struct sockaddr_in6 *status_sin = (struct sockaddr_in6 *)&(status->syncpeer); 30266fc7fc2dSLuiz Amaral struct sockaddr_in6 *sc_sin = (struct sockaddr_in6 *)&sc->sc_sync_peer; 30276fc7fc2dSLuiz Amaral sc_sin->sin6_family = AF_INET6; 30286fc7fc2dSLuiz Amaral sc_sin->sin6_len = sizeof(*sc_sin); 30296fc7fc2dSLuiz Amaral if(IN6_IS_ADDR_UNSPECIFIED(&status_sin->sin6_addr)) { 30306fc7fc2dSLuiz Amaral sc_sin->sin6_addr = in6addr_linklocal_pfsync_group; 30316fc7fc2dSLuiz Amaral } else { 30326fc7fc2dSLuiz Amaral sc_sin->sin6_addr = status_sin->sin6_addr; 30336fc7fc2dSLuiz Amaral } 30346fc7fc2dSLuiz Amaral break; 30356fc7fc2dSLuiz Amaral } 30366fc7fc2dSLuiz Amaral } 3037813c5b75SLuiz Amaral 3038813c5b75SLuiz Amaral sc->sc_maxupdates = status->maxupdates; 3039813c5b75SLuiz Amaral if (status->flags & PFSYNCF_DEFER) { 3040813c5b75SLuiz Amaral sc->sc_flags |= PFSYNCF_DEFER; 3041813c5b75SLuiz Amaral V_pfsync_defer_ptr = pfsync_defer; 3042813c5b75SLuiz Amaral } else { 3043813c5b75SLuiz Amaral sc->sc_flags &= ~PFSYNCF_DEFER; 3044813c5b75SLuiz Amaral V_pfsync_defer_ptr = NULL; 3045813c5b75SLuiz Amaral } 3046813c5b75SLuiz Amaral 3047813c5b75SLuiz Amaral if (sifp == NULL) { 3048813c5b75SLuiz Amaral if (sc->sc_sync_if) 3049813c5b75SLuiz Amaral if_rele(sc->sc_sync_if); 3050813c5b75SLuiz Amaral sc->sc_sync_if = NULL; 3051813c5b75SLuiz Amaral pfsync_multicast_cleanup(sc); 3052813c5b75SLuiz Amaral PFSYNC_UNLOCK(sc); 3053813c5b75SLuiz Amaral return (0); 3054813c5b75SLuiz Amaral } 3055813c5b75SLuiz Amaral 3056813c5b75SLuiz Amaral for (c = 0; c < pfsync_buckets; c++) { 3057813c5b75SLuiz Amaral PFSYNC_BUCKET_LOCK(&sc->sc_buckets[c]); 3058813c5b75SLuiz Amaral if (sc->sc_buckets[c].b_len > PFSYNC_MINPKT && 3059813c5b75SLuiz Amaral (sifp->if_mtu < sc->sc_ifp->if_mtu || 3060813c5b75SLuiz Amaral (sc->sc_sync_if != NULL && 3061813c5b75SLuiz Amaral sifp->if_mtu < sc->sc_sync_if->if_mtu) || 3062813c5b75SLuiz Amaral sifp->if_mtu < MCLBYTES - sizeof(struct ip))) 3063813c5b75SLuiz Amaral pfsync_sendout(1, c); 3064813c5b75SLuiz Amaral PFSYNC_BUCKET_UNLOCK(&sc->sc_buckets[c]); 3065813c5b75SLuiz Amaral } 3066813c5b75SLuiz Amaral 3067813c5b75SLuiz Amaral pfsync_multicast_cleanup(sc); 3068813c5b75SLuiz Amaral 30696fc7fc2dSLuiz Amaral if (((sc->sc_sync_peer.ss_family == AF_INET) && 30706fc7fc2dSLuiz Amaral IN_MULTICAST(ntohl(((struct sockaddr_in *) 30716fc7fc2dSLuiz Amaral &sc->sc_sync_peer)->sin_addr.s_addr))) || 30726fc7fc2dSLuiz Amaral ((sc->sc_sync_peer.ss_family == AF_INET6) && 30736fc7fc2dSLuiz Amaral IN6_IS_ADDR_MULTICAST(&((struct sockaddr_in6*) 30746fc7fc2dSLuiz Amaral &sc->sc_sync_peer)->sin6_addr))) { 30756fc7fc2dSLuiz Amaral error = pfsync_multicast_setup(sc, sifp, imf, im6f); 3076813c5b75SLuiz Amaral if (error) { 3077813c5b75SLuiz Amaral if_rele(sifp); 3078813c5b75SLuiz Amaral PFSYNC_UNLOCK(sc); 307977c9e608SKristof Provost #ifdef INET 30806fc7fc2dSLuiz Amaral if (imf != NULL) 30816fc7fc2dSLuiz Amaral ip_mfilter_free(imf); 308277c9e608SKristof Provost #endif 308377c9e608SKristof Provost #ifdef INET6 30846fc7fc2dSLuiz Amaral if (im6f != NULL) 30856fc7fc2dSLuiz Amaral ip6_mfilter_free(im6f); 308677c9e608SKristof Provost #endif 3087813c5b75SLuiz Amaral return (error); 3088813c5b75SLuiz Amaral } 3089813c5b75SLuiz Amaral } 3090813c5b75SLuiz Amaral if (sc->sc_sync_if) 3091813c5b75SLuiz Amaral if_rele(sc->sc_sync_if); 3092813c5b75SLuiz Amaral sc->sc_sync_if = sifp; 3093813c5b75SLuiz Amaral 30946fc7fc2dSLuiz Amaral switch (sc->sc_sync_peer.ss_family) { 309577c9e608SKristof Provost #ifdef INET 30966fc7fc2dSLuiz Amaral case AF_INET: { 30976fc7fc2dSLuiz Amaral struct ip *ip; 3098813c5b75SLuiz Amaral ip = &sc->sc_template.ipv4; 3099813c5b75SLuiz Amaral bzero(ip, sizeof(*ip)); 3100813c5b75SLuiz Amaral ip->ip_v = IPVERSION; 3101813c5b75SLuiz Amaral ip->ip_hl = sizeof(sc->sc_template.ipv4) >> 2; 3102813c5b75SLuiz Amaral ip->ip_tos = IPTOS_LOWDELAY; 3103813c5b75SLuiz Amaral /* len and id are set later. */ 3104813c5b75SLuiz Amaral ip->ip_off = htons(IP_DF); 3105813c5b75SLuiz Amaral ip->ip_ttl = PFSYNC_DFLTTL; 3106813c5b75SLuiz Amaral ip->ip_p = IPPROTO_PFSYNC; 3107813c5b75SLuiz Amaral ip->ip_src.s_addr = INADDR_ANY; 31086fc7fc2dSLuiz Amaral ip->ip_dst = ((struct sockaddr_in *)&sc->sc_sync_peer)->sin_addr; 31096fc7fc2dSLuiz Amaral break; 31106fc7fc2dSLuiz Amaral } 311177c9e608SKristof Provost #endif 311277c9e608SKristof Provost #ifdef INET6 31136fc7fc2dSLuiz Amaral case AF_INET6: { 31146fc7fc2dSLuiz Amaral struct ip6_hdr *ip6; 31156fc7fc2dSLuiz Amaral ip6 = &sc->sc_template.ipv6; 31166fc7fc2dSLuiz Amaral bzero(ip6, sizeof(*ip6)); 31176fc7fc2dSLuiz Amaral ip6->ip6_vfc = IPV6_VERSION; 31186fc7fc2dSLuiz Amaral ip6->ip6_hlim = PFSYNC_DFLTTL; 31196fc7fc2dSLuiz Amaral ip6->ip6_nxt = IPPROTO_PFSYNC; 31206fc7fc2dSLuiz Amaral ip6->ip6_dst = ((struct sockaddr_in6 *)&sc->sc_sync_peer)->sin6_addr; 31216fc7fc2dSLuiz Amaral 31226fc7fc2dSLuiz Amaral struct epoch_tracker et; 31236fc7fc2dSLuiz Amaral NET_EPOCH_ENTER(et); 31246fc7fc2dSLuiz Amaral in6_selectsrc_addr(if_getfib(sc->sc_sync_if), &ip6->ip6_dst, 0, 31256fc7fc2dSLuiz Amaral sc->sc_sync_if, &ip6->ip6_src, NULL); 31266fc7fc2dSLuiz Amaral NET_EPOCH_EXIT(et); 31276fc7fc2dSLuiz Amaral break; 31286fc7fc2dSLuiz Amaral } 312977c9e608SKristof Provost #endif 31306fc7fc2dSLuiz Amaral } 3131813c5b75SLuiz Amaral 3132813c5b75SLuiz Amaral /* Request a full state table update. */ 3133813c5b75SLuiz Amaral if ((sc->sc_flags & PFSYNCF_OK) && carp_demote_adj_p) 3134813c5b75SLuiz Amaral (*carp_demote_adj_p)(V_pfsync_carp_adj, 3135813c5b75SLuiz Amaral "pfsync bulk start"); 3136813c5b75SLuiz Amaral sc->sc_flags &= ~PFSYNCF_OK; 3137813c5b75SLuiz Amaral if (V_pf_status.debug >= PF_DEBUG_MISC) 3138813c5b75SLuiz Amaral printf("pfsync: requesting bulk update\n"); 3139813c5b75SLuiz Amaral PFSYNC_UNLOCK(sc); 3140813c5b75SLuiz Amaral PFSYNC_BUCKET_LOCK(&sc->sc_buckets[0]); 3141813c5b75SLuiz Amaral pfsync_request_update(0, 0); 3142813c5b75SLuiz Amaral PFSYNC_BUCKET_UNLOCK(&sc->sc_buckets[0]); 3143813c5b75SLuiz Amaral PFSYNC_BLOCK(sc); 3144813c5b75SLuiz Amaral sc->sc_ureq_sent = time_uptime; 3145813c5b75SLuiz Amaral callout_reset(&sc->sc_bulkfail_tmo, 5 * hz, pfsync_bulk_fail, sc); 3146813c5b75SLuiz Amaral PFSYNC_BUNLOCK(sc); 3147813c5b75SLuiz Amaral return (0); 3148813c5b75SLuiz Amaral } 3149813c5b75SLuiz Amaral 31507b6fbb73SGleb Smirnoff static void 3151766f3c80SDimitry Andric pfsync_pointers_init(void) 31527b6fbb73SGleb Smirnoff { 31537b6fbb73SGleb Smirnoff 31547b6fbb73SGleb Smirnoff PF_RULES_WLOCK(); 31555f6cf24eSKristof Provost V_pfsync_state_import_ptr = pfsync_state_import; 31565f6cf24eSKristof Provost V_pfsync_insert_state_ptr = pfsync_insert_state; 31575f6cf24eSKristof Provost V_pfsync_update_state_ptr = pfsync_update_state; 31585f6cf24eSKristof Provost V_pfsync_delete_state_ptr = pfsync_delete_state; 31595f6cf24eSKristof Provost V_pfsync_clear_states_ptr = pfsync_clear_states; 31605f6cf24eSKristof Provost V_pfsync_defer_ptr = pfsync_defer; 31617b6fbb73SGleb Smirnoff PF_RULES_WUNLOCK(); 31627b6fbb73SGleb Smirnoff } 31637b6fbb73SGleb Smirnoff 31647b6fbb73SGleb Smirnoff static void 3165766f3c80SDimitry Andric pfsync_pointers_uninit(void) 31667b6fbb73SGleb Smirnoff { 31677b6fbb73SGleb Smirnoff 31687b6fbb73SGleb Smirnoff PF_RULES_WLOCK(); 31695f6cf24eSKristof Provost V_pfsync_state_import_ptr = NULL; 31705f6cf24eSKristof Provost V_pfsync_insert_state_ptr = NULL; 31715f6cf24eSKristof Provost V_pfsync_update_state_ptr = NULL; 31725f6cf24eSKristof Provost V_pfsync_delete_state_ptr = NULL; 31735f6cf24eSKristof Provost V_pfsync_clear_states_ptr = NULL; 31745f6cf24eSKristof Provost V_pfsync_defer_ptr = NULL; 31757b6fbb73SGleb Smirnoff PF_RULES_WUNLOCK(); 31767b6fbb73SGleb Smirnoff } 31777b6fbb73SGleb Smirnoff 317866c00e9eSBjoern A. Zeeb static void 317966c00e9eSBjoern A. Zeeb vnet_pfsync_init(const void *unused __unused) 31803b3a8eb9SGleb Smirnoff { 318166c00e9eSBjoern A. Zeeb int error; 31823b3a8eb9SGleb Smirnoff 318342a58907SGleb Smirnoff V_pfsync_cloner = if_clone_simple(pfsyncname, 318442a58907SGleb Smirnoff pfsync_clone_create, pfsync_clone_destroy, 1); 3185cecfaf9bSKristof Provost error = swi_add(&V_pfsync_swi_ie, pfsyncname, pfsyncintr, V_pfsyncif, 31863b3a8eb9SGleb Smirnoff SWI_NET, INTR_MPSAFE, &V_pfsync_swi_cookie); 318766c00e9eSBjoern A. Zeeb if (error) { 318866c00e9eSBjoern A. Zeeb if_clone_detach(V_pfsync_cloner); 318966c00e9eSBjoern A. Zeeb log(LOG_INFO, "swi_add() failed in %s\n", __func__); 31903b3a8eb9SGleb Smirnoff } 31915f6cf24eSKristof Provost 31925f6cf24eSKristof Provost pfsync_pointers_init(); 319366c00e9eSBjoern A. Zeeb } 319466c00e9eSBjoern A. Zeeb VNET_SYSINIT(vnet_pfsync_init, SI_SUB_PROTO_FIREWALL, SI_ORDER_ANY, 319566c00e9eSBjoern A. Zeeb vnet_pfsync_init, NULL); 319666c00e9eSBjoern A. Zeeb 319766c00e9eSBjoern A. Zeeb static void 319866c00e9eSBjoern A. Zeeb vnet_pfsync_uninit(const void *unused __unused) 319966c00e9eSBjoern A. Zeeb { 3200bcd4c17cSMateusz Guzik int ret __diagused; 320166c00e9eSBjoern A. Zeeb 32025f6cf24eSKristof Provost pfsync_pointers_uninit(); 32035f6cf24eSKristof Provost 320466c00e9eSBjoern A. Zeeb if_clone_detach(V_pfsync_cloner); 3205cecfaf9bSKristof Provost ret = swi_remove(V_pfsync_swi_cookie); 3206cecfaf9bSKristof Provost MPASS(ret == 0); 3207cecfaf9bSKristof Provost ret = intr_event_destroy(V_pfsync_swi_ie); 3208cecfaf9bSKristof Provost MPASS(ret == 0); 320966c00e9eSBjoern A. Zeeb } 321026549dfcSKristof Provost 321126549dfcSKristof Provost VNET_SYSUNINIT(vnet_pfsync_uninit, SI_SUB_PROTO_FIREWALL, SI_ORDER_FOURTH, 321266c00e9eSBjoern A. Zeeb vnet_pfsync_uninit, NULL); 321366c00e9eSBjoern A. Zeeb 321466c00e9eSBjoern A. Zeeb static int 3215766f3c80SDimitry Andric pfsync_init(void) 321666c00e9eSBjoern A. Zeeb { 321766c00e9eSBjoern A. Zeeb int error; 321866c00e9eSBjoern A. Zeeb 3219fbbf436dSKristof Provost pfsync_detach_ifnet_ptr = pfsync_detach_ifnet; 3220fbbf436dSKristof Provost 32216fc7fc2dSLuiz Amaral #ifdef INET 322278b1fc05SGleb Smirnoff error = ipproto_register(IPPROTO_PFSYNC, pfsync_input, NULL); 32233b3a8eb9SGleb Smirnoff if (error) 322466c00e9eSBjoern A. Zeeb return (error); 32253b3a8eb9SGleb Smirnoff #endif 32266fc7fc2dSLuiz Amaral #ifdef INET6 32276fc7fc2dSLuiz Amaral error = ip6proto_register(IPPROTO_PFSYNC, pfsync6_input, NULL); 32286fc7fc2dSLuiz Amaral if (error) { 32296fc7fc2dSLuiz Amaral ipproto_unregister(IPPROTO_PFSYNC); 32306fc7fc2dSLuiz Amaral return (error); 32316fc7fc2dSLuiz Amaral } 32326fc7fc2dSLuiz Amaral #endif 32333b3a8eb9SGleb Smirnoff 32343b3a8eb9SGleb Smirnoff return (0); 32353b3a8eb9SGleb Smirnoff } 32363b3a8eb9SGleb Smirnoff 32373b3a8eb9SGleb Smirnoff static void 3238766f3c80SDimitry Andric pfsync_uninit(void) 32393b3a8eb9SGleb Smirnoff { 3240fbbf436dSKristof Provost pfsync_detach_ifnet_ptr = NULL; 32413b3a8eb9SGleb Smirnoff 324266c00e9eSBjoern A. Zeeb #ifdef INET 32433b3a8eb9SGleb Smirnoff ipproto_unregister(IPPROTO_PFSYNC); 324466c00e9eSBjoern A. Zeeb #endif 32456fc7fc2dSLuiz Amaral #ifdef INET6 32466fc7fc2dSLuiz Amaral ip6proto_unregister(IPPROTO_PFSYNC); 32476fc7fc2dSLuiz Amaral #endif 32483b3a8eb9SGleb Smirnoff } 32493b3a8eb9SGleb Smirnoff 32503b3a8eb9SGleb Smirnoff static int 32513b3a8eb9SGleb Smirnoff pfsync_modevent(module_t mod, int type, void *data) 32523b3a8eb9SGleb Smirnoff { 32533b3a8eb9SGleb Smirnoff int error = 0; 32543b3a8eb9SGleb Smirnoff 32553b3a8eb9SGleb Smirnoff switch (type) { 32563b3a8eb9SGleb Smirnoff case MOD_LOAD: 32573b3a8eb9SGleb Smirnoff error = pfsync_init(); 32583b3a8eb9SGleb Smirnoff break; 32593b3a8eb9SGleb Smirnoff case MOD_UNLOAD: 32603b3a8eb9SGleb Smirnoff pfsync_uninit(); 32613b3a8eb9SGleb Smirnoff break; 32623b3a8eb9SGleb Smirnoff default: 32633b3a8eb9SGleb Smirnoff error = EINVAL; 32643b3a8eb9SGleb Smirnoff break; 32653b3a8eb9SGleb Smirnoff } 32663b3a8eb9SGleb Smirnoff 32673b3a8eb9SGleb Smirnoff return (error); 32683b3a8eb9SGleb Smirnoff } 32693b3a8eb9SGleb Smirnoff 32703b3a8eb9SGleb Smirnoff static moduledata_t pfsync_mod = { 327142a58907SGleb Smirnoff pfsyncname, 32723b3a8eb9SGleb Smirnoff pfsync_modevent, 32739823d527SKevin Lo 0 32743b3a8eb9SGleb Smirnoff }; 32753b3a8eb9SGleb Smirnoff 32763b3a8eb9SGleb Smirnoff #define PFSYNC_MODVER 1 32773b3a8eb9SGleb Smirnoff 327866c00e9eSBjoern A. Zeeb /* Stay on FIREWALL as we depend on pf being initialized and on inetdomain. */ 327966c00e9eSBjoern A. Zeeb DECLARE_MODULE(pfsync, pfsync_mod, SI_SUB_PROTO_FIREWALL, SI_ORDER_ANY); 32803b3a8eb9SGleb Smirnoff MODULE_VERSION(pfsync, PFSYNC_MODVER); 32813b3a8eb9SGleb Smirnoff MODULE_DEPEND(pfsync, pf, PF_MODVER, PF_MODVER, PF_MODVER); 3282