diff --git a/lib/libipfw3/basic/ipfw3_basic.c b/lib/libipfw3/basic/ipfw3_basic.c index d686295..0282642 100644 --- a/lib/libipfw3/basic/ipfw3_basic.c +++ b/lib/libipfw3/basic/ipfw3_basic.c @@ -56,7 +56,7 @@ #include #include "../../../sys/net/ipfw3/ip_fw3.h" -#include "../../../sbin/ipfw3/ipfw.h" +#include "../../../sbin/ipfw3/ipfw3.h" #include "ipfw3_basic.h" @@ -96,21 +96,7 @@ static struct char_int_map ether_types[] = { { NULL, 0 } }; -/** - * match_token takes a table and a string, returns the value associated - * with the string (0 meaning an error in most cases) - */ -static int -match_token(struct char_int_map *table, char *string) -{ - while (table->key) { - if (strcmp(table->key, string) == 0) - return table->val; - table++; - } - return 0; -}; static char * match_token2(struct char_int_map *table, int val) diff --git a/sbin/ipfw3/Makefile b/sbin/ipfw3/Makefile index 07e6fa2..8ac691e 100644 --- a/sbin/ipfw3/Makefile +++ b/sbin/ipfw3/Makefile @@ -1,9 +1,10 @@ # $FreeBSD: src/sbin/ipfw/Makefile,v 1.6.6.3 2002/07/24 03:21:23 luigi Exp $ -PROG= ipfw3 -MAN= ipfw3.8 -SRCS= ipfw3.c +PROG = ipfw3 +MAN = ipfw3.8 +SRCS = ipfw3.c SRCS += ipfw3sync.c ipfw3sync.h +SRCS += ipfw3nat.c ipfw3nat.h WARNS?= 2 .include diff --git a/sbin/ipfw3/ipfw.h b/sbin/ipfw3/ipfw.h deleted file mode 100644 index 94130e2..0000000 --- a/sbin/ipfw3/ipfw.h +++ /dev/null @@ -1,56 +0,0 @@ -/* - * Copyright (c) 2014 The DragonFly Project. All rights reserved. - * - * This code is derived from software contributed to The DragonFly Project - * by Bill Yuan - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in - * the documentation and/or other materials provided with the - * distribution. - * 3. Neither the name of The DragonFly Project nor the names of its - * contributors may be used to endorse or promote products derived - * from this software without specific, prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS - * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE - * COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, - * INCIDENTAL, SPECIAL, EXEMPLARY OR CONSEQUENTIAL DAMAGES (INCLUDING, - * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED - * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, - * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT - * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - */ - - -#ifndef _IPFW_H -#define _IPFW_H - - -struct char_int_map { - char *key; - int val; -}; - - -typedef void (*parser_func)(ipfw_insn **cmd,int *ac, char **av[]); -typedef void (*shower_func)(ipfw_insn *cmd, int show_or); -typedef void (*register_func)(int module, int opcode,parser_func parser,shower_func shower); -typedef void (*register_keyword)(int module,int opcode,char *word,int type); -void register_ipfw_keyword(int module, int opcode,char *word,int type); -void register_ipfw_func(int module, int opcode,parser_func parser,shower_func shower); -typedef void (*init_module)(register_func func,register_keyword keyword); -int do_get_x(int optname, void *rule, int *optlen); -int do_set_x(int optname, void *rule, int optlen); - -#endif diff --git a/sbin/ipfw3/ipfw3.c b/sbin/ipfw3/ipfw3.c index d303255..c61a7df 100644 --- a/sbin/ipfw3/ipfw3.c +++ b/sbin/ipfw3/ipfw3.c @@ -64,8 +64,10 @@ #include "../../sys/net/libalias/alias.h" #include "../../sys/net/ipfw3_basic/ip_fw3_basic.h" #include "../../sys/net/ipfw3_nat/ip_fw3_nat.h" -#include "ipfw.h" + +#include "ipfw3.h" #include "ipfw3sync.h" +#include "ipfw3nat.h" #define KEYWORD_SIZE 256 @@ -76,7 +78,6 @@ #define WHITESP " \t\f\v\n\r" #define IPFW_LIB_PATH "/usr/lib/libipfw3%s.so" #define IP_MASK_ALL 0xffffffff -#define NAT_BUF_LEN 1024 /* * we use IPPROTO_ETHERTYPE as a fake protocol id to call the print routines * This is only used in this code. @@ -84,18 +85,6 @@ #define IPPROTO_ETHERTYPE 0x1000 /* - * This macro returns the size of a struct sockaddr when passed - * through a routing socket. Basically we round up sa_len to - * a multiple of sizeof(long), with a minimum of sizeof(long). - * The check for a NULL pointer is just a convenience, probably never used. - * The case sa_len == 0 should only apply to empty structures. - */ -#define SA_SIZE(sa) \ - ( (!(sa) || ((struct sockaddr *)(sa))->sa_len == 0) ? \ - sizeof(long) : \ - 1 + ( (((struct sockaddr *)(sa))->sa_len - 1) | (sizeof(long) - 1) ) ) - -/* * show_rules() prints the body of an ipfw rule. * Because the standard rule has at least proto src_ip dst_ip, we use * a helper function to produce these entries if not provided explicitly. @@ -116,32 +105,6 @@ #define HAVE_IP (HAVE_PROTO | HAVE_SRCIP | HAVE_DSTIP) -/* - * 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)) - -#define INC_ARGCV() do { \ - (*_av)++; \ - (*_ac)--; \ - av = *_av; \ - ac = *_ac; \ -} while (0) - int ipfw_socket = -1; /* main RAW socket */ int do_resolv, /* Would try to resolve all */ @@ -158,42 +121,6 @@ int do_resolv, /* Would try to resolve all */ show_sets, /* display rule sets */ verbose; -enum tokens { - TOK_NULL=0, - - TOK_IP, - TOK_IF, - TOK_ALOG, - 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_PIPE, - TOK_QUEUE, - TOK_PLR, - TOK_NOERROR, - TOK_BUCKETS, - TOK_DSTIP, - TOK_SRCIP, - TOK_DSTPORT, - TOK_SRCPORT, - TOK_ALL, - TOK_MASK, - TOK_BW, - TOK_DELAY, - TOK_RED, - TOK_GRED, - TOK_DROPTAIL, - TOK_PROTO, - TOK_WEIGHT, -}; - struct char_int_map dummynet_params[] = { { "plr", TOK_PLR }, { "noerror", TOK_NOERROR }, @@ -218,22 +145,6 @@ struct char_int_map dummynet_params[] = { { NULL, 0 } }; -struct char_int_map nat_params[] = { - { "ip", TOK_IP }, - { "if", TOK_IF }, - { "log", TOK_ALOG }, - { "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 }, - { "redirect_addr", TOK_REDIR_ADDR }, - { "redirect_port", TOK_REDIR_PORT }, - { "redirect_proto", TOK_REDIR_PROTO }, - { NULL, 0 }, -}; - struct ipfw_keyword { int type; char word[MAX_KEYWORD_LEN]; @@ -252,7 +163,7 @@ struct ipfw_mapping { struct ipfw_keyword keywords[KEYWORD_SIZE]; struct ipfw_mapping mappings[MAPPING_SIZE]; -static int +int match_token(struct char_int_map *table, char *string) { while (table->key) { @@ -1650,17 +1561,6 @@ help(void) exit(EX_USAGE); } -static void -delete_nat_config(int ac, char *av[]) -{ - NEXT_ARG; - int i = 0; - if (ac > 0) { - i = atoi(*av); - } - if (do_set_x(IP_FW_NAT_DEL, &i, sizeof(i)) == -1) - errx(EX_USAGE, "NAT %d in use or not exists", i); -} static void delete_rules(int ac, char *av[]) @@ -1693,7 +1593,8 @@ delete_rules(int ac, char *av[]) if (i) { exitval = 1; warn("rule %u: setsockopt(IP_DUMMYNET_DEL)", - do_pipe == 1 ? pipe.pipe_nr : pipe.fs.fs_nr); + do_pipe == 1 ? pipe.pipe_nr : + pipe.fs.fs_nr); } } else { rulenum = (i & 0xffff) | (do_set << 24); @@ -1887,7 +1788,8 @@ config_dummynet(int ac, char **av) if (a > 255) errx(EX_DATAERR, "mask: must be 8 bit"); - pipe.fs.flow_mask.u.ip.proto = (uint8_t)a; + pipe.fs.flow_mask.u.ip.proto = + (uint8_t)a; } if (a != 0) pipe.fs.flags_fs |= DN_HAVE_FLOW_MASK; @@ -1938,7 +1840,8 @@ end_mask: case TOK_BW: NEED1("bw needs bandwidth\n"); if (do_pipe != 1) - errx(EX_DATAERR, "bandwidth only valid for pipes"); + errx(EX_DATAERR, + "bandwidth only valid for pipes"); /* * set bandwidth value */ @@ -1958,7 +1861,8 @@ end_mask: case TOK_WEIGHT: if (do_pipe == 1) - errx(EX_DATAERR, "weight only valid for queues"); + errx(EX_DATAERR, + "weight only valid for queues"); NEED1("weight needs argument 0..100\n"); pipe.fs.weight = strtoul(av[0], &end, 0); NEXT_ARG; @@ -2182,7 +2086,8 @@ add(int ac, char *av[]) for (i = 0, key = keywords; i < KEYWORD_SIZE; i++, key++) { if (ac > 0 && key->type == ACTION && strcmp(key->word, *av) == 0) { - for (j = 0, map = mappings; jtype == IN_USE && map->module == key->module && map->opcode == key->opcode) { @@ -2208,7 +2113,8 @@ add(int ac, char *av[]) for (i = 0, key = keywords; i < KEYWORD_SIZE; i++, key++) { if (key->type == PROTO && strcmp(key->word, "proto") == 0) { - for (j = 0, map = mappings; jtype == IN_USE && map->module == key->module && map->opcode == key->opcode ) { @@ -2294,7 +2200,8 @@ done: for (src = (ipfw_insn *)cmdbuf; src != cmd; src += i) { /* pick comment out */ i = F_LEN(src); - if (src->module == MODULE_BASIC_ID && src->opcode == O_BASIC_COMMENT) { + if (src->module == MODULE_BASIC_ID && + src->opcode == O_BASIC_COMMENT) { the_comment=src; } else { bcopy(src, dst, i * sizeof(u_int32_t)); @@ -2385,7 +2292,8 @@ resetlog(int ac, char *av[]) if (!ac) { /* clear all entries */ - if (setsockopt(ipfw_socket, IPPROTO_IP, IP_FW_RESETLOG, NULL, 0) < 0) + if (setsockopt(ipfw_socket, IPPROTO_IP, + IP_FW_RESETLOG, NULL, 0) < 0) err(EX_UNAVAILABLE, "setsockopt(IP_FW_RESETLOG)"); if (!do_quiet) printf("Logging counts reset.\n"); @@ -2400,10 +2308,12 @@ resetlog(int ac, char *av[]) NEXT_ARG; if (setsockopt(ipfw_socket, IPPROTO_IP, IP_FW_RESETLOG, &rulenum, sizeof rulenum)) { - warn("rule %u: setsockopt(IP_FW_RESETLOG)", rulenum); + warn("rule %u: setsockopt(IP_FW_RESETLOG)", + rulenum); failed = EX_UNAVAILABLE; } else if (!do_quiet) - printf("Entry %d logging count reset\n", rulenum); + printf("Entry %d logging count reset\n", + rulenum); } else { errx(EX_DATAERR, "invalid rule number ``%s''", *av); } @@ -2418,8 +2328,6 @@ flush(void) int cmd = IP_FW_FLUSH; if (do_pipe) { cmd = IP_DUMMYNET_FLUSH; - } else if (do_nat) { - cmd = IP_FW_NAT_FLUSH; } if (!do_force) { int c; @@ -2438,740 +2346,11 @@ flush(void) if (do_set_x(cmd, NULL, 0) < 0 ) { if (do_pipe) errx(EX_USAGE, "pipe/queue in use"); - else if (do_nat) - errx(EX_USAGE, "NAT configuration in use"); else - errx(EX_USAGE, "do_set_x(IP_FWFLUSH) failed"); + errx(EX_USAGE, "do_set_x(IP_FW_FLUSH) failed"); } if (!do_quiet) { - printf("Flushed all %s.\n", do_pipe ? "pipes": - (do_nat?"nat configurations":"rules")); - } -} - -static void -str2addr(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 -str2portrange(const char* str, const char* proto, port_range *portRange) -{ - struct servent* sp; - char* sep; - char* end; - u_short loPort, 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 -str2proto(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 -str2addr_portrange (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; - - str2addr (str, addr); - return str2portrange (ptr, proto, portRange); -} - -/* - * 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) -{ - struct if_msghdr *ifm; - struct ifa_msghdr *ifam; - struct sockaddr_dl *sdl; - struct sockaddr_in *sin; - char *buf, *lim, *next; - size_t needed; - int mib[6]; - int ifIndex, ifMTU; - - mib[0] = CTL_NET; - mib[1] = PF_ROUTE; - mib[2] = 0; - mib[3] = AF_INET; - mib[4] = NET_RT_IFLIST; - mib[5] = 0; - - /* - * 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); -} - -static int -setup_redir_addr(char *spool_buf, int len, int *_ac, char ***_av) -{ - struct cfg_redir *r; - struct cfg_spool *tmp; - char **av, *sep; - char tmp_spool_buf[NAT_BUF_LEN]; - int ac, i, space, lsnat; - - i=0; - av = *_av; - ac = *_ac; - space = 0; - lsnat = 0; - 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, "redirect_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 { - str2addr(*av, &r->laddr); - } - INC_ARGCV(); - - /* Extract public address. */ - if (ac == 0) - errx(EX_DATAERR, "redirect_addr: missing public address"); - - str2addr(*av, &r->paddr); - INC_ARGCV(); - - /* Setup LSNAT server pool. */ - if (sep) { - 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; - str2addr(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, "redirect_addr: buf is too small\n"); -} - -static int -setup_redir_port(char *spool_buf, int len, int *_ac, char ***_av) -{ - char **av, *sep, *protoName; - char tmp_spool_buf[NAT_BUF_LEN]; - int ac, space, lsnat; - struct cfg_redir *r; - struct cfg_spool *tmp; - u_short numLocalPorts; - port_range portRange; - - av = *_av; - ac = *_ac; - space = 0; - lsnat = 0; - numLocalPorts = 0; - - 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 = str2proto(*av); - protoName = *av; - INC_ARGCV(); - - /* - * Extract local address. - */ - if (ac == 0) - errx (EX_DATAERR, "redirect_port: missing local address"); - - sep = strchr(*av, ','); - /* LSNAT redirection syntax. */ - if (sep) { - 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 (str2addr_portrange (*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 (str2addr_portrange (*av, &r->paddr, protoName, &portRange) != 0) - errx(EX_DATAERR, "redirect_port:" - "invalid public port range"); - } else { - r->paddr.s_addr = INADDR_ANY; - if (str2portrange(*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. - */ - /* - * NB: 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 (str2addr_portrange (*av, &r->raddr, - protoName, &portRange) != 0) - errx(EX_DATAERR, "redirect_port:" - "invalid remote port range"); - } else { - SETLOPORT(portRange, 0); - SETNUMPORTS(portRange, 1); - str2addr (*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) { - 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 (str2addr_portrange(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, "redirect_port: buf is too small\n"); -} - -static int -setup_redir_proto(char *spool_buf, int len, int *_ac, char ***_av) -{ - struct protoent *protoent; - struct cfg_redir *r; - int ac, i, space; - char **av; - - i=0; - av = *_av; - ac = *_ac; - 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 - str2addr(*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)) { - str2addr(*av, &r->paddr); - INC_ARGCV(); - - /* - * Extract optional remote address. - */ - /* see above in setup_redir_port() */ - if (ac != 0 && !isalpha(**av)) { - str2addr(*av, &r->raddr); - INC_ARGCV(); - } - } - } - return (space); - -nospace: - errx(EX_DATAERR, "redirect_proto: buf is too small\n"); -} - -static void -show_nat_config(char *buf) { - struct cfg_nat *n; - struct cfg_redir *t; - struct cfg_spool *s; - struct protoent *p; - int i, cnt, flag, off; - - n = (struct cfg_nat *)buf; - flag = 1; - off = sizeof(*n); - 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++) { - t = (struct cfg_redir *)&buf[off]; - off += SOF_REDIR; - switch (t->mode) { - case REDIR_ADDR: - printf(" redirect_addr"); - if (t->spool_cnt == 0) - printf(" %s", inet_ntoa(t->laddr)); - else - for (i = 0; i < t->spool_cnt; i++) { - s = (struct cfg_spool *)&buf[off]; - if (i) - printf(", "); - else - printf(" "); - printf("%s", inet_ntoa(s->addr)); - off += SOF_SPOOL; - } - printf(" %s", inet_ntoa(t->paddr)); - break; - case REDIR_PORT: - p = getprotobynumber(t->proto); - printf(" redirect_port %s ", p->p_name); - if (!t->spool_cnt) { - printf("%s:%u", inet_ntoa(t->laddr), t->lport); - if (t->pport_cnt > 1) - printf("-%u", t->lport + t->pport_cnt - 1); - } else - for (i=0; i < t->spool_cnt; i++) { - s = (struct cfg_spool *)&buf[off]; - if (i) - printf(", "); - printf("%s:%u", inet_ntoa(s->addr), s->port); - off += SOF_SPOOL; - } - - printf(" "); - if (t->paddr.s_addr) - printf("%s:", inet_ntoa(t->paddr)); - printf("%u", t->pport); - if (!t->spool_cnt && t->pport_cnt > 1) - printf("-%u", t->pport + t->pport_cnt - 1); - - if (t->raddr.s_addr) { - printf(" %s", inet_ntoa(t->raddr)); - if (t->rport) { - printf(":%u", t->rport); - if (!t->spool_cnt && t->rport_cnt > 1) - printf("-%u", t->rport + - t->rport_cnt - 1); - } - } - break; - case REDIR_PROTO: - p = getprotobynumber(t->proto); - printf(" redirect_proto %s %s", p->p_name, - inet_ntoa(t->laddr)); - if (t->paddr.s_addr != 0) { - printf(" %s", inet_ntoa(t->paddr)); - if (t->raddr.s_addr) - printf(" %s", inet_ntoa(t->raddr)); - } - break; - default: - errx(EX_DATAERR, "unknown redir mode"); - break; - } - } - printf("\n"); -} - - -static void -show_nat(int ac, char **av) { - struct cfg_nat *n; - struct cfg_redir *e; - int i, nbytes, nalloc, size; - int nat_cnt, redir_cnt, nat_id; - uint8_t *data; - - nalloc = 1024; - size = 0; - data = NULL; - - NEXT_ARG; - - if (ac == 0) - nat_id = 0; - else - nat_id = strtoul(*av, NULL, 10); - - nbytes = nalloc; - while (nbytes >= nalloc) { - nalloc = nalloc * 2; - nbytes = nalloc; - if ((data = realloc(data, nbytes)) == NULL) { - err(EX_OSERR, "realloc"); - } - if (do_get_x(IP_FW_NAT_GET, data, &nbytes) < 0) { - err(EX_OSERR, "do_get_x(IP_FW_NAT_GET)"); - } - } - - if (nbytes == 0) { - exit(EX_OK); - } - - nat_cnt = *((int *)data); - for (i = sizeof(nat_cnt); nat_cnt; nat_cnt--) { - n = (struct cfg_nat *)&data[i]; - if (n->id >= 0 && n->id <= IPFW_DEFAULT_RULE) { - if (nat_id == 0 || n->id == nat_id) - show_nat_config(&data[i]); - } - i += sizeof(struct cfg_nat); - for (redir_cnt = 0; redir_cnt < n->redir_cnt; redir_cnt++) { - e = (struct cfg_redir *)&data[i]; - i += sizeof(struct cfg_redir) + - e->spool_cnt * sizeof(struct cfg_spool); - } - } -} - -int -get_kern_boottime(void) -{ - struct timeval boottime; - size_t size; - int mib[2]; - mib[0] = CTL_KERN; - mib[1] = KERN_BOOTTIME; - size = sizeof(boottime); - if (sysctl(mib, 2, &boottime, &size, NULL, 0) != -1 && - boottime.tv_sec != 0) { - return boottime.tv_sec; - } - return -1; -} - -void -show_nat_state(int ac, char **av) -{ - int nbytes, nalloc; - int nat_id; - uint8_t *data; - - nalloc = 1024; - data = NULL; - - NEXT_ARG; - if (ac == 0) - nat_id = 0; - else - nat_id = strtoul(*av, NULL, 10); - - nbytes = nalloc; - while (nbytes >= nalloc) { - nalloc = nalloc * 2; - nbytes = nalloc; - if ((data = realloc(data, nbytes)) == NULL) { - err(EX_OSERR, "realloc"); - } - memcpy(data, &nat_id, sizeof(int)); - if (do_get_x(IP_FW_NAT_LOG, data, &nbytes) < 0) { - err(EX_OSERR, "do_get_x(IP_FW_NAT_GET_STATE)"); - } - } - if (nbytes == 0) - exit(EX_OK); - struct ipfw_ioc_nat_state *nat_state; - nat_state =(struct ipfw_ioc_nat_state *)data; - int count = nbytes / sizeof( struct ipfw_ioc_nat_state); - int i, uptime_sec; - uptime_sec = get_kern_boottime(); - for (i = 0; i < count; i ++) { - struct protoent *pe = getprotobynumber(nat_state->link_type); - printf("%s ", pe->p_name); - printf("%s:%hu => ",inet_ntoa(nat_state->src_addr), - htons(nat_state->src_port)); - printf("%s:%hu",inet_ntoa(nat_state->alias_addr), - htons(nat_state->alias_port)); - printf(" -> %s:%hu ",inet_ntoa(nat_state->dst_addr), - htons(nat_state->dst_port)); - if (do_time == 1) { - char timestr[30]; - time_t t = _long_to_time(uptime_sec + nat_state->timestamp); - strcpy(timestr, ctime(&t)); - *strchr(timestr, '\n') = '\0'; - printf("%s ", timestr); - } else if (do_time == 2) { - printf( "%10u ", uptime_sec + nat_state->timestamp); - } - printf("\n"); - nat_state++; + printf("Flushed all %s.\n", do_pipe ? "pipes" : "rules"); } } @@ -3226,107 +2405,6 @@ do_get_x(int optname, void *rule, int *optlen) return retval; } -static void -config_nat(int ac, char **av) -{ - struct cfg_nat *n; /* Nat instance configuration. */ - int i, len, off, tok; - char *id, buf[NAT_BUF_LEN]; /* Buffer for serialized data. */ - - len = NAT_BUF_LEN; - /* Offset in buf: save space for n at the beginning. */ - off = sizeof(struct cfg_nat); - memset(buf, 0, sizeof(buf)); - n = (struct cfg_nat *)buf; - - NEXT_ARG; - /* Nat id. */ - if (ac && isdigit(**av)) { - id = *av; - i = atoi(*av); - NEXT_ARG; - n->id = i; - } else - errx(EX_DATAERR, "missing nat id"); - if (ac == 0) - errx(EX_DATAERR, "missing option"); - - while (ac > 0) { - tok = match_token(nat_params, *av); - NEXT_ARG; - switch (tok) { - case TOK_IP: - if (ac == 0) - errx(EX_DATAERR, "missing option"); - if (!inet_aton(av[0], &(n->ip))) - errx(EX_DATAERR, "bad ip address ``%s''", - av[0]); - NEXT_ARG; - break; - case TOK_IF: - if (ac == 0) - errx(EX_DATAERR, "missing option"); - set_addr_dynamic(av[0], n); - NEXT_ARG; - break; - case TOK_ALOG: - n->mode |= PKT_ALIAS_LOG; - break; - case TOK_DENY_INC: - n->mode |= PKT_ALIAS_DENY_INCOMING; - break; - case TOK_SAME_PORTS: - n->mode |= PKT_ALIAS_SAME_PORTS; - break; - case TOK_UNREG_ONLY: - n->mode |= PKT_ALIAS_UNREGISTERED_ONLY; - break; - case TOK_RESET_ADDR: - n->mode |= PKT_ALIAS_RESET_ON_ADDR_CHANGE; - break; - case TOK_ALIAS_REV: - n->mode |= PKT_ALIAS_REVERSE; - break; - case TOK_PROXY_ONLY: - n->mode |= PKT_ALIAS_PROXY_ONLY; - break; - /* - * All the setup_redir_* functions work directly in the final - * buffer, see above for details. - */ - case TOK_REDIR_ADDR: - case TOK_REDIR_PORT: - case TOK_REDIR_PROTO: - switch (tok) { - case TOK_REDIR_ADDR: - i = setup_redir_addr(&buf[off], len, &ac, &av); - break; - case TOK_REDIR_PORT: - i = setup_redir_port(&buf[off], len, &ac, &av); - break; - case TOK_REDIR_PROTO: - i = setup_redir_proto(&buf[off], len, &ac, &av); - break; - } - n->redir_cnt++; - off += i; - len -= i; - break; - default: - errx(EX_DATAERR, "unrecognised option ``%s''", av[-1]); - } - } - i = do_set_x(IP_FW_NAT_CFG, buf, off); - if (i) - err(1, "do_set_x(%s)", "IP_FW_NAT_CFG"); - - /* After every modification, we show the resultant rule. */ - int _ac = 2; - char *_av[] = {"config", id}; - show_nat(_ac, _av); -} - - static int ipfw_main(int ac, char **av) { @@ -3456,31 +2534,7 @@ ipfw_main(int ac, char **av) } } else if (!strncmp(*av, "nat", strlen(*av))) { NEXT_ARG; - if (!strncmp(*av, "config", strlen(*av))) { - config_nat(ac, av); - } else if (!strncmp(*av, "flush", strlen(*av))) { - flush(); - } else if (!strncmp(*av, "show", strlen(*av)) || - !strncmp(*av, "list", strlen(*av))) { - if (ac > 2 && isdigit(*(av[1]))) { - char *p = av[1]; - av[1] = av[2]; - av[2] = p; - } - NEXT_ARG; - if (!strncmp(*av, "config", strlen(*av))) { - show_nat(ac, av); - } else if (!strncmp(*av, "state", strlen(*av))) { - show_nat_state(ac,av); - } else { - errx(EX_USAGE, - "bad nat show command `%s'", *av); - } - } else if (!strncmp(*av, "delete", strlen(*av))) { - delete_nat_config(ac, av); - } else { - errx(EX_USAGE, "bad ipfw nat command `%s'", *av); - } + nat_main(ac, av); } else if (!strncmp(*av, "pipe", strlen(*av)) || !strncmp(*av, "queue", strlen(*av))) { NEXT_ARG; diff --git a/sbin/ipfw3/ipfw3sync.c b/sbin/ipfw3/ipfw3sync.c index 41fcae0..914a23d 100644 --- a/sbin/ipfw3/ipfw3sync.c +++ b/sbin/ipfw3/ipfw3sync.c @@ -76,7 +76,7 @@ #include "../../sys/net/ipfw3_basic/ip_fw3_basic.h" #include "../../sys/net/ipfw3_nat/ip_fw3_nat.h" -#include "ipfw.h" +#include "ipfw3.h" #include "ipfw3sync.h" void diff --git a/sys/net/ipfw3/ip_fw3.c b/sys/net/ipfw3/ip_fw3.c index e77aafa..28c9c2c 100644 --- a/sys/net/ipfw3/ip_fw3.c +++ b/sys/net/ipfw3/ip_fw3.c @@ -135,18 +135,12 @@ struct netmsg_zent { uint16_t log_only; }; -ipfw_nat_cfg_t *ipfw_nat_cfg_ptr; -ipfw_nat_cfg_t *ipfw_nat_del_ptr; -ipfw_nat_cfg_t *ipfw_nat_flush_ptr; -ipfw_nat_cfg_t *ipfw_nat_get_cfg_ptr; -ipfw_nat_cfg_t *ipfw_nat_get_log_ptr; +ip_fw_ctl_t *ipfw_ctl_nat_ptr = NULL; /* handlers which implemented in ipfw_basic module */ ipfw_basic_delete_state_t *ipfw_basic_flush_state_prt = NULL; ipfw_basic_append_state_t *ipfw_basic_append_state_prt = NULL; -static struct ipfw_nat_context *ipfw_nat_ctx; - extern int ip_fw_loaded; static uint32_t static_count; /* # of static rules */ static uint32_t static_ioc_len; /* bytes of static rules */ @@ -206,7 +200,7 @@ register_ipfw_module(int module_id,char *module_name) } tmp++; } - kprintf("ipfw3 module %s loaded ", module_name); + kprintf("ipfw3 module %s loaded\n", module_name); } int @@ -242,7 +236,8 @@ decide: for (i = 0; i < MAX_MODULE; i++) { if (tmp->type == 1 && tmp->id == module_id) { tmp->type = 0; - kprintf("ipfw3 module %s unloaded ", tmp->name); + kprintf("ipfw3 module %s unloaded\n", + tmp->name); break; } tmp++; @@ -1677,20 +1672,14 @@ ipfw_ctl(struct sockopt *sopt) error = ipfw_ctl_zero_entry(rulenum, sopt->sopt_name == IP_FW_RESETLOG); break; - case IP_FW_NAT_CFG: - error = ipfw_nat_cfg_ptr(sopt); - break; + case IP_FW_NAT_ADD: case IP_FW_NAT_DEL: - error = ipfw_nat_del_ptr(sopt); - break; case IP_FW_NAT_FLUSH: - error = ipfw_nat_flush_ptr(sopt); - break; case IP_FW_NAT_GET: - error = ipfw_nat_get_cfg_ptr(sopt); - break; - case IP_FW_NAT_LOG: - error = ipfw_nat_get_log_ptr(sopt); + case IP_FW_NAT_GET_RECORD: + if (ipfw_ctl_nat_ptr != NULL) { + error = ipfw_ctl_nat_ptr(sopt); + } break; case IP_DUMMYNET_GET: case IP_DUMMYNET_CONFIGURE: @@ -1973,11 +1962,6 @@ ipfw_ctx_init_dispatch(netmsg_t nmsg) struct ipfw_context *ctx; struct ip_fw *def_rule; - if (mycpuid == 0 ) { - ipfw_nat_ctx = kmalloc(sizeof(struct ipfw_nat_context), - M_IPFW3, M_WAITOK | M_ZERO); - } - ctx = kmalloc(sizeof(struct ipfw_context), M_IPFW3, M_WAITOK | M_ZERO); ipfw_ctx[mycpuid] = ctx; @@ -2025,7 +2009,7 @@ ipfw_init_dispatch(netmsg_t nmsg) struct netmsg_ipfw fwmsg; int error = 0; if (IPFW3_LOADED) { - kprintf("IP firewall already loaded\n"); + kprintf("ipfw3 already loaded\n"); error = EEXIST; goto reply; } @@ -2039,17 +2023,9 @@ ipfw_init_dispatch(netmsg_t nmsg) ip_fw_ctl_x_ptr = ipfw_ctl_x; ip_fw_dn_io_ptr = ipfw_dummynet_io; - kprintf("ipfw3 initialized, default to %s, logging ", - (int)(ipfw_ctx[mycpuid]->ipfw_default_rule->cmd[0].opcode) == - O_BASIC_ACCEPT ? "accept" : "deny"); + kprintf("ipfw3 initialized, default to %s\n", + filters_default_to_accept ? "accept" : "deny"); -#ifdef IPFIREWALL_VERBOSE - fw_verbose = 1; -#endif - if (fw_verbose == 0) { - kprintf("disabled "); - } - kprintf("\n"); ip_fw3_loaded = 1; if (fw3_enable) ipfw_hook(); @@ -2099,9 +2075,7 @@ ipfw_fini_dispatch(netmsg_t nmsg) ipfw_ctx[cpu] = NULL; } } - kfree(ipfw_nat_ctx,M_IPFW3); - ipfw_nat_ctx = NULL; - kprintf("IP firewall unloaded\n"); + kprintf("ipfw3 unloaded\n"); lwkt_replymsg(&nmsg->lmsg, error); } diff --git a/sys/net/ipfw3/ip_fw3.h b/sys/net/ipfw3/ip_fw3.h index 9fb12d5..2d40fe6 100644 --- a/sys/net/ipfw3/ip_fw3.h +++ b/sys/net/ipfw3/ip_fw3.h @@ -344,7 +344,6 @@ struct dn_flow_set; typedef int ip_fw_chk_t(struct ip_fw_args *); typedef int ip_fw_ctl_t(struct sockopt *); -typedef int ipfw_nat_cfg_t(struct sockopt *); typedef void ip_fw_dn_io_t(struct mbuf *, int, int, struct ip_fw_args *); @@ -380,10 +379,6 @@ struct ipfw_state_context { int count; }; -/* place to hold the nat conf */ -struct ipfw_nat_context { - LIST_HEAD(, cfg_nat) nat; /* list of nat entries */ -}; typedef void (*filter_func)(int *cmd_ctl,int *cmd_val,struct ip_fw_args **args, struct ip_fw **f,ipfw_insn *cmd,uint16_t ip_len); @@ -542,11 +537,11 @@ typedef void ipfw_sync_send_state_t(struct ip_fw_state *, int cpu, int hash); #define IP_FW_MODULE 67 /* get modules names */ -#define IP_FW_NAT_CFG 68 /* add/config a nat rule */ +#define IP_FW_NAT_ADD 68 /* add/config a nat rule */ #define IP_FW_NAT_DEL 69 /* delete a nat rule */ #define IP_FW_NAT_FLUSH 70 /* get configuration of a nat rule */ #define IP_FW_NAT_GET 71 /* get config of a nat rule */ -#define IP_FW_NAT_LOG 72 /* get nat record of a nat rule */ +#define IP_FW_NAT_GET_RECORD 72 /* get nat record of a nat rule */ #define IP_FW_STATE_ADD 56 /* add one state */ #define IP_FW_STATE_DEL 57 /* delete states of one rulenum */ diff --git a/sys/net/ipfw3_nat/ip_fw3_nat.c b/sys/net/ipfw3_nat/ip_fw3_nat.c index 9f2a2f0..a5eba5d 100644 --- a/sys/net/ipfw3_nat/ip_fw3_nat.c +++ b/sys/net/ipfw3_nat/ip_fw3_nat.c @@ -1,8 +1,8 @@ /* - * Copyright (c) 2014 The DragonFly Project. All rights reserved. + * Copyright (c) 2014 - 2016 The DragonFly Project. All rights reserved. * * This code is derived from software contributed to The DragonFly Project - * by Bill Yuan + * by Bill Yuan * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -78,24 +78,25 @@ #include "ip_fw3_nat.h" -static struct lock nat_lock; +struct ipfw_nat_context *ipfw_nat_ctx[MAXCPU]; +extern struct ipfw_context *ipfw_ctx[MAXCPU]; +extern ip_fw_ctl_t *ipfw_ctl_nat_ptr; -extern struct ipfw_nat_context *ipfw_nat_ctx; -extern struct ipfw_context *ipfw_ctx[MAXCPU]; -extern ipfw_nat_cfg_t *ipfw_nat_cfg_ptr; -extern ipfw_nat_cfg_t *ipfw_nat_del_ptr; -extern ipfw_nat_cfg_t *ipfw_nat_flush_ptr; -extern ipfw_nat_cfg_t *ipfw_nat_get_cfg_ptr; -extern ipfw_nat_cfg_t *ipfw_nat_get_log_ptr; - -typedef int ipfw_nat_t(struct ip_fw_args *, struct cfg_nat *, struct mbuf *); - -int ipfw_nat(struct ip_fw_args *args, struct cfg_nat *t, struct mbuf *m); -int ipfw_nat_cfg(struct sockopt *sopt); -int ipfw_nat_del(struct sockopt *sopt); -int ipfw_nat_flush(struct sockopt *sopt); void check_nat(int *cmd_ctl, int *cmd_val, struct ip_fw_args **args, struct ip_fw **f, ipfw_insn *cmd, uint16_t ip_len); +void add_alias_link_dispatch(netmsg_t nat_del_msg); +int ipfw_nat(struct ip_fw_args *args, struct cfg_nat *t, struct mbuf *m); +void nat_add_dispatch(netmsg_t msg); +int ipfw_ctl_nat_add(struct sockopt *sopt); +void nat_del_dispatch(netmsg_t msg); +int ipfw_ctl_nat_del(struct sockopt *sopt); +int ipfw_ctl_nat_flush(struct sockopt *sopt); +int ipfw_ctl_nat_sockopt(struct sockopt *sopt); +void nat_init_ctx_dispatch(netmsg_t msg); +int ipfw_ctl_nat_get_cfg(struct sockopt *sopt); +void del_redir_spool_cfg(struct cfg_nat *n, struct redir_chain *head); +int add_redir_spool_cfg(char *buf, struct cfg_nat *ptr); +int ipfw_ctl_nat_get_record(struct sockopt *sopt); void @@ -107,16 +108,18 @@ check_nat(int *cmd_ctl, int *cmd_val, struct ip_fw_args **args, *cmd_val = IP_FW_NOT_MATCH; return; } + + struct ipfw_nat_context *nat_ctx; struct cfg_nat *t; int nat_id; + + nat_ctx = ipfw_nat_ctx[mycpuid]; (*args)->rule = *f; - lockmgr(&nat_lock, LK_SHARED); t = ((ipfw_insn_nat *)cmd)->nat; if (t == NULL) { nat_id = cmd->arg1; - LOOKUP_NAT((*ipfw_nat_ctx), nat_id, t); + LOOKUP_NAT((*nat_ctx), nat_id, t); if (t == NULL) { - lockmgr(&nat_lock, LK_RELEASE); *cmd_val = IP_FW_DENY; *cmd_ctl = IP_FW_CTL_DONE; return; @@ -124,11 +127,210 @@ check_nat(int *cmd_ctl, int *cmd_val, struct ip_fw_args **args, ((ipfw_insn_nat *)cmd)->nat = t; } *cmd_val = ipfw_nat(*args, t, (*args)->m); - lockmgr(&nat_lock, LK_RELEASE); *cmd_ctl = IP_FW_CTL_NAT; } -static void +/* Local prototypes */ +u_int StartPointIn(struct in_addr, u_short, int); + +u_int StartPointOut(struct in_addr, struct in_addr, + u_short, u_short, int); + +u_int +StartPointIn(struct in_addr alias_addr, + u_short alias_port, + int link_type) +{ + u_int n; + + n = alias_addr.s_addr; + if (link_type != LINK_PPTP) + n += alias_port; + n += link_type; + return (n % LINK_TABLE_IN_SIZE); +} + + +u_int +StartPointOut(struct in_addr src_addr, struct in_addr dst_addr, + u_short src_port, u_short dst_port, int link_type) +{ + u_int n; + + n = src_addr.s_addr; + n += dst_addr.s_addr; + if (link_type != LINK_PPTP) { + n += src_port; + n += dst_port; + } + n += link_type; + + return (n % LINK_TABLE_OUT_SIZE); +} + + +void +add_alias_link_dispatch(netmsg_t alias_link_add) +{ + struct ipfw_nat_context *nat_ctx; + struct netmsg_alias_link_add *msg; + struct libalias *la; + struct alias_link *lnk; + struct cfg_nat *t; + struct tcp_dat *aux_tcp; + u_int start_point; + + msg = (struct netmsg_alias_link_add *)alias_link_add; + nat_ctx = ipfw_nat_ctx[mycpuid]; + LOOKUP_NAT((*nat_ctx), msg->id, t); + la = t->lib; + lnk = kmalloc(sizeof(struct alias_link), M_ALIAS, M_WAITOK | M_ZERO); + memcpy(lnk, msg->lnk, sizeof(struct alias_link)); + lnk->la = la; + if (msg->is_tcp) { + aux_tcp = kmalloc(sizeof(struct tcp_dat), + M_ALIAS, M_WAITOK | M_ZERO); + memcpy(aux_tcp, msg->lnk->data.tcp, sizeof(struct tcp_dat)); + lnk->data.tcp = aux_tcp; + } + + /* Set up pointers for output lookup table */ + start_point = StartPointOut(lnk->src_addr, lnk->dst_addr, + lnk->src_port, lnk->dst_port, lnk->link_type); + LIST_INSERT_HEAD(&la->linkTableOut[start_point], lnk, list_out); + + /* Set up pointers for input lookup table */ + start_point = StartPointIn(lnk->alias_addr, + lnk->alias_port, lnk->link_type); + LIST_INSERT_HEAD(&la->linkTableIn[start_point], lnk, list_in); + kfree(alias_link_add, M_IPFW_NAT); +} + +int +ipfw_nat(struct ip_fw_args *args, struct cfg_nat *t, struct mbuf *m) +{ + struct alias_link *new = NULL; + struct mbuf *mcl; + struct ip *ip; + int ldt, retval, nextcpu; + char *c; + + ldt = 0; + retval = 0; + 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); + } + + if (mcl->m_pkthdr.rcvif == NULL && + mcl->m_pkthdr.csum_flags & CSUM_DELAY_DATA) { + ldt = 1; + } + + c = mtod(mcl, char *); + if (args->oif == NULL) { + retval = LibAliasIn(t->lib, c, + mcl->m_len + M_TRAILINGSPACE(mcl), &new); + } else { + retval = LibAliasOut(t->lib, c, + mcl->m_len + M_TRAILINGSPACE(mcl), &new); + } + if (retval != PKT_ALIAS_OK && + retval != PKT_ALIAS_FOUND_HEADER_FRAGMENT) { + /* XXX - should i add some logging? */ + m_free(mcl); +badnat: + args->m = NULL; + return IP_FW_DENY; + } + mcl->m_pkthdr.len = mcl->m_len = ntohs(ip->ip_len); + + 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 (new != NULL && + (ip->ip_p == IPPROTO_TCP || ip->ip_p == IPPROTO_UDP)) { + ip_hashfn(&mcl, 0); + nextcpu = netisr_hashcpu(m->m_pkthdr.hash); + if (nextcpu != mycpuid) { + struct netmsg_alias_link_add *msg; + msg = kmalloc(sizeof(struct netmsg_alias_link_add), + M_IPFW_NAT, M_NOWAIT | M_ZERO); + + netmsg_init(&msg->base, NULL, + &curthread->td_msgport, 0, + add_alias_link_dispatch); + msg->lnk = new; + msg->id = t->id; + if (ip->ip_p == IPPROTO_TCP) { + msg->is_tcp = 1; + } + if (args->oif == NULL) { + msg->is_outgoing = 0; + } else { + msg->is_outgoing = 1; + } + ifnet_sendmsg(&msg->base.lmsg, nextcpu); + } + } + 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); + 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; + return IP_FW_NAT; +} + +void del_redir_spool_cfg(struct cfg_nat *n, struct redir_chain *head) { struct cfg_redir *r, *tmp_r; @@ -166,7 +368,7 @@ del_redir_spool_cfg(struct cfg_nat *n, struct redir_chain *head) } } -static int +int add_redir_spool_cfg(char *buf, struct cfg_nat *ptr) { struct cfg_redir *r, *ser_r; @@ -242,30 +444,31 @@ bad: panic("%s\n", panic_err); } -static int -ipfw_nat_get_cfg(struct sockopt *sopt) +int +ipfw_ctl_nat_get_cfg(struct sockopt *sopt) { - uint8_t *data; + struct ipfw_nat_context *nat_ctx; struct cfg_nat *n; struct cfg_redir *r; struct cfg_spool *s; int nat_cnt, off, nat_cfg_size; size_t size; + uint8_t *data; nat_cnt = 0; nat_cfg_size = 0; off = sizeof(nat_cnt); + nat_ctx = ipfw_nat_ctx[mycpuid]; size = sopt->sopt_valsize; data = sopt->sopt_val; - lockmgr(&nat_lock, LK_SHARED); /* count the size of nat cfg */ - LIST_FOREACH(n, &((*ipfw_nat_ctx).nat), _next) { + LIST_FOREACH(n, &((*nat_ctx).nat), _next) { nat_cfg_size += SOF_NAT; } - LIST_FOREACH(n, &((*ipfw_nat_ctx).nat), _next) { + LIST_FOREACH(n, &((*nat_ctx).nat), _next) { nat_cnt++; if (off + SOF_NAT < size) { bcopy(n, &data[off], SOF_NAT); @@ -291,191 +494,102 @@ ipfw_nat_get_cfg(struct sockopt *sopt) } bcopy(&nat_cnt, data, sizeof(nat_cnt)); sopt->sopt_valsize = nat_cfg_size; - lockmgr(&nat_lock, LK_RELEASE); return 0; nospace: - lockmgr(&nat_lock, LK_RELEASE); bzero(sopt->sopt_val, sopt->sopt_valsize); sopt->sopt_valsize = nat_cfg_size; return 0; } -static int -ipfw_nat_get_log(struct sockopt *sopt) +int +ipfw_ctl_nat_get_record(struct sockopt *sopt) { + struct ipfw_nat_context *nat_ctx; struct cfg_nat *t; struct alias_link *lnk; struct libalias *la; size_t sopt_size, all_lnk_size = 0; - int i, *nat_id; + int i, *nat_id, id, n; struct ipfw_ioc_nat_state *nat_state; + int cpu; + nat_id = (int *)(sopt->sopt_val); + n = *nat_id; sopt_size = sopt->sopt_valsize; - - lockmgr(&nat_lock, LK_SHARED); - LOOKUP_NAT((*ipfw_nat_ctx), *nat_id, t); - if (t != NULL) { - nat_state = (struct ipfw_ioc_nat_state *)sopt->sopt_val; - la = t->lib; - LIBALIAS_LOCK_ASSERT(la); - for (i = 0; i < LINK_TABLE_OUT_SIZE; i ++) { - LIST_FOREACH(lnk, &la->linkTableOut[i], list_out) { - all_lnk_size += sizeof(*nat_state); - if (all_lnk_size > sopt_size) - goto nospace; - nat_state->src_addr = lnk->src_addr; - nat_state->dst_addr = lnk->dst_addr; - nat_state->alias_addr = lnk->alias_addr; - nat_state->src_port = lnk->src_port; - nat_state->dst_port = lnk->dst_port; - nat_state->alias_port = lnk->alias_port; - nat_state->link_type = lnk->link_type; - nat_state->timestamp = lnk->timestamp; - nat_state++; + nat_state = (struct ipfw_ioc_nat_state *)sopt->sopt_val; + for (cpu = 0; cpu < ncpus; cpu++) { + nat_ctx = ipfw_nat_ctx[cpu]; + id = n; + LOOKUP_NAT((*nat_ctx), id, t); + if (t != NULL) { + la = t->lib; + LIBALIAS_LOCK_ASSERT(la); + for (i = 0; i < LINK_TABLE_OUT_SIZE; i++) { + LIST_FOREACH(lnk, &la->linkTableOut[i], + list_out) { + all_lnk_size += sizeof(*nat_state); + if (all_lnk_size > sopt_size) + goto nospace; + nat_state->src_addr = lnk->src_addr; + nat_state->dst_addr = lnk->dst_addr; + nat_state->alias_addr = lnk->alias_addr; + nat_state->src_port = lnk->src_port; + nat_state->dst_port = lnk->dst_port; + nat_state->alias_port = lnk->alias_port; + nat_state->link_type = lnk->link_type; + nat_state->timestamp = lnk->timestamp; + nat_state->cpuid = cpu; + nat_state->is_outgoing = 1; + nat_state++; + } + LIST_FOREACH(lnk, &la->linkTableIn[i], + list_out) { + all_lnk_size += sizeof(*nat_state); + if (all_lnk_size > sopt_size) + goto nospace; + nat_state->src_addr = lnk->src_addr; + nat_state->dst_addr = lnk->dst_addr; + nat_state->alias_addr = lnk->alias_addr; + nat_state->src_port = lnk->src_port; + nat_state->dst_port = lnk->dst_port; + nat_state->alias_port = lnk->alias_port; + nat_state->link_type = lnk->link_type; + nat_state->timestamp = lnk->timestamp; + nat_state->cpuid = cpu; + nat_state->is_outgoing = 0; + nat_state++; + } } } } sopt->sopt_valsize = all_lnk_size; - lockmgr(&nat_lock, LK_RELEASE); return 0; nospace: - lockmgr(&nat_lock, LK_RELEASE); return 0; } -int -ipfw_nat(struct ip_fw_args *args, struct cfg_nat *t, struct mbuf *m) -{ - struct mbuf *mcl; - struct ip *ip; - int ldt, retval; - char *c; - ldt = 0; - retval = 0; - 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); - } - - if (mcl->m_pkthdr.rcvif == NULL && - mcl->m_pkthdr.csum_flags & - CSUM_DELAY_DATA) - ldt = 1; - - c = mtod(mcl, char *); - if (args->oif == NULL) - retval = LibAliasIn(t->lib, c, - mcl->m_len + M_TRAILINGSPACE(mcl)); - else - retval = LibAliasOut(t->lib, c, - mcl->m_len + M_TRAILINGSPACE(mcl)); - if (retval != PKT_ALIAS_OK && - retval != PKT_ALIAS_FOUND_HEADER_FRAGMENT) { - /* XXX - should i add some logging? */ - m_free(mcl); -badnat: - args->m = NULL; - return IP_FW_DENY; - } - mcl->m_pkthdr.len = mcl->m_len = ntohs(ip->ip_len); - - 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); - 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; - return IP_FW_NAT; -} - -int ipfw_nat_cfg(struct sockopt *sopt) +void +nat_add_dispatch(netmsg_t nat_add_msg) { + struct ipfw_nat_context *nat_ctx; struct cfg_nat *ptr, *ser_n; - char *buf; + struct netmsg_nat_add *msg; - buf = kmalloc(sopt->sopt_valsize, M_IPFW_NAT, M_WAITOK | M_ZERO); - sooptcopyin(sopt, buf, sopt->sopt_valsize, sizeof(struct cfg_nat)); - ser_n = (struct cfg_nat *)(sopt->sopt_val); + msg = (struct netmsg_nat_add *)nat_add_msg; - /* - * Find/create nat rule. - */ - lockmgr(&nat_lock, LK_EXCLUSIVE); - LOOKUP_NAT((*ipfw_nat_ctx), ser_n->id, ptr); + ser_n = (struct cfg_nat *)(msg->buf); - if (ptr == NULL) { - /* New rule: allocate and init new instance. */ - ptr = kmalloc(sizeof(struct cfg_nat), M_IPFW_NAT, - M_WAITOK | M_ZERO); - - ptr->lib = LibAliasInit(NULL); - if (ptr->lib == NULL) { - kfree(ptr, M_IPFW_NAT); - kfree(buf, M_IPFW_NAT); - lockmgr(&nat_lock, LK_RELEASE); - return EINVAL; - } + /* New rule: allocate and init new instance. */ + ptr = kmalloc(sizeof(struct cfg_nat), M_IPFW_NAT, M_WAITOK | M_ZERO); - LIST_INIT(&ptr->redir_chain); - } else { - /* XXX TODO Entry already exists */ - goto done; + ptr->lib = LibAliasInit(NULL); + if (ptr->lib == NULL) { + kfree(ptr, M_IPFW_NAT); + kfree(msg->buf, M_IPFW_NAT); } + LIST_INIT(&ptr->redir_chain); /* * Basic nat configuration. */ @@ -494,45 +608,79 @@ int ipfw_nat_cfg(struct sockopt *sopt) memcpy(ptr->if_name, ser_n->if_name, IF_NAMESIZE); /* Add new entries. */ - add_redir_spool_cfg(&buf[(sizeof(struct cfg_nat))], ptr); - HOOK_NAT(&(ipfw_nat_ctx->nat), ptr); + add_redir_spool_cfg(&msg->buf[(sizeof(struct cfg_nat))], ptr); + + nat_ctx = ipfw_nat_ctx[mycpuid]; + HOOK_NAT(&(nat_ctx->nat), ptr); + ifnet_forwardmsg(&msg->base.lmsg, mycpuid + 1); +} + +int +ipfw_ctl_nat_add(struct sockopt *sopt) +{ + struct ipfw_nat_context *nat_ctx; + struct cfg_nat *ptr, *ser_n; + ser_n = (struct cfg_nat *)(sopt->sopt_val); + + nat_ctx = ipfw_nat_ctx[mycpuid]; + /* + * Find/create nat rule. + */ + LOOKUP_NAT((*nat_ctx), ser_n->id, ptr); + + if (ptr == NULL) { + struct netmsg_nat_add nat_add_msg; + struct netmsg_nat_add *msg; + + msg = &nat_add_msg; + msg->buf = kmalloc(sopt->sopt_valsize, + M_IPFW_NAT, M_WAITOK | M_ZERO); + + sooptcopyin(sopt, msg->buf, sopt->sopt_valsize, + sizeof(struct cfg_nat)); + + netmsg_init(&msg->base, NULL, &curthread->td_msgport, + 0, nat_add_dispatch); + + + ifnet_domsg(&msg->base.lmsg, 0); + kfree(msg->buf, M_IPFW_NAT); + } else { + goto done; + } done: - lockmgr(&nat_lock, LK_RELEASE); - kfree(buf, M_IPFW_NAT); return 0; } -int -ipfw_nat_del(struct sockopt *sopt) +void +nat_del_dispatch(netmsg_t nat_del_msg) { + struct ipfw_nat_context *nat_ctx; struct ipfw_context *ctx; struct cfg_nat *n, *tmp; + struct netmsg_nat_del *msg; struct ip_fw *f; ipfw_insn *cmd; - int *i, cpu; + int id; - i = sopt->sopt_val; - lockmgr(&nat_lock, LK_EXCLUSIVE); - LOOKUP_NAT((*ipfw_nat_ctx), *i, n); + msg = (struct netmsg_nat_del *)nat_del_msg; + id = msg->id; + + nat_ctx = ipfw_nat_ctx[mycpuid]; + LOOKUP_NAT((*nat_ctx), id, n); if (n == NULL) { - lockmgr(&nat_lock, LK_RELEASE); - return EINVAL; } /* * stop deleting when this cfg_nat was in use in ipfw_ctx */ - for (cpu = 0; cpu < ncpus; cpu++) { - ctx = ipfw_ctx[cpu]; - for (f = ctx->ipfw_rule_chain; f; f = f->next) { - cmd = ACTION_PTR(f); - if ((int)cmd->module == MODULE_NAT_ID && - (int)cmd->opcode == O_NAT_NAT) { - tmp = ((ipfw_insn_nat *)cmd)->nat; - if (tmp != NULL && tmp->id == n->id) { - lockmgr(&nat_lock, LK_RELEASE); - return EINVAL; - } + ctx = ipfw_ctx[mycpuid]; + for (f = ctx->ipfw_rule_chain; f; f = f->next) { + cmd = ACTION_PTR(f); + if ((int)cmd->module == MODULE_NAT_ID && + (int)cmd->opcode == O_NAT_NAT) { + tmp = ((ipfw_insn_nat *)cmd)->nat; + if (tmp != NULL && tmp->id == n->id) { } } } @@ -541,13 +689,30 @@ ipfw_nat_del(struct sockopt *sopt) del_redir_spool_cfg(n, &n->redir_chain); LibAliasUninit(n->lib); kfree(n, M_IPFW_NAT); - lockmgr(&nat_lock, LK_RELEASE); +} + +int +ipfw_ctl_nat_del(struct sockopt *sopt) +{ + struct netmsg_nat_del nat_del_msg; + struct netmsg_nat_del *msg; + int *id; + + msg = &nat_del_msg; + id = sopt->sopt_val; + msg->id = *id; + + netmsg_init(&msg->base, NULL, &curthread->td_msgport, + 0, nat_del_dispatch); + + ifnet_domsg(&msg->base.lmsg, 0); return 0; } int -ipfw_nat_flush(struct sockopt *sopt) +ipfw_ctl_nat_flush(struct sockopt *sopt) { + struct ipfw_nat_context *nat_ctx; struct ipfw_context *ctx; struct cfg_nat *ptr, *tmp; struct ip_fw *f; @@ -568,67 +733,108 @@ ipfw_nat_flush(struct sockopt *sopt) } } - lockmgr(&nat_lock, LK_EXCLUSIVE); - LIST_FOREACH_MUTABLE(ptr, &(ipfw_nat_ctx->nat), _next, tmp) { + nat_ctx = ipfw_nat_ctx[mycpuid]; + + LIST_FOREACH_MUTABLE(ptr, &(nat_ctx->nat), _next, tmp) { LIST_REMOVE(ptr, _next); del_redir_spool_cfg(ptr, &ptr->redir_chain); LibAliasUninit(ptr->lib); kfree(ptr, M_IPFW_NAT); } - lockmgr(&nat_lock, LK_RELEASE); return 0; } +int +ipfw_ctl_nat_sockopt(struct sockopt *sopt) +{ + int error = 0; + switch (sopt->sopt_name) { + case IP_FW_NAT_ADD: + error = ipfw_ctl_nat_add(sopt); + break; + case IP_FW_NAT_DEL: + error = ipfw_ctl_nat_del(sopt); + break; + case IP_FW_NAT_FLUSH: + error = ipfw_ctl_nat_flush(sopt); + break; + case IP_FW_NAT_GET: + error = ipfw_ctl_nat_get_cfg(sopt); + break; + case IP_FW_NAT_GET_RECORD: + error = ipfw_ctl_nat_get_record(sopt); + break; + default: + kprintf("ipfw3 nat invalid socket option %d\n", + sopt->sopt_name); + } + return error; +} + +void +nat_init_ctx_dispatch(netmsg_t msg) +{ + struct ipfw_nat_context *tmp; + tmp = kmalloc(sizeof(struct ipfw_nat_context), + M_IPFW_NAT, M_WAITOK | M_ZERO); + ipfw_nat_ctx[mycpuid] = tmp; + ifnet_forwardmsg(&msg->lmsg, mycpuid + 1); +} + static int ipfw_nat_init(void) { - lockinit(&nat_lock, "ipfw3 nat lock", 0, 0); + struct netmsg_base msg; register_ipfw_module(MODULE_NAT_ID, MODULE_NAT_NAME); register_ipfw_filter_funcs(MODULE_NAT_ID, O_NAT_NAT, (filter_func)check_nat); - ipfw_nat_cfg_ptr = ipfw_nat_cfg; - ipfw_nat_del_ptr = ipfw_nat_del; - ipfw_nat_flush_ptr = ipfw_nat_flush; - ipfw_nat_get_cfg_ptr = ipfw_nat_get_cfg; - ipfw_nat_get_log_ptr = ipfw_nat_get_log; + ipfw_ctl_nat_ptr = ipfw_ctl_nat_sockopt; + netmsg_init(&msg, NULL, &curthread->td_msgport, + 0, nat_init_ctx_dispatch); + ifnet_domsg(&msg.lmsg, 0); return 0; } static int -ipfw_nat_stop(void) +ipfw_nat_fini(void) { - struct cfg_nat *ptr, *ptr_temp; - lockuninit(&nat_lock); - LIST_FOREACH_MUTABLE(ptr, &(ipfw_nat_ctx->nat), _next, ptr_temp) { - LIST_REMOVE(ptr, _next); - del_redir_spool_cfg(ptr, &ptr->redir_chain); - LibAliasUninit(ptr->lib); - kfree(ptr, M_IPFW_NAT); - } + struct cfg_nat *ptr, *tmp; + struct ipfw_nat_context *ctx; - ipfw_nat_cfg_ptr = NULL; - ipfw_nat_del_ptr = NULL; - ipfw_nat_flush_ptr = NULL; - ipfw_nat_get_cfg_ptr = NULL; - ipfw_nat_get_log_ptr = NULL; + for (cpu = 0; cpu < ncpus; cpu++) { + ctx = ipfw_nat_ctx[cpu]; + if(ctx != NULL) { + LIST_FOREACH_MUTABLE(ptr, &(ctx->nat), _next, tmp) { + LIST_REMOVE(ptr, _next); + del_redir_spool_cfg(ptr, &ptr->redir_chain); + LibAliasUninit(ptr->lib); + kfree(ptr, M_IPFW_NAT); + } + + kfree(ctx, M_IPFW_NAT); + ipfw_nat_ctx[cpu] = NULL; + } + } + ipfw_ctl_nat_ptr = NULL; return unregister_ipfw_module(MODULE_NAT_ID); } -static int ipfw_nat_modevent(module_t mod, int type, void *data) +static int +ipfw_nat_modevent(module_t mod, int type, void *data) { switch (type) { case MOD_LOAD: return ipfw_nat_init(); case MOD_UNLOAD: - return ipfw_nat_stop(); + return ipfw_nat_fini(); default: break; } return 0; } -static moduledata_t ipfw_nat_mod = { +moduledata_t ipfw_nat_mod = { "ipfw3_nat", ipfw_nat_modevent, NULL diff --git a/sys/net/ipfw3_nat/ip_fw3_nat.h b/sys/net/ipfw3_nat/ip_fw3_nat.h index b51b31a..4f86689 100644 --- a/sys/net/ipfw3_nat/ip_fw3_nat.h +++ b/sys/net/ipfw3_nat/ip_fw3_nat.h @@ -39,7 +39,32 @@ #define MODULE_NAT_NAME "nat" #ifdef _KERNEL + MALLOC_DEFINE(M_IPFW_NAT, "IPFW3/NAT", "IPFW3/NAT 's"); + +/* place to hold the nat conf */ +struct ipfw_nat_context { + LIST_HEAD(, cfg_nat) nat; /* list of nat entries*/ +}; + +struct netmsg_nat_del { + struct netmsg_base base; + int id; +}; + +struct netmsg_nat_add { + struct netmsg_base base; + char *buf; +}; + +struct netmsg_alias_link_add { + struct netmsg_base base; + struct alias_link *lnk; + int id; + int is_outgoing; + int is_tcp; +}; + #endif enum ipfw_nat_opcodes { @@ -54,6 +79,8 @@ struct ipfw_ioc_nat_state { int timestamp; int expire_time; int nat_id; + int cpuid; + int is_outgoing; u_short src_port; u_short dst_port; u_short alias_port; diff --git a/sys/net/libalias/alias.c b/sys/net/libalias/alias.c index 4749c67..4da85d2 100644 --- a/sys/net/libalias/alias.c +++ b/sys/net/libalias/alias.c @@ -245,26 +245,35 @@ the gateway machine or other machines on a local area network. /* Local prototypes */ -static int IcmpAliasIn1(struct libalias *, struct ip *); -static int IcmpAliasIn2(struct libalias *, struct ip *); -static int IcmpAliasIn(struct libalias *, struct ip *); - -static int IcmpAliasOut1(struct libalias *, struct ip *, int create); -static int IcmpAliasOut2(struct libalias *, struct ip *); -static int IcmpAliasOut(struct libalias *, struct ip *, int create); +static int IcmpAliasIn1(struct libalias *, struct ip *, + struct alias_link **); +static int IcmpAliasIn2(struct libalias *, struct ip *, + struct alias_link **); +static int IcmpAliasIn(struct libalias *, struct ip *, + struct alias_link **); + +static int IcmpAliasOut1(struct libalias *, struct ip *, int create, + struct alias_link **); +static int IcmpAliasOut2(struct libalias *, struct ip *, + struct alias_link **); +static int IcmpAliasOut(struct libalias *, struct ip *, int create, + struct alias_link **); static int ProtoAliasIn(struct libalias *, struct ip *); static int ProtoAliasOut(struct libalias *, struct ip *, int create); -static int UdpAliasIn(struct libalias *, struct ip *); -static int UdpAliasOut(struct libalias *, struct ip *, int create); +static int UdpAliasIn(struct libalias *, struct ip *,struct alias_link **); +static int UdpAliasOut(struct libalias *, struct ip *, int create, + struct alias_link **); -static int TcpAliasIn(struct libalias *, struct ip *); -static int TcpAliasOut(struct libalias *, struct ip *, int, int create); +static int TcpAliasIn(struct libalias *, struct ip *, + struct alias_link **); +static int TcpAliasOut(struct libalias *, struct ip *, int, int create, + struct alias_link **); static int -IcmpAliasIn1(struct libalias *la, struct ip *pip) +IcmpAliasIn1(struct libalias *la, struct ip *pip, struct alias_link **new) { LIBALIAS_LOCK_ASSERT(la); @@ -280,6 +289,7 @@ IcmpAliasIn1(struct libalias *la, struct ip *pip) /* Get source address from ICMP data field and restore original data */ lnk = FindIcmpIn(la, pip->ip_src, pip->ip_dst, ic->icmp_id, 1); if (lnk != NULL) { + *new = lnk; u_short original_id; int accumulate; @@ -309,7 +319,7 @@ IcmpAliasIn1(struct libalias *la, struct ip *pip) } static int -IcmpAliasIn2(struct libalias *la, struct ip *pip) +IcmpAliasIn2(struct libalias *la, struct ip *pip, struct alias_link **new) { LIBALIAS_LOCK_ASSERT(la); @@ -411,7 +421,7 @@ fragment contained in ICMP data section */ static int -IcmpAliasIn(struct libalias *la, struct ip *pip) +IcmpAliasIn(struct libalias *la, struct ip *pip, struct alias_link **new) { int iresult; struct icmp *ic; @@ -428,18 +438,18 @@ IcmpAliasIn(struct libalias *la, struct ip *pip) case ICMP_ECHOREPLY: case ICMP_TSTAMPREPLY: if (ic->icmp_code == 0) { - iresult = IcmpAliasIn1(la, pip); + iresult = IcmpAliasIn1(la, pip, new); } break; case ICMP_UNREACH: case ICMP_SOURCEQUENCH: case ICMP_TIMXCEED: case ICMP_PARAMPROB: - iresult = IcmpAliasIn2(la, pip); + iresult = IcmpAliasIn2(la, pip, new); break; case ICMP_ECHO: case ICMP_TSTAMP: - iresult = IcmpAliasIn1(la, pip); + iresult = IcmpAliasIn1(la, pip, new); break; } return (iresult); @@ -447,7 +457,8 @@ IcmpAliasIn(struct libalias *la, struct ip *pip) static int -IcmpAliasOut1(struct libalias *la, struct ip *pip, int create) +IcmpAliasOut1(struct libalias *la, struct ip *pip, int create, + struct alias_link **new) { /* Alias outgoing echo and timestamp requests. @@ -462,6 +473,9 @@ IcmpAliasOut1(struct libalias *la, struct ip *pip, int create) /* Save overwritten data for when echo packet returns */ lnk = FindIcmpOut(la, pip->ip_src, pip->ip_dst, ic->icmp_id, create); if (lnk != NULL) { + if (create) { + *new = lnk; + } u_short alias_id; int accumulate; @@ -492,7 +506,7 @@ IcmpAliasOut1(struct libalias *la, struct ip *pip, int create) static int -IcmpAliasOut2(struct libalias *la, struct ip *pip) +IcmpAliasOut2(struct libalias *la, struct ip *pip, struct alias_link **new) { /* Alias outgoing ICMP error messages containing @@ -593,7 +607,8 @@ fragment contained in ICMP data section */ static int -IcmpAliasOut(struct libalias *la, struct ip *pip, int create) +IcmpAliasOut(struct libalias *la, struct ip *pip, int create, + struct alias_link **new) { int iresult; struct icmp *ic; @@ -612,18 +627,18 @@ IcmpAliasOut(struct libalias *la, struct ip *pip, int create) case ICMP_ECHO: case ICMP_TSTAMP: if (ic->icmp_code == 0) { - iresult = IcmpAliasOut1(la, pip, create); + iresult = IcmpAliasOut1(la, pip, create, new); } break; case ICMP_UNREACH: case ICMP_SOURCEQUENCH: case ICMP_TIMXCEED: case ICMP_PARAMPROB: - iresult = IcmpAliasOut2(la, pip); + iresult = IcmpAliasOut2(la, pip, new); break; case ICMP_ECHOREPLY: case ICMP_TSTAMPREPLY: - iresult = IcmpAliasOut1(la, pip, create); + iresult = IcmpAliasOut1(la, pip, create, new); } return (iresult); } @@ -698,7 +713,7 @@ ProtoAliasOut(struct libalias *la, struct ip *pip, int create) static int -UdpAliasIn(struct libalias *la, struct ip *pip) +UdpAliasIn(struct libalias *la, struct ip *pip, struct alias_link **new) { struct udphdr *ud; struct alias_link *lnk; @@ -714,6 +729,7 @@ UdpAliasIn(struct libalias *la, struct ip *pip) ud->uh_sport, ud->uh_dport, IPPROTO_UDP, 1); if (lnk != NULL) { + *new = lnk; struct in_addr alias_address; struct in_addr original_address; u_short alias_port; @@ -763,7 +779,8 @@ UdpAliasIn(struct libalias *la, struct ip *pip) } static int -UdpAliasOut(struct libalias *la, struct ip *pip, int create) +UdpAliasOut(struct libalias *la, struct ip *pip, int create, + struct alias_link **new) { struct udphdr *ud; struct alias_link *lnk; @@ -780,6 +797,9 @@ UdpAliasOut(struct libalias *la, struct ip *pip, int create) ud->uh_sport, ud->uh_dport, IPPROTO_UDP, create); if (lnk != NULL) { + if (create) { + *new = lnk; + } u_short alias_port; struct in_addr alias_address; struct alias_data ad = { @@ -825,7 +845,7 @@ UdpAliasOut(struct libalias *la, struct ip *pip, int create) static int -TcpAliasIn(struct libalias *la, struct ip *pip) +TcpAliasIn(struct libalias *la, struct ip *pip, struct alias_link **new) { struct tcphdr *tc; struct alias_link *lnk; @@ -838,6 +858,9 @@ TcpAliasIn(struct libalias *la, struct ip *pip) IPPROTO_TCP, !(la->packetAliasMode & PKT_ALIAS_PROXY_ONLY)); if (lnk != NULL) { + if (!(la->packetAliasMode & PKT_ALIAS_PROXY_ONLY)) { + *new = lnk; + } struct in_addr alias_address; struct in_addr original_address; struct in_addr proxy_address; @@ -945,7 +968,8 @@ TcpAliasIn(struct libalias *la, struct ip *pip) } static int -TcpAliasOut(struct libalias *la, struct ip *pip, int maxpacketsize, int create) +TcpAliasOut(struct libalias *la, struct ip *pip, int maxpacketsize, int create, + struct alias_link **new) { int proxy_type, error; u_short dest_port; @@ -992,6 +1016,9 @@ TcpAliasOut(struct libalias *la, struct ip *pip, int maxpacketsize, int create) if (lnk == NULL) return (PKT_ALIAS_IGNORED); if (lnk != NULL) { + if (create) { + *new = lnk; + } u_short alias_port; struct in_addr alias_address; int accumulate; @@ -1197,24 +1224,26 @@ LibAliasFragmentIn(struct libalias *la, char *ptr, /* Points to correctly /* Local prototypes */ static int LibAliasOutLocked(struct libalias *la, char *ptr, - int maxpacketsize, int create); + int maxpacketsize, int create, struct alias_link **); static int LibAliasInLocked(struct libalias *la, char *ptr, - int maxpacketsize); + int maxpacketsize, struct alias_link **); int -LibAliasIn(struct libalias *la, char *ptr, int maxpacketsize) +LibAliasIn(struct libalias *la, char *ptr, int maxpacketsize, + struct alias_link **new) { int res; LIBALIAS_LOCK(la); - res = LibAliasInLocked(la, ptr, maxpacketsize); + res = LibAliasInLocked(la, ptr, maxpacketsize, new); LIBALIAS_UNLOCK(la); return (res); } static int -LibAliasInLocked(struct libalias *la, char *ptr, int maxpacketsize) +LibAliasInLocked(struct libalias *la, char *ptr, int maxpacketsize, + struct alias_link **new) { struct in_addr alias_addr; struct ip *pip; @@ -1222,7 +1251,7 @@ LibAliasInLocked(struct libalias *la, char *ptr, int maxpacketsize) if (la->packetAliasMode & PKT_ALIAS_REVERSE) { la->packetAliasMode &= ~PKT_ALIAS_REVERSE; - iresult = LibAliasOutLocked(la, ptr, maxpacketsize, 1); + iresult = LibAliasOutLocked(la, ptr, maxpacketsize, 1, new); la->packetAliasMode |= PKT_ALIAS_REVERSE; goto getout; } @@ -1242,13 +1271,13 @@ LibAliasInLocked(struct libalias *la, char *ptr, int maxpacketsize) if ((ntohs(pip->ip_off) & IP_OFFMASK) == 0) { switch (pip->ip_p) { case IPPROTO_ICMP: - iresult = IcmpAliasIn(la, pip); + iresult = IcmpAliasIn(la, pip, new); break; case IPPROTO_UDP: - iresult = UdpAliasIn(la, pip); + iresult = UdpAliasIn(la, pip, new); break; case IPPROTO_TCP: - iresult = TcpAliasIn(la, pip); + iresult = TcpAliasIn(la, pip, new); break; case IPPROTO_GRE: { int error; @@ -1311,23 +1340,25 @@ getout: #define UNREG_ADDR_C_UPPER 0xc0a8ffff int -LibAliasOut(struct libalias *la, char *ptr, int maxpacketsize) +LibAliasOut(struct libalias *la, char *ptr, int maxpacketsize, + struct alias_link **new) { int res; LIBALIAS_LOCK(la); - res = LibAliasOutLocked(la, ptr, maxpacketsize, 1); + res = LibAliasOutLocked(la, ptr, maxpacketsize, 1, new); LIBALIAS_UNLOCK(la); return (res); } int -LibAliasOutTry(struct libalias *la, char *ptr, int maxpacketsize, int create) +LibAliasOutTry(struct libalias *la, char *ptr, int maxpacketsize, int create, + struct alias_link **new) { int res; LIBALIAS_LOCK(la); - res = LibAliasOutLocked(la, ptr, maxpacketsize, create); + res = LibAliasOutLocked(la, ptr, maxpacketsize, create, new); LIBALIAS_UNLOCK(la); return (res); } @@ -1337,6 +1368,7 @@ LibAliasOutLocked(struct libalias *la, char *ptr, /* valid IP packet */ int maxpacketsize, /* How much the packet data may grow (FTP * and IRC inline changes) */ int create /* Create new entries ? */ + , struct alias_link **new ) { int iresult; @@ -1345,7 +1377,7 @@ LibAliasOutLocked(struct libalias *la, char *ptr, /* valid IP packet */ if (la->packetAliasMode & PKT_ALIAS_REVERSE) { la->packetAliasMode &= ~PKT_ALIAS_REVERSE; - iresult = LibAliasInLocked(la, ptr, maxpacketsize); + iresult = LibAliasInLocked(la, ptr, maxpacketsize, new); la->packetAliasMode |= PKT_ALIAS_REVERSE; goto getout; } @@ -1384,13 +1416,14 @@ LibAliasOutLocked(struct libalias *la, char *ptr, /* valid IP packet */ if ((ntohs(pip->ip_off) & IP_OFFMASK) == 0) { switch (pip->ip_p) { case IPPROTO_ICMP: - iresult = IcmpAliasOut(la, pip, create); + iresult = IcmpAliasOut(la, pip, create, new); break; case IPPROTO_UDP: - iresult = UdpAliasOut(la, pip, create); + iresult = UdpAliasOut(la, pip, create, new); break; case IPPROTO_TCP: - iresult = TcpAliasOut(la, pip, maxpacketsize, create); + iresult = TcpAliasOut(la, pip, maxpacketsize, create, + new); break; case IPPROTO_GRE: { int error; diff --git a/sys/net/libalias/alias.h b/sys/net/libalias/alias.h index 259064b..1ad70e4 100644 --- a/sys/net/libalias/alias.h +++ b/sys/net/libalias/alias.h @@ -249,9 +249,12 @@ unsigned int void LibAliasUninit(struct libalias *); /* Packet Handling functions. */ -int LibAliasIn (struct libalias *, char *_ptr, int _maxpacketsize); -int LibAliasOut(struct libalias *, char *_ptr, int _maxpacketsize); -int LibAliasOutTry(struct libalias *, char *_ptr, int _maxpacketsize, int _create); +int LibAliasIn (struct libalias *, char *_ptr, int _maxpacketsize, + struct alias_link **); +int LibAliasOut(struct libalias *, char *_ptr, int _maxpacketsize, + struct alias_link **); +int LibAliasOutTry(struct libalias *, char *_ptr, int + _maxpacketsize, int _create, struct alias_link **); int LibAliasUnaliasOut(struct libalias *, char *_ptr, int _maxpacketsize); /* Port and address redirection functions. */