免费注册 查看新帖 |

Chinaunix

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

求助:关于ipset与内核通信的机制 [复制链接]

论坛徽章:
0
跳转到指定楼层
1 [收藏(0)] [报告]
发表于 2011-12-14 17:18 |只看该作者 |倒序浏览
本帖最后由 ellisonfan 于 2011-12-14 17:59 编辑

求助,最近在看ipset2.3的代码,但是怎么与内核通信的没看明白。

我知道一般与内核通信会采取netlink方式,而且似乎ipset后期也是采取这样的方式。但这个版本用的方式实在看不明白,下面是用户空间的代码,希望有高手帮忙解惑
  1. static int kernel_getsocket(void)
  2. {
  3.         int sockfd = -1;

  4.         sockfd = socket(AF_INET, SOCK_RAW, IPPROTO_RAW);
  5.         if (sockfd < 0)
  6.                 exit_error(OTHER_PROBLEM,
  7.                            "You need to be root to perform this command.");

  8.         return sockfd;
  9. }
复制代码
  1. static inline int wrapped_getsockopt(void *data, socklen_t *size)
  2. {
  3.         int res;
  4.         int sockfd = kernel_getsocket();

  5.         /* Send! */
  6.         res = getsockopt(sockfd, SOL_IP, SO_IP_SET, data, size);
  7.         if (res != 0
  8.             && errno == ENOPROTOOPT
  9.             && ipset_insmod("ip_set", "/sbin/modprobe") == 0)
  10.                 res = getsockopt(sockfd, SOL_IP, SO_IP_SET, data, size);
  11.         DP("res=%d errno=%d", res, errno);
  12.        
  13.         return res;
  14. }
复制代码
  1. static inline int wrapped_setsockopt(void *data, socklen_t size)
  2. {
  3.         int res;
  4.         int sockfd = kernel_getsocket();

  5.         /* Send! */
  6.         res = setsockopt(sockfd, SOL_IP, SO_IP_SET, data, size);
  7.         if (res != 0
  8.             && errno == ENOPROTOOPT
  9.             && ipset_insmod("ip_set", "/sbin/modprobe") == 0)
  10.                 res = setsockopt(sockfd, SOL_IP, SO_IP_SET, data, size);
  11.         DP("res=%d errno=%d", res, errno);
  12.        
  13.         return res;
  14. }
复制代码
  1. static void kernel_getfrom(unsigned cmd, void *data, socklen_t * size)
  2. {
  3.         int res = wrapped_getsockopt(data, size);

  4.         if (res != 0)
  5.                 kernel_error(cmd, errno);
  6. }
复制代码
  1. static void kernel_sendto(unsigned cmd, void *data, size_t size)
  2. {
  3.         int res = wrapped_setsockopt(data, size);

  4.         if (res != 0)
  5.                 kernel_error(cmd, errno);
  6. }
复制代码

论坛徽章:
5
处女座
日期:2014-10-15 11:57:302015年亚洲杯之中国
日期:2015-03-04 17:05:552015亚冠之西悉尼流浪者
日期:2015-07-31 12:14:2915-16赛季CBA联赛之同曦
日期:2015-12-10 18:14:0615-16赛季CBA联赛之北京
日期:2016-07-07 17:01:53
2 [报告]
发表于 2011-12-14 20:50 |只看该作者
netfilter提供了nf_register_sockopt()和nf_unregister_sockopt()来动态登记或取消sockopt命令字。
应用层通过getsockopt和setsockopt来传递命令


ipset内核层的代码创建了一个nf_sockopt_ops 实例:

static struct nf_sockopt_ops so_set = {
        .pf                 = PF_INET,
        .set_optmin         = SO_IP_SET,
        .set_optmax         = SO_IP_SET + 1,
        .set                 = &ip_set_sockfn_set,
        .get_optmin         = SO_IP_SET,
        .get_optmax        = SO_IP_SET + 1,
        .get                = &ip_set_sockfn_get,
#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,23)
        .use                = 0,
#else
        .owner                = THIS_MODULE,
#endif
};


初始化的时候再向内核注册:

static int __init
ip_set_init(void)
{
        int res;

        /* For the -rt branch, DECLARE_MUTEX/init_MUTEX avoided */
        sema_init(&ip_set_app_mutex, 1);

        if (max_sets)
                ip_set_max = max_sets;
        if (ip_set_max >= IP_SET_INVALID_ID)
                ip_set_max = IP_SET_INVALID_ID - 1;

        ip_set_list = vmalloc(sizeof(struct ip_set *) * ip_set_max);
        if (!ip_set_list) {
                printk(KERN_ERR "Unable to create ip_set_list\n");
                return -ENOMEM;
        }
        memset(ip_set_list, 0, sizeof(struct ip_set *) * ip_set_max);

        INIT_LIST_HEAD(&set_type_list);

        res = nf_register_sockopt(&so_set); //向内核注册so_set,后续便可以和应用层通信。
        if (res != 0) {
                ip_set_printk("SO_SET registry failed: %d", res);
                vfree(ip_set_list);
                return res;
        }

        printk("ip_set version %u loaded\n", IP_SET_PROTOCOL_VERSION);       
        return 0;
}


具体代码可以查看ip_set.c这个文件。我也是新手哈,表述不清楚的地方请见谅。

论坛徽章:
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
3 [报告]
发表于 2011-12-14 20:55 |只看该作者
嗯,看了上面贴的部分代码,感觉应该是用的 socekopt。

论坛徽章:
6
金牛座
日期:2013-10-08 10:19:10技术图书徽章
日期:2013-10-14 16:24:09CU十二周年纪念徽章
日期:2013-10-24 15:41:34狮子座
日期:2013-11-24 19:26:19未羊
日期:2014-01-23 15:50:002015年亚洲杯之阿联酋
日期:2015-05-09 14:36:15
4 [报告]
发表于 2011-12-15 07:42 |只看该作者
回复 1# ellisonfan
内核与用户态通信的方法有很多种,这里用的应该是sockopt。
要想看ipset最新的通信机制,建议看最新的代码ipset-6.10.tar.bz2(下载地址http://ipset.netfilter.org/install.html)

论坛徽章:
0
5 [报告]
发表于 2011-12-15 09:17 |只看该作者
本帖最后由 ellisonfan 于 2011-12-15 09:19 编辑

回复 2# zhanglin496
谢谢你的帮忙,嗯,我找到那个函数了,用的是netfilter提供的函数,非常感谢
也非常感谢楼上几位的帮忙
您需要登录后才可以回帖 登录 | 注册

本版积分规则 发表回复

  

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

清除 Cookies - ChinaUnix - Archiver - WAP - TOP