@@ -701,10 +701,18 @@ static struct error_record *ip6addr_type_parse(struct parse_ctx *ctx,
return error(&sym->location, "Invalid IPv6 address");
} else {
struct addrinfo *ai, hints = { .ai_family = AF_INET6,
- .ai_socktype = SOCK_DGRAM};
+ .ai_socktype = SOCK_DGRAM,
+ .ai_flags = AI_V4MAPPED |
+ AI_NUMERICHOST};
int err;
+ /* first try: regular IPv6 addresses or IPv4-mapped */
err = getaddrinfo(sym->identifier, NULL, &hints, &ai);
+ if (err != 0) {
+ /* second try: hostnames, but ignore A records */
+ hints.ai_flags = 0;
+ err = getaddrinfo(sym->identifier, NULL, &hints, &ai);
+ }
if (err != 0)
return error(&sym->location, "Could not resolve hostname: %s",
gai_strerror(err));
@@ -11,10 +11,10 @@ meta l4proto tcp dnat to :80;ok;meta l4proto 6 dnat to :80
dnat ip to ct mark map { 0x00000014 : 1.2.3.4};ok
dnat ip to ct mark . ip daddr map { 0x00000014 . 1.1.1.1 : 1.2.3.4};ok
-dnat ip6 to 1.2.3.4;fail
+dnat ip6 to 1.2.3.4;ok;dnat ip6 to ::ffff:1.2.3.4
dnat to 1.2.3.4;fail
-dnat ip6 to ct mark . ip daddr map { 0x00000014 . 1.1.1.1 : 1.2.3.4};fail
-ip6 daddr dead::beef dnat to 10.1.2.3;fail
+dnat ip6 to ct mark . ip daddr map { 0x00000014 . 1.1.1.1 : 1.2.3.4};ok;dnat ip6 to ct mark . ip daddr map { 0x00000014 . 1.1.1.1 : ::ffff:1.2.3.4}
+ip6 daddr dead::beef dnat to 10.1.2.3;ok;ip6 daddr dead::beef dnat ip6 to ::ffff:10.1.2.3
meta l4proto { tcp, udp } dnat ip to 1.1.1.1:80;ok;meta l4proto { 6, 17} dnat ip to 1.1.1.1:80
ip protocol { tcp, udp } dnat ip to 1.1.1.1:80;ok;ip protocol { 6, 17} dnat ip to 1.1.1.1:80
@@ -164,6 +164,78 @@
}
]
+# dnat ip6 to 1.2.3.4
+[
+ {
+ "dnat": {
+ "addr": "1.2.3.4",
+ "family": "ip6"
+ }
+ }
+]
+
+# dnat ip6 to ct mark . ip daddr map { 0x00000014 . 1.1.1.1 : 1.2.3.4}
+[
+ {
+ "dnat": {
+ "addr": {
+ "map": {
+ "data": {
+ "set": [
+ [
+ {
+ "concat": [
+ 20,
+ "1.1.1.1"
+ ]
+ },
+ "1.2.3.4"
+ ]
+ ]
+ },
+ "key": {
+ "concat": [
+ {
+ "ct": {
+ "key": "mark"
+ }
+ },
+ {
+ "payload": {
+ "field": "daddr",
+ "protocol": "ip"
+ }
+ }
+ ]
+ }
+ }
+ },
+ "family": "ip6"
+ }
+ }
+]
+
+# ip6 daddr dead::beef dnat to 10.1.2.3
+[
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "daddr",
+ "protocol": "ip6"
+ }
+ },
+ "op": "==",
+ "right": "dead::beef"
+ }
+ },
+ {
+ "dnat": {
+ "addr": "10.1.2.3"
+ }
+ }
+]
+
# meta l4proto { tcp, udp } dnat ip to 1.1.1.1:80
[
{
@@ -53,6 +53,30 @@ inet test-inet prerouting
[ lookup reg 1 set __map%d dreg 1 ]
[ nat dnat ip addr_min reg 1 ]
+# dnat ip6 to 1.2.3.4
+inet test-inet prerouting
+ [ immediate reg 1 0x00000000 0x00000000 0xffff0000 0x04030201 ]
+ [ nat dnat ip6 addr_min reg 1 ]
+
+# dnat ip6 to ct mark . ip daddr map { 0x00000014 . 1.1.1.1 : 1.2.3.4}
+ element 00000014 01010101 : 00000000 00000000 ffff0000 04030201 0 [end]
+inet test-inet prerouting
+ [ meta load nfproto => reg 1 ]
+ [ cmp eq reg 1 0x00000002 ]
+ [ ct load mark => reg 1 ]
+ [ payload load 4b @ network header + 16 => reg 9 ]
+ [ lookup reg 1 set __map%d dreg 1 ]
+ [ nat dnat ip6 addr_min reg 1 ]
+
+# ip6 daddr dead::beef dnat to 10.1.2.3
+inet test-inet prerouting
+ [ meta load nfproto => reg 1 ]
+ [ cmp eq reg 1 0x0000000a ]
+ [ payload load 16b @ network header + 24 => reg 1 ]
+ [ cmp eq reg 1 0x0000adde 0x00000000 0x00000000 0xefbe0000 ]
+ [ immediate reg 1 0x00000000 0x00000000 0xffff0000 0x0302010a ]
+ [ nat dnat ip6 addr_min reg 1 ]
+
# meta l4proto { tcp, udp } dnat ip to 1.1.1.1:80
__set%d test-inet 3
__set%d test-inet 0
@@ -13,7 +13,7 @@
?set2 dead::beef timeout 5s;ok
ip saddr @set1 drop;ok
-ip saddr != @set2 drop;fail
+ip saddr != @set2 drop;ok
ip6 daddr != @set2 accept;ok
ip6 daddr @set1 drop;fail
@@ -17,6 +17,25 @@
}
]
+# ip saddr != @set2 drop
+[
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "saddr",
+ "protocol": "ip"
+ }
+ },
+ "op": "!=",
+ "right": "@set2"
+ }
+ },
+ {
+ "drop": null
+ }
+]
+
# ip6 daddr != @set2 accept
[
{
@@ -6,6 +6,15 @@ bridge test-inet input
[ lookup reg 1 set set1 ]
[ immediate reg 0 drop ]
+# ip saddr != @set2 drop
+bridge test-inet input
+ [ meta load protocol => reg 1 ]
+ [ cmp eq reg 1 0x00000008 ]
+ [ immediate reg 1 0x00000000 0x00000000 0xffff0000 ]
+ [ payload load 4b @ network header + 12 => reg 11 ]
+ [ lookup reg 1 set set2 0x1 ]
+ [ immediate reg 0 drop ]
+
# ip6 daddr != @set2 accept
bridge test-inet input
[ meta load protocol => reg 1 ]
@@ -6,6 +6,15 @@ inet test-inet input
[ lookup reg 1 set set1 ]
[ immediate reg 0 drop ]
+# ip saddr != @set2 drop
+inet test-inet input
+ [ meta load nfproto => reg 1 ]
+ [ cmp eq reg 1 0x00000002 ]
+ [ immediate reg 1 0x00000000 0x00000000 0xffff0000 ]
+ [ payload load 4b @ network header + 12 => reg 11 ]
+ [ lookup reg 1 set set2 0x1 ]
+ [ immediate reg 0 drop ]
+
# ip6 daddr != @set2 accept
inet test-inet input
[ meta load nfproto => reg 1 ]
@@ -6,6 +6,15 @@ netdev test-netdev ingress
[ lookup reg 1 set set1 ]
[ immediate reg 0 drop ]
+# ip saddr != @set2 drop
+netdev test-netdev ingress
+ [ meta load protocol => reg 1 ]
+ [ cmp eq reg 1 0x00000008 ]
+ [ immediate reg 1 0x00000000 0x00000000 0xffff0000 ]
+ [ payload load 4b @ network header + 12 => reg 11 ]
+ [ lookup reg 1 set set2 0x1 ]
+ [ immediate reg 0 drop ]
+
# ip6 daddr != @set2 accept
netdev test-netdev ingress
[ meta load protocol => reg 1 ]
@@ -13,7 +13,7 @@ iifname "foo" masquerade random;ok
snat to 192.168.3.2;fail
-snat ip6 to 192.168.3.2;fail
+snat ip6 to 192.168.3.2;ok;snat ip6 to ::ffff:192.168.3.2
snat to dead::beef;fail
snat ip to dead::beef;fail
snat ip daddr 1.2.3.4 to dead::beef;fail
@@ -129,3 +129,12 @@
}
]
+# snat ip6 to 192.168.3.2
+[
+ {
+ "snat": {
+ "addr": "192.168.3.2",
+ "family": "ip6"
+ }
+ }
+]
@@ -20,3 +20,12 @@
}
]
+# snat ip6 to 192.168.3.2
+[
+ {
+ "snat": {
+ "addr": "::ffff:192.168.3.2",
+ "family": "ip6"
+ }
+ }
+]
@@ -40,3 +40,8 @@ inet test-inet postrouting
[ meta load iifname => reg 1 ]
[ cmp eq reg 1 0x006f6f66 0x00000000 0x00000000 0x00000000 ]
[ masq flags 0x4 ]
+
+# snat ip6 to 192.168.3.2
+inet test-inet postrouting
+ [ immediate reg 1 0x00000000 0x00000000 0xffff0000 0x0203a8c0 ]
+ [ nat snat ip6 addr_min reg 1 ]
@@ -8,7 +8,7 @@
*netdev;test-netdev;ingress,egress
!ip6addrset type ipv6_addr;ok
-?ip6addrset feed::c0:ffee, ::ffff:1.2.3.4;ok
+?ip6addrset feed::c0:ffee, ::ffff:1.2.3.4, 192.168.1.1;ok
!v4v6set type ipv4_addr . ipv6_addr;ok
?v4v6set 1.2.3.4 . ::ffff:5.6.7.8;ok
!v6v4set type ipv6_addr . ipv4_addr;ok
@@ -145,6 +145,8 @@ ip6 saddr ::1 ip6 daddr ::2;ok
ip6 daddr != {::1234:1234:1234:1234:1234:1234:1234, 1234:1234::1234:1234:1234:1234:1234 };ok;ip6 daddr != {0:1234:1234:1234:1234:1234:1234:1234, 1234:1234:0:1234:1234:1234:1234:1234}
ip6 daddr != ::1234:1234:1234:1234:1234:1234:1234-1234:1234::1234:1234:1234:1234:1234;ok;ip6 daddr != 0:1234:1234:1234:1234:1234:1234:1234-1234:1234:0:1234:1234:1234:1234:1234
+ip6 saddr 192.168.1.1;ok;ip6 saddr ::ffff:192.168.1.1
+
# limit impact to lo
iif "lo" ip6 daddr set ::1;ok
iif "lo" ip6 hoplimit set 1;ok
@@ -1401,6 +1401,22 @@
}
]
+# ip6 saddr 192.168.1.1
+[
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "saddr",
+ "protocol": "ip6"
+ }
+ },
+ "op": "==",
+ "right": "192.168.1.1"
+ }
+ }
+]
+
# iif "lo" ip6 daddr set ::1
[
{
@@ -372,3 +372,18 @@
}
]
+# ip6 saddr 192.168.1.1
+[
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "saddr",
+ "protocol": "ip6"
+ }
+ },
+ "op": "==",
+ "right": "::ffff:192.168.1.1"
+ }
+ }
+]
@@ -592,6 +592,13 @@ inet test-inet input
[ payload load 16b @ network header + 24 => reg 1 ]
[ range neq reg 1 0x34120000 0x34123412 0x34123412 0x34123412 0x34123412 0x34120000 0x34123412 0x34123412 ]
+# ip6 saddr 192.168.1.1
+inet test-inet input
+ [ meta load nfproto => reg 1 ]
+ [ cmp eq reg 1 0x0000000a ]
+ [ payload load 16b @ network header + 8 => reg 1 ]
+ [ cmp eq reg 1 0x00000000 0x00000000 0xffff0000 0x0101a8c0 ]
+
# iif "lo" ip6 daddr set ::1
inet test-inet input
[ meta load iif => reg 1 ]
@@ -442,6 +442,11 @@ ip6 test-ip6 input
[ payload load 16b @ network header + 24 => reg 1 ]
[ range neq reg 1 0x34120000 0x34123412 0x34123412 0x34123412 0x34123412 0x34120000 0x34123412 0x34123412 ]
+# ip6 saddr 192.168.1.1
+ip6 test-ip6 input
+ [ payload load 16b @ network header + 8 => reg 1 ]
+ [ cmp eq reg 1 0x00000000 0x00000000 0xffff0000 0x0101a8c0 ]
+
# iif "lo" ip6 daddr set ::1
ip6 test-ip6 input
[ meta load iif => reg 1 ]
@@ -2,5 +2,5 @@
*ip6;test-ip6;output
-rt nexthop 192.168.0.1;fail
+rt nexthop 192.168.0.1;ok;rt ip6 nexthop ::ffff:192.168.0.1
rt nexthop fd00::1;ok;rt ip6 nexthop fd00::1
@@ -1,3 +1,18 @@
+# rt nexthop 192.168.0.1
+[
+ {
+ "match": {
+ "left": {
+ "rt": {
+ "key": "nexthop"
+ }
+ },
+ "op": "==",
+ "right": "192.168.0.1"
+ }
+ }
+]
+
# rt nexthop fd00::1
[
{
@@ -1,3 +1,8 @@
+# rt nexthop 192.168.0.1
+ip6 test-ip6 output
+ [ rt load nexthop6 => reg 1 ]
+ [ cmp eq reg 1 0x00000000 0x00000000 0xffff0000 0x0100a8c0 ]
+
# rt nexthop fd00::1
ip6 test-ip6 output
[ rt load nexthop6 => reg 1 ]
@@ -17,7 +17,7 @@
?set2 1234:1234::1234:1234:1234:1234:1234;ok
?set2 1234::1234:1234:1234;ok
?set2 1234:1234:1234:1234:1234::1234:1234, 1234:1234::123;ok
-?set2 192.168.3.8, 192.168.3.9;fail
+?set2 192.168.3.8, 192.168.3.9;ok
?set2 1234:1234::1234:1234:1234:1234;ok
?set2 1234:1234::1234:1234:1234:1234;ok
?set2 1234:1234:1234::1234;ok
@@ -48,4 +48,4 @@ add @map1 { ip6 saddr . ip6 daddr : meta mark };ok
delete @set5 { ip6 saddr . ip6 daddr };ok
!map2 type ipv6_addr . ipv6_addr . inet_service : ipv6_addr . inet_service;ok
-add @map2 { ip6 saddr . ip6 daddr . th dport : 1234::1 . 80 };ok
\ No newline at end of file
+add @map2 { ip6 saddr . ip6 daddr . th dport : 1234::1 . 80 };ok
Complement on-demand ip {s,d}addr expression conversion to IPv4-mapped IPv6 by accepting IPv4 addresses in places where an IPv6 one is expected. This way users don't have to use IPv4-mapped notation when populating sets. In order to avoid chaos and breakage, prevent host names (temporarily) resolving to IPv4 addresses only from being accepted as IPv6 address. Map IPv4 addresses only if users explicitly specified them. Suggested-by: Florian Westphal <fw@strlen.de> Signed-off-by: Phil Sutter <phil@nwl.cc> --- src/datatype.c | 10 +++- tests/py/inet/dnat.t | 6 +-- tests/py/inet/dnat.t.json | 72 +++++++++++++++++++++++++++++ tests/py/inet/dnat.t.payload | 24 ++++++++++ tests/py/inet/sets.t | 2 +- tests/py/inet/sets.t.json | 19 ++++++++ tests/py/inet/sets.t.payload.bridge | 9 ++++ tests/py/inet/sets.t.payload.inet | 9 ++++ tests/py/inet/sets.t.payload.netdev | 9 ++++ tests/py/inet/snat.t | 2 +- tests/py/inet/snat.t.json | 9 ++++ tests/py/inet/snat.t.json.output | 9 ++++ tests/py/inet/snat.t.payload | 5 ++ tests/py/ip/ip.t | 2 +- tests/py/ip6/ip6.t | 2 + tests/py/ip6/ip6.t.json | 16 +++++++ tests/py/ip6/ip6.t.json.output | 15 ++++++ tests/py/ip6/ip6.t.payload.inet | 7 +++ tests/py/ip6/ip6.t.payload.ip6 | 5 ++ tests/py/ip6/rt0.t | 2 +- tests/py/ip6/rt0.t.json | 15 ++++++ tests/py/ip6/rt0.t.payload | 5 ++ tests/py/ip6/sets.t | 4 +- 23 files changed, 248 insertions(+), 10 deletions(-)