Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

Merge branch 'master' of git://git.kernel.org/pub/scm/linux/kernel/git/pablo/nftables

Pablo Neira Ayuso says: <pablo@netfilter.org>

====================
nftables updates for net-next

The following patchset contains nftables updates for your net-next tree,
they are:

* Add set operation to the meta expression by means of the select_ops()
infrastructure, this allows us to set the packet mark among other things.
From Arturo Borrero Gonzalez.

* Fix wrong format in sscanf in nf_tables_set_alloc_name(), from Daniel
Borkmann.

* Add new queue expression to nf_tables. These comes with two previous patches
to prepare this new feature, one to add mask in nf_tables_core to
evaluate the queue verdict appropriately and another to refactor common
code with xt_NFQUEUE, from Eric Leblond.

* Do not hide nftables from Kconfig if nfnetlink is not enabled, also from
Eric Leblond.

* Add the reject expression to nf_tables, this adds the missing TCP RST
support. It comes with an initial patch to refactor common code with
xt_NFQUEUE, again from Eric Leblond.

* Remove an unused variable assignment in nf_tables_dump_set(), from Michal
Nazarewicz.

* Remove the nft_meta_target code, now that Arturo added the set operation
to the meta expression, from me.

* Add help information for nf_tables to Kconfig, also from me.

* Allow to dump all sets by specifying NFPROTO_UNSPEC, similar feature is
available to other nf_tables objects, requested by Arturo, from me.

* Expose the table usage counter, so we can know how many chains are using
this table without dumping the list of chains, from Tomasz Bursztyka.
====================

Signed-off-by: David S. Miller <davem@davemloft.net>

