diff options
author | David S. Miller <davem@davemloft.net> | 2018-08-05 19:25:22 -0400 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2018-08-05 19:25:22 -0400 |
commit | 074fb8801667add0b63083af90a3af6edca9532c (patch) | |
tree | 44244193ce484025e6dfb6eaef43342f93d73f3f | |
parent | c1c8626fcebed467184ffd8de0ab5c9f9d9c3594 (diff) | |
parent | 483f3fdcc70b3c3a1f314235ab0066f3dbd4cfbe (diff) |
Merge git://git.kernel.org/pub/scm/linux/kernel/git/pablo/nf-next
Pablo Neira Ayuso says:
====================
Netfilter updates for net-next
The following patchset contains Netfilter updates for your net-next tree:
1) Support for transparent proxying for nf_tables, from Mate Eckl.
2) Patchset to add OS passive fingerprint recognition for nf_tables,
from Fernando Fernandez. This takes common code from xt_osf and
place it into the new nfnetlink_osf module for codebase sharing.
3) Lightweight tunneling support for nf_tables.
4) meta and lookup are likely going to be used in rulesets, make them
direct calls. From Florian Westphal.
A bunch of incremental updates:
5) use PTR_ERR_OR_ZERO() from nft_numgen, from YueHaibing.
6) Use kvmalloc_array() to allocate hashtables, from Li RongQing.
7) Explicit dependencies between nfnetlink_cttimeout and conntrack
timeout extensions, from Harsha Sharma.
8) Simplify NLM_F_CREATE handling in nf_tables.
9) Removed unused variable in the get element command, from
YueHaibing.
10) Expose bridge hook priorities through uapi, from Mate Eckl.
And a few fixes for previous Netfilter batch for net-next:
11) Use per-netns mutex from flowtable event, from Florian Westphal.
12) Remove explicit dependency on iptables CT target from conntrack
zones, from Florian.
13) Fix use-after-free in rmmod nf_conntrack path, also from Florian.
====================
Signed-off-by: David S. Miller <davem@davemloft.net>
31 files changed, 1417 insertions, 254 deletions
diff --git a/include/linux/netfilter/nf_osf.h b/include/linux/netfilter/nfnetlink_osf.h index 0e114c492fb8..a7311bc03d3a 100644 --- a/include/linux/netfilter/nf_osf.h +++ b/include/linux/netfilter/nfnetlink_osf.h | |||
@@ -1,4 +1,8 @@ | |||
1 | #include <uapi/linux/netfilter/nf_osf.h> | 1 | /* SPDX-License-Identifier: GPL-2.0 */ |
2 | #ifndef _NFOSF_H | ||
3 | #define _NFOSF_H | ||
4 | |||
5 | #include <uapi/linux/netfilter/nfnetlink_osf.h> | ||
2 | 6 | ||
3 | /* Initial window size option state machine: multiple of mss, mtu or | 7 | /* Initial window size option state machine: multiple of mss, mtu or |
4 | * plain numeric value. Can also be made as plain numeric value which | 8 | * plain numeric value. Can also be made as plain numeric value which |
@@ -21,6 +25,8 @@ enum osf_fmatch_states { | |||
21 | FMATCH_OPT_WRONG, | 25 | FMATCH_OPT_WRONG, |
22 | }; | 26 | }; |
23 | 27 | ||
28 | extern struct list_head nf_osf_fingers[2]; | ||
29 | |||
24 | struct nf_osf_finger { | 30 | struct nf_osf_finger { |
25 | struct rcu_head rcu_head; | 31 | struct rcu_head rcu_head; |
26 | struct list_head finger_entry; | 32 | struct list_head finger_entry; |
@@ -31,3 +37,8 @@ bool nf_osf_match(const struct sk_buff *skb, u_int8_t family, | |||
31 | int hooknum, struct net_device *in, struct net_device *out, | 37 | int hooknum, struct net_device *in, struct net_device *out, |
32 | const struct nf_osf_info *info, struct net *net, | 38 | const struct nf_osf_info *info, struct net *net, |
33 | const struct list_head *nf_osf_fingers); | 39 | const struct list_head *nf_osf_fingers); |
40 | |||
41 | const char *nf_osf_find(const struct sk_buff *skb, | ||
42 | const struct list_head *nf_osf_fingers); | ||
43 | |||
44 | #endif /* _NFOSF_H */ | ||
diff --git a/include/linux/netfilter_bridge.h b/include/linux/netfilter_bridge.h index b671fdfd212b..fa0686500970 100644 --- a/include/linux/netfilter_bridge.h +++ b/include/linux/netfilter_bridge.h | |||
@@ -5,17 +5,6 @@ | |||
5 | #include <uapi/linux/netfilter_bridge.h> | 5 | #include <uapi/linux/netfilter_bridge.h> |
6 | #include <linux/skbuff.h> | 6 | #include <linux/skbuff.h> |
7 | 7 | ||
8 | enum nf_br_hook_priorities { | ||
9 | NF_BR_PRI_FIRST = INT_MIN, | ||
10 | NF_BR_PRI_NAT_DST_BRIDGED = -300, | ||
11 | NF_BR_PRI_FILTER_BRIDGED = -200, | ||
12 | NF_BR_PRI_BRNF = 0, | ||
13 | NF_BR_PRI_NAT_DST_OTHER = 100, | ||
14 | NF_BR_PRI_FILTER_OTHER = 200, | ||
15 | NF_BR_PRI_NAT_SRC = 300, | ||
16 | NF_BR_PRI_LAST = INT_MAX, | ||
17 | }; | ||
18 | |||
19 | #if IS_ENABLED(CONFIG_BRIDGE_NETFILTER) | 8 | #if IS_ENABLED(CONFIG_BRIDGE_NETFILTER) |
20 | 9 | ||
21 | int br_handle_frame_finish(struct net *net, struct sock *sk, struct sk_buff *skb); | 10 | int br_handle_frame_finish(struct net *net, struct sock *sk, struct sk_buff *skb); |
diff --git a/include/net/netfilter/nf_conntrack.h b/include/net/netfilter/nf_conntrack.h index a2b0ed025908..7e012312cd61 100644 --- a/include/net/netfilter/nf_conntrack.h +++ b/include/net/netfilter/nf_conntrack.h | |||
@@ -176,8 +176,6 @@ void nf_ct_netns_put(struct net *net, u8 nfproto); | |||
176 | */ | 176 | */ |
177 | void *nf_ct_alloc_hashtable(unsigned int *sizep, int nulls); | 177 | void *nf_ct_alloc_hashtable(unsigned int *sizep, int nulls); |
178 | 178 | ||
179 | void nf_ct_free_hashtable(void *hash, unsigned int size); | ||
180 | |||
181 | int nf_conntrack_hash_check_insert(struct nf_conn *ct); | 179 | int nf_conntrack_hash_check_insert(struct nf_conn *ct); |
182 | bool nf_ct_delete(struct nf_conn *ct, u32 pid, int report); | 180 | bool nf_ct_delete(struct nf_conn *ct, u32 pid, int report); |
183 | 181 | ||
diff --git a/include/net/netfilter/nf_tables_core.h b/include/net/netfilter/nf_tables_core.h index a05134507e7b..8da837d2aaf9 100644 --- a/include/net/netfilter/nf_tables_core.h +++ b/include/net/netfilter/nf_tables_core.h | |||
@@ -71,4 +71,11 @@ extern struct nft_set_type nft_set_hash_fast_type; | |||
71 | extern struct nft_set_type nft_set_rbtree_type; | 71 | extern struct nft_set_type nft_set_rbtree_type; |
72 | extern struct nft_set_type nft_set_bitmap_type; | 72 | extern struct nft_set_type nft_set_bitmap_type; |
73 | 73 | ||
74 | struct nft_expr; | ||
75 | struct nft_regs; | ||
76 | struct nft_pktinfo; | ||
77 | void nft_meta_get_eval(const struct nft_expr *expr, | ||
78 | struct nft_regs *regs, const struct nft_pktinfo *pkt); | ||
79 | void nft_lookup_eval(const struct nft_expr *expr, | ||
80 | struct nft_regs *regs, const struct nft_pktinfo *pkt); | ||
74 | #endif /* _NET_NF_TABLES_CORE_H */ | 81 | #endif /* _NET_NF_TABLES_CORE_H */ |
diff --git a/include/uapi/linux/netfilter/nf_tables.h b/include/uapi/linux/netfilter/nf_tables.h index f466860bcf75..357862d948de 100644 --- a/include/uapi/linux/netfilter/nf_tables.h +++ b/include/uapi/linux/netfilter/nf_tables.h | |||
@@ -1253,6 +1253,22 @@ enum nft_nat_attributes { | |||
1253 | #define NFTA_NAT_MAX (__NFTA_NAT_MAX - 1) | 1253 | #define NFTA_NAT_MAX (__NFTA_NAT_MAX - 1) |
1254 | 1254 | ||
1255 | /** | 1255 | /** |
1256 | * enum nft_tproxy_attributes - nf_tables tproxy expression netlink attributes | ||
1257 | * | ||
1258 | * NFTA_TPROXY_FAMILY: Target address family (NLA_U32: nft_registers) | ||
1259 | * NFTA_TPROXY_REG_ADDR: Target address register (NLA_U32: nft_registers) | ||
1260 | * NFTA_TPROXY_REG_PORT: Target port register (NLA_U32: nft_registers) | ||
1261 | */ | ||
1262 | enum nft_tproxy_attributes { | ||
1263 | NFTA_TPROXY_UNSPEC, | ||
1264 | NFTA_TPROXY_FAMILY, | ||
1265 | NFTA_TPROXY_REG_ADDR, | ||
1266 | NFTA_TPROXY_REG_PORT, | ||
1267 | __NFTA_TPROXY_MAX | ||
1268 | }; | ||
1269 | #define NFTA_TPROXY_MAX (__NFTA_TPROXY_MAX - 1) | ||
1270 | |||
1271 | /** | ||
1256 | * enum nft_masq_attributes - nf_tables masquerade expression attributes | 1272 | * enum nft_masq_attributes - nf_tables masquerade expression attributes |
1257 | * | 1273 | * |
1258 | * @NFTA_MASQ_FLAGS: NAT flags (see NF_NAT_RANGE_* in linux/netfilter/nf_nat.h) (NLA_U32) | 1274 | * @NFTA_MASQ_FLAGS: NAT flags (see NF_NAT_RANGE_* in linux/netfilter/nf_nat.h) (NLA_U32) |
@@ -1400,7 +1416,8 @@ enum nft_ct_helper_attributes { | |||
1400 | #define NFT_OBJECT_CT_HELPER 3 | 1416 | #define NFT_OBJECT_CT_HELPER 3 |
1401 | #define NFT_OBJECT_LIMIT 4 | 1417 | #define NFT_OBJECT_LIMIT 4 |
1402 | #define NFT_OBJECT_CONNLIMIT 5 | 1418 | #define NFT_OBJECT_CONNLIMIT 5 |
1403 | #define __NFT_OBJECT_MAX 6 | 1419 | #define NFT_OBJECT_TUNNEL 6 |
1420 | #define __NFT_OBJECT_MAX 7 | ||
1404 | #define NFT_OBJECT_MAX (__NFT_OBJECT_MAX - 1) | 1421 | #define NFT_OBJECT_MAX (__NFT_OBJECT_MAX - 1) |
1405 | 1422 | ||
1406 | /** | 1423 | /** |
@@ -1463,6 +1480,13 @@ enum nft_flowtable_hook_attributes { | |||
1463 | }; | 1480 | }; |
1464 | #define NFTA_FLOWTABLE_HOOK_MAX (__NFTA_FLOWTABLE_HOOK_MAX - 1) | 1481 | #define NFTA_FLOWTABLE_HOOK_MAX (__NFTA_FLOWTABLE_HOOK_MAX - 1) |
1465 | 1482 | ||
1483 | enum nft_osf_attributes { | ||
1484 | NFTA_OSF_UNSPEC, | ||
1485 | NFTA_OSF_DREG, | ||
1486 | __NFTA_OSF_MAX, | ||
1487 | }; | ||
1488 | #define NFTA_OSF_MAX (__NFTA_OSF_MAX - 1) | ||
1489 | |||
1466 | /** | 1490 | /** |
1467 | * enum nft_device_attributes - nf_tables device netlink attributes | 1491 | * enum nft_device_attributes - nf_tables device netlink attributes |
1468 | * | 1492 | * |
@@ -1557,4 +1581,85 @@ enum nft_ng_types { | |||
1557 | }; | 1581 | }; |
1558 | #define NFT_NG_MAX (__NFT_NG_MAX - 1) | 1582 | #define NFT_NG_MAX (__NFT_NG_MAX - 1) |
1559 | 1583 | ||
1584 | enum nft_tunnel_key_ip_attributes { | ||
1585 | NFTA_TUNNEL_KEY_IP_UNSPEC, | ||
1586 | NFTA_TUNNEL_KEY_IP_SRC, | ||
1587 | NFTA_TUNNEL_KEY_IP_DST, | ||
1588 | __NFTA_TUNNEL_KEY_IP_MAX | ||
1589 | }; | ||
1590 | #define NFTA_TUNNEL_KEY_IP_MAX (__NFTA_TUNNEL_KEY_IP_MAX - 1) | ||
1591 | |||
1592 | enum nft_tunnel_ip6_attributes { | ||
1593 | NFTA_TUNNEL_KEY_IP6_UNSPEC, | ||
1594 | NFTA_TUNNEL_KEY_IP6_SRC, | ||
1595 | NFTA_TUNNEL_KEY_IP6_DST, | ||
1596 | NFTA_TUNNEL_KEY_IP6_FLOWLABEL, | ||
1597 | __NFTA_TUNNEL_KEY_IP6_MAX | ||
1598 | }; | ||
1599 | #define NFTA_TUNNEL_KEY_IP6_MAX (__NFTA_TUNNEL_KEY_IP6_MAX - 1) | ||
1600 | |||
1601 | enum nft_tunnel_opts_attributes { | ||
1602 | NFTA_TUNNEL_KEY_OPTS_UNSPEC, | ||
1603 | NFTA_TUNNEL_KEY_OPTS_VXLAN, | ||
1604 | NFTA_TUNNEL_KEY_OPTS_ERSPAN, | ||
1605 | __NFTA_TUNNEL_KEY_OPTS_MAX | ||
1606 | }; | ||
1607 | #define NFTA_TUNNEL_KEY_OPTS_MAX (__NFTA_TUNNEL_KEY_OPTS_MAX - 1) | ||
1608 | |||
1609 | enum nft_tunnel_opts_vxlan_attributes { | ||
1610 | NFTA_TUNNEL_KEY_VXLAN_UNSPEC, | ||
1611 | NFTA_TUNNEL_KEY_VXLAN_GBP, | ||
1612 | __NFTA_TUNNEL_KEY_VXLAN_MAX | ||
1613 | }; | ||
1614 | #define NFTA_TUNNEL_KEY_VXLAN_MAX (__NFTA_TUNNEL_KEY_VXLAN_MAX - 1) | ||
1615 | |||
1616 | enum nft_tunnel_opts_erspan_attributes { | ||
1617 | NFTA_TUNNEL_KEY_ERSPAN_UNSPEC, | ||
1618 | NFTA_TUNNEL_KEY_ERSPAN_VERSION, | ||
1619 | NFTA_TUNNEL_KEY_ERSPAN_V1_INDEX, | ||
1620 | NFTA_TUNNEL_KEY_ERSPAN_V2_HWID, | ||
1621 | NFTA_TUNNEL_KEY_ERSPAN_V2_DIR, | ||
1622 | __NFTA_TUNNEL_KEY_ERSPAN_MAX | ||
1623 | }; | ||
1624 | #define NFTA_TUNNEL_KEY_ERSPAN_MAX (__NFTA_TUNNEL_KEY_ERSPAN_MAX - 1) | ||
1625 | |||
1626 | enum nft_tunnel_flags { | ||
1627 | NFT_TUNNEL_F_ZERO_CSUM_TX = (1 << 0), | ||
1628 | NFT_TUNNEL_F_DONT_FRAGMENT = (1 << 1), | ||
1629 | NFT_TUNNEL_F_SEQ_NUMBER = (1 << 2), | ||
1630 | }; | ||
1631 | #define NFT_TUNNEL_F_MASK (NFT_TUNNEL_F_ZERO_CSUM_TX | \ | ||
1632 | NFT_TUNNEL_F_DONT_FRAGMENT | \ | ||
1633 | NFT_TUNNEL_F_SEQ_NUMBER) | ||
1634 | |||
1635 | enum nft_tunnel_key_attributes { | ||
1636 | NFTA_TUNNEL_KEY_UNSPEC, | ||
1637 | NFTA_TUNNEL_KEY_ID, | ||
1638 | NFTA_TUNNEL_KEY_IP, | ||
1639 | NFTA_TUNNEL_KEY_IP6, | ||
1640 | NFTA_TUNNEL_KEY_FLAGS, | ||
1641 | NFTA_TUNNEL_KEY_TOS, | ||
1642 | NFTA_TUNNEL_KEY_TTL, | ||
1643 | NFTA_TUNNEL_KEY_SPORT, | ||
1644 | NFTA_TUNNEL_KEY_DPORT, | ||
1645 | NFTA_TUNNEL_KEY_OPTS, | ||
1646 | __NFTA_TUNNEL_KEY_MAX | ||
1647 | }; | ||
1648 | #define NFTA_TUNNEL_KEY_MAX (__NFTA_TUNNEL_KEY_MAX - 1) | ||
1649 | |||
1650 | enum nft_tunnel_keys { | ||
1651 | NFT_TUNNEL_PATH, | ||
1652 | NFT_TUNNEL_ID, | ||
1653 | __NFT_TUNNEL_MAX | ||
1654 | }; | ||
1655 | #define NFT_TUNNEL_MAX (__NFT_TUNNEL_MAX - 1) | ||
1656 | |||
1657 | enum nft_tunnel_attributes { | ||
1658 | NFTA_TUNNEL_UNSPEC, | ||
1659 | NFTA_TUNNEL_KEY, | ||
1660 | NFTA_TUNNEL_DREG, | ||
1661 | __NFTA_TUNNEL_MAX | ||
1662 | }; | ||
1663 | #define NFTA_TUNNEL_MAX (__NFTA_TUNNEL_MAX - 1) | ||
1664 | |||
1560 | #endif /* _LINUX_NF_TABLES_H */ | 1665 | #endif /* _LINUX_NF_TABLES_H */ |
diff --git a/include/uapi/linux/netfilter/nf_osf.h b/include/uapi/linux/netfilter/nfnetlink_osf.h index 3738116b2bbe..3b93fbb9fc24 100644 --- a/include/uapi/linux/netfilter/nf_osf.h +++ b/include/uapi/linux/netfilter/nfnetlink_osf.h | |||
@@ -94,4 +94,13 @@ enum nf_osf_attr_type { | |||
94 | OSF_ATTR_MAX, | 94 | OSF_ATTR_MAX, |
95 | }; | 95 | }; |
96 | 96 | ||
97 | /* | ||
98 | * Add/remove fingerprint from the kernel. | ||
99 | */ | ||
100 | enum nf_osf_msg_types { | ||
101 | OSF_MSG_ADD, | ||
102 | OSF_MSG_REMOVE, | ||
103 | OSF_MSG_MAX, | ||
104 | }; | ||
105 | |||
97 | #endif /* _NF_OSF_H */ | 106 | #endif /* _NF_OSF_H */ |
diff --git a/include/uapi/linux/netfilter/xt_osf.h b/include/uapi/linux/netfilter/xt_osf.h index b189007f4f28..c56c59605c2b 100644 --- a/include/uapi/linux/netfilter/xt_osf.h +++ b/include/uapi/linux/netfilter/xt_osf.h | |||
@@ -23,7 +23,7 @@ | |||
23 | #include <linux/types.h> | 23 | #include <linux/types.h> |
24 | #include <linux/ip.h> | 24 | #include <linux/ip.h> |
25 | #include <linux/tcp.h> | 25 | #include <linux/tcp.h> |
26 | #include <linux/netfilter/nf_osf.h> | 26 | #include <linux/netfilter/nfnetlink_osf.h> |
27 | 27 | ||
28 | #define XT_OSF_GENRE NF_OSF_GENRE | 28 | #define XT_OSF_GENRE NF_OSF_GENRE |
29 | #define XT_OSF_INVERT NF_OSF_INVERT | 29 | #define XT_OSF_INVERT NF_OSF_INVERT |
@@ -47,13 +47,6 @@ | |||
47 | #define xt_osf_nlmsg nf_osf_nlmsg | 47 | #define xt_osf_nlmsg nf_osf_nlmsg |
48 | 48 | ||
49 | #define xt_osf_attr_type nf_osf_attr_type | 49 | #define xt_osf_attr_type nf_osf_attr_type |
50 | /* | 50 | #define xt_osf_msg_types nf_osf_msg_types |
51 | * Add/remove fingerprint from the kernel. | ||
52 | */ | ||
53 | enum xt_osf_msg_types { | ||
54 | OSF_MSG_ADD, | ||
55 | OSF_MSG_REMOVE, | ||
56 | OSF_MSG_MAX, | ||
57 | }; | ||
58 | 51 | ||
59 | #endif /* _XT_OSF_H */ | 52 | #endif /* _XT_OSF_H */ |
diff --git a/include/uapi/linux/netfilter_bridge.h b/include/uapi/linux/netfilter_bridge.h index 12fb77633f83..156ccd089df1 100644 --- a/include/uapi/linux/netfilter_bridge.h +++ b/include/uapi/linux/netfilter_bridge.h | |||
@@ -26,4 +26,15 @@ | |||
26 | #define NF_BR_BROUTING 5 | 26 | #define NF_BR_BROUTING 5 |
27 | #define NF_BR_NUMHOOKS 6 | 27 | #define NF_BR_NUMHOOKS 6 |
28 | 28 | ||
29 | enum nf_br_hook_priorities { | ||
30 | NF_BR_PRI_FIRST = INT_MIN, | ||
31 | NF_BR_PRI_NAT_DST_BRIDGED = -300, | ||
32 | NF_BR_PRI_FILTER_BRIDGED = -200, | ||
33 | NF_BR_PRI_BRNF = 0, | ||
34 | NF_BR_PRI_NAT_DST_OTHER = 100, | ||
35 | NF_BR_PRI_FILTER_OTHER = 200, | ||
36 | NF_BR_PRI_NAT_SRC = 300, | ||
37 | NF_BR_PRI_LAST = INT_MAX, | ||
38 | }; | ||
39 | |||
29 | #endif /* _UAPI__LINUX_BRIDGE_NETFILTER_H */ | 40 | #endif /* _UAPI__LINUX_BRIDGE_NETFILTER_H */ |
diff --git a/net/bridge/br_netfilter_hooks.c b/net/bridge/br_netfilter_hooks.c index 9b16eaf33819..6e0dc6bcd32a 100644 --- a/net/bridge/br_netfilter_hooks.c +++ b/net/bridge/br_netfilter_hooks.c | |||
@@ -26,6 +26,7 @@ | |||
26 | #include <linux/if_pppox.h> | 26 | #include <linux/if_pppox.h> |
27 | #include <linux/ppp_defs.h> | 27 | #include <linux/ppp_defs.h> |
28 | #include <linux/netfilter_bridge.h> | 28 | #include <linux/netfilter_bridge.h> |
29 | #include <uapi/linux/netfilter_bridge.h> | ||
29 | #include <linux/netfilter_ipv4.h> | 30 | #include <linux/netfilter_ipv4.h> |
30 | #include <linux/netfilter_ipv6.h> | 31 | #include <linux/netfilter_ipv6.h> |
31 | #include <linux/netfilter_arp.h> | 32 | #include <linux/netfilter_arp.h> |
diff --git a/net/bridge/netfilter/ebtable_filter.c b/net/bridge/netfilter/ebtable_filter.c index c41da5fac84f..550324c516ee 100644 --- a/net/bridge/netfilter/ebtable_filter.c +++ b/net/bridge/netfilter/ebtable_filter.c | |||
@@ -9,6 +9,7 @@ | |||
9 | */ | 9 | */ |
10 | 10 | ||
11 | #include <linux/netfilter_bridge/ebtables.h> | 11 | #include <linux/netfilter_bridge/ebtables.h> |
12 | #include <uapi/linux/netfilter_bridge.h> | ||
12 | #include <linux/module.h> | 13 | #include <linux/module.h> |
13 | 14 | ||
14 | #define FILTER_VALID_HOOKS ((1 << NF_BR_LOCAL_IN) | (1 << NF_BR_FORWARD) | \ | 15 | #define FILTER_VALID_HOOKS ((1 << NF_BR_LOCAL_IN) | (1 << NF_BR_FORWARD) | \ |
diff --git a/net/bridge/netfilter/ebtable_nat.c b/net/bridge/netfilter/ebtable_nat.c index 08df7406ecb3..c0fb3ca518af 100644 --- a/net/bridge/netfilter/ebtable_nat.c +++ b/net/bridge/netfilter/ebtable_nat.c | |||
@@ -9,6 +9,7 @@ | |||
9 | */ | 9 | */ |
10 | 10 | ||
11 | #include <linux/netfilter_bridge/ebtables.h> | 11 | #include <linux/netfilter_bridge/ebtables.h> |
12 | #include <uapi/linux/netfilter_bridge.h> | ||
12 | #include <linux/module.h> | 13 | #include <linux/module.h> |
13 | 14 | ||
14 | #define NAT_VALID_HOOKS ((1 << NF_BR_PRE_ROUTING) | (1 << NF_BR_LOCAL_OUT) | \ | 15 | #define NAT_VALID_HOOKS ((1 << NF_BR_PRE_ROUTING) | (1 << NF_BR_LOCAL_OUT) | \ |
diff --git a/net/core/dst.c b/net/core/dst.c index 2d9b37f8944a..81ccf20e2826 100644 --- a/net/core/dst.c +++ b/net/core/dst.c | |||
@@ -307,6 +307,7 @@ void metadata_dst_free(struct metadata_dst *md_dst) | |||
307 | #endif | 307 | #endif |
308 | kfree(md_dst); | 308 | kfree(md_dst); |
309 | } | 309 | } |
310 | EXPORT_SYMBOL_GPL(metadata_dst_free); | ||
310 | 311 | ||
311 | struct metadata_dst __percpu * | 312 | struct metadata_dst __percpu * |
312 | metadata_dst_alloc_percpu(u8 optslen, enum metadata_type type, gfp_t flags) | 313 | metadata_dst_alloc_percpu(u8 optslen, enum metadata_type type, gfp_t flags) |
diff --git a/net/netfilter/Kconfig b/net/netfilter/Kconfig index 6f6c959aeb8f..71709c104081 100644 --- a/net/netfilter/Kconfig +++ b/net/netfilter/Kconfig | |||
@@ -46,6 +46,14 @@ config NETFILTER_NETLINK_LOG | |||
46 | and is also scheduled to replace the old syslog-based ipt_LOG | 46 | and is also scheduled to replace the old syslog-based ipt_LOG |
47 | and ip6t_LOG modules. | 47 | and ip6t_LOG modules. |
48 | 48 | ||
49 | config NETFILTER_NETLINK_OSF | ||
50 | tristate "Netfilter OSF over NFNETLINK interface" | ||
51 | depends on NETFILTER_ADVANCED | ||
52 | select NETFILTER_NETLINK | ||
53 | help | ||
54 | If this option is enabled, the kernel will include support | ||
55 | for passive OS fingerprint via NFNETLINK. | ||
56 | |||
49 | config NF_CONNTRACK | 57 | config NF_CONNTRACK |
50 | tristate "Netfilter connection tracking support" | 58 | tristate "Netfilter connection tracking support" |
51 | default m if NETFILTER_ADVANCED=n | 59 | default m if NETFILTER_ADVANCED=n |
@@ -98,7 +106,6 @@ config NF_CONNTRACK_SECMARK | |||
98 | config NF_CONNTRACK_ZONES | 106 | config NF_CONNTRACK_ZONES |
99 | bool 'Connection tracking zones' | 107 | bool 'Connection tracking zones' |
100 | depends on NETFILTER_ADVANCED | 108 | depends on NETFILTER_ADVANCED |
101 | depends on NETFILTER_XT_TARGET_CT | ||
102 | help | 109 | help |
103 | This option enables support for connection tracking zones. | 110 | This option enables support for connection tracking zones. |
104 | Normally, each connection needs to have a unique system wide | 111 | Normally, each connection needs to have a unique system wide |
@@ -150,10 +157,11 @@ config NF_CONNTRACK_TIMESTAMP | |||
150 | If unsure, say `N'. | 157 | If unsure, say `N'. |
151 | 158 | ||
152 | config NF_CONNTRACK_LABELS | 159 | config NF_CONNTRACK_LABELS |
153 | bool | 160 | bool "Connection tracking labels" |
154 | help | 161 | help |
155 | This option enables support for assigning user-defined flag bits | 162 | This option enables support for assigning user-defined flag bits |
156 | to connection tracking entries. It selected by the connlabel match. | 163 | to connection tracking entries. It can be used with xtables connlabel |
164 | match and the nftables ct expression. | ||
157 | 165 | ||
158 | config NF_CT_PROTO_DCCP | 166 | config NF_CT_PROTO_DCCP |
159 | bool 'DCCP protocol connection tracking support' | 167 | bool 'DCCP protocol connection tracking support' |
@@ -357,6 +365,7 @@ config NF_CT_NETLINK_TIMEOUT | |||
357 | tristate 'Connection tracking timeout tuning via Netlink' | 365 | tristate 'Connection tracking timeout tuning via Netlink' |
358 | select NETFILTER_NETLINK | 366 | select NETFILTER_NETLINK |
359 | depends on NETFILTER_ADVANCED | 367 | depends on NETFILTER_ADVANCED |
368 | depends on NF_CONNTRACK_TIMEOUT | ||
360 | help | 369 | help |
361 | This option enables support for connection tracking timeout | 370 | This option enables support for connection tracking timeout |
362 | fine-grain tuning. This allows you to attach specific timeout | 371 | fine-grain tuning. This allows you to attach specific timeout |
@@ -442,9 +451,6 @@ config NETFILTER_SYNPROXY | |||
442 | 451 | ||
443 | endif # NF_CONNTRACK | 452 | endif # NF_CONNTRACK |
444 | 453 | ||
445 | config NF_OSF | ||
446 | tristate | ||
447 | |||
448 | config NF_TABLES | 454 | config NF_TABLES |
449 | select NETFILTER_NETLINK | 455 | select NETFILTER_NETLINK |
450 | tristate "Netfilter nf_tables support" | 456 | tristate "Netfilter nf_tables support" |
@@ -553,6 +559,12 @@ config NFT_NAT | |||
553 | This option adds the "nat" expression that you can use to perform | 559 | This option adds the "nat" expression that you can use to perform |
554 | typical Network Address Translation (NAT) packet transformations. | 560 | typical Network Address Translation (NAT) packet transformations. |
555 | 561 | ||
562 | config NFT_TUNNEL | ||
563 | tristate "Netfilter nf_tables tunnel module" | ||
564 | help | ||
565 | This option adds the "tunnel" expression that you can use to set | ||
566 | tunneling policies. | ||
567 | |||
556 | config NFT_OBJREF | 568 | config NFT_OBJREF |
557 | tristate "Netfilter nf_tables stateful object reference module" | 569 | tristate "Netfilter nf_tables stateful object reference module" |
558 | help | 570 | help |
@@ -622,6 +634,23 @@ config NFT_SOCKET | |||
622 | This option allows matching for the presence or absence of a | 634 | This option allows matching for the presence or absence of a |
623 | corresponding socket and its attributes. | 635 | corresponding socket and its attributes. |
624 | 636 | ||
637 | config NFT_OSF | ||
638 | tristate "Netfilter nf_tables passive OS fingerprint support" | ||
639 | depends on NETFILTER_ADVANCED | ||
640 | select NETFILTER_NETLINK_OSF | ||
641 | help | ||
642 | This option allows matching packets from an specific OS. | ||
643 | |||
644 | config NFT_TPROXY | ||
645 | tristate "Netfilter nf_tables tproxy support" | ||
646 | depends on IPV6 || IPV6=n | ||
647 | select NF_DEFRAG_IPV4 | ||
648 | select NF_DEFRAG_IPV6 if NF_TABLES_IPV6 | ||
649 | select NF_TPROXY_IPV4 | ||
650 | select NF_TPROXY_IPV6 if NF_TABLES_IPV6 | ||
651 | help | ||
652 | This makes transparent proxy support available in nftables. | ||
653 | |||
625 | if NF_TABLES_NETDEV | 654 | if NF_TABLES_NETDEV |
626 | 655 | ||
627 | config NF_DUP_NETDEV | 656 | config NF_DUP_NETDEV |
@@ -1368,8 +1397,8 @@ config NETFILTER_XT_MATCH_NFACCT | |||
1368 | 1397 | ||
1369 | config NETFILTER_XT_MATCH_OSF | 1398 | config NETFILTER_XT_MATCH_OSF |
1370 | tristate '"osf" Passive OS fingerprint match' | 1399 | tristate '"osf" Passive OS fingerprint match' |
1371 | depends on NETFILTER_ADVANCED && NETFILTER_NETLINK | 1400 | depends on NETFILTER_ADVANCED |
1372 | select NF_OSF | 1401 | select NETFILTER_NETLINK_OSF |
1373 | help | 1402 | help |
1374 | This option selects the Passive OS Fingerprinting match module | 1403 | This option selects the Passive OS Fingerprinting match module |
1375 | that allows to passively match the remote operating system by | 1404 | that allows to passively match the remote operating system by |
diff --git a/net/netfilter/Makefile b/net/netfilter/Makefile index dd26e4961f43..16895e045b66 100644 --- a/net/netfilter/Makefile +++ b/net/netfilter/Makefile | |||
@@ -20,6 +20,7 @@ obj-$(CONFIG_NETFILTER_NETLINK) += nfnetlink.o | |||
20 | obj-$(CONFIG_NETFILTER_NETLINK_ACCT) += nfnetlink_acct.o | 20 | obj-$(CONFIG_NETFILTER_NETLINK_ACCT) += nfnetlink_acct.o |
21 | obj-$(CONFIG_NETFILTER_NETLINK_QUEUE) += nfnetlink_queue.o | 21 | obj-$(CONFIG_NETFILTER_NETLINK_QUEUE) += nfnetlink_queue.o |
22 | obj-$(CONFIG_NETFILTER_NETLINK_LOG) += nfnetlink_log.o | 22 | obj-$(CONFIG_NETFILTER_NETLINK_LOG) += nfnetlink_log.o |
23 | obj-$(CONFIG_NETFILTER_NETLINK_OSF) += nfnetlink_osf.o | ||
23 | 24 | ||
24 | # connection tracking | 25 | # connection tracking |
25 | obj-$(CONFIG_NF_CONNTRACK) += nf_conntrack.o | 26 | obj-$(CONFIG_NF_CONNTRACK) += nf_conntrack.o |
@@ -100,6 +101,7 @@ obj-$(CONFIG_NFT_QUEUE) += nft_queue.o | |||
100 | obj-$(CONFIG_NFT_QUOTA) += nft_quota.o | 101 | obj-$(CONFIG_NFT_QUOTA) += nft_quota.o |
101 | obj-$(CONFIG_NFT_REJECT) += nft_reject.o | 102 | obj-$(CONFIG_NFT_REJECT) += nft_reject.o |
102 | obj-$(CONFIG_NFT_REJECT_INET) += nft_reject_inet.o | 103 | obj-$(CONFIG_NFT_REJECT_INET) += nft_reject_inet.o |
104 | obj-$(CONFIG_NFT_TUNNEL) += nft_tunnel.o | ||
103 | obj-$(CONFIG_NFT_COUNTER) += nft_counter.o | 105 | obj-$(CONFIG_NFT_COUNTER) += nft_counter.o |
104 | obj-$(CONFIG_NFT_LOG) += nft_log.o | 106 | obj-$(CONFIG_NFT_LOG) += nft_log.o |
105 | obj-$(CONFIG_NFT_MASQ) += nft_masq.o | 107 | obj-$(CONFIG_NFT_MASQ) += nft_masq.o |
@@ -108,8 +110,9 @@ obj-$(CONFIG_NFT_HASH) += nft_hash.o | |||
108 | obj-$(CONFIG_NFT_FIB) += nft_fib.o | 110 | obj-$(CONFIG_NFT_FIB) += nft_fib.o |
109 | obj-$(CONFIG_NFT_FIB_INET) += nft_fib_inet.o | 111 | obj-$(CONFIG_NFT_FIB_INET) += nft_fib_inet.o |
110 | obj-$(CONFIG_NFT_FIB_NETDEV) += nft_fib_netdev.o | 112 | obj-$(CONFIG_NFT_FIB_NETDEV) += nft_fib_netdev.o |
111 | obj-$(CONFIG_NF_OSF) += nf_osf.o | ||
112 | obj-$(CONFIG_NFT_SOCKET) += nft_socket.o | 113 | obj-$(CONFIG_NFT_SOCKET) += nft_socket.o |
114 | obj-$(CONFIG_NFT_OSF) += nft_osf.o | ||
115 | obj-$(CONFIG_NFT_TPROXY) += nft_tproxy.o | ||
113 | 116 | ||
114 | # nf_tables netdev | 117 | # nf_tables netdev |
115 | obj-$(CONFIG_NFT_DUP_NETDEV) += nft_dup_netdev.o | 118 | obj-$(CONFIG_NFT_DUP_NETDEV) += nft_dup_netdev.o |
diff --git a/net/netfilter/nf_conntrack_core.c b/net/netfilter/nf_conntrack_core.c index 8a113ca1eea2..a676d5f76bdc 100644 --- a/net/netfilter/nf_conntrack_core.c +++ b/net/netfilter/nf_conntrack_core.c | |||
@@ -2022,16 +2022,6 @@ static int kill_all(struct nf_conn *i, void *data) | |||
2022 | return net_eq(nf_ct_net(i), data); | 2022 | return net_eq(nf_ct_net(i), data); |
2023 | } | 2023 | } |
2024 | 2024 | ||
2025 | void nf_ct_free_hashtable(void *hash, unsigned int size) | ||
2026 | { | ||
2027 | if (is_vmalloc_addr(hash)) | ||
2028 | vfree(hash); | ||
2029 | else | ||
2030 | free_pages((unsigned long)hash, | ||
2031 | get_order(sizeof(struct hlist_head) * size)); | ||
2032 | } | ||
2033 | EXPORT_SYMBOL_GPL(nf_ct_free_hashtable); | ||
2034 | |||
2035 | void nf_conntrack_cleanup_start(void) | 2025 | void nf_conntrack_cleanup_start(void) |
2036 | { | 2026 | { |
2037 | conntrack_gc_work.exiting = true; | 2027 | conntrack_gc_work.exiting = true; |
@@ -2042,7 +2032,7 @@ void nf_conntrack_cleanup_end(void) | |||
2042 | { | 2032 | { |
2043 | RCU_INIT_POINTER(nf_ct_hook, NULL); | 2033 | RCU_INIT_POINTER(nf_ct_hook, NULL); |
2044 | cancel_delayed_work_sync(&conntrack_gc_work.dwork); | 2034 | cancel_delayed_work_sync(&conntrack_gc_work.dwork); |
2045 | nf_ct_free_hashtable(nf_conntrack_hash, nf_conntrack_htable_size); | 2035 | kvfree(nf_conntrack_hash); |
2046 | 2036 | ||
2047 | nf_conntrack_proto_fini(); | 2037 | nf_conntrack_proto_fini(); |
2048 | nf_conntrack_seqadj_fini(); | 2038 | nf_conntrack_seqadj_fini(); |
@@ -2108,7 +2098,6 @@ void *nf_ct_alloc_hashtable(unsigned int *sizep, int nulls) | |||
2108 | { | 2098 | { |
2109 | struct hlist_nulls_head *hash; | 2099 | struct hlist_nulls_head *hash; |
2110 | unsigned int nr_slots, i; | 2100 | unsigned int nr_slots, i; |
2111 | size_t sz; | ||
2112 | 2101 | ||
2113 | if (*sizep > (UINT_MAX / sizeof(struct hlist_nulls_head))) | 2102 | if (*sizep > (UINT_MAX / sizeof(struct hlist_nulls_head))) |
2114 | return NULL; | 2103 | return NULL; |
@@ -2116,14 +2105,8 @@ void *nf_ct_alloc_hashtable(unsigned int *sizep, int nulls) | |||
2116 | BUILD_BUG_ON(sizeof(struct hlist_nulls_head) != sizeof(struct hlist_head)); | 2105 | BUILD_BUG_ON(sizeof(struct hlist_nulls_head) != sizeof(struct hlist_head)); |
2117 | nr_slots = *sizep = roundup(*sizep, PAGE_SIZE / sizeof(struct hlist_nulls_head)); | 2106 | nr_slots = *sizep = roundup(*sizep, PAGE_SIZE / sizeof(struct hlist_nulls_head)); |
2118 | 2107 | ||
2119 | if (nr_slots > (UINT_MAX / sizeof(struct hlist_nulls_head))) | 2108 | hash = kvmalloc_array(nr_slots, sizeof(struct hlist_nulls_head), |
2120 | return NULL; | 2109 | GFP_KERNEL | __GFP_ZERO); |
2121 | |||
2122 | sz = nr_slots * sizeof(struct hlist_nulls_head); | ||
2123 | hash = (void *)__get_free_pages(GFP_KERNEL | __GFP_NOWARN | __GFP_ZERO, | ||
2124 | get_order(sz)); | ||
2125 | if (!hash) | ||
2126 | hash = vzalloc(sz); | ||
2127 | 2110 | ||
2128 | if (hash && nulls) | 2111 | if (hash && nulls) |
2129 | for (i = 0; i < nr_slots; i++) | 2112 | for (i = 0; i < nr_slots; i++) |
@@ -2150,7 +2133,7 @@ int nf_conntrack_hash_resize(unsigned int hashsize) | |||
2150 | 2133 | ||
2151 | old_size = nf_conntrack_htable_size; | 2134 | old_size = nf_conntrack_htable_size; |
2152 | if (old_size == hashsize) { | 2135 | if (old_size == hashsize) { |
2153 | nf_ct_free_hashtable(hash, hashsize); | 2136 | kvfree(hash); |
2154 | return 0; | 2137 | return 0; |
2155 | } | 2138 | } |
2156 | 2139 | ||
@@ -2186,7 +2169,7 @@ int nf_conntrack_hash_resize(unsigned int hashsize) | |||
2186 | local_bh_enable(); | 2169 | local_bh_enable(); |
2187 | 2170 | ||
2188 | synchronize_net(); | 2171 | synchronize_net(); |
2189 | nf_ct_free_hashtable(old_hash, old_size); | 2172 | kvfree(old_hash); |
2190 | return 0; | 2173 | return 0; |
2191 | } | 2174 | } |
2192 | 2175 | ||
@@ -2350,7 +2333,7 @@ err_acct: | |||
2350 | err_expect: | 2333 | err_expect: |
2351 | kmem_cache_destroy(nf_conntrack_cachep); | 2334 | kmem_cache_destroy(nf_conntrack_cachep); |
2352 | err_cachep: | 2335 | err_cachep: |
2353 | nf_ct_free_hashtable(nf_conntrack_hash, nf_conntrack_htable_size); | 2336 | kvfree(nf_conntrack_hash); |
2354 | return ret; | 2337 | return ret; |
2355 | } | 2338 | } |
2356 | 2339 | ||
diff --git a/net/netfilter/nf_conntrack_expect.c b/net/netfilter/nf_conntrack_expect.c index 3f586ba23d92..27b84231db10 100644 --- a/net/netfilter/nf_conntrack_expect.c +++ b/net/netfilter/nf_conntrack_expect.c | |||
@@ -712,5 +712,5 @@ void nf_conntrack_expect_fini(void) | |||
712 | { | 712 | { |
713 | rcu_barrier(); /* Wait for call_rcu() before destroy */ | 713 | rcu_barrier(); /* Wait for call_rcu() before destroy */ |
714 | kmem_cache_destroy(nf_ct_expect_cachep); | 714 | kmem_cache_destroy(nf_ct_expect_cachep); |
715 | nf_ct_free_hashtable(nf_ct_expect_hash, nf_ct_expect_hsize); | 715 | kvfree(nf_ct_expect_hash); |
716 | } | 716 | } |
diff --git a/net/netfilter/nf_conntrack_helper.c b/net/netfilter/nf_conntrack_helper.c index d557a425289d..e24b762ffa1d 100644 --- a/net/netfilter/nf_conntrack_helper.c +++ b/net/netfilter/nf_conntrack_helper.c | |||
@@ -562,12 +562,12 @@ int nf_conntrack_helper_init(void) | |||
562 | 562 | ||
563 | return 0; | 563 | return 0; |
564 | out_extend: | 564 | out_extend: |
565 | nf_ct_free_hashtable(nf_ct_helper_hash, nf_ct_helper_hsize); | 565 | kvfree(nf_ct_helper_hash); |
566 | return ret; | 566 | return ret; |
567 | } | 567 | } |
568 | 568 | ||
569 | void nf_conntrack_helper_fini(void) | 569 | void nf_conntrack_helper_fini(void) |
570 | { | 570 | { |
571 | nf_ct_extend_unregister(&helper_extend); | 571 | nf_ct_extend_unregister(&helper_extend); |
572 | nf_ct_free_hashtable(nf_ct_helper_hash, nf_ct_helper_hsize); | 572 | kvfree(nf_ct_helper_hash); |
573 | } | 573 | } |
diff --git a/net/netfilter/nf_conntrack_proto.c b/net/netfilter/nf_conntrack_proto.c index 803607a90102..30070732ee50 100644 --- a/net/netfilter/nf_conntrack_proto.c +++ b/net/netfilter/nf_conntrack_proto.c | |||
@@ -940,14 +940,13 @@ void nf_conntrack_proto_fini(void) | |||
940 | { | 940 | { |
941 | unsigned int i; | 941 | unsigned int i; |
942 | 942 | ||
943 | nf_ct_l4proto_unregister(builtin_l4proto, | ||
944 | ARRAY_SIZE(builtin_l4proto)); | ||
945 | nf_unregister_sockopt(&so_getorigdst); | 943 | nf_unregister_sockopt(&so_getorigdst); |
946 | #if IS_ENABLED(CONFIG_IPV6) | 944 | #if IS_ENABLED(CONFIG_IPV6) |
947 | nf_unregister_sockopt(&so_getorigdst6); | 945 | nf_unregister_sockopt(&so_getorigdst6); |
948 | #endif | 946 | #endif |
949 | 947 | /* No need to call nf_ct_l4proto_unregister(), the register | |
950 | /* free l3proto protocol tables */ | 948 | * tables are free'd here anyway. |
949 | */ | ||
951 | for (i = 0; i < ARRAY_SIZE(nf_ct_protos); i++) | 950 | for (i = 0; i < ARRAY_SIZE(nf_ct_protos); i++) |
952 | kfree(nf_ct_protos[i]); | 951 | kfree(nf_ct_protos[i]); |
953 | } | 952 | } |
diff --git a/net/netfilter/nf_nat_core.c b/net/netfilter/nf_nat_core.c index 6366f0c0b8c1..e2b196054dfc 100644 --- a/net/netfilter/nf_nat_core.c +++ b/net/netfilter/nf_nat_core.c | |||
@@ -1056,7 +1056,7 @@ static int __init nf_nat_init(void) | |||
1056 | 1056 | ||
1057 | ret = nf_ct_extend_register(&nat_extend); | 1057 | ret = nf_ct_extend_register(&nat_extend); |
1058 | if (ret < 0) { | 1058 | if (ret < 0) { |
1059 | nf_ct_free_hashtable(nf_nat_bysource, nf_nat_htable_size); | 1059 | kvfree(nf_nat_bysource); |
1060 | pr_err("Unable to register extension\n"); | 1060 | pr_err("Unable to register extension\n"); |
1061 | return ret; | 1061 | return ret; |
1062 | } | 1062 | } |
@@ -1094,7 +1094,7 @@ static void __exit nf_nat_cleanup(void) | |||
1094 | for (i = 0; i < NFPROTO_NUMPROTO; i++) | 1094 | for (i = 0; i < NFPROTO_NUMPROTO; i++) |
1095 | kfree(nf_nat_l4protos[i]); | 1095 | kfree(nf_nat_l4protos[i]); |
1096 | synchronize_net(); | 1096 | synchronize_net(); |
1097 | nf_ct_free_hashtable(nf_nat_bysource, nf_nat_htable_size); | 1097 | kvfree(nf_nat_bysource); |
1098 | unregister_pernet_subsys(&nat_net_ops); | 1098 | unregister_pernet_subsys(&nat_net_ops); |
1099 | } | 1099 | } |
1100 | 1100 | ||
diff --git a/net/netfilter/nf_tables_api.c b/net/netfilter/nf_tables_api.c index f18085639807..67cdd5c4f4f5 100644 --- a/net/netfilter/nf_tables_api.c +++ b/net/netfilter/nf_tables_api.c | |||
@@ -1442,7 +1442,7 @@ struct nft_chain_hook { | |||
1442 | static int nft_chain_parse_hook(struct net *net, | 1442 | static int nft_chain_parse_hook(struct net *net, |
1443 | const struct nlattr * const nla[], | 1443 | const struct nlattr * const nla[], |
1444 | struct nft_chain_hook *hook, u8 family, | 1444 | struct nft_chain_hook *hook, u8 family, |
1445 | bool create) | 1445 | bool autoload) |
1446 | { | 1446 | { |
1447 | struct nlattr *ha[NFTA_HOOK_MAX + 1]; | 1447 | struct nlattr *ha[NFTA_HOOK_MAX + 1]; |
1448 | const struct nft_chain_type *type; | 1448 | const struct nft_chain_type *type; |
@@ -1467,7 +1467,7 @@ static int nft_chain_parse_hook(struct net *net, | |||
1467 | type = chain_type[family][NFT_CHAIN_T_DEFAULT]; | 1467 | type = chain_type[family][NFT_CHAIN_T_DEFAULT]; |
1468 | if (nla[NFTA_CHAIN_TYPE]) { | 1468 | if (nla[NFTA_CHAIN_TYPE]) { |
1469 | type = nf_tables_chain_type_lookup(net, nla[NFTA_CHAIN_TYPE], | 1469 | type = nf_tables_chain_type_lookup(net, nla[NFTA_CHAIN_TYPE], |
1470 | family, create); | 1470 | family, autoload); |
1471 | if (IS_ERR(type)) | 1471 | if (IS_ERR(type)) |
1472 | return PTR_ERR(type); | 1472 | return PTR_ERR(type); |
1473 | } | 1473 | } |
@@ -1534,7 +1534,7 @@ static struct nft_rule **nf_tables_chain_alloc_rules(const struct nft_chain *cha | |||
1534 | } | 1534 | } |
1535 | 1535 | ||
1536 | static int nf_tables_addchain(struct nft_ctx *ctx, u8 family, u8 genmask, | 1536 | static int nf_tables_addchain(struct nft_ctx *ctx, u8 family, u8 genmask, |
1537 | u8 policy, bool create) | 1537 | u8 policy) |
1538 | { | 1538 | { |
1539 | const struct nlattr * const *nla = ctx->nla; | 1539 | const struct nlattr * const *nla = ctx->nla; |
1540 | struct nft_table *table = ctx->table; | 1540 | struct nft_table *table = ctx->table; |
@@ -1552,7 +1552,7 @@ static int nf_tables_addchain(struct nft_ctx *ctx, u8 family, u8 genmask, | |||
1552 | struct nft_chain_hook hook; | 1552 | struct nft_chain_hook hook; |
1553 | struct nf_hook_ops *ops; | 1553 | struct nf_hook_ops *ops; |
1554 | 1554 | ||
1555 | err = nft_chain_parse_hook(net, nla, &hook, family, create); | 1555 | err = nft_chain_parse_hook(net, nla, &hook, family, true); |
1556 | if (err < 0) | 1556 | if (err < 0) |
1557 | return err; | 1557 | return err; |
1558 | 1558 | ||
@@ -1643,8 +1643,7 @@ err1: | |||
1643 | return err; | 1643 | return err; |
1644 | } | 1644 | } |
1645 | 1645 | ||
1646 | static int nf_tables_updchain(struct nft_ctx *ctx, u8 genmask, u8 policy, | 1646 | static int nf_tables_updchain(struct nft_ctx *ctx, u8 genmask, u8 policy) |
1647 | bool create) | ||
1648 | { | 1647 | { |
1649 | const struct nlattr * const *nla = ctx->nla; | 1648 | const struct nlattr * const *nla = ctx->nla; |
1650 | struct nft_table *table = ctx->table; | 1649 | struct nft_table *table = ctx->table; |
@@ -1661,7 +1660,7 @@ static int nf_tables_updchain(struct nft_ctx *ctx, u8 genmask, u8 policy, | |||
1661 | return -EBUSY; | 1660 | return -EBUSY; |
1662 | 1661 | ||
1663 | err = nft_chain_parse_hook(ctx->net, nla, &hook, ctx->family, | 1662 | err = nft_chain_parse_hook(ctx->net, nla, &hook, ctx->family, |
1664 | create); | 1663 | false); |
1665 | if (err < 0) | 1664 | if (err < 0) |
1666 | return err; | 1665 | return err; |
1667 | 1666 | ||
@@ -1761,9 +1760,6 @@ static int nf_tables_newchain(struct net *net, struct sock *nlsk, | |||
1761 | u8 policy = NF_ACCEPT; | 1760 | u8 policy = NF_ACCEPT; |
1762 | struct nft_ctx ctx; | 1761 | struct nft_ctx ctx; |
1763 | u64 handle = 0; | 1762 | u64 handle = 0; |
1764 | bool create; | ||
1765 | |||
1766 | create = nlh->nlmsg_flags & NLM_F_CREATE ? true : false; | ||
1767 | 1763 | ||
1768 | lockdep_assert_held(&net->nft.commit_mutex); | 1764 | lockdep_assert_held(&net->nft.commit_mutex); |
1769 | 1765 | ||
@@ -1828,10 +1824,10 @@ static int nf_tables_newchain(struct net *net, struct sock *nlsk, | |||
1828 | if (nlh->nlmsg_flags & NLM_F_REPLACE) | 1824 | if (nlh->nlmsg_flags & NLM_F_REPLACE) |
1829 | return -EOPNOTSUPP; | 1825 | return -EOPNOTSUPP; |
1830 | 1826 | ||
1831 | return nf_tables_updchain(&ctx, genmask, policy, create); | 1827 | return nf_tables_updchain(&ctx, genmask, policy); |
1832 | } | 1828 | } |
1833 | 1829 | ||
1834 | return nf_tables_addchain(&ctx, family, genmask, policy, create); | 1830 | return nf_tables_addchain(&ctx, family, genmask, policy); |
1835 | } | 1831 | } |
1836 | 1832 | ||
1837 | static int nf_tables_delchain(struct net *net, struct sock *nlsk, | 1833 | static int nf_tables_delchain(struct net *net, struct sock *nlsk, |
@@ -2529,13 +2525,10 @@ static int nf_tables_newrule(struct net *net, struct sock *nlsk, | |||
2529 | struct nlattr *tmp; | 2525 | struct nlattr *tmp; |
2530 | unsigned int size, i, n, ulen = 0, usize = 0; | 2526 | unsigned int size, i, n, ulen = 0, usize = 0; |
2531 | int err, rem; | 2527 | int err, rem; |
2532 | bool create; | ||
2533 | u64 handle, pos_handle; | 2528 | u64 handle, pos_handle; |
2534 | 2529 | ||
2535 | lockdep_assert_held(&net->nft.commit_mutex); | 2530 | lockdep_assert_held(&net->nft.commit_mutex); |
2536 | 2531 | ||
2537 | create = nlh->nlmsg_flags & NLM_F_CREATE ? true : false; | ||
2538 | |||
2539 | table = nft_table_lookup(net, nla[NFTA_RULE_TABLE], family, genmask); | 2532 | table = nft_table_lookup(net, nla[NFTA_RULE_TABLE], family, genmask); |
2540 | if (IS_ERR(table)) { | 2533 | if (IS_ERR(table)) { |
2541 | NL_SET_BAD_ATTR(extack, nla[NFTA_RULE_TABLE]); | 2534 | NL_SET_BAD_ATTR(extack, nla[NFTA_RULE_TABLE]); |
@@ -2565,7 +2558,8 @@ static int nf_tables_newrule(struct net *net, struct sock *nlsk, | |||
2565 | else | 2558 | else |
2566 | return -EOPNOTSUPP; | 2559 | return -EOPNOTSUPP; |
2567 | } else { | 2560 | } else { |
2568 | if (!create || nlh->nlmsg_flags & NLM_F_REPLACE) | 2561 | if (!(nlh->nlmsg_flags & NLM_F_CREATE) || |
2562 | nlh->nlmsg_flags & NLM_F_REPLACE) | ||
2569 | return -EINVAL; | 2563 | return -EINVAL; |
2570 | handle = nf_tables_alloc_handle(table); | 2564 | handle = nf_tables_alloc_handle(table); |
2571 | 2565 | ||
@@ -3361,7 +3355,6 @@ static int nf_tables_newset(struct net *net, struct sock *nlsk, | |||
3361 | struct nft_ctx ctx; | 3355 | struct nft_ctx ctx; |
3362 | char *name; | 3356 | char *name; |
3363 | unsigned int size; | 3357 | unsigned int size; |
3364 | bool create; | ||
3365 | u64 timeout; | 3358 | u64 timeout; |
3366 | u32 ktype, dtype, flags, policy, gc_int, objtype; | 3359 | u32 ktype, dtype, flags, policy, gc_int, objtype; |
3367 | struct nft_set_desc desc; | 3360 | struct nft_set_desc desc; |
@@ -3462,8 +3455,6 @@ static int nf_tables_newset(struct net *net, struct sock *nlsk, | |||
3462 | return err; | 3455 | return err; |
3463 | } | 3456 | } |
3464 | 3457 | ||
3465 | create = nlh->nlmsg_flags & NLM_F_CREATE ? true : false; | ||
3466 | |||
3467 | table = nft_table_lookup(net, nla[NFTA_SET_TABLE], family, genmask); | 3458 | table = nft_table_lookup(net, nla[NFTA_SET_TABLE], family, genmask); |
3468 | if (IS_ERR(table)) { | 3459 | if (IS_ERR(table)) { |
3469 | NL_SET_BAD_ATTR(extack, nla[NFTA_SET_TABLE]); | 3460 | NL_SET_BAD_ATTR(extack, nla[NFTA_SET_TABLE]); |
@@ -4029,7 +4020,6 @@ static int nft_get_set_elem(struct nft_ctx *ctx, struct nft_set *set, | |||
4029 | const struct nlattr *attr) | 4020 | const struct nlattr *attr) |
4030 | { | 4021 | { |
4031 | struct nlattr *nla[NFTA_SET_ELEM_MAX + 1]; | 4022 | struct nlattr *nla[NFTA_SET_ELEM_MAX + 1]; |
4032 | const struct nft_set_ext *ext; | ||
4033 | struct nft_data_desc desc; | 4023 | struct nft_data_desc desc; |
4034 | struct nft_set_elem elem; | 4024 | struct nft_set_elem elem; |
4035 | struct sk_buff *skb; | 4025 | struct sk_buff *skb; |
@@ -4063,7 +4053,6 @@ static int nft_get_set_elem(struct nft_ctx *ctx, struct nft_set *set, | |||
4063 | return PTR_ERR(priv); | 4053 | return PTR_ERR(priv); |
4064 | 4054 | ||
4065 | elem.priv = priv; | 4055 | elem.priv = priv; |
4066 | ext = nft_set_elem_ext(set, &elem); | ||
4067 | 4056 | ||
4068 | err = -ENOMEM; | 4057 | err = -ENOMEM; |
4069 | skb = nlmsg_new(NLMSG_GOODSIZE, GFP_ATOMIC); | 4058 | skb = nlmsg_new(NLMSG_GOODSIZE, GFP_ATOMIC); |
@@ -5940,13 +5929,13 @@ static int nf_tables_flowtable_event(struct notifier_block *this, | |||
5940 | if (!net) | 5929 | if (!net) |
5941 | return 0; | 5930 | return 0; |
5942 | 5931 | ||
5943 | nfnl_lock(NFNL_SUBSYS_NFTABLES); | 5932 | mutex_lock(&net->nft.commit_mutex); |
5944 | list_for_each_entry(table, &net->nft.tables, list) { | 5933 | list_for_each_entry(table, &net->nft.tables, list) { |
5945 | list_for_each_entry(flowtable, &table->flowtables, list) { | 5934 | list_for_each_entry(flowtable, &table->flowtables, list) { |
5946 | nft_flowtable_event(event, dev, flowtable); | 5935 | nft_flowtable_event(event, dev, flowtable); |
5947 | } | 5936 | } |
5948 | } | 5937 | } |
5949 | nfnl_unlock(NFNL_SUBSYS_NFTABLES); | 5938 | mutex_unlock(&net->nft.commit_mutex); |
5950 | put_net(net); | 5939 | put_net(net); |
5951 | return NOTIFY_DONE; | 5940 | return NOTIFY_DONE; |
5952 | } | 5941 | } |
diff --git a/net/netfilter/nf_tables_core.c b/net/netfilter/nf_tables_core.c index 8de912ca53d3..ffd5c0f9412b 100644 --- a/net/netfilter/nf_tables_core.c +++ b/net/netfilter/nf_tables_core.c | |||
@@ -120,6 +120,20 @@ struct nft_jumpstack { | |||
120 | struct nft_rule *const *rules; | 120 | struct nft_rule *const *rules; |
121 | }; | 121 | }; |
122 | 122 | ||
123 | static void expr_call_ops_eval(const struct nft_expr *expr, | ||
124 | struct nft_regs *regs, | ||
125 | struct nft_pktinfo *pkt) | ||
126 | { | ||
127 | unsigned long e = (unsigned long)expr->ops->eval; | ||
128 | |||
129 | if (e == (unsigned long)nft_meta_get_eval) | ||
130 | nft_meta_get_eval(expr, regs, pkt); | ||
131 | else if (e == (unsigned long)nft_lookup_eval) | ||
132 | nft_lookup_eval(expr, regs, pkt); | ||
133 | else | ||
134 | expr->ops->eval(expr, regs, pkt); | ||
135 | } | ||
136 | |||
123 | unsigned int | 137 | unsigned int |
124 | nft_do_chain(struct nft_pktinfo *pkt, void *priv) | 138 | nft_do_chain(struct nft_pktinfo *pkt, void *priv) |
125 | { | 139 | { |
@@ -153,7 +167,7 @@ next_rule: | |||
153 | nft_cmp_fast_eval(expr, ®s); | 167 | nft_cmp_fast_eval(expr, ®s); |
154 | else if (expr->ops != &nft_payload_fast_ops || | 168 | else if (expr->ops != &nft_payload_fast_ops || |
155 | !nft_payload_fast_eval(expr, ®s, pkt)) | 169 | !nft_payload_fast_eval(expr, ®s, pkt)) |
156 | expr->ops->eval(expr, ®s, pkt); | 170 | expr_call_ops_eval(expr, ®s, pkt); |
157 | 171 | ||
158 | if (regs.verdict.code != NFT_CONTINUE) | 172 | if (regs.verdict.code != NFT_CONTINUE) |
159 | break; | 173 | break; |
diff --git a/net/netfilter/nfnetlink_cttimeout.c b/net/netfilter/nfnetlink_cttimeout.c index d9d952fad3e0..4199e5300575 100644 --- a/net/netfilter/nfnetlink_cttimeout.c +++ b/net/netfilter/nfnetlink_cttimeout.c | |||
@@ -503,7 +503,6 @@ err: | |||
503 | return err; | 503 | return err; |
504 | } | 504 | } |
505 | 505 | ||
506 | #ifdef CONFIG_NF_CONNTRACK_TIMEOUT | ||
507 | static struct ctnl_timeout * | 506 | static struct ctnl_timeout * |
508 | ctnl_timeout_find_get(struct net *net, const char *name) | 507 | ctnl_timeout_find_get(struct net *net, const char *name) |
509 | { | 508 | { |
@@ -534,7 +533,6 @@ static void ctnl_timeout_put(struct ctnl_timeout *timeout) | |||
534 | 533 | ||
535 | module_put(THIS_MODULE); | 534 | module_put(THIS_MODULE); |
536 | } | 535 | } |
537 | #endif /* CONFIG_NF_CONNTRACK_TIMEOUT */ | ||
538 | 536 | ||
539 | static const struct nfnl_callback cttimeout_cb[IPCTNL_MSG_TIMEOUT_MAX] = { | 537 | static const struct nfnl_callback cttimeout_cb[IPCTNL_MSG_TIMEOUT_MAX] = { |
540 | [IPCTNL_MSG_TIMEOUT_NEW] = { .call = cttimeout_new_timeout, | 538 | [IPCTNL_MSG_TIMEOUT_NEW] = { .call = cttimeout_new_timeout, |
@@ -605,10 +603,8 @@ static int __init cttimeout_init(void) | |||
605 | "nfnetlink.\n"); | 603 | "nfnetlink.\n"); |
606 | goto err_out; | 604 | goto err_out; |
607 | } | 605 | } |
608 | #ifdef CONFIG_NF_CONNTRACK_TIMEOUT | ||
609 | RCU_INIT_POINTER(nf_ct_timeout_find_get_hook, ctnl_timeout_find_get); | 606 | RCU_INIT_POINTER(nf_ct_timeout_find_get_hook, ctnl_timeout_find_get); |
610 | RCU_INIT_POINTER(nf_ct_timeout_put_hook, ctnl_timeout_put); | 607 | RCU_INIT_POINTER(nf_ct_timeout_put_hook, ctnl_timeout_put); |
611 | #endif /* CONFIG_NF_CONNTRACK_TIMEOUT */ | ||
612 | return 0; | 608 | return 0; |
613 | 609 | ||
614 | err_out: | 610 | err_out: |
@@ -621,11 +617,9 @@ static void __exit cttimeout_exit(void) | |||
621 | nfnetlink_subsys_unregister(&cttimeout_subsys); | 617 | nfnetlink_subsys_unregister(&cttimeout_subsys); |
622 | 618 | ||
623 | unregister_pernet_subsys(&cttimeout_ops); | 619 | unregister_pernet_subsys(&cttimeout_ops); |
624 | #ifdef CONFIG_NF_CONNTRACK_TIMEOUT | ||
625 | RCU_INIT_POINTER(nf_ct_timeout_find_get_hook, NULL); | 620 | RCU_INIT_POINTER(nf_ct_timeout_find_get_hook, NULL); |
626 | RCU_INIT_POINTER(nf_ct_timeout_put_hook, NULL); | 621 | RCU_INIT_POINTER(nf_ct_timeout_put_hook, NULL); |
627 | synchronize_rcu(); | 622 | synchronize_rcu(); |
628 | #endif /* CONFIG_NF_CONNTRACK_TIMEOUT */ | ||
629 | } | 623 | } |
630 | 624 | ||
631 | module_init(cttimeout_init); | 625 | module_init(cttimeout_init); |
diff --git a/net/netfilter/nf_osf.c b/net/netfilter/nfnetlink_osf.c index b44d62d5d9a9..f9dba62c450f 100644 --- a/net/netfilter/nf_osf.c +++ b/net/netfilter/nfnetlink_osf.c | |||
@@ -18,7 +18,14 @@ | |||
18 | #include <linux/netfilter/nfnetlink.h> | 18 | #include <linux/netfilter/nfnetlink.h> |
19 | #include <linux/netfilter/x_tables.h> | 19 | #include <linux/netfilter/x_tables.h> |
20 | #include <net/netfilter/nf_log.h> | 20 | #include <net/netfilter/nf_log.h> |
21 | #include <linux/netfilter/nf_osf.h> | 21 | #include <linux/netfilter/nfnetlink_osf.h> |
22 | |||
23 | /* | ||
24 | * Indexed by dont-fragment bit. | ||
25 | * It is the only constant value in the fingerprint. | ||
26 | */ | ||
27 | struct list_head nf_osf_fingers[2]; | ||
28 | EXPORT_SYMBOL_GPL(nf_osf_fingers); | ||
22 | 29 | ||
23 | static inline int nf_osf_ttl(const struct sk_buff *skb, | 30 | static inline int nf_osf_ttl(const struct sk_buff *skb, |
24 | int ttl_check, unsigned char f_ttl) | 31 | int ttl_check, unsigned char f_ttl) |
@@ -249,4 +256,181 @@ nf_osf_match(const struct sk_buff *skb, u_int8_t family, | |||
249 | } | 256 | } |
250 | EXPORT_SYMBOL_GPL(nf_osf_match); | 257 | EXPORT_SYMBOL_GPL(nf_osf_match); |
251 | 258 | ||
259 | const char *nf_osf_find(const struct sk_buff *skb, | ||
260 | const struct list_head *nf_osf_fingers) | ||
261 | { | ||
262 | const struct iphdr *ip = ip_hdr(skb); | ||
263 | const struct nf_osf_user_finger *f; | ||
264 | unsigned char opts[MAX_IPOPTLEN]; | ||
265 | const struct nf_osf_finger *kf; | ||
266 | struct nf_osf_hdr_ctx ctx; | ||
267 | const struct tcphdr *tcp; | ||
268 | const char *genre = NULL; | ||
269 | |||
270 | memset(&ctx, 0, sizeof(ctx)); | ||
271 | |||
272 | tcp = nf_osf_hdr_ctx_init(&ctx, skb, ip, opts); | ||
273 | if (!tcp) | ||
274 | return false; | ||
275 | |||
276 | list_for_each_entry_rcu(kf, &nf_osf_fingers[ctx.df], finger_entry) { | ||
277 | f = &kf->finger; | ||
278 | if (!nf_osf_match_one(skb, f, -1, &ctx)) | ||
279 | continue; | ||
280 | |||
281 | genre = f->genre; | ||
282 | break; | ||
283 | } | ||
284 | |||
285 | return genre; | ||
286 | } | ||
287 | EXPORT_SYMBOL_GPL(nf_osf_find); | ||
288 | |||
289 | static const struct nla_policy nfnl_osf_policy[OSF_ATTR_MAX + 1] = { | ||
290 | [OSF_ATTR_FINGER] = { .len = sizeof(struct nf_osf_user_finger) }, | ||
291 | }; | ||
292 | |||
293 | static int nfnl_osf_add_callback(struct net *net, struct sock *ctnl, | ||
294 | struct sk_buff *skb, const struct nlmsghdr *nlh, | ||
295 | const struct nlattr * const osf_attrs[], | ||
296 | struct netlink_ext_ack *extack) | ||
297 | { | ||
298 | struct nf_osf_user_finger *f; | ||
299 | struct nf_osf_finger *kf = NULL, *sf; | ||
300 | int err = 0; | ||
301 | |||
302 | if (!capable(CAP_NET_ADMIN)) | ||
303 | return -EPERM; | ||
304 | |||
305 | if (!osf_attrs[OSF_ATTR_FINGER]) | ||
306 | return -EINVAL; | ||
307 | |||
308 | if (!(nlh->nlmsg_flags & NLM_F_CREATE)) | ||
309 | return -EINVAL; | ||
310 | |||
311 | f = nla_data(osf_attrs[OSF_ATTR_FINGER]); | ||
312 | |||
313 | kf = kmalloc(sizeof(struct nf_osf_finger), GFP_KERNEL); | ||
314 | if (!kf) | ||
315 | return -ENOMEM; | ||
316 | |||
317 | memcpy(&kf->finger, f, sizeof(struct nf_osf_user_finger)); | ||
318 | |||
319 | list_for_each_entry(sf, &nf_osf_fingers[!!f->df], finger_entry) { | ||
320 | if (memcmp(&sf->finger, f, sizeof(struct nf_osf_user_finger))) | ||
321 | continue; | ||
322 | |||
323 | kfree(kf); | ||
324 | kf = NULL; | ||
325 | |||
326 | if (nlh->nlmsg_flags & NLM_F_EXCL) | ||
327 | err = -EEXIST; | ||
328 | break; | ||
329 | } | ||
330 | |||
331 | /* | ||
332 | * We are protected by nfnl mutex. | ||
333 | */ | ||
334 | if (kf) | ||
335 | list_add_tail_rcu(&kf->finger_entry, &nf_osf_fingers[!!f->df]); | ||
336 | |||
337 | return err; | ||
338 | } | ||
339 | |||
340 | static int nfnl_osf_remove_callback(struct net *net, struct sock *ctnl, | ||
341 | struct sk_buff *skb, | ||
342 | const struct nlmsghdr *nlh, | ||
343 | const struct nlattr * const osf_attrs[], | ||
344 | struct netlink_ext_ack *extack) | ||
345 | { | ||
346 | struct nf_osf_user_finger *f; | ||
347 | struct nf_osf_finger *sf; | ||
348 | int err = -ENOENT; | ||
349 | |||
350 | if (!capable(CAP_NET_ADMIN)) | ||
351 | return -EPERM; | ||
352 | |||
353 | if (!osf_attrs[OSF_ATTR_FINGER]) | ||
354 | return -EINVAL; | ||
355 | |||
356 | f = nla_data(osf_attrs[OSF_ATTR_FINGER]); | ||
357 | |||
358 | list_for_each_entry(sf, &nf_osf_fingers[!!f->df], finger_entry) { | ||
359 | if (memcmp(&sf->finger, f, sizeof(struct nf_osf_user_finger))) | ||
360 | continue; | ||
361 | |||
362 | /* | ||
363 | * We are protected by nfnl mutex. | ||
364 | */ | ||
365 | list_del_rcu(&sf->finger_entry); | ||
366 | kfree_rcu(sf, rcu_head); | ||
367 | |||
368 | err = 0; | ||
369 | break; | ||
370 | } | ||
371 | |||
372 | return err; | ||
373 | } | ||
374 | |||
375 | static const struct nfnl_callback nfnl_osf_callbacks[OSF_MSG_MAX] = { | ||
376 | [OSF_MSG_ADD] = { | ||
377 | .call = nfnl_osf_add_callback, | ||
378 | .attr_count = OSF_ATTR_MAX, | ||
379 | .policy = nfnl_osf_policy, | ||
380 | }, | ||
381 | [OSF_MSG_REMOVE] = { | ||
382 | .call = nfnl_osf_remove_callback, | ||
383 | .attr_count = OSF_ATTR_MAX, | ||
384 | .policy = nfnl_osf_policy, | ||
385 | }, | ||
386 | }; | ||
387 | |||
388 | static const struct nfnetlink_subsystem nfnl_osf_subsys = { | ||
389 | .name = "osf", | ||
390 | .subsys_id = NFNL_SUBSYS_OSF, | ||
391 | .cb_count = OSF_MSG_MAX, | ||
392 | .cb = nfnl_osf_callbacks, | ||
393 | }; | ||
394 | |||
395 | static int __init nfnl_osf_init(void) | ||
396 | { | ||
397 | int err = -EINVAL; | ||
398 | int i; | ||
399 | |||
400 | for (i = 0; i < ARRAY_SIZE(nf_osf_fingers); ++i) | ||
401 | INIT_LIST_HEAD(&nf_osf_fingers[i]); | ||
402 | |||
403 | err = nfnetlink_subsys_register(&nfnl_osf_subsys); | ||
404 | if (err < 0) { | ||
405 | pr_err("Failed to register OSF nsfnetlink helper (%d)\n", err); | ||
406 | goto err_out_exit; | ||
407 | } | ||
408 | return 0; | ||
409 | |||
410 | err_out_exit: | ||
411 | return err; | ||
412 | } | ||
413 | |||
414 | static void __exit nfnl_osf_fini(void) | ||
415 | { | ||
416 | struct nf_osf_finger *f; | ||
417 | int i; | ||
418 | |||
419 | nfnetlink_subsys_unregister(&nfnl_osf_subsys); | ||
420 | |||
421 | rcu_read_lock(); | ||
422 | for (i = 0; i < ARRAY_SIZE(nf_osf_fingers); ++i) { | ||
423 | list_for_each_entry_rcu(f, &nf_osf_fingers[i], finger_entry) { | ||
424 | list_del_rcu(&f->finger_entry); | ||
425 | kfree_rcu(f, rcu_head); | ||
426 | } | ||
427 | } | ||
428 | rcu_read_unlock(); | ||
429 | |||
430 | rcu_barrier(); | ||
431 | } | ||
432 | |||
433 | module_init(nfnl_osf_init); | ||
434 | module_exit(nfnl_osf_fini); | ||
435 | |||
252 | MODULE_LICENSE("GPL"); | 436 | MODULE_LICENSE("GPL"); |
diff --git a/net/netfilter/nft_lookup.c b/net/netfilter/nft_lookup.c index c2a1d84cdfc4..ad13e8643599 100644 --- a/net/netfilter/nft_lookup.c +++ b/net/netfilter/nft_lookup.c | |||
@@ -26,9 +26,9 @@ struct nft_lookup { | |||
26 | struct nft_set_binding binding; | 26 | struct nft_set_binding binding; |
27 | }; | 27 | }; |
28 | 28 | ||
29 | static void nft_lookup_eval(const struct nft_expr *expr, | 29 | void nft_lookup_eval(const struct nft_expr *expr, |
30 | struct nft_regs *regs, | 30 | struct nft_regs *regs, |
31 | const struct nft_pktinfo *pkt) | 31 | const struct nft_pktinfo *pkt) |
32 | { | 32 | { |
33 | const struct nft_lookup *priv = nft_expr_priv(expr); | 33 | const struct nft_lookup *priv = nft_expr_priv(expr); |
34 | const struct nft_set *set = priv->set; | 34 | const struct nft_set *set = priv->set; |
diff --git a/net/netfilter/nft_meta.c b/net/netfilter/nft_meta.c index 2b94dcc43456..297fe7d97c18 100644 --- a/net/netfilter/nft_meta.c +++ b/net/netfilter/nft_meta.c | |||
@@ -41,9 +41,9 @@ static DEFINE_PER_CPU(struct rnd_state, nft_prandom_state); | |||
41 | #include "../bridge/br_private.h" | 41 | #include "../bridge/br_private.h" |
42 | #endif | 42 | #endif |
43 | 43 | ||
44 | static void nft_meta_get_eval(const struct nft_expr *expr, | 44 | void nft_meta_get_eval(const struct nft_expr *expr, |
45 | struct nft_regs *regs, | 45 | struct nft_regs *regs, |
46 | const struct nft_pktinfo *pkt) | 46 | const struct nft_pktinfo *pkt) |
47 | { | 47 | { |
48 | const struct nft_meta *priv = nft_expr_priv(expr); | 48 | const struct nft_meta *priv = nft_expr_priv(expr); |
49 | const struct sk_buff *skb = pkt->skb; | 49 | const struct sk_buff *skb = pkt->skb; |
diff --git a/net/netfilter/nft_numgen.c b/net/netfilter/nft_numgen.c index 1f4d0854cf70..649d1700ec5b 100644 --- a/net/netfilter/nft_numgen.c +++ b/net/netfilter/nft_numgen.c | |||
@@ -237,10 +237,8 @@ static int nft_ng_random_map_init(const struct nft_ctx *ctx, | |||
237 | priv->map = nft_set_lookup_global(ctx->net, ctx->table, | 237 | priv->map = nft_set_lookup_global(ctx->net, ctx->table, |
238 | tb[NFTA_NG_SET_NAME], | 238 | tb[NFTA_NG_SET_NAME], |
239 | tb[NFTA_NG_SET_ID], genmask); | 239 | tb[NFTA_NG_SET_ID], genmask); |
240 | if (IS_ERR(priv->map)) | ||
241 | return PTR_ERR(priv->map); | ||
242 | 240 | ||
243 | return 0; | 241 | return PTR_ERR_OR_ZERO(priv->map); |
244 | } | 242 | } |
245 | 243 | ||
246 | static int nft_ng_random_dump(struct sk_buff *skb, const struct nft_expr *expr) | 244 | static int nft_ng_random_dump(struct sk_buff *skb, const struct nft_expr *expr) |
diff --git a/net/netfilter/nft_osf.c b/net/netfilter/nft_osf.c new file mode 100644 index 000000000000..9b2f3de7be4f --- /dev/null +++ b/net/netfilter/nft_osf.c | |||
@@ -0,0 +1,106 @@ | |||
1 | #include <net/ip.h> | ||
2 | #include <net/tcp.h> | ||
3 | |||
4 | #include <net/netfilter/nf_tables.h> | ||
5 | #include <linux/netfilter/nfnetlink_osf.h> | ||
6 | |||
7 | #define OSF_GENRE_SIZE 32 | ||
8 | |||
9 | struct nft_osf { | ||
10 | enum nft_registers dreg:8; | ||
11 | }; | ||
12 | |||
13 | static const struct nla_policy nft_osf_policy[NFTA_OSF_MAX + 1] = { | ||
14 | [NFTA_OSF_DREG] = { .type = NLA_U32 }, | ||
15 | }; | ||
16 | |||
17 | static void nft_osf_eval(const struct nft_expr *expr, struct nft_regs *regs, | ||
18 | const struct nft_pktinfo *pkt) | ||
19 | { | ||
20 | struct nft_osf *priv = nft_expr_priv(expr); | ||
21 | u32 *dest = ®s->data[priv->dreg]; | ||
22 | struct sk_buff *skb = pkt->skb; | ||
23 | const struct tcphdr *tcp; | ||
24 | struct tcphdr _tcph; | ||
25 | const char *os_name; | ||
26 | |||
27 | tcp = skb_header_pointer(skb, ip_hdrlen(skb), | ||
28 | sizeof(struct tcphdr), &_tcph); | ||
29 | if (!tcp) { | ||
30 | regs->verdict.code = NFT_BREAK; | ||
31 | return; | ||
32 | } | ||
33 | if (!tcp->syn) { | ||
34 | regs->verdict.code = NFT_BREAK; | ||
35 | return; | ||
36 | } | ||
37 | |||
38 | os_name = nf_osf_find(skb, nf_osf_fingers); | ||
39 | if (!os_name) | ||
40 | strncpy((char *)dest, "unknown", IFNAMSIZ); | ||
41 | else | ||
42 | strncpy((char *)dest, os_name, IFNAMSIZ); | ||
43 | } | ||
44 | |||
45 | static int nft_osf_init(const struct nft_ctx *ctx, | ||
46 | const struct nft_expr *expr, | ||
47 | const struct nlattr * const tb[]) | ||
48 | { | ||
49 | struct nft_osf *priv = nft_expr_priv(expr); | ||
50 | int err; | ||
51 | |||
52 | priv->dreg = nft_parse_register(tb[NFTA_OSF_DREG]); | ||
53 | err = nft_validate_register_store(ctx, priv->dreg, NULL, | ||
54 | NFTA_DATA_VALUE, OSF_GENRE_SIZE); | ||
55 | if (err < 0) | ||
56 | return err; | ||
57 | |||
58 | return 0; | ||
59 | } | ||
60 | |||
61 | static int nft_osf_dump(struct sk_buff *skb, const struct nft_expr *expr) | ||
62 | { | ||
63 | const struct nft_osf *priv = nft_expr_priv(expr); | ||
64 | |||
65 | if (nft_dump_register(skb, NFTA_OSF_DREG, priv->dreg)) | ||
66 | goto nla_put_failure; | ||
67 | |||
68 | return 0; | ||
69 | |||
70 | nla_put_failure: | ||
71 | return -1; | ||
72 | } | ||
73 | |||
74 | static struct nft_expr_type nft_osf_type; | ||
75 | static const struct nft_expr_ops nft_osf_op = { | ||
76 | .eval = nft_osf_eval, | ||
77 | .size = NFT_EXPR_SIZE(sizeof(struct nft_osf)), | ||
78 | .init = nft_osf_init, | ||
79 | .dump = nft_osf_dump, | ||
80 | .type = &nft_osf_type, | ||
81 | }; | ||
82 | |||
83 | static struct nft_expr_type nft_osf_type __read_mostly = { | ||
84 | .ops = &nft_osf_op, | ||
85 | .name = "osf", | ||
86 | .owner = THIS_MODULE, | ||
87 | .policy = nft_osf_policy, | ||
88 | .maxattr = NFTA_OSF_MAX, | ||
89 | }; | ||
90 | |||
91 | static int __init nft_osf_module_init(void) | ||
92 | { | ||
93 | return nft_register_expr(&nft_osf_type); | ||
94 | } | ||
95 | |||
96 | static void __exit nft_osf_module_exit(void) | ||
97 | { | ||
98 | return nft_unregister_expr(&nft_osf_type); | ||
99 | } | ||
100 | |||
101 | module_init(nft_osf_module_init); | ||
102 | module_exit(nft_osf_module_exit); | ||
103 | |||
104 | MODULE_LICENSE("GPL"); | ||
105 | MODULE_AUTHOR("Fernando Fernandez <ffmancera@riseup.net>"); | ||
106 | MODULE_ALIAS_NFT_EXPR("osf"); | ||
diff --git a/net/netfilter/nft_tproxy.c b/net/netfilter/nft_tproxy.c new file mode 100644 index 000000000000..eff99dffc842 --- /dev/null +++ b/net/netfilter/nft_tproxy.c | |||
@@ -0,0 +1,316 @@ | |||
1 | /* SPDX-License-Identifier: GPL-2.0 */ | ||
2 | #include <linux/module.h> | ||
3 | #include <linux/netfilter/nf_tables.h> | ||
4 | #include <net/netfilter/nf_tables.h> | ||
5 | #include <net/netfilter/nf_tables_core.h> | ||
6 | #include <net/netfilter/nf_tproxy.h> | ||
7 | #include <net/inet_sock.h> | ||
8 | #include <net/tcp.h> | ||
9 | #include <linux/if_ether.h> | ||
10 | #include <net/netfilter/ipv4/nf_defrag_ipv4.h> | ||
11 | #if IS_ENABLED(CONFIG_NF_TABLES_IPV6) | ||
12 | #include <net/netfilter/ipv6/nf_defrag_ipv6.h> | ||
13 | #endif | ||
14 | |||
15 | struct nft_tproxy { | ||
16 | enum nft_registers sreg_addr:8; | ||
17 | enum nft_registers sreg_port:8; | ||
18 | u8 family; | ||
19 | }; | ||
20 | |||
21 | static void nft_tproxy_eval_v4(const struct nft_expr *expr, | ||
22 | struct nft_regs *regs, | ||
23 | const struct nft_pktinfo *pkt) | ||
24 | { | ||
25 | const struct nft_tproxy *priv = nft_expr_priv(expr); | ||
26 | struct sk_buff *skb = pkt->skb; | ||
27 | const struct iphdr *iph = ip_hdr(skb); | ||
28 | struct udphdr _hdr, *hp; | ||
29 | __be32 taddr = 0; | ||
30 | __be16 tport = 0; | ||
31 | struct sock *sk; | ||
32 | |||
33 | hp = skb_header_pointer(skb, ip_hdrlen(skb), sizeof(_hdr), &_hdr); | ||
34 | if (!hp) { | ||
35 | regs->verdict.code = NFT_BREAK; | ||
36 | return; | ||
37 | } | ||
38 | |||
39 | /* check if there's an ongoing connection on the packet addresses, this | ||
40 | * happens if the redirect already happened and the current packet | ||
41 | * belongs to an already established connection | ||
42 | */ | ||
43 | sk = nf_tproxy_get_sock_v4(nft_net(pkt), skb, iph->protocol, | ||
44 | iph->saddr, iph->daddr, | ||
45 | hp->source, hp->dest, | ||
46 | skb->dev, NF_TPROXY_LOOKUP_ESTABLISHED); | ||
47 | |||
48 | if (priv->sreg_addr) | ||
49 | taddr = regs->data[priv->sreg_addr]; | ||
50 | taddr = nf_tproxy_laddr4(skb, taddr, iph->daddr); | ||
51 | |||
52 | if (priv->sreg_port) | ||
53 | tport = regs->data[priv->sreg_port]; | ||
54 | if (!tport) | ||
55 | tport = hp->dest; | ||
56 | |||
57 | /* UDP has no TCP_TIME_WAIT state, so we never enter here */ | ||
58 | if (sk && sk->sk_state == TCP_TIME_WAIT) { | ||
59 | /* reopening a TIME_WAIT connection needs special handling */ | ||
60 | sk = nf_tproxy_handle_time_wait4(nft_net(pkt), skb, taddr, tport, sk); | ||
61 | } else if (!sk) { | ||
62 | /* no, there's no established connection, check if | ||
63 | * there's a listener on the redirected addr/port | ||
64 | */ | ||
65 | sk = nf_tproxy_get_sock_v4(nft_net(pkt), skb, iph->protocol, | ||
66 | iph->saddr, taddr, | ||
67 | hp->source, tport, | ||
68 | skb->dev, NF_TPROXY_LOOKUP_LISTENER); | ||
69 | } | ||
70 | |||
71 | if (sk && nf_tproxy_sk_is_transparent(sk)) | ||
72 | nf_tproxy_assign_sock(skb, sk); | ||
73 | else | ||
74 | regs->verdict.code = NFT_BREAK; | ||
75 | } | ||
76 | |||
77 | #if IS_ENABLED(CONFIG_NF_TABLES_IPV6) | ||
78 | static void nft_tproxy_eval_v6(const struct nft_expr *expr, | ||
79 | struct nft_regs *regs, | ||
80 | const struct nft_pktinfo *pkt) | ||
81 | { | ||
82 | const struct nft_tproxy *priv = nft_expr_priv(expr); | ||
83 | struct sk_buff *skb = pkt->skb; | ||
84 | const struct ipv6hdr *iph = ipv6_hdr(skb); | ||
85 | struct in6_addr taddr = {0}; | ||
86 | int thoff = pkt->xt.thoff; | ||
87 | struct udphdr _hdr, *hp; | ||
88 | __be16 tport = 0; | ||
89 | struct sock *sk; | ||
90 | int l4proto; | ||
91 | |||
92 | if (!pkt->tprot_set) { | ||
93 | regs->verdict.code = NFT_BREAK; | ||
94 | return; | ||
95 | } | ||
96 | l4proto = pkt->tprot; | ||
97 | |||
98 | hp = skb_header_pointer(skb, thoff, sizeof(_hdr), &_hdr); | ||
99 | if (hp == NULL) { | ||
100 | regs->verdict.code = NFT_BREAK; | ||
101 | return; | ||
102 | } | ||
103 | |||
104 | /* check if there's an ongoing connection on the packet addresses, this | ||
105 | * happens if the redirect already happened and the current packet | ||
106 | * belongs to an already established connection | ||
107 | */ | ||
108 | sk = nf_tproxy_get_sock_v6(nft_net(pkt), skb, thoff, l4proto, | ||
109 | &iph->saddr, &iph->daddr, | ||
110 | hp->source, hp->dest, | ||
111 | nft_in(pkt), NF_TPROXY_LOOKUP_ESTABLISHED); | ||
112 | |||
113 | if (priv->sreg_addr) | ||
114 | memcpy(&taddr, ®s->data[priv->sreg_addr], sizeof(taddr)); | ||
115 | taddr = *nf_tproxy_laddr6(skb, &taddr, &iph->daddr); | ||
116 | |||
117 | if (priv->sreg_port) | ||
118 | tport = regs->data[priv->sreg_port]; | ||
119 | if (!tport) | ||
120 | tport = hp->dest; | ||
121 | |||
122 | /* UDP has no TCP_TIME_WAIT state, so we never enter here */ | ||
123 | if (sk && sk->sk_state == TCP_TIME_WAIT) { | ||
124 | /* reopening a TIME_WAIT connection needs special handling */ | ||
125 | sk = nf_tproxy_handle_time_wait6(skb, l4proto, thoff, | ||
126 | nft_net(pkt), | ||
127 | &taddr, | ||
128 | tport, | ||
129 | sk); | ||
130 | } else if (!sk) { | ||
131 | /* no there's no established connection, check if | ||
132 | * there's a listener on the redirected addr/port | ||
133 | */ | ||
134 | sk = nf_tproxy_get_sock_v6(nft_net(pkt), skb, thoff, | ||
135 | l4proto, &iph->saddr, &taddr, | ||
136 | hp->source, tport, | ||
137 | nft_in(pkt), NF_TPROXY_LOOKUP_LISTENER); | ||
138 | } | ||
139 | |||
140 | /* NOTE: assign_sock consumes our sk reference */ | ||
141 | if (sk && nf_tproxy_sk_is_transparent(sk)) | ||
142 | nf_tproxy_assign_sock(skb, sk); | ||
143 | else | ||
144 | regs->verdict.code = NFT_BREAK; | ||
145 | } | ||
146 | #endif | ||
147 | |||
148 | static void nft_tproxy_eval(const struct nft_expr *expr, | ||
149 | struct nft_regs *regs, | ||
150 | const struct nft_pktinfo *pkt) | ||
151 | { | ||
152 | const struct nft_tproxy *priv = nft_expr_priv(expr); | ||
153 | |||
154 | switch (nft_pf(pkt)) { | ||
155 | case NFPROTO_IPV4: | ||
156 | switch (priv->family) { | ||
157 | case NFPROTO_IPV4: | ||
158 | case NFPROTO_UNSPEC: | ||
159 | nft_tproxy_eval_v4(expr, regs, pkt); | ||
160 | return; | ||
161 | } | ||
162 | break; | ||
163 | #if IS_ENABLED(CONFIG_NF_TABLES_IPV6) | ||
164 | case NFPROTO_IPV6: | ||
165 | switch (priv->family) { | ||
166 | case NFPROTO_IPV6: | ||
167 | case NFPROTO_UNSPEC: | ||
168 | nft_tproxy_eval_v6(expr, regs, pkt); | ||
169 | return; | ||
170 | } | ||
171 | #endif | ||
172 | } | ||
173 | regs->verdict.code = NFT_BREAK; | ||
174 | } | ||
175 | |||
176 | static const struct nla_policy nft_tproxy_policy[NFTA_TPROXY_MAX + 1] = { | ||
177 | [NFTA_TPROXY_FAMILY] = { .type = NLA_U32 }, | ||
178 | [NFTA_TPROXY_REG_ADDR] = { .type = NLA_U32 }, | ||
179 | [NFTA_TPROXY_REG_PORT] = { .type = NLA_U32 }, | ||
180 | }; | ||
181 | |||
182 | static int nft_tproxy_init(const struct nft_ctx *ctx, | ||
183 | const struct nft_expr *expr, | ||
184 | const struct nlattr * const tb[]) | ||
185 | { | ||
186 | struct nft_tproxy *priv = nft_expr_priv(expr); | ||
187 | unsigned int alen = 0; | ||
188 | int err; | ||
189 | |||
190 | if (!tb[NFTA_TPROXY_FAMILY] || | ||
191 | (!tb[NFTA_TPROXY_REG_ADDR] && !tb[NFTA_TPROXY_REG_PORT])) | ||
192 | return -EINVAL; | ||
193 | |||
194 | priv->family = ntohl(nla_get_be32(tb[NFTA_TPROXY_FAMILY])); | ||
195 | |||
196 | switch (ctx->family) { | ||
197 | case NFPROTO_IPV4: | ||
198 | if (priv->family != NFPROTO_IPV4) | ||
199 | return -EINVAL; | ||
200 | break; | ||
201 | #if IS_ENABLED(CONFIG_NF_TABLES_IPV6) | ||
202 | case NFPROTO_IPV6: | ||
203 | if (priv->family != NFPROTO_IPV6) | ||
204 | return -EINVAL; | ||
205 | break; | ||
206 | #endif | ||
207 | case NFPROTO_INET: | ||
208 | break; | ||
209 | default: | ||
210 | return -EOPNOTSUPP; | ||
211 | } | ||
212 | |||
213 | /* Address is specified but the rule family is not set accordingly */ | ||
214 | if (priv->family == NFPROTO_UNSPEC && tb[NFTA_TPROXY_REG_ADDR]) | ||
215 | return -EINVAL; | ||
216 | |||
217 | switch (priv->family) { | ||
218 | case NFPROTO_IPV4: | ||
219 | alen = FIELD_SIZEOF(union nf_inet_addr, in); | ||
220 | err = nf_defrag_ipv4_enable(ctx->net); | ||
221 | if (err) | ||
222 | return err; | ||
223 | break; | ||
224 | #if IS_ENABLED(CONFIG_NF_TABLES_IPV6) | ||
225 | case NFPROTO_IPV6: | ||
226 | alen = FIELD_SIZEOF(union nf_inet_addr, in6); | ||
227 | err = nf_defrag_ipv6_enable(ctx->net); | ||
228 | if (err) | ||
229 | return err; | ||
230 | break; | ||
231 | #endif | ||
232 | case NFPROTO_UNSPEC: | ||
233 | /* No address is specified here */ | ||
234 | err = nf_defrag_ipv4_enable(ctx->net); | ||
235 | if (err) | ||
236 | return err; | ||
237 | #if IS_ENABLED(CONFIG_NF_TABLES_IPV6) | ||
238 | err = nf_defrag_ipv6_enable(ctx->net); | ||
239 | if (err) | ||
240 | return err; | ||
241 | #endif | ||
242 | break; | ||
243 | default: | ||
244 | return -EOPNOTSUPP; | ||
245 | } | ||
246 | |||
247 | if (tb[NFTA_TPROXY_REG_ADDR]) { | ||
248 | priv->sreg_addr = nft_parse_register(tb[NFTA_TPROXY_REG_ADDR]); | ||
249 | err = nft_validate_register_load(priv->sreg_addr, alen); | ||
250 | if (err < 0) | ||
251 | return err; | ||
252 | } | ||
253 | |||
254 | if (tb[NFTA_TPROXY_REG_PORT]) { | ||
255 | priv->sreg_port = nft_parse_register(tb[NFTA_TPROXY_REG_PORT]); | ||
256 | err = nft_validate_register_load(priv->sreg_port, sizeof(u16)); | ||
257 | if (err < 0) | ||
258 | return err; | ||
259 | } | ||
260 | |||
261 | return 0; | ||
262 | } | ||
263 | |||
264 | static int nft_tproxy_dump(struct sk_buff *skb, | ||
265 | const struct nft_expr *expr) | ||
266 | { | ||
267 | const struct nft_tproxy *priv = nft_expr_priv(expr); | ||
268 | |||
269 | if (nla_put_be32(skb, NFTA_TPROXY_FAMILY, htonl(priv->family))) | ||
270 | return -1; | ||
271 | |||
272 | if (priv->sreg_addr && | ||
273 | nft_dump_register(skb, NFTA_TPROXY_REG_ADDR, priv->sreg_addr)) | ||
274 | return -1; | ||
275 | |||
276 | if (priv->sreg_port && | ||
277 | nft_dump_register(skb, NFTA_TPROXY_REG_PORT, priv->sreg_port)) | ||
278 | return -1; | ||
279 | |||
280 | return 0; | ||
281 | } | ||
282 | |||
283 | static struct nft_expr_type nft_tproxy_type; | ||
284 | static const struct nft_expr_ops nft_tproxy_ops = { | ||
285 | .type = &nft_tproxy_type, | ||
286 | .size = NFT_EXPR_SIZE(sizeof(struct nft_tproxy)), | ||
287 | .eval = nft_tproxy_eval, | ||
288 | .init = nft_tproxy_init, | ||
289 | .dump = nft_tproxy_dump, | ||
290 | }; | ||
291 | |||
292 | static struct nft_expr_type nft_tproxy_type __read_mostly = { | ||
293 | .name = "tproxy", | ||
294 | .ops = &nft_tproxy_ops, | ||
295 | .policy = nft_tproxy_policy, | ||
296 | .maxattr = NFTA_TPROXY_MAX, | ||
297 | .owner = THIS_MODULE, | ||
298 | }; | ||
299 | |||
300 | static int __init nft_tproxy_module_init(void) | ||
301 | { | ||
302 | return nft_register_expr(&nft_tproxy_type); | ||
303 | } | ||
304 | |||
305 | static void __exit nft_tproxy_module_exit(void) | ||
306 | { | ||
307 | nft_unregister_expr(&nft_tproxy_type); | ||
308 | } | ||
309 | |||
310 | module_init(nft_tproxy_module_init); | ||
311 | module_exit(nft_tproxy_module_exit); | ||
312 | |||
313 | MODULE_LICENSE("GPL"); | ||
314 | MODULE_AUTHOR("Máté Eckl"); | ||
315 | MODULE_DESCRIPTION("nf_tables tproxy support module"); | ||
316 | MODULE_ALIAS_NFT_EXPR("tproxy"); | ||
diff --git a/net/netfilter/nft_tunnel.c b/net/netfilter/nft_tunnel.c new file mode 100644 index 000000000000..3a15f219e4e7 --- /dev/null +++ b/net/netfilter/nft_tunnel.c | |||
@@ -0,0 +1,566 @@ | |||
1 | /* SPDX-License-Identifier: GPL-2.0 */ | ||
2 | #include <linux/kernel.h> | ||
3 | #include <linux/init.h> | ||
4 | #include <linux/module.h> | ||
5 | #include <linux/seqlock.h> | ||
6 | #include <linux/netlink.h> | ||
7 | #include <linux/netfilter.h> | ||
8 | #include <linux/netfilter/nf_tables.h> | ||
9 | #include <net/netfilter/nf_tables.h> | ||
10 | #include <net/dst_metadata.h> | ||
11 | #include <net/ip_tunnels.h> | ||
12 | #include <net/vxlan.h> | ||
13 | #include <net/erspan.h> | ||
14 | |||
15 | struct nft_tunnel { | ||
16 | enum nft_tunnel_keys key:8; | ||
17 | enum nft_registers dreg:8; | ||
18 | }; | ||
19 | |||
20 | static void nft_tunnel_get_eval(const struct nft_expr *expr, | ||
21 | struct nft_regs *regs, | ||
22 | const struct nft_pktinfo *pkt) | ||
23 | { | ||
24 | const struct nft_tunnel *priv = nft_expr_priv(expr); | ||
25 | u32 *dest = ®s->data[priv->dreg]; | ||
26 | struct ip_tunnel_info *tun_info; | ||
27 | |||
28 | tun_info = skb_tunnel_info(pkt->skb); | ||
29 | |||
30 | switch (priv->key) { | ||
31 | case NFT_TUNNEL_PATH: | ||
32 | nft_reg_store8(dest, !!tun_info); | ||
33 | break; | ||
34 | case NFT_TUNNEL_ID: | ||
35 | if (!tun_info) { | ||
36 | regs->verdict.code = NFT_BREAK; | ||
37 | return; | ||
38 | } | ||
39 | *dest = ntohl(tunnel_id_to_key32(tun_info->key.tun_id)); | ||
40 | break; | ||
41 | default: | ||
42 | WARN_ON(1); | ||
43 | regs->verdict.code = NFT_BREAK; | ||
44 | } | ||
45 | } | ||
46 | |||
47 | static const struct nla_policy nft_tunnel_policy[NFTA_TUNNEL_MAX + 1] = { | ||
48 | [NFTA_TUNNEL_KEY] = { .type = NLA_U32 }, | ||
49 | [NFTA_TUNNEL_DREG] = { .type = NLA_U32 }, | ||
50 | }; | ||
51 | |||
52 | static int nft_tunnel_get_init(const struct nft_ctx *ctx, | ||
53 | const struct nft_expr *expr, | ||
54 | const struct nlattr * const tb[]) | ||
55 | { | ||
56 | struct nft_tunnel *priv = nft_expr_priv(expr); | ||
57 | u32 len; | ||
58 | |||
59 | if (!tb[NFTA_TUNNEL_KEY] && | ||
60 | !tb[NFTA_TUNNEL_DREG]) | ||
61 | return -EINVAL; | ||
62 | |||
63 | priv->key = ntohl(nla_get_be32(tb[NFTA_TUNNEL_KEY])); | ||
64 | switch (priv->key) { | ||
65 | case NFT_TUNNEL_PATH: | ||
66 | len = sizeof(u8); | ||
67 | break; | ||
68 | case NFT_TUNNEL_ID: | ||
69 | len = sizeof(u32); | ||
70 | break; | ||
71 | default: | ||
72 | return -EOPNOTSUPP; | ||
73 | } | ||
74 | |||
75 | priv->dreg = nft_parse_register(tb[NFTA_TUNNEL_DREG]); | ||
76 | |||
77 | return nft_validate_register_store(ctx, priv->dreg, NULL, | ||
78 | NFT_DATA_VALUE, len); | ||
79 | } | ||
80 | |||
81 | static int nft_tunnel_get_dump(struct sk_buff *skb, | ||
82 | const struct nft_expr *expr) | ||
83 | { | ||
84 | const struct nft_tunnel *priv = nft_expr_priv(expr); | ||
85 | |||
86 | if (nla_put_be32(skb, NFTA_TUNNEL_KEY, htonl(priv->key))) | ||
87 | goto nla_put_failure; | ||
88 | if (nft_dump_register(skb, NFTA_TUNNEL_DREG, priv->dreg)) | ||
89 | goto nla_put_failure; | ||
90 | return 0; | ||
91 | |||
92 | nla_put_failure: | ||
93 | return -1; | ||
94 | } | ||
95 | |||
96 | static struct nft_expr_type nft_tunnel_type; | ||
97 | static const struct nft_expr_ops nft_tunnel_get_ops = { | ||
98 | .type = &nft_tunnel_type, | ||
99 | .size = NFT_EXPR_SIZE(sizeof(struct nft_tunnel)), | ||
100 | .eval = nft_tunnel_get_eval, | ||
101 | .init = nft_tunnel_get_init, | ||
102 | .dump = nft_tunnel_get_dump, | ||
103 | }; | ||
104 | |||
105 | static struct nft_expr_type nft_tunnel_type __read_mostly = { | ||
106 | .name = "tunnel", | ||
107 | .ops = &nft_tunnel_get_ops, | ||
108 | .policy = nft_tunnel_policy, | ||
109 | .maxattr = NFTA_TUNNEL_MAX, | ||
110 | .owner = THIS_MODULE, | ||
111 | }; | ||
112 | |||
113 | struct nft_tunnel_opts { | ||
114 | union { | ||
115 | struct vxlan_metadata vxlan; | ||
116 | struct erspan_metadata erspan; | ||
117 | } u; | ||
118 | u32 len; | ||
119 | __be16 flags; | ||
120 | }; | ||
121 | |||
122 | struct nft_tunnel_obj { | ||
123 | struct metadata_dst *md; | ||
124 | struct nft_tunnel_opts opts; | ||
125 | }; | ||
126 | |||
127 | static const struct nla_policy nft_tunnel_ip_policy[NFTA_TUNNEL_KEY_IP_MAX + 1] = { | ||
128 | [NFTA_TUNNEL_KEY_IP_SRC] = { .type = NLA_U32 }, | ||
129 | [NFTA_TUNNEL_KEY_IP_DST] = { .type = NLA_U32 }, | ||
130 | }; | ||
131 | |||
132 | static int nft_tunnel_obj_ip_init(const struct nft_ctx *ctx, | ||
133 | const struct nlattr *attr, | ||
134 | struct ip_tunnel_info *info) | ||
135 | { | ||
136 | struct nlattr *tb[NFTA_TUNNEL_KEY_IP_MAX + 1]; | ||
137 | int err; | ||
138 | |||
139 | err = nla_parse_nested(tb, NFTA_TUNNEL_KEY_IP_MAX, attr, | ||
140 | nft_tunnel_ip_policy, NULL); | ||
141 | if (err < 0) | ||
142 | return err; | ||
143 | |||
144 | if (!tb[NFTA_TUNNEL_KEY_IP_DST]) | ||
145 | return -EINVAL; | ||
146 | |||
147 | if (tb[NFTA_TUNNEL_KEY_IP_SRC]) | ||
148 | info->key.u.ipv4.src = nla_get_be32(tb[NFTA_TUNNEL_KEY_IP_SRC]); | ||
149 | if (tb[NFTA_TUNNEL_KEY_IP_DST]) | ||
150 | info->key.u.ipv4.dst = nla_get_be32(tb[NFTA_TUNNEL_KEY_IP_DST]); | ||
151 | |||
152 | return 0; | ||
153 | } | ||
154 | |||
155 | static const struct nla_policy nft_tunnel_ip6_policy[NFTA_TUNNEL_KEY_IP6_MAX + 1] = { | ||
156 | [NFTA_TUNNEL_KEY_IP6_SRC] = { .len = sizeof(struct in6_addr), }, | ||
157 | [NFTA_TUNNEL_KEY_IP6_DST] = { .len = sizeof(struct in6_addr), }, | ||
158 | [NFTA_TUNNEL_KEY_IP6_FLOWLABEL] = { .type = NLA_U32, } | ||
159 | }; | ||
160 | |||
161 | static int nft_tunnel_obj_ip6_init(const struct nft_ctx *ctx, | ||
162 | const struct nlattr *attr, | ||
163 | struct ip_tunnel_info *info) | ||
164 | { | ||
165 | struct nlattr *tb[NFTA_TUNNEL_KEY_IP6_MAX + 1]; | ||
166 | int err; | ||
167 | |||
168 | err = nla_parse_nested(tb, NFTA_TUNNEL_KEY_IP6_MAX, attr, | ||
169 | nft_tunnel_ip6_policy, NULL); | ||
170 | if (err < 0) | ||
171 | return err; | ||
172 | |||
173 | if (!tb[NFTA_TUNNEL_KEY_IP6_DST]) | ||
174 | return -EINVAL; | ||
175 | |||
176 | if (tb[NFTA_TUNNEL_KEY_IP6_SRC]) { | ||
177 | memcpy(&info->key.u.ipv6.src, | ||
178 | nla_data(tb[NFTA_TUNNEL_KEY_IP6_SRC]), | ||
179 | sizeof(struct in6_addr)); | ||
180 | } | ||
181 | if (tb[NFTA_TUNNEL_KEY_IP6_DST]) { | ||
182 | memcpy(&info->key.u.ipv6.dst, | ||
183 | nla_data(tb[NFTA_TUNNEL_KEY_IP6_DST]), | ||
184 | sizeof(struct in6_addr)); | ||
185 | } | ||
186 | if (tb[NFTA_TUNNEL_KEY_IP6_FLOWLABEL]) | ||
187 | info->key.label = nla_get_be32(tb[NFTA_TUNNEL_KEY_IP6_FLOWLABEL]); | ||
188 | |||
189 | info->mode |= IP_TUNNEL_INFO_IPV6; | ||
190 | |||
191 | return 0; | ||
192 | } | ||
193 | |||
194 | static const struct nla_policy nft_tunnel_opts_vxlan_policy[NFTA_TUNNEL_KEY_VXLAN_MAX + 1] = { | ||
195 | [NFTA_TUNNEL_KEY_VXLAN_GBP] = { .type = NLA_U32 }, | ||
196 | }; | ||
197 | |||
198 | static int nft_tunnel_obj_vxlan_init(const struct nlattr *attr, | ||
199 | struct nft_tunnel_opts *opts) | ||
200 | { | ||
201 | struct nlattr *tb[NFTA_TUNNEL_KEY_VXLAN_MAX + 1]; | ||
202 | int err; | ||
203 | |||
204 | err = nla_parse_nested(tb, NFTA_TUNNEL_KEY_VXLAN_MAX, attr, | ||
205 | nft_tunnel_opts_vxlan_policy, NULL); | ||
206 | if (err < 0) | ||
207 | return err; | ||
208 | |||
209 | if (!tb[NFTA_TUNNEL_KEY_VXLAN_GBP]) | ||
210 | return -EINVAL; | ||
211 | |||
212 | opts->u.vxlan.gbp = ntohl(nla_get_be32(tb[NFTA_TUNNEL_KEY_VXLAN_GBP])); | ||
213 | |||
214 | opts->len = sizeof(struct vxlan_metadata); | ||
215 | opts->flags = TUNNEL_VXLAN_OPT; | ||
216 | |||
217 | return 0; | ||
218 | } | ||
219 | |||
220 | static const struct nla_policy nft_tunnel_opts_erspan_policy[NFTA_TUNNEL_KEY_ERSPAN_MAX + 1] = { | ||
221 | [NFTA_TUNNEL_KEY_ERSPAN_V1_INDEX] = { .type = NLA_U32 }, | ||
222 | [NFTA_TUNNEL_KEY_ERSPAN_V2_DIR] = { .type = NLA_U8 }, | ||
223 | [NFTA_TUNNEL_KEY_ERSPAN_V2_HWID] = { .type = NLA_U8 }, | ||
224 | }; | ||
225 | |||
226 | static int nft_tunnel_obj_erspan_init(const struct nlattr *attr, | ||
227 | struct nft_tunnel_opts *opts) | ||
228 | { | ||
229 | struct nlattr *tb[NFTA_TUNNEL_KEY_ERSPAN_MAX + 1]; | ||
230 | uint8_t hwid, dir; | ||
231 | int err, version; | ||
232 | |||
233 | err = nla_parse_nested(tb, NFTA_TUNNEL_KEY_ERSPAN_MAX, attr, | ||
234 | nft_tunnel_opts_erspan_policy, NULL); | ||
235 | if (err < 0) | ||
236 | return err; | ||
237 | |||
238 | version = ntohl(nla_get_be32(tb[NFTA_TUNNEL_KEY_ERSPAN_VERSION])); | ||
239 | switch (version) { | ||
240 | case ERSPAN_VERSION: | ||
241 | if (!tb[NFTA_TUNNEL_KEY_ERSPAN_V1_INDEX]) | ||
242 | return -EINVAL; | ||
243 | |||
244 | opts->u.erspan.u.index = | ||
245 | nla_get_be32(tb[NFTA_TUNNEL_KEY_ERSPAN_V1_INDEX]); | ||
246 | break; | ||
247 | case ERSPAN_VERSION2: | ||
248 | if (!tb[NFTA_TUNNEL_KEY_ERSPAN_V2_DIR] || | ||
249 | !tb[NFTA_TUNNEL_KEY_ERSPAN_V2_HWID]) | ||
250 | return -EINVAL; | ||
251 | |||
252 | hwid = nla_get_u8(tb[NFTA_TUNNEL_KEY_ERSPAN_V2_HWID]); | ||
253 | dir = nla_get_u8(tb[NFTA_TUNNEL_KEY_ERSPAN_V2_DIR]); | ||
254 | |||
255 | set_hwid(&opts->u.erspan.u.md2, hwid); | ||
256 | opts->u.erspan.u.md2.dir = dir; | ||
257 | break; | ||
258 | default: | ||
259 | return -EOPNOTSUPP; | ||
260 | } | ||
261 | opts->u.erspan.version = version; | ||
262 | |||
263 | opts->len = sizeof(struct erspan_metadata); | ||
264 | opts->flags = TUNNEL_ERSPAN_OPT; | ||
265 | |||
266 | return 0; | ||
267 | } | ||
268 | |||
269 | static const struct nla_policy nft_tunnel_opts_policy[NFTA_TUNNEL_KEY_OPTS_MAX + 1] = { | ||
270 | [NFTA_TUNNEL_KEY_OPTS_VXLAN] = { .type = NLA_NESTED, }, | ||
271 | [NFTA_TUNNEL_KEY_OPTS_ERSPAN] = { .type = NLA_NESTED, }, | ||
272 | }; | ||
273 | |||
274 | static int nft_tunnel_obj_opts_init(const struct nft_ctx *ctx, | ||
275 | const struct nlattr *attr, | ||
276 | struct ip_tunnel_info *info, | ||
277 | struct nft_tunnel_opts *opts) | ||
278 | { | ||
279 | struct nlattr *tb[NFTA_TUNNEL_KEY_OPTS_MAX + 1]; | ||
280 | int err; | ||
281 | |||
282 | err = nla_parse_nested(tb, NFTA_TUNNEL_KEY_OPTS_MAX, attr, | ||
283 | nft_tunnel_opts_policy, NULL); | ||
284 | if (err < 0) | ||
285 | return err; | ||
286 | |||
287 | if (tb[NFTA_TUNNEL_KEY_OPTS_VXLAN]) { | ||
288 | err = nft_tunnel_obj_vxlan_init(tb[NFTA_TUNNEL_KEY_OPTS_VXLAN], | ||
289 | opts); | ||
290 | } else if (tb[NFTA_TUNNEL_KEY_OPTS_ERSPAN]) { | ||
291 | err = nft_tunnel_obj_erspan_init(tb[NFTA_TUNNEL_KEY_OPTS_ERSPAN], | ||
292 | opts); | ||
293 | } else { | ||
294 | return -EOPNOTSUPP; | ||
295 | } | ||
296 | |||
297 | return err; | ||
298 | } | ||
299 | |||
300 | static const struct nla_policy nft_tunnel_key_policy[NFTA_TUNNEL_KEY_MAX + 1] = { | ||
301 | [NFTA_TUNNEL_KEY_IP] = { .type = NLA_NESTED, }, | ||
302 | [NFTA_TUNNEL_KEY_IP6] = { .type = NLA_NESTED, }, | ||
303 | [NFTA_TUNNEL_KEY_ID] = { .type = NLA_U32, }, | ||
304 | [NFTA_TUNNEL_KEY_FLAGS] = { .type = NLA_U32, }, | ||
305 | [NFTA_TUNNEL_KEY_TOS] = { .type = NLA_U8, }, | ||
306 | [NFTA_TUNNEL_KEY_TTL] = { .type = NLA_U8, }, | ||
307 | [NFTA_TUNNEL_KEY_OPTS] = { .type = NLA_NESTED, }, | ||
308 | }; | ||
309 | |||
310 | static int nft_tunnel_obj_init(const struct nft_ctx *ctx, | ||
311 | const struct nlattr * const tb[], | ||
312 | struct nft_object *obj) | ||
313 | { | ||
314 | struct nft_tunnel_obj *priv = nft_obj_data(obj); | ||
315 | struct ip_tunnel_info info; | ||
316 | struct metadata_dst *md; | ||
317 | int err; | ||
318 | |||
319 | if (!tb[NFTA_TUNNEL_KEY_ID]) | ||
320 | return -EINVAL; | ||
321 | |||
322 | memset(&info, 0, sizeof(info)); | ||
323 | info.mode = IP_TUNNEL_INFO_TX; | ||
324 | info.key.tun_id = key32_to_tunnel_id(nla_get_be32(tb[NFTA_TUNNEL_KEY_ID])); | ||
325 | info.key.tun_flags = TUNNEL_KEY | TUNNEL_CSUM | TUNNEL_NOCACHE; | ||
326 | |||
327 | if (tb[NFTA_TUNNEL_KEY_IP]) { | ||
328 | err = nft_tunnel_obj_ip_init(ctx, tb[NFTA_TUNNEL_KEY_IP], &info); | ||
329 | if (err < 0) | ||
330 | return err; | ||
331 | } else if (tb[NFTA_TUNNEL_KEY_IP6]) { | ||
332 | err = nft_tunnel_obj_ip6_init(ctx, tb[NFTA_TUNNEL_KEY_IP6], &info); | ||
333 | if (err < 0) | ||
334 | return err; | ||
335 | } else { | ||
336 | return -EINVAL; | ||
337 | } | ||
338 | |||
339 | if (tb[NFTA_TUNNEL_KEY_SPORT]) { | ||
340 | info.key.tp_src = nla_get_be16(tb[NFTA_TUNNEL_KEY_SPORT]); | ||
341 | } | ||
342 | if (tb[NFTA_TUNNEL_KEY_DPORT]) { | ||
343 | info.key.tp_dst = nla_get_be16(tb[NFTA_TUNNEL_KEY_DPORT]); | ||
344 | } | ||
345 | |||
346 | if (tb[NFTA_TUNNEL_KEY_FLAGS]) { | ||
347 | u32 tun_flags; | ||
348 | |||
349 | tun_flags = ntohl(nla_get_be32(tb[NFTA_TUNNEL_KEY_FLAGS])); | ||
350 | if (tun_flags & ~NFT_TUNNEL_F_MASK) | ||
351 | return -EOPNOTSUPP; | ||
352 | |||
353 | if (tun_flags & NFT_TUNNEL_F_ZERO_CSUM_TX) | ||
354 | info.key.tun_flags &= ~TUNNEL_CSUM; | ||
355 | if (tun_flags & NFT_TUNNEL_F_DONT_FRAGMENT) | ||
356 | info.key.tun_flags |= TUNNEL_DONT_FRAGMENT; | ||
357 | if (tun_flags & NFT_TUNNEL_F_SEQ_NUMBER) | ||
358 | info.key.tun_flags |= TUNNEL_SEQ; | ||
359 | } | ||
360 | if (tb[NFTA_TUNNEL_KEY_TOS]) | ||
361 | info.key.tos = nla_get_u8(tb[NFTA_TUNNEL_KEY_TOS]); | ||
362 | if (tb[NFTA_TUNNEL_KEY_TTL]) | ||
363 | info.key.ttl = nla_get_u8(tb[NFTA_TUNNEL_KEY_TTL]); | ||
364 | else | ||
365 | info.key.ttl = U8_MAX; | ||
366 | |||
367 | if (tb[NFTA_TUNNEL_KEY_OPTS]) { | ||
368 | err = nft_tunnel_obj_opts_init(ctx, tb[NFTA_TUNNEL_KEY_OPTS], | ||
369 | &info, &priv->opts); | ||
370 | if (err < 0) | ||
371 | return err; | ||
372 | } | ||
373 | |||
374 | md = metadata_dst_alloc(priv->opts.len, METADATA_IP_TUNNEL, GFP_KERNEL); | ||
375 | if (!md) | ||
376 | return -ENOMEM; | ||
377 | |||
378 | memcpy(&md->u.tun_info, &info, sizeof(info)); | ||
379 | ip_tunnel_info_opts_set(&md->u.tun_info, &priv->opts.u, priv->opts.len, | ||
380 | priv->opts.flags); | ||
381 | priv->md = md; | ||
382 | |||
383 | return 0; | ||
384 | } | ||
385 | |||
386 | static inline void nft_tunnel_obj_eval(struct nft_object *obj, | ||
387 | struct nft_regs *regs, | ||
388 | const struct nft_pktinfo *pkt) | ||
389 | { | ||
390 | struct nft_tunnel_obj *priv = nft_obj_data(obj); | ||
391 | struct sk_buff *skb = pkt->skb; | ||
392 | |||
393 | skb_dst_drop(skb); | ||
394 | dst_hold((struct dst_entry *) priv->md); | ||
395 | skb_dst_set(skb, (struct dst_entry *) priv->md); | ||
396 | } | ||
397 | |||
398 | static int nft_tunnel_ip_dump(struct sk_buff *skb, struct ip_tunnel_info *info) | ||
399 | { | ||
400 | struct nlattr *nest; | ||
401 | |||
402 | if (info->mode & IP_TUNNEL_INFO_IPV6) { | ||
403 | nest = nla_nest_start(skb, NFTA_TUNNEL_KEY_IP6); | ||
404 | if (!nest) | ||
405 | return -1; | ||
406 | |||
407 | if (nla_put_in6_addr(skb, NFTA_TUNNEL_KEY_IP6_SRC, &info->key.u.ipv6.src) < 0 || | ||
408 | nla_put_in6_addr(skb, NFTA_TUNNEL_KEY_IP6_DST, &info->key.u.ipv6.dst) < 0 || | ||
409 | nla_put_be32(skb, NFTA_TUNNEL_KEY_IP6_FLOWLABEL, info->key.label)) | ||
410 | return -1; | ||
411 | |||
412 | nla_nest_end(skb, nest); | ||
413 | } else { | ||
414 | nest = nla_nest_start(skb, NFTA_TUNNEL_KEY_IP); | ||
415 | if (!nest) | ||
416 | return -1; | ||
417 | |||
418 | if (nla_put_in_addr(skb, NFTA_TUNNEL_KEY_IP_SRC, info->key.u.ipv4.src) < 0 || | ||
419 | nla_put_in_addr(skb, NFTA_TUNNEL_KEY_IP_DST, info->key.u.ipv4.dst) < 0) | ||
420 | return -1; | ||
421 | |||
422 | nla_nest_end(skb, nest); | ||
423 | } | ||
424 | |||
425 | return 0; | ||
426 | } | ||
427 | |||
428 | static int nft_tunnel_opts_dump(struct sk_buff *skb, | ||
429 | struct nft_tunnel_obj *priv) | ||
430 | { | ||
431 | struct nft_tunnel_opts *opts = &priv->opts; | ||
432 | struct nlattr *nest; | ||
433 | |||
434 | nest = nla_nest_start(skb, NFTA_TUNNEL_KEY_OPTS); | ||
435 | if (!nest) | ||
436 | return -1; | ||
437 | |||
438 | if (opts->flags & TUNNEL_VXLAN_OPT) { | ||
439 | if (nla_put_be32(skb, NFTA_TUNNEL_KEY_VXLAN_GBP, | ||
440 | htonl(opts->u.vxlan.gbp))) | ||
441 | return -1; | ||
442 | } else if (opts->flags & TUNNEL_ERSPAN_OPT) { | ||
443 | switch (opts->u.erspan.version) { | ||
444 | case ERSPAN_VERSION: | ||
445 | if (nla_put_be32(skb, NFTA_TUNNEL_KEY_ERSPAN_V1_INDEX, | ||
446 | opts->u.erspan.u.index)) | ||
447 | return -1; | ||
448 | break; | ||
449 | case ERSPAN_VERSION2: | ||
450 | if (nla_put_u8(skb, NFTA_TUNNEL_KEY_ERSPAN_V2_HWID, | ||
451 | get_hwid(&opts->u.erspan.u.md2)) || | ||
452 | nla_put_u8(skb, NFTA_TUNNEL_KEY_ERSPAN_V2_DIR, | ||
453 | opts->u.erspan.u.md2.dir)) | ||
454 | return -1; | ||
455 | break; | ||
456 | } | ||
457 | } | ||
458 | nla_nest_end(skb, nest); | ||
459 | |||
460 | return 0; | ||
461 | } | ||
462 | |||
463 | static int nft_tunnel_ports_dump(struct sk_buff *skb, | ||
464 | struct ip_tunnel_info *info) | ||
465 | { | ||
466 | if (nla_put_be16(skb, NFTA_TUNNEL_KEY_SPORT, htons(info->key.tp_src)) < 0 || | ||
467 | nla_put_be16(skb, NFTA_TUNNEL_KEY_DPORT, htons(info->key.tp_dst)) < 0) | ||
468 | return -1; | ||
469 | |||
470 | return 0; | ||
471 | } | ||
472 | |||
473 | static int nft_tunnel_flags_dump(struct sk_buff *skb, | ||
474 | struct ip_tunnel_info *info) | ||
475 | { | ||
476 | u32 flags = 0; | ||
477 | |||
478 | if (info->key.tun_flags & TUNNEL_DONT_FRAGMENT) | ||
479 | flags |= NFT_TUNNEL_F_DONT_FRAGMENT; | ||
480 | if (!(info->key.tun_flags & TUNNEL_CSUM)) | ||
481 | flags |= NFT_TUNNEL_F_ZERO_CSUM_TX; | ||
482 | if (info->key.tun_flags & TUNNEL_SEQ) | ||
483 | flags |= NFT_TUNNEL_F_SEQ_NUMBER; | ||
484 | |||
485 | if (nla_put_be32(skb, NFTA_TUNNEL_KEY_FLAGS, htonl(flags)) < 0) | ||
486 | return -1; | ||
487 | |||
488 | return 0; | ||
489 | } | ||
490 | |||
491 | static int nft_tunnel_obj_dump(struct sk_buff *skb, | ||
492 | struct nft_object *obj, bool reset) | ||
493 | { | ||
494 | struct nft_tunnel_obj *priv = nft_obj_data(obj); | ||
495 | struct ip_tunnel_info *info = &priv->md->u.tun_info; | ||
496 | |||
497 | if (nla_put_be32(skb, NFTA_TUNNEL_KEY_ID, | ||
498 | tunnel_id_to_key32(info->key.tun_id)) || | ||
499 | nft_tunnel_ip_dump(skb, info) < 0 || | ||
500 | nft_tunnel_ports_dump(skb, info) < 0 || | ||
501 | nft_tunnel_flags_dump(skb, info) < 0 || | ||
502 | nla_put_u8(skb, NFTA_TUNNEL_KEY_TOS, info->key.tos) || | ||
503 | nla_put_u8(skb, NFTA_TUNNEL_KEY_TTL, info->key.ttl) || | ||
504 | nft_tunnel_opts_dump(skb, priv) < 0) | ||
505 | goto nla_put_failure; | ||
506 | |||
507 | return 0; | ||
508 | |||
509 | nla_put_failure: | ||
510 | return -1; | ||
511 | } | ||
512 | |||
513 | static void nft_tunnel_obj_destroy(const struct nft_ctx *ctx, | ||
514 | struct nft_object *obj) | ||
515 | { | ||
516 | struct nft_tunnel_obj *priv = nft_obj_data(obj); | ||
517 | |||
518 | metadata_dst_free(priv->md); | ||
519 | } | ||
520 | |||
521 | static struct nft_object_type nft_tunnel_obj_type; | ||
522 | static const struct nft_object_ops nft_tunnel_obj_ops = { | ||
523 | .type = &nft_tunnel_obj_type, | ||
524 | .size = sizeof(struct nft_tunnel_obj), | ||
525 | .eval = nft_tunnel_obj_eval, | ||
526 | .init = nft_tunnel_obj_init, | ||
527 | .destroy = nft_tunnel_obj_destroy, | ||
528 | .dump = nft_tunnel_obj_dump, | ||
529 | }; | ||
530 | |||
531 | static struct nft_object_type nft_tunnel_obj_type __read_mostly = { | ||
532 | .type = NFT_OBJECT_TUNNEL, | ||
533 | .ops = &nft_tunnel_obj_ops, | ||
534 | .maxattr = NFTA_TUNNEL_KEY_MAX, | ||
535 | .policy = nft_tunnel_key_policy, | ||
536 | .owner = THIS_MODULE, | ||
537 | }; | ||
538 | |||
539 | static int __init nft_tunnel_module_init(void) | ||
540 | { | ||
541 | int err; | ||
542 | |||
543 | err = nft_register_expr(&nft_tunnel_type); | ||
544 | if (err < 0) | ||
545 | return err; | ||
546 | |||
547 | err = nft_register_obj(&nft_tunnel_obj_type); | ||
548 | if (err < 0) | ||
549 | nft_unregister_expr(&nft_tunnel_type); | ||
550 | |||
551 | return err; | ||
552 | } | ||
553 | |||
554 | static void __exit nft_tunnel_module_exit(void) | ||
555 | { | ||
556 | nft_unregister_obj(&nft_tunnel_obj_type); | ||
557 | nft_unregister_expr(&nft_tunnel_type); | ||
558 | } | ||
559 | |||
560 | module_init(nft_tunnel_module_init); | ||
561 | module_exit(nft_tunnel_module_exit); | ||
562 | |||
563 | MODULE_LICENSE("GPL"); | ||
564 | MODULE_AUTHOR("Pablo Neira Ayuso <pablo@netfilter.org>"); | ||
565 | MODULE_ALIAS_NFT_EXPR("tunnel"); | ||
566 | MODULE_ALIAS_NFT_OBJ(NFT_OBJECT_TUNNEL); | ||
diff --git a/net/netfilter/xt_connlimit.c b/net/netfilter/xt_connlimit.c index 6275106ccf50..bc6c8ab0fa62 100644 --- a/net/netfilter/xt_connlimit.c +++ b/net/netfilter/xt_connlimit.c | |||
@@ -93,10 +93,8 @@ static int connlimit_mt_check(const struct xt_mtchk_param *par) | |||
93 | 93 | ||
94 | /* init private data */ | 94 | /* init private data */ |
95 | info->data = nf_conncount_init(par->net, par->family, keylen); | 95 | info->data = nf_conncount_init(par->net, par->family, keylen); |
96 | if (IS_ERR(info->data)) | ||
97 | return PTR_ERR(info->data); | ||
98 | 96 | ||
99 | return 0; | 97 | return PTR_ERR_OR_ZERO(info->data); |
100 | } | 98 | } |
101 | 99 | ||
102 | static void connlimit_mt_destroy(const struct xt_mtdtor_param *par) | 100 | static void connlimit_mt_destroy(const struct xt_mtdtor_param *par) |
diff --git a/net/netfilter/xt_osf.c b/net/netfilter/xt_osf.c index 9cfef73b4107..bf7bba80e24c 100644 --- a/net/netfilter/xt_osf.c +++ b/net/netfilter/xt_osf.c | |||
@@ -37,118 +37,6 @@ | |||
37 | #include <net/netfilter/nf_log.h> | 37 | #include <net/netfilter/nf_log.h> |
38 | #include <linux/netfilter/xt_osf.h> | 38 | #include <linux/netfilter/xt_osf.h> |
39 | 39 | ||
40 | /* | ||
41 | * Indexed by dont-fragment bit. | ||
42 | * It is the only constant value in the fingerprint. | ||
43 | */ | ||
44 | static struct list_head xt_osf_fingers[2]; | ||
45 | |||
46 | static const struct nla_policy xt_osf_policy[OSF_ATTR_MAX + 1] = { | ||
47 | [OSF_ATTR_FINGER] = { .len = sizeof(struct xt_osf_user_finger) }, | ||
48 | }; | ||
49 | |||
50 | static int xt_osf_add_callback(struct net *net, struct sock *ctnl, | ||
51 | struct sk_buff *skb, const struct nlmsghdr *nlh, | ||
52 | const struct nlattr * const osf_attrs[], | ||
53 | struct netlink_ext_ack *extack) | ||
54 | { | ||
55 | struct xt_osf_user_finger *f; | ||
56 | struct xt_osf_finger *kf = NULL, *sf; | ||
57 | int err = 0; | ||
58 | |||
59 | if (!capable(CAP_NET_ADMIN)) | ||
60 | return -EPERM; | ||
61 | |||
62 | if (!osf_attrs[OSF_ATTR_FINGER]) | ||
63 | return -EINVAL; | ||
64 | |||
65 | if (!(nlh->nlmsg_flags & NLM_F_CREATE)) | ||
66 | return -EINVAL; | ||
67 | |||
68 | f = nla_data(osf_attrs[OSF_ATTR_FINGER]); | ||
69 | |||
70 | kf = kmalloc(sizeof(struct xt_osf_finger), GFP_KERNEL); | ||
71 | if (!kf) | ||
72 | return -ENOMEM; | ||
73 | |||
74 | memcpy(&kf->finger, f, sizeof(struct xt_osf_user_finger)); | ||
75 | |||
76 | list_for_each_entry(sf, &xt_osf_fingers[!!f->df], finger_entry) { | ||
77 | if (memcmp(&sf->finger, f, sizeof(struct xt_osf_user_finger))) | ||
78 | continue; | ||
79 | |||
80 | kfree(kf); | ||
81 | kf = NULL; | ||
82 | |||
83 | if (nlh->nlmsg_flags & NLM_F_EXCL) | ||
84 | err = -EEXIST; | ||
85 | break; | ||
86 | } | ||
87 | |||
88 | /* | ||
89 | * We are protected by nfnl mutex. | ||
90 | */ | ||
91 | if (kf) | ||
92 | list_add_tail_rcu(&kf->finger_entry, &xt_osf_fingers[!!f->df]); | ||
93 | |||
94 | return err; | ||
95 | } | ||
96 | |||
97 | static int xt_osf_remove_callback(struct net *net, struct sock *ctnl, | ||
98 | struct sk_buff *skb, | ||
99 | const struct nlmsghdr *nlh, | ||
100 | const struct nlattr * const osf_attrs[], | ||
101 | struct netlink_ext_ack *extack) | ||
102 | { | ||
103 | struct xt_osf_user_finger *f; | ||
104 | struct xt_osf_finger *sf; | ||
105 | int err = -ENOENT; | ||
106 | |||
107 | if (!capable(CAP_NET_ADMIN)) | ||
108 | return -EPERM; | ||
109 | |||
110 | if (!osf_attrs[OSF_ATTR_FINGER]) | ||
111 | return -EINVAL; | ||
112 | |||
113 | f = nla_data(osf_attrs[OSF_ATTR_FINGER]); | ||
114 | |||
115 | list_for_each_entry(sf, &xt_osf_fingers[!!f->df], finger_entry) { | ||
116 | if (memcmp(&sf->finger, f, sizeof(struct xt_osf_user_finger))) | ||
117 | continue; | ||
118 | |||
119 | /* | ||
120 | * We are protected by nfnl mutex. | ||
121 | */ | ||
122 | list_del_rcu(&sf->finger_entry); | ||
123 | kfree_rcu(sf, rcu_head); | ||
124 | |||
125 | err = 0; | ||
126 | break; | ||
127 | } | ||
128 | |||
129 | return err; | ||
130 | } | ||
131 | |||
132 | static const struct nfnl_callback xt_osf_nfnetlink_callbacks[OSF_MSG_MAX] = { | ||
133 | [OSF_MSG_ADD] = { | ||
134 | .call = xt_osf_add_callback, | ||
135 | .attr_count = OSF_ATTR_MAX, | ||
136 | .policy = xt_osf_policy, | ||
137 | }, | ||
138 | [OSF_MSG_REMOVE] = { | ||
139 | .call = xt_osf_remove_callback, | ||
140 | .attr_count = OSF_ATTR_MAX, | ||
141 | .policy = xt_osf_policy, | ||
142 | }, | ||
143 | }; | ||
144 | |||
145 | static const struct nfnetlink_subsystem xt_osf_nfnetlink = { | ||
146 | .name = "osf", | ||
147 | .subsys_id = NFNL_SUBSYS_OSF, | ||
148 | .cb_count = OSF_MSG_MAX, | ||
149 | .cb = xt_osf_nfnetlink_callbacks, | ||
150 | }; | ||
151 | |||
152 | static bool | 40 | static bool |
153 | xt_osf_match_packet(const struct sk_buff *skb, struct xt_action_param *p) | 41 | xt_osf_match_packet(const struct sk_buff *skb, struct xt_action_param *p) |
154 | { | 42 | { |
@@ -159,7 +47,7 @@ xt_osf_match_packet(const struct sk_buff *skb, struct xt_action_param *p) | |||
159 | return false; | 47 | return false; |
160 | 48 | ||
161 | return nf_osf_match(skb, xt_family(p), xt_hooknum(p), xt_in(p), | 49 | return nf_osf_match(skb, xt_family(p), xt_hooknum(p), xt_in(p), |
162 | xt_out(p), info, net, xt_osf_fingers); | 50 | xt_out(p), info, net, nf_osf_fingers); |
163 | } | 51 | } |
164 | 52 | ||
165 | static struct xt_match xt_osf_match = { | 53 | static struct xt_match xt_osf_match = { |
@@ -177,52 +65,21 @@ static struct xt_match xt_osf_match = { | |||
177 | 65 | ||
178 | static int __init xt_osf_init(void) | 66 | static int __init xt_osf_init(void) |
179 | { | 67 | { |
180 | int err = -EINVAL; | 68 | int err; |
181 | int i; | ||
182 | |||
183 | for (i=0; i<ARRAY_SIZE(xt_osf_fingers); ++i) | ||
184 | INIT_LIST_HEAD(&xt_osf_fingers[i]); | ||
185 | |||
186 | err = nfnetlink_subsys_register(&xt_osf_nfnetlink); | ||
187 | if (err < 0) { | ||
188 | pr_err("Failed to register OSF nsfnetlink helper (%d)\n", err); | ||
189 | goto err_out_exit; | ||
190 | } | ||
191 | 69 | ||
192 | err = xt_register_match(&xt_osf_match); | 70 | err = xt_register_match(&xt_osf_match); |
193 | if (err) { | 71 | if (err) { |
194 | pr_err("Failed to register OS fingerprint " | 72 | pr_err("Failed to register OS fingerprint " |
195 | "matching module (%d)\n", err); | 73 | "matching module (%d)\n", err); |
196 | goto err_out_remove; | 74 | return err; |
197 | } | 75 | } |
198 | 76 | ||
199 | return 0; | 77 | return 0; |
200 | |||
201 | err_out_remove: | ||
202 | nfnetlink_subsys_unregister(&xt_osf_nfnetlink); | ||
203 | err_out_exit: | ||
204 | return err; | ||
205 | } | 78 | } |
206 | 79 | ||
207 | static void __exit xt_osf_fini(void) | 80 | static void __exit xt_osf_fini(void) |
208 | { | 81 | { |
209 | struct xt_osf_finger *f; | ||
210 | int i; | ||
211 | |||
212 | nfnetlink_subsys_unregister(&xt_osf_nfnetlink); | ||
213 | xt_unregister_match(&xt_osf_match); | 82 | xt_unregister_match(&xt_osf_match); |
214 | |||
215 | rcu_read_lock(); | ||
216 | for (i=0; i<ARRAY_SIZE(xt_osf_fingers); ++i) { | ||
217 | |||
218 | list_for_each_entry_rcu(f, &xt_osf_fingers[i], finger_entry) { | ||
219 | list_del_rcu(&f->finger_entry); | ||
220 | kfree_rcu(f, rcu_head); | ||
221 | } | ||
222 | } | ||
223 | rcu_read_unlock(); | ||
224 | |||
225 | rcu_barrier(); | ||
226 | } | 83 | } |
227 | 84 | ||
228 | module_init(xt_osf_init); | 85 | module_init(xt_osf_init); |