zoukankan      html  css  js  c++  java
  • 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
    }
    
    var tunDevicePath = "/dev/net/tun"
    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

     test2:

        fd, err := syscall.Open(tunDevicePath, os.O_RDWR, 0)
        if err != nil {
            fmt.Printf("failed to open tun device: %+v", err)
            return nil, err
        }
    
        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 nil, err
        }
        if err := sendFCtlMessage(fd, syscall.F_SETFD, syscall.FD_CLOEXEC); err != nil {
            return nil, err
        }
        if err := sendIOCtlMessage(uintptr(fd), syscall.TUNSETPERSIST, 1); err != nil {
            return nil, err
        }
    
        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 nil, err
        }
    
        var reqRaw intfReq
        copy(reqRaw.name[:], DeviceName)
        reqRaw.flags = syscall.IFF_UP
        if err := sendIOCtlMessage(uintptr(raw),
            syscall.SIOCSIFFLAGS, uintptr(unsafe.Pointer(&reqRaw))); err != nil {
            return nil, err
        }
        if err := syscall.Close(raw); err != nil {
            fmt.Printf("failed to close RAW socket: %+v", err)
            return nil, err
        }
    
        return &device{fd: fd}, nil
  • 相关阅读:
    函数输出参数 双重指针
    NotePad++ 支持日语字体
    C++ 前置操作符与后置操作符
    用js判断 iPhone6 iPhone6 plus iphonex?
    从浏览器输入一个地址到渲染出网页这个过程发生了什么???
    对.Net 垃圾回收Finalize 和Dispose的理解
    在.NET环境中使用单元测试工具NUnit
    信道
    asp.net 获取当前URL的正确方法
    ASP.NET中常用输出JS脚本的类
  • 原文地址:https://www.cnblogs.com/wangjq19920210/p/11760820.html
Copyright © 2011-2022 走看看