diff options
-rw-r--r-- | net/ipv4/ip_input.c | 93 |
1 files changed, 54 insertions, 39 deletions
diff --git a/net/ipv4/ip_input.c b/net/ipv4/ip_input.c index 6a06e15694dc..48e4ddc1e337 100644 --- a/net/ipv4/ip_input.c +++ b/net/ipv4/ip_input.c | |||
@@ -279,6 +279,58 @@ int ip_local_deliver(struct sk_buff *skb) | |||
279 | ip_local_deliver_finish); | 279 | ip_local_deliver_finish); |
280 | } | 280 | } |
281 | 281 | ||
282 | static inline int ip_rcv_options(struct sk_buff *skb) | ||
283 | { | ||
284 | struct ip_options *opt; | ||
285 | struct iphdr *iph; | ||
286 | struct net_device *dev = skb->dev; | ||
287 | |||
288 | /* It looks as overkill, because not all | ||
289 | IP options require packet mangling. | ||
290 | But it is the easiest for now, especially taking | ||
291 | into account that combination of IP options | ||
292 | and running sniffer is extremely rare condition. | ||
293 | --ANK (980813) | ||
294 | */ | ||
295 | if (skb_cow(skb, skb_headroom(skb))) { | ||
296 | IP_INC_STATS_BH(IPSTATS_MIB_INDISCARDS); | ||
297 | goto drop; | ||
298 | } | ||
299 | |||
300 | iph = skb->nh.iph; | ||
301 | |||
302 | if (ip_options_compile(NULL, skb)) { | ||
303 | IP_INC_STATS_BH(IPSTATS_MIB_INHDRERRORS); | ||
304 | goto drop; | ||
305 | } | ||
306 | |||
307 | opt = &(IPCB(skb)->opt); | ||
308 | if (unlikely(opt->srr)) { | ||
309 | struct in_device *in_dev = in_dev_get(dev); | ||
310 | if (in_dev) { | ||
311 | if (!IN_DEV_SOURCE_ROUTE(in_dev)) { | ||
312 | if (IN_DEV_LOG_MARTIANS(in_dev) && | ||
313 | net_ratelimit()) | ||
314 | printk(KERN_INFO "source route option " | ||
315 | "%u.%u.%u.%u -> %u.%u.%u.%u\n", | ||
316 | NIPQUAD(iph->saddr), | ||
317 | NIPQUAD(iph->daddr)); | ||
318 | in_dev_put(in_dev); | ||
319 | goto drop; | ||
320 | } | ||
321 | |||
322 | in_dev_put(in_dev); | ||
323 | } | ||
324 | |||
325 | if (ip_options_rcv_srr(skb)) | ||
326 | goto drop; | ||
327 | } | ||
328 | |||
329 | return 0; | ||
330 | drop: | ||
331 | return -1; | ||
332 | } | ||
333 | |||
282 | static inline int ip_rcv_finish(struct sk_buff *skb) | 334 | static inline int ip_rcv_finish(struct sk_buff *skb) |
283 | { | 335 | { |
284 | struct net_device *dev = skb->dev; | 336 | struct net_device *dev = skb->dev; |
@@ -308,48 +360,11 @@ static inline int ip_rcv_finish(struct sk_buff *skb) | |||
308 | } | 360 | } |
309 | #endif | 361 | #endif |
310 | 362 | ||
311 | if (iph->ihl > 5) { | 363 | if (iph->ihl > 5 && ip_rcv_options(skb)) |
312 | struct ip_options *opt; | 364 | goto drop; |
313 | |||
314 | /* It looks as overkill, because not all | ||
315 | IP options require packet mangling. | ||
316 | But it is the easiest for now, especially taking | ||
317 | into account that combination of IP options | ||
318 | and running sniffer is extremely rare condition. | ||
319 | --ANK (980813) | ||
320 | */ | ||
321 | |||
322 | if (skb_cow(skb, skb_headroom(skb))) { | ||
323 | IP_INC_STATS_BH(IPSTATS_MIB_INDISCARDS); | ||
324 | goto drop; | ||
325 | } | ||
326 | iph = skb->nh.iph; | ||
327 | |||
328 | if (ip_options_compile(NULL, skb)) | ||
329 | goto inhdr_error; | ||
330 | |||
331 | opt = &(IPCB(skb)->opt); | ||
332 | if (opt->srr) { | ||
333 | struct in_device *in_dev = in_dev_get(dev); | ||
334 | if (in_dev) { | ||
335 | if (!IN_DEV_SOURCE_ROUTE(in_dev)) { | ||
336 | if (IN_DEV_LOG_MARTIANS(in_dev) && net_ratelimit()) | ||
337 | printk(KERN_INFO "source route option %u.%u.%u.%u -> %u.%u.%u.%u\n", | ||
338 | NIPQUAD(iph->saddr), NIPQUAD(iph->daddr)); | ||
339 | in_dev_put(in_dev); | ||
340 | goto drop; | ||
341 | } | ||
342 | in_dev_put(in_dev); | ||
343 | } | ||
344 | if (ip_options_rcv_srr(skb)) | ||
345 | goto drop; | ||
346 | } | ||
347 | } | ||
348 | 365 | ||
349 | return dst_input(skb); | 366 | return dst_input(skb); |
350 | 367 | ||
351 | inhdr_error: | ||
352 | IP_INC_STATS_BH(IPSTATS_MIB_INHDRERRORS); | ||
353 | drop: | 368 | drop: |
354 | kfree_skb(skb); | 369 | kfree_skb(skb); |
355 | return NET_RX_DROP; | 370 | return NET_RX_DROP; |