#2
hellovfp2012-08-02 12:53
|
当一个包被送到了ip_rcv()之后,收到的信息必须被检查,
以确保包的正确性。最主要的检查就是checksum的计算,
看它是否和header中的值相匹配。
其他检查包括packet大小是否有IP header的最小值;
这个包是不是IP version 4。
当检查做完之后,内核不会立刻处理这个包,而是允许一个 netfilter hook被唤醒,
那样packet就可以在userspace被处理了。
netfilter hook 被安插在内核代码的一些固定地方,来使得packet可以被动态的操作。
这些Hooks在网络这个子系统的不同处,并且每个都有一个label,比如
NF_IP_POST_ROUTING.
当kernel来到了hook处,一些为了这个label而被注册的程序(routine)则在 userspace被唤醒。
下一步,这些被收到的IP packet 就来到了十字路口,是被送往本地机器更高层还是被送往远程机器(remote computer)。
函数ip_route_input()负责作出选择,到底是选ip_local_deliver()函数还是ip_forward()函数
ip_rcv()函数定已在linux/net/ipv4/in_input.c中
程序代码:
370/*
371 * Main IP Receive routine.
372 */
373int ip_rcv(struct sk_buff *skb, struct net_device *dev, struct packet_type *pt, struct net_device *orig_dev)
374{
375 struct iphdr *iph;
376 u32 len;
377
378 /* When the interface is in promisc. mode, drop all the crap
379 * that it receives, do not try to analyse it.
380 */
381 if (skb->pkt_type == PACKET_OTHERHOST)
382 goto drop;
383
384 IP_INC_STATS_BH(IPSTATS_MIB_INRECEIVES);
385
386 if ((skb = skb_share_check(skb, GFP_ATOMIC)) == NULL) {
387 IP_INC_STATS_BH(IPSTATS_MIB_INDISCARDS);
388 goto out;
389 }
390
391 if (!pskb_may_pull(skb, sizeof(struct iphdr)))
392 goto inhdr_error;
393
394 iph = skb->nh.iph;
395
396 /*
397 * RFC1122: 3.1.2.2 MUST silently discard any IP frame that fails the checksum.
398 *
399 * Is the datagram acceptable?
400 *
401 * 1. Length at least the size of an ip header
402 * 2. Version of 4
403 * 3. Checksums correctly. [Speed optimisation for later, skip loopback checksums]
404 * 4. Doesn't have a bogus length
405 */
406
407 if (iph->ihl < 5 || iph->version != 4)
408 goto inhdr_error;
409
410 if (!pskb_may_pull(skb, iph->ihl*4))
411 goto inhdr_error;
412
413 iph = skb->nh.iph;
414
415 if (unlikely(ip_fast_csum((u8 *)iph, iph->ihl)))
416 goto inhdr_error;
417
418 len = ntohs(iph->tot_len);
419 if (skb->len < len || len < (iph->ihl*4))
420 goto inhdr_error;
421
422 /* Our transport medium may have padded the buffer out. Now we know it
423 * is IP we can trim to the true length of the frame.
424 * Note this now means skb->len holds ntohs(iph->tot_len).
425 */
426 if (pskb_trim_rcsum(skb, len)) {
427 IP_INC_STATS_BH(IPSTATS_MIB_INDISCARDS);
428 goto drop;
429 }
430
431 /* Remove any debris in the socket control block */
432 memset(IPCB(skb), 0, sizeof(struct inet_skb_parm));
433
434 return NF_HOOK(PF_INET, NF_IP_PRE_ROUTING, skb, dev, NULL,
435 ip_rcv_finish);
436
437inhdr_error:
438 IP_INC_STATS_BH(IPSTATS_MIB_INHDRERRORS);
439drop:
440 kfree_skb(skb);
441out:
442 return NET_RX_DROP;
443}
371 * Main IP Receive routine.
372 */
373int ip_rcv(struct sk_buff *skb, struct net_device *dev, struct packet_type *pt, struct net_device *orig_dev)
374{
375 struct iphdr *iph;
376 u32 len;
377
378 /* When the interface is in promisc. mode, drop all the crap
379 * that it receives, do not try to analyse it.
380 */
381 if (skb->pkt_type == PACKET_OTHERHOST)
382 goto drop;
383
384 IP_INC_STATS_BH(IPSTATS_MIB_INRECEIVES);
385
386 if ((skb = skb_share_check(skb, GFP_ATOMIC)) == NULL) {
387 IP_INC_STATS_BH(IPSTATS_MIB_INDISCARDS);
388 goto out;
389 }
390
391 if (!pskb_may_pull(skb, sizeof(struct iphdr)))
392 goto inhdr_error;
393
394 iph = skb->nh.iph;
395
396 /*
397 * RFC1122: 3.1.2.2 MUST silently discard any IP frame that fails the checksum.
398 *
399 * Is the datagram acceptable?
400 *
401 * 1. Length at least the size of an ip header
402 * 2. Version of 4
403 * 3. Checksums correctly. [Speed optimisation for later, skip loopback checksums]
404 * 4. Doesn't have a bogus length
405 */
406
407 if (iph->ihl < 5 || iph->version != 4)
408 goto inhdr_error;
409
410 if (!pskb_may_pull(skb, iph->ihl*4))
411 goto inhdr_error;
412
413 iph = skb->nh.iph;
414
415 if (unlikely(ip_fast_csum((u8 *)iph, iph->ihl)))
416 goto inhdr_error;
417
418 len = ntohs(iph->tot_len);
419 if (skb->len < len || len < (iph->ihl*4))
420 goto inhdr_error;
421
422 /* Our transport medium may have padded the buffer out. Now we know it
423 * is IP we can trim to the true length of the frame.
424 * Note this now means skb->len holds ntohs(iph->tot_len).
425 */
426 if (pskb_trim_rcsum(skb, len)) {
427 IP_INC_STATS_BH(IPSTATS_MIB_INDISCARDS);
428 goto drop;
429 }
430
431 /* Remove any debris in the socket control block */
432 memset(IPCB(skb), 0, sizeof(struct inet_skb_parm));
433
434 return NF_HOOK(PF_INET, NF_IP_PRE_ROUTING, skb, dev, NULL,
435 ip_rcv_finish);
436
437inhdr_error:
438 IP_INC_STATS_BH(IPSTATS_MIB_INHDRERRORS);
439drop:
440 kfree_skb(skb);
441out:
442 return NET_RX_DROP;
443}
[ 本帖最后由 madfrogme 于 2012-8-2 01:48 编辑 ]