navarro has asked for the wisdom of the Perl Monks concerning the following question:

Hi Monks, i hope you are all right! This is my first question so please pardon me if it is execess newbie. I`m trying to code a client/server remote administrator with some functions like port knocking and etc.. but one special situation i have a problem. I make server connect to my client to avoid firewall configurations and it connects right but when i try to do my commands only the first one is executed, take a look:
----- # ./client.pl Connection estabilished from: Source IP-> 127.0.0.1 Source port-> 32894 command> uname Linux -----
And then it is freeze. I know that server is ok becouse when i use netcat as client everythings goes nice, here is a piece of client`s code:
sub listen() { $local = IO::Socket::INET->new(Listen=>1, Proto=>'tcp', LocalAddr=>'eth0', LocalPort=>5000, ReuseAddr=>1,) or die "$!"; $local->autoflush(1); $addr_handle = $local->accept(); $remotehost = $addr_handle->peerhost ; $remoteport = $addr_handle->peerport ; print "Connection estabilished from:\nSource IP-> $remotehost\nSource +port-> $remoteport\n"; print "command> "; while(defined ($comm = <STDIN>)) { print $addr_handle $comm; while(<$addr_handle>) { print STDOUT $_ } print "command> "; } }
Any help would be nice. Happy new year!

Replies are listed 'Best First'.
Re: Socket hangs
by salva (Canon) on Dec 23, 2005 at 12:51 UTC
    your scripts hangs here:
    while(<$addr_handle>) {
    because it keeps trying to read until the EOF is reached, but this only happens if the remote server closes the connection.

    To read (or write) from sockets without blocking you have to use sysread, syswrite and select. Any good book about Unix or Network programing explains how to do it (usually in C, but in Perl it's almost the same), Stein's "Network Programing with Perl" is also a good book. And I am sure there are also several tutorials online.

      Thnks for pointing this out for me Salva, but i still have same problem:
      # ./client.pl Command> uname Linux
      Here is the code after sugested changes:
      sub listen() { $local = IO::Socket::INET->new(Listen=>1, Proto=>'tcp', LocalAddr=>'eth0', LocalPort=>5000, ReuseAddr=>1,) or die "$!"; $local->autoflush(1); $sel = new IO::Select($local); while(@ready = $sel->can_read) { print "Command> "; foreach $fh (@ready) { if($fh == $local) { # Create a new socket $new = $local->accept; $sel->add($new); $comm = <STDIN>; print $new $comm; sub closeback() {exit(0)} while(sysread($new,$buffer,1024)) { print $buffer } } } } }
      It`s still freezing, what is wrong? Thank you!
Re: Socket hangs
by mikeock (Hermit) on Dec 23, 2005 at 16:25 UTC
    Whenever I do a socket connection I loop through the socket. You can send a shutdown($local, 1) to read all of the info.

    From the camel book: This is used to close only your side of the connection, so that the remote gets an end of file, but you can still read data coming from the server.

      Well, i tryed to use shutdown() but i`ve got same behavior but in other hand i could make it work but still have some small problems, take a look:
      # ./client.pl Connected from: 127.0.0.1:33703 Command> >uname Linux Command> id nobody uid=99(nobody) gid=99(nogroup) groups=99(nogroup),98(nobody) Command>
      That is ok, but in some commands (i dont know why) i can execute them sucessfully and them i`ve freeze again, look:
      Command> touch test
      And look what happens if i use ";" followed by some other command:
      Command> touch test ; ls client.pl client.pl~ salvo.pl server.pl server.pl~ test Command>
      Here is the code:
      sub listen() { $local = IO::Socket::INET->new(Listen=>1, Proto=>'tcp', LocalAddr=>'eth0' LocalPort=>5000, ReuseAddr=>1,) or die "$!"; $local->autoflush(1); $addr = $local->accept(); $remotehost = $addr->peerhost ; $remoteport = $addr->peerport ; print "Connected from: $remotehost:$remoteport\n"; print "Command> "; while($comm = <STDIN>) { print $addr $comm; sub closeback() {exit(0)} while(sysread($addr,$buffer,1024)) { print $buffer; last; } print "Command> "; } }
      Any tip? thanks.

        First of all, navarro, what behaviour are you looking for? Your first version accepts a single connection from the server and expects to see a sequence of multiple commands being received over it, the second changes to one new socket accept per command, and the last one reverts to behaviour that is almost like the first one except that it has an additional bug (see below). Which one are you looking for?

        If you want to receive multiple commands one after another over the same socket, then the client (the side that executes the command) will have to use some kind of scheme to mark the end of the results of that command so that the server knows to stop reading output and send a new command. You expressly do not want to use shutdown for the purpose in this case because you want the socket to stay open bidirectionally for the next command. In this case you should look at how some of the common internet protocols like SMTP do it: schemes like dot stuffing. Any kind of quoting scheme will do if the command output can contain arbitrary data, and if the command output cannot contain arbitrary data, then some marker that consists of impossible data for the command will do. When you receive this marker, you would exit from the read loop (it doesn't matter whether it's read or sysread). Your most recent example does not do this properly: it exits from the while loop (via last) after the first sysread unconditionally (you may as well have not had a loop there). You may or may not have finished collecting all of the output from the command at that point!

        If, on the other hand, you want to accept only one command per socket and open a new socket for the next command, then it becomes easier. The client end (which you have not shown code for) should shutdown the socket after it has finished sending the command output and the server will then see an EOF in its read loop. This is analogous to what FTP does with its dedicated data TCP connection for each data transfer.

        More importantly than any of this, you should seriously consider how secure all of this is! You have already noticed how you can send multiple commands by seperating them with a semicolon, which I guess means you are passing the commands to a shell on the client side, but even if you were not doing that, your client program appears to be a "please crack me" client. It connects to a server that is not required to authenticated itself, via an unprotected channel, and proceeds to execute any arbitrary command that comes over that socket. Are you sure you want to do this?

        I have never gotton the sysread to function properly on a socket. All of the implementations that I have use the shutdown command.

        That is why I recomed the shutdown($socketname, 1) to return the data.

        My only experience with sockets is when i connect send a command dissconnect and then reconenct for another command.

Re: Socket hangs
by Anonymous Monk on Dec 23, 2005 at 12:23 UTC
    Who hangs, server or client? Where is the code that hangs?