Commit 309c9768 authored by Francesc Guasch's avatar Francesc Guasch
Browse files

[#51] drop other and use iptables from pause/resume

parent c284bf82
......@@ -835,6 +835,22 @@ sub _cmd_resume {
}
sub _cmd_open_iptables {
my $self = shift;
my $request = shift;
my $uid = $request->args('uid');
my $user = Ravada::Auth::SQL->search_by_id($uid);
my $domain = $self->search_domain_by_id($request->args('id_domain'));
die "Unknown domain" if !$domain;
$domain->open_iptables(
remote_ip => $request->args('remote_ip')
,uid => $user->id
);
}
sub _cmd_start {
my $self = shift;
my $request = shift;
......@@ -952,6 +968,7 @@ sub _req_method {
,remove_base => \&_cmd_remove_base
,ping_backend => \&_cmd_ping_backend
,prepare_base => \&_cmd_prepare_base
,open_iptables => \&_cmd_open_iptables
,list_vm_types => \&_cmd_list_vm_types
);
return $methods{$cmd};
......
......@@ -724,7 +724,7 @@ sub _remove_iptables {
my $args = {@_};
my $ipt_obj = _open_iptables();
my $ipt_obj = _obj_iptables();
my $sth = $$CONNECTOR->dbh->prepare(
"UPDATE iptables SET time_deleted=?"
......@@ -777,13 +777,13 @@ sub _add_iptable {
my $remote_ip = $args{remote_ip} or return;
my $owner = Ravada::Auth::SQL->search_by_id($self->id_owner);
my $user = $args{user};
my $uid = $user->id;
my $display = $self->display($owner);
my $display = $self->display($user);
my ($local_ip, $local_port) = $display =~ m{\w+://(.*):(\d+)};
my $ipt_obj = _open_iptables();
my $ipt_obj = _obj_iptables();
# append rule at the end of the RAVADA chain in the filter table to
# allow all traffic from $local_ip to $remote_ip via port $local_port
#
......@@ -801,11 +801,35 @@ sub _add_iptable {
($rv, $out_ar, $errs_ar) = $ipt_obj->append_ip_rule(@iptables_arg);
$self->_log_iptable(iptables => \@iptables_arg, @_);
$self->_log_iptable(iptables => \@iptables_arg, %args);
}
sub _open_iptables {
=head2 open_iptables
Open iptables for a remote client
=over
=item user
=item remote_ip
=back
=cut
sub open_iptables {
my $self = shift;
my %args = @_;
my $user = Ravada::Auth::SQL->search_by_id($args{uid});
$args{user} = $user;
delete $args{uid};
$self->_add_iptable(%args);
}
sub _obj_iptables {
my %opts = (
'use_ipv6' => 0, # can set to 1 to force ip6tables usage
......@@ -849,9 +873,16 @@ sub _log_iptable {
return;
}
my %args = @_;
lock_hash(%args);
my $remote_ip = $args{remote_ip};#~ or return;
my $user = $args{user};
my $uid = $args{uid};
confess "Chyoose wehter uid or user "
if $user && $uid;
lock_hash(%args);
$uid = $args{user}->id if !$uid;
my $iptables = $args{iptables};
my $sth = $$CONNECTOR->dbh->prepare(
......@@ -859,7 +890,7 @@ sub _log_iptable {
."(id_domain, id_user, remote_ip, time_req, iptables)"
."VALUES(?, ?, ?, ?, ?)"
);
$sth->execute($self->id, $user->id, $remote_ip, Ravada::Utils::now()
$sth->execute($self->id, $uid, $remote_ip, Ravada::Utils::now()
,encode_json($iptables));
$sth->finish;
......
......@@ -24,7 +24,7 @@ our %FIELD_RO = map { $_ => 1 } qw(id name);
our $args_manage = { name => 1 , uid => 1 };
our $args_prepare = { id_domain => 1 , uid => 1 };
our $args_remove_base = { domain => 1 , uid => 1 };
our $args_manage_ip = {%$args_manage, remote_ip => 1};
our $args_manage_iptables = {uid => 1, id_domain => 1, remote_ip => 1};
our %VALID_ARG = (
create_domain => {
......@@ -38,7 +38,7 @@ our %VALID_ARG = (
,disk => 2
,network => 2
}
,open_iptables => $args_manage_ip
,open_iptables => $args_manage_iptables
,remove_base => $args_remove_base
,prepare_base => $args_prepare
,pause_domain => $args_manage
......@@ -637,6 +637,27 @@ sub screenshot_domain {
}
=head2 open_iptables
Request to open iptables for a remote client
=cut
sub open_iptables {
my $proto = shift;
my $class=ref($proto) || $proto;
my $args = _check_args('open_iptables', @_ );
my $self = {};
bless($self,$class);
return $self->_new_request(
command => 'open_iptables'
, id_domain => $args->{id_domain}
, args => encode_json($args));
}
sub AUTOLOAD {
my $self = shift;
......
......@@ -642,8 +642,9 @@ sub show_link {
return access_denied($c) if $USER->id != $domain->id_owner && !$USER->is_admin;
my $req;
if ( !$domain->is_active ) {
my $req = Ravada::Request->start_domain(
$req = Ravada::Request->start_domain(
uid => $USER->id
,name => $domain->name
,remote_ip => _remote_ip($c)
......@@ -659,7 +660,9 @@ sub show_link {
if !$req->status eq 'done';
}
if ( $domain->is_paused) {
my $req = Ravada::Request->resume_domain(name => $domain->name, uid => $USER->id);
$req = Ravada::Request->resume_domain(name => $domain->name, uid => $USER->id
, remote_ip => _remote_ip($c)
);
$RAVADA->wait_request($req);
warn "ERROR: ".$req->error if $req->error();
......@@ -678,10 +681,24 @@ sub show_link {
$c->render(template => 'fail', name => $domain->name);
return;
}
_open_iptables($c,$domain)
if !$req;
$c->render(template => 'bootstrap/run', url => $uri , name => $domain->name
,login => $c->session('login'));
}
sub _open_iptables {
my ($c, $domain) = @_;
my $req = Ravada::Request->open_iptables(
uid => $USER->id
,id_domain => $domain->id
,remote_ip => _remote_ip($c)
);
$RAVADA->wait_request($req);
return $c->render(data => 'ERROR opening domain for '._remote_ip($c)." ".$req->error)
if $req->error;
}
sub check_back_running {
#TODO;
......
use warnings;
use strict;
use Data::Dumper;
use JSON::XS;
use Test::More;
use Test::SQL::Data;
use IPTables::ChainMgr;
use lib 't/lib';
use Test::Ravada;
my $test = Test::SQL::Data->new(config => 't/etc/sql.conf');
use_ok('Ravada');
use_ok('Ravada::Request');
my $FILE_CONFIG = 't/etc/ravada.conf';
my @ARG_RVD = ( config => $FILE_CONFIG, connector => $test->connector);
my %ARG_CREATE_DOM = (
KVM => [ id_iso => 1 ]
,Void => [ ]
);
init($test->connector, $FILE_CONFIG);
my $USER = create_user("foo","bar");
my $CHAIN = 'RAVADA';
##########################################################
sub test_create_domain {
my $vm_name = shift;
my $ravada = Ravada->new(@ARG_RVD);
my $vm = $ravada->search_vm($vm_name);
ok($vm,"I can't find VM $vm_name") or return;
my $name = new_domain_name();
if (!$ARG_CREATE_DOM{$vm_name}) {
diag("VM $vm_name should be defined at \%ARG_CREATE_DOM");
return;
}
my @arg_create = @{$ARG_CREATE_DOM{$vm_name}};
my $domain;
eval { $domain = $vm->create_domain(name => $name
, id_owner => $USER->id
, @{$ARG_CREATE_DOM{$vm_name}})
};
ok($domain,"No domain $name created with ".ref($vm)." ".($@ or '')) or exit;
ok($domain->name
&& $domain->name eq $name,"Expecting domain name '$name' , got "
.($domain->name or '<UNDEF>')
." for VM $vm_name"
);
return $domain->name;
}
sub test_fw_domain{
my ($vm_name, $domain_name) = @_;
my $remote_ip = '99.88.77.66';
my $local_ip;
my $local_port;
my $domain_id;
{
my $vm = rvd_back->search_vm($vm_name);
my $domain = $vm->search_domain($domain_name);
ok($domain,"Searching for domain $domain_name") or return;
$domain->start( user => $USER, remote_ip => $remote_ip);
my $display = $domain->display($USER);
($local_port) = $display =~ m{\d+\.\d+\.\d+\.\d+\:(\d+)};
$local_ip = $vm->ip;
ok(defined $local_port, "Expecting a port in display '$display'") or return;
ok($domain->is_active);
my $ipt = open_ipt();
$ipt->flush_chain('filter', $CHAIN);
test_chain($vm_name, $local_ip,$local_port, $remote_ip, 0);
$domain_id = $domain->id;
}
{
my $req = Ravada::Request->open_iptables(
uid => $USER->id
,id_domain => $domain_id
,remote_ip => $remote_ip
);
ok($req);
ok($req->status);
rvd_back->process_requests();
wait_request($req);
is($req->status,'done');
is($req->error,'');
test_chain($vm_name, $local_ip,$local_port, $remote_ip, 1);
}
}
sub open_ipt {
my %opts = (
'use_ipv6' => 0, # can set to 1 to force ip6tables usage
'ipt_rules_file' => '', # optional file path from
# which to read iptables rules
'iptout' => '/tmp/iptables.out',
'ipterr' => '/tmp/iptables.err',
'debug' => 0,
'verbose' => 0,
### advanced options
'ipt_alarm' => 5, ### max seconds to wait for iptables execution.
'ipt_exec_style' => 'waitpid', ### can be 'waitpid',
### 'system', or 'popen'.
'ipt_exec_sleep' => 1, ### add in time delay between execution of
### iptables commands (default is 0).
);
my $ipt_obj = IPTables::ChainMgr->new(%opts)
or die "[*] Could not acquire IPTables::ChainMgr object";
}
sub test_chain {
my $vm_name = shift;
my ($local_ip, $local_port, $remote_ip, $enabled) = @_;
my $ipt = open_ipt();
my ($rule_num , $chain_rules)
= $ipt->find_ip_rule($remote_ip, $local_ip,'filter', $CHAIN, 'ACCEPT'
, {normalize => 1 , d_port => $local_port });
ok($rule_num,"[$vm_name] Expecting rule for $remote_ip -> $local_ip: $local_port")
if $enabled;
ok(!$rule_num,"[$vm_name] Expecting no rule for $remote_ip -> $local_ip: $local_port"
.", got $rule_num ")
if !$enabled;
}
sub flush_rules {
my $ipt = open_ipt();
$ipt->flush_chain('filter', $CHAIN);
$ipt->delete_chain('filter', 'INPUT', $CHAIN);
}
#######################################################
remove_old_domains();
remove_old_disks();
#TODO: dump current chain and restore in the end
# maybe ($rv, $out_ar, $errs_ar) = $ipt_obj->run_ipt_cmd('/sbin/iptables
# -t filter -v -n -L RAVADA');
for my $vm_name (qw( Void KVM )) {
diag("Testing $vm_name VM");
my $CLASS= "Ravada::VM::$vm_name";
use_ok($CLASS) or next;
my $vm_ok;
eval {
my $vm = rvd_back->search_vm($vm_name);
$vm_ok=1 if $vm;
};
SKIP: {
#TODO: find out if this system has iptables
my $msg = "SKIPPED test: No $vm_name VM found ";
diag($msg) if !$vm_ok;
skip $msg,10 if !$vm_ok;
flush_rules();
my $domain_name = test_create_domain($vm_name);
test_fw_domain($vm_name, $domain_name);
};
}
flush_rules();
remove_old_domains();
remove_old_disks();
done_testing();
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment