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

Alright Monks?

I am trying to write a script that will listen on a specified port, accepting connections only from listed IP's, and accept/run commands.

For example, i could telnet/use another script to connect to the server running this script on port 12345, pass a command such as 'touch blah' followed by another command such as 'touch mooo', and those commands would be run on the remote machine.

The code i have so far is here:
#!/usr/bin/perl use Socket; $SOMAXCONN=2; socket(SERVER, AF_INET, SOCK_STREAM, getprotobyname('tcp')) || die "ca +nt create socket $!"; setsockopt(SERVER,SOL_SOCKET,SO_REUSEADDR,1) || warn "cant make socket + reusable\n"; bind(SERVER, sockaddr_in(8850, INADDR_ANY)) || die "cant bind IP to so +cket $!";; listen(SERVER, SOMAXCONN) || die "cant listen on port $!";; print "server PID $$ is listening\n"; while(){ $REMOT_ADDR=accept(CLIENT, SERVER); # after connection ($R_port,$R_addr)=sockaddr_in($REMOT_ADDR); $R_addr=inet_ntoa($R_addr); print "connection from $R_addr on $R_port\n"; }
Can anybody help me on this one?

Replies are listed 'Best First'.
Re: Sockets, And Running Commands.
by tos (Deacon) on Jun 28, 2003 at 16:08 UTC
    Hi,

    another more perlish way and perhaps of academic interest could be this using the IO::socket-modul

    recip is listening on homer ...

    tos@homer ~/tos/tmp # cat recip #!/usr/bin/perl use strict; use warnings; use IO::Socket; my $socket=new IO::Socket::INET (LocalPort => 1960, Proto => 'tcp', Listen => 5, Reuse => 1, ); die "could'nt create socket: $!" unless $socket; while (my $new_socket = $socket->accept()) { while (defined (my $buf = <$new_socket>)) { print $buf; $buf =~ /^ls/ && do { system ("ls") }; } } close ($socket);
    ... while sndr ...
    tos@VRANZ /cygdrive/t/tos/tmp # cat sndr #!/usr/bin/perl use strict; use warnings; use IO::Socket; my $socket=new IO::Socket::INET (PeerAddr => 'homer', PeerPort => 1960, Proto => 'tcp' ); die "couldn't create socket: $!" unless $socket; foreach (1..3) { print $socket "message $_\n"; $socket->flush(); } print $socket "ls\n"; $socket->flush(); close ($socket);
    ... sends some messages from VRANZ ...
    tos@VRANZ /cygdrive/t/tos/tmp # perl sndr tos@VRANZ /cygdrive/t/tos/tmp #
    recip receives the messages, dumps them and proceeds the "ls"-cmd
    tos@homer ~/tos/tmp # perl recip message 1 message 2 message 3 ls recip sndr sndr~ x
    Be aware that this code is merely as secure as ftp and telnet are. For secure connections i can imagine that there is something to find at CPAN. Otherwise use the former recommended ssh-utilities.

    greetings, tos

Re: Sockets, And Running Commands.
by zentara (Cardinal) on Jun 29, 2003 at 13:48 UTC
    Have you looked at Net::EasyTCP ? It has encrypted connections, and is quite easy to use. Someone awhile back critisized me for saying it's secure, because the password was sent in the clear; but I recently tested it on my machine, and the password was never sent in the clear. One other thing, it automatically chooses encryption algorithm, to find a compatible one when the client connects. It will default to Crypt::Rsa which is very slow. Either comment it out of the EasyTCP.pm or don't install it, and it will use Rijandael,which is very fast. It also uses a port password.
    Here is a sample client-server: SERVER: #!/usr/bin/perl use Net::EasyTCP; $server = new Net::EasyTCP( host => "localhost", mode => "server", port => 2345, password => "ztest", donotcompress => 1, # donotencrypt => 1, welcome => "Hi! Wecome to the test server!\n", ) || die "ERROR CREATING SERVER: $@\n"; $server->setcallback( data => \&gotdata, connect => \&connected, disconnect => \&disconnected, ) || die "ERROR SETTING CALLBACKS: $@\n"; $server->start() || die "ERROR STARTING SERVER: $@\n"; #################################################### sub gotdata() { my $client = shift; my $serial = $client->serial(); my $data = $client->data(); print "Client $serial sent me some data, sending it right back to them + again\n"; $client->send($data) || die "ERROR SENDING TO CLIENT: $@\n"; if ($data eq "QUIT") { $client->close() || die "ERROR CLOSING CLIENT: $@\n"; } elsif ($data eq "DIE") { $server->stop() || die "ERROR STOPPING SERVER: $@\n"; } } ##################################################### sub connected() { my $client = shift; my $serial = $client->serial(); print "Client $serial just connected\n"; } ################################################### sub disconnected() { my $client = shift; my $serial = $client->serial(); print "Client $serial just disconnected\n"; } __END__ CLIENT: #!/usr/bin/perl use Net::EasyTCP; $client = new Net::EasyTCP( mode => "client", host => 'localhost', port => 2345, password => ztest ) || die "ERROR CREATING CLIENT: $@\n"; #Send and receive a simple string $client->send("HELLO THERE") || die "ERROR SENDING: $@\n"; $reply = $client->receive() || die "ERROR RECEIVING: $@\n"; print "$reply\n"; #Send and receive complex objects/strings/arrays/hashes by reference #%hash = ("to be or" => "not to be" , "just another" => "perl hacker") +; #$client->send(\%hash) || die "ERROR SENDING: $@\n"; #$reply = $client->receive() || die "ERROR RECEIVING: $@\n"; #foreach (keys %{$reply}) { #print "Received key: $_ = $reply->{$_}\n"; #} #Send and receive large binary data #for (1..4096) { #for (0..255) { #$largedata .= chr($_); #} #} #$client->send($largedata) || die "ERROR SENDING: $@\n"; #$reply = $client->receive() || die "ERROR RECEIVING: $@\n"; #$client->close(); $client->send('Hello from Joe') || die "ERROR SENDING: $@\n"; $reply = $client->receive() || die "ERROR RECEIVING: $@\n"; print "$reply\n"; while(1){ $input = <STDIN>; $client->send($input) || die "ERROR SENDING: $@\n"; $reply = $client->receive() || die "ERROR RECEIVING: $@\n"; print "$reply\n"; } __END__
Re: Sockets, And Running Commands.
by ctilmes (Vicar) on Jun 28, 2003 at 14:18 UTC
    Try "ssh".
      won't that be just as complex? Plus my server needs a keyfile in order to ssh in.
        No, it won't be just as complex. Keyfile creation is dead simple anyway, just use the ssh-keygen command to generate a key and copy it to the remote host's ~/.ssh/authorized_keys2 file. Obviously running this as root is ill advised. If it's necessary for root to implement the file on the remote, you can do something like run a pickup script from cron on the remote that checks for a new file periodically.

        ~~
        naChoZ