1############################################################################
2#
3#  Standalone nathelper which can be used with SIP proxy
4#  for transferring RTP data between networks/through a firewall..
5#  uses Net::SIP::NAT::NATHelper::Server which communicates
6#  with Net::SIP::NAT::NATHelper::Client
7#
8#  Communication is via sock_stream sockets (unix domain or tcp) and the
9#  commands are are an array-ref consisting of the command name
10#  and the arguments. Commands are 'allocate','activate' and 'close'.
11#  For the arguments of the command and the return values see the
12#  methods in Net::SIP::NATHelper::Base.
13#  For transport the requests and responses will be packet with
14#  Storable::nfreeze and prefixed with a long in network format containing
15#  the length of the freezed packet (necessary, because stream sockets
16#  are used).
17#
18############################################################################
19
20use strict;
21use warnings;
22use Getopt::Long qw(:config posix_default bundling);
23use File::Path;
24use IO::Socket;
25use Net::SIP ':debug';
26use Net::SIP::NATHelper::Server;
27
28############################################################################
29#  USAGE
30############################################################################
31
32sub usage {
33    print STDERR "ERROR: @_\n" if @_;
34    print STDERR <<USAGE;
35
36NAT Helper for SIP proxy.
37Reads cmds from cmd-socket, allocates sockets for RTP and send
38information about sockets back to caller, which then rewrites the
39SDP bodies in the SIP packets.
40
41$0 [options] cmd-socket+
42Options:
43    -d|--debug [level]           Enable debugging
44    -h|--help                    Help (this info)
45    -R|--chroot cage-dir         run chrooted (after opening sockets)
46
47cmd-socket is a UNIX domain socket if it contains '/'. If it points
48to an existing directory or contains a trailing '/' cmd-socket will be
49interpreted as a directory name and a file 'socket' will be created below
50the directory.
51If the syntax is 'host:port' a TCP socket will be created.
52Multiple cmd-sockets can be specified.
53
54USAGE
55    exit( @_ ? 1:0 );
56}
57
58############################################################################
59#  Read Options
60############################################################################
61
62my ($debug,$chroot);
63GetOptions(
64    'd|debug:i' => \$debug,
65    'h|help'    => sub { usage() },
66    'R|chroot=s' => \$chroot,
67) || usage( 'bad option' );
68Net::SIP::Debug->level( $debug || 1 ) if defined $debug;
69
70my @sockets = @ARGV;
71@sockets or usage( "no command sockets" );
72
73my @cfd;
74foreach my $socket ( @sockets ) {
75    DEBUG( $socket );
76    if ( $socket =~ m{/} ) {
77	if ( $socket =~m{/$} or -d $socket ) {
78	    -d $socket or mkpath( $socket, 0,0700 )
79		or die $!;
80	    $socket = $socket."/socket";
81	}
82	push @cfd, IO::Socket::UNIX->new( Type => SOCK_STREAM, Local => $socket )
83	    || die $!;
84    } elsif ( $socket =~ m{^(.*):(\d+)$} ) {
85	push @cfd, IO::Socket::INET->new(
86	    LocalAddr => $1,
87	    LocalPort => $2,
88	    Listen => 10,
89	    Reuse => 1,
90	) || die $!;
91    }
92}
93
94# all sockets allocated, now we can change root if necessary
95if ( $chroot ) {
96    # load Storable::* by eval if chroot
97    eval { Storable::thaw() };
98    eval { Storable::nfreeze() };
99
100    chdir( $chroot ) || die $!;
101    chroot( '.' ) || die $!;
102}
103
104# create wrapper and run
105Net::SIP::NATHelper::Server->new( @cfd )->loop;
106