From f485603215a5bcb93a900498ec8861da2e3a0106 Mon Sep 17 00:00:00 2001 From: lazedo Date: Tue, 5 Mar 2019 17:50:27 +0000 Subject: [PATCH] presence nat --- kamailio/db_scripts/db_extra_check.sql | 3 + kamailio/db_scripts/db_init_presence_nat.sql | 10 ++ kamailio/db_scripts/db_kazoo-specific | 13 +- kamailio/default.cfg | 3 +- kamailio/nat-traversal-role.cfg | 2 +- kamailio/presence-nat.cfg | 122 +++++++++++++++++++ kamailio/presence-notify.cfg | 4 +- kamailio/presence-role.cfg | 45 +++---- kamailio/registrar-role.cfg | 4 + 9 files changed, 171 insertions(+), 35 deletions(-) create mode 100644 kamailio/db_scripts/db_init_presence_nat.sql create mode 100644 kamailio/presence-nat.cfg diff --git a/kamailio/db_scripts/db_extra_check.sql b/kamailio/db_scripts/db_extra_check.sql index df1b7c8..74522a9 100644 --- a/kamailio/db_scripts/db_extra_check.sql +++ b/kamailio/db_scripts/db_extra_check.sql @@ -23,4 +23,7 @@ KazooDB -db ${DB_CURRENT_DB} "drop table if exists tmp_probe;" KazooDB -db ${DB_CURRENT_DB} "create table tmp_probe as select distinct a.event, a.presentity_uri, cast(2 as integer) action from presentities a inner join active_watchers b on a.presentity_uri = b.presentity_uri and a.event = b.event where state in('early', 'confirmed', 'onthephone', 'busy');" KazooDB -db ${DB_CURRENT_DB} "delete from presentity where id in(select id from presentities where state in('early', 'confirmed', 'onthephone', 'busy'));" +## presence nat +KazooDB -db ${DB_CURRENT_DB} "delete from presence_nat where id in(select id from presence_nat a where not exists (select id from active_watchers b where b.contact = a.contact));" + } diff --git a/kamailio/db_scripts/db_init_presence_nat.sql b/kamailio/db_scripts/db_init_presence_nat.sql new file mode 100644 index 0000000..0df244d --- /dev/null +++ b/kamailio/db_scripts/db_init_presence_nat.sql @@ -0,0 +1,10 @@ +CREATE TABLE if not exists presence_nat ( + id INTEGER PRIMARY KEY NOT NULL, + contact VARCHAR(2048) NOT NULL COLLATE NOCASE, + local_contact VARCHAR(32) NOT NULL COLLATE NOCASE, + time_inserted timestamp DEFAULT CURRENT_TIMESTAMP, + time_sent timestamp DEFAULT CURRENT_TIMESTAMP, + slot INTEGER NOT NULL, + selected INTEGER DEFAULT 0, + CONSTRAINT presence_nat_idx UNIQUE (contact) + ); diff --git a/kamailio/db_scripts/db_kazoo-specific b/kamailio/db_scripts/db_kazoo-specific index 85d731b..b8a3c2d 100644 --- a/kamailio/db_scripts/db_kazoo-specific +++ b/kamailio/db_scripts/db_kazoo-specific @@ -41,7 +41,18 @@ CREATE TABLE active_watchers_log ( user_agent VARCHAR(255) DEFAULT '' COLLATE NOCASE, CONSTRAINT active_watchers_active_watchers_log_idx UNIQUE (presentity_uri, watcher_username, watcher_domain, event) ); - + +CREATE TABLE presence_nat ( + id INTEGER PRIMARY KEY NOT NULL, + contact VARCHAR(2048) NOT NULL COLLATE NOCASE, + local_contact VARCHAR(128) NOT NULL COLLATE NOCASE, + time_inserted timestamp DEFAULT CURRENT_TIMESTAMP, + time_sent timestamp DEFAULT CURRENT_TIMESTAMP, + slot INTEGER NOT NULL, + selected INTEGER DEFAULT 0, + CONSTRAINT presence_nat_idx UNIQUE (contact) + ); + create view presentities as select id, cast(printf("sip:%s@%s",username,domain) as varchar(64)) presentity_uri , username, domain, event, cast(substr(etag, instr(etag,"@")+1) as varchar(64)) callid, datetime(received_time, 'unixepoch') as received, diff --git a/kamailio/default.cfg b/kamailio/default.cfg index cc97967..52e8bcd 100644 --- a/kamailio/default.cfg +++ b/kamailio/default.cfg @@ -940,8 +940,9 @@ event_route[tm:local-request] #!endif #!ifdef PRESENCE_ROLE - route(PRESENCE_LOCAL_NOTIFY); + route(PRESENCE_LOCAL_REQUEST); #!endif + } event_route[evrexec:DEFERRED_INIT] diff --git a/kamailio/nat-traversal-role.cfg b/kamailio/nat-traversal-role.cfg index 879721b..6d62690 100644 --- a/kamailio/nat-traversal-role.cfg +++ b/kamailio/nat-traversal-role.cfg @@ -4,7 +4,7 @@ loadmodule "nathelper.so" #!trydef NATHELPER_LOADED #!endif modparam("nathelper", "received_avp", "$avp(AVP_RECV_PARAM)") -modparam("nathelper", "sipping_from", "sip:registrar-check@MY_HOSTNAME") +modparam("nathelper", "sipping_from", "sip:registrar@MY_HOSTNAME") #!ifdef WEBSOCKETS_ROLE #!trydef KZ_NAT_DETECT 83 diff --git a/kamailio/presence-nat.cfg b/kamailio/presence-nat.cfg new file mode 100644 index 0000000..e3913bf --- /dev/null +++ b/kamailio/presence-nat.cfg @@ -0,0 +1,122 @@ +######## Presence NAT ######## + +modparam("htable", "htable", "keepalive=>size=32;autoexpire=3600;initval=0;") + +#!trydef KZ_PRESENCE_KEEPALIVE_UDP_ONLY 0 +#!trydef PRESENCE_NAT_TIMERS 4 +#!trydef PRESENCE_NAT_INTERVAL 30 +#!trydef PRESENCE_NAT_SKIP_REGISTERED 1 +#!trydef PRESENCE_NAT_FROM_URI sip:keepalive@MY_HOSTNAME +#!trydef PRESENCE_NAT_TIMEOUT 3500 + +#!substdef "!PRESENCE_NAT_S_FROM_URI!sip:keepalive@MY_HOSTNAME!g" +#!substdef "!PRESENCE_NAT_S_TIMERS!$def(PRESENCE_NAT_TIMERS)!g" + +kazoo.presence_keepalive_udp_only = KZ_PRESENCE_KEEPALIVE_UDP_ONLY descr "should we keepalive nat phones for udp only" +kazoo.presence_keepalive_skip_registered = PRESENCE_NAT_SKIP_REGISTERED descr "skip if there's a registered contact from same ip/port (avoids multiple pings)" + +modparam("rtimer", "timer", "name=presence_nat_timer;interval=1;mode=PRESENCE_NAT_S_TIMERS;") +modparam("rtimer", "exec", "timer=presence_nat_timer;route=PRESENCE_NAT_TIMER") + +####### Presence Logic ######## + +route[PRESENCE_NAT] +{ + #!ifdef NAT_TRAVERSAL_ROLE + if (isflagset(FLT_NATS)) { + $xavp(regcfg=>match_received) = $su; + if(!( ($sel(cfg_get.kazoo.presence_keepalive_udp_only) == 1 && $proto != "udp") + || ($proto == "ws" || $proto == "wss") +#!ifdef REGISTRAR_ROLE + || ($sel(cfg_get.kazoo.presence_keepalive_skip_registered) == 1 && registered("location", "$rz:$Au", 2, 1) == 1) +#!endif + )) { + $var(slot) = $(subs(contact){s.corehash, PRESENCE_NAT_S_TIMERS}); + $var(sql) = $_s(INSERT OR IGNORE INTO presence_nat (contact, local_contact, slot) values("$subs(contact)", "$subs(local_contact)", $var(slot))); + mq_add("presence_last_notity", "$ci", "$var(sql)"); + } + } + #!endif + + return; +} + + +route[PRESENCE_NAT_TIMER] +{ + $var(Query) = $_s(UPDATE presence_nat SET selected = 1 WHERE slot = $rtimer_worker AND selected = 0 AND time_sent < datetime('now', '-$def(PRESENCE_NAT_INTERVAL) seconds')); + $var(sqlres) = sql_query("cb", "$var(Query)"); + if($var(sqlres) < 0) { + xlog("L_ERROR", "$rtimer_worker|log|error running query : $var(Query)\n"); + } else { + $var(nrows) = $sqlrows(cb); + xlog("L_DEBUG", "$rtimer_worker|log|selected $var(nrows) endpoints to ping\n"); + } + + $var(Query) = $_s(SELECT id, contact, local_contact from presence_nat WHERE slot = $rtimer_worker AND selected = 1); + xlog("L_DEBUG", "$rtimer_worker|timer|SQL => $var(Query)\n"); + if (sql_xquery("cb", "$var(Query)", "ra") == 1) + { + while($xavp(ra) != $null) { + $var(loop) = 0; + while($xavp(ra) != $null && $var(loop) < MAX_WHILE_LOOPS) { + route(PRESENCE_NAT_PING); + pv_unset("$xavp(ra)"); + $var(loop) = $var(loop) + 1; + } + } + } + + $var(Query) = $_s(UPDATE presence_nat SET selected = 2 WHERE slot = $rtimer_worker AND selected = 1); + $var(sqlres) = sql_query("cb", "$var(Query)"); + if($var(sqlres) < 0) { + xlog("L_ERROR", "$rtimer_worker|log|error running query : $var(Query)\n"); + } + +} + +route[PRESENCE_NAT_PING] +{ + $var(CallId) = $uuid(g); + xlog("L_DEBUG", "$var(CallId)|$rtimer_worker|timer|SENDING PING FROM $(xavp(ra=>local_contact){uri.tosocket}) TO => $xavp(ra=>contact)\n"); + t_uac_send("OPTIONS", "$xavp(ra=>contact)", "", "$(xavp(ra=>local_contact){uri.tosocket})", "CSeq: 1 OPTIONS\r\nFrom: PRESENCE_NAT_S_FROM_URI\r\nTo: $xavp(ra=>contact);nat_id=$xavp(ra=>id)\r\nContact: <$xavp(ra=>local_contact)>\r\nCall-ID: $var(CallId)\r\n", ""); +} + +onreply_route[PRESENCE_NAT_REPLY] +{ + xlog("L_DEBUG", "$ci|nat|NAT REPLY $(tu{nameaddr.uri})\n"); + $var(Query) = $_s(UPDATE presence_nat SET selected = 0, time_sent = datetime('now') WHERE id = $(tu{uri.param,nat_id});); + xlog("L_DEBUG", "$ci|nat|NAT UPDATE SQL => '$var(Query)'\n"); + mq_add("presence_last_notity", "$uuid(g)", "$var(Query)"); +} + +failure_route[PRESENCE_NAT_FAULT] +{ + xlog("L_WARNING", "$ci|nat|received error $T_reply_code $T_reply_reason from $(tu{nameaddr.uri})\n"); + $var(Query) = $_s(DELETE FROM presence_nat WHERE id = $(tu{uri.param,nat_id});); + xlog("L_DEBUG", "$ci|nat|NAT REMOVE SQL => '$var(Query)'\n"); + mq_add("presence_last_notity", "$uuid(g)", "$var(Query)"); +} + +route[PRESENCE_LOCAL_REQ_NAT] +{ + #!ifdef NAT_TRAVERSAL_ROLE + if($rm == "OPTIONS" && $fu == "PRESENCE_NAT_S_FROM_URI") { + t_on_reply("PRESENCE_NAT_REPLY"); + t_on_failure("PRESENCE_NAT_FAULT"); + t_set_fr(0, PRESENCE_NAT_TIMEOUT); + handle_ruri_alias(); + record_route(); + } + #!endif + return; +} + +route[PRESENCE_NAT_ON_REGISTRATION] +{ + #!ifdef NAT_TRAVERSAL_ROLE + $var(Query) = $_s(DELETE FROM presence_nat WHERE contact like "$xavp(ulrcd=>contact)%";); + mq_add("presence_last_notity", "$uuid(g)", "$var(Query)"); + #!endif + return; +} diff --git a/kamailio/presence-notify.cfg b/kamailio/presence-notify.cfg index 7c263e6..0b9f46f 100644 --- a/kamailio/presence-notify.cfg +++ b/kamailio/presence-notify.cfg @@ -17,7 +17,7 @@ modparam("htable", "htable", "notify=>size=16;autoexpire=3600;updateexpire=1;ini #!trydef PRESENCE_NOTIFY_INIT #!trydef MAX_NOTIFY_ERROR 5 -route[PRESENCE_LOCAL_NOTIFY] +route[PRESENCE_LOCAL_REQ_NOTIFY] { if($rm != "NOTIFY") { return; @@ -202,6 +202,8 @@ route[PRESENCE_EXPIRED_REGISTRATION] $var(watcher) = $_s(sip:$ulc(exp=>aor)); $var(watcher_username) = $(var(watcher){uri.user}); $var(watcher_domain) = $(var(watcher){uri.host}); + $var(Query) = $_s(DELETE FROM presence_nat where contact in(select distinct contact from active_watchers WHERE watcher_username = "$var(watcher_username)" and watcher_domain = "$var(watcher_domain)");); + mq_add("presence_last_notity", "$uuid(g)", "$var(Query)"); $var(Query) = $_s(DELETE FROM active_watchers WHERE watcher_username = "$var(watcher_username)" and watcher_domain = "$var(watcher_domain)";); mq_add("presence_last_notity", "$uuid(g)", "$var(Query)"); } diff --git a/kamailio/presence-role.cfg b/kamailio/presence-role.cfg index f8be4c6..78e52d3 100644 --- a/kamailio/presence-role.cfg +++ b/kamailio/presence-role.cfg @@ -12,8 +12,7 @@ #!trydef KZ_PRESENCE_REQUEST_PROBE 1 #!trydef KZ_PRESENCE_NO_TARGETS_LOG_LEVEL L_DBG -modparam("htable", "htable", "p=>size=32;autoexpire=3600;") -modparam("htable", "htable", "first=>size=32;autoexpire=3600;initval =0;updateexpire=1;") +modparam("htable", "htable", "first=>size=32;autoexpire=3600;initval=0;") loadmodule "presence.so" loadmodule "presence_dialoginfo.so" @@ -53,17 +52,6 @@ modparam("presence", "cseq_offset", KZ_PRESENCE_CSEQ_OFFSET) modparam("kazoo", "db_url", "KAZOO_DB_URL") modparam("kazoo", "pua_mode", 1) -#!ifdef NAT_TRAVERSAL_ROLE -#!ifndef NAT_TRAVERSAL_LOADED -#!trydef NAT_TRAVERSAL_LOADED -loadmodule "nat_traversal.so" -#!endif -modparam("nat_traversal", "keepalive_method", "OPTIONS") -modparam("nat_traversal", "keepalive_from", "sip:presence-check@MY_HOSTNAME") -modparam("nat_traversal", "keepalive_state_file", "KAZOO_DATA_DIR/keep_alive_state") -modparam("nat_traversal", "keepalive_interval", 30) -#!endif - kazoo.presence_sync_amqp = KZ_PRESENCE_AMQP_PUBLISH descr "sync subscriptions to amqp" kazoo.presence_request_probe = KZ_PRESENCE_REQUEST_PROBE descr "request probe for new subscriptions" kazoo.presence_request_resubscribe_probe = KZ_PRESENCE_REQUEST_RESUBSCRIBE_PROBE descr "request probe for resubscriptions" @@ -75,23 +63,10 @@ kazoo.presence_no_targets_log_level = KZ_PRESENCE_NO_TARGETS_LOG_LEVEL descr "wh #!include_file "presence-notify.cfg" #!include_file "presence-reset.cfg" #!include_file "presence-fast-pickup.cfg" +#!include_file "presence-nat.cfg" ####### Presence Logic ######## -#!ifdef NAT_TRAVERSAL_ROLE -route[PRESENCE_NAT] -{ - if (isflagset(FLT_NATS)) { - $xavp(regcfg=>match_received) = $su; - if(!( ($proto != "udp") || - (registered("location", "$rz:$Au", 2, 1) == 1) - )) { - nat_keepalive(); - } - } -} -#!endif - route[HANDLE_SUBSCRIBE] { if (!is_method("SUBSCRIBE")) { @@ -111,10 +86,6 @@ route[HANDLE_SUBSCRIBE] exit; } - #!ifdef NAT_TRAVERSAL_ROLE - route(PRESENCE_NAT); - #!endif - if(has_totag()) { loose_route(); } @@ -190,6 +161,7 @@ route[HANDLE_NEW_SUBSCRIBE] route(DELETE_DUPLICATED_SUBSCRIPTIONS); route(SUBSCRIBE_AMQP); route(REQUEST_PROBE); + route(PRESENCE_NAT); } else { xlog("L_INFO", "$ci|stop|error $T_reply_code for new $hdr(Event) subscription from $fU to $tU in realm $fd\n"); } @@ -544,4 +516,15 @@ route[PRESENCE_API_BINDINGS] } +route[PRESENCE_LOCAL_REQUEST] +{ + route(PRESENCE_LOCAL_REQ_NOTIFY); + route(PRESENCE_LOCAL_REQ_NAT); +} + +route[PRESENCE_ON_REGISTRATION] +{ + route(PRESENCE_NAT_ON_REGISTRATION); +} + # vim: tabstop=4 softtabstop=4 shiftwidth=4 expandtab diff --git a/kamailio/registrar-role.cfg b/kamailio/registrar-role.cfg index e281ad4..453077f 100644 --- a/kamailio/registrar-role.cfg +++ b/kamailio/registrar-role.cfg @@ -353,6 +353,10 @@ route[SAVE_LOCATION] route(PUSHER_ON_REGISTRATION); #!endif + #!ifdef PRESENCE_ROLE + route(PRESENCE_ON_REGISTRATION); + #!endif + exit; }