Added sample PHP external resolver script, allows blacklisting IP addresses of failed SIP gateways.
git-svn-id: http://yate.null.ro/svn/yate/trunk@2718 acf43c95-373e-0410-b603-e72c3f656dc1
This commit is contained in:
parent
e4bb7cac09
commit
a41297889b
|
@ -0,0 +1,170 @@
|
|||
#!/usr/bin/php -q
|
||||
<?
|
||||
/* Caching resolver script for the Yate PHP interface
|
||||
Needs php pear Net_DNS http://pear.php.net/package/Net_DNS
|
||||
|
||||
Intercepts call.execute and turns hostnames into IP addresses.
|
||||
Example: sip/sip:123@example.com:5060 -> sip/sip:123@10.0.0.1:5060
|
||||
|
||||
If multiple A records are returned a random one will be picked from cache
|
||||
for each call. The TTL of each returned address is capped.
|
||||
|
||||
When SIP calls fail with error 408 (No gateway response) the address to
|
||||
which the failed call was sent to is removed from cache.
|
||||
|
||||
To use add in extmodule.conf
|
||||
|
||||
[scripts]
|
||||
resolver.php=
|
||||
*/
|
||||
require_once("libyate.php");
|
||||
require_once("Net/DNS.php");
|
||||
|
||||
// Always the first action to do
|
||||
Yate::Init();
|
||||
// Uncomment next line to see debug messages
|
||||
Yate::Debug(true);
|
||||
|
||||
$maxttl = 120; // limit to the TTL we accept, in seconds
|
||||
$cache = array();
|
||||
$resolver = new Net_DNS_Resolver();
|
||||
// The following can be commented out to use defaults
|
||||
$resolver->retry = 3; // resolver retry, in seconds
|
||||
$resolver->retrans = 2; // resolver repeat count
|
||||
|
||||
class Cached {
|
||||
var $address;
|
||||
var $expires;
|
||||
|
||||
function Cached($addr,$ttl)
|
||||
{
|
||||
$this->address = $addr;
|
||||
$this->expires = $ttl + time();
|
||||
}
|
||||
}
|
||||
|
||||
function resolve($host)
|
||||
{
|
||||
global $resolver, $cache, $maxttl;
|
||||
|
||||
if (isset($cache[$host])) {
|
||||
Yate::Debug("Found host $host in cache, checking...");
|
||||
$t = time();
|
||||
$changed = false;
|
||||
foreach ($cache[$host] as $idx => $cached) {
|
||||
if ($t >= $cached->expires) {
|
||||
Yate::Debug("Expiring address " . $cached->address);
|
||||
unset($cache[$host][$idx]);
|
||||
$changed = true;
|
||||
}
|
||||
}
|
||||
$c = count($cache[$host]);
|
||||
if ($c != 0) {
|
||||
if ($changed)
|
||||
$cache[$host] = array_values($cache[$host]);
|
||||
return $cache[$host][rand(0,$c-1)]->address;
|
||||
}
|
||||
Yate::Debug("Expiring entire host $host");
|
||||
unset($cache[$host]);
|
||||
}
|
||||
|
||||
Yate::Debug("Resolving host $host");
|
||||
$pkt = $resolver->query($host,'A','IN');
|
||||
if (!$pkt)
|
||||
return false;
|
||||
$entries = array();
|
||||
foreach ($pkt->answer as $rr) {
|
||||
$ttl = $rr->ttl;
|
||||
if ($ttl <= 0 || $ttl > $maxttl)
|
||||
$ttl = $maxttl;
|
||||
$entries[] = new Cached($rr->address,$ttl);
|
||||
}
|
||||
$c = count($entries);
|
||||
Yate::Debug("Caching $c addresses for host $host");
|
||||
$cache[$host] = $entries;
|
||||
return $entries[rand(0,$c-1)]->address;
|
||||
}
|
||||
|
||||
function invalidate($address)
|
||||
{
|
||||
global $cache;
|
||||
foreach($cache as $host => &$entries) {
|
||||
$changed = false;
|
||||
foreach ($entries as $idx => $cached) {
|
||||
if ($cached->address == $address) {
|
||||
Yate::Output("Invalidating $address of host $host");
|
||||
unset($entries[$idx]);
|
||||
$changed = true;
|
||||
}
|
||||
}
|
||||
if (count($entries) == 0) {
|
||||
Yate::Debug("Invalidating entire host $host");
|
||||
unset($cache[$host]);
|
||||
}
|
||||
else if ($changed)
|
||||
$cache[$host] = array_values($cache[$host]);
|
||||
}
|
||||
}
|
||||
|
||||
Yate::Install("call.execute",80);
|
||||
Yate::Install("chan.hangup",120,"cause_sip","408");
|
||||
Yate::SetLocal("restart",true);
|
||||
|
||||
function _disable_warnings_handler($errno, $errstr, $errfile, $errline)
|
||||
{
|
||||
switch ($errno) {
|
||||
case E_USER_ERROR:
|
||||
case E_WARNING:
|
||||
case E_USER_WARNING:
|
||||
_yate_error_handler($errno, $errstr, $errfile, $errline);
|
||||
default:
|
||||
if (!strpos($errfile,'Net/DNS'))
|
||||
_yate_error_handler($errno, $errstr, $errfile, $errline);
|
||||
}
|
||||
}
|
||||
// Net_DNS has static call issues so disable its many warnings...
|
||||
set_error_handler("_disable_warnings_handler");
|
||||
|
||||
/* The main loop. We pick events and handle them */
|
||||
for (;;) {
|
||||
$ev=Yate::GetEvent();
|
||||
if ($ev === false)
|
||||
break;
|
||||
if ($ev === true)
|
||||
continue;
|
||||
if ($ev->type == "incoming") {
|
||||
switch ($ev->name) {
|
||||
case "call.execute":
|
||||
$callto = $ev->GetValue("callto");
|
||||
$parts = array();
|
||||
// Separate host part from called resource
|
||||
if (eregi('^([a-z]+/)([0-9a-z]+:)?([^@:]+@)?([0-9a-z.-]+)(.*)$',$callto,$parts)) {
|
||||
$host = $parts[4];
|
||||
// Check if it's not a dotted IPv4
|
||||
if (ereg('[a-z-]',$host)) {
|
||||
$callto = resolve($host);
|
||||
if ($callto) {
|
||||
Yate::Debug("Resolved '$host' to '$callto'");
|
||||
$callto = $parts[1] . $parts[2] . $parts[3] . $callto . $parts[5];
|
||||
$ev->SetParam("callto",$callto);
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
case "chan.hangup":
|
||||
if ($ev->GetValue("status") == "outgoing") {
|
||||
$address = $ev->GetValue("address");
|
||||
$parts = array();
|
||||
if (ereg('^([0-9.]+)(:[0-9]+)?',$address,$parts))
|
||||
invalidate($parts[1]);
|
||||
}
|
||||
break;
|
||||
}
|
||||
$ev->Acknowledge();
|
||||
}
|
||||
}
|
||||
|
||||
Yate::Output("PHP: bye!");
|
||||
|
||||
/* vi: set ts=8 sw=4 sts=4 noet: */
|
||||
?>
|
Loading…
Reference in New Issue