Beefy Boxes and Bandwidth Generously Provided by pair Networks
We don't bite newbies here... much
 
PerlMonks  

Socket Traffic Cop

by sans-clue (Beadle)
on Apr 12, 2010 at 17:52 UTC ( [id://834326]=perlquestion: print w/replies, xml ) Need Help??

sans-clue has asked for the wisdom of the Perl Monks concerning the following question:

I am not asking for code (yet), but is it feasible to have a perl socket listener on one single tcp port that then redirects the socket feed after examining the ip address to another listener on the same box ? I have multiple Tandem event feeds that can only connect to one single global ip and port combination, yet each of the 5 Tandem feeds needs to go to its own listening port (process) on this linux box. It sounds just like a firewall sort of function, but it doesn't have to be secure. Thanks

Replies are listed 'Best First'.
Re: Socket Traffic Cop
by zwon (Abbot) on Apr 12, 2010 at 18:15 UTC

    Yes, that's possible. Upd: and actually quite trivial, have a look on IO::Select

      Great, so how would I determine remote IP address before I call spawn_client_side ? as below where the ????? are. Thanks
      #!/usr/bin/perl use warnings; use strict; use POE qw(Component::Server::TCP Component::Client::TCP); # Spawn the forwarder server on port 1110. When new connections # arrive, spawn clients to connect them to their destination. POE::Component::Server::TCP->new( Port => 1110, ClientConnected => sub { my ($heap, $session) = @_[HEAP, SESSION]; logevent('server got connection', $session); # How to determine remote ip address ????? # if ($remote_ip =~ /^10\.10\.10\.1$/) { # $port = 7077 ; } spawn_client_side($port); }, ClientInput => sub { my ($kernel, $session, $heap, $input) = @_[KERNEL, SESSION, HEAP, +ARG0]; logevent('server got input', $session, $input); $kernel->post($heap->{client_id} => send_stuff => $input); }, ClientDisconnected => sub { my ($kernel, $session, $heap) = @_[KERNEL, SESSION, HEAP]; logevent('server got disconnect', $session); $kernel->post($heap->{client_id} => "shutdown"); }, InlineStates => { send_stuff => sub { my ($heap, $stuff) = @_[HEAP, ARG0]; logevent("sending to server", $_[SESSION]); $heap->{client}->put($stuff); }, _child => sub { my ($heap, $child_op, $child) = @_[HEAP, ARG0, ARG1]; if ($child_op eq "create") { $heap->{client_id} = $child->ID; } }, }, ); sub spawn_client_side { my ($oporto) = @_; POE::Component::Client::TCP->new( RemoteAddress => 'localhost', RemotePort => $oporto, Started => sub { $_[HEAP]->{server_id} = $_[SENDER]->ID; }, Connected => sub { my ($heap, $session) = @_[HEAP, SESSION]; logevent('client connected', $session); }, ServerInput => sub { my ($kernel, $heap, $session, $input) = @_[KERNEL, HEAP, SESSION +, ARG0]; logevent('client got input', $session, $input); $kernel->post($heap->{server_id} => send_stuff => $input); }, Disconnected => sub { my ($kernel, $heap, $session) = @_[KERNEL, HEAP, SESSION]; logevent('client disconnected', $session); $kernel->post($heap->{server_id} => 'shutdown'); }, InlineStates => { send_stuff => sub { my ($heap, $stuff) = @_[HEAP, ARG0]; logevent("sending to client", $_[SESSION]); $heap->{server}->put($stuff); }, }, ); } sub logevent { my ($state, $session, $arg) = @_; my $id = $session->ID(); print "session $id $state "; print ": $arg" if (defined $arg); print "\n"; } warn 'running'; $poe_kernel->run(); exit 0;
        How to determine remote ip address

        See peerhost() — in case POE::Component::Server::TCP is based on IO::Socket::INET, that is...

        Update: just checked the docs, and there's remote_ip, which seems to be what you want.

Re: Socket Traffic Cop
by BrowserUk (Patriarch) on Apr 12, 2010 at 22:59 UTC
    is it feasible to have a perl socket listener on one single tcp port that then redirects the socket feed after examining the ip address to another listener on the same box ?

    It doesn't make much sense to do that at the level of a Perl script. Once the remote client connects, it won't, in the absence of some pre-existing protocol, reconnect to another listener. All you could do is have your server connect to the other local listeners and then act as go-between (proxy), forwarding each inbound packet and getting any responses and sending them back to the remote system.

    It won't make any future connects (seperate or concurrent) from that remote system go directly to the other local listener. They'll still come through the original listener. Each having to connect to a new instance of the other local listener and relay through. You'd just be creating lots of middleman processes that do nothing but create a bottleneck.

    Once a remote client connects to your listener, all you need is to hand off the accepted socket to the right piece of code--be that a process or thread--dependent upon the remote IP of the inbound connection. And that's very easy, far less costly, and far less fragile.


    Examine what is said, not who speaks -- Silence betokens consent -- Love the truth but pardon error.
    "Science is about questioning the status quo. Questioning authority".
    In the absence of evidence, opinion is indistinguishable from prejudice.
      That is an astute observation. In fact I tried that, but the said 'right piece of code' works correctly only with one connection, when I hand that same code the socket connection from the multi connection version, it doesn't work correctly.
      I think I will have to use an F5 appliance to do this unfortunately. Thanks

        Hm I have no idea what an "F5 appliance" is. But, I'd love to understand what you mean by:

        but the said 'right piece of code' works correctly only with one connection, when I hand that same code the socket connection from the multi connection version, it doesn't work correctly.

        The socket returned from accept, will only be connected to one client at any given time. It could come from any of the five client machines. Discovering which machine (ip address) it comes from is easy. So routing each incoming client connection to a thread that is dedicated to dealing with that connection should be very easy.

        Ostensibly:

        sub client1 { my $fno = shift; open my $client, '+<&', $fno or die; while( <$client> { if( /... / { print $client ...; } elsif( /.../ ) { print $client ...; else { print $client ...; } } } sub client2 { ... } sub client3 { ... } sub client4 { ... } sub client5 { ... } my %lookup = ( 'xxx.xxx.xxx.xxx' => \&client1, 'yyy.yyy.yyy.yyy' => \&client2, ... ); my $lsn = IO::Socket::INET->new( Listen => 5, LocalPort => $port ); while( my $client = $lst->accept ) { my $addr = $client->peerhost; thread->create( $lookup{ $addr }, fileno( $client ) )->detach; }

        And that's pretty much it. Each client (type/machine/whatever) gets a dedicate thread that talks to it and only it. That thread runs a simple conversation dedicated to that clients needs. Even concurrent clients from a given machine get a thread dedicated to just that conversation.

        No complicated, state machine mixing concerns of listening for clients; accepting input and sending output all together in a spaghetti nightmare of global variables and transient states. But, people seem to like complicated.

        POE is extraordinarily clever code. Trouble is, it seems to require extraordinary programmers to use it. And if one them has coded a wheel that does exactly what you need to do, and you can find it, and understand the documentation, then you can hire it and you're set to go.

        But need something slightly different to what's available and you're in the lap of the gods awaiting yet another distribution tailored to your exact needs.


        Examine what is said, not who speaks -- Silence betokens consent -- Love the truth but pardon error.
        "Science is about questioning the status quo. Questioning authority".
        In the absence of evidence, opinion is indistinguishable from prejudice.
Re: Socket Traffic Cop
by Crackers2 (Parson) on Apr 12, 2010 at 19:52 UTC

    Assuming you're on linux, I'd recommend skipping perl and using iptables to take care of this.

    iptables -A PREROUTING -i <interface> -s <sourceip> -p tcp -m tcp --dp +ort <port> -j REDIRECT --to-ports <newport>

    There's also an option to specify a source network instead of a single IP.

      Turns out to be solaris... they won't let me install POE. Could you give me any tips on how to install a localized (to my home dir) perl dist for solaris ? I see that many modules POE requires are not in the prod perl dist that I can't touch.
      I might be able to use a linux box to do this and route the solaris ports, thanks for the tip.

        Did you read the INSTALL file, and the platform specific readme file?

Re: Socket Traffic Cop
by jonadab (Parson) on Apr 12, 2010 at 18:40 UTC
    it doesn't have to be secure

    This sequence of words frightens me. Just saying.

Log In?
Username:
Password:

What's my password?
Create A New User
Domain Nodelet?
Node Status?
node history
Node Type: perlquestion [id://834326]
Approved by Corion
Front-paged by ww
help
Chatterbox?
and the web crawler heard nothing...

How do I use this?Last hourOther CB clients
Other Users?
Others about the Monastery: (3)
As of 2024-04-19 05:03 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    No recent polls found