免费注册 查看新帖 |

Chinaunix

  平台 论坛 博客 文库
12下一页
最近访问板块 发新帖
查看: 7169 | 回复: 15
打印 上一主题 下一主题

JNI+Netlink+Netfilter+Java多线程(毕设进行中) [复制链接]

论坛徽章:
0
跳转到指定楼层
1 [收藏(0)] [报告]
发表于 2009-04-26 15:31 |只看该作者 |倒序浏览
关于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 编辑 ]

论坛徽章:
0
2 [报告]
发表于 2009-04-26 18:15 |只看该作者
和你讨论一个问题,用户层为什么要用多线程?
这两个线程做的功能不一样?

论坛徽章:
0
3 [报告]
发表于 2009-04-26 20:45 |只看该作者
原帖由 emmoblin 于 2009-4-26 18:15 发表
和你讨论一个问题,用户层为什么要用多线程?
这两个线程做的功能不一样?


恩 是的


刚看了下,全局有个 nf_conntrack_hash 这个数据结构,我想问的是,是不是我用户层直接用这个HASH表就可以了??

恩 ,因为lsmod 有看到 nf_conntrack_ipv4这个module

我等会打出这个hash表中的node节点试试,如果可以的话,我就直接用这个结构返回给上层应用了。

[ 本帖最后由 C__J 于 2009-4-26 23:21 编辑 ]

论坛徽章:
36
IT运维版块每日发帖之星
日期:2016-04-10 06:20:00IT运维版块每日发帖之星
日期:2016-04-16 06:20:0015-16赛季CBA联赛之广东
日期:2016-04-16 19:59:32IT运维版块每日发帖之星
日期:2016-04-18 06:20:00IT运维版块每日发帖之星
日期:2016-04-19 06:20:00每日论坛发贴之星
日期:2016-04-19 06:20:00IT运维版块每日发帖之星
日期:2016-04-25 06:20:00IT运维版块每日发帖之星
日期:2016-05-06 06:20:00IT运维版块每日发帖之星
日期:2016-05-08 06:20:00IT运维版块每日发帖之星
日期:2016-05-13 06:20:00IT运维版块每日发帖之星
日期:2016-05-28 06:20:00每日论坛发贴之星
日期:2016-05-28 06:20:00
4 [报告]
发表于 2009-04-26 22:06 |只看该作者
原帖由 C__J 于 2009-4-26 20:45 发表


恩 是的


刚看了下,全局有个 nf_conntrack_hash 这个数据结构,我想问的是,是不是我用户层直接用这个HASH表就可以了??


你想在用户层对这个表执行什么操作呢?

论坛徽章:
3
金牛座
日期:2014-06-14 22:04:062015年辞旧岁徽章
日期:2015-03-03 16:54:152015年迎新春徽章
日期:2015-03-04 09:49:45
5 [报告]
发表于 2009-04-26 22:40 |只看该作者
有个问题,楼主要搞清楚,netlink的通信句柄是pid,如果你使用的是posix线程,这可能并不是轻量级进程,所以thread id不能拿来通信。

论坛徽章:
0
6 [报告]
发表于 2009-04-26 22:47 |只看该作者
原帖由 Godbach 于 2009-4-26 22:06 发表


你想在用户层对这个表执行什么操作呢?


你好,谢谢你的文章,给我带来了很多思路。

因为工具有个查看连接状态功能

我需要那些连接状态信息。



有个问题,楼主要搞清楚,netlink的通信句柄是pid,如果你使用的是posix线程,这可能并不是轻量级进程,所以thread id不能拿来通信。

恩,谢谢。
因为上层是用JAVA写的 我直接是用的Java的基础类  Thread 所以至于是不是posix线程 我就不明了 不过我是直接用的thread id通讯。而且IP过滤和端口过滤已经了NL实现了

class MyThread extends Thread
{
&nbsp;&nbsp;...
}


[ 本帖最后由 C__J 于 2009-4-26 22:50 编辑 ]

