Date: Sun, 25 Jun 2006 18:39:23 GMT From: Paolo Pisati <piso@FreeBSD.org> To: Perforce Change Reviews <perforce@freebsd.org> Subject: PERFORCE change 99995 for review Message-ID: <200606251839.k5PIdNS9053058@repoman.freebsd.org>
next in thread | raw e-mail | index | archive | help
http://perforce.freebsd.org/chv.cgi?CH=99995 Change 99995 by piso@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@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) <<<
Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?200606251839.k5PIdNS9053058>