Merge branch 'main' of ssh://gitolite.kernel.org/pub/scm/linux/kernel/git/netfilter/nf-next
Florian Westphal says: ==================== netfilter updates for net-next This pull request contains changes for the *net-next* tree. 1. Change IPv6 stack to keep conntrack references until ipsec policy checks are done, like ipv4, from Madhu Koriginja. This update was missed when IPv6 NAT support was added 10 years ago. 2. get rid of old 'compat' structure layout in nf_nat_redirect core and move the conversion to the only user that needs the old layout for abi reasons. From Jeremy Sowden. 3. Compact some common code paths in nft_redir, also from Jeremy. 4. Time to remove the 'default y' knob so iptables 32bit compat interface isn't compiled in by default anymore, from myself. 5. Move ip(6)tables builtin icmp matches to the udptcp one. This has the advantage that icmp/icmpv6 match doesn't load the iptables/ip6tables modules anymore when iptables-nft is used. Also from myself. * 'main' of ssh://gitolite.kernel.org/pub/scm/linux/kernel/git/netfilter/nf-next: netfilter: keep conntrack reference until IPsecv6 policy checks are done xtables: move icmp/icmpv6 logic to xt_tcpudp netfilter: xtables: disable 32bit compat interface by default netfilter: nft_masq: deduplicate eval call-backs netfilter: nft_redir: use `struct nf_nat_range2` throughout and deduplicate eval call-backs ==================== Link: https://lore.kernel.org/r/20230322210802.6743-1-fw@strlen.de Signed-off-by: Jakub Kicinski <kuba@kernel.org>
This commit is contained in:
commit
e346df60b8
@ -6,8 +6,7 @@
|
|||||||
#include <uapi/linux/netfilter/nf_nat.h>
|
#include <uapi/linux/netfilter/nf_nat.h>
|
||||||
|
|
||||||
unsigned int
|
unsigned int
|
||||||
nf_nat_redirect_ipv4(struct sk_buff *skb,
|
nf_nat_redirect_ipv4(struct sk_buff *skb, const struct nf_nat_range2 *range,
|
||||||
const struct nf_nat_ipv4_multi_range_compat *mr,
|
|
||||||
unsigned int hooknum);
|
unsigned int hooknum);
|
||||||
unsigned int
|
unsigned int
|
||||||
nf_nat_redirect_ipv6(struct sk_buff *skb, const struct nf_nat_range2 *range,
|
nf_nat_redirect_ipv6(struct sk_buff *skb, const struct nf_nat_range2 *range,
|
||||||
|
@ -784,6 +784,7 @@ lookup:
|
|||||||
|
|
||||||
if (!xfrm6_policy_check(sk, XFRM_POLICY_IN, skb))
|
if (!xfrm6_policy_check(sk, XFRM_POLICY_IN, skb))
|
||||||
goto discard_and_relse;
|
goto discard_and_relse;
|
||||||
|
nf_reset_ct(skb);
|
||||||
|
|
||||||
return __sk_receive_skb(sk, skb, 1, dh->dccph_doff * 4,
|
return __sk_receive_skb(sk, skb, 1, dh->dccph_doff * 4,
|
||||||
refcounted) ? -1 : 0;
|
refcounted) ? -1 : 0;
|
||||||
|
@ -14,7 +14,6 @@
|
|||||||
#include <linux/vmalloc.h>
|
#include <linux/vmalloc.h>
|
||||||
#include <linux/netdevice.h>
|
#include <linux/netdevice.h>
|
||||||
#include <linux/module.h>
|
#include <linux/module.h>
|
||||||
#include <linux/icmp.h>
|
|
||||||
#include <net/ip.h>
|
#include <net/ip.h>
|
||||||
#include <net/compat.h>
|
#include <net/compat.h>
|
||||||
#include <linux/uaccess.h>
|
#include <linux/uaccess.h>
|
||||||
@ -31,7 +30,6 @@
|
|||||||
MODULE_LICENSE("GPL");
|
MODULE_LICENSE("GPL");
|
||||||
MODULE_AUTHOR("Netfilter Core Team <coreteam@netfilter.org>");
|
MODULE_AUTHOR("Netfilter Core Team <coreteam@netfilter.org>");
|
||||||
MODULE_DESCRIPTION("IPv4 packet filter");
|
MODULE_DESCRIPTION("IPv4 packet filter");
|
||||||
MODULE_ALIAS("ipt_icmp");
|
|
||||||
|
|
||||||
void *ipt_alloc_initial_table(const struct xt_table *info)
|
void *ipt_alloc_initial_table(const struct xt_table *info)
|
||||||
{
|
{
|
||||||
@ -1799,52 +1797,6 @@ void ipt_unregister_table_exit(struct net *net, const char *name)
|
|||||||
__ipt_unregister_table(net, table);
|
__ipt_unregister_table(net, table);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Returns 1 if the type and code is matched by the range, 0 otherwise */
|
|
||||||
static inline bool
|
|
||||||
icmp_type_code_match(u_int8_t test_type, u_int8_t min_code, u_int8_t max_code,
|
|
||||||
u_int8_t type, u_int8_t code,
|
|
||||||
bool invert)
|
|
||||||
{
|
|
||||||
return ((test_type == 0xFF) ||
|
|
||||||
(type == test_type && code >= min_code && code <= max_code))
|
|
||||||
^ invert;
|
|
||||||
}
|
|
||||||
|
|
||||||
static bool
|
|
||||||
icmp_match(const struct sk_buff *skb, struct xt_action_param *par)
|
|
||||||
{
|
|
||||||
const struct icmphdr *ic;
|
|
||||||
struct icmphdr _icmph;
|
|
||||||
const struct ipt_icmp *icmpinfo = par->matchinfo;
|
|
||||||
|
|
||||||
/* Must not be a fragment. */
|
|
||||||
if (par->fragoff != 0)
|
|
||||||
return false;
|
|
||||||
|
|
||||||
ic = skb_header_pointer(skb, par->thoff, sizeof(_icmph), &_icmph);
|
|
||||||
if (ic == NULL) {
|
|
||||||
/* We've been asked to examine this packet, and we
|
|
||||||
* can't. Hence, no choice but to drop.
|
|
||||||
*/
|
|
||||||
par->hotdrop = true;
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
return icmp_type_code_match(icmpinfo->type,
|
|
||||||
icmpinfo->code[0],
|
|
||||||
icmpinfo->code[1],
|
|
||||||
ic->type, ic->code,
|
|
||||||
!!(icmpinfo->invflags&IPT_ICMP_INV));
|
|
||||||
}
|
|
||||||
|
|
||||||
static int icmp_checkentry(const struct xt_mtchk_param *par)
|
|
||||||
{
|
|
||||||
const struct ipt_icmp *icmpinfo = par->matchinfo;
|
|
||||||
|
|
||||||
/* Must specify no unknown invflags */
|
|
||||||
return (icmpinfo->invflags & ~IPT_ICMP_INV) ? -EINVAL : 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
static struct xt_target ipt_builtin_tg[] __read_mostly = {
|
static struct xt_target ipt_builtin_tg[] __read_mostly = {
|
||||||
{
|
{
|
||||||
.name = XT_STANDARD_TARGET,
|
.name = XT_STANDARD_TARGET,
|
||||||
@ -1875,18 +1827,6 @@ static struct nf_sockopt_ops ipt_sockopts = {
|
|||||||
.owner = THIS_MODULE,
|
.owner = THIS_MODULE,
|
||||||
};
|
};
|
||||||
|
|
||||||
static struct xt_match ipt_builtin_mt[] __read_mostly = {
|
|
||||||
{
|
|
||||||
.name = "icmp",
|
|
||||||
.match = icmp_match,
|
|
||||||
.matchsize = sizeof(struct ipt_icmp),
|
|
||||||
.checkentry = icmp_checkentry,
|
|
||||||
.proto = IPPROTO_ICMP,
|
|
||||||
.family = NFPROTO_IPV4,
|
|
||||||
.me = THIS_MODULE,
|
|
||||||
},
|
|
||||||
};
|
|
||||||
|
|
||||||
static int __net_init ip_tables_net_init(struct net *net)
|
static int __net_init ip_tables_net_init(struct net *net)
|
||||||
{
|
{
|
||||||
return xt_proto_init(net, NFPROTO_IPV4);
|
return xt_proto_init(net, NFPROTO_IPV4);
|
||||||
@ -1914,19 +1854,14 @@ static int __init ip_tables_init(void)
|
|||||||
ret = xt_register_targets(ipt_builtin_tg, ARRAY_SIZE(ipt_builtin_tg));
|
ret = xt_register_targets(ipt_builtin_tg, ARRAY_SIZE(ipt_builtin_tg));
|
||||||
if (ret < 0)
|
if (ret < 0)
|
||||||
goto err2;
|
goto err2;
|
||||||
ret = xt_register_matches(ipt_builtin_mt, ARRAY_SIZE(ipt_builtin_mt));
|
|
||||||
if (ret < 0)
|
|
||||||
goto err4;
|
|
||||||
|
|
||||||
/* Register setsockopt */
|
/* Register setsockopt */
|
||||||
ret = nf_register_sockopt(&ipt_sockopts);
|
ret = nf_register_sockopt(&ipt_sockopts);
|
||||||
if (ret < 0)
|
if (ret < 0)
|
||||||
goto err5;
|
goto err4;
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
err5:
|
|
||||||
xt_unregister_matches(ipt_builtin_mt, ARRAY_SIZE(ipt_builtin_mt));
|
|
||||||
err4:
|
err4:
|
||||||
xt_unregister_targets(ipt_builtin_tg, ARRAY_SIZE(ipt_builtin_tg));
|
xt_unregister_targets(ipt_builtin_tg, ARRAY_SIZE(ipt_builtin_tg));
|
||||||
err2:
|
err2:
|
||||||
@ -1939,7 +1874,6 @@ static void __exit ip_tables_fini(void)
|
|||||||
{
|
{
|
||||||
nf_unregister_sockopt(&ipt_sockopts);
|
nf_unregister_sockopt(&ipt_sockopts);
|
||||||
|
|
||||||
xt_unregister_matches(ipt_builtin_mt, ARRAY_SIZE(ipt_builtin_mt));
|
|
||||||
xt_unregister_targets(ipt_builtin_tg, ARRAY_SIZE(ipt_builtin_tg));
|
xt_unregister_targets(ipt_builtin_tg, ARRAY_SIZE(ipt_builtin_tg));
|
||||||
unregister_pernet_subsys(&ip_tables_net_ops);
|
unregister_pernet_subsys(&ip_tables_net_ops);
|
||||||
}
|
}
|
||||||
|
@ -404,10 +404,6 @@ resubmit_final:
|
|||||||
/* Only do this once for first final protocol */
|
/* Only do this once for first final protocol */
|
||||||
have_final = true;
|
have_final = true;
|
||||||
|
|
||||||
/* Free reference early: we don't need it any more,
|
|
||||||
and it may hold ip_conntrack module loaded
|
|
||||||
indefinitely. */
|
|
||||||
nf_reset_ct(skb);
|
|
||||||
|
|
||||||
skb_postpull_rcsum(skb, skb_network_header(skb),
|
skb_postpull_rcsum(skb, skb_network_header(skb),
|
||||||
skb_network_header_len(skb));
|
skb_network_header_len(skb));
|
||||||
@ -430,10 +426,12 @@ resubmit_final:
|
|||||||
goto discard;
|
goto discard;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (!(ipprot->flags & INET6_PROTO_NOPOLICY) &&
|
if (!(ipprot->flags & INET6_PROTO_NOPOLICY)) {
|
||||||
!xfrm6_policy_check(NULL, XFRM_POLICY_IN, skb)) {
|
if (!xfrm6_policy_check(NULL, XFRM_POLICY_IN, skb)) {
|
||||||
SKB_DR_SET(reason, XFRM_POLICY);
|
SKB_DR_SET(reason, XFRM_POLICY);
|
||||||
goto discard;
|
goto discard;
|
||||||
|
}
|
||||||
|
nf_reset_ct(skb);
|
||||||
}
|
}
|
||||||
|
|
||||||
ret = INDIRECT_CALL_2(ipprot->handler, tcp_v6_rcv, udpv6_rcv,
|
ret = INDIRECT_CALL_2(ipprot->handler, tcp_v6_rcv, udpv6_rcv,
|
||||||
|
@ -18,7 +18,6 @@
|
|||||||
#include <linux/netdevice.h>
|
#include <linux/netdevice.h>
|
||||||
#include <linux/module.h>
|
#include <linux/module.h>
|
||||||
#include <linux/poison.h>
|
#include <linux/poison.h>
|
||||||
#include <linux/icmpv6.h>
|
|
||||||
#include <net/ipv6.h>
|
#include <net/ipv6.h>
|
||||||
#include <net/compat.h>
|
#include <net/compat.h>
|
||||||
#include <linux/uaccess.h>
|
#include <linux/uaccess.h>
|
||||||
@ -35,7 +34,6 @@
|
|||||||
MODULE_LICENSE("GPL");
|
MODULE_LICENSE("GPL");
|
||||||
MODULE_AUTHOR("Netfilter Core Team <coreteam@netfilter.org>");
|
MODULE_AUTHOR("Netfilter Core Team <coreteam@netfilter.org>");
|
||||||
MODULE_DESCRIPTION("IPv6 packet filter");
|
MODULE_DESCRIPTION("IPv6 packet filter");
|
||||||
MODULE_ALIAS("ip6t_icmp6");
|
|
||||||
|
|
||||||
void *ip6t_alloc_initial_table(const struct xt_table *info)
|
void *ip6t_alloc_initial_table(const struct xt_table *info)
|
||||||
{
|
{
|
||||||
@ -1805,52 +1803,6 @@ void ip6t_unregister_table_exit(struct net *net, const char *name)
|
|||||||
__ip6t_unregister_table(net, table);
|
__ip6t_unregister_table(net, table);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Returns 1 if the type and code is matched by the range, 0 otherwise */
|
|
||||||
static inline bool
|
|
||||||
icmp6_type_code_match(u_int8_t test_type, u_int8_t min_code, u_int8_t max_code,
|
|
||||||
u_int8_t type, u_int8_t code,
|
|
||||||
bool invert)
|
|
||||||
{
|
|
||||||
return (type == test_type && code >= min_code && code <= max_code)
|
|
||||||
^ invert;
|
|
||||||
}
|
|
||||||
|
|
||||||
static bool
|
|
||||||
icmp6_match(const struct sk_buff *skb, struct xt_action_param *par)
|
|
||||||
{
|
|
||||||
const struct icmp6hdr *ic;
|
|
||||||
struct icmp6hdr _icmph;
|
|
||||||
const struct ip6t_icmp *icmpinfo = par->matchinfo;
|
|
||||||
|
|
||||||
/* Must not be a fragment. */
|
|
||||||
if (par->fragoff != 0)
|
|
||||||
return false;
|
|
||||||
|
|
||||||
ic = skb_header_pointer(skb, par->thoff, sizeof(_icmph), &_icmph);
|
|
||||||
if (ic == NULL) {
|
|
||||||
/* We've been asked to examine this packet, and we
|
|
||||||
* can't. Hence, no choice but to drop.
|
|
||||||
*/
|
|
||||||
par->hotdrop = true;
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
return icmp6_type_code_match(icmpinfo->type,
|
|
||||||
icmpinfo->code[0],
|
|
||||||
icmpinfo->code[1],
|
|
||||||
ic->icmp6_type, ic->icmp6_code,
|
|
||||||
!!(icmpinfo->invflags&IP6T_ICMP_INV));
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Called when user tries to insert an entry of this type. */
|
|
||||||
static int icmp6_checkentry(const struct xt_mtchk_param *par)
|
|
||||||
{
|
|
||||||
const struct ip6t_icmp *icmpinfo = par->matchinfo;
|
|
||||||
|
|
||||||
/* Must specify no unknown invflags */
|
|
||||||
return (icmpinfo->invflags & ~IP6T_ICMP_INV) ? -EINVAL : 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* The built-in targets: standard (NULL) and error. */
|
/* The built-in targets: standard (NULL) and error. */
|
||||||
static struct xt_target ip6t_builtin_tg[] __read_mostly = {
|
static struct xt_target ip6t_builtin_tg[] __read_mostly = {
|
||||||
{
|
{
|
||||||
@ -1882,18 +1834,6 @@ static struct nf_sockopt_ops ip6t_sockopts = {
|
|||||||
.owner = THIS_MODULE,
|
.owner = THIS_MODULE,
|
||||||
};
|
};
|
||||||
|
|
||||||
static struct xt_match ip6t_builtin_mt[] __read_mostly = {
|
|
||||||
{
|
|
||||||
.name = "icmp6",
|
|
||||||
.match = icmp6_match,
|
|
||||||
.matchsize = sizeof(struct ip6t_icmp),
|
|
||||||
.checkentry = icmp6_checkentry,
|
|
||||||
.proto = IPPROTO_ICMPV6,
|
|
||||||
.family = NFPROTO_IPV6,
|
|
||||||
.me = THIS_MODULE,
|
|
||||||
},
|
|
||||||
};
|
|
||||||
|
|
||||||
static int __net_init ip6_tables_net_init(struct net *net)
|
static int __net_init ip6_tables_net_init(struct net *net)
|
||||||
{
|
{
|
||||||
return xt_proto_init(net, NFPROTO_IPV6);
|
return xt_proto_init(net, NFPROTO_IPV6);
|
||||||
@ -1921,19 +1861,14 @@ static int __init ip6_tables_init(void)
|
|||||||
ret = xt_register_targets(ip6t_builtin_tg, ARRAY_SIZE(ip6t_builtin_tg));
|
ret = xt_register_targets(ip6t_builtin_tg, ARRAY_SIZE(ip6t_builtin_tg));
|
||||||
if (ret < 0)
|
if (ret < 0)
|
||||||
goto err2;
|
goto err2;
|
||||||
ret = xt_register_matches(ip6t_builtin_mt, ARRAY_SIZE(ip6t_builtin_mt));
|
|
||||||
if (ret < 0)
|
|
||||||
goto err4;
|
|
||||||
|
|
||||||
/* Register setsockopt */
|
/* Register setsockopt */
|
||||||
ret = nf_register_sockopt(&ip6t_sockopts);
|
ret = nf_register_sockopt(&ip6t_sockopts);
|
||||||
if (ret < 0)
|
if (ret < 0)
|
||||||
goto err5;
|
goto err4;
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
err5:
|
|
||||||
xt_unregister_matches(ip6t_builtin_mt, ARRAY_SIZE(ip6t_builtin_mt));
|
|
||||||
err4:
|
err4:
|
||||||
xt_unregister_targets(ip6t_builtin_tg, ARRAY_SIZE(ip6t_builtin_tg));
|
xt_unregister_targets(ip6t_builtin_tg, ARRAY_SIZE(ip6t_builtin_tg));
|
||||||
err2:
|
err2:
|
||||||
@ -1946,7 +1881,6 @@ static void __exit ip6_tables_fini(void)
|
|||||||
{
|
{
|
||||||
nf_unregister_sockopt(&ip6t_sockopts);
|
nf_unregister_sockopt(&ip6t_sockopts);
|
||||||
|
|
||||||
xt_unregister_matches(ip6t_builtin_mt, ARRAY_SIZE(ip6t_builtin_mt));
|
|
||||||
xt_unregister_targets(ip6t_builtin_tg, ARRAY_SIZE(ip6t_builtin_tg));
|
xt_unregister_targets(ip6t_builtin_tg, ARRAY_SIZE(ip6t_builtin_tg));
|
||||||
unregister_pernet_subsys(&ip6_tables_net_ops);
|
unregister_pernet_subsys(&ip6_tables_net_ops);
|
||||||
}
|
}
|
||||||
|
@ -194,10 +194,8 @@ static bool ipv6_raw_deliver(struct sk_buff *skb, int nexthdr)
|
|||||||
struct sk_buff *clone = skb_clone(skb, GFP_ATOMIC);
|
struct sk_buff *clone = skb_clone(skb, GFP_ATOMIC);
|
||||||
|
|
||||||
/* Not releasing hash table! */
|
/* Not releasing hash table! */
|
||||||
if (clone) {
|
if (clone)
|
||||||
nf_reset_ct(clone);
|
|
||||||
rawv6_rcv(sk, clone);
|
rawv6_rcv(sk, clone);
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
rcu_read_unlock();
|
rcu_read_unlock();
|
||||||
@ -391,6 +389,7 @@ int rawv6_rcv(struct sock *sk, struct sk_buff *skb)
|
|||||||
kfree_skb_reason(skb, SKB_DROP_REASON_XFRM_POLICY);
|
kfree_skb_reason(skb, SKB_DROP_REASON_XFRM_POLICY);
|
||||||
return NET_RX_DROP;
|
return NET_RX_DROP;
|
||||||
}
|
}
|
||||||
|
nf_reset_ct(skb);
|
||||||
|
|
||||||
if (!rp->checksum)
|
if (!rp->checksum)
|
||||||
skb->ip_summed = CHECKSUM_UNNECESSARY;
|
skb->ip_summed = CHECKSUM_UNNECESSARY;
|
||||||
|
@ -1723,6 +1723,8 @@ process:
|
|||||||
if (drop_reason)
|
if (drop_reason)
|
||||||
goto discard_and_relse;
|
goto discard_and_relse;
|
||||||
|
|
||||||
|
nf_reset_ct(skb);
|
||||||
|
|
||||||
if (tcp_filter(sk, skb)) {
|
if (tcp_filter(sk, skb)) {
|
||||||
drop_reason = SKB_DROP_REASON_SOCKET_FILTER;
|
drop_reason = SKB_DROP_REASON_SOCKET_FILTER;
|
||||||
goto discard_and_relse;
|
goto discard_and_relse;
|
||||||
|
@ -704,6 +704,7 @@ static int udpv6_queue_rcv_one_skb(struct sock *sk, struct sk_buff *skb)
|
|||||||
drop_reason = SKB_DROP_REASON_XFRM_POLICY;
|
drop_reason = SKB_DROP_REASON_XFRM_POLICY;
|
||||||
goto drop;
|
goto drop;
|
||||||
}
|
}
|
||||||
|
nf_reset_ct(skb);
|
||||||
|
|
||||||
if (static_branch_unlikely(&udpv6_encap_needed_key) && up->encap_type) {
|
if (static_branch_unlikely(&udpv6_encap_needed_key) && up->encap_type) {
|
||||||
int (*encap_rcv)(struct sock *sk, struct sk_buff *skb);
|
int (*encap_rcv)(struct sock *sk, struct sk_buff *skb);
|
||||||
@ -1027,6 +1028,7 @@ int __udp6_lib_rcv(struct sk_buff *skb, struct udp_table *udptable,
|
|||||||
|
|
||||||
if (!xfrm6_policy_check(NULL, XFRM_POLICY_IN, skb))
|
if (!xfrm6_policy_check(NULL, XFRM_POLICY_IN, skb))
|
||||||
goto discard;
|
goto discard;
|
||||||
|
nf_reset_ct(skb);
|
||||||
|
|
||||||
if (udp_lib_checksum_complete(skb))
|
if (udp_lib_checksum_complete(skb))
|
||||||
goto csum_error;
|
goto csum_error;
|
||||||
|
@ -753,7 +753,6 @@ if NETFILTER_XTABLES
|
|||||||
config NETFILTER_XTABLES_COMPAT
|
config NETFILTER_XTABLES_COMPAT
|
||||||
bool "Netfilter Xtables 32bit support"
|
bool "Netfilter Xtables 32bit support"
|
||||||
depends on COMPAT
|
depends on COMPAT
|
||||||
default y
|
|
||||||
help
|
help
|
||||||
This option provides a translation layer to run 32bit arp,ip(6),ebtables
|
This option provides a translation layer to run 32bit arp,ip(6),ebtables
|
||||||
binaries on 64bit kernels.
|
binaries on 64bit kernels.
|
||||||
|
@ -10,6 +10,7 @@
|
|||||||
|
|
||||||
#include <linux/if.h>
|
#include <linux/if.h>
|
||||||
#include <linux/inetdevice.h>
|
#include <linux/inetdevice.h>
|
||||||
|
#include <linux/in.h>
|
||||||
#include <linux/ip.h>
|
#include <linux/ip.h>
|
||||||
#include <linux/kernel.h>
|
#include <linux/kernel.h>
|
||||||
#include <linux/netdevice.h>
|
#include <linux/netdevice.h>
|
||||||
@ -24,54 +25,56 @@
|
|||||||
#include <net/netfilter/nf_nat.h>
|
#include <net/netfilter/nf_nat.h>
|
||||||
#include <net/netfilter/nf_nat_redirect.h>
|
#include <net/netfilter/nf_nat_redirect.h>
|
||||||
|
|
||||||
|
static unsigned int
|
||||||
|
nf_nat_redirect(struct sk_buff *skb, const struct nf_nat_range2 *range,
|
||||||
|
const union nf_inet_addr *newdst)
|
||||||
|
{
|
||||||
|
struct nf_nat_range2 newrange;
|
||||||
|
enum ip_conntrack_info ctinfo;
|
||||||
|
struct nf_conn *ct;
|
||||||
|
|
||||||
|
ct = nf_ct_get(skb, &ctinfo);
|
||||||
|
|
||||||
|
memset(&newrange, 0, sizeof(newrange));
|
||||||
|
|
||||||
|
newrange.flags = range->flags | NF_NAT_RANGE_MAP_IPS;
|
||||||
|
newrange.min_addr = *newdst;
|
||||||
|
newrange.max_addr = *newdst;
|
||||||
|
newrange.min_proto = range->min_proto;
|
||||||
|
newrange.max_proto = range->max_proto;
|
||||||
|
|
||||||
|
return nf_nat_setup_info(ct, &newrange, NF_NAT_MANIP_DST);
|
||||||
|
}
|
||||||
|
|
||||||
unsigned int
|
unsigned int
|
||||||
nf_nat_redirect_ipv4(struct sk_buff *skb,
|
nf_nat_redirect_ipv4(struct sk_buff *skb, const struct nf_nat_range2 *range,
|
||||||
const struct nf_nat_ipv4_multi_range_compat *mr,
|
|
||||||
unsigned int hooknum)
|
unsigned int hooknum)
|
||||||
{
|
{
|
||||||
struct nf_conn *ct;
|
union nf_inet_addr newdst = {};
|
||||||
enum ip_conntrack_info ctinfo;
|
|
||||||
__be32 newdst;
|
|
||||||
struct nf_nat_range2 newrange;
|
|
||||||
|
|
||||||
WARN_ON(hooknum != NF_INET_PRE_ROUTING &&
|
WARN_ON(hooknum != NF_INET_PRE_ROUTING &&
|
||||||
hooknum != NF_INET_LOCAL_OUT);
|
hooknum != NF_INET_LOCAL_OUT);
|
||||||
|
|
||||||
ct = nf_ct_get(skb, &ctinfo);
|
|
||||||
WARN_ON(!(ct && (ctinfo == IP_CT_NEW || ctinfo == IP_CT_RELATED)));
|
|
||||||
|
|
||||||
/* Local packets: make them go to loopback */
|
/* Local packets: make them go to loopback */
|
||||||
if (hooknum == NF_INET_LOCAL_OUT) {
|
if (hooknum == NF_INET_LOCAL_OUT) {
|
||||||
newdst = htonl(0x7F000001);
|
newdst.ip = htonl(INADDR_LOOPBACK);
|
||||||
} else {
|
} else {
|
||||||
const struct in_device *indev;
|
const struct in_device *indev;
|
||||||
|
|
||||||
newdst = 0;
|
|
||||||
|
|
||||||
indev = __in_dev_get_rcu(skb->dev);
|
indev = __in_dev_get_rcu(skb->dev);
|
||||||
if (indev) {
|
if (indev) {
|
||||||
const struct in_ifaddr *ifa;
|
const struct in_ifaddr *ifa;
|
||||||
|
|
||||||
ifa = rcu_dereference(indev->ifa_list);
|
ifa = rcu_dereference(indev->ifa_list);
|
||||||
if (ifa)
|
if (ifa)
|
||||||
newdst = ifa->ifa_local;
|
newdst.ip = ifa->ifa_local;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!newdst)
|
if (!newdst.ip)
|
||||||
return NF_DROP;
|
return NF_DROP;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Transfer from original range. */
|
return nf_nat_redirect(skb, range, &newdst);
|
||||||
memset(&newrange.min_addr, 0, sizeof(newrange.min_addr));
|
|
||||||
memset(&newrange.max_addr, 0, sizeof(newrange.max_addr));
|
|
||||||
newrange.flags = mr->range[0].flags | NF_NAT_RANGE_MAP_IPS;
|
|
||||||
newrange.min_addr.ip = newdst;
|
|
||||||
newrange.max_addr.ip = newdst;
|
|
||||||
newrange.min_proto = mr->range[0].min;
|
|
||||||
newrange.max_proto = mr->range[0].max;
|
|
||||||
|
|
||||||
/* Hand modified range to generic setup. */
|
|
||||||
return nf_nat_setup_info(ct, &newrange, NF_NAT_MANIP_DST);
|
|
||||||
}
|
}
|
||||||
EXPORT_SYMBOL_GPL(nf_nat_redirect_ipv4);
|
EXPORT_SYMBOL_GPL(nf_nat_redirect_ipv4);
|
||||||
|
|
||||||
@ -81,14 +84,10 @@ unsigned int
|
|||||||
nf_nat_redirect_ipv6(struct sk_buff *skb, const struct nf_nat_range2 *range,
|
nf_nat_redirect_ipv6(struct sk_buff *skb, const struct nf_nat_range2 *range,
|
||||||
unsigned int hooknum)
|
unsigned int hooknum)
|
||||||
{
|
{
|
||||||
struct nf_nat_range2 newrange;
|
union nf_inet_addr newdst = {};
|
||||||
struct in6_addr newdst;
|
|
||||||
enum ip_conntrack_info ctinfo;
|
|
||||||
struct nf_conn *ct;
|
|
||||||
|
|
||||||
ct = nf_ct_get(skb, &ctinfo);
|
|
||||||
if (hooknum == NF_INET_LOCAL_OUT) {
|
if (hooknum == NF_INET_LOCAL_OUT) {
|
||||||
newdst = loopback_addr;
|
newdst.in6 = loopback_addr;
|
||||||
} else {
|
} else {
|
||||||
struct inet6_dev *idev;
|
struct inet6_dev *idev;
|
||||||
struct inet6_ifaddr *ifa;
|
struct inet6_ifaddr *ifa;
|
||||||
@ -98,7 +97,7 @@ nf_nat_redirect_ipv6(struct sk_buff *skb, const struct nf_nat_range2 *range,
|
|||||||
if (idev != NULL) {
|
if (idev != NULL) {
|
||||||
read_lock_bh(&idev->lock);
|
read_lock_bh(&idev->lock);
|
||||||
list_for_each_entry(ifa, &idev->addr_list, if_list) {
|
list_for_each_entry(ifa, &idev->addr_list, if_list) {
|
||||||
newdst = ifa->addr;
|
newdst.in6 = ifa->addr;
|
||||||
addr = true;
|
addr = true;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@ -109,12 +108,6 @@ nf_nat_redirect_ipv6(struct sk_buff *skb, const struct nf_nat_range2 *range,
|
|||||||
return NF_DROP;
|
return NF_DROP;
|
||||||
}
|
}
|
||||||
|
|
||||||
newrange.flags = range->flags | NF_NAT_RANGE_MAP_IPS;
|
return nf_nat_redirect(skb, range, &newdst);
|
||||||
newrange.min_addr.in6 = newdst;
|
|
||||||
newrange.max_addr.in6 = newdst;
|
|
||||||
newrange.min_proto = range->min_proto;
|
|
||||||
newrange.max_proto = range->max_proto;
|
|
||||||
|
|
||||||
return nf_nat_setup_info(ct, &newrange, NF_NAT_MANIP_DST);
|
|
||||||
}
|
}
|
||||||
EXPORT_SYMBOL_GPL(nf_nat_redirect_ipv6);
|
EXPORT_SYMBOL_GPL(nf_nat_redirect_ipv6);
|
||||||
|
@ -96,23 +96,39 @@ nla_put_failure:
|
|||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void nft_masq_ipv4_eval(const struct nft_expr *expr,
|
static void nft_masq_eval(const struct nft_expr *expr,
|
||||||
struct nft_regs *regs,
|
struct nft_regs *regs,
|
||||||
const struct nft_pktinfo *pkt)
|
const struct nft_pktinfo *pkt)
|
||||||
{
|
{
|
||||||
struct nft_masq *priv = nft_expr_priv(expr);
|
const struct nft_masq *priv = nft_expr_priv(expr);
|
||||||
struct nf_nat_range2 range;
|
struct nf_nat_range2 range;
|
||||||
|
|
||||||
memset(&range, 0, sizeof(range));
|
memset(&range, 0, sizeof(range));
|
||||||
range.flags = priv->flags;
|
range.flags = priv->flags;
|
||||||
if (priv->sreg_proto_min) {
|
if (priv->sreg_proto_min) {
|
||||||
range.min_proto.all = (__force __be16)nft_reg_load16(
|
range.min_proto.all = (__force __be16)
|
||||||
®s->data[priv->sreg_proto_min]);
|
nft_reg_load16(®s->data[priv->sreg_proto_min]);
|
||||||
range.max_proto.all = (__force __be16)nft_reg_load16(
|
range.max_proto.all = (__force __be16)
|
||||||
®s->data[priv->sreg_proto_max]);
|
nft_reg_load16(®s->data[priv->sreg_proto_max]);
|
||||||
|
}
|
||||||
|
|
||||||
|
switch (nft_pf(pkt)) {
|
||||||
|
case NFPROTO_IPV4:
|
||||||
|
regs->verdict.code = nf_nat_masquerade_ipv4(pkt->skb,
|
||||||
|
nft_hook(pkt),
|
||||||
|
&range,
|
||||||
|
nft_out(pkt));
|
||||||
|
break;
|
||||||
|
#ifdef CONFIG_NF_TABLES_IPV6
|
||||||
|
case NFPROTO_IPV6:
|
||||||
|
regs->verdict.code = nf_nat_masquerade_ipv6(pkt->skb, &range,
|
||||||
|
nft_out(pkt));
|
||||||
|
break;
|
||||||
|
#endif
|
||||||
|
default:
|
||||||
|
WARN_ON_ONCE(1);
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
regs->verdict.code = nf_nat_masquerade_ipv4(pkt->skb, nft_hook(pkt),
|
|
||||||
&range, nft_out(pkt));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
@ -125,7 +141,7 @@ static struct nft_expr_type nft_masq_ipv4_type;
|
|||||||
static const struct nft_expr_ops nft_masq_ipv4_ops = {
|
static const struct nft_expr_ops nft_masq_ipv4_ops = {
|
||||||
.type = &nft_masq_ipv4_type,
|
.type = &nft_masq_ipv4_type,
|
||||||
.size = NFT_EXPR_SIZE(sizeof(struct nft_masq)),
|
.size = NFT_EXPR_SIZE(sizeof(struct nft_masq)),
|
||||||
.eval = nft_masq_ipv4_eval,
|
.eval = nft_masq_eval,
|
||||||
.init = nft_masq_init,
|
.init = nft_masq_init,
|
||||||
.destroy = nft_masq_ipv4_destroy,
|
.destroy = nft_masq_ipv4_destroy,
|
||||||
.dump = nft_masq_dump,
|
.dump = nft_masq_dump,
|
||||||
@ -143,25 +159,6 @@ static struct nft_expr_type nft_masq_ipv4_type __read_mostly = {
|
|||||||
};
|
};
|
||||||
|
|
||||||
#ifdef CONFIG_NF_TABLES_IPV6
|
#ifdef CONFIG_NF_TABLES_IPV6
|
||||||
static void nft_masq_ipv6_eval(const struct nft_expr *expr,
|
|
||||||
struct nft_regs *regs,
|
|
||||||
const struct nft_pktinfo *pkt)
|
|
||||||
{
|
|
||||||
struct nft_masq *priv = nft_expr_priv(expr);
|
|
||||||
struct nf_nat_range2 range;
|
|
||||||
|
|
||||||
memset(&range, 0, sizeof(range));
|
|
||||||
range.flags = priv->flags;
|
|
||||||
if (priv->sreg_proto_min) {
|
|
||||||
range.min_proto.all = (__force __be16)nft_reg_load16(
|
|
||||||
®s->data[priv->sreg_proto_min]);
|
|
||||||
range.max_proto.all = (__force __be16)nft_reg_load16(
|
|
||||||
®s->data[priv->sreg_proto_max]);
|
|
||||||
}
|
|
||||||
regs->verdict.code = nf_nat_masquerade_ipv6(pkt->skb, &range,
|
|
||||||
nft_out(pkt));
|
|
||||||
}
|
|
||||||
|
|
||||||
static void
|
static void
|
||||||
nft_masq_ipv6_destroy(const struct nft_ctx *ctx, const struct nft_expr *expr)
|
nft_masq_ipv6_destroy(const struct nft_ctx *ctx, const struct nft_expr *expr)
|
||||||
{
|
{
|
||||||
@ -172,7 +169,7 @@ static struct nft_expr_type nft_masq_ipv6_type;
|
|||||||
static const struct nft_expr_ops nft_masq_ipv6_ops = {
|
static const struct nft_expr_ops nft_masq_ipv6_ops = {
|
||||||
.type = &nft_masq_ipv6_type,
|
.type = &nft_masq_ipv6_type,
|
||||||
.size = NFT_EXPR_SIZE(sizeof(struct nft_masq)),
|
.size = NFT_EXPR_SIZE(sizeof(struct nft_masq)),
|
||||||
.eval = nft_masq_ipv6_eval,
|
.eval = nft_masq_eval,
|
||||||
.init = nft_masq_init,
|
.init = nft_masq_init,
|
||||||
.destroy = nft_masq_ipv6_destroy,
|
.destroy = nft_masq_ipv6_destroy,
|
||||||
.dump = nft_masq_dump,
|
.dump = nft_masq_dump,
|
||||||
@ -204,20 +201,6 @@ static inline void nft_masq_module_exit_ipv6(void) {}
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifdef CONFIG_NF_TABLES_INET
|
#ifdef CONFIG_NF_TABLES_INET
|
||||||
static void nft_masq_inet_eval(const struct nft_expr *expr,
|
|
||||||
struct nft_regs *regs,
|
|
||||||
const struct nft_pktinfo *pkt)
|
|
||||||
{
|
|
||||||
switch (nft_pf(pkt)) {
|
|
||||||
case NFPROTO_IPV4:
|
|
||||||
return nft_masq_ipv4_eval(expr, regs, pkt);
|
|
||||||
case NFPROTO_IPV6:
|
|
||||||
return nft_masq_ipv6_eval(expr, regs, pkt);
|
|
||||||
}
|
|
||||||
|
|
||||||
WARN_ON_ONCE(1);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void
|
static void
|
||||||
nft_masq_inet_destroy(const struct nft_ctx *ctx, const struct nft_expr *expr)
|
nft_masq_inet_destroy(const struct nft_ctx *ctx, const struct nft_expr *expr)
|
||||||
{
|
{
|
||||||
@ -228,7 +211,7 @@ static struct nft_expr_type nft_masq_inet_type;
|
|||||||
static const struct nft_expr_ops nft_masq_inet_ops = {
|
static const struct nft_expr_ops nft_masq_inet_ops = {
|
||||||
.type = &nft_masq_inet_type,
|
.type = &nft_masq_inet_type,
|
||||||
.size = NFT_EXPR_SIZE(sizeof(struct nft_masq)),
|
.size = NFT_EXPR_SIZE(sizeof(struct nft_masq)),
|
||||||
.eval = nft_masq_inet_eval,
|
.eval = nft_masq_eval,
|
||||||
.init = nft_masq_init,
|
.init = nft_masq_init,
|
||||||
.destroy = nft_masq_inet_destroy,
|
.destroy = nft_masq_inet_destroy,
|
||||||
.dump = nft_masq_dump,
|
.dump = nft_masq_dump,
|
||||||
|
@ -64,6 +64,8 @@ static int nft_redir_init(const struct nft_ctx *ctx,
|
|||||||
} else {
|
} else {
|
||||||
priv->sreg_proto_max = priv->sreg_proto_min;
|
priv->sreg_proto_max = priv->sreg_proto_min;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
priv->flags |= NF_NAT_RANGE_PROTO_SPECIFIED;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (tb[NFTA_REDIR_FLAGS]) {
|
if (tb[NFTA_REDIR_FLAGS]) {
|
||||||
@ -99,25 +101,37 @@ nla_put_failure:
|
|||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void nft_redir_ipv4_eval(const struct nft_expr *expr,
|
static void nft_redir_eval(const struct nft_expr *expr,
|
||||||
struct nft_regs *regs,
|
struct nft_regs *regs,
|
||||||
const struct nft_pktinfo *pkt)
|
const struct nft_pktinfo *pkt)
|
||||||
{
|
{
|
||||||
struct nft_redir *priv = nft_expr_priv(expr);
|
const struct nft_redir *priv = nft_expr_priv(expr);
|
||||||
struct nf_nat_ipv4_multi_range_compat mr;
|
struct nf_nat_range2 range;
|
||||||
|
|
||||||
memset(&mr, 0, sizeof(mr));
|
memset(&range, 0, sizeof(range));
|
||||||
|
range.flags = priv->flags;
|
||||||
if (priv->sreg_proto_min) {
|
if (priv->sreg_proto_min) {
|
||||||
mr.range[0].min.all = (__force __be16)nft_reg_load16(
|
range.min_proto.all = (__force __be16)
|
||||||
®s->data[priv->sreg_proto_min]);
|
nft_reg_load16(®s->data[priv->sreg_proto_min]);
|
||||||
mr.range[0].max.all = (__force __be16)nft_reg_load16(
|
range.max_proto.all = (__force __be16)
|
||||||
®s->data[priv->sreg_proto_max]);
|
nft_reg_load16(®s->data[priv->sreg_proto_max]);
|
||||||
mr.range[0].flags |= NF_NAT_RANGE_PROTO_SPECIFIED;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
mr.range[0].flags |= priv->flags;
|
switch (nft_pf(pkt)) {
|
||||||
|
case NFPROTO_IPV4:
|
||||||
regs->verdict.code = nf_nat_redirect_ipv4(pkt->skb, &mr, nft_hook(pkt));
|
regs->verdict.code = nf_nat_redirect_ipv4(pkt->skb, &range,
|
||||||
|
nft_hook(pkt));
|
||||||
|
break;
|
||||||
|
#ifdef CONFIG_NF_TABLES_IPV6
|
||||||
|
case NFPROTO_IPV6:
|
||||||
|
regs->verdict.code = nf_nat_redirect_ipv6(pkt->skb, &range,
|
||||||
|
nft_hook(pkt));
|
||||||
|
break;
|
||||||
|
#endif
|
||||||
|
default:
|
||||||
|
WARN_ON_ONCE(1);
|
||||||
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
@ -130,7 +144,7 @@ static struct nft_expr_type nft_redir_ipv4_type;
|
|||||||
static const struct nft_expr_ops nft_redir_ipv4_ops = {
|
static const struct nft_expr_ops nft_redir_ipv4_ops = {
|
||||||
.type = &nft_redir_ipv4_type,
|
.type = &nft_redir_ipv4_type,
|
||||||
.size = NFT_EXPR_SIZE(sizeof(struct nft_redir)),
|
.size = NFT_EXPR_SIZE(sizeof(struct nft_redir)),
|
||||||
.eval = nft_redir_ipv4_eval,
|
.eval = nft_redir_eval,
|
||||||
.init = nft_redir_init,
|
.init = nft_redir_init,
|
||||||
.destroy = nft_redir_ipv4_destroy,
|
.destroy = nft_redir_ipv4_destroy,
|
||||||
.dump = nft_redir_dump,
|
.dump = nft_redir_dump,
|
||||||
@ -148,28 +162,6 @@ static struct nft_expr_type nft_redir_ipv4_type __read_mostly = {
|
|||||||
};
|
};
|
||||||
|
|
||||||
#ifdef CONFIG_NF_TABLES_IPV6
|
#ifdef CONFIG_NF_TABLES_IPV6
|
||||||
static void nft_redir_ipv6_eval(const struct nft_expr *expr,
|
|
||||||
struct nft_regs *regs,
|
|
||||||
const struct nft_pktinfo *pkt)
|
|
||||||
{
|
|
||||||
struct nft_redir *priv = nft_expr_priv(expr);
|
|
||||||
struct nf_nat_range2 range;
|
|
||||||
|
|
||||||
memset(&range, 0, sizeof(range));
|
|
||||||
if (priv->sreg_proto_min) {
|
|
||||||
range.min_proto.all = (__force __be16)nft_reg_load16(
|
|
||||||
®s->data[priv->sreg_proto_min]);
|
|
||||||
range.max_proto.all = (__force __be16)nft_reg_load16(
|
|
||||||
®s->data[priv->sreg_proto_max]);
|
|
||||||
range.flags |= NF_NAT_RANGE_PROTO_SPECIFIED;
|
|
||||||
}
|
|
||||||
|
|
||||||
range.flags |= priv->flags;
|
|
||||||
|
|
||||||
regs->verdict.code =
|
|
||||||
nf_nat_redirect_ipv6(pkt->skb, &range, nft_hook(pkt));
|
|
||||||
}
|
|
||||||
|
|
||||||
static void
|
static void
|
||||||
nft_redir_ipv6_destroy(const struct nft_ctx *ctx, const struct nft_expr *expr)
|
nft_redir_ipv6_destroy(const struct nft_ctx *ctx, const struct nft_expr *expr)
|
||||||
{
|
{
|
||||||
@ -180,7 +172,7 @@ static struct nft_expr_type nft_redir_ipv6_type;
|
|||||||
static const struct nft_expr_ops nft_redir_ipv6_ops = {
|
static const struct nft_expr_ops nft_redir_ipv6_ops = {
|
||||||
.type = &nft_redir_ipv6_type,
|
.type = &nft_redir_ipv6_type,
|
||||||
.size = NFT_EXPR_SIZE(sizeof(struct nft_redir)),
|
.size = NFT_EXPR_SIZE(sizeof(struct nft_redir)),
|
||||||
.eval = nft_redir_ipv6_eval,
|
.eval = nft_redir_eval,
|
||||||
.init = nft_redir_init,
|
.init = nft_redir_init,
|
||||||
.destroy = nft_redir_ipv6_destroy,
|
.destroy = nft_redir_ipv6_destroy,
|
||||||
.dump = nft_redir_dump,
|
.dump = nft_redir_dump,
|
||||||
@ -199,20 +191,6 @@ static struct nft_expr_type nft_redir_ipv6_type __read_mostly = {
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifdef CONFIG_NF_TABLES_INET
|
#ifdef CONFIG_NF_TABLES_INET
|
||||||
static void nft_redir_inet_eval(const struct nft_expr *expr,
|
|
||||||
struct nft_regs *regs,
|
|
||||||
const struct nft_pktinfo *pkt)
|
|
||||||
{
|
|
||||||
switch (nft_pf(pkt)) {
|
|
||||||
case NFPROTO_IPV4:
|
|
||||||
return nft_redir_ipv4_eval(expr, regs, pkt);
|
|
||||||
case NFPROTO_IPV6:
|
|
||||||
return nft_redir_ipv6_eval(expr, regs, pkt);
|
|
||||||
}
|
|
||||||
|
|
||||||
WARN_ON_ONCE(1);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void
|
static void
|
||||||
nft_redir_inet_destroy(const struct nft_ctx *ctx, const struct nft_expr *expr)
|
nft_redir_inet_destroy(const struct nft_ctx *ctx, const struct nft_expr *expr)
|
||||||
{
|
{
|
||||||
@ -223,7 +201,7 @@ static struct nft_expr_type nft_redir_inet_type;
|
|||||||
static const struct nft_expr_ops nft_redir_inet_ops = {
|
static const struct nft_expr_ops nft_redir_inet_ops = {
|
||||||
.type = &nft_redir_inet_type,
|
.type = &nft_redir_inet_type,
|
||||||
.size = NFT_EXPR_SIZE(sizeof(struct nft_redir)),
|
.size = NFT_EXPR_SIZE(sizeof(struct nft_redir)),
|
||||||
.eval = nft_redir_inet_eval,
|
.eval = nft_redir_eval,
|
||||||
.init = nft_redir_init,
|
.init = nft_redir_init,
|
||||||
.destroy = nft_redir_inet_destroy,
|
.destroy = nft_redir_inet_destroy,
|
||||||
.dump = nft_redir_dump,
|
.dump = nft_redir_dump,
|
||||||
|
@ -46,7 +46,6 @@ static void redirect_tg_destroy(const struct xt_tgdtor_param *par)
|
|||||||
nf_ct_netns_put(par->net, par->family);
|
nf_ct_netns_put(par->net, par->family);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* FIXME: Take multiple ranges --RR */
|
|
||||||
static int redirect_tg4_check(const struct xt_tgchk_param *par)
|
static int redirect_tg4_check(const struct xt_tgchk_param *par)
|
||||||
{
|
{
|
||||||
const struct nf_nat_ipv4_multi_range_compat *mr = par->targinfo;
|
const struct nf_nat_ipv4_multi_range_compat *mr = par->targinfo;
|
||||||
@ -65,7 +64,14 @@ static int redirect_tg4_check(const struct xt_tgchk_param *par)
|
|||||||
static unsigned int
|
static unsigned int
|
||||||
redirect_tg4(struct sk_buff *skb, const struct xt_action_param *par)
|
redirect_tg4(struct sk_buff *skb, const struct xt_action_param *par)
|
||||||
{
|
{
|
||||||
return nf_nat_redirect_ipv4(skb, par->targinfo, xt_hooknum(par));
|
const struct nf_nat_ipv4_multi_range_compat *mr = par->targinfo;
|
||||||
|
struct nf_nat_range2 range = {
|
||||||
|
.flags = mr->range[0].flags,
|
||||||
|
.min_proto = mr->range[0].min,
|
||||||
|
.max_proto = mr->range[0].max,
|
||||||
|
};
|
||||||
|
|
||||||
|
return nf_nat_redirect_ipv4(skb, &range, xt_hooknum(par));
|
||||||
}
|
}
|
||||||
|
|
||||||
static struct xt_target redirect_tg_reg[] __read_mostly = {
|
static struct xt_target redirect_tg_reg[] __read_mostly = {
|
||||||
|
@ -4,6 +4,7 @@
|
|||||||
#include <linux/module.h>
|
#include <linux/module.h>
|
||||||
#include <net/ip.h>
|
#include <net/ip.h>
|
||||||
#include <linux/ipv6.h>
|
#include <linux/ipv6.h>
|
||||||
|
#include <linux/icmp.h>
|
||||||
#include <net/ipv6.h>
|
#include <net/ipv6.h>
|
||||||
#include <net/tcp.h>
|
#include <net/tcp.h>
|
||||||
#include <net/udp.h>
|
#include <net/udp.h>
|
||||||
@ -20,6 +21,8 @@ MODULE_ALIAS("ipt_udp");
|
|||||||
MODULE_ALIAS("ipt_tcp");
|
MODULE_ALIAS("ipt_tcp");
|
||||||
MODULE_ALIAS("ip6t_udp");
|
MODULE_ALIAS("ip6t_udp");
|
||||||
MODULE_ALIAS("ip6t_tcp");
|
MODULE_ALIAS("ip6t_tcp");
|
||||||
|
MODULE_ALIAS("ipt_icmp");
|
||||||
|
MODULE_ALIAS("ip6t_icmp6");
|
||||||
|
|
||||||
/* Returns 1 if the port is matched by the range, 0 otherwise */
|
/* Returns 1 if the port is matched by the range, 0 otherwise */
|
||||||
static inline bool
|
static inline bool
|
||||||
@ -161,6 +164,95 @@ static int udp_mt_check(const struct xt_mtchk_param *par)
|
|||||||
return (udpinfo->invflags & ~XT_UDP_INV_MASK) ? -EINVAL : 0;
|
return (udpinfo->invflags & ~XT_UDP_INV_MASK) ? -EINVAL : 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Returns 1 if the type and code is matched by the range, 0 otherwise */
|
||||||
|
static bool type_code_in_range(u8 test_type, u8 min_code, u8 max_code,
|
||||||
|
u8 type, u8 code)
|
||||||
|
{
|
||||||
|
return type == test_type && code >= min_code && code <= max_code;
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool icmp_type_code_match(u8 test_type, u8 min_code, u8 max_code,
|
||||||
|
u8 type, u8 code, bool invert)
|
||||||
|
{
|
||||||
|
return (test_type == 0xFF ||
|
||||||
|
type_code_in_range(test_type, min_code, max_code, type, code))
|
||||||
|
^ invert;
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool icmp6_type_code_match(u8 test_type, u8 min_code, u8 max_code,
|
||||||
|
u8 type, u8 code, bool invert)
|
||||||
|
{
|
||||||
|
return type_code_in_range(test_type, min_code, max_code, type, code) ^ invert;
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool
|
||||||
|
icmp_match(const struct sk_buff *skb, struct xt_action_param *par)
|
||||||
|
{
|
||||||
|
const struct icmphdr *ic;
|
||||||
|
struct icmphdr _icmph;
|
||||||
|
const struct ipt_icmp *icmpinfo = par->matchinfo;
|
||||||
|
|
||||||
|
/* Must not be a fragment. */
|
||||||
|
if (par->fragoff != 0)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
ic = skb_header_pointer(skb, par->thoff, sizeof(_icmph), &_icmph);
|
||||||
|
if (!ic) {
|
||||||
|
/* We've been asked to examine this packet, and we
|
||||||
|
* can't. Hence, no choice but to drop.
|
||||||
|
*/
|
||||||
|
par->hotdrop = true;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return icmp_type_code_match(icmpinfo->type,
|
||||||
|
icmpinfo->code[0],
|
||||||
|
icmpinfo->code[1],
|
||||||
|
ic->type, ic->code,
|
||||||
|
!!(icmpinfo->invflags & IPT_ICMP_INV));
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool
|
||||||
|
icmp6_match(const struct sk_buff *skb, struct xt_action_param *par)
|
||||||
|
{
|
||||||
|
const struct icmp6hdr *ic;
|
||||||
|
struct icmp6hdr _icmph;
|
||||||
|
const struct ip6t_icmp *icmpinfo = par->matchinfo;
|
||||||
|
|
||||||
|
/* Must not be a fragment. */
|
||||||
|
if (par->fragoff != 0)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
ic = skb_header_pointer(skb, par->thoff, sizeof(_icmph), &_icmph);
|
||||||
|
if (!ic) {
|
||||||
|
/* We've been asked to examine this packet, and we
|
||||||
|
* can't. Hence, no choice but to drop.
|
||||||
|
*/
|
||||||
|
par->hotdrop = true;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return icmp6_type_code_match(icmpinfo->type,
|
||||||
|
icmpinfo->code[0],
|
||||||
|
icmpinfo->code[1],
|
||||||
|
ic->icmp6_type, ic->icmp6_code,
|
||||||
|
!!(icmpinfo->invflags & IP6T_ICMP_INV));
|
||||||
|
}
|
||||||
|
|
||||||
|
static int icmp_checkentry(const struct xt_mtchk_param *par)
|
||||||
|
{
|
||||||
|
const struct ipt_icmp *icmpinfo = par->matchinfo;
|
||||||
|
|
||||||
|
return (icmpinfo->invflags & ~IPT_ICMP_INV) ? -EINVAL : 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int icmp6_checkentry(const struct xt_mtchk_param *par)
|
||||||
|
{
|
||||||
|
const struct ip6t_icmp *icmpinfo = par->matchinfo;
|
||||||
|
|
||||||
|
return (icmpinfo->invflags & ~IP6T_ICMP_INV) ? -EINVAL : 0;
|
||||||
|
}
|
||||||
|
|
||||||
static struct xt_match tcpudp_mt_reg[] __read_mostly = {
|
static struct xt_match tcpudp_mt_reg[] __read_mostly = {
|
||||||
{
|
{
|
||||||
.name = "tcp",
|
.name = "tcp",
|
||||||
@ -216,6 +308,24 @@ static struct xt_match tcpudp_mt_reg[] __read_mostly = {
|
|||||||
.proto = IPPROTO_UDPLITE,
|
.proto = IPPROTO_UDPLITE,
|
||||||
.me = THIS_MODULE,
|
.me = THIS_MODULE,
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
.name = "icmp",
|
||||||
|
.match = icmp_match,
|
||||||
|
.matchsize = sizeof(struct ipt_icmp),
|
||||||
|
.checkentry = icmp_checkentry,
|
||||||
|
.proto = IPPROTO_ICMP,
|
||||||
|
.family = NFPROTO_IPV4,
|
||||||
|
.me = THIS_MODULE,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
.name = "icmp6",
|
||||||
|
.match = icmp6_match,
|
||||||
|
.matchsize = sizeof(struct ip6t_icmp),
|
||||||
|
.checkentry = icmp6_checkentry,
|
||||||
|
.proto = IPPROTO_ICMPV6,
|
||||||
|
.family = NFPROTO_IPV6,
|
||||||
|
.me = THIS_MODULE,
|
||||||
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
static int __init tcpudp_mt_init(void)
|
static int __init tcpudp_mt_init(void)
|
||||||
|
Loading…
Reference in New Issue
Block a user