######## 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"); $uac_req(method)="OPTIONS"; $uac_req(hdrs) = "X-TM-Local: PRESENCE_ROUTE_NAT_PING\r\nX-TM-Contact: " + $xavp(ra=>local_contact) + "\r\n"; $uac_req(turi) = $xavp(ra=>contact); $uac_req(ruri) = $xavp(ra=>contact); $uac_req(furi) = $_s(PRESENCE_NAT_S_FROM_URI;nat_id=$xavp(ra=>id)); $uac_req(ouri) = "sip:127.0.0.1:5090;transport=tcp"; $uac_req(callid) = $var(CallId); uac_req_send(); } 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 = $(fu{uri.param,nat_id});); xlog("L_DEBUG", "$ci|nat|NAT UPDATE SQL => '$var(Query)'\n"); mq_add("presence_last_notity", "$uuid(g)", "$var(Query)"); t_drop(); } 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 = $(fu{uri.param,nat_id});); xlog("L_DEBUG", "$ci|nat|NAT REMOVE SQL => '$var(Query)'\n"); mq_add("presence_last_notity", "$uuid(g)", "$var(Query)"); t_drop(); } route[PRESENCE_ROUTE_NAT_PING] { $fs = $(hdr(X-TM-Contact){uri.tosocket}); remove_hf_re("^X-TM-Contact"); force_rport(); handle_ruri_alias(); record_route(); xlog("L_DEBUG", "$ci|local|sending nat keepalive from $fu to $ru => $du => $tu\n"); t_on_reply("PRESENCE_NAT_REPLY"); t_on_failure("PRESENCE_NAT_FAULT"); t_set_fr(0, PRESENCE_NAT_TIMEOUT); t_relay(); } 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; }