File Coverage

lib/STUN/Client.pm
Criterion Covered Total %
statement 1 3 33.3
branch n/a
condition n/a
subroutine 1 1 100.0
pod n/a
total 2 4 50.0


line stmt bran cond sub pod time code
1             #!/usr/bin/perl
2              
3             package STUN::Client;
4              
5 1     1   54649 use Moose;
  0            
  0            
6             use Moose::Util::TypeConstraints;
7              
8             use Socket;
9             use Data::Validate::IP;
10              
11             use STUN::RFC_5389;
12              
13             our $VERSION = '0.04';
14              
15             has stun_server => (
16             is => 'rw',
17             isa => 'Str'
18             );
19              
20             has port => (
21             is => 'rw',
22             isa => 'Int',
23             default => 3478,
24             );
25              
26             has 'local_address' => (
27             is => 'rw',
28             isa => 'Str'
29             );
30              
31             has 'local_port' => (
32             is => 'rw',
33             isa => 'Int',
34             default => 0
35             );
36              
37             has proto => (
38             is => 'rw',
39             isa => enum([qw[tcp udp]]),
40             default => 'udp',
41             );
42              
43             has 'retries' => (
44             is => 'rw',
45             isa => 'Int',
46             default => 5
47             );
48              
49             has 'timeout' => (
50             is => 'rw',
51             isa => 'Int',
52             default => 2
53             );
54              
55             has 'response' => (
56             is => 'rw',
57             isa => 'HashRef'
58             );
59              
60             sub _select {
61             my ($self, $rinh) = @_;
62             my ($rin, $win, $ein);
63             $rin = $win = $ein = '';
64             vec($rin,fileno($rinh), 1) = 1;
65             $ein = $rin;
66             my ($rout, $wout, $eout);
67             my $nfound = select($rout=$rin, $wout=$win, $eout=$ein, $self->timeout);
68             return $nfound;
69             }
70              
71             sub get () {
72             my ($self) = @_;
73              
74             socket(S, PF_INET, SOCK_DGRAM, getprotobyname($self->proto));
75              
76             if ($self->local_address) {
77             my $bind_addr = gethostbyname($self->local_address)
78             || die "$0: Couldn't bind.\n";
79             my $bind_sin = sockaddr_in($self->local_port, $bind_addr);
80             bind(S, $bind_sin) || die "$0: Couldn't bind $!\n";
81             }
82              
83             my $iaddr = gethostbyname($self->stun_server);
84             my $sin = sockaddr_in($self->port, $iaddr);
85              
86             my $msg = STUN::RFC_5389->Client( { request => 1 } );
87              
88             my $try = 0;
89              
90             while (++$try <= $self->retries) {
91             my $s = send(S, $msg, 0, $sin);
92             defined $s && $s == length($msg) || die "send: $!";
93              
94             # Timeout
95             next if !$self->_select(\*S);
96              
97             my $rmsg = '';
98             my $r = recv(S, $rmsg, 1024, 0);
99             # || die "recv: $!";
100              
101             next if !defined $r;
102              
103             my $answer = STUN::RFC_5389->Client( $rmsg );
104              
105             my $ma = $answer->{attributes}{'0020'} ? '0020' : '0001';
106             my $ret = {
107             message_type => $answer->{message_type},
108             message_length => $answer->{message_length},
109             transaction_id => $answer->{magic_cookie} . $answer->{transaction_id},
110             attr_type => $ma,
111             attr_length => 8,
112             ma_dummy => '00',
113             ma_family => $answer->{attributes}{$ma}{family},
114             ma_port => $answer->{attributes}{$ma}{port},
115             ma_address => $answer->{attributes}{$ma}{address}
116             };
117             $self->response($ret);
118              
119             return ( $ret, $answer );
120             }
121             }
122              
123              
124             1;
125              
126             __END__
127              
128             =head1 NAME
129              
130             STUN::Client - Session Traversal Utilities for NAT (STUN) client. (RFC 5389)
131              
132             =head1 SYNOPSIS
133              
134             use STUN::Client;
135             use Data::Dumper;
136              
137             $stun_client = STUN::Client->new;
138              
139             $stun_client->stun_server('stun.server.org');
140              
141             ($r_old, $r_new) = $stun_client->get;
142              
143             print Dumper($r_old);
144             print Dumper($r_new);
145              
146             =head1 DESCRIPTION
147              
148             Session Traversal Utilities for NAT (STUN) is a protocol that serves as a tool for other protocols in dealing with Network Address Translator (NAT) traversal. It can be used by an endpoint to determine the IP address and port allocated to it by a NAT. It can also be used to check connectivity between two endpoints, and as a keep-alive protocol to maintain NAT bindings. STUN works with many existing NATs, and does not require any special behavior from them.
149              
150             STUN is not a NAT traversal solution by itself. Rather, it is a tool to be used in the context of a NAT traversal solution.
151              
152             =head1 ATTRIBUTES
153              
154             =head2 stun_server
155              
156             Hostname of STUN server.
157              
158             =head2 proto
159              
160             Protocol to use for connect, 'udp' or 'tcp'.
161              
162             Default: udp.
163              
164             =head2 port
165              
166             Port number of STUN server.
167              
168             Default: 3478
169              
170             =head2 local_address
171              
172             Local Internet address.
173              
174             =head2 local_port
175              
176             Local port number, but it is necessary that local_address is explicity.
177              
178             =head2 retries
179              
180             The client retries the request, this time including its username and the
181             realm, and echoing the nonce provided by the server. The client also
182             includes a message-integrity, which provides an HMAC over the entire
183             request, including the nonce. The server validates the nonce and
184             checks the message integrity. If they match, the request is
185             authenticated. If the nonce is no longer valid, it is considered
186             "stale", and the server rejects the request, providing a new nonce.
187              
188             Default: 5
189              
190             =head2 timeout
191              
192             Retransmit a STUN request message starting with an interval of RTO ("Retransmission TimeOut"), doubling after each retransmission.
193              
194             Default: 2
195              
196             =head2 method
197              
198             STUN methods in the range 0x000 - 0x7FF are assigned by IETF Review
199             [RFC5226]. STUN methods in the range 0x800 - 0xFFF are assigned by
200             Designated Expert [RFC5226].
201              
202             =head2 data
203              
204             Data to send in package.
205              
206             =head1 METHODS
207              
208             =head2 get
209              
210             Connect to a stun_server and receive the answer. The first argument returned
211             is a hash reference in the format retuned by the versions
212             previous to 0.04. The second argument is a hash reference as returned
213             by L<STUN::RFC_5389>.
214              
215             =head1 STUN Servers
216              
217             * stun.ekiga.net
218             * stun.fwdnet.net
219             * stun.ideasip.com
220             * stun01.sipphone.com (no DNS SRV record)
221             * stun.softjoys.com (no DNS SRV record)
222             * stun.voipbuster.com (no DNS SRV record)
223             * stun.voxgratia.org (no DNS SRV record)
224             * stun.xten.com
225             * stunserver.org see their usage policy
226             * stun.sipgate.net:10000
227              
228              
229             =head1 SEE ALSO
230              
231             L<STUN::RFC_5389>
232              
233             =head1 CONTRIBUTORS
234              
235             Detlef Pilzecker
236              
237             =head1 AUTHOR
238              
239             Thiago Rondon, <thiago@aware.com.br>
240              
241             http://www.aware.com.br/
242              
243             =head1 LICENSE
244              
245             Perl license.
246