http://www.perlmonks.org?node_id=1223251


in reply to Client-Server app

Hello,

I finally switched to POE, It works great for what I need and today I was working in a script with SSL support and works great. Here is the code

#!/usr/bin/perl use warnings; use strict; use POE qw(Component::Server::TCP); use POE::Component::SSLify qw(Server_SSLify SSLify_Options); my @allowed_ips = ('127.0.0.1', '172.16.0.17', '172.16.0.1', '172.1 +6.0.225'); my $listen_address = '172.16.0.224'; my $listen_port = '1337'; my $listen_conns = '-1'; my $listen_alias = 'rc-listener'; my $output = '/home/projects/perl/rc-listener/unknown-commands +.txt'; my $ssl = 1; my $ssl_certfile = '/home/projects/perl/rc-listener/cert.crt'; my $ssl_keyfile = '/home/projects/perl/rc-listener/cert.key'; my $ssl_version = 'default'; POE::Component::Server::TCP->new( # Listen options Address => $listen_address, Port => $listen_port, Concurrency => $listen_conns, Alias => $listen_alias, # Server handlers Error => \&handle_server_error, Started => \&handle_server_started, Stopped => \&handle_server_stopped, # Client handlers ClientPreConnect => \&handle_client_pre_connect, ClientConnected => \&handle_client_connect, ClientDisconnected => \&handle_client_disconnect, ClientInput => \&handle_client_input, ClientError => \&handle_client_error, ClientFlushed => \&handle_client_flushed, ); # Start the server. POE::Kernel->run(); exit 0; sub handle_client_pre_connect { my ($session, $heap, $socket) = @_[SESSION, HEAP, ARG0]; my $session_id = $session->ID; my $remote_ip = $heap->{remote_ip}; my $remote_port = $heap->{remote_port}; my $remote = "[${remote_ip}]:${remote_port}"; unless (client_allowed($remote_ip)){ warn "ERROR > Connection from ${remote} with Session-ID ${sess +ion_id} denied by IP Policy.\n"; return undef; } if($ssl){ eval { SSLify_Options($ssl_keyfile, $ssl_certfile, $ssl_versio +n) }; if($@){ warn "ERROR > Server unable to load key or certificate fil +e.\n"; return undef; } my $ssl_socket = eval { Server_SSLify($socket) }; if($@){ warn "ERROR > Server unable to make an SSL connection.\n"; return undef; } return $ssl_socket; } else { return $socket; } } sub handle_client_connect { my ($session, $heap, $input) = @_[SESSION, HEAP, ARG0]; my $session_id = $session->ID; my $client = $heap->{client}; my $remote_ip = $heap->{remote_ip}; my $remote_port = $heap->{remote_port}; my $remote = "[${remote_ip}]:${remote_port}"; $client->put("Welcome ${remote} your Session-ID is ${session_id}") +; $client->put("Type 'help' for a complete list of accepted commands +"); warn "WARN > Client ${remote} connected with Session-ID ${session +_id}\n"; } sub handle_client_disconnect { my ($session, $heap, $input) = @_[SESSION, HEAP, ARG0]; my $session_id = $session->ID; my $client = $heap->{client}; my $remote_ip = $heap->{remote_ip}; my $remote_port = $heap->{remote_port}; my $remote = "[${remote_ip}]:${remote_port}"; warn "WARN > Client ${remote} with Session-ID ${session_id} disco +nnected\n"; } sub handle_client_input { my ($session, $heap, $input) = @_[SESSION, HEAP, ARG0]; my $session_id = $session->ID; my $client = $heap->{client}; my $remote_ip = $heap->{remote_ip}; my $remote_port = $heap->{remote_port}; my $remote = "[${remote_ip}]:${remote_port}"; if ($input eq "quit") { $client->put("Goodbye ${remote}"); $_[KERNEL]->yield("shutdown"); return; } if ($input eq "ping") { $client->put("pong"); return; } if ($input eq "whoami") { $client->put("Your IP Address is ${remote_ip}"); $client->put("Your port is ${remote_port}"); return; } if ($input eq "help") { $client->put("Really? C'mon, just type something!"); return; } open(my $fh, '>>', $output) or die "Could not open file '$output' +$!"; print $fh "${input}\n"; #$heap->{client}->put("Received input: ".$input); warn "WARN > Client ${remote} Session-ID ${session_id}: ${input}\ +n"; } sub handle_client_error { my ($syscall_name, $err_num, $err_str) = @_[ARG0..ARG2]; warn "ERROR > Client: ${err_num} - ${err_str}\n"; } sub handle_client_flushed { my ($session, $heap, $input) = @_[SESSION, HEAP, ARG0]; my $session_id = $session->ID; my $client = $heap->{client}; my $remote_ip = $heap->{remote_ip}; my $remote_port = $heap->{remote_port}; my $remote = "[${remote_ip}]:${remote_port}"; warn "INFO > Client ${remote} flushed\n"; } sub handle_server_started { warn "INFO > Server [${listen_address}]:${listen_port} started\n" +; } sub handle_server_stopped { warn "INFO > Server [".$listen_address."]:".$listen_port." stoppe +d\n"; } sub handle_server_error { my ($syscall_name, $err_num, $err_str) = @_[ARG0..ARG2]; warn "ERROR > Server: ${err_num} - ${err_str}\n"; } sub client_allowed { my $client_ip = shift; return grep { $_ eq $client_ip || $_ eq '0/0' || $_ eq '0.0.0.0/0' + } @allowed_ips; }

It's working like I want, obviusly still need a lot of work but hey, for now it's working pretty good

Now the next thing I want is to make some authentication mechanism, any hint?

What I was thinking is to save a plain text "database" or a postgresql table with a relation of ip address and token and match each IP address with the token

The database connector and checks it's not the big deal here, what I need is some type of auth in the connect handle or something to not be very database intensive, for example I'm thinking to load the entire table to an array on load the listener and make it "static" and refresh the array every 30 seconds with a subroutine or something

Really this is the "thing" I don't know how to do, what I'm trying to do is to make some bolean variable with the session-id and after first check insert it into the array and on each read/write from the client check it with the array

I'm near to the answer or anyone have another mechanism to achieve this?

Thanks for all, I really appreciate all the comments