App-ReslirpTunnel
view release on metacpan or search on metacpan
lib/App/ReslirpTunnel/ElevatedSlave.pm view on Meta::CPAN
use constant IFF_TAP => 0x0002;
use constant IFF_NO_PI => 0x1000;
sub _create_tap {
my ($self, $tap_device) = @_;
$self->_log(debug => "Opening device $tap_device");
sysopen(my $tap_fd, "/dev/net/tun", O_RDWR) or $self->_die("Cannot open /dev/net/tun", $!);
my $ifr = pack("Z16 s", $tap_device, IFF_TAP | IFF_NO_PI);
ioctl($tap_fd, TUNSETIFF, $ifr) or $self->_die("ioctl TUNSETIFF failed", $!);
return $tap_fd;
}
sub _create_tap__rpc {
my ($self, $request) = @_;
my $tap_device = $request->{device} or $self->_die("Device name is required");
my $tap_fd = $self->_create_tap($tap_device);
{status => "ok", fd => $tap_fd }
}
sub _do_system {
my $self = shift;
$self->_log(debug => "Running command", "@_");
if (system(@_) == 0) {
return { status => "ok" };
}
$self->_die("Command @_ failed", "rc=".($? >> 8));
}
sub _screen_reset__rpc { shift->_do_system("reset") }
sub _device_up__rpc {
my ($self, $request) = @_;
my $tap_device = $request->{device};
$self->_do_system("ip", "link", "set", "dev", $tap_device, "up");
}
sub _device_addr_add__rpc {
my ($self, $request) = @_;
my $tap_device = $request->{device};
my $addr = $request->{addr};
my $mask = $request->{mask};
$self->_do_system("ip", "addr", "add", "$addr/$mask", "dev", $tap_device);
}
sub _start_dnsmasq__rpc {
my ($self, $request) = @_;
my $mapping = $request->{net_mapping};
my $forward = $request->{forward_dns};
my $user = $request->{user} // 'nobody';
my $group = $request->{group} // 'nogroup';
my $pid_fn = $request->{pid_fn} // '';
my $log_fn = $request->{log_fn};
my @args = ('dnsmasq',
'--pid-file='.$pid_fn,
'--log-facility='.$log_fn,
'--user='.$user,
'--group='.$group,
'--no-hosts',
'--no-resolv',
'--bind-interfaces',
'--except-interface=lo',
'--log-queries',
'--server=',
'--no-dhcp-interface=*');
for my $domain (keys %$mapping) {
push @args, "--address=/$domain/$_" for @{$mapping->{$domain}};
}
for my $domain (keys %$forward) {
push @args, "--server=/$domain/$_" for @{$forward->{$domain}};
}
my $r = $self->_do_system(@args);
# Wait for the pid file to appear
for (1..100) {
if (open my $fh, '<', $pid_fn) {
my $line = <$fh>;
if ($line =~ /^(\d+)\n/) {
return { %$r, pid => $1 }
}
}
select (undef, undef, undef, 0.1);
}
$self->_die("Failed to start dnsmasq, cannot read PID file at $pid_fn");
}
sub _resolvectl_domain__rpc {
my ($self, $request) = @_;
my $tap_device = $request->{device};
my $domain = $request->{domain};
$self->_do_system("resolvectl", "domain", $tap_device, "~$domain");
}
sub _resolvectl_dns__rpc {
my ($self, $request) = @_;
my $tap_device = $request->{device};
my $dns = $request->{dns};
$self->_do_system("resolvectl", "dns", $tap_device, $dns);
}
sub _route_add__rpc {
my ($self, $request) = @_;
my $tap_device = $request->{device};
my $net = $request->{net};
my $gw = $request->{gw};
$self->_do_system("ip", "route", "add", $net, "via", $gw, "dev", $tap_device);
}
sub _bye__rpc {
return { status => "bye" }
}
sub _hello__rpc {
return { status => "ok" }
}
sub _run {
( run in 0.833 second using v1.01-cache-2.11-cpan-2398b32b56e )