#!/usr/bin/perl use Getopt::Std; use Socket; use POSIX qw(strftime); use Sys::Syslog; use Sys::Syslog qw(setlogsock); print STDERR <<'EOM'; #======================================================================== # # relay_udp_bcast ... Relay UDP broadcast packet to another network/host # # KAWAMATA Yoshihiro / kaw@teny.co.jp # $Id: relay_udp_packet.pl,v 1.13 2004/11/29 02:36:34 cvs Exp $ # #======================================================================== EOM #-------------------- # default values # $OSTYPE = 'bsd'; # linux or bsd for now $MAX_RECV_PACKET = 64 * 1024; # receiving max 64kB at once #-------------------- # command line options # getopts('dhc:', \%opt); if ($opt{'h'}) { print STDERR <<"EOM"; Usage: $0 [-d] [-h] [-c config-file] -d : debug mode -h : print this help -c config-file : read configuration from config-file EOM exit; } if ($opt{'d'}) { $debug = 1; } #-------------------- # warning message and logging # setlogsock('unix'); openlog('relay_udp', 'ndelay,pid', 'daemon'); sub logfor { if ($debug) { print strftime('%Y/%m/%d %H:%M:%S: ', localtime), $_[0], "\n"; } else { syslog('err', $_[0]); } } sub diefor { logfor($_[0]); die; } #-------------------- # signal handlers # sub terminate { diefor('...Terminated'); } $SIG{'TERM'} = \&terminate; sub interrupt { diefor('...Intrrupted'); } $SIG{'INT'} = \&interrupt; #-------------------- # read configuration # $configfile = $opt{'c'} || '/etc/rup.rc'; { local(@INC); logfor("Staring up - loading $configfile"); eval('require($configfile)') || diefor($!); } #-------------------- # run as a daemon # select(IN); $| = 1; select(OUT); $| = 1; select(STDOUT); unless ($debug) { $pid = fork(); if ($pid == 0) { if ($OSTYPE eq 'linux') { # Linux case; # This is the kluge - FIXME. eval 'sub TIOCNOTTY () {0x5422;}' unless defined(&TIOCNOTTY); } elsif ($OSTYPE eq 'bsd') { require('sys/ttycom.ph') || diefor($!); } elsif (! $OSTYPE) { diefor("System type not defined."); } else { diefor("Unknown system type '$OSTYPE' ."); } close(STDIN); close(STDOUT); close(STDERR); if (open(CTTY, '/dev/tty')) { ioctl(CTTY, &TIOCNOTTY, my $dummy); close(CTTY); } } elsif (0 < $pid) { exit(0); } else { diefor('cannot fork'); } } #-------------------- # setup socket for incoming packet # socket(IN, PF_INET, SOCK_DGRAM, getprotobyname('udp')) || &diefor("socket for input: $!"); # to receive BROADCAST # (OS depedent?, maybe almost unnecessary...) setsockopt(IN, SOL_SOCKET, SO_BROADCAST, 1) || &diefor("setsockopt for input: $!"); # $in_ent = sockaddr_in($orig_port, inet_aton($orig_addr)); bind(IN, $in_ent) || &diefor("bind for input: $!"); logfor("Original: $orig_addr, port = $orig_port"); #-------------------- # setup socket for outgoing packet # socket(OUT, PF_INET, SOCK_DGRAM, getprotobyname('udp')) || &diefor("socket for output: $!"); # to send BROADCAST setsockopt(OUT, SOL_SOCKET, SO_BROADCAST, 1) || &diefor("setsockopt for output: $!"); $out_ent = sockaddr_in(0, INADDR_ANY); bind(OUT, $out_ent) || &diefor("bind for output: $!"); #-------------------- # destinations to relay # foreach $dhost (@dest_host) { ($dest_addr, $dest_port) = split(':', $dhost); $ent = sockaddr_in($dest_port, inet_aton($dest_addr)); push(@dest_ent, $ent); logfor("Relay: $dest_addr, port = $dest_port"); } #-------------------- # main from here. # logfor('Running ...'); while (1) { $src_ent = recv(IN, $indata, $MAX_RECV_PACKET, 0); if ($debug) { ($src_port, $src_addr) = sockaddr_in($src_ent); logfor(sprintf("Received %d bytes from %s", length($indata), join('.', unpack('C4', $src_addr)))); } foreach $ent (@dest_ent) { if ($debug) { ($dest_port, $dest_addr) = sockaddr_in($ent); logfor(sprintf("Sending %d bytes to %s", length($indata), join('.', unpack('C4', $dest_addr)))); } send(OUT, $indata, 0, $ent) || logfor("Send Error: $!"); } } # # That's all, forks. #--------------------