[asterisk-dev] stun support in asterisk ? (and a related hack for rtp.c)

Luigi Rizzo rizzo at icir.org
Wed Jul 11 11:39:06 CDT 2007


Brief followup.
There is some code in rtp.c that does the basic stun message
build/decode, and i am trying to comment it a bit.  The way it is
used now is probably too tightly related to rtp (e.g.  functions
take a struct ast_rtp as an argument), whereas other protocols (e.g.
SIP) might as well benefit from it.

Doing basic STUN transactions is really trivial indeed, see the attached
piece of php that implements it.

So it should be relatively straightforward to provide a config file
option that, if enabled, after opening/binding a socket tries a
STUN transaction to determine the externally visible address and
overrides things such as externip= and bindport= when used e.g. in
sip.conf . The only (minor) difficulty is the potential delay involved
in the transaction. On the other hand, often we also do a DNS
lookup when e.g. starting to talk to a peer, and that's equally
blocking.

Once support for this is in, it should be relatively straightforward,
again, to use the hook to call smarter nat traversal algorithms,
make the option configurable per-destination and not just globally,
and so on.

	cheers
	luigi

#!/usr/local/bin/php
<?
#
# $Id$
# a simple stun client

error_reporting(E_ALL);

go("192.245.12.229"); # the argument is the stun server's IP

function usock() {
	$s = socket_create(AF_INET, SOCK_DGRAM, 0);
	socket_set_option($s, SOL_SOCKET, SO_REUSEADDR, 1);
	return $s;
}

function htons($x) {
	return chr(round($x / 256)) . chr($x % 256) ;
}
function htonl($x) {
	return htons($x >> 16) . htons($x % 65536);
}

function ntohs($x) {
	return ord($x[0])* 256 + ord($x[1]);
}

function make_req($ty, $body) {
	$xid = chr(rand(0,255)) . chr(rand(0,255)) . "23456789abcdef";
	$len = strlen($body);
	$pkt = htons($ty) . htons($len) . $xid . $body;
	echo "packet is " . bin2hex($pkt) . "\n";
	return $pkt;
}

$stun_types = array(
	0x0001 => 'Binding Request',
	0x0101 => 'Binding Response',
	0x0111 => 'Binding Error Response',
	0x0002 => 'Shared Secret Request',
	0x0102 => 'Shared Secret Response',
	0x0112 => 'Shared Secret Error Response',
);

$stun_attributes = array(
	0x0001 => 'MAPPED-ADDRESS',
	0x0002 => 'RESPONSE-ADDRESS',
	0x0003 => 'CHANGE-REQUEST',
	0x0004 => 'SOURCE-ADDRESS',
	0x0005 => 'CHANGED-ADDRESS',
	0x0006 => 'USERNAME',
	0x0007 => 'PASSWORD',
	0x0008 => 'MESSAGE-INTEGRITY',
	0x0009 => 'ERROR-CODE',
	0x000a => 'UNKNOWN-ATTRIBUTES',
	0x000b => 'REFLECTED-FROM',
);

function stun_print_addr($a) {
	$len = strlen($a);
	if ($len != 8)
		return "";
	return sprintf("%d %d.%d.%d.%d:%d",
		ord($a[1]),
		ord($a[4]), ord($a[5]), ord($a[6]), ord($a[7]),
		ntohs(substr($a, 2, 2)) );
}

function stun_decode($msg) {
	global $stun_types;
	global $stun_attributes;
	$ty = ntohs(substr($msg, 0, 2));
	printf("type 0x%x %s len 0x%x\n", $ty, $stun_types[$ty],
		ntohs(substr($msg, 2, 2) ) );
	$i = 0x14;	/* past header and xid */
	$l = strlen($msg);
	while ($i < $l) {
	    $attr = ntohs(substr($msg, $i, 2));
	    $len = ntohs(substr($msg, $i+2, 2));
	    printf("attribute 0x%04x %20s [%3d] [%s] [%s]\n",
		$attr, $stun_attributes[$attr], $len,
		bin2hex(substr($msg, $i+4, $len)),
		stun_print_addr(substr($msg, $i+4, $len)) );
	    $i += 4+ $len;
	}
}

function go($ser) {
    $s = usock();
    for (;;) {
    	$a = make_req(0x1, "");
	socket_sendto($s, $a, strlen($a), 0, $ser', 3478);
	$e = NULL;
	$w = NULL;
	$r[] = $s;
	$x = socket_select($r, $w, $e, 5);
	echo "select returns $x\n";
	if ($x == 0)
		continue;
	$resp = "";
	$peer = "";
	$port = "";
	$err = socket_recvfrom($s, $resp, 1024, 0, $peer, $port);
	echo "Response from $peer : $port size $err\n";
	stun_decode($resp);
    }
}

?>



More information about the asterisk-dev mailing list