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