netlink总结

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/wangzhen_csdn/article/details/84142302

Netfilter_queue 知识总结

函数名称:

struct nfnl_handle *nfnl_open(void)

 

函数说明:

开启nfnetlink 处理程序

函数参数:

void
函数功能:

该函数创建一个nfnetlink 处理程序,此函数创建NFNETLink处理程序,这是需要建立的用户空间与NFNETLink系统之间的通信。

 

返回值:

成功 指向nfnl_handle structure的有效地址。

失败:NULL

 

 

 

 

 

函数名称:

int nfq_unbind_pf(struct nfq_handle *h, u_int16_t pf)

或者

int nfq_bind_pf(struct nfq_handle *h, u_int16_t pf)

函数说明:

解绑(绑定)nf_queue 队列

函数参数:

h:nfq_open()返回struct nfnl_handle结构的指针;

pf: 协议族 AF_BRIDGE:7多协议桥,AF_INET:2 路由模式

 

返回值:失败 : -1

 成功 :  0

 

 

 

 

函数名称:

struct nfq_q_handle *nfq_create_queue(struct nfq_handle *h,

u_int16_t num,

nfq_callback *cb,

void *data)

 

函数说明:

将此套接字绑定到特定的队列号.

函数参数:

h : nfq_open()返回struct nfnl_handle结构的指针;

num: 队列的序列号

cb : 数据包的处理函数(回调函数)

data: 自定义数据

 

返回值:

成功:struct nfq_q_handle 指针

失败 : null

 

 

 

 

 

函数名称:

int nfq_set_mode(struct nfq_q_handle *qh,u_int8_t mode, u_int32_t range)

 

函数说明:

从netlink系统里设置copy数据的方式

 

函数参数:

       qh   :  nfq_create_queue()函数的返回值

mode : copy 方式

NFQNL_COPY_NONE,

NFQNL_COPY_META,

NFQNL_COPY_PACKET,

range:copy 数据长度

 

返回值:

成功0

失败 -1

 

 

函数名称:

int nfq_handle_packet(struct nfq_handle *h, char *buf, int len)

函数说明:

处理接收的数据

 

函数参数:

       h   : nfq_open()返回struct nfnl_handle结构的指针;

buf: 待处理的数据

len:数据长度

 

 

 

 

综上所述:

nf_queue仍然使用的netlink机制与内核之间进行通信,不同的是nf_queue根据不同的queue_num,将数据包传递给不同的用户注册的回调函数。但是请注意,它们共用一个socket套接字.

 

 

 

 

 

问题1:nfq_handle_packet()怎样和处理函数nfq_create_queue参数cb 建立起联系的?

 

struct nfq_q_handle

{

struct nfq_q_handle *next;

struct nfq_handle *h;

u_int16_t id;

 

nfq_callback *cb;

void *data;

};

 

typedef int  nfq_callback(struct nfq_q_handle *gh, struct nfgenmsg *nfmsg,

       struct nfq_data *nfad, void *data);

 

static int cb(struct nfq_q_handle *qh, struct nfgenmsg *nfmsg,

      struct nfq_data *nfa, void *data)

{

u_int32_t id = print_pkt(nfa);

printf("entering callback\n");

return nfq_set_verdict(qh, id, NF_ACCEPT, 0, NULL);

}

 

struct nfq_q_handle *nfq_create_queue(struct nfq_handle *h,

u_int16_t num,

nfq_callback *cb,

void *data)

{

int ret;

struct nfq_q_handle *qh;

 

if (find_qh(h, num))

return NULL;

 

qh = malloc(sizeof(*qh));

 

memset(qh, 0, sizeof(*qh));

qh->h = h;

qh->id = num;

qh->cb = cb;

qh->data = data;

 

ret = __build_send_cfg_msg(h, NFQNL_CFG_CMD_BIND, num, 0);

if (ret < 0) {

nfq_errno = ret;

free(qh);

return NULL;

}

 

add_qh(qh);

return qh;

}

 

//接收数据包

while ((rv = recv(fd, buf, sizeof(buf), 0)) && rv >= 0) {

printf("pkt received\n");

nfq_handle_packet(h, buf, rv);

}

 

nfq_handle_packe://处理数据包函数

--> nfnl_handle_packet(h->nfnlh, buf, len);

--> __nfnl_handle_msg(h, nlh, rlen)

 

static int __nfnl_handle_msg(struct nfnl_handle *h, struct nlmsghdr *nlh,

     int len)

{

struct nfnl_subsys_handle *ssh;

。。。。。

 

ssh = &h->subsys[subsys_id];

 

if (ssh->cb[type].attr_count) {

if (ssh->cb[type].call)

return ssh->cb[type].call(nlh, nfa, ssh->cb[type].data);

}

return 0;

}

 

 

结构体定义:

struct nfnl_subsys_handle {

struct nfnl_handle *nfnlh;

u_int32_t subscriptions;

u_int8_t subsys_id;

u_int8_t cb_count;

struct nfnl_callback *cb; /* array of callbacks */

};

struct nfnl_callback {

int (*call)(struct nlmsghdr *nlh, struct nfattr *nfa[], void *data);

void *data;

u_int16_t attr_count;

};

 

 call:是一个函数指针(钩子)

 

static struct nfnl_callback pkt_cb = {

.call = &__nfq_rcv_pkt,

.attr_count = NFQA_MAX,

};

 

函数的实现:

 

static int __nfq_rcv_pkt(struct nlmsghdr *nlh, struct nfattr *nfa[],

void *data)

{

struct nfgenmsg *nfmsg = NLMSG_DATA(nlh);

struct nfq_handle *h = data;

u_int16_t queue_num = ntohs(nfmsg->res_id);

struct nfq_q_handle *qh = find_qh(h, queue_num);

struct nfq_data nfqa;

 

if (!qh)

return -ENODEV;

 

if (!qh->cb)

return -ENODEV;

 

nfqa.data = nfa;

 

return qh->cb(qh, nfmsg, &nfqa, qh->data);

}

 

就这样

nfq_handle_packet(h, buf, rv)和 qh = nfq_create_queue(h,  0, &cb, NULL);联系在一起拉

 

 

 

 

问题2:怎样获取vlanid port 信息;

 

在dhcpsnoop获取端口信息 vlan信息 的实现接

 

 

在应用层条用接口:

 

ph = nfq_get_msg_packet_hdr(tb); //协议类型

mark = nfq_get_nfmark(tb);  //端口信息

ifi = nfq_get_indev(tb);或 ifi = nfq_get_outdev(tb); //接口信息

nfq_get_payload(tb,&data);//数据内容

怎样确定接口含义呢:

需要在内核中查找代码实现:

我们可以nfq_get_nfmark(tb);获取端口信息为例

uint32_t nfq_get_nfmark(struct nfq_data *nfad)

{

return ntohl(nfnl_get_data(nfad->data, NFQA_MARK, u_int32_t));

}

 

在内核linux-2.6.36/net目录下搜索NFQA_MARK,会发现

static struct sk_buff *

nfqnl_build_packet_message(struct nfqnl_instance *queue,

                           struct nf_queue_entry *entry)

 

猜你喜欢

转载自blog.csdn.net/wangzhen_csdn/article/details/84142302