您的位置:首页 > 其它

AF_PACKET套接字解密 --- 01

2013-03-13 18:24 260 查看
AF_PACKET套接字解密 --- 01 2012-05-23
22:08:23

分类: LINUX

使用socket(AF_PACKET, SOCK_RAW, ETH_P_ALL)创建的套接字到底为何于众不同,今日追踪了一下。使用Linux 3.2.5版内核

net/socket.c

点击(此处)折叠或打开

SYSCALL_DEFINE3(socket, int, family, int, type, int, protocol)

{

......

retval = sock_create(family, type, protocol, &sock);

......

}

点击(此处)折叠或打开

int sock_create(int family, int type, int protocol, struct socket **res)

{

return __sock_create(current->nsproxy->net_ns, family, type, protocol, res, 0);

}

点击(此处)折叠或打开

int __sock_create(struct net *net, int family, int type, int protocol,

struct socket **res, int kern)

{

......

pf = rcu_dereference(net_families[family]);

......

err = pf->create(net, sock, protocol, kern);

......

}

点击(此处)折叠或打开

static const struct net_proto_family __rcu *net_families[NPROTO] __read_mostly;

int sock_register(const struct net_proto_family *ops)

{

......

if (rcu_dereference_protected(net_families[ops->family],

lockdep_is_held(&net_family_lock)))

err = -EEXIST;

else {

rcu_assign_pointer(net_families[ops->family], ops);

err = 0;

}

......

}

net/packet/af_packet.c

点击(此处)折叠或打开

static const struct net_proto_family packet_family_ops = {

.family = PF_PACKET,

.create = packet_create,

.owner = THIS_MODULE,

};

static int __init packet_init(void)

{

......

sock_register(&packet_family_ops);

......

}

module_init(packet_init);

点击(此处)折叠或打开

static int packet_create(struct net *net, struct socket *sock, int protocol,

int kern)

{

struct sock *sk;

struct packet_sock *po;

__be16 proto = (__force __be16)protocol; /* weird, but documented */

......

sk = sk_alloc(net, PF_PACKET, GFP_KERNEL, &packet_proto);

......

sock->ops = &packet_ops;

......

po = pkt_sk(sk);

sk->sk_family = PF_PACKET;

po->num = proto;

......

po->prot_hook.func = packet_rcv;

......

po->prot_hook.af_packet_priv = sk;

if (proto) {

po->prot_hook.type = proto;

register_prot_hook(sk);

}

......

}

AF_PACKET套接字的功能来源于prot_hook,其本身是struct packet_type类型:

1:type成员设定为了socket()传递的参数(这里是ETH_P_ALL)

2:过滤得到的包的处理函数保存于func成员,这里被设定为 packet_rcv()

3:dev成员用于对net_device的过滤,可以在bind()中指定

点击(此处)折叠或打开

static int packet_bind(struct socket *sock, struct
sockaddr *uaddr, int addr_len)

{

......

if (sll->sll_ifindex) {

err = -ENODEV;

dev = dev_get_by_index(sock_net(sk), sll->sll_ifindex);

if (dev == NULL)

goto out;

}

err = packet_do_bind(sk, dev, sll->sll_protocol ? : pkt_sk(sk)->num);

......

}

点击(此处)折叠或打开

static int packet_do_bind(struct sock *sk, struct
net_device *dev, __be16 protocol)

{

struct packet_sock *po = pkt_sk(sk);

......

po->prot_hook.dev = dev;

po->ifindex = dev ? dev->ifindex : 0;

......

if (!dev || (dev->flags & IFF_UP)) {

register_prot_hook(sk);

......

}

可见在bind()中若指定了绑定的net_device同样会触发prot_hook的注册动作。

点击(此处)折叠或打开

static void register_prot_hook(struct sock *sk)

{

struct packet_sock *po = pkt_sk(sk);

if (!po->running) {

if (po->fanout)

__fanout_link(sk, po);

else

dev_add_pack(&po->prot_hook);

sock_hold(sk);

po->running = 1;

}

}

net/core/dev.c

点击(此处)折叠或打开

void dev_add_pack(struct packet_type *pt)

{

struct list_head *head = ptype_head(pt);

spin_lock(&ptype_lock);

list_add_rcu(&pt->list, head);

spin_unlock(&ptype_lock);

}

点击(此处)折叠或打开

static struct list_head ptype_all __read_mostly; /* Taps */

static inline struct list_head *ptype_head(const struct
packet_type *pt)

{

if (pt->type == htons(ETH_P_ALL))

return &ptype_all;

else

return &ptype_base[ntohs(pt->type) & PTYPE_HASH_MASK];

}

历尽千辛万苦,终于知道AF_PACKET套接字把自己的prot_hook挂到了ptype_all链表上或ptype_base链表上。至于prot_hook怎么发挥作用进行监听,请听下回分解!
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: