diff options
author | luigi <luigi@FreeBSD.org> | 2009-01-27 12:01:30 +0000 |
---|---|---|
committer | luigi <luigi@FreeBSD.org> | 2009-01-27 12:01:30 +0000 |
commit | 8a3b5c8587eefdf155a589610647bbc582948ce7 (patch) | |
tree | f06b5de4d78a1614f8a0927f17e29b5ec6459ad1 /sbin/ipfw/ipfw2.c | |
parent | 5153c1f1c42195d9130f83a12b751e798054a287 (diff) | |
download | FreeBSD-src-8a3b5c8587eefdf155a589610647bbc582948ce7.zip FreeBSD-src-8a3b5c8587eefdf155a589610647bbc582948ce7.tar.gz |
Put nat and ipv6 support in their own files.
Usual moving of code with no changes from ipfw2.c to the
newly created files, and addition of prototypes to ipfw2.h
I have added forward declarations for ipfw_insn_* in ipfw2.h
to avoid a global dependency on ip_fw.h
Diffstat (limited to 'sbin/ipfw/ipfw2.c')
-rw-r--r-- | sbin/ipfw/ipfw2.c | 1319 |
1 files changed, 2 insertions, 1317 deletions
diff --git a/sbin/ipfw/ipfw2.c b/sbin/ipfw/ipfw2.c index 5d73567..ffd74e8 100644 --- a/sbin/ipfw/ipfw2.c +++ b/sbin/ipfw/ipfw2.c @@ -52,11 +52,9 @@ #include <netinet/in_systm.h> #include <netinet/ip.h> #include <netinet/ip_icmp.h> -#include <netinet/icmp6.h> #include <netinet/ip_fw.h> #include <netinet/tcp.h> #include <arpa/inet.h> -#include <alias.h> struct cmdline_opts co; /* global options */ @@ -192,22 +190,6 @@ static struct _s_x ether_types[] = { }; -static struct _s_x 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 } /* terminator */ -}; - static struct _s_x rule_actions[] = { { "accept", TOK_ACCEPT }, { "pass", TOK_ACCEPT }, @@ -401,7 +383,7 @@ match_token(struct _s_x *table, char *string) * match_value takes a table and a value, returns the string associated * with the value (NULL in case of failure). */ -static char const * +char const * match_value(struct _s_x *p, int value) { for (; p->s != NULL; p++) @@ -786,40 +768,6 @@ print_reject_code(uint16_t code) printf("unreach %u", code); } -static struct _s_x icmp6codes[] = { - { "no-route", ICMP6_DST_UNREACH_NOROUTE }, - { "admin-prohib", ICMP6_DST_UNREACH_ADMIN }, - { "address", ICMP6_DST_UNREACH_ADDR }, - { "port", ICMP6_DST_UNREACH_NOPORT }, - { NULL, 0 } -}; - -static void -fill_unreach6_code(u_short *codep, char *str) -{ - int val; - char *s; - - val = strtoul(str, &s, 0); - if (s == str || *s != '\0' || val >= 0x100) - val = match_token(icmp6codes, str); - if (val < 0) - errx(EX_DATAERR, "unknown ICMPv6 unreachable code ``%s''", str); - *codep = val; - return; -} - -static void -print_unreach6_code(uint16_t code) -{ - char const *s = match_value(icmp6codes, code); - - if (s != NULL) - printf("unreach6 %s", s); - else - printf("unreach6 %u", code); -} - /* * Returns the number of bits set (from left) in a contiguous bitmask, * or -1 if the mask is not contiguous. @@ -831,7 +779,7 @@ print_unreach6_code(uint16_t code) * the first bit on the wire is bit 0 of the first byte. * len is the max length in bits. */ -static int +int contigmask(uint8_t *p, int len) { int i, n; @@ -1022,226 +970,6 @@ print_icmptypes(ipfw_insn_u32 *cmd) } } -/* - * Print the ip address contained in a command. - */ -static void -print_ip6(ipfw_insn_ip6 *cmd, char const *s) -{ - struct hostent *he = NULL; - int len = F_LEN((ipfw_insn *) cmd) - 1; - struct in6_addr *a = &(cmd->addr6); - char trad[255]; - - printf("%s%s ", cmd->o.len & F_NOT ? " not": "", s); - - if (cmd->o.opcode == O_IP6_SRC_ME || cmd->o.opcode == O_IP6_DST_ME) { - printf("me6"); - return; - } - if (cmd->o.opcode == O_IP6) { - printf(" ip6"); - return; - } - - /* - * len == 4 indicates a single IP, whereas lists of 1 or more - * addr/mask pairs have len = (2n+1). We convert len to n so we - * use that to count the number of entries. - */ - - for (len = len / 4; len > 0; len -= 2, a += 2) { - int mb = /* mask length */ - (cmd->o.opcode == O_IP6_SRC || cmd->o.opcode == O_IP6_DST) ? - 128 : contigmask((uint8_t *)&(a[1]), 128); - - if (mb == 128 && co.do_resolv) - he = gethostbyaddr((char *)a, sizeof(*a), AF_INET6); - if (he != NULL) /* resolved to name */ - printf("%s", he->h_name); - else if (mb == 0) /* any */ - printf("any"); - else { /* numeric IP followed by some kind of mask */ - if (inet_ntop(AF_INET6, a, trad, sizeof( trad ) ) == NULL) - printf("Error ntop in print_ip6\n"); - printf("%s", trad ); - if (mb < 0) /* XXX not really legal... */ - printf(":%s", - inet_ntop(AF_INET6, &a[1], trad, sizeof(trad))); - else if (mb < 128) - printf("/%d", mb); - } - if (len > 2) - printf(","); - } -} - -static void -fill_icmp6types(ipfw_insn_icmp6 *cmd, char *av) -{ - uint8_t type; - - bzero(cmd, sizeof(*cmd)); - while (*av) { - if (*av == ',') - av++; - type = strtoul(av, &av, 0); - if (*av != ',' && *av != '\0') - errx(EX_DATAERR, "invalid ICMP6 type"); - /* - * XXX: shouldn't this be 0xFF? I can't see any reason why - * we shouldn't be able to filter all possiable values - * regardless of the ability of the rest of the kernel to do - * anything useful with them. - */ - if (type > ICMP6_MAXTYPE) - errx(EX_DATAERR, "ICMP6 type out of range"); - cmd->d[type / 32] |= ( 1 << (type % 32)); - } - cmd->o.opcode = O_ICMP6TYPE; - cmd->o.len |= F_INSN_SIZE(ipfw_insn_icmp6); -} - - -static void -print_icmp6types(ipfw_insn_u32 *cmd) -{ - int i, j; - char sep= ' '; - - printf(" ip6 icmp6types"); - for (i = 0; i < 7; i++) - for (j=0; j < 32; ++j) { - if ( (cmd->d[i] & (1 << (j))) == 0) - continue; - printf("%c%d", sep, (i*32 + j)); - sep = ','; - } -} - -static void -print_flow6id( ipfw_insn_u32 *cmd) -{ - uint16_t i, limit = cmd->o.arg1; - char sep = ','; - - printf(" flow-id "); - for( i=0; i < limit; ++i) { - if (i == limit - 1) - sep = ' '; - printf("%d%c", cmd->d[i], sep); - } -} - -/* structure and define for the extension header in ipv6 */ -static struct _s_x ext6hdrcodes[] = { - { "frag", EXT_FRAGMENT }, - { "hopopt", EXT_HOPOPTS }, - { "route", EXT_ROUTING }, - { "dstopt", EXT_DSTOPTS }, - { "ah", EXT_AH }, - { "esp", EXT_ESP }, - { "rthdr0", EXT_RTHDR0 }, - { "rthdr2", EXT_RTHDR2 }, - { NULL, 0 } -}; - -/* fills command for the extension header filtering */ -static int -fill_ext6hdr( ipfw_insn *cmd, char *av) -{ - int tok; - char *s = av; - - cmd->arg1 = 0; - - while(s) { - av = strsep( &s, ",") ; - tok = match_token(ext6hdrcodes, av); - switch (tok) { - case EXT_FRAGMENT: - cmd->arg1 |= EXT_FRAGMENT; - break; - - case EXT_HOPOPTS: - cmd->arg1 |= EXT_HOPOPTS; - break; - - case EXT_ROUTING: - cmd->arg1 |= EXT_ROUTING; - break; - - case EXT_DSTOPTS: - cmd->arg1 |= EXT_DSTOPTS; - break; - - case EXT_AH: - cmd->arg1 |= EXT_AH; - break; - - case EXT_ESP: - cmd->arg1 |= EXT_ESP; - break; - - case EXT_RTHDR0: - cmd->arg1 |= EXT_RTHDR0; - break; - - case EXT_RTHDR2: - cmd->arg1 |= EXT_RTHDR2; - break; - - default: - errx( EX_DATAERR, "invalid option for ipv6 exten header" ); - break; - } - } - if (cmd->arg1 == 0 ) - return 0; - cmd->opcode = O_EXT_HDR; - cmd->len |= F_INSN_SIZE( ipfw_insn ); - return 1; -} - -static void -print_ext6hdr( ipfw_insn *cmd ) -{ - char sep = ' '; - - printf(" extension header:"); - if (cmd->arg1 & EXT_FRAGMENT ) { - printf("%cfragmentation", sep); - sep = ','; - } - if (cmd->arg1 & EXT_HOPOPTS ) { - printf("%chop options", sep); - sep = ','; - } - if (cmd->arg1 & EXT_ROUTING ) { - printf("%crouting options", sep); - sep = ','; - } - if (cmd->arg1 & EXT_RTHDR0 ) { - printf("%crthdr0", sep); - sep = ','; - } - if (cmd->arg1 & EXT_RTHDR2 ) { - printf("%crthdr2", sep); - sep = ','; - } - if (cmd->arg1 & EXT_DSTOPTS ) { - printf("%cdestination options", sep); - sep = ','; - } - if (cmd->arg1 & EXT_AH ) { - printf("%cauthentication header", sep); - sep = ','; - } - if (cmd->arg1 & EXT_ESP ) { - printf("%cencapsulated security payload", sep); - } -} - /* * show_ipfw() prints the body of an ipfw rule. * Because the standard rule has at least proto src_ip dst_ip, we use @@ -2490,21 +2218,6 @@ fill_ip(ipfw_insn_ip *cmd, char *av) } -/* Try to find ipv6 address by hostname */ -static int -lookup_host6 (char *host, struct in6_addr *ip6addr) -{ - struct hostent *he; - - if (!inet_pton(AF_INET6, host, ip6addr)) { - if ((he = gethostbyname2(host, AF_INET6)) == NULL) - return(-1); - memcpy(ip6addr, he->h_addr_list[0], sizeof( struct in6_addr)); - } - return(0); -} - - /* n2mask sets n bits of the mask */ void n2mask(struct in6_addr *mask, int n) @@ -2526,196 +2239,6 @@ n2mask(struct in6_addr *mask, int n) /* - * fill the addr and mask fields in the instruction as appropriate from av. - * Update length as appropriate. - * The following formats are allowed: - * any matches any IP6. Actually returns an empty instruction. - * me returns O_IP6_*_ME - * - * 03f1::234:123:0342 single IP6 addres - * 03f1::234:123:0342/24 address/mask - * 03f1::234:123:0342/24,03f1::234:123:0343/ List of address - * - * Set of address (as in ipv6) not supported because ipv6 address - * are typically random past the initial prefix. - * Return 1 on success, 0 on failure. - */ -static int -fill_ip6(ipfw_insn_ip6 *cmd, char *av) -{ - int len = 0; - struct in6_addr *d = &(cmd->addr6); - /* - * Needed for multiple address. - * Note d[1] points to struct in6_add r mask6 of cmd - */ - - cmd->o.len &= ~F_LEN_MASK; /* zero len */ - - if (strcmp(av, "any") == 0) - return (1); - - - if (strcmp(av, "me") == 0) { /* Set the data for "me" opt*/ - cmd->o.len |= F_INSN_SIZE(ipfw_insn); - return (1); - } - - if (strcmp(av, "me6") == 0) { /* Set the data for "me" opt*/ - cmd->o.len |= F_INSN_SIZE(ipfw_insn); - return (1); - } - - av = strdup(av); - while (av) { - /* - * After the address we can have '/' indicating a mask, - * or ',' indicating another address follows. - */ - - char *p; - int masklen; - char md = '\0'; - - if ((p = strpbrk(av, "/,")) ) { - md = *p; /* save the separator */ - *p = '\0'; /* terminate address string */ - p++; /* and skip past it */ - } - /* now p points to NULL, mask or next entry */ - - /* lookup stores address in *d as a side effect */ - if (lookup_host6(av, d) != 0) { - /* XXX: failed. Free memory and go */ - errx(EX_DATAERR, "bad address \"%s\"", av); - } - /* next, look at the mask, if any */ - masklen = (md == '/') ? atoi(p) : 128; - if (masklen > 128 || masklen < 0) - errx(EX_DATAERR, "bad width \"%s\''", p); - else - n2mask(&d[1], masklen); - - APPLY_MASK(d, &d[1]) /* mask base address with mask */ - - /* find next separator */ - - if (md == '/') { /* find separator past the mask */ - p = strpbrk(p, ","); - if (p != NULL) - p++; - } - av = p; - - /* Check this entry */ - if (masklen == 0) { - /* - * 'any' turns the entire list into a NOP. - * 'not any' never matches, so it is removed from the - * list unless it is the only item, in which case we - * report an error. - */ - if (cmd->o.len & F_NOT && av == NULL && len == 0) - errx(EX_DATAERR, "not any never matches"); - continue; - } - - /* - * A single IP can be stored alone - */ - if (masklen == 128 && av == NULL && len == 0) { - len = F_INSN_SIZE(struct in6_addr); - break; - } - - /* Update length and pointer to arguments */ - len += F_INSN_SIZE(struct in6_addr)*2; - d += 2; - } /* end while */ - - /* - * Total length of the command, remember that 1 is the size of - * the base command. - */ - if (len + 1 > F_LEN_MASK) - errx(EX_DATAERR, "address list too long"); - cmd->o.len |= len+1; - free(av); - return (1); -} - -/* - * fills command for ipv6 flow-id filtering - * note that the 20 bit flow number is stored in a array of u_int32_t - * it's supported lists of flow-id, so in the o.arg1 we store how many - * additional flow-id we want to filter, the basic is 1 - */ -static void -fill_flow6( ipfw_insn_u32 *cmd, char *av ) -{ - u_int32_t type; /* Current flow number */ - u_int16_t nflow = 0; /* Current flow index */ - char *s = av; - cmd->d[0] = 0; /* Initializing the base number*/ - - while (s) { - av = strsep( &s, ",") ; - type = strtoul(av, &av, 0); - if (*av != ',' && *av != '\0') - errx(EX_DATAERR, "invalid ipv6 flow number %s", av); - if (type > 0xfffff) - errx(EX_DATAERR, "flow number out of range %s", av); - cmd->d[nflow] |= type; - nflow++; - } - if( nflow > 0 ) { - cmd->o.opcode = O_FLOW6ID; - cmd->o.len |= F_INSN_SIZE(ipfw_insn_u32) + nflow; - cmd->o.arg1 = nflow; - } - else { - errx(EX_DATAERR, "invalid ipv6 flow number %s", av); - } -} - -static ipfw_insn * -add_srcip6(ipfw_insn *cmd, char *av) -{ - - fill_ip6((ipfw_insn_ip6 *)cmd, av); - if (F_LEN(cmd) == 0) { /* any */ - } else if (F_LEN(cmd) == F_INSN_SIZE(ipfw_insn)) { /* "me" */ - cmd->opcode = O_IP6_SRC_ME; - } else if (F_LEN(cmd) == - (F_INSN_SIZE(struct in6_addr) + F_INSN_SIZE(ipfw_insn))) { - /* single IP, no mask*/ - cmd->opcode = O_IP6_SRC; - } else { /* addr/mask opt */ - cmd->opcode = O_IP6_SRC_MASK; - } - return cmd; -} - -static ipfw_insn * -add_dstip6(ipfw_insn *cmd, char *av) -{ - - fill_ip6((ipfw_insn_ip6 *)cmd, av); - if (F_LEN(cmd) == 0) { /* any */ - } else if (F_LEN(cmd) == F_INSN_SIZE(ipfw_insn)) { /* "me" */ - cmd->opcode = O_IP6_DST_ME; - } else if (F_LEN(cmd) == - (F_INSN_SIZE(struct in6_addr) + F_INSN_SIZE(ipfw_insn))) { - /* single IP, no mask*/ - cmd->opcode = O_IP6_DST; - } else { /* addr/mask opt */ - cmd->opcode = O_IP6_DST_MASK; - } - return cmd; -} - - -/* * helper function to process a set of flags and set bits in the * appropriate masks. */ @@ -2824,769 +2347,6 @@ fill_iface(ipfw_insn_if *cmd, char *arg) 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; - 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"); - buf = safe_calloc(1, needed); - 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 (co.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 (co.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 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, *sep; /* Token separator. */ - /* Temporary buffer used to hold server pool ip's. */ - char tmp_spool_buf[NAT_BUF_LEN]; - int ac, space, lsnat; - struct cfg_redir *r; - struct cfg_spool *tmp; - - 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 - StrToAddr(*av, &r->laddr); - INC_ARGCV(); - - /* Extract public address. */ - if (ac == 0) - errx(EX_DATAERR, "redirect_addr: missing public address"); - StrToAddr(*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; - 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, "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 = StrToProto(*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 (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. - */ - /* - * 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 (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) { - 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, "redirect_port: buf is too small\n"); -} - -static int -setup_redir_proto(char *spool_buf, int len, - int *_ac, char ***_av) -{ - char **av; - int ac, space; - struct protoent *protoent; - struct cfg_redir *r; - - 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 - 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, "redirect_proto: buf is too small\n"); -} - -static void -print_nat_config(unsigned char *buf) -{ - struct cfg_nat *n; - int i, cnt, flag, off; - struct cfg_redir *t; - struct cfg_spool *s; - struct protoent *p; - - 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"); -} - -void -ipfw_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(*n); - memset(buf, 0, sizeof(buf)); - n = (struct cfg_nat *)buf; - - av++; ac--; - /* Nat id. */ - if (ac && isdigit(**av)) { - id = *av; - i = atoi(*av); - ac--; av++; - 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); - ac--; av++; - 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]); - ac--; av++; - break; - case TOK_IF: - if (ac == 0) - errx(EX_DATAERR, "missing option"); - set_addr_dynamic(av[0], n); - ac--; av++; - 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_cmd(IP_FW_NAT_CFG, buf, off); - if (i) - err(1, "setsockopt(%s)", "IP_FW_NAT_CFG"); - - if (!co.do_quiet) { - /* After every modification, we show the resultant rule. */ - int _ac = 3; - char *_av[] = {"show", "config", id}; - ipfw_show_nat(_ac, _av); - } -} - static void get_mac_addr_mask(const char *p, uint8_t *addr, uint8_t *mask) { @@ -5149,78 +3909,3 @@ table_list(ipfw_table_entry ent, int need_header) } free(tbl); } - -void -ipfw_show_nat(int ac, char **av) -{ - struct cfg_nat *n; - struct cfg_redir *e; - int cmd, i, nbytes, do_cfg, do_rule, frule, lrule, nalloc, size; - int nat_cnt, redir_cnt, r; - uint8_t *data, *p; - char *endptr; - - do_rule = 0; - nalloc = 1024; - size = 0; - data = NULL; - frule = 0; - lrule = IPFW_DEFAULT_RULE; /* max ipfw rule number */ - ac--; av++; - - if (co.test_only) - return; - - /* Parse parameters. */ - for (cmd = IP_FW_NAT_GET_LOG, do_cfg = 0; ac != 0; ac--, av++) { - if (!strncmp(av[0], "config", strlen(av[0]))) { - cmd = IP_FW_NAT_GET_CONFIG, do_cfg = 1; - continue; - } - /* Convert command line rule #. */ - frule = lrule = strtoul(av[0], &endptr, 10); - if (*endptr == '-') - lrule = strtoul(endptr+1, &endptr, 10); - if (lrule == 0) - err(EX_USAGE, "invalid rule number: %s", av[0]); - do_rule = 1; - } - - nbytes = nalloc; - while (nbytes >= nalloc) { - nalloc = nalloc * 2; - nbytes = nalloc; - data = safe_realloc(data, nbytes); - if (do_cmd(cmd, data, (uintptr_t)&nbytes) < 0) - err(EX_OSERR, "getsockopt(IP_FW_GET_%s)", - (cmd == IP_FW_NAT_GET_LOG) ? "LOG" : "CONFIG"); - } - if (nbytes == 0) - exit(0); - if (do_cfg) { - nat_cnt = *((int *)data); - for (i = sizeof(nat_cnt); nat_cnt; nat_cnt--) { - n = (struct cfg_nat *)&data[i]; - if (frule <= n->id && lrule >= n->id) - print_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); - } - } - } else { - for (i = 0; 1; i += LIBALIAS_BUF_SIZE + sizeof(int)) { - p = &data[i]; - if (p == data + nbytes) - break; - bcopy(p, &r, sizeof(int)); - if (do_rule) { - if (!(frule <= r && lrule >= r)) - continue; - } - printf("nat %u: %s\n", r, p+sizeof(int)); - } - } -} |