Skip to content

Instantly share code, notes, and snippets.

@songgao
Created March 18, 2013 18:58
Show Gist options
  • Select an option

  • Save songgao/5189799 to your computer and use it in GitHub Desktop.

Select an option

Save songgao/5189799 to your computer and use it in GitHub Desktop.

Revisions

  1. songgao created this gist Mar 18, 2013.
    96 changes: 96 additions & 0 deletions TUN example in Go
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,96 @@
    package main

    import (
    "io"
    "net"
    "os"
    "fmt"
    "strings"
    "syscall"
    "unsafe"
    )

    const (
    cIFF_TUN = 0x0001
    cIFF_NO_PI = 0x1000
    )

    const (
    cMAX_PACKET_SIZE = 1500 //MTU
    )

    type ifReq struct {
    Name [0x10]byte
    Flags uint16
    pad [0x28 - 0x10 - 2]byte
    }

    type tunIF struct {
    name string
    file *os.File
    }

    func (tun *tunIF) Name() string {
    return tun.name
    }

    func (tun *tunIF) createInterface(ifPattern string) (err error) {
    var req ifReq
    req.Flags = cIFF_TUN | cIFF_NO_PI
    copy(req.Name[:], ifPattern)
    _, _, errno := syscall.Syscall(syscall.SYS_IOCTL, tun.file.Fd(), uintptr(syscall.TUNSETIFF), uintptr(unsafe.Pointer(&req)))
    if errno != 0 {
    return errno
    }
    tun.name = strings.Trim(string(req.Name[:]), "\x00")
    return
    }

    func newTun(ifPattern string) (tun *tunIF, err error) {
    file, err := os.OpenFile("/dev/net/tun", os.O_RDWR, 0)
    if err != nil {
    return nil, err
    }
    tun = &tunIF{name: "", file: file}
    err = tun.createInterface(ifPattern)
    if err != nil {
    file.Close()
    return nil, err
    }
    return
    }

    // Read a packet from TUN device.
    func (tun *tunIF) Read() (packet []byte, err error) {
    buf := make([]byte, cMAX_PACKET_SIZE)
    n, err := tun.file.Read(buf)
    if err != nil && err != io.EOF {
    return
    }
    packet = buf[:n]
    return packet, nil
    }

    // Write a packet into TUN device (blocking)
    func (tun *tunIF) Write(packet []byte) (err error) {
    _, err = tun.file.Write(packet)
    return
    }

    func IPFrom(bytes []byte) net.IP {
    return net.IPv4(bytes[0], bytes[1], bytes[2], bytes[3]).To4()
    }

    func main() {
    tun, err := newTun("tun0")
    if err != nil{
    fmt.Println(err)
    }
    for {
    packet, err := tun.Read()
    if err != nil {
    break
    }
    fmt.Printf("From: %v; To: %v\n", IPFrom(packet[12:16]), IPFrom(packet[16:20]))
    }
    }