예제 #1
0
파일: udp.go 프로젝트: xiaokangwang/govpn
func startUDP() {
	bind, err := net.ResolveUDPAddr("udp", *bindAddr)
	if err != nil {
		log.Fatalln("Can not resolve bind address:", err)
	}
	conn, err := net.ListenUDP("udp", bind)
	if err != nil {
		log.Fatalln("Can not listen on UDP:", err)
	}
	log.Println("Listening on UDP:" + *bindAddr)

	udpBufs <- make([]byte, govpn.MTUMax)
	go func() {
		var buf []byte
		var raddr *net.UDPAddr
		var addr string
		var n int
		var err error
		var ps *PeerState
		var hs *govpn.Handshake
		var addrPrev string
		var exists bool
		var peerId *govpn.PeerId
		var peer *govpn.Peer
		var conf *govpn.PeerConf
		for {
			buf = <-udpBufs
			n, raddr, err = conn.ReadFromUDP(buf)
			if err != nil {
				log.Println("Unexpected error when receiving", err)
				break
			}
			addr = raddr.String()

			peersLock.RLock()
			ps, exists = peers[addr]
			peersLock.RUnlock()
			if !exists {
				goto CheckHandshake
			}
			go func(ps *govpn.Peer, tap *govpn.TAP, buf []byte, n int) {
				peer.PktProcess(buf[:n], tap, true)
				udpBufs <- buf
			}(ps.peer, ps.tap, buf, n)
			continue
		CheckHandshake:
			hsLock.RLock()
			hs, exists = handshakes[addr]
			hsLock.RUnlock()
			if !exists {
				goto CheckID
			}
			peer = hs.Server(buf[:n])
			if peer == nil {
				goto Finished
			}

			log.Println("Peer handshake finished:", addr, peer.Id.String())
			hs.Zero()
			hsLock.Lock()
			delete(handshakes, addr)
			hsLock.Unlock()

			go func() {
				udpBufs <- make([]byte, govpn.MTUMax)
				udpBufs <- make([]byte, govpn.MTUMax)
			}()
			peersByIdLock.RLock()
			addrPrev, exists = peersById[*peer.Id]
			peersByIdLock.RUnlock()
			if exists {
				peersLock.Lock()
				peers[addrPrev].terminator <- struct{}{}
				ps = &PeerState{
					peer:       peer,
					tap:        peers[addrPrev].tap,
					terminator: make(chan struct{}),
				}
				go func(ps PeerState) {
					peerReady(ps)
					<-udpBufs
					<-udpBufs
				}(*ps)
				peersByIdLock.Lock()
				kpLock.Lock()
				delete(peers, addrPrev)
				delete(knownPeers, addrPrev)
				peers[addr] = ps
				knownPeers[addr] = &peer
				peersById[*peer.Id] = addr
				peersLock.Unlock()
				peersByIdLock.Unlock()
				kpLock.Unlock()
				log.Println("Rehandshake processed:", peer.Id.String())
			} else {
				go func(addr string, peer *govpn.Peer) {
					ifaceName, err := callUp(peer.Id)
					if err != nil {
						return
					}
					tap, err := govpn.TAPListen(ifaceName, peer.MTU)
					if err != nil {
						log.Println("Unable to create TAP:", err)
						return
					}
					ps = &PeerState{
						peer:       peer,
						tap:        tap,
						terminator: make(chan struct{}),
					}
					go func(ps PeerState) {
						peerReady(ps)
						<-udpBufs
						<-udpBufs
					}(*ps)
					peersLock.Lock()
					peersByIdLock.Lock()
					kpLock.Lock()
					peers[addr] = ps
					knownPeers[addr] = &peer
					peersById[*peer.Id] = addr
					peersLock.Unlock()
					peersByIdLock.Unlock()
					kpLock.Unlock()
					log.Println("Peer created:", peer.Id.String())
				}(addr, peer)
			}
			goto Finished
		CheckID:
			peerId = idsCache.Find(buf[:n])
			if peerId == nil {
				log.Println("Unknown identity from:", addr)
				goto Finished
			}
			conf = confs[*peerId]
			if conf == nil {
				log.Println("Unable to get peer configuration:", peerId.String())
				goto Finished
			}
			hs = govpn.NewHandshake(
				addr,
				UDPSender{conn: conn, addr: raddr},
				conf,
			)
			hs.Server(buf[:n])
			hsLock.Lock()
			handshakes[addr] = hs
			hsLock.Unlock()
		Finished:
			udpBufs <- buf
		}
	}()
}
예제 #2
0
파일: tcp.go 프로젝트: xiaokangwang/govpn
func handleTCP(conn net.Conn) {
	addr := conn.RemoteAddr().String()
	buf := make([]byte, govpn.EnclessEnlargeSize+2*govpn.MTUMax)
	var n int
	var err error
	var prev int
	var hs *govpn.Handshake
	var ps *PeerState
	var peer *govpn.Peer
	var tap *govpn.TAP
	var conf *govpn.PeerConf
	for {
		if prev == len(buf) {
			break
		}
		conn.SetReadDeadline(time.Now().Add(time.Duration(govpn.TimeoutDefault) * time.Second))
		n, err = conn.Read(buf[prev:])
		if err != nil {
			// Either EOFed or timeouted
			break
		}
		prev += n
		peerId := idsCache.Find(buf[:prev])
		if peerId == nil {
			continue
		}
		if hs == nil {
			conf = confs[*peerId]
			if conf == nil {
				log.Println("Can not get peer configuration:", peerId.String())
				break
			}
			hs = govpn.NewHandshake(addr, conn, conf)
		}
		peer = hs.Server(buf[:prev])
		prev = 0
		if peer == nil {
			continue
		}
		hs.Zero()
		log.Println("Peer handshake finished:", addr, peer.Id.String())
		peersByIdLock.RLock()
		addrPrev, exists := peersById[*peer.Id]
		peersByIdLock.RUnlock()
		if exists {
			peersLock.Lock()
			peers[addrPrev].terminator <- struct{}{}
			tap = peers[addrPrev].tap
			ps = &PeerState{
				peer:       peer,
				tap:        tap,
				terminator: make(chan struct{}),
			}
			go peerReady(*ps)
			peersByIdLock.Lock()
			kpLock.Lock()
			delete(peers, addrPrev)
			delete(knownPeers, addrPrev)
			peers[addr] = ps
			knownPeers[addr] = &peer
			peersById[*peer.Id] = addr
			peersLock.Unlock()
			peersByIdLock.Unlock()
			kpLock.Unlock()
			log.Println("Rehandshake processed:", peer.Id.String())
		} else {
			ifaceName, err := callUp(peer.Id)
			if err != nil {
				peer = nil
				break
			}
			tap, err = govpn.TAPListen(ifaceName, peer.MTU)
			if err != nil {
				log.Println("Unable to create TAP:", err)
				peer = nil
				break
			}
			ps = &PeerState{
				peer:       peer,
				tap:        tap,
				terminator: make(chan struct{}, 1),
			}
			go peerReady(*ps)
			peersLock.Lock()
			peersByIdLock.Lock()
			kpLock.Lock()
			peers[addr] = ps
			peersById[*peer.Id] = addr
			knownPeers[addr] = &peer
			peersLock.Unlock()
			peersByIdLock.Unlock()
			kpLock.Unlock()
			log.Println("Peer created:", peer.Id.String())
		}
		break
	}
	if hs != nil {
		hs.Zero()
	}
	if peer == nil {
		return
	}

	nonceExpectation := make([]byte, govpn.NonceSize)
	peer.NonceExpectation(nonceExpectation)
	prev = 0
	var i int
	for {
		if prev == len(buf) {
			break
		}
		conn.SetReadDeadline(time.Now().Add(conf.Timeout))
		n, err = conn.Read(buf[prev:])
		if err != nil {
			// Either EOFed or timeouted
			break
		}
		prev += n
	CheckMore:
		if prev < govpn.MinPktLength {
			continue
		}
		i = bytes.Index(buf[:prev], nonceExpectation)
		if i == -1 {
			continue
		}
		if !peer.PktProcess(buf[:i+govpn.NonceSize], tap, false) {
			log.Println(
				"Unauthenticated packet, dropping connection",
				addr, peer.Id.String(),
			)
			break
		}
		peer.NonceExpectation(nonceExpectation)
		copy(buf, buf[i+govpn.NonceSize:prev])
		prev = prev - i - govpn.NonceSize
		goto CheckMore
	}
	peer.Zero()
}