func sndrThread(conn *net.UDPConn, iface *water.Interface) { // first time fill with random numbers ivbuf := make([]byte, aes.BlockSize) if _, err := io.ReadFull(rand.Reader, ivbuf); err != nil { log.Fatalln("Unable to get rand data:", err) } var packet IPPacket = make([]byte, BUFFERSIZE) for { plen, err := iface.Read(packet[2 : MTU+2]) if err != nil { break } if 4 != packet.IPver() { header, _ := ipv4.ParseHeader(packet[2:]) log.Printf("Non IPv4 packet [%+v]\n", header) continue } // each time get pointer to (probably) new config c := config.Load().(VPNState) dst := packet.Dst() wanted := false addr, ok := c.remotes[dst] if ok { wanted = true } if dst == c.Main.bcastIP || packet.IsMulticast() { wanted = true } // very ugly and useful only for a limited numbers of routes! if !wanted { ip := packet.DstV4() for n, s := range c.routes { if n.Contains(ip) { addr = s ok = true wanted = true break } } } if wanted { // store orig packet len packet[0] = byte(plen % 256) packet[1] = byte(plen / 256) // encrypt clen := plen + 2 if clen%aes.BlockSize != 0 { clen += aes.BlockSize - (clen % aes.BlockSize) } if clen > len(packet) { log.Println("clen > len(package)", clen, len(packet)) continue } ciphertext := make([]byte, aes.BlockSize+clen) iv := ciphertext[:aes.BlockSize] copy(iv, ivbuf) mode := cipher.NewCBCEncrypter(c.Main.block, iv) mode.CryptBlocks(ciphertext[aes.BlockSize:], packet[:clen]) // save new iv copy(ivbuf, ciphertext[clen-aes.BlockSize:]) if ok { n, err := conn.WriteToUDP(ciphertext, addr) if nil != err { log.Println("Error sending package:", err) } if n != len(ciphertext) { log.Println("Only ", n, " bytes of ", len(ciphertext), " sent") } } else { // multicast or broadcast for _, addr := range c.remotes { n, err := conn.WriteToUDP(ciphertext, addr) if nil != err { log.Println("Error sending package:", err) } if n != len(ciphertext) { log.Println("Only ", n, " bytes of ", len(ciphertext), " sent") } } } } else { fmt.Println("Unknown dst", dst) } } }