package main import ( "encoding/binary" "fmt" "log" "net" "os" "os/exec" "sync" "baalvpn/shared" "github.com/songgao/packets/ethernet" "github.com/songgao/water" ) const IFACE_NAME = "baalvpn" type Peer struct { RealIP string InternalIP string } var ( peers = map[string]*Peer{} peersMutex sync.Mutex nextIP = 3 ) func main() { if os.Geteuid() != 0 { panic("root permissions needed") } config := water.Config{DeviceType: water.TAP} config.Name = IFACE_NAME iface, err := water.New(config) if err != nil { panic(err) } if err := exec.Command("ip", "addr", "add", "10.1.0.10/24", "dev", IFACE_NAME).Run(); err != nil { panic(err) } if err := exec.Command("ip", "link", "set", "dev", IFACE_NAME, "up").Run(); err != nil { panic(err) } log.Println("Listening...") go receivePackets() sendPackets(iface) } func sendPackets(iface *water.Interface) { var frame ethernet.Frame for { frame.Resize(1500) n, err := iface.Read([]byte(frame)) if err != nil { panic(err) } frame = frame[:n] if frame.Destination()[0]&0x01 == 0x01 { log.Println("multicast") continue } 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()) } } func receivePackets() { listenAddr, err := net.ResolveUDPAddr("udp", ":38000") if err != nil { panic(err) } listener, err := net.ListenUDP("udp", listenAddr) if err != nil { panic(err) } defer listener.Close() for { buffer := make([]byte, 50000) n, addr, err := listener.ReadFromUDP(buffer) if err != nil { log.Println(err) continue } if n == 0 { continue } go receivePacket(listener, buffer[:n], addr) } } func receivePacket(c *net.UDPConn, pkt []byte, addr *net.UDPAddr) { if len(pkt) < 4 { log.Println("packet too short") return } version := binary.LittleEndian.Uint16(pkt[0:]) if version != shared.PROTO_VERSION { log.Println("mismatched packet version") return } pktType := binary.LittleEndian.Uint16(pkt[2:]) peerIP := addr.IP.String() switch pktType { case shared.REQ_REGISTER: peersMutex.Lock() defer peersMutex.Unlock() internalIP := fmt.Sprintf("10.1.0.%d", nextIP) if peer, ok := peers[addr.IP.String()]; ok { internalIP = peer.InternalIP } else { peers[addr.IP.String()] = &Peer{ RealIP: peerIP, InternalIP: internalIP, } nextIP++ } resp := shared.BuildPkt(shared.RESP_REGISTER, net.ParseIP(internalIP).To4()) if _, err := c.WriteToUDP(resp, addr); err != nil { log.Printf("register WriteToUDP: %v\n", err) } default: log.Println("unknown packet type") } }