aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorPablo Neira Ayuso <pablo@netfilter.org>2014-09-26 08:35:15 -0400
committerPablo Neira Ayuso <pablo@netfilter.org>2014-10-02 12:30:49 -0400
commitc8d7b98bec43faaa6583c3135030be5eb4693acb (patch)
treef7a8eaf696632ec402b61bbefd534d66d2b48c33
parent51b0a5d8c21a91801bbef9bcc8639dc0b206c6cd (diff)
netfilter: move nf_send_resetX() code to nf_reject_ipvX modules
Move nf_send_reset() and nf_send_reset6() to nf_reject_ipv4 and nf_reject_ipv6 respectively. This code is shared by x_tables and nf_tables. Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
-rw-r--r--include/net/netfilter/ipv4/nf_reject.h118
-rw-r--r--net/ipv4/netfilter/Kconfig6
-rw-r--r--net/ipv4/netfilter/Makefile3
-rw-r--r--net/ipv4/netfilter/nf_reject_ipv4.c127
-rw-r--r--net/ipv6/netfilter/Kconfig6
-rw-r--r--net/ipv6/netfilter/Makefile3
-rw-r--r--net/ipv6/netfilter/nf_reject_ipv6.c163
7 files changed, 309 insertions, 117 deletions
diff --git a/include/net/netfilter/ipv4/nf_reject.h b/include/net/netfilter/ipv4/nf_reject.h
index 8ce06385a552..e8427193c777 100644
--- a/include/net/netfilter/ipv4/nf_reject.h
+++ b/include/net/netfilter/ipv4/nf_reject.h
@@ -1,10 +1,6 @@
1#ifndef _IPV4_NF_REJECT_H 1#ifndef _IPV4_NF_REJECT_H
2#define _IPV4_NF_REJECT_H 2#define _IPV4_NF_REJECT_H
3 3
4#include <net/ip.h>
5#include <net/tcp.h>
6#include <net/route.h>
7#include <net/dst.h>
8#include <net/icmp.h> 4#include <net/icmp.h>
9 5
10static inline void nf_send_unreach(struct sk_buff *skb_in, int code) 6static inline void nf_send_unreach(struct sk_buff *skb_in, int code)
@@ -12,118 +8,6 @@ static inline void nf_send_unreach(struct sk_buff *skb_in, int code)
12 icmp_send(skb_in, ICMP_DEST_UNREACH, code, 0); 8 icmp_send(skb_in, ICMP_DEST_UNREACH, code, 0);
13} 9}
14 10
15/* Send RST reply */ 11void nf_send_reset(struct sk_buff *oldskb, int hook);
16static void nf_send_reset(struct sk_buff *oldskb, int hook)
17{
18 struct sk_buff *nskb;
19 const struct iphdr *oiph;
20 struct iphdr *niph;
21 const struct tcphdr *oth;
22 struct tcphdr _otcph, *tcph;
23
24 /* IP header checks: fragment. */
25 if (ip_hdr(oldskb)->frag_off & htons(IP_OFFSET))
26 return;
27
28 oth = skb_header_pointer(oldskb, ip_hdrlen(oldskb),
29 sizeof(_otcph), &_otcph);
30 if (oth == NULL)
31 return;
32
33 /* No RST for RST. */
34 if (oth->rst)
35 return;
36
37 if (skb_rtable(oldskb)->rt_flags & (RTCF_BROADCAST | RTCF_MULTICAST))
38 return;
39
40 /* Check checksum */
41 if (nf_ip_checksum(oldskb, hook, ip_hdrlen(oldskb), IPPROTO_TCP))
42 return;
43 oiph = ip_hdr(oldskb);
44
45 nskb = alloc_skb(sizeof(struct iphdr) + sizeof(struct tcphdr) +
46 LL_MAX_HEADER, GFP_ATOMIC);
47 if (!nskb)
48 return;
49
50 skb_reserve(nskb, LL_MAX_HEADER);
51
52 skb_reset_network_header(nskb);
53 niph = (struct iphdr *)skb_put(nskb, sizeof(struct iphdr));
54 niph->version = 4;
55 niph->ihl = sizeof(struct iphdr) / 4;
56 niph->tos = 0;
57 niph->id = 0;
58 niph->frag_off = htons(IP_DF);
59 niph->protocol = IPPROTO_TCP;
60 niph->check = 0;
61 niph->saddr = oiph->daddr;
62 niph->daddr = oiph->saddr;
63
64 skb_reset_transport_header(nskb);
65 tcph = (struct tcphdr *)skb_put(nskb, sizeof(struct tcphdr));
66 memset(tcph, 0, sizeof(*tcph));
67 tcph->source = oth->dest;
68 tcph->dest = oth->source;
69 tcph->doff = sizeof(struct tcphdr) / 4;
70
71 if (oth->ack)
72 tcph->seq = oth->ack_seq;
73 else {
74 tcph->ack_seq = htonl(ntohl(oth->seq) + oth->syn + oth->fin +
75 oldskb->len - ip_hdrlen(oldskb) -
76 (oth->doff << 2));
77 tcph->ack = 1;
78 }
79
80 tcph->rst = 1;
81 tcph->check = ~tcp_v4_check(sizeof(struct tcphdr), niph->saddr,
82 niph->daddr, 0);
83 nskb->ip_summed = CHECKSUM_PARTIAL;
84 nskb->csum_start = (unsigned char *)tcph - nskb->head;
85 nskb->csum_offset = offsetof(struct tcphdr, check);
86
87 /* ip_route_me_harder expects skb->dst to be set */
88 skb_dst_set_noref(nskb, skb_dst(oldskb));
89
90 nskb->protocol = htons(ETH_P_IP);
91 if (ip_route_me_harder(nskb, RTN_UNSPEC))
92 goto free_nskb;
93
94 niph->ttl = ip4_dst_hoplimit(skb_dst(nskb));
95
96 /* "Never happens" */
97 if (nskb->len > dst_mtu(skb_dst(nskb)))
98 goto free_nskb;
99
100 nf_ct_attach(nskb, oldskb);
101
102#if IS_ENABLED(CONFIG_BRIDGE_NETFILTER)
103 /* If we use ip_local_out for bridged traffic, the MAC source on
104 * the RST will be ours, instead of the destination's. This confuses
105 * some routers/firewalls, and they drop the packet. So we need to
106 * build the eth header using the original destination's MAC as the
107 * source, and send the RST packet directly.
108 */
109 if (oldskb->nf_bridge) {
110 struct ethhdr *oeth = eth_hdr(oldskb);
111 nskb->dev = oldskb->nf_bridge->physindev;
112 niph->tot_len = htons(nskb->len);
113 ip_send_check(niph);
114 if (dev_hard_header(nskb, nskb->dev, ntohs(nskb->protocol),
115 oeth->h_source, oeth->h_dest, nskb->len) < 0)
116 goto free_nskb;
117 dev_queue_xmit(nskb);
118 } else
119#endif
120 ip_local_out(nskb);
121
122 return;
123
124 free_nskb:
125 kfree_skb(nskb);
126}
127
128 12
129#endif /* _IPV4_NF_REJECT_H */ 13#endif /* _IPV4_NF_REJECT_H */
diff --git a/net/ipv4/netfilter/Kconfig b/net/ipv4/netfilter/Kconfig
index 345242a79db6..4c019d5c3f57 100644
--- a/net/ipv4/netfilter/Kconfig
+++ b/net/ipv4/netfilter/Kconfig
@@ -61,8 +61,13 @@ config NFT_CHAIN_ROUTE_IPV4
61 fields such as the source, destination, type of service and 61 fields such as the source, destination, type of service and
62 the packet mark. 62 the packet mark.
63 63
64config NF_REJECT_IPV4
65 tristate "IPv4 packet rejection"
66 default m if NETFILTER_ADVANCED=n
67
64config NFT_REJECT_IPV4 68config NFT_REJECT_IPV4
65 depends on NF_TABLES_IPV4 69 depends on NF_TABLES_IPV4
70 select NF_REJECT_IPV4
66 default NFT_REJECT 71 default NFT_REJECT
67 tristate 72 tristate
68 73
@@ -208,6 +213,7 @@ config IP_NF_FILTER
208config IP_NF_TARGET_REJECT 213config IP_NF_TARGET_REJECT
209 tristate "REJECT target support" 214 tristate "REJECT target support"
210 depends on IP_NF_FILTER 215 depends on IP_NF_FILTER
216 select NF_REJECT_IPV4
211 default m if NETFILTER_ADVANCED=n 217 default m if NETFILTER_ADVANCED=n
212 help 218 help
213 The REJECT target allows a filtering rule to specify that an ICMP 219 The REJECT target allows a filtering rule to specify that an ICMP
diff --git a/net/ipv4/netfilter/Makefile b/net/ipv4/netfilter/Makefile
index 14488cc5fd2c..f4cef5af0969 100644
--- a/net/ipv4/netfilter/Makefile
+++ b/net/ipv4/netfilter/Makefile
@@ -23,6 +23,9 @@ obj-$(CONFIG_NF_DEFRAG_IPV4) += nf_defrag_ipv4.o
23obj-$(CONFIG_NF_LOG_ARP) += nf_log_arp.o 23obj-$(CONFIG_NF_LOG_ARP) += nf_log_arp.o
24obj-$(CONFIG_NF_LOG_IPV4) += nf_log_ipv4.o 24obj-$(CONFIG_NF_LOG_IPV4) += nf_log_ipv4.o
25 25
26# reject
27obj-$(CONFIG_NF_REJECT_IPV4) += nf_reject_ipv4.o
28
26# NAT helpers (nf_conntrack) 29# NAT helpers (nf_conntrack)
27obj-$(CONFIG_NF_NAT_H323) += nf_nat_h323.o 30obj-$(CONFIG_NF_NAT_H323) += nf_nat_h323.o
28obj-$(CONFIG_NF_NAT_PPTP) += nf_nat_pptp.o 31obj-$(CONFIG_NF_NAT_PPTP) += nf_nat_pptp.o
diff --git a/net/ipv4/netfilter/nf_reject_ipv4.c b/net/ipv4/netfilter/nf_reject_ipv4.c
new file mode 100644
index 000000000000..b023b4eb1a96
--- /dev/null
+++ b/net/ipv4/netfilter/nf_reject_ipv4.c
@@ -0,0 +1,127 @@
1/* (C) 1999-2001 Paul `Rusty' Russell
2 * (C) 2002-2004 Netfilter Core Team <coreteam@netfilter.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
9#include <net/ip.h>
10#include <net/tcp.h>
11#include <net/route.h>
12#include <net/dst.h>
13#include <linux/netfilter_ipv4.h>
14
15/* Send RST reply */
16void nf_send_reset(struct sk_buff *oldskb, int hook)
17{
18 struct sk_buff *nskb;
19 const struct iphdr *oiph;
20 struct iphdr *niph;
21 const struct tcphdr *oth;
22 struct tcphdr _otcph, *tcph;
23
24 /* IP header checks: fragment. */
25 if (ip_hdr(oldskb)->frag_off & htons(IP_OFFSET))
26 return;
27
28 oth = skb_header_pointer(oldskb, ip_hdrlen(oldskb),
29 sizeof(_otcph), &_otcph);
30 if (oth == NULL)
31 return;
32
33 /* No RST for RST. */
34 if (oth->rst)
35 return;
36
37 if (skb_rtable(oldskb)->rt_flags & (RTCF_BROADCAST | RTCF_MULTICAST))
38 return;
39
40 /* Check checksum */
41 if (nf_ip_checksum(oldskb, hook, ip_hdrlen(oldskb), IPPROTO_TCP))
42 return;
43 oiph = ip_hdr(oldskb);
44
45 nskb = alloc_skb(sizeof(struct iphdr) + sizeof(struct tcphdr) +
46 LL_MAX_HEADER, GFP_ATOMIC);
47 if (!nskb)
48 return;
49
50 skb_reserve(nskb, LL_MAX_HEADER);
51
52 skb_reset_network_header(nskb);
53 niph = (struct iphdr *)skb_put(nskb, sizeof(struct iphdr));
54 niph->version = 4;
55 niph->ihl = sizeof(struct iphdr) / 4;
56 niph->tos = 0;
57 niph->id = 0;
58 niph->frag_off = htons(IP_DF);
59 niph->protocol = IPPROTO_TCP;
60 niph->check = 0;
61 niph->saddr = oiph->daddr;
62 niph->daddr = oiph->saddr;
63
64 skb_reset_transport_header(nskb);
65 tcph = (struct tcphdr *)skb_put(nskb, sizeof(struct tcphdr));
66 memset(tcph, 0, sizeof(*tcph));
67 tcph->source = oth->dest;
68 tcph->dest = oth->source;
69 tcph->doff = sizeof(struct tcphdr) / 4;
70
71 if (oth->ack)
72 tcph->seq = oth->ack_seq;
73 else {
74 tcph->ack_seq = htonl(ntohl(oth->seq) + oth->syn + oth->fin +
75 oldskb->len - ip_hdrlen(oldskb) -
76 (oth->doff << 2));
77 tcph->ack = 1;
78 }
79
80 tcph->rst = 1;
81 tcph->check = ~tcp_v4_check(sizeof(struct tcphdr), niph->saddr,
82 niph->daddr, 0);
83 nskb->ip_summed = CHECKSUM_PARTIAL;
84 nskb->csum_start = (unsigned char *)tcph - nskb->head;
85 nskb->csum_offset = offsetof(struct tcphdr, check);
86
87 /* ip_route_me_harder expects skb->dst to be set */
88 skb_dst_set_noref(nskb, skb_dst(oldskb));
89
90 nskb->protocol = htons(ETH_P_IP);
91 if (ip_route_me_harder(nskb, RTN_UNSPEC))
92 goto free_nskb;
93
94 niph->ttl = ip4_dst_hoplimit(skb_dst(nskb));
95
96 /* "Never happens" */
97 if (nskb->len > dst_mtu(skb_dst(nskb)))
98 goto free_nskb;
99
100 nf_ct_attach(nskb, oldskb);
101
102#if IS_ENABLED(CONFIG_BRIDGE_NETFILTER)
103 /* If we use ip_local_out for bridged traffic, the MAC source on
104 * the RST will be ours, instead of the destination's. This confuses
105 * some routers/firewalls, and they drop the packet. So we need to
106 * build the eth header using the original destination's MAC as the
107 * source, and send the RST packet directly.
108 */
109 if (oldskb->nf_bridge) {
110 struct ethhdr *oeth = eth_hdr(oldskb);
111 nskb->dev = oldskb->nf_bridge->physindev;
112 niph->tot_len = htons(nskb->len);
113 ip_send_check(niph);
114 if (dev_hard_header(nskb, nskb->dev, ntohs(nskb->protocol),
115 oeth->h_source, oeth->h_dest, nskb->len) < 0)
116 goto free_nskb;
117 dev_queue_xmit(nskb);
118 } else
119#endif
120 ip_local_out(nskb);
121
122 return;
123
124 free_nskb:
125 kfree_skb(nskb);
126}
127EXPORT_SYMBOL_GPL(nf_send_reset);
diff --git a/net/ipv6/netfilter/Kconfig b/net/ipv6/netfilter/Kconfig
index bb1a40db7be1..6af874fc187f 100644
--- a/net/ipv6/netfilter/Kconfig
+++ b/net/ipv6/netfilter/Kconfig
@@ -40,8 +40,13 @@ config NFT_CHAIN_ROUTE_IPV6
40 fields such as the source, destination, flowlabel, hop-limit and 40 fields such as the source, destination, flowlabel, hop-limit and
41 the packet mark. 41 the packet mark.
42 42
43config NF_REJECT_IPV6
44 tristate "IPv6 packet rejection"
45 default m if NETFILTER_ADVANCED=n
46
43config NFT_REJECT_IPV6 47config NFT_REJECT_IPV6
44 depends on NF_TABLES_IPV6 48 depends on NF_TABLES_IPV6
49 select NF_REJECT_IPV6
45 default NFT_REJECT 50 default NFT_REJECT
46 tristate 51 tristate
47 52
@@ -208,6 +213,7 @@ config IP6_NF_FILTER
208config IP6_NF_TARGET_REJECT 213config IP6_NF_TARGET_REJECT
209 tristate "REJECT target support" 214 tristate "REJECT target support"
210 depends on IP6_NF_FILTER 215 depends on IP6_NF_FILTER
216 select NF_REJECT_IPV6
211 default m if NETFILTER_ADVANCED=n 217 default m if NETFILTER_ADVANCED=n
212 help 218 help
213 The REJECT target allows a filtering rule to specify that an ICMPv6 219 The REJECT target allows a filtering rule to specify that an ICMPv6
diff --git a/net/ipv6/netfilter/Makefile b/net/ipv6/netfilter/Makefile
index 0f7e5b3f328d..fbb25f01143c 100644
--- a/net/ipv6/netfilter/Makefile
+++ b/net/ipv6/netfilter/Makefile
@@ -27,6 +27,9 @@ obj-$(CONFIG_NF_DEFRAG_IPV6) += nf_defrag_ipv6.o
27# logging 27# logging
28obj-$(CONFIG_NF_LOG_IPV6) += nf_log_ipv6.o 28obj-$(CONFIG_NF_LOG_IPV6) += nf_log_ipv6.o
29 29
30# reject
31obj-$(CONFIG_NF_REJECT_IPV6) += nf_reject_ipv6.o
32
30# nf_tables 33# nf_tables
31obj-$(CONFIG_NF_TABLES_IPV6) += nf_tables_ipv6.o 34obj-$(CONFIG_NF_TABLES_IPV6) += nf_tables_ipv6.o
32obj-$(CONFIG_NFT_CHAIN_ROUTE_IPV6) += nft_chain_route_ipv6.o 35obj-$(CONFIG_NFT_CHAIN_ROUTE_IPV6) += nft_chain_route_ipv6.o
diff --git a/net/ipv6/netfilter/nf_reject_ipv6.c b/net/ipv6/netfilter/nf_reject_ipv6.c
new file mode 100644
index 000000000000..5f5f0438d74d
--- /dev/null
+++ b/net/ipv6/netfilter/nf_reject_ipv6.c
@@ -0,0 +1,163 @@
1/* (C) 1999-2001 Paul `Rusty' Russell
2 * (C) 2002-2004 Netfilter Core Team <coreteam@netfilter.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#include <net/ipv6.h>
9#include <net/ip6_route.h>
10#include <net/ip6_fib.h>
11#include <net/ip6_checksum.h>
12#include <linux/netfilter_ipv6.h>
13
14void nf_send_reset6(struct net *net, struct sk_buff *oldskb, int hook)
15{
16 struct sk_buff *nskb;
17 struct tcphdr otcph, *tcph;
18 unsigned int otcplen, hh_len;
19 int tcphoff, needs_ack;
20 const struct ipv6hdr *oip6h = ipv6_hdr(oldskb);
21 struct ipv6hdr *ip6h;
22#define DEFAULT_TOS_VALUE 0x0U
23 const __u8 tclass = DEFAULT_TOS_VALUE;
24 struct dst_entry *dst = NULL;
25 u8 proto;
26 __be16 frag_off;
27 struct flowi6 fl6;
28
29 if ((!(ipv6_addr_type(&oip6h->saddr) & IPV6_ADDR_UNICAST)) ||
30 (!(ipv6_addr_type(&oip6h->daddr) & IPV6_ADDR_UNICAST))) {
31 pr_debug("addr is not unicast.\n");
32 return;
33 }
34
35 proto = oip6h->nexthdr;
36 tcphoff = ipv6_skip_exthdr(oldskb, ((u8*)(oip6h+1) - oldskb->data), &proto, &frag_off);
37
38 if ((tcphoff < 0) || (tcphoff > oldskb->len)) {
39 pr_debug("Cannot get TCP header.\n");
40 return;
41 }
42
43 otcplen = oldskb->len - tcphoff;
44
45 /* IP header checks: fragment, too short. */
46 if (proto != IPPROTO_TCP || otcplen < sizeof(struct tcphdr)) {
47 pr_debug("proto(%d) != IPPROTO_TCP, "
48 "or too short. otcplen = %d\n",
49 proto, otcplen);
50 return;
51 }
52
53 if (skb_copy_bits(oldskb, tcphoff, &otcph, sizeof(struct tcphdr)))
54 BUG();
55
56 /* No RST for RST. */
57 if (otcph.rst) {
58 pr_debug("RST is set\n");
59 return;
60 }
61
62 /* Check checksum. */
63 if (nf_ip6_checksum(oldskb, hook, tcphoff, IPPROTO_TCP)) {
64 pr_debug("TCP checksum is invalid\n");
65 return;
66 }
67
68 memset(&fl6, 0, sizeof(fl6));
69 fl6.flowi6_proto = IPPROTO_TCP;
70 fl6.saddr = oip6h->daddr;
71 fl6.daddr = oip6h->saddr;
72 fl6.fl6_sport = otcph.dest;
73 fl6.fl6_dport = otcph.source;
74 security_skb_classify_flow(oldskb, flowi6_to_flowi(&fl6));
75 dst = ip6_route_output(net, NULL, &fl6);
76 if (dst == NULL || dst->error) {
77 dst_release(dst);
78 return;
79 }
80 dst = xfrm_lookup(net, dst, flowi6_to_flowi(&fl6), NULL, 0);
81 if (IS_ERR(dst))
82 return;
83
84 hh_len = (dst->dev->hard_header_len + 15)&~15;
85 nskb = alloc_skb(hh_len + 15 + dst->header_len + sizeof(struct ipv6hdr)
86 + sizeof(struct tcphdr) + dst->trailer_len,
87 GFP_ATOMIC);
88
89 if (!nskb) {
90 net_dbg_ratelimited("cannot alloc skb\n");
91 dst_release(dst);
92 return;
93 }
94
95 skb_dst_set(nskb, dst);
96
97 skb_reserve(nskb, hh_len + dst->header_len);
98
99 skb_put(nskb, sizeof(struct ipv6hdr));
100 skb_reset_network_header(nskb);
101 ip6h = ipv6_hdr(nskb);
102 ip6_flow_hdr(ip6h, tclass, 0);
103 ip6h->hop_limit = ip6_dst_hoplimit(dst);
104 ip6h->nexthdr = IPPROTO_TCP;
105 ip6h->saddr = oip6h->daddr;
106 ip6h->daddr = oip6h->saddr;
107
108 skb_reset_transport_header(nskb);
109 tcph = (struct tcphdr *)skb_put(nskb, sizeof(struct tcphdr));
110 /* Truncate to length (no data) */
111 tcph->doff = sizeof(struct tcphdr)/4;
112 tcph->source = otcph.dest;
113 tcph->dest = otcph.source;
114
115 if (otcph.ack) {
116 needs_ack = 0;
117 tcph->seq = otcph.ack_seq;
118 tcph->ack_seq = 0;
119 } else {
120 needs_ack = 1;
121 tcph->ack_seq = htonl(ntohl(otcph.seq) + otcph.syn + otcph.fin
122 + otcplen - (otcph.doff<<2));
123 tcph->seq = 0;
124 }
125
126 /* Reset flags */
127 ((u_int8_t *)tcph)[13] = 0;
128 tcph->rst = 1;
129 tcph->ack = needs_ack;
130 tcph->window = 0;
131 tcph->urg_ptr = 0;
132 tcph->check = 0;
133
134 /* Adjust TCP checksum */
135 tcph->check = csum_ipv6_magic(&ipv6_hdr(nskb)->saddr,
136 &ipv6_hdr(nskb)->daddr,
137 sizeof(struct tcphdr), IPPROTO_TCP,
138 csum_partial(tcph,
139 sizeof(struct tcphdr), 0));
140
141 nf_ct_attach(nskb, oldskb);
142
143#if IS_ENABLED(CONFIG_BRIDGE_NETFILTER)
144 /* If we use ip6_local_out for bridged traffic, the MAC source on
145 * the RST will be ours, instead of the destination's. This confuses
146 * some routers/firewalls, and they drop the packet. So we need to
147 * build the eth header using the original destination's MAC as the
148 * source, and send the RST packet directly.
149 */
150 if (oldskb->nf_bridge) {
151 struct ethhdr *oeth = eth_hdr(oldskb);
152 nskb->dev = oldskb->nf_bridge->physindev;
153 nskb->protocol = htons(ETH_P_IPV6);
154 ip6h->payload_len = htons(sizeof(struct tcphdr));
155 if (dev_hard_header(nskb, nskb->dev, ntohs(nskb->protocol),
156 oeth->h_source, oeth->h_dest, nskb->len) < 0)
157 return;
158 dev_queue_xmit(nskb);
159 } else
160#endif
161 ip6_local_out(nskb);
162}
163EXPORT_SYMBOL_GPL(nf_send_reset6);