diff options
author | Pablo Neira Ayuso <pablo@netfilter.org> | 2014-10-25 12:24:57 -0400 |
---|---|---|
committer | Pablo Neira Ayuso <pablo@netfilter.org> | 2014-10-31 07:49:05 -0400 |
commit | 052b9498eea532deb5de75277a53f6e0623215dc (patch) | |
tree | f66e2e445c077efede2901d6888646851aa4a13f /net | |
parent | 4d87716cd057bde3f90e304289c1fec88d45a1cc (diff) |
netfilter: nf_reject_ipv4: split nf_send_reset() in smaller functions
That can be reused by the reject bridge expression to build the reject
packet. The new functions are:
* nf_reject_ip_tcphdr_get(): to sanitize and to obtain the TCP header.
* nf_reject_iphdr_put(): to build the IPv4 header.
* nf_reject_ip_tcphdr_put(): to build the TCP header.
Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
Diffstat (limited to 'net')
-rw-r--r-- | net/ipv4/netfilter/nf_reject_ipv4.c | 88 |
1 files changed, 62 insertions, 26 deletions
diff --git a/net/ipv4/netfilter/nf_reject_ipv4.c b/net/ipv4/netfilter/nf_reject_ipv4.c index 92b303dbd5fc..1baaa83dfe5c 100644 --- a/net/ipv4/netfilter/nf_reject_ipv4.c +++ b/net/ipv4/netfilter/nf_reject_ipv4.c | |||
@@ -12,43 +12,39 @@ | |||
12 | #include <net/route.h> | 12 | #include <net/route.h> |
13 | #include <net/dst.h> | 13 | #include <net/dst.h> |
14 | #include <linux/netfilter_ipv4.h> | 14 | #include <linux/netfilter_ipv4.h> |
15 | #include <net/netfilter/ipv4/nf_reject.h> | ||
15 | 16 | ||
16 | /* Send RST reply */ | 17 | const struct tcphdr *nf_reject_ip_tcphdr_get(struct sk_buff *oldskb, |
17 | void nf_send_reset(struct sk_buff *oldskb, int hook) | 18 | struct tcphdr *_oth, int hook) |
18 | { | 19 | { |
19 | struct sk_buff *nskb; | ||
20 | const struct iphdr *oiph; | ||
21 | struct iphdr *niph; | ||
22 | const struct tcphdr *oth; | 20 | const struct tcphdr *oth; |
23 | struct tcphdr _otcph, *tcph; | ||
24 | 21 | ||
25 | /* IP header checks: fragment. */ | 22 | /* IP header checks: fragment. */ |
26 | if (ip_hdr(oldskb)->frag_off & htons(IP_OFFSET)) | 23 | if (ip_hdr(oldskb)->frag_off & htons(IP_OFFSET)) |
27 | return; | 24 | return NULL; |
28 | 25 | ||
29 | oth = skb_header_pointer(oldskb, ip_hdrlen(oldskb), | 26 | oth = skb_header_pointer(oldskb, ip_hdrlen(oldskb), |
30 | sizeof(_otcph), &_otcph); | 27 | sizeof(struct tcphdr), _oth); |
31 | if (oth == NULL) | 28 | if (oth == NULL) |
32 | return; | 29 | return NULL; |
33 | 30 | ||
34 | /* No RST for RST. */ | 31 | /* No RST for RST. */ |
35 | if (oth->rst) | 32 | if (oth->rst) |
36 | return; | 33 | return NULL; |
37 | |||
38 | if (skb_rtable(oldskb)->rt_flags & (RTCF_BROADCAST | RTCF_MULTICAST)) | ||
39 | return; | ||
40 | 34 | ||
41 | /* Check checksum */ | 35 | /* Check checksum */ |
42 | if (nf_ip_checksum(oldskb, hook, ip_hdrlen(oldskb), IPPROTO_TCP)) | 36 | if (nf_ip_checksum(oldskb, hook, ip_hdrlen(oldskb), IPPROTO_TCP)) |
43 | return; | 37 | return NULL; |
44 | oiph = ip_hdr(oldskb); | ||
45 | 38 | ||
46 | nskb = alloc_skb(sizeof(struct iphdr) + sizeof(struct tcphdr) + | 39 | return oth; |
47 | LL_MAX_HEADER, GFP_ATOMIC); | 40 | } |
48 | if (!nskb) | 41 | EXPORT_SYMBOL_GPL(nf_reject_ip_tcphdr_get); |
49 | return; | ||
50 | 42 | ||
51 | skb_reserve(nskb, LL_MAX_HEADER); | 43 | struct iphdr *nf_reject_iphdr_put(struct sk_buff *nskb, |
44 | const struct sk_buff *oldskb, | ||
45 | __be16 protocol, int ttl) | ||
46 | { | ||
47 | struct iphdr *niph, *oiph = ip_hdr(oldskb); | ||
52 | 48 | ||
53 | skb_reset_network_header(nskb); | 49 | skb_reset_network_header(nskb); |
54 | niph = (struct iphdr *)skb_put(nskb, sizeof(struct iphdr)); | 50 | niph = (struct iphdr *)skb_put(nskb, sizeof(struct iphdr)); |
@@ -57,10 +53,23 @@ void nf_send_reset(struct sk_buff *oldskb, int hook) | |||
57 | niph->tos = 0; | 53 | niph->tos = 0; |
58 | niph->id = 0; | 54 | niph->id = 0; |
59 | niph->frag_off = htons(IP_DF); | 55 | niph->frag_off = htons(IP_DF); |
60 | niph->protocol = IPPROTO_TCP; | 56 | niph->protocol = protocol; |
61 | niph->check = 0; | 57 | niph->check = 0; |
62 | niph->saddr = oiph->daddr; | 58 | niph->saddr = oiph->daddr; |
63 | niph->daddr = oiph->saddr; | 59 | niph->daddr = oiph->saddr; |
60 | niph->ttl = ttl; | ||
61 | |||
62 | nskb->protocol = htons(ETH_P_IP); | ||
63 | |||
64 | return niph; | ||
65 | } | ||
66 | EXPORT_SYMBOL_GPL(nf_reject_iphdr_put); | ||
67 | |||
68 | void nf_reject_ip_tcphdr_put(struct sk_buff *nskb, const struct sk_buff *oldskb, | ||
69 | const struct tcphdr *oth) | ||
70 | { | ||
71 | struct iphdr *niph = ip_hdr(nskb); | ||
72 | struct tcphdr *tcph; | ||
64 | 73 | ||
65 | skb_reset_transport_header(nskb); | 74 | skb_reset_transport_header(nskb); |
66 | tcph = (struct tcphdr *)skb_put(nskb, sizeof(struct tcphdr)); | 75 | tcph = (struct tcphdr *)skb_put(nskb, sizeof(struct tcphdr)); |
@@ -69,9 +78,9 @@ void nf_send_reset(struct sk_buff *oldskb, int hook) | |||
69 | tcph->dest = oth->source; | 78 | tcph->dest = oth->source; |
70 | tcph->doff = sizeof(struct tcphdr) / 4; | 79 | tcph->doff = sizeof(struct tcphdr) / 4; |
71 | 80 | ||
72 | if (oth->ack) | 81 | if (oth->ack) { |
73 | tcph->seq = oth->ack_seq; | 82 | tcph->seq = oth->ack_seq; |
74 | else { | 83 | } else { |
75 | tcph->ack_seq = htonl(ntohl(oth->seq) + oth->syn + oth->fin + | 84 | tcph->ack_seq = htonl(ntohl(oth->seq) + oth->syn + oth->fin + |
76 | oldskb->len - ip_hdrlen(oldskb) - | 85 | oldskb->len - ip_hdrlen(oldskb) - |
77 | (oth->doff << 2)); | 86 | (oth->doff << 2)); |
@@ -84,16 +93,43 @@ void nf_send_reset(struct sk_buff *oldskb, int hook) | |||
84 | nskb->ip_summed = CHECKSUM_PARTIAL; | 93 | nskb->ip_summed = CHECKSUM_PARTIAL; |
85 | nskb->csum_start = (unsigned char *)tcph - nskb->head; | 94 | nskb->csum_start = (unsigned char *)tcph - nskb->head; |
86 | nskb->csum_offset = offsetof(struct tcphdr, check); | 95 | nskb->csum_offset = offsetof(struct tcphdr, check); |
96 | } | ||
97 | EXPORT_SYMBOL_GPL(nf_reject_ip_tcphdr_put); | ||
98 | |||
99 | /* Send RST reply */ | ||
100 | void nf_send_reset(struct sk_buff *oldskb, int hook) | ||
101 | { | ||
102 | struct sk_buff *nskb; | ||
103 | const struct iphdr *oiph; | ||
104 | struct iphdr *niph; | ||
105 | const struct tcphdr *oth; | ||
106 | struct tcphdr _oth; | ||
107 | |||
108 | oth = nf_reject_ip_tcphdr_get(oldskb, &_oth, hook); | ||
109 | if (!oth) | ||
110 | return; | ||
111 | |||
112 | if (skb_rtable(oldskb)->rt_flags & (RTCF_BROADCAST | RTCF_MULTICAST)) | ||
113 | return; | ||
114 | |||
115 | oiph = ip_hdr(oldskb); | ||
116 | |||
117 | nskb = alloc_skb(sizeof(struct iphdr) + sizeof(struct tcphdr) + | ||
118 | LL_MAX_HEADER, GFP_ATOMIC); | ||
119 | if (!nskb) | ||
120 | return; | ||
87 | 121 | ||
88 | /* ip_route_me_harder expects skb->dst to be set */ | 122 | /* ip_route_me_harder expects skb->dst to be set */ |
89 | skb_dst_set_noref(nskb, skb_dst(oldskb)); | 123 | skb_dst_set_noref(nskb, skb_dst(oldskb)); |
90 | 124 | ||
91 | nskb->protocol = htons(ETH_P_IP); | 125 | skb_reserve(nskb, LL_MAX_HEADER); |
126 | niph = nf_reject_iphdr_put(nskb, oldskb, IPPROTO_TCP, | ||
127 | ip4_dst_hoplimit(skb_dst(nskb))); | ||
128 | nf_reject_ip_tcphdr_put(nskb, oldskb, oth); | ||
129 | |||
92 | if (ip_route_me_harder(nskb, RTN_UNSPEC)) | 130 | if (ip_route_me_harder(nskb, RTN_UNSPEC)) |
93 | goto free_nskb; | 131 | goto free_nskb; |
94 | 132 | ||
95 | niph->ttl = ip4_dst_hoplimit(skb_dst(nskb)); | ||
96 | |||
97 | /* "Never happens" */ | 133 | /* "Never happens" */ |
98 | if (nskb->len > dst_mtu(skb_dst(nskb))) | 134 | if (nskb->len > dst_mtu(skb_dst(nskb))) |
99 | goto free_nskb; | 135 | goto free_nskb; |