18aaffd78SIgor Ostapenko /*- 28aaffd78SIgor Ostapenko * SPDX-License-Identifier: BSD-2-Clause 38aaffd78SIgor Ostapenko * 48aaffd78SIgor Ostapenko * Copyright (c) 2024 Igor Ostapenko <pm@igoro.pro> 58aaffd78SIgor Ostapenko * 68aaffd78SIgor Ostapenko * Redistribution and use in source and binary forms, with or without 78aaffd78SIgor Ostapenko * modification, are permitted provided that the following conditions 88aaffd78SIgor Ostapenko * are met: 98aaffd78SIgor Ostapenko * 1. Redistributions of source code must retain the above copyright 108aaffd78SIgor Ostapenko * notice, this list of conditions and the following disclaimer. 118aaffd78SIgor Ostapenko * 2. Redistributions in binary form must reproduce the above copyright 128aaffd78SIgor Ostapenko * notice, this list of conditions and the following disclaimer in the 138aaffd78SIgor Ostapenko * documentation and/or other materials provided with the distribution. 148aaffd78SIgor Ostapenko * 158aaffd78SIgor Ostapenko * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 168aaffd78SIgor Ostapenko * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 178aaffd78SIgor Ostapenko * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 188aaffd78SIgor Ostapenko * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 198aaffd78SIgor Ostapenko * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 208aaffd78SIgor Ostapenko * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 218aaffd78SIgor Ostapenko * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 228aaffd78SIgor Ostapenko * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 238aaffd78SIgor Ostapenko * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 248aaffd78SIgor Ostapenko * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 258aaffd78SIgor Ostapenko * SUCH DAMAGE. 268aaffd78SIgor Ostapenko */ 278aaffd78SIgor Ostapenko 288aaffd78SIgor Ostapenko #include "opt_inet.h" 298aaffd78SIgor Ostapenko #include "opt_inet6.h" 308aaffd78SIgor Ostapenko 318aaffd78SIgor Ostapenko #include <sys/param.h> 328aaffd78SIgor Ostapenko #include <sys/kernel.h> 338aaffd78SIgor Ostapenko #include <sys/mbuf.h> 348aaffd78SIgor Ostapenko #include <sys/module.h> 358aaffd78SIgor Ostapenko #include <sys/socket.h> 368aaffd78SIgor Ostapenko #include <sys/sysctl.h> 378aaffd78SIgor Ostapenko 388aaffd78SIgor Ostapenko #include <net/if.h> 398aaffd78SIgor Ostapenko #include <net/if_var.h> 403f2eb1acSJustin Hibbits #include <net/if_private.h> 418aaffd78SIgor Ostapenko #include <net/vnet.h> 428aaffd78SIgor Ostapenko #include <net/pfil.h> 438aaffd78SIgor Ostapenko 449f146a81SIgor Ostapenko static int validate_rules(const char *); 459f146a81SIgor Ostapenko 468aaffd78SIgor Ostapenko /* 478aaffd78SIgor Ostapenko * Separate sysctl sub-tree 488aaffd78SIgor Ostapenko */ 498aaffd78SIgor Ostapenko 508aaffd78SIgor Ostapenko SYSCTL_NODE(_net, OID_AUTO, dummymbuf, 0, NULL, 518aaffd78SIgor Ostapenko "Dummy mbuf sysctl"); 528aaffd78SIgor Ostapenko 538aaffd78SIgor Ostapenko /* 548aaffd78SIgor Ostapenko * Rules 558aaffd78SIgor Ostapenko */ 568aaffd78SIgor Ostapenko 578aaffd78SIgor Ostapenko static MALLOC_DEFINE(M_DUMMYMBUF_RULES, "dummymbuf_rules", 588aaffd78SIgor Ostapenko "dummymbuf rules string buffer"); 598aaffd78SIgor Ostapenko 608aaffd78SIgor Ostapenko #define RULES_MAXLEN 1024 618aaffd78SIgor Ostapenko VNET_DEFINE_STATIC(char *, dmb_rules) = NULL; 628aaffd78SIgor Ostapenko #define V_dmb_rules VNET(dmb_rules) 638aaffd78SIgor Ostapenko 648aaffd78SIgor Ostapenko VNET_DEFINE_STATIC(struct sx, dmb_rules_lock); 658aaffd78SIgor Ostapenko #define V_dmb_rules_lock VNET(dmb_rules_lock) 668aaffd78SIgor Ostapenko 678aaffd78SIgor Ostapenko #define DMB_RULES_SLOCK() sx_slock(&V_dmb_rules_lock) 688aaffd78SIgor Ostapenko #define DMB_RULES_SUNLOCK() sx_sunlock(&V_dmb_rules_lock) 698aaffd78SIgor Ostapenko #define DMB_RULES_XLOCK() sx_xlock(&V_dmb_rules_lock) 708aaffd78SIgor Ostapenko #define DMB_RULES_XUNLOCK() sx_xunlock(&V_dmb_rules_lock) 719f146a81SIgor Ostapenko #define DMB_RULES_LOCK_ASSERT() sx_assert(&V_dmb_rules_lock, SA_LOCKED) 728aaffd78SIgor Ostapenko 738aaffd78SIgor Ostapenko static int 748aaffd78SIgor Ostapenko dmb_sysctl_handle_rules(SYSCTL_HANDLER_ARGS) 758aaffd78SIgor Ostapenko { 768aaffd78SIgor Ostapenko int error = 0; 778aaffd78SIgor Ostapenko char empty = '\0'; 788aaffd78SIgor Ostapenko char **rulesp = (char **)arg1; 798aaffd78SIgor Ostapenko 808aaffd78SIgor Ostapenko if (req->newptr == NULL) { 8161295e09SMark Johnston /* read only */ 828aaffd78SIgor Ostapenko DMB_RULES_SLOCK(); 838aaffd78SIgor Ostapenko arg1 = *rulesp; 848aaffd78SIgor Ostapenko if (arg1 == NULL) { 858aaffd78SIgor Ostapenko arg1 = ∅ 868aaffd78SIgor Ostapenko arg2 = 0; 878aaffd78SIgor Ostapenko } 888aaffd78SIgor Ostapenko error = sysctl_handle_string(oidp, arg1, arg2, req); 898aaffd78SIgor Ostapenko DMB_RULES_SUNLOCK(); 908aaffd78SIgor Ostapenko } else { 9161295e09SMark Johnston /* read and write */ 928aaffd78SIgor Ostapenko DMB_RULES_XLOCK(); 939f146a81SIgor Ostapenko arg1 = malloc(arg2, M_DUMMYMBUF_RULES, M_WAITOK | M_ZERO); 948aaffd78SIgor Ostapenko error = sysctl_handle_string(oidp, arg1, arg2, req); 959f146a81SIgor Ostapenko if (error == 0 && (error = validate_rules(arg1)) == 0) { 969f146a81SIgor Ostapenko free(*rulesp, M_DUMMYMBUF_RULES); 979f146a81SIgor Ostapenko *rulesp = arg1; 989f146a81SIgor Ostapenko arg1 = NULL; 999f146a81SIgor Ostapenko } 1009f146a81SIgor Ostapenko free(arg1, M_DUMMYMBUF_RULES); 1018aaffd78SIgor Ostapenko DMB_RULES_XUNLOCK(); 1028aaffd78SIgor Ostapenko } 1038aaffd78SIgor Ostapenko 1048aaffd78SIgor Ostapenko return (error); 1058aaffd78SIgor Ostapenko } 1068aaffd78SIgor Ostapenko 1078aaffd78SIgor Ostapenko SYSCTL_PROC(_net_dummymbuf, OID_AUTO, rules, 1088aaffd78SIgor Ostapenko CTLTYPE_STRING | CTLFLAG_MPSAFE | CTLFLAG_RW | CTLFLAG_VNET, 1098aaffd78SIgor Ostapenko &VNET_NAME(dmb_rules), RULES_MAXLEN, dmb_sysctl_handle_rules, "A", 11061295e09SMark Johnston "{inet|inet6|ethernet} {in|out} <ifname> <opname>[ <opargs>]; ...;"); 1118aaffd78SIgor Ostapenko 1128aaffd78SIgor Ostapenko /* 1138aaffd78SIgor Ostapenko * Statistics 1148aaffd78SIgor Ostapenko */ 1158aaffd78SIgor Ostapenko 1168aaffd78SIgor Ostapenko VNET_DEFINE_STATIC(counter_u64_t, dmb_hits); 1178aaffd78SIgor Ostapenko #define V_dmb_hits VNET(dmb_hits) 1188aaffd78SIgor Ostapenko SYSCTL_PROC(_net_dummymbuf, OID_AUTO, hits, 1198aaffd78SIgor Ostapenko CTLTYPE_U64 | CTLFLAG_MPSAFE | CTLFLAG_STATS | CTLFLAG_RW | CTLFLAG_VNET, 1208aaffd78SIgor Ostapenko &VNET_NAME(dmb_hits), 0, sysctl_handle_counter_u64, 1218aaffd78SIgor Ostapenko "QU", "Number of times a rule has been applied"); 1228aaffd78SIgor Ostapenko 1238aaffd78SIgor Ostapenko /* 1248aaffd78SIgor Ostapenko * pfil(9) context 1258aaffd78SIgor Ostapenko */ 1268aaffd78SIgor Ostapenko 127aa72c5baSGleb Smirnoff #ifdef INET 1288aaffd78SIgor Ostapenko VNET_DEFINE_STATIC(pfil_hook_t, dmb_pfil_inet_hook); 1298aaffd78SIgor Ostapenko #define V_dmb_pfil_inet_hook VNET(dmb_pfil_inet_hook) 130aa72c5baSGleb Smirnoff #endif 1318aaffd78SIgor Ostapenko 132aa72c5baSGleb Smirnoff #ifdef INET6 1338aaffd78SIgor Ostapenko VNET_DEFINE_STATIC(pfil_hook_t, dmb_pfil_inet6_hook); 1348aaffd78SIgor Ostapenko #define V_dmb_pfil_inet6_hook VNET(dmb_pfil_inet6_hook) 135aa72c5baSGleb Smirnoff #endif 1368aaffd78SIgor Ostapenko 1378aaffd78SIgor Ostapenko VNET_DEFINE_STATIC(pfil_hook_t, dmb_pfil_ethernet_hook); 1388aaffd78SIgor Ostapenko #define V_dmb_pfil_ethernet_hook VNET(dmb_pfil_ethernet_hook) 1398aaffd78SIgor Ostapenko 1408aaffd78SIgor Ostapenko /* 1418aaffd78SIgor Ostapenko * Logging 1428aaffd78SIgor Ostapenko */ 1438aaffd78SIgor Ostapenko 1449f146a81SIgor Ostapenko #define FEEDBACK_RULE(rule, msg) \ 1459f146a81SIgor Ostapenko printf("dummymbuf: %s: %.*s\n", \ 1469f146a81SIgor Ostapenko (msg), \ 1479f146a81SIgor Ostapenko (rule).syntax_len, (rule).syntax_begin \ 1489f146a81SIgor Ostapenko ) 1499f146a81SIgor Ostapenko 1509f146a81SIgor Ostapenko #define FEEDBACK_PFIL(pfil_type, pfil_flags, ifp, rule, msg) \ 1518aaffd78SIgor Ostapenko printf("dummymbuf: %s %b %s: %s: %.*s\n", \ 1526bd8d855SIgor Ostapenko ((pfil_type) == PFIL_TYPE_IP4 ? "PFIL_TYPE_IP4" : \ 1536bd8d855SIgor Ostapenko (pfil_type) == PFIL_TYPE_IP6 ? "PFIL_TYPE_IP6" : \ 1546bd8d855SIgor Ostapenko (pfil_type) == PFIL_TYPE_ETHERNET ? "PFIL_TYPE_ETHERNET" : \ 1558aaffd78SIgor Ostapenko "PFIL_TYPE_UNKNOWN"), \ 1568aaffd78SIgor Ostapenko (pfil_flags), "\20\21PFIL_IN\22PFIL_OUT", \ 1578aaffd78SIgor Ostapenko (ifp)->if_xname, \ 1588aaffd78SIgor Ostapenko (msg), \ 1598aaffd78SIgor Ostapenko (rule).syntax_len, (rule).syntax_begin \ 1608aaffd78SIgor Ostapenko ) 1618aaffd78SIgor Ostapenko 1628aaffd78SIgor Ostapenko /* 1638aaffd78SIgor Ostapenko * Internals 1648aaffd78SIgor Ostapenko */ 1658aaffd78SIgor Ostapenko 1668aaffd78SIgor Ostapenko struct rule; 1678aaffd78SIgor Ostapenko typedef struct mbuf * (*op_t)(struct mbuf *, struct rule *); 1688aaffd78SIgor Ostapenko struct rule { 1698aaffd78SIgor Ostapenko const char *syntax_begin; 1708aaffd78SIgor Ostapenko int syntax_len; 1718aaffd78SIgor Ostapenko int pfil_type; 1728aaffd78SIgor Ostapenko int pfil_dir; 1738aaffd78SIgor Ostapenko char ifname[IFNAMSIZ]; 1748aaffd78SIgor Ostapenko op_t op; 1758aaffd78SIgor Ostapenko const char *opargs; 1768aaffd78SIgor Ostapenko }; 1778aaffd78SIgor Ostapenko 1788aaffd78SIgor Ostapenko static struct mbuf * 1798aaffd78SIgor Ostapenko dmb_m_pull_head(struct mbuf *m, struct rule *rule) 1808aaffd78SIgor Ostapenko { 1818aaffd78SIgor Ostapenko struct mbuf *n; 1828aaffd78SIgor Ostapenko int count; 1838aaffd78SIgor Ostapenko 1848aaffd78SIgor Ostapenko count = (int)strtol(rule->opargs, NULL, 10); 1858aaffd78SIgor Ostapenko if (count < 0 || count > MCLBYTES) 1868aaffd78SIgor Ostapenko goto bad; 1878aaffd78SIgor Ostapenko 1888aaffd78SIgor Ostapenko if (!(m->m_flags & M_PKTHDR)) 1898aaffd78SIgor Ostapenko goto bad; 1908aaffd78SIgor Ostapenko if (m->m_pkthdr.len <= 0) 1918aaffd78SIgor Ostapenko return (m); 1928aaffd78SIgor Ostapenko if (count > m->m_pkthdr.len) 1938aaffd78SIgor Ostapenko count = m->m_pkthdr.len; 1948aaffd78SIgor Ostapenko 1958aaffd78SIgor Ostapenko if ((n = m_getcl(M_NOWAIT, MT_DATA, M_PKTHDR)) == NULL) 1968aaffd78SIgor Ostapenko goto bad; 1978aaffd78SIgor Ostapenko 1988aaffd78SIgor Ostapenko m_move_pkthdr(n, m); 1998aaffd78SIgor Ostapenko m_copydata(m, 0, count, n->m_ext.ext_buf); 2008aaffd78SIgor Ostapenko n->m_len = count; 2018aaffd78SIgor Ostapenko 2028aaffd78SIgor Ostapenko m_adj(m, count); 2038aaffd78SIgor Ostapenko n->m_next = m; 2048aaffd78SIgor Ostapenko 2058aaffd78SIgor Ostapenko return (n); 2068aaffd78SIgor Ostapenko 2078aaffd78SIgor Ostapenko bad: 2088aaffd78SIgor Ostapenko m_freem(m); 2098aaffd78SIgor Ostapenko return (NULL); 2108aaffd78SIgor Ostapenko } 2118aaffd78SIgor Ostapenko 212*76e00c72SKristof Provost static struct mbuf * 213*76e00c72SKristof Provost dmb_m_enlarge(struct mbuf *m, struct rule *rule) 214*76e00c72SKristof Provost { 215*76e00c72SKristof Provost struct mbuf *n; 216*76e00c72SKristof Provost int size; 217*76e00c72SKristof Provost 218*76e00c72SKristof Provost size = (int)strtol(rule->opargs, NULL, 10); 219*76e00c72SKristof Provost if (size < 0 || size > MJUM16BYTES) 220*76e00c72SKristof Provost goto bad; 221*76e00c72SKristof Provost 222*76e00c72SKristof Provost if (!(m->m_flags & M_PKTHDR)) 223*76e00c72SKristof Provost goto bad; 224*76e00c72SKristof Provost if (m->m_pkthdr.len <= 0) 225*76e00c72SKristof Provost return (m); 226*76e00c72SKristof Provost 227*76e00c72SKristof Provost if ((n = m_get3(size, M_NOWAIT, MT_DATA, M_PKTHDR)) == NULL) 228*76e00c72SKristof Provost goto bad; 229*76e00c72SKristof Provost 230*76e00c72SKristof Provost m_move_pkthdr(n, m); 231*76e00c72SKristof Provost m_copydata(m, 0, m->m_pkthdr.len, n->m_ext.ext_buf); 232*76e00c72SKristof Provost n->m_len = m->m_pkthdr.len; 233*76e00c72SKristof Provost 234*76e00c72SKristof Provost n->m_next = m; 235*76e00c72SKristof Provost 236*76e00c72SKristof Provost return (n); 237*76e00c72SKristof Provost 238*76e00c72SKristof Provost bad: 239*76e00c72SKristof Provost m_freem(m); 240*76e00c72SKristof Provost return (NULL); 241*76e00c72SKristof Provost } 242*76e00c72SKristof Provost 2438aaffd78SIgor Ostapenko static bool 2449f146a81SIgor Ostapenko read_rule(const char **cur, struct rule *rule, bool *eof) 2458aaffd78SIgor Ostapenko { 2466bd8d855SIgor Ostapenko /* {inet|inet6|ethernet} {in|out} <ifname> <opname>[ <opargs>]; */ 2478aaffd78SIgor Ostapenko 2488aaffd78SIgor Ostapenko rule->syntax_begin = NULL; 2498aaffd78SIgor Ostapenko rule->syntax_len = 0; 2508aaffd78SIgor Ostapenko 2518aaffd78SIgor Ostapenko if (*cur == NULL) 2528aaffd78SIgor Ostapenko return (false); 2538aaffd78SIgor Ostapenko 2546bd8d855SIgor Ostapenko /* syntax_begin */ 2558aaffd78SIgor Ostapenko while (**cur == ' ') 2568aaffd78SIgor Ostapenko (*cur)++; 2578aaffd78SIgor Ostapenko rule->syntax_begin = *cur; 258dfcb8de5SIgor Ostapenko rule->syntax_len = strlen(rule->syntax_begin); 2598aaffd78SIgor Ostapenko 2606bd8d855SIgor Ostapenko /* syntax_len */ 2618aaffd78SIgor Ostapenko char *delim = strchr(*cur, ';'); 2628aaffd78SIgor Ostapenko if (delim == NULL) 2638aaffd78SIgor Ostapenko return (false); 2648aaffd78SIgor Ostapenko rule->syntax_len = (int)(delim - *cur + 1); 2658aaffd78SIgor Ostapenko 2666bd8d855SIgor Ostapenko /* pfil_type */ 2678aaffd78SIgor Ostapenko if (strstr(*cur, "inet6") == *cur) { 2688aaffd78SIgor Ostapenko rule->pfil_type = PFIL_TYPE_IP6; 2698aaffd78SIgor Ostapenko *cur += strlen("inet6"); 2708aaffd78SIgor Ostapenko } else if (strstr(*cur, "inet") == *cur) { 2718aaffd78SIgor Ostapenko rule->pfil_type = PFIL_TYPE_IP4; 2728aaffd78SIgor Ostapenko *cur += strlen("inet"); 2738aaffd78SIgor Ostapenko } else if (strstr(*cur, "ethernet")) { 2748aaffd78SIgor Ostapenko rule->pfil_type = PFIL_TYPE_ETHERNET; 2758aaffd78SIgor Ostapenko *cur += strlen("ethernet"); 2768aaffd78SIgor Ostapenko } else { 2778aaffd78SIgor Ostapenko return (false); 2788aaffd78SIgor Ostapenko } 2798aaffd78SIgor Ostapenko while (**cur == ' ') 2808aaffd78SIgor Ostapenko (*cur)++; 2818aaffd78SIgor Ostapenko 2826bd8d855SIgor Ostapenko /* pfil_dir */ 2838aaffd78SIgor Ostapenko if (strstr(*cur, "in") == *cur) { 2848aaffd78SIgor Ostapenko rule->pfil_dir = PFIL_IN; 2858aaffd78SIgor Ostapenko *cur += strlen("in"); 2868aaffd78SIgor Ostapenko } else if (strstr(*cur, "out") == *cur) { 2878aaffd78SIgor Ostapenko rule->pfil_dir = PFIL_OUT; 2888aaffd78SIgor Ostapenko *cur += strlen("out"); 2898aaffd78SIgor Ostapenko } else { 2908aaffd78SIgor Ostapenko return (false); 2918aaffd78SIgor Ostapenko } 2928aaffd78SIgor Ostapenko while (**cur == ' ') 2938aaffd78SIgor Ostapenko (*cur)++; 2948aaffd78SIgor Ostapenko 2956bd8d855SIgor Ostapenko /* ifname */ 2968aaffd78SIgor Ostapenko char *sp = strchr(*cur, ' '); 2978aaffd78SIgor Ostapenko if (sp == NULL || sp > delim) 2988aaffd78SIgor Ostapenko return (false); 2998aaffd78SIgor Ostapenko size_t len = sp - *cur; 3008aaffd78SIgor Ostapenko if (len >= sizeof(rule->ifname)) 3018aaffd78SIgor Ostapenko return (false); 3028aaffd78SIgor Ostapenko strncpy(rule->ifname, *cur, len); 3038aaffd78SIgor Ostapenko rule->ifname[len] = 0; 3048aaffd78SIgor Ostapenko *cur = sp; 3058aaffd78SIgor Ostapenko while (**cur == ' ') 3068aaffd78SIgor Ostapenko (*cur)++; 3078aaffd78SIgor Ostapenko 3086bd8d855SIgor Ostapenko /* opname */ 3098aaffd78SIgor Ostapenko if (strstr(*cur, "pull-head") == *cur) { 3108aaffd78SIgor Ostapenko rule->op = dmb_m_pull_head; 3118aaffd78SIgor Ostapenko *cur += strlen("pull-head"); 312*76e00c72SKristof Provost } else if (strstr(*cur, "enlarge") == *cur) { 313*76e00c72SKristof Provost rule->op = dmb_m_enlarge; 314*76e00c72SKristof Provost *cur += strlen("enlarge"); 3158aaffd78SIgor Ostapenko } else { 3168aaffd78SIgor Ostapenko return (false); 3178aaffd78SIgor Ostapenko } 3188aaffd78SIgor Ostapenko while (**cur == ' ') 3198aaffd78SIgor Ostapenko (*cur)++; 3208aaffd78SIgor Ostapenko 3216bd8d855SIgor Ostapenko /* opargs */ 3228aaffd78SIgor Ostapenko if (*cur > delim) 3238aaffd78SIgor Ostapenko return (false); 3248aaffd78SIgor Ostapenko rule->opargs = *cur; 3258aaffd78SIgor Ostapenko 3266bd8d855SIgor Ostapenko /* the next rule & eof */ 3278aaffd78SIgor Ostapenko *cur = delim + 1; 3289f146a81SIgor Ostapenko while (**cur == ' ') 3299f146a81SIgor Ostapenko (*cur)++; 3309f146a81SIgor Ostapenko *eof = strlen(*cur) == 0; 3318aaffd78SIgor Ostapenko 3328aaffd78SIgor Ostapenko return (true); 3338aaffd78SIgor Ostapenko } 3348aaffd78SIgor Ostapenko 3359f146a81SIgor Ostapenko static int 3369f146a81SIgor Ostapenko validate_rules(const char *rules) 3379f146a81SIgor Ostapenko { 3389f146a81SIgor Ostapenko const char *cursor = rules; 3399f146a81SIgor Ostapenko bool parsed; 3409f146a81SIgor Ostapenko struct rule rule; 3419f146a81SIgor Ostapenko bool eof = false; 3429f146a81SIgor Ostapenko 3439f146a81SIgor Ostapenko DMB_RULES_LOCK_ASSERT(); 3449f146a81SIgor Ostapenko 3459f146a81SIgor Ostapenko while (!eof && (parsed = read_rule(&cursor, &rule, &eof))) { 3469f146a81SIgor Ostapenko /* noop */ 3479f146a81SIgor Ostapenko } 3489f146a81SIgor Ostapenko 3499f146a81SIgor Ostapenko if (!parsed) { 3509f146a81SIgor Ostapenko FEEDBACK_RULE(rule, "rule parsing failed"); 3519f146a81SIgor Ostapenko return (EINVAL); 3529f146a81SIgor Ostapenko } 3539f146a81SIgor Ostapenko 3549f146a81SIgor Ostapenko return (0); 3559f146a81SIgor Ostapenko } 3569f146a81SIgor Ostapenko 3578aaffd78SIgor Ostapenko static pfil_return_t 3588aaffd78SIgor Ostapenko dmb_pfil_mbuf_chk(int pfil_type, struct mbuf **mp, struct ifnet *ifp, 3598aaffd78SIgor Ostapenko int flags, void *ruleset, void *unused) 3608aaffd78SIgor Ostapenko { 3618aaffd78SIgor Ostapenko struct mbuf *m = *mp; 3628aaffd78SIgor Ostapenko const char *cursor; 3638aaffd78SIgor Ostapenko bool parsed; 3648aaffd78SIgor Ostapenko struct rule rule; 3659f146a81SIgor Ostapenko bool eof = false; 3668aaffd78SIgor Ostapenko 3678aaffd78SIgor Ostapenko DMB_RULES_SLOCK(); 3688aaffd78SIgor Ostapenko cursor = V_dmb_rules; 3699f146a81SIgor Ostapenko while (!eof && (parsed = read_rule(&cursor, &rule, &eof))) { 3708aaffd78SIgor Ostapenko if (rule.pfil_type == pfil_type && 3718aaffd78SIgor Ostapenko rule.pfil_dir == (flags & rule.pfil_dir) && 3728aaffd78SIgor Ostapenko strcmp(rule.ifname, ifp->if_xname) == 0) { 3738aaffd78SIgor Ostapenko m = rule.op(m, &rule); 3748aaffd78SIgor Ostapenko if (m == NULL) { 3759f146a81SIgor Ostapenko FEEDBACK_PFIL(pfil_type, flags, ifp, rule, 3768aaffd78SIgor Ostapenko "mbuf operation failed"); 3778aaffd78SIgor Ostapenko break; 3788aaffd78SIgor Ostapenko } 3798aaffd78SIgor Ostapenko counter_u64_add(V_dmb_hits, 1); 3808aaffd78SIgor Ostapenko } 3818aaffd78SIgor Ostapenko } 3828aaffd78SIgor Ostapenko if (!parsed) { 3839f146a81SIgor Ostapenko FEEDBACK_PFIL(pfil_type, flags, ifp, rule, 3849f146a81SIgor Ostapenko "rule parsing failed"); 3858aaffd78SIgor Ostapenko m_freem(m); 3868aaffd78SIgor Ostapenko m = NULL; 3878aaffd78SIgor Ostapenko } 3888aaffd78SIgor Ostapenko DMB_RULES_SUNLOCK(); 3898aaffd78SIgor Ostapenko 3908aaffd78SIgor Ostapenko if (m == NULL) { 3918aaffd78SIgor Ostapenko *mp = NULL; 3928aaffd78SIgor Ostapenko return (PFIL_DROPPED); 3938aaffd78SIgor Ostapenko } 3948aaffd78SIgor Ostapenko if (m != *mp) { 3958aaffd78SIgor Ostapenko *mp = m; 3968aaffd78SIgor Ostapenko return (PFIL_REALLOCED); 3978aaffd78SIgor Ostapenko } 3988aaffd78SIgor Ostapenko 3998aaffd78SIgor Ostapenko return (PFIL_PASS); 4008aaffd78SIgor Ostapenko } 4018aaffd78SIgor Ostapenko 402aa72c5baSGleb Smirnoff #ifdef INET 4038aaffd78SIgor Ostapenko static pfil_return_t 4048aaffd78SIgor Ostapenko dmb_pfil_inet_mbuf_chk(struct mbuf **mp, struct ifnet *ifp, int flags, 4058aaffd78SIgor Ostapenko void *ruleset, struct inpcb *inp) 4068aaffd78SIgor Ostapenko { 4078aaffd78SIgor Ostapenko return (dmb_pfil_mbuf_chk(PFIL_TYPE_IP4, mp, ifp, flags, 4088aaffd78SIgor Ostapenko ruleset, inp)); 4098aaffd78SIgor Ostapenko } 410aa72c5baSGleb Smirnoff #endif 4118aaffd78SIgor Ostapenko 412aa72c5baSGleb Smirnoff #ifdef INET6 4138aaffd78SIgor Ostapenko static pfil_return_t 4148aaffd78SIgor Ostapenko dmb_pfil_inet6_mbuf_chk(struct mbuf **mp, struct ifnet *ifp, int flags, 4158aaffd78SIgor Ostapenko void *ruleset, struct inpcb *inp) 4168aaffd78SIgor Ostapenko { 4178aaffd78SIgor Ostapenko return (dmb_pfil_mbuf_chk(PFIL_TYPE_IP6, mp, ifp, flags, 4188aaffd78SIgor Ostapenko ruleset, inp)); 4198aaffd78SIgor Ostapenko } 420aa72c5baSGleb Smirnoff #endif 4218aaffd78SIgor Ostapenko 4228aaffd78SIgor Ostapenko static pfil_return_t 4238aaffd78SIgor Ostapenko dmb_pfil_ethernet_mbuf_chk(struct mbuf **mp, struct ifnet *ifp, int flags, 4248aaffd78SIgor Ostapenko void *ruleset, struct inpcb *inp) 4258aaffd78SIgor Ostapenko { 4268aaffd78SIgor Ostapenko return (dmb_pfil_mbuf_chk(PFIL_TYPE_ETHERNET, mp, ifp, flags, 4278aaffd78SIgor Ostapenko ruleset, inp)); 4288aaffd78SIgor Ostapenko } 4298aaffd78SIgor Ostapenko 4308aaffd78SIgor Ostapenko static void 4318aaffd78SIgor Ostapenko dmb_pfil_init(void) 4328aaffd78SIgor Ostapenko { 4338aaffd78SIgor Ostapenko struct pfil_hook_args pha = { 4348aaffd78SIgor Ostapenko .pa_version = PFIL_VERSION, 4358aaffd78SIgor Ostapenko .pa_modname = "dummymbuf", 4368aaffd78SIgor Ostapenko .pa_flags = PFIL_IN | PFIL_OUT, 4378aaffd78SIgor Ostapenko }; 4388aaffd78SIgor Ostapenko 4398aaffd78SIgor Ostapenko #ifdef INET 4408aaffd78SIgor Ostapenko pha.pa_type = PFIL_TYPE_IP4; 4418aaffd78SIgor Ostapenko pha.pa_mbuf_chk = dmb_pfil_inet_mbuf_chk; 4428aaffd78SIgor Ostapenko pha.pa_rulname = "inet"; 4438aaffd78SIgor Ostapenko V_dmb_pfil_inet_hook = pfil_add_hook(&pha); 4448aaffd78SIgor Ostapenko #endif 4458aaffd78SIgor Ostapenko 4468aaffd78SIgor Ostapenko #ifdef INET6 4478aaffd78SIgor Ostapenko pha.pa_type = PFIL_TYPE_IP6; 4488aaffd78SIgor Ostapenko pha.pa_mbuf_chk = dmb_pfil_inet6_mbuf_chk; 4498aaffd78SIgor Ostapenko pha.pa_rulname = "inet6"; 4508aaffd78SIgor Ostapenko V_dmb_pfil_inet6_hook = pfil_add_hook(&pha); 4518aaffd78SIgor Ostapenko #endif 4528aaffd78SIgor Ostapenko 4538aaffd78SIgor Ostapenko pha.pa_type = PFIL_TYPE_ETHERNET; 4548aaffd78SIgor Ostapenko pha.pa_mbuf_chk = dmb_pfil_ethernet_mbuf_chk; 4558aaffd78SIgor Ostapenko pha.pa_rulname = "ethernet"; 4568aaffd78SIgor Ostapenko V_dmb_pfil_ethernet_hook = pfil_add_hook(&pha); 4578aaffd78SIgor Ostapenko } 4588aaffd78SIgor Ostapenko 4598aaffd78SIgor Ostapenko static void 4608aaffd78SIgor Ostapenko dmb_pfil_uninit(void) 4618aaffd78SIgor Ostapenko { 4628aaffd78SIgor Ostapenko #ifdef INET 4638aaffd78SIgor Ostapenko pfil_remove_hook(V_dmb_pfil_inet_hook); 4648aaffd78SIgor Ostapenko #endif 4658aaffd78SIgor Ostapenko 4668aaffd78SIgor Ostapenko #ifdef INET6 4678aaffd78SIgor Ostapenko pfil_remove_hook(V_dmb_pfil_inet6_hook); 4688aaffd78SIgor Ostapenko #endif 4698aaffd78SIgor Ostapenko 4708aaffd78SIgor Ostapenko pfil_remove_hook(V_dmb_pfil_ethernet_hook); 4718aaffd78SIgor Ostapenko } 4728aaffd78SIgor Ostapenko 4738aaffd78SIgor Ostapenko static void 4748be18c2dSSHENGYI HONG vnet_dmb_init(const void *unused __unused) 4758aaffd78SIgor Ostapenko { 4768aaffd78SIgor Ostapenko sx_init(&V_dmb_rules_lock, "dummymbuf rules"); 4778aaffd78SIgor Ostapenko V_dmb_hits = counter_u64_alloc(M_WAITOK); 4788aaffd78SIgor Ostapenko dmb_pfil_init(); 4798aaffd78SIgor Ostapenko } 4808aaffd78SIgor Ostapenko VNET_SYSINIT(vnet_dmb_init, SI_SUB_PROTO_PFIL, SI_ORDER_ANY, 4818aaffd78SIgor Ostapenko vnet_dmb_init, NULL); 4828aaffd78SIgor Ostapenko 4838aaffd78SIgor Ostapenko static void 4848be18c2dSSHENGYI HONG vnet_dmb_uninit(const void *unused __unused) 4858aaffd78SIgor Ostapenko { 4868aaffd78SIgor Ostapenko dmb_pfil_uninit(); 4878aaffd78SIgor Ostapenko counter_u64_free(V_dmb_hits); 4888aaffd78SIgor Ostapenko sx_destroy(&V_dmb_rules_lock); 4898aaffd78SIgor Ostapenko free(V_dmb_rules, M_DUMMYMBUF_RULES); 4908aaffd78SIgor Ostapenko } 4918aaffd78SIgor Ostapenko VNET_SYSUNINIT(vnet_dmb_uninit, SI_SUB_PROTO_PFIL, SI_ORDER_ANY, 4928aaffd78SIgor Ostapenko vnet_dmb_uninit, NULL); 4938aaffd78SIgor Ostapenko 4948aaffd78SIgor Ostapenko static int 4958aaffd78SIgor Ostapenko dmb_modevent(module_t mod __unused, int event, void *arg __unused) 4968aaffd78SIgor Ostapenko { 4978aaffd78SIgor Ostapenko int error = 0; 4988aaffd78SIgor Ostapenko 4998aaffd78SIgor Ostapenko switch (event) { 5008aaffd78SIgor Ostapenko case MOD_LOAD: 5018aaffd78SIgor Ostapenko case MOD_UNLOAD: 5028aaffd78SIgor Ostapenko break; 5038aaffd78SIgor Ostapenko default: 5048aaffd78SIgor Ostapenko error = EOPNOTSUPP; 5058aaffd78SIgor Ostapenko break; 5068aaffd78SIgor Ostapenko } 5078aaffd78SIgor Ostapenko 5088aaffd78SIgor Ostapenko return (error); 5098aaffd78SIgor Ostapenko } 5108aaffd78SIgor Ostapenko 5118aaffd78SIgor Ostapenko static moduledata_t dmb_mod = { 5128aaffd78SIgor Ostapenko "dummymbuf", 5138aaffd78SIgor Ostapenko dmb_modevent, 5148aaffd78SIgor Ostapenko NULL 5158aaffd78SIgor Ostapenko }; 5168aaffd78SIgor Ostapenko 5178aaffd78SIgor Ostapenko DECLARE_MODULE(dummymbuf, dmb_mod, SI_SUB_PROTO_PFIL, SI_ORDER_ANY); 5188aaffd78SIgor Ostapenko MODULE_VERSION(dummymbuf, 1); 519