diff options
author | ae <ae@FreeBSD.org> | 2015-03-13 09:03:25 +0000 |
---|---|---|
committer | ae <ae@FreeBSD.org> | 2015-03-13 09:03:25 +0000 |
commit | 8ee4f19c0595d4c5a1b5edfbe92740fb80a562e6 (patch) | |
tree | 144121f14d0d8db127f25dbdb377dd06ecdda3b4 /sbin/ipfw | |
parent | b74bc609255aad13afd0fe21e53fd6ba0f470bb3 (diff) | |
download | FreeBSD-src-8ee4f19c0595d4c5a1b5edfbe92740fb80a562e6.zip FreeBSD-src-8ee4f19c0595d4c5a1b5edfbe92740fb80a562e6.tar.gz |
Fix `ipfw fwd tablearg'. Use dedicated field nh4 in struct table_value
to obtain IPv4 next hop address in tablearg case.
Add `fwd tablearg' support for IPv6. ipfw(8) uses INADDR_ANY as next hop
address in O_FORWARD_IP opcode for specifying tablearg case. For IPv6 we
still use this opcode, but when packet identified as IPv6 packet, we
obtain next hop address from dedicated field nh6 in struct table_value.
Replace hopstore field in struct ip_fw_args with anonymous union and add
hopstore6 field. Use this field to copy tablearg value for IPv6.
Replace spare1 field in struct table_value with zoneid. Use it to keep
scope zone id for link-local IPv6 addresses. Since spare1 was used
internally, replace spare0 array with two variables spare0 and spare1.
Use getaddrinfo(3)/getnameinfo(3) functions for parsing and formatting
IPv6 addresses in table_value. Use zoneid field in struct table_value
to store sin6_scope_id value.
Since the kernel still uses embedded scope zone id to represent
link-local addresses, convert next_hop6 address into this form before
return from pfil processing. This also fixes in6_localip() check
for link-local addresses.
Differential Revision: https://reviews.freebsd.org/D2015
Obtained from: Yandex LLC
Sponsored by: Yandex LLC
Diffstat (limited to 'sbin/ipfw')
-rw-r--r-- | sbin/ipfw/ipfw.8 | 4 | ||||
-rw-r--r-- | sbin/ipfw/tables.c | 37 |
2 files changed, 32 insertions, 9 deletions
diff --git a/sbin/ipfw/ipfw.8 b/sbin/ipfw/ipfw.8 index 6d25174..63f04cf 100644 --- a/sbin/ipfw/ipfw.8 +++ b/sbin/ipfw/ipfw.8 @@ -1,7 +1,7 @@ .\" .\" $FreeBSD$ .\" -.Dd Aug 13, 2014 +.Dd March 13, 2015 .Dt IPFW 8 .Os .Sh NAME @@ -2078,6 +2078,8 @@ hook number to move packet to. maximum number of connections. .It Cm ipv4 IPv4 nexthop to fwd packets to. +.It Cm ipv6 +IPv6 nexthop to fwd packets to. .El .Pp The diff --git a/sbin/ipfw/tables.c b/sbin/ipfw/tables.c index 4829fec..4ea5b7b 100644 --- a/sbin/ipfw/tables.c +++ b/sbin/ipfw/tables.c @@ -35,6 +35,7 @@ #include <netinet/in.h> #include <netinet/ip_fw.h> #include <arpa/inet.h> +#include <netdb.h> #include "ipfw2.h" @@ -1384,6 +1385,7 @@ static void tentry_fill_value(ipfw_obj_header *oh, ipfw_obj_tentry *tent, char *arg, uint8_t type, uint32_t vmask) { + struct addrinfo hints, *res; uint32_t a4, flag, val, vm; ipfw_table_value *v; uint32_t i; @@ -1494,9 +1496,19 @@ tentry_fill_value(ipfw_obj_header *oh, ipfw_obj_tentry *tent, char *arg, } break; case IPFW_VTYPE_NH6: - if (strchr(n, ':') != NULL && - inet_pton(AF_INET6, n, &v->nh6) == 1) - break; + if (strchr(n, ':') != NULL) { + memset(&hints, 0, sizeof(hints)); + hints.ai_family = AF_INET6; + hints.ai_flags = AI_NUMERICHOST; + if (getaddrinfo(n, NULL, &hints, &res) == 0) { + v->nh6 = ((struct sockaddr_in6 *) + res->ai_addr)->sin6_addr; + v->zoneid = ((struct sockaddr_in6 *) + res->ai_addr)->sin6_scope_id; + freeaddrinfo(res); + break; + } + } etype = "ipv6"; break; } @@ -1643,10 +1655,11 @@ static void table_show_value(char *buf, size_t bufsize, ipfw_table_value *v, uint32_t vmask, int print_ip) { + char abuf[INET6_ADDRSTRLEN + IF_NAMESIZE + 2]; + struct sockaddr_in6 sa6; uint32_t flag, i, l; size_t sz; struct in_addr a4; - char abuf[INET6_ADDRSTRLEN]; sz = bufsize; @@ -1702,8 +1715,15 @@ table_show_value(char *buf, size_t bufsize, ipfw_table_value *v, l = snprintf(buf, sz, "%d,", v->dscp); break; case IPFW_VTYPE_NH6: - inet_ntop(AF_INET6, &v->nh6, abuf, sizeof(abuf)); - l = snprintf(buf, sz, "%s,", abuf); + sa6.sin6_family = AF_INET6; + sa6.sin6_len = sizeof(sa6); + sa6.sin6_addr = v->nh6; + sa6.sin6_port = 0; + sa6.sin6_scope_id = v->zoneid; + if (getnameinfo((const struct sockaddr *)&sa6, + sa6.sin6_len, abuf, sizeof(abuf), NULL, 0, + NI_NUMERICHOST) == 0) + l = snprintf(buf, sz, "%s,", abuf); break; } @@ -1862,11 +1882,12 @@ struct _table_value { uint32_t nat; /* O_NAT */ uint32_t nh4; uint8_t dscp; - uint8_t spare0[3]; + uint8_t spare0; + uint16_t spare1; /* -- 32 bytes -- */ struct in6_addr nh6; uint32_t limit; /* O_LIMIT */ - uint32_t spare1; + uint32_t zoneid; uint64_t refcnt; /* Number of references */ }; |