summaryrefslogtreecommitdiffstats
path: root/sbin/ipfw/ipfw2.c
diff options
context:
space:
mode:
authorluigi <luigi@FreeBSD.org>2009-01-27 12:01:30 +0000
committerluigi <luigi@FreeBSD.org>2009-01-27 12:01:30 +0000
commit8a3b5c8587eefdf155a589610647bbc582948ce7 (patch)
treef06b5de4d78a1614f8a0927f17e29b5ec6459ad1 /sbin/ipfw/ipfw2.c
parent5153c1f1c42195d9130f83a12b751e798054a287 (diff)
downloadFreeBSD-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.c1319
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));
- }
- }
-}
OpenPOWER on IntegriCloud