github.com/SagerNet/gvisor@v0.0.0-20210707092255-7731c139d75c/pkg/tcpip/link/tun/tun_unsafe.go (about)

     1  // Copyright 2018 The gVisor Authors.
     2  //
     3  // Licensed under the Apache License, Version 2.0 (the "License");
     4  // you may not use this file except in compliance with the License.
     5  // You may obtain a copy of the License at
     6  //
     7  //     http://www.apache.org/licenses/LICENSE-2.0
     8  //
     9  // Unless required by applicable law or agreed to in writing, software
    10  // distributed under the License is distributed on an "AS IS" BASIS,
    11  // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    12  // See the License for the specific language governing permissions and
    13  // limitations under the License.
    14  
    15  // +build linux
    16  
    17  // Package tun contains methods to open TAP and TUN devices.
    18  package tun
    19  
    20  import (
    21  	"unsafe"
    22  
    23  	"golang.org/x/sys/unix"
    24  )
    25  
    26  // Open opens the specified TUN device, sets it to non-blocking mode, and
    27  // returns its file descriptor.
    28  func Open(name string) (int, error) {
    29  	return open(name, unix.IFF_TUN|unix.IFF_NO_PI)
    30  }
    31  
    32  // OpenTAP opens the specified TAP device, sets it to non-blocking mode, and
    33  // returns its file descriptor.
    34  func OpenTAP(name string) (int, error) {
    35  	return open(name, unix.IFF_TAP|unix.IFF_NO_PI)
    36  }
    37  
    38  func open(name string, flags uint16) (int, error) {
    39  	fd, err := unix.Open("/dev/net/tun", unix.O_RDWR, 0)
    40  	if err != nil {
    41  		return -1, err
    42  	}
    43  
    44  	var ifr struct {
    45  		name  [16]byte
    46  		flags uint16
    47  		_     [22]byte
    48  	}
    49  
    50  	copy(ifr.name[:], name)
    51  	ifr.flags = flags
    52  	_, _, errno := unix.Syscall(unix.SYS_IOCTL, uintptr(fd), unix.TUNSETIFF, uintptr(unsafe.Pointer(&ifr)))
    53  	if errno != 0 {
    54  		unix.Close(fd)
    55  		return -1, errno
    56  	}
    57  
    58  	if err = unix.SetNonblock(fd, true); err != nil {
    59  		unix.Close(fd)
    60  		return -1, err
    61  	}
    62  
    63  	return fd, nil
    64  }