intip_rcv(struct sk_buff *skb,struct net_device *dev,struct packet_type *pt,struct net_device *orig_dev){struct iphdr *iph;
u32 len;/* When the interface is in promisc. mode, drop all the crap
* that it receives, do not try to analyse it.
*/// 若目的mac地址不是本机mac地址,丢包if(skb->pkt_type == PACKET_OTHERHOST)goto drop;IP_UPD_PO_STATS_BH(dev_net(dev), IPSTATS_MIB_IN, skb->len);// 检查skb是否共享,若共享,clone skbif((skb =skb_share_check(skb, GFP_ATOMIC))==NULL){IP_INC_STATS_BH(dev_net(dev), IPSTATS_MIB_INDISCARDS);goto out;}// 检查data到tail的长度是否 >= sizeof(struct iphdr)if(!pskb_may_pull(skb,sizeof(struct iphdr)))goto inhdr_error;
iph =ip_hdr(skb);// ip_hdr() -> skb_network_header()/*
* RFC1122: 3.2.1.2 MUST silently discard any IP frame that fails the checksum.
*
* Is the datagram acceptable?
*
* 1. Length at least the size of an ip header
* 2. Version of 4
* 3. Checksums correctly. [Speed optimisation for later, skip loopback checksums]
* 4. Doesn't have a bogus length
*/if(iph->ihl <5|| iph->version !=4)goto inhdr_error;// 检查data到tail的长度是否 >= iph->ihl*4if(!pskb_may_pull(skb, iph->ihl*4))goto inhdr_error;
iph =ip_hdr(skb);if(unlikely(ip_fast_csum((u8 *)iph, iph->ihl)))goto inhdr_error;
len =ntohs(iph->tot_len);if(skb->len < len){// 若data到tail的长度 < 总长度IP_INC_STATS_BH(dev_net(dev), IPSTATS_MIB_INTRUNCATEDPKTS);goto drop;}elseif(len <(iph->ihl*4))// 若总长度 < iph->ihl*4goto inhdr_error;/* Our transport medium may have padded the buffer out. Now we know it
* is IP we can trim to the true length of the frame.
* Note this now means skb->len holds ntohs(iph->tot_len).
*/if(pskb_trim_rcsum(skb, len)){IP_INC_STATS_BH(dev_net(dev), IPSTATS_MIB_INDISCARDS);goto drop;}/* Remove any debris in the socket control block */memset(IPCB(skb),0,sizeof(struct inet_skb_parm));/* Must drop socket now because of tproxy. */skb_orphan(skb);returnNF_HOOK(PF_INET, NF_INET_PRE_ROUTING, skb, dev,NULL,
ip_rcv_finish);// 调用NF_HOOK宏
inhdr_error:IP_INC_STATS_BH(dev_net(dev), IPSTATS_MIB_INHDRERRORS);
drop:kfree_skb(skb);
out:return NET_RX_DROP;}
NF_HOOK
#define NF_HOOK(pf, hook, skb, indev, outdev, okfn) \
NF_HOOK_THRESH(pf, hook, skb, indev, outdev, okfn, INT_MIN)#define NF_HOOK_THRESH(pf, hook, skb, indev, outdev, okfn, thresh) \
({int __ret; \
if ((__ret=nf_hook_thresh(pf, hook, (skb), indev, outdev, okfn, thresh, 1)) == 1)\
__ret = (okfn)(skb); \ // 执行okfn
__ret;})staticinlineintnf_hook_thresh(u_int8_t pf,unsignedint hook,struct sk_buff *skb,struct net_device *indev,struct net_device *outdev,int(*okfn)(struct sk_buff *),int thresh,int cond){if(!cond)return1;#ifndef CONFIG_NETFILTER_DEBUGif(list_empty(&nf_hooks[pf][hook]))return1;#endifreturnnf_hook_slow(pf, hook, skb, indev, outdev, okfn, thresh);}intnf_hook_slow(u_int8_t pf,unsignedint hook,struct sk_buff *skb,struct net_device *indev,struct net_device *outdev,int(*okfn)(struct sk_buff *),int hook_thresh){struct list_head *elem;unsignedint verdict;int ret =0;/* We may already have this, but read-locks nest anyway */rcu_read_lock();
elem =&nf_hooks[pf][hook];
next_hook:
verdict =nf_iterate(&nf_hooks[pf][hook], skb, hook, indev,
outdev,&elem, okfn, hook_thresh);if(verdict == NF_ACCEPT || verdict == NF_STOP){
ret =1;}elseif(verdict == NF_DROP){kfree_skb(skb);
ret =-EPERM;}elseif((verdict & NF_VERDICT_MASK)== NF_QUEUE){if(!nf_queue(skb, elem, pf, hook, indev, outdev, okfn,
verdict >> NF_VERDICT_BITS))goto next_hook;}rcu_read_unlock();return ret;}unsignedintnf_iterate(struct list_head *head,struct sk_buff *skb,unsignedint hook,conststruct net_device *indev,conststruct net_device *outdev,struct list_head **i,int(*okfn)(struct sk_buff *),int hook_thresh){unsignedint verdict;/*
* The caller must not block between calls to this
* function because of risk of continuing from deleted element.
*/list_for_each_continue_rcu(*i, head){// 遍历NF_INET_PRE_ROUTING链表上的nf_hook_opsstruct nf_hook_ops *elem =(struct nf_hook_ops *)*i;if(hook_thresh > elem->priority)continue;/* Optimization: we don't need to hold module
reference here, since function can't sleep. --RR */
verdict = elem->hook(hook, skb, indev, outdev, okfn);// 执行hook函数if(verdict != NF_ACCEPT){#ifdef CONFIG_NETFILTER_DEBUGif(unlikely((verdict & NF_VERDICT_MASK)> NF_MAX_VERDICT)){NFDEBUG("Evil return from %p(%u).\n",
elem->hook, hook);continue;}#endifif(verdict != NF_REPEAT)return verdict;*i =(*i)->prev;}}return NF_ACCEPT;}