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

netfilter: REJECT: separate reusable code

This patch prepares the addition of TCP reset support in
the nft_reject module by moving reusable code into a header
file.

Signed-off-by: Eric Leblond <eric@regit.org>
Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>

authored by

Eric Leblond and committed by
Pablo Neira Ayuso
cc70d069 5f291c28

+317 -301
+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 */
+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;
+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);