Skip to content

Instantly share code, notes, and snippets.

@bcho
Created July 25, 2020 09:22
Show Gist options
  • Save bcho/bcba3ee2651f7a9f4c43f167eb2c5beb to your computer and use it in GitHub Desktop.
Save bcho/bcba3ee2651f7a9f4c43f167eb2c5beb to your computer and use it in GitHub Desktop.

Revisions

  1. bcho created this gist Jul 25, 2020.
    80 changes: 80 additions & 0 deletions tun.go
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,80 @@
    package main

    import (
    "encoding/binary"
    "fmt"
    "net"
    "os"
    "unsafe"

    "golang.org/x/sys/unix"
    )

    const (
    tunDevice = "/dev/net/tun"
    ifReqSize = unix.IFNAMSIZ + 64
    )

    func checkErr(err error) {
    if err == nil {
    return
    }

    panic(err)
    }

    // https://www.kernel.org/doc/Documentation/networking/tuntap.txt
    // setup: ip link set up wg1 && ip addr add 10.0.1.2/24 dev wg1
    // test: ping -c1 -b 10.0.1.255
    func main() {
    nfd, err := unix.Open(tunDevice, os.O_RDWR, 0)
    checkErr(err)

    var ifr [ifReqSize]byte
    var flags uint16 = unix.IFF_TUN | unix.IFF_NO_PI
    name := []byte("wg1")
    copy(ifr[:], name)
    *(*uint16)(unsafe.Pointer(&ifr[unix.IFNAMSIZ])) = flags
    fmt.Println(string(ifr[:unix.IFNAMSIZ]))

    _, _, errno := unix.Syscall(
    unix.SYS_IOCTL,
    uintptr(nfd),
    uintptr(unix.TUNSETIFF),
    uintptr(unsafe.Pointer(&ifr[0])),
    )
    if errno != 0 {
    checkErr(fmt.Errorf("ioctl errno: %d", errno))
    }

    err = unix.SetNonblock(nfd, true)

    fd := os.NewFile(uintptr(nfd), tunDevice)
    checkErr(err)

    for {
    buf := make([]byte, 1500)
    _, err := fd.Read(buf)
    if err != nil {
    fmt.Printf("read error: %v\n", err)
    continue
    }

    fmt.Println("received packet")

    switch buf[0] & 0xF0 {
    case 0x40:
    fmt.Println("received ipv4")
    fmt.Printf("Length: %d\n", binary.BigEndian.Uint16(buf[2:4]))
    fmt.Printf("Protocol: %d (1=ICMP, 6=TCP, 17=UDP)\n", buf[9])
    fmt.Printf("Source IP: %s\n", net.IP(buf[12:16]))
    fmt.Printf("Destination IP: %s\n", net.IP(buf[16:20]))
    case 0x60:
    fmt.Println("received ipv6")
    fmt.Printf("Length: %d\n", binary.BigEndian.Uint16(buf[4:6]))
    fmt.Printf("Protocol: %d (1=ICMP, 6=TCP, 17=UDP)\n", buf[7])
    fmt.Printf("Source IP: %s\n", net.IP(buf[8:24]))
    fmt.Printf("Destination IP: %s\n", net.IP(buf[24:40]))
    }
    }
    }