netfilter: autoload NAT support for non-builtin L4 protocols
Subsystems (2)
cover netfilter: autoload NAT support for non-builtin L4 protocols
this series fixes SNAT/DNAT rules where port number translation is explicitly configured, but only the L3 address is translated:
# iptables -t nat -A POSTROUTING -o eth1 -p stcp -j SNAT --to-source 10.0.0.1:61000
# tcpdump -s46 -tni eth1 sctp
tcpdump: verbose output suppressed, use -v or -vv for full protocol decode
listening on eth1, link-type EN10MB (Ethernet), capture size 46 bytes
IP 10.0.0.1.37788 > 10.0.0.2.2000: sctp
^^^^^
IP 10.0.0.2.2000 > 10.0.0.1.37788: sctp
IP 10.0.0.1.37788 > 10.0.0.2.2000: sctp
IP 10.0.0.2.2000 > 10.0.0.1.37788: sctp
IP 10.0.0.2.2000 > 10.0.0.1.37788: sctp
IP 10.0.0.1.37788 > 10.0.0.2.2000: sctp
IP 10.0.0.2.2000 > 10.0.0.1.37788: sctpThis happens for all protocols that don't have L4 NAT support built into nf_nat.ko, such as DCCP, SCTP and UDPLite: unless the user modprobes nf_nat_proto_{dccp,sctp,udplite}.ko, port translation as specified in the above rule will not be done.
The first patch provides persistent and generic aliases for the above modules; the second patch autoloads nf_nat_proto_{dccp,sctp,udplite} when a SNAT/DNAT rule matching one of the above protocols is created.
Davide Caratti (2):
netfilter: persistent aliases for l4 nat protocols
xt_nat: probe module for non-builtin L4 protocols
include/net/netfilter/nf_nat_l4proto.h | 3 +++ net/netfilter/nf_nat_proto_dccp.c | 1 + net/netfilter/nf_nat_proto_sctp.c | 1 + net/netfilter/nf_nat_proto_udplite.c | 1 + net/netfilter/xt_nat.c | 47 ++++++++++++++++++++++++++++++++++ 5 files changed, 53 insertions(+)
Signature · 1 line
2.5.5
PATCH 1/2 netfilter: persistent aliases for l4 nat protocols
add macro MODULE_ALIAS_NF_NAT_L4PROTO to provide generic and persistent aliases for those layer-4 transport protocols whose NAT support is not built-in into nf_nat.ko.
--- include/net/netfilter/nf_nat_l4proto.h | 3 +++ net/netfilter/nf_nat_proto_dccp.c | 1 + net/netfilter/nf_nat_proto_sctp.c | 1 + net/netfilter/nf_nat_proto_udplite.c | 1 + 4 files changed, 6 insertions(+)
include/net/netfilter/nf_nat_l4proto.h +3 -0
@@ -69,4 +69,7 @@ void nf_nat_l4proto_unique_tuple(const struct nf_nat_l3proto *l3proto,int nf_nat_l4proto_nlattr_to_range (struct nlattr *tb[],struct nf_nat_range *range); +#define MODULE_ALIAS_NF_NAT_L4PROTO (l4protocol) \ + MODULE_ALIAS("nf-nat-l4-" __stringify(l4protocol)) +#endif /*_NF_NAT_L4PROTO_H*/
net/netfilter/nf_nat_proto_dccp.c +1 -0
@@ -114,3 +114,4 @@ module_exit(nf_nat_proto_dccp_fini);MODULE_AUTHOR ("Patrick McHardy <[email protected]>" );MODULE_DESCRIPTION ("DCCP NAT protocol helper" );MODULE_LICENSE ("GPL" ); +MODULE_ALIAS_NF_NAT_L4PROTO (33 );/* IPPROTO_DCCP */
net/netfilter/nf_nat_proto_sctp.c +1 -0
@@ -94,3 +94,4 @@ module_exit(nf_nat_proto_sctp_exit);MODULE_LICENSE ("GPL" );MODULE_DESCRIPTION ("SCTP NAT protocol helper" );MODULE_AUTHOR ("Patrick McHardy <[email protected]>" ); +MODULE_ALIAS_NF_NAT_L4PROTO (132 );/* IPPROTO_SCTP */
net/netfilter/nf_nat_proto_udplite.c +1 -0
@@ -104,3 +104,4 @@ module_exit(nf_nat_proto_udplite_fini);MODULE_LICENSE ("GPL" );MODULE_DESCRIPTION ("UDP-Lite NAT protocol helper" );MODULE_AUTHOR ("Patrick McHardy <[email protected]>" ); +MODULE_ALIAS_NF_NAT_L4PROTO (136 );/* IPPROTO_UDPLITE */
Signature · 1 line
2.5.5
PATCH 2/2 xt_nat: probe module for non-builtin L4 protocols
In reply to Davide Carattiautoload nf_nat_proto_{dccp,sctp,udplite}.ko on invocation of checkentry() callback, if rule matches DCCP, SCTP or UDPLITE protocols. This avoids situations where, after a SNAT/DNAT rule with specified sport/dport is created, no port translation is done unless the user manually loads nf_nat_proto_{dccp,udplite,sctp}.ko with insmod/modprobe commands.
--- net/netfilter/xt_nat.c | 47 +++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 47 insertions(+)
net/netfilter/xt_nat.c +47 -0
@@ -13,6 +13,44 @@#include <linux/netfilter.h> #include <linux/netfilter/x_tables.h> #include <net/netfilter/nf_nat_core.h> +#include <net/netfilter/nf_nat_l4proto.h> +#include <linux/netfilter_ipv4/ip_tables.h> +#include <linux/netfilter_ipv6/ip6_tables.h> + +static void xt_nat_probe_proto (const struct xt_tgchk_param *par) +{ +const struct ip6t_ip6 *i6; +const struct ipt_ip *i; +u8 proto, l4proto; + +switch (par->family) { +case NFPROTO_IPV4 : + i = (const struct ipt_ip *)par->entryinfo; +if (i->invflags &IPT_INV_PROTO ) +return ; + proto = i->proto; +break ; +case NFPROTO_IPV6 : + i6 = (const struct ip6t_ip6 *)par->entryinfo; +if (i6->invflags &IP6T_INV_PROTO ) +return ; + proto = i6->proto; +break ; +default : +return ; + } + +switch (proto) { +case IPPROTO_UDPLITE : +case IPPROTO_SCTP : +case IPPROTO_DCCP : +rcu_read_lock (); + l4proto =__nf_nat_l4proto_find (par->family, proto)->l4proto; +rcu_read_unlock (); +if (!l4proto) +request_module ("nf-nat-l4-%u" , proto); + } +}static int xt_nat_checkentry_v0 (const struct xt_tgchk_param *par) {
@@ -23,6 +61,13 @@ static int xt_nat_checkentry_v0(const struct xt_tgchk_param *par) par->target->name);return -EINVAL ; } +xt_nat_probe_proto (par); +return 0 ; +} + +static int xt_nat_checkentry_v1 (const struct xt_tgchk_param *par) +{ +xt_nat_probe_proto (par);return 0 ; }
@@ -129,6 +174,7 @@ static struct xt_target xt_nat_target_reg[] __read_mostly = { { .name = "SNAT", .revision = 1, + .checkentry = xt_nat_checkentry_v1, .target = xt_snat_target_v1, .targetsize = sizeof(struct nf_nat_range), .table = "nat",
@@ -139,6 +185,7 @@ static struct xt_target xt_nat_target_reg[] __read_mostly = { { .name = "DNAT", .revision = 1, + .checkentry = xt_nat_checkentry_v1, .target = xt_dnat_target_v1, .targetsize = sizeof(struct nf_nat_range), .table = "nat",
Signature · 1 line
2.5.5
Quoted 16 lines · Davide Caratti
this series fixes SNAT/DNAT rules where port number translation is explicitly configured, but only the L3 address is translated:
# iptables -t nat -A POSTROUTING -o eth1 -p stcp -j SNAT --to-source 10.0.0.1:61000 # tcpdump -s46 -tni eth1 sctp tcpdump: verbose output suppressed, use -v or -vv for full protocol decode listening on eth1, link-type EN10MB (Ethernet), capture size 46 bytes IP 10.0.0.1.37788 > 10.0.0.2.2000: sctp ^^^^^ IP 10.0.0.2.2000 > 10.0.0.1.37788: sctp IP 10.0.0.1.37788 > 10.0.0.2.2000: sctp IP 10.0.0.2.2000 > 10.0.0.1.37788: sctp IP 10.0.0.2.2000 > 10.0.0.1.37788: sctp IP 10.0.0.1.37788 > 10.0.0.2.2000: sctp IP 10.0.0.2.2000 > 10.0.0.1.37788: sctp
Quoted 8 lines
This happens for all protocols that don't have L4 NAT support built into nf_nat.ko, such as DCCP, SCTP and UDPLite: unless the user modprobes nf_nat_proto_{dccp,sctp,udplite}.ko, port translation as specified in the above rule will not be done.
The first patch provides persistent and generic aliases for the above modules; the second patch autoloads nf_nat_proto_{dccp,sctp,udplite} when a SNAT/DNAT rule matching one of the above protocols is created.
Since I can add the same rule in nftables, I wonder if the same problem happens:
chain postrouting {
type nat hook postrouting priority 0; policy accept; ip protocol sctp snat 10.0.0.1:61000
}
Signature · 1 line
Arturo Borrero González
Quoted 8 lines · Arturo Borrero Gonzalez
Since I can add the same rule in nftables, I wonder if the same problem happens:
chain postrouting {
type nat hook postrouting priority 0; policy accept; ip protocol sctp snat 10.0.0.1:61000
}
hello Arturo,
thank you for looking at this. I just did a test following your suggestion:
# iptables -F -t nat
# rmmod nf_nat_proto_sctp
# nft add table nat
# nft add chain nat prerouting { type nat hook prerouting priority 1 \; }
# nft add chain nat postrouting { type nat hook postrouting priority 0 \; }
# nft add rule nat postrouting oif eth1 ip protocol sctp snat 10.0.0.1:61000
# IP 10.0.0.1.55836 > 10.0.0.2.2000: sctp
IP 10.0.0.2.2000 > 10.0.0.1.55836: sctp
IP 10.0.0.1.55836 > 10.0.0.2.2000: sctp
IP 10.0.0.2.2000 > 10.0.0.1.55836: sctp
IP 10.0.0.1.55836 > 10.0.0.2.2000: sctp
IP 10.0.0.2.2000 > 10.0.0.1.55836: sctp
IP 10.0.0.1.55836 > 10.0.0.2.2000: sctp
IP 10.0.0.2.2000 > 10.0.0.1.55836: sctp
IP 10.0.0.1.55836 > 10.0.0.2.2000: sctp
# modprobe nf_nat_proto_sctp
# IP 10.0.0.1.61000 > 10.0.0.2.2000: sctp
IP 10.0.0.2.2000 > 10.0.0.1.61000: sctp
IP 10.0.0.1.61000 > 10.0.0.2.2000: sctp
IP 10.0.0.2.2000 > 10.0.0.1.61000: sctp
IP 10.0.0.1.61000 > 10.0.0.2.2000: sctp
IP 10.0.0.2.2000 > 10.0.0.1.61000: sctp
IP 10.0.0.1.61000 > 10.0.0.2.2000: sctp
IP 10.0.0.2.2000 > 10.0.0.1.61000: sctp
IP 10.0.0.1.61000 > 10.0.0.2.2000: sctp
#you are right, unless you manually modprobe nf_nat_proto_sctp.ko, you will see wrong port translation also with nftables, and this patch does not fix it. Then I will submit a v2 that also handles nftables.
regards,
--
davide
Quoted 41 lines · Davide Caratti
Quoted 8 lines · Arturo Borrero Gonzalez
Since I can add the same rule in nftables, I wonder if the same problem happens:
chain postrouting {
type nat hook postrouting priority 0; policy accept; ip protocol sctp snat 10.0.0.1:61000
}hello Arturo,
thank you for looking at this. I just did a test following your suggestion:
# iptables -F -t nat # rmmod nf_nat_proto_sctp # nft add table nat # nft add chain nat prerouting { type nat hook prerouting priority 1 \; } # nft add chain nat postrouting { type nat hook postrouting priority 0 \; } # nft add rule nat postrouting oif eth1 ip protocol sctp snat 10.0.0.1:61000 # IP 10.0.0.1.55836 > 10.0.0.2.2000: sctp IP 10.0.0.2.2000 > 10.0.0.1.55836: sctp IP 10.0.0.1.55836 > 10.0.0.2.2000: sctp IP 10.0.0.2.2000 > 10.0.0.1.55836: sctp IP 10.0.0.1.55836 > 10.0.0.2.2000: sctp IP 10.0.0.2.2000 > 10.0.0.1.55836: sctp IP 10.0.0.1.55836 > 10.0.0.2.2000: sctp IP 10.0.0.2.2000 > 10.0.0.1.55836: sctp IP 10.0.0.1.55836 > 10.0.0.2.2000: sctp # modprobe nf_nat_proto_sctp # IP 10.0.0.1.61000 > 10.0.0.2.2000: sctp IP 10.0.0.2.2000 > 10.0.0.1.61000: sctp IP 10.0.0.1.61000 > 10.0.0.2.2000: sctp IP 10.0.0.2.2000 > 10.0.0.1.61000: sctp IP 10.0.0.1.61000 > 10.0.0.2.2000: sctp IP 10.0.0.2.2000 > 10.0.0.1.61000: sctp IP 10.0.0.1.61000 > 10.0.0.2.2000: sctp IP 10.0.0.2.2000 > 10.0.0.1.61000: sctp IP 10.0.0.1.61000 > 10.0.0.2.2000: sctp #
Quoted 4 lines
you are right, unless you manually modprobe nf_nat_proto_sctp.ko, you will see wrong port translation also with nftables, and this patch does not fix it. Then I will submit a v2 that also handles nftables.
Thanks Davide for your work and time.
Unlike in iptables, in nftables we don't know the expected l4 protocol at rule setup time.
In the iptables<->nftables compat layer, we have an expression attribute which is filled from userspace with the l4 protocol (NFTA_RULE_COMPAT_PROTO).
Not sure if it's worth adding a new netlink attribute for nft_nat to tell the expression about the expected l4 NAT protocol.
Signature · 1 line
Arturo Borrero González
Florian Westphal
maintainerQuoted 9 lines · Arturo Borrero Gonzalez
Unlike in iptables, in nftables we don't know the expected l4 protocol at rule setup time.
In the iptables<->nftables compat layer, we have an expression attribute which is filled from userspace with the l4 protocol (
NFTA_RULE_COMPAT_PROTO).Not sure if it's worth adding a new netlink attribute for
nft_natto tell the expression about the expected l4 NAT protocol.
Right, it might more sense to handle this in nft frontend instead.
Pablo Neira Ayuso
maintainerQuoted 16 lines · Davide Caratti
this series fixes SNAT/DNAT rules where port number translation is explicitly configured, but only the L3 address is translated:
# iptables -t nat -A POSTROUTING -o eth1 -p stcp -j SNAT --to-source 10.0.0.1:61000 # tcpdump -s46 -tni eth1 sctp tcpdump: verbose output suppressed, use -v or -vv for full protocol decode listening on eth1, link-type EN10MB (Ethernet), capture size 46 bytes IP 10.0.0.1.37788 > 10.0.0.2.2000: sctp ^^^^^ IP 10.0.0.2.2000 > 10.0.0.1.37788: sctp IP 10.0.0.1.37788 > 10.0.0.2.2000: sctp IP 10.0.0.2.2000 > 10.0.0.1.37788: sctp IP 10.0.0.2.2000 > 10.0.0.1.37788: sctp IP 10.0.0.1.37788 > 10.0.0.2.2000: sctp IP 10.0.0.2.2000 > 10.0.0.1.37788: sctp
Quoted 7 lines
This happens for all protocols that don't have L4 NAT support built into nf_nat.ko, such as DCCP, SCTP and UDPLite: unless the user modprobes nf_nat_proto_{dccp,sctp,udplite}.ko, port translation as specified in the above rule will not be done.
The first patch provides persistent and generic aliases for the above modules; the second patch autoloads nf_nat_proto_{dccp,sctp,udplite} when a SNAT/DNAT rule matching one of the above protocols is created.
I would really like to see DCCP, SCTP and UDPlite built-in, just like other protocol trackers (TCP, UDP...). This may require a bit of review work on your/our side, but it would greatly appreciated.
We discussed this during the last Netfilter Workshop, the current situation is not good, we're in some way responsible for breaking the deployment of new protocols on the Internet.
Many vendors rely on default configurations, not even looking into modprobing things, so these protocols are hopeless in the current situation since routers running Netfilter will likely not supported them. This is worse since nf_conntrack drops packets for protocols like SCTP and DCCP since the generic protocol can no longer be used.
Once these protocols are supported built-in, users can configure from our control plane, ie. iptables/nft, if they explicitly don't want to allow them by dropping protocols of this kind. But in that case we would not be responsible anymore for the current situation at least.
Moreover, following this approach, we would also avoid the new attribute in nft_nat to indicate the layer 4 protocol that you have mentioned already.
Thanks!
hello Pablo,
Quoted 3 lines · Pablo Neira Ayuso
I would really like to see DCCP, SCTP and UDPlite built-in, just like other protocol trackers (TCP, UDP...). This may require a bit of review work on your/our side, but it would greatly appreciated.
thank you for looking at this. At the moment, I'm testing a v2 of this patch extending to REDIRECT targets _ which are exposing the same issue as SNAT and DNAT, and using existing NFTA_RULE_COMPAT_PROTO attribute to carry the transport protocol number in case a SNAT/DNAT/REDIRECT target is specified in a nftables statement.
Quoted 5 lines
Many vendors rely on default configurations, not even looking into modprobing things, so these protocols are hopeless in the current situation since routers running Netfilter will likely not supported them. This is worse since
nf_conntrackdrops packets for protocols like SCTP and DCCP since the generic protocol can no longer be used.
true, unless user modprobes nf_conntrack_proto_{dccp,udplite,sctp}, any SNAT/DNAT/REDIRECT rule will not be hit by traffic.
Quoted 8 lines
Once these protocols are supported built-in, users can configure from our control plane, ie. iptables/nft, if they explicitly don't want to allow them by dropping protocols of this kind. But in that case we would not be responsible anymore for the current situation at least.
Moreover, following this approach, we would also avoid the new attribute in
nft_natto indicate the layer 4 protocol that you have mentioned already.
Ok - so do you think it's better to have nf_nat_proto_{dccp,sctp,udplite}.o built into nf_nat.ko and nf_conntrack_proto_{dccp,sctp,udplite}.o, and maybe also nf_conntrack_proto_gre.o, built into nf_conntrack.ko?
thank you in advance,
regards
--
davide
Pablo Neira Ayuso
maintainerOn Tue, Oct 18, 2016 at 11:12:42AM +0200, Davide Caratti wrote:
[...]
Quoted 5 lines
Quoted 5 lines
Once these protocols are supported built-in, users can configure from our control plane, ie. iptables/nft, if they explicitly don't want to allow them by dropping protocols of this kind. But in that case we would not be responsible anymore for the current situation at least.
Quoted 7 lines
Quoted 3 lines
Moreover, following this approach, we would also avoid the new attribute in
nft_natto indicate the layer 4 protocol that you have mentioned already.Ok - so do you think it's better to have nf_nat_proto_{dccp,sctp,udplite}.o built into nf_nat.ko and nf_conntrack_proto_{dccp,sctp,udplite}.o,
Yes. We agreed on doing so during the Netfilter Workshop Amsterdam.
Quoted 2 lines
and maybe also nf_conntrack_proto_gre.o, built into nf_conntrack.ko?
Please, keep gre back by now, I think this is quite specific of the pptp conntrack helper that we have in the tree and it only works for IPv4 and it cannot work with NAT either, it's very limited. So please start by building in dccp, sctp and udplite protocols.
Thanks.
Florian Westphal
maintainerQuoted 11 lines · Pablo Neira Ayuso
On Tue, Oct 18, 2016 at 11:12:42AM +0200, Davide Caratti wrote:
[...]Quoted 9 lines
Quoted 8 lines
Once these protocols are supported built-in, users can configure from our control plane, ie. iptables/nft, if they explicitly don't want to allow them by dropping protocols of this kind. But in that case we would not be responsible anymore for the current situation at least.
Moreover, following this approach, we would also avoid the new attribute in
nft_natto indicate the layer 4 protocol that you have mentioned already.
Quoted 5 lines
Quoted 3 lines
Ok - so do you think it's better to have nf_nat_proto_{dccp,sctp,udplite}.o built into nf_nat.ko and nf_conntrack_proto_{dccp,sctp,udplite}.o,
Yes. We agreed on doing so during the Netfilter Workshop Amsterdam.
Hmm, did we? I wonder what my opinion on that subject was :)
Quoted 7 lines
Quoted 2 lines
and maybe also nf_conntrack_proto_gre.o, built into nf_conntrack.ko?
Please, keep gre back by now, I think this is quite specific of the pptp conntrack helper that we have in the tree and it only works for IPv4 and it cannot work with NAT either, it's very limited. So please start by building in dccp, sctp and udplite protocols.
Wrt. udplite, I think it makes sense to merge it into udp one, I suspect a lot of this becomes redundant after some refactoring.
For sctp I am not so sure, it will add a dependency of conntrack on crc32, but maybe thats not so important...?
Merging NAT makes sense, the external helper modules are very small (~120 lines inlcuding boilerplate...).
Pablo Neira Ayuso
maintainerQuoted 1 line · Florian Westphal
Pablo Neira Ayuso <[email protected]> wrote:
[...]
Quoted 10 lines
Quoted 7 lines
Quoted 2 lines
and maybe also nf_conntrack_proto_gre.o, built into nf_conntrack.ko?
Please, keep gre back by now, I think this is quite specific of the pptp conntrack helper that we have in the tree and it only works for IPv4 and it cannot work with NAT either, it's very limited. So please start by building in dccp, sctp and udplite protocols.
Wrt. udplite, I think it makes sense to merge it into udp one, I suspect a lot of this becomes redundant after some refactoring.
At quick glance, udplite is a copy and paste from udp trackers, except for the udplite_error() function. So glad to see this merged into UDP.
Quoted 2 lines
For sctp I am not so sure, it will add a dependency of conntrack on crc32, but maybe thats not so important...?
Actually, this would add a dependency for nf_nat, not for nf_conntrack. The real crc32c implementation details are placed behind the crypto infrastructure, I don't see any way we can skip this.
We can still keep config NF_NAT_PROTO_SCTP around, just turn it into boolean toggle, so people can still compile this out if such dependency becomes a problem.
I would also remove 'default IP_SCTP' from CONFIG_NF_CT_PROTO_SCTP since we don't need any local SCTP stack support to forward packets.
Just to summarize: What we're discuss here is a good default configuration. After reading those RFCs that propose SCTP over UDP tunneling tricks to workaround firewalls on the Internet, my impression is that we may be probably responsible for this in some way.
Quoted 2 lines
Merging NAT makes sense, the external helper modules are very small (~120 lines inlcuding boilerplate...).
Correct, it's fairly small amount of code.