PERFORCE change 99995 for review
Paolo Pisati
piso at FreeBSD.org
Sun Jun 25 18:39:26 UTC 2006
http://perforce.freebsd.org/chv.cgi?CH=99995
Change 99995 by piso at piso_newluxor on 2006/06/25 18:38:49
Apply my libalias+ipfw patch
Affected files ...
.. //depot/projects/soc2005/libalias/etc/Makefile#2 edit
.. //depot/projects/soc2005/libalias/etc/libalias.conf#1 add
.. //depot/projects/soc2005/libalias/lib/libalias/Makefile#2 edit
.. //depot/projects/soc2005/libalias/lib/libalias/lib-cuseeme/Makefile#1 add
.. //depot/projects/soc2005/libalias/lib/libalias/lib-dummy/Makefile#1 add
.. //depot/projects/soc2005/libalias/lib/libalias/lib-ftp/Makefile#1 add
.. //depot/projects/soc2005/libalias/lib/libalias/lib-irc/Makefile#1 add
.. //depot/projects/soc2005/libalias/lib/libalias/lib-libalias/Makefile#1 add
.. //depot/projects/soc2005/libalias/lib/libalias/lib-nbt/Makefile#1 add
.. //depot/projects/soc2005/libalias/lib/libalias/lib-pptp/Makefile#1 add
.. //depot/projects/soc2005/libalias/lib/libalias/lib-skinny/Makefile#1 add
.. //depot/projects/soc2005/libalias/lib/libalias/lib-smedia/Makefile#1 add
.. //depot/projects/soc2005/libalias/sbin/ipfw/ipfw.8#2 edit
.. //depot/projects/soc2005/libalias/sbin/ipfw/ipfw2.c#2 edit
.. //depot/projects/soc2005/libalias/sbin/natd/natd.c#2 edit
.. //depot/projects/soc2005/libalias/sys/conf/files#2 edit
.. //depot/projects/soc2005/libalias/sys/modules/libalias/Makefile#2 edit
.. //depot/projects/soc2005/libalias/sys/modules/libalias/kld-cuseeme/Makefile#1 add
.. //depot/projects/soc2005/libalias/sys/modules/libalias/kld-dummy/Makefile#1 add
.. //depot/projects/soc2005/libalias/sys/modules/libalias/kld-ftp/Makefile#1 add
.. //depot/projects/soc2005/libalias/sys/modules/libalias/kld-irc/Makefile#1 add
.. //depot/projects/soc2005/libalias/sys/modules/libalias/kld-libalias/Makefile#1 add
.. //depot/projects/soc2005/libalias/sys/modules/libalias/kld-nbt/Makefile#1 add
.. //depot/projects/soc2005/libalias/sys/modules/libalias/kld-pptp/Makefile#1 add
.. //depot/projects/soc2005/libalias/sys/modules/libalias/kld-skinny/Makefile#1 add
.. //depot/projects/soc2005/libalias/sys/modules/libalias/kld-smedia/Makefile#1 add
.. //depot/projects/soc2005/libalias/sys/netinet/in.h#2 edit
.. //depot/projects/soc2005/libalias/sys/netinet/ip_fw.h#2 edit
.. //depot/projects/soc2005/libalias/sys/netinet/ip_fw2.c#2 edit
.. //depot/projects/soc2005/libalias/sys/netinet/ip_fw_pfil.c#2 edit
.. //depot/projects/soc2005/libalias/sys/netinet/libalias/alias.c#2 edit
.. //depot/projects/soc2005/libalias/sys/netinet/libalias/alias.h#2 edit
.. //depot/projects/soc2005/libalias/sys/netinet/libalias/alias_cuseeme.c#2 edit
.. //depot/projects/soc2005/libalias/sys/netinet/libalias/alias_db.c#2 edit
.. //depot/projects/soc2005/libalias/sys/netinet/libalias/alias_dummy.c#1 add
.. //depot/projects/soc2005/libalias/sys/netinet/libalias/alias_ftp.c#2 edit
.. //depot/projects/soc2005/libalias/sys/netinet/libalias/alias_irc.c#2 edit
.. //depot/projects/soc2005/libalias/sys/netinet/libalias/alias_local.h#2 edit
.. //depot/projects/soc2005/libalias/sys/netinet/libalias/alias_mod.c#1 add
.. //depot/projects/soc2005/libalias/sys/netinet/libalias/alias_mod.h#1 add
.. //depot/projects/soc2005/libalias/sys/netinet/libalias/alias_nbt.c#2 edit
.. //depot/projects/soc2005/libalias/sys/netinet/libalias/alias_old.c#2 edit
.. //depot/projects/soc2005/libalias/sys/netinet/libalias/alias_pptp.c#2 edit
.. //depot/projects/soc2005/libalias/sys/netinet/libalias/alias_proxy.c#2 edit
.. //depot/projects/soc2005/libalias/sys/netinet/libalias/alias_skinny.c#2 edit
.. //depot/projects/soc2005/libalias/sys/netinet/libalias/alias_smedia.c#2 edit
.. //depot/projects/soc2005/libalias/sys/netinet/libalias/alias_util.c#2 edit
.. //depot/projects/soc2005/libalias/sys/netinet/libalias/libalias.3#2 edit
.. //depot/projects/soc2005/libalias/sys/netinet/raw_ip.c#2 edit
.. //depot/projects/soc2005/libalias/usr.sbin/ppp/main.c#2 edit
Differences ...
==== //depot/projects/soc2005/libalias/etc/Makefile#2 (text+ko) ====
@@ -11,7 +11,7 @@
crontab csh.cshrc csh.login csh.logout devd.conf devfs.conf \
dhclient.conf disktab fbtab ftpusers gettytab group \
hosts hosts.allow hosts.equiv hosts.lpd \
- inetd.conf login.access login.conf mac.conf motd \
+ inetd.conf libalias.conf login.access login.conf mac.conf motd \
netconfig network.subr networks newsyslog.conf nsswitch.conf \
portsnap.conf pf.conf pf.os phones profile protocols \
rc rc.bsdextended rc.firewall rc.firewall6 rc.initdiskless \
==== //depot/projects/soc2005/libalias/lib/libalias/Makefile#2 (text+ko) ====
@@ -1,16 +1,12 @@
# $FreeBSD: src/lib/libalias/Makefile,v 1.31 2005/07/22 17:18:59 kensmith Exp $
-
-.PATH: ${.CURDIR}/../../sys/netinet/libalias
-
-LIB= alias
-SHLIBDIR?= /lib
-SHLIB_MAJOR= 5
-MAN= libalias.3
-SRCS= alias.c alias_cuseeme.c alias_db.c alias_ftp.c alias_irc.c \
- alias_nbt.c alias_pptp.c alias_proxy.c alias_skinny.c alias_smedia.c \
- alias_util.c alias_old.c
-INCS= alias.h
-WARNS?= 6
-NO_WERROR=
-
-.include <bsd.lib.mk>
+SUBDIR= lib-cuseeme \
+ lib-dummy \
+ lib-ftp \
+ lib-irc \
+ lib-libalias \
+ lib-nbt \
+ lib-pptp \
+ lib-skinny \
+ lib-smedia
+
+.include <bsd.subdir.mk>
==== //depot/projects/soc2005/libalias/sbin/ipfw/ipfw.8#2 (text+ko) ====
@@ -2031,6 +2031,98 @@
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,
the packets are dropped.
+.Sh IPFW NAT
+To support nat operations inside ipfw, the syntax was extended with a
+new action: nat.
+Then, to configure/handle nat instances the following syntax was
+added (trying to follow closely pipe|queue options):
+.Bd -ragged -offset indent
+.Bk -words
+.Cm nat
+.Ar nat_number
+.Cm config
+.Ar options
+.Ek
+.Ed
+.Pp
+where
+.Ar options
+is one or more mandatory fields that can assume the
+following values:
+.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
+For more information about aliasing modes, take a look
+at libalias(
+.Xr libalias 3
+).
+.Pp
+Other commands to manipulate nats are:
+.Bd -ragged -offset indent
+.Bk -words
+.Cm nat
+.Ar nat_number
+.Cm show
+.Cm config
+.Ek
+.Ed
+.Pp
+to see nat configuration of
+.Ar nat_number
+.
+.Pp
+.Bd -ragged -offset indent
+.Bk -words
+.Cm nat
+.Ar nat_number
+.Cm show
+.Ek
+.Ed
+.Pp
+to see the logs of
+.Ar nat_number
+(if any)
+.Pp
+In these two previous examples
+.Ar nat_number
+could be a single number to see the configuration of that
+instance (i.e. 123, a range of numbers (i.e 333-555) to see the
+configurations all the instances in that range or nothing, to see all
+the configured instances.
+.Pp
+See Section
+.Sx EXAMPLES
+for some examples on how to use nat.
+.Sh REDIRECT AND LSNAT SUPPORT IN IPFW
+Redirect and LSNAT support follow closely the syntax used in natd: refer to natd's man page
+for syntax details.
+The only difference between natd's redirect and ipfw redirect is:
+instead of redirect_[addr|port|prot] i chose redir_[addr|port|proto].
+.Pp
+See Section
+.Sx EXAMPLES
+for some examples on how to do redirect and lsnat.
.Sh SYSCTL VARIABLES
A set of
.Xr sysctl 8
@@ -2410,6 +2502,55 @@
Otherwise, e.g.\& if
you cannot access your box, the ruleset will be disabled after
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 redir_addr 10.0.0.1 10.0.0.66"
+.Dl " redir_port tcp 192.168.0.1:80 500"
+.Dl " redir_proto udp 192.168.1.43 192.168.1.1"
+.Dl " redir_addr 192.168.0.10,192.168.0.11"
+.Dl " 10.0.0.100 # LSNAT"
+.Dl " redir_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 redir_addr 10.0.0.1 10.0.0.66"
+.Dl "ipfw nat 2 config redir_port tcp 192.168.0.1:80 500"
+.Dl "ipfw nat 3 config redir_proto udp 192.168.1.43 192.168.1.1"
+.Dl "ipfw nat 4 config redir_addr 192.168.0.10,192.168.0.11,192.168.0.12"
+.Dl " 10.0.0.100"
+.Dl "ipfw nat 5 config redir_port tcp"
+.Dl " 192.168.0.1:80,192.168.0.10:22,192.168.0.20:25 500"
+.Pp
.Sh SEE ALSO
.Xr cpp 1 ,
.Xr m4 1 ,
@@ -2451,6 +2592,11 @@
.An Daniel Boulet
for BSDI.
.Pp
+.An -nosplit
+In-kernel NAT support written by
+.An Paolo Pisati Aq piso at FreeBSD.org
+as part of a Summer of Code 2005 project.
+.Pp
Work on
.Xr dummynet 4
traffic shaper supported by Akamba Corp.
==== //depot/projects/soc2005/libalias/sbin/ipfw/ipfw2.c#2 (text+ko) ====
@@ -48,6 +48,7 @@
#include <fcntl.h>
#include <net/if.h>
+#include <net/if_dl.h>
#include <net/pfvar.h>
#include <net/route.h> /* def. of struct route */
#include <netinet/in.h>
@@ -59,12 +60,14 @@
#include <netinet/ip_dummynet.h>
#include <netinet/tcp.h>
#include <arpa/inet.h>
+#include <alias.h>
int
do_resolv, /* Would try to resolve all */
do_time, /* Show time stamps */
do_quiet, /* Be quiet in add and flush */
do_pipe, /* this cmd refers to a pipe */
+ do_nat, /* nat configuration */
do_sort, /* field to sort results (0 = no) */
do_dynamic, /* display dynamic rules */
do_expired, /* display expired dynamic rules */
@@ -247,6 +250,7 @@
TOK_RESET,
TOK_UNREACH,
TOK_CHECKSTATE,
+ TOK_NAT,
TOK_ALTQ,
TOK_LOG,
@@ -309,6 +313,18 @@
TOK_DROPTAIL,
TOK_PROTO,
TOK_WEIGHT,
+ TOK_IP,
+ TOK_IF,
+ TOK_LOG,
+ TOK_DENY_INC,
+ TOK_SAME_PORTS,
+ TOK_UNREG_ONLY,
+ TOK_RESET_ADDR,
+ TOK_ALIAS_REV,
+ TOK_PROXY_ONLY,
+ TOK_REDIR_ADDR,
+ TOK_REDIR_PORT,
+ TOK_REDIR_PROTO,
TOK_IPV6,
TOK_FLOWID,
@@ -351,6 +367,22 @@
{ NULL, 0 } /* terminator */
};
+struct _s_x nat_params[] = {
+ { "ip", TOK_IP },
+ { "if", TOK_IF },
+ { "log", TOK_LOG },
+ { "deny_in", TOK_DENY_INC },
+ { "same_ports", TOK_SAME_PORTS },
+ { "unreg_only", TOK_UNREG_ONLY },
+ { "reset", TOK_RESET_ADDR },
+ { "reverse", TOK_ALIAS_REV },
+ { "proxy_only", TOK_PROXY_ONLY },
+ { "redir_addr", TOK_REDIR_ADDR },
+ { "redir_port", TOK_REDIR_PORT },
+ { "redir_proto", TOK_REDIR_PROTO },
+ { NULL, 0 } /* terminator */
+};
+
struct _s_x rule_actions[] = {
{ "accept", TOK_ACCEPT },
{ "pass", TOK_ACCEPT },
@@ -375,6 +407,7 @@
{ "unreach", TOK_UNREACH },
{ "check-state", TOK_CHECKSTATE },
{ "//", TOK_COMMENT },
+ { "nat", TOK_NAT},
{ NULL, 0 } /* terminator */
};
@@ -482,7 +515,7 @@
{
static int s = -1; /* the socket */
int i;
-
+
if (test_only)
return 0;
@@ -493,7 +526,8 @@
if (optname == IP_FW_GET || optname == IP_DUMMYNET_GET ||
optname == IP_FW_ADD || optname == IP_FW_TABLE_LIST ||
- optname == IP_FW_TABLE_GETSIZE)
+ optname == IP_FW_TABLE_GETSIZE || optname == IP_FW_NAT_GET_CONFIG ||
+ optname == IP_FW_NAT_GET_LOG)
i = getsockopt(s, IPPROTO_IP, optname, optval,
(socklen_t *)optlen);
else
@@ -1563,6 +1597,10 @@
tagptr = cmd;
break;
+ case O_NAT:
+ printf("nat %u", cmd->arg1);
+ break;
+
default:
printf("** unrecognized action %d len %d ",
cmd->opcode, cmd->len);
@@ -2625,13 +2663,16 @@
"add [num] [set N] [prob x] RULE-BODY\n"
"{pipe|queue} N config PIPE-BODY\n"
"[pipe|queue] {zero|delete|show} [N{,N}]\n"
+"nat N config {ip IPADDR|if IFNAME|log|deny_in|same_ports|unreg_only|reset|\n"
+" reverse|proxy_only|redir_addr linkspec| redir_port linkspec|\n"
+" redir_proto linkspec}\n"
"set [disable N... enable N...] | move [rule] X to Y | swap X Y | show\n"
"table N {add ip[/bits] [value] | delete ip[/bits] | flush | list}\n"
"\n"
"RULE-BODY: check-state [PARAMS] | ACTION [PARAMS] ADDR [OPTION_LIST]\n"
"ACTION: check-state | allow | count | deny | unreach{,6} CODE |\n"
" skipto N | {divert|tee} PORT | forward ADDR |\n"
-" pipe N | queue N\n"
+" pipe N | queue N | nat N\n"
"PARAMS: [log [logamount LOGLIMIT]] [altq QUEUE_NAME]\n"
"ADDR: [ MAC dst src ether_type ] \n"
" [ ip from IPADDR [ PORT ] to IPADDR [ PORTLIST ] ]\n"
@@ -3140,7 +3181,14 @@
/* Rule number */
while (ac && isdigit(**av)) {
i = atoi(*av); av++; ac--;
- if (do_pipe) {
+ if (do_nat) {
+ exitval = do_cmd(IP_FW_NAT_DEL, &i, sizeof i);
+ if (exitval) {
+ exitval = EX_UNAVAILABLE;
+ warn("rule %u not available",
+ i);
+ }
+ } else if (do_pipe) {
if (do_pipe == 1)
p.pipe_nr = i;
else
@@ -3165,7 +3213,6 @@
exit(exitval);
}
-
/*
* fill the interface structure. We do not check the name as we can
* create interfaces dynamically, so checking them at insert time
@@ -3189,7 +3236,754 @@
errx(EX_DATAERR, "bad ip address ``%s''", arg);
}
+/*
+ * Search for interface with name "ifn", and fill n accordingly:
+ *
+ * n->ip ip address of interface "ifn"
+ * n->if_name copy of interface name "ifn"
+ */
static void
+set_addr_dynamic(const char *ifn, struct cfg_nat *n)
+{
+ size_t needed;
+ int mib[6];
+ char *buf, *lim, *next;
+ struct if_msghdr *ifm;
+ struct ifa_msghdr *ifam;
+ struct sockaddr_dl *sdl;
+ struct sockaddr_in *sin;
+ int ifIndex, ifMTU;
+
+ mib[0] = CTL_NET;
+ mib[1] = PF_ROUTE;
+ mib[2] = 0;
+ mib[3] = AF_INET; /* Only IP addresses please */
+ mib[4] = NET_RT_IFLIST;
+ mib[5] = 0; /* ifIndex??? */
+/*
+ * Get interface data.
+ */
+ if (sysctl(mib, 6, NULL, &needed, NULL, 0) == -1)
+ err(1, "iflist-sysctl-estimate");
+ if ((buf = malloc(needed)) == NULL)
+ errx(1, "malloc failed");
+ if (sysctl(mib, 6, buf, &needed, NULL, 0) == -1)
+ err(1, "iflist-sysctl-get");
+ lim = buf + needed;
+/*
+ * Loop through interfaces until one with
+ * given name is found. This is done to
+ * find correct interface index for routing
+ * message processing.
+ */
+ ifIndex = 0;
+ next = buf;
+ while (next < lim) {
+ ifm = (struct if_msghdr *)next;
+ next += ifm->ifm_msglen;
+ if (ifm->ifm_version != RTM_VERSION) {
+ if (verbose)
+ warnx("routing message version %d "
+ "not understood", ifm->ifm_version);
+ continue;
+ }
+ if (ifm->ifm_type == RTM_IFINFO) {
+ sdl = (struct sockaddr_dl *)(ifm + 1);
+ if (strlen(ifn) == sdl->sdl_nlen &&
+ strncmp(ifn, sdl->sdl_data, sdl->sdl_nlen) == 0) {
+ ifIndex = ifm->ifm_index;
+ ifMTU = ifm->ifm_data.ifi_mtu;
+ break;
+ }
+ }
+ }
+ if (!ifIndex)
+ errx(1, "unknown interface name %s", ifn);
+/*
+ * Get interface address.
+ */
+ sin = NULL;
+ while (next < lim) {
+ ifam = (struct ifa_msghdr *)next;
+ next += ifam->ifam_msglen;
+ if (ifam->ifam_version != RTM_VERSION) {
+ if (verbose)
+ warnx("routing message version %d "
+ "not understood", ifam->ifam_version);
+ continue;
+ }
+ if (ifam->ifam_type != RTM_NEWADDR)
+ break;
+ if (ifam->ifam_addrs & RTA_IFA) {
+ int i;
+ char *cp = (char *)(ifam + 1);
+
+ for (i = 1; i < RTA_IFA; i <<= 1)
+ if (ifam->ifam_addrs & i)
+ cp += SA_SIZE((struct sockaddr *)cp);
+ if (((struct sockaddr *)cp)->sa_family == AF_INET) {
+ sin = (struct sockaddr_in *)cp;
+ break;
+ }
+ }
+ }
+ if (sin == NULL)
+ errx(1, "%s: cannot get interface address", ifn);
+
+ n->ip = sin->sin_addr;
+ strncpy(n->if_name, ifn, IF_NAMESIZE);
+
+ free(buf);
+}
+
+/*
+ * XXX: the following functions, macros and definitions come from natd.c:
+ * it would be better to move them outside of natd.c, in a file
+ * (redirect_support.[ch]?) shared by ipfw and natd, but for now i can live
+ * with it...
+ */
+
+/*
+ * Definition of a port range, and macros to deal with values.
+ * FORMAT: HI 16-bits == first port in range, 0 == all ports.
+ * LO 16-bits == number of ports in range
+ * NOTES: - Port values are not stored in network byte order.
+ */
+
+#define port_range u_long
+
+#define GETLOPORT(x) ((x) >> 0x10)
+#define GETNUMPORTS(x) ((x) & 0x0000ffff)
+#define GETHIPORT(x) (GETLOPORT((x)) + GETNUMPORTS((x)))
+
+/* Set y to be the low-port value in port_range variable x. */
+#define SETLOPORT(x,y) ((x) = ((x) & 0x0000ffff) | ((y) << 0x10))
+
+/* Set y to be the number of ports in port_range variable x. */
+#define SETNUMPORTS(x,y) ((x) = ((x) & 0xffff0000) | (y))
+
+static void
+StrToAddr (const char* str, struct in_addr* addr)
+{
+ struct hostent* hp;
+
+ if (inet_aton (str, addr))
+ return;
+
+ hp = gethostbyname (str);
+ if (!hp)
+ errx (1, "unknown host %s", str);
+
+ memcpy (addr, hp->h_addr, sizeof (struct in_addr));
+}
+
+static int
+StrToPortRange (const char* str, const char* proto, port_range *portRange)
+{
+ char* sep;
+ struct servent* sp;
+ char* end;
+ u_short loPort;
+ u_short hiPort;
+
+ /* First see if this is a service, return corresponding port if so. */
+ sp = getservbyname (str,proto);
+ if (sp) {
+ SETLOPORT(*portRange, ntohs(sp->s_port));
+ SETNUMPORTS(*portRange, 1);
+ return 0;
+ }
+
+ /* Not a service, see if it's a single port or port range. */
+ sep = strchr (str, '-');
+ if (sep == NULL) {
+ SETLOPORT(*portRange, strtol(str, &end, 10));
+ if (end != str) {
+ /* Single port. */
+ SETNUMPORTS(*portRange, 1);
+ return 0;
+ }
+
+ /* Error in port range field. */
+ errx (EX_DATAERR, "%s/%s: unknown service", str, proto);
+ }
+
+ /* Port range, get the values and sanity check. */
+ sscanf (str, "%hu-%hu", &loPort, &hiPort);
+ SETLOPORT(*portRange, loPort);
+ SETNUMPORTS(*portRange, 0); /* Error by default */
+ if (loPort <= hiPort)
+ SETNUMPORTS(*portRange, hiPort - loPort + 1);
+
+ if (GETNUMPORTS(*portRange) == 0)
+ errx (EX_DATAERR, "invalid port range %s", str);
+
+ return 0;
+}
+
+static int
+StrToProto (const char* str)
+{
+ if (!strcmp (str, "tcp"))
+ return IPPROTO_TCP;
+
+ if (!strcmp (str, "udp"))
+ return IPPROTO_UDP;
+
+ errx (EX_DATAERR, "unknown protocol %s. Expected tcp or udp", str);
+}
+
+static int
+StrToAddrAndPortRange (const char* str, struct in_addr* addr, char* proto, port_range *portRange)
+{
+ char* ptr;
+
+ ptr = strchr (str, ':');
+ if (!ptr)
+ errx (EX_DATAERR, "%s is missing port number", str);
+
+ *ptr = '\0';
+ ++ptr;
+
+ StrToAddr (str, addr);
+ return StrToPortRange (ptr, proto, portRange);
+}
+
+/* end of stuff taken from natd.c */
+
+#define INC_ARGCV() do { \
+ (*_av)++; \
+ (*_ac)--; \
+ av = *_av; \
+ ac = *_ac; \
+} while(0)
+
+/*
+ * The next 3 functions add support for the addr, port and proto redirect and
+ * their logic is loosely based on SetupAddressRedirect(), SetupPortRedirect()
+ * and SetupProtoRedirect() from natd.c.
+ *
+ * Every setup_* function fills at least one redirect entry
+ * (struct cfg_redir) and zero or more server pool entry (struct cfg_spool)
+ * in buf.
+ *
+ * The format of data in buf is:
+ *
+ *
+ * cfg_nat cfg_redir cfg_spool ...... cfg_spool
+ *
+ * ------------------------------------- ------------
+ * | | .....X ... | | | | .....
+ * ------------------------------------- ...... ------------
+ * ^
+ * spool_cnt n=0 ...... n=(X-1)
+ *
+ * len points to the amount of available space in buf
+ * space counts the memory consumed by every function
+ *
+ * XXX - Every function get all the argv params so it
+ * has to check, in optional parameters, that the next
+ * args is a valid option for the redir entry and not
+ * another token. Only redir_port and redir_proto are
+ * affected by this.
+ */
+
+static int
+setup_redir_addr(char *spool_buf, int len,
+ int *_ac, char ***_av)
+{
+ char **av = *_av, *sep; /* token separator */
+ /* temporary buffer used to hold server pool ip's */
+ char tmp_spool_buf[NAT_BUF_LEN];
+ int ac = *_ac, i, space = 0, lsnat = 0;
+ int sof_redir = sizeof(struct cfg_redir);
+ struct cfg_redir *r;
+
+ if (len >= sof_redir) {
+ r = (struct cfg_redir *)spool_buf;
+ /* skip cfg_redir at beginning of buf */
+ spool_buf = &spool_buf[sof_redir];
+ space = sof_redir;
+ len -= sof_redir;
+ } else
+ goto nospace;
+ r->mode = REDIR_ADDR;
+ /* extract local address */
+ if (ac == 0)
+ errx(EX_DATAERR, "redir_addr: missing local address");
+ sep = strchr(*av, ',');
+ if (sep) { /* LSNAT redirection syntax. */
+ r->laddr.s_addr = INADDR_NONE;
+ /* preserve av, copy spool servers to tmp_spool_buf */
+ strncpy(tmp_spool_buf, *av, strlen(*av)+1);
+ lsnat = 1;
+ } else
+ StrToAddr(*av, &r->laddr);
+ INC_ARGCV();
+
+ /* extract public address */
+ if (ac == 0)
+ errx(EX_DATAERR, "redir_addr: missing public address");
+ StrToAddr(*av, &r->paddr);
+ INC_ARGCV();
+
+ /* setup LSNAT server pool */
+ if (sep) {
+ int sof_spool = sizeof(struct cfg_spool);
+ struct cfg_spool *tmp;
+
+ sep = strtok(tmp_spool_buf, ",");
+ while (sep != NULL) {
+ tmp = (struct cfg_spool *)spool_buf;
+ if (len < sof_spool)
+ goto nospace;
+ len -= sof_spool;
+ space += sof_spool;
+ StrToAddr(sep, &tmp->addr);
+ tmp->port = ~0;
+ r->spool_cnt++;
+ /* point to the next possible cfg_spool */
+ spool_buf = &spool_buf[sof_spool];
+ sep = strtok(NULL, ",");
+ }
+ }
+ return(space);
+nospace:
+ errx(EX_DATAERR, "redir_addr: buf is too small\n");
+}
+
+static int
+setup_redir_port(char *spool_buf, int len,
+ int *_ac, char ***_av)
+{
+ char **av = *_av, *sep, *protoName;
+ char tmp_spool_buf[NAT_BUF_LEN];
+ int ac = *_ac, space = 0, lsnat = 0;
+ int sof_redir = sizeof(struct cfg_redir);
+ struct cfg_redir *r;
+ u_short numLocalPorts = 0;
+ port_range portRange;
+
+ if (len >= sof_redir) {
+ r = (struct cfg_redir *)spool_buf;
+ /* skip cfg_redir at beginning of buf */
+ spool_buf = &spool_buf[sof_redir];
+ space = sof_redir;
+ len -= sof_redir;
+ } else
+ goto nospace;
+ r->mode = REDIR_PORT;
+ /*
+ * Extract protocol.
+ */
+ if (ac == 0)
+ errx (EX_DATAERR, "redirect_port: missing protocol");
+ r->proto = StrToProto(*av);
+ protoName = *av;
+ INC_ARGCV();
+
+ /*
+ * Extract local address.
+ */
+ if (ac == 0)
+ errx (EX_DATAERR, "redirect_port: missing local address");
+
+ sep = strchr(*av, ',');
+ if (sep) { /* LSNAT redirection syntax. */
+ r->laddr.s_addr = INADDR_NONE;
+ r->lport = ~0;
+ numLocalPorts = 1;
+ /* preserve av, copy spool servers to tmp_spool_buf */
+ strncpy(tmp_spool_buf, *av, strlen(*av)+1);
+ lsnat = 1;
+ } else {
+ if ( StrToAddrAndPortRange (*av, &r->laddr, protoName, &portRange) != 0 )
+ errx (EX_DATAERR, "redirect_port: invalid local port range");
+
+ r->lport = GETLOPORT(portRange);
+ numLocalPorts = GETNUMPORTS(portRange);
+ }
+ INC_ARGCV();
+
+ /*
+ * Extract public port and optionally address.
+ */
+ if (ac == 0)
+ errx (EX_DATAERR, "redirect_port: missing public port");
+
+ sep = strchr (*av, ':');
+ if (sep) {
+ if (StrToAddrAndPortRange (*av, &r->paddr, protoName, &portRange) != 0 )
+ errx (EX_DATAERR, "redirect_port: invalid public port range");
+ } else {
+ r->paddr.s_addr = INADDR_ANY;
+ if (StrToPortRange (*av, protoName, &portRange) != 0)
+ errx (EX_DATAERR, "redirect_port: invalid public port range");
+ }
+
+ r->pport = GETLOPORT(portRange);
+ r->pport_cnt = GETNUMPORTS(portRange);
+ INC_ARGCV();
+
+ /*
+ * Extract remote address and optionally port.
+ */
+ /*
+ * isalpha(**av) => we've to check that next parameter is really an
+ * option for this redirect entry, else stop here processing arg[cv]
+ */
+ if (ac != 0 && !isalpha(**av)) {
+ sep = strchr (*av, ':');
+ if (sep) {
+ if (StrToAddrAndPortRange (*av, &r->raddr, protoName, &portRange) != 0)
+ errx (EX_DATAERR, "redirect_port: invalid remote port range");
+ } else {
+ SETLOPORT(portRange, 0);
+ SETNUMPORTS(portRange, 1);
+ StrToAddr (*av, &r->raddr);
+ }
+ INC_ARGCV();
+ } else {
+ SETLOPORT(portRange, 0);
+ SETNUMPORTS(portRange, 1);
+ r->raddr.s_addr = INADDR_ANY;
+ }
+ r->rport = GETLOPORT(portRange);
+ r->rport_cnt = GETNUMPORTS(portRange);
+
+ /*
+ * Make sure port ranges match up, then add the redirect ports.
+ */
+ if (numLocalPorts != r->pport_cnt)
+ errx(EX_DATAERR, "redirect_port: port ranges must be equal in size");
+
+ /* Remote port range is allowed to be '0' which means all ports. */
+ if (r->rport_cnt != numLocalPorts && (r->rport_cnt != 1 || r->rport != 0))
+ errx(EX_DATAERR, "redirect_port: remote port must be 0 or equal to local port range in size");
+
+ /*
+ * Setup LSNAT server pool.
+ */
+ if (lsnat) {
+ int sof_spool = sizeof(struct cfg_spool);
+ struct cfg_spool *tmp;
+
+ sep = strtok(tmp_spool_buf, ",");
+ while (sep != NULL) {
+ tmp = (struct cfg_spool *)spool_buf;
+ if (len < sof_spool)
+ goto nospace;
+ len -= sof_spool;
+ space += sof_spool;
+ if (StrToAddrAndPortRange(sep, &tmp->addr, protoName, &portRange) != 0)
+ errx(EX_DATAERR, "redirect_port: invalid local port range");
+ if (GETNUMPORTS(portRange) != 1)
+ errx(EX_DATAERR, "redirect_port: local port must be single in this context");
+ tmp->port = GETLOPORT(portRange);
+ r->spool_cnt++;
+ /* point to the next possible cfg_spool */
+ spool_buf = &spool_buf[sof_spool];
+ sep = strtok(NULL, ",");
+ }
+ }
+ return(space);
+nospace:
+ errx(EX_DATAERR, "redir_port: buf is too small\n");
+}
+
+static int
+setup_redir_proto(char *spool_buf, int len,
+ int *_ac, char ***_av)
+{
+ char **av = *_av;
+ int ac = *_ac, i, space;
+ struct protoent *protoent;
+ int sof_redir = sizeof(struct cfg_redir);
+ struct cfg_redir *r;
+
+ if (len >= sof_redir) {
+ r = (struct cfg_redir *)spool_buf;
+ /* skip cfg_redir at beginning of buf */
+ spool_buf = &spool_buf[sof_redir];
+ space = sof_redir;
+ len -= sof_redir;
+ } else
+ goto nospace;
+ r->mode = REDIR_PROTO;
+ /*
+ * Extract protocol.
+ */
+ if (ac == 0)
+ errx(EX_DATAERR, "redirect_proto: missing protocol");
+
+ protoent = getprotobyname(*av);
+ if (protoent == NULL)
+ errx(EX_DATAERR, "redirect_proto: unknown protocol %s", *av);
+ else
+ r->proto = protoent->p_proto;
+
+ INC_ARGCV();
+
+ /*
+ * Extract local address.
+ */
+ if (ac == 0)
+ errx(EX_DATAERR, "redirect_proto: missing local address");
+ else
+ StrToAddr(*av, &r->laddr);
+
+ INC_ARGCV();
+
+ /*
+ * Extract optional public address.
+ */
+ if (ac == 0) {
+ r->paddr.s_addr = INADDR_ANY;
+ r->raddr.s_addr = INADDR_ANY;
+ } else {
+ /* see above in setup_redir_port() */
+ if (!isalpha(**av)) {
+ StrToAddr(*av, &r->paddr);
+ INC_ARGCV();
+
+ /*
+ * Extract optional remote address.
+ */
+ /* see above in setup_redir_port() */
+ if (ac!=0 && !isalpha(**av)) {
+ StrToAddr(*av, &r->raddr);
+ INC_ARGCV();
+ }
+ }
+ }
+ return(space);
+nospace:
+ errx(EX_DATAERR, "redir_proto: buf is too small\n");
+}
+
+static void
+show_nat(int ac, char **av);
+
+static void
+print_nat_config(char *buf) {
+ struct cfg_nat *n = (struct cfg_nat *)buf;
+ int i, cnt, flag = 1, off = sizeof(*n);
+ int sof_redir = sizeof(struct cfg_redir);
+ int sof_spool = sizeof(struct cfg_spool);
+ struct cfg_redir *t;
+ struct cfg_spool *s;
+ struct protoent *p;
+
+ printf("ipfw nat %u config", n->id);
+ if (strlen(n->if_name) != 0)
+ printf(" if %s", n->if_name);
+ else if (n->ip.s_addr != 0)
+ printf(" ip %s", inet_ntoa(n->ip));
+ while (n->mode != 0) {
+ if (n->mode & PKT_ALIAS_LOG) {
+ printf(" log");
+ n->mode &= ~PKT_ALIAS_LOG;
+ } else if (n->mode & PKT_ALIAS_DENY_INCOMING) {
+ printf(" deny_in");
+ n->mode &= ~PKT_ALIAS_DENY_INCOMING;
+ } else if (n->mode & PKT_ALIAS_SAME_PORTS) {
+ printf(" same_ports");
+ n->mode &= ~PKT_ALIAS_SAME_PORTS;
+ } else if (n->mode & PKT_ALIAS_UNREGISTERED_ONLY) {
+ printf(" unreg_only");
+ n->mode &= ~PKT_ALIAS_UNREGISTERED_ONLY;
+ } else if (n->mode & PKT_ALIAS_RESET_ON_ADDR_CHANGE) {
+ printf(" reset");
+ n->mode &= ~PKT_ALIAS_RESET_ON_ADDR_CHANGE;
+ } else if (n->mode & PKT_ALIAS_REVERSE) {
+ printf(" reverse");
+ n->mode &= ~PKT_ALIAS_REVERSE;
+ } else if (n->mode & PKT_ALIAS_PROXY_ONLY) {
+ printf(" proxy_only");
+ n->mode &= ~PKT_ALIAS_PROXY_ONLY;
+ }
+ }
+ /* print all the redirect's data configuration */
+ for (cnt=0; cnt < n->redir_cnt; cnt++) {
>>> TRUNCATED FOR MAIL (1000 lines) <<<
More information about the p4-projects
mailing list