Skip to content

Instantly share code, notes, and snippets.

@glacjay
Created September 18, 2010 12:26
Show Gist options
  • Star 13 You must be signed in to star a gist
  • Fork 4 You must be signed in to fork a gist
  • Save glacjay/585620 to your computer and use it in GitHub Desktop.
Save glacjay/585620 to your computer and use it in GitHub Desktop.
Reading/Writing Linux's TUN/TAP device in Go.
package main
import (
"exec"
"log"
"os"
"syscall"
"unsafe"
)
func main() {
file, err := os.Open("/dev/net/tun", os.O_RDWR, 0)
if err != nil {
log.Exitf("error os.Open(): %v\n", err)
}
ifr := make([]byte, 18)
copy(ifr, []byte("tun0"))
ifr[16] = 0x01
ifr[17] = 0x10
_, _, errno := syscall.Syscall(syscall.SYS_IOCTL, uintptr(file.Fd()),
uintptr(0x400454ca), uintptr(unsafe.Pointer(&ifr[0])))
if errno != 0 {
log.Exitf("error syscall.Ioctl(): %v\n", os.Errno(errno))
}
cmd, err := exec.Run("/sbin/ifconfig",
[]string{"ifconfig", "tun0", "192.168.7.1",
"pointopoint", "192.168.7.2", "up"},
nil, ".", 0, 1, 2)
if err != nil {
log.Exitf("error exec.Run(): %v\n", err)
}
cmd.Wait(0)
for {
buf := make([]byte, 2048)
read, err := file.Read(buf)
if err != nil {
log.Exitf("error os.Read(): %v\n", err)
}
for i := 0; i < 4; i++ {
buf[i+12], buf[i+16] = buf[i+16], buf[i+12]
}
buf[20] = 0
buf[22] = 0
buf[23] = 0
var checksum uint16
for i := 20; i < read; i += 2 {
checksum += uint16(buf[i])<<8 + uint16(buf[i+1])
}
checksum = ^(checksum + 4)
buf[22] = byte(checksum >> 8)
buf[23] = byte(checksum & ((1 << 8) - 1))
_, err = file.Write(buf)
if err != nil {
log.Exitf("error os.Write(): %v\n", err)
}
}
}
@shyandsy
Copy link

are there any way to pass the request to TCPIP stack?

@glacjay
Copy link
Author

glacjay commented Jul 16, 2019

are there any way to pass the request to TCPIP stack?

not sure what you mean

@KusakabeShi
Copy link

KusakabeShi commented Aug 23, 2021

Normally TCPIP stack are handled by OS kernel. But you get layer 2 packet directly. If you want to handle this like generate HTTP request, you have to use userspace implemented tcp/ip stack such as gvisor/vpp etc or construct your own tcp/ip stack and handle it yourself.

Here is an example: https://github.com/WireGuard/wireguard-go/blob/master/tun/netstack/examples/http_server.go , it serves a http server under wireguard which is a layer3 VPN. In this case it handle layer3 packet directly to serve a http server.

In your case you get layer2 packet but convert it to layer3 is pretty easy, you need to fill/remove the layer2 header such as source MAC address and Destination MAC address so that you can convert a layer2 packet to layer3 packet.

Layer 3 to layer 4 you have to construct tcp/ip stack or use gvisor.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment