aboutsummaryrefslogtreecommitdiffstats
path: root/net/ipv4
diff options
context:
space:
mode:
authorDenys Vlasenko <vda.linux@googlemail.com>2008-01-15 02:44:26 -0500
committerDavid S. Miller <davem@davemloft.net>2008-01-28 18:02:30 -0500
commit9ba99b0d3f45d0aedeafce1cfa4f720b19d04477 (patch)
tree54c5aab40ef717d111deecc1f28fe3d09bda13b9 /net/ipv4
parent022748a9357c4c1a0113ec1ce5612f383b80156f (diff)
[NETFILTER]: ipt_REJECT: properly handle IP options
The current TCP RST construction reuses the old packet and can't deal with IP options as a consequence of that. Construct the RST from scratch instead. Signed-off-by: Patrick McHardy <kaber@trash.net> Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'net/ipv4')
-rw-r--r--net/ipv4/netfilter/ipt_REJECT.c102
1 files changed, 37 insertions, 65 deletions
diff --git a/net/ipv4/netfilter/ipt_REJECT.c b/net/ipv4/netfilter/ipt_REJECT.c
index e3c2ecc341e..22606e2baa1 100644
--- a/net/ipv4/netfilter/ipt_REJECT.c
+++ b/net/ipv4/netfilter/ipt_REJECT.c
@@ -35,11 +35,8 @@ MODULE_DESCRIPTION("Xtables: packet \"rejection\" target for IPv4");
35static void send_reset(struct sk_buff *oldskb, int hook) 35static void send_reset(struct sk_buff *oldskb, int hook)
36{ 36{
37 struct sk_buff *nskb; 37 struct sk_buff *nskb;
38 struct iphdr *niph; 38 struct iphdr *oiph, *niph;
39 struct tcphdr _otcph, *oth, *tcph; 39 struct tcphdr _otcph, *oth, *tcph;
40 __be16 tmp_port;
41 __be32 tmp_addr;
42 int needs_ack;
43 unsigned int addr_type; 40 unsigned int addr_type;
44 41
45 /* IP header checks: fragment. */ 42 /* IP header checks: fragment. */
@@ -58,69 +55,47 @@ static void send_reset(struct sk_buff *oldskb, int hook)
58 /* Check checksum */ 55 /* Check checksum */
59 if (nf_ip_checksum(oldskb, hook, ip_hdrlen(oldskb), IPPROTO_TCP)) 56 if (nf_ip_checksum(oldskb, hook, ip_hdrlen(oldskb), IPPROTO_TCP))
60 return; 57 return;
58 oiph = ip_hdr(oldskb);
61 59
62 /* We need a linear, writeable skb. We also need to expand 60 nskb = alloc_skb(sizeof(struct iphdr) + sizeof(struct tcphdr) +
63 headroom in case hh_len of incoming interface < hh_len of 61 LL_MAX_HEADER, GFP_ATOMIC);
64 outgoing interface */
65 nskb = skb_copy_expand(oldskb, LL_MAX_HEADER, skb_tailroom(oldskb),
66 GFP_ATOMIC);
67 if (!nskb) 62 if (!nskb)
68 return; 63 return;
69 64
70 /* This packet will not be the same as the other: clear nf fields */ 65 skb_reserve(nskb, LL_MAX_HEADER);
71 nf_reset(nskb); 66
72 nskb->mark = 0; 67 skb_reset_network_header(nskb);
73 skb_init_secmark(nskb); 68 niph = (struct iphdr *)skb_put(nskb, sizeof(struct iphdr));
74 69 niph->version = 4;
75 skb_shinfo(nskb)->gso_size = 0; 70 niph->ihl = sizeof(struct iphdr) / 4;
76 skb_shinfo(nskb)->gso_segs = 0; 71 niph->tos = 0;
77 skb_shinfo(nskb)->gso_type = 0; 72 niph->id = 0;
78 73 niph->frag_off = htons(IP_DF);
79 tcph = (struct tcphdr *)(skb_network_header(nskb) + ip_hdrlen(nskb)); 74 niph->protocol = IPPROTO_TCP;
80 75 niph->check = 0;
81 /* Swap source and dest */ 76 niph->saddr = oiph->daddr;
82 niph = ip_hdr(nskb); 77 niph->daddr = oiph->saddr;
83 tmp_addr = niph->saddr; 78
84 niph->saddr = niph->daddr; 79 tcph = (struct tcphdr *)skb_put(nskb, sizeof(struct tcphdr));
85 niph->daddr = tmp_addr; 80 memset(tcph, 0, sizeof(*tcph));
86 tmp_port = tcph->source; 81 tcph->source = oth->dest;
87 tcph->source = tcph->dest; 82 tcph->dest = oth->source;
88 tcph->dest = tmp_port; 83 tcph->doff = sizeof(struct tcphdr) / 4;
89 84
90 /* Truncate to length (no data) */ 85 if (oth->ack)
91 tcph->doff = sizeof(struct tcphdr)/4;
92 skb_trim(nskb, ip_hdrlen(nskb) + sizeof(struct tcphdr));
93
94 if (tcph->ack) {
95 needs_ack = 0;
96 tcph->seq = oth->ack_seq; 86 tcph->seq = oth->ack_seq;
97 tcph->ack_seq = 0; 87 else {
98 } else {
99 needs_ack = 1;
100 tcph->ack_seq = htonl(ntohl(oth->seq) + oth->syn + oth->fin + 88 tcph->ack_seq = htonl(ntohl(oth->seq) + oth->syn + oth->fin +
101 oldskb->len - ip_hdrlen(oldskb) - 89 oldskb->len - ip_hdrlen(oldskb) -
102 (oth->doff << 2)); 90 (oth->doff << 2));
103 tcph->seq = 0; 91 tcph->ack = 1;
104 } 92 }
105 93
106 /* Reset flags */ 94 tcph->rst = 1;
107 ((u_int8_t *)tcph)[13] = 0; 95 tcph->check = tcp_v4_check(sizeof(struct tcphdr),
108 tcph->rst = 1; 96 niph->saddr, niph->daddr,
109 tcph->ack = needs_ack; 97 csum_partial(tcph,
110 98 sizeof(struct tcphdr), 0));
111 tcph->window = 0;
112 tcph->urg_ptr = 0;
113
114 /* Adjust TCP checksum */
115 tcph->check = 0;
116 tcph->check = tcp_v4_check(sizeof(struct tcphdr),
117 niph->saddr, niph->daddr,
118 csum_partial(tcph,
119 sizeof(struct tcphdr), 0));
120
121 /* Set DF, id = 0 */
122 niph->frag_off = htons(IP_DF);
123 niph->id = 0;
124 99
125 addr_type = RTN_UNSPEC; 100 addr_type = RTN_UNSPEC;
126 if (hook != NF_INET_FORWARD 101 if (hook != NF_INET_FORWARD
@@ -130,14 +105,16 @@ static void send_reset(struct sk_buff *oldskb, int hook)
130 ) 105 )
131 addr_type = RTN_LOCAL; 106 addr_type = RTN_LOCAL;
132 107
108 /* ip_route_me_harder expects skb->dst to be set */
109 dst_hold(oldskb->dst);
110 nskb->dst = oldskb->dst;
111
133 if (ip_route_me_harder(nskb, addr_type)) 112 if (ip_route_me_harder(nskb, addr_type))
134 goto free_nskb; 113 goto free_nskb;
135 114
115 niph->ttl = dst_metric(nskb->dst, RTAX_HOPLIMIT);
136 nskb->ip_summed = CHECKSUM_NONE; 116 nskb->ip_summed = CHECKSUM_NONE;
137 117
138 /* Adjust IP TTL */
139 niph->ttl = dst_metric(nskb->dst, RTAX_HOPLIMIT);
140
141 /* "Never happens" */ 118 /* "Never happens" */
142 if (nskb->len > dst_mtu(nskb->dst)) 119 if (nskb->len > dst_mtu(nskb->dst))
143 goto free_nskb; 120 goto free_nskb;
@@ -163,11 +140,6 @@ reject_tg(struct sk_buff *skb, const struct net_device *in,
163{ 140{
164 const struct ipt_reject_info *reject = targinfo; 141 const struct ipt_reject_info *reject = targinfo;
165 142
166 /* Our naive response construction doesn't deal with IP
167 options, and probably shouldn't try. */
168 if (ip_hdrlen(skb) != sizeof(struct iphdr))
169 return NF_DROP;
170
171 /* WARNING: This code causes reentry within iptables. 143 /* WARNING: This code causes reentry within iptables.
172 This means that the iptables jump stack is now crap. We 144 This means that the iptables jump stack is now crap. We
173 must return an absolute verdict. --RR */ 145 must return an absolute verdict. --RR */