diff --git a/sbin/ipfw/Makefile b/sbin/ipfw/Makefile index bd0b38bd001..b25f38ca2e8 100644 --- a/sbin/ipfw/Makefile +++ b/sbin/ipfw/Makefile @@ -1,7 +1,7 @@ # $FreeBSD$ PROG= ipfw -SRCS= ipfw2.c dummynet.c ipv6.c main.c nat.c altq.c context.c +SRCS= ipfw2.c dummynet.c ipv6.c main.c nat.c altq.c WARNS?= 2 DPADD= ${LIBUTIL} LDADD= -lutil diff --git a/sbin/ipfw/context.c b/sbin/ipfw/context.c deleted file mode 100644 index f121b2eb176..00000000000 --- a/sbin/ipfw/context.c +++ /dev/null @@ -1,148 +0,0 @@ -/* - * Copyright (c) 2013 Ermal Lu‡i - * - * Redistribution and use in source forms, with and without modification, - * are permitted provided that this entire comment appears intact. - * - * Redistribution in binary form may occur without any restrictions. - * Obviously, it would be nice if you gave credit where credit is due - * but requiring it would be too onerous. - * - * This software is provided ``AS IS'' without any warranties of any kind. - * - * $FreeBSD$ - */ - -#include -#include - -#include -#include - -#include -#include - -#include "ipfw2.h" - -#include -#include -#include -#include -#include -#include -#include - -extern int ipfw_socket; - -int -ipfw_context_handler(int ac, char **av) -{ - ip_fw3_opheader *op3; - int error = 0; - uint32_t action = 0; - socklen_t len, nlen; - char *ifname; - - av++; - ac--; - NEED1("bad arguments, for usage summary ``ipfw''"); - - if (!strncmp(*av, "list", strlen(*av))) { - action = IP_FW_CTX_GET; - av++; - ac--; - if (ac > 0) - errx(EX_DATAERR, "list: does not take any extra arguments."); - - } else { - co.ctx = atoi(*av); - - av++; - ac--; - NEED1("bad arguments, for usage summary ``ipfw''"); - - if (!strncmp(*av, "create", strlen(*av))) - action = IP_FW_CTX_ADD; - else if (!strncmp(*av, "destroy", strlen(*av))) - action = IP_FW_CTX_DEL; - else { - if (!strncmp(*av, "madd", strlen(*av))) - action = IP_FW_CTX_ADDMEMBER; - else if (!strncmp(*av, "mdel", strlen(*av))) - action = IP_FW_CTX_DELMEMBER; - else - errx(EX_DATAERR, "Wrong parameters passed"); - - av++; - ac--; - NEED1("bad arguments, for usage summary ``ipfw''"); - - ifname = *av; - } - - ac--; - if (ac > 0) - errx(EX_DATAERR, "context handling: Too many arguments passed"); - - } - - if (co.test_only) - return (0); - - if (ipfw_socket < 0) - ipfw_socket = socket(AF_INET, SOCK_RAW, IPPROTO_RAW); - if (ipfw_socket < 0) - err(EX_UNAVAILABLE, "socket"); - - switch (action) { - case IP_FW_CTX_ADD: - case IP_FW_CTX_DEL: - case IP_FW_CTX_SET: - len = sizeof(ip_fw3_opheader); - op3 = alloca(len); - /* Zero reserved fields */ - memset(op3, 0, sizeof(ip_fw3_opheader)); - op3->opcode = action; - op3->ctxid = co.ctx; - error = setsockopt(ipfw_socket, IPPROTO_IP, IP_FW3, op3, len); - break; - case IP_FW_CTX_ADDMEMBER: - case IP_FW_CTX_DELMEMBER: - len = sizeof(ip_fw3_opheader) + strlen(ifname) + 1; - op3 = alloca(len); - /* Zero reserved fields */ - memset(op3, 0, sizeof(ip_fw3_opheader)); - memcpy((op3 + 1), ifname, strlen(ifname)); - op3->opcode = action; - op3->ctxid = co.ctx; - error = setsockopt(ipfw_socket, IPPROTO_IP, IP_FW3, op3, len); - break; - case IP_FW_CTX_GET: - len = sizeof(ip_fw3_opheader) + 1000; - nlen = len; - do { - if (nlen > len) { - len = nlen; - } - op3 = alloca(len); - /* Zero reserved fields */ - memset(op3, 0, sizeof(ip_fw3_opheader)); - op3->opcode = action; - op3->ctxid = co.ctx; - nlen = len; - error = getsockopt(ipfw_socket, IPPROTO_IP, IP_FW3, op3, &nlen); - } while (nlen > len && !error); - - if (!error) { - if (nlen == 0) - printf("There are no contextes defined\n"); - else - printf("Currently defined contextes and their members:\n%s\n", (char *)op3); - } else - err(EX_UNAVAILABLE, "Error returned: %s\n", strerror(error)); - - break; - } - - return (error); -} diff --git a/sbin/ipfw/ipfw2.c b/sbin/ipfw/ipfw2.c index 8b834e2a22b..577d6444de1 100644 --- a/sbin/ipfw/ipfw2.c +++ b/sbin/ipfw/ipfw2.c @@ -54,7 +54,7 @@ #include #include -struct cmdline_opts co = { 0 }; /* global options */ +struct cmdline_opts co; /* global options */ int resvd_set_number = RESVD_SET; @@ -420,7 +420,6 @@ safe_realloc(void *ptr, size_t size) int do_cmd(int optname, void *optval, uintptr_t optlen) { - ip_fw3_opheader op3; int i; if (co.test_only) @@ -431,15 +430,6 @@ do_cmd(int optname, void *optval, uintptr_t optlen) if (ipfw_socket < 0) err(EX_UNAVAILABLE, "socket"); - if (optname != IP_FW3 && optname != IP_DUMMYNET3 && optname != -IP_DUMMYNET3) { - memset(&op3, 0, sizeof op3); - op3.ctxid = co.ctx; - op3.opcode = IP_FW_CTX_SET; - i = setsockopt(ipfw_socket, IPPROTO_IP, IP_FW3, &op3, sizeof(op3)); - if (i) - errx(EX_OSERR, "setsockopt: choosing context"); - } - if (optname == IP_FW_GET || optname == IP_DUMMYNET_GET || optname == IP_FW_ADD || optname == IP_FW3 || optname == IP_FW_NAT_GET_CONFIG || @@ -485,7 +475,6 @@ do_setcmd3(int optname, void *optval, socklen_t optlen) memset(op3, 0, sizeof(ip_fw3_opheader)); memcpy(op3 + 1, optval, optlen); op3->opcode = optname; - op3->ctxid = co.ctx; return setsockopt(ipfw_socket, IPPROTO_IP, IP_FW3, op3, len); } @@ -4339,7 +4328,6 @@ table_list(uint16_t num, int need_header) a = (uint32_t *)(op3 + 1); *a = num; op3->opcode = IP_FW_TABLE_XGETSIZE; - op3->ctxid = co.ctx; if (do_cmd(IP_FW3, op3, (uintptr_t)&l) < 0) err(EX_OSERR, "getsockopt(IP_FW_TABLE_XGETSIZE)"); diff --git a/sbin/ipfw/ipfw2.h b/sbin/ipfw/ipfw2.h index 65006f3646e..d592930338f 100644 --- a/sbin/ipfw/ipfw2.h +++ b/sbin/ipfw/ipfw2.h @@ -54,7 +54,6 @@ struct cmdline_opts { int use_set; /* work with specified set number */ /* 0 means all sets, otherwise apply to set use_set - 1 */ - u_int ctx; }; extern struct cmdline_opts co; @@ -278,9 +277,6 @@ void dummynet_list(int ac, char *av[], int show_counters); void dummynet_flush(void); int ipfw_delete_pipe(int pipe_or_queue, int n); -/* Contextes */ -int ipfw_context_handler(int, char **); - /* ipv6.c */ void print_unreach6_code(uint16_t code); void print_ip6(struct _ipfw_insn_ip6 *cmd, char const *s); diff --git a/sbin/ipfw/main.c b/sbin/ipfw/main.c index ab75a1bbef9..82a299bbd58 100644 --- a/sbin/ipfw/main.c +++ b/sbin/ipfw/main.c @@ -262,7 +262,7 @@ ipfw_main(int oldac, char **oldav) save_av = av; optind = optreset = 1; /* restart getopt() */ - while ((ch = getopt(ac, av, "abcdefhinNp:qs:STtvx:")) != -1) + while ((ch = getopt(ac, av, "abcdefhinNp:qs:STtv")) != -1) switch (ch) { case 'a': do_acct = 1; @@ -335,12 +335,6 @@ ipfw_main(int oldac, char **oldav) co.verbose = 1; break; - case 'x': - co.ctx = atoi(optarg); - if (co.ctx == 0) - errx(EX_USAGE, "Context 0 is invalid"); - break; - default: free(save_av); return 1; @@ -368,9 +362,7 @@ ipfw_main(int oldac, char **oldav) co.do_nat = 0; co.do_pipe = 0; co.use_set = 0; - if (!strncmp(*av, "zone", strlen(*av))) - return (ipfw_context_handler(ac, av)); - else if (!strncmp(*av, "nat", strlen(*av))) + if (!strncmp(*av, "nat", strlen(*av))) co.do_nat = 1; else if (!strncmp(*av, "pipe", strlen(*av))) co.do_pipe = 1; @@ -397,9 +389,6 @@ ipfw_main(int oldac, char **oldav) } NEED1("missing command"); - if (!co.ctx && !co.do_pipe) - err(11, "Context is mandatory"); - /* * For pipes, queues and nats we normally say 'nat|pipe NN config' * but the code is easier to parse as 'nat|pipe config NN' @@ -469,7 +458,7 @@ ipfw_readfile(int ac, char *av[]) FILE *f = NULL; pid_t preproc = 0; - while ((c = getopt(ac, av, "cfNnp:qSx:")) != -1) { + while ((c = getopt(ac, av, "cfNnp:qS")) != -1) { switch(c) { case 'c': co.do_compact = 1; @@ -520,12 +509,6 @@ ipfw_readfile(int ac, char *av[]) co.show_sets = 1; break; - case 'x': - co.ctx = atoi(optarg); - if (co.ctx == 0) - errx(EX_USAGE, "Context 0 is invalid"); - break; - default: errx(EX_USAGE, "bad arguments, for usage" " summary ``ipfw''"); diff --git a/sys/netinet/ip_fw.h b/sys/netinet/ip_fw.h index f32fe052dab..de713120ea9 100644 --- a/sys/netinet/ip_fw.h +++ b/sys/netinet/ip_fw.h @@ -65,8 +65,7 @@ /* IP_FW3 header/opcodes */ typedef struct _ip_fw3_opheader { uint16_t opcode; /* Operation opcode */ - uint16_t ctxid; - uint16_t reserved[2]; /* Align to 64-bit boundary */ + uint16_t reserved[3]; /* Align to 64-bit boundary */ } ip_fw3_opheader; @@ -77,12 +76,6 @@ typedef struct _ip_fw3_opheader { #define IP_FW_TABLE_XLIST 89 /* list table contents */ #define IP_FW_TABLE_XLISTENTRY 90 /* list one table entry contents */ #define IP_FW_TABLE_XZEROENTRY 91 /* zero one table entry stats */ -#define IP_FW_CTX_GET 92 -#define IP_FW_CTX_ADD 93 -#define IP_FW_CTX_DEL 94 -#define IP_FW_CTX_SET 95 -#define IP_FW_CTX_ADDMEMBER 96 -#define IP_FW_CTX_DELMEMBER 97 /* * The kernel representation of ipfw rules is made of a list of diff --git a/sys/netpfil/ipfw/ip_fw2.c b/sys/netpfil/ipfw/ip_fw2.c index d395480cf39..128afad3ad6 100644 --- a/sys/netpfil/ipfw/ip_fw2.c +++ b/sys/netpfil/ipfw/ip_fw2.c @@ -139,7 +139,8 @@ VNET_DEFINE(int, fw_verbose); VNET_DEFINE(u_int64_t, norule_counter); VNET_DEFINE(int, verbose_limit); -VNET_DEFINE(struct ip_fw_contextes, ip_fw_contexts); +/* layer3_chain contains the list of rules for layer 3 */ +VNET_DEFINE(struct ip_fw_chain, layer3_chain); VNET_DEFINE(int, ipfw_nat_ready) = 0; @@ -180,6 +181,9 @@ SYSCTL_INT(_net_inet_ip_fw, OID_AUTO, default_to_accept, CTLFLAG_RDTUN, "Make the default rule accept all packets."); TUNABLE_INT("net.inet.ip.fw.default_to_accept", &default_to_accept); TUNABLE_INT("net.inet.ip.fw.tables_max", (int *)&default_fw_tables); +SYSCTL_VNET_INT(_net_inet_ip_fw, OID_AUTO, static_count, + CTLFLAG_RD, &VNET_NAME(layer3_chain.n_rules), 0, + "Number of static rules"); #ifdef INET6 SYSCTL_DECL(_net_inet6_ip6); @@ -899,9 +903,6 @@ ipfw_chk(struct ip_fw_args *args) */ struct ifnet *oif = args->oif; - if (V_ip_fw_contexts.chain[oif->if_ispare[0]] == NULL) - return (IP_FW_PASS); - int f_pos = 0; /* index of current rule in the array */ int retval = 0; @@ -952,13 +953,7 @@ ipfw_chk(struct ip_fw_args *args) */ int dyn_dir = MATCH_UNKNOWN; ipfw_dyn_rule *q = NULL; - - /* XXX: WARNING - The chain is accessed unlocked here. - * There is a potential race here with context handling. - * The chain pointer will get destroyed and a NULL - * pointer dereference can happen! - */ - struct ip_fw_chain *chain = V_ip_fw_contexts.chain[oif->if_ispare[0]]; + struct ip_fw_chain *chain = &V_layer3_chain; /* * We store in ulp a pointer to the upper layer protocol header. @@ -2417,7 +2412,7 @@ do { \ set_match(args, f_pos, chain); /* Check if this is 'global' nat rule */ if (cmd->arg1 == 0) { - retval = ipfw_nat_ptr(args, NULL, m, chain); + retval = ipfw_nat_ptr(args, NULL, m); l = 0; done = 1; break; @@ -2436,7 +2431,7 @@ do { \ if (cmd->arg1 != IP_FW_TABLEARG) ((ipfw_insn_nat *)cmd)->nat = t; } - retval = ipfw_nat_ptr(args, t, m, chain); + retval = ipfw_nat_ptr(args, t, m); } l = 0; /* exit inner loop */ done = 1; /* exit outer loop */ @@ -2543,9 +2538,7 @@ sysctl_ipfw_table_num(SYSCTL_HANDLER_ARGS) if ((error != 0) || (req->newptr == NULL)) return (error); - for (int i = 1; i < IP_FW_MAXCTX; i++) - error += ipfw_resize_tables(V_ip_fw_contexts.chain[i], ntables); - return (error); + return (ipfw_resize_tables(&V_layer3_chain, ntables)); } #endif /* @@ -2623,6 +2616,11 @@ ipfw_destroy(void) static int vnet_ipfw_init(const void *unused) { + int error; + struct ip_fw *rule = NULL; + struct ip_fw_chain *chain; + + chain = &V_layer3_chain; /* First set up some values that are compile time options */ V_autoinc_step = 100; /* bounded to 1..1000 in add_rule() */ @@ -2633,16 +2631,39 @@ vnet_ipfw_init(const void *unused) #ifdef IPFIREWALL_VERBOSE_LIMIT V_verbose_limit = IPFIREWALL_VERBOSE_LIMIT; #endif +#ifdef IPFIREWALL_NAT + LIST_INIT(&chain->nat); +#endif - for (int i = 0; i < IP_FW_MAXCTX; i++) - V_ip_fw_contexts.chain[i] = NULL; + /* insert the default rule and create the initial map */ + chain->n_rules = 1; + chain->static_len = sizeof(struct ip_fw); + chain->map = malloc(sizeof(struct ip_fw *), M_IPFW, M_WAITOK | M_ZERO); + if (chain->map) + rule = malloc(chain->static_len, M_IPFW, M_WAITOK | M_ZERO); - IPFW_CTX_LOCK_INIT(); + /* Set initial number of tables */ + V_fw_tables_max = default_fw_tables; + error = ipfw_init_tables(chain); + if (error) { + printf("ipfw2: setting up tables failed\n"); + free(chain->map, M_IPFW); + free(rule, M_IPFW); + return (ENOSPC); + } - V_ip_fw_contexts.ifnet_arrival = EVENTHANDLER_REGISTER(ifnet_arrival_event, - ipfw_attach_ifnet_event, NULL, EVENTHANDLER_PRI_ANY); + /* fill and insert the default rule */ + rule->act_ofs = 0; + rule->rulenum = IPFW_DEFAULT_RULE; + rule->cmd_len = 1; + rule->set = RESVD_SET; + rule->cmd[0].len = 1; + rule->cmd[0].opcode = default_to_accept ? O_ACCEPT : O_DENY; + chain->rules = chain->default_rule = chain->map[0] = rule; + chain->id = rule->id = 1; - ipfw_dyn_init(); + IPFW_LOCK_INIT(chain); + ipfw_dyn_init(chain); /* First set up some values that are compile time options */ V_ipfw_vnet_ready = 1; /* Open for business */ @@ -2661,55 +2682,8 @@ vnet_ipfw_init(const void *unused) * is checked on each packet because there are no pfil hooks. */ V_ip_fw_ctl_ptr = ipfw_ctl; - return ipfw_attach_hooks(1); -} - -int -ipfw_context_init(int index) -{ - struct ip_fw_chain *chain; - struct ip_fw *rule = NULL; - - if (index > IP_FW_MAXCTX) - return (-1); - - TAILQ_INIT(&V_ip_fw_contexts.iflist[index]); - - chain = V_ip_fw_contexts.chain[index]; - - IPFW_LOCK_INIT(chain); - -#ifdef IPFIREWALL_NAT - LIST_INIT(&chain->nat); -#endif - /* insert the default rule and create the initial map */ - chain->n_rules = 1; - chain->static_len = sizeof(struct ip_fw); - chain->map = malloc(sizeof(struct ip_fw *), M_IPFW, M_WAITOK | M_ZERO); - if (chain->map) - rule = malloc(chain->static_len, M_IPFW, M_WAITOK | M_ZERO); - - /* Set initial number of tables */ - V_fw_tables_max = default_fw_tables; - ipfw_init_tables(chain); - - /* fill and insert the default rule */ - rule->act_ofs = 0; - rule->rulenum = IPFW_DEFAULT_RULE; - rule->cmd_len = 1; - rule->set = RESVD_SET; - rule->cmd[0].len = 1; - rule->cmd[0].opcode = default_to_accept ? O_ACCEPT : O_DENY; - chain->rules = chain->default_rule = chain->map[0] = rule; - chain->id = rule->id = 1; - - /* - * This can potentially be done on first dynamic rule - * being added to chain. - */ - resize_dynamic_table(chain, V_curr_dyn_buckets); - - return (0); + error = ipfw_attach_hooks(1); + return (error); } /* @@ -2718,9 +2692,11 @@ ipfw_context_init(int index) static int vnet_ipfw_uninit(const void *unused) { + struct ip_fw *reap, *rule; + struct ip_fw_chain *chain = &V_layer3_chain; + int i; V_ipfw_vnet_ready = 0; /* tell new callers to go away */ - /* * disconnect from ipv4, ipv6, layer2 and sockopt. * Then grab, release and grab again the WLOCK so we make @@ -2728,51 +2704,14 @@ vnet_ipfw_uninit(const void *unused) */ (void)ipfw_attach_hooks(0 /* detach */); V_ip_fw_ctl_ptr = NULL; - - ipfw_dyn_uninit(0); /* run the callout_drain */ - - IPFW_CTX_WLOCK(); - EVENTHANDLER_DEREGISTER(ifnet_arrival_event, V_ip_fw_contexts.ifnet_arrival); - for (int i = 0; i < IP_FW_MAXCTX; i++) { - ipfw_context_uninit(i); - } - IPFW_CTX_WUNLOCK(); - IPFW_CTX_LOCK_DESTROY(); - - ipfw_dyn_uninit(1); /* free the remaining parts */ - - return (0); -} - -int -ipfw_context_uninit(int index) -{ - struct ip_fw_chain *chain; - struct ip_fw_ctx_iflist *ifl; - struct ip_fw *reap, *rule; - struct ifnet *ifp; - int i; - - if (index > IP_FW_MAXCTX) - return (-1); - - chain = V_ip_fw_contexts.chain[index]; - if (chain == NULL) - return (0); - - while (!TAILQ_EMPTY(&V_ip_fw_contexts.iflist[index])) { - ifl = TAILQ_FIRST(&V_ip_fw_contexts.iflist[index]); - TAILQ_REMOVE(&V_ip_fw_contexts.iflist[index], ifl, entry); - ifp = ifunit(ifl->ifname); - if (ifp != NULL) - ifp->if_ispare[0] = 0; - free(ifl, M_IPFW); - } - IPFW_UH_WLOCK(chain); IPFW_UH_WUNLOCK(chain); IPFW_UH_WLOCK(chain); + IPFW_WLOCK(chain); + ipfw_dyn_uninit(0); /* run the callout_drain */ + IPFW_WUNLOCK(chain); + ipfw_destroy_tables(chain); reap = NULL; IPFW_WLOCK(chain); @@ -2788,10 +2727,8 @@ ipfw_context_uninit(int index) if (reap != NULL) ipfw_reap_rules(reap); IPFW_LOCK_DESTROY(chain); - - free(chain, M_IPFW); - - return (0); + ipfw_dyn_uninit(1); /* free the remaining parts */ + return 0; } /* diff --git a/sys/netpfil/ipfw/ip_fw_dynamic.c b/sys/netpfil/ipfw/ip_fw_dynamic.c index 1772a697267..b0456d37f98 100644 --- a/sys/netpfil/ipfw/ip_fw_dynamic.c +++ b/sys/netpfil/ipfw/ip_fw_dynamic.c @@ -121,9 +121,11 @@ struct ipfw_dyn_bucket { */ static VNET_DEFINE(struct ipfw_dyn_bucket *, ipfw_dyn_v); static VNET_DEFINE(u_int32_t, dyn_buckets_max); +static VNET_DEFINE(u_int32_t, curr_dyn_buckets); static VNET_DEFINE(struct callout, ipfw_timeout); #define V_ipfw_dyn_v VNET(ipfw_dyn_v) #define V_dyn_buckets_max VNET(dyn_buckets_max) +#define V_curr_dyn_buckets VNET(curr_dyn_buckets) #define V_ipfw_timeout VNET(ipfw_timeout) static VNET_DEFINE(uma_zone_t, ipfw_dyn_rule_zone); @@ -179,8 +181,6 @@ static VNET_DEFINE(u_int32_t, dyn_max); /* max # of dynamic rules */ static int last_log; /* Log ratelimiting */ -VNET_DEFINE(u_int32_t, curr_dyn_buckets); - static void ipfw_dyn_tick(void *vnetx); static void check_dyn_rules(struct ip_fw_chain *, struct ip_fw *, int, int, int); @@ -470,7 +470,7 @@ ipfw_dyn_unlock(ipfw_dyn_rule *q) IPFW_BUCK_UNLOCK(q->bucket); } -int +static int resize_dynamic_table(struct ip_fw_chain *chain, int nbuckets) { int i, k, nbuckets_old; @@ -970,6 +970,7 @@ ipfw_dyn_send_ka(struct mbuf **mtailp, ipfw_dyn_rule *q) static void ipfw_dyn_tick(void * vnetx) { + struct ip_fw_chain *chain; int check_ka = 0; #ifdef VIMAGE struct vnet *vp = vnetx; @@ -977,6 +978,7 @@ ipfw_dyn_tick(void * vnetx) CURVNET_SET(vp); + chain = &V_layer3_chain; /* Run keepalive checks every keepalive_period iff ka is enabled */ if ((V_dyn_keepalive_last + V_dyn_keepalive_period <= time_uptime) && @@ -985,12 +987,7 @@ ipfw_dyn_tick(void * vnetx) check_ka = 1; } - IPFW_CTX_RLOCK(); - for (int i = 1; i < IP_FW_MAXCTX; i++) { - if (V_ip_fw_contexts.chain[i] != NULL) - check_dyn_rules(V_ip_fw_contexts.chain[i], NULL, RESVD_SET, check_ka, 1); - } - IPFW_CTX_RUNLOCK(); + check_dyn_rules(chain, NULL, RESVD_SET, check_ka, 1); callout_reset_on(&V_ipfw_timeout, hz, ipfw_dyn_tick, vnetx, 0); @@ -1306,7 +1303,7 @@ ipfw_expire_dyn_rules(struct ip_fw_chain *chain, struct ip_fw *rule, int set) } void -ipfw_dyn_init() +ipfw_dyn_init(struct ip_fw_chain *chain) { V_ipfw_dyn_v = NULL; @@ -1335,6 +1332,12 @@ ipfw_dyn_init() uma_zone_set_max(V_ipfw_dyn_rule_zone, V_dyn_max); callout_init(&V_ipfw_timeout, CALLOUT_MPSAFE); + + /* + * This can potentially be done on first dynamic rule + * being added to chain. + */ + resize_dynamic_table(chain, V_curr_dyn_buckets); } void diff --git a/sys/netpfil/ipfw/ip_fw_nat.c b/sys/netpfil/ipfw/ip_fw_nat.c index 5c04a36363b..d4348b5fb35 100644 --- a/sys/netpfil/ipfw/ip_fw_nat.c +++ b/sys/netpfil/ipfw/ip_fw_nat.c @@ -64,33 +64,26 @@ ifaddr_change(void *arg __unused, struct ifnet *ifp) KASSERT(curvnet == ifp->if_vnet, ("curvnet(%p) differs from iface vnet(%p)", curvnet, ifp->if_vnet)); - - IPFW_CTX_RLOCK(); - for (int i = 1; i < IP_FW_MAXCTX; i++) { - chain = V_ip_fw_contexts.chain[i]; - if (chain == NULL) + chain = &V_layer3_chain; + IPFW_WLOCK(chain); + /* Check every nat entry... */ + LIST_FOREACH(ptr, &chain->nat, _next) { + /* ...using nic 'ifp->if_xname' as dynamic alias address. */ + if (strncmp(ptr->if_name, ifp->if_xname, IF_NAMESIZE) != 0) continue; - IPFW_WLOCK(chain); - /* Check every nat entry... */ - LIST_FOREACH(ptr, &chain->nat, _next) { - /* ...using nic 'ifp->if_xname' as dynamic alias address. */ - if (strncmp(ptr->if_name, ifp->if_xname, IF_NAMESIZE) != 0) + if_addr_rlock(ifp); + TAILQ_FOREACH(ifa, &ifp->if_addrhead, ifa_link) { + if (ifa->ifa_addr == NULL) continue; - if_addr_rlock(ifp); - TAILQ_FOREACH(ifa, &ifp->if_addrhead, ifa_link) { - if (ifa->ifa_addr == NULL) - continue; - if (ifa->ifa_addr->sa_family != AF_INET) - continue; - ptr->ip = ((struct sockaddr_in *) - (ifa->ifa_addr))->sin_addr; - LibAliasSetAddress(ptr->lib, ptr->ip); - } - if_addr_runlock(ifp); + if (ifa->ifa_addr->sa_family != AF_INET) + continue; + ptr->ip = ((struct sockaddr_in *) + (ifa->ifa_addr))->sin_addr; + LibAliasSetAddress(ptr->lib, ptr->ip); } - IPFW_WUNLOCK(chain); + if_addr_runlock(ifp); } - IPFW_CTX_RUNLOCK(); + IPFW_WUNLOCK(chain); } /* @@ -213,18 +206,18 @@ add_redir_spool_cfg(char *buf, struct cfg_nat *ptr) /* * ipfw_nat - perform mbuf header translation. * - * Note *chain has to be locked while calling ipfw_nat() in + * Note V_layer3_chain has to be locked while calling ipfw_nat() in * 'global' operation mode (t == NULL). * */ static int -ipfw_nat(struct ip_fw_args *args, struct cfg_nat *t, struct mbuf *m, - struct ip_fw_chain *chain) +ipfw_nat(struct ip_fw_args *args, struct cfg_nat *t, struct mbuf *m) { struct mbuf *mcl; struct ip *ip; /* XXX - libalias duct tape */ int ldt, retval, found; + struct ip_fw_chain *chain; char *c; ldt = 0; @@ -283,6 +276,7 @@ ipfw_nat(struct ip_fw_args *args, struct cfg_nat *t, struct mbuf *m, } found = 0; + chain = &V_layer3_chain; IPFW_RLOCK_ASSERT(chain); /* Check every nat entry... */ LIST_FOREACH(t, &chain->nat, _next) { @@ -397,10 +391,11 @@ lookup_nat(struct nat_list *l, int nat_id) } static int -ipfw_nat_cfg(struct sockopt *sopt, struct ip_fw_chain *chain) +ipfw_nat_cfg(struct sockopt *sopt) { struct cfg_nat *cfg, *ptr; char *buf; + struct ip_fw_chain *chain = &V_layer3_chain; size_t len; int gencnt, error = 0; @@ -473,9 +468,10 @@ out: } static int -ipfw_nat_del(struct sockopt *sopt, struct ip_fw_chain *chain) +ipfw_nat_del(struct sockopt *sopt) { struct cfg_nat *ptr; + struct ip_fw_chain *chain = &V_layer3_chain; int i; sooptcopyin(sopt, &i, sizeof i, sizeof i); @@ -496,8 +492,9 @@ ipfw_nat_del(struct sockopt *sopt, struct ip_fw_chain *chain) } static int -ipfw_nat_get_cfg(struct sockopt *sopt, struct ip_fw_chain *chain) +ipfw_nat_get_cfg(struct sockopt *sopt) { + struct ip_fw_chain *chain = &V_layer3_chain; struct cfg_nat *n; struct cfg_redir *r; struct cfg_spool *s; @@ -555,11 +552,14 @@ retry: } static int -ipfw_nat_get_log(struct sockopt *sopt, struct ip_fw_chain *chain) +ipfw_nat_get_log(struct sockopt *sopt) { uint8_t *data; struct cfg_nat *ptr; int i, size; + struct ip_fw_chain *chain; + + chain = &V_layer3_chain; IPFW_RLOCK(chain); /* one pass to count, one to copy the data */ @@ -604,22 +604,17 @@ vnet_ipfw_nat_uninit(const void *arg __unused) struct cfg_nat *ptr, *ptr_temp; struct ip_fw_chain *chain; - IPFW_CTX_RLOCK(); - for (int i = 1; i < IP_FW_MAXCTX; i++) { - chain = V_ip_fw_contexts.chain[i]; - IPFW_WLOCK(chain); - LIST_FOREACH_SAFE(ptr, &chain->nat, _next, ptr_temp) { - LIST_REMOVE(ptr, _next); - del_redir_spool_cfg(ptr, &ptr->redir_chain); - LibAliasUninit(ptr->lib); - free(ptr, M_IPFW); - } - flush_nat_ptrs(chain, -1 /* flush all */); - V_ipfw_nat_ready = 0; - IPFW_WUNLOCK(chain); + chain = &V_layer3_chain; + IPFW_WLOCK(chain); + LIST_FOREACH_SAFE(ptr, &chain->nat, _next, ptr_temp) { + LIST_REMOVE(ptr, _next); + del_redir_spool_cfg(ptr, &ptr->redir_chain); + LibAliasUninit(ptr->lib); + free(ptr, M_IPFW); } - IPFW_CTX_RUNLOCK(); - + flush_nat_ptrs(chain, -1 /* flush all */); + V_ipfw_nat_ready = 0; + IPFW_WUNLOCK(chain); return (0); } diff --git a/sys/netpfil/ipfw/ip_fw_private.h b/sys/netpfil/ipfw/ip_fw_private.h index 2e679f36915..a8d7eea4edf 100644 --- a/sys/netpfil/ipfw/ip_fw_private.h +++ b/sys/netpfil/ipfw/ip_fw_private.h @@ -170,9 +170,6 @@ enum { /* result for matching dynamic rules */ MATCH_UNKNOWN, }; -VNET_DECLARE(u_int32_t, curr_dyn_buckets); -#define V_curr_dyn_buckets VNET(curr_dyn_buckets) - /* * The lock for dynamic rules is only used once outside the file, * and only to release the result of lookup_dyn_rule(). @@ -181,7 +178,6 @@ VNET_DECLARE(u_int32_t, curr_dyn_buckets); struct ip_fw_chain; void ipfw_expire_dyn_rules(struct ip_fw_chain *, struct ip_fw *, int); void ipfw_dyn_unlock(ipfw_dyn_rule *q); -int resize_dynamic_table(struct ip_fw_chain *, int); struct tcphdr; struct mbuf *ipfw_send_pkt(struct mbuf *, struct ipfw_flow_id *, @@ -193,7 +189,7 @@ ipfw_dyn_rule *ipfw_lookup_dyn_rule(struct ipfw_flow_id *pkt, void ipfw_remove_dyn_children(struct ip_fw *rule); void ipfw_get_dynamic(struct ip_fw_chain *chain, char **bp, const char *ep); -void ipfw_dyn_init(void); /* per-vnet initialization */ +void ipfw_dyn_init(struct ip_fw_chain *); /* per-vnet initialization */ void ipfw_dyn_uninit(int); /* per-vnet deinitialization */ int ipfw_dyn_len(void); @@ -204,6 +200,9 @@ VNET_DECLARE(int, fw_one_pass); VNET_DECLARE(int, fw_verbose); #define V_fw_verbose VNET(fw_verbose) +VNET_DECLARE(struct ip_fw_chain, layer3_chain); +#define V_layer3_chain VNET(layer3_chain) + VNET_DECLARE(u_int32_t, set_disable); #define V_set_disable VNET(set_disable) @@ -235,33 +234,6 @@ struct ip_fw_chain { uint32_t gencnt; /* generation count */ }; -struct ip_fw_ctx_iflist { - TAILQ_ENTRY(ip_fw_ctx_iflist) entry; - char ifname[IFNAMSIZ]; -}; - -#define IP_FW_MAXCTX 4096 -struct ip_fw_contextes { - struct ip_fw_chain *chain[IP_FW_MAXCTX]; /* Arrays of contextes */ - TAILQ_HEAD(, ip_fw_ctx_iflist) iflist[IP_FW_MAXCTX]; - struct rwlock rwctx; - eventhandler_tag ifnet_arrival; -}; - -VNET_DECLARE(struct ip_fw_contextes, ip_fw_contexts); -#define V_ip_fw_contexts VNET(ip_fw_contexts) - -#define IPFW_CTX_LOCK_INIT() rw_init(&V_ip_fw_contexts.rwctx, "IPFW context") -#define IPFW_CTX_LOCK_DESTROY() rw_destroy(&V_ip_fw_contexts.rwctx) -#define IPFW_CTX_WLOCK() rw_wlock(&V_ip_fw_contexts.rwctx) -#define IPFW_CTX_WUNLOCK() rw_wunlock(&V_ip_fw_contexts.rwctx) -#define IPFW_CTX_RLOCK() rw_rlock(&V_ip_fw_contexts.rwctx) -#define IPFW_CTX_RUNLOCK() rw_runlock(&V_ip_fw_contexts.rwctx) - -void ipfw_attach_ifnet_event(void *, struct ifnet *); -int ipfw_context_init(int); -int ipfw_context_uninit(int); - struct sockopt; /* used by tcp_var.h */ /* Macro for working with various counters */ @@ -352,9 +324,8 @@ int ipfw_resize_tables(struct ip_fw_chain *ch, unsigned int ntables); extern struct cfg_nat *(*lookup_nat_ptr)(struct nat_list *, int); -typedef int ipfw_nat_t(struct ip_fw_args *, struct cfg_nat *, struct mbuf *, - struct ip_fw_chain *); -typedef int ipfw_nat_cfg_t(struct sockopt *, struct ip_fw_chain *); +typedef int ipfw_nat_t(struct ip_fw_args *, struct cfg_nat *, struct mbuf *); +typedef int ipfw_nat_cfg_t(struct sockopt *); VNET_DECLARE(int, ipfw_nat_ready); #define V_ipfw_nat_ready VNET(ipfw_nat_ready) diff --git a/sys/netpfil/ipfw/ip_fw_sockopt.c b/sys/netpfil/ipfw/ip_fw_sockopt.c index 576bf4f9f9c..64f09a56a2a 100644 --- a/sys/netpfil/ipfw/ip_fw_sockopt.c +++ b/sys/netpfil/ipfw/ip_fw_sockopt.c @@ -943,15 +943,12 @@ ipfw_ctl(struct sockopt *sopt) #define RULE_MAXSIZE (256*sizeof(u_int32_t)) int error; size_t size, len, valsize; - struct ifnet *ifp; struct ip_fw *buf, *rule; - static struct ip_fw_chain *chain; - struct ip_fw_ctx_iflist *tmpifl, *tmpifl2; - ip_fw3_opheader *op3 = NULL; + struct ip_fw_chain *chain; u_int32_t rulenum[2]; uint32_t opt; char xbuf[128]; - char *ifname; + ip_fw3_opheader *op3 = NULL; error = priv_check(sopt->sopt_td, PRIV_NETINET_IPFW); if (error) @@ -968,6 +965,7 @@ ipfw_ctl(struct sockopt *sopt) return (error); } + chain = &V_layer3_chain; error = 0; /* Save original valsize before it is altered via sooptcopyin() */ @@ -982,236 +980,9 @@ ipfw_ctl(struct sockopt *sopt) return (error); op3 = (ip_fw3_opheader *)xbuf; opt = op3->opcode; - - if (op3->ctxid > IP_FW_MAXCTX) - return (EINVAL); - - if (opt != IP_FW_CTX_GET) { - if (opt != IP_FW_CTX_ADD) { - if (op3->ctxid == 0) - return (ENOENT); - } - - chain = V_ip_fw_contexts.chain[op3->ctxid]; - } - } - - /* Verification needed to avoid problems */ - switch (opt) { - case IP_FW_CTX_GET: - case IP_FW_CTX_ADD: - case IP_FW_CTX_DEL: - break; - default: - if (chain == NULL) - return (EINVAL); - /* NOTREACHED */ } switch (opt) { - case IP_FW_CTX_ADD: - IPFW_CTX_WLOCK(); - if (V_ip_fw_contexts.chain[op3->ctxid] != NULL) { - IPFW_CTX_WUNLOCK(); - return (EEXIST); - } - - chain = malloc(sizeof(struct ip_fw_chain), M_IPFW, M_WAITOK | M_ZERO); - TAILQ_INIT(&V_ip_fw_contexts.iflist[op3->ctxid]); - V_ip_fw_contexts.chain[op3->ctxid] = chain; - ipfw_context_init(op3->ctxid); /* XXX: error checking */ - IPFW_CTX_WUNLOCK(); - break; - - case IP_FW_CTX_DEL: - IPFW_CTX_WLOCK(); - if (V_ip_fw_contexts.chain[op3->ctxid] == NULL) { - IPFW_CTX_WUNLOCK(); - return (ENOENT); - } - - ipfw_context_uninit(op3->ctxid); - V_ip_fw_contexts.chain[op3->ctxid] = NULL; - IPFW_CTX_WUNLOCK(); - break; - - case IP_FW_CTX_GET: - { - int i, n, len = 0, want; - char *bufout, *tmpbuf; - - sopt->sopt_valsize = valsize; - - IPFW_CTX_RLOCK(); - for (i = 1; i < IP_FW_MAXCTX; i++) { - if (op3->ctxid > 0 && op3->ctxid != i) - continue; - if (op3->ctxid > 0 && op3->ctxid < i) - break; - - if (V_ip_fw_contexts.chain[i] == NULL) - continue; - - /* Calculate number of bytes for the integer */ - n = i; - while (n > 0) { - n /= 10; - len++; - } - TAILQ_FOREACH(tmpifl, &V_ip_fw_contexts.iflist[i], entry) { - len += strlen(tmpifl->ifname) + 1; - } - len += 3; // newline, :, space - } - IPFW_CTX_RUNLOCK(); - - if (len > sopt->sopt_valsize) { - sopt->sopt_valsize = len; - break; - } - - bufout = malloc(len, M_TEMP, M_WAITOK | M_ZERO); - if (bufout == NULL) - break; - - /* Record our size for later checks */ - want = len; - len = 0; - IPFW_CTX_RLOCK(); - /* Recalculate length to detect if smth changed */ - for (i = 1; i < IP_FW_MAXCTX; i++) { - if (op3->ctxid > 0 && op3->ctxid != i) - continue; - if (op3->ctxid > 0 && op3->ctxid < i) - break; - - if (V_ip_fw_contexts.chain[i] == NULL) - continue; - - /* Calculate number of bytes for the integer */ - n = i; - while (n > 0) { - n /= 10; - len++; - } - TAILQ_FOREACH(tmpifl, &V_ip_fw_contexts.iflist[i], entry) { - len += strlen(tmpifl->ifname) + 1; - } - len += 3; // newline, :, space - } - - if (want >= len) { - tmpbuf = bufout; - for (i = 1; i < IP_FW_MAXCTX; i++) { - if (op3->ctxid > 0 && op3->ctxid != i) - continue; - if (op3->ctxid > 0 && op3->ctxid < i) - break; - - if (V_ip_fw_contexts.chain[i] == NULL) - continue; - - sprintf(tmpbuf, "%d: ", i); - tmpbuf += strlen(tmpbuf); - TAILQ_FOREACH(tmpifl, &V_ip_fw_contexts.iflist[i], entry) { - sprintf(tmpbuf, "%s,", tmpifl->ifname); - tmpbuf += strlen(tmpifl->ifname) + 1; - } - sprintf(tmpbuf, "\n"); - tmpbuf++; - } - } - IPFW_CTX_RUNLOCK(); - - if (want >= len) - error = sooptcopyout(sopt, bufout, len); - else - len = 0; - free(bufout, M_TEMP); - } - break; - - case IP_FW_CTX_SET: - /* XXX: Maybe not use this option at all? */ - IPFW_CTX_RLOCK(); - if (V_ip_fw_contexts.chain[op3->ctxid] == NULL) - error = ENOENT; - else - chain = V_ip_fw_contexts.chain[op3->ctxid]; - IPFW_CTX_RUNLOCK(); - break; - - case IP_FW_CTX_ADDMEMBER: - { - int i; - - ifname = (char *)(op3 + 1); - ifp = ifunit(ifname); - if (ifp == NULL) - return (ENOENT); - - tmpifl = malloc(sizeof(*tmpifl), M_IPFW, M_WAITOK | M_ZERO); - - IPFW_CTX_WLOCK(); - if (V_ip_fw_contexts.chain[op3->ctxid] == NULL) { - IPFW_CTX_WUNLOCK(); - free(tmpifl, M_IPFW); - return (ENOENT); - } - - for (i = 1; i < IP_FW_MAXCTX; i++) { - if (V_ip_fw_contexts.chain[i] == NULL) - continue; - - TAILQ_FOREACH(tmpifl2, &V_ip_fw_contexts.iflist[i], entry) { - if (strlen(tmpifl2->ifname) != strlen(ifname)) - continue; - if (!strcmp(tmpifl2->ifname, ifname)) - goto ctxifacefound; - } - } -ctxifacefound: - if (tmpifl2 != NULL) { - IPFW_CTX_WUNLOCK(); - free(tmpifl, M_IPFW); - return (EEXIST); - } - - strlcpy(tmpifl->ifname, ifname, IFNAMSIZ); - TAILQ_INSERT_HEAD(&V_ip_fw_contexts.iflist[op3->ctxid], tmpifl, entry); - ifp->if_ispare[0] = op3->ctxid; - IPFW_CTX_WUNLOCK(); - } - break; - - case IP_FW_CTX_DELMEMBER: - IPFW_CTX_WLOCK(); - if (V_ip_fw_contexts.chain[op3->ctxid] == NULL) { - IPFW_CTX_WUNLOCK(); - return (ENOENT); - } - - ifname = (char *)(op3 + 1); - TAILQ_FOREACH(tmpifl2, &V_ip_fw_contexts.iflist[op3->ctxid], entry) { - if (strlen(tmpifl2->ifname) != strlen(ifname)) - continue; - if (!strcmp(tmpifl2->ifname, ifname)) - break; - } - if (tmpifl2 == NULL) { - IPFW_CTX_WUNLOCK(); - return (ENOENT); - } - - TAILQ_REMOVE(&V_ip_fw_contexts.iflist[op3->ctxid], tmpifl2, entry); - IPFW_CTX_WUNLOCK(); - free(tmpifl2, M_IPFW); - - ifp = ifunit(ifname); - if (ifp != NULL) - ifp->if_ispare[0] = 0; - break; - case IP_FW_GET: /* * pass up a copy of the current rules. Static rules @@ -1509,7 +1280,7 @@ ctxifacefound: /*--- NAT operations are protected by the IPFW_LOCK ---*/ case IP_FW_NAT_CFG: if (IPFW_NAT_LOADED) - error = ipfw_nat_cfg_ptr(sopt, chain); + error = ipfw_nat_cfg_ptr(sopt); else { printf("IP_FW_NAT_CFG: %s\n", "ipfw_nat not present, please load it"); @@ -1519,7 +1290,7 @@ ctxifacefound: case IP_FW_NAT_DEL: if (IPFW_NAT_LOADED) - error = ipfw_nat_del_ptr(sopt, chain); + error = ipfw_nat_del_ptr(sopt); else { printf("IP_FW_NAT_DEL: %s\n", "ipfw_nat not present, please load it"); @@ -1529,7 +1300,7 @@ ctxifacefound: case IP_FW_NAT_GET_CONFIG: if (IPFW_NAT_LOADED) - error = ipfw_nat_get_cfg_ptr(sopt, chain); + error = ipfw_nat_get_cfg_ptr(sopt); else { printf("IP_FW_NAT_GET_CFG: %s\n", "ipfw_nat not present, please load it"); @@ -1539,7 +1310,7 @@ ctxifacefound: case IP_FW_NAT_GET_LOG: if (IPFW_NAT_LOADED) - error = ipfw_nat_get_log_ptr(sopt, chain); + error = ipfw_nat_get_log_ptr(sopt); else { printf("IP_FW_NAT_GET_LOG: %s\n", "ipfw_nat not present, please load it"); @@ -1556,33 +1327,6 @@ ctxifacefound: #undef RULE_MAXSIZE } -void -ipfw_attach_ifnet_event(void *arg __unused, struct ifnet *ifp) -{ - struct ip_fw_ctx_iflist *tmpifl; - - CURVNET_SET(ifp->if_vnet); - - IPFW_CTX_RLOCK(); - for (int i = 1; i < IP_FW_MAXCTX; i++) { - if (V_ip_fw_contexts.chain[i] == NULL) - continue; - TAILQ_FOREACH(tmpifl, &V_ip_fw_contexts.iflist[i], entry) { - if (strlen(tmpifl->ifname) != strlen(ifp->if_xname)) - continue; - if (!strcmp(tmpifl->ifname, ifp->if_xname)) { - printf("Restoring context for interface %s to %d\n", ifp->if_xname, i); - ifp->if_ispare[0] = i; - goto ifctxdone; - break; - } - } - } -ifctxdone: - IPFW_CTX_RUNLOCK(); - - CURVNET_RESTORE(); -} #define RULE_MAXSIZE (256*sizeof(u_int32_t))