Advertisement

09.18.2008 at 01:16AM PDT, ID: 23741539
[x]
Attachment Details
[x]
The Solution Rating System

With so many solutions, how can you tell which solutions are most likely to help you and which ones are not? To provide you with a tool to use, we rate our solutions based on various elements that most accurately determine if a solution is a quality solution. To explain what factors affect the solution rating, here are the elements we take into consideration when formulating our solution rating.

  • The Grade of the Solution
  • The Zone Rank of the Expert Providing the Solution
  • The Number of Author and Expert Comments
  • The Number of Experts Contributing
  • The Feedback of the Community

Your Input Matters
Because of the way the system is set up, the most important variable in this equation is you. As a member of Experts Exchange, you are able to cast your vote on the quality of the solutions in regard to how complete, accurate, helpful and easy to understand each solution is. When you provide your feedback, each rating is adjusted accordingly. So, if you see a solution that has a poor rating that you think is a good solution, let us know by rating it. As you do, the rating will be adjusted and will become more accurate for other members of our site.

If you have any suggestions that you would like to make for our rating system, please ask a question in the Suggestions Zone of Community Support.

Thank you!

8.2

IO::Socket::INET dies when using 'udp': unknown error

Asked by o-tvw-ee in Perl Programming Language

Tags:

Hi all,

I'm adapting a proxy script I got from:http://www.accordata.de/downloads/port-proxy/index.html
This script can be used for port forwarding but is written for TCP connections only. We also need UDP connections so I'm trying to enhance the script with UDP functionality (see code snippet).
All works for TCP, but if I try UDP the script dies on line 218 with a very helpfull error message:  IO::Socket::INET: Unknown error

I'm a newbie when it comes to perl...

Add these lines to a file port-proxy.conf to test it (change ip address if necessary):
forward=3784,192.168.40.80:3784,tcp      #Ventrilo
forward=3784,192.168.40.80:3784,udp      #VentriloStart Free Trial
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
20:
21:
22:
23:
24:
25:
26:
27:
28:
29:
30:
31:
32:
33:
34:
35:
36:
37:
38:
39:
40:
41:
42:
43:
44:
45:
46:
47:
48:
49:
50:
51:
52:
53:
54:
55:
56:
57:
58:
59:
60:
61:
62:
63:
64:
65:
66:
67:
68:
69:
70:
71:
72:
73:
74:
75:
76:
77:
78:
79:
80:
81:
82:
83:
84:
85:
86:
87:
88:
89:
90:
91:
92:
93:
94:
95:
96:
97:
98:
99:
100:
101:
102:
103:
104:
105:
106:
107:
108:
109:
110:
111:
112:
113:
114:
115:
116:
117:
118:
119:
120:
121:
122:
123:
124:
125:
126:
127:
128:
129:
130:
131:
132:
133:
134:
135:
136:
137:
138:
139:
140:
141:
142:
143:
144:
145:
146:
147:
148:
149:
150:
151:
152:
153:
154:
155:
156:
157:
158:
159:
160:
161:
162:
163:
164:
165:
166:
167:
168:
169:
170:
171:
172:
173:
174:
175:
176:
177:
178:
179:
180:
181:
182:
183:
184:
185:
186:
187:
188:
189:
190:
191:
192:
193:
194:
195:
196:
197:
198:
199:
200:
201:
202:
203:
204:
205:
206:
207:
208:
209:
210:
211:
212:
213:
214:
215:
216:
217:
218:
219:
220:
221:
222:
223:
224:
225:
226:
227:
228:
229:
230:
231:
232:
233:
234:
235:
236:
237:
238:
239:
240:
241:
242:
243:
244:
245:
246:
247:
248:
249:
250:
251:
252:
253:
254:
255:
256:
257:
258:
259:
260:
261:
262:
263:
264:
265:
266:
267:
268:
269:
270:
271:
272:
273:
274:
275:
276:
277:
278:
279:
280:
281:
282:
283:
284:
285:
286:
287:
288:
289:
290:
291:
292:
293:
294:
295:
296:
297:
298:
299:
300:
301:
302:
303:
304:
305:
306:
307:
308:
309:
310:
311:
312:
313:
314:
315:
316:
317:
318:
319:
320:
321:
322:
323:
324:
325:
326:
327:
328:
329:
330:
331:
332:
333:
334:
335:
336:
337:
338:
339:
340:
341:
342:
343:
344:
345:
346:
347:
348:
349:
350:
351:
352:
353:
354:
355:
356:
357:
358:
359:
#!/usr/bin/perl
##############################################################################
#
# Port-Proxy, V 0.95 (C) 2004 Accordata GmbH,  Ralf Amandi
# Port-Proxy is Perl script to forward ports from the local system to another system.
# Ralf.Amandi@accordata.net
##############################################################################
use strict;
use IO::Socket;
use IO::Select;
use Getopt::Std;
use POSIX 'setsid';
#use Win32::Daemon;
 
