windowsgoipnic

How to bind physical nic to send a ip package with golang?


I set up a virtual network card(TUN) on the windows client for the vpn to get traffic. When capturing virtual NIC traffic, I perform the following resource judgment logic: When accessing certain resources, the traffic (IP packets) will not be sent through the VPN channel. I want to send the traffic (IP packets) directly through the physical NIC. The problem now is how do I get the traffic sent directly through the physical network card.

--SYSTEM:WINDOWS --LANGUAGE:GOLANG

I tried to simulate TCP/UDP by parsing IP packets and binding network adapter addresses for sending, but this was too slow. Is there a way to directly bind the physical NIC and send IP packets?


Solution

  • Raw sockets are disabled since Windows XP, so you need third party software to inject IP packets.

    I used WinPcap library for this. The Go binding exists: https://pkg.go.dev/github.com/google/gopacket/pcap

    The function that writes Ethernet frames to the datalink is Handle.WritePacketData

    The steps are:

    1. Create a handle to your physical NIC with OpenLive
    2. Wrap IP packed into datalink layer frame
    3. Write the frame to the handle with Handle.WritePacketData

    The tricky part with the step 1 is the name of the interface. In windows there are no such names as eth0. The required name looks like \Device\NPF_{BBECCD43-3F2B-4594-B17B-5F38E73787E8}

    To get the proper names of the devices you can query FindAllDevs function. As Administrator!

    package main
    
    import (
        "fmt"
    
        "github.com/google/gopacket/pcap"
    )
    
    func main() {
        // Get device list - run as ADMINISTRATOR!
        devices, err := pcap.FindAllDevs()
        if err != nil {
            panic(err)
        }
    
        // Print device information
        fmt.Println("Devices:")
        for _, device := range devices {
            fmt.Println("-----------------------")
            fmt.Println("Name: ", device.Name)
            fmt.Println("Description: ", device.Description)
            fmt.Println("Addresses: ", device.Description)
            for _, address := range device.Addresses {
                fmt.Println("  IP address: ", address.IP)
                fmt.Println("  Netmask: ", address.Netmask)
            }
        }
    }
    

    Sample output (this is my WiFi adapter):

    -----------------------
    Name:  \Device\NPF_{BBECCD43-3F2B-4594-B17B-5F38E73787E8}
    Description:  Microsoft
    Addresses:  Microsoft
      IP address:  fe80::de52:6717:446:57a1
      Netmask:  <nil>
      IP address:  172.30.1.95
      Netmask:  ffffff00