acc_radius.c

00001 /*
00002  * Accounting module
00003  *
00004  * $Id$
00005  *
00006  * Copyright (C) 2001-2003 FhG FOKUS
00007  * Copyright (C) 2005 iptelorg GmbH
00008  *
00009  * This file is part of ser, a free SIP server.
00010  *
00011  * ser is free software; you can redistribute it and/or modify
00012  * it under the terms of the GNU General Public License as published by
00013  * the Free Software Foundation; either version 2 of the License, or
00014  * (at your option) any later version
00015  *
00016  * For a license to use the ser software under conditions
00017  * other than those described here, or to purchase support for this
00018  * software, please contact iptel.org by e-mail at the following addresses:
00019  *    info@iptel.org
00020  *
00021  * ser is distributed in the hope that it will be useful,
00022  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00023  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00024  * GNU General Public License for more details.
00025  *
00026  * You should have received a copy of the GNU General Public License
00027  * along with this program; if not, write to the Free Software
00028  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
00029  *
00030  */
00031 
00032 #include <stdio.h>
00033 #include <string.h>
00034 #include <time.h>
00035 #include <radiusclient-ng.h>
00036 #include "../../rad_dict.h"
00037 
00038 #include "../../sr_module.h"
00039 #include "../../dprint.h"
00040 #include "../../mem/mem.h"
00041 #include "../../modules/tm/t_hooks.h"
00042 #include "../../modules/tm/tm_load.h"
00043 #include "../../modules/tm/h_table.h"
00044 #include "../../parser/msg_parser.h"
00045 #include "../../parser/parse_from.h"
00046 #include "../../parser/digest/digest.h"
00047 #include "../../usr_avp.h"
00048 #include "../../id.h"
00049 #include "../../modules/tm/tm_load.h"
00050 
00051 #include "../../parser/parse_rr.h"
00052 #include "../../trim.h"
00053 #include "../acc_syslog/attrs.h"
00054 
00055 /*
00056  * FIXME:
00057  * - Quote attribute values properly
00058  * - Explicitly called accounting function will generate Acct-Status-Type
00059  *   set to failed (rad_status does not work properly in this case), it
00060  *   should generate Interim-Update
00061  * - INVITEs with to tag should generate Interim-Update
00062  * - Configurable option which allows to switch From/To based on the
00063  *   value of ftag route parameter
00064  */
00065 
00066 /*
00067  * a: attr
00068  * c: sip_callid
00069  * d: to_tag
00070  * f: sip_from
00071  * g: flags
00072  * i: inbound_ruri
00073  * m: sip_method
00074  * n: sip_cseq
00075  * o: outbound_ruri
00076  * p: source_ip
00077  * r: from_tag
00078  * s: server_id
00079  * t: sip_to
00080  * u: digest_username
00081  * x: request_timestamp
00082  * D: to_did
00083  * F: from_uri
00084  * I: from_uid
00085  * M: from_did
00086  * R: digest_realm
00087  * P: source_port
00088  * S: sip_status
00089  * T: to_uri
00090  * U: to_uid
00091  * X: response_timestamp
00092  */
00093 
00094 
00095 #define ALL_LOG_FMT "acdfgimnoprstuxDFIMPRSTUX"
00096 #define ALL_LOG_FMT_LEN (sizeof(ALL_LOG_FMT) - 1)
00097 
00098 MODULE_VERSION
00099 
00100 struct tm_binds tmb;
00101 
00102 static int mod_init( void );
00103 static int fix_log_flag( modparam_t type, void* val);
00104 static int fix_log_missed_flag( modparam_t type, void* val);
00105 
00106 static int early_media = 0;         /* Enable/disable early media (183) accounting */
00107 static int failed_transactions = 0; /* Enable/disable accounting of failed (>= 300) transactions */
00108 static int report_cancels = 0;      /* Enable/disable CANCEL reporting */
00109 static int report_ack = 0;          /* Enable/disable end-to-end ACK reports */
00110 static int log_flag = 0;            /* Flag that marks transactions to be accounted */
00111 static int log_missed_flag = 0;     /* Transaction having this flag set will be accounted in missed calls when fails */
00112 static char* log_fmt = ALL_LOG_FMT; /* Formating string that controls what information will be collected and accounted */
00113 
00114 /* Attribute-value pairs */
00115 static char* attrs_param = "";
00116 avp_ident_t* avps;
00117 int avps_n;
00118 
00119 static char *radius_config = "/usr/local/etc/radiusclient-ng/radiusclient.conf";
00120 static int service_type = -1;
00121 static int swap_dir = 0;
00122 
00123 static void *rh;
00124 static struct attr attrs[A_MAX];
00125 static struct val vals[V_MAX];
00126 
00127 static int acc_rad_request0(struct sip_msg *rq, char *p1, char *p2);
00128 static int acc_rad_missed0(struct sip_msg *rq, char *p1, char *p2);
00129 static int acc_rad_request1(struct sip_msg *rq, char *p1, char *p2);
00130 static int acc_rad_missed1(struct sip_msg *rq, char *p1, char *p2);
00131 
00132 static cmd_export_t cmds[] = {
00133         {"acc_rad_log",    acc_rad_request0, 0, 0,               REQUEST_ROUTE | FAILURE_ROUTE},
00134         {"acc_rad_missed", acc_rad_missed0,  0, 0,               REQUEST_ROUTE | FAILURE_ROUTE},
00135         {"acc_rad_log",    acc_rad_request1, 1, fixup_var_int_1, REQUEST_ROUTE | FAILURE_ROUTE},
00136         {"acc_rad_missed", acc_rad_missed1,  1, fixup_var_int_1, REQUEST_ROUTE | FAILURE_ROUTE},
00137         {0, 0, 0, 0, 0}
00138 };
00139 
00140 
00141 static param_export_t params[] = {
00142         {"early_media",         PARAM_INT, &early_media         },
00143         {"failed_transactions", PARAM_INT, &failed_transactions },
00144         {"report_ack",          PARAM_INT, &report_ack          },
00145         {"report_cancels",      PARAM_INT, &report_cancels      },
00146         {"log_flag",            PARAM_INT, &log_flag            },
00147         {"log_flag",            PARAM_STRING|PARAM_USE_FUNC, fix_log_flag},
00148         {"log_missed_flag",     PARAM_INT, &log_missed_flag     },
00149         {"log_missed_flag",     PARAM_STRING|PARAM_USE_FUNC, fix_log_missed_flag},
00150         {"log_fmt",             PARAM_STRING, &log_fmt          },
00151         {"attrs",               PARAM_STRING, &attrs_param      },
00152         {"radius_config",       PARAM_STRING, &radius_config    },
00153         {"service_type",        PARAM_INT, &service_type        },
00154         {"swap_direction",      PARAM_INT, &swap_dir            },
00155         {0, 0, 0}
00156 };
00157 
00158 
00159 struct module_exports exports= {
00160         "acc_radius",
00161         cmds,     /* exported functions */
00162         0,        /* RPC methods */
00163         params,   /* exported params */
00164         mod_init, /* initialization module */
00165         0,        /* response function */
00166         0,        /* destroy function */
00167         0,        /* oncancel function */
00168         0         /* per-child init function */
00169 };
00170 
00171 
00172 
00173 /* fixes log_flag param (resolves possible named flags) */
00174 static int fix_log_flag( modparam_t type, void* val)
00175 {
00176         return fix_flag(type, val, "acc_radius", "log_flag", &log_flag);
00177 }
00178 
00179 
00180 
00181 /* fixes log_missed_flag param (resolves possible named flags) */
00182 static int fix_log_missed_flag( modparam_t type, void* val)
00183 {
00184         return fix_flag(type, val, "acc_radius", "log_missed_flag", &log_missed_flag);
00185 }
00186 
00187 
00188 
00189 static inline int skip_cancel(struct sip_msg *msg)
00190 {
00191         return (msg->REQ_METHOD == METHOD_CANCEL) && report_cancels == 0;
00192 }
00193 
00194 static int check_ftag(struct sip_msg* msg, str* uri)
00195 {
00196         param_hooks_t hooks;
00197         param_t* params;
00198         char* semi;
00199         struct to_body* from;
00200         str t;
00201 
00202         t = *uri;
00203         params = 0;
00204         semi = q_memchr(t.s, ';', t.len);
00205         if (!semi) {
00206                 DBG("No ftag parameter found\n");
00207                 return -1;
00208         }
00209 
00210         t.len -= semi - uri->s + 1;
00211         t.s = semi + 1;
00212         trim_leading(&t);
00213 
00214         if (parse_params(&t, CLASS_URI, &hooks, &params) < 0) {
00215                 ERR("Error while parsing parameters\n");
00216                 return -1;
00217         }
00218 
00219         if (!hooks.uri.ftag) {
00220                 DBG("No ftag parameter found\n");
00221                 goto err;
00222         }
00223 
00224         from = get_from(msg);
00225 
00226         if (!from || !from->tag_value.len || !from->tag_value.s) {
00227                 DBG("No from tag parameter found\n");
00228                 goto err;
00229         }
00230 
00231         if (from->tag_value.len == hooks.uri.ftag->body.len &&
00232             !strncmp(from->tag_value.s, hooks.uri.ftag->body.s, hooks.uri.ftag->body.len)) {
00233                 DBG("Route ftag and From tag are same\n");
00234                 free_params(params);
00235                 return 0;
00236         } else {
00237                 DBG("Route ftag and From tag are NOT same\n");
00238                 free_params(params);
00239                 return 1;
00240         }
00241 
00242  err:
00243         if (params) free_params(params);
00244         return -1;
00245 }
00246 
00247 static int get_direction(struct sip_msg* msg)
00248 {
00249         int ret;
00250         if (parse_orig_ruri(msg) < 0) {
00251                 return -1;
00252         }
00253 
00254         if (!msg->parsed_orig_ruri_ok) {
00255                 ERR("Error while parsing original Request-URI\n");
00256                 return -1;
00257         }
00258 
00259         ret = check_self(&msg->parsed_orig_ruri.host,
00260                          msg->parsed_orig_ruri.port_no ? msg->parsed_orig_ruri.port_no : SIP_PORT, 0);/* match all protos*/
00261         if (ret < 0) return -1;
00262         if (ret > 0) {
00263                      /* Route is in ruri */
00264                 return check_ftag(msg, &msg->first_line.u.request.uri);
00265         } else {
00266                 if (msg->route) {
00267                         if (parse_rr(msg->route) < 0) {
00268                                 ERR("Error while parsing Route HF\n");
00269                                 return -1;
00270                         }
00271                         ret = check_ftag(msg, &((rr_t*)msg->route->parsed)->nameaddr.uri);
00272                         if (msg->route->parsed) free_rr((rr_t**)(void*)&msg->route->parsed);
00273                         return ret;
00274                 } else {
00275                         DBG("No Route headers found\n");
00276                         return -1;
00277                 }
00278         }
00279 }
00280 
00281 
00282 int verify_fmt(char *fmt) {
00283 
00284         if (!fmt) {
00285                 LOG(L_ERR, "ERROR:acc:verify_fmt: formatting string zero\n");
00286                 return -1;
00287         }
00288 
00289         if (!(*fmt)) {
00290                 LOG(L_ERR, "ERROR:acc:verify_fmt: formatting string empty\n");
00291                 return -1;
00292         }
00293 
00294         if (strlen(fmt) > ALL_LOG_FMT_LEN) {
00295                 LOG(L_ERR, "ERROR:acc:verify_fmt: formatting string too long\n");
00296                 return -1;
00297         }
00298 
00299         while(*fmt) {
00300                 if (!strchr(ALL_LOG_FMT, *fmt)) {
00301                         LOG(L_ERR, "ERROR:acc:verify_fmt: char in log_fmt invalid: %c\n", *fmt);
00302                         return -1;
00303                 }
00304                 fmt++;
00305         }
00306         return 1;
00307 }
00308 
00309 
00310 /*
00311  * Return true if accounting is enabled and the
00312  * transaction is marked for accounting
00313  */
00314 static inline int is_acc_on(struct sip_msg *rq)
00315 {
00316         return log_flag && isflagset(rq, log_flag) == 1;
00317 }
00318 
00319 
00320 /*
00321  * Return true if missed_call accounting is enabled
00322  * and the transaction has the flag set
00323  */
00324 static inline int is_mc_on(struct sip_msg *rq)
00325 {
00326         return log_missed_flag && isflagset(rq, log_missed_flag) == 1;
00327 }
00328 
00329 
00330 static inline void preparse_req(struct sip_msg *rq)
00331 {
00332              /* try to parse from for From-tag for accounted transactions;
00333               * don't be worried about parsing outcome -- if it failed,
00334               * we will report N/A. There is no need to parse digest credentials
00335               * here even if we account them, because the authentication function
00336               * will do it before us and if not then we will account n/a.
00337               */
00338         parse_headers(rq, HDR_CALLID_F | HDR_FROM_F | HDR_TO_F | HDR_CSEQ_F | HDR_ROUTE_F, 0 );
00339         parse_from_header(rq);
00340 }
00341 
00342 
00343 /* is this reply of interest for accounting ? */
00344 static inline int should_acc_reply(struct cell* t, int code)
00345 {
00346         struct sip_msg *r;
00347 
00348         r = t->uas.request;
00349 
00350              /* validation */
00351         if (r == 0) {
00352                 LOG(L_ERR, "ERROR:acc:should_acc_reply: 0 request\n");
00353                 return 0;
00354         }
00355 
00356              /* negative transactions reported otherwise only if explicitly
00357               * demanded */
00358         if (!failed_transactions && code >= 300) return 0;
00359         if (!is_acc_on(r)) return 0;
00360         if (skip_cancel(r)) return 0;
00361         if (code < 200 && ! (early_media && code == 183)) return 0;
00362         return 1; /* seed is through, we will account this reply */
00363 }
00364 
00365 
00366 /* Extract username attribute from authorized credentials */
00367 static inline str* cred_user(struct sip_msg* rq)
00368 {
00369         struct hdr_field* h;
00370         auth_body_t* cred;
00371 
00372         get_authorized_cred(rq->proxy_auth, &h);
00373         if (!h) get_authorized_cred(rq->authorization, &h);
00374         if (!h) return 0;
00375         cred = (auth_body_t*)(h->parsed);
00376         if (!cred || !cred->digest.username.user.len)
00377                 return 0;
00378         return &cred->digest.username.user;
00379 }
00380 
00381 
00382 /* Extract realm attribute from authorized credentials */
00383 static inline str* cred_realm(struct sip_msg* rq)
00384 {
00385         str* realm;
00386         struct hdr_field* h;
00387         auth_body_t* cred;
00388 
00389         get_authorized_cred(rq->proxy_auth, &h);
00390         if (!h) get_authorized_cred(rq->authorization, &h);
00391         if (!h) return 0;
00392         cred = (auth_body_t*)(h->parsed);
00393         if (!cred) return 0;
00394         realm = GET_REALM(&cred->digest);
00395         if (!realm->len || !realm->s) {
00396                 return 0;
00397         }
00398         return realm;
00399 }
00400 
00401 
00402 /* Return To header field from the request in case of faked reply or
00403  * missing To header field in the reply
00404  */
00405 static inline struct hdr_field* valid_to(struct cell* t, struct sip_msg* reply)
00406 {
00407         if (reply == FAKED_REPLY || !reply || !reply->to) {
00408                 return t->uas.request->to;
00409         } else {
00410                 return reply->to;
00411         }
00412 }
00413 
00414 
00415 /* create an array of str's for accounting using a formatting string;
00416  * this is the heart of the accounting module -- it prints whatever
00417  * requested in a way, that can be used for syslog, radius,
00418  * sql, whatsoever
00419  * tm sip_msg_clones does not clone (shmmem-zed) parsed fields, other then Via1,2. Such fields clone now or use from rq_rp
00420  */
00421 static int fmt2rad(char *fmt,
00422                    struct sip_msg *rq,
00423                    str* ouri,
00424                    struct hdr_field *to,
00425                    unsigned int code,
00426                    VALUE_PAIR** send,
00427                    time_t req_time)       /* Timestamp of the request */
00428 {
00429         static unsigned int cseq_num, src_port, src_ip;
00430         static time_t rq_time, rs_time;
00431         int cnt;
00432         struct to_body* from, *pto;
00433         str val, *cr, *at;
00434         struct cseq_body *cseq;
00435         struct attr* attr;
00436         int dir;
00437 
00438         cnt = 0;
00439         dir = -2;
00440 
00441              /* we don't care about parsing here; either the function
00442               * was called from script, in which case the wrapping function
00443               * is supposed to parse, or from reply processing in which case
00444               * TM should have preparsed from REQUEST_IN callback.
00445               */
00446         while(*fmt) {
00447                 if (cnt == ALL_LOG_FMT_LEN) {
00448                         LOG(L_ERR, "ERROR:acc:fmt2rad: Formatting string is too long\n");
00449                         return 0;
00450                 }
00451 
00452                 attr = 0;
00453                 switch(*fmt) {
00454                 case 'a': /* attr */
00455                         at = print_attrs(avps, avps_n, 0);
00456                         if (at) {
00457                                 attr = &attrs[A_SER_ATTR];
00458                                 val = *at;
00459                         }
00460                         break;
00461 
00462                 case 'c': /* sip_callid */
00463                         if (rq->callid && rq->callid->body.len) {
00464                                 attr = &attrs[A_ACCT_SESSION_ID];
00465                                 val = rq->callid->body;
00466                         }
00467                         break;
00468 
00469                 case 'd': /* to_tag */
00470                         if (swap_dir && dir == -2) dir = get_direction(rq);
00471                         if (dir <= 0) {
00472                                 if (to && (pto = (struct to_body*)(to->parsed)) && pto->tag_value.len) {
00473                                         attr = &attrs[A_SIP_TO_TAG];
00474                                         val = pto->tag_value;
00475                                 }
00476                         } else {
00477                                 if (rq->from && (from = get_from(rq)) && from->tag_value.len) {
00478                                         attr = &attrs[A_SIP_TO_TAG];
00479                                         val = from->tag_value;
00480                                 }
00481                         }
00482                         break;
00483 
00484                 case 'f': /* sip_from */
00485                         if (rq->from && rq->from->body.len) {
00486                                 attr = &attrs[A_SER_FROM];
00487                                 val = rq->from->body;
00488                         }
00489                         break;
00490 
00491                 case 'g': /* flags */
00492                         attr = &attrs[A_SER_FLAGS];
00493                         val.s = (char*)&rq->flags;
00494                         val.len = sizeof(unsigned int);
00495                         break;
00496 
00497                 case 'i': /* inbound_ruri */
00498                         attr = &attrs[A_SER_ORIGINAL_REQUEST_ID];
00499                         val = rq->first_line.u.request.uri;
00500                         break;
00501 
00502                 case 'm': /* sip_method */
00503                         attr = &attrs[A_SIP_METHOD];
00504                         val = rq->first_line.u.request.method;
00505                         break;
00506 
00507                 case 'n': /* sip_cseq */
00508                         if (rq->cseq && (cseq = get_cseq(rq)) && cseq->number.len) {
00509                                 attr = &attrs[A_SIP_CSEQ];
00510                                 str2int(&cseq->number, &cseq_num);
00511                                 val.s = (char*)&cseq_num;
00512                                 val.len = sizeof(unsigned int);
00513                         }
00514                         break;
00515 
00516                 case 'o': /* outbound_ruri */
00517                         attr = &attrs[A_SIP_TRANSLATED_REQUEST_ID];
00518                         val = *ouri;
00519                         break;
00520 
00521                 case 'p': /* Source IP address */
00522                         attr = &attrs[A_SIP_SOURCE_IP_ADDRESS];
00523                         src_ip = ntohl(rq->rcv.src_ip.u.addr32[0]);
00524                         val.s = (char*)&src_ip;
00525                         val.len = sizeof(src_ip);
00526                         break;
00527 
00528                 case 'r': /* from_tag */
00529                         if (swap_dir && dir == -2) dir = get_direction(rq);
00530                         if (dir <= 0) {
00531                                 if (rq->from && (from = get_from(rq)) && from->tag_value.len) {
00532                                         attr = &attrs[A_SIP_FROM_TAG];
00533                                         val = from->tag_value;
00534                                 }
00535                         } else {
00536                                 if (to && (pto = (struct to_body*)(to->parsed)) && pto->tag_value.len) {
00537                                         attr = &attrs[A_SIP_FROM_TAG];
00538                                         val = pto->tag_value;
00539                                 }
00540                         }
00541                         break;
00542 
00543                 case 's': /* server_id */
00544                         attr = &attrs[A_SER_SERVER_ID];
00545                         val.s = (char*)&server_id;
00546                         val.len = sizeof(int);
00547                         break;
00548 
00549                 case 't': /* sip_to */
00550                         if (to && to->body.len) {
00551                                 attr = &attrs[A_SER_TO];
00552                                 val = to->body;
00553                         }
00554                         break;
00555 
00556                 case 'u': /* digest_username */
00557                         cr = cred_user(rq);
00558                         if (cr) {
00559                                 attr = &attrs[A_SER_DIGEST_USERNAME];
00560                                 val = *cr;
00561                         }
00562                         break;
00563 
00564                 case 'x': /* request_timestamp */
00565                         attr = &attrs[A_SER_REQUEST_TIMESTAMP];
00566                         rq_time = req_time;
00567                         val.s = (char*)&rq_time;
00568                         val.len = sizeof(time_t);
00569                         break;
00570 
00571                 case 'D': /* to_did */
00572                         break;
00573 
00574                 case 'F': /* from_uri */
00575                         if (swap_dir && dir == -2) dir = get_direction(rq);
00576                         if (dir <= 0) {
00577                                 if (rq->from && (from = get_from(rq)) && from->uri.len) {
00578                                         attr = &attrs[A_CALLING_STATION_ID];
00579                                         val = from->uri;
00580                                 }
00581                         } else {
00582                                 if (rq->to && (pto = get_to(rq)) && pto->uri.len) {
00583                                         attr = &attrs[A_CALLING_STATION_ID];
00584                                         val = pto->uri;
00585                                 }
00586                         }
00587                         break;
00588 
00589                 case 'I': /* from_uid */
00590                         if (get_from_uid(&val, rq) < 0) {
00591                                 attr = &attrs[A_SER_FROM_UID];
00592                         }
00593                         break;
00594 
00595                 case 'M': /* from_did */
00596                         break;
00597 
00598                 case 'P': /* Source port */
00599                         attr = &attrs[A_SIP_SOURCE_PORT];
00600                         src_port = rq->rcv.src_port;
00601                         val.s = (char*)&src_port;
00602                         val.len = sizeof(unsigned int);
00603                         break;
00604 
00605                 case 'R': /* digest_realm */
00606                         cr = cred_realm(rq);
00607                         if (cr) {
00608                                 attr = &attrs[A_SER_DIGEST_REALM];
00609                                 val = *cr;
00610                         }
00611                         break;
00612 
00613                 case 'S': /* sip_status */
00614                         attr = &attrs[A_SIP_RESPONSE_CODE];
00615                         val.s = (char*)&code;
00616                         val.len = sizeof(unsigned int);
00617                         break;
00618 
00619                 case 'T': /* to_uri */
00620                         if (swap_dir && dir == -2) dir = get_direction(rq);
00621                         if (dir <= 0) {
00622                                 if (rq->to && (pto = get_to(rq)) && pto->uri.len) {
00623                                         attr = &attrs[A_CALLED_STATION_ID];
00624                                         val = pto->uri;
00625                                 }
00626                         } else {
00627                                 if (rq->from && (from = get_from(rq)) && from->uri.len) {
00628                                         attr = &attrs[A_CALLED_STATION_ID];
00629                                         val = from->uri;
00630                                 }
00631                         }
00632                         break;
00633 
00634                 case 'U': /* to_uid */
00635                         if (get_from_uid(&val, rq) < 0) {
00636                                 attr = &attrs[A_SER_TO_UID];
00637                         }
00638                         break;
00639 
00640                 case 'X': /* response_timestamp */
00641                         attr = &attrs[A_SER_RESPONSE_TIMESTAMP];
00642                         rs_time = time(0);
00643                         val.s = (char*)&rs_time;
00644                         val.len = sizeof(time_t);
00645                         break;
00646 
00647                 default:
00648                         LOG(L_CRIT, "BUG:acc:fmt2rad: unknown char: %c\n", *fmt);
00649                         return -1;
00650                 } /* switch (*fmt) */
00651 
00652                 if (attr) {
00653                         if (!rc_avpair_add(rh, send, ATTRID(attr->v), val.s, val.len, VENDOR(attr->v))) {
00654                                 LOG(L_ERR, "ERROR:acc:fmt2rad: Failed to add attribute %s\n",
00655                                     attr->n);
00656                                 return -1;
00657                         }
00658                 }
00659 
00660                 fmt++;
00661                 cnt++;
00662         } /* while (*fmt) */
00663 
00664         return 0;
00665 }
00666 
00667 
00668 /*
00669  * Return the value of Acc-Status-Type attribute based on SIP method
00670  * and response code
00671  */
00672 static inline UINT4 rad_status(struct sip_msg *rq, unsigned int code)
00673 {
00674              /* Faked reply */
00675         if (code == 0) {
00676                 return vals[V_FAILED].v;
00677         }
00678 
00679              /* Successful call start */
00680         if ((rq->REQ_METHOD == METHOD_INVITE || rq->REQ_METHOD == METHOD_ACK)
00681             && code >= 200 && code < 300) {
00682                 return vals[V_START].v;
00683         }
00684 
00685              /* Successful call termination */
00686         if ((rq->REQ_METHOD == METHOD_BYE || rq->REQ_METHOD == METHOD_CANCEL)) {
00687                 return vals[V_STOP].v;
00688         }
00689 
00690              /* Successful transaction */
00691         if (code >= 200 && code < 300) {
00692                 return vals[V_INTERIM_UPDATE].v;
00693         }
00694 
00695              /* Otherwise it failed */
00696         return vals[V_FAILED].v;
00697 }
00698 
00699 
00700 /*
00701  * Add User-Name attribute
00702  */
00703 static inline int add_user_name(struct sip_msg* rq, void* rh, VALUE_PAIR** send)
00704 {
00705         struct sip_uri puri;
00706         str* user, *realm;
00707         str user_name;
00708         struct to_body* from;
00709 
00710         user = cred_user(rq);  /* try to take it from credentials */
00711         realm = cred_realm(rq);
00712 
00713         if (!user || !realm) {
00714                 if (rq->from && (from = get_from(rq)) && from->uri.len) {
00715                         if (parse_uri(from->uri.s, from->uri.len, &puri) < 0 ) {
00716                                 LOG(L_ERR, "ERROR:acc:add_user_name: Bad From URI\n");
00717                                 return -1;
00718                         }
00719 
00720                         user = &puri.user;
00721                         realm = &puri.host;
00722                 } else {
00723                         DBG("acc:add_user_name: Neither digest nor From found, mandatory attribute User-Name not added\n");
00724                         return -1;
00725                 }
00726         }
00727 
00728         user_name.len = user->len + 1 + realm->len;
00729         user_name.s = pkg_malloc(user_name.len);
00730         if (!user_name.s) {
00731                 LOG(L_ERR, "ERROR:acc:add_user_name: no memory\n");
00732                 return -1;
00733         }
00734         memcpy(user_name.s, user->s, user->len);
00735         user_name.s[user->len] = '@';
00736         memcpy(user_name.s + user->len + 1, realm->s, realm->len);
00737 
00738         if (!rc_avpair_add(rh, send, ATTRID(attrs[A_USER_NAME].v),
00739                            user_name.s, user_name.len, VENDOR(attrs[A_USER_NAME].v))) {
00740                 LOG(L_ERR, "ERROR:acc:add_user_name: Failed to add User-Name attribute\n");
00741                 pkg_free(user_name.s);
00742                 return -1;
00743         }
00744         pkg_free(user_name.s);
00745         
00746         return 0;
00747 }
00748 
00749 
00750 /* skip leading text and begin with first item's
00751  * separator ", " which will be overwritten by the
00752  * leading text later
00753  *
00754  */
00755 static int log_request(struct sip_msg* rq, str* ouri, struct hdr_field* to, unsigned int code, time_t req_time)
00756 {
00757         VALUE_PAIR *send;
00758         UINT4 av_type;
00759 
00760         send = NULL;
00761         if (skip_cancel(rq)) return 1;
00762 
00763         if (fmt2rad(log_fmt, rq, ouri, to, code, &send, req_time) < 0) goto error;
00764 
00765              /* Add Acct-Status-Type attribute */
00766         av_type = rad_status(rq, code);
00767         if (!rc_avpair_add(rh, &send, ATTRID(attrs[A_ACCT_STATUS_TYPE].v), &av_type, -1, 
00768                            VENDOR(attrs[A_ACCT_STATUS_TYPE].v))) {
00769                 ERR("Add Status-Type\n");
00770                 goto error;
00771         }
00772 
00773              /* Add Service-Type attribute */
00774         av_type = (service_type != -1) ? service_type : vals[V_SIP_SESSION].v;
00775         if (!rc_avpair_add(rh, &send, ATTRID(attrs[A_SERVICE_TYPE].v), &av_type, -1, 
00776                            VENDOR(attrs[A_SERVICE_TYPE].v))) {
00777                 ERR("add STATUS_TYPE\n");
00778                 goto error;
00779         }
00780 
00781              /* Add User-Name attribute */
00782         if (add_user_name(rq, rh, &send) < 0) goto error;
00783 
00784              /* Send the request out */
00785         if (rc_acct(rh, SIP_PORT, send) != OK_RC) {
00786                 ERR("RADIUS accounting request failed\n");
00787                 goto error;
00788         }
00789 
00790         rc_avpair_free(send);
00791         return 1;
00792 
00793 error:
00794         rc_avpair_free(send);
00795         return -1;
00796 }
00797 
00798 
00799 static void log_reply(struct cell* t , struct sip_msg* reply, unsigned int code, time_t req_time)
00800 {
00801         str* ouri;
00802 
00803         if (t->relayed_reply_branch >= 0) {
00804             ouri = &t->uac[t->relayed_reply_branch].uri;
00805         } else {
00806             ouri = GET_NEXT_HOP(t->uas.request);
00807         }
00808 
00809         log_request(t->uas.request, ouri, valid_to(t, reply), code, req_time);
00810 }
00811 
00812 
00813 static void log_ack(struct cell* t , struct sip_msg *ack, time_t req_time)
00814 {
00815         struct sip_msg *rq;
00816         struct hdr_field *to;
00817 
00818         rq = t->uas.request;
00819         if (ack->to) to = ack->to;
00820         else to = rq->to;
00821         log_request(ack, GET_RURI(ack), to, t->uas.status, req_time);
00822 }
00823 
00824 
00825 static void log_missed(struct cell* t, struct sip_msg* reply, unsigned int code, time_t req_time)
00826 {
00827         str* ouri;
00828 
00829         if (t->relayed_reply_branch >= 0) {
00830             ouri = &t->uac[t->relayed_reply_branch].uri;
00831         } else {
00832             ouri = GET_NEXT_HOP(t->uas.request);
00833         }
00834 
00835         log_request(t->uas.request, ouri , valid_to(t, reply), code, req_time);
00836 }
00837 
00838 
00839 /* these wrappers parse all what may be needed; they don't care about
00840  * the result -- accounting functions just display "unavailable" if there
00841  * is nothing meaningful
00842  */
00843 static int acc_rad_request0(struct sip_msg *rq, char* p1, char* p2)
00844 {
00845         preparse_req(rq);
00846         return log_request(rq, GET_RURI(rq), rq->to, 0, time(0));
00847 }
00848 
00849 
00850 /* these wrappers parse all what may be needed; they don't care about
00851  * the result -- accounting functions just display "unavailable" if there
00852  * is nothing meaningful
00853  */
00854 static int acc_rad_missed0(struct sip_msg *rq, char* p1, char* p2)
00855 {
00856         preparse_req(rq);
00857         return log_request(rq, GET_RURI(rq), rq->to, 0, time(0));
00858 }
00859 
00860 /* these wrappers parse all what may be needed; they don't care about
00861  * the result -- accounting functions just display "unavailable" if there
00862  * is nothing meaningful
00863  */
00864 static int acc_rad_request1(struct sip_msg *rq, char* p1, char* p2)
00865 {
00866     int code;
00867     preparse_req(rq);
00868     if (get_int_fparam(&code, rq, (fparam_t*)p1) < 0) {
00869         code = 0;
00870     }
00871     return log_request(rq, GET_RURI(rq), rq->to, code, time(0));
00872 }
00873 
00874 
00875 /* these wrappers parse all what may be needed; they don't care about
00876  * the result -- accounting functions just display "unavailable" if there
00877  * is nothing meaningful
00878  */
00879 static int acc_rad_missed1(struct sip_msg *rq, char* p1, char* p2)
00880 {
00881     int code;
00882     preparse_req(rq);
00883     if (get_int_fparam(&code, rq, (fparam_t*)p1) < 0) {
00884         code = 0;
00885     }
00886     return log_request(rq, GET_RURI(rq), rq->to, code, time(0));
00887 }
00888 
00889 
00890 static void ack_handler(struct cell* t, int type, struct tmcb_params* ps)
00891 {
00892         if (is_acc_on(t->uas.request)) {
00893                 preparse_req(ps->req);
00894                 log_ack(t, ps->req, (time_t)*(ps->param));
00895         }
00896 }
00897 
00898 
00899 /* initiate a report if we previously enabled MC accounting for this t */
00900 static void failure_handler(struct cell *t, int type, struct tmcb_params* ps)
00901 {
00902         /* validation */
00903         if (t->uas.request == 0) {
00904                 DBG("DBG:acc:failure_handler: No uas.request, skipping local transaction\n");
00905                 return;
00906         }
00907 
00908         if (is_invite(t) && ps->code >= 300) {
00909                 if (is_mc_on(t->uas.request)) {
00910                         log_missed(t, ps->rpl, ps->code, (time_t)*(ps->param));
00911                         resetflag(t->uas.request, log_missed_flag);
00912                 }
00913         }
00914 }
00915 
00916 
00917 /* initiate a report if we previously enabled accounting for this t */
00918 static void replyout_handler(struct cell* t, int type, struct tmcb_params* ps)
00919 {
00920         if (t->uas.request == 0) {
00921                 DBG("DBG:acc:replyout_handler: No uas.request, local transaction, skipping\n");
00922                 return;
00923         }
00924 
00925              /* acc_onreply is bound to TMCB_REPLY which may be called
00926               * from _reply, like when FR hits; we should not miss this
00927               * event for missed calls either
00928               */
00929         failure_handler(t, type, ps);
00930         if (!should_acc_reply(t, ps->code)) return;
00931         if (is_acc_on(t->uas.request)) log_reply(t, ps->rpl, ps->code, (time_t)*(ps->param));
00932 }
00933 
00934 
00935 /* parse incoming replies before cloning */
00936 static void replyin_handler(struct cell *t, int type, struct tmcb_params* ps)
00937 {
00938              /* validation */
00939         if (t->uas.request == 0) {
00940                 LOG(L_ERR, "ERROR:acc:replyin_handler:replyin_handler: 0 request\n");
00941                 return;
00942         }
00943 
00944              /* don't parse replies in which we are not interested */
00945              /* missed calls enabled ? */
00946         if (((is_invite(t) && ps->code >= 300 && is_mc_on(t->uas.request))
00947              || should_acc_reply(t, ps->code))
00948             && (ps->rpl && ps->rpl != FAKED_REPLY)) {
00949                 parse_headers(ps->rpl, HDR_TO_F, 0);
00950         }
00951 }
00952 
00953 
00954 /* prepare message and transaction context for later accounting */
00955 void on_req(struct cell* t, int type, struct tmcb_params *ps)
00956 {
00957         time_t req_time;
00958              /* Pass the timestamp of the request as a parameter to callbacks */
00959         req_time = time(0);
00960 
00961         if (is_acc_on(ps->req) || is_mc_on(ps->req)) {
00962                 if (tmb.register_tmcb(0, t, TMCB_RESPONSE_OUT, replyout_handler,
00963                                                                 (void*)req_time, 0) <= 0) {
00964                         LOG(L_ERR, "ERROR:acc:on_req: Error while registering TMCB_RESPONSE_OUT callback\n");
00965                         return;
00966                 }
00967 
00968                 if (report_ack) {
00969                         if (tmb.register_tmcb(0, t, TMCB_E2EACK_IN, ack_handler,
00970                                                                         (void*)req_time, 0) <= 0) {
00971                                 LOG(L_ERR, "ERROR:acc:on_req: Error while registering TMCB_E2EACK_IN callback\n");
00972                                 return;
00973                         }
00974                 }
00975 
00976                 if (tmb.register_tmcb(0, t, TMCB_ON_FAILURE_RO, failure_handler,
00977                                                                 (void*)req_time, 0) <= 0) {
00978                         LOG(L_ERR, "ERROR:acc:on_req: Error while registering TMCB_ON_FAILURE_RO callback\n");
00979                         return;
00980                 }
00981 
00982                 if (tmb.register_tmcb(0, t, TMCB_RESPONSE_IN, replyin_handler,
00983                                                                 (void*)req_time, 0) <= 0) {
00984                         LOG(L_ERR, "ERROR:acc:on_req: Error while registering TMCB_RESPONSE_IN callback\n");
00985                         return;
00986                 }
00987 
00988                      /* do some parsing in advance */
00989                 preparse_req(ps->req);
00990                      /* also, if that is INVITE, disallow silent t-drop */
00991                 if (ps->req->REQ_METHOD == METHOD_INVITE) {
00992                         DBG("DEBUG: noisy_timer set for accounting\n");
00993                         t->flags |= T_NOISY_CTIMER_FLAG;
00994                 }
00995         }
00996 }
00997 
00998 
00999 static int mod_init(void)
01000 {
01001         DICT_VENDOR *vend;
01002         load_tm_f load_tm;
01003 
01004              /* import the TM auto-loading function */
01005         if ( !(load_tm=(load_tm_f)find_export("load_tm", NO_SCRIPT, 0))) {
01006                 LOG(L_ERR, "ERROR:acc:mod_init: can't import load_tm\n");
01007                 return -1;
01008         }
01009              /* let the auto-loading function load all TM stuff */
01010         if (load_tm( &tmb )==-1) return -1;
01011         if (verify_fmt(log_fmt)==-1) return -1;
01012 
01013              /* register callbacks*/
01014              /* listen for all incoming requests  */
01015         if (tmb.register_tmcb( 0, 0, TMCB_REQUEST_IN, on_req, 0, 0) <= 0) {
01016                 LOG(L_ERR,"ERROR:acc:mod_init: cannot register TMCB_REQUEST_IN "
01017                     "callback\n");
01018                 return -1;
01019         }
01020 
01021         memset(attrs, 0, sizeof(attrs));
01022         memset(vals, 0, sizeof(vals));
01023 
01024         attrs[A_USER_NAME].n                 = "User-Name";
01025         attrs[A_SERVICE_TYPE].n              = "Service-Type";
01026         attrs[A_CALLED_STATION_ID].n         = "Called-Station-Id";
01027         attrs[A_CALLING_STATION_ID].n        = "Calling-Station-Id";
01028         attrs[A_ACCT_STATUS_TYPE].n          = "Acct-Status-Type";
01029         attrs[A_ACCT_SESSION_ID].n           = "Acct-Session-Id";
01030 
01031         attrs[A_SIP_METHOD].n                = "Sip-Method";
01032         attrs[A_SIP_RESPONSE_CODE].n         = "Sip-Response-Code";
01033         attrs[A_SIP_CSEQ].n                  = "Sip-CSeq";
01034         attrs[A_SIP_TO_TAG].n                = "Sip-To-Tag";
01035         attrs[A_SIP_FROM_TAG].n              = "Sip-From-Tag";
01036         attrs[A_SIP_TRANSLATED_REQUEST_ID].n = "Sip-Translated-Request-Id";
01037         attrs[A_SIP_SOURCE_IP_ADDRESS].n     = "Sip-Source-IP-Address";
01038         attrs[A_SIP_SOURCE_PORT].n           = "Sip-Source-Port";
01039 
01040         attrs[A_SER_ATTR].n                  = "SER-Attr";
01041         attrs[A_SER_FROM].n                  = "SER-From";
01042         attrs[A_SER_FLAGS].n                 = "SER-Flags";
01043         attrs[A_SER_ORIGINAL_REQUEST_ID].n   = "SER-Original-Request-Id";
01044         attrs[A_SER_TO].n                    = "SER-To";
01045         attrs[A_SER_DIGEST_USERNAME].n       = "SER-Digest-Username";
01046         attrs[A_SER_DIGEST_REALM].n          = "SER-Digest-Realm";
01047         attrs[A_SER_REQUEST_TIMESTAMP].n     = "SER-Request-Timestamp";
01048         attrs[A_SER_TO_DID].n                = "SER-To-DID";
01049         attrs[A_SER_FROM_UID].n              = "SER-From-UID";
01050         attrs[A_SER_FROM_DID].n              = "SER-From-DID";
01051         attrs[A_SER_TO_UID].n                = "SER-To-UID";
01052         attrs[A_SER_RESPONSE_TIMESTAMP].n    = "SER-Response-Timestamp";
01053         attrs[A_SER_SERVER_ID].n             = "SER-Server-ID";
01054 
01055         vals[V_START].n                      = "Start";
01056         vals[V_STOP].n                       = "Stop";
01057         vals[V_INTERIM_UPDATE].n             = "Interim-Update";
01058         vals[V_FAILED].n                     = "Failed";
01059         vals[V_SIP_SESSION].n                = "Sip-Session";
01060 
01061              /* open log */
01062         rc_openlog("ser");
01063              /* read config */
01064         if ((rh = rc_read_config(radius_config)) == NULL) {
01065                 LOG(L_ERR, "ERROR:acc:mod_init: Error opening radius config file: %s\n",
01066                     radius_config);
01067                 return -1;
01068         }
01069              /* read dictionary */
01070         if (rc_read_dictionary(rh, rc_conf_str(rh, "dictionary")) != 0) {
01071                 LOG(L_ERR, "ERROR:acc:mod_init: Error reading radius dictionary\n");
01072                 return -1;
01073         }
01074 
01075         vend = rc_dict_findvend(rh, "iptelorg");
01076         if (vend == NULL) {
01077                 ERR("RADIUS dictionary is missing required vendor 'iptelorg'\n");
01078                 return -1;
01079         }
01080 
01081         INIT_AV(rh, attrs, vals, "acc", -1, -1);
01082 
01083         if (service_type != -1) {
01084                 vals[V_SIP_SESSION].v = service_type;
01085         }
01086 
01087         if (parse_attrs(&avps, &avps_n, attrs_param) < 0) {
01088                 ERR("Error while parsing 'attrs' module parameter\n");
01089                 return -1;
01090         }
01091 
01092         return 0;
01093 }