App-ReslirpTunnel
view release on metacpan or search on metacpan
lib/App/ReslirpTunnel.pm view on Meta::CPAN
my $self = { args => \%args };
bless $self, $class;
return $self;
}
sub go {
my $self = shift;
eval {
$self->_init_xdg;
$self->_init_time;
$self->_init_logger;
$self->_log(info => "Starting ReslirpTunnel");
$self->_set_signal_handlers;
$self->_init_config;
$self->_init_butler;
$self->_init_ssh;
$self->_send_to_background;
$self->_init_tap_device;
$self->_init_reslirp;
$self->_init_loop;
$self->_config_forward_dns;
$self->_config_net_mappings;
$self->_init_dnsmasq;
$self->_init_resolver_rules;
$self->_init_routes;
$self->_wait_for_something;
$self->_log(info => "Terminating ReslirpTunnel");
};
if ($@) {
die "Something went wrong: $@\n";
}
$self->_kill_everything;
}
sub _init_xdg {
my $self = shift;
my $app_name = $self->{args}{app_name} or die "App name missing, unable to initialize XDG helper";
$self->{xdg} = File::XDG->new(name => $app_name, path_class => 'Path::Tiny');
}
sub _init_time {
my $self = shift;
$self->{timestamp} = POSIX::strftime("%Y%m%dT%H%M%SZ", gmtime);
}
sub _init_logger {
my $self = shift;
my $level = $self->{args}{log_level};
my $log_to_stderr = $self->{args}{log_to_stderr};
my $fn = $self->{args}{log_file};
unless (defined $fn) {
my $parent_dir = $self->{xdg}->state_home->child('logs')->mkdir;
$fn = $parent_dir->child($self->{timestamp}.".reslirp-tunnel.log");
eval {
my $sl = $parent_dir->child('latest.reslirp-tunnel.log');
unlink $sl if -l $sl;
symlink $fn, $sl;
};
}
$self->SUPER::_init_logger(log_level => $level, log_to_stderr => $log_to_stderr, log_file => $fn);
}
sub _set_signal_handlers {
my $self = shift;
my $signal_count = 0;
$self->{signal_count_ref} = \$signal_count;
$self->{signal_handler} = sub {
$signal_count++;
$self->_log(info => "Signal received, count: $signal_count");
};
$SIG{INT} = $self->{signal_handler};
$SIG{TERM} = $self->{signal_handler};
}
sub _init_config {
my $self = shift;
my $args = $self->{args};
$self->{run_in_foreground} = $args->{run_in_foreground} // 0;
$self->{dont_close_stdio} = $args->{dont_close_stdio} // 0;
$self->{ssh_host} = $args->{ssh_host};
$self->{ssh_port} = $args->{ssh_port};
$self->{ssh_user} = $args->{ssh_user};
$self->{remote_network} = $args->{remote_network} // '10.0.2.0';
is_ipv4($self->{remote_network}) or $self->_die("Invalid remote network address, $self->{remote_network}");
$self->{remote_netmask} = $self->_parse_netmask($args->{remote_netmask} // 24);
$self->{remote_dns} = $self->_parse_ip($args->{remote_dns});
$self->{remote_gw} = $self->_parse_ip($args->{remote_gw});
$self->{local_ip} = $self->_parse_ip($args->{local_ip});
}
sub _parse_netmask {
my ($self, $netmask) = @_;
($netmask =~ /^\d+$/ && $netmask >= 1 && $netmask <= 31) or $self->_die("Invalid netmask", $netmask);
return $netmask;
}
sub _parse_ip {
my ($self, $ip) = @_;
my $network = $self->{remote_network};
my $netmask = $self->{remote_netmask};
if ($ip =~ /^\d+$/) {
$ip = $network =~ s/\d+$/$ip/r;
}
is_ipv4($ip) or $self->_die("Invalid IP address", $ip);
my $ip_int = __ip_to_int($ip);
my $net_int = __ip_to_int($network);
my $bitmask = ~0 << (32 - $netmask);
unless (($ip_int & $bitmask) == ($ip_int & $bitmask)) {
$self->_die("IP address $ip is not inside remote network $network/$netmask");
}
return $ip;
}
( run in 2.458 seconds using v1.01-cache-2.11-cpan-b301d465b3d )