aboutsummaryrefslogtreecommitdiffstats
path: root/net/dccp
diff options
context:
space:
mode:
authorEric Dumazet <edumazet@google.com>2015-03-22 13:22:24 -0400
committerDavid S. Miller <davem@davemloft.net>2015-03-23 16:52:26 -0400
commit85645bab57bfc6b0b43bb96a301c4ef83925c07d (patch)
treeadc831565f5f8e0bb666f087cf656b2b18d48f4b /net/dccp
parent2215089b224412bfb28c5ae823b2a5d4e28a49d7 (diff)
ipv4: dccp: handle ICMP messages on DCCP_NEW_SYN_RECV request sockets
dccp_v4_err() can restrict lookups to ehash table, and not to listeners. Note this patch creates the infrastructure, but this means that ICMP messages for request sockets are ignored until complete conversion. New dccp_req_err() helper is exported so that we can use it in IPv6 in following patch. Signed-off-by: Eric Dumazet <edumazet@google.com> Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'net/dccp')
-rw-r--r--net/dccp/dccp.h1
-rw-r--r--net/dccp/ipv4.c70
2 files changed, 35 insertions, 36 deletions
diff --git a/net/dccp/dccp.h b/net/dccp/dccp.h
index 2396f50c5b04..bebc735f5afc 100644
--- a/net/dccp/dccp.h
+++ b/net/dccp/dccp.h
@@ -317,6 +317,7 @@ int inet_dccp_listen(struct socket *sock, int backlog);
317unsigned int dccp_poll(struct file *file, struct socket *sock, 317unsigned int dccp_poll(struct file *file, struct socket *sock,
318 poll_table *wait); 318 poll_table *wait);
319int dccp_v4_connect(struct sock *sk, struct sockaddr *uaddr, int addr_len); 319int dccp_v4_connect(struct sock *sk, struct sockaddr *uaddr, int addr_len);
320void dccp_req_err(struct sock *sk, u64 seq);
320 321
321struct sk_buff *dccp_ctl_make_reset(struct sock *sk, struct sk_buff *skb); 322struct sk_buff *dccp_ctl_make_reset(struct sock *sk, struct sk_buff *skb);
322int dccp_send_reset(struct sock *sk, enum dccp_reset_codes code); 323int dccp_send_reset(struct sock *sk, enum dccp_reset_codes code);
diff --git a/net/dccp/ipv4.c b/net/dccp/ipv4.c
index 1f7161e05403..6310b8b19598 100644
--- a/net/dccp/ipv4.c
+++ b/net/dccp/ipv4.c
@@ -195,6 +195,32 @@ static void dccp_do_redirect(struct sk_buff *skb, struct sock *sk)
195 dst->ops->redirect(dst, sk, skb); 195 dst->ops->redirect(dst, sk, skb);
196} 196}
197 197
198void dccp_req_err(struct sock *sk, u64 seq)
199 {
200 struct request_sock *req = inet_reqsk(sk);
201 struct net *net = sock_net(sk);
202
203 /*
204 * ICMPs are not backlogged, hence we cannot get an established
205 * socket here.
206 */
207 WARN_ON(req->sk);
208
209 if (!between48(seq, dccp_rsk(req)->dreq_iss, dccp_rsk(req)->dreq_gss)) {
210 NET_INC_STATS_BH(net, LINUX_MIB_OUTOFWINDOWICMPS);
211 } else {
212 /*
213 * Still in RESPOND, just remove it silently.
214 * There is no good way to pass the error to the newly
215 * created socket, and POSIX does not want network
216 * errors returned from accept().
217 */
218 inet_csk_reqsk_queue_drop(req->rsk_listener, req);
219 }
220 reqsk_put(req);
221}
222EXPORT_SYMBOL(dccp_req_err);
223
198/* 224/*
199 * This routine is called by the ICMP module when it gets some sort of error 225 * This routine is called by the ICMP module when it gets some sort of error
200 * condition. If err < 0 then the socket should be closed and the error 226 * condition. If err < 0 then the socket should be closed and the error
@@ -227,10 +253,11 @@ static void dccp_v4_err(struct sk_buff *skb, u32 info)
227 return; 253 return;
228 } 254 }
229 255
230 sk = inet_lookup(net, &dccp_hashinfo, 256 sk = __inet_lookup_established(net, &dccp_hashinfo,
231 iph->daddr, dh->dccph_dport, 257 iph->daddr, dh->dccph_dport,
232 iph->saddr, dh->dccph_sport, inet_iif(skb)); 258 iph->saddr, ntohs(dh->dccph_sport),
233 if (sk == NULL) { 259 inet_iif(skb));
260 if (!sk) {
234 ICMP_INC_STATS_BH(net, ICMP_MIB_INERRORS); 261 ICMP_INC_STATS_BH(net, ICMP_MIB_INERRORS);
235 return; 262 return;
236 } 263 }
@@ -239,6 +266,9 @@ static void dccp_v4_err(struct sk_buff *skb, u32 info)
239 inet_twsk_put(inet_twsk(sk)); 266 inet_twsk_put(inet_twsk(sk));
240 return; 267 return;
241 } 268 }
269 seq = dccp_hdr_seq(dh);
270 if (sk->sk_state == DCCP_NEW_SYN_RECV)
271 return dccp_req_err(sk, seq);
242 272
243 bh_lock_sock(sk); 273 bh_lock_sock(sk);
244 /* If too many ICMPs get dropped on busy 274 /* If too many ICMPs get dropped on busy
@@ -251,7 +281,6 @@ static void dccp_v4_err(struct sk_buff *skb, u32 info)
251 goto out; 281 goto out;
252 282
253 dp = dccp_sk(sk); 283 dp = dccp_sk(sk);
254 seq = dccp_hdr_seq(dh);
255 if ((1 << sk->sk_state) & ~(DCCPF_REQUESTING | DCCPF_LISTEN) && 284 if ((1 << sk->sk_state) & ~(DCCPF_REQUESTING | DCCPF_LISTEN) &&
256 !between48(seq, dp->dccps_awl, dp->dccps_awh)) { 285 !between48(seq, dp->dccps_awl, dp->dccps_awh)) {
257 NET_INC_STATS_BH(net, LINUX_MIB_OUTOFWINDOWICMPS); 286 NET_INC_STATS_BH(net, LINUX_MIB_OUTOFWINDOWICMPS);
@@ -288,37 +317,6 @@ static void dccp_v4_err(struct sk_buff *skb, u32 info)
288 } 317 }
289 318
290 switch (sk->sk_state) { 319 switch (sk->sk_state) {
291 struct request_sock *req;
292 case DCCP_LISTEN:
293 if (sock_owned_by_user(sk))
294 goto out;
295 req = inet_csk_search_req(sk, dh->dccph_dport,
296 iph->daddr, iph->saddr);
297 if (!req)
298 goto out;
299
300 /*
301 * ICMPs are not backlogged, hence we cannot get an established
302 * socket here.
303 */
304 WARN_ON(req->sk);
305
306 if (!between48(seq, dccp_rsk(req)->dreq_iss,
307 dccp_rsk(req)->dreq_gss)) {
308 NET_INC_STATS_BH(net, LINUX_MIB_OUTOFWINDOWICMPS);
309 reqsk_put(req);
310 goto out;
311 }
312 /*
313 * Still in RESPOND, just remove it silently.
314 * There is no good way to pass the error to the newly
315 * created socket, and POSIX does not want network
316 * errors returned from accept().
317 */
318 inet_csk_reqsk_queue_drop(sk, req);
319 reqsk_put(req);
320 goto out;
321
322 case DCCP_REQUESTING: 320 case DCCP_REQUESTING:
323 case DCCP_RESPOND: 321 case DCCP_RESPOND:
324 if (!sock_owned_by_user(sk)) { 322 if (!sock_owned_by_user(sk)) {