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>radius</depend>
34 ASTERISK_FILE_VERSION(__FILE__, "$Rev$")
42 #include <sys/types.h>
43 #include <radiusclient-ng.h>
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"
50 #include "asterisk/options.h"
52 /*! ISO 8601 standard format */
53 #define DATE_FORMAT "%Y-%m-%d %T %z"
55 #define VENDOR_CODE 22736
58 PW_AST_ACCT_CODE = 101,
64 PW_AST_DST_CHAN = 107,
65 PW_AST_LAST_APP = 108,
66 PW_AST_LAST_DATA = 109,
67 PW_AST_START_TIME = 110,
68 PW_AST_ANSWER_TIME = 111,
69 PW_AST_END_TIME = 112,
70 PW_AST_DURATION = 113,
71 PW_AST_BILL_SEC = 114,
72 PW_AST_DISPOSITION = 115,
73 PW_AST_AMA_FLAGS = 116,
74 PW_AST_UNIQUE_ID = 117,
75 PW_AST_USER_FIELD = 118
79 /*! Log dates and times in UTC */
80 RADIUS_FLAG_USEGMTIME = (1 << 0),
82 RADIUS_FLAG_LOGUNIQUEID = (1 << 1),
84 RADIUS_FLAG_LOGUSERFIELD = (1 << 2)
87 static char *desc = "RADIUS CDR Backend";
88 static char *name = "radius";
89 static char *cdr_config = "cdr.conf";
91 static char radiuscfg[PATH_MAX] = "/etc/radiusclient-ng/radiusclient.conf";
93 static struct ast_flags global_flags = { RADIUS_FLAG_USEGMTIME | RADIUS_FLAG_LOGUNIQUEID | RADIUS_FLAG_LOGUSERFIELD };
95 static rc_handle *rh = NULL;
97 static int build_radius_record(VALUE_PAIR **send, struct ast_cdr *cdr)
99 int recordtype = PW_STATUS_STOP;
104 if (!rc_avpair_add(rh, send, PW_ACCT_STATUS_TYPE, &recordtype, 0, 0))
108 if (!rc_avpair_add(rh, send, PW_AST_ACCT_CODE, &cdr->accountcode, strlen(cdr->accountcode), VENDOR_CODE))
112 if (!rc_avpair_add(rh, send, PW_AST_SRC, &cdr->src, strlen(cdr->src), VENDOR_CODE))
116 if (!rc_avpair_add(rh, send, PW_AST_DST, &cdr->dst, strlen(cdr->dst), VENDOR_CODE))
119 /* Destination context */
120 if (!rc_avpair_add(rh, send, PW_AST_DST_CTX, &cdr->dcontext, strlen(cdr->dcontext), VENDOR_CODE))
124 if (!rc_avpair_add(rh, send, PW_AST_CLID, &cdr->clid, strlen(cdr->clid), VENDOR_CODE))
128 if (!rc_avpair_add(rh, send, PW_AST_CHAN, &cdr->channel, strlen(cdr->channel), VENDOR_CODE))
131 /* Destination Channel */
132 if (!rc_avpair_add(rh, send, PW_AST_DST_CHAN, &cdr->dstchannel, strlen(cdr->dstchannel), VENDOR_CODE))
135 /* Last Application */
136 if (!rc_avpair_add(rh, send, PW_AST_LAST_APP, &cdr->lastapp, strlen(cdr->lastapp), VENDOR_CODE))
140 if (!rc_avpair_add(rh, send, PW_AST_LAST_DATA, &cdr->lastdata, strlen(cdr->lastdata), VENDOR_CODE))
145 if (ast_test_flag(&global_flags, RADIUS_FLAG_USEGMTIME))
146 gmtime_r(&(cdr->start.tv_sec), &tm);
148 localtime_r(&(cdr->start.tv_sec), &tm);
149 strftime(timestr, sizeof(timestr), DATE_FORMAT, &tm);
150 if (!rc_avpair_add(rh, send, PW_AST_START_TIME, timestr, strlen(timestr), VENDOR_CODE))
154 if (ast_test_flag(&global_flags, RADIUS_FLAG_USEGMTIME))
155 gmtime_r(&(cdr->answer.tv_sec), &tm);
157 localtime_r(&(cdr->answer.tv_sec), &tm);
158 strftime(timestr, sizeof(timestr), DATE_FORMAT, &tm);
159 if (!rc_avpair_add(rh, send, PW_AST_ANSWER_TIME, timestr, strlen(timestr), VENDOR_CODE))
163 if (ast_test_flag(&global_flags, RADIUS_FLAG_USEGMTIME))
164 gmtime_r(&(cdr->end.tv_sec), &tm);
166 localtime_r(&(cdr->end.tv_sec), &tm);
167 strftime(timestr, sizeof(timestr), DATE_FORMAT, &tm);
168 if (!rc_avpair_add(rh, send, PW_AST_END_TIME, timestr, strlen(timestr), VENDOR_CODE))
172 if (!rc_avpair_add(rh, send, PW_AST_DURATION, &cdr->duration, 0, VENDOR_CODE))
175 /* Billable seconds */
176 if (!rc_avpair_add(rh, send, PW_AST_BILL_SEC, &cdr->billsec, 0, VENDOR_CODE))
180 tmp = ast_cdr_disp2str(cdr->disposition);
181 if (!rc_avpair_add(rh, send, PW_AST_DISPOSITION, tmp, strlen(tmp), VENDOR_CODE))
185 tmp = ast_cdr_flags2str(cdr->amaflags);
186 if (!rc_avpair_add(rh, send, PW_AST_AMA_FLAGS, tmp, strlen(tmp), VENDOR_CODE))
189 if (ast_test_flag(&global_flags, RADIUS_FLAG_LOGUNIQUEID)) {
191 if (!rc_avpair_add(rh, send, PW_AST_UNIQUE_ID, &cdr->uniqueid, strlen(cdr->uniqueid), VENDOR_CODE))
195 if (ast_test_flag(&global_flags, RADIUS_FLAG_LOGUSERFIELD)) {
196 /* append the user field */
197 if (!rc_avpair_add(rh, send, PW_AST_USER_FIELD, &cdr->userfield, strlen(cdr->userfield), VENDOR_CODE))
201 /* Setting Acct-Session-Id & User-Name attributes for proper generation
202 of Acct-Unique-Session-Id on server side */
204 if (!rc_avpair_add(rh, send, PW_USER_NAME, &cdr->channel, strlen(cdr->channel), 0))
208 if (!rc_avpair_add(rh, send, PW_ACCT_SESSION_ID, &cdr->uniqueid, strlen(cdr->uniqueid), 0))
214 static int radius_log(struct ast_cdr *cdr)
216 int result = ERROR_RC;
217 VALUE_PAIR *send = NULL;
219 if (build_radius_record(&send, cdr)) {
221 ast_log(LOG_DEBUG, "Unable to create RADIUS record. CDR not recorded!\n");
225 result = rc_acct(rh, 0, send);
227 ast_log(LOG_ERROR, "Failed to record Radius CDR record!\n");
232 static const char *description(void)
237 static int unload_module(void *mod)
239 ast_cdr_unregister(name);
243 static int load_module(void *mod)
245 struct ast_config *cfg;
248 if ((cfg = ast_config_load(cdr_config))) {
249 ast_set2_flag(&global_flags, ast_true(ast_variable_retrieve(cfg, "radius", "usegmtime")), RADIUS_FLAG_USEGMTIME);
250 ast_set2_flag(&global_flags, ast_true(ast_variable_retrieve(cfg, "radius", "loguniqueid")), RADIUS_FLAG_LOGUNIQUEID);
251 ast_set2_flag(&global_flags, ast_true(ast_variable_retrieve(cfg, "radius", "loguserfield")), RADIUS_FLAG_LOGUSERFIELD);
252 if ((tmp = ast_variable_retrieve(cfg, "radius", "radiuscfg")))
253 ast_copy_string(radiuscfg, tmp, sizeof(radiuscfg));
254 ast_config_destroy(cfg);
258 rc_openlog("asterisk");
260 /* read radiusclient-ng config file */
261 if (!(rh = rc_read_config(radiuscfg))) {
262 ast_log(LOG_NOTICE, "Cannot load radiusclient-ng configuration file %s.\n", radiuscfg);
266 /* read radiusclient-ng dictionaries */
267 if (rc_read_dictionary(rh, rc_conf_str(rh, "dictionary"))) {
268 ast_log(LOG_NOTICE, "Cannot load radiusclient-ng dictionary file.\n");
272 return ast_cdr_register(name, desc, radius_log);
275 static const char *key(void)
277 return ASTERISK_GPL_KEY;
280 STD_MOD(MOD_0, NULL, NULL, NULL);