00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032 #include "asterisk.h"
00033
00034 ASTERISK_FILE_VERSION(__FILE__, "$Rev: 186229 $")
00035
00036 #include <stdlib.h>
00037 #include <stdio.h>
00038 #include <string.h>
00039 #include <errno.h>
00040 #include <unistd.h>
00041 #include <time.h>
00042 #include <sys/types.h>
00043 #include <radiusclient-ng.h>
00044
00045 #include "asterisk/channel.h"
00046 #include "asterisk/cdr.h"
00047 #include "asterisk/module.h"
00048 #include "asterisk/logger.h"
00049 #include "asterisk/utils.h"
00050 #include "asterisk/options.h"
00051
00052
00053 #define DATE_FORMAT "%Y-%m-%d %T %z"
00054
00055 #define VENDOR_CODE 22736
00056
00057 enum {
00058 PW_AST_ACCT_CODE = 101,
00059 PW_AST_SRC = 102,
00060 PW_AST_DST = 103,
00061 PW_AST_DST_CTX = 104,
00062 PW_AST_CLID = 105,
00063 PW_AST_CHAN = 106,
00064 PW_AST_DST_CHAN = 107,
00065 PW_AST_LAST_APP = 108,
00066 PW_AST_LAST_DATA = 109,
00067 PW_AST_START_TIME = 110,
00068 PW_AST_ANSWER_TIME = 111,
00069 PW_AST_END_TIME = 112,
00070 PW_AST_DURATION = 113,
00071 PW_AST_BILL_SEC = 114,
00072 PW_AST_DISPOSITION = 115,
00073 PW_AST_AMA_FLAGS = 116,
00074 PW_AST_UNIQUE_ID = 117,
00075 PW_AST_USER_FIELD = 118
00076 };
00077
00078 enum {
00079
00080 RADIUS_FLAG_USEGMTIME = (1 << 0),
00081
00082 RADIUS_FLAG_LOGUNIQUEID = (1 << 1),
00083
00084 RADIUS_FLAG_LOGUSERFIELD = (1 << 2)
00085 };
00086
00087 static char *desc = "RADIUS CDR Backend";
00088 static char *name = "radius";
00089 static char *cdr_config = "cdr.conf";
00090
00091 static char radiuscfg[PATH_MAX] = "/etc/radiusclient-ng/radiusclient.conf";
00092
00093 static struct ast_flags global_flags = { RADIUS_FLAG_USEGMTIME | RADIUS_FLAG_LOGUNIQUEID | RADIUS_FLAG_LOGUSERFIELD };
00094
00095 static rc_handle *rh = NULL;
00096
00097 static int build_radius_record(VALUE_PAIR **send, struct ast_cdr *cdr)
00098 {
00099 int recordtype = PW_STATUS_STOP;
00100 struct tm tm;
00101 char timestr[128];
00102 char *tmp;
00103
00104 if (!rc_avpair_add(rh, send, PW_ACCT_STATUS_TYPE, &recordtype, 0, 0))
00105 return -1;
00106
00107
00108 if (!rc_avpair_add(rh, send, PW_AST_ACCT_CODE, &cdr->accountcode, strlen(cdr->accountcode), VENDOR_CODE))
00109 return -1;
00110
00111
00112 if (!rc_avpair_add(rh, send, PW_AST_SRC, &cdr->src, strlen(cdr->src), VENDOR_CODE))
00113 return -1;
00114
00115
00116 if (!rc_avpair_add(rh, send, PW_AST_DST, &cdr->dst, strlen(cdr->dst), VENDOR_CODE))
00117 return -1;
00118
00119
00120 if (!rc_avpair_add(rh, send, PW_AST_DST_CTX, &cdr->dcontext, strlen(cdr->dcontext), VENDOR_CODE))
00121 return -1;
00122
00123
00124 if (!rc_avpair_add(rh, send, PW_AST_CLID, &cdr->clid, strlen(cdr->clid), VENDOR_CODE))
00125 return -1;
00126
00127
00128 if (!rc_avpair_add(rh, send, PW_AST_CHAN, &cdr->channel, strlen(cdr->channel), VENDOR_CODE))
00129 return -1;
00130
00131
00132 if (!rc_avpair_add(rh, send, PW_AST_DST_CHAN, &cdr->dstchannel, strlen(cdr->dstchannel), VENDOR_CODE))
00133 return -1;
00134
00135
00136 if (!rc_avpair_add(rh, send, PW_AST_LAST_APP, &cdr->lastapp, strlen(cdr->lastapp), VENDOR_CODE))
00137 return -1;
00138
00139
00140 if (!rc_avpair_add(rh, send, PW_AST_LAST_DATA, &cdr->lastdata, strlen(cdr->lastdata), VENDOR_CODE))
00141 return -1;
00142
00143
00144
00145 if (ast_test_flag(&global_flags, RADIUS_FLAG_USEGMTIME))
00146 gmtime_r(&(cdr->start.tv_sec), &tm);
00147 else
00148 ast_localtime(&(cdr->start.tv_sec), &tm, NULL);
00149 strftime(timestr, sizeof(timestr), DATE_FORMAT, &tm);
00150 if (!rc_avpair_add(rh, send, PW_AST_START_TIME, timestr, strlen(timestr), VENDOR_CODE))
00151 return -1;
00152
00153
00154 if (ast_test_flag(&global_flags, RADIUS_FLAG_USEGMTIME))
00155 gmtime_r(&(cdr->answer.tv_sec), &tm);
00156 else
00157 ast_localtime(&(cdr->answer.tv_sec), &tm, NULL);
00158 strftime(timestr, sizeof(timestr), DATE_FORMAT, &tm);
00159 if (!rc_avpair_add(rh, send, PW_AST_ANSWER_TIME, timestr, strlen(timestr), VENDOR_CODE))
00160 return -1;
00161
00162
00163 if (ast_test_flag(&global_flags, RADIUS_FLAG_USEGMTIME))
00164 gmtime_r(&(cdr->end.tv_sec), &tm);
00165 else
00166 ast_localtime(&(cdr->end.tv_sec), &tm, NULL);
00167 strftime(timestr, sizeof(timestr), DATE_FORMAT, &tm);
00168 if (!rc_avpair_add(rh, send, PW_AST_END_TIME, timestr, strlen(timestr), VENDOR_CODE))
00169 return -1;
00170
00171
00172 if (!rc_avpair_add(rh, send, PW_AST_DURATION, &cdr->duration, 0, VENDOR_CODE))
00173 return -1;
00174
00175
00176 if (!rc_avpair_add(rh, send, PW_AST_BILL_SEC, &cdr->billsec, 0, VENDOR_CODE))
00177 return -1;
00178
00179
00180 tmp = ast_cdr_disp2str(cdr->disposition);
00181 if (!rc_avpair_add(rh, send, PW_AST_DISPOSITION, tmp, strlen(tmp), VENDOR_CODE))
00182 return -1;
00183
00184
00185 tmp = ast_cdr_flags2str(cdr->amaflags);
00186 if (!rc_avpair_add(rh, send, PW_AST_AMA_FLAGS, tmp, strlen(tmp), VENDOR_CODE))
00187 return -1;
00188
00189 if (ast_test_flag(&global_flags, RADIUS_FLAG_LOGUNIQUEID)) {
00190
00191 if (!rc_avpair_add(rh, send, PW_AST_UNIQUE_ID, &cdr->uniqueid, strlen(cdr->uniqueid), VENDOR_CODE))
00192 return -1;
00193 }
00194
00195 if (ast_test_flag(&global_flags, RADIUS_FLAG_LOGUSERFIELD)) {
00196
00197 if (!rc_avpair_add(rh, send, PW_AST_USER_FIELD, &cdr->userfield, strlen(cdr->userfield), VENDOR_CODE))
00198 return -1;
00199 }
00200
00201
00202
00203
00204 if (!rc_avpair_add(rh, send, PW_USER_NAME, &cdr->channel, strlen(cdr->channel), 0))
00205 return -1;
00206
00207
00208 if (!rc_avpair_add(rh, send, PW_ACCT_SESSION_ID, &cdr->uniqueid, strlen(cdr->uniqueid), 0))
00209 return -1;
00210
00211 return 0;
00212 }
00213
00214 static int radius_log(struct ast_cdr *cdr)
00215 {
00216 int result = ERROR_RC;
00217 VALUE_PAIR *send = NULL;
00218
00219 if (build_radius_record(&send, cdr)) {
00220 if (option_debug)
00221 ast_log(LOG_DEBUG, "Unable to create RADIUS record. CDR not recorded!\n");
00222 goto return_cleanup;
00223 }
00224
00225 result = rc_acct(rh, 0, send);
00226 if (result != OK_RC) {
00227 ast_log(LOG_ERROR, "Failed to record Radius CDR record!\n");
00228 }
00229
00230 return_cleanup:
00231 if (send) {
00232 rc_avpair_free(send);
00233 }
00234
00235 return result;
00236 }
00237
00238 static int unload_module(void)
00239 {
00240 ast_cdr_unregister(name);
00241 return 0;
00242 }
00243
00244 static int load_module(void)
00245 {
00246 struct ast_config *cfg;
00247 int res;
00248 const char *tmp;
00249
00250 if ((cfg = ast_config_load(cdr_config))) {
00251 ast_set2_flag(&global_flags, ast_true(ast_variable_retrieve(cfg, "radius", "usegmtime")), RADIUS_FLAG_USEGMTIME);
00252 ast_set2_flag(&global_flags, ast_true(ast_variable_retrieve(cfg, "radius", "loguniqueid")), RADIUS_FLAG_LOGUNIQUEID);
00253 ast_set2_flag(&global_flags, ast_true(ast_variable_retrieve(cfg, "radius", "loguserfield")), RADIUS_FLAG_LOGUSERFIELD);
00254 if ((tmp = ast_variable_retrieve(cfg, "radius", "radiuscfg")))
00255 ast_copy_string(radiuscfg, tmp, sizeof(radiuscfg));
00256 ast_config_destroy(cfg);
00257 } else
00258 return AST_MODULE_LOAD_DECLINE;
00259
00260
00261 rc_openlog("asterisk");
00262
00263
00264 if (!(rh = rc_read_config(radiuscfg))) {
00265 ast_log(LOG_NOTICE, "Cannot load radiusclient-ng configuration file %s.\n", radiuscfg);
00266 return AST_MODULE_LOAD_DECLINE;
00267 }
00268
00269
00270 if (rc_read_dictionary(rh, rc_conf_str(rh, "dictionary"))) {
00271 ast_log(LOG_NOTICE, "Cannot load radiusclient-ng dictionary file.\n");
00272 return AST_MODULE_LOAD_DECLINE;
00273 }
00274
00275 res = ast_cdr_register(name, desc, radius_log);
00276 return AST_MODULE_LOAD_SUCCESS;
00277 }
00278
00279 AST_MODULE_INFO_STANDARD(ASTERISK_GPL_KEY, "RADIUS CDR Backend");