svn commit: r187770 - head/sbin/ipfw
Luigi Rizzo
luigi at FreeBSD.org
Tue Jan 27 04:02:22 PST 2009
Author: luigi
Date: Tue Jan 27 12:01:30 2009
New Revision: 187770
URL: http://svn.freebsd.org/changeset/base/187770
Log:
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
Added:
head/sbin/ipfw/ipv6.c (contents, props changed)
head/sbin/ipfw/nat.c (contents, props changed)
Modified:
head/sbin/ipfw/Makefile
head/sbin/ipfw/ipfw2.c
head/sbin/ipfw/ipfw2.h
Modified: head/sbin/ipfw/Makefile
==============================================================================
--- head/sbin/ipfw/Makefile Tue Jan 27 11:06:59 2009 (r187769)
+++ head/sbin/ipfw/Makefile Tue Jan 27 12:01:30 2009 (r187770)
@@ -1,7 +1,7 @@
# $FreeBSD$
PROG= ipfw
-SRCS= ipfw2.c dummynet.c main.c
+SRCS= ipfw2.c dummynet.c ipv6.c main.c nat.c
WARNS?= 0
MAN= ipfw.8
Modified: head/sbin/ipfw/ipfw2.c
==============================================================================
--- head/sbin/ipfw/ipfw2.c Tue Jan 27 11:06:59 2009 (r187769)
+++ head/sbin/ipfw/ipfw2.c Tue Jan 27 12:01:30 2009 (r187770)
@@ -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 *st
* 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");
*** DIFF OUTPUT TRUNCATED AT 1000 LINES ***
More information about the svn-src-all
mailing list