Created
September 18, 2010 12:26
-
-
Save glacjay/585620 to your computer and use it in GitHub Desktop.
Reading/Writing Linux's TUN/TAP device in Go.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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) | |
} | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
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.