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 ast_localtime(&(cdr
->start
.tv_sec
), &tm
, NULL
);
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 ast_localtime(&(cdr
->answer
.tv_sec
), &tm
, NULL
);
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 ast_localtime(&(cdr
->end
.tv_sec
), &tm
, NULL
);
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 int unload_module(void)
234 ast_cdr_unregister(name
);
238 static int load_module(void)
240 struct ast_config
*cfg
;
244 if ((cfg
= ast_config_load(cdr_config
))) {
245 ast_set2_flag(&global_flags
, ast_true(ast_variable_retrieve(cfg
, "radius", "usegmtime")), RADIUS_FLAG_USEGMTIME
);
246 ast_set2_flag(&global_flags
, ast_true(ast_variable_retrieve(cfg
, "radius", "loguniqueid")), RADIUS_FLAG_LOGUNIQUEID
);
247 ast_set2_flag(&global_flags
, ast_true(ast_variable_retrieve(cfg
, "radius", "loguserfield")), RADIUS_FLAG_LOGUSERFIELD
);
248 if ((tmp
= ast_variable_retrieve(cfg
, "radius", "radiuscfg")))
249 ast_copy_string(radiuscfg
, tmp
, sizeof(radiuscfg
));
250 ast_config_destroy(cfg
);
252 return AST_MODULE_LOAD_DECLINE
;
255 rc_openlog("asterisk");
257 /* read radiusclient-ng config file */
258 if (!(rh
= rc_read_config(radiuscfg
))) {
259 ast_log(LOG_NOTICE
, "Cannot load radiusclient-ng configuration file %s.\n", radiuscfg
);
260 return AST_MODULE_LOAD_DECLINE
;
263 /* read radiusclient-ng dictionaries */
264 if (rc_read_dictionary(rh
, rc_conf_str(rh
, "dictionary"))) {
265 ast_log(LOG_NOTICE
, "Cannot load radiusclient-ng dictionary file.\n");
266 return AST_MODULE_LOAD_DECLINE
;
269 res
= ast_cdr_register(name
, desc
, radius_log
);
270 return AST_MODULE_LOAD_SUCCESS
;
273 AST_MODULE_INFO_STANDARD(ASTERISK_GPL_KEY
, "RADIUS CDR Backend");