- 论坛徽章:
- 0
|
关于Nat
拜模下yfydz(端木隐)大哥。
NAT操作也是以netfilter节点形式挂接在相应的处理点上的,DNAT挂接在NF_IP_PRE_ROUTING点上,优先级高于 FILTER低于MANGLE,表示在mangle表后处理,但在filter表前处理数据包;SNAT挂接在NF_IP_POST_ROUTING点上,优先级低于FILTER,表示在filter表后面处理数据包。
由于作NAT后要修改IP地址以及端口,因此原来的主连接中描述子连接的信息必须进行修改,(*help) 函数的功能就要要找到一个空闲的tuple对应新的子连接,修改期待的子连接,然后修改主连接的通信内容,修改关于IP地址和端口部分的描述信息为空闲 tuple的信息,由于修改了应用层数据,数据的校验和必须重新计算,而且如果数据长度发生变化,会引起TCP序列号的变化,在连接的协议相关数据中会记录这些变化,对后续的所有数据都要进行相应的调整;该函数在do_bindings()函数中调用;
不是太清楚这段话。
感谢独孤和Godbach大哥们的精彩帖子,给我做毕业设计带了帮助!!
虽然目前差不多实现了一个多线程的ip数据包查看和ip简单过滤功能。
但对nl(netlink通讯)还有一点疑问。
下面也总结下我遇到的问题,也分享给大家。
Filter实现
先说说大致思路:
我用的JAVA SWING 做的UI 然后底层就是SO库和内核进行通讯了,用到就是NETLINK 和NETFILTER那套东西。
大致流程就不说了,上面两位大哥们还有很多前辈们都说明白了。而我只是运用到了实际的一个TOOL下面。自己的内核是2.6.25的(和以前版本有点出处)。
______________________________________
java:
Thread A Thread B
\ /
\ /
\___/
so库: static int skfd;(上层线程共用一个sock链接)
|
receive()|send()
|
内核层:
cj_fw.ko模块
so库: static int skfd;(上层线程共用一个sock链接)
-?疑问一:我有尝试创建多个sock,但每次bind()失败,难道不能同时创建多个sock与内核的一个sock通讯么? 不能有“多对一”的关系么?
这个sock链接是绑定了nl协议的(skfd = socket(AF_NETLINK, SOCK_RAW, NL_FW);//NL_FW是自定义协议
创建NETLINK连接
struct sockaddr_nl local;//表示用户进程的nl地址
struct sockaddr_nl kpeer;//表示内核进程的nl地址
详细代码:
//初始化用户本地nl地址
memset(&local, 0, sizeof(local));
local.nl_family = AF_NETLINK;//设置环境
local.nl_pid = pthread_self() << 16 | getpid();//设置通讯id
local.nl_groups = 0;//是否指定多播
//用于把一个打开的 netlink socket 与 netlink 源 socket 地址绑定在一起
if(bind(skfd, (struct sockaddr*)&local, sizeof(local)) != 0)
{
printf("bind() error in ip\n");
return 0;
}
//初始化内核进程nl地址
memset(&kpeer, 0, sizeof(kpeer));
kpeer.nl_family = AF_NETLINK;
kpeer.nl_pid = 0; //0表示内核进程
kpeer.nl_groups = 0;
//初始化用户本地nl地址
memset(&local, 0, sizeof(local));
local.nl_family = AF_NETLINK;//设置环境
local.nl_pid = pthread_self() << 16 | getpid();//设置通讯id
local.nl_groups = 0;//是否指定多播
//用于把一个打开的 netlink socket 与 netlink 源 socket 地址绑定在一起
if(bind(skfd, (struct sockaddr*)&local, sizeof(local)) != 0)
{
printf("bind() error in ip\n");
return 0;
}
//初始化内核进程nl地址
memset(&kpeer, 0, sizeof(kpeer));
kpeer.nl_family = AF_NETLINK;
kpeer.nl_pid = 0; //0表示内核进程
kpeer.nl_groups = 0;
发送消息给内核:
sendto(skfd, &message, message.hdr.nlmsg_len, 0, (struct sockaddr *)(&kpeer),
sizeof(kpeer));
sendto(skfd, &message, message.hdr.nlmsg_len, 0, (struct sockaddr *)(&kpeer),
sizeof(kpeer));
接收内核的消息:
rcvlen = recvfrom(skfd, &info, sizeof(struct u_packet_info),
0, (struct sockaddr*)&kpeer, &kpeerlen);
rcvlen = recvfrom(skfd, &info, sizeof(struct u_packet_info),
0, (struct sockaddr*)&kpeer, &kpeerlen);
_______________________________________________-
内核层:
cj_fw.ko模块
详细注册代码:
struct sock *nlfd=NULL;
static int init(void)
{
//创建一个netlink
nlfd = netlink_kernel_create(&init_net,NL_FW,0, kernel_receive,NULL,THIS_MODULE);
if(!nlfd)
{
printk("can not create a netlink socket\n");
if (nlfd){
sock_release(nlfd->sk_socket);
}
return -1;
}
....
}
static int init(void)
{
//创建一个netlink
nlfd = netlink_kernel_create(&init_net,NL_FW,0, kernel_receive,NULL,THIS_MODULE);
if(!nlfd)
{
printk("can not create a netlink socket\n");
if (nlfd){
sock_release(nlfd->sk_socket);
}
return -1;
}
....
}
接收用户消息:
Java代码
static void kernel_receive(struct sk_buff * __skb)
static void kernel_receive(struct sk_buff * __skb)
发送用户消息:
Java代码
static int send_to_user(struct packet_info *info)
static int send_to_user(struct packet_info *info)
-------------------------?疑问二:一个模块只能创建一个netlink sock吗?我尝试过创建2个以上,但失败。具体原因又是什么呢?
小结和问题:
目前我觉得多线程共用一个sock和内核一个sock通讯的效率不高,内核模块稍微处理不好,就发生堵塞,所有要注意的地方是不管网络层是否有网络数据包,内核模块都需要即使返回消息给用户态,这样才不会让用户态无限等下去..
但发生堵塞的原因还是共用了一个sock,不知道大家有什么改进的方法么?
进度:
然后目前在看Godbach 大哥写的那篇“连接状态跟踪分析”了,目前自己也还在理解阶段。
对于4个HOOK点分别对应了 ip_conntrack_in_ops ip_conntrack_local_out_ops ip_conntrack_out_ops ip_conntrack_local_in_ops 和 4个 HOOK函数:ip_conntrack_in,ip_conntrack_local,ip_refrag, ip_confirm
最后,希望和大家多多交流!
已实现过滤功能如下:
连接跟踪实现:
貌似现在的思路越来越明朗了:
关于链接跟踪
1,通过"proc"与nf_conntrack内核模块通讯,获取连接信息
2,通过之前自己已实现ip包过滤模块的hook,来获得ip头,tcp,udp头信息并通过netlink获取连接信息
类似“ipv4 2 tcp 6 5 TIME_WAIT src=192.168.0.25 dst=221.238.249.178 sport=39027 dport=80 packets=6 bytes=1119 src=221.238.249.178 dst=192.168.0.25 sport=80 dport=39027 packets=5 bytes=2474 [ASSURED] mark=0 secmark=0 use=1"
只是里面的bytes mark secmark use TIME_WAIT 这几个信息不知道是从哪来的???
ip包消息头:
struct iphdr {
#if defined(__LITTLE_ENDIAN_BITFIELD)
__u8 ihl:4,
version:4;
#elif defined (__BIG_ENDIAN_BITFIELD)
__u8 version:4,
ihl:4;
#else
#error "Please fix <asm/byteorder.h>"
#endif
__u8 tos;
__be16 tot_len;
__be16 id;
__be16 frag_off;
__u8 ttl;
__u8 protocol; __u8是unsigned char类型
__sum16 check;
__be32 saddr;
__be32 daddr;
/*The options start here. */
};
struct udphdr {
__be16 source;
__be16 dest;
__be16 len;
__sum16 check;
};
struct tcphdr {
__be16 source;
__be16 dest;
__be32 seq;
__be32 ack_seq;
#if defined(__LITTLE_ENDIAN_BITFIELD)
__u16 res1:4,
doff:4,
fin:1,
syn:1,
rst:1,
psh:1,
ack:1,
urg:1,
ece:1,
cwr:1;
#elif defined(__BIG_ENDIAN_BITFIELD)
__u16 doff:4,
res1:4,
cwr:1,
ece:1,
urg:1,
ack:1,
psh:1,
rst:1,
syn:1,
fin:1;
#else
#error "Adjust your <asm/byteorder.h> defines"
#endif
__be16 window;
__sum16 check;
__be16 urg_ptr;
}; |
[ 本帖最后由 C__J 于 2009-5-5 01:12 编辑 ] |
|