Re: LWP and LocalIP/LocalPort
by sauoq (Abbot) on Oct 16, 2002 at 03:09 UTC
|
Something along those lines should work. The only issue I can see is that, when making a request, specifying the local IP makes sense but specifying the port doesn't. I would try it with a value of simply '1.2.3.4'. Assuming, of course, that 1.2.3.4 is really an IP on your box which is visible by the server you want to reach.
-sauoq
"My two cents aren't worth a dime.";
| [reply] |
Re: LWP and LocalIP/LocalPort
by rob_au (Abbot) on Oct 16, 2002 at 13:27 UTC
|
This is actually really easy to achieve and I'm surprised that this solution hasn't been forwarded already ...
@LWP::Protocol::http::EXTRA_SOCK_OPTS = ( LocalAddr => '1.2.3.4', Loca
+lPort => '8080' );
These parameters are passed to the IO::Socket::INET class which is created within the LWP::Protocol::http object that is used to fetch HTTP pages. From this module ...
local($^W) = 0; # IO::Socket::INET can be noisy
my $sock = $self->socket_class->new(PeerAddr => $host,
PeerPort => $port,
Proto => 'tcp',
Timeout => $timeout,
KeepAlive => !!$conn_cache,
SendTE => 1,
$self->_extra_sock_opts($host, $po
+rt),
);
This allows for any of the default options of the IO::Socket::INET class to be re-defined as required.
perl -e 'print+unpack("N",pack("B32","00000000000000000000000111010001")),"\n"' | [reply] [d/l] [select] |
|
| [reply] [d/l] |
Re: LWP and LocalIP/LocalPort
by jj808 (Hermit) on Oct 16, 2002 at 03:09 UTC
|
I'm not sure why you want to set the local port as well as the local IP address. Most services (although RSH is a notable exception) do not take any notice of the local port number, so you should be able to use whatever port is assigned by your OS when the socket is created.
In this case I suspect that your machine already has a server running on port 8080. If the port is already taken, the OS will not let you use it for an outgoing connection.
If you want to connect from a specified local IP to a server that is running on port 8080, set the Local IP with
@LWP::Protocol::http::EXTRA_SOCK_OPTS = ( LocalAddr => '1.2.3.4' );
Then set the destination port as part of the URL you are retrieving, e.g. http://hostname:8080/index.html
JJ | [reply] [d/l] |
|
The Short Answer:
The reason I want to set the local port as well is so the outgoing connection is predictable and filterable.
The Long Answer:
I've got a web server with MovableType running on it. One of the functions that MT performs is to send XML 'pings' or update notices to external web servers. This server and the firewall in front of it have both ingress and egress filtering in place. In other words, the web server is not allowed to contact stuff on the internet all by it's lonesome in case of virus/rootkit infection.
Now there is the quandry. I can't let this machine contact *:80 on the internet. That defeats the purpose of the egress filtering. But, if I can lock it down (kind of like Bind's query-source option) to a predictable IP/port, I can allow the software out, but other *:80 requests form the machine will still be blocked.
I could install tinyproxy in this machine to proxy those requests, but that's overkill when I should be able to specify the LocalIP/LocalPort in LWP.
| [reply] |
|
I can see what you're trying to achieve, but by restricting the outgoing port there will always be a potential for failure.
Say for example your outgoing connection for the XML 'pings' was set to always use port 50000 (and it was working :-). You do not have control over the ports that incoming connections to your MT server will be using (i.e. the local ports on computers browsing your site), so there is a chance that an incoming connection could be using port 50000 at the same time as MT was trying to open an outgoing socket. Your XML 'ping' would fail.
Would it be secure enough to make a list of the IP addresses you need to XML 'ping' and then allow connections from any local ports (in the range 1024-65535) to port 80 on the specific IP addresses, e.g. 10.0.0.1:80, 10.0.0.2:80 etc? Then your OS can still allocate outgoing port numbers in the usual manner.
JJ
| [reply] |
|
Re: LWP and LocalIP/LocalPort
by jj808 (Hermit) on Oct 16, 2002 at 16:06 UTC
|
This problem's starting to bug me now ;-)
So I've done some tests.
- Specify the local port as part of the LocalAddr parameter ('1.2.3.4:8080')
Set something listening on a port:
perl -mHTTP::Daemon -e '$d=new HTTP::Daemon(LocalPort=>12345);while ($
+c=$d->accept){sleep 10;$c->send_file_response("index.html")}'
Try to connect to it:
perl -e 'use LWP::Simple;@LWP::Protocol::http::EXTRA_SOCK_OPTS = (Loca
+lAddr=>"localhost:54321");get("http://localhost:12345")'
Check netstat -a
tcp 71 0 mondas:12345 mondas:51575 ES
+TABLISHED
So we can use a string in the form 'x.x.x.x:port' with LocalAddr
- Two processes trying to use the same outgoing port number
http://jonallen.info/cgi/delay.pl will wait 10 seconds, then print "Hello, World!" (to give me time to run netstat and set up processes on different machines).
We know now that specifying an local port number works. What would happen if, under high load, your server tried to send several XML 'pings' at once?
[jj@mondas jj]$ perl -le 'use LWP::Simple;@LWP::Protocol::http::EXTRA_
+SOCK_OPTS = (LocalAddr=>"192.168.1.1:54321");getprint("http://jonalle
+n.info/cgi/delay.pl");'
Hello, World!
At the same time, try to access a different remote server using the same local port
[jj@mondas jj]$ perl -e 'use LWP::Simple;@LWP::Protocol::http::EXTRA_S
+OCK_OPTS = (LocalAddr=>"192.168.1.1:54321");getprint("http://www.goog
+le.com");'
500 Can't connect to www.google.com:80 (Cannot assign requested addres
+s)
<URL:http://www.google.com>
So if you are going to restrict the outgoing port numbers, be aware that in some conditions the local port you need will be in use. If you *really* need to do this, set up a range of ports and have your program try to use each one in turn and only fail if they are all in use.
- Using the same port number on different aliased IP addresses
Machine has 192.168.1.10 aliased to 192.168.1.1
[root@mondas log]# ifconfig
eth0 Link encap:Ethernet HWaddr 52:54:05:C5:13:7A
inet addr:192.168.1.1 Bcast:192.168.1.255 Mask:255.255.255
+.0
EtherTalk Phase 2 addr:65280/97
UP BROADCAST RUNNING MULTICAST MTU:1500 Metric:1
RX packets:27996973 errors:0 dropped:2 overruns:0 frame:6
TX packets:32099772 errors:484 dropped:0 overruns:0 carrier:
+968
collisions:146707
RX bytes:3038904039 (2898.1 Mb) TX bytes:4085277291 (3896.0
+ Mb)
eth0:0 Link encap:Ethernet HWaddr 52:54:05:C5:13:7A
inet addr:192.168.1.10 Bcast:192.168.1.255 Mask:255.255.25
+5.0
UP BROADCAST RUNNING MULTICAST MTU:1500 Metric:1
lo Link encap:Local Loopback
inet addr:127.0.0.1 Mask:255.0.0.0
EtherTalk Phase 2 addr:0/0
UP LOOPBACK RUNNING MTU:16436 Metric:1
RX packets:17172 errors:0 dropped:0 overruns:0 frame:0
TX packets:17172 errors:0 dropped:0 overruns:0 carrier:0
collisions:0
RX bytes:4381193 (4.1 Mb) TX bytes:4381193 (4.1 Mb)
Start Apache as an unprivileged user (will bind to port 8080).
[jj@mondas jj]$ perl -e 'use LWP::Simple;@LWP::Protocol::http::EXTRA_S
+OCK_OPTS = (LocalAddr=>"192.168.1.1:8080");getprint("http://jonallen.
+info/cgi/delay.pl");'
500 Can't connect to jonallen.info:80 (Address already in use) <URL:ht
+tp://jonallen.info/cgi/delay.pl>
[jj@mondas jj]$ perl -e 'use LWP::Simple;@LWP::Protocol::http::EXTRA_S
+OCK_OPTS = (LocalAddr=>"192.168.1.10:8080");getprint("http://jonallen
+.info/cgi/delay.pl");'
500 Can't connect to jonallen.info:80 (Address already in use) <URL:ht
+tp://jonallen.info/cgi/delay.pl>
You can of course use the Listen and BindAddress directives in httpd.conf to force Apache to use only a certain IP alias. However the default configuration will bind to every IP address, so it is worth checking with netstat that nothing else is using the local port that you want to use.
- Using the same port number for incoming & outgoing connections
Start the HTTP::Daemon one-liner (on 192.168.1.1). From another computer, connect to this daemon with a local port of 11111
perl -e 'use LWP::Simple;@LWP::Protocol::http::EXTRA_SOCK_OPTS = (Loca
+lAddr=>"192.168.1.8:11111");getprint("http://192.168.1.1:12345");'
Then (at the same time) from the machine running HTTP::Daemon, try to use the local port 11111:
perl -e 'use LWP::Simple;@LWP::Protocol::http::EXTRA_SOCK_OPTS = (Loca
+lAddr=>"192.168.1.1:11111");getprint("http://jonallen.info/cgi/delay.
+pl");'
Check netstat on 192.168.1.1
tcp 0 0 mondas.coldsoluti:11111 212.69.202.117:http ES
+TABLISHED
tcp 73 0 mondas.coldsoluti:12345 lclus1.coldsoluti:11111 ES
+TABLISHED
So incoming connections do not restrict what ports you can use for outgoing connections.
This leads me to the conclusion that your code is fine, and as long as nothing else is listening on port 8080, it should work. Note however that if you try these sort of examples over the Internet, caches and proxies run by ISPs will change the local port numbers. So if machine 'A' opens a connection with a destination address of machine 'B' and a local port '22222', you cannot guarantee that when machine 'B' accepts the connection the remote port will be '22222'.
I would suggest that you disable your firewall (at least for outgoing connections), try your code again, and use netstat to find out exactly what it is doing.
JJ | [reply] [d/l] [select] |
|
Just for giggles, what Perl version and LWP version are you running?
Updated: Color me stupid, but in the first example you specify the clients local port as 54321, but the netstat shows
tcp 71 0 mondas:12345 mondas:51575 ES
+TABLISHED
51575 instead of 54321 ? What am I missing?
| [reply] [d/l] |
|
That would mean I cut & pasted the wrong netstat print.
perl -e 'for(1..100){print "I must check my posts before clicking Subm
+it\n";}'
Have you tried removing the firewall and getting netstat prints?
I am using Perl 5.6.1 and LWP version 5.65.
JJ | [reply] [d/l] |
|