Merge git://git.kernel.org/pub/scm/linux/kernel/git/pablo/nf-next
Pablo Neira Ayuso says: ==================== Netfilter/IPVS updates for net-next The following patchset contains Netfilter updates for net-next: 1) Remove the broute pseudo hook, implement this from the bridge prerouting hook instead. Now broute becomes real table in ebtables, from Florian Westphal. This also includes a size reduction patch for the bridge control buffer area via squashing boolean into bitfields and a selftest. 2) Add OS passive fingerprint version matching, from Fernando Fernandez. 3) Support for gue encapsulation for IPVS, from Jacky Hu. 4) Add support for NAT to the inet family, from Florian Westphal. This includes support for masquerade, redirect and nat extensions. 5) Skip interface lookup in flowtable, use device in the dst object. 6) Add jiffies64_to_msecs() and use it, from Li RongQing. 7) Remove unused parameter in nf_tables_set_desc_parse(), from Colin Ian King. 8) Statify several functions, patches from YueHaibing and Florian Westphal. 9) Add an optimized version of nf_inet_addr_cmp(), from Li RongQing. 10) Merge route extension to core, also from Florian. 11) Use IS_ENABLED(CONFIG_NF_NAT) instead of NF_NAT_NEEDED, from Florian. 12) Merge ip/ip6 masquerade extensions, from Florian. This includes netdevice notifier unification. ==================== Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
commit
95337b9821
|
@ -56,9 +56,6 @@ struct br_ip_list {
|
|||
|
||||
extern void brioctl_set(int (*ioctl_hook)(struct net *, unsigned int, void __user *));
|
||||
|
||||
typedef int br_should_route_hook_t(struct sk_buff *skb);
|
||||
extern br_should_route_hook_t __rcu *br_should_route_hook;
|
||||
|
||||
#if IS_ENABLED(CONFIG_BRIDGE) && IS_ENABLED(CONFIG_BRIDGE_IGMP_SNOOPING)
|
||||
int br_multicast_list_adjacent(struct net_device *dev,
|
||||
struct list_head *br_ip_list);
|
||||
|
|
|
@ -297,6 +297,7 @@ static inline u64 jiffies_to_nsecs(const unsigned long j)
|
|||
}
|
||||
|
||||
extern u64 jiffies64_to_nsecs(u64 j);
|
||||
extern u64 jiffies64_to_msecs(u64 j);
|
||||
|
||||
extern unsigned long __msecs_to_jiffies(const unsigned int m);
|
||||
#if HZ <= MSEC_PER_SEC && !(MSEC_PER_SEC % HZ)
|
||||
|
|
|
@ -24,10 +24,17 @@ static inline int NF_DROP_GETERR(int verdict)
|
|||
static inline int nf_inet_addr_cmp(const union nf_inet_addr *a1,
|
||||
const union nf_inet_addr *a2)
|
||||
{
|
||||
#if defined(CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS) && BITS_PER_LONG == 64
|
||||
const unsigned long *ul1 = (const unsigned long *)a1;
|
||||
const unsigned long *ul2 = (const unsigned long *)a2;
|
||||
|
||||
return ((ul1[0] ^ ul2[0]) | (ul1[1] ^ ul2[1])) == 0UL;
|
||||
#else
|
||||
return a1->all[0] == a2->all[0] &&
|
||||
a1->all[1] == a2->all[1] &&
|
||||
a1->all[2] == a2->all[2] &&
|
||||
a1->all[3] == a2->all[3];
|
||||
#endif
|
||||
}
|
||||
|
||||
static inline void nf_inet_addr_mask(const union nf_inet_addr *a1,
|
||||
|
@ -360,7 +367,7 @@ extern struct nf_nat_hook __rcu *nf_nat_hook;
|
|||
static inline void
|
||||
nf_nat_decode_session(struct sk_buff *skb, struct flowi *fl, u_int8_t family)
|
||||
{
|
||||
#ifdef CONFIG_NF_NAT_NEEDED
|
||||
#if IS_ENABLED(CONFIG_NF_NAT)
|
||||
struct nf_nat_hook *nat_hook;
|
||||
|
||||
rcu_read_lock();
|
||||
|
|
|
@ -21,13 +21,18 @@ struct nf_osf_finger {
|
|||
struct nf_osf_user_finger finger;
|
||||
};
|
||||
|
||||
struct nf_osf_data {
|
||||
const char *genre;
|
||||
const char *version;
|
||||
};
|
||||
|
||||
bool nf_osf_match(const struct sk_buff *skb, u_int8_t family,
|
||||
int hooknum, struct net_device *in, struct net_device *out,
|
||||
const struct nf_osf_info *info, struct net *net,
|
||||
const struct list_head *nf_osf_fingers);
|
||||
|
||||
const char *nf_osf_find(const struct sk_buff *skb,
|
||||
const struct list_head *nf_osf_fingers,
|
||||
const int ttl_check);
|
||||
bool nf_osf_find(const struct sk_buff *skb,
|
||||
const struct list_head *nf_osf_fingers,
|
||||
const int ttl_check, struct nf_osf_data *data);
|
||||
|
||||
#endif /* _NFOSF_H */
|
||||
|
|
|
@ -317,7 +317,6 @@ struct xt_table_info *xt_replace_table(struct xt_table *table,
|
|||
int *error);
|
||||
|
||||
struct xt_match *xt_find_match(u8 af, const char *name, u8 revision);
|
||||
struct xt_target *xt_find_target(u8 af, const char *name, u8 revision);
|
||||
struct xt_match *xt_request_find_match(u8 af, const char *name, u8 revision);
|
||||
struct xt_target *xt_request_find_target(u8 af, const char *name, u8 revision);
|
||||
int xt_find_revision(u8 af, const char *name, u8 revision, int target,
|
||||
|
|
|
@ -87,6 +87,21 @@ static inline int nf_ip6_route(struct net *net, struct dst_entry **dst,
|
|||
}
|
||||
|
||||
int ip6_route_me_harder(struct net *net, struct sk_buff *skb);
|
||||
|
||||
static inline int nf_ip6_route_me_harder(struct net *net, struct sk_buff *skb)
|
||||
{
|
||||
#if IS_MODULE(CONFIG_IPV6)
|
||||
const struct nf_ipv6_ops *v6_ops = nf_get_ipv6_ops();
|
||||
|
||||
if (!v6_ops)
|
||||
return -EHOSTUNREACH;
|
||||
|
||||
return v6_ops->route_me_harder(net, skb);
|
||||
#else
|
||||
return ip6_route_me_harder(net, skb);
|
||||
#endif
|
||||
}
|
||||
|
||||
__sum16 nf_ip6_checksum(struct sk_buff *skb, unsigned int hook,
|
||||
unsigned int dataoff, u_int8_t protocol);
|
||||
|
||||
|
|
|
@ -600,6 +600,9 @@ struct ip_vs_dest_user_kern {
|
|||
|
||||
/* Address family of addr */
|
||||
u16 af;
|
||||
|
||||
u16 tun_type; /* tunnel type */
|
||||
__be16 tun_port; /* tunnel port */
|
||||
};
|
||||
|
||||
|
||||
|
@ -660,6 +663,8 @@ struct ip_vs_dest {
|
|||
atomic_t conn_flags; /* flags to copy to conn */
|
||||
atomic_t weight; /* server weight */
|
||||
atomic_t last_weight; /* server latest weight */
|
||||
__u16 tun_type; /* tunnel type */
|
||||
__be16 tun_port; /* tunnel port */
|
||||
|
||||
refcount_t refcnt; /* reference counter */
|
||||
struct ip_vs_stats stats; /* statistics */
|
||||
|
|
|
@ -1,15 +0,0 @@
|
|||
/* SPDX-License-Identifier: GPL-2.0 */
|
||||
#ifndef _NF_NAT_MASQUERADE_IPV4_H_
|
||||
#define _NF_NAT_MASQUERADE_IPV4_H_
|
||||
|
||||
#include <net/netfilter/nf_nat.h>
|
||||
|
||||
unsigned int
|
||||
nf_nat_masquerade_ipv4(struct sk_buff *skb, unsigned int hooknum,
|
||||
const struct nf_nat_range2 *range,
|
||||
const struct net_device *out);
|
||||
|
||||
int nf_nat_masquerade_ipv4_register_notifier(void);
|
||||
void nf_nat_masquerade_ipv4_unregister_notifier(void);
|
||||
|
||||
#endif /*_NF_NAT_MASQUERADE_IPV4_H_ */
|
|
@ -1,11 +0,0 @@
|
|||
/* SPDX-License-Identifier: GPL-2.0 */
|
||||
#ifndef _NF_NAT_MASQUERADE_IPV6_H_
|
||||
#define _NF_NAT_MASQUERADE_IPV6_H_
|
||||
|
||||
unsigned int
|
||||
nf_nat_masquerade_ipv6(struct sk_buff *skb, const struct nf_nat_range2 *range,
|
||||
const struct net_device *out);
|
||||
int nf_nat_masquerade_ipv6_register_notifier(void);
|
||||
void nf_nat_masquerade_ipv6_unregister_notifier(void);
|
||||
|
||||
#endif /* _NF_NAT_MASQUERADE_IPV6_H_ */
|
|
@ -48,7 +48,7 @@ struct nf_conntrack_expect {
|
|||
/* Expectation class */
|
||||
unsigned int class;
|
||||
|
||||
#ifdef CONFIG_NF_NAT_NEEDED
|
||||
#if IS_ENABLED(CONFIG_NF_NAT)
|
||||
union nf_inet_addr saved_addr;
|
||||
/* This is the original per-proto part, used to map the
|
||||
* expected connection the way the recipient expects. */
|
||||
|
|
|
@ -69,9 +69,9 @@ static inline bool nf_nat_oif_changed(unsigned int hooknum,
|
|||
#endif
|
||||
}
|
||||
|
||||
int nf_nat_register_fn(struct net *net, const struct nf_hook_ops *ops,
|
||||
int nf_nat_register_fn(struct net *net, u8 pf, const struct nf_hook_ops *ops,
|
||||
const struct nf_hook_ops *nat_ops, unsigned int ops_count);
|
||||
void nf_nat_unregister_fn(struct net *net, const struct nf_hook_ops *ops,
|
||||
void nf_nat_unregister_fn(struct net *net, u8 pf, const struct nf_hook_ops *ops,
|
||||
unsigned int ops_count);
|
||||
|
||||
unsigned int nf_nat_packet(struct nf_conn *ct, enum ip_conntrack_info ctinfo,
|
||||
|
@ -98,6 +98,9 @@ void nf_nat_ipv4_unregister_fn(struct net *net, const struct nf_hook_ops *ops);
|
|||
int nf_nat_ipv6_register_fn(struct net *net, const struct nf_hook_ops *ops);
|
||||
void nf_nat_ipv6_unregister_fn(struct net *net, const struct nf_hook_ops *ops);
|
||||
|
||||
int nf_nat_inet_register_fn(struct net *net, const struct nf_hook_ops *ops);
|
||||
void nf_nat_inet_unregister_fn(struct net *net, const struct nf_hook_ops *ops);
|
||||
|
||||
unsigned int
|
||||
nf_nat_inet_fn(void *priv, struct sk_buff *skb,
|
||||
const struct nf_hook_state *state);
|
||||
|
|
|
@ -0,0 +1,19 @@
|
|||
/* SPDX-License-Identifier: GPL-2.0 */
|
||||
#ifndef _NF_NAT_MASQUERADE_H_
|
||||
#define _NF_NAT_MASQUERADE_H_
|
||||
|
||||
#include <net/netfilter/nf_nat.h>
|
||||
|
||||
unsigned int
|
||||
nf_nat_masquerade_ipv4(struct sk_buff *skb, unsigned int hooknum,
|
||||
const struct nf_nat_range2 *range,
|
||||
const struct net_device *out);
|
||||
|
||||
int nf_nat_masquerade_inet_register_notifiers(void);
|
||||
void nf_nat_masquerade_inet_unregister_notifiers(void);
|
||||
|
||||
unsigned int
|
||||
nf_nat_masquerade_ipv6(struct sk_buff *skb, const struct nf_nat_range2 *range,
|
||||
const struct net_device *out);
|
||||
|
||||
#endif /*_NF_NAT_MASQUERADE_H_ */
|
|
@ -119,4 +119,7 @@ nfqueue_hash(const struct sk_buff *skb, u16 queue, u16 queues_total, u8 family,
|
|||
return queue;
|
||||
}
|
||||
|
||||
int nf_queue(struct sk_buff *skb, struct nf_hook_state *state,
|
||||
const struct nf_hook_entries *entries, unsigned int index,
|
||||
unsigned int verdict);
|
||||
#endif /* _NF_QUEUE_H */
|
||||
|
|
|
@ -475,8 +475,6 @@ void nf_tables_deactivate_set(const struct nft_ctx *ctx, struct nft_set *set,
|
|||
enum nft_trans_phase phase);
|
||||
int nf_tables_bind_set(const struct nft_ctx *ctx, struct nft_set *set,
|
||||
struct nft_set_binding *binding);
|
||||
void nf_tables_unbind_set(const struct nft_ctx *ctx, struct nft_set *set,
|
||||
struct nft_set_binding *binding, bool commit);
|
||||
void nf_tables_destroy_set(const struct nft_ctx *ctx, struct nft_set *set);
|
||||
|
||||
/**
|
||||
|
@ -1411,4 +1409,6 @@ struct nft_trans_flowtable {
|
|||
int __init nft_chain_filter_init(void);
|
||||
void nft_chain_filter_fini(void);
|
||||
|
||||
void __init nft_chain_route_init(void);
|
||||
void nft_chain_route_fini(void);
|
||||
#endif /* _NET_NF_TABLES_H */
|
||||
|
|
|
@ -124,6 +124,13 @@
|
|||
|
||||
#define IP_VS_PEDATA_MAXLEN 255
|
||||
|
||||
/* Tunnel types */
|
||||
enum {
|
||||
IP_VS_CONN_F_TUNNEL_TYPE_IPIP = 0, /* IPIP */
|
||||
IP_VS_CONN_F_TUNNEL_TYPE_GUE, /* GUE */
|
||||
IP_VS_CONN_F_TUNNEL_TYPE_MAX,
|
||||
};
|
||||
|
||||
/*
|
||||
* The struct ip_vs_service_user and struct ip_vs_dest_user are
|
||||
* used to set IPVS rules through setsockopt.
|
||||
|
@ -392,6 +399,10 @@ enum {
|
|||
|
||||
IPVS_DEST_ATTR_STATS64, /* nested attribute for dest stats */
|
||||
|
||||
IPVS_DEST_ATTR_TUN_TYPE, /* tunnel type */
|
||||
|
||||
IPVS_DEST_ATTR_TUN_PORT, /* tunnel port */
|
||||
|
||||
__IPVS_DEST_ATTR_MAX,
|
||||
};
|
||||
|
||||
|
|
|
@ -1522,15 +1522,21 @@ enum nft_flowtable_hook_attributes {
|
|||
*
|
||||
* @NFTA_OSF_DREG: destination register (NLA_U32: nft_registers)
|
||||
* @NFTA_OSF_TTL: Value of the TTL osf option (NLA_U8)
|
||||
* @NFTA_OSF_FLAGS: flags (NLA_U32)
|
||||
*/
|
||||
enum nft_osf_attributes {
|
||||
NFTA_OSF_UNSPEC,
|
||||
NFTA_OSF_DREG,
|
||||
NFTA_OSF_TTL,
|
||||
NFTA_OSF_FLAGS,
|
||||
__NFTA_OSF_MAX,
|
||||
};
|
||||
#define NFTA_OSF_MAX (__NFTA_OSF_MAX - 1)
|
||||
|
||||
enum nft_osf_flags {
|
||||
NFT_OSF_F_VERSION = (1 << 0),
|
||||
};
|
||||
|
||||
/**
|
||||
* enum nft_device_attributes - nf_tables device netlink attributes
|
||||
*
|
||||
|
|
|
@ -783,6 +783,16 @@ u64 jiffies64_to_nsecs(u64 j)
|
|||
}
|
||||
EXPORT_SYMBOL(jiffies64_to_nsecs);
|
||||
|
||||
u64 jiffies64_to_msecs(const u64 j)
|
||||
{
|
||||
#if HZ <= MSEC_PER_SEC && !(MSEC_PER_SEC % HZ)
|
||||
return (MSEC_PER_SEC / HZ) * j;
|
||||
#else
|
||||
return div_u64(j * HZ_TO_MSEC_NUM, HZ_TO_MSEC_DEN);
|
||||
#endif
|
||||
}
|
||||
EXPORT_SYMBOL(jiffies64_to_msecs);
|
||||
|
||||
/**
|
||||
* nsecs_to_jiffies64 - Convert nsecs in u64 to jiffies64
|
||||
*
|
||||
|
|
|
@ -131,7 +131,7 @@ void br_do_proxy_suppress_arp(struct sk_buff *skb, struct net_bridge *br,
|
|||
u8 *arpptr, *sha;
|
||||
__be32 sip, tip;
|
||||
|
||||
BR_INPUT_SKB_CB(skb)->proxyarp_replied = false;
|
||||
BR_INPUT_SKB_CB(skb)->proxyarp_replied = 0;
|
||||
|
||||
if ((dev->flags & IFF_NOARP) ||
|
||||
!pskb_may_pull(skb, arp_hdr_len(dev)))
|
||||
|
@ -161,7 +161,7 @@ void br_do_proxy_suppress_arp(struct sk_buff *skb, struct net_bridge *br,
|
|||
return;
|
||||
if (ipv4_is_zeronet(sip) || sip == tip) {
|
||||
/* prevent flooding to neigh suppress ports */
|
||||
BR_INPUT_SKB_CB(skb)->proxyarp_replied = true;
|
||||
BR_INPUT_SKB_CB(skb)->proxyarp_replied = 1;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
@ -181,7 +181,7 @@ void br_do_proxy_suppress_arp(struct sk_buff *skb, struct net_bridge *br,
|
|||
/* its our local ip, so don't proxy reply
|
||||
* and don't forward to neigh suppress ports
|
||||
*/
|
||||
BR_INPUT_SKB_CB(skb)->proxyarp_replied = true;
|
||||
BR_INPUT_SKB_CB(skb)->proxyarp_replied = 1;
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -217,7 +217,7 @@ void br_do_proxy_suppress_arp(struct sk_buff *skb, struct net_bridge *br,
|
|||
*/
|
||||
if (replied ||
|
||||
br_opt_get(br, BROPT_NEIGH_SUPPRESS_ENABLED))
|
||||
BR_INPUT_SKB_CB(skb)->proxyarp_replied = true;
|
||||
BR_INPUT_SKB_CB(skb)->proxyarp_replied = 1;
|
||||
}
|
||||
|
||||
neigh_release(n);
|
||||
|
@ -393,7 +393,7 @@ void br_do_suppress_nd(struct sk_buff *skb, struct net_bridge *br,
|
|||
struct ipv6hdr *iphdr;
|
||||
struct neighbour *n;
|
||||
|
||||
BR_INPUT_SKB_CB(skb)->proxyarp_replied = false;
|
||||
BR_INPUT_SKB_CB(skb)->proxyarp_replied = 0;
|
||||
|
||||
if (p && (p->flags & BR_NEIGH_SUPPRESS))
|
||||
return;
|
||||
|
@ -401,7 +401,7 @@ void br_do_suppress_nd(struct sk_buff *skb, struct net_bridge *br,
|
|||
if (msg->icmph.icmp6_type == NDISC_NEIGHBOUR_ADVERTISEMENT &&
|
||||
!msg->icmph.icmp6_solicited) {
|
||||
/* prevent flooding to neigh suppress ports */
|
||||
BR_INPUT_SKB_CB(skb)->proxyarp_replied = true;
|
||||
BR_INPUT_SKB_CB(skb)->proxyarp_replied = 1;
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -414,7 +414,7 @@ void br_do_suppress_nd(struct sk_buff *skb, struct net_bridge *br,
|
|||
|
||||
if (ipv6_addr_any(saddr) || !ipv6_addr_cmp(saddr, daddr)) {
|
||||
/* prevent flooding to neigh suppress ports */
|
||||
BR_INPUT_SKB_CB(skb)->proxyarp_replied = true;
|
||||
BR_INPUT_SKB_CB(skb)->proxyarp_replied = 1;
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -432,7 +432,7 @@ void br_do_suppress_nd(struct sk_buff *skb, struct net_bridge *br,
|
|||
/* its our own ip, so don't proxy reply
|
||||
* and don't forward to arp suppress ports
|
||||
*/
|
||||
BR_INPUT_SKB_CB(skb)->proxyarp_replied = true;
|
||||
BR_INPUT_SKB_CB(skb)->proxyarp_replied = 1;
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -465,7 +465,7 @@ void br_do_suppress_nd(struct sk_buff *skb, struct net_bridge *br,
|
|||
*/
|
||||
if (replied ||
|
||||
br_opt_get(br, BROPT_NEIGH_SUPPRESS_ENABLED))
|
||||
BR_INPUT_SKB_CB(skb)->proxyarp_replied = true;
|
||||
BR_INPUT_SKB_CB(skb)->proxyarp_replied = 1;
|
||||
}
|
||||
neigh_release(n);
|
||||
}
|
||||
|
|
|
@ -16,6 +16,9 @@
|
|||
#include <linux/netdevice.h>
|
||||
#include <linux/etherdevice.h>
|
||||
#include <linux/netfilter_bridge.h>
|
||||
#ifdef CONFIG_NETFILTER_FAMILY_BRIDGE
|
||||
#include <net/netfilter/nf_queue.h>
|
||||
#endif
|
||||
#include <linux/neighbour.h>
|
||||
#include <net/arp.h>
|
||||
#include <linux/export.h>
|
||||
|
@ -23,10 +26,6 @@
|
|||
#include "br_private.h"
|
||||
#include "br_private_tunnel.h"
|
||||
|
||||
/* Hook for brouter */
|
||||
br_should_route_hook_t __rcu *br_should_route_hook __read_mostly;
|
||||
EXPORT_SYMBOL(br_should_route_hook);
|
||||
|
||||
static int
|
||||
br_netif_receive_skb(struct net *net, struct sock *sk, struct sk_buff *skb)
|
||||
{
|
||||
|
@ -206,6 +205,59 @@ static int br_handle_local_finish(struct net *net, struct sock *sk, struct sk_bu
|
|||
return 0;
|
||||
}
|
||||
|
||||
static int nf_hook_bridge_pre(struct sk_buff *skb, struct sk_buff **pskb)
|
||||
{
|
||||
#ifdef CONFIG_NETFILTER_FAMILY_BRIDGE
|
||||
struct nf_hook_entries *e = NULL;
|
||||
struct nf_hook_state state;
|
||||
unsigned int verdict, i;
|
||||
struct net *net;
|
||||
int ret;
|
||||
|
||||
net = dev_net(skb->dev);
|
||||
#ifdef HAVE_JUMP_LABEL
|
||||
if (!static_key_false(&nf_hooks_needed[NFPROTO_BRIDGE][NF_BR_PRE_ROUTING]))
|
||||
goto frame_finish;
|
||||
#endif
|
||||
|
||||
e = rcu_dereference(net->nf.hooks_bridge[NF_BR_PRE_ROUTING]);
|
||||
if (!e)
|
||||
goto frame_finish;
|
||||
|
||||
nf_hook_state_init(&state, NF_BR_PRE_ROUTING,
|
||||
NFPROTO_BRIDGE, skb->dev, NULL, NULL,
|
||||
net, br_handle_frame_finish);
|
||||
|
||||
for (i = 0; i < e->num_hook_entries; i++) {
|
||||
verdict = nf_hook_entry_hookfn(&e->hooks[i], skb, &state);
|
||||
switch (verdict & NF_VERDICT_MASK) {
|
||||
case NF_ACCEPT:
|
||||
if (BR_INPUT_SKB_CB(skb)->br_netfilter_broute) {
|
||||
*pskb = skb;
|
||||
return RX_HANDLER_PASS;
|
||||
}
|
||||
break;
|
||||
case NF_DROP:
|
||||
kfree_skb(skb);
|
||||
return RX_HANDLER_CONSUMED;
|
||||
case NF_QUEUE:
|
||||
ret = nf_queue(skb, &state, e, i, verdict);
|
||||
if (ret == 1)
|
||||
continue;
|
||||
return RX_HANDLER_CONSUMED;
|
||||
default: /* STOLEN */
|
||||
return RX_HANDLER_CONSUMED;
|
||||
}
|
||||
}
|
||||
frame_finish:
|
||||
net = dev_net(skb->dev);
|
||||
br_handle_frame_finish(net, NULL, skb);
|
||||
#else
|
||||
br_handle_frame_finish(dev_net(skb->dev), NULL, skb);
|
||||
#endif
|
||||
return RX_HANDLER_CONSUMED;
|
||||
}
|
||||
|
||||
/*
|
||||
* Return NULL if skb is handled
|
||||
* note: already called with rcu_read_lock
|
||||
|
@ -215,7 +267,6 @@ rx_handler_result_t br_handle_frame(struct sk_buff **pskb)
|
|||
struct net_bridge_port *p;
|
||||
struct sk_buff *skb = *pskb;
|
||||
const unsigned char *dest = eth_hdr(skb)->h_dest;
|
||||
br_should_route_hook_t *rhook;
|
||||
|
||||
if (unlikely(skb->pkt_type == PACKET_LOOPBACK))
|
||||
return RX_HANDLER_PASS;
|
||||
|
@ -227,6 +278,8 @@ rx_handler_result_t br_handle_frame(struct sk_buff **pskb)
|
|||
if (!skb)
|
||||
return RX_HANDLER_CONSUMED;
|
||||
|
||||
memset(skb->cb, 0, sizeof(struct br_input_skb_cb));
|
||||
|
||||
p = br_port_get_rcu(skb->dev);
|
||||
if (p->flags & BR_VLAN_TUNNEL) {
|
||||
if (br_handle_ingress_vlan_tunnel(skb, p,
|
||||
|
@ -289,23 +342,11 @@ rx_handler_result_t br_handle_frame(struct sk_buff **pskb)
|
|||
forward:
|
||||
switch (p->state) {
|
||||
case BR_STATE_FORWARDING:
|
||||
rhook = rcu_dereference(br_should_route_hook);
|
||||
if (rhook) {
|
||||
if ((*rhook)(skb)) {
|
||||
*pskb = skb;
|
||||
return RX_HANDLER_PASS;
|
||||
}
|
||||
dest = eth_hdr(skb)->h_dest;
|
||||
}
|
||||
/* fall through */
|
||||
case BR_STATE_LEARNING:
|
||||
if (ether_addr_equal(p->br->dev->dev_addr, dest))
|
||||
skb->pkt_type = PACKET_HOST;
|
||||
|
||||
NF_HOOK(NFPROTO_BRIDGE, NF_BR_PRE_ROUTING,
|
||||
dev_net(skb->dev), NULL, skb, skb->dev, NULL,
|
||||
br_handle_frame_finish);
|
||||
break;
|
||||
return nf_hook_bridge_pre(skb, pskb);
|
||||
default:
|
||||
drop:
|
||||
kfree_skb(skb);
|
||||
|
|
|
@ -425,15 +425,16 @@ struct br_input_skb_cb {
|
|||
struct net_device *brdev;
|
||||
|
||||
#ifdef CONFIG_BRIDGE_IGMP_SNOOPING
|
||||
int igmp;
|
||||
int mrouters_only;
|
||||
u8 igmp;
|
||||
u8 mrouters_only:1;
|
||||
#endif
|
||||
|
||||
bool proxyarp_replied;
|
||||
bool src_port_isolated;
|
||||
|
||||
u8 proxyarp_replied:1;
|
||||
u8 src_port_isolated:1;
|
||||
#ifdef CONFIG_BRIDGE_VLAN_FILTERING
|
||||
bool vlan_filtered;
|
||||
u8 vlan_filtered:1;
|
||||
#endif
|
||||
#ifdef CONFIG_NETFILTER_FAMILY_BRIDGE
|
||||
u8 br_netfilter_broute:1;
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_NET_SWITCHDEV
|
||||
|
|
|
@ -15,6 +15,8 @@
|
|||
#include <linux/module.h>
|
||||
#include <linux/if_bridge.h>
|
||||
|
||||
#include "../br_private.h"
|
||||
|
||||
/* EBT_ACCEPT means the frame will be bridged
|
||||
* EBT_DROP means the frame will be routed
|
||||
*/
|
||||
|
@ -48,30 +50,63 @@ static const struct ebt_table broute_table = {
|
|||
.me = THIS_MODULE,
|
||||
};
|
||||
|
||||
static int ebt_broute(struct sk_buff *skb)
|
||||
static unsigned int ebt_broute(void *priv, struct sk_buff *skb,
|
||||
const struct nf_hook_state *s)
|
||||
{
|
||||
struct net_bridge_port *p = br_port_get_rcu(skb->dev);
|
||||
struct nf_hook_state state;
|
||||
unsigned char *dest;
|
||||
int ret;
|
||||
|
||||
if (!p || p->state != BR_STATE_FORWARDING)
|
||||
return NF_ACCEPT;
|
||||
|
||||
nf_hook_state_init(&state, NF_BR_BROUTING,
|
||||
NFPROTO_BRIDGE, skb->dev, NULL, NULL,
|
||||
dev_net(skb->dev), NULL);
|
||||
NFPROTO_BRIDGE, s->in, NULL, NULL,
|
||||
s->net, NULL);
|
||||
|
||||
ret = ebt_do_table(skb, &state, state.net->xt.broute_table);
|
||||
if (ret == NF_DROP)
|
||||
return 1; /* route it */
|
||||
return 0; /* bridge it */
|
||||
|
||||
if (ret != NF_DROP)
|
||||
return ret;
|
||||
|
||||
/* DROP in ebtables -t broute means that the
|
||||
* skb should be routed, not bridged.
|
||||
* This is awkward, but can't be changed for compatibility
|
||||
* reasons.
|
||||
*
|
||||
* We map DROP to ACCEPT and set the ->br_netfilter_broute flag.
|
||||
*/
|
||||
BR_INPUT_SKB_CB(skb)->br_netfilter_broute = 1;
|
||||
|
||||
/* undo PACKET_HOST mangling done in br_input in case the dst
|
||||
* address matches the logical bridge but not the port.
|
||||
*/
|
||||
dest = eth_hdr(skb)->h_dest;
|
||||
if (skb->pkt_type == PACKET_HOST &&
|
||||
!ether_addr_equal(skb->dev->dev_addr, dest) &&
|
||||
ether_addr_equal(p->br->dev->dev_addr, dest))
|
||||
skb->pkt_type = PACKET_OTHERHOST;
|
||||
|
||||
return NF_ACCEPT;
|
||||
}
|
||||
|
||||
static const struct nf_hook_ops ebt_ops_broute = {
|
||||
.hook = ebt_broute,
|
||||
.pf = NFPROTO_BRIDGE,
|
||||
.hooknum = NF_BR_PRE_ROUTING,
|
||||
.priority = NF_BR_PRI_FIRST,
|
||||
};
|
||||
|
||||
static int __net_init broute_net_init(struct net *net)
|
||||
{
|
||||
return ebt_register_table(net, &broute_table, NULL,
|
||||
return ebt_register_table(net, &broute_table, &ebt_ops_broute,
|
||||
&net->xt.broute_table);
|
||||
}
|
||||
|
||||
static void __net_exit broute_net_exit(struct net *net)
|
||||
{
|
||||
ebt_unregister_table(net, net->xt.broute_table, NULL);
|
||||
ebt_unregister_table(net, net->xt.broute_table, &ebt_ops_broute);
|
||||
}
|
||||
|
||||
static struct pernet_operations broute_net_ops = {
|
||||
|
@ -81,21 +116,11 @@ static struct pernet_operations broute_net_ops = {
|
|||
|
||||
static int __init ebtable_broute_init(void)
|
||||
{
|
||||
int ret;
|
||||
|
||||
ret = register_pernet_subsys(&broute_net_ops);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
/* see br_input.c */
|
||||
RCU_INIT_POINTER(br_should_route_hook,
|
||||
(br_should_route_hook_t *)ebt_broute);
|
||||
return 0;
|
||||
return register_pernet_subsys(&broute_net_ops);
|
||||
}
|
||||
|
||||
static void __exit ebtable_broute_fini(void)
|
||||
{
|
||||
RCU_INIT_POINTER(br_should_route_hook, NULL);
|
||||
synchronize_net();
|
||||
unregister_pernet_subsys(&broute_net_ops);
|
||||
}
|
||||
|
||||
|
|
|
@ -1221,10 +1221,6 @@ int ebt_register_table(struct net *net, const struct ebt_table *input_table,
|
|||
mutex_unlock(&ebt_mutex);
|
||||
|
||||
WRITE_ONCE(*res, table);
|
||||
|
||||
if (!ops)
|
||||
return 0;
|
||||
|
||||
ret = nf_register_net_hooks(net, ops, hweight32(table->valid_hooks));
|
||||
if (ret) {
|
||||
__ebt_unregister_table(net, table);
|
||||
|
@ -1248,8 +1244,7 @@ out:
|
|||
void ebt_unregister_table(struct net *net, struct ebt_table *table,
|
||||
const struct nf_hook_ops *ops)
|
||||
{
|
||||
if (ops)
|
||||
nf_unregister_net_hooks(net, ops, hweight32(table->valid_hooks));
|
||||
nf_unregister_net_hooks(net, ops, hweight32(table->valid_hooks));
|
||||
__ebt_unregister_table(net, table);
|
||||
}
|
||||
|
||||
|
|
|
@ -27,14 +27,6 @@ config NF_TABLES_IPV4
|
|||
|
||||
if NF_TABLES_IPV4
|
||||
|
||||
config NFT_CHAIN_ROUTE_IPV4
|
||||
tristate "IPv4 nf_tables route chain support"
|
||||
help
|
||||
This option enables the "route" chain for IPv4 in nf_tables. This
|
||||
chain type is used to force packet re-routing after mangling header
|
||||
fields such as the source, destination, type of service and
|
||||
the packet mark.
|
||||
|
||||
config NFT_REJECT_IPV4
|
||||
select NF_REJECT_IPV4
|
||||
default NFT_REJECT
|
||||
|
@ -232,16 +224,10 @@ if IP_NF_NAT
|
|||
|
||||
config IP_NF_TARGET_MASQUERADE
|
||||
tristate "MASQUERADE target support"
|
||||
select NF_NAT_MASQUERADE
|
||||
default m if NETFILTER_ADVANCED=n
|
||||
select NETFILTER_XT_TARGET_MASQUERADE
|
||||
help
|
||||
Masquerading is a special case of NAT: all outgoing connections are
|
||||
changed to seem to come from a particular interface's address, and
|
||||
if the interface goes down, those connections are lost. This is
|
||||
only useful for dialup accounts with dynamic IP address (ie. your IP
|
||||
address will be different on next dialup).
|
||||
|
||||
To compile it as a module, choose M here. If unsure, say N.
|
||||
This is a backwards-compat option for the user's convenience
|
||||
(e.g. when running oldconfig). It selects NETFILTER_XT_TARGET_MASQUERADE.
|
||||
|
||||
config IP_NF_TARGET_NETMAP
|
||||
tristate "NETMAP target support"
|
||||
|
|
|
@ -24,7 +24,6 @@ nf_nat_snmp_basic-y := nf_nat_snmp_basic.asn1.o nf_nat_snmp_basic_main.o
|
|||
$(obj)/nf_nat_snmp_basic_main.o: $(obj)/nf_nat_snmp_basic.asn1.h
|
||||
obj-$(CONFIG_NF_NAT_SNMP_BASIC) += nf_nat_snmp_basic.o
|
||||
|
||||
obj-$(CONFIG_NFT_CHAIN_ROUTE_IPV4) += nft_chain_route_ipv4.o
|
||||
obj-$(CONFIG_NFT_REJECT_IPV4) += nft_reject_ipv4.o
|
||||
obj-$(CONFIG_NFT_FIB_IPV4) += nft_fib_ipv4.o
|
||||
obj-$(CONFIG_NFT_DUP_IPV4) += nft_dup_ipv4.o
|
||||
|
@ -49,7 +48,6 @@ obj-$(CONFIG_IP_NF_MATCH_RPFILTER) += ipt_rpfilter.o
|
|||
# targets
|
||||
obj-$(CONFIG_IP_NF_TARGET_CLUSTERIP) += ipt_CLUSTERIP.o
|
||||
obj-$(CONFIG_IP_NF_TARGET_ECN) += ipt_ECN.o
|
||||
obj-$(CONFIG_IP_NF_TARGET_MASQUERADE) += ipt_MASQUERADE.o
|
||||
obj-$(CONFIG_IP_NF_TARGET_REJECT) += ipt_REJECT.o
|
||||
obj-$(CONFIG_IP_NF_TARGET_SYNPROXY) += ipt_SYNPROXY.o
|
||||
|
||||
|
|
|
@ -1,89 +0,0 @@
|
|||
/*
|
||||
* Copyright (c) 2008 Patrick McHardy <kaber@trash.net>
|
||||
* Copyright (c) 2012 Pablo Neira Ayuso <pablo@netfilter.org>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation.
|
||||
*/
|
||||
|
||||
#include <linux/module.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/list.h>
|
||||
#include <linux/skbuff.h>
|
||||
#include <linux/netlink.h>
|
||||
#include <linux/netfilter.h>
|
||||
#include <linux/netfilter_ipv4.h>
|
||||
#include <linux/netfilter/nfnetlink.h>
|
||||
#include <linux/netfilter/nf_tables.h>
|
||||
#include <net/netfilter/nf_tables.h>
|
||||
#include <net/netfilter/nf_tables_ipv4.h>
|
||||
#include <net/route.h>
|
||||
#include <net/ip.h>
|
||||
|
||||
static unsigned int nf_route_table_hook(void *priv,
|
||||
struct sk_buff *skb,
|
||||
const struct nf_hook_state *state)
|
||||
{
|
||||
unsigned int ret;
|
||||
struct nft_pktinfo pkt;
|
||||
u32 mark;
|
||||
__be32 saddr, daddr;
|
||||
u_int8_t tos;
|
||||
const struct iphdr *iph;
|
||||
int err;
|
||||
|
||||
nft_set_pktinfo(&pkt, skb, state);
|
||||
nft_set_pktinfo_ipv4(&pkt, skb);
|
||||
|
||||
mark = skb->mark;
|
||||
iph = ip_hdr(skb);
|
||||
saddr = iph->saddr;
|
||||
daddr = iph->daddr;
|
||||
tos = iph->tos;
|
||||
|
||||
ret = nft_do_chain(&pkt, priv);
|
||||
if (ret != NF_DROP && ret != NF_STOLEN) {
|
||||
iph = ip_hdr(skb);
|
||||
|
||||
if (iph->saddr != saddr ||
|
||||
iph->daddr != daddr ||
|
||||
skb->mark != mark ||
|
||||
iph->tos != tos) {
|
||||
err = ip_route_me_harder(state->net, skb, RTN_UNSPEC);
|
||||
if (err < 0)
|
||||
ret = NF_DROP_ERR(err);
|
||||
}
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
static const struct nft_chain_type nft_chain_route_ipv4 = {
|
||||
.name = "route",
|
||||
.type = NFT_CHAIN_T_ROUTE,
|
||||
.family = NFPROTO_IPV4,
|
||||
.owner = THIS_MODULE,
|
||||
.hook_mask = (1 << NF_INET_LOCAL_OUT),
|
||||
.hooks = {
|
||||
[NF_INET_LOCAL_OUT] = nf_route_table_hook,
|
||||
},
|
||||
};
|
||||
|
||||
static int __init nft_chain_route_init(void)
|
||||
{
|
||||
nft_register_chain_type(&nft_chain_route_ipv4);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void __exit nft_chain_route_exit(void)
|
||||
{
|
||||
nft_unregister_chain_type(&nft_chain_route_ipv4);
|
||||
}
|
||||
|
||||
module_init(nft_chain_route_init);
|
||||
module_exit(nft_chain_route_exit);
|
||||
|
||||
MODULE_LICENSE("GPL");
|
||||
MODULE_AUTHOR("Patrick McHardy <kaber@trash.net>");
|
||||
MODULE_ALIAS_NFT_CHAIN(AF_INET, "route");
|
|
@ -23,14 +23,6 @@ config NF_TABLES_IPV6
|
|||
|
||||
if NF_TABLES_IPV6
|
||||
|
||||
config NFT_CHAIN_ROUTE_IPV6
|
||||
tristate "IPv6 nf_tables route chain support"
|
||||
help
|
||||
This option enables the "route" chain for IPv6 in nf_tables. This
|
||||
chain type is used to force packet re-routing after mangling header
|
||||
fields such as the source, destination, flowlabel, hop-limit and
|
||||
the packet mark.
|
||||
|
||||
config NFT_REJECT_IPV6
|
||||
select NF_REJECT_IPV6
|
||||
default NFT_REJECT
|
||||
|
@ -278,15 +270,10 @@ if IP6_NF_NAT
|
|||
|
||||
config IP6_NF_TARGET_MASQUERADE
|
||||
tristate "MASQUERADE target support"
|
||||
select NF_NAT_MASQUERADE
|
||||
select NETFILTER_XT_TARGET_MASQUERADE
|
||||
help
|
||||
Masquerading is a special case of NAT: all outgoing connections are
|
||||
changed to seem to come from a particular interface's address, and
|
||||
if the interface goes down, those connections are lost. This is
|
||||
only useful for dialup accounts with dynamic IP address (ie. your IP
|
||||
address will be different on next dialup).
|
||||
|
||||
To compile it as a module, choose M here. If unsure, say N.
|
||||
This is a backwards-compat option for the user's convenience
|
||||
(e.g. when running oldconfig). It selects NETFILTER_XT_TARGET_MASQUERADE.
|
||||
|
||||
config IP6_NF_TARGET_NPT
|
||||
tristate "NPT (Network Prefix translation) target support"
|
||||
|
|
|
@ -27,7 +27,6 @@ obj-$(CONFIG_NF_REJECT_IPV6) += nf_reject_ipv6.o
|
|||
obj-$(CONFIG_NF_DUP_IPV6) += nf_dup_ipv6.o
|
||||
|
||||
# nf_tables
|
||||
obj-$(CONFIG_NFT_CHAIN_ROUTE_IPV6) += nft_chain_route_ipv6.o
|
||||
obj-$(CONFIG_NFT_REJECT_IPV6) += nft_reject_ipv6.o
|
||||
obj-$(CONFIG_NFT_DUP_IPV6) += nft_dup_ipv6.o
|
||||
obj-$(CONFIG_NFT_FIB_IPV6) += nft_fib_ipv6.o
|
||||
|
@ -47,7 +46,6 @@ obj-$(CONFIG_IP6_NF_MATCH_RT) += ip6t_rt.o
|
|||
obj-$(CONFIG_IP6_NF_MATCH_SRH) += ip6t_srh.o
|
||||
|
||||
# targets
|
||||
obj-$(CONFIG_IP6_NF_TARGET_MASQUERADE) += ip6t_MASQUERADE.o
|
||||
obj-$(CONFIG_IP6_NF_TARGET_NPT) += ip6t_NPT.o
|
||||
obj-$(CONFIG_IP6_NF_TARGET_REJECT) += ip6t_REJECT.o
|
||||
obj-$(CONFIG_IP6_NF_TARGET_SYNPROXY) += ip6t_SYNPROXY.o
|
||||
|
|
|
@ -1,81 +0,0 @@
|
|||
/*
|
||||
* Copyright (c) 2011 Patrick McHardy <kaber@trash.net>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* Based on Rusty Russell's IPv6 MASQUERADE target. Development of IPv6
|
||||
* NAT funded by Astaro.
|
||||
*/
|
||||
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/netdevice.h>
|
||||
#include <linux/ipv6.h>
|
||||
#include <linux/netfilter.h>
|
||||
#include <linux/netfilter_ipv6.h>
|
||||
#include <linux/netfilter/x_tables.h>
|
||||
#include <net/netfilter/nf_nat.h>
|
||||
#include <net/addrconf.h>
|
||||
#include <net/ipv6.h>
|
||||
#include <net/netfilter/ipv6/nf_nat_masquerade.h>
|
||||
|
||||
static unsigned int
|
||||
masquerade_tg6(struct sk_buff *skb, const struct xt_action_param *par)
|
||||
{
|
||||
return nf_nat_masquerade_ipv6(skb, par->targinfo, xt_out(par));
|
||||
}
|
||||
|
||||
static int masquerade_tg6_checkentry(const struct xt_tgchk_param *par)
|
||||
{
|
||||
const struct nf_nat_range2 *range = par->targinfo;
|
||||
|
||||
if (range->flags & NF_NAT_RANGE_MAP_IPS)
|
||||
return -EINVAL;
|
||||
return nf_ct_netns_get(par->net, par->family);
|
||||
}
|
||||
|
||||
static void masquerade_tg6_destroy(const struct xt_tgdtor_param *par)
|
||||
{
|
||||
nf_ct_netns_put(par->net, par->family);
|
||||
}
|
||||
|
||||
static struct xt_target masquerade_tg6_reg __read_mostly = {
|
||||
.name = "MASQUERADE",
|
||||
.family = NFPROTO_IPV6,
|
||||
.checkentry = masquerade_tg6_checkentry,
|
||||
.destroy = masquerade_tg6_destroy,
|
||||
.target = masquerade_tg6,
|
||||
.targetsize = sizeof(struct nf_nat_range),
|
||||
.table = "nat",
|
||||
.hooks = 1 << NF_INET_POST_ROUTING,
|
||||
.me = THIS_MODULE,
|
||||
};
|
||||
|
||||
static int __init masquerade_tg6_init(void)
|
||||
{
|
||||
int err;
|
||||
|
||||
err = xt_register_target(&masquerade_tg6_reg);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
err = nf_nat_masquerade_ipv6_register_notifier();
|
||||
if (err)
|
||||
xt_unregister_target(&masquerade_tg6_reg);
|
||||
|
||||
return err;
|
||||
}
|
||||
static void __exit masquerade_tg6_exit(void)
|
||||
{
|
||||
nf_nat_masquerade_ipv6_unregister_notifier();
|
||||
xt_unregister_target(&masquerade_tg6_reg);
|
||||
}
|
||||
|
||||
module_init(masquerade_tg6_init);
|
||||
module_exit(masquerade_tg6_exit);
|
||||
|
||||
MODULE_LICENSE("GPL");
|
||||
MODULE_AUTHOR("Patrick McHardy <kaber@trash.net>");
|
||||
MODULE_DESCRIPTION("Xtables: automatic address SNAT");
|
|
@ -1,91 +0,0 @@
|
|||
/*
|
||||
* Copyright (c) 2008 Patrick McHardy <kaber@trash.net>
|
||||
* Copyright (c) 2012 Pablo Neira Ayuso <pablo@netfilter.org>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* Development of this code funded by Astaro AG (http://www.astaro.com/)
|
||||
*/
|
||||
|
||||
#include <linux/module.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/list.h>
|
||||
#include <linux/skbuff.h>
|
||||
#include <linux/netlink.h>
|
||||
#include <linux/netfilter.h>
|
||||
#include <linux/netfilter_ipv6.h>
|
||||
#include <linux/netfilter/nfnetlink.h>
|
||||
#include <linux/netfilter/nf_tables.h>
|
||||
#include <net/netfilter/nf_tables.h>
|
||||
#include <net/netfilter/nf_tables_ipv6.h>
|
||||
#include <net/route.h>
|
||||
|
||||
static unsigned int nf_route_table_hook(void *priv,
|
||||
struct sk_buff *skb,
|
||||
const struct nf_hook_state *state)
|
||||
{
|
||||
unsigned int ret;
|
||||
struct nft_pktinfo pkt;
|
||||
struct in6_addr saddr, daddr;
|
||||
u_int8_t hop_limit;
|
||||
u32 mark, flowlabel;
|
||||
int err;
|
||||
|
||||
nft_set_pktinfo(&pkt, skb, state);
|
||||
nft_set_pktinfo_ipv6(&pkt, skb);
|
||||
|
||||
/* save source/dest address, mark, hoplimit, flowlabel, priority */
|
||||
memcpy(&saddr, &ipv6_hdr(skb)->saddr, sizeof(saddr));
|
||||
memcpy(&daddr, &ipv6_hdr(skb)->daddr, sizeof(daddr));
|
||||
mark = skb->mark;
|
||||
hop_limit = ipv6_hdr(skb)->hop_limit;
|
||||
|
||||
/* flowlabel and prio (includes version, which shouldn't change either */
|
||||
flowlabel = *((u32 *)ipv6_hdr(skb));
|
||||
|
||||
ret = nft_do_chain(&pkt, priv);
|
||||
if (ret != NF_DROP && ret != NF_STOLEN &&
|
||||
(memcmp(&ipv6_hdr(skb)->saddr, &saddr, sizeof(saddr)) ||
|
||||
memcmp(&ipv6_hdr(skb)->daddr, &daddr, sizeof(daddr)) ||
|
||||
skb->mark != mark ||
|
||||
ipv6_hdr(skb)->hop_limit != hop_limit ||
|
||||
flowlabel != *((u_int32_t *)ipv6_hdr(skb)))) {
|
||||
err = ip6_route_me_harder(state->net, skb);
|
||||
if (err < 0)
|
||||
ret = NF_DROP_ERR(err);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static const struct nft_chain_type nft_chain_route_ipv6 = {
|
||||
.name = "route",
|
||||
.type = NFT_CHAIN_T_ROUTE,
|
||||
.family = NFPROTO_IPV6,
|
||||
.owner = THIS_MODULE,
|
||||
.hook_mask = (1 << NF_INET_LOCAL_OUT),
|
||||
.hooks = {
|
||||
[NF_INET_LOCAL_OUT] = nf_route_table_hook,
|
||||
},
|
||||
};
|
||||
|
||||
static int __init nft_chain_route_init(void)
|
||||
{
|
||||
nft_register_chain_type(&nft_chain_route_ipv6);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void __exit nft_chain_route_exit(void)
|
||||
{
|
||||
nft_unregister_chain_type(&nft_chain_route_ipv6);
|
||||
}
|
||||
|
||||
module_init(nft_chain_route_init);
|
||||
module_exit(nft_chain_route_exit);
|
||||
|
||||
MODULE_LICENSE("GPL");
|
||||
MODULE_AUTHOR("Patrick McHardy <kaber@trash.net>");
|
||||
MODULE_ALIAS_NFT_CHAIN(AF_INET6, "route");
|
|
@ -404,11 +404,6 @@ config NF_NAT
|
|||
forms of full Network Address Port Translation. This can be
|
||||
controlled by iptables, ip6tables or nft.
|
||||
|
||||
config NF_NAT_NEEDED
|
||||
bool
|
||||
depends on NF_NAT
|
||||
default y
|
||||
|
||||
config NF_NAT_AMANDA
|
||||
tristate
|
||||
depends on NF_CONNTRACK && NF_NAT
|
||||
|
@ -1002,6 +997,20 @@ config NETFILTER_XT_TARGET_REDIRECT
|
|||
|
||||
To compile it as a module, choose M here. If unsure, say N.
|
||||
|
||||
config NETFILTER_XT_TARGET_MASQUERADE
|
||||
tristate "MASQUERADE target support"
|
||||
depends on NF_NAT
|
||||
default m if NETFILTER_ADVANCED=n
|
||||
select NF_NAT_MASQUERADE
|
||||
help
|
||||
Masquerading is a special case of NAT: all outgoing connections are
|
||||
changed to seem to come from a particular interface's address, and
|
||||
if the interface goes down, those connections are lost. This is
|
||||
only useful for dialup accounts with dynamic IP address (ie. your IP
|
||||
address will be different on next dialup).
|
||||
|
||||
To compile it as a module, choose M here. If unsure, say N.
|
||||
|
||||
config NETFILTER_XT_TARGET_TEE
|
||||
tristate '"TEE" - packet cloning to alternate destination'
|
||||
depends on NETFILTER_ADVANCED
|
||||
|
|
|
@ -77,7 +77,8 @@ obj-$(CONFIG_NF_DUP_NETDEV) += nf_dup_netdev.o
|
|||
nf_tables-objs := nf_tables_core.o nf_tables_api.o nft_chain_filter.o \
|
||||
nf_tables_trace.o nft_immediate.o nft_cmp.o nft_range.o \
|
||||
nft_bitwise.o nft_byteorder.o nft_payload.o nft_lookup.o \
|
||||
nft_dynset.o nft_meta.o nft_rt.o nft_exthdr.o
|
||||
nft_dynset.o nft_meta.o nft_rt.o nft_exthdr.o \
|
||||
nft_chain_route.o
|
||||
|
||||
nf_tables_set-objs := nf_tables_set_core.o \
|
||||
nft_set_hash.o nft_set_bitmap.o nft_set_rbtree.o
|
||||
|
@ -147,6 +148,7 @@ obj-$(CONFIG_NETFILTER_XT_TARGET_NFLOG) += xt_NFLOG.o
|
|||
obj-$(CONFIG_NETFILTER_XT_TARGET_NFQUEUE) += xt_NFQUEUE.o
|
||||
obj-$(CONFIG_NETFILTER_XT_TARGET_RATEEST) += xt_RATEEST.o
|
||||
obj-$(CONFIG_NETFILTER_XT_TARGET_REDIRECT) += xt_REDIRECT.o
|
||||
obj-$(CONFIG_NETFILTER_XT_TARGET_MASQUERADE) += xt_MASQUERADE.o
|
||||
obj-$(CONFIG_NETFILTER_XT_TARGET_SECMARK) += xt_SECMARK.o
|
||||
obj-$(CONFIG_NETFILTER_XT_TARGET_TPROXY) += xt_TPROXY.o
|
||||
obj-$(CONFIG_NETFILTER_XT_TARGET_TCPMSS) += xt_TCPMSS.o
|
||||
|
|
|
@ -23,6 +23,7 @@
|
|||
#include <linux/mm.h>
|
||||
#include <linux/rcupdate.h>
|
||||
#include <net/net_namespace.h>
|
||||
#include <net/netfilter/nf_queue.h>
|
||||
#include <net/sock.h>
|
||||
|
||||
#include "nf_internals.h"
|
||||
|
|
|
@ -831,6 +831,10 @@ __ip_vs_update_dest(struct ip_vs_service *svc, struct ip_vs_dest *dest,
|
|||
conn_flags = udest->conn_flags & IP_VS_CONN_F_DEST_MASK;
|
||||
conn_flags |= IP_VS_CONN_F_INACTIVE;
|
||||
|
||||
/* set the tunnel info */
|
||||
dest->tun_type = udest->tun_type;
|
||||
dest->tun_port = udest->tun_port;
|
||||
|
||||
/* set the IP_VS_CONN_F_NOOUTPUT flag if not masquerading/NAT */
|
||||
if ((conn_flags & IP_VS_CONN_F_FWD_MASK) != IP_VS_CONN_F_MASQ) {
|
||||
conn_flags |= IP_VS_CONN_F_NOOUTPUT;
|
||||
|
@ -987,6 +991,13 @@ ip_vs_add_dest(struct ip_vs_service *svc, struct ip_vs_dest_user_kern *udest)
|
|||
return -ERANGE;
|
||||
}
|
||||
|
||||
if (udest->tun_type == IP_VS_CONN_F_TUNNEL_TYPE_GUE) {
|
||||
if (udest->tun_port == 0) {
|
||||
pr_err("%s(): tunnel port is zero\n", __func__);
|
||||
return -EINVAL;
|
||||
}
|
||||
}
|
||||
|
||||
ip_vs_addr_copy(udest->af, &daddr, &udest->addr);
|
||||
|
||||
/* We use function that requires RCU lock */
|
||||
|
@ -1051,6 +1062,13 @@ ip_vs_edit_dest(struct ip_vs_service *svc, struct ip_vs_dest_user_kern *udest)
|
|||
return -ERANGE;
|
||||
}
|
||||
|
||||
if (udest->tun_type == IP_VS_CONN_F_TUNNEL_TYPE_GUE) {
|
||||
if (udest->tun_port == 0) {
|
||||
pr_err("%s(): tunnel port is zero\n", __func__);
|
||||
return -EINVAL;
|
||||
}
|
||||
}
|
||||
|
||||
ip_vs_addr_copy(udest->af, &daddr, &udest->addr);
|
||||
|
||||
/* We use function that requires RCU lock */
|
||||
|
@ -2333,6 +2351,7 @@ static void ip_vs_copy_udest_compat(struct ip_vs_dest_user_kern *udest,
|
|||
udest->u_threshold = udest_compat->u_threshold;
|
||||
udest->l_threshold = udest_compat->l_threshold;
|
||||
udest->af = AF_INET;
|
||||
udest->tun_type = IP_VS_CONN_F_TUNNEL_TYPE_IPIP;
|
||||
}
|
||||
|
||||
static int
|
||||
|
@ -2890,6 +2909,8 @@ static const struct nla_policy ip_vs_dest_policy[IPVS_DEST_ATTR_MAX + 1] = {
|
|||
[IPVS_DEST_ATTR_PERSIST_CONNS] = { .type = NLA_U32 },
|
||||
[IPVS_DEST_ATTR_STATS] = { .type = NLA_NESTED },
|
||||
[IPVS_DEST_ATTR_ADDR_FAMILY] = { .type = NLA_U16 },
|
||||
[IPVS_DEST_ATTR_TUN_TYPE] = { .type = NLA_U8 },
|
||||
[IPVS_DEST_ATTR_TUN_PORT] = { .type = NLA_U16 },
|
||||
};
|
||||
|
||||
static int ip_vs_genl_fill_stats(struct sk_buff *skb, int container_type,
|
||||
|
@ -3193,6 +3214,10 @@ static int ip_vs_genl_fill_dest(struct sk_buff *skb, struct ip_vs_dest *dest)
|
|||
IP_VS_CONN_F_FWD_MASK)) ||
|
||||
nla_put_u32(skb, IPVS_DEST_ATTR_WEIGHT,
|
||||
atomic_read(&dest->weight)) ||
|
||||
nla_put_u8(skb, IPVS_DEST_ATTR_TUN_TYPE,
|
||||
dest->tun_type) ||
|
||||
nla_put_be16(skb, IPVS_DEST_ATTR_TUN_PORT,
|
||||
dest->tun_port) ||
|
||||
nla_put_u32(skb, IPVS_DEST_ATTR_U_THRESH, dest->u_threshold) ||
|
||||
nla_put_u32(skb, IPVS_DEST_ATTR_L_THRESH, dest->l_threshold) ||
|
||||
nla_put_u32(skb, IPVS_DEST_ATTR_ACTIVE_CONNS,
|
||||
|
@ -3315,12 +3340,14 @@ static int ip_vs_genl_parse_dest(struct ip_vs_dest_user_kern *udest,
|
|||
/* If a full entry was requested, check for the additional fields */
|
||||
if (full_entry) {
|
||||
struct nlattr *nla_fwd, *nla_weight, *nla_u_thresh,
|
||||
*nla_l_thresh;
|
||||
*nla_l_thresh, *nla_tun_type, *nla_tun_port;
|
||||
|
||||
nla_fwd = attrs[IPVS_DEST_ATTR_FWD_METHOD];
|
||||
nla_weight = attrs[IPVS_DEST_ATTR_WEIGHT];
|
||||
nla_u_thresh = attrs[IPVS_DEST_ATTR_U_THRESH];
|
||||
nla_l_thresh = attrs[IPVS_DEST_ATTR_L_THRESH];
|
||||
nla_tun_type = attrs[IPVS_DEST_ATTR_TUN_TYPE];
|
||||
nla_tun_port = attrs[IPVS_DEST_ATTR_TUN_PORT];
|
||||
|
||||
if (!(nla_fwd && nla_weight && nla_u_thresh && nla_l_thresh))
|
||||
return -EINVAL;
|
||||
|
@ -3330,6 +3357,12 @@ static int ip_vs_genl_parse_dest(struct ip_vs_dest_user_kern *udest,
|
|||
udest->weight = nla_get_u32(nla_weight);
|
||||
udest->u_threshold = nla_get_u32(nla_u_thresh);
|
||||
udest->l_threshold = nla_get_u32(nla_l_thresh);
|
||||
|
||||
if (nla_tun_type)
|
||||
udest->tun_type = nla_get_u8(nla_tun_type);
|
||||
|
||||
if (nla_tun_port)
|
||||
udest->tun_port = nla_get_be16(nla_tun_port);
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
|
|
@ -32,6 +32,7 @@
|
|||
#include <linux/slab.h>
|
||||
#include <linux/tcp.h> /* for tcphdr */
|
||||
#include <net/ip.h>
|
||||
#include <net/gue.h>
|
||||
#include <net/tcp.h> /* for csum_tcpudp_magic */
|
||||
#include <net/udp.h>
|
||||
#include <net/icmp.h> /* for icmp_send */
|
||||
|
@ -382,6 +383,10 @@ __ip_vs_get_out_rt(struct netns_ipvs *ipvs, int skb_af, struct sk_buff *skb,
|
|||
mtu = dst_mtu(&rt->dst);
|
||||
} else {
|
||||
mtu = dst_mtu(&rt->dst) - sizeof(struct iphdr);
|
||||
if (!dest)
|
||||
goto err_put;
|
||||
if (dest->tun_type == IP_VS_CONN_F_TUNNEL_TYPE_GUE)
|
||||
mtu -= sizeof(struct udphdr) + sizeof(struct guehdr);
|
||||
if (mtu < 68) {
|
||||
IP_VS_DBG_RL("%s(): mtu less than 68\n", __func__);
|
||||
goto err_put;
|
||||
|
@ -533,6 +538,10 @@ __ip_vs_get_out_rt_v6(struct netns_ipvs *ipvs, int skb_af, struct sk_buff *skb,
|
|||
mtu = dst_mtu(&rt->dst);
|
||||
else {
|
||||
mtu = dst_mtu(&rt->dst) - sizeof(struct ipv6hdr);
|
||||
if (!dest)
|
||||
goto err_put;
|
||||
if (dest->tun_type == IP_VS_CONN_F_TUNNEL_TYPE_GUE)
|
||||
mtu -= sizeof(struct udphdr) + sizeof(struct guehdr);
|
||||
if (mtu < IPV6_MIN_MTU) {
|
||||
IP_VS_DBG_RL("%s(): mtu less than %d\n", __func__,
|
||||
IPV6_MIN_MTU);
|
||||
|
@ -989,6 +998,41 @@ static inline int __tun_gso_type_mask(int encaps_af, int orig_af)
|
|||
}
|
||||
}
|
||||
|
||||
static int
|
||||
ipvs_gue_encap(struct net *net, struct sk_buff *skb,
|
||||
struct ip_vs_conn *cp, __u8 *next_protocol)
|
||||
{
|
||||
__be16 dport;
|
||||
__be16 sport = udp_flow_src_port(net, skb, 0, 0, false);
|
||||
struct udphdr *udph; /* Our new UDP header */
|
||||
struct guehdr *gueh; /* Our new GUE header */
|
||||
|
||||
skb_push(skb, sizeof(struct guehdr));
|
||||
|
||||
gueh = (struct guehdr *)skb->data;
|
||||
|
||||
gueh->control = 0;
|
||||
gueh->version = 0;
|
||||
gueh->hlen = 0;
|
||||
gueh->flags = 0;
|
||||
gueh->proto_ctype = *next_protocol;
|
||||
|
||||
skb_push(skb, sizeof(struct udphdr));
|
||||
skb_reset_transport_header(skb);
|
||||
|
||||
udph = udp_hdr(skb);
|
||||
|
||||
dport = cp->dest->tun_port;
|
||||
udph->dest = dport;
|
||||
udph->source = sport;
|
||||
udph->len = htons(skb->len);
|
||||
udph->check = 0;
|
||||
|
||||
*next_protocol = IPPROTO_UDP;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* IP Tunneling transmitter
|
||||
*
|
||||
|
@ -1025,6 +1069,7 @@ ip_vs_tunnel_xmit(struct sk_buff *skb, struct ip_vs_conn *cp,
|
|||
struct iphdr *iph; /* Our new IP header */
|
||||
unsigned int max_headroom; /* The extra header space needed */
|
||||
int ret, local;
|
||||
int tun_type, gso_type;
|
||||
|
||||
EnterFunction(10);
|
||||
|
||||
|
@ -1046,6 +1091,11 @@ ip_vs_tunnel_xmit(struct sk_buff *skb, struct ip_vs_conn *cp,
|
|||
*/
|
||||
max_headroom = LL_RESERVED_SPACE(tdev) + sizeof(struct iphdr);
|
||||
|
||||
tun_type = cp->dest->tun_type;
|
||||
|
||||
if (tun_type == IP_VS_CONN_F_TUNNEL_TYPE_GUE)
|
||||
max_headroom += sizeof(struct udphdr) + sizeof(struct guehdr);
|
||||
|
||||
/* We only care about the df field if sysctl_pmtu_disc(ipvs) is set */
|
||||
dfp = sysctl_pmtu_disc(ipvs) ? &df : NULL;
|
||||
skb = ip_vs_prepare_tunneled_skb(skb, cp->af, max_headroom,
|
||||
|
@ -1054,11 +1104,20 @@ ip_vs_tunnel_xmit(struct sk_buff *skb, struct ip_vs_conn *cp,
|
|||
if (IS_ERR(skb))
|
||||
goto tx_error;
|
||||
|
||||
if (iptunnel_handle_offloads(skb, __tun_gso_type_mask(AF_INET, cp->af)))
|
||||
gso_type = __tun_gso_type_mask(AF_INET, cp->af);
|
||||
if (tun_type == IP_VS_CONN_F_TUNNEL_TYPE_GUE)
|
||||
gso_type |= SKB_GSO_UDP_TUNNEL;
|
||||
|
||||
if (iptunnel_handle_offloads(skb, gso_type))
|
||||
goto tx_error;
|
||||
|
||||
skb->transport_header = skb->network_header;
|
||||
|
||||
skb_set_inner_ipproto(skb, next_protocol);
|
||||
|
||||
if (tun_type == IP_VS_CONN_F_TUNNEL_TYPE_GUE)
|
||||
ipvs_gue_encap(net, skb, cp, &next_protocol);
|
||||
|
||||
skb_push(skb, sizeof(struct iphdr));
|
||||
skb_reset_network_header(skb);
|
||||
memset(&(IPCB(skb)->opt), 0, sizeof(IPCB(skb)->opt));
|
||||
|
@ -1102,6 +1161,8 @@ int
|
|||
ip_vs_tunnel_xmit_v6(struct sk_buff *skb, struct ip_vs_conn *cp,
|
||||
struct ip_vs_protocol *pp, struct ip_vs_iphdr *ipvsh)
|
||||
{
|
||||
struct netns_ipvs *ipvs = cp->ipvs;
|
||||
struct net *net = ipvs->net;
|
||||
struct rt6_info *rt; /* Route to the other host */
|
||||
struct in6_addr saddr; /* Source for tunnel */
|
||||
struct net_device *tdev; /* Device to other host */
|
||||
|
@ -1112,10 +1173,11 @@ ip_vs_tunnel_xmit_v6(struct sk_buff *skb, struct ip_vs_conn *cp,
|
|||
struct ipv6hdr *iph; /* Our new IP header */
|
||||
unsigned int max_headroom; /* The extra header space needed */
|
||||
int ret, local;
|
||||
int tun_type, gso_type;
|
||||
|
||||
EnterFunction(10);
|
||||
|
||||
local = __ip_vs_get_out_rt_v6(cp->ipvs, cp->af, skb, cp->dest,
|
||||
local = __ip_vs_get_out_rt_v6(ipvs, cp->af, skb, cp->dest,
|
||||
&cp->daddr.in6,
|
||||
&saddr, ipvsh, 1,
|
||||
IP_VS_RT_MODE_LOCAL |
|
||||
|
@ -1134,17 +1196,31 @@ ip_vs_tunnel_xmit_v6(struct sk_buff *skb, struct ip_vs_conn *cp,
|
|||
*/
|
||||
max_headroom = LL_RESERVED_SPACE(tdev) + sizeof(struct ipv6hdr);
|
||||
|
||||
tun_type = cp->dest->tun_type;
|
||||
|
||||
if (tun_type == IP_VS_CONN_F_TUNNEL_TYPE_GUE)
|
||||
max_headroom += sizeof(struct udphdr) + sizeof(struct guehdr);
|
||||
|
||||
skb = ip_vs_prepare_tunneled_skb(skb, cp->af, max_headroom,
|
||||
&next_protocol, &payload_len,
|
||||
&dsfield, &ttl, NULL);
|
||||
if (IS_ERR(skb))
|
||||
goto tx_error;
|
||||
|
||||
if (iptunnel_handle_offloads(skb, __tun_gso_type_mask(AF_INET6, cp->af)))
|
||||
gso_type = __tun_gso_type_mask(AF_INET6, cp->af);
|
||||
if (tun_type == IP_VS_CONN_F_TUNNEL_TYPE_GUE)
|
||||
gso_type |= SKB_GSO_UDP_TUNNEL;
|
||||
|
||||
if (iptunnel_handle_offloads(skb, gso_type))
|
||||
goto tx_error;
|
||||
|
||||
skb->transport_header = skb->network_header;
|
||||
|
||||
skb_set_inner_ipproto(skb, next_protocol);
|
||||
|
||||
if (tun_type == IP_VS_CONN_F_TUNNEL_TYPE_GUE)
|
||||
ipvs_gue_encap(net, skb, cp, &next_protocol);
|
||||
|
||||
skb_push(skb, sizeof(struct ipv6hdr));
|
||||
skb_reset_network_header(skb);
|
||||
memset(&(IPCB(skb)->opt), 0, sizeof(IPCB(skb)->opt));
|
||||
|
@ -1167,7 +1243,7 @@ ip_vs_tunnel_xmit_v6(struct sk_buff *skb, struct ip_vs_conn *cp,
|
|||
|
||||
ret = ip_vs_tunnel_xmit_prepare(skb, cp);
|
||||
if (ret == NF_ACCEPT)
|
||||
ip6_local_out(cp->ipvs->net, skb->sk, skb);
|
||||
ip6_local_out(net, skb->sk, skb);
|
||||
else if (ret == NF_DROP)
|
||||
kfree_skb(skb);
|
||||
|
||||
|
|
|
@ -336,7 +336,7 @@ void nf_ct_expect_init(struct nf_conntrack_expect *exp, unsigned int class,
|
|||
|
||||
exp->tuple.dst.u.all = *dst;
|
||||
|
||||
#ifdef CONFIG_NF_NAT_NEEDED
|
||||
#if IS_ENABLED(CONFIG_NF_NAT)
|
||||
memset(&exp->saved_addr, 0, sizeof(exp->saved_addr));
|
||||
memset(&exp->saved_proto, 0, sizeof(exp->saved_proto));
|
||||
#endif
|
||||
|
|
|
@ -45,7 +45,7 @@
|
|||
#include <net/netfilter/nf_conntrack_timestamp.h>
|
||||
#include <net/netfilter/nf_conntrack_labels.h>
|
||||
#include <net/netfilter/nf_conntrack_synproxy.h>
|
||||
#ifdef CONFIG_NF_NAT_NEEDED
|
||||
#if IS_ENABLED(CONFIG_NF_NAT)
|
||||
#include <net/netfilter/nf_nat.h>
|
||||
#include <net/netfilter/nf_nat_helper.h>
|
||||
#endif
|
||||
|
@ -655,7 +655,7 @@ static size_t ctnetlink_nlmsg_size(const struct nf_conn *ct)
|
|||
+ nla_total_size(0) /* CTA_HELP */
|
||||
+ nla_total_size(NF_CT_HELPER_NAME_LEN) /* CTA_HELP_NAME */
|
||||
+ ctnetlink_secctx_size(ct)
|
||||
#ifdef CONFIG_NF_NAT_NEEDED
|
||||
#if IS_ENABLED(CONFIG_NF_NAT)
|
||||
+ 2 * nla_total_size(0) /* CTA_NAT_SEQ_ADJ_ORIG|REPL */
|
||||
+ 6 * nla_total_size(sizeof(u_int32_t)) /* CTA_NAT_SEQ_OFFSET */
|
||||
#endif
|
||||
|
@ -1494,7 +1494,7 @@ static int ctnetlink_get_ct_unconfirmed(struct net *net, struct sock *ctnl,
|
|||
return -EOPNOTSUPP;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_NF_NAT_NEEDED
|
||||
#if IS_ENABLED(CONFIG_NF_NAT)
|
||||
static int
|
||||
ctnetlink_parse_nat_setup(struct nf_conn *ct,
|
||||
enum nf_nat_manip_type manip,
|
||||
|
@ -1586,7 +1586,7 @@ ctnetlink_change_status(struct nf_conn *ct, const struct nlattr * const cda[])
|
|||
static int
|
||||
ctnetlink_setup_nat(struct nf_conn *ct, const struct nlattr * const cda[])
|
||||
{
|
||||
#ifdef CONFIG_NF_NAT_NEEDED
|
||||
#if IS_ENABLED(CONFIG_NF_NAT)
|
||||
int ret;
|
||||
|
||||
if (!cda[CTA_NAT_DST] && !cda[CTA_NAT_SRC])
|
||||
|
@ -2369,7 +2369,7 @@ ctnetlink_glue_build_size(const struct nf_conn *ct)
|
|||
+ nla_total_size(0) /* CTA_HELP */
|
||||
+ nla_total_size(NF_CT_HELPER_NAME_LEN) /* CTA_HELP_NAME */
|
||||
+ ctnetlink_secctx_size(ct)
|
||||
#ifdef CONFIG_NF_NAT_NEEDED
|
||||
#if IS_ENABLED(CONFIG_NF_NAT)
|
||||
+ 2 * nla_total_size(0) /* CTA_NAT_SEQ_ADJ_ORIG|REPL */
|
||||
+ 6 * nla_total_size(sizeof(u_int32_t)) /* CTA_NAT_SEQ_OFFSET */
|
||||
#endif
|
||||
|
@ -2699,7 +2699,7 @@ ctnetlink_exp_dump_expect(struct sk_buff *skb,
|
|||
struct nf_conn *master = exp->master;
|
||||
long timeout = ((long)exp->timeout.expires - (long)jiffies) / HZ;
|
||||
struct nf_conn_help *help;
|
||||
#ifdef CONFIG_NF_NAT_NEEDED
|
||||
#if IS_ENABLED(CONFIG_NF_NAT)
|
||||
struct nlattr *nest_parms;
|
||||
struct nf_conntrack_tuple nat_tuple = {};
|
||||
#endif
|
||||
|
@ -2717,7 +2717,7 @@ ctnetlink_exp_dump_expect(struct sk_buff *skb,
|
|||
CTA_EXPECT_MASTER) < 0)
|
||||
goto nla_put_failure;
|
||||
|
||||
#ifdef CONFIG_NF_NAT_NEEDED
|
||||
#if IS_ENABLED(CONFIG_NF_NAT)
|
||||
if (!nf_inet_addr_cmp(&exp->saved_addr, &any_addr) ||
|
||||
exp->saved_proto.all) {
|
||||
nest_parms = nla_nest_start(skb, CTA_EXPECT_NAT | NLA_F_NESTED);
|
||||
|
@ -3180,7 +3180,7 @@ ctnetlink_parse_expect_nat(const struct nlattr *attr,
|
|||
struct nf_conntrack_expect *exp,
|
||||
u_int8_t u3)
|
||||
{
|
||||
#ifdef CONFIG_NF_NAT_NEEDED
|
||||
#if IS_ENABLED(CONFIG_NF_NAT)
|
||||
struct nlattr *tb[CTA_EXPECT_NAT_MAX+1];
|
||||
struct nf_conntrack_tuple nat_tuple = {};
|
||||
int err;
|
||||
|
|
|
@ -928,7 +928,7 @@ static int set_expected_rtp_rtcp(struct sk_buff *skb, unsigned int protoff,
|
|||
nfct_help(exp->master)->helper != nfct_help(ct)->helper ||
|
||||
exp->class != class)
|
||||
break;
|
||||
#ifdef CONFIG_NF_NAT_NEEDED
|
||||
#if IS_ENABLED(CONFIG_NF_NAT)
|
||||
if (!direct_rtp &&
|
||||
(!nf_inet_addr_cmp(&exp->saved_addr, &exp->tuple.dst.u3) ||
|
||||
exp->saved_proto.udp.port != exp->tuple.dst.u.udp.port) &&
|
||||
|
|
|
@ -235,13 +235,10 @@ nf_flow_offload_ip_hook(void *priv, struct sk_buff *skb,
|
|||
if (tuplehash == NULL)
|
||||
return NF_ACCEPT;
|
||||
|
||||
outdev = dev_get_by_index_rcu(state->net, tuplehash->tuple.oifidx);
|
||||
if (!outdev)
|
||||
return NF_ACCEPT;
|
||||
|
||||
dir = tuplehash->tuple.dir;
|
||||
flow = container_of(tuplehash, struct flow_offload, tuplehash[dir]);
|
||||
rt = (struct rtable *)flow->tuplehash[dir].tuple.dst_cache;
|
||||
outdev = rt->dst.dev;
|
||||
|
||||
if (unlikely(nf_flow_exceeds_mtu(skb, flow->tuplehash[dir].tuple.mtu)) &&
|
||||
(ip_hdr(skb)->frag_off & htons(IP_DF)) != 0)
|
||||
|
@ -452,13 +449,10 @@ nf_flow_offload_ipv6_hook(void *priv, struct sk_buff *skb,
|
|||
if (tuplehash == NULL)
|
||||
return NF_ACCEPT;
|
||||
|
||||
outdev = dev_get_by_index_rcu(state->net, tuplehash->tuple.oifidx);
|
||||
if (!outdev)
|
||||
return NF_ACCEPT;
|
||||
|
||||
dir = tuplehash->tuple.dir;
|
||||
flow = container_of(tuplehash, struct flow_offload, tuplehash[dir]);
|
||||
rt = (struct rt6_info *)flow->tuplehash[dir].tuple.dst_cache;
|
||||
outdev = rt->dst.dev;
|
||||
|
||||
if (unlikely(nf_flow_exceeds_mtu(skb, flow->tuplehash[dir].tuple.mtu)))
|
||||
return NF_ACCEPT;
|
||||
|
|
|
@ -7,9 +7,6 @@
|
|||
#include <linux/netdevice.h>
|
||||
|
||||
/* nf_queue.c */
|
||||
int nf_queue(struct sk_buff *skb, struct nf_hook_state *state,
|
||||
const struct nf_hook_entries *entries, unsigned int index,
|
||||
unsigned int verdict);
|
||||
void nf_queue_nf_hook_drop(struct net *net);
|
||||
|
||||
/* nf_log.c */
|
||||
|
|
|
@ -1009,7 +1009,7 @@ static struct nf_ct_helper_expectfn follow_master_nat = {
|
|||
.expectfn = nf_nat_follow_master,
|
||||
};
|
||||
|
||||
int nf_nat_register_fn(struct net *net, const struct nf_hook_ops *ops,
|
||||
int nf_nat_register_fn(struct net *net, u8 pf, const struct nf_hook_ops *ops,
|
||||
const struct nf_hook_ops *orig_nat_ops, unsigned int ops_count)
|
||||
{
|
||||
struct nat_net *nat_net = net_generic(net, nat_net_id);
|
||||
|
@ -1019,14 +1019,12 @@ int nf_nat_register_fn(struct net *net, const struct nf_hook_ops *ops,
|
|||
struct nf_hook_ops *nat_ops;
|
||||
int i, ret;
|
||||
|
||||
if (WARN_ON_ONCE(ops->pf >= ARRAY_SIZE(nat_net->nat_proto_net)))
|
||||
if (WARN_ON_ONCE(pf >= ARRAY_SIZE(nat_net->nat_proto_net)))
|
||||
return -EINVAL;
|
||||
|
||||
nat_proto_net = &nat_net->nat_proto_net[ops->pf];
|
||||
nat_proto_net = &nat_net->nat_proto_net[pf];
|
||||
|
||||
for (i = 0; i < ops_count; i++) {
|
||||
if (WARN_ON(orig_nat_ops[i].pf != ops->pf))
|
||||
return -EINVAL;
|
||||
if (orig_nat_ops[i].hooknum == hooknum) {
|
||||
hooknum = i;
|
||||
break;
|
||||
|
@ -1086,8 +1084,8 @@ int nf_nat_register_fn(struct net *net, const struct nf_hook_ops *ops,
|
|||
return ret;
|
||||
}
|
||||
|
||||
void nf_nat_unregister_fn(struct net *net, const struct nf_hook_ops *ops,
|
||||
unsigned int ops_count)
|
||||
void nf_nat_unregister_fn(struct net *net, u8 pf, const struct nf_hook_ops *ops,
|
||||
unsigned int ops_count)
|
||||
{
|
||||
struct nat_net *nat_net = net_generic(net, nat_net_id);
|
||||
struct nf_nat_hooks_net *nat_proto_net;
|
||||
|
@ -1096,10 +1094,10 @@ void nf_nat_unregister_fn(struct net *net, const struct nf_hook_ops *ops,
|
|||
int hooknum = ops->hooknum;
|
||||
int i;
|
||||
|
||||
if (ops->pf >= ARRAY_SIZE(nat_net->nat_proto_net))
|
||||
if (pf >= ARRAY_SIZE(nat_net->nat_proto_net))
|
||||
return;
|
||||
|
||||
nat_proto_net = &nat_net->nat_proto_net[ops->pf];
|
||||
nat_proto_net = &nat_net->nat_proto_net[pf];
|
||||
|
||||
mutex_lock(&nf_nat_proto_mutex);
|
||||
if (WARN_ON(nat_proto_net->users == 0))
|
||||
|
|
|
@ -7,12 +7,10 @@
|
|||
#include <linux/netfilter_ipv4.h>
|
||||
#include <linux/netfilter_ipv6.h>
|
||||
|
||||
#include <net/netfilter/ipv4/nf_nat_masquerade.h>
|
||||
#include <net/netfilter/ipv6/nf_nat_masquerade.h>
|
||||
#include <net/netfilter/nf_nat_masquerade.h>
|
||||
|
||||
static DEFINE_MUTEX(masq_mutex);
|
||||
static unsigned int masq_refcnt4 __read_mostly;
|
||||
static unsigned int masq_refcnt6 __read_mostly;
|
||||
static unsigned int masq_refcnt __read_mostly;
|
||||
|
||||
unsigned int
|
||||
nf_nat_masquerade_ipv4(struct sk_buff *skb, unsigned int hooknum,
|
||||
|
@ -137,56 +135,6 @@ static struct notifier_block masq_inet_notifier = {
|
|||
.notifier_call = masq_inet_event,
|
||||
};
|
||||
|
||||
int nf_nat_masquerade_ipv4_register_notifier(void)
|
||||
{
|
||||
int ret = 0;
|
||||
|
||||
mutex_lock(&masq_mutex);
|
||||
if (WARN_ON_ONCE(masq_refcnt4 == UINT_MAX)) {
|
||||
ret = -EOVERFLOW;
|
||||
goto out_unlock;
|
||||
}
|
||||
|
||||
/* check if the notifier was already set */
|
||||
if (++masq_refcnt4 > 1)
|
||||
goto out_unlock;
|
||||
|
||||
/* Register for device down reports */
|
||||
ret = register_netdevice_notifier(&masq_dev_notifier);
|
||||
if (ret)
|
||||
goto err_dec;
|
||||
/* Register IP address change reports */
|
||||
ret = register_inetaddr_notifier(&masq_inet_notifier);
|
||||
if (ret)
|
||||
goto err_unregister;
|
||||
|
||||
mutex_unlock(&masq_mutex);
|
||||
return ret;
|
||||
|
||||
err_unregister:
|
||||
unregister_netdevice_notifier(&masq_dev_notifier);
|
||||
err_dec:
|
||||
masq_refcnt4--;
|
||||
out_unlock:
|
||||
mutex_unlock(&masq_mutex);
|
||||
return ret;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(nf_nat_masquerade_ipv4_register_notifier);
|
||||
|
||||
void nf_nat_masquerade_ipv4_unregister_notifier(void)
|
||||
{
|
||||
mutex_lock(&masq_mutex);
|
||||
/* check if the notifier still has clients */
|
||||
if (--masq_refcnt4 > 0)
|
||||
goto out_unlock;
|
||||
|
||||
unregister_netdevice_notifier(&masq_dev_notifier);
|
||||
unregister_inetaddr_notifier(&masq_inet_notifier);
|
||||
out_unlock:
|
||||
mutex_unlock(&masq_mutex);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(nf_nat_masquerade_ipv4_unregister_notifier);
|
||||
|
||||
#if IS_ENABLED(CONFIG_IPV6)
|
||||
static atomic_t v6_worker_count __read_mostly;
|
||||
|
||||
|
@ -322,44 +270,68 @@ static struct notifier_block masq_inet6_notifier = {
|
|||
.notifier_call = masq_inet6_event,
|
||||
};
|
||||
|
||||
int nf_nat_masquerade_ipv6_register_notifier(void)
|
||||
static int nf_nat_masquerade_ipv6_register_notifier(void)
|
||||
{
|
||||
return register_inet6addr_notifier(&masq_inet6_notifier);
|
||||
}
|
||||
#else
|
||||
static inline int nf_nat_masquerade_ipv6_register_notifier(void) { return 0; }
|
||||
#endif
|
||||
|
||||
int nf_nat_masquerade_inet_register_notifiers(void)
|
||||
{
|
||||
int ret = 0;
|
||||
|
||||
mutex_lock(&masq_mutex);
|
||||
if (WARN_ON_ONCE(masq_refcnt6 == UINT_MAX)) {
|
||||
if (WARN_ON_ONCE(masq_refcnt == UINT_MAX)) {
|
||||
ret = -EOVERFLOW;
|
||||
goto out_unlock;
|
||||
}
|
||||
|
||||
/* check if the notifier is already set */
|
||||
if (++masq_refcnt6 > 1)
|
||||
/* check if the notifier was already set */
|
||||
if (++masq_refcnt > 1)
|
||||
goto out_unlock;
|
||||
|
||||
ret = register_inet6addr_notifier(&masq_inet6_notifier);
|
||||
/* Register for device down reports */
|
||||
ret = register_netdevice_notifier(&masq_dev_notifier);
|
||||
if (ret)
|
||||
goto err_dec;
|
||||
/* Register IP address change reports */
|
||||
ret = register_inetaddr_notifier(&masq_inet_notifier);
|
||||
if (ret)
|
||||
goto err_unregister;
|
||||
|
||||
ret = nf_nat_masquerade_ipv6_register_notifier();
|
||||
if (ret)
|
||||
goto err_unreg_inet;
|
||||
|
||||
mutex_unlock(&masq_mutex);
|
||||
return ret;
|
||||
err_unreg_inet:
|
||||
unregister_inetaddr_notifier(&masq_inet_notifier);
|
||||
err_unregister:
|
||||
unregister_netdevice_notifier(&masq_dev_notifier);
|
||||
err_dec:
|
||||
masq_refcnt6--;
|
||||
masq_refcnt--;
|
||||
out_unlock:
|
||||
mutex_unlock(&masq_mutex);
|
||||
return ret;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(nf_nat_masquerade_ipv6_register_notifier);
|
||||
EXPORT_SYMBOL_GPL(nf_nat_masquerade_inet_register_notifiers);
|
||||
|
||||
void nf_nat_masquerade_ipv6_unregister_notifier(void)
|
||||
void nf_nat_masquerade_inet_unregister_notifiers(void)
|
||||
{
|
||||
mutex_lock(&masq_mutex);
|
||||
/* check if the notifier still has clients */
|
||||
if (--masq_refcnt6 > 0)
|
||||
/* check if the notifiers still have clients */
|
||||
if (--masq_refcnt > 0)
|
||||
goto out_unlock;
|
||||
|
||||
unregister_netdevice_notifier(&masq_dev_notifier);
|
||||
unregister_inetaddr_notifier(&masq_inet_notifier);
|
||||
#if IS_ENABLED(CONFIG_IPV6)
|
||||
unregister_inet6addr_notifier(&masq_inet6_notifier);
|
||||
#endif
|
||||
out_unlock:
|
||||
mutex_unlock(&masq_mutex);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(nf_nat_masquerade_ipv6_unregister_notifier);
|
||||
#endif
|
||||
EXPORT_SYMBOL_GPL(nf_nat_masquerade_inet_unregister_notifiers);
|
||||
|
|
|
@ -725,7 +725,7 @@ nf_nat_ipv4_local_fn(void *priv, struct sk_buff *skb,
|
|||
return ret;
|
||||
}
|
||||
|
||||
static const struct nf_hook_ops nf_nat_ipv4_ops[] = {
|
||||
const struct nf_hook_ops nf_nat_ipv4_ops[] = {
|
||||
/* Before packet filtering, change destination */
|
||||
{
|
||||
.hook = nf_nat_ipv4_in,
|
||||
|
@ -758,13 +758,14 @@ static const struct nf_hook_ops nf_nat_ipv4_ops[] = {
|
|||
|
||||
int nf_nat_ipv4_register_fn(struct net *net, const struct nf_hook_ops *ops)
|
||||
{
|
||||
return nf_nat_register_fn(net, ops, nf_nat_ipv4_ops, ARRAY_SIZE(nf_nat_ipv4_ops));
|
||||
return nf_nat_register_fn(net, ops->pf, ops, nf_nat_ipv4_ops,
|
||||
ARRAY_SIZE(nf_nat_ipv4_ops));
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(nf_nat_ipv4_register_fn);
|
||||
|
||||
void nf_nat_ipv4_unregister_fn(struct net *net, const struct nf_hook_ops *ops)
|
||||
{
|
||||
nf_nat_unregister_fn(net, ops, ARRAY_SIZE(nf_nat_ipv4_ops));
|
||||
nf_nat_unregister_fn(net, ops->pf, ops, ARRAY_SIZE(nf_nat_ipv4_ops));
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(nf_nat_ipv4_unregister_fn);
|
||||
|
||||
|
@ -925,20 +926,6 @@ nf_nat_ipv6_out(void *priv, struct sk_buff *skb,
|
|||
return ret;
|
||||
}
|
||||
|
||||
static int nat_route_me_harder(struct net *net, struct sk_buff *skb)
|
||||
{
|
||||
#ifdef CONFIG_IPV6_MODULE
|
||||
const struct nf_ipv6_ops *v6_ops = nf_get_ipv6_ops();
|
||||
|
||||
if (!v6_ops)
|
||||
return -EHOSTUNREACH;
|
||||
|
||||
return v6_ops->route_me_harder(net, skb);
|
||||
#else
|
||||
return ip6_route_me_harder(net, skb);
|
||||
#endif
|
||||
}
|
||||
|
||||
static unsigned int
|
||||
nf_nat_ipv6_local_fn(void *priv, struct sk_buff *skb,
|
||||
const struct nf_hook_state *state)
|
||||
|
@ -958,7 +945,7 @@ nf_nat_ipv6_local_fn(void *priv, struct sk_buff *skb,
|
|||
|
||||
if (!nf_inet_addr_cmp(&ct->tuplehash[dir].tuple.dst.u3,
|
||||
&ct->tuplehash[!dir].tuple.src.u3)) {
|
||||
err = nat_route_me_harder(state->net, skb);
|
||||
err = nf_ip6_route_me_harder(state->net, skb);
|
||||
if (err < 0)
|
||||
ret = NF_DROP_ERR(err);
|
||||
}
|
||||
|
@ -977,7 +964,7 @@ nf_nat_ipv6_local_fn(void *priv, struct sk_buff *skb,
|
|||
return ret;
|
||||
}
|
||||
|
||||
static const struct nf_hook_ops nf_nat_ipv6_ops[] = {
|
||||
const struct nf_hook_ops nf_nat_ipv6_ops[] = {
|
||||
/* Before packet filtering, change destination */
|
||||
{
|
||||
.hook = nf_nat_ipv6_in,
|
||||
|
@ -1010,14 +997,44 @@ static const struct nf_hook_ops nf_nat_ipv6_ops[] = {
|
|||
|
||||
int nf_nat_ipv6_register_fn(struct net *net, const struct nf_hook_ops *ops)
|
||||
{
|
||||
return nf_nat_register_fn(net, ops, nf_nat_ipv6_ops,
|
||||
return nf_nat_register_fn(net, ops->pf, ops, nf_nat_ipv6_ops,
|
||||
ARRAY_SIZE(nf_nat_ipv6_ops));
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(nf_nat_ipv6_register_fn);
|
||||
|
||||
void nf_nat_ipv6_unregister_fn(struct net *net, const struct nf_hook_ops *ops)
|
||||
{
|
||||
nf_nat_unregister_fn(net, ops, ARRAY_SIZE(nf_nat_ipv6_ops));
|
||||
nf_nat_unregister_fn(net, ops->pf, ops, ARRAY_SIZE(nf_nat_ipv6_ops));
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(nf_nat_ipv6_unregister_fn);
|
||||
#endif /* CONFIG_IPV6 */
|
||||
|
||||
#if defined(CONFIG_NF_TABLES_INET) && IS_ENABLED(CONFIG_NFT_NAT)
|
||||
int nf_nat_inet_register_fn(struct net *net, const struct nf_hook_ops *ops)
|
||||
{
|
||||
int ret;
|
||||
|
||||
if (WARN_ON_ONCE(ops->pf != NFPROTO_INET))
|
||||
return -EINVAL;
|
||||
|
||||
ret = nf_nat_register_fn(net, NFPROTO_IPV6, ops, nf_nat_ipv6_ops,
|
||||
ARRAY_SIZE(nf_nat_ipv6_ops));
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ret = nf_nat_register_fn(net, NFPROTO_IPV4, ops, nf_nat_ipv4_ops,
|
||||
ARRAY_SIZE(nf_nat_ipv4_ops));
|
||||
if (ret)
|
||||
nf_nat_ipv6_unregister_fn(net, ops);
|
||||
|
||||
return ret;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(nf_nat_inet_register_fn);
|
||||
|
||||
void nf_nat_inet_unregister_fn(struct net *net, const struct nf_hook_ops *ops)
|
||||
{
|
||||
nf_nat_unregister_fn(net, NFPROTO_IPV4, ops, ARRAY_SIZE(nf_nat_ipv4_ops));
|
||||
nf_nat_unregister_fn(net, NFPROTO_IPV6, ops, ARRAY_SIZE(nf_nat_ipv6_ops));
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(nf_nat_inet_unregister_fn);
|
||||
#endif /* NFT INET NAT */
|
||||
|
|
|
@ -240,6 +240,7 @@ int nf_queue(struct sk_buff *skb, struct nf_hook_state *state,
|
|||
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(nf_queue);
|
||||
|
||||
static unsigned int nf_iterate(struct sk_buff *skb,
|
||||
struct nf_hook_state *state,
|
||||
|
|
|
@ -3193,9 +3193,7 @@ static int nf_msecs_to_jiffies64(const struct nlattr *nla, u64 *result)
|
|||
|
||||
static __be64 nf_jiffies64_to_msecs(u64 input)
|
||||
{
|
||||
u64 ms = jiffies64_to_nsecs(input);
|
||||
|
||||
return cpu_to_be64(div_u64(ms, NSEC_PER_MSEC));
|
||||
return cpu_to_be64(jiffies64_to_msecs(input));
|
||||
}
|
||||
|
||||
static int nf_tables_fill_set(struct sk_buff *skb, const struct nft_ctx *ctx,
|
||||
|
@ -3438,8 +3436,7 @@ err:
|
|||
return err;
|
||||
}
|
||||
|
||||
static int nf_tables_set_desc_parse(const struct nft_ctx *ctx,
|
||||
struct nft_set_desc *desc,
|
||||
static int nf_tables_set_desc_parse(struct nft_set_desc *desc,
|
||||
const struct nlattr *nla)
|
||||
{
|
||||
struct nlattr *da[NFTA_SET_DESC_MAX + 1];
|
||||
|
@ -3565,7 +3562,7 @@ static int nf_tables_newset(struct net *net, struct sock *nlsk,
|
|||
policy = ntohl(nla_get_be32(nla[NFTA_SET_POLICY]));
|
||||
|
||||
if (nla[NFTA_SET_DESC] != NULL) {
|
||||
err = nf_tables_set_desc_parse(&ctx, &desc, nla[NFTA_SET_DESC]);
|
||||
err = nf_tables_set_desc_parse(&desc, nla[NFTA_SET_DESC]);
|
||||
if (err < 0)
|
||||
return err;
|
||||
}
|
||||
|
@ -3785,8 +3782,8 @@ bind:
|
|||
}
|
||||
EXPORT_SYMBOL_GPL(nf_tables_bind_set);
|
||||
|
||||
void nf_tables_unbind_set(const struct nft_ctx *ctx, struct nft_set *set,
|
||||
struct nft_set_binding *binding, bool event)
|
||||
static void nf_tables_unbind_set(const struct nft_ctx *ctx, struct nft_set *set,
|
||||
struct nft_set_binding *binding, bool event)
|
||||
{
|
||||
list_del_rcu(&binding->list);
|
||||
|
||||
|
@ -3797,7 +3794,6 @@ void nf_tables_unbind_set(const struct nft_ctx *ctx, struct nft_set *set,
|
|||
GFP_KERNEL);
|
||||
}
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(nf_tables_unbind_set);
|
||||
|
||||
void nf_tables_deactivate_set(const struct nft_ctx *ctx, struct nft_set *set,
|
||||
struct nft_set_binding *binding,
|
||||
|
@ -7533,6 +7529,7 @@ static int __init nf_tables_module_init(void)
|
|||
if (err < 0)
|
||||
goto err5;
|
||||
|
||||
nft_chain_route_init();
|
||||
return err;
|
||||
err5:
|
||||
rhltable_destroy(&nft_objname_ht);
|
||||
|
@ -7552,6 +7549,7 @@ static void __exit nf_tables_module_exit(void)
|
|||
nfnetlink_subsys_unregister(&nf_tables_subsys);
|
||||
unregister_netdevice_notifier(&nf_tables_flowtable_notifier);
|
||||
nft_chain_filter_fini();
|
||||
nft_chain_route_fini();
|
||||
unregister_pernet_subsys(&nf_tables_net_ops);
|
||||
cancel_work_sync(&trans_destroy_work);
|
||||
rcu_barrier();
|
||||
|
|
|
@ -255,9 +255,9 @@ nf_osf_match(const struct sk_buff *skb, u_int8_t family,
|
|||
}
|
||||
EXPORT_SYMBOL_GPL(nf_osf_match);
|
||||
|
||||
const char *nf_osf_find(const struct sk_buff *skb,
|
||||
const struct list_head *nf_osf_fingers,
|
||||
const int ttl_check)
|
||||
bool nf_osf_find(const struct sk_buff *skb,
|
||||
const struct list_head *nf_osf_fingers,
|
||||
const int ttl_check, struct nf_osf_data *data)
|
||||
{
|
||||
const struct iphdr *ip = ip_hdr(skb);
|
||||
const struct nf_osf_user_finger *f;
|
||||
|
@ -265,24 +265,24 @@ const char *nf_osf_find(const struct sk_buff *skb,
|
|||
const struct nf_osf_finger *kf;
|
||||
struct nf_osf_hdr_ctx ctx;
|
||||
const struct tcphdr *tcp;
|
||||
const char *genre = NULL;
|
||||
|
||||
memset(&ctx, 0, sizeof(ctx));
|
||||
|
||||
tcp = nf_osf_hdr_ctx_init(&ctx, skb, ip, opts);
|
||||
if (!tcp)
|
||||
return NULL;
|
||||
return false;
|
||||
|
||||
list_for_each_entry_rcu(kf, &nf_osf_fingers[ctx.df], finger_entry) {
|
||||
f = &kf->finger;
|
||||
if (!nf_osf_match_one(skb, f, ttl_check, &ctx))
|
||||
continue;
|
||||
|
||||
genre = f->genre;
|
||||
data->genre = f->genre;
|
||||
data->version = f->version;
|
||||
break;
|
||||
}
|
||||
|
||||
return genre;
|
||||
return true;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(nf_osf_find);
|
||||
|
||||
|
|
|
@ -74,6 +74,36 @@ static const struct nft_chain_type nft_chain_nat_ipv6 = {
|
|||
};
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_NF_TABLES_INET
|
||||
static int nft_nat_inet_reg(struct net *net, const struct nf_hook_ops *ops)
|
||||
{
|
||||
return nf_nat_inet_register_fn(net, ops);
|
||||
}
|
||||
|
||||
static void nft_nat_inet_unreg(struct net *net, const struct nf_hook_ops *ops)
|
||||
{
|
||||
nf_nat_inet_unregister_fn(net, ops);
|
||||
}
|
||||
|
||||
static const struct nft_chain_type nft_chain_nat_inet = {
|
||||
.name = "nat",
|
||||
.type = NFT_CHAIN_T_NAT,
|
||||
.family = NFPROTO_INET,
|
||||
.hook_mask = (1 << NF_INET_PRE_ROUTING) |
|
||||
(1 << NF_INET_LOCAL_IN) |
|
||||
(1 << NF_INET_LOCAL_OUT) |
|
||||
(1 << NF_INET_POST_ROUTING),
|
||||
.hooks = {
|
||||
[NF_INET_PRE_ROUTING] = nft_nat_do_chain,
|
||||
[NF_INET_LOCAL_IN] = nft_nat_do_chain,
|
||||
[NF_INET_LOCAL_OUT] = nft_nat_do_chain,
|
||||
[NF_INET_POST_ROUTING] = nft_nat_do_chain,
|
||||
},
|
||||
.ops_register = nft_nat_inet_reg,
|
||||
.ops_unregister = nft_nat_inet_unreg,
|
||||
};
|
||||
#endif
|
||||
|
||||
static int __init nft_chain_nat_init(void)
|
||||
{
|
||||
#ifdef CONFIG_NF_TABLES_IPV6
|
||||
|
@ -82,6 +112,9 @@ static int __init nft_chain_nat_init(void)
|
|||
#ifdef CONFIG_NF_TABLES_IPV4
|
||||
nft_register_chain_type(&nft_chain_nat_ipv4);
|
||||
#endif
|
||||
#ifdef CONFIG_NF_TABLES_INET
|
||||
nft_register_chain_type(&nft_chain_nat_inet);
|
||||
#endif
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -94,6 +127,9 @@ static void __exit nft_chain_nat_exit(void)
|
|||
#ifdef CONFIG_NF_TABLES_IPV6
|
||||
nft_unregister_chain_type(&nft_chain_nat_ipv6);
|
||||
#endif
|
||||
#ifdef CONFIG_NF_TABLES_INET
|
||||
nft_unregister_chain_type(&nft_chain_nat_inet);
|
||||
#endif
|
||||
}
|
||||
|
||||
module_init(nft_chain_nat_init);
|
||||
|
|
|
@ -0,0 +1,169 @@
|
|||
// SPDX-License-Identifier: GPL-2.0
|
||||
|
||||
#include <linux/skbuff.h>
|
||||
#include <linux/netfilter.h>
|
||||
#include <linux/netfilter_ipv4.h>
|
||||
#include <linux/netfilter_ipv6.h>
|
||||
#include <linux/netfilter/nfnetlink.h>
|
||||
#include <linux/netfilter/nf_tables.h>
|
||||
#include <net/netfilter/nf_tables.h>
|
||||
#include <net/netfilter/nf_tables_ipv4.h>
|
||||
#include <net/netfilter/nf_tables_ipv6.h>
|
||||
#include <net/route.h>
|
||||
#include <net/ip.h>
|
||||
|
||||
#ifdef CONFIG_NF_TABLES_IPV4
|
||||
static unsigned int nf_route_table_hook4(void *priv,
|
||||
struct sk_buff *skb,
|
||||
const struct nf_hook_state *state)
|
||||
{
|
||||
const struct iphdr *iph;
|
||||
struct nft_pktinfo pkt;
|
||||
__be32 saddr, daddr;
|
||||
unsigned int ret;
|
||||
u32 mark;
|
||||
int err;
|
||||
u8 tos;
|
||||
|
||||
nft_set_pktinfo(&pkt, skb, state);
|
||||
nft_set_pktinfo_ipv4(&pkt, skb);
|
||||
|
||||
mark = skb->mark;
|
||||
iph = ip_hdr(skb);
|
||||
saddr = iph->saddr;
|
||||
daddr = iph->daddr;
|
||||
tos = iph->tos;
|
||||
|
||||
ret = nft_do_chain(&pkt, priv);
|
||||
if (ret == NF_ACCEPT) {
|
||||
iph = ip_hdr(skb);
|
||||
|
||||
if (iph->saddr != saddr ||
|
||||
iph->daddr != daddr ||
|
||||
skb->mark != mark ||
|
||||
iph->tos != tos) {
|
||||
err = ip_route_me_harder(state->net, skb, RTN_UNSPEC);
|
||||
if (err < 0)
|
||||
ret = NF_DROP_ERR(err);
|
||||
}
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
static const struct nft_chain_type nft_chain_route_ipv4 = {
|
||||
.name = "route",
|
||||
.type = NFT_CHAIN_T_ROUTE,
|
||||
.family = NFPROTO_IPV4,
|
||||
.hook_mask = (1 << NF_INET_LOCAL_OUT),
|
||||
.hooks = {
|
||||
[NF_INET_LOCAL_OUT] = nf_route_table_hook4,
|
||||
},
|
||||
};
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_NF_TABLES_IPV6
|
||||
static unsigned int nf_route_table_hook6(void *priv,
|
||||
struct sk_buff *skb,
|
||||
const struct nf_hook_state *state)
|
||||
{
|
||||
struct in6_addr saddr, daddr;
|
||||
struct nft_pktinfo pkt;
|
||||
u32 mark, flowlabel;
|
||||
unsigned int ret;
|
||||
u8 hop_limit;
|
||||
int err;
|
||||
|
||||
nft_set_pktinfo(&pkt, skb, state);
|
||||
nft_set_pktinfo_ipv6(&pkt, skb);
|
||||
|
||||
/* save source/dest address, mark, hoplimit, flowlabel, priority */
|
||||
memcpy(&saddr, &ipv6_hdr(skb)->saddr, sizeof(saddr));
|
||||
memcpy(&daddr, &ipv6_hdr(skb)->daddr, sizeof(daddr));
|
||||
mark = skb->mark;
|
||||
hop_limit = ipv6_hdr(skb)->hop_limit;
|
||||
|
||||
/* flowlabel and prio (includes version, which shouldn't change either)*/
|
||||
flowlabel = *((u32 *)ipv6_hdr(skb));
|
||||
|
||||
ret = nft_do_chain(&pkt, priv);
|
||||
if (ret == NF_ACCEPT &&
|
||||
(memcmp(&ipv6_hdr(skb)->saddr, &saddr, sizeof(saddr)) ||
|
||||
memcmp(&ipv6_hdr(skb)->daddr, &daddr, sizeof(daddr)) ||
|
||||
skb->mark != mark ||
|
||||
ipv6_hdr(skb)->hop_limit != hop_limit ||
|
||||
flowlabel != *((u32 *)ipv6_hdr(skb)))) {
|
||||
err = nf_ip6_route_me_harder(state->net, skb);
|
||||
if (err < 0)
|
||||
ret = NF_DROP_ERR(err);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static const struct nft_chain_type nft_chain_route_ipv6 = {
|
||||
.name = "route",
|
||||
.type = NFT_CHAIN_T_ROUTE,
|
||||
.family = NFPROTO_IPV6,
|
||||
.hook_mask = (1 << NF_INET_LOCAL_OUT),
|
||||
.hooks = {
|
||||
[NF_INET_LOCAL_OUT] = nf_route_table_hook6,
|
||||
},
|
||||
};
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_NF_TABLES_INET
|
||||
static unsigned int nf_route_table_inet(void *priv,
|
||||
struct sk_buff *skb,
|
||||
const struct nf_hook_state *state)
|
||||
{
|
||||
struct nft_pktinfo pkt;
|
||||
|
||||
switch (state->pf) {
|
||||
case NFPROTO_IPV4:
|
||||
return nf_route_table_hook4(priv, skb, state);
|
||||
case NFPROTO_IPV6:
|
||||
return nf_route_table_hook6(priv, skb, state);
|
||||
default:
|
||||
nft_set_pktinfo(&pkt, skb, state);
|
||||
break;
|
||||
}
|
||||
|
||||
return nft_do_chain(&pkt, priv);
|
||||
}
|
||||
|
||||
static const struct nft_chain_type nft_chain_route_inet = {
|
||||
.name = "route",
|
||||
.type = NFT_CHAIN_T_ROUTE,
|
||||
.family = NFPROTO_INET,
|
||||
.hook_mask = (1 << NF_INET_LOCAL_OUT),
|
||||
.hooks = {
|
||||
[NF_INET_LOCAL_OUT] = nf_route_table_inet,
|
||||
},
|
||||
};
|
||||
#endif
|
||||
|
||||
void __init nft_chain_route_init(void)
|
||||
{
|
||||
#ifdef CONFIG_NF_TABLES_IPV6
|
||||
nft_register_chain_type(&nft_chain_route_ipv6);
|
||||
#endif
|
||||
#ifdef CONFIG_NF_TABLES_IPV4
|
||||
nft_register_chain_type(&nft_chain_route_ipv4);
|
||||
#endif
|
||||
#ifdef CONFIG_NF_TABLES_INET
|
||||
nft_register_chain_type(&nft_chain_route_inet);
|
||||
#endif
|
||||
}
|
||||
|
||||
void __exit nft_chain_route_fini(void)
|
||||
{
|
||||
#ifdef CONFIG_NF_TABLES_IPV6
|
||||
nft_unregister_chain_type(&nft_chain_route_ipv6);
|
||||
#endif
|
||||
#ifdef CONFIG_NF_TABLES_IPV4
|
||||
nft_unregister_chain_type(&nft_chain_route_ipv4);
|
||||
#endif
|
||||
#ifdef CONFIG_NF_TABLES_INET
|
||||
nft_unregister_chain_type(&nft_chain_route_inet);
|
||||
#endif
|
||||
}
|
|
@ -14,8 +14,7 @@
|
|||
#include <linux/netfilter/nf_tables.h>
|
||||
#include <net/netfilter/nf_tables.h>
|
||||
#include <net/netfilter/nf_nat.h>
|
||||
#include <net/netfilter/ipv4/nf_nat_masquerade.h>
|
||||
#include <net/netfilter/ipv6/nf_nat_masquerade.h>
|
||||
#include <net/netfilter/nf_nat_masquerade.h>
|
||||
|
||||
struct nft_masq {
|
||||
u32 flags;
|
||||
|
@ -196,28 +195,73 @@ static struct nft_expr_type nft_masq_ipv6_type __read_mostly = {
|
|||
|
||||
static int __init nft_masq_module_init_ipv6(void)
|
||||
{
|
||||
int ret = nft_register_expr(&nft_masq_ipv6_type);
|
||||
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ret = nf_nat_masquerade_ipv6_register_notifier();
|
||||
if (ret < 0)
|
||||
nft_unregister_expr(&nft_masq_ipv6_type);
|
||||
|
||||
return ret;
|
||||
return nft_register_expr(&nft_masq_ipv6_type);
|
||||
}
|
||||
|
||||
static void nft_masq_module_exit_ipv6(void)
|
||||
{
|
||||
nft_unregister_expr(&nft_masq_ipv6_type);
|
||||
nf_nat_masquerade_ipv6_unregister_notifier();
|
||||
}
|
||||
#else
|
||||
static inline int nft_masq_module_init_ipv6(void) { return 0; }
|
||||
static inline void nft_masq_module_exit_ipv6(void) {}
|
||||
#endif
|
||||
|
||||
#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
|
||||
nft_masq_inet_destroy(const struct nft_ctx *ctx, const struct nft_expr *expr)
|
||||
{
|
||||
nf_ct_netns_put(ctx->net, NFPROTO_INET);
|
||||
}
|
||||
|
||||
static struct nft_expr_type nft_masq_inet_type;
|
||||
static const struct nft_expr_ops nft_masq_inet_ops = {
|
||||
.type = &nft_masq_inet_type,
|
||||
.size = NFT_EXPR_SIZE(sizeof(struct nft_masq)),
|
||||
.eval = nft_masq_inet_eval,
|
||||
.init = nft_masq_init,
|
||||
.destroy = nft_masq_inet_destroy,
|
||||
.dump = nft_masq_dump,
|
||||
.validate = nft_masq_validate,
|
||||
};
|
||||
|
||||
static struct nft_expr_type nft_masq_inet_type __read_mostly = {
|
||||
.family = NFPROTO_INET,
|
||||
.name = "masq",
|
||||
.ops = &nft_masq_inet_ops,
|
||||
.policy = nft_masq_policy,
|
||||
.maxattr = NFTA_MASQ_MAX,
|
||||
.owner = THIS_MODULE,
|
||||
};
|
||||
|
||||
static int __init nft_masq_module_init_inet(void)
|
||||
{
|
||||
return nft_register_expr(&nft_masq_inet_type);
|
||||
}
|
||||
|
||||
static void nft_masq_module_exit_inet(void)
|
||||
{
|
||||
nft_unregister_expr(&nft_masq_inet_type);
|
||||
}
|
||||
#else
|
||||
static inline int nft_masq_module_init_inet(void) { return 0; }
|
||||
static inline void nft_masq_module_exit_inet(void) {}
|
||||
#endif
|
||||
|
||||
static int __init nft_masq_module_init(void)
|
||||
{
|
||||
int ret;
|
||||
|
@ -226,15 +270,23 @@ static int __init nft_masq_module_init(void)
|
|||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
ret = nft_register_expr(&nft_masq_ipv4_type);
|
||||
ret = nft_masq_module_init_inet();
|
||||
if (ret < 0) {
|
||||
nft_masq_module_exit_ipv6();
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret = nf_nat_masquerade_ipv4_register_notifier();
|
||||
ret = nft_register_expr(&nft_masq_ipv4_type);
|
||||
if (ret < 0) {
|
||||
nft_masq_module_exit_inet();
|
||||
nft_masq_module_exit_ipv6();
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret = nf_nat_masquerade_inet_register_notifiers();
|
||||
if (ret < 0) {
|
||||
nft_masq_module_exit_ipv6();
|
||||
nft_masq_module_exit_inet();
|
||||
nft_unregister_expr(&nft_masq_ipv4_type);
|
||||
return ret;
|
||||
}
|
||||
|
@ -245,8 +297,9 @@ static int __init nft_masq_module_init(void)
|
|||
static void __exit nft_masq_module_exit(void)
|
||||
{
|
||||
nft_masq_module_exit_ipv6();
|
||||
nft_masq_module_exit_inet();
|
||||
nft_unregister_expr(&nft_masq_ipv4_type);
|
||||
nf_nat_masquerade_ipv4_unregister_notifier();
|
||||
nf_nat_masquerade_inet_unregister_notifiers();
|
||||
}
|
||||
|
||||
module_init(nft_masq_module_init);
|
||||
|
|
|
@ -140,7 +140,7 @@ static int nft_nat_init(const struct nft_ctx *ctx, const struct nft_expr *expr,
|
|||
return -EINVAL;
|
||||
|
||||
family = ntohl(nla_get_be32(tb[NFTA_NAT_FAMILY]));
|
||||
if (family != ctx->family)
|
||||
if (ctx->family != NFPROTO_INET && ctx->family != family)
|
||||
return -EOPNOTSUPP;
|
||||
|
||||
switch (family) {
|
||||
|
@ -278,13 +278,67 @@ static struct nft_expr_type nft_nat_type __read_mostly = {
|
|||
.owner = THIS_MODULE,
|
||||
};
|
||||
|
||||
#ifdef CONFIG_NF_TABLES_INET
|
||||
static void nft_nat_inet_eval(const struct nft_expr *expr,
|
||||
struct nft_regs *regs,
|
||||
const struct nft_pktinfo *pkt)
|
||||
{
|
||||
const struct nft_nat *priv = nft_expr_priv(expr);
|
||||
|
||||
if (priv->family == nft_pf(pkt))
|
||||
nft_nat_eval(expr, regs, pkt);
|
||||
}
|
||||
|
||||
static const struct nft_expr_ops nft_nat_inet_ops = {
|
||||
.type = &nft_nat_type,
|
||||
.size = NFT_EXPR_SIZE(sizeof(struct nft_nat)),
|
||||
.eval = nft_nat_inet_eval,
|
||||
.init = nft_nat_init,
|
||||
.destroy = nft_nat_destroy,
|
||||
.dump = nft_nat_dump,
|
||||
.validate = nft_nat_validate,
|
||||
};
|
||||
|
||||
static struct nft_expr_type nft_inet_nat_type __read_mostly = {
|
||||
.name = "nat",
|
||||
.family = NFPROTO_INET,
|
||||
.ops = &nft_nat_inet_ops,
|
||||
.policy = nft_nat_policy,
|
||||
.maxattr = NFTA_NAT_MAX,
|
||||
.owner = THIS_MODULE,
|
||||
};
|
||||
|
||||
static int nft_nat_inet_module_init(void)
|
||||
{
|
||||
return nft_register_expr(&nft_inet_nat_type);
|
||||
}
|
||||
|
||||
static void nft_nat_inet_module_exit(void)
|
||||
{
|
||||
nft_unregister_expr(&nft_inet_nat_type);
|
||||
}
|
||||
#else
|
||||
static int nft_nat_inet_module_init(void) { return 0; }
|
||||
static void nft_nat_inet_module_exit(void) { }
|
||||
#endif
|
||||
|
||||
static int __init nft_nat_module_init(void)
|
||||
{
|
||||
return nft_register_expr(&nft_nat_type);
|
||||
int ret = nft_nat_inet_module_init();
|
||||
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ret = nft_register_expr(&nft_nat_type);
|
||||
if (ret)
|
||||
nft_nat_inet_module_exit();
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void __exit nft_nat_module_exit(void)
|
||||
{
|
||||
nft_nat_inet_module_exit();
|
||||
nft_unregister_expr(&nft_nat_type);
|
||||
}
|
||||
|
||||
|
|
|
@ -7,11 +7,13 @@
|
|||
struct nft_osf {
|
||||
enum nft_registers dreg:8;
|
||||
u8 ttl;
|
||||
u32 flags;
|
||||
};
|
||||
|
||||
static const struct nla_policy nft_osf_policy[NFTA_OSF_MAX + 1] = {
|
||||
[NFTA_OSF_DREG] = { .type = NLA_U32 },
|
||||
[NFTA_OSF_TTL] = { .type = NLA_U8 },
|
||||
[NFTA_OSF_FLAGS] = { .type = NLA_U32 },
|
||||
};
|
||||
|
||||
static void nft_osf_eval(const struct nft_expr *expr, struct nft_regs *regs,
|
||||
|
@ -20,9 +22,10 @@ static void nft_osf_eval(const struct nft_expr *expr, struct nft_regs *regs,
|
|||
struct nft_osf *priv = nft_expr_priv(expr);
|
||||
u32 *dest = ®s->data[priv->dreg];
|
||||
struct sk_buff *skb = pkt->skb;
|
||||
char os_match[NFT_OSF_MAXGENRELEN + 1];
|
||||
const struct tcphdr *tcp;
|
||||
struct nf_osf_data data;
|
||||
struct tcphdr _tcph;
|
||||
const char *os_name;
|
||||
|
||||
tcp = skb_header_pointer(skb, ip_hdrlen(skb),
|
||||
sizeof(struct tcphdr), &_tcph);
|
||||
|
@ -35,11 +38,17 @@ static void nft_osf_eval(const struct nft_expr *expr, struct nft_regs *regs,
|
|||
return;
|
||||
}
|
||||
|
||||
os_name = nf_osf_find(skb, nf_osf_fingers, priv->ttl);
|
||||
if (!os_name)
|
||||
if (!nf_osf_find(skb, nf_osf_fingers, priv->ttl, &data)) {
|
||||
strncpy((char *)dest, "unknown", NFT_OSF_MAXGENRELEN);
|
||||
else
|
||||
strncpy((char *)dest, os_name, NFT_OSF_MAXGENRELEN);
|
||||
} else {
|
||||
if (priv->flags & NFT_OSF_F_VERSION)
|
||||
snprintf(os_match, NFT_OSF_MAXGENRELEN, "%s:%s",
|
||||
data.genre, data.version);
|
||||
else
|
||||
strlcpy(os_match, data.genre, NFT_OSF_MAXGENRELEN);
|
||||
|
||||
strncpy((char *)dest, os_match, NFT_OSF_MAXGENRELEN);
|
||||
}
|
||||
}
|
||||
|
||||
static int nft_osf_init(const struct nft_ctx *ctx,
|
||||
|
@ -47,6 +56,7 @@ static int nft_osf_init(const struct nft_ctx *ctx,
|
|||
const struct nlattr * const tb[])
|
||||
{
|
||||
struct nft_osf *priv = nft_expr_priv(expr);
|
||||
u32 flags;
|
||||
int err;
|
||||
u8 ttl;
|
||||
|
||||
|
@ -57,6 +67,13 @@ static int nft_osf_init(const struct nft_ctx *ctx,
|
|||
priv->ttl = ttl;
|
||||
}
|
||||
|
||||
if (tb[NFTA_OSF_FLAGS]) {
|
||||
flags = ntohl(nla_get_be32(tb[NFTA_OSF_FLAGS]));
|
||||
if (flags != NFT_OSF_F_VERSION)
|
||||
return -EINVAL;
|
||||
priv->flags = flags;
|
||||
}
|
||||
|
||||
priv->dreg = nft_parse_register(tb[NFTA_OSF_DREG]);
|
||||
err = nft_validate_register_store(ctx, priv->dreg, NULL,
|
||||
NFT_DATA_VALUE, NFT_OSF_MAXGENRELEN);
|
||||
|
@ -73,6 +90,9 @@ static int nft_osf_dump(struct sk_buff *skb, const struct nft_expr *expr)
|
|||
if (nla_put_u8(skb, NFTA_OSF_TTL, priv->ttl))
|
||||
goto nla_put_failure;
|
||||
|
||||
if (nla_put_be32(skb, NFTA_OSF_FLAGS, ntohl(priv->flags)))
|
||||
goto nla_put_failure;
|
||||
|
||||
if (nft_dump_register(skb, NFTA_OSF_DREG, priv->dreg))
|
||||
goto nla_put_failure;
|
||||
|
||||
|
|
|
@ -82,7 +82,7 @@ static int nft_redir_init(const struct nft_ctx *ctx,
|
|||
return nf_ct_netns_get(ctx->net, ctx->family);
|
||||
}
|
||||
|
||||
int nft_redir_dump(struct sk_buff *skb, const struct nft_expr *expr)
|
||||
static int nft_redir_dump(struct sk_buff *skb, const struct nft_expr *expr)
|
||||
{
|
||||
const struct nft_redir *priv = nft_expr_priv(expr);
|
||||
|
||||
|
@ -202,6 +202,55 @@ static struct nft_expr_type nft_redir_ipv6_type __read_mostly = {
|
|||
};
|
||||
#endif
|
||||
|
||||
#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
|
||||
nft_redir_inet_destroy(const struct nft_ctx *ctx, const struct nft_expr *expr)
|
||||
{
|
||||
nf_ct_netns_put(ctx->net, NFPROTO_INET);
|
||||
}
|
||||
|
||||
static struct nft_expr_type nft_redir_inet_type;
|
||||
static const struct nft_expr_ops nft_redir_inet_ops = {
|
||||
.type = &nft_redir_inet_type,
|
||||
.size = NFT_EXPR_SIZE(sizeof(struct nft_redir)),
|
||||
.eval = nft_redir_inet_eval,
|
||||
.init = nft_redir_init,
|
||||
.destroy = nft_redir_inet_destroy,
|
||||
.dump = nft_redir_dump,
|
||||
.validate = nft_redir_validate,
|
||||
};
|
||||
|
||||
static struct nft_expr_type nft_redir_inet_type __read_mostly = {
|
||||
.family = NFPROTO_INET,
|
||||
.name = "redir",
|
||||
.ops = &nft_redir_inet_ops,
|
||||
.policy = nft_redir_policy,
|
||||
.maxattr = NFTA_MASQ_MAX,
|
||||
.owner = THIS_MODULE,
|
||||
};
|
||||
|
||||
static int __init nft_redir_module_init_inet(void)
|
||||
{
|
||||
return nft_register_expr(&nft_redir_inet_type);
|
||||
}
|
||||
#else
|
||||
static inline int nft_redir_module_init_inet(void) { return 0; }
|
||||
#endif
|
||||
|
||||
static int __init nft_redir_module_init(void)
|
||||
{
|
||||
int ret = nft_register_expr(&nft_redir_ipv4_type);
|
||||
|
@ -217,6 +266,15 @@ static int __init nft_redir_module_init(void)
|
|||
}
|
||||
#endif
|
||||
|
||||
ret = nft_redir_module_init_inet();
|
||||
if (ret < 0) {
|
||||
nft_unregister_expr(&nft_redir_ipv4_type);
|
||||
#ifdef CONFIG_NF_TABLES_IPV6
|
||||
nft_unregister_expr(&nft_redir_ipv6_type);
|
||||
#endif
|
||||
return ret;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
@ -226,6 +284,9 @@ static void __exit nft_redir_module_exit(void)
|
|||
#ifdef CONFIG_NF_TABLES_IPV6
|
||||
nft_unregister_expr(&nft_redir_ipv6_type);
|
||||
#endif
|
||||
#ifdef CONFIG_NF_TABLES_INET
|
||||
nft_unregister_expr(&nft_redir_inet_type);
|
||||
#endif
|
||||
}
|
||||
|
||||
module_init(nft_redir_module_init);
|
||||
|
|
|
@ -227,7 +227,7 @@ xt_request_find_match(uint8_t nfproto, const char *name, uint8_t revision)
|
|||
EXPORT_SYMBOL_GPL(xt_request_find_match);
|
||||
|
||||
/* Find target, grabs ref. Returns ERR_PTR() on error. */
|
||||
struct xt_target *xt_find_target(u8 af, const char *name, u8 revision)
|
||||
static struct xt_target *xt_find_target(u8 af, const char *name, u8 revision)
|
||||
{
|
||||
struct xt_target *t;
|
||||
int err = -ENOENT;
|
||||
|
@ -255,7 +255,6 @@ struct xt_target *xt_find_target(u8 af, const char *name, u8 revision)
|
|||
|
||||
return ERR_PTR(err);
|
||||
}
|
||||
EXPORT_SYMBOL(xt_find_target);
|
||||
|
||||
struct xt_target *xt_request_find_target(u8 af, const char *name, u8 revision)
|
||||
{
|
||||
|
|
|
@ -9,20 +9,10 @@
|
|||
* published by the Free Software Foundation.
|
||||
*/
|
||||
#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
|
||||
#include <linux/types.h>
|
||||
#include <linux/inetdevice.h>
|
||||
#include <linux/ip.h>
|
||||
#include <linux/timer.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/netfilter.h>
|
||||
#include <net/protocol.h>
|
||||
#include <net/ip.h>
|
||||
#include <net/checksum.h>
|
||||
#include <net/route.h>
|
||||
#include <linux/netfilter_ipv4.h>
|
||||
#include <linux/netfilter/x_tables.h>
|
||||
#include <net/netfilter/nf_nat.h>
|
||||
#include <net/netfilter/ipv4/nf_nat_masquerade.h>
|
||||
#include <net/netfilter/nf_nat_masquerade.h>
|
||||
|
||||
MODULE_LICENSE("GPL");
|
||||
MODULE_AUTHOR("Netfilter Core Team <coreteam@netfilter.org>");
|
||||
|
@ -64,38 +54,78 @@ static void masquerade_tg_destroy(const struct xt_tgdtor_param *par)
|
|||
nf_ct_netns_put(par->net, par->family);
|
||||
}
|
||||
|
||||
static struct xt_target masquerade_tg_reg __read_mostly = {
|
||||
.name = "MASQUERADE",
|
||||
.family = NFPROTO_IPV4,
|
||||
.target = masquerade_tg,
|
||||
.targetsize = sizeof(struct nf_nat_ipv4_multi_range_compat),
|
||||
.table = "nat",
|
||||
.hooks = 1 << NF_INET_POST_ROUTING,
|
||||
.checkentry = masquerade_tg_check,
|
||||
.destroy = masquerade_tg_destroy,
|
||||
.me = THIS_MODULE,
|
||||
#if IS_ENABLED(CONFIG_IPV6)
|
||||
static unsigned int
|
||||
masquerade_tg6(struct sk_buff *skb, const struct xt_action_param *par)
|
||||
{
|
||||
return nf_nat_masquerade_ipv6(skb, par->targinfo, xt_out(par));
|
||||
}
|
||||
|
||||
static int masquerade_tg6_checkentry(const struct xt_tgchk_param *par)
|
||||
{
|
||||
const struct nf_nat_range2 *range = par->targinfo;
|
||||
|
||||
if (range->flags & NF_NAT_RANGE_MAP_IPS)
|
||||
return -EINVAL;
|
||||
|
||||
return nf_ct_netns_get(par->net, par->family);
|
||||
}
|
||||
#endif
|
||||
|
||||
static struct xt_target masquerade_tg_reg[] __read_mostly = {
|
||||
{
|
||||
#if IS_ENABLED(CONFIG_IPV6)
|
||||
.name = "MASQUERADE",
|
||||
.family = NFPROTO_IPV6,
|
||||
.target = masquerade_tg6,
|
||||
.targetsize = sizeof(struct nf_nat_range),
|
||||
.table = "nat",
|
||||
.hooks = 1 << NF_INET_POST_ROUTING,
|
||||
.checkentry = masquerade_tg6_checkentry,
|
||||
.destroy = masquerade_tg_destroy,
|
||||
.me = THIS_MODULE,
|
||||
}, {
|
||||
#endif
|
||||
.name = "MASQUERADE",
|
||||
.family = NFPROTO_IPV4,
|
||||
.target = masquerade_tg,
|
||||
.targetsize = sizeof(struct nf_nat_ipv4_multi_range_compat),
|
||||
.table = "nat",
|
||||
.hooks = 1 << NF_INET_POST_ROUTING,
|
||||
.checkentry = masquerade_tg_check,
|
||||
.destroy = masquerade_tg_destroy,
|
||||
.me = THIS_MODULE,
|
||||
}
|
||||
};
|
||||
|
||||
static int __init masquerade_tg_init(void)
|
||||
{
|
||||
int ret;
|
||||
|
||||
ret = xt_register_target(&masquerade_tg_reg);
|
||||
ret = xt_register_targets(masquerade_tg_reg,
|
||||
ARRAY_SIZE(masquerade_tg_reg));
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ret = nf_nat_masquerade_ipv4_register_notifier();
|
||||
if (ret)
|
||||
xt_unregister_target(&masquerade_tg_reg);
|
||||
ret = nf_nat_masquerade_inet_register_notifiers();
|
||||
if (ret) {
|
||||
xt_unregister_targets(masquerade_tg_reg,
|
||||
ARRAY_SIZE(masquerade_tg_reg));
|
||||
return ret;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void __exit masquerade_tg_exit(void)
|
||||
{
|
||||
xt_unregister_target(&masquerade_tg_reg);
|
||||
nf_nat_masquerade_ipv4_unregister_notifier();
|
||||
xt_unregister_targets(masquerade_tg_reg, ARRAY_SIZE(masquerade_tg_reg));
|
||||
nf_nat_masquerade_inet_unregister_notifiers();
|
||||
}
|
||||
|
||||
module_init(masquerade_tg_init);
|
||||
module_exit(masquerade_tg_exit);
|
||||
#if IS_ENABLED(CONFIG_IPV6)
|
||||
MODULE_ALIAS("ip6t_MASQUERADE");
|
||||
#endif
|
||||
MODULE_ALIAS("ipt_MASQUERADE");
|
|
@ -29,7 +29,7 @@
|
|||
#include <net/netfilter/ipv6/nf_defrag_ipv6.h>
|
||||
#include <net/ipv6_frag.h>
|
||||
|
||||
#ifdef CONFIG_NF_NAT_NEEDED
|
||||
#if IS_ENABLED(CONFIG_NF_NAT)
|
||||
#include <net/netfilter/nf_nat.h>
|
||||
#endif
|
||||
|
||||
|
@ -75,7 +75,7 @@ struct ovs_conntrack_info {
|
|||
struct md_mark mark;
|
||||
struct md_labels labels;
|
||||
char timeout[CTNL_TIMEOUT_NAME_MAX];
|
||||
#ifdef CONFIG_NF_NAT_NEEDED
|
||||
#if IS_ENABLED(CONFIG_NF_NAT)
|
||||
struct nf_nat_range2 range; /* Only present for SRC NAT and DST NAT. */
|
||||
#endif
|
||||
};
|
||||
|
@ -721,7 +721,7 @@ static bool skb_nfct_cached(struct net *net,
|
|||
return ct_executed;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_NF_NAT_NEEDED
|
||||
#if IS_ENABLED(CONFIG_NF_NAT)
|
||||
/* Modelled after nf_nat_ipv[46]_fn().
|
||||
* range is only used for new, uninitialized NAT state.
|
||||
* Returns either NF_ACCEPT or NF_DROP.
|
||||
|
@ -903,7 +903,7 @@ static int ovs_ct_nat(struct net *net, struct sw_flow_key *key,
|
|||
|
||||
return err;
|
||||
}
|
||||
#else /* !CONFIG_NF_NAT_NEEDED */
|
||||
#else /* !CONFIG_NF_NAT */
|
||||
static int ovs_ct_nat(struct net *net, struct sw_flow_key *key,
|
||||
const struct ovs_conntrack_info *info,
|
||||
struct sk_buff *skb, struct nf_conn *ct,
|
||||
|
@ -1330,7 +1330,7 @@ static int ovs_ct_add_helper(struct ovs_conntrack_info *info, const char *name,
|
|||
return 0;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_NF_NAT_NEEDED
|
||||
#if IS_ENABLED(CONFIG_NF_NAT)
|
||||
static int parse_nat(const struct nlattr *attr,
|
||||
struct ovs_conntrack_info *info, bool log)
|
||||
{
|
||||
|
@ -1467,7 +1467,7 @@ static const struct ovs_ct_len_tbl ovs_ct_attr_lens[OVS_CT_ATTR_MAX + 1] = {
|
|||
.maxlen = sizeof(struct md_labels) },
|
||||
[OVS_CT_ATTR_HELPER] = { .minlen = 1,
|
||||
.maxlen = NF_CT_HELPER_NAME_LEN },
|
||||
#ifdef CONFIG_NF_NAT_NEEDED
|
||||
#if IS_ENABLED(CONFIG_NF_NAT)
|
||||
/* NAT length is checked when parsing the nested attributes. */
|
||||
[OVS_CT_ATTR_NAT] = { .minlen = 0, .maxlen = INT_MAX },
|
||||
#endif
|
||||
|
@ -1547,7 +1547,7 @@ static int parse_ct(const struct nlattr *attr, struct ovs_conntrack_info *info,
|
|||
return -EINVAL;
|
||||
}
|
||||
break;
|
||||
#ifdef CONFIG_NF_NAT_NEEDED
|
||||
#if IS_ENABLED(CONFIG_NF_NAT)
|
||||
case OVS_CT_ATTR_NAT: {
|
||||
int err = parse_nat(a, info, log);
|
||||
|
||||
|
@ -1677,7 +1677,7 @@ err_free_ct:
|
|||
return err;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_NF_NAT_NEEDED
|
||||
#if IS_ENABLED(CONFIG_NF_NAT)
|
||||
static bool ovs_ct_nat_to_attr(const struct ovs_conntrack_info *info,
|
||||
struct sk_buff *skb)
|
||||
{
|
||||
|
@ -1783,7 +1783,7 @@ int ovs_ct_action_to_attr(const struct ovs_conntrack_info *ct_info,
|
|||
return -EMSGSIZE;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_NF_NAT_NEEDED
|
||||
#if IS_ENABLED(CONFIG_NF_NAT)
|
||||
if (ct_info->nat && !ovs_ct_nat_to_attr(ct_info, skb))
|
||||
return -EMSGSIZE;
|
||||
#endif
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
# SPDX-License-Identifier: GPL-2.0
|
||||
# Makefile for netfilter selftests
|
||||
|
||||
TEST_PROGS := nft_trans_stress.sh nft_nat.sh
|
||||
TEST_PROGS := nft_trans_stress.sh nft_nat.sh bridge_brouter.sh
|
||||
|
||||
include ../lib.mk
|
||||
|
|
|
@ -0,0 +1,146 @@
|
|||
#!/bin/bash
|
||||
#
|
||||
# This test is for bridge 'brouting', i.e. make some packets being routed
|
||||
# rather than getting bridged even though they arrive on interface that is
|
||||
# part of a bridge.
|
||||
|
||||
# eth0 br0 eth0
|
||||
# setup is: ns1 <-> ns0 <-> ns2
|
||||
|
||||
# Kselftest framework requirement - SKIP code is 4.
|
||||
ksft_skip=4
|
||||
ret=0
|
||||
|
||||
ebtables -V > /dev/null 2>&1
|
||||
if [ $? -ne 0 ];then
|
||||
echo "SKIP: Could not run test without ebtables"
|
||||
exit $ksft_skip
|
||||
fi
|
||||
|
||||
ip -Version > /dev/null 2>&1
|
||||
if [ $? -ne 0 ];then
|
||||
echo "SKIP: Could not run test without ip tool"
|
||||
exit $ksft_skip
|
||||
fi
|
||||
|
||||
ip netns add ns0
|
||||
ip netns add ns1
|
||||
ip netns add ns2
|
||||
|
||||
ip link add veth0 netns ns0 type veth peer name eth0 netns ns1
|
||||
if [ $? -ne 0 ]; then
|
||||
echo "SKIP: Can't create veth device"
|
||||
exit $ksft_skip
|
||||
fi
|
||||
ip link add veth1 netns ns0 type veth peer name eth0 netns ns2
|
||||
|
||||
ip -net ns0 link set lo up
|
||||
ip -net ns0 link set veth0 up
|
||||
ip -net ns0 link set veth1 up
|
||||
|
||||
ip -net ns0 link add br0 type bridge
|
||||
if [ $? -ne 0 ]; then
|
||||
echo "SKIP: Can't create bridge br0"
|
||||
exit $ksft_skip
|
||||
fi
|
||||
|
||||
ip -net ns0 link set veth0 master br0
|
||||
ip -net ns0 link set veth1 master br0
|
||||
ip -net ns0 link set br0 up
|
||||
ip -net ns0 addr add 10.0.0.1/24 dev br0
|
||||
|
||||
# place both in same subnet, ns1 and ns2 connected via ns0:br0
|
||||
for i in 1 2; do
|
||||
ip -net ns$i link set lo up
|
||||
ip -net ns$i link set eth0 up
|
||||
ip -net ns$i addr add 10.0.0.1$i/24 dev eth0
|
||||
done
|
||||
|
||||
test_ebtables_broute()
|
||||
{
|
||||
local cipt
|
||||
|
||||
# redirect is needed so the dstmac is rewritten to the bridge itself,
|
||||
# ip stack won't process OTHERHOST (foreign unicast mac) packets.
|
||||
ip netns exec ns0 ebtables -t broute -A BROUTING -p ipv4 --ip-protocol icmp -j redirect --redirect-target=DROP
|
||||
if [ $? -ne 0 ]; then
|
||||
echo "SKIP: Could not add ebtables broute redirect rule"
|
||||
return $ksft_skip
|
||||
fi
|
||||
|
||||
# ping netns1, expected to not work (ip forwarding is off)
|
||||
ip netns exec ns1 ping -q -c 1 10.0.0.12 > /dev/null 2>&1
|
||||
if [ $? -eq 0 ]; then
|
||||
echo "ERROR: ping works, should have failed" 1>&2
|
||||
return 1
|
||||
fi
|
||||
|
||||
# enable forwarding on both interfaces.
|
||||
# neither needs an ip address, but at least the bridge needs
|
||||
# an ip address in same network segment as ns1 and ns2 (ns0
|
||||
# needs to be able to determine route for to-be-forwarded packet).
|
||||
ip netns exec ns0 sysctl -q net.ipv4.conf.veth0.forwarding=1
|
||||
ip netns exec ns0 sysctl -q net.ipv4.conf.veth1.forwarding=1
|
||||
|
||||
sleep 1
|
||||
|
||||
ip netns exec ns1 ping -q -c 1 10.0.0.12 > /dev/null
|
||||
if [ $? -ne 0 ]; then
|
||||
echo "ERROR: ping did not work, but it should (broute+forward)" 1>&2
|
||||
return 1
|
||||
fi
|
||||
|
||||
echo "PASS: ns1/ns2 connectivity with active broute rule"
|
||||
ip netns exec ns0 ebtables -t broute -F
|
||||
|
||||
# ping netns1, expected to work (frames are bridged)
|
||||
ip netns exec ns1 ping -q -c 1 10.0.0.12 > /dev/null
|
||||
if [ $? -ne 0 ]; then
|
||||
echo "ERROR: ping did not work, but it should (bridged)" 1>&2
|
||||
return 1
|
||||
fi
|
||||
|
||||
ip netns exec ns0 ebtables -t filter -A FORWARD -p ipv4 --ip-protocol icmp -j DROP
|
||||
|
||||
# ping netns1, expected to not work (DROP in bridge forward)
|
||||
ip netns exec ns1 ping -q -c 1 10.0.0.12 > /dev/null 2>&1
|
||||
if [ $? -eq 0 ]; then
|
||||
echo "ERROR: ping works, should have failed (icmp forward drop)" 1>&2
|
||||
return 1
|
||||
fi
|
||||
|
||||
# re-activate brouter
|
||||
ip netns exec ns0 ebtables -t broute -A BROUTING -p ipv4 --ip-protocol icmp -j redirect --redirect-target=DROP
|
||||
|
||||
ip netns exec ns2 ping -q -c 1 10.0.0.11 > /dev/null
|
||||
if [ $? -ne 0 ]; then
|
||||
echo "ERROR: ping did not work, but it should (broute+forward 2)" 1>&2
|
||||
return 1
|
||||
fi
|
||||
|
||||
echo "PASS: ns1/ns2 connectivity with active broute rule and bridge forward drop"
|
||||
return 0
|
||||
}
|
||||
|
||||
# test basic connectivity
|
||||
ip netns exec ns1 ping -c 1 -q 10.0.0.12 > /dev/null
|
||||
if [ $? -ne 0 ]; then
|
||||
echo "ERROR: Could not reach ns2 from ns1" 1>&2
|
||||
ret=1
|
||||
fi
|
||||
|
||||
ip netns exec ns2 ping -c 1 -q 10.0.0.11 > /dev/null
|
||||
if [ $? -ne 0 ]; then
|
||||
echo "ERROR: Could not reach ns1 from ns2" 1>&2
|
||||
ret=1
|
||||
fi
|
||||
|
||||
if [ $ret -eq 0 ];then
|
||||
echo "PASS: netns connectivity: ns1 and ns2 can reach each other"
|
||||
fi
|
||||
|
||||
test_ebtables_broute
|
||||
ret=$?
|
||||
for i in 0 1 2; do ip netns del ns$i;done
|
||||
|
||||
exit $ret
|
|
@ -6,6 +6,7 @@
|
|||
# Kselftest framework requirement - SKIP code is 4.
|
||||
ksft_skip=4
|
||||
ret=0
|
||||
test_inet_nat=true
|
||||
|
||||
nft --version > /dev/null 2>&1
|
||||
if [ $? -ne 0 ];then
|
||||
|
@ -141,17 +142,24 @@ reset_counters()
|
|||
|
||||
test_local_dnat6()
|
||||
{
|
||||
local family=$1
|
||||
local lret=0
|
||||
local IPF=""
|
||||
|
||||
if [ $family = "inet" ];then
|
||||
IPF="ip6"
|
||||
fi
|
||||
|
||||
ip netns exec ns0 nft -f - <<EOF
|
||||
table ip6 nat {
|
||||
table $family nat {
|
||||
chain output {
|
||||
type nat hook output priority 0; policy accept;
|
||||
ip6 daddr dead:1::99 dnat to dead:2::99
|
||||
ip6 daddr dead:1::99 dnat $IPF to dead:2::99
|
||||
}
|
||||
}
|
||||
EOF
|
||||
if [ $? -ne 0 ]; then
|
||||
echo "SKIP: Could not add add ip6 dnat hook"
|
||||
echo "SKIP: Could not add add $family dnat hook"
|
||||
return $ksft_skip
|
||||
fi
|
||||
|
||||
|
@ -201,7 +209,7 @@ EOF
|
|||
fi
|
||||
done
|
||||
|
||||
test $lret -eq 0 && echo "PASS: ipv6 ping to ns1 was NATted to ns2"
|
||||
test $lret -eq 0 && echo "PASS: ipv6 ping to ns1 was $family NATted to ns2"
|
||||
ip netns exec ns0 nft flush chain ip6 nat output
|
||||
|
||||
return $lret
|
||||
|
@ -209,15 +217,32 @@ EOF
|
|||
|
||||
test_local_dnat()
|
||||
{
|
||||
local family=$1
|
||||
local lret=0
|
||||
ip netns exec ns0 nft -f - <<EOF
|
||||
table ip nat {
|
||||
local IPF=""
|
||||
|
||||
if [ $family = "inet" ];then
|
||||
IPF="ip"
|
||||
fi
|
||||
|
||||
ip netns exec ns0 nft -f - <<EOF 2>/dev/null
|
||||
table $family nat {
|
||||
chain output {
|
||||
type nat hook output priority 0; policy accept;
|
||||
ip daddr 10.0.1.99 dnat to 10.0.2.99
|
||||
ip daddr 10.0.1.99 dnat $IPF to 10.0.2.99
|
||||
}
|
||||
}
|
||||
EOF
|
||||
if [ $? -ne 0 ]; then
|
||||
if [ $family = "inet" ];then
|
||||
echo "SKIP: inet nat tests"
|
||||
test_inet_nat=false
|
||||
return $ksft_skip
|
||||
fi
|
||||
echo "SKIP: Could not add add $family dnat hook"
|
||||
return $ksft_skip
|
||||
fi
|
||||
|
||||
# ping netns1, expect rewrite to netns2
|
||||
ip netns exec ns0 ping -q -c 1 10.0.1.99 > /dev/null
|
||||
if [ $? -ne 0 ]; then
|
||||
|
@ -264,9 +289,9 @@ EOF
|
|||
fi
|
||||
done
|
||||
|
||||
test $lret -eq 0 && echo "PASS: ping to ns1 was NATted to ns2"
|
||||
test $lret -eq 0 && echo "PASS: ping to ns1 was $family NATted to ns2"
|
||||
|
||||
ip netns exec ns0 nft flush chain ip nat output
|
||||
ip netns exec ns0 nft flush chain $family nat output
|
||||
|
||||
reset_counters
|
||||
ip netns exec ns0 ping -q -c 1 10.0.1.99 > /dev/null
|
||||
|
@ -313,7 +338,7 @@ EOF
|
|||
fi
|
||||
done
|
||||
|
||||
test $lret -eq 0 && echo "PASS: ping to ns1 OK after nat output chain flush"
|
||||
test $lret -eq 0 && echo "PASS: ping to ns1 OK after $family nat output chain flush"
|
||||
|
||||
return $lret
|
||||
}
|
||||
|
@ -321,6 +346,7 @@ EOF
|
|||
|
||||
test_masquerade6()
|
||||
{
|
||||
local family=$1
|
||||
local lret=0
|
||||
|
||||
ip netns exec ns0 sysctl net.ipv6.conf.all.forwarding=1 > /dev/null
|
||||
|
@ -351,16 +377,21 @@ test_masquerade6()
|
|||
|
||||
# add masquerading rule
|
||||
ip netns exec ns0 nft -f - <<EOF
|
||||
table ip6 nat {
|
||||
table $family nat {
|
||||
chain postrouting {
|
||||
type nat hook postrouting priority 0; policy accept;
|
||||
meta oif veth0 masquerade
|
||||
}
|
||||
}
|
||||
EOF
|
||||
if [ $? -ne 0 ]; then
|
||||
echo "SKIP: Could not add add $family masquerade hook"
|
||||
return $ksft_skip
|
||||
fi
|
||||
|
||||
ip netns exec ns2 ping -q -c 1 dead:1::99 > /dev/null # ping ns2->ns1
|
||||
if [ $? -ne 0 ] ; then
|
||||
echo "ERROR: cannot ping ns1 from ns2 with active ipv6 masquerading"
|
||||
echo "ERROR: cannot ping ns1 from ns2 with active $family masquerading"
|
||||
lret=1
|
||||
fi
|
||||
|
||||
|
@ -397,19 +428,20 @@ EOF
|
|||
fi
|
||||
done
|
||||
|
||||
ip netns exec ns0 nft flush chain ip6 nat postrouting
|
||||
ip netns exec ns0 nft flush chain $family nat postrouting
|
||||
if [ $? -ne 0 ]; then
|
||||
echo "ERROR: Could not flush ip6 nat postrouting" 1>&2
|
||||
echo "ERROR: Could not flush $family nat postrouting" 1>&2
|
||||
lret=1
|
||||
fi
|
||||
|
||||
test $lret -eq 0 && echo "PASS: IPv6 masquerade for ns2"
|
||||
test $lret -eq 0 && echo "PASS: $family IPv6 masquerade for ns2"
|
||||
|
||||
return $lret
|
||||
}
|
||||
|
||||
test_masquerade()
|
||||
{
|
||||
local family=$1
|
||||
local lret=0
|
||||
|
||||
ip netns exec ns0 sysctl net.ipv4.conf.veth0.forwarding=1 > /dev/null
|
||||
|
@ -440,16 +472,21 @@ test_masquerade()
|
|||
|
||||
# add masquerading rule
|
||||
ip netns exec ns0 nft -f - <<EOF
|
||||
table ip nat {
|
||||
table $family nat {
|
||||
chain postrouting {
|
||||
type nat hook postrouting priority 0; policy accept;
|
||||
meta oif veth0 masquerade
|
||||
}
|
||||
}
|
||||
EOF
|
||||
if [ $? -ne 0 ]; then
|
||||
echo "SKIP: Could not add add $family masquerade hook"
|
||||
return $ksft_skip
|
||||
fi
|
||||
|
||||
ip netns exec ns2 ping -q -c 1 10.0.1.99 > /dev/null # ping ns2->ns1
|
||||
if [ $? -ne 0 ] ; then
|
||||
echo "ERROR: cannot ping ns1 from ns2 with active ip masquerading"
|
||||
echo "ERROR: cannot ping ns1 from ns2 with active $family masquerading"
|
||||
lret=1
|
||||
fi
|
||||
|
||||
|
@ -485,19 +522,20 @@ EOF
|
|||
fi
|
||||
done
|
||||
|
||||
ip netns exec ns0 nft flush chain ip nat postrouting
|
||||
ip netns exec ns0 nft flush chain $family nat postrouting
|
||||
if [ $? -ne 0 ]; then
|
||||
echo "ERROR: Could not flush nat postrouting" 1>&2
|
||||
echo "ERROR: Could not flush $family nat postrouting" 1>&2
|
||||
lret=1
|
||||
fi
|
||||
|
||||
test $lret -eq 0 && echo "PASS: IP masquerade for ns2"
|
||||
test $lret -eq 0 && echo "PASS: $family IP masquerade for ns2"
|
||||
|
||||
return $lret
|
||||
}
|
||||
|
||||
test_redirect6()
|
||||
{
|
||||
local family=$1
|
||||
local lret=0
|
||||
|
||||
ip netns exec ns0 sysctl net.ipv6.conf.all.forwarding=1 > /dev/null
|
||||
|
@ -527,16 +565,21 @@ test_redirect6()
|
|||
|
||||
# add redirect rule
|
||||
ip netns exec ns0 nft -f - <<EOF
|
||||
table ip6 nat {
|
||||
table $family nat {
|
||||
chain prerouting {
|
||||
type nat hook prerouting priority 0; policy accept;
|
||||
meta iif veth1 meta l4proto icmpv6 ip6 saddr dead:2::99 ip6 daddr dead:1::99 redirect
|
||||
}
|
||||
}
|
||||
EOF
|
||||
if [ $? -ne 0 ]; then
|
||||
echo "SKIP: Could not add add $family redirect hook"
|
||||
return $ksft_skip
|
||||
fi
|
||||
|
||||
ip netns exec ns2 ping -q -c 1 dead:1::99 > /dev/null # ping ns2->ns1
|
||||
if [ $? -ne 0 ] ; then
|
||||
echo "ERROR: cannot ping ns1 from ns2 with active ip6 redirect"
|
||||
echo "ERROR: cannot ping ns1 from ns2 via ipv6 with active $family redirect"
|
||||
lret=1
|
||||
fi
|
||||
|
||||
|
@ -560,19 +603,20 @@ EOF
|
|||
fi
|
||||
done
|
||||
|
||||
ip netns exec ns0 nft delete table ip6 nat
|
||||
ip netns exec ns0 nft delete table $family nat
|
||||
if [ $? -ne 0 ]; then
|
||||
echo "ERROR: Could not delete ip6 nat table" 1>&2
|
||||
echo "ERROR: Could not delete $family nat table" 1>&2
|
||||
lret=1
|
||||
fi
|
||||
|
||||
test $lret -eq 0 && echo "PASS: IPv6 redirection for ns2"
|
||||
test $lret -eq 0 && echo "PASS: $family IPv6 redirection for ns2"
|
||||
|
||||
return $lret
|
||||
}
|
||||
|
||||
test_redirect()
|
||||
{
|
||||
local family=$1
|
||||
local lret=0
|
||||
|
||||
ip netns exec ns0 sysctl net.ipv4.conf.veth0.forwarding=1 > /dev/null
|
||||
|
@ -603,16 +647,21 @@ test_redirect()
|
|||
|
||||
# add redirect rule
|
||||
ip netns exec ns0 nft -f - <<EOF
|
||||
table ip nat {
|
||||
table $family nat {
|
||||
chain prerouting {
|
||||
type nat hook prerouting priority 0; policy accept;
|
||||
meta iif veth1 ip protocol icmp ip saddr 10.0.2.99 ip daddr 10.0.1.99 redirect
|
||||
}
|
||||
}
|
||||
EOF
|
||||
if [ $? -ne 0 ]; then
|
||||
echo "SKIP: Could not add add $family redirect hook"
|
||||
return $ksft_skip
|
||||
fi
|
||||
|
||||
ip netns exec ns2 ping -q -c 1 10.0.1.99 > /dev/null # ping ns2->ns1
|
||||
if [ $? -ne 0 ] ; then
|
||||
echo "ERROR: cannot ping ns1 from ns2 with active ip redirect"
|
||||
echo "ERROR: cannot ping ns1 from ns2 with active $family ip redirect"
|
||||
lret=1
|
||||
fi
|
||||
|
||||
|
@ -637,13 +686,13 @@ EOF
|
|||
fi
|
||||
done
|
||||
|
||||
ip netns exec ns0 nft delete table ip nat
|
||||
ip netns exec ns0 nft delete table $family nat
|
||||
if [ $? -ne 0 ]; then
|
||||
echo "ERROR: Could not delete nat table" 1>&2
|
||||
echo "ERROR: Could not delete $family nat table" 1>&2
|
||||
lret=1
|
||||
fi
|
||||
|
||||
test $lret -eq 0 && echo "PASS: IP redirection for ns2"
|
||||
test $lret -eq 0 && echo "PASS: $family IP redirection for ns2"
|
||||
|
||||
return $lret
|
||||
}
|
||||
|
@ -746,16 +795,25 @@ if [ $ret -eq 0 ];then
|
|||
fi
|
||||
|
||||
reset_counters
|
||||
test_local_dnat
|
||||
test_local_dnat6
|
||||
test_local_dnat ip
|
||||
test_local_dnat6 ip6
|
||||
reset_counters
|
||||
$test_inet_nat && test_local_dnat inet
|
||||
$test_inet_nat && test_local_dnat6 inet
|
||||
|
||||
reset_counters
|
||||
test_masquerade
|
||||
test_masquerade6
|
||||
test_masquerade ip
|
||||
test_masquerade6 ip6
|
||||
reset_counters
|
||||
$test_inet_nat && test_masquerade inet
|
||||
$test_inet_nat && test_masquerade6 inet
|
||||
|
||||
reset_counters
|
||||
test_redirect
|
||||
test_redirect6
|
||||
test_redirect ip
|
||||
test_redirect6 ip6
|
||||
reset_counters
|
||||
$test_inet_nat && test_redirect inet
|
||||
$test_inet_nat && test_redirect6 inet
|
||||
|
||||
for i in 0 1 2; do ip netns del ns$i;done
|
||||
|
||||
|
|
Loading…
Reference in New Issue