Revert "tools: apply CP_multi_instance_ipfw.diff"

This reverts commit ddd376bb68.

Conflicts:
	sys/netpfil/ipfw/ip_fw2.c
This commit is contained in:
Ad Schellevis 2014-11-16 12:04:52 +01:00
parent 316b1f8425
commit b62f18765f
11 changed files with 126 additions and 664 deletions

View file

@ -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

View file

@ -1,148 +0,0 @@
/*
* Copyright (c) 2013 Ermal Lui
*
* 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 <sys/types.h>
#include <sys/socket.h>
#include <net/if.h>
#include <net/if_var.h>
#include <netinet/in.h>
#include <netinet/ip_fw.h>
#include "ipfw2.h"
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sysexits.h>
#include <string.h>
#include <errno.h>
#include <err.h>
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);
}

View file

@ -54,7 +54,7 @@
#include <netinet/tcp.h>
#include <arpa/inet.h>
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)");

View file

@ -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);

View file

@ -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''");

View file

@ -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

View file

@ -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;
}
/*

View file

@ -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

View file

@ -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);
}

View file

@ -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)

View file

@ -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))