#---- Configuration
my $configFile= './port-proxy.conf';
my $Version="0.96";
my $debug=0; #0,1,2
my $detach=0; # detach (unix only)
 
#-- options --
my %opts;
getopt('d:c:D',\%opts);
if (exists $opts{'d'}) { $debug=1; }
if (exists $opts{'c'}) { $configFile=$opts{'c'}; }
if (exists $opts{'D'}) { $detach=1; }
 
#---- Global Vars ---
my @allow_proxy_to=();
my $sock_list = new IO::Select(); # A list of sockets for the "select" function
my $socknr=0; # Counts socket
my %sock_params=();
my $lastsig;
# For each socket this hash contains an hash reference with socket parameters
# Params: type, remote_addr, proxy_addr, corresponding_sock, state
 
 
Main();
exit 0;
 
#---- Main  ----
# Read Config
# Check known sockets for aktion and handles Read/Connect requests
sub Main
{
    my (@ready,@canwrite,@haserror,$sock,$type,$state, $param,$val,$buff,$bufflen,$ok,$proxy_prot);
 
    #---- Banner ----
    print "Accordata GmbH - Port-Proxy V $Version\n";
    print "----------------------------------\n\n";
 
    #---- Setup Listen Ports; read config file ----
    ReadConfig();
    print "\n";
 
    $SIG{'HUP'}=\&sigHandler;	# ReRead Config File
    $SIG{'TERM'}=\&sigHandler;
    $SIG{'KILL'}=\&sigHandler;
    $SIG{'INT'}=\&sigHandler;
 
    if ($detach) { daemonize(); }
 
    #---- Listen loop ----
    while(1) {
	while($lastsig eq '') {
	    #-- write? (not used) --
#	    @canwrite = $sock_list->can_write(1);
#	    foreach $sock (@canwrite) {
#		$param=$sock_params{$sock};
#		if ($param->{'type'} ne 'L') { print "W ".$param->{'type'}." $sock\n"; 	}
#	    }
	    #-- read --
	    @ready = $sock_list->can_read(0.25);
	    foreach $sock (@ready) {
			$param=$sock_params{$sock};
			$type=$param->{'type'};
			$state=$param->{'state'};
			$proxy_prot=$param->{'proxy_prot'};
			if ($debug) { print "R $type ".$param->{'id'}." $state $sock\n"; }
			if ($type eq 'L') {	# Listen Socket
			    NewConnect($sock);
			} elsif ($state eq 'forward') { # Forward Data; used for type C,D,P
			    $bufflen=sysread($sock,$buff,4096);
			    if ($debug>=2) { print "[".length($buff)."]$buff\n"; }
			    if ($bufflen==0) {
				CloseSocket($sock);
			    } else {
				my $l=syswrite($param->{'corresponding_sock'},$buff);
				if ($l != $bufflen) { die "can't write all data\n"; }
			    }
			} else { # Read from socket an check Data
			    $bufflen=sysread($sock,$buff,4096);
			    if ($debug>=2) { print "[".length($buff)."]$buff\n"; }
			    if ($bufflen==0) {
				CloseSocket($sock);
				next;
			    }
			    $ok=0; $val=$buff;
			    # We asume, that all we need is in one read. This is a little bit dirty, but works for now.
			    if ($state eq 'readDestAddr') { # Except CONNECT xx.xx.xx.xx:yy..[CR/LF][CR/LF]
					if ($buff =~ /^CONNECT\s+(.+?)\r?\n\r?\n(.*)$/s) { # read to first cr/lf
					    $val=$1; $buff=$2; $val=~s/\s.*//g;
					    print "PROXY CONNECT TO: $val\n";
					    if (! check_dest_allowed($val) ) {
							syswrite($sock,"403 FORBIDDEN\n\n");
					    } elsif (remote_connect($sock,$val,1,$proxy_prot)) {
							syswrite($sock,"HTTP/1.0 200 OK\n\n");
							$ok=1; $state='forward';
					    }
					}
			    } elsif ($state  eq 'readProxyResponse') {
					if ($buff =~ /^(.*?)\r?\n\r?\n(.*)$/s) { # read to double cr/lf
					    $val=$1; $buff=$2;
					    if ($val =~ / 200 /) {
						$ok=1;
						if ($param->{'remote_addr'} ne '') { # now send the address to the 2nd proxy
						    syswrite($sock,"CONNECT ".$param->{'remote_addr'}." HTTP/1.0\n\n");
						    $param->{'remote_addr'}='';
						} else {
						    $state='forward';
						}
					    }
					}
			    }
			    if ($ok) {
				$param->{'state'}=$state; # set new state
				if (length($buff)>0) { syswrite($param->{'corresponding_sock'},$buff); } # forward rest of data
			    } else {
				print "ERR: $val\n";
				CloseSocket($sock);
			    }
			}
	    }
	    #-- errors? --
#	    @haserror = $sock_list->has_exception(0); # has_exception not supported on older perl version
#	    foreach $sock (@haserror) {
#		CloseSocket($sock);
#	    }
	}
	#-- Check sig --
	if ($lastsig eq 'HUP') {
	    print "Caught a SIG$lastsig\, restart\n";
	    foreach $sock ($sock_list->handles()) {
		if ($sock_params{$sock}->{'type'} eq 'L') { CloseSocket($sock); } # CLose listening socket
	    }
	    ReadConfig();
	    # On my Linux I detected problems, since the ports seems to be blocked after closing
	} else {
	    print "Caught a SIG$lastsig\, shutting down\n";
	    foreach $sock ($sock_list->handles()) {
		CloseSocket($sock);
	    }
	    exit(0);
	}
	$lastsig='';
    }
}
 
