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. ====================
Unified · Split
| @@ -0,0 +1,128 @@ | ||
| 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 */ | |
| @@ -0,0 +1,171 @@ | ||
| 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 */ | |
| @@ -1,6 +1,10 @@ | ||
| 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; |
| @@ -33,4 +37,62 @@ void nf_reinject(struct nf_queue_entry *entry, unsigned int verdict); · 26 unmodified lines | ||
| 33 | 37 | bool nf_queue_entry_get_refs(struct nf_queue_entry *entry); |
| 34 | 38 | void nf_queue_entry_release_refs(struct nf_queue_entry *entry); |
| 35 | 39 | |
| 40 | +static inline void init_hashrandom(u32 *jhash_initval) | |
| 41 | +{ | |
| 42 | + while (*jhash_initval == 0) | |
| 43 | + *jhash_initval = prandom_u32(); | |
| 44 | +} | |
| 45 | + | |
| 46 | +static inline u32 hash_v4(const struct sk_buff *skb, u32 jhash_initval) | |
| 47 | +{ | |
| 48 | + const struct iphdr *iph = ip_hdr(skb); | |
| 49 | + | |
| 50 | + /* packets in either direction go into same queue */ | |
| 51 | + if ((__force u32)iph->saddr < (__force u32)iph->daddr) | |
| 52 | + return jhash_3words((__force u32)iph->saddr, | |
| 53 | + (__force u32)iph->daddr, iph->protocol, jhash_initval); | |
| 54 | + | |
| 55 | + return jhash_3words((__force u32)iph->daddr, | |
| 56 | + (__force u32)iph->saddr, iph->protocol, jhash_initval); | |
| 57 | +} | |
| 58 | + | |
| 59 | +#if IS_ENABLED(CONFIG_IP6_NF_IPTABLES) | |
| 60 | +static inline u32 hash_v6(const struct sk_buff *skb, u32 jhash_initval) | |
| 61 | +{ | |
| 62 | + const struct ipv6hdr *ip6h = ipv6_hdr(skb); | |
| 63 | + u32 a, b, c; | |
| 64 | + | |
| 65 | + if ((__force u32)ip6h->saddr.s6_addr32[3] < | |
| 66 | + (__force u32)ip6h->daddr.s6_addr32[3]) { | |
| 67 | + a = (__force u32) ip6h->saddr.s6_addr32[3]; | |
| 68 | + b = (__force u32) ip6h->daddr.s6_addr32[3]; | |
| 69 | + } else { | |
| 70 | + b = (__force u32) ip6h->saddr.s6_addr32[3]; | |
| 71 | + a = (__force u32) ip6h->daddr.s6_addr32[3]; | |
| 72 | + } | |
| 73 | + | |
| 74 | + if ((__force u32)ip6h->saddr.s6_addr32[1] < | |
| 75 | + (__force u32)ip6h->daddr.s6_addr32[1]) | |
| 76 | + c = (__force u32) ip6h->saddr.s6_addr32[1]; | |
| 77 | + else | |
| 78 | + c = (__force u32) ip6h->daddr.s6_addr32[1]; | |
| 79 | + | |
| 80 | + return jhash_3words(a, b, c, jhash_initval); | |
| 81 | +} | |
| 82 | +#endif | |
| 83 | + | |
| 84 | +static inline u32 | |
| 85 | +nfqueue_hash(const struct sk_buff *skb, u16 queue, u16 queues_total, u8 family, | |
| 86 | + u32 jhash_initval) | |
| 87 | +{ | |
| 88 | + if (family == NFPROTO_IPV4) | |
| 89 | + queue += ((u64) hash_v4(skb, jhash_initval) * queues_total) >> 32; | |
| 90 | +#if IS_ENABLED(CONFIG_IP6_NF_IPTABLES) | |
| 91 | + else if (family == NFPROTO_IPV6) | |
| 92 | + queue += ((u64) hash_v6(skb, jhash_initval) * queues_total) >> 32; | |
| 93 | +#endif | |
| 94 | + | |
| 95 | + return queue; | |
| 96 | +} | |
| 97 | + | |
| 36 | 98 | #endif /* _NF_QUEUE_H */ |
| @@ -110,11 +110,13 @@ enum nft_table_flags { · 109 unmodified lines | ||
| 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) |
| @@ -553,11 +555,13 @@ enum nft_meta_keys { · 432 unmodified lines | ||
| 553 | 555 | * |
| 554 | 556 | * @NFTA_META_DREG: destination register (NLA_U32) |
| 555 | 557 | * @NFTA_META_KEY: meta data item to load (NLA_U32: nft_meta_keys) |
| 558 | + * @NFTA_META_SREG: source register (NLA_U32) | |
| 556 | 559 | */ |
| 557 | 560 | enum nft_meta_attributes { |
| 558 | 561 | NFTA_META_UNSPEC, |
| 559 | 562 | NFTA_META_DREG, |
| 560 | 563 | NFTA_META_KEY, |
| 564 | + NFTA_META_SREG, | |
| 561 | 565 | __NFTA_META_MAX |
| 562 | 566 | }; |
| 563 | 567 | #define NFTA_META_MAX (__NFTA_META_MAX - 1) |
| @@ -657,6 +661,26 @@ enum nft_log_attributes { · 93 unmodified lines | ||
| 657 | 661 | }; |
| 658 | 662 | #define NFTA_LOG_MAX (__NFTA_LOG_MAX - 1) |
| 659 | 663 | |
| 664 | +/** | |
| 665 | + * enum nft_queue_attributes - nf_tables queue expression netlink attributes | |
| 666 | + * | |
| 667 | + * @NFTA_QUEUE_NUM: netlink queue to send messages to (NLA_U16) | |
| 668 | + * @NFTA_QUEUE_TOTAL: number of queues to load balance packets on (NLA_U16) | |
| 669 | + * @NFTA_QUEUE_FLAGS: various flags (NLA_U16) | |
| 670 | + */ | |
| 671 | +enum nft_queue_attributes { | |
| 672 | + NFTA_QUEUE_UNSPEC, | |
| 673 | + NFTA_QUEUE_NUM, | |
| 674 | + NFTA_QUEUE_TOTAL, | |
| 675 | + NFTA_QUEUE_FLAGS, | |
| 676 | + __NFTA_QUEUE_MAX | |
| 677 | +}; | |
| 678 | +#define NFTA_QUEUE_MAX (__NFTA_QUEUE_MAX - 1) | |
| 679 | + | |
| 680 | +#define NFT_QUEUE_FLAG_BYPASS 0x01 /* for compatibility with v2 */ | |
| 681 | +#define NFT_QUEUE_FLAG_CPU_FANOUT 0x02 /* use current CPU (no hashing) */ | |
| 682 | +#define NFT_QUEUE_FLAG_MASK 0x03 | |
| 683 | + | |
| 660 | 684 | /** |
| 661 | 685 | * enum nft_reject_types - nf_tables reject expression reject types |
| 662 | 686 | * |
| @@ -39,23 +39,33 @@ config NF_CONNTRACK_PROC_COMPAT · 38 unmodified lines | ||
| 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)" |
| @@ -28,7 +28,6 @@ obj-$(CONFIG_NF_NAT_SNMP_BASIC) += nf_nat_snmp_basic.o · 27 unmodified lines | ||
| 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 |
| @@ -17,10 +17,6 @@ · 16 unmodified lines | ||
| 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> |
| @@ -28,128 +24,12 @@ · 1 unmodified line | ||
| 28 | 24 | #include <linux/netfilter_bridge.h> |
| 29 | 25 | #endif |
| 30 | 26 | |
| 27 | +#include <net/netfilter/ipv4/nf_reject.h> | |
| 28 | + | |
| 31 | 29 | MODULE_LICENSE("GPL"); |
| 32 | 30 | MODULE_AUTHOR("Netfilter Core Team <coreteam@netfilter.org>"); |
| 33 | 31 | MODULE_DESCRIPTION("Xtables: packet \"rejection\" target for IPv4"); |
| 34 | 32 | |
| 35 | −/* Send RST reply */ | |
| 36 | −static void send_reset(struct sk_buff *oldskb, int hook) | |
| 37 | −{ | |
| 38 | − struct sk_buff *nskb; | |
| 39 | − const struct iphdr *oiph; | |
| 40 | − struct iphdr *niph; | |
| 41 | − const struct tcphdr *oth; | |
| 42 | − struct tcphdr _otcph, *tcph; | |
| 43 | − | |
| 44 | − /* IP header checks: fragment. */ | |
| 45 | − if (ip_hdr(oldskb)->frag_off & htons(IP_OFFSET)) | |
| 46 | − return; | |
| 47 | − | |
| 48 | − oth = skb_header_pointer(oldskb, ip_hdrlen(oldskb), | |
| 49 | − sizeof(_otcph), &_otcph); | |
| 50 | − if (oth == NULL) | |
| 51 | − return; | |
| 52 | − | |
| 53 | − /* No RST for RST. */ | |
| 54 | − if (oth->rst) | |
| 55 | − return; | |
| 56 | − | |
| 57 | − if (skb_rtable(oldskb)->rt_flags & (RTCF_BROADCAST | RTCF_MULTICAST)) | |
| 58 | − return; | |
| 59 | − | |
| 60 | − /* Check checksum */ | |
| 61 | − if (nf_ip_checksum(oldskb, hook, ip_hdrlen(oldskb), IPPROTO_TCP)) | |
| 62 | − return; | |
| 63 | − oiph = ip_hdr(oldskb); | |
| 64 | − | |
| 65 | − nskb = alloc_skb(sizeof(struct iphdr) + sizeof(struct tcphdr) + | |
| 66 | − LL_MAX_HEADER, GFP_ATOMIC); | |
| 67 | − if (!nskb) | |
| 68 | − return; | |
| 69 | − | |
| 70 | − skb_reserve(nskb, LL_MAX_HEADER); | |
| 71 | − | |
| 72 | − skb_reset_network_header(nskb); | |
| 73 | − niph = (struct iphdr *)skb_put(nskb, sizeof(struct iphdr)); | |
| 74 | − niph->version = 4; | |
| 75 | − niph->ihl = sizeof(struct iphdr) / 4; | |
| 76 | − niph->tos = 0; | |
| 77 | − niph->id = 0; | |
| 78 | − niph->frag_off = htons(IP_DF); | |
| 79 | − niph->protocol = IPPROTO_TCP; | |
| 80 | − niph->check = 0; | |
| 81 | − niph->saddr = oiph->daddr; | |
| 82 | − niph->daddr = oiph->saddr; | |
| 83 | − | |
| 84 | − skb_reset_transport_header(nskb); | |
| 85 | − tcph = (struct tcphdr *)skb_put(nskb, sizeof(struct tcphdr)); | |
| 86 | − memset(tcph, 0, sizeof(*tcph)); | |
| 87 | − tcph->source = oth->dest; | |
| 88 | − tcph->dest = oth->source; | |
| 89 | − tcph->doff = sizeof(struct tcphdr) / 4; | |
| 90 | − | |
| 91 | − if (oth->ack) | |
| 92 | − tcph->seq = oth->ack_seq; | |
| 93 | − else { | |
| 94 | − tcph->ack_seq = htonl(ntohl(oth->seq) + oth->syn + oth->fin + | |
| 95 | − oldskb->len - ip_hdrlen(oldskb) - | |
| 96 | − (oth->doff << 2)); | |
| 97 | − tcph->ack = 1; | |
| 98 | − } | |
| 99 | − | |
| 100 | − tcph->rst = 1; | |
| 101 | − tcph->check = ~tcp_v4_check(sizeof(struct tcphdr), niph->saddr, | |
| 102 | − niph->daddr, 0); | |
| 103 | − nskb->ip_summed = CHECKSUM_PARTIAL; | |
| 104 | − nskb->csum_start = (unsigned char *)tcph - nskb->head; | |
| 105 | − nskb->csum_offset = offsetof(struct tcphdr, check); | |
| 106 | − | |
| 107 | − /* ip_route_me_harder expects skb->dst to be set */ | |
| 108 | − skb_dst_set_noref(nskb, skb_dst(oldskb)); | |
| 109 | − | |
| 110 | − nskb->protocol = htons(ETH_P_IP); | |
| 111 | − if (ip_route_me_harder(nskb, RTN_UNSPEC)) | |
| 112 | − goto free_nskb; | |
| 113 | − | |
| 114 | − niph->ttl = ip4_dst_hoplimit(skb_dst(nskb)); | |
| 115 | − | |
| 116 | − /* "Never happens" */ | |
| 117 | − if (nskb->len > dst_mtu(skb_dst(nskb))) | |
| 118 | − goto free_nskb; | |
| 119 | − | |
| 120 | − nf_ct_attach(nskb, oldskb); | |
| 121 | − | |
| 122 | −#ifdef CONFIG_BRIDGE_NETFILTER | |
| 123 | − /* If we use ip_local_out for bridged traffic, the MAC source on | |
| 124 | − * the RST will be ours, instead of the destination's. This confuses | |
| 125 | − * some routers/firewalls, and they drop the packet. So we need to | |
| 126 | − * build the eth header using the original destination's MAC as the | |
| 127 | − * source, and send the RST packet directly. | |
| 128 | − */ | |
| 129 | − if (oldskb->nf_bridge) { | |
| 130 | − struct ethhdr *oeth = eth_hdr(oldskb); | |
| 131 | − nskb->dev = oldskb->nf_bridge->physindev; | |
| 132 | − niph->tot_len = htons(nskb->len); | |
| 133 | − ip_send_check(niph); | |
| 134 | − if (dev_hard_header(nskb, nskb->dev, ntohs(nskb->protocol), | |
| 135 | − oeth->h_source, oeth->h_dest, nskb->len) < 0) | |
| 136 | − goto free_nskb; | |
| 137 | − dev_queue_xmit(nskb); | |
| 138 | − } else | |
| 139 | −#endif | |
| 140 | − ip_local_out(nskb); | |
| 141 | − | |
| 142 | − return; | |
| 143 | − | |
| 144 | − free_nskb: | |
| 145 | − kfree_skb(nskb); | |
| 146 | −} | |
| 147 | − | |
| 148 | −static inline void send_unreach(struct sk_buff *skb_in, int code) | |
| 149 | −{ | |
| 150 | − icmp_send(skb_in, ICMP_DEST_UNREACH, code, 0); | |
| 151 | −} | |
| 152 | − | |
| 153 | 33 | static unsigned int |
| 154 | 34 | reject_tg(struct sk_buff *skb, const struct xt_action_param *par) |
| 155 | 35 | { |
| @@ -157,28 +37,28 @@ reject_tg(struct sk_buff *skb, const struct xt_action_param *par) · 1 unmodified line | ||
| 157 | 37 | |
| 158 | 38 | switch (reject->with) { |
| 159 | 39 | case IPT_ICMP_NET_UNREACHABLE: |
| 160 | − send_unreach(skb, ICMP_NET_UNREACH); | |
| 40 | + nf_send_unreach(skb, ICMP_NET_UNREACH); | |
| 161 | 41 | break; |
| 162 | 42 | case IPT_ICMP_HOST_UNREACHABLE: |
| 163 | − send_unreach(skb, ICMP_HOST_UNREACH); | |
| 43 | + nf_send_unreach(skb, ICMP_HOST_UNREACH); | |
| 164 | 44 | break; |
| 165 | 45 | case IPT_ICMP_PROT_UNREACHABLE: |
| 166 | − send_unreach(skb, ICMP_PROT_UNREACH); | |
| 46 | + nf_send_unreach(skb, ICMP_PROT_UNREACH); | |
| 167 | 47 | break; |
| 168 | 48 | case IPT_ICMP_PORT_UNREACHABLE: |
| 169 | − send_unreach(skb, ICMP_PORT_UNREACH); | |
| 49 | + nf_send_unreach(skb, ICMP_PORT_UNREACH); | |
| 170 | 50 | break; |
| 171 | 51 | case IPT_ICMP_NET_PROHIBITED: |
| 172 | − send_unreach(skb, ICMP_NET_ANO); | |
| 52 | + nf_send_unreach(skb, ICMP_NET_ANO); | |
| 173 | 53 | break; |
| 174 | 54 | case IPT_ICMP_HOST_PROHIBITED: |
| 175 | − send_unreach(skb, ICMP_HOST_ANO); | |
| 55 | + nf_send_unreach(skb, ICMP_HOST_ANO); | |
| 176 | 56 | break; |
| 177 | 57 | case IPT_ICMP_ADMIN_PROHIBITED: |
| 178 | − send_unreach(skb, ICMP_PKT_FILTERED); | |
| 58 | + nf_send_unreach(skb, ICMP_PKT_FILTERED); | |
| 179 | 59 | break; |
| 180 | 60 | case IPT_TCP_RESET: |
| 181 | − send_reset(skb, par->hooknum); | |
| 61 | + nf_send_reset(skb, par->hooknum); | |
| 182 | 62 | case IPT_ICMP_ECHOREPLY: |
| 183 | 63 | /* Doesn't happen. */ |
| 184 | 64 | break; |
| @@ -28,15 +28,27 @@ config NF_CONNTRACK_IPV6 · 27 unmodified lines | ||
| 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)" |
| @@ -23,181 +23,18 @@ · 22 unmodified lines | ||
| 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) |
| @@ -208,25 +45,25 @@ reject_tg6(struct sk_buff *skb, const struct xt_action_param *par) · 4 unmodified lines | ||
| 208 | 45 | pr_debug("%s: medium point\n", __func__); |
| 209 | 46 | switch (reject->with) { |
| 210 | 47 | case IP6T_ICMP6_NO_ROUTE: |
| 211 | − send_unreach(net, skb, ICMPV6_NOROUTE, par->hooknum); | |
| 48 | + nf_send_unreach6(net, skb, ICMPV6_NOROUTE, par->hooknum); | |
| 212 | 49 | break; |
| 213 | 50 | case IP6T_ICMP6_ADM_PROHIBITED: |
| 214 | − send_unreach(net, skb, ICMPV6_ADM_PROHIBITED, par->hooknum); | |
| 51 | + nf_send_unreach6(net, skb, ICMPV6_ADM_PROHIBITED, par->hooknum); | |
| 215 | 52 | break; |
| 216 | 53 | case IP6T_ICMP6_NOT_NEIGHBOUR: |
| 217 | − send_unreach(net, skb, ICMPV6_NOT_NEIGHBOUR, par->hooknum); | |
| 54 | + nf_send_unreach6(net, skb, ICMPV6_NOT_NEIGHBOUR, par->hooknum); | |
| 218 | 55 | break; |
| 219 | 56 | case IP6T_ICMP6_ADDR_UNREACH: |
| 220 | − send_unreach(net, skb, ICMPV6_ADDR_UNREACH, par->hooknum); | |
| 57 | + nf_send_unreach6(net, skb, ICMPV6_ADDR_UNREACH, par->hooknum); | |
| 221 | 58 | break; |
| 222 | 59 | case IP6T_ICMP6_PORT_UNREACH: |
| 223 | − send_unreach(net, skb, ICMPV6_PORT_UNREACH, par->hooknum); | |
| 60 | + nf_send_unreach6(net, skb, ICMPV6_PORT_UNREACH, par->hooknum); | |
| 224 | 61 | break; |
| 225 | 62 | case IP6T_ICMP6_ECHOREPLY: |
| 226 | 63 | /* Do nothing */ |
| 227 | 64 | break; |
| 228 | 65 | case IP6T_TCP_RESET: |
| 229 | − send_reset(net, skb, par->hooknum); | |
| 66 | + nf_send_reset6(net, skb, par->hooknum); | |
| 230 | 67 | break; |
| 231 | 68 | default: |
| 232 | 69 | net_info_ratelimited("case %u not handled yet\n", reject->with); |
| @@ -414,47 +414,104 @@ config NETFILTER_SYNPROXY · 413 unmodified lines | ||
| 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 |
| @@ -76,7 +76,8 @@ obj-$(CONFIG_NFT_META) += nft_meta.o · 75 unmodified lines | ||
| 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 |
| @@ -180,7 +180,8 @@ static int nf_tables_fill_table_info(struct sk_buff *skb, u32 portid, u32 seq, · 179 unmodified lines | ||
| 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); |
| @@ -1923,12 +1924,14 @@ static int nft_ctx_init_from_setattr(struct nft_ctx *ctx, · 1736 unmodified lines | ||
| 1923 | 1924 | { |
| 1924 | 1925 | struct net *net = sock_net(skb->sk); |
| 1925 | 1926 | const struct nfgenmsg *nfmsg = nlmsg_data(nlh); |
| 1926 | − const struct nft_af_info *afi; | |
| 1927 | + const struct nft_af_info *afi = NULL; | |
| 1927 | 1928 | const struct nft_table *table = NULL; |
| 1928 | 1929 | |
| 1929 | − afi = nf_tables_afinfo_lookup(net, nfmsg->nfgen_family, false); | |
| 1930 | − if (IS_ERR(afi)) | |
| 1931 | − return PTR_ERR(afi); | |
| 1930 | + if (nfmsg->nfgen_family != NFPROTO_UNSPEC) { | |
| 1931 | + afi = nf_tables_afinfo_lookup(net, nfmsg->nfgen_family, false); | |
| 1932 | + if (IS_ERR(afi)) | |
| 1933 | + return PTR_ERR(afi); | |
| 1934 | + } | |
| 1932 | 1935 | |
| 1933 | 1936 | if (nla[NFTA_SET_TABLE] != NULL) { |
| 1934 | 1937 | table = nf_tables_table_lookup(afi, nla[NFTA_SET_TABLE]); |
| @@ -1973,11 +1976,14 @@ static int nf_tables_set_alloc_name(struct nft_ctx *ctx, struct nft_set *set, · 38 unmodified lines | ||
| 1973 | 1976 | return -ENOMEM; |
| 1974 | 1977 | |
| 1975 | 1978 | list_for_each_entry(i, &ctx->table->sets, list) { |
| 1976 | − if (!sscanf(i->name, name, &n)) | |
| 1979 | + int tmp; | |
| 1980 | + | |
| 1981 | + if (!sscanf(i->name, name, &tmp)) | |
| 1977 | 1982 | continue; |
| 1978 | − if (n < 0 || n > BITS_PER_LONG * PAGE_SIZE) | |
| 1983 | + if (tmp < 0 || tmp > BITS_PER_LONG * PAGE_SIZE) | |
| 1979 | 1984 | continue; |
| 1980 | − set_bit(n, inuse); | |
| 1985 | + | |
| 1986 | + set_bit(tmp, inuse); | |
| 1981 | 1987 | } |
| 1982 | 1988 | |
| 1983 | 1989 | n = find_first_zero_bit(inuse, BITS_PER_LONG * PAGE_SIZE); |
| @@ -2094,8 +2100,8 @@ done: · 110 unmodified lines | ||
| 2094 | 2100 | return skb->len; |
| 2095 | 2101 | } |
| 2096 | 2102 | |
| 2097 | −static int nf_tables_dump_sets_all(struct nft_ctx *ctx, struct sk_buff *skb, | |
| 2098 | − struct netlink_callback *cb) | |
| 2103 | +static int nf_tables_dump_sets_family(struct nft_ctx *ctx, struct sk_buff *skb, | |
| 2104 | + struct netlink_callback *cb) | |
| 2099 | 2105 | { |
| 2100 | 2106 | const struct nft_set *set; |
| 2101 | 2107 | unsigned int idx = 0, s_idx = cb->args[0]; |
| @@ -2127,6 +2133,61 @@ done: · 25 unmodified lines | ||
| 2127 | 2133 | return skb->len; |
| 2128 | 2134 | } |
| 2129 | 2135 | |
| 2136 | +static int nf_tables_dump_sets_all(struct nft_ctx *ctx, struct sk_buff *skb, | |
| 2137 | + struct netlink_callback *cb) | |
| 2138 | +{ | |
| 2139 | + const struct nft_set *set; | |
| 2140 | + unsigned int idx, s_idx = cb->args[0]; | |
| 2141 | + const struct nft_af_info *afi; | |
| 2142 | + struct nft_table *table, *cur_table = (struct nft_table *)cb->args[2]; | |
| 2143 | + struct net *net = sock_net(skb->sk); | |
| 2144 | + int cur_family = cb->args[3]; | |
| 2145 | + | |
| 2146 | + if (cb->args[1]) | |
| 2147 | + return skb->len; | |
| 2148 | + | |
| 2149 | + list_for_each_entry(afi, &net->nft.af_info, list) { | |
| 2150 | + if (cur_family) { | |
| 2151 | + if (afi->family != cur_family) | |
| 2152 | + continue; | |
| 2153 | + | |
| 2154 | + cur_family = 0; | |
| 2155 | + } | |
| 2156 | + | |
| 2157 | + list_for_each_entry(table, &afi->tables, list) { | |
| 2158 | + if (cur_table) { | |
| 2159 | + if (cur_table != table) | |
| 2160 | + continue; | |
| 2161 | + | |
| 2162 | + cur_table = NULL; | |
| 2163 | + } | |
| 2164 | + | |
| 2165 | + ctx->table = table; | |
| 2166 | + ctx->afi = afi; | |
| 2167 | + idx = 0; | |
| 2168 | + list_for_each_entry(set, &ctx->table->sets, list) { | |
| 2169 | + if (idx < s_idx) | |
| 2170 | + goto cont; | |
| 2171 | + if (nf_tables_fill_set(skb, ctx, set, | |
| 2172 | + NFT_MSG_NEWSET, | |
| 2173 | + NLM_F_MULTI) < 0) { | |
| 2174 | + cb->args[0] = idx; | |
| 2175 | + cb->args[2] = (unsigned long) table; | |
| 2176 | + cb->args[3] = afi->family; | |
| 2177 | + goto done; | |
| 2178 | + } | |
| 2179 | +cont: | |
| 2180 | + idx++; | |
| 2181 | + } | |
| 2182 | + if (s_idx) | |
| 2183 | + s_idx = 0; | |
| 2184 | + } | |
| 2185 | + } | |
| 2186 | + cb->args[1] = 1; | |
| 2187 | +done: | |
| 2188 | + return skb->len; | |
| 2189 | +} | |
| 2190 | + | |
| 2130 | 2191 | static int nf_tables_dump_sets(struct sk_buff *skb, struct netlink_callback *cb) |
| 2131 | 2192 | { |
| 2132 | 2193 | const struct nfgenmsg *nfmsg = nlmsg_data(cb->nlh); |
| @@ -2143,9 +2204,12 @@ static int nf_tables_dump_sets(struct sk_buff *skb, struct netlink_callback *cb) · 10 unmodified lines | ||
| 2143 | 2204 | if (err < 0) |
| 2144 | 2205 | return err; |
| 2145 | 2206 | |
| 2146 | − if (ctx.table == NULL) | |
| 2147 | − ret = nf_tables_dump_sets_all(&ctx, skb, cb); | |
| 2148 | − else | |
| 2207 | + if (ctx.table == NULL) { | |
| 2208 | + if (ctx.afi == NULL) | |
| 2209 | + ret = nf_tables_dump_sets_all(&ctx, skb, cb); | |
| 2210 | + else | |
| 2211 | + ret = nf_tables_dump_sets_family(&ctx, skb, cb); | |
| 2212 | + } else | |
| 2149 | 2213 | ret = nf_tables_dump_sets_table(&ctx, skb, cb); |
| 2150 | 2214 | |
| 2151 | 2215 | return ret; |
| @@ -2158,6 +2222,7 @@ static int nf_tables_getset(struct sock *nlsk, struct sk_buff *skb, · 6 unmodified lines | ||
| 2158 | 2222 | const struct nft_set *set; |
| 2159 | 2223 | struct nft_ctx ctx; |
| 2160 | 2224 | struct sk_buff *skb2; |
| 2225 | + const struct nfgenmsg *nfmsg = nlmsg_data(nlh); | |
| 2161 | 2226 | int err; |
| 2162 | 2227 | |
| 2163 | 2228 | /* Verify existance before starting dump */ |
| @@ -2172,6 +2237,10 @@ static int nf_tables_getset(struct sock *nlsk, struct sk_buff *skb, · 8 unmodified lines | ||
| 2172 | 2237 | return netlink_dump_start(nlsk, skb, nlh, &c); |
| 2173 | 2238 | } |
| 2174 | 2239 | |
| 2240 | + /* Only accept unspec with dump */ | |
| 2241 | + if (nfmsg->nfgen_family == NFPROTO_UNSPEC) | |
| 2242 | + return -EAFNOSUPPORT; | |
| 2243 | + | |
| 2175 | 2244 | set = nf_tables_set_lookup(ctx.table, nla[NFTA_SET_NAME]); |
| 2176 | 2245 | if (IS_ERR(set)) |
| 2177 | 2246 | return PTR_ERR(set); |
| @@ -2341,6 +2410,7 @@ static int nf_tables_delset(struct sock *nlsk, struct sk_buff *skb, · 163 unmodified lines | ||
| 2341 | 2410 | const struct nlmsghdr *nlh, |
| 2342 | 2411 | const struct nlattr * const nla[]) |
| 2343 | 2412 | { |
| 2413 | + const struct nfgenmsg *nfmsg = nlmsg_data(nlh); | |
| 2344 | 2414 | struct nft_set *set; |
| 2345 | 2415 | struct nft_ctx ctx; |
| 2346 | 2416 | int err; |
| @@ -2352,6 +2422,9 @@ static int nf_tables_delset(struct sock *nlsk, struct sk_buff *skb, · 5 unmodified lines | ||
| 2352 | 2422 | if (err < 0) |
| 2353 | 2423 | return err; |
| 2354 | 2424 | |
| 2425 | + if (nfmsg->nfgen_family == NFPROTO_UNSPEC) | |
| 2426 | + return -EAFNOSUPPORT; | |
| 2427 | + | |
| 2355 | 2428 | set = nf_tables_set_lookup(ctx.table, nla[NFTA_SET_NAME]); |
| 2356 | 2429 | if (IS_ERR(set)) |
| 2357 | 2430 | return PTR_ERR(set); |
| @@ -2521,9 +2594,8 @@ static int nf_tables_dump_set(struct sk_buff *skb, struct netlink_callback *cb) · 163 unmodified lines | ||
| 2521 | 2594 | u32 portid, seq; |
| 2522 | 2595 | int event, err; |
| 2523 | 2596 | |
| 2524 | − nfmsg = nlmsg_data(cb->nlh); | |
| 2525 | − err = nlmsg_parse(cb->nlh, sizeof(*nfmsg), nla, NFTA_SET_ELEM_LIST_MAX, | |
| 2526 | − nft_set_elem_list_policy); | |
| 2597 | + err = nlmsg_parse(cb->nlh, sizeof(struct nfgenmsg), nla, | |
| 2598 | + NFTA_SET_ELEM_LIST_MAX, nft_set_elem_list_policy); | |
| 2527 | 2599 | if (err < 0) |
| 2528 | 2600 | return err; |
| 2529 | 2601 | |
| @@ -164,7 +164,7 @@ next_rule: · 163 unmodified lines | ||
| 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,6 +172,9 @@ next_rule: · 1 unmodified line | ||
| 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); |
| @@ -21,12 +21,15 @@ · 20 unmodified lines | ||
| 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; |
| @@ -132,23 +135,50 @@ err: · 99 unmodified lines | ||
| 132 | 135 | data[NFT_REG_VERDICT].verdict = NFT_BREAK; |
| 133 | 136 | } |
| 134 | 137 | |
| 138 | +static void nft_meta_set_eval(const struct nft_expr *expr, | |
| 139 | + struct nft_data data[NFT_REG_MAX + 1], | |
| 140 | + const struct nft_pktinfo *pkt) | |
| 141 | +{ | |
| 142 | + const struct nft_meta *meta = nft_expr_priv(expr); | |
| 143 | + struct sk_buff *skb = pkt->skb; | |
| 144 | + u32 value = data[meta->sreg].data[0]; | |
| 145 | + | |
| 146 | + switch (meta->key) { | |
| 147 | + case NFT_META_MARK: | |
| 148 | + skb->mark = value; | |
| 149 | + break; | |
| 150 | + case NFT_META_PRIORITY: | |
| 151 | + skb->priority = value; | |
| 152 | + break; | |
| 153 | + case NFT_META_NFTRACE: | |
| 154 | + skb->nf_trace = 1; | |
| 155 | + break; | |
| 156 | + default: | |
| 157 | + WARN_ON(1); | |
| 158 | + } | |
| 159 | +} | |
| 160 | + | |
| 135 | 161 | static const struct nla_policy nft_meta_policy[NFTA_META_MAX + 1] = { |
| 136 | 162 | [NFTA_META_DREG] = { .type = NLA_U32 }, |
| 137 | 163 | [NFTA_META_KEY] = { .type = NLA_U32 }, |
| 164 | + [NFTA_META_SREG] = { .type = NLA_U32 }, | |
| 138 | 165 | }; |
| 139 | 166 | |
| 140 | −static int nft_meta_init(const struct nft_ctx *ctx, const struct nft_expr *expr, | |
| 141 | − const struct nlattr * const tb[]) | |
| 167 | +static int nft_meta_init_validate_set(uint32_t key) | |
| 142 | 168 | { |
| 143 | − struct nft_meta *priv = nft_expr_priv(expr); | |
| 144 | − int err; | |
| 145 | − | |
| 146 | − if (tb[NFTA_META_DREG] == NULL || | |
| 147 | − tb[NFTA_META_KEY] == NULL) | |
| 148 | − return -EINVAL; | |
| 169 | + switch (key) { | |
| 170 | + case NFT_META_MARK: | |
| 171 | + case NFT_META_PRIORITY: | |
| 172 | + case NFT_META_NFTRACE: | |
| 173 | + return 0; | |
| 174 | + default: | |
| 175 | + return -EOPNOTSUPP; | |
| 176 | + } | |
| 177 | +} | |
| 149 | 178 | |
| 150 | − priv->key = ntohl(nla_get_be32(tb[NFTA_META_KEY])); | |
| 151 | − switch (priv->key) { | |
| 179 | +static int nft_meta_init_validate_get(uint32_t key) | |
| 180 | +{ | |
| 181 | + switch (key) { | |
| 152 | 182 | case NFT_META_LEN: |
| 153 | 183 | case NFT_META_PROTOCOL: |
| 154 | 184 | case NFT_META_PRIORITY: |
| @@ -167,26 +197,69 @@ static int nft_meta_init(const struct nft_ctx *ctx, const struct nft_expr *expr, · 12 unmodified lines | ||
| 167 | 197 | #ifdef CONFIG_NETWORK_SECMARK |
| 168 | 198 | case NFT_META_SECMARK: |
| 169 | 199 | #endif |
| 170 | − break; | |
| 200 | + return 0; | |
| 171 | 201 | default: |
| 172 | 202 | return -EOPNOTSUPP; |
| 173 | 203 | } |
| 174 | 204 | |
| 175 | − priv->dreg = ntohl(nla_get_be32(tb[NFTA_META_DREG])); | |
| 176 | − err = nft_validate_output_register(priv->dreg); | |
| 205 | +} | |
| 206 | + | |
| 207 | +static int nft_meta_init(const struct nft_ctx *ctx, const struct nft_expr *expr, | |
| 208 | + const struct nlattr * const tb[]) | |
| 209 | +{ | |
| 210 | + struct nft_meta *priv = nft_expr_priv(expr); | |
| 211 | + int err; | |
| 212 | + | |
| 213 | + priv->key = ntohl(nla_get_be32(tb[NFTA_META_KEY])); | |
| 214 | + | |
| 215 | + if (tb[NFTA_META_DREG]) { | |
| 216 | + err = nft_meta_init_validate_get(priv->key); | |
| 217 | + if (err < 0) | |
| 218 | + return err; | |
| 219 | + | |
| 220 | + priv->dreg = ntohl(nla_get_be32(tb[NFTA_META_DREG])); | |
| 221 | + err = nft_validate_output_register(priv->dreg); | |
| 222 | + if (err < 0) | |
| 223 | + return err; | |
| 224 | + | |
| 225 | + return nft_validate_data_load(ctx, priv->dreg, NULL, | |
| 226 | + NFT_DATA_VALUE); | |
| 227 | + } | |
| 228 | + | |
| 229 | + err = nft_meta_init_validate_set(priv->key); | |
| 177 | 230 | if (err < 0) |
| 178 | 231 | return err; |
| 179 | − return nft_validate_data_load(ctx, priv->dreg, NULL, NFT_DATA_VALUE); | |
| 232 | + | |
| 233 | + priv->sreg = ntohl(nla_get_be32(tb[NFTA_META_SREG])); | |
| 234 | + | |
| 235 | + return 0; | |
| 180 | 236 | } |
| 181 | 237 | |
| 182 | −static int nft_meta_dump(struct sk_buff *skb, const struct nft_expr *expr) | |
| 238 | +static int nft_meta_get_dump(struct sk_buff *skb, | |
| 239 | + const struct nft_expr *expr) | |
| 183 | 240 | { |
| 184 | 241 | const struct nft_meta *priv = nft_expr_priv(expr); |
| 185 | 242 | |
| 243 | + if (nla_put_be32(skb, NFTA_META_KEY, htonl(priv->key))) | |
| 244 | + goto nla_put_failure; | |
| 186 | 245 | if (nla_put_be32(skb, NFTA_META_DREG, htonl(priv->dreg))) |
| 187 | 246 | goto nla_put_failure; |
| 247 | + return 0; | |
| 248 | + | |
| 249 | +nla_put_failure: | |
| 250 | + return -1; | |
| 251 | +} | |
| 252 | + | |
| 253 | +static int nft_meta_set_dump(struct sk_buff *skb, | |
| 254 | + const struct nft_expr *expr) | |
| 255 | +{ | |
| 256 | + const struct nft_meta *priv = nft_expr_priv(expr); | |
| 257 | + | |
| 188 | 258 | if (nla_put_be32(skb, NFTA_META_KEY, htonl(priv->key))) |
| 189 | 259 | goto nla_put_failure; |
| 260 | + if (nla_put_be32(skb, NFTA_META_SREG, htonl(priv->sreg))) | |
| 261 | + goto nla_put_failure; | |
| 262 | + | |
| 190 | 263 | return 0; |
| 191 | 264 | |
| 192 | 265 | nla_put_failure: |
| @@ -194,17 +267,44 @@ nla_put_failure: · 1 unmodified line | ||
| 194 | 267 | } |
| 195 | 268 | |
| 196 | 269 | static struct nft_expr_type nft_meta_type; |
| 197 | −static const struct nft_expr_ops nft_meta_ops = { | |
| 270 | +static const struct nft_expr_ops nft_meta_get_ops = { | |
| 198 | 271 | .type = &nft_meta_type, |
| 199 | 272 | .size = NFT_EXPR_SIZE(sizeof(struct nft_meta)), |
| 200 | − .eval = nft_meta_eval, | |
| 273 | + .eval = nft_meta_get_eval, | |
| 201 | 274 | .init = nft_meta_init, |
| 202 | − .dump = nft_meta_dump, | |
| 275 | + .dump = nft_meta_get_dump, | |
| 203 | 276 | }; |
| 204 | 277 | |
| 278 | +static const struct nft_expr_ops nft_meta_set_ops = { | |
| 279 | + .type = &nft_meta_type, | |
| 280 | + .size = NFT_EXPR_SIZE(sizeof(struct nft_meta)), | |
| 281 | + .eval = nft_meta_set_eval, | |
| 282 | + .init = nft_meta_init, | |
| 283 | + .dump = nft_meta_set_dump, | |
| 284 | +}; | |
| 285 | + | |
| 286 | +static const struct nft_expr_ops * | |
| 287 | +nft_meta_select_ops(const struct nft_ctx *ctx, | |
| 288 | + const struct nlattr * const tb[]) | |
| 289 | +{ | |
| 290 | + if (tb[NFTA_META_KEY] == NULL) | |
| 291 | + return ERR_PTR(-EINVAL); | |
| 292 | + | |
| 293 | + if (tb[NFTA_META_DREG] && tb[NFTA_META_SREG]) | |
| 294 | + return ERR_PTR(-EINVAL); | |
| 295 | + | |
| 296 | + if (tb[NFTA_META_DREG]) | |
| 297 | + return &nft_meta_get_ops; | |
| 298 | + | |
| 299 | + if (tb[NFTA_META_SREG]) | |
| 300 | + return &nft_meta_set_ops; | |
| 301 | + | |
| 302 | + return ERR_PTR(-EINVAL); | |
| 303 | +} | |
| 304 | + | |
| 205 | 305 | static struct nft_expr_type nft_meta_type __read_mostly = { |
| 206 | 306 | .name = "meta", |
| 207 | − .ops = &nft_meta_ops, | |
| 307 | + .select_ops = &nft_meta_select_ops, | |
| 208 | 308 | .policy = nft_meta_policy, |
| 209 | 309 | .maxattr = NFTA_META_MAX, |
| 210 | 310 | .owner = THIS_MODULE, |
| @@ -1,117 +0,0 @@ | ||
| 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"); | |
| @@ -0,0 +1,134 @@ | ||
| 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"); | |
| @@ -1,5 +1,6 @@ | ||
| 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 |
| @@ -16,10 +17,16 @@ · 10 unmodified lines | ||
| 16 | 17 | #include <linux/netfilter/nf_tables.h> |
| 17 | 18 | #include <net/netfilter/nf_tables.h> |
| 18 | 19 | #include <net/icmp.h> |
| 20 | +#include <net/netfilter/ipv4/nf_reject.h> | |
| 21 | + | |
| 22 | +#if IS_ENABLED(CONFIG_NF_TABLES_IPV6) | |
| 23 | +#include <net/netfilter/ipv6/nf_reject.h> | |
| 24 | +#endif | |
| 19 | 25 | |
| 20 | 26 | struct nft_reject { |
| 21 | 27 | enum nft_reject_types type:8; |
| 22 | 28 | u8 icmp_code; |
| 29 | + u8 family; | |
| 23 | 30 | }; |
| 24 | 31 | |
| 25 | 32 | static void nft_reject_eval(const struct nft_expr *expr, |
| @@ -27,12 +34,25 @@ static void nft_reject_eval(const struct nft_expr *expr, · 1 unmodified line | ||
| 27 | 34 | const struct nft_pktinfo *pkt) |
| 28 | 35 | { |
| 29 | 36 | struct nft_reject *priv = nft_expr_priv(expr); |
| 37 | + struct net *net = dev_net((pkt->in != NULL) ? pkt->in : pkt->out); | |
| 30 | 38 | |
| 31 | 39 | switch (priv->type) { |
| 32 | 40 | case NFT_REJECT_ICMP_UNREACH: |
| 33 | − icmp_send(pkt->skb, ICMP_DEST_UNREACH, priv->icmp_code, 0); | |
| 41 | + if (priv->family == NFPROTO_IPV4) | |
| 42 | + nf_send_unreach(pkt->skb, priv->icmp_code); | |
| 43 | +#if IS_ENABLED(CONFIG_NF_TABLES_IPV6) | |
| 44 | + else if (priv->family == NFPROTO_IPV6) | |
| 45 | + nf_send_unreach6(net, pkt->skb, priv->icmp_code, | |
| 46 | + pkt->hooknum); | |
| 47 | +#endif | |
| 34 | 48 | break; |
| 35 | 49 | case NFT_REJECT_TCP_RST: |
| 50 | + if (priv->family == NFPROTO_IPV4) | |
| 51 | + nf_send_reset(pkt->skb, pkt->hooknum); | |
| 52 | +#if IS_ENABLED(CONFIG_NF_TABLES_IPV6) | |
| 53 | + else if (priv->family == NFPROTO_IPV6) | |
| 54 | + nf_send_reset6(net, pkt->skb, pkt->hooknum); | |
| 55 | +#endif | |
| 36 | 56 | break; |
| 37 | 57 | } |
| 38 | 58 | |
| @@ -53,6 +73,7 @@ static int nft_reject_init(const struct nft_ctx *ctx, · 14 unmodified lines | ||
| 53 | 73 | if (tb[NFTA_REJECT_TYPE] == NULL) |
| 54 | 74 | return -EINVAL; |
| 55 | 75 | |
| 76 | + priv->family = ctx->afi->family; | |
| 56 | 77 | priv->type = ntohl(nla_get_be32(tb[NFTA_REJECT_TYPE])); |
| 57 | 78 | switch (priv->type) { |
| 58 | 79 | case NFT_REJECT_ICMP_UNREACH: |
| @@ -11,15 +11,13 @@ · 10 unmodified lines | ||
| 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> |
| 22 | 18 | |
| 19 | +#include <net/netfilter/nf_queue.h> | |
| 20 | + | |
| 23 | 21 | MODULE_AUTHOR("Harald Welte <laforge@netfilter.org>"); |
| 24 | 22 | MODULE_DESCRIPTION("Xtables: packet forwarding to netlink"); |
| 25 | 23 | MODULE_LICENSE("GPL"); |
| @@ -28,7 +26,6 @@ MODULE_ALIAS("ip6t_NFQUEUE"); · 2 unmodified lines | ||
| 28 | 26 | MODULE_ALIAS("arpt_NFQUEUE"); |
| 29 | 27 | |
| 30 | 28 | static u32 jhash_initval __read_mostly; |
| 31 | −static bool rnd_inited __read_mostly; | |
| 32 | 29 | |
| 33 | 30 | static unsigned int |
| 34 | 31 | nfqueue_tg(struct sk_buff *skb, const struct xt_action_param *par) |
| @@ -38,69 +35,16 @@ nfqueue_tg(struct sk_buff *skb, const struct xt_action_param *par) · 3 unmodified lines | ||
| 38 | 35 | return NF_QUEUE_NR(tinfo->queuenum); |
| 39 | 36 | } |
| 40 | 37 | |
| 41 | −static u32 hash_v4(const struct sk_buff *skb) | |
| 42 | −{ | |
| 43 | − const struct iphdr *iph = ip_hdr(skb); | |
| 44 | − | |
| 45 | − /* packets in either direction go into same queue */ | |
| 46 | − if ((__force u32)iph->saddr < (__force u32)iph->daddr) | |
| 47 | − return jhash_3words((__force u32)iph->saddr, | |
| 48 | − (__force u32)iph->daddr, iph->protocol, jhash_initval); | |
| 49 | − | |
| 50 | − return jhash_3words((__force u32)iph->daddr, | |
| 51 | − (__force u32)iph->saddr, iph->protocol, jhash_initval); | |
| 52 | −} | |
| 53 | − | |
| 54 | −#if IS_ENABLED(CONFIG_IP6_NF_IPTABLES) | |
| 55 | −static u32 hash_v6(const struct sk_buff *skb) | |
| 56 | −{ | |
| 57 | − const struct ipv6hdr *ip6h = ipv6_hdr(skb); | |
| 58 | − u32 a, b, c; | |
| 59 | − | |
| 60 | − if ((__force u32)ip6h->saddr.s6_addr32[3] < | |
| 61 | − (__force u32)ip6h->daddr.s6_addr32[3]) { | |
| 62 | − a = (__force u32) ip6h->saddr.s6_addr32[3]; | |
| 63 | − b = (__force u32) ip6h->daddr.s6_addr32[3]; | |
| 64 | − } else { | |
| 65 | − b = (__force u32) ip6h->saddr.s6_addr32[3]; | |
| 66 | − a = (__force u32) ip6h->daddr.s6_addr32[3]; | |
| 67 | − } | |
| 68 | − | |
| 69 | − if ((__force u32)ip6h->saddr.s6_addr32[1] < | |
| 70 | − (__force u32)ip6h->daddr.s6_addr32[1]) | |
| 71 | − c = (__force u32) ip6h->saddr.s6_addr32[1]; | |
| 72 | − else | |
| 73 | − c = (__force u32) ip6h->daddr.s6_addr32[1]; | |
| 74 | − | |
| 75 | − return jhash_3words(a, b, c, jhash_initval); | |
| 76 | −} | |
| 77 | −#endif | |
| 78 | − | |
| 79 | −static u32 | |
| 80 | −nfqueue_hash(const struct sk_buff *skb, const struct xt_action_param *par) | |
| 81 | −{ | |
| 82 | − const struct xt_NFQ_info_v1 *info = par->targinfo; | |
| 83 | − u32 queue = info->queuenum; | |
| 84 | − | |
| 85 | − if (par->family == NFPROTO_IPV4) | |
| 86 | − queue += ((u64) hash_v4(skb) * info->queues_total) >> 32; | |
| 87 | −#if IS_ENABLED(CONFIG_IP6_NF_IPTABLES) | |
| 88 | − else if (par->family == NFPROTO_IPV6) | |
| 89 | − queue += ((u64) hash_v6(skb) * info->queues_total) >> 32; | |
| 90 | −#endif | |
| 91 | − | |
| 92 | − return queue; | |
| 93 | −} | |
| 94 | − | |
| 95 | 38 | static unsigned int |
| 96 | 39 | nfqueue_tg_v1(struct sk_buff *skb, const struct xt_action_param *par) |
| 97 | 40 | { |
| 98 | 41 | const struct xt_NFQ_info_v1 *info = par->targinfo; |
| 99 | 42 | u32 queue = info->queuenum; |
| 100 | 43 | |
| 101 | − if (info->queues_total > 1) | |
| 102 | − queue = nfqueue_hash(skb, par); | |
| 103 | − | |
| 44 | + if (info->queues_total > 1) { | |
| 45 | + queue = nfqueue_hash(skb, queue, info->queues_total, | |
| 46 | + par->family, jhash_initval); | |
| 47 | + } | |
| 104 | 48 | return NF_QUEUE_NR(queue); |
| 105 | 49 | } |
| 106 | 50 | |
| @@ -120,10 +64,8 @@ static int nfqueue_tg_check(const struct xt_tgchk_param *par) · 13 unmodified lines | ||
| 120 | 64 | const struct xt_NFQ_info_v3 *info = par->targinfo; |
| 121 | 65 | u32 maxid; |
| 122 | 66 | |
| 123 | − if (unlikely(!rnd_inited)) { | |
| 124 | − get_random_bytes(&jhash_initval, sizeof(jhash_initval)); | |
| 125 | − rnd_inited = true; | |
| 126 | − } | |
| 67 | + init_hashrandom(&jhash_initval); | |
| 68 | + | |
| 127 | 69 | if (info->queues_total == 0) { |
| 128 | 70 | pr_err("NFQUEUE: number of total queues is 0\n"); |
| 129 | 71 | return -EINVAL; |
| @@ -154,8 +96,10 @@ nfqueue_tg_v3(struct sk_buff *skb, const struct xt_action_param *par) · 24 unmodified lines | ||
| 154 | 96 | int cpu = smp_processor_id(); |
| 155 | 97 | |
| 156 | 98 | queue = info->queuenum + cpu % info->queues_total; |
| 157 | − } else | |
| 158 | − queue = nfqueue_hash(skb, par); | |
| 99 | + } else { | |
| 100 | + queue = nfqueue_hash(skb, queue, info->queues_total, | |
| 101 | + par->family, jhash_initval); | |
| 102 | + } | |
| 159 | 103 | } |
| 160 | 104 | |
| 161 | 105 | ret = NF_QUEUE_NR(queue); |