| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377 | package nebulaimport (	"bytes"	"sync/atomic"	"time"	"github.com/flynn/noise"	"github.com/golang/protobuf/proto")// NOISE IX Handshakes// This function constructs a handshake packet, but does not actually send it// Sending is done by the handshake managerfunc ixHandshakeStage0(f *Interface, vpnIp uint32, hostinfo *HostInfo) {	// This queries the lighthouse if we don't know a remote for the host	if hostinfo.remote == nil {		ips, err := f.lightHouse.Query(vpnIp, f)		if err != nil {			//l.Debugln(err)		}		for _, ip := range ips {			hostinfo.AddRemote(ip)		}	}	myIndex, err := generateIndex()	if err != nil {		l.WithError(err).WithField("vpnIp", IntIp(vpnIp)).			WithField("handshake", m{"stage": 0, "style": "ix_psk0"}).Error("Failed to generate index")		return	}	ci := hostinfo.ConnectionState	f.handshakeManager.AddIndexHostInfo(myIndex, hostinfo)	hsProto := &NebulaHandshakeDetails{		InitiatorIndex: myIndex,		Time:           uint64(time.Now().Unix()),		Cert:           ci.certState.rawCertificateNoKey,	}	hsBytes := []byte{}	hs := &NebulaHandshake{		Details: hsProto,	}	hsBytes, err = proto.Marshal(hs)	if err != nil {		l.WithError(err).WithField("vpnIp", IntIp(vpnIp)).			WithField("handshake", m{"stage": 0, "style": "ix_psk0"}).Error("Failed to marshal handshake message")		return	}	header := HeaderEncode(make([]byte, HeaderLen), Version, uint8(handshake), handshakeIXPSK0, 0, 1)	atomic.AddUint64(ci.messageCounter, 1)	msg, _, _, err := ci.H.WriteMessage(header, hsBytes)	if err != nil {		l.WithError(err).WithField("vpnIp", IntIp(vpnIp)).			WithField("handshake", m{"stage": 0, "style": "ix_psk0"}).Error("Failed to call noise.WriteMessage")		return	}	hostinfo.HandshakePacket[0] = msg	hostinfo.HandshakeReady = true	hostinfo.handshakeStart = time.Now()}func ixHandshakeStage1(f *Interface, addr *udpAddr, hostinfo *HostInfo, packet []byte, h *Header) bool {	var ip uint32	if h.RemoteIndex == 0 {		ci := f.newConnectionState(false, noise.HandshakeIX, []byte{}, 0)		// Mark packet 1 as seen so it doesn't show up as missed		ci.window.Update(1)		msg, _, _, err := ci.H.ReadMessage(nil, packet[HeaderLen:])		if err != nil {			l.WithError(err).WithField("udpAddr", addr).				WithField("handshake", m{"stage": 1, "style": "ix_psk0"}).Error("Failed to call noise.ReadMessage")			return true		}		hs := &NebulaHandshake{}		err = proto.Unmarshal(msg, hs)		/*			l.Debugln("GOT INDEX: ", hs.Details.InitiatorIndex)		*/		if err != nil || hs.Details == nil {			l.WithError(err).WithField("udpAddr", addr).				WithField("handshake", m{"stage": 1, "style": "ix_psk0"}).Error("Failed unmarshal handshake message")			return true		}		hostinfo, _ := f.handshakeManager.pendingHostMap.QueryReverseIndex(hs.Details.InitiatorIndex)		if hostinfo != nil && bytes.Equal(hostinfo.HandshakePacket[0], packet[HeaderLen:]) {			if msg, ok := hostinfo.HandshakePacket[2]; ok {				f.messageMetrics.Tx(handshake, NebulaMessageSubType(msg[1]), 1)				err := f.outside.WriteTo(msg, addr)				if err != nil {					l.WithField("vpnIp", IntIp(hostinfo.hostId)).WithField("udpAddr", addr).						WithField("handshake", m{"stage": 2, "style": "ix_psk0"}).WithField("cached", true).						WithError(err).Error("Failed to send handshake message")				} else {					l.WithField("vpnIp", IntIp(hostinfo.hostId)).WithField("udpAddr", addr).						WithField("handshake", m{"stage": 2, "style": "ix_psk0"}).WithField("cached", true).						Info("Handshake message sent")				}				return false			}			l.WithField("vpnIp", IntIp(hostinfo.hostId)).WithField("udpAddr", addr).				WithField("handshake", m{"stage": 1, "style": "ix_psk0"}).WithField("cached", true).				WithField("packets", hostinfo.HandshakePacket).				Error("Seen this handshake packet already but don't have a cached packet to return")		}		remoteCert, err := RecombineCertAndValidate(ci.H, hs.Details.Cert)		if err != nil {			l.WithError(err).WithField("udpAddr", addr).				WithField("handshake", m{"stage": 1, "style": "ix_psk0"}).WithField("cert", remoteCert).				Info("Invalid certificate from host")			return true		}		vpnIP := ip2int(remoteCert.Details.Ips[0].IP)		certName := remoteCert.Details.Name		fingerprint, _ := remoteCert.Sha256Sum()		myIndex, err := generateIndex()		if err != nil {			l.WithError(err).WithField("vpnIp", IntIp(vpnIP)).WithField("udpAddr", addr).				WithField("certName", certName).				WithField("fingerprint", fingerprint).				WithField("handshake", m{"stage": 1, "style": "ix_psk0"}).Error("Failed to generate index")			return true		}		hostinfo, err = f.handshakeManager.AddIndex(myIndex, ci)		if err != nil {			l.WithError(err).WithField("vpnIp", IntIp(vpnIP)).WithField("udpAddr", addr).				WithField("certName", certName).				WithField("fingerprint", fingerprint).				WithField("handshake", m{"stage": 1, "style": "ix_psk0"}).Error("Error adding index to connection manager")			return true		}		l.WithField("vpnIp", IntIp(vpnIP)).WithField("udpAddr", addr).			WithField("certName", certName).			WithField("fingerprint", fingerprint).			WithField("initiatorIndex", hs.Details.InitiatorIndex).WithField("responderIndex", hs.Details.ResponderIndex).			WithField("remoteIndex", h.RemoteIndex).WithField("handshake", m{"stage": 1, "style": "ix_psk0"}).			Info("Handshake message received")		hostinfo.remoteIndexId = hs.Details.InitiatorIndex		hs.Details.ResponderIndex = myIndex		hs.Details.Cert = ci.certState.rawCertificateNoKey		hsBytes, err := proto.Marshal(hs)		if err != nil {			l.WithError(err).WithField("vpnIp", IntIp(hostinfo.hostId)).WithField("udpAddr", addr).				WithField("certName", certName).				WithField("fingerprint", fingerprint).				WithField("handshake", m{"stage": 1, "style": "ix_psk0"}).Error("Failed to marshal handshake message")			return true		}		header := HeaderEncode(make([]byte, HeaderLen), Version, uint8(handshake), handshakeIXPSK0, hs.Details.InitiatorIndex, 2)		msg, dKey, eKey, err := ci.H.WriteMessage(header, hsBytes)		if err != nil {			l.WithError(err).WithField("vpnIp", IntIp(hostinfo.hostId)).WithField("udpAddr", addr).				WithField("certName", certName).				WithField("fingerprint", fingerprint).				WithField("handshake", m{"stage": 1, "style": "ix_psk0"}).Error("Failed to call noise.WriteMessage")			return true		}		if f.hostMap.CheckHandshakeCompleteIP(vpnIP) && vpnIP < ip2int(f.certState.certificate.Details.Ips[0].IP) {			l.WithField("vpnIp", IntIp(vpnIP)).WithField("udpAddr", addr).				WithField("certName", certName).				WithField("fingerprint", fingerprint).				WithField("initiatorIndex", hs.Details.InitiatorIndex).WithField("responderIndex", hs.Details.ResponderIndex).				WithField("remoteIndex", h.RemoteIndex).WithField("handshake", m{"stage": 1, "style": "ix_psk0"}).				Info("Prevented a handshake race")			// Send a test packet to trigger an authenticated tunnel test, this should suss out any lingering tunnel issues			f.SendMessageToVpnIp(test, testRequest, vpnIP, []byte(""), make([]byte, 12, 12), make([]byte, mtu))			return true		}		hostinfo.HandshakePacket[0] = make([]byte, len(packet[HeaderLen:]))		copy(hostinfo.HandshakePacket[0], packet[HeaderLen:])		// Regardless of whether you are the sender or receiver, you should arrive here		// and complete standing up the connection.		if dKey != nil && eKey != nil {			hostinfo.HandshakePacket[2] = make([]byte, len(msg))			copy(hostinfo.HandshakePacket[2], msg)			f.messageMetrics.Tx(handshake, NebulaMessageSubType(msg[1]), 1)			err := f.outside.WriteTo(msg, addr)			if err != nil {				l.WithField("vpnIp", IntIp(vpnIP)).WithField("udpAddr", addr).					WithField("certName", certName).					WithField("fingerprint", fingerprint).					WithField("initiatorIndex", hs.Details.InitiatorIndex).WithField("responderIndex", hs.Details.ResponderIndex).					WithField("remoteIndex", h.RemoteIndex).WithField("handshake", m{"stage": 2, "style": "ix_psk0"}).					WithError(err).Error("Failed to send handshake")			} else {				l.WithField("vpnIp", IntIp(vpnIP)).WithField("udpAddr", addr).					WithField("certName", certName).					WithField("fingerprint", fingerprint).					WithField("initiatorIndex", hs.Details.InitiatorIndex).WithField("responderIndex", hs.Details.ResponderIndex).					WithField("remoteIndex", h.RemoteIndex).WithField("handshake", m{"stage": 2, "style": "ix_psk0"}).					Info("Handshake message sent")			}			ip = ip2int(remoteCert.Details.Ips[0].IP)			ci.peerCert = remoteCert			ci.dKey = NewNebulaCipherState(dKey)			ci.eKey = NewNebulaCipherState(eKey)			//l.Debugln("got symmetric pairs")			//hostinfo.ClearRemotes()			hostinfo.AddRemote(*addr)			hostinfo.CreateRemoteCIDR(remoteCert)			f.lightHouse.AddRemoteAndReset(ip, addr)			if f.serveDns {				dnsR.Add(remoteCert.Details.Name+".", remoteCert.Details.Ips[0].IP.String())			}			ho, err := f.hostMap.QueryVpnIP(vpnIP)			if err == nil && ho.localIndexId != 0 {				l.WithField("vpnIp", vpnIP).					WithField("certName", certName).					WithField("fingerprint", fingerprint).					WithField("action", "removing stale index").					WithField("index", ho.localIndexId).					Debug("Handshake processing")				f.hostMap.DeleteIndex(ho.localIndexId)			}			f.hostMap.AddIndexHostInfo(hostinfo.localIndexId, hostinfo)			f.hostMap.AddVpnIPHostInfo(vpnIP, hostinfo)			hostinfo.handshakeComplete()		} else {			l.WithField("vpnIp", IntIp(hostinfo.hostId)).WithField("udpAddr", addr).				WithField("certName", certName).				WithField("fingerprint", fingerprint).				WithField("handshake", m{"stage": 1, "style": "ix_psk0"}).				Error("Noise did not arrive at a key")			return true		}	}	f.hostMap.AddRemote(ip, addr)	return false}func ixHandshakeStage2(f *Interface, addr *udpAddr, hostinfo *HostInfo, packet []byte, h *Header) bool {	if hostinfo == nil {		return true	}	if bytes.Equal(hostinfo.HandshakePacket[2], packet[HeaderLen:]) {		l.WithField("vpnIp", IntIp(hostinfo.hostId)).WithField("udpAddr", addr).			WithField("handshake", m{"stage": 2, "style": "ix_psk0"}).WithField("header", h).			Error("Already seen this handshake packet")		return false	}	ci := hostinfo.ConnectionState	// Mark packet 2 as seen so it doesn't show up as missed	ci.window.Update(2)	hostinfo.HandshakePacket[2] = make([]byte, len(packet[HeaderLen:]))	copy(hostinfo.HandshakePacket[2], packet[HeaderLen:])	msg, eKey, dKey, err := ci.H.ReadMessage(nil, packet[HeaderLen:])	if err != nil {		l.WithError(err).WithField("vpnIp", IntIp(hostinfo.hostId)).WithField("udpAddr", addr).			WithField("handshake", m{"stage": 2, "style": "ix_psk0"}).WithField("header", h).			Error("Failed to call noise.ReadMessage")		// We don't want to tear down the connection on a bad ReadMessage because it could be an attacker trying		// to DOS us. Every other error condition after should to allow a possible good handshake to complete in the		// near future		return false	}	hs := &NebulaHandshake{}	err = proto.Unmarshal(msg, hs)	if err != nil || hs.Details == nil {		l.WithError(err).WithField("vpnIp", IntIp(hostinfo.hostId)).WithField("udpAddr", addr).			WithField("handshake", m{"stage": 2, "style": "ix_psk0"}).Error("Failed unmarshal handshake message")		return true	}	remoteCert, err := RecombineCertAndValidate(ci.H, hs.Details.Cert)	if err != nil {		l.WithError(err).WithField("vpnIp", IntIp(hostinfo.hostId)).WithField("udpAddr", addr).			WithField("cert", remoteCert).WithField("handshake", m{"stage": 2, "style": "ix_psk0"}).			Error("Invalid certificate from host")		return true	}	vpnIP := ip2int(remoteCert.Details.Ips[0].IP)	certName := remoteCert.Details.Name	fingerprint, _ := remoteCert.Sha256Sum()	duration := time.Since(hostinfo.handshakeStart).Nanoseconds()	l.WithField("vpnIp", IntIp(vpnIP)).WithField("udpAddr", addr).		WithField("certName", certName).		WithField("fingerprint", fingerprint).		WithField("initiatorIndex", hs.Details.InitiatorIndex).WithField("responderIndex", hs.Details.ResponderIndex).		WithField("remoteIndex", h.RemoteIndex).WithField("handshake", m{"stage": 2, "style": "ix_psk0"}).		WithField("durationNs", duration).		Info("Handshake message received")	//ci.remoteIndex = hs.ResponderIndex	hostinfo.remoteIndexId = hs.Details.ResponderIndex	hs.Details.Cert = ci.certState.rawCertificateNoKey	/*		hsBytes, err := proto.Marshal(hs)		if err != nil {			l.Debugln("Failed to marshal handshake: ", err)			return		}	*/	// Regardless of whether you are the sender or receiver, you should arrive here	// and complete standing up the connection.	if dKey != nil && eKey != nil {		ip := ip2int(remoteCert.Details.Ips[0].IP)		ci.peerCert = remoteCert		ci.dKey = NewNebulaCipherState(dKey)		ci.eKey = NewNebulaCipherState(eKey)		//l.Debugln("got symmetric pairs")		//hostinfo.ClearRemotes()		f.hostMap.AddRemote(ip, addr)		hostinfo.CreateRemoteCIDR(remoteCert)		f.lightHouse.AddRemoteAndReset(ip, addr)		if f.serveDns {			dnsR.Add(remoteCert.Details.Name+".", remoteCert.Details.Ips[0].IP.String())		}		ho, err := f.hostMap.QueryVpnIP(vpnIP)		if err == nil && ho.localIndexId != 0 {			l.WithField("vpnIp", vpnIP).				WithField("certName", certName).				WithField("fingerprint", fingerprint).				WithField("action", "removing stale index").				WithField("index", ho.localIndexId).				Debug("Handshake processing")			f.hostMap.DeleteIndex(ho.localIndexId)		}		f.hostMap.AddVpnIPHostInfo(vpnIP, hostinfo)		f.hostMap.AddIndexHostInfo(hostinfo.localIndexId, hostinfo)		hostinfo.handshakeComplete()		f.metricHandshakes.Update(duration)	} else {		l.WithField("vpnIp", IntIp(hostinfo.hostId)).WithField("udpAddr", addr).			WithField("certName", certName).			WithField("fingerprint", fingerprint).			WithField("handshake", m{"stage": 2, "style": "ix_psk0"}).			Error("Noise did not arrive at a key")		return true	}	return false}
 |