sub ReadConfig()
{
    my ($val, $line,@aval,$param);	
    @allow_proxy_to=();
    open(F,"<$configFile") || die "can't open file $configFile\n";
    while(<F>) {
	$line=$_;
	$line=~s/#.*$//g; # remove comments
	if ($debug) { print "Conf>$line"; }
	if ( $line=~/^\s*(.+?)=(.*?)\s*$/) {
	    $param=$1; $val=$2;
	    if ($param eq 'forward') {
		@aval=split(/ *, */,$val);
		print "Parameters: $aval[0]-$aval[1]-$aval[2]-$aval[3]-$aval[4]\n";
		CreateListenSock($aval[0],$aval[1],$aval[2],$aval[3],$aval[4]);
	    } elsif($param eq 'allow_proxy_to') {
		push(@allow_proxy_to,$val)
	    }
	}
    }
    close(F);
}
 
#---
# Handle some (unix) signals; HUP: restart with reading config; TERM/KILL: shut down
sub sigHandler($) # sigHandler(signame)
{
    my($sig) = @_;
    my ($sock,$param);
    if ($sig eq 'KILL') {
	die "Caught a SIG$sig, stop immediatly\n";
    } elsif ($sig eq $lastsig && $sig ne 'HUP') {
	die "Caught a SIG$$sig twice, stop immediatly\n";
    }
    $lastsig=$sig;
}
##############################################################################
# Socket Funktion 
##############################################################################
# Add a open socket to our structures ($sock_list,$sock_params); gives back params hash
sub AddSockList($$) # AddSockList($sock,$type):paramHashRef
{
    my ($sock,$type)=@_;
    my %params=('type',$type,'id',++$socknr);
    $sock_params{$sock}=\%params;
    $sock_list->add($sock);
    return \%params
}
 
#---
# Creates an Socket for listening and add it with all needed params to our structures
sub CreateListenSock ($$$) # CreateListeSock($local_addr,$remote_addr,$proxy_addr) :paramHashRef
{
    my($local_addr,$remote_addr,$proxy_prot,$proxy_addr,$proxy2_addr)=@_;
    print "Param2: $local_addr-$remote_addr-$proxy_addr-$proxy_prot-$proxy2_addr\n";
    my ($new_sock,$param);
    if ($local_addr =~ /:/) {	    
		$new_sock=new IO::Socket::INET(Listen => 5, LocalAddr => $local_addr, Proto => $proxy_prot) or die "Can't bind : $@\n";;
    } else {	    
		$new_sock=new IO::Socket::INET(Listen => 5, LocalPort => $local_addr, Proto => $proxy_prot) or die "Can't bind : $@\n";;
    }
    if (!$new_sock) { die "Error listening on port $local_addr ($proxy_prot)\n"; }
    $param=AddSockList($new_sock,'L');
    $param->{'remote_addr'}=$remote_addr; # host:port
    $param->{'proxy_addr'}=$proxy_addr; # host:port
    $param->{'proxy2_addr'}=$proxy2_addr; # host:port
    $param->{'proxy_prot'}=$proxy_prot; # host:port
    if ($proxy2_addr ne '') {
		print "Listen on $local_addr; forward via $proxy_addr via $proxy2_addr to $remote_addr ($proxy_prot)\n";
    } elsif ($proxy_addr ne '') {
		print "Listen on $local_addr; forward via proxy $proxy_addr to $remote_addr ($proxy_prot)\n";
    } else {
		print "Listen on $local_addr; forward to $remote_addr ($proxy_prot)\n";
    }
    return $param;
}
 
#---
# Close this and any corresponding socket; remove from sock_list and sock_params
sub CloseSocket($) # CloseSocket($sock):bool;
{
    my ($sock)=@_;
    if (! $sock) { return; }
    #-- Remove from sock_params and sock_list--
    my $param=$sock_params{$sock};
    if (! $param) { return; } # already closed
    if ($param->{'type'} eq 'C') {
	print "Closing connection from ".$sock->peerhost().':'.$sock->peerport().' to '.$sock->sockhost ().':'.$sock->sockport()."\n";
    }
    $sock_params{$sock}=undef;
    $sock_list->remove($sock);
    $sock->close();
    if ($debug) { print " close ".$param->{'type'}.' '.$param->{'id'}." $sock\n"; }
    #-- Close corresponding sockets --
    CloseSocket($param->{'corresponding_sock'});
    return 1;
}
 
#---
# Start an new connection established on ListenSock
sub NewConnect($) # NewConnect($ListenSock): Start an new Connection
{
    my ($listen_sock)=@_;
    my ($sock,$param);
    if (! $listen_sock) { return; }
    my $listen_param=$sock_params{$listen_sock};
 
    #-- Create New Socket; copy params --
    $sock=$listen_sock->accept;
    $param=AddSockList($sock,'C');
    $param->{'proxy_addr'}=$listen_param->{'proxy_addr'};
    $param->{'proxy2_addr'}=$listen_param->{'proxy2_addr'};
    $param->{'proxy_prot'}=$listen_param->{'proxy_prot'};
    print "New connection from ".$sock->peerhost().':'.$sock->peerport().' to '.$sock->sockhost ().':'.$sock->sockport()."\n";
 
    #-- Connect to remote --
    if ($listen_param->{'remote_addr'} eq '[PROXY]') { # Read destination from sock (act as proxy)
		$param->{'state'}='readDestAddr';
		return 1;
    } elsif (remote_connect($sock,$listen_param->{'remote_addr'},0,$param->{'proxy_prot'})) { # Connect direct or via proxy
		$param->{'state'}='forward';
		print "  established\n";
		return 1;
    } else {
		CloseSocket($sock);
		print "  aborted\n";
		return undef;
    }
}
 
