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
24 * \arg See also \ref AstCDR
25 * \ingroup cdr_drivers
29 <depend>radiusclient</depend>
38 #include <sys/types.h>
39 #include <radiusclient-ng.h>
43 ASTERISK_FILE_VERSION(__FILE__, "$Rev$")
45 #include "asterisk/channel.h"
46 #include "asterisk/cdr.h"
47 #include "asterisk/module.h"
48 #include "asterisk/logger.h"
49 #include "asterisk/utils.h"
51 /*! ISO 8601 standard format */
52 #define DATE_FORMAT "%Y-%m-%d %T %z"
54 #define VENDOR_CODE 22736
57 PW_AST_ACCT_CODE = 101,
63 PW_AST_DST_CHAN = 107,
64 PW_AST_LAST_APP = 108,
65 PW_AST_LAST_DATA = 109,
66 PW_AST_START_TIME = 110,
67 PW_AST_ANSWER_TIME = 111,
68 PW_AST_END_TIME = 112,
69 PW_AST_DURATION = 113,
70 PW_AST_BILL_SEC = 114,
71 PW_AST_DISPOSITION = 115,
72 PW_AST_AMA_FLAGS = 116,
73 PW_AST_UNIQUE_ID = 117,
74 PW_AST_USER_FIELD = 118
78 /*! Log dates and times in UTC */
79 RADIUS_FLAG_USEGMTIME = (1 << 0),
81 RADIUS_FLAG_LOGUNIQUEID = (1 << 1),
83 RADIUS_FLAG_LOGUSERFIELD = (1 << 2)
86 static char *desc = "RADIUS CDR Backend";
87 static char *name = "radius";
88 static char *cdr_config = "cdr.conf";
90 static char radiuscfg[AST_CONFIG_MAX_PATH] = "/etc/radiusclient-ng/radiusclient.conf";
92 static struct ast_flags global_flags = { RADIUS_FLAG_USEGMTIME | RADIUS_FLAG_LOGUNIQUEID | RADIUS_FLAG_LOGUSERFIELD };
94 static rc_handle *rh = NULL;
96 static int build_radius_record(VALUE_PAIR **send, struct ast_cdr *cdr)
98 int recordtype = PW_STATUS_STOP;
103 if (!rc_avpair_add(rh, send, PW_ACCT_STATUS_TYPE, &recordtype, 0, 0)) {
104 ast_log(LOG_WARNING, "Failed to add VALUE PAIR. RADIUS CDR not recorded!\n");
109 if (!rc_avpair_add(rh, send, PW_AST_ACCT_CODE, &cdr->accountcode, strlen(cdr->accountcode), VENDOR_CODE)) {
110 ast_log(LOG_WARNING, "Failed to add VALUE PAIR. RADIUS CDR not recorded!\n");
115 if (!rc_avpair_add(rh, send, PW_AST_SRC, &cdr->src, strlen(cdr->src), VENDOR_CODE)) {
116 ast_log(LOG_WARNING, "Failed to add VALUE PAIR. RADIUS CDR not recorded!\n");
121 if (!rc_avpair_add(rh, send, PW_AST_DST, &cdr->dst, strlen(cdr->dst), VENDOR_CODE)) {
122 ast_log(LOG_WARNING, "Failed to add VALUE PAIR. RADIUS CDR not recorded!\n");
126 /* Destination context */
127 if (!rc_avpair_add(rh, send, PW_AST_DST_CTX, &cdr->dcontext, strlen(cdr->dcontext), VENDOR_CODE)) {
128 ast_log(LOG_WARNING, "Failed to add VALUE PAIR. RADIUS CDR not recorded!\n");
133 if (!rc_avpair_add(rh, send, PW_AST_CLID, &cdr->clid, strlen(cdr->clid), VENDOR_CODE)) {
134 ast_log(LOG_WARNING, "Failed to add VALUE PAIR. RADIUS CDR not recorded!\n");
139 if (!rc_avpair_add(rh, send, PW_AST_CHAN, &cdr->channel, strlen(cdr->channel), VENDOR_CODE)) {
140 ast_log(LOG_WARNING, "Failed to add VALUE PAIR. RADIUS CDR not recorded!\n");
144 /* Destination Channel */
145 if (!rc_avpair_add(rh, send, PW_AST_DST_CHAN, &cdr->dstchannel, strlen(cdr->dstchannel), VENDOR_CODE)) {
146 ast_log(LOG_WARNING, "Failed to add VALUE PAIR. RADIUS CDR not recorded!\n");
150 /* Last Application */
151 if (!rc_avpair_add(rh, send, PW_AST_LAST_APP, &cdr->lastapp, strlen(cdr->lastapp), VENDOR_CODE)) {
152 ast_log(LOG_WARNING, "Failed to add VALUE PAIR. RADIUS CDR not recorded!\n");
157 if (!rc_avpair_add(rh, send, PW_AST_LAST_DATA, &cdr->lastdata, strlen(cdr->lastdata), VENDOR_CODE)) {
158 ast_log(LOG_WARNING, "Failed to add VALUE PAIR. RADIUS CDR not recorded!\n");
164 if (ast_test_flag(&global_flags, RADIUS_FLAG_USEGMTIME))
165 gmtime_r(&(cdr->start.tv_sec), &tm);
167 localtime_r(&(cdr->start.tv_sec), &tm);
168 strftime(timestr, sizeof(timestr), DATE_FORMAT, &tm);
169 if (!rc_avpair_add(rh, send, PW_AST_START_TIME, timestr, strlen(timestr), VENDOR_CODE)) {
170 ast_log(LOG_WARNING, "Failed to add VALUE PAIR. RADIUS CDR not recorded!\n");
175 if (ast_test_flag(&global_flags, RADIUS_FLAG_USEGMTIME))
176 gmtime_r(&(cdr->answer.tv_sec), &tm);
178 localtime_r(&(cdr->answer.tv_sec), &tm);
179 strftime(timestr, sizeof(timestr), DATE_FORMAT, &tm);
180 if (!rc_avpair_add(rh, send, PW_AST_ANSWER_TIME, timestr, strlen(timestr), VENDOR_CODE)) {
181 ast_log(LOG_WARNING, "Failed to add VALUE PAIR. RADIUS CDR not recorded!\n");
186 if (ast_test_flag(&global_flags, RADIUS_FLAG_USEGMTIME))
187 gmtime_r(&(cdr->end.tv_sec), &tm);
189 localtime_r(&(cdr->end.tv_sec), &tm);
190 strftime(timestr, sizeof(timestr), DATE_FORMAT, &tm);
191 if (!rc_avpair_add(rh, send, PW_AST_END_TIME, timestr, strlen(timestr), VENDOR_CODE)) {
192 ast_log(LOG_WARNING, "Failed to add VALUE PAIR. RADIUS CDR not recorded!\n");
197 if (!rc_avpair_add(rh, send, PW_AST_DURATION, &cdr->duration, 0, VENDOR_CODE)) {
198 ast_log(LOG_WARNING, "Failed to add VALUE PAIR. RADIUS CDR not recorded!\n");
202 /* Billable seconds */
203 if (!rc_avpair_add(rh, send, PW_AST_BILL_SEC, &cdr->billsec, 0, VENDOR_CODE)) {
204 ast_log(LOG_WARNING, "Failed to add VALUE PAIR. RADIUS CDR not recorded!\n");
209 tmp = ast_cdr_disp2str(cdr->disposition);
210 if (!rc_avpair_add(rh, send, PW_AST_DISPOSITION, tmp, strlen(tmp), VENDOR_CODE)) {
211 ast_log(LOG_WARNING, "Failed to add VALUE PAIR. RADIUS CDR not recorded!\n");
216 tmp = ast_cdr_flags2str(cdr->amaflags);
217 if (!rc_avpair_add(rh, send, PW_AST_AMA_FLAGS, tmp, strlen(tmp), VENDOR_CODE)) {
218 ast_log(LOG_WARNING, "Failed to add VALUE PAIR. RADIUS CDR not recorded!\n");
222 if (ast_test_flag(&global_flags, RADIUS_FLAG_LOGUNIQUEID)) {
224 if (!rc_avpair_add(rh, send, PW_AST_UNIQUE_ID, &cdr->uniqueid, strlen(cdr->uniqueid), VENDOR_CODE)) {
225 ast_log(LOG_WARNING, "Failed to add VALUE PAIR. RADIUS CDR not recorded!\n");
230 if (ast_test_flag(&global_flags, RADIUS_FLAG_LOGUSERFIELD)) {
231 /* append the user field */
232 if (!rc_avpair_add(rh, send, PW_AST_USER_FIELD, &cdr->userfield, strlen(cdr->userfield), VENDOR_CODE)) {
233 ast_log(LOG_WARNING, "Failed to add VALUE PAIR. RADIUS CDR not recorded!\n");
238 /* Setting Acct-Session-Id & User-Name attributes for proper generation
239 of Acct-Unique-Session-Id on server side */
241 if (!rc_avpair_add(rh, send, PW_USER_NAME, &cdr->channel, strlen(cdr->channel), 0)) {
242 ast_log(LOG_WARNING, "Failed to add VALUE PAIR. RADIUS CDR not recorded!\n");
246 if (!rc_avpair_add(rh, send, PW_ACCT_SESSION_ID, &cdr->uniqueid, strlen(cdr->uniqueid), 0)) {
247 ast_log(LOG_WARNING, "Failed to add VALUE PAIR. RADIUS CDR not recorded!\n");
253 static int radius_log(struct ast_cdr *cdr)
255 int result = ERROR_RC;
256 VALUE_PAIR *send = NULL;
258 if (build_radius_record(&send, cdr)) {
259 ast_log(LOG_WARNING, "Unable to create RADIUS record. CDR not recorded!\n");
263 result = rc_acct(rh, 0, send);
265 ast_log(LOG_ERROR, "Failed to record Radius CDR record!\n");
270 static const char *description(void)
275 static int unload_module(void *mod)
277 ast_cdr_unregister(name);
281 static int load_module(void *mod)
283 struct ast_config *cfg;
286 if ((cfg = ast_config_load(cdr_config))) {
287 ast_set2_flag(&global_flags, ast_true(ast_variable_retrieve(cfg, "radius", "usegmtime")), RADIUS_FLAG_USEGMTIME);
288 ast_set2_flag(&global_flags, ast_true(ast_variable_retrieve(cfg, "radius", "loguniqueid")), RADIUS_FLAG_LOGUNIQUEID);
289 ast_set2_flag(&global_flags, ast_true(ast_variable_retrieve(cfg, "radius", "loguserfield")), RADIUS_FLAG_LOGUSERFIELD);
290 if ((tmp = ast_variable_retrieve(cfg, "radius", "radiuscfg")))
291 ast_copy_string(radiuscfg, tmp, sizeof(radiuscfg));
292 ast_config_destroy(cfg);
296 rc_openlog("asterisk");
298 /* read radiusclient-ng config file */
299 if (!(rh = rc_read_config(radiuscfg))) {
300 ast_log(LOG_NOTICE, "Cannot load radiusclient-ng configuration file %s.\n", radiuscfg);
304 /* read radiusclient-ng dictionaries */
305 if (rc_read_dictionary(rh, rc_conf_str(rh, "dictionary"))) {
306 ast_log(LOG_NOTICE, "Cannot load radiusclient-ng dictionary file.\n");
310 return ast_cdr_register(name, desc, radius_log);
313 static const char *key(void)
315 return ASTERISK_GPL_KEY;
318 STD_MOD(MOD_0, NULL, NULL, NULL);