123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377 |
- package nebula
- import (
- "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 manager
- func 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
- }
|