water Go Library

repository·master·Indexed 24 days ago

https://github.com/songgao/water

A native Go library for managing TUN/TAP network interfaces. It provides a wrapper around syscalls and exposes standard Go interfaces like io.Reader for network packet manipulation. Supports Linux (TAP/TUN), Windows (experimental TAP), and macOS (TUN only).

Tokens
1.1K
Snippets
5
Records
6
Agent score
30%

What's inside water

  1. Supported Platforms for water

    master

    The water library supports the following platforms:

    • Linux: Full support for TAP and TUN.
    • Windows: Experimental support for TAP (requires a TAP driver like tap-windows6 or OpenVPN). APIs may change.
    • macOS: Supports TUN only (point-to-point). TAP is not supported natively on macOS.
  2. Configure TAP interfaces on Windows

    master

    When using TAP on Windows, you can use water.PlatformSpecificParams within your water.Config to select a specific device if you are using multiple TAP interfaces. This is useful for targeting a specific InterfaceName or ComponentID.

    ifce, err := water.New(water.Config{
    	DeviceType: water.TAP,
    	PlatformSpecificParams: water.PlatformSpecificParams{
    		ComponentID:   "tap0901",
    		InterfaceName: "Ethernet 3",
    		Network:       "192.168.1.10/24",
    	},
    })
  3. Example: Create and read a TUN interface on macOS

    master

    This example creates a point-to-point TUN interface.

    macOS Caveats:

    1. Only Point-to-Point user TUN devices are supported.
    2. Custom interface names are not supported; names are automatically generated (e.g., utun<#>).

    After running with sudo, use ifconfig to find the interface name and bring it up with an IP address.

    package main
    
    import (
    	"log"
    
    	"github.com/songgao/water"
    )
    
    func main() {
    	ifce, err := water.New(water.Config{
    		DeviceType: water.TUN,
    	}); err != nil {
    		log.Fatal(err)
    	}
    
    	log.Printf("Interface Name: %s\n", ifce.Name())
    
    	packet := make([]byte, 2000)
    	for {
    		n, err := ifce.Read(packet)
    		if err != nil {
    			log.Fatal(err)
    		}
    		log.Printf("Packet Received: % x\n", packet[:n])
    	}
    }
  4. Example: Create and read a TAP interface on Linux

    master

    This example creates a TAP interface named O_O and continuously reads Ethernet frames, printing their source, destination, and payload.

    Note: You must run the application with sudo and manually bring the interface up and assign an IP address using ip commands.

    package main
    
    import (
    	"log"
    
    	"github.com/songgao/packets/ethernet"
    	"github.com/songgao/water"
    )
    
    func main() {
    	config := water.Config{
    		DeviceType: water.TAP,
    	}
    	config.Name = "O_O"
    
    	ifce, err := water.New(config);
    		if err != nil {
    			log.Fatal(err)
    		}
    	var frame ethernet.Frame
    
    	for {
    		frame.Resize(1500)
    		n, err := ifce.Read([]byte(frame))
    		if err != nil {
    			log.Fatal(err)
    		}
    		frame = frame[:n]
    		log.Printf("Dst: %s\n", frame.Destination())
    		log.Printf("Src: %s\n", frame.Source())
    		log.Printf("Ethertype: % x\n", frame.Ethertype())
    		log.Printf("Payload: % x\n", frame.Payload())
    	}
    }
  5. Create a new TUN/TAP interface with water.New()

    master

    Use water.New(config) to create a new network interface. The water.Config struct allows you to specify the DeviceType (either water.TAP or water.TUN) and an optional Name.

    Note that water does not handle memory management for buffers; you are responsible for allocating and reusing slices passed to Read.

    config := water.Config{
    	DeviceType: water.TAP,
    	Name:       "O_O",
    }
    
    ifce, err := water.New(config)