#---
# Check if we proxy to the given address (The Address is send by the client if the Config Entry is [PROXY])
sub check_dest_allowed($)
{
    my ($addr)=@_;	
    my ($cmp);
    foreach $cmp (@allow_proxy_to) {
	if ($addr =~/^$cmp$/) {
		return 1;
	}
    }
    return 0;
}
#---
# connect directly to remote or via proxy; Called after connect (with CheckAddr=0) or after the client sends the destination (checkaddr=1)
sub remote_connect($$$$) # (src_sock,addr,checkaddr):bool
{
    my ($src_sock,$addr,$checkaddr,$proxy_prot)=@_;
    my $src_param=$sock_params{$src_sock};
    my ($corresponding_sock,$corresponding_param);
    if ($src_param->{'proxy2_addr'} ne '') {
	($corresponding_sock,$corresponding_param)=dest_connect($src_param->{'proxy_addr'},'P',$src_sock,$proxy_prot);
	if ($corresponding_sock) {
	    syswrite($corresponding_sock,"CONNECT ".$src_param->{'proxy2_addr'}." HTTP/1.0\n\n");
	    $corresponding_param->{'state'}='readProxyResponse';
	    $corresponding_param->{'remote_addr'}=$addr;
	}
    } elsif ($src_param->{'proxy_addr'} ne '') {
	($corresponding_sock,$corresponding_param)=dest_connect($src_param->{'proxy_addr'},'P',$src_sock,$proxy_prot);
	if ($corresponding_sock) {
	    print "  proxy connection established ask for connection to $addr\n";
	    syswrite($corresponding_sock,"CONNECT $addr HTTP/1.0\n\n");
	    $corresponding_param->{'state'}='readProxyResponse';
	}
    } else { #-- direct connection --
	($corresponding_sock,$corresponding_param)=dest_connect($addr,'D',$src_sock,$proxy_prot);
	$corresponding_param->{'state'}='forward';
    }
    #-- Return ok/nok
    return ($corresponding_sock != undef);
}
#---
# Connect to Destination or Proxy; Add Sock to our known socks with $type;
# Set Link Param (corresponding_sock) for  Destionation an Source socket
sub dest_connect($$$$) # dest_connect($addr,$type,$src_sock) returns ($sock,$params)
{
    my ($addr,$type,$src_sock,$proxy_prot)=@_;
    my $sock=IO::Socket::INET->new(PeerAddr=>$addr,proto=>,$proxy_prot);
    if (! $sock) { return undef; }
    my $param=AddSockList($sock,$type); # 'P'=Proxy', 'D'=Dest
    if ($src_sock) {
	$param->{'corresponding_sock'}=$src_sock;
	$sock_params{$src_sock}->{'corresponding_sock'}=$sock;
    }
    return ($sock,$param)
}
 
##############################################################################
# other funtions
##############################################################################
 
# Detach as daemon (function copied from perl doc)
sub daemonize {
#        chdir '/'               or die "Can't chdir to /: $!";
	open STDIN, '/dev/null' or die "Can't read /dev/null: $!";
	open STDOUT, '>/dev/null' or die "Can't write to /dev/null: $!";
	defined(my $pid = fork) or die "Can't fork: $!";
	exit if $pid;
        setsid                  or die "Can't start a new session: $!";
        open STDERR, '>&STDOUT' or die "Can't dup stdout: $!";
}
 
Loading Advertisement...
 
[+][-]09.18.2008 at 02:14PM PDT, ID: 22515561

View this solution now by starting your 30-day free trial. Setting up your free trial is quick, easy, and secure. We will return you to this solution, unlocked, when you're done.

 

About this solution

Zone: Perl Programming Language
Tags: Perl IO::Socket
Sign Up Now!
Solution Provided By: MadShiva
Participating Experts: 1
Solution Grade: A
 
 
 
Loading Advertisement...
20081112-EE-VQP-44 / EE_QW_2_20070628