论坛徽章:
3
金牛座
日期:2014-06-14 22:04:062015年辞旧岁徽章
日期:2015-03-03 16:54:152015年迎新春徽章
日期:2015-03-04 09:49:45
7 [报告]
发表于 2009-04-26 22:55 |只看该作者

回复 #6 C__J 的帖子

那你的thread id通信成功了么?

论坛徽章:
36
IT运维版块每日发帖之星
日期:2016-04-10 06:20:00IT运维版块每日发帖之星
日期:2016-04-16 06:20:0015-16赛季CBA联赛之广东
日期:2016-04-16 19:59:32IT运维版块每日发帖之星
日期:2016-04-18 06:20:00IT运维版块每日发帖之星
日期:2016-04-19 06:20:00每日论坛发贴之星
日期:2016-04-19 06:20:00IT运维版块每日发帖之星
日期:2016-04-25 06:20:00IT运维版块每日发帖之星
日期:2016-05-06 06:20:00IT运维版块每日发帖之星
日期:2016-05-08 06:20:00IT运维版块每日发帖之星
日期:2016-05-13 06:20:00IT运维版块每日发帖之星
日期:2016-05-28 06:20:00每日论坛发贴之星
日期:2016-05-28 06:20:00
8 [报告]
发表于 2009-04-26 23:11 |只看该作者
你好,谢谢你的文章,给我带来了很多思路。

因为工具有个查看连接状态功能

我需要那些连接状态信息。
'
客气。如果你只是需要哪些连接的状态信息,那么直接:
cat /proc/net/ip_conntrack应该就可以列出当前所有的连接信息了。

论坛徽章:
0
9 [报告]
发表于 2009-04-26 23:13 |只看该作者

回复 #7 dreamice 的帖子

恩 成功了,上层的2个线程 共用一个nl sock通讯,只是每次nl.pid是  

local.nl_pid =  pthread_self() << 16 | getpid();//设置通讯id

其实我感觉这里设置什么牵连的不大,因为多线程每次保证了同时只有一个sock通讯,而且是等待kernel space返回信息包给上层应用才结束了这次sock通讯的,当然这只是我的理解,并且这些都是我已经实现的功能了。

客气。如果你只是需要哪些连接的状态信息,那么直接:
cat /proc/net/ip_conntrack应该就可以列出当前所有的连接信息了。


恩, 因为之前的ip过滤功能是用的netlink通讯,而且异步给我带来了很大的方便  

所以我想不改变大的背景,虽然我相信cat方式也能获取到,但我相信netlink应该能够做到,而且也方便多线程的编写和一些扩展性

刚试了下 cat 可能Godbach兄在2.6.12的版本下  我的2.6.25下的conntrack模块是nf_conntrack哈~

[ 本帖最后由 C__J 于 2009-4-26 23:28 编辑 ]

论坛徽章:
0
10 [报告]
发表于 2009-04-26 23:50 |只看该作者
恩 ,想了会,cat好像也不用考虑同步和异步的问题。

这是一条路,恩  谢谢!!

不过,因为后期可能nat就不好实现了吧,所以nl这边也会继续下去的。

我先输出下extern struct hlist_head *nf_conntrack_hash; 这个数据结构吧


输出的是00000  想了会,其实也应该是000000 ,因为我没和nf_conntrack模块发生任何通讯


是不是nf_conntrack模块与上层通讯的方式只有 "proc“呢?

[ 本帖最后由 C__J 于 2009-4-27 00:55 编辑 ]
您需要登录后才可以回帖 登录 | 注册

本版积分规则 发表回复

  

北京盛拓优讯信息技术有限公司. 版权所有 京ICP备16024965号-6 北京市公安局海淀分局网监中心备案编号:11010802020122 niuxiaotong@pcpop.com 17352615567
未成年举报专区
中国互联网协会会员  联系我们:huangweiwei@itpub.net
感谢所有关心和支持过ChinaUnix的朋友们 转载本站内容请注明原作者名及出处

清除 Cookies - ChinaUnix - Archiver - WAP - TOP