コード例 #1
0
ファイル: main.go プロジェクト: kanocz/lcvpn
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)
		}
	}

}