+876 -538
+128
include/net/netfilter/ipv4/nf_reject.h
··· 1 + #ifndef _IPV4_NF_REJECT_H 2 + #define _IPV4_NF_REJECT_H 3 + 4 + #include <net/ip.h> 5 + #include <net/tcp.h> 6 + #include <net/route.h> 7 + #include <net/dst.h> 8 + 9 + static inline void nf_send_unreach(struct sk_buff *skb_in, int code) 10 + { 11 + icmp_send(skb_in, ICMP_DEST_UNREACH, code, 0); 12 + } 13 + 14 + /* Send RST reply */ 15 + static void nf_send_reset(struct sk_buff *oldskb, int hook) 16 + { 17 + struct sk_buff *nskb; 18 + const struct iphdr *oiph; 19 + struct iphdr *niph; 20 + const struct tcphdr *oth; 21 + struct tcphdr _otcph, *tcph; 22 + 23 + /* IP header checks: fragment. */ 24 + if (ip_hdr(oldskb)->frag_off & htons(IP_OFFSET)) 25 + return; 26 + 27 + oth = skb_header_pointer(oldskb, ip_hdrlen(oldskb), 28 + sizeof(_otcph), &_otcph); 29 + if (oth == NULL) 30 + return; 31 + 32 + /* No RST for RST. */ 33 + if (oth->rst) 34 + return; 35 + 36 + if (skb_rtable(oldskb)->rt_flags & (RTCF_BROADCAST | RTCF_MULTICAST)) 37 + return; 38 + 39 + /* Check checksum */ 40 + if (nf_ip_checksum(oldskb, hook, ip_hdrlen(oldskb), IPPROTO_TCP)) 41 + return; 42 + oiph = ip_hdr(oldskb); 43 + 44 + nskb = alloc_skb(sizeof(struct iphdr) + sizeof(struct tcphdr) + 45 + LL_MAX_HEADER, GFP_ATOMIC); 46 + if (!nskb) 47 + return; 48 + 49 + skb_reserve(nskb, LL_MAX_HEADER); 50 + 51 + skb_reset_network_header(nskb); 52 + niph = (struct iphdr *)skb_put(nskb, sizeof(struct iphdr)); 53 + niph->version = 4; 54 + niph->ihl = sizeof(struct iphdr) / 4; 55 + niph->tos = 0; 56 + niph->id = 0; 57 + niph->frag_off = htons(IP_DF); 58 + niph->protocol = IPPROTO_TCP; 59 + niph->check = 0; 60 + niph->saddr = oiph->daddr; 61 + niph->daddr = oiph->saddr; 62 + 63 + skb_reset_transport_header(nskb); 64 + tcph = (struct tcphdr *)skb_put(nskb, sizeof(struct tcphdr)); 65 + memset(tcph, 0, sizeof(*tcph)); 66 + tcph->source = oth->dest; 67 + tcph->dest = oth->source; 68 + tcph->doff = sizeof(struct tcphdr) / 4; 69 + 70 + if (oth->ack) 71 + tcph->seq = oth->ack_seq; 72 + else { 73 + tcph->ack_seq = htonl(ntohl(oth->seq) + oth->syn + oth->fin + 74 + oldskb->len - ip_hdrlen(oldskb) - 75 + (oth->doff << 2)); 76 + tcph->ack = 1; 77 + } 78 + 79 + tcph->rst = 1; 80 + tcph->check = ~tcp_v4_check(sizeof(struct tcphdr), niph->saddr, 81 + niph->daddr, 0); 82 + nskb->ip_summed = CHECKSUM_PARTIAL; 83 + nskb->csum_start = (unsigned char *)tcph - nskb->head; 84 + nskb->csum_offset = offsetof(struct tcphdr, check); 85 + 86 + /* ip_route_me_harder expects skb->dst to be set */ 87 + skb_dst_set_noref(nskb, skb_dst(oldskb)); 88 + 89 + nskb->protocol = htons(ETH_P_IP); 90 + if (ip_route_me_harder(nskb, RTN_UNSPEC)) 91 + goto free_nskb; 92 + 93 + niph->ttl = ip4_dst_hoplimit(skb_dst(nskb)); 94 + 95 + /* "Never happens" */ 96 + if (nskb->len > dst_mtu(skb_dst(nskb))) 97 + goto free_nskb; 98 + 99 + nf_ct_attach(nskb, oldskb); 100 + 101 + #ifdef CONFIG_BRIDGE_NETFILTER 102 + /* If we use ip_local_out for bridged traffic, the MAC source on 103 + * the RST will be ours, instead of the destination's. This confuses 104 + * some routers/firewalls, and they drop the packet. So we need to 105 + * build the eth header using the original destination's MAC as the 106 + * source, and send the RST packet directly. 107 + */ 108 + if (oldskb->nf_bridge) { 109 + struct ethhdr *oeth = eth_hdr(oldskb); 110 + nskb->dev = oldskb->nf_bridge->physindev; 111 + niph->tot_len = htons(nskb->len); 112 + ip_send_check(niph); 113 + if (dev_hard_header(nskb, nskb->dev, ntohs(nskb->protocol), 114 + oeth->h_source, oeth->h_dest, nskb->len) < 0) 115 + goto free_nskb; 116 + dev_queue_xmit(nskb); 117 + } else 118 + #endif 119 + ip_local_out(nskb); 120 + 121 + return; 122 + 123 + free_nskb: 124 + kfree_skb(nskb); 125 + } 126 + 127 + 128 + #endif /* _IPV4_NF_REJECT_H */
+171
include/net/netfilter/ipv6/nf_reject.h
··· 1 + #ifndef _IPV6_NF_REJECT_H 2 + #define _IPV6_NF_REJECT_H 3 + 4 + #include <net/ipv6.h> 5 + #include <net/ip6_route.h> 6 + #include <net/ip6_fib.h> 7 + #include <net/ip6_checksum.h> 8 + #include <linux/netfilter_ipv6.h> 9 + 10 + static inline void 11 + nf_send_unreach6(struct net *net, struct sk_buff *skb_in, unsigned char code, 12 + unsigned int hooknum) 13 + { 14 + if (hooknum == NF_INET_LOCAL_OUT && skb_in->dev == NULL) 15 + skb_in->dev = net->loopback_dev; 16 + 17 + icmpv6_send(skb_in, ICMPV6_DEST_UNREACH, code, 0); 18 + } 19 + 20 + /* Send RST reply */ 21 + static void nf_send_reset6(struct net *net, struct sk_buff *oldskb, int hook) 22 + { 23 + struct sk_buff *nskb; 24 + struct tcphdr otcph, *tcph; 25 + unsigned int otcplen, hh_len; 26 + int tcphoff, needs_ack; 27 + const struct ipv6hdr *oip6h = ipv6_hdr(oldskb); 28 + struct ipv6hdr *ip6h; 29 + #define DEFAULT_TOS_VALUE 0x0U 30 + const __u8 tclass = DEFAULT_TOS_VALUE; 31 + struct dst_entry *dst = NULL; 32 + u8 proto; 33 + __be16 frag_off; 34 + struct flowi6 fl6; 35 + 36 + if ((!(ipv6_addr_type(&oip6h->saddr) & IPV6_ADDR_UNICAST)) || 37 + (!(ipv6_addr_type(&oip6h->daddr) & IPV6_ADDR_UNICAST))) { 38 + pr_debug("addr is not unicast.\n"); 39 + return; 40 + } 41 + 42 + proto = oip6h->nexthdr; 43 + tcphoff = ipv6_skip_exthdr(oldskb, ((u8*)(oip6h+1) - oldskb->data), &proto, &frag_off); 44 + 45 + if ((tcphoff < 0) || (tcphoff > oldskb->len)) { 46 + pr_debug("Cannot get TCP header.\n"); 47 + return; 48 + } 49 + 50 + otcplen = oldskb->len - tcphoff; 51 + 52 + /* IP header checks: fragment, too short. */ 53 + if (proto != IPPROTO_TCP || otcplen < sizeof(struct tcphdr)) { 54 + pr_debug("proto(%d) != IPPROTO_TCP, " 55 + "or too short. otcplen = %d\n", 56 + proto, otcplen); 57 + return; 58 + } 59 + 60 + if (skb_copy_bits(oldskb, tcphoff, &otcph, sizeof(struct tcphdr))) 61 + BUG(); 62 + 63 + /* No RST for RST. */ 64 + if (otcph.rst) { 65 + pr_debug("RST is set\n"); 66 + return; 67 + } 68 + 69 + /* Check checksum. */ 70 + if (nf_ip6_checksum(oldskb, hook, tcphoff, IPPROTO_TCP)) { 71 + pr_debug("TCP checksum is invalid\n"); 72 + return; 73 + } 74 + 75 + memset(&fl6, 0, sizeof(fl6)); 76 + fl6.flowi6_proto = IPPROTO_TCP; 77 + fl6.saddr = oip6h->daddr; 78 + fl6.daddr = oip6h->saddr; 79 + fl6.fl6_sport = otcph.dest; 80 + fl6.fl6_dport = otcph.source; 81 + security_skb_classify_flow(oldskb, flowi6_to_flowi(&fl6)); 82 + dst = ip6_route_output(net, NULL, &fl6); 83 + if (dst == NULL || dst->error) { 84 + dst_release(dst); 85 + return; 86 + } 87 + dst = xfrm_lookup(net, dst, flowi6_to_flowi(&fl6), NULL, 0); 88 + if (IS_ERR(dst)) 89 + return; 90 + 91 + hh_len = (dst->dev->hard_header_len + 15)&~15; 92 + nskb = alloc_skb(hh_len + 15 + dst->header_len + sizeof(struct ipv6hdr) 93 + + sizeof(struct tcphdr) + dst->trailer_len, 94 + GFP_ATOMIC); 95 + 96 + if (!nskb) { 97 + net_dbg_ratelimited("cannot alloc skb\n"); 98 + dst_release(dst); 99 + return; 100 + } 101 + 102 + skb_dst_set(nskb, dst); 103 + 104 + skb_reserve(nskb, hh_len + dst->header_len); 105 + 106 + skb_put(nskb, sizeof(struct ipv6hdr)); 107 + skb_reset_network_header(nskb); 108 + ip6h = ipv6_hdr(nskb); 109 + ip6_flow_hdr(ip6h, tclass, 0); 110 + ip6h->hop_limit = ip6_dst_hoplimit(dst); 111 + ip6h->nexthdr = IPPROTO_TCP; 112 + ip6h->saddr = oip6h->daddr; 113 + ip6h->daddr = oip6h->saddr; 114 + 115 + skb_reset_transport_header(nskb); 116 + tcph = (struct tcphdr *)skb_put(nskb, sizeof(struct tcphdr)); 117 + /* Truncate to length (no data) */ 118 + tcph->doff = sizeof(struct tcphdr)/4; 119 + tcph->source = otcph.dest; 120 + tcph->dest = otcph.source; 121 + 122 + if (otcph.ack) { 123 + needs_ack = 0; 124 + tcph->seq = otcph.ack_seq; 125 + tcph->ack_seq = 0; 126 + } else { 127 + needs_ack = 1; 128 + tcph->ack_seq = htonl(ntohl(otcph.seq) + otcph.syn + otcph.fin 129 + + otcplen - (otcph.doff<<2)); 130 + tcph->seq = 0; 131 + } 132 + 133 + /* Reset flags */ 134 + ((u_int8_t *)tcph)[13] = 0; 135 + tcph->rst = 1; 136 + tcph->ack = needs_ack; 137 + tcph->window = 0; 138 + tcph->urg_ptr = 0; 139 + tcph->check = 0; 140 + 141 + /* Adjust TCP checksum */ 142 + tcph->check = csum_ipv6_magic(&ipv6_hdr(nskb)->saddr, 143 + &ipv6_hdr(nskb)->daddr, 144 + sizeof(struct tcphdr), IPPROTO_TCP, 145 + csum_partial(tcph, 146 + sizeof(struct tcphdr), 0)); 147 + 148 + nf_ct_attach(nskb, oldskb); 149 + 150 + #ifdef CONFIG_BRIDGE_NETFILTER 151 + /* If we use ip6_local_out for bridged traffic, the MAC source on 152 + * the RST will be ours, instead of the destination's. This confuses 153 + * some routers/firewalls, and they drop the packet. So we need to 154 + * build the eth header using the original destination's MAC as the 155 + * source, and send the RST packet directly. 156 + */ 157 + if (oldskb->nf_bridge) { 158 + struct ethhdr *oeth = eth_hdr(oldskb); 159 + nskb->dev = oldskb->nf_bridge->physindev; 160 + nskb->protocol = htons(ETH_P_IPV6); 161 + ip6h->payload_len = htons(sizeof(struct tcphdr)); 162 + if (dev_hard_header(nskb, nskb->dev, ntohs(nskb->protocol), 163 + oeth->h_source, oeth->h_dest, nskb->len) < 0) 164 + return; 165 + dev_queue_xmit(nskb); 166 + } else 167 + #endif 168 + ip6_local_out(nskb); 169 + } 170 + 171 + #endif /* _IPV6_NF_REJECT_H */
+62
include/net/netfilter/nf_queue.h
··· 1 1 #ifndef _NF_QUEUE_H 2 2 #define _NF_QUEUE_H 3 3 4 + #include <linux/ip.h> 5 + #include <linux/ipv6.h> 6 + #include <linux/jhash.h> 7 + 4 8 /* Each queued (to userspace) skbuff has one of these. */ 5 9 struct nf_queue_entry { 6 10 struct list_head list; ··· 36 32 37 33 bool nf_queue_entry_get_refs(struct nf_queue_entry *entry); 38 34 void nf_queue_entry_release_refs(struct nf_queue_entry *entry); 35 + 36 + static inline void init_hashrandom(u32 *jhash_initval) 37 + { 38 + while (*jhash_initval == 0) 39 + *jhash_initval = prandom_u32(); 40 + } 41 + 42 + static inline u32 hash_v4(const struct sk_buff *skb, u32 jhash_initval) 43 + { 44 + const struct iphdr *iph = ip_hdr(skb); 45 + 46 + /* packets in either direction go into same queue */ 47 + if ((__force u32)iph->saddr < (__force u32)iph->daddr) 48 + return jhash_3words((__force u32)iph->saddr, 49 + (__force u32)iph->daddr, iph->protocol, jhash_initval); 50 + 51 + return jhash_3words((__force u32)iph->daddr, 52 + (__force u32)iph->saddr, iph->protocol, jhash_initval); 53 + } 54 + 55 + #if IS_ENABLED(CONFIG_IP6_NF_IPTABLES) 56 + static inline u32 hash_v6(const struct sk_buff *skb, u32 jhash_initval) 57 + { 58 + const struct ipv6hdr *ip6h = ipv6_hdr(skb); 59 + u32 a, b, c; 60 + 61 + if ((__force u32)ip6h->saddr.s6_addr32[3] < 62 + (__force u32)ip6h->daddr.s6_addr32[3]) { 63 + a = (__force u32) ip6h->saddr.s6_addr32[3]; 64 + b = (__force u32) ip6h->daddr.s6_addr32[3]; 65 + } else { 66 + b = (__force u32) ip6h->saddr.s6_addr32[3]; 67 + a = (__force u32) ip6h->daddr.s6_addr32[3]; 68 + } 69 + 70 + if ((__force u32)ip6h->saddr.s6_addr32[1] < 71 + (__force u32)ip6h->daddr.s6_addr32[1]) 72 + c = (__force u32) ip6h->saddr.s6_addr32[1]; 73 + else 74 + c = (__force u32) ip6h->daddr.s6_addr32[1]; 75 + 76 + return jhash_3words(a, b, c, jhash_initval); 77 + } 78 + #endif 79 + 80 + static inline u32 81 + nfqueue_hash(const struct sk_buff *skb, u16 queue, u16 queues_total, u8 family, 82 + u32 jhash_initval) 83 + { 84 + if (family == NFPROTO_IPV4) 85 + queue += ((u64) hash_v4(skb, jhash_initval) * queues_total) >> 32; 86 + #if IS_ENABLED(CONFIG_IP6_NF_IPTABLES) 87 + else if (family == NFPROTO_IPV6) 88 + queue += ((u64) hash_v6(skb, jhash_initval) * queues_total) >> 32; 89 + #endif 90 + 91 + return queue; 92 + } 39 93 40 94 #endif /* _NF_QUEUE_H */
+24
include/uapi/linux/netfilter/nf_tables.h
··· 110 110 * 111 111 * @NFTA_TABLE_NAME: name of the table (NLA_STRING) 112 112 * @NFTA_TABLE_FLAGS: bitmask of enum nft_table_flags (NLA_U32) 113 + * @NFTA_TABLE_USE: number of chains in this table (NLA_U32) 113 114 */ 114 115 enum nft_table_attributes { 115 116 NFTA_TABLE_UNSPEC, 116 117 NFTA_TABLE_NAME, 117 118 NFTA_TABLE_FLAGS, 119 + NFTA_TABLE_USE, 118 120 __NFTA_TABLE_MAX 119 121 }; 120 122 #define NFTA_TABLE_MAX (__NFTA_TABLE_MAX - 1) ··· 555 553 * 556 554 * @NFTA_META_DREG: destination register (NLA_U32) 557 555 * @NFTA_META_KEY: meta data item to load (NLA_U32: nft_meta_keys) 556 + * @NFTA_META_SREG: source register (NLA_U32) 558 557 */ 559 558 enum nft_meta_attributes { 560 559 NFTA_META_UNSPEC, 561 560 NFTA_META_DREG, 562 561 NFTA_META_KEY, 562 + NFTA_META_SREG, 563 563 __NFTA_META_MAX 564 564 }; 565 565 #define NFTA_META_MAX (__NFTA_META_MAX - 1) ··· 660 656 __NFTA_LOG_MAX 661 657 }; 662 658 #define NFTA_LOG_MAX (__NFTA_LOG_MAX - 1) 659 + 660 + /** 661 + * enum nft_queue_attributes - nf_tables queue expression netlink attributes 662 + * 663 + * @NFTA_QUEUE_NUM: netlink queue to send messages to (NLA_U16) 664 + * @NFTA_QUEUE_TOTAL: number of queues to load balance packets on (NLA_U16) 665 + * @NFTA_QUEUE_FLAGS: various flags (NLA_U16) 666 + */ 667 + enum nft_queue_attributes { 668 + NFTA_QUEUE_UNSPEC, 669 + NFTA_QUEUE_NUM, 670 + NFTA_QUEUE_TOTAL, 671 + NFTA_QUEUE_FLAGS, 672 + __NFTA_QUEUE_MAX 673 + }; 674 + #define NFTA_QUEUE_MAX (__NFTA_QUEUE_MAX - 1) 675 + 676 + #define NFT_QUEUE_FLAG_BYPASS 0x01 /* for compatibility with v2 */ 677 + #define NFT_QUEUE_FLAG_CPU_FANOUT 0x02 /* use current CPU (no hashing) */ 678 + #define NFT_QUEUE_FLAG_MASK 0x03 663 679 664 680 /** 665 681 * enum nft_reject_types - nf_tables reject expression reject types
+14 -4
net/ipv4/netfilter/Kconfig
··· 39 39 config NF_TABLES_IPV4 40 40 depends on NF_TABLES 41 41 tristate "IPv4 nf_tables support" 42 - 43 - config NFT_REJECT_IPV4 44 - depends on NF_TABLES_IPV4 45 - tristate "nf_tables IPv4 reject support" 42 + help 43 + This option enables the IPv4 support for nf_tables. 46 44 47 45 config NFT_CHAIN_ROUTE_IPV4 48 46 depends on NF_TABLES_IPV4 49 47 tristate "IPv4 nf_tables route chain support" 48 + help 49 + This option enables the "route" chain for IPv4 in nf_tables. This 50 + chain type is used to force packet re-routing after mangling header 51 + fields such as the source, destination, type of service and 52 + the packet mark. 50 53 51 54 config NFT_CHAIN_NAT_IPV4 52 55 depends on NF_TABLES_IPV4 53 56 depends on NF_NAT_IPV4 && NFT_NAT 54 57 tristate "IPv4 nf_tables nat chain support" 58 + help 59 + This option enables the "nat" chain for IPv4 in nf_tables. This 60 + chain type is used to perform Network Address Translation (NAT) 61 + packet transformations such as the source, destination address and 62 + source and destination ports. 55 63 56 64 config NF_TABLES_ARP 57 65 depends on NF_TABLES 58 66 tristate "ARP nf_tables support" 67 + help 68 + This option enables the ARP support for nf_tables. 59 69 60 70 config IP_NF_IPTABLES 61 71 tristate "IP tables support (required for filtering/masq/NAT)"
-1
net/ipv4/netfilter/Makefile
··· 28 28 obj-$(CONFIG_NF_NAT_PROTO_GRE) += nf_nat_proto_gre.o 29 29 30 30 obj-$(CONFIG_NF_TABLES_IPV4) += nf_tables_ipv4.o 31 - obj-$(CONFIG_NFT_REJECT_IPV4) += nft_reject_ipv4.o 32 31 obj-$(CONFIG_NFT_CHAIN_ROUTE_IPV4) += nft_chain_route_ipv4.o 33 32 obj-$(CONFIG_NFT_CHAIN_NAT_IPV4) += nft_chain_nat_ipv4.o 34 33 obj-$(CONFIG_NF_TABLES_ARP) += nf_tables_arp.o
+10 -130
net/ipv4/netfilter/ipt_REJECT.c
··· 17 17 #include <linux/udp.h> 18 18 #include <linux/icmp.h> 19 19 #include <net/icmp.h> 20 - #include <net/ip.h> 21 - #include <net/tcp.h> 22 - #include <net/route.h> 23 - #include <net/dst.h> 24 20 #include <linux/netfilter/x_tables.h> 25 21 #include <linux/netfilter_ipv4/ip_tables.h> 26 22 #include <linux/netfilter_ipv4/ipt_REJECT.h> ··· 24 28 #include <linux/netfilter_bridge.h> 25 29 #endif 26 30 31 + #include <net/netfilter/ipv4/nf_reject.h> 32 + 27 33 MODULE_LICENSE("GPL"); 28 34 MODULE_AUTHOR("Netfilter Core Team <coreteam@netfilter.org>"); 29 35 MODULE_DESCRIPTION("Xtables: packet \"rejection\" target for IPv4"); 30 - 31 - /* Send RST reply */ 32 - static void send_reset(struct sk_buff *oldskb, int hook) 33 - { 34 - struct sk_buff *nskb; 35 - const struct iphdr *oiph; 36 - struct iphdr *niph; 37 - const struct tcphdr *oth; 38 - struct tcphdr _otcph, *tcph; 39 - 40 - /* IP header checks: fragment. */ 41 - if (ip_hdr(oldskb)->frag_off & htons(IP_OFFSET)) 42 - return; 43 - 44 - oth = skb_header_pointer(oldskb, ip_hdrlen(oldskb), 45 - sizeof(_otcph), &_otcph); 46 - if (oth == NULL) 47 - return; 48 - 49 - /* No RST for RST. */ 50 - if (oth->rst) 51 - return; 52 - 53 - if (skb_rtable(oldskb)->rt_flags & (RTCF_BROADCAST | RTCF_MULTICAST)) 54 - return; 55 - 56 - /* Check checksum */ 57 - if (nf_ip_checksum(oldskb, hook, ip_hdrlen(oldskb), IPPROTO_TCP)) 58 - return; 59 - oiph = ip_hdr(oldskb); 60 - 61 - nskb = alloc_skb(sizeof(struct iphdr) + sizeof(struct tcphdr) + 62 - LL_MAX_HEADER, GFP_ATOMIC); 63 - if (!nskb) 64 - return; 65 - 66 - skb_reserve(nskb, LL_MAX_HEADER); 67 - 68 - skb_reset_network_header(nskb); 69 - niph = (struct iphdr *)skb_put(nskb, sizeof(struct iphdr)); 70 - niph->version = 4; 71 - niph->ihl = sizeof(struct iphdr) / 4; 72 - niph->tos = 0; 73 - niph->id = 0; 74 - niph->frag_off = htons(IP_DF); 75 - niph->protocol = IPPROTO_TCP; 76 - niph->check = 0; 77 - niph->saddr = oiph->daddr; 78 - niph->daddr = oiph->saddr; 79 - 80 - skb_reset_transport_header(nskb); 81 - tcph = (struct tcphdr *)skb_put(nskb, sizeof(struct tcphdr)); 82 - memset(tcph, 0, sizeof(*tcph)); 83 - tcph->source = oth->dest; 84 - tcph->dest = oth->source; 85 - tcph->doff = sizeof(struct tcphdr) / 4; 86 - 87 - if (oth->ack) 88 - tcph->seq = oth->ack_seq; 89 - else { 90 - tcph->ack_seq = htonl(ntohl(oth->seq) + oth->syn + oth->fin + 91 - oldskb->len - ip_hdrlen(oldskb) - 92 - (oth->doff << 2)); 93 - tcph->ack = 1; 94 - } 95 - 96 - tcph->rst = 1; 97 - tcph->check = ~tcp_v4_check(sizeof(struct tcphdr), niph->saddr, 98 - niph->daddr, 0); 99 - nskb->ip_summed = CHECKSUM_PARTIAL; 100 - nskb->csum_start = (unsigned char *)tcph - nskb->head; 101 - nskb->csum_offset = offsetof(struct tcphdr, check); 102 - 103 - /* ip_route_me_harder expects skb->dst to be set */ 104 - skb_dst_set_noref(nskb, skb_dst(oldskb)); 105 - 106 - nskb->protocol = htons(ETH_P_IP); 107 - if (ip_route_me_harder(nskb, RTN_UNSPEC)) 108 - goto free_nskb; 109 - 110 - niph->ttl = ip4_dst_hoplimit(skb_dst(nskb)); 111 - 112 - /* "Never happens" */ 113 - if (nskb->len > dst_mtu(skb_dst(nskb))) 114 - goto free_nskb; 115 - 116 - nf_ct_attach(nskb, oldskb); 117 - 118 - #ifdef CONFIG_BRIDGE_NETFILTER 119 - /* If we use ip_local_out for bridged traffic, the MAC source on 120 - * the RST will be ours, instead of the destination's. This confuses 121 - * some routers/firewalls, and they drop the packet. So we need to 122 - * build the eth header using the original destination's MAC as the 123 - * source, and send the RST packet directly. 124 - */ 125 - if (oldskb->nf_bridge) { 126 - struct ethhdr *oeth = eth_hdr(oldskb); 127 - nskb->dev = oldskb->nf_bridge->physindev; 128 - niph->tot_len = htons(nskb->len); 129 - ip_send_check(niph); 130 - if (dev_hard_header(nskb, nskb->dev, ntohs(nskb->protocol), 131 - oeth->h_source, oeth->h_dest, nskb->len) < 0) 132 - goto free_nskb; 133 - dev_queue_xmit(nskb); 134 - } else 135 - #endif 136 - ip_local_out(nskb); 137 - 138 - return; 139 - 140 - free_nskb: 141 - kfree_skb(nskb); 142 - } 143 - 144 - static inline void send_unreach(struct sk_buff *skb_in, int code) 145 - { 146 - icmp_send(skb_in, ICMP_DEST_UNREACH, code, 0); 147 - } 148 36 149 37 static unsigned int 150 38 reject_tg(struct sk_buff *skb, const struct xt_action_param *par) ··· 37 157 38 158 switch (reject->with) { 39 159 case IPT_ICMP_NET_UNREACHABLE: 40 - send_unreach(skb, ICMP_NET_UNREACH); 160 + nf_send_unreach(skb, ICMP_NET_UNREACH); 41 161 break; 42 162 case IPT_ICMP_HOST_UNREACHABLE: 43 - send_unreach(skb, ICMP_HOST_UNREACH); 163 + nf_send_unreach(skb, ICMP_HOST_UNREACH); 44 164 break; 45 165 case IPT_ICMP_PROT_UNREACHABLE: 46 - send_unreach(skb, ICMP_PROT_UNREACH); 166 + nf_send_unreach(skb, ICMP_PROT_UNREACH); 47 167 break; 48 168 case IPT_ICMP_PORT_UNREACHABLE: 49 - send_unreach(skb, ICMP_PORT_UNREACH); 169 + nf_send_unreach(skb, ICMP_PORT_UNREACH); 50 170 break; 51 171 case IPT_ICMP_NET_PROHIBITED: 52 - send_unreach(skb, ICMP_NET_ANO); 172 + nf_send_unreach(skb, ICMP_NET_ANO); 53 173 break; 54 174 case IPT_ICMP_HOST_PROHIBITED: 55 - send_unreach(skb, ICMP_HOST_ANO); 175 + nf_send_unreach(skb, ICMP_HOST_ANO); 56 176 break; 57 177 case IPT_ICMP_ADMIN_PROHIBITED: 58 - send_unreach(skb, ICMP_PKT_FILTERED); 178 + nf_send_unreach(skb, ICMP_PKT_FILTERED); 59 179 break; 60 180 case IPT_TCP_RESET: 61 - send_reset(skb, par->hooknum); 181 + nf_send_reset(skb, par->hooknum); 62 182 case IPT_ICMP_ECHOREPLY: 63 183 /* Doesn't happen. */ 64 184 break;
+22 -1
net/ipv4/netfilter/nft_reject_ipv4.c net/netfilter/nft_reject.c
··· 1 1 /* 2 2 * Copyright (c) 2008-2009 Patrick McHardy <kaber@trash.net> 3 + * Copyright (c) 2013 Eric Leblond <eric@regit.org> 3 4 * 4 5 * This program is free software; you can redistribute it and/or modify 5 6 * it under the terms of the GNU General Public License version 2 as ··· 17 16 #include <linux/netfilter/nf_tables.h> 18 17 #include <net/netfilter/nf_tables.h> 19 18 #include <net/icmp.h> 19 + #include <net/netfilter/ipv4/nf_reject.h> 20 + 21 + #if IS_ENABLED(CONFIG_NF_TABLES_IPV6) 22 + #include <net/netfilter/ipv6/nf_reject.h> 23 + #endif 20 24 21 25 struct nft_reject { 22 26 enum nft_reject_types type:8; 23 27 u8 icmp_code; 28 + u8 family; 24 29 }; 25 30 26 31 static void nft_reject_eval(const struct nft_expr *expr, ··· 34 27 const struct nft_pktinfo *pkt) 35 28 { 36 29 struct nft_reject *priv = nft_expr_priv(expr); 30 + struct net *net = dev_net((pkt->in != NULL) ? pkt->in : pkt->out); 37 31 38 32 switch (priv->type) { 39 33 case NFT_REJECT_ICMP_UNREACH: 40 - icmp_send(pkt->skb, ICMP_DEST_UNREACH, priv->icmp_code, 0); 34 + if (priv->family == NFPROTO_IPV4) 35 + nf_send_unreach(pkt->skb, priv->icmp_code); 36 + #if IS_ENABLED(CONFIG_NF_TABLES_IPV6) 37 + else if (priv->family == NFPROTO_IPV6) 38 + nf_send_unreach6(net, pkt->skb, priv->icmp_code, 39 + pkt->hooknum); 40 + #endif 41 41 break; 42 42 case NFT_REJECT_TCP_RST: 43 + if (priv->family == NFPROTO_IPV4) 44 + nf_send_reset(pkt->skb, pkt->hooknum); 45 + #if IS_ENABLED(CONFIG_NF_TABLES_IPV6) 46 + else if (priv->family == NFPROTO_IPV6) 47 + nf_send_reset6(net, pkt->skb, pkt->hooknum); 48 + #endif 43 49 break; 44 50 } 45 51 ··· 73 53 if (tb[NFTA_REJECT_TYPE] == NULL) 74 54 return -EINVAL; 75 55 56 + priv->family = ctx->afi->family; 76 57 priv->type = ntohl(nla_get_be32(tb[NFTA_REJECT_TYPE])); 77 58 switch (priv->type) { 78 59 case NFT_REJECT_ICMP_UNREACH:
+12
net/ipv6/netfilter/Kconfig
··· 28 28 config NF_TABLES_IPV6 29 29 depends on NF_TABLES 30 30 tristate "IPv6 nf_tables support" 31 + help 32 + This option enables the IPv6 support for nf_tables. 31 33 32 34 config NFT_CHAIN_ROUTE_IPV6 33 35 depends on NF_TABLES_IPV6 34 36 tristate "IPv6 nf_tables route chain support" 37 + help 38 + This option enables the "route" chain for IPv6 in nf_tables. This 39 + chain type is used to force packet re-routing after mangling header 40 + fields such as the source, destination, flowlabel, hop-limit and 41 + the packet mark. 35 42 36 43 config NFT_CHAIN_NAT_IPV6 37 44 depends on NF_TABLES_IPV6 38 45 depends on NF_NAT_IPV6 && NFT_NAT 39 46 tristate "IPv6 nf_tables nat chain support" 47 + help 48 + This option enables the "nat" chain for IPv6 in nf_tables. This 49 + chain type is used to perform Network Address Translation (NAT) 50 + packet transformations such as the source, destination address and 51 + source and destination ports. 40 52 41 53 config IP6_NF_IPTABLES 42 54 tristate "IP6 tables support (required for filtering)"
+8 -171
net/ipv6/netfilter/ip6t_REJECT.c
··· 23 23 #include <linux/skbuff.h> 24 24 #include <linux/icmpv6.h> 25 25 #include <linux/netdevice.h> 26 - #include <net/ipv6.h> 27 - #include <net/tcp.h> 28 26 #include <net/icmp.h> 29 - #include <net/ip6_checksum.h> 30 - #include <net/ip6_fib.h> 31 - #include <net/ip6_route.h> 32 27 #include <net/flow.h> 33 28 #include <linux/netfilter/x_tables.h> 34 29 #include <linux/netfilter_ipv6/ip6_tables.h> 35 30 #include <linux/netfilter_ipv6/ip6t_REJECT.h> 36 31 32 + #include <net/netfilter/ipv6/nf_reject.h> 33 + 37 34 MODULE_AUTHOR("Yasuyuki KOZAKAI <yasuyuki.kozakai@toshiba.co.jp>"); 38 35 MODULE_DESCRIPTION("Xtables: packet \"rejection\" target for IPv6"); 39 36 MODULE_LICENSE("GPL"); 40 37 41 - /* Send RST reply */ 42 - static void send_reset(struct net *net, struct sk_buff *oldskb, int hook) 43 - { 44 - struct sk_buff *nskb; 45 - struct tcphdr otcph, *tcph; 46 - unsigned int otcplen, hh_len; 47 - int tcphoff, needs_ack; 48 - const struct ipv6hdr *oip6h = ipv6_hdr(oldskb); 49 - struct ipv6hdr *ip6h; 50 - #define DEFAULT_TOS_VALUE 0x0U 51 - const __u8 tclass = DEFAULT_TOS_VALUE; 52 - struct dst_entry *dst = NULL; 53 - u8 proto; 54 - __be16 frag_off; 55 - struct flowi6 fl6; 56 - 57 - if ((!(ipv6_addr_type(&oip6h->saddr) & IPV6_ADDR_UNICAST)) || 58 - (!(ipv6_addr_type(&oip6h->daddr) & IPV6_ADDR_UNICAST))) { 59 - pr_debug("addr is not unicast.\n"); 60 - return; 61 - } 62 - 63 - proto = oip6h->nexthdr; 64 - tcphoff = ipv6_skip_exthdr(oldskb, ((u8*)(oip6h+1) - oldskb->data), &proto, &frag_off); 65 - 66 - if ((tcphoff < 0) || (tcphoff > oldskb->len)) { 67 - pr_debug("Cannot get TCP header.\n"); 68 - return; 69 - } 70 - 71 - otcplen = oldskb->len - tcphoff; 72 - 73 - /* IP header checks: fragment, too short. */ 74 - if (proto != IPPROTO_TCP || otcplen < sizeof(struct tcphdr)) { 75 - pr_debug("proto(%d) != IPPROTO_TCP, " 76 - "or too short. otcplen = %d\n", 77 - proto, otcplen); 78 - return; 79 - } 80 - 81 - if (skb_copy_bits(oldskb, tcphoff, &otcph, sizeof(struct tcphdr))) 82 - BUG(); 83 - 84 - /* No RST for RST. */ 85 - if (otcph.rst) { 86 - pr_debug("RST is set\n"); 87 - return; 88 - } 89 - 90 - /* Check checksum. */ 91 - if (nf_ip6_checksum(oldskb, hook, tcphoff, IPPROTO_TCP)) { 92 - pr_debug("TCP checksum is invalid\n"); 93 - return; 94 - } 95 - 96 - memset(&fl6, 0, sizeof(fl6)); 97 - fl6.flowi6_proto = IPPROTO_TCP; 98 - fl6.saddr = oip6h->daddr; 99 - fl6.daddr = oip6h->saddr; 100 - fl6.fl6_sport = otcph.dest; 101 - fl6.fl6_dport = otcph.source; 102 - security_skb_classify_flow(oldskb, flowi6_to_flowi(&fl6)); 103 - dst = ip6_route_output(net, NULL, &fl6); 104 - if (dst == NULL || dst->error) { 105 - dst_release(dst); 106 - return; 107 - } 108 - dst = xfrm_lookup(net, dst, flowi6_to_flowi(&fl6), NULL, 0); 109 - if (IS_ERR(dst)) 110 - return; 111 - 112 - hh_len = (dst->dev->hard_header_len + 15)&~15; 113 - nskb = alloc_skb(hh_len + 15 + dst->header_len + sizeof(struct ipv6hdr) 114 - + sizeof(struct tcphdr) + dst->trailer_len, 115 - GFP_ATOMIC); 116 - 117 - if (!nskb) { 118 - net_dbg_ratelimited("cannot alloc skb\n"); 119 - dst_release(dst); 120 - return; 121 - } 122 - 123 - skb_dst_set(nskb, dst); 124 - 125 - skb_reserve(nskb, hh_len + dst->header_len); 126 - 127 - skb_put(nskb, sizeof(struct ipv6hdr)); 128 - skb_reset_network_header(nskb); 129 - ip6h = ipv6_hdr(nskb); 130 - ip6_flow_hdr(ip6h, tclass, 0); 131 - ip6h->hop_limit = ip6_dst_hoplimit(dst); 132 - ip6h->nexthdr = IPPROTO_TCP; 133 - ip6h->saddr = oip6h->daddr; 134 - ip6h->daddr = oip6h->saddr; 135 - 136 - skb_reset_transport_header(nskb); 137 - tcph = (struct tcphdr *)skb_put(nskb, sizeof(struct tcphdr)); 138 - /* Truncate to length (no data) */ 139 - tcph->doff = sizeof(struct tcphdr)/4; 140 - tcph->source = otcph.dest; 141 - tcph->dest = otcph.source; 142 - 143 - if (otcph.ack) { 144 - needs_ack = 0; 145 - tcph->seq = otcph.ack_seq; 146 - tcph->ack_seq = 0; 147 - } else { 148 - needs_ack = 1; 149 - tcph->ack_seq = htonl(ntohl(otcph.seq) + otcph.syn + otcph.fin 150 - + otcplen - (otcph.doff<<2)); 151 - tcph->seq = 0; 152 - } 153 - 154 - /* Reset flags */ 155 - ((u_int8_t *)tcph)[13] = 0; 156 - tcph->rst = 1; 157 - tcph->ack = needs_ack; 158 - tcph->window = 0; 159 - tcph->urg_ptr = 0; 160 - tcph->check = 0; 161 - 162 - /* Adjust TCP checksum */ 163 - tcph->check = csum_ipv6_magic(&ipv6_hdr(nskb)->saddr, 164 - &ipv6_hdr(nskb)->daddr, 165 - sizeof(struct tcphdr), IPPROTO_TCP, 166 - csum_partial(tcph, 167 - sizeof(struct tcphdr), 0)); 168 - 169 - nf_ct_attach(nskb, oldskb); 170 - 171 - #ifdef CONFIG_BRIDGE_NETFILTER 172 - /* If we use ip6_local_out for bridged traffic, the MAC source on 173 - * the RST will be ours, instead of the destination's. This confuses 174 - * some routers/firewalls, and they drop the packet. So we need to 175 - * build the eth header using the original destination's MAC as the 176 - * source, and send the RST packet directly. 177 - */ 178 - if (oldskb->nf_bridge) { 179 - struct ethhdr *oeth = eth_hdr(oldskb); 180 - nskb->dev = oldskb->nf_bridge->physindev; 181 - nskb->protocol = htons(ETH_P_IPV6); 182 - ip6h->payload_len = htons(sizeof(struct tcphdr)); 183 - if (dev_hard_header(nskb, nskb->dev, ntohs(nskb->protocol), 184 - oeth->h_source, oeth->h_dest, nskb->len) < 0) 185 - return; 186 - dev_queue_xmit(nskb); 187 - } else 188 - #endif 189 - ip6_local_out(nskb); 190 - } 191 - 192 - static inline void 193 - send_unreach(struct net *net, struct sk_buff *skb_in, unsigned char code, 194 - unsigned int hooknum) 195 - { 196 - if (hooknum == NF_INET_LOCAL_OUT && skb_in->dev == NULL) 197 - skb_in->dev = net->loopback_dev; 198 - 199 - icmpv6_send(skb_in, ICMPV6_DEST_UNREACH, code, 0); 200 - } 201 38 202 39 static unsigned int 203 40 reject_tg6(struct sk_buff *skb, const struct xt_action_param *par) ··· 45 208 pr_debug("%s: medium point\n", __func__); 46 209 switch (reject->with) { 47 210 case IP6T_ICMP6_NO_ROUTE: 48 - send_unreach(net, skb, ICMPV6_NOROUTE, par->hooknum); 211 + nf_send_unreach6(net, skb, ICMPV6_NOROUTE, par->hooknum); 49 212 break; 50 213 case IP6T_ICMP6_ADM_PROHIBITED: 51 - send_unreach(net, skb, ICMPV6_ADM_PROHIBITED, par->hooknum); 214 + nf_send_unreach6(net, skb, ICMPV6_ADM_PROHIBITED, par->hooknum); 52 215 break; 53 216 case IP6T_ICMP6_NOT_NEIGHBOUR: 54 - send_unreach(net, skb, ICMPV6_NOT_NEIGHBOUR, par->hooknum); 217 + nf_send_unreach6(net, skb, ICMPV6_NOT_NEIGHBOUR, par->hooknum); 55 218 break; 56 219 case IP6T_ICMP6_ADDR_UNREACH: 57 - send_unreach(net, skb, ICMPV6_ADDR_UNREACH, par->hooknum); 220 + nf_send_unreach6(net, skb, ICMPV6_ADDR_UNREACH, par->hooknum); 58 221 break; 59 222 case IP6T_ICMP6_PORT_UNREACH: 60 - send_unreach(net, skb, ICMPV6_PORT_UNREACH, par->hooknum); 223 + nf_send_unreach6(net, skb, ICMPV6_PORT_UNREACH, par->hooknum); 61 224 break; 62 225 case IP6T_ICMP6_ECHOREPLY: 63 226 /* Do nothing */ 64 227 break; 65 228 case IP6T_TCP_RESET: 66 - send_reset(net, skb, par->hooknum); 229 + nf_send_reset6(net, skb, par->hooknum); 67 230 break; 68 231 default: 69 232 net_info_ratelimited("case %u not handled yet\n", reject->with);
+58 -1
net/netfilter/Kconfig
··· 414 414 endif # NF_CONNTRACK 415 415 416 416 config NF_TABLES 417 - depends on NETFILTER_NETLINK 417 + select NETFILTER_NETLINK 418 418 tristate "Netfilter nf_tables support" 419 + help 420 + nftables is the new packet classification framework that intends to 421 + replace the existing {ip,ip6,arp,eb}_tables infrastructure. It 422 + provides a pseudo-state machine with an extensible instruction-set 423 + (also known as expressions) that the userspace 'nft' utility 424 + (http://www.netfilter.org/projects/nftables) uses to build the 425 + rule-set. It also comes with the generic set infrastructure that 426 + allows you to construct mappings between matchings and actions 427 + for performance lookups. 428 + 429 + To compile it as a module, choose M here. 419 430 420 431 config NFT_EXTHDR 421 432 depends on NF_TABLES 422 433 tristate "Netfilter nf_tables IPv6 exthdr module" 434 + help 435 + This option adds the "exthdr" expression that you can use to match 436 + IPv6 extension headers. 423 437 424 438 config NFT_META 425 439 depends on NF_TABLES 426 440 tristate "Netfilter nf_tables meta module" 441 + help 442 + This option adds the "meta" expression that you can use to match and 443 + to set packet metainformation such as the packet mark. 427 444 428 445 config NFT_CT 429 446 depends on NF_TABLES 430 447 depends on NF_CONNTRACK 431 448 tristate "Netfilter nf_tables conntrack module" 449 + help 450 + This option adds the "meta" expression that you can use to match 451 + connection tracking information such as the flow state. 432 452 433 453 config NFT_RBTREE 434 454 depends on NF_TABLES 435 455 tristate "Netfilter nf_tables rbtree set module" 456 + help 457 + This option adds the "rbtree" set type (Red Black tree) that is used 458 + to build interval-based sets. 436 459 437 460 config NFT_HASH 438 461 depends on NF_TABLES 439 462 tristate "Netfilter nf_tables hash set module" 463 + help 464 + This option adds the "hash" set type that is used to build one-way 465 + mappings between matchings and actions. 440 466 441 467 config NFT_COUNTER 442 468 depends on NF_TABLES 443 469 tristate "Netfilter nf_tables counter module" 470 + help 471 + This option adds the "counter" expression that you can use to 472 + include packet and byte counters in a rule. 444 473 445 474 config NFT_LOG 446 475 depends on NF_TABLES 447 476 tristate "Netfilter nf_tables log module" 477 + help 478 + This option adds the "log" expression that you can use to log 479 + packets matching some criteria. 448 480 449 481 config NFT_LIMIT 450 482 depends on NF_TABLES 451 483 tristate "Netfilter nf_tables limit module" 484 + help 485 + This option adds the "limit" expression that you can use to 486 + ratelimit rule matchings. 452 487 453 488 config NFT_NAT 454 489 depends on NF_TABLES 455 490 depends on NF_CONNTRACK 456 491 depends on NF_NAT 457 492 tristate "Netfilter nf_tables nat module" 493 + help 494 + This option adds the "nat" expression that you can use to perform 495 + typical Network Address Translation (NAT) packet transformations. 496 + 497 + config NFT_QUEUE 498 + depends on NF_TABLES 499 + depends on NETFILTER_XTABLES 500 + depends on NETFILTER_NETLINK_QUEUE 501 + tristate "Netfilter nf_tables queue module" 502 + help 503 + This is required if you intend to use the userspace queueing 504 + infrastructure (also known as NFQUEUE) from nftables. 505 + 506 + config NFT_REJECT 507 + depends on NF_TABLES 508 + depends on NF_TABLES_IPV6 || !NF_TABLES_IPV6 509 + default m if NETFILTER_ADVANCED=n 510 + tristate "Netfilter nf_tables reject support" 511 + help 512 + This option adds the "reject" expression that you can use to 513 + explicitly deny and notify via TCP reset/ICMP informational errors 514 + unallowed traffic. 458 515 459 516 config NFT_COMPAT 460 517 depends on NF_TABLES
+2 -1
net/netfilter/Makefile
··· 76 76 obj-$(CONFIG_NFT_CT) += nft_ct.o 77 77 obj-$(CONFIG_NFT_LIMIT) += nft_limit.o 78 78 obj-$(CONFIG_NFT_NAT) += nft_nat.o 79 - #nf_tables-objs += nft_meta_target.o 79 + obj-$(CONFIG_NFT_QUEUE) += nft_queue.o 80 + obj-$(CONFIG_NFT_REJECT) += nft_reject.o 80 81 obj-$(CONFIG_NFT_RBTREE) += nft_rbtree.o 81 82 obj-$(CONFIG_NFT_HASH) += nft_hash.o 82 83 obj-$(CONFIG_NFT_COUNTER) += nft_counter.o
+88 -16
net/netfilter/nf_tables_api.c
··· 180 180 nfmsg->res_id = 0; 181 181 182 182 if (nla_put_string(skb, NFTA_TABLE_NAME, table->name) || 183 - nla_put_be32(skb, NFTA_TABLE_FLAGS, htonl(table->flags))) 183 + nla_put_be32(skb, NFTA_TABLE_FLAGS, htonl(table->flags)) || 184 + nla_put_be32(skb, NFTA_TABLE_USE, htonl(table->use))) 184 185 goto nla_put_failure; 185 186 186 187 return nlmsg_end(skb, nlh); ··· 1924 1923 { 1925 1924 struct net *net = sock_net(skb->sk); 1926 1925 const struct nfgenmsg *nfmsg = nlmsg_data(nlh); 1927 - const struct nft_af_info *afi; 1926 + const struct nft_af_info *afi = NULL; 1928 1927 const struct nft_table *table = NULL; 1929 1928 1930 - afi = nf_tables_afinfo_lookup(net, nfmsg->nfgen_family, false); 1931 - if (IS_ERR(afi)) 1932 - return PTR_ERR(afi); 1929 + if (nfmsg->nfgen_family != NFPROTO_UNSPEC) { 1930 + afi = nf_tables_afinfo_lookup(net, nfmsg->nfgen_family, false); 1931 + if (IS_ERR(afi)) 1932 + return PTR_ERR(afi); 1933 + } 1933 1934 1934 1935 if (nla[NFTA_SET_TABLE] != NULL) { 1935 1936 table = nf_tables_table_lookup(afi, nla[NFTA_SET_TABLE]); ··· 1976 1973 return -ENOMEM; 1977 1974 1978 1975 list_for_each_entry(i, &ctx->table->sets, list) { 1979 - if (!sscanf(i->name, name, &n)) 1976 + int tmp; 1977 + 1978 + if (!sscanf(i->name, name, &tmp)) 1980 1979 continue; 1981 - if (n < 0 || n > BITS_PER_LONG * PAGE_SIZE) 1980 + if (tmp < 0 || tmp > BITS_PER_LONG * PAGE_SIZE) 1982 1981 continue; 1983 - set_bit(n, inuse); 1982 + 1983 + set_bit(tmp, inuse); 1984 1984 } 1985 1985 1986 1986 n = find_first_zero_bit(inuse, BITS_PER_LONG * PAGE_SIZE); ··· 2100 2094 return skb->len; 2101 2095 } 2102 2096 2103 - static int nf_tables_dump_sets_all(struct nft_ctx *ctx, struct sk_buff *skb, 2104 - struct netlink_callback *cb) 2097 + static int nf_tables_dump_sets_family(struct nft_ctx *ctx, struct sk_buff *skb, 2098 + struct netlink_callback *cb) 2105 2099 { 2106 2100 const struct nft_set *set; 2107 2101 unsigned int idx = 0, s_idx = cb->args[0]; ··· 2133 2127 return skb->len; 2134 2128 } 2135 2129 2130 + static int nf_tables_dump_sets_all(struct nft_ctx *ctx, struct sk_buff *skb, 2131 + struct netlink_callback *cb) 2132 + { 2133 + const struct nft_set *set; 2134 + unsigned int idx, s_idx = cb->args[0]; 2135 + const struct nft_af_info *afi; 2136 + struct nft_table *table, *cur_table = (struct nft_table *)cb->args[2]; 2137 + struct net *net = sock_net(skb->sk); 2138 + int cur_family = cb->args[3]; 2139 + 2140 + if (cb->args[1]) 2141 + return skb->len; 2142 + 2143 + list_for_each_entry(afi, &net->nft.af_info, list) { 2144 + if (cur_family) { 2145 + if (afi->family != cur_family) 2146 + continue; 2147 + 2148 + cur_family = 0; 2149 + } 2150 + 2151 + list_for_each_entry(table, &afi->tables, list) { 2152 + if (cur_table) { 2153 + if (cur_table != table) 2154 + continue; 2155 + 2156 + cur_table = NULL; 2157 + } 2158 + 2159 + ctx->table = table; 2160 + ctx->afi = afi; 2161 + idx = 0; 2162 + list_for_each_entry(set, &ctx->table->sets, list) { 2163 + if (idx < s_idx) 2164 + goto cont; 2165 + if (nf_tables_fill_set(skb, ctx, set, 2166 + NFT_MSG_NEWSET, 2167 + NLM_F_MULTI) < 0) { 2168 + cb->args[0] = idx; 2169 + cb->args[2] = (unsigned long) table; 2170 + cb->args[3] = afi->family; 2171 + goto done; 2172 + } 2173 + cont: 2174 + idx++; 2175 + } 2176 + if (s_idx) 2177 + s_idx = 0; 2178 + } 2179 + } 2180 + cb->args[1] = 1; 2181 + done: 2182 + return skb->len; 2183 + } 2184 + 2136 2185 static int nf_tables_dump_sets(struct sk_buff *skb, struct netlink_callback *cb) 2137 2186 { 2138 2187 const struct nfgenmsg *nfmsg = nlmsg_data(cb->nlh); ··· 2204 2143 if (err < 0) 2205 2144 return err; 2206 2145 2207 - if (ctx.table == NULL) 2208 - ret = nf_tables_dump_sets_all(&ctx, skb, cb); 2209 - else 2146 + if (ctx.table == NULL) { 2147 + if (ctx.afi == NULL) 2148 + ret = nf_tables_dump_sets_all(&ctx, skb, cb); 2149 + else 2150 + ret = nf_tables_dump_sets_family(&ctx, skb, cb); 2151 + } else 2210 2152 ret = nf_tables_dump_sets_table(&ctx, skb, cb); 2211 2153 2212 2154 return ret; ··· 2222 2158 const struct nft_set *set; 2223 2159 struct nft_ctx ctx; 2224 2160 struct sk_buff *skb2; 2161 + const struct nfgenmsg *nfmsg = nlmsg_data(nlh); 2225 2162 int err; 2226 2163 2227 2164 /* Verify existance before starting dump */ ··· 2236 2171 }; 2237 2172 return netlink_dump_start(nlsk, skb, nlh, &c); 2238 2173 } 2174 + 2175 + /* Only accept unspec with dump */ 2176 + if (nfmsg->nfgen_family == NFPROTO_UNSPEC) 2177 + return -EAFNOSUPPORT; 2239 2178 2240 2179 set = nf_tables_set_lookup(ctx.table, nla[NFTA_SET_NAME]); 2241 2180 if (IS_ERR(set)) ··· 2410 2341 const struct nlmsghdr *nlh, 2411 2342 const struct nlattr * const nla[]) 2412 2343 { 2344 + const struct nfgenmsg *nfmsg = nlmsg_data(nlh); 2413 2345 struct nft_set *set; 2414 2346 struct nft_ctx ctx; 2415 2347 int err; ··· 2421 2351 err = nft_ctx_init_from_setattr(&ctx, skb, nlh, nla); 2422 2352 if (err < 0) 2423 2353 return err; 2354 + 2355 + if (nfmsg->nfgen_family == NFPROTO_UNSPEC) 2356 + return -EAFNOSUPPORT; 2424 2357 2425 2358 set = nf_tables_set_lookup(ctx.table, nla[NFTA_SET_NAME]); 2426 2359 if (IS_ERR(set)) ··· 2594 2521 u32 portid, seq; 2595 2522 int event, err; 2596 2523 2597 - nfmsg = nlmsg_data(cb->nlh); 2598 - err = nlmsg_parse(cb->nlh, sizeof(*nfmsg), nla, NFTA_SET_ELEM_LIST_MAX, 2599 - nft_set_elem_list_policy); 2524 + err = nlmsg_parse(cb->nlh, sizeof(struct nfgenmsg), nla, 2525 + NFTA_SET_ELEM_LIST_MAX, nft_set_elem_list_policy); 2600 2526 if (err < 0) 2601 2527 return err; 2602 2528
+4 -1
net/netfilter/nf_tables_core.c
··· 164 164 break; 165 165 } 166 166 167 - switch (data[NFT_REG_VERDICT].verdict) { 167 + switch (data[NFT_REG_VERDICT].verdict & NF_VERDICT_MASK) { 168 168 case NF_ACCEPT: 169 169 case NF_DROP: 170 170 case NF_QUEUE: ··· 172 172 nft_trace_packet(pkt, chain, rulenum, NFT_TRACE_RULE); 173 173 174 174 return data[NFT_REG_VERDICT].verdict; 175 + } 176 + 177 + switch (data[NFT_REG_VERDICT].verdict) { 175 178 case NFT_JUMP: 176 179 if (unlikely(pkt->skb->nf_trace)) 177 180 nft_trace_packet(pkt, chain, rulenum, NFT_TRACE_RULE);
+127 -27
net/netfilter/nft_meta.c
··· 21 21 22 22 struct nft_meta { 23 23 enum nft_meta_keys key:8; 24 - enum nft_registers dreg:8; 24 + union { 25 + enum nft_registers dreg:8; 26 + enum nft_registers sreg:8; 27 + }; 25 28 }; 26 29 27 - static void nft_meta_eval(const struct nft_expr *expr, 28 - struct nft_data data[NFT_REG_MAX + 1], 29 - const struct nft_pktinfo *pkt) 30 + static void nft_meta_get_eval(const struct nft_expr *expr, 31 + struct nft_data data[NFT_REG_MAX + 1], 32 + const struct nft_pktinfo *pkt) 30 33 { 31 34 const struct nft_meta *priv = nft_expr_priv(expr); 32 35 const struct sk_buff *skb = pkt->skb; ··· 135 132 data[NFT_REG_VERDICT].verdict = NFT_BREAK; 136 133 } 137 134 135 + static void nft_meta_set_eval(const struct nft_expr *expr, 136 + struct nft_data data[NFT_REG_MAX + 1], 137 + const struct nft_pktinfo *pkt) 138 + { 139 + const struct nft_meta *meta = nft_expr_priv(expr); 140 + struct sk_buff *skb = pkt->skb; 141 + u32 value = data[meta->sreg].data[0]; 142 + 143 + switch (meta->key) { 144 + case NFT_META_MARK: 145 + skb->mark = value; 146 + break; 147 + case NFT_META_PRIORITY: 148 + skb->priority = value; 149 + break; 150 + case NFT_META_NFTRACE: 151 + skb->nf_trace = 1; 152 + break; 153 + default: 154 + WARN_ON(1); 155 + } 156 + } 157 + 138 158 static const struct nla_policy nft_meta_policy[NFTA_META_MAX + 1] = { 139 159 [NFTA_META_DREG] = { .type = NLA_U32 }, 140 160 [NFTA_META_KEY] = { .type = NLA_U32 }, 161 + [NFTA_META_SREG] = { .type = NLA_U32 }, 141 162 }; 142 163 143 - static int nft_meta_init(const struct nft_ctx *ctx, const struct nft_expr *expr, 144 - const struct nlattr * const tb[]) 164 + static int nft_meta_init_validate_set(uint32_t key) 145 165 { 146 - struct nft_meta *priv = nft_expr_priv(expr); 147 - int err; 166 + switch (key) { 167 + case NFT_META_MARK: 168 + case NFT_META_PRIORITY: 169 + case NFT_META_NFTRACE: 170 + return 0; 171 + default: 172 + return -EOPNOTSUPP; 173 + } 174 + } 148 175 149 - if (tb[NFTA_META_DREG] == NULL || 150 - tb[NFTA_META_KEY] == NULL) 151 - return -EINVAL; 152 - 153 - priv->key = ntohl(nla_get_be32(tb[NFTA_META_KEY])); 154 - switch (priv->key) { 176 + static int nft_meta_init_validate_get(uint32_t key) 177 + { 178 + switch (key) { 155 179 case NFT_META_LEN: 156 180 case NFT_META_PROTOCOL: 157 181 case NFT_META_PRIORITY: ··· 197 167 #ifdef CONFIG_NETWORK_SECMARK 198 168 case NFT_META_SECMARK: 199 169 #endif 200 - break; 170 + return 0; 201 171 default: 202 172 return -EOPNOTSUPP; 203 173 } 204 174 205 - priv->dreg = ntohl(nla_get_be32(tb[NFTA_META_DREG])); 206 - err = nft_validate_output_register(priv->dreg); 207 - if (err < 0) 208 - return err; 209 - return nft_validate_data_load(ctx, priv->dreg, NULL, NFT_DATA_VALUE); 210 175 } 211 176 212 - static int nft_meta_dump(struct sk_buff *skb, const struct nft_expr *expr) 177 + static int nft_meta_init(const struct nft_ctx *ctx, const struct nft_expr *expr, 178 + const struct nlattr * const tb[]) 179 + { 180 + struct nft_meta *priv = nft_expr_priv(expr); 181 + int err; 182 + 183 + priv->key = ntohl(nla_get_be32(tb[NFTA_META_KEY])); 184 + 185 + if (tb[NFTA_META_DREG]) { 186 + err = nft_meta_init_validate_get(priv->key); 187 + if (err < 0) 188 + return err; 189 + 190 + priv->dreg = ntohl(nla_get_be32(tb[NFTA_META_DREG])); 191 + err = nft_validate_output_register(priv->dreg); 192 + if (err < 0) 193 + return err; 194 + 195 + return nft_validate_data_load(ctx, priv->dreg, NULL, 196 + NFT_DATA_VALUE); 197 + } 198 + 199 + err = nft_meta_init_validate_set(priv->key); 200 + if (err < 0) 201 + return err; 202 + 203 + priv->sreg = ntohl(nla_get_be32(tb[NFTA_META_SREG])); 204 + 205 + return 0; 206 + } 207 + 208 + static int nft_meta_get_dump(struct sk_buff *skb, 209 + const struct nft_expr *expr) 213 210 { 214 211 const struct nft_meta *priv = nft_expr_priv(expr); 215 212 216 - if (nla_put_be32(skb, NFTA_META_DREG, htonl(priv->dreg))) 217 - goto nla_put_failure; 218 213 if (nla_put_be32(skb, NFTA_META_KEY, htonl(priv->key))) 214 + goto nla_put_failure; 215 + if (nla_put_be32(skb, NFTA_META_DREG, htonl(priv->dreg))) 219 216 goto nla_put_failure; 220 217 return 0; 221 218 ··· 250 193 return -1; 251 194 } 252 195 196 + static int nft_meta_set_dump(struct sk_buff *skb, 197 + const struct nft_expr *expr) 198 + { 199 + const struct nft_meta *priv = nft_expr_priv(expr); 200 + 201 + if (nla_put_be32(skb, NFTA_META_KEY, htonl(priv->key))) 202 + goto nla_put_failure; 203 + if (nla_put_be32(skb, NFTA_META_SREG, htonl(priv->sreg))) 204 + goto nla_put_failure; 205 + 206 + return 0; 207 + 208 + nla_put_failure: 209 + return -1; 210 + } 211 + 253 212 static struct nft_expr_type nft_meta_type; 254 - static const struct nft_expr_ops nft_meta_ops = { 213 + static const struct nft_expr_ops nft_meta_get_ops = { 255 214 .type = &nft_meta_type, 256 215 .size = NFT_EXPR_SIZE(sizeof(struct nft_meta)), 257 - .eval = nft_meta_eval, 216 + .eval = nft_meta_get_eval, 258 217 .init = nft_meta_init, 259 - .dump = nft_meta_dump, 218 + .dump = nft_meta_get_dump, 260 219 }; 220 + 221 + static const struct nft_expr_ops nft_meta_set_ops = { 222 + .type = &nft_meta_type, 223 + .size = NFT_EXPR_SIZE(sizeof(struct nft_meta)), 224 + .eval = nft_meta_set_eval, 225 + .init = nft_meta_init, 226 + .dump = nft_meta_set_dump, 227 + }; 228 + 229 + static const struct nft_expr_ops * 230 + nft_meta_select_ops(const struct nft_ctx *ctx, 231 + const struct nlattr * const tb[]) 232 + { 233 + if (tb[NFTA_META_KEY] == NULL) 234 + return ERR_PTR(-EINVAL); 235 + 236 + if (tb[NFTA_META_DREG] && tb[NFTA_META_SREG]) 237 + return ERR_PTR(-EINVAL); 238 + 239 + if (tb[NFTA_META_DREG]) 240 + return &nft_meta_get_ops; 241 + 242 + if (tb[NFTA_META_SREG]) 243 + return &nft_meta_set_ops; 244 + 245 + return ERR_PTR(-EINVAL); 246 + } 261 247 262 248 static struct nft_expr_type nft_meta_type __read_mostly = { 263 249 .name = "meta", 264 - .ops = &nft_meta_ops, 250 + .select_ops = &nft_meta_select_ops, 265 251 .policy = nft_meta_policy, 266 252 .maxattr = NFTA_META_MAX, 267 253 .owner = THIS_MODULE,
-117
net/netfilter/nft_meta_target.c
··· 1 - /* 2 - * Copyright (c) 2008 Patrick McHardy <kaber@trash.net> 3 - * 4 - * This program is free software; you can redistribute it and/or modify 5 - * it under the terms of the GNU General Public License version 2 as 6 - * published by the Free Software Foundation. 7 - * 8 - * Development of this code funded by Astaro AG (http://www.astaro.com/) 9 - */ 10 - 11 - #include <linux/kernel.h> 12 - #include <linux/init.h> 13 - #include <linux/list.h> 14 - #include <linux/rbtree.h> 15 - #include <linux/netlink.h> 16 - #include <linux/netfilter.h> 17 - #include <linux/netfilter/nf_tables.h> 18 - #include <net/netfilter/nf_tables.h> 19 - 20 - struct nft_meta { 21 - enum nft_meta_keys key; 22 - }; 23 - 24 - static void nft_meta_eval(const struct nft_expr *expr, 25 - struct nft_data *nfres, 26 - struct nft_data *data, 27 - const struct nft_pktinfo *pkt) 28 - { 29 - const struct nft_meta *meta = nft_expr_priv(expr); 30 - struct sk_buff *skb = pkt->skb; 31 - u32 val = data->data[0]; 32 - 33 - switch (meta->key) { 34 - case NFT_META_MARK: 35 - skb->mark = val; 36 - break; 37 - case NFT_META_PRIORITY: 38 - skb->priority = val; 39 - break; 40 - case NFT_META_NFTRACE: 41 - skb->nf_trace = val; 42 - break; 43 - #ifdef CONFIG_NETWORK_SECMARK 44 - case NFT_META_SECMARK: 45 - skb->secmark = val; 46 - break; 47 - #endif 48 - default: 49 - WARN_ON(1); 50 - } 51 - } 52 - 53 - static const struct nla_policy nft_meta_policy[NFTA_META_MAX + 1] = { 54 - [NFTA_META_KEY] = { .type = NLA_U32 }, 55 - }; 56 - 57 - static int nft_meta_init(const struct nft_expr *expr, struct nlattr *tb[]) 58 - { 59 - struct nft_meta *meta = nft_expr_priv(expr); 60 - 61 - if (tb[NFTA_META_KEY] == NULL) 62 - return -EINVAL; 63 - 64 - meta->key = ntohl(nla_get_be32(tb[NFTA_META_KEY])); 65 - switch (meta->key) { 66 - case NFT_META_MARK: 67 - case NFT_META_PRIORITY: 68 - case NFT_META_NFTRACE: 69 - #ifdef CONFIG_NETWORK_SECMARK 70 - case NFT_META_SECMARK: 71 - #endif 72 - break; 73 - default: 74 - return -EINVAL; 75 - } 76 - 77 - return 0; 78 - } 79 - 80 - static int nft_meta_dump(struct sk_buff *skb, const struct nft_expr *expr) 81 - { 82 - struct nft_meta *meta = nft_expr_priv(expr); 83 - 84 - NLA_PUT_BE32(skb, NFTA_META_KEY, htonl(meta->key)); 85 - return 0; 86 - 87 - nla_put_failure: 88 - return -1; 89 - } 90 - 91 - static struct nft_expr_ops meta_target __read_mostly = { 92 - .name = "meta", 93 - .size = NFT_EXPR_SIZE(sizeof(struct nft_meta)), 94 - .owner = THIS_MODULE, 95 - .eval = nft_meta_eval, 96 - .init = nft_meta_init, 97 - .dump = nft_meta_dump, 98 - .policy = nft_meta_policy, 99 - .maxattr = NFTA_META_MAX, 100 - }; 101 - 102 - static int __init nft_meta_target_init(void) 103 - { 104 - return nft_register_expr(&meta_target); 105 - } 106 - 107 - static void __exit nft_meta_target_exit(void) 108 - { 109 - nft_unregister_expr(&meta_target); 110 - } 111 - 112 - module_init(nft_meta_target_init); 113 - module_exit(nft_meta_target_exit); 114 - 115 - MODULE_LICENSE("GPL"); 116 - MODULE_AUTHOR("Patrick McHardy <kaber@trash.net>"); 117 - MODULE_ALIAS_NFT_EXPR("meta");
+134
net/netfilter/nft_queue.c
··· 1 + /* 2 + * Copyright (c) 2013 Eric Leblond <eric@regit.org> 3 + * 4 + * This program is free software; you can redistribute it and/or modify 5 + * it under the terms of the GNU General Public License version 2 as 6 + * published by the Free Software Foundation. 7 + * 8 + * Development of this code partly funded by OISF 9 + * (http://www.openinfosecfoundation.org/) 10 + */ 11 + 12 + #include <linux/kernel.h> 13 + #include <linux/init.h> 14 + #include <linux/module.h> 15 + #include <linux/netlink.h> 16 + #include <linux/jhash.h> 17 + #include <linux/netfilter.h> 18 + #include <linux/netfilter/nf_tables.h> 19 + #include <net/netfilter/nf_tables.h> 20 + #include <net/netfilter/nf_queue.h> 21 + 22 + static u32 jhash_initval __read_mostly; 23 + 24 + struct nft_queue { 25 + u16 queuenum; 26 + u16 queues_total; 27 + u16 flags; 28 + u8 family; 29 + }; 30 + 31 + static void nft_queue_eval(const struct nft_expr *expr, 32 + struct nft_data data[NFT_REG_MAX + 1], 33 + const struct nft_pktinfo *pkt) 34 + { 35 + struct nft_queue *priv = nft_expr_priv(expr); 36 + u32 queue = priv->queuenum; 37 + u32 ret; 38 + 39 + if (priv->queues_total > 1) { 40 + if (priv->flags & NFT_QUEUE_FLAG_CPU_FANOUT) { 41 + int cpu = smp_processor_id(); 42 + 43 + queue = priv->queuenum + cpu % priv->queues_total; 44 + } else { 45 + queue = nfqueue_hash(pkt->skb, queue, 46 + priv->queues_total, priv->family, 47 + jhash_initval); 48 + } 49 + } 50 + 51 + ret = NF_QUEUE_NR(queue); 52 + if (priv->flags & NFT_QUEUE_FLAG_BYPASS) 53 + ret |= NF_VERDICT_FLAG_QUEUE_BYPASS; 54 + 55 + data[NFT_REG_VERDICT].verdict = ret; 56 + } 57 + 58 + static const struct nla_policy nft_queue_policy[NFTA_QUEUE_MAX + 1] = { 59 + [NFTA_QUEUE_NUM] = { .type = NLA_U16 }, 60 + [NFTA_QUEUE_TOTAL] = { .type = NLA_U16 }, 61 + [NFTA_QUEUE_FLAGS] = { .type = NLA_U16 }, 62 + }; 63 + 64 + static int nft_queue_init(const struct nft_ctx *ctx, 65 + const struct nft_expr *expr, 66 + const struct nlattr * const tb[]) 67 + { 68 + struct nft_queue *priv = nft_expr_priv(expr); 69 + 70 + if (tb[NFTA_QUEUE_NUM] == NULL) 71 + return -EINVAL; 72 + 73 + init_hashrandom(&jhash_initval); 74 + priv->family = ctx->afi->family; 75 + priv->queuenum = ntohs(nla_get_be16(tb[NFTA_QUEUE_NUM])); 76 + 77 + if (tb[NFTA_QUEUE_TOTAL] != NULL) 78 + priv->queues_total = ntohs(nla_get_be16(tb[NFTA_QUEUE_TOTAL])); 79 + if (tb[NFTA_QUEUE_FLAGS] != NULL) { 80 + priv->flags = ntohs(nla_get_be16(tb[NFTA_QUEUE_FLAGS])); 81 + if (priv->flags & ~NFT_QUEUE_FLAG_MASK) 82 + return -EINVAL; 83 + } 84 + return 0; 85 + } 86 + 87 + static int nft_queue_dump(struct sk_buff *skb, const struct nft_expr *expr) 88 + { 89 + const struct nft_queue *priv = nft_expr_priv(expr); 90 + 91 + if (nla_put_be16(skb, NFTA_QUEUE_NUM, htons(priv->queuenum)) || 92 + nla_put_be16(skb, NFTA_QUEUE_TOTAL, htons(priv->queues_total)) || 93 + nla_put_be16(skb, NFTA_QUEUE_FLAGS, htons(priv->flags))) 94 + goto nla_put_failure; 95 + 96 + return 0; 97 + 98 + nla_put_failure: 99 + return -1; 100 + } 101 + 102 + static struct nft_expr_type nft_queue_type; 103 + static const struct nft_expr_ops nft_queue_ops = { 104 + .type = &nft_queue_type, 105 + .size = NFT_EXPR_SIZE(sizeof(struct nft_queue)), 106 + .eval = nft_queue_eval, 107 + .init = nft_queue_init, 108 + .dump = nft_queue_dump, 109 + }; 110 + 111 + static struct nft_expr_type nft_queue_type __read_mostly = { 112 + .name = "queue", 113 + .ops = &nft_queue_ops, 114 + .policy = nft_queue_policy, 115 + .maxattr = NFTA_QUEUE_MAX, 116 + .owner = THIS_MODULE, 117 + }; 118 + 119 + static int __init nft_queue_module_init(void) 120 + { 121 + return nft_register_expr(&nft_queue_type); 122 + } 123 + 124 + static void __exit nft_queue_module_exit(void) 125 + { 126 + nft_unregister_expr(&nft_queue_type); 127 + } 128 + 129 + module_init(nft_queue_module_init); 130 + module_exit(nft_queue_module_exit); 131 + 132 + MODULE_LICENSE("GPL"); 133 + MODULE_AUTHOR("Eric Leblond <eric@regit.org>"); 134 + MODULE_ALIAS_NFT_EXPR("queue");
+12 -68
net/netfilter/xt_NFQUEUE.c
··· 11 11 #include <linux/module.h> 12 12 #include <linux/skbuff.h> 13 13 14 - #include <linux/ip.h> 15 - #include <linux/ipv6.h> 16 - #include <linux/jhash.h> 17 - 18 14 #include <linux/netfilter.h> 19 15 #include <linux/netfilter_arp.h> 20 16 #include <linux/netfilter/x_tables.h> 21 17 #include <linux/netfilter/xt_NFQUEUE.h> 18 + 19 + #include <net/netfilter/nf_queue.h> 22 20 23 21 MODULE_AUTHOR("Harald Welte <laforge@netfilter.org>"); 24 22 MODULE_DESCRIPTION("Xtables: packet forwarding to netlink"); ··· 26 28 MODULE_ALIAS("arpt_NFQUEUE"); 27 29 28 30 static u32 jhash_initval __read_mostly; 29 - static bool rnd_inited __read_mostly; 30 31 31 32 static unsigned int 32 33 nfqueue_tg(struct sk_buff *skb, const struct xt_action_param *par) ··· 35 38 return NF_QUEUE_NR(tinfo->queuenum); 36 39 } 37 40 38 - static u32 hash_v4(const struct sk_buff *skb) 39 - { 40 - const struct iphdr *iph = ip_hdr(skb); 41 - 42 - /* packets in either direction go into same queue */ 43 - if ((__force u32)iph->saddr < (__force u32)iph->daddr) 44 - return jhash_3words((__force u32)iph->saddr, 45 - (__force u32)iph->daddr, iph->protocol, jhash_initval); 46 - 47 - return jhash_3words((__force u32)iph->daddr, 48 - (__force u32)iph->saddr, iph->protocol, jhash_initval); 49 - } 50 - 51 - #if IS_ENABLED(CONFIG_IP6_NF_IPTABLES) 52 - static u32 hash_v6(const struct sk_buff *skb) 53 - { 54 - const struct ipv6hdr *ip6h = ipv6_hdr(skb); 55 - u32 a, b, c; 56 - 57 - if ((__force u32)ip6h->saddr.s6_addr32[3] < 58 - (__force u32)ip6h->daddr.s6_addr32[3]) { 59 - a = (__force u32) ip6h->saddr.s6_addr32[3]; 60 - b = (__force u32) ip6h->daddr.s6_addr32[3]; 61 - } else { 62 - b = (__force u32) ip6h->saddr.s6_addr32[3]; 63 - a = (__force u32) ip6h->daddr.s6_addr32[3]; 64 - } 65 - 66 - if ((__force u32)ip6h->saddr.s6_addr32[1] < 67 - (__force u32)ip6h->daddr.s6_addr32[1]) 68 - c = (__force u32) ip6h->saddr.s6_addr32[1]; 69 - else 70 - c = (__force u32) ip6h->daddr.s6_addr32[1]; 71 - 72 - return jhash_3words(a, b, c, jhash_initval); 73 - } 74 - #endif 75 - 76 - static u32 77 - nfqueue_hash(const struct sk_buff *skb, const struct xt_action_param *par) 78 - { 79 - const struct xt_NFQ_info_v1 *info = par->targinfo; 80 - u32 queue = info->queuenum; 81 - 82 - if (par->family == NFPROTO_IPV4) 83 - queue += ((u64) hash_v4(skb) * info->queues_total) >> 32; 84 - #if IS_ENABLED(CONFIG_IP6_NF_IPTABLES) 85 - else if (par->family == NFPROTO_IPV6) 86 - queue += ((u64) hash_v6(skb) * info->queues_total) >> 32; 87 - #endif 88 - 89 - return queue; 90 - } 91 - 92 41 static unsigned int 93 42 nfqueue_tg_v1(struct sk_buff *skb, const struct xt_action_param *par) 94 43 { 95 44 const struct xt_NFQ_info_v1 *info = par->targinfo; 96 45 u32 queue = info->queuenum; 97 46 98 - if (info->queues_total > 1) 99 - queue = nfqueue_hash(skb, par); 100 - 47 + if (info->queues_total > 1) { 48 + queue = nfqueue_hash(skb, queue, info->queues_total, 49 + par->family, jhash_initval); 50 + } 101 51 return NF_QUEUE_NR(queue); 102 52 } 103 53 ··· 64 120 const struct xt_NFQ_info_v3 *info = par->targinfo; 65 121 u32 maxid; 66 122 67 - if (unlikely(!rnd_inited)) { 68 - get_random_bytes(&jhash_initval, sizeof(jhash_initval)); 69 - rnd_inited = true; 70 - } 123 + init_hashrandom(&jhash_initval); 124 + 71 125 if (info->queues_total == 0) { 72 126 pr_err("NFQUEUE: number of total queues is 0\n"); 73 127 return -EINVAL; ··· 96 154 int cpu = smp_processor_id(); 97 155 98 156 queue = info->queuenum + cpu % info->queues_total; 99 - } else 100 - queue = nfqueue_hash(skb, par); 157 + } else { 158 + queue = nfqueue_hash(skb, queue, info->queues_total, 159 + par->family, jhash_initval); 160 + } 101 161 } 102 162 103 163 ret = NF_QUEUE_NR(queue);