2 * Asterisk -- An open source telephony toolkit.
4 * Copyright (C) 1999 - 2005, Digium, Inc.
6 * Mark Spencer <markster@digium.com>
8 * See http://www.asterisk.org for more information about
9 * the Asterisk project. Please do not directly contact
10 * any of the maintainers of this project for assistance;
11 * the project provides a web site, mailing lists and IRC
12 * channels for your use.
14 * This program is free software, distributed under the terms of
15 * the GNU General Public License Version 2. See the LICENSE file
16 * at the top of the source tree.
21 * \brief RADIUS CDR Support
22 * \author Philippe Sultan
23 * \extref The Radius Client Library - http://developer.berlios.de/projects/radiusclient-ng/
25 * \arg See also \ref AstCDR
26 * \ingroup cdr_drivers
30 <depend>radius</depend>
35 ASTERISK_FILE_VERSION(__FILE__
, "$Rev$")
38 #include <radiusclient-ng.h>
40 #include "asterisk/channel.h"
41 #include "asterisk/cdr.h"
42 #include "asterisk/module.h"
43 #include "asterisk/utils.h"
45 /*! ISO 8601 standard format */
46 #define DATE_FORMAT "%Y-%m-%d %T %z"
48 #define VENDOR_CODE 22736
51 PW_AST_ACCT_CODE
= 101,
57 PW_AST_DST_CHAN
= 107,
58 PW_AST_LAST_APP
= 108,
59 PW_AST_LAST_DATA
= 109,
60 PW_AST_START_TIME
= 110,
61 PW_AST_ANSWER_TIME
= 111,
62 PW_AST_END_TIME
= 112,
63 PW_AST_DURATION
= 113,
64 PW_AST_BILL_SEC
= 114,
65 PW_AST_DISPOSITION
= 115,
66 PW_AST_AMA_FLAGS
= 116,
67 PW_AST_UNIQUE_ID
= 117,
68 PW_AST_USER_FIELD
= 118
72 /*! Log dates and times in UTC */
73 RADIUS_FLAG_USEGMTIME
= (1 << 0),
75 RADIUS_FLAG_LOGUNIQUEID
= (1 << 1),
77 RADIUS_FLAG_LOGUSERFIELD
= (1 << 2)
80 static char *desc
= "RADIUS CDR Backend";
81 static char *name
= "radius";
82 static char *cdr_config
= "cdr.conf";
84 static char radiuscfg
[PATH_MAX
] = "/etc/radiusclient-ng/radiusclient.conf";
86 static struct ast_flags global_flags
= { RADIUS_FLAG_USEGMTIME
| RADIUS_FLAG_LOGUNIQUEID
| RADIUS_FLAG_LOGUSERFIELD
};
88 static rc_handle
*rh
= NULL
;
90 static int build_radius_record(VALUE_PAIR
**send
, struct ast_cdr
*cdr
)
92 int recordtype
= PW_STATUS_STOP
;
97 if (!rc_avpair_add(rh
, send
, PW_ACCT_STATUS_TYPE
, &recordtype
, 0, 0))
101 if (!rc_avpair_add(rh
, send
, PW_AST_ACCT_CODE
, &cdr
->accountcode
, strlen(cdr
->accountcode
), VENDOR_CODE
))
105 if (!rc_avpair_add(rh
, send
, PW_AST_SRC
, &cdr
->src
, strlen(cdr
->src
), VENDOR_CODE
))
109 if (!rc_avpair_add(rh
, send
, PW_AST_DST
, &cdr
->dst
, strlen(cdr
->dst
), VENDOR_CODE
))
112 /* Destination context */
113 if (!rc_avpair_add(rh
, send
, PW_AST_DST_CTX
, &cdr
->dcontext
, strlen(cdr
->dcontext
), VENDOR_CODE
))
117 if (!rc_avpair_add(rh
, send
, PW_AST_CLID
, &cdr
->clid
, strlen(cdr
->clid
), VENDOR_CODE
))
121 if (!rc_avpair_add(rh
, send
, PW_AST_CHAN
, &cdr
->channel
, strlen(cdr
->channel
), VENDOR_CODE
))
124 /* Destination Channel */
125 if (!rc_avpair_add(rh
, send
, PW_AST_DST_CHAN
, &cdr
->dstchannel
, strlen(cdr
->dstchannel
), VENDOR_CODE
))
128 /* Last Application */
129 if (!rc_avpair_add(rh
, send
, PW_AST_LAST_APP
, &cdr
->lastapp
, strlen(cdr
->lastapp
), VENDOR_CODE
))
133 if (!rc_avpair_add(rh
, send
, PW_AST_LAST_DATA
, &cdr
->lastdata
, strlen(cdr
->lastdata
), VENDOR_CODE
))
138 ast_strftime(timestr
, sizeof(timestr
), DATE_FORMAT
,
139 ast_localtime(&cdr
->start
, &tm
,
140 ast_test_flag(&global_flags
, RADIUS_FLAG_USEGMTIME
) ? "GMT" : NULL
));
141 if (!rc_avpair_add(rh
, send
, PW_AST_START_TIME
, timestr
, strlen(timestr
), VENDOR_CODE
))
145 ast_strftime(timestr
, sizeof(timestr
), DATE_FORMAT
,
146 ast_localtime(&cdr
->answer
, &tm
,
147 ast_test_flag(&global_flags
, RADIUS_FLAG_USEGMTIME
) ? "GMT" : NULL
));
148 if (!rc_avpair_add(rh
, send
, PW_AST_ANSWER_TIME
, timestr
, strlen(timestr
), VENDOR_CODE
))
152 ast_strftime(timestr
, sizeof(timestr
), DATE_FORMAT
,
153 ast_localtime(&cdr
->end
, &tm
,
154 ast_test_flag(&global_flags
, RADIUS_FLAG_USEGMTIME
) ? "GMT" : NULL
));
155 if (!rc_avpair_add(rh
, send
, PW_AST_END_TIME
, timestr
, strlen(timestr
), VENDOR_CODE
))
159 if (!rc_avpair_add(rh
, send
, PW_AST_DURATION
, &cdr
->duration
, 0, VENDOR_CODE
))
162 /* Billable seconds */
163 if (!rc_avpair_add(rh
, send
, PW_AST_BILL_SEC
, &cdr
->billsec
, 0, VENDOR_CODE
))
167 tmp
= ast_cdr_disp2str(cdr
->disposition
);
168 if (!rc_avpair_add(rh
, send
, PW_AST_DISPOSITION
, tmp
, strlen(tmp
), VENDOR_CODE
))
172 tmp
= ast_cdr_flags2str(cdr
->amaflags
);
173 if (!rc_avpair_add(rh
, send
, PW_AST_AMA_FLAGS
, tmp
, strlen(tmp
), VENDOR_CODE
))
176 if (ast_test_flag(&global_flags
, RADIUS_FLAG_LOGUNIQUEID
)) {
178 if (!rc_avpair_add(rh
, send
, PW_AST_UNIQUE_ID
, &cdr
->uniqueid
, strlen(cdr
->uniqueid
), VENDOR_CODE
))
182 if (ast_test_flag(&global_flags
, RADIUS_FLAG_LOGUSERFIELD
)) {
183 /* append the user field */
184 if (!rc_avpair_add(rh
, send
, PW_AST_USER_FIELD
, &cdr
->userfield
, strlen(cdr
->userfield
), VENDOR_CODE
))
188 /* Setting Acct-Session-Id & User-Name attributes for proper generation
189 of Acct-Unique-Session-Id on server side */
191 if (!rc_avpair_add(rh
, send
, PW_USER_NAME
, &cdr
->channel
, strlen(cdr
->channel
), 0))
195 if (!rc_avpair_add(rh
, send
, PW_ACCT_SESSION_ID
, &cdr
->uniqueid
, strlen(cdr
->uniqueid
), 0))
201 static int radius_log(struct ast_cdr
*cdr
)
203 int result
= ERROR_RC
;
204 VALUE_PAIR
*send
= NULL
;
206 if (build_radius_record(&send
, cdr
)) {
207 ast_debug(1, "Unable to create RADIUS record. CDR not recorded!\n");
211 result
= rc_acct(rh
, 0, send
);
213 ast_log(LOG_ERROR
, "Failed to record Radius CDR record!\n");
218 static int unload_module(void)
220 ast_cdr_unregister(name
);
224 static int load_module(void)
226 struct ast_config
*cfg
;
227 struct ast_flags config_flags
= { 0 };
231 if ((cfg
= ast_config_load(cdr_config
, config_flags
))) {
232 ast_set2_flag(&global_flags
, ast_true(ast_variable_retrieve(cfg
, "radius", "usegmtime")), RADIUS_FLAG_USEGMTIME
);
233 ast_set2_flag(&global_flags
, ast_true(ast_variable_retrieve(cfg
, "radius", "loguniqueid")), RADIUS_FLAG_LOGUNIQUEID
);
234 ast_set2_flag(&global_flags
, ast_true(ast_variable_retrieve(cfg
, "radius", "loguserfield")), RADIUS_FLAG_LOGUSERFIELD
);
235 if ((tmp
= ast_variable_retrieve(cfg
, "radius", "radiuscfg")))
236 ast_copy_string(radiuscfg
, tmp
, sizeof(radiuscfg
));
237 ast_config_destroy(cfg
);
239 return AST_MODULE_LOAD_DECLINE
;
242 rc_openlog("asterisk");
244 /* read radiusclient-ng config file */
245 if (!(rh
= rc_read_config(radiuscfg
))) {
246 ast_log(LOG_NOTICE
, "Cannot load radiusclient-ng configuration file %s.\n", radiuscfg
);
247 return AST_MODULE_LOAD_DECLINE
;
250 /* read radiusclient-ng dictionaries */
251 if (rc_read_dictionary(rh
, rc_conf_str(rh
, "dictionary"))) {
252 ast_log(LOG_NOTICE
, "Cannot load radiusclient-ng dictionary file.\n");
253 return AST_MODULE_LOAD_DECLINE
;
256 res
= ast_cdr_register(name
, desc
, radius_log
);
257 return AST_MODULE_LOAD_SUCCESS
;
260 AST_MODULE_INFO_STANDARD(ASTERISK_GPL_KEY
, "RADIUS CDR Backend");