- 論壇徽章:
- 0
|
關(guān)于Nat
拜模下yfydz(端木隱)大哥。
NAT操作也是以netfilter節(jié)點(diǎn)形式掛接在相應(yīng)的處理點(diǎn)上的,DNAT掛接在NF_IP_PRE_ROUTING點(diǎn)上,優(yōu)先級(jí)高于 FILTER低于MANGLE,表示在mangle表后處理,但在filter表前處理數(shù)據(jù)包;SNAT掛接在NF_IP_POST_ROUTING點(diǎn)上,優(yōu)先級(jí)低于FILTER,表示在filter表后面處理數(shù)據(jù)包。
由于作NAT后要修改IP地址以及端口,因此原來(lái)的主連接中描述子連接的信息必須進(jìn)行修改,(*help) 函數(shù)的功能就要要找到一個(gè)空閑的tuple對(duì)應(yīng)新的子連接,修改期待的子連接,然后修改主連接的通信內(nèi)容,修改關(guān)于IP地址和端口部分的描述信息為空閑 tuple的信息,由于修改了應(yīng)用層數(shù)據(jù),數(shù)據(jù)的校驗(yàn)和必須重新計(jì)算,而且如果數(shù)據(jù)長(zhǎng)度發(fā)生變化,會(huì)引起TCP序列號(hào)的變化,在連接的協(xié)議相關(guān)數(shù)據(jù)中會(huì)記錄這些變化,對(duì)后續(xù)的所有數(shù)據(jù)都要進(jìn)行相應(yīng)的調(diào)整;該函數(shù)在do_bindings()函數(shù)中調(diào)用;
不是太清楚這段話。
感謝獨(dú)孤和Godbach大哥們的精彩帖子,給我做畢業(yè)設(shè)計(jì)帶了幫助!!
雖然目前差不多實(shí)現(xiàn)了一個(gè)多線程的ip數(shù)據(jù)包查看和ip簡(jiǎn)單過(guò)濾功能。
但對(duì)nl(netlink通訊)還有一點(diǎn)疑問(wèn)。
下面也總結(jié)下我遇到的問(wèn)題,也分享給大家。
Filter實(shí)現(xiàn)
先說(shuō)說(shuō)大致思路:
我用的JAVA SWING 做的UI 然后底層就是SO庫(kù)和內(nèi)核進(jìn)行通訊了,用到就是NETLINK 和NETFILTER那套東西。
大致流程就不說(shuō)了,上面兩位大哥們還有很多前輩們都說(shuō)明白了。而我只是運(yùn)用到了實(shí)際的一個(gè)TOOL下面。自己的內(nèi)核是2.6.25的(和以前版本有點(diǎn)出處)。
______________________________________
java:
Thread A Thread B
\ /
\ /
\___/
so庫(kù): static int skfd;(上層線程共用一個(gè)sock鏈接)
|
receive()|send()
|
內(nèi)核層:
cj_fw.ko模塊
so庫(kù): static int skfd;(上層線程共用一個(gè)sock鏈接)
-?疑問(wèn)一:我有嘗試創(chuàng)建多個(gè)sock,但每次bind()失敗,難道不能同時(shí)創(chuàng)建多個(gè)sock與內(nèi)核的一個(gè)sock通訊么? 不能有“多對(duì)一”的關(guān)系么?
這個(gè)sock鏈接是綁定了nl協(xié)議的(skfd = socket(AF_NETLINK, SOCK_RAW, NL_FW);//NL_FW是自定義協(xié)議
創(chuàng)建NETLINK連接
struct sockaddr_nl local;//表示用戶進(jìn)程的nl地址
struct sockaddr_nl kpeer;//表示內(nèi)核進(jìn)程的nl地址
詳細(xì)代碼:
//初始化用戶本地nl地址
memset(&local, 0, sizeof(local));
local.nl_family = AF_NETLINK;//設(shè)置環(huán)境
local.nl_pid = pthread_self() << 16 | getpid();//設(shè)置通訊id
local.nl_groups = 0;//是否指定多播
//用于把一個(gè)打開的 netlink socket 與 netlink 源 socket 地址綁定在一起
if(bind(skfd, (struct sockaddr*)&local, sizeof(local)) != 0)
{
printf("bind() error in ip\n");
return 0;
}
//初始化內(nèi)核進(jìn)程nl地址
memset(&kpeer, 0, sizeof(kpeer));
kpeer.nl_family = AF_NETLINK;
kpeer.nl_pid = 0; //0表示內(nèi)核進(jìn)程
kpeer.nl_groups = 0;
//初始化用戶本地nl地址
memset(&local, 0, sizeof(local));
local.nl_family = AF_NETLINK;//設(shè)置環(huán)境
local.nl_pid = pthread_self() << 16 | getpid();//設(shè)置通訊id
local.nl_groups = 0;//是否指定多播
//用于把一個(gè)打開的 netlink socket 與 netlink 源 socket 地址綁定在一起
if(bind(skfd, (struct sockaddr*)&local, sizeof(local)) != 0)
{
printf("bind() error in ip\n");
return 0;
}
//初始化內(nèi)核進(jìn)程nl地址
memset(&kpeer, 0, sizeof(kpeer));
kpeer.nl_family = AF_NETLINK;
kpeer.nl_pid = 0; //0表示內(nèi)核進(jìn)程
kpeer.nl_groups = 0;
發(fā)送消息給內(nèi)核:
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));
接收內(nèi)核的消息:
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);
_______________________________________________-
內(nèi)核層:
cj_fw.ko模塊
詳細(xì)注冊(cè)代碼:
struct sock *nlfd=NULL;
static int init(void)
{
//創(chuàng)建一個(gè)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)
{
//創(chuàng)建一個(gè)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)
發(fā)送用戶消息:
Java代碼
static int send_to_user(struct packet_info *info)
static int send_to_user(struct packet_info *info)
-------------------------?疑問(wèn)二:一個(gè)模塊只能創(chuàng)建一個(gè)netlink sock嗎?我嘗試過(guò)創(chuàng)建2個(gè)以上,但失敗。具體原因又是什么呢?
小結(jié)和問(wèn)題:
目前我覺(jué)得多線程共用一個(gè)sock和內(nèi)核一個(gè)sock通訊的效率不高,內(nèi)核模塊稍微處理不好,就發(fā)生堵塞,所有要注意的地方是不管網(wǎng)絡(luò)層是否有網(wǎng)絡(luò)數(shù)據(jù)包,內(nèi)核模塊都需要即使返回消息給用戶態(tài),這樣才不會(huì)讓用戶態(tài)無(wú)限等下去..
但發(fā)生堵塞的原因還是共用了一個(gè)sock,不知道大家有什么改進(jìn)的方法么?
進(jìn)度:
然后目前在看Godbach 大哥寫的那篇“連接狀態(tài)跟蹤分析”了,目前自己也還在理解階段。
對(duì)于4個(gè)HOOK點(diǎn)分別對(duì)應(yīng)了 ip_conntrack_in_ops ip_conntrack_local_out_ops ip_conntrack_out_ops ip_conntrack_local_in_ops 和 4個(gè) HOOK函數(shù):ip_conntrack_in,ip_conntrack_local,ip_refrag, ip_confirm
最后,希望和大家多多交流!
已實(shí)現(xiàn)過(guò)濾功能如下:
924bfe26-465a-3979-8962-55065482e6ef.png (71.75 KB, 下載次數(shù): 25)
下載附件
2009-04-26 22:48 上傳
連接跟蹤實(shí)現(xiàn):
貌似現(xiàn)在的思路越來(lái)越明朗了:
關(guān)于鏈接跟蹤
1,通過(guò)"proc"與nf_conntrack內(nèi)核模塊通訊,獲取連接信息
2,通過(guò)之前自己已實(shí)現(xiàn)ip包過(guò)濾模塊的hook,來(lái)獲得ip頭,tcp,udp頭信息并通過(guò)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 這幾個(gè)信息不知道是從哪來(lái)的???
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 編輯 ] |
|