github.com/clmul/water@v0.0.3-0.20221017135504-100d910a03ab/syscalls_darwin.go (about)

     1  package water
     2  
     3  import (
     4  	"unsafe"
     5  
     6  	"golang.org/x/sys/unix"
     7  )
     8  
     9  type Config struct{}
    10  
    11  const appleUTUNCtl = "com.apple.net.utun_control"
    12  
    13  /*
    14   * From ioctl.h:
    15   * #define	IOCPARM_MASK	0x1fff		// parameter length, at most 13 bits
    16   * ...
    17   * #define	IOC_OUT		0x40000000	// copy out parameters
    18   * #define	IOC_IN		0x80000000	// copy in parameters
    19   * #define	IOC_INOUT	(IOC_IN|IOC_OUT)
    20   * ...
    21   * #define _IOC(inout,group,num,len) \
    22   * 	(inout | ((len & IOCPARM_MASK) << 16) | ((group) << 8) | (num))
    23   * ...
    24   * #define	_IOWR(g,n,t)	_IOC(IOC_INOUT,	(g), (n), sizeof(t))
    25   *
    26   * From kern_control.h:
    27   * #define CTLIOCGINFO     _IOWR('N', 3, struct ctl_info)	// get id from name
    28   *
    29   */
    30  
    31  const appleCTLIOCGINFO = (0x40000000 | 0x80000000) | ((100 & 0x1fff) << 16) | uint32(byte('N'))<<8 | 3
    32  
    33  /*
    34   * #define _IOW(g,n,t) _IOC(IOC_IN, (g), (n), sizeof(t))
    35   * #define TUNSIFMODE _IOW('t', 94, int)
    36   */
    37  const appleTUNSIFMODE = (0x80000000) | ((4 & 0x1fff) << 16) | uint32(byte('t'))<<8 | 94
    38  
    39  /*
    40   * struct sockaddr_ctl {
    41   *     u_char sc_len; // depends on size of bundle ID string
    42   *     u_char sc_family; // AF_SYSTEM
    43   *     u_int16_t ss_sysaddr; // AF_SYS_KERNCONTROL
    44   *     u_int32_t sc_id; // Controller unique identifier
    45   *     u_int32_t sc_unit; // Developer private unit number
    46   *     u_int32_t sc_reserved[5];
    47   * };
    48   */
    49  type sockaddrCtl struct {
    50  	scLen      uint8
    51  	scFamily   uint8
    52  	ssSysaddr  uint16
    53  	scID       uint32
    54  	scUnit     uint32
    55  	scReserved [5]uint32
    56  }
    57  
    58  var sockaddrCtlSize uintptr = 32
    59  
    60  func open(Config) (int, string, error) {
    61  	// Supposed to be socket(PF_SYSTEM, SOCK_DGRAM, SYSPROTO_CONTROL), but ...
    62  	//
    63  	// In sys/socket.h:
    64  	// #define PF_SYSTEM	AF_SYSTEM
    65  	//
    66  	// In sys/sys_domain.h:
    67  	// #define SYSPROTO_CONTROL       	2	/* kernel control protocol */
    68  	fd, err := unix.Socket(unix.AF_SYSTEM, unix.SOCK_DGRAM, 2)
    69  	if err != nil {
    70  		return 0, "", err
    71  	}
    72  
    73  	var ctlInfo = &struct {
    74  		ctlID   uint32
    75  		ctlName [96]byte
    76  	}{}
    77  	copy(ctlInfo.ctlName[:], []byte(appleUTUNCtl))
    78  
    79  	_, _, errno := unix.Syscall(unix.SYS_IOCTL, uintptr(fd), uintptr(appleCTLIOCGINFO), uintptr(unsafe.Pointer(ctlInfo)))
    80  	if errno != 0 {
    81  		return 0, "", errno
    82  	}
    83  
    84  	addrP := unsafe.Pointer(&sockaddrCtl{
    85  		scLen:    uint8(sockaddrCtlSize),
    86  		scFamily: unix.AF_SYSTEM,
    87  
    88  		/* #define AF_SYS_CONTROL 2 */
    89  		ssSysaddr: 2,
    90  
    91  		scID:   ctlInfo.ctlID,
    92  		scUnit: 0,
    93  	})
    94  	_, _, errno = unix.Syscall(unix.SYS_CONNECT, uintptr(fd), uintptr(addrP), uintptr(sockaddrCtlSize))
    95  	if errno != 0 {
    96  		return 0, "", errno
    97  	}
    98  
    99  	var ifName [16]byte
   100  	ifNameSize := uintptr(16)
   101  	_, _, errno = unix.Syscall6(unix.SYS_GETSOCKOPT, uintptr(fd),
   102  		2, /* #define SYSPROTO_CONTROL 2 */
   103  		2, /* #define UTUN_OPT_IFNAME 2 */
   104  		uintptr(unsafe.Pointer(&ifName)),
   105  		uintptr(unsafe.Pointer(&ifNameSize)), 0)
   106  	if errno != 0 {
   107  		return 0, "", errno
   108  	}
   109  
   110  	name := string(ifName[:ifNameSize-1])
   111  	return fd, name, nil
   112  }
   113  
   114  // this is a hack to work around the first 4 bytes "packet information"
   115  // because there doesn't seem to be an IFF_NO_PI for darwin.
   116  func (ifce *Interface) Read(buffer []byte) (int, error) {
   117  	n, err := ifce.File.Read(buffer)
   118  	if err != nil {
   119  		return 0, err
   120  	}
   121  	copy(buffer, buffer[4:])
   122  	return n - 4, nil
   123  }
   124  
   125  func (ifce *Interface) Write(buffer []byte) (int, error) {
   126  	// Determine the IP Family for the NULL L2 Header
   127  	buffer = buffer[:len(buffer)+4]
   128  	copy(buffer[4:], buffer)
   129  	ipVer := buffer[0] >> 4
   130  	switch ipVer {
   131  	case 4:
   132  		buffer[3] = unix.AF_INET
   133  	case 6:
   134  		buffer[3] = unix.AF_INET6
   135  	default:
   136  		panic("unable to determine IP version from packet")
   137  	}
   138  
   139  	buffer[0] = 0
   140  	buffer[1] = 0
   141  	buffer[2] = 0
   142  
   143  	n, err := ifce.File.Write(buffer)
   144  	return n - 4, err
   145  }