We read every piece of feedback, and take your input very seriously.
To see all available qualifiers, see our documentation.
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
在项目当中有时需要连接跟踪相关的信息,netfilter官网提供了一个libnetfilter_conntrack的用户态库,通过netlink的方式与内核对应的模块通信操作conntrack,但是会有性能瓶颈,还有就是问题不好定位,本文提供一种用户层获取连接跟踪的实现思路,在继续阅读之前,请确保具备以下基本知识:
解决思路很清晰,在内核层面netfilter钩子当中hook数据包,然后强行在L4和payload之间封装一层协议,有点类似运营商植入广告,将连接跟踪的信息通过这层协议传递给用户态,用户态先解这层协议。再读取数据。
比如说,用户层比较关心DNAT之前的目的地址(origin_ip)和目的端口(origin_port),那么可以将origin_ip和origin_port再加上payload的长度三个字段作为一层协议,插入到tcp和payload之间。这样用户层的应用只需要正常读数据,读取协议头,再读取payload即可。
以TCP为例,部分示例代码如下:
// tcp static int handle_tcp(struct sk_buff *skb){ struct iphdr *ip = ip_hdr(skb); struct tcphdr *tcp = tcp_hdr(skb); // conntrack enum ip_conntrack_info conntrack_info; struct nf_conntrack_tuple *origin_tuple = NULL; struct nf_conn *ct = NULL; // inject buffer char insert_data[8]; char *ptr = &insert_data[0]; // origin payload char *origin_data = skb_network_header(skb) + ip->ihl * 4 + tcp->doff * 4; int origin_len = skb->tail - skb->network_header - ip->ihl * 4 - tcp->doff * 4; ct = get_conntrack(skb, &conntrack_info); if (ct == NULL) { return NF_ACCEPT; } origin_tuple = &ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple; // force accepted pkt if (is_accepted_pkt(origin_tuple, ip->daddr, tcp->dest) != 0) { return NF_ACCEPT; } // empty payload if (origin_len == 0) { return NF_ACCEPT; } // modify tcp payload ptr = encode32u(ptr, origin_tuple->dst.u3.ip); ptr = encode16u(ptr, ntohs(origin_tuple->dst.u.all)); ptr = encode16u(ptr, origin_len); // expand skb tailroom if (skb_tailroom(skb) < 8) { if (expand_skb(skb, skb_headroom(skb), skb_tailroom(skb) + 40) != 0) { return NF_DROP; } } // copy conntrack data into skb payload memmove(origin_data + 8, origin_data, origin_len); memcpy(origin_data, &insert_data[0], 8); nfct_seqadj_ext_add(ct); __nf_nat_mangle_tcp_packet(skb, ct, conntrack_info, ip->ihl * 4, 0, origin_len, origin_data, origin_len + 8, true); return NF_ACCEPT; }
在用户态先读八个字节的协议,将origin_ip和origin_port以及payload长度length读取出来,然后再读取length字节的数据。不需要任何库,难点在于编写一个稳定的内核模块。
The text was updated successfully, but these errors were encountered:
No branches or pull requests
在项目当中有时需要连接跟踪相关的信息,netfilter官网提供了一个libnetfilter_conntrack的用户态库,通过netlink的方式与内核对应的模块通信操作conntrack,但是会有性能瓶颈,还有就是问题不好定位,本文提供一种用户层获取连接跟踪的实现思路,在继续阅读之前,请确保具备以下基本知识:
解决思路很清晰,在内核层面netfilter钩子当中hook数据包,然后强行在L4和payload之间封装一层协议,有点类似运营商植入广告,将连接跟踪的信息通过这层协议传递给用户态,用户态先解这层协议。再读取数据。
比如说,用户层比较关心DNAT之前的目的地址(origin_ip)和目的端口(origin_port),那么可以将origin_ip和origin_port再加上payload的长度三个字段作为一层协议,插入到tcp和payload之间。这样用户层的应用只需要正常读数据,读取协议头,再读取payload即可。
以TCP为例,部分示例代码如下:
在用户态先读八个字节的协议,将origin_ip和origin_port以及payload长度length读取出来,然后再读取length字节的数据。不需要任何库,难点在于编写一个稳定的内核模块。
The text was updated successfully, but these errors were encountered: