1*da1b64c4Sbluhm# $OpenBSD: Tap.pm,v 1.1 2016/09/28 12:40:35 bluhm Exp $ 2*da1b64c4Sbluhm 3*da1b64c4Sbluhm# Copyright (c) 2014 Alexander Bluhm <bluhm@openbsd.org> 4*da1b64c4Sbluhm# 5*da1b64c4Sbluhm# Permission to use, copy, modify, and distribute this software for any 6*da1b64c4Sbluhm# purpose with or without fee is hereby granted, provided that the above 7*da1b64c4Sbluhm# copyright notice and this permission notice appear in all copies. 8*da1b64c4Sbluhm# 9*da1b64c4Sbluhm# THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 10*da1b64c4Sbluhm# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 11*da1b64c4Sbluhm# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 12*da1b64c4Sbluhm# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 13*da1b64c4Sbluhm# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 14*da1b64c4Sbluhm# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 15*da1b64c4Sbluhm# OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 16*da1b64c4Sbluhm 17*da1b64c4Sbluhm# Encapsulate tap interface handling into separate module. 18*da1b64c4Sbluhm 19*da1b64c4Sbluhmuse strict; 20*da1b64c4Sbluhmuse warnings; 21*da1b64c4Sbluhm 22*da1b64c4Sbluhmpackage Tap; 23*da1b64c4Sbluhmuse parent 'Exporter'; 24*da1b64c4Sbluhmour @EXPORT_OK = qw(opentap); 25*da1b64c4Sbluhm 26*da1b64c4Sbluhmuse Carp; 27*da1b64c4Sbluhmuse Fcntl; 28*da1b64c4Sbluhmuse File::Basename; 29*da1b64c4Sbluhmuse POSIX qw(_exit); 30*da1b64c4Sbluhmuse PassFd 'recvfd'; 31*da1b64c4Sbluhmuse Socket; 32*da1b64c4Sbluhm 33*da1b64c4Sbluhmsub opentap { 34*da1b64c4Sbluhm my ($tap_number) = @_; 35*da1b64c4Sbluhm my $tap_device = "/dev/tap$tap_number"; 36*da1b64c4Sbluhm 37*da1b64c4Sbluhm if ($> == 0) { 38*da1b64c4Sbluhm sysopen(my $tap, $tap_device, O_RDWR) 39*da1b64c4Sbluhm or croak "Open $tap_device failed: $!"; 40*da1b64c4Sbluhm return $tap; 41*da1b64c4Sbluhm } 42*da1b64c4Sbluhm 43*da1b64c4Sbluhm if (!$ENV{SUDO}) { 44*da1b64c4Sbluhm die "To open the device $tap_device you must run as root or\n". 45*da1b64c4Sbluhm "set the SUDO environment variable and allow closefrom_override.\n"; 46*da1b64c4Sbluhm } 47*da1b64c4Sbluhm 48*da1b64c4Sbluhm my $opentap; 49*da1b64c4Sbluhm my $curdir = dirname($0) || "."; 50*da1b64c4Sbluhm if (-x "$curdir/opentap") { 51*da1b64c4Sbluhm $opentap = "$curdir/opentap"; 52*da1b64c4Sbluhm } elsif (-x "./opentap") { 53*da1b64c4Sbluhm $opentap = "./opentap"; 54*da1b64c4Sbluhm } else { 55*da1b64c4Sbluhm die "To open the device $tap_device the tool opentap is needed.\n". 56*da1b64c4Sbluhm "Executable opentap not found in $curdir or current directory.\n"; 57*da1b64c4Sbluhm } 58*da1b64c4Sbluhm 59*da1b64c4Sbluhm socketpair(my $parent, my $child, AF_UNIX, SOCK_STREAM, PF_UNSPEC) 60*da1b64c4Sbluhm or croak "Socketpair failed: $!"; 61*da1b64c4Sbluhm $child->fcntl(F_SETFD, 0) 62*da1b64c4Sbluhm or croak "Fcntl setfd failed: $!"; 63*da1b64c4Sbluhm 64*da1b64c4Sbluhm defined(my $pid = fork()) 65*da1b64c4Sbluhm or croak "Fork failed: $!"; 66*da1b64c4Sbluhm 67*da1b64c4Sbluhm unless ($pid) { 68*da1b64c4Sbluhm # child process 69*da1b64c4Sbluhm close($parent) or do { 70*da1b64c4Sbluhm warn "Close parent socket failed: $!"; 71*da1b64c4Sbluhm _exit(3); 72*da1b64c4Sbluhm }; 73*da1b64c4Sbluhm my @cmd = ($ENV{SUDO}, '-C', $child->fileno()+1, $opentap, 74*da1b64c4Sbluhm $child->fileno(), $tap_number); 75*da1b64c4Sbluhm exec(@cmd); 76*da1b64c4Sbluhm warn "Exec '@cmd' failed: $!"; 77*da1b64c4Sbluhm _exit(3); 78*da1b64c4Sbluhm } 79*da1b64c4Sbluhm 80*da1b64c4Sbluhm # parent process 81*da1b64c4Sbluhm close($child) 82*da1b64c4Sbluhm or croak "Close child socket failed: $!"; 83*da1b64c4Sbluhm my $tap = recvfd($parent) 84*da1b64c4Sbluhm or croak "Recvfd failed: $!"; 85*da1b64c4Sbluhm wait() 86*da1b64c4Sbluhm or croak "Wait failed: $!"; 87*da1b64c4Sbluhm $? == 0 88*da1b64c4Sbluhm or croak "Child process failed: $?"; 89*da1b64c4Sbluhm 90*da1b64c4Sbluhm return $tap; 91*da1b64c4Sbluhm} 92*da1b64c4Sbluhm 93*da1b64c4Sbluhm1; 94