为什么sk_buff的sk总是NULL

kava_java 2011-02-17 12:10:41
下面是代码:
#define __KERNEL__
#define MODULE

#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/netfilter.h>
#include <linux/netfilter_ipv4.h>
#include <linux/if_packet.h>
#include <linux/tcp.h>
#include <linux/jiffies.h>
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/skbuff.h>
#include <linux/ip.h> /* For IP header */
#include <linux/netfilter.h>
#include <linux/netfilter_ipv4.h>
#include <linux/in.h>
#include <net/tcp.h>

MODULE_LICENSE("GPL");

static struct nf_hook_ops nfho;

unsigned int hook_func(unsigned int hooknum,
struct sk_buff **pskb,
const struct net_device *in,
const struct net_device *out,
int (*okfn)(struct sk_buff *))
{
struct sk_buff *skb;
struct iphdr *iph;
struct tcphdr *th;
struct tcp_sock *tp;
int rtt;

// Just for easy read
if (!pskb || !(*pskb))
return NF_ACCEPT;
skb = *pskb;

if (skb->pkt_type != PACKET_HOST)
return NF_ACCEPT;

if (!pskb_may_pull(skb, sizeof(struct tcphdr)))
return NF_ACCEPT;

// Get iphdr
if (!(skb->nh.iph))
return NF_ACCEPT;
iph = skb->nh.iph;

// Let go if not TCP.
if (iph->protocol != IPPROTO_TCP)
return NF_ACCEPT;


// Let go if sanity check fail.
th = tcp_hdr(skb);

if (!(skb->sk)) {
printk(KERN_ALERT "skb->sk:%p, head:%p, data:%p, tail:%p, end:%p\n", skb->sk, skb->head, skb->data, skb->tail, skb->end);
printk(KERN_ALERT "len:%d, data_len:%d, truesize: %d, dest:%d, doff = %d, sizeof(struct tcphdr) = %d\n", skb->len, skb->data_len, skb->truesi
ze, ntohl(th->dest), th->doff, sizeof(struct tcphdr));
return NF_ACCEPT;
}

printk(KERN_ALERT "OK!");

return NF_ACCEPT;

}

int init_module()
{
nfho.hook = hook_func;
nfho.hooknum = NF_IP_LOCAL_IN;
nfho.pf = PF_INET;
nfho.priority = NF_IP_PRI_FIRST;

nf_register_hook(&nfho);

return 0;
}

void cleanup_module()
{
nf_unregister_hook(&nfho);
}


===========
下面是dmesg看到的输出结果:
skb->sk:0000000000000000, head:ffff81005ac4d000, data:ffff81005ac4d0cc, tail:ffff81005ac4d101, end:ffff81005ac4de80
len:53, data_len:0, truesize: 3952, dest:3473408, doff = 0, sizeof(struct tcphdr) = 20
skb->sk:0000000000000000, head:ffff81005b5c8400, data:ffff81005b5c84ac, tail:ffff81005b5c84e0, end:ffff81005b5c8500
len:52, data_len:0, truesize: 496, dest:3407872, doff = 0, sizeof(struct tcphdr) = 20
skb->sk:0000000000000000, head:ffff81005ac4d000, data:ffff81005ac4d0cc, tail:ffff81005ac4d24f, end:ffff81005ac4de80
len:387, data_len:0, truesize: 3952, dest:25362432, doff = 0, sizeof(struct tcphdr) = 20
skb->sk:0000000000000000, head:ffff81005c1ae000, data:ffff81005c1ae0cc, tail:ffff81005c1ae6b4, end:ffff81005c1aee80
len:1512, data_len:0, truesize: 3952, dest:99090432, doff = 0, sizeof(struct tcphdr) = 20
skb->sk:0000000000000000, head:ffff81005c8af000, data:ffff81005c8af0cc, tail:ffff81005c8af101, end:ffff81005c8afe80
len:53, data_len:0, truesize: 3952, dest:3473408, doff = 0, sizeof(struct tcphdr) = 20
skb->sk:0000000000000000, head:ffff81005a3ea000, data:ffff81005a3ea0cc, tail:ffff81005a3ea101, end:ffff81005a3eae80
len:53, data_len:0, truesize: 3952, dest:3473408, doff = 0, sizeof(struct tcphdr) = 20
skb->sk:0000000000000000, head:ffff81005c8af000, data:ffff81005c8af0cc, tail:ffff81005c8af24f, end:ffff81005c8afe80
len:387, data_len:0, truesize: 3952, dest:25362432, doff = 0, sizeof(struct tcphdr) = 20
skb->sk:0000000000000000, head:ffff81005a486000, data:ffff81005a4860cc, tail:ffff81005a4866b4, end:ffff81005a486e80
len:1512, data_len:0, truesize: 3952, dest:99090432, doff = 0, sizeof(struct tcphdr) = 20
skb->sk:0000000000000000, head:ffff81006151e800, data:ffff81006151e830, tail:ffff81006151e88c, end:ffff81006151e900
len:92, data_len:0, truesize: 496, dest:6029312, doff = 0, sizeof(struct tcphdr) = 20
skb->sk:0000000000000000, head:ffff810060e05800, data:ffff810060e058ac, tail:ffff810060e058e0, end:ffff810060e05900
len:52, data_len:0, truesize: 496, dest:3407872, doff = 0, sizeof(struct tcphdr) = 20
skb->sk:0000000000000000, head:ffff81005ae12000, data:ffff81005ae120cc, tail:ffff81005ae12101, end:ffff81005ae12e80
len:53, data_len:0, truesize: 3952, dest:3473408, doff = 0, sizeof(struct tcphdr) = 20
skb->sk:0000000000000000, head:ffff810059dda000, data:ffff810059dda0cc, tail:ffff810059dda101, end:ffff810059ddae80
len:53, data_len:0, truesize: 3952, dest:3473408, doff = 0, sizeof(struct tcphdr) = 20
skb->sk:0000000000000000, head:ffff81005a5c3000, data:ffff81005a5c30ac, tail:ffff81005a5c30e0, end:ffff81005a5c3100
len:52, data_len:0, truesize: 496, dest:3407872, doff = 0, sizeof(struct tcphdr) = 20
skb->sk:0000000000000000, head:ffff810059dda000, data:ffff810059dda0cc, tail:ffff810059dda24f, end:ffff810059ddae80
len:387, data_len:0, truesize: 3952, dest:25362432, doff = 0, sizeof(struct tcphdr) = 20
skb->sk:0000000000000000, head:ffff81005a0ce000, data:ffff81005a0ce0cc, tail:ffff81005a0ce6b4, end:ffff81005a0cee80
len:1512, data_len:0, truesize: 3952, dest:99090432, doff = 0, sizeof(struct tcphdr) = 20
skb->sk:0000000000000000, head:ffff81005a5c3000, data:ffff81005a5c30ac, tail:ffff81005a5c30e0, end:ffff81005a5c3100
len:52, data_len:0, truesize: 496, dest:3407872, doff = 0, sizeof(struct tcphdr) = 20
skb->sk:0000000000000000, head:ffff81005f4bb000, data:ffff81005f4bb030, tail:ffff81005f4bb08c, end:ffff81005f4bb100
len:92, data_len:0, truesize: 496, dest:6029312, doff = 0, sizeof(struct tcphdr) = 20


=====
问题:
为什么skb->sk总是NULL呢?
...全文
85 2 打赏 收藏 转发到动态 举报
写回复
用AI写文章
2 条回复
切换为时间正序
请发表友善的回复…
发表回复
kava_java 2011-02-21
  • 打赏
  • 举报
回复
netfilter的HOOK点NF_IP_LOCAL_IN工作在IP和TCP层之间. skb->sk在TCP层初始化.因此,在进入TCP层之前skb->sk为NULL是OK的.

IP报文接收流程之协议栈阶段:
1. kerner/softirq.c:do_softirq()
2. net/core/dev.c:net_rx_action()
3. net/ipv4/ip_input.c:ip_rcv()
4. 检查报文有效性
5. NH_HOOK(.., NF_IP_PRE_ROUTING,.., ip_rcv_finish)
6. net/ipv4/ip_input_.c:ip_rcv_finish()
7. ip_route_input()
8. ip_route_input_slow() // 假设这里是本地报文
9. net/ipv4/ip_input.c:ip_localdeliver()
10.ip_defrag()
11.NF_HOOK(..,NF_IP_LOCAL_IN,..,ip_local_deliver_finish)
12.ip_local_deliver_finish()
13.net/ipv4/ipip.c:ipip_rcv()

这里需要解释的是第11步. 如果没有#def CONFIG_NETFILTER,那么直接执行ip_local_deliver_finish, 如果有#def CONFIG_NETFILTER, 执行所有我们通过nf_register_hook注册在NF_IP_LOCAL_IN的钩子函数,最后执行ip_local_deliver_finish.

ip_local_deliver_finish才真正地进入TCP层处理.
在进入TCP层处理之前skb->sk为NULL是没有问题的.

下面贴一下源码. (仅仅示意一下)


inlcude/linux/netfilter.h

#ifdef CONFIG_NETFILTER
#define NF_HOOK(pf, hook, skb, indev, outdev, okfn) \
({int __ret; \
if ((__ret=nf_hook_thresh(pf, hook, &(skb), indev, outdev, okfn, INT_MIN, 1)) == 1)\
__ret = (okfn)(skb); \
__ret;})

static inline int nf_hook_thresh(int pf, unsigned int hook,
struct sk_buff **pskb,
struct net_device *indev,
struct net_device *outdev,
int (*okfn)(struct sk_buff *), int thresh,
int cond)
{
if (!cond)
return 1;
#ifndef CONFIG_NETFILTER_DEBUG
if (list_empty(&nf_hooks[pf][hook]))
return 1;
#endif
return nf_hook_slow(pf, hook, pskb, indev, outdev, okfn, thresh);
}
#else /* !CONFIG_NETFILTER */
#define NF_HOOK(pf, hook, skb, indev, outdev, okfn) (okfn)(skb)
static inline int nf_hook_thresh(int pf, unsigned int hook,
struct sk_buff **pskb,
struct net_device *indev,
struct net_device *outdev,
int (*okfn)(struct sk_buff *), int thresh,
int cond)
{
return okfn(*pskb);
}

#endif /*CONFIG_NETFILTER*/


net/netfilter/core.c
int nf_hook_slow(int pf, unsigned int hook, struct sk_buff **pskb,
struct net_device *indev,
struct net_device *outdev,
int (*okfn)(struct sk_buff *),
int hook_thresh)
{
struct list_head *elem;
unsigned int 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], pskb, hook, indev,
outdev, &elem, okfn, hook_thresh);

if (verdict == NF_ACCEPT || verdict == NF_STOP) {
ret = 1;
goto unlock;
} else if (verdict == NF_DROP) {
kfree_skb(*pskb);
ret = -EPERM;
} else if ((verdict & NF_VERDICT_MASK) == NF_QUEUE) {
NFDEBUG("nf_hook: Verdict = QUEUE.\n");
if (!nf_queue(pskb, elem, pf, hook, indev, outdev, okfn,
verdict >> NF_VERDICT_BITS))
goto next_hook;
}
unlock:
rcu_read_unlock();
return ret;
}
EXPORT_SYMBOL(nf_hook_slow);

net/ipv4/af_inet.c

static struct net_protocol tcp_protocol = {
.handler = tcp_v4_rcv,
.err_handler = tcp_v4_err,
.gso_send_check = tcp_v4_gso_send_check,
.gso_segment = tcp_tso_segment,
.no_policy = 1,
};

static int __init inet_init(void)
{
struct sk_buff *dummy_skb;
struct inet_protosw *q;
struct list_head *r;
int rc = -EINVAL;

if (sizeof(struct inet_skb_parm) > sizeof(dummy_skb->cb)) {
printk(KERN_CRIT "%s: panic\n", __FUNCTION__);
goto out;
}

rc = proto_register(&tcp_prot, 1);
if (rc)
goto out;

rc = proto_register(&udp_prot, 1);
if (rc)
goto out_unregister_tcp_proto;

rc = proto_register(&raw_prot, 1);
if (rc)
goto out_unregister_udp_proto;

/*
* Tell SOCKET that we are alive...
*/

(void)sock_register(&inet_family_ops);

/*
* Add all the base protocols.
*/

if (inet_add_protocol(&icmp_protocol, IPPROTO_ICMP) < 0)
printk(KERN_CRIT "inet_init: Cannot add ICMP protocol\n");
if (inet_add_protocol(&udp_protocol, IPPROTO_UDP) < 0)
printk(KERN_CRIT "inet_init: Cannot add UDP protocol\n");
if (inet_add_protocol(&tcp_protocol, IPPROTO_TCP) < 0)
printk(KERN_CRIT "inet_init: Cannot add TCP protocol\n");

#ifdef CONFIG_IP_MULTICAST
if (inet_add_protocol(&igmp_protocol, IPPROTO_IGMP) < 0)
printk(KERN_CRIT "inet_init: Cannot add IGMP protocol\n");
#endif

/* Register the socket-side information for inet_create. */
for (r = &inetsw[0]; r < &inetsw[SOCK_MAX]; ++r)
INIT_LIST_HEAD(r);

for (q = inetsw_array; q < &inetsw_array[INETSW_ARRAY_LEN]; ++q)
inet_register_protosw(q);

/*
* Set the ARP module up
*/

arp_init();

/*
* Set the IP module up
*/

ip_init();

tcp_v4_init(&inet_family_ops);

/* Setup TCP slab cache for open requests. */
tcp_init();


/*
* Set the ICMP layer up
*/

icmp_init(&inet_family_ops);

/*
* Initialise the multicast router
*/
#if defined(CONFIG_IP_MROUTE)
ip_mr_init();
#endif
/*
* Initialise per-cpu ipv4 mibs
*/

if(init_ipv4_mibs())
printk(KERN_CRIT "inet_init: Cannot init ipv4 mibs\n"); ;

ipv4_proc_init();

ipfrag_init();

dev_add_pack(&ip_packet_type);

rc = 0;
out:
return rc;
out_unregister_tcp_proto:
proto_unregister(&tcp_prot);
out_unregister_udp_proto:
proto_unregister(&udp_prot);
goto out;
}

fs_initcall(inet_init);

4,436

社区成员

发帖
与我相关
我的任务
社区描述
Linux/Unix社区 内核源代码研究区
社区管理员
  • 内核源代码研究区社区
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

试试用AI创作助手写篇文章吧