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/.