Table of Contents
- acc-headers.tgz - new acc tarball (whole module)
- acc_headers.patch.gz - gzipped patch
- acc_headers.patch - patch to acc
- acc.html - acc readme in html format
To achive the functionality described in this document you have to apply the above patch to “acc” module from CVS head at November 1, 2004. You can also download the whole module from this site, link provided in “Downloads” section.
This is a basic example about how to account extra data along with the the standard accounted data. It shows how to get the data - mainly from SIP messages - how to configure the “acc” module to store it and where is stored.
The extra accounting facility allows dynamic configurable accounting of data from SIP messages - mainly SIP headers - and from AVP (Attribute Value Pair) - which can contain basically anything.
The example shows how to use the canonical URI for a better accounting - in a configuration with heavier RURI transformations (aliases, speed-dial, prefixes), accounting only input an output uri proves insufficient o correlate the CDRs with the actual user - so, saving the canonical URI (user@domain as subscribed) will not require to apply again the transformations on CDRs to find the actual user.
Along the canonical-URI, the example show how additional information - like source IP of the request and the User-Agent header - can be also included for accounting.
For extra accounting message headers, nothing special needs to be made. For extra accounting AVPs, we need to put the data we want into AVPs. For this the “avpops” module is used, and to make the script more clear we define the following AVP aliases (we recommend the usage of ID AVPs since are much faster than the NAME avps):
... # "c_uri" (canonical URI) alias to ID AVP 888 # "s_ip" (source IP) alias to ID AVP 999 modparam("avpops", "avp_aliases", "c_uri=i:888; s_ip=i:999" ) ...
To get the date into AVPs, the "avp_write" function has to be used:
... avp_write( "$src_ip", "$s_ip"); #store the src_ip avp_write( "$ruri", "$c_uri"); #store the ruri ...
The extra data to be accounting is specify via “xxx_extra” parameter of “acc” module. For each type of accounting - syslog, database, radius, diameter - another set of extra data can be set.
The example accounts the User-Agent header into syslog, labeled “ua”, and canonical uri and source IP into database, labeled “uuid” and “src_ip”:
... modparam("acc", "log_extra" ,"ua=hdr/User-Agent") modparam("acc", "db_extra" ,"uuid=avp/i:888; src_ip=avp/i:999") ...
In order to extra account in database, the structure of “acc” and “missed_calls” tables must be extended in order to wrap up the new values. All the extra values are logged as string values, so, in mysql, just do:
... ALTER TABLE acc ADD uuid varchar(128) NOT NULL default ""; ALTER TABLE acc ADD src_ip varchar(128) NOT NULL default ""; ALTER TABLE missed_calls ADD uuid varchar(128) NOT NULL default ""; ALTER TABLE missed_calls ADD src_ip varchar(128) NOT NULL default ""; ...
After these, the “acc” and “missed_calls” tables' structure should be like:
... +------------+---------------+------+-----+---------------------+-------+ | Field | Type | Null | Key | Default | Extra | +------------+---------------+------+-----+---------------------+-------+ | sip_from | varchar(128) | | | | | | sip_to | varchar(128) | | | | | | sip_status | varchar(128) | | | | | | sip_method | varchar(16) | | | | | | i_uri | varchar(128) | | | | | | o_uri | varchar(128) | | | | | | from_uri | varchar(128) | | | | | | to_uri | varchar(128) | | | | | | sip_callid | varchar(128) | | MUL | | | | username | varchar(64) | | MUL | | | | domain | varchar(128) | | | | | | fromtag | varchar(128) | | | | | | totag | varchar(128) | | | | | | time | datetime | | | 0000-00-00 00:00:00 | | | timestamp | timestamp(14) | YES | | NULL | | | uuid | varchar(128) | | | | | | src_ip | varchar(128) | | | | | +------------+---------------+------+-----+---------------------+-------+ ...
For accounting to syslog, no modifications are required.
The example shows a basic SER script with accounting support. All extra values must be fetched in the proper places, before the accounting process:
“src_ip” is loaded into AVP immediately as the request is considered valid
“canonical uri” is loaded into AVP after all the transformations where applied - after doing lookup("aliases"), but before the lookup("location").
The script does accounting for all requests at syslog and database, but reports the missed calls only to database.
... # **** global configuration parameters **** debug=9 fork=no log_stderror=yes check_via=no dns=no rev_dns=no port=5070 listen=xxx.xxx.xxx.xxx # **** modules **** loadmodule "/usr/local/lib/ser/modules/sl.so" loadmodule "/usr/local/lib/ser/modules/mysql.so" loadmodule "/usr/local/lib/ser/modules/tm.so" loadmodule "/usr/local/lib/ser/modules/acc.so" loadmodule "/usr/local/lib/ser/modules/rr.so" loadmodule "/usr/local/lib/ser/modules/maxfwd.so" loadmodule "/usr/local/lib/ser/modules/usrloc.so" loadmodule "/usr/local/lib/ser/modules/registrar.so" loadmodule "/usr/local/lib/ser/modules/avpops.so" loadmodule "/usr/local/lib/ser/modules/textops.so" # **** module parameters **** # don't use databse for usrloc modparam("usrloc", "db_mode", 0) # add value to ;lr param modparam("rr", "enable_full_lr", 1) # accounting modparam("acc", "log_flag", 1) modparam("acc", "db_flag", 3) modparam("acc", "db_missed_flag", 4) modparam("acc", "failed_transactions", 1) modparam("acc", "db_url" , "mysql://ser:heslo@localhost/ser") # extra accounting - log User-Agent hdr to syslog and AVP ID 888 to database modparam("acc", "log_extra" ,"ua=hdr/User-Agent") # extra accounting - log AVP ID 888 as "uuid" and AVP ID 999 as "src_ip" # to database modparam("acc", "db_extra" ,"uuid=avp/i:888; src_ip=avp/i:999") # avp aliases - define c_uri (canonical uri) as AVP ID 888 and s_ip as ID 999 modparam("avpops", "avp_aliases", "c_uri=i:888; s_ip=i:999" ) # **** routing script **** route{ # initial sanity checks if (!mf_process_maxfwd_header("10")) { sl_send_reply("483","Too Many Hops"); break; }; if (msg:len >= max_len ) { sl_send_reply("513", "Message too big"); break; }; # do record-route for non-REGISTER messages if (!method=="REGISTER") record_route(); # write the source IP as avp "s_ip" for accounting purposes avp_write( "$src_ip", "$s_ip"); # enable both syslog and db accountings setflag(1); setflag(3); # follow Route headers if (loose_route()) { # mark routing logic in request append_hf("P-hint: rr-enforced\r\n"); route(1); break; }; # request is for our domain ? if (!uri==myself) { append_hf("P-hint: outbound\r\n"); } else { # deal with REGISTERs if (method=="REGISTER") { save("location"); break; }; lookup("aliases"); if (!uri==myself) { append_hf("P-hint: outbound alias\r\n"); route(1); break; }; # write the current RURI as avp "c_uri" for accounting purposes avp_write( "$ruri", "$c_uri"); # native SIP destinations are handled using our USRLOC DB if (!lookup("location")) { sl_send_reply("404", "Not Found"); # account the call as missed acc_db_request("404 missed call", "missed_calls"); break; }; # set flag for missed calls accounting setflag(4); append_hf("P-hint: usrloc applied\r\n"); }; # generic forward route(1); } # generic statefull forward route[1] { if (!t_relay()) { sl_reply_error(); }; } ...
The AVPOPS has been introduced into CVS at the beginning of November 2004. A tutorial about its capabilties can be found at http://www.voice-system.ro/docs/avpops/.