| Commit message (Collapse) | Author | Age | Files | Lines |
| |
|
| |
|
| |
|
| |
|
| |
|
| |
|
|\
| |
| | |
Support ipv6 for masquerade and dnat in nspawn and networkd
|
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| | |
The nft set backend doesn't support network masks, it works with
ranges. Inputs like dead::/64 thus need to be translated to two
'start' and 'end' elements.
The 'start' element is the first element in the range (i.e., dead::).
The 'stop' element is the first element *past* the range, (dead:0:0100::
in the example).
This adds a few test cases.
|
| |
| |
| |
| |
| |
| |
| | |
In case external entity wiped the ruleset, we need to clear the
'previous' address -- its already gone.
This prevents the transaction from succeeding: the delete operation fails.
|
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| | |
closely mirrors the existing ipv4 ruleset:
table ip6 io.systemd.nat {
set masq_saddr {
type ipv6_addr
flags interval
}
map map_port_ipport {
type inet_proto . inet_service : ipv6_addr . inet_service
}
chain prerouting {
type nat hook prerouting priority dstnat + 1; policy accept;
fib daddr type local dnat ip6 addr . port to meta l4proto . th dport map @map_port_ipport
}
chain output {
type nat hook output priority -99; policy accept;
ip6 daddr != ::1 oif "lo" dnat ip6 addr . port to meta l4proto . th dport map @map_port_ipport
}
chain postrouting {
type nat hook postrouting priority srcnat + 1; policy accept;
ip6 saddr @masq_saddr masquerade
}
}
Only difference is the use of ipv6 addresses instead of ipv4 ones.
Currently has no effect: all in-tree callers pass AF_INET exclusively.
Followup patches will make nspawn expose ipv6 too and rework
IPMasquerade option to support both/v4/v6.
|
|/
|
|
|
| |
Follow-up for db9ecf050165fd1033c6f81485917e229c4be537 and
faa73d4e0c8095fedd98ff29851b9634810ff97e.
|
| |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
When someone runs 'nft flush ruleset' in the same net namespace
this will also tear down the systemd nat table.
Unlike iptables -t nat -F, which will remove all rules added by
the systemd iptables backend, iptables has builtin chains that cannot
be deleted. IOW, the next add operation will 'just work'.
In the nftables case however, the entire table gets removed.
When the systemd nat table is removed by an external entity next
attempt to add a set element will yield -ENOENT.
If this happens, recreate the table, and, if successful, re-do
the add operation.
Note that this doesn't protect against external sabotage such as
a running 'while true; nft flush ruleset;done'. However, there is
nothing that could be done short of extending the kernel to allow
tables to be "frozen" or otherwise tied to a process such as
systemd-networkd.
|
|
Idea is to use a static ruleset, added when the first attempt to
add a masquerade or dnat rule is made.
The alternative would be to add the ruleset when the init function is called.
The disadvantage is that this enables connection tracking and NAT in the kernel
(as the ruleset needs this to work), which comes with some overhead that might
not be needed (no nspawn usage and no IPMasquerade option set).
There is no additional dependency on the 'nft' userspace binary or other libraries.
sd-netlinks nfnetlink backend is used to modify the nftables ruleset.
The commit message/comments still use nft syntax since that is what
users will see when they use the nft tool to list the ruleset.
The added initial skeleton (added on first fw_add_masquerade/local_dnat
call) looks like this:
table ip io.systemd.nat {
set masq_saddr {
type ipv4_addr
flags interval
elements = { 192.168.59.160/28 }
}
map map_port_ipport {
type inet_proto . inet_service : ipv4_addr . inet_service
elements = { tcp . 2222 : 192.168.59.169 . 22 }
}
chain prerouting {
type nat hook prerouting priority dstnat + 1; policy accept;
fib daddr type local dnat ip addr . port to meta l4proto . th dport map @map_port_ipport
}
chain output {
type nat hook output priority -99; policy accept;
ip daddr != 127.0.0.0/8 oif "lo" dnat ip addr . port to meta l4proto . th dport map @map_port_ipport
}
chain postrouting {
type nat hook postrouting priority srcnat + 1; policy accept;
ip saddr @masq_saddr masquerade
}
}
Next calls to fw_add_masquerade/add_local_dnat will then only add/delete the
element/mapping to masq_saddr and map_port_ipport, i.e. the ruleset doesn't
change -- only the set/map content does.
Running test-firewall-util with this backend gives following output
on a parallel 'nft monitor':
$ nft monitor
add table ip io.systemd.nat
add chain ip io.systemd.nat prerouting { type nat hook prerouting priority dstnat + 1; policy accept; }
add chain ip io.systemd.nat output { type nat hook output priority -99; policy accept; }
add chain ip io.systemd.nat postrouting { type nat hook postrouting priority srcnat + 1; policy accept; }
add set ip io.systemd.nat masq_saddr { type ipv4_addr; flags interval; }
add map ip io.systemd.nat map_port_ipport { type inet_proto . inet_service : ipv4_addr . inet_service; }
add rule ip io.systemd.nat prerouting fib daddr type local dnat ip addr . port to meta l4proto . th dport map @map_port_ipport
add rule ip io.systemd.nat output ip daddr != 127.0.0.0/8 fib daddr type local dnat ip addr . port to meta l4proto . th dport map @map_port_ipport
add rule ip io.systemd.nat postrouting ip saddr @masq_saddr masquerade
add element ip io.systemd.nat masq_saddr { 10.1.2.3 }
add element ip io.systemd.nat masq_saddr { 10.0.2.0/28 }
delete element ip io.systemd.nat masq_saddr { 10.0.2.0/28 }
delete element ip io.systemd.nat masq_saddr { 10.1.2.3 }
add element ip io.systemd.nat map_port_ipport { tcp . 4711 : 1.2.3.4 . 815 }
delete element ip io.systemd.nat map_port_ipport { tcp . 4711 : 1.2.3.4 . 815 }
add element ip io.systemd.nat map_port_ipport { tcp . 4711 : 1.2.3.5 . 815 }
delete element ip io.systemd.nat map_port_ipport { tcp . 4711 : 1.2.3.5 . 815 }
CTRL-C
Things not implemented/supported:
1. Change monitoring. The kernel allows userspace to learn about changes
made by other clients (using nfnetlink notifications). It would be
possible to detect when e.g. someone removes the systemd nat table.
This would need more work. Its also not clear on how to react to
external changes -- it doesn't seem like a good idea to just auto-undo
everthing.
2. 'set masq_saddr' doesn't handle overlaps.
Example:
fw_add_masquerade(true, AF_INET, "10.0.0.0" , 16);
fw_add_masquerade(true, AF_INET, "10.0.0.0" , 8); /* fails */
With the iptables backend the second call works, as it adds an
independent iptables rule.
With the nftables backend, the range 10.0.0.0-10.255.255.255 clashes with
the existing range of 10.0.0.0-10.0.255.255 so 2nd add gets rejected by the
kernel.
This will generate an error message from networkd ("Could not enable IP
masquerading: File exists").
To resolve this it would be needed to either keep track of the added elements
and perform range merging when overlaps are detected.
However, the add erquests are done using the configured network on a
device, so no overlaps should occur in normal setups.
IPv6 support is added in a extra changeset.
Fixes: #13307
|