golang 创建 tun 设备
Posted wangjq19920210
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了golang 创建 tun 设备相关的知识,希望对你有一定的参考价值。
源码:
package main import ( "flag" "fmt" "github.com/pkg/errors" "net" "os" "syscall" "unsafe" ) var ( HostName, _ = os.Hostname() ETH_P_ARP = 0x0806 AF_INET = int32(2) AF_INET6 = int32(10) AF_BRIDGE = int32(7) ) func Htons(i uint16) uint16 { return (i<<8)&0xff00 | i>>8 } type intfReq struct { name [16]byte flags uint16 } // sendIOCtlMessage ioctl system call func sendIOCtlMessage(fd uintptr, request uintptr, ifReq uintptr) error { fmt.Printf("syscall fd %+v, request %+v, ifReq %+v", fd, request, ifReq) _, _, errno := syscall.Syscall(syscall.SYS_IOCTL, fd, request, ifReq) if errno != 0 { fmt.Printf("Fail to execute ioctl, the errno is %+v", errno) return errors.New("failed execute ioctl") } return nil } // sendFCtlMessage fcntl system call func sendFCtlMessage(fd int, cmd int, arg int) error { _, _, err := syscall.Syscall(syscall.SYS_FCNTL, uintptr(fd), uintptr(cmd), uintptr(arg)) if err != 0 { fmt.Printf("Fail to execute fctl, the error is %+v", err) return errors.New("failed execute fctl") } return nil } func main() { var DeviceName string flag.StringVar(&DeviceName, "name", "", "pkt0") flag.Parse() flag.Usage() fd, err := syscall.Open(tunDevicePath, os.O_RDWR, 0) if err != nil { fmt.Printf("failed to open tun device: %+v", err) return } var req intfReq req.flags = syscall.IFF_TAP | syscall.IFF_NO_PI copy(req.name[:], DeviceName) if err := sendIOCtlMessage(uintptr(fd), uintptr(syscall.TUNSETIFF), uintptr(unsafe.Pointer(&req))); err != nil { return } if err := sendFCtlMessage(fd, syscall.F_SETFD, syscall.FD_CLOEXEC); err != nil { return } if err := sendIOCtlMessage(uintptr(fd), syscall.TUNSETPERSIST, 1); err != nil { return } raw, err := syscall.Socket(syscall.AF_PACKET, syscall.SOCK_RAW, int(Htons(syscall.ETH_P_ALL))) if err != nil { fmt.Printf("failed to create RAW socket: %+v", err) return } var reqRaw intfReq copy(reqRaw.name[:], DeviceName) if err := sendIOCtlMessage(uintptr(raw), syscall.SIOCGIFINDEX, uintptr(unsafe.Pointer(&reqRaw))); err != nil { return } ifi, err := net.InterfaceByName(DeviceName) if err != nil { fmt.Printf("failed to get device: %+v", err) return } if err := syscall.Bind(raw, &syscall.SockaddrLinklayer{ Protocol: uint16(Htons(syscall.ETH_P_ALL)), Ifindex: ifi.Index, }); err != nil { fmt.Printf("failed to bind: %+v", err) return } if err := sendIOCtlMessage(uintptr(raw), syscall.SIOCSIFTXQLEN, uintptr(unsafe.Pointer(&reqRaw))); err != nil { return } if err := sendIOCtlMessage(uintptr(raw), syscall.SIOCGIFFLAGS, uintptr(unsafe.Pointer(&reqRaw))); err != nil { return } reqRaw.flags = syscall.IFF_UP if err := sendIOCtlMessage(uintptr(raw), syscall.SIOCSIFFLAGS, uintptr(unsafe.Pointer(&reqRaw))); err != nil { return } var r intfReq copy(r.name[:], DeviceName) if err := sendIOCtlMessage(uintptr(raw), syscall.SIOCGIFFLAGS, uintptr(unsafe.Pointer(&r))); err != nil { return } if err := syscall.Close(raw); err != nil { fmt.Printf("failed to close RAW socket: %+v", err) return } return }
运行结果:
[root@wangjq tun]# ./main -name demo Usage of ./main: -name string pkt0 syscall fd 3, request 1074025674, ifReq 824634130180 syscall fd 3, request 1074025675, ifReq 1 syscall fd 5, request 35123, ifReq 824634130162 syscall fd 5, request 35139, ifReq 824634130162 syscall fd 5, request 35091, ifReq 824634130162 syscall fd 5, request 35092, ifReq 824634130162 syscall fd 5, request 35091, ifReq 824634130198 [root@wangjq tun]# ip link show demo 10: demo: <NO-CARRIER,BROADCAST,UP> mtu 1500 qdisc pfifo_fast state DOWN mode DEFAULT group default qlen 10 link/ether 7e:e7:77:ad:f7:9e brd ff:ff:ff:ff:ff:ff
以上是关于golang 创建 tun 设备的主要内容,如果未能解决你的问题,请参考以下文章
Linux 网络工具详解之 ip tuntap 和 tunctl 创建 tap/tun 设备
Linux 网络工具详解之 ip tuntap 和 tunctl 创建 tap/tun 设备
[Linux用户空间编程-4]:Linux虚拟网络设备TUN/TAP的工作原理与代码示例