linux ip rcv,【linux网络】ip_rcv()函数

/* * Main IP Receive routine. * 对IP头部合法性进行严格检查,然后把具体功能交给ip_rcv_finish */

int ip_rcv(struct sk_buff *skb, struct net_device *dev, struct packet_type *pt, struct net_device *orig_dev)

{

const struct iphdr *iph;

u32 len;

/* * 当网卡处于混杂模式时,丢掉所有接收到的的垃圾数据,不要试图解析它 */

//noted: 其实也就是丢弃掉不是发往本地的数据包。网卡在混杂模式下会接收一切到达网卡的数据,不管目的地mac是否是本网卡

//noted: 在调用ip_rcv之前,内核会将该数据包交给嗅探器,所以该函数仅丢弃该包

if (skb->pkt_type == PACKET_OTHERHOST)

goto drop;

//noted:该宏用于内核做一些统计,关于网络层snmp统计的信息,也可以通过netstat 指令看到这些统计值

IP_UPD_PO_STATS_BH(dev_net(dev), IPSTATS_MIB_IN, skb->len);

//noted: ip_rcv是由netif_receive_skb函数调用,如果嗅探器或者其他的用户对数据包需要进

//进行处理,则在调用ip_rcv之前,netif_receive_skb会增加skb的引用计数,既该引

//用计数会大于1。若如此次,则skb_share_check会创建sk_buff的一份拷贝。

if ((skb = skb_share_check(skb, GFP_ATOMIC)) == NULL) {

//noted: SNMP所需要的统计数据,忽略

IP_INC_STATS_BH(dev_net(dev), IPSTATS_MIB_INDISCARDS);

goto out;

}

//noted:pskb_may_pull确保skb->data指向的内存包含的数据至少为IP头部大小,由于每个

//IP数据包包括IP分片必须包含一个完整的IP头部。如果小于IP头部大小,则缺失

//的部分将从数据分片中拷贝。这些分片保存在skb_shinfo(skb)->frags[]中。

if (!pskb_may_pull(skb, sizeof(struct iphdr)))

goto inhdr_error;

//noted: pskb_may_pull可能会调整skb中的指针,所以需要重新定义IP头部

iph = ip_hdr(skb);

/* * RFC1122: 3.2.1.2 必须默默地放弃任何IP帧校验和失败. * * 数据报可接收? * * 1. 长度至少是一个ip报头的大小 * 2. 版本4 * 3. 校验和正确。(速度优化后,跳过回路校验和) * 4. 没有虚假的长度 */

//noted: 检测ip首部长度及协议版本

if (iph->ihl <5 || iph->version !=4)

goto inhdr_error;

//noted: 确保IP完整的头部包括选项在内存中

if (!pskb_may_pull(skb, iph->ihl*4))

goto inhdr_error;

iph = ip_hdr(skb);

//noted:验证IP头部的校验和

if (unlikely(ip_fast_csum((u8 *)iph, iph->ihl)))

goto csum_error;

//noted:检测ip报文长度是否小于skb->len

len = ntohs(iph->tot_len);

if (skb->len < len) {

IP_INC_STATS_BH(dev_net(dev), IPSTATS_MIB_INTRUNCATEDPKTS);

goto drop;

} else if (len < (iph->ihl*4))

goto inhdr_error;

/* 我们的传输介质可能填充缓冲区。现在我们知道这是 我们可以从此帧中削减的真实长度的ip帧 * 注意现在意味着skb->len包括ntohs(iph->tot_len) */

if (pskb_trim_rcsum(skb, len)) {

IP_INC_STATS_BH(dev_net(dev), IPSTATS_MIB_INDISCARDS);

goto drop;

}

//noted: 设置tcp报头指针

skb->transport_header = skb->network_header + iph->ihl*4;

/* 删除任何套接字控制块碎片 */

memset(IPCB(skb),0, sizeof(struct inet_skb_parm));

/* 因为tproxy,现在必须丢掉socket */

//noted: tproxy是iptables的一附加控件,在mangle表的PREROUTING链中使用,不修改数据包包头,

//直接把数据传递给一个本地socket(即不对数据包进行任何nat操作)。具体百度搜索tproxy

skb_orphan(skb);

//noted: 在做完基本的头校验等工作后,就交由NF_HOOK管理了

//noted: NF_HOOK在做完PRE_ROUTING的筛选后,PRE_ROUTING点上注册的所有钩子都

//返回NF_ACCEPT才会执行后面的ip_rcv_finish函数 ,然后继续执行路由等处理

//如果是本地的就会交给更高层的协议进行处理,如果不是交由本地的就执行FORWARD

return NF_HOOK(NFPROTO_IPV4, NF_INET_PRE_ROUTING, skb, dev, NULL,

ip_rcv_finish);

csum_error:

IP_INC_STATS_BH(dev_net(dev), IPSTATS_MIB_CSUMERRORS);

inhdr_error:

IP_INC_STATS_BH(dev_net(dev), IPSTATS_MIB_INHDRERRORS);

drop:

kfree_skb(skb);

out:

return NET_RX_DROP;

}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值