aitap has asked for the wisdom of the Perl Monks concerning the following question:

Hi, Monks!

I'm writing an application which is going to use UDP-based protocol and STUN as a way to build connections between users. I found STUN::RFC_5389 on CPAN. But how do I actually use it?

My code is:

#!/usr/bin/perl use warnings; use strict; use STUN::RFC_5389; use IO::Socket::INET; die "$0 <server> [port]\n" unless $#ARGV >= 0; my ($server,$port) = @ARGV; $port = $port // 3478; my $request = Client STUN::RFC_5389 { request => 1 }; my $lport = 10000+(int rand 55536); my $socket = new IO::Socket::INET ( LocalPort => $lport, PeerAddr => $server, PeerPort => $port, Proto => 'udp', ) || die "connect: $@\n"; send($socket,$request,0); my $response; recv($socket,$response,1024,0); close($socket); my $mapped_address = ${Client STUN::RFC_5389 $response}{attributes}->{ +'MAPPED-ADDRESS'}; print $mapped_address->{address},":",$mapped_address->{port},"\n"; my $listen = new IO::Socket::INET ( LocalPort => $lport, Proto => 'udp', ) || die "bind: $@\n"; my $buf; $|=1; while ($listen->recv($buf,1)) { print $buf } die "recv: $!\n";
When I then try to send some data to the received address and port (using nc -u <ip address> <port>), nothing shows up there. I even tried sniffing with Wireshark, but there is no incoming traffic.

It looks that I should somehow open the socket, send the STUN request from it, receive it and stay working with it without closing. After reading UDP: Message Passing I have rewritten the code:

#!/usr/bin/perl use warnings; use strict; use STUN::RFC_5389; use Socket; die "$0 <server> [port]\n" unless $#ARGV >= 0; my ($server,$port) = @ARGV; $port = $port // 3478; $|=1; my $request = Client STUN::RFC_5389 { request => 1 }; my $lport = 10000+(int rand 55536); my $lpaddr = sockaddr_in($port, inet_aton("0.0.0.0")) || die "sockaddr +_in: $!\n"; print "socket: "; socket(SOCKET, PF_INET, SOCK_DGRAM, getprotobyname("udp")) && print "\ +n" || die "$!\n"; print "bind: "; bind(SOCKET, $lpaddr) && print "\n" || die "$!\n"; my $siaddr = inet_aton($server) || die "inet_aton: $!\n"; my $spaddr = sockaddr_in($port, $siaddr) || die "sockaddr_in: $!\n"; print "send: "; defined(send(SOCKET, 0, 0, $spaddr)) && print "\n" || die "$!\n"; my $response; print "recv: "; recv(SOCKET, $response, 1024, 0) && print "\n" || die "$!\n"; my $mapped_address = ${Client STUN::RFC_5389 $response}{attributes}->{ +'MAPPED-ADDRESS'}; print $mapped_address->{address},":",$mapped_address->{port},"\n"; print "Listening\n"; my $buf; $|=1; while (recv(SOCKET,$buf,1,0)) { print $buf } die "recv: $!\n";
but it hangs on the first recv(). I tried to enable non-blocking mode (using Fcntl), sleep for some time, then recv 1024 bytes and print received data, and nothing showed up. I guess that I'm doing something wrong again.

How do I use STUN properly?

Replies are listed 'Best First'.
Re: How to use STUN? And other UDP-related problems.
by Neighbour (Friar) on Jul 23, 2012 at 12:19 UTC
    If wireshark shows nothing, and your blocking recv blocks, and your non-blocking recv shows nothing then there can only be one conclusion:
    The data is not arriving at the machine you are expecting it to.
    Find out why (hardware firewalling/routers elsewhere?). Wireshark gets its data from the raw network device, so locally present iptables are not in effect.

      So, just asking STUN server for IP address and port should be enough to receive UDP traffic sent from anywhere (even from my machine) to that address and port? That's sad.

      Anyway, thanks for your answer. I'll search for some other way of bypassing NAT.

Re: How to use STUN? And other UDP-related problems.
by bulk88 (Priest) on Jul 23, 2012 at 23:48 UTC
    Its been years since I last worked with STUN. First get your code working between 2 PCs NOT separated by NAT. Then get your code working between 2 PCs with local software firewalls (think ZoneAlarm). Then get your code working between real Linksys box NAT. Per Wikipedia, http://en.wikipedia.org/wiki/Full_cone_NAT#Full-cone_NAT and http://en.wikipedia.org/wiki/STUN, STUN usually doesn't work against ISP/Linksys box NAT (1 public IP for many private IPs), only "firewalls". Some corporate and university networks that were well endowed in 90s and 80s with whole Class As and Class Bs give FIREWALLED public IPs to all the internal wifi and desktop workstations, STUN was designed for and basically only works for this case.

    I think I remember some algorithms for symmetric/linksys NAT where the NATed client starts sending packets out to a selected server, the server sees all the packets and their source ports (source port selected by NAT box), and the server sends the port increments to the NATed client, I think the hack is that most OSes/NAT boxes allocate source ports on upticking counters (or less often, lowest port first, subject to a multi minute no reuse timer), a pattern can be identified, once both NATed clients see the port allocation patterns, they tell each other their external public IP side source port allocation patterns and they try to DOS/brute force the NAT tables of their NAT boxes until a race condition causes both NAT boxes to simultaneously add matching routes (from private IP side to public internet side packets of course) and a link is broken through. There are only 2^16 (65K) ports, so its not impossible. Most NAT boxes aren't smart to ban their private IP clients from connection flooding the NAT box route table. See http://en.wikipedia.org/wiki/UDP_hole_punching and http://en.wikipedia.org/wiki/TCP_hole_punching.