Summer of Code 2005: improve libalias - part 2 of 2
With the second (and last) part of my previous Summer of Code work, we get: -ipfw's in kernel nat -redirect_* and LSNAT support General information about nat syntax and some examples are available in the ipfw (8) man page. The redirect and LSNAT syntax are identical to natd, so please refer to natd (8) man page. To enable in kernel nat in rc.conf, two options were added: o firewall_nat_enable: equivalent to natd_enable o firewall_nat_interface: equivalent to natd_interface Remember to set net.inet.ip.fw.one_pass to 0, if you want the packet to continue being checked by the firewall ruleset after being (de)aliased. NOTA BENE: due to some problems with libalias architecture, in kernel nat won't work with TSO enabled nic, thus you have to disable TSO via ifconfig (ifconfig foo0 -tso). Approved by: glebius (mentor)
This commit is contained in:
parent
139bc87fda
commit
ff2f6fe80f
Notes:
svn2git
2020-12-20 02:59:44 +00:00
svn path=/head/; revision=165648
@ -129,6 +129,14 @@ case ${firewall_type} in
|
|||||||
fi
|
fi
|
||||||
;;
|
;;
|
||||||
esac
|
esac
|
||||||
|
case ${firewall_nat_enable} in
|
||||||
|
[Yy][Ee][Ss])
|
||||||
|
if [ -n "${firewall_nat_interface}" ]; then
|
||||||
|
${fwcmd} nat 123 config if ${firewall_nat_interface} log
|
||||||
|
${fwcmd} add 50 nat 123 ip4 from any to any via ${firewall_nat_interface}
|
||||||
|
fi
|
||||||
|
;;
|
||||||
|
esac
|
||||||
esac
|
esac
|
||||||
|
|
||||||
############
|
############
|
||||||
|
114
sbin/ipfw/ipfw.8
114
sbin/ipfw/ipfw.8
@ -2035,6 +2035,59 @@ diverted to that port.
|
|||||||
If no socket is bound to the destination port, or if the divert module is
|
If no socket is bound to the destination port, or if the divert module is
|
||||||
not loaded, or if the kernel was not compiled with divert socket support,
|
not loaded, or if the kernel was not compiled with divert socket support,
|
||||||
the packets are dropped.
|
the packets are dropped.
|
||||||
|
.Sh NETWORK ADDRESS TRANSLATION (NAT)
|
||||||
|
The nat configuration command is the following:
|
||||||
|
.Bd -ragged -offset indent
|
||||||
|
.Bk -words
|
||||||
|
.Cm nat
|
||||||
|
.Ar nat_number
|
||||||
|
.Cm config
|
||||||
|
.Ar nat-configuration
|
||||||
|
.Ek
|
||||||
|
.Ed
|
||||||
|
.Pp
|
||||||
|
.
|
||||||
|
The following parameters can be configured:
|
||||||
|
.Bl -tag -width indent
|
||||||
|
.It Cm ip Ar ip_address
|
||||||
|
Define an ip address to use for aliasing.
|
||||||
|
.It Cm if Ar nic
|
||||||
|
Use ip addres of NIC for aliasing, dynamically changing
|
||||||
|
it if NIC's ip address change.
|
||||||
|
.It Cm log
|
||||||
|
Enable logging on this nat instance.
|
||||||
|
.It Cm deny_in
|
||||||
|
Deny any incoming connection from outside world.
|
||||||
|
.It Cm same_ports
|
||||||
|
Try to leave the alias port numbers unchanged from
|
||||||
|
the actual local port numbers.
|
||||||
|
.It Cm unreg_only
|
||||||
|
Traffic on the local network not originating from an
|
||||||
|
unregistered address spaces will be ignored.
|
||||||
|
.It Cm reset
|
||||||
|
Reset table of the packet aliasing engine on address change.
|
||||||
|
.It Cm reverse
|
||||||
|
Reverse the way libalias handles aliasing.
|
||||||
|
.It Cm proxy_only
|
||||||
|
Obey transparent proxy rules only, packet aliasing is not performed.
|
||||||
|
.El
|
||||||
|
.Pp
|
||||||
|
To let the packet continue after being (de)aliased, set the sysctl variable
|
||||||
|
.Em net.inet.ip.fw.one_pass
|
||||||
|
to 0.
|
||||||
|
For more information about aliasing modes, refer to
|
||||||
|
.Xr libalias 3
|
||||||
|
.
|
||||||
|
See Section
|
||||||
|
.Sx EXAMPLES
|
||||||
|
for some examples about nat usage.
|
||||||
|
.Sh REDIRECT AND LSNAT SUPPORT IN IPFW
|
||||||
|
Redirect and LSNAT support follow closely the syntax used in
|
||||||
|
.Xr natd 8
|
||||||
|
.
|
||||||
|
See Section
|
||||||
|
.Sx EXAMPLES
|
||||||
|
for some examples on how to do redirect and lsnat.
|
||||||
.Sh SYSCTL VARIABLES
|
.Sh SYSCTL VARIABLES
|
||||||
A set of
|
A set of
|
||||||
.Xr sysctl 8
|
.Xr sysctl 8
|
||||||
@ -2423,6 +2476,55 @@ terminates, and your ruleset will be left active.
|
|||||||
Otherwise, e.g.\& if
|
Otherwise, e.g.\& if
|
||||||
you cannot access your box, the ruleset will be disabled after
|
you cannot access your box, the ruleset will be disabled after
|
||||||
the sleep terminates thus restoring the previous situation.
|
the sleep terminates thus restoring the previous situation.
|
||||||
|
.Ss NAT, REDIRECT AND LSNAT
|
||||||
|
First redirect all the traffic to nat instance 123:
|
||||||
|
.Pp
|
||||||
|
.Dl "ipfw add nat 123 all from any to any"
|
||||||
|
.Pp
|
||||||
|
Then to configure nat instance 123 to alias all the outgoing traffic with ip
|
||||||
|
192.168.0.123, blocking all incoming connections, trying to keep
|
||||||
|
same ports on both sides, clearing aliasing table on address change
|
||||||
|
and keeping a log of traffic/link statistics:
|
||||||
|
.Pp
|
||||||
|
.Dl "ipfw nat 123 config ip 192.168.0.123 log deny_in reset same_ports"
|
||||||
|
.Pp
|
||||||
|
Or to change address of instance 123, aliasing table will be cleared (see
|
||||||
|
reset option):
|
||||||
|
.Pp
|
||||||
|
.Dl "ipfw nat 123 config ip 10.0.0.1"
|
||||||
|
.Pp
|
||||||
|
To see configuration of nat instance 123:
|
||||||
|
.Pp
|
||||||
|
.Dl "ipfw nat 123 show config"
|
||||||
|
.Pp
|
||||||
|
To show logs of all the instances in range 111-999:
|
||||||
|
.Pp
|
||||||
|
.Dl "ipfw nat 111-999 show"
|
||||||
|
.Pp
|
||||||
|
To see configurations of all instances:
|
||||||
|
.Pp
|
||||||
|
.Dl "ipfw nat show config"
|
||||||
|
.Pp
|
||||||
|
Or a redirect rule with mixed modes could looks like:
|
||||||
|
.Pp
|
||||||
|
.Dl "ipfw nat 123 config redirect_addr 10.0.0.1 10.0.0.66"
|
||||||
|
.Dl " redirect_port tcp 192.168.0.1:80 500"
|
||||||
|
.Dl " redirect_proto udp 192.168.1.43 192.168.1.1"
|
||||||
|
.Dl " redirect_addr 192.168.0.10,192.168.0.11"
|
||||||
|
.Dl " 10.0.0.100 # LSNAT"
|
||||||
|
.Dl " redirect_port tcp 192.168.0.1:80,192.168.0.10:22"
|
||||||
|
.Dl " 500 # LSNAT"
|
||||||
|
.Pp
|
||||||
|
or it could be splitted in:
|
||||||
|
.Pp
|
||||||
|
.Dl "ipfw nat 1 config redirect_addr 10.0.0.1 10.0.0.66"
|
||||||
|
.Dl "ipfw nat 2 config redirect_port tcp 192.168.0.1:80 500"
|
||||||
|
.Dl "ipfw nat 3 config redirect_proto udp 192.168.1.43 192.168.1.1"
|
||||||
|
.Dl "ipfw nat 4 config redirect_addr 192.168.0.10,192.168.0.11,192.168.0.12"
|
||||||
|
.Dl " 10.0.0.100"
|
||||||
|
.Dl "ipfw nat 5 config redirect_port tcp"
|
||||||
|
.Dl " 192.168.0.1:80,192.168.0.10:22,192.168.0.20:25 500"
|
||||||
|
.Pp
|
||||||
.Sh SEE ALSO
|
.Sh SEE ALSO
|
||||||
.Xr cpp 1 ,
|
.Xr cpp 1 ,
|
||||||
.Xr m4 1 ,
|
.Xr m4 1 ,
|
||||||
@ -2464,6 +2566,11 @@ API based upon code written by
|
|||||||
.An Daniel Boulet
|
.An Daniel Boulet
|
||||||
for BSDI.
|
for BSDI.
|
||||||
.Pp
|
.Pp
|
||||||
|
.An -nosplit
|
||||||
|
In-kernel NAT support written by
|
||||||
|
.An Paolo Pisati Aq piso@FreeBSD.org
|
||||||
|
as part of a Summer of Code 2005 project.
|
||||||
|
.Pp
|
||||||
Work on
|
Work on
|
||||||
.Xr dummynet 4
|
.Xr dummynet 4
|
||||||
traffic shaper supported by Akamba Corp.
|
traffic shaper supported by Akamba Corp.
|
||||||
@ -2520,3 +2627,10 @@ violations in its implementation.
|
|||||||
Rule syntax is subject to the command line environment and some patterns
|
Rule syntax is subject to the command line environment and some patterns
|
||||||
may need to be escaped with the backslash character
|
may need to be escaped with the backslash character
|
||||||
or quoted appropriately.
|
or quoted appropriately.
|
||||||
|
.Pp
|
||||||
|
Due to the architecture of
|
||||||
|
.Xr libalias 3 ,
|
||||||
|
ipfw nat is not compatible with the tcp segmentation offloading
|
||||||
|
(TSO). Thus, to reliably nat your network traffic, please disable TSO
|
||||||
|
on your NICs using
|
||||||
|
.Xr ifconfig 8 .
|
||||||
|
File diff suppressed because it is too large
Load Diff
@ -410,6 +410,11 @@ __END_DECLS
|
|||||||
#define IP_FW_GET 54 /* get entire firewall rule chain */
|
#define IP_FW_GET 54 /* get entire firewall rule chain */
|
||||||
#define IP_FW_RESETLOG 55 /* reset logging counters */
|
#define IP_FW_RESETLOG 55 /* reset logging counters */
|
||||||
|
|
||||||
|
#define IP_FW_NAT_CFG 56 /* add/config a nat rule */
|
||||||
|
#define IP_FW_NAT_DEL 57 /* delete a nat rule */
|
||||||
|
#define IP_FW_NAT_GET_CONFIG 58 /* get configuration of a nat rule */
|
||||||
|
#define IP_FW_NAT_GET_LOG 59 /* get log of a nat rule */
|
||||||
|
|
||||||
#define IP_DUMMYNET_CONFIGURE 60 /* add/configure a dummynet pipe */
|
#define IP_DUMMYNET_CONFIGURE 60 /* add/configure a dummynet pipe */
|
||||||
#define IP_DUMMYNET_DEL 61 /* delete a dummynet pipe from chain */
|
#define IP_DUMMYNET_DEL 61 /* delete a dummynet pipe from chain */
|
||||||
#define IP_DUMMYNET_FLUSH 62 /* flush dummynet */
|
#define IP_DUMMYNET_FLUSH 62 /* flush dummynet */
|
||||||
|
@ -124,6 +124,7 @@ enum ipfw_opcodes { /* arguments (4 byte each) */
|
|||||||
O_TEE, /* arg1=port number */
|
O_TEE, /* arg1=port number */
|
||||||
O_FORWARD_IP, /* fwd sockaddr */
|
O_FORWARD_IP, /* fwd sockaddr */
|
||||||
O_FORWARD_MAC, /* fwd mac */
|
O_FORWARD_MAC, /* fwd mac */
|
||||||
|
O_NAT, /* nope */
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* More opcodes.
|
* More opcodes.
|
||||||
@ -307,6 +308,64 @@ typedef struct _ipfw_insn_log {
|
|||||||
u_int32_t log_left; /* how many left to log */
|
u_int32_t log_left; /* how many left to log */
|
||||||
} ipfw_insn_log;
|
} ipfw_insn_log;
|
||||||
|
|
||||||
|
/* Server pool support (LSNAT). */
|
||||||
|
struct cfg_spool {
|
||||||
|
LIST_ENTRY(cfg_spool) _next; /* chain of spool instances */
|
||||||
|
struct in_addr addr;
|
||||||
|
u_short port;
|
||||||
|
};
|
||||||
|
|
||||||
|
/* Redirect modes id. */
|
||||||
|
#define REDIR_ADDR 0x01
|
||||||
|
#define REDIR_PORT 0x02
|
||||||
|
#define REDIR_PROTO 0x04
|
||||||
|
|
||||||
|
/* Nat redirect configuration. */
|
||||||
|
struct cfg_redir {
|
||||||
|
LIST_ENTRY(cfg_redir) _next; /* chain of redir instances */
|
||||||
|
u_int16_t mode; /* type of redirect mode */
|
||||||
|
struct in_addr laddr; /* local ip address */
|
||||||
|
struct in_addr paddr; /* public ip address */
|
||||||
|
struct in_addr raddr; /* remote ip address */
|
||||||
|
u_short lport; /* local port */
|
||||||
|
u_short pport; /* public port */
|
||||||
|
u_short rport; /* remote port */
|
||||||
|
u_short pport_cnt; /* number of public ports */
|
||||||
|
u_short rport_cnt; /* number of remote ports */
|
||||||
|
int proto; /* protocol: tcp/udp */
|
||||||
|
struct alias_link **alink;
|
||||||
|
/* num of entry in spool chain */
|
||||||
|
u_int16_t spool_cnt;
|
||||||
|
/* chain of spool instances */
|
||||||
|
LIST_HEAD(spool_chain, cfg_spool) spool_chain;
|
||||||
|
};
|
||||||
|
|
||||||
|
#define NAT_BUF_LEN 1024
|
||||||
|
/* Nat configuration data struct. */
|
||||||
|
struct cfg_nat {
|
||||||
|
/* chain of nat instances */
|
||||||
|
LIST_ENTRY(cfg_nat) _next;
|
||||||
|
int id; /* nat id */
|
||||||
|
struct in_addr ip; /* nat ip address */
|
||||||
|
char if_name[IF_NAMESIZE]; /* interface name */
|
||||||
|
int mode; /* aliasing mode */
|
||||||
|
struct libalias *lib; /* libalias instance */
|
||||||
|
/* number of entry in spool chain */
|
||||||
|
int redir_cnt;
|
||||||
|
/* chain of redir instances */
|
||||||
|
LIST_HEAD(redir_chain, cfg_redir) redir_chain;
|
||||||
|
};
|
||||||
|
|
||||||
|
#define SOF_NAT sizeof(struct cfg_nat)
|
||||||
|
#define SOF_REDIR sizeof(struct cfg_redir)
|
||||||
|
#define SOF_SPOOL sizeof(struct cfg_spool)
|
||||||
|
|
||||||
|
/* Nat command. */
|
||||||
|
typedef struct _ipfw_insn_nat {
|
||||||
|
ipfw_insn o;
|
||||||
|
struct cfg_nat *nat;
|
||||||
|
} ipfw_insn_nat;
|
||||||
|
|
||||||
/* Apply ipv6 mask on ipv6 addr */
|
/* Apply ipv6 mask on ipv6 addr */
|
||||||
#define APPLY_MASK(addr,mask) \
|
#define APPLY_MASK(addr,mask) \
|
||||||
(addr)->__u6_addr.__u6_addr32[0] &= (mask)->__u6_addr.__u6_addr32[0]; \
|
(addr)->__u6_addr.__u6_addr32[0] &= (mask)->__u6_addr.__u6_addr32[0]; \
|
||||||
@ -483,6 +542,7 @@ enum {
|
|||||||
IP_FW_DUMMYNET,
|
IP_FW_DUMMYNET,
|
||||||
IP_FW_NETGRAPH,
|
IP_FW_NETGRAPH,
|
||||||
IP_FW_NGTEE,
|
IP_FW_NGTEE,
|
||||||
|
IP_FW_NAT,
|
||||||
};
|
};
|
||||||
|
|
||||||
/* flags for divert mtag */
|
/* flags for divert mtag */
|
||||||
|
@ -47,6 +47,7 @@
|
|||||||
#include <sys/param.h>
|
#include <sys/param.h>
|
||||||
#include <sys/systm.h>
|
#include <sys/systm.h>
|
||||||
#include <sys/condvar.h>
|
#include <sys/condvar.h>
|
||||||
|
#include <sys/eventhandler.h>
|
||||||
#include <sys/malloc.h>
|
#include <sys/malloc.h>
|
||||||
#include <sys/mbuf.h>
|
#include <sys/mbuf.h>
|
||||||
#include <sys/kernel.h>
|
#include <sys/kernel.h>
|
||||||
@ -84,6 +85,8 @@
|
|||||||
#include <netinet/udp_var.h>
|
#include <netinet/udp_var.h>
|
||||||
#include <netinet/sctp.h>
|
#include <netinet/sctp.h>
|
||||||
|
|
||||||
|
#include <netinet/libalias/alias.h>
|
||||||
|
#include <netinet/libalias/alias_local.h>
|
||||||
#include <netgraph/ng_ipfw.h>
|
#include <netgraph/ng_ipfw.h>
|
||||||
|
|
||||||
#include <altq/if_altq.h>
|
#include <altq/if_altq.h>
|
||||||
@ -138,6 +141,7 @@ struct ip_fw_ugid {
|
|||||||
struct ip_fw_chain {
|
struct ip_fw_chain {
|
||||||
struct ip_fw *rules; /* list of rules */
|
struct ip_fw *rules; /* list of rules */
|
||||||
struct ip_fw *reap; /* list of rules to reap */
|
struct ip_fw *reap; /* list of rules to reap */
|
||||||
|
LIST_HEAD(, cfg_nat) nat; /* list of nat entries */
|
||||||
struct radix_node_head *tables[IPFW_TABLES_MAX];
|
struct radix_node_head *tables[IPFW_TABLES_MAX];
|
||||||
struct rwlock rwmtx;
|
struct rwlock rwmtx;
|
||||||
};
|
};
|
||||||
@ -303,6 +307,7 @@ static struct sysctl_oid *ip6_fw_sysctl_tree;
|
|||||||
#endif /* INET6 */
|
#endif /* INET6 */
|
||||||
#endif /* SYSCTL_NODE */
|
#endif /* SYSCTL_NODE */
|
||||||
|
|
||||||
|
MODULE_DEPEND(ipfw, libalias, 1, 1, 1);
|
||||||
static int fw_deny_unknown_exthdrs = 1;
|
static int fw_deny_unknown_exthdrs = 1;
|
||||||
|
|
||||||
|
|
||||||
@ -861,6 +866,9 @@ ipfw_log(struct ip_fw *f, u_int hlen, struct ip_fw_args *args,
|
|||||||
snprintf(SNPARGS(action2, 0), "Ngtee %d",
|
snprintf(SNPARGS(action2, 0), "Ngtee %d",
|
||||||
cmd->arg1);
|
cmd->arg1);
|
||||||
break;
|
break;
|
||||||
|
case O_NAT:
|
||||||
|
action = "Nat";
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
action = "UNKNOWN";
|
action = "UNKNOWN";
|
||||||
break;
|
break;
|
||||||
@ -2028,6 +2036,178 @@ check_uidgid(ipfw_insn_u32 *insn,
|
|||||||
return match;
|
return match;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static eventhandler_tag ifaddr_event_tag;
|
||||||
|
|
||||||
|
static void
|
||||||
|
ifaddr_change(void *arg __unused, struct ifnet *ifp) {
|
||||||
|
struct cfg_nat *ptr;
|
||||||
|
struct ifaddr *ifa;
|
||||||
|
|
||||||
|
IPFW_WLOCK(&layer3_chain);
|
||||||
|
/* Check every nat entry... */
|
||||||
|
LIST_FOREACH(ptr, &layer3_chain.nat, _next) {
|
||||||
|
/* ...using nic 'ifp->if_xname' as dynamic alias address. */
|
||||||
|
if (strncmp(ptr->if_name, ifp->if_xname, IF_NAMESIZE) == 0) {
|
||||||
|
mtx_lock(&ifp->if_addr_mtx);
|
||||||
|
TAILQ_FOREACH(ifa, &ifp->if_addrlist, ifa_list) {
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
mtx_unlock(&ifp->if_addr_mtx);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
IPFW_WUNLOCK(&layer3_chain);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
flush_nat_ptrs(const int i) {
|
||||||
|
struct ip_fw *rule;
|
||||||
|
|
||||||
|
IPFW_WLOCK_ASSERT(&layer3_chain);
|
||||||
|
for (rule = layer3_chain.rules; rule; rule = rule->next) {
|
||||||
|
ipfw_insn_nat *cmd = (ipfw_insn_nat *)ACTION_PTR(rule);
|
||||||
|
if (cmd->o.opcode != O_NAT)
|
||||||
|
continue;
|
||||||
|
if (cmd->nat != NULL && cmd->nat->id == i)
|
||||||
|
cmd->nat = NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static struct cfg_nat *
|
||||||
|
lookup_nat(const int i) {
|
||||||
|
struct cfg_nat *ptr;
|
||||||
|
|
||||||
|
LIST_FOREACH(ptr, &layer3_chain.nat, _next)
|
||||||
|
if (ptr->id == i)
|
||||||
|
return(ptr);
|
||||||
|
return (NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
#define HOOK_NAT(b, p) do { \
|
||||||
|
IPFW_WLOCK_ASSERT(&layer3_chain); \
|
||||||
|
LIST_INSERT_HEAD(b, p, _next); \
|
||||||
|
} while (0)
|
||||||
|
|
||||||
|
#define UNHOOK_NAT(p) do { \
|
||||||
|
IPFW_WLOCK_ASSERT(&layer3_chain); \
|
||||||
|
LIST_REMOVE(p, _next); \
|
||||||
|
} while (0)
|
||||||
|
|
||||||
|
#define HOOK_REDIR(b, p) do { \
|
||||||
|
LIST_INSERT_HEAD(b, p, _next); \
|
||||||
|
} while (0)
|
||||||
|
|
||||||
|
#define HOOK_SPOOL(b, p) do { \
|
||||||
|
LIST_INSERT_HEAD(b, p, _next); \
|
||||||
|
} while (0)
|
||||||
|
|
||||||
|
static void
|
||||||
|
del_redir_spool_cfg(struct cfg_nat *n, struct redir_chain *head) {
|
||||||
|
struct cfg_redir *r, *tmp_r;
|
||||||
|
struct cfg_spool *s, *tmp_s;
|
||||||
|
int i, num;
|
||||||
|
|
||||||
|
LIST_FOREACH_SAFE(r, head, _next, tmp_r) {
|
||||||
|
num = 1; /* Number of alias_link to delete. */
|
||||||
|
switch (r->mode) {
|
||||||
|
case REDIR_PORT:
|
||||||
|
num = r->pport_cnt;
|
||||||
|
/* FALLTHROUGH */
|
||||||
|
case REDIR_ADDR:
|
||||||
|
case REDIR_PROTO:
|
||||||
|
/* Delete all libalias redirect entry. */
|
||||||
|
for (i = 0; i < num; i++)
|
||||||
|
LibAliasRedirectDelete(n->lib, r->alink[i]);
|
||||||
|
/* Del spool cfg if any. */
|
||||||
|
LIST_FOREACH_SAFE(s, &r->spool_chain, _next, tmp_s) {
|
||||||
|
LIST_REMOVE(s, _next);
|
||||||
|
free(s, M_IPFW);
|
||||||
|
}
|
||||||
|
free(r->alink, M_IPFW);
|
||||||
|
LIST_REMOVE(r, _next);
|
||||||
|
free(r, M_IPFW);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
printf("unknown redirect mode: %u\n", r->mode);
|
||||||
|
/* XXX - panic?!?!? */
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
add_redir_spool_cfg(char *buf, struct cfg_nat *ptr) {
|
||||||
|
struct cfg_redir *r, *ser_r;
|
||||||
|
struct cfg_spool *s, *ser_s;
|
||||||
|
int cnt, off, i;
|
||||||
|
char *panic_err;
|
||||||
|
|
||||||
|
for (cnt = 0, off = 0; cnt < ptr->redir_cnt; cnt++) {
|
||||||
|
ser_r = (struct cfg_redir *)&buf[off];
|
||||||
|
r = malloc(SOF_REDIR, M_IPFW, M_WAITOK | M_ZERO);
|
||||||
|
memcpy(r, ser_r, SOF_REDIR);
|
||||||
|
LIST_INIT(&r->spool_chain);
|
||||||
|
off += SOF_REDIR;
|
||||||
|
r->alink = malloc(sizeof(struct alias_link *) * r->pport_cnt,
|
||||||
|
M_IPFW, M_WAITOK | M_ZERO);
|
||||||
|
switch (r->mode) {
|
||||||
|
case REDIR_ADDR:
|
||||||
|
r->alink[0] = LibAliasRedirectAddr(ptr->lib, r->laddr,
|
||||||
|
r->paddr);
|
||||||
|
break;
|
||||||
|
case REDIR_PORT:
|
||||||
|
for (i = 0 ; i < r->pport_cnt; i++) {
|
||||||
|
/* If remotePort is all ports, set it to 0. */
|
||||||
|
u_short remotePortCopy = r->rport + i;
|
||||||
|
if (r->rport_cnt == 1 && r->rport == 0)
|
||||||
|
remotePortCopy = 0;
|
||||||
|
r->alink[i] = LibAliasRedirectPort(ptr->lib,
|
||||||
|
r->laddr, htons(r->lport + i), r->raddr,
|
||||||
|
htons(remotePortCopy), r->paddr,
|
||||||
|
htons(r->pport + i), r->proto);
|
||||||
|
if (r->alink[i] == NULL) {
|
||||||
|
r->alink[0] = NULL;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case REDIR_PROTO:
|
||||||
|
r->alink[0] = LibAliasRedirectProto(ptr->lib ,r->laddr,
|
||||||
|
r->raddr, r->paddr, r->proto);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
printf("unknown redirect mode: %u\n", r->mode);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (r->alink[0] == NULL) {
|
||||||
|
panic_err = "LibAliasRedirect* returned NULL";
|
||||||
|
goto bad;
|
||||||
|
} else /* LSNAT handling. */
|
||||||
|
for (i = 0; i < r->spool_cnt; i++) {
|
||||||
|
ser_s = (struct cfg_spool *)&buf[off];
|
||||||
|
s = malloc(SOF_REDIR, M_IPFW,
|
||||||
|
M_WAITOK | M_ZERO);
|
||||||
|
memcpy(s, ser_s, SOF_SPOOL);
|
||||||
|
LibAliasAddServer(ptr->lib, r->alink[0],
|
||||||
|
s->addr, htons(s->port));
|
||||||
|
off += SOF_SPOOL;
|
||||||
|
/* Hook spool entry. */
|
||||||
|
HOOK_SPOOL(&r->spool_chain, s);
|
||||||
|
}
|
||||||
|
/* And finally hook this redir entry. */
|
||||||
|
HOOK_REDIR(&ptr->redir_chain, r);
|
||||||
|
}
|
||||||
|
return (1);
|
||||||
|
bad:
|
||||||
|
/* something really bad happened: panic! */
|
||||||
|
panic("%s\n", panic_err);
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* The main check routine for the firewall.
|
* The main check routine for the firewall.
|
||||||
*
|
*
|
||||||
@ -3257,6 +3437,177 @@ do { \
|
|||||||
IP_FW_NETGRAPH : IP_FW_NGTEE;
|
IP_FW_NETGRAPH : IP_FW_NGTEE;
|
||||||
goto done;
|
goto done;
|
||||||
|
|
||||||
|
case O_NAT: {
|
||||||
|
struct cfg_nat *t;
|
||||||
|
struct mbuf *mcl;
|
||||||
|
/* XXX - libalias duct tape */
|
||||||
|
int ldt;
|
||||||
|
char *c;
|
||||||
|
|
||||||
|
ldt = 0;
|
||||||
|
args->rule = f; /* Report matching rule. */
|
||||||
|
retval = 0;
|
||||||
|
t = ((ipfw_insn_nat *)cmd)->nat;
|
||||||
|
if (t == NULL) {
|
||||||
|
t = lookup_nat(cmd->arg1);
|
||||||
|
if (t == NULL) {
|
||||||
|
retval = IP_FW_DENY;
|
||||||
|
goto done;
|
||||||
|
} else
|
||||||
|
((ipfw_insn_nat *)cmd)->nat =
|
||||||
|
t;
|
||||||
|
}
|
||||||
|
if ((mcl = m_megapullup(m, m->m_pkthdr.len)) ==
|
||||||
|
NULL)
|
||||||
|
goto badnat;
|
||||||
|
ip = mtod(mcl, struct ip *);
|
||||||
|
if (args->eh == NULL) {
|
||||||
|
ip->ip_len = htons(ip->ip_len);
|
||||||
|
ip->ip_off = htons(ip->ip_off);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* XXX - Libalias checksum offload 'duct tape':
|
||||||
|
*
|
||||||
|
* locally generated packets have only
|
||||||
|
* pseudo-header checksum calculated
|
||||||
|
* and libalias will screw it[1], so
|
||||||
|
* mark them for later fix. Moreover
|
||||||
|
* there are cases when libalias
|
||||||
|
* modify tcp packet data[2], mark it
|
||||||
|
* for later fix too.
|
||||||
|
*
|
||||||
|
* [1] libalias was never meant to run
|
||||||
|
* in kernel, so it doesn't have any
|
||||||
|
* knowledge about checksum
|
||||||
|
* offloading, and it expects a packet
|
||||||
|
* with a full internet
|
||||||
|
* checksum. Unfortunately, packets
|
||||||
|
* generated locally will have just the
|
||||||
|
* pseudo header calculated, and when
|
||||||
|
* libalias tries to adjust the
|
||||||
|
* checksum it will actually screw it.
|
||||||
|
*
|
||||||
|
* [2] when libalias modify tcp's data
|
||||||
|
* content, full TCP checksum has to
|
||||||
|
* be recomputed: the problem is that
|
||||||
|
* libalias doesn't have any idea
|
||||||
|
* about checksum offloading To
|
||||||
|
* workaround this, we do not do
|
||||||
|
* checksumming in LibAlias, but only
|
||||||
|
* mark the packets in th_x2 field. If
|
||||||
|
* we receive a marked packet, we
|
||||||
|
* calculate correct checksum for it
|
||||||
|
* aware of offloading. Why such a
|
||||||
|
* terrible hack instead of
|
||||||
|
* recalculating checksum for each
|
||||||
|
* packet? Because the previous
|
||||||
|
* checksum was not checked!
|
||||||
|
* Recalculating checksums for EVERY
|
||||||
|
* packet will hide ALL transmission
|
||||||
|
* errors. Yes, marked packets still
|
||||||
|
* suffer from this problem. But,
|
||||||
|
* sigh, natd(8) has this problem,
|
||||||
|
* too.
|
||||||
|
*
|
||||||
|
* TODO: -make libalias mbuf aware (so
|
||||||
|
* it can handle delayed checksum and tso)
|
||||||
|
*/
|
||||||
|
|
||||||
|
if (mcl->m_pkthdr.rcvif == NULL &&
|
||||||
|
mcl->m_pkthdr.csum_flags &
|
||||||
|
CSUM_DELAY_DATA)
|
||||||
|
ldt = 1;
|
||||||
|
|
||||||
|
c = mtod(mcl, char *);
|
||||||
|
if (oif == NULL)
|
||||||
|
retval = LibAliasIn(t->lib, c,
|
||||||
|
MCLBYTES);
|
||||||
|
else
|
||||||
|
retval = LibAliasOut(t->lib, c,
|
||||||
|
MCLBYTES);
|
||||||
|
if (retval != PKT_ALIAS_OK) {
|
||||||
|
/* XXX - should i add some logging? */
|
||||||
|
m_free(mcl);
|
||||||
|
badnat:
|
||||||
|
args->m = NULL;
|
||||||
|
retval = IP_FW_DENY;
|
||||||
|
goto done;
|
||||||
|
}
|
||||||
|
mcl->m_pkthdr.len = mcl->m_len =
|
||||||
|
ntohs(ip->ip_len);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* XXX - libalias checksum offload
|
||||||
|
* 'duct tape' (see above)
|
||||||
|
*/
|
||||||
|
|
||||||
|
if ((ip->ip_off & htons(IP_OFFMASK)) == 0 &&
|
||||||
|
ip->ip_p == IPPROTO_TCP) {
|
||||||
|
struct tcphdr *th;
|
||||||
|
|
||||||
|
th = (struct tcphdr *)(ip + 1);
|
||||||
|
if (th->th_x2)
|
||||||
|
ldt = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ldt) {
|
||||||
|
struct tcphdr *th;
|
||||||
|
struct udphdr *uh;
|
||||||
|
u_short cksum;
|
||||||
|
|
||||||
|
ip->ip_len = ntohs(ip->ip_len);
|
||||||
|
cksum = in_pseudo(
|
||||||
|
ip->ip_src.s_addr,
|
||||||
|
ip->ip_dst.s_addr,
|
||||||
|
htons(ip->ip_p + ip->ip_len -
|
||||||
|
(ip->ip_hl << 2))
|
||||||
|
);
|
||||||
|
|
||||||
|
switch (ip->ip_p) {
|
||||||
|
case IPPROTO_TCP:
|
||||||
|
th = (struct tcphdr *)(ip + 1);
|
||||||
|
/*
|
||||||
|
* Maybe it was set in
|
||||||
|
* libalias...
|
||||||
|
*/
|
||||||
|
th->th_x2 = 0;
|
||||||
|
th->th_sum = cksum;
|
||||||
|
mcl->m_pkthdr.csum_data =
|
||||||
|
offsetof(struct tcphdr,
|
||||||
|
th_sum);
|
||||||
|
break;
|
||||||
|
case IPPROTO_UDP:
|
||||||
|
uh = (struct udphdr *)(ip + 1);
|
||||||
|
uh->uh_sum = cksum;
|
||||||
|
mcl->m_pkthdr.csum_data =
|
||||||
|
offsetof(struct udphdr,
|
||||||
|
uh_sum);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
/*
|
||||||
|
* No hw checksum offloading: do it
|
||||||
|
* by ourself.
|
||||||
|
*/
|
||||||
|
if ((mcl->m_pkthdr.csum_flags &
|
||||||
|
CSUM_DELAY_DATA) == 0) {
|
||||||
|
in_delayed_cksum(mcl);
|
||||||
|
mcl->m_pkthdr.csum_flags &=
|
||||||
|
~CSUM_DELAY_DATA;
|
||||||
|
}
|
||||||
|
ip->ip_len = htons(ip->ip_len);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (args->eh == NULL) {
|
||||||
|
ip->ip_len = ntohs(ip->ip_len);
|
||||||
|
ip->ip_off = ntohs(ip->ip_off);
|
||||||
|
}
|
||||||
|
|
||||||
|
args->m = mcl;
|
||||||
|
retval = IP_FW_NAT;
|
||||||
|
goto done;
|
||||||
|
}
|
||||||
|
|
||||||
default:
|
default:
|
||||||
panic("-- unknown opcode %d\n", cmd->opcode);
|
panic("-- unknown opcode %d\n", cmd->opcode);
|
||||||
} /* end of switch() on opcodes */
|
} /* end of switch() on opcodes */
|
||||||
@ -3826,6 +4177,10 @@ check_ipfw_struct(struct ip_fw *rule, int size)
|
|||||||
return EINVAL;
|
return EINVAL;
|
||||||
else
|
else
|
||||||
goto check_size;
|
goto check_size;
|
||||||
|
case O_NAT:
|
||||||
|
if (cmdlen != F_INSN_SIZE(ipfw_insn_nat))
|
||||||
|
goto bad_size;
|
||||||
|
goto check_action;
|
||||||
case O_FORWARD_MAC: /* XXX not implemented yet */
|
case O_FORWARD_MAC: /* XXX not implemented yet */
|
||||||
case O_CHECK_STATE:
|
case O_CHECK_STATE:
|
||||||
case O_COUNT:
|
case O_COUNT:
|
||||||
@ -4201,6 +4556,185 @@ ipfw_ctl(struct sockopt *sopt)
|
|||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case IP_FW_NAT_CFG:
|
||||||
|
{
|
||||||
|
struct cfg_nat *ptr, *ser_n;
|
||||||
|
char *buf;
|
||||||
|
|
||||||
|
buf = malloc(NAT_BUF_LEN, M_IPFW, M_WAITOK | M_ZERO);
|
||||||
|
error = sooptcopyin(sopt, buf, NAT_BUF_LEN,
|
||||||
|
sizeof(struct cfg_nat));
|
||||||
|
ser_n = (struct cfg_nat *)buf;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Find/create nat rule.
|
||||||
|
*/
|
||||||
|
IPFW_WLOCK(&layer3_chain);
|
||||||
|
ptr = lookup_nat(ser_n->id);
|
||||||
|
if (ptr == NULL) {
|
||||||
|
/* New rule: allocate and init new instance. */
|
||||||
|
ptr = malloc(sizeof(struct cfg_nat),
|
||||||
|
M_IPFW, M_NOWAIT | M_ZERO);
|
||||||
|
if (ptr == NULL) {
|
||||||
|
IPFW_WUNLOCK(&layer3_chain);
|
||||||
|
free(buf, M_IPFW);
|
||||||
|
return (ENOSPC);
|
||||||
|
}
|
||||||
|
ptr->lib = LibAliasInit(NULL);
|
||||||
|
if (ptr->lib == NULL) {
|
||||||
|
IPFW_WUNLOCK(&layer3_chain);
|
||||||
|
free(ptr, M_IPFW);
|
||||||
|
free(buf, M_IPFW);
|
||||||
|
return (EINVAL);
|
||||||
|
}
|
||||||
|
LIST_INIT(&ptr->redir_chain);
|
||||||
|
} else {
|
||||||
|
/* Entry already present: temporarly unhook it. */
|
||||||
|
UNHOOK_NAT(ptr);
|
||||||
|
flush_nat_ptrs(ser_n->id);
|
||||||
|
}
|
||||||
|
IPFW_WUNLOCK(&layer3_chain);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Basic nat configuration.
|
||||||
|
*/
|
||||||
|
ptr->id = ser_n->id;
|
||||||
|
/*
|
||||||
|
* XXX - what if this rule doesn't nat any ip and just
|
||||||
|
* redirect?
|
||||||
|
* do we set aliasaddress to 0.0.0.0?
|
||||||
|
*/
|
||||||
|
ptr->ip = ser_n->ip;
|
||||||
|
ptr->redir_cnt = ser_n->redir_cnt;
|
||||||
|
ptr->mode = ser_n->mode;
|
||||||
|
LibAliasSetMode(ptr->lib, ser_n->mode, ser_n->mode);
|
||||||
|
LibAliasSetAddress(ptr->lib, ptr->ip);
|
||||||
|
memcpy(ptr->if_name, ser_n->if_name, IF_NAMESIZE);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Redir and LSNAT configuration.
|
||||||
|
*/
|
||||||
|
/* Delete old cfgs. */
|
||||||
|
del_redir_spool_cfg(ptr, &ptr->redir_chain);
|
||||||
|
/* Add new entries. */
|
||||||
|
add_redir_spool_cfg(&buf[(sizeof(struct cfg_nat))], ptr);
|
||||||
|
free(buf, M_IPFW);
|
||||||
|
IPFW_WLOCK(&layer3_chain);
|
||||||
|
HOOK_NAT(&layer3_chain.nat, ptr);
|
||||||
|
IPFW_WUNLOCK(&layer3_chain);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case IP_FW_NAT_DEL:
|
||||||
|
{
|
||||||
|
struct cfg_nat *ptr;
|
||||||
|
int i;
|
||||||
|
|
||||||
|
error = sooptcopyin(sopt, &i, sizeof i, sizeof i);
|
||||||
|
IPFW_WLOCK(&layer3_chain);
|
||||||
|
ptr = lookup_nat(i);
|
||||||
|
if (ptr == NULL) {
|
||||||
|
error = EINVAL;
|
||||||
|
IPFW_WUNLOCK(&layer3_chain);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
UNHOOK_NAT(ptr);
|
||||||
|
flush_nat_ptrs(i);
|
||||||
|
IPFW_WUNLOCK(&layer3_chain);
|
||||||
|
del_redir_spool_cfg(ptr, &ptr->redir_chain);
|
||||||
|
LibAliasUninit(ptr->lib);
|
||||||
|
free(ptr, M_IPFW);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case IP_FW_NAT_GET_CONFIG:
|
||||||
|
{
|
||||||
|
uint8_t *data;
|
||||||
|
struct cfg_nat *n;
|
||||||
|
struct cfg_redir *r;
|
||||||
|
struct cfg_spool *s;
|
||||||
|
int nat_cnt, off;
|
||||||
|
|
||||||
|
nat_cnt = 0;
|
||||||
|
off = sizeof(nat_cnt);
|
||||||
|
|
||||||
|
data = malloc(NAT_BUF_LEN, M_IPFW, M_WAITOK | M_ZERO);
|
||||||
|
IPFW_RLOCK(&layer3_chain);
|
||||||
|
/* Serialize all the data. */
|
||||||
|
LIST_FOREACH(n, &layer3_chain.nat, _next) {
|
||||||
|
nat_cnt++;
|
||||||
|
if (off + SOF_NAT < NAT_BUF_LEN) {
|
||||||
|
bcopy(n, &data[off], SOF_NAT);
|
||||||
|
off += SOF_NAT;
|
||||||
|
LIST_FOREACH(r, &n->redir_chain, _next) {
|
||||||
|
if (off + SOF_REDIR < NAT_BUF_LEN) {
|
||||||
|
bcopy(r, &data[off],
|
||||||
|
SOF_REDIR);
|
||||||
|
off += SOF_REDIR;
|
||||||
|
LIST_FOREACH(s, &r->spool_chain,
|
||||||
|
_next) {
|
||||||
|
if (off + SOF_SPOOL <
|
||||||
|
NAT_BUF_LEN) {
|
||||||
|
bcopy(s,
|
||||||
|
&data[off],
|
||||||
|
SOF_SPOOL);
|
||||||
|
off +=
|
||||||
|
SOF_SPOOL;
|
||||||
|
} else
|
||||||
|
goto nospace;
|
||||||
|
}
|
||||||
|
} else
|
||||||
|
goto nospace;
|
||||||
|
}
|
||||||
|
} else
|
||||||
|
goto nospace;
|
||||||
|
}
|
||||||
|
bcopy(&nat_cnt, data, sizeof(nat_cnt));
|
||||||
|
IPFW_RUNLOCK(&layer3_chain);
|
||||||
|
error = sooptcopyout(sopt, data, NAT_BUF_LEN);
|
||||||
|
free(data, M_IPFW);
|
||||||
|
break;
|
||||||
|
nospace:
|
||||||
|
IPFW_RUNLOCK(&layer3_chain);
|
||||||
|
printf("serialized data buffer not big enough:"
|
||||||
|
"please increase NAT_BUF_LEN\n");
|
||||||
|
free(data, M_IPFW);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case IP_FW_NAT_GET_LOG:
|
||||||
|
{
|
||||||
|
uint8_t *data;
|
||||||
|
struct cfg_nat *ptr;
|
||||||
|
int i, size, cnt, sof;
|
||||||
|
|
||||||
|
data = NULL;
|
||||||
|
sof = LIBALIAS_BUF_SIZE;
|
||||||
|
cnt = 0;
|
||||||
|
|
||||||
|
IPFW_RLOCK(&layer3_chain);
|
||||||
|
size = i = 0;
|
||||||
|
LIST_FOREACH(ptr, &layer3_chain.nat, _next) {
|
||||||
|
if (ptr->lib->logDesc == NULL)
|
||||||
|
continue;
|
||||||
|
cnt++;
|
||||||
|
size = cnt * (sof + sizeof(int));
|
||||||
|
data = realloc(data, size, M_IPFW, M_NOWAIT | M_ZERO);
|
||||||
|
if (data == NULL) {
|
||||||
|
IPFW_RUNLOCK(&layer3_chain);
|
||||||
|
return (ENOSPC);
|
||||||
|
}
|
||||||
|
bcopy(&ptr->id, &data[i], sizeof(int));
|
||||||
|
i += sizeof(int);
|
||||||
|
bcopy(ptr->lib->logDesc, &data[i], sof);
|
||||||
|
i += sof;
|
||||||
|
}
|
||||||
|
IPFW_RUNLOCK(&layer3_chain);
|
||||||
|
error = sooptcopyout(sopt, data, size);
|
||||||
|
free(data, M_IPFW);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
printf("ipfw: ipfw_ctl invalid option %d\n", sopt->sopt_name);
|
printf("ipfw: ipfw_ctl invalid option %d\n", sopt->sopt_name);
|
||||||
error = EINVAL;
|
error = EINVAL;
|
||||||
@ -4372,8 +4906,10 @@ ipfw_init(void)
|
|||||||
}
|
}
|
||||||
ip_fw_ctl_ptr = ipfw_ctl;
|
ip_fw_ctl_ptr = ipfw_ctl;
|
||||||
ip_fw_chk_ptr = ipfw_chk;
|
ip_fw_chk_ptr = ipfw_chk;
|
||||||
callout_reset(&ipfw_timeout, hz, ipfw_tick, NULL);
|
callout_reset(&ipfw_timeout, hz, ipfw_tick, NULL);
|
||||||
|
LIST_INIT(&layer3_chain.nat);
|
||||||
|
ifaddr_event_tag = EVENTHANDLER_REGISTER(ifaddr_event, ifaddr_change,
|
||||||
|
NULL, EVENTHANDLER_PRI_ANY);
|
||||||
return (0);
|
return (0);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -4381,12 +4917,20 @@ void
|
|||||||
ipfw_destroy(void)
|
ipfw_destroy(void)
|
||||||
{
|
{
|
||||||
struct ip_fw *reap;
|
struct ip_fw *reap;
|
||||||
|
struct cfg_nat *ptr, *ptr_temp;
|
||||||
|
|
||||||
ip_fw_chk_ptr = NULL;
|
ip_fw_chk_ptr = NULL;
|
||||||
ip_fw_ctl_ptr = NULL;
|
ip_fw_ctl_ptr = NULL;
|
||||||
callout_drain(&ipfw_timeout);
|
callout_drain(&ipfw_timeout);
|
||||||
IPFW_WLOCK(&layer3_chain);
|
IPFW_WLOCK(&layer3_chain);
|
||||||
flush_tables(&layer3_chain);
|
flush_tables(&layer3_chain);
|
||||||
|
LIST_FOREACH_SAFE(ptr, &layer3_chain.nat, _next, ptr_temp) {
|
||||||
|
LIST_REMOVE(ptr, _next);
|
||||||
|
del_redir_spool_cfg(ptr, &ptr->redir_chain);
|
||||||
|
LibAliasUninit(ptr->lib);
|
||||||
|
free(ptr, M_IPFW);
|
||||||
|
}
|
||||||
|
EVENTHANDLER_DEREGISTER(ifaddr_event, ifaddr_event_tag);
|
||||||
layer3_chain.reap = NULL;
|
layer3_chain.reap = NULL;
|
||||||
free_chain(&layer3_chain, 1 /* kill default rule */);
|
free_chain(&layer3_chain, 1 /* kill default rule */);
|
||||||
reap = layer3_chain.reap, layer3_chain.reap = NULL;
|
reap = layer3_chain.reap, layer3_chain.reap = NULL;
|
||||||
|
@ -189,6 +189,9 @@ ipfw_check_in(void *arg, struct mbuf **m0, struct ifnet *ifp, int dir,
|
|||||||
if (!NG_IPFW_LOADED)
|
if (!NG_IPFW_LOADED)
|
||||||
goto drop;
|
goto drop;
|
||||||
return ng_ipfw_input_p(m0, NG_IPFW_IN, &args, 0);
|
return ng_ipfw_input_p(m0, NG_IPFW_IN, &args, 0);
|
||||||
|
|
||||||
|
case IP_FW_NAT:
|
||||||
|
goto again; /* continue with packet */
|
||||||
|
|
||||||
default:
|
default:
|
||||||
KASSERT(0, ("%s: unknown retval", __func__));
|
KASSERT(0, ("%s: unknown retval", __func__));
|
||||||
@ -315,6 +318,9 @@ ipfw_check_out(void *arg, struct mbuf **m0, struct ifnet *ifp, int dir,
|
|||||||
goto drop;
|
goto drop;
|
||||||
return ng_ipfw_input_p(m0, NG_IPFW_OUT, &args, 0);
|
return ng_ipfw_input_p(m0, NG_IPFW_OUT, &args, 0);
|
||||||
|
|
||||||
|
case IP_FW_NAT:
|
||||||
|
goto again; /* continue with packet */
|
||||||
|
|
||||||
default:
|
default:
|
||||||
KASSERT(0, ("%s: unknown retval", __func__));
|
KASSERT(0, ("%s: unknown retval", __func__));
|
||||||
}
|
}
|
||||||
|
@ -389,6 +389,8 @@ rip_ctloutput(struct socket *so, struct sockopt *sopt)
|
|||||||
case IP_FW_GET:
|
case IP_FW_GET:
|
||||||
case IP_FW_TABLE_GETSIZE:
|
case IP_FW_TABLE_GETSIZE:
|
||||||
case IP_FW_TABLE_LIST:
|
case IP_FW_TABLE_LIST:
|
||||||
|
case IP_FW_NAT_GET_CONFIG:
|
||||||
|
case IP_FW_NAT_GET_LOG:
|
||||||
/*
|
/*
|
||||||
* XXXRW: Isn't this checked one layer down? Yes, it
|
* XXXRW: Isn't this checked one layer down? Yes, it
|
||||||
* is.
|
* is.
|
||||||
@ -458,6 +460,8 @@ rip_ctloutput(struct socket *so, struct sockopt *sopt)
|
|||||||
case IP_FW_TABLE_ADD:
|
case IP_FW_TABLE_ADD:
|
||||||
case IP_FW_TABLE_DEL:
|
case IP_FW_TABLE_DEL:
|
||||||
case IP_FW_TABLE_FLUSH:
|
case IP_FW_TABLE_FLUSH:
|
||||||
|
case IP_FW_NAT_CFG:
|
||||||
|
case IP_FW_NAT_DEL:
|
||||||
/*
|
/*
|
||||||
* XXXRW: Isn't this checked one layer down?
|
* XXXRW: Isn't this checked one layer down?
|
||||||
*/
|
*/
|
||||||
|
Loading…
Reference in New Issue
Block a user