Beefy Boxes and Bandwidth Generously Provided by pair Networks Russ
Perl Monk, Perl Meditation
 
PerlMonks  

golf challenge: one-liner netcat clone

by salva (Monsignor)
on Dec 10, 2011 at 19:31 UTC ( #942861=perlquestion: print w/ replies, xml ) Need Help??
salva has asked for the wisdom of the Perl Monks concerning the following question:

Dear Monks,

I am working on Net::OpenSSH::Gateway, a Net::OpenSSH extension that allows this module to cross through proxies and SSH gateways.

As part of it, I have written a Perl one-liner that is a netcat clone, but this one-liner is bigger than I wish, so I would like to get your help in order to reduce its length.

You can improve on the current version or rewrite it from scratch, I don't mind as long as it is able to run an SSH session on top of it (using ProxyCommand, see ssh_config) and exit when any side of the connection closes. It should only use core modules and be able to run on older Perls.

Here is the current one-liner:

perl -MFcntl=F_SETFL,F_GETFL,O_NONBLOCK -MSocket '-e$0=perl;socket($c, +AF_INET,SOCK_STREAM,0)&&connect($c,sockaddr_in$ARGV[1],inet_aton$ARGV +[0])||die$!;fcntl$_,F_SETFL,O_NONBLOCK|fcntl$_,F_GETFL,0 for@d=(*STDI +N,$c),@e=($c,*STDOUT);L:for(0,1){sysread($d[$_],$f,8**5)||exit and$f[ +$_].=$f if vec$g,$_*($h=fileno$c),1;substr$f[$_],0,syswrite($e[$_],$f +[$_],8**5),"";vec($g,$_*$h,1)=($i=length$f[$_]<8**5);vec($j,$_||$h,1) +=!!$i}select$g,$j,$k,5;goto L' perlmonks.org 80

It is automatically generated from this more readable version:

$0=perl; socket($socket, AF_INET, SOCK_STREAM, 0) && connect($socket, sockaddr_in PORT, inet_aton "SERVER") || die $!; fcntl $_, F_SETFL, O_NONBLOCK|fcntl $_, F_GETFL, 0 for @in = (*STDIN, +$socket), @out = ($socket, *STDOUT); L: for (0, 1) { sysread ($in[$_], $buffer, 8**5) || exit and $buffer[$_] .= $buffe +r if vec $iv, $_ * ($socket_fileno = fileno $socket), 1; substr $buffer[$_], 0, syswrite($out[$_], $buffer[$_], 8**5), ""; vec($iv, $_ * $socket_fileno, 1) = ($l = length $buffer[$_] < 8**5 +); vec($ov, $_ || $socket_fileno, 1) = !!$l; } select $iv, $ov, $u, 5; goto L

Comment on golf challenge: one-liner netcat clone
Select or Download Code
Re: golf challenge: one-liner netcat clone
by cavac (Chaplain) on Dec 10, 2011 at 22:08 UTC

    Here's what i use to tunnel VNC sessions. Maybe it'll help. I'm not really a fan of one-liners, so i'll leave it in a readable form ;-)

    use POE; use POE::Filter::Stream; use POE::Filter::Line; use POE::Component::Proxy::TCP; $|++; POE::Component::Proxy::TCP->new (Alias => "ProxyServerSessionAlias", Port => $ARGV[1], OrigPort => $ARGV[2], OrigAddress => $ARGV[0], RemoteClientFilter => "POE::Filter::Stream", RemoteServerOutputFilter => "POE::Filter::Stream", RemoteServerInputFilter => "POE::Filter::Stream" ); $poe_kernel->run(); exit 0;

    Note: I don't fully understand the code (or more precise the workings of the POE:: stuff), i just copied it from various examples and modified it until it more or less worked. I *know* one shouldn't do that, but i was in a bit of hurry... And YES, it lacks strict and warnings. You wanted small code, right?

    Don't use '#ff0000':
    use Acme::AutoColor; my $redcolor = RED();
    All colors subject to change without notice.
Re: golf challenge: one-liner netcat clone
by ikegami (Pope) on Dec 10, 2011 at 22:24 UTC

    I don't see a check to see how much can be written without blocking. You can have a write in one direction blocking writes in the other direction, which can lead to a deadlock.

    As for golfing, this bit:

    139: socket($c,AF_INET,SOCK_STREAM,0)&&connect($c,sockaddr_in$ARGV[1], +inet_aton$ARGV[0])||die$!;fcntl$_,F_SETFL,O_NONBLOCK|fcntl$_,F_GETFL, +0 for

    (whose only space is not needed) can be reduced to:

    100: -MIO::Socket::INET $c=IO::Socket::INET->new(PeerHost=>"$ARGV[0]:$ +ARGV[1]")||die$!;$_->blocking(0)for

    By the way, if you hardcoded the host and port, you could save a bunch more.

    Update:

    99: -MIO::Socket::INET $c=IO::Socket::INET->new(PeerHost,"$ARGV[0]:$A +RGV[1]")||die$!;$_->blocking(0)for 95: -MIO::Socket::INET $c=new IO::Socket::INET PeerHost,"$ARGV[0]:$AR +GV[1]"or die$!;blocking$_ 0for 85: -MIO::Socket::INET $c=new IO::Socket::INET"$ARGV[0]:$ARGV[1]"or d +ie$!;blocking$_ 0for
      $_->blocking(0) for *STDIN dies with a Can't call method "blocking" without a package or object reference

      On Linux, setting the sockets and pipes to non-blocking doesn't seem to be required at all, but I am not sure it other Unixes will perform the same.

        Did you load the module as I did? (Although you don't even need to do that with 5.14)

        I take back my comment about write-blocking ("I don't see a check to see how much can be written without blocking"). I forgot to factor in that non-blocking applies to writing too.

        So you don't have a problem with syswrite, but you do have a problem with sysread. If the sysread would block, it'll return undef, and your program will exit prematurely.

        On Linux, setting the sockets and pipes to non-blocking doesn't seem to be required at all, but I am not sure it other Unixes will perform the same.

        Nonsense. Imagine if the remote end does

        print while <>;

        If you try reading from the socket, your program will become permanently blocked.

Log In?
Username:
Password:

What's my password?
Create A New User
Node Status?
node history
Node Type: perlquestion [id://942861]
Approved by keszler
help
Chatterbox?
and the web crawler heard nothing...

How do I use this? | Other CB clients
Other Users?
Others studying the Monastery: (7)
As of 2014-04-18 03:23 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    April first is:







    Results (460 votes), past polls