天天看点

# freeradius3.x扩展模块开发freeradius3.x扩展模块开发

freeradius3.x扩展模块开发

最近有个任务要移植做一个freeradius扩展模块完成认证计费功能,鼓捣了很久,终于做出来了,就记录下来,做个总结。

主要内容

大致可以分一下几个步骤

1. (如果有) 私有字段的添加

2. 模块结构配置

3. 模块结构体填充及函数编写

一、私有字段

在radius源码目录中share/dictionary 文件中添加一个私有字段的配置

一般位置放在

#   Vendor dictionaries are listed after the standard ones.
$INCLUDE dictionary.test
           

然后在这里创建一个文件

dictionary.test

里面就可以定义你自己的radius协议会发送的字段

具体可以参考已有的文件 比如思科交换机的 dictionary.cisco

首先需要一个vendor

VENDOR      Cisco               
BEGIN-VENDOR    Cisco
#这里就是可以写上你的私有字段了
ATTRIBUTE   Cisco-Account-Info           string
#这个是属性定义  要有id 和 类型
VALUE   Cisco-Disconnect-Cause      Unknown         
#这个是值的定义 也可以不定义值 但是你得知道你通过属性获取到值的时候代表什么
#这个就是你代码逻辑的处理,加上值的定以后,比如你有个属性是整形的,然后你得到了2
#freeradius会显示为unkonwn 但是即使不定义这个2 你在代码中仍然不影响你去进行判断
#所以只要你自己明白,可以value的定义不是必须的

END-VENDOR  Cisco  
           

二、模块结构配置

当要开发一个扩展模块时 ,很可能需要有些东西能够进行配置,

首先这些东西都是在一个结构体中,其实就是模块的实例结构 。比如下面

typedef struct rlm_example_t {
    bool        boolean;
    uint32_t    value;
    char const  *string;
    fr_ipaddr_t ipaddr;
} rlm_example_t;
           

这个结构就是模块在调用之前初始化和调用的时候你要用到的数据内容

里面可能是你的配置或者其他需要的东西,按需要自己定义。

然后可以对其进行一个默认的配置

static const CONF_PARSER module_config[] = {
    { "integer", FR_CONF_OFFSET(PW_TYPE_INTEGER, rlm_example_t, value), "1" },
    { "boolean", FR_CONF_OFFSET(PW_TYPE_BOOLEAN, rlm_example_t, boolean), "no" },
    { "string", FR_CONF_OFFSET(PW_TYPE_STRING, rlm_example_t, string), NULL },
    { "ipaddr", FR_CONF_OFFSET(PW_TYPE_IPV4_ADDR, rlm_example_t, ipaddr), "*" },
    CONF_PARSER_TERMINATOR
};
           

这里顶一个一个解析器,可以添入默认的值,但这个在你读取配置文件的时候是会被覆盖掉,所以在配置文件里 如果不想被覆盖的东西就不要进行配置了

==模块的配置文件放在raddb/mods-available/模块名 这样一个文件==

文件格式可以仿照其他进行编写

==字段一定要和结构体里进行匹配==

三、总体和代码的编写

一个完整的扩展模块基本上内容是

1. 一个以 rlm_模块命称 命名的文件夹,里面放有 源码还有 configure.ac 等需要用来配置编译的文件 位置在src/modules/文件夹下

2. 一个以 模块名称 命名的 配置文件放在 raddb/mods-avaliable/下面。并且需要在raddb/all.mk中加上它的名字这样就可以在编译的时候进行链接 自动安装。

3. 一个已 dictionary.模块名称 命名的 私有字段配置 。在dictionary中进行include

以上两步基本上把配置都搞定了 ,底下最重要的就是代码的编写了

在模块文件夹中rlm_modname.c 中 要定义一个全局的module注册结构

extern module_t rlm_example;
module_t rlm_example = {
    .magic      = RLM_MODULE_INIT,
    .name       = "example",
    .type       = RLM_TYPE_THREAD_SAFE,
    .inst_size  = sizeof(rlm_example_t),
    .config     = module_config,// 配置的全局数组
    .instantiate    = mod_instantiate,//初始化函数
    .detach     = mod_detach, //释放函数
    .methods = {
        [MOD_AUTHENTICATE]  = mod_authenticate, 
        [MOD_AUTHORIZE]     = mod_authorize, //认证函数
#ifdef WITH_ACCOUNTING
        [MOD_PREACCT]       = mod_preacct,
        [MOD_ACCOUNTING]    = mod_accounting,//计费函数
        [MOD_SESSION]       = mod_checksimul
#endif
    },
};
           

根据需要添入相应的字段

然后就可以进行模块的编写了 。具体代码逻辑就看个人了

有一点要注意的是

私有字段的获取方法

fr_pair_find_by_num(request->packet->vps, 自定义的id, 自定义vendorid, TAG_ANY);
           

默认字段的获取方法

fr_pair_find_by_num(request->packet->vps, 字段id, , TAG_ANY);
           

这个地方我找了很久才发现的,走了很多弯路。

其他东西就是看需求进行模块的编写了,整体还是有些难度的,可以参考rlm_example

这个模块的事例,

另外有一个官方的教程 也可以作为参考 并不全

链接如下

http://wiki.freeradius.org/contributing/Modules3

希望可以帮助到大家 转载注明出处 ,不对的地方欢迎指正 ,其实我根本没看懂那模块怎么注册怎么调用的,我根本不知道freeradius整体的源码内容,时间紧,水平有限 只是根据已存在的模块进行扩展模块的编写,所以如果有大牛欢迎指点我