2019-11-19 10:00:20 -07:00
|
|
|
package nebula
|
|
|
|
|
|
|
|
import (
|
|
|
|
"time"
|
|
|
|
|
|
|
|
"github.com/flynn/noise"
|
2021-11-03 19:54:04 -06:00
|
|
|
"github.com/slackhq/nebula/header"
|
|
|
|
"github.com/slackhq/nebula/iputil"
|
|
|
|
"github.com/slackhq/nebula/udp"
|
2019-11-19 10:00:20 -07:00
|
|
|
)
|
|
|
|
|
|
|
|
// NOISE IX Handshakes
|
|
|
|
|
|
|
|
// This function constructs a handshake packet, but does not actually send it
|
|
|
|
// Sending is done by the handshake manager
|
2021-11-03 19:54:04 -06:00
|
|
|
func ixHandshakeStage0(f *Interface, vpnIp iputil.VpnIp, hostinfo *HostInfo) {
|
2019-11-19 10:00:20 -07:00
|
|
|
// This queries the lighthouse if we don't know a remote for the host
|
2021-04-14 12:50:09 -06:00
|
|
|
// We do it here to provoke the lighthouse to preempt our timer wheel and trigger the stage 1 packet to send
|
|
|
|
// more quickly, effect is a quicker handshake.
|
2019-11-19 10:00:20 -07:00
|
|
|
if hostinfo.remote == nil {
|
2021-04-14 12:50:09 -06:00
|
|
|
f.lightHouse.QueryServer(vpnIp, f)
|
2019-11-19 10:00:20 -07:00
|
|
|
}
|
|
|
|
|
2021-03-12 12:16:25 -07:00
|
|
|
err := f.handshakeManager.AddIndexHostInfo(hostinfo)
|
2019-11-19 10:00:20 -07:00
|
|
|
if err != nil {
|
2021-11-03 19:54:04 -06:00
|
|
|
f.l.WithError(err).WithField("vpnIp", vpnIp).
|
2019-11-19 10:00:20 -07:00
|
|
|
WithField("handshake", m{"stage": 0, "style": "ix_psk0"}).Error("Failed to generate index")
|
|
|
|
return
|
|
|
|
}
|
2021-03-12 12:16:25 -07:00
|
|
|
|
2019-11-19 10:00:20 -07:00
|
|
|
ci := hostinfo.ConnectionState
|
|
|
|
|
|
|
|
hsProto := &NebulaHandshakeDetails{
|
2021-03-12 12:16:25 -07:00
|
|
|
InitiatorIndex: hostinfo.localIndexId,
|
2021-05-03 13:10:00 -06:00
|
|
|
Time: uint64(time.Now().UnixNano()),
|
2019-11-19 10:00:20 -07:00
|
|
|
Cert: ci.certState.rawCertificateNoKey,
|
|
|
|
}
|
|
|
|
|
2019-11-23 09:50:36 -07:00
|
|
|
hsBytes := []byte{}
|
|
|
|
|
2019-11-19 10:00:20 -07:00
|
|
|
hs := &NebulaHandshake{
|
|
|
|
Details: hsProto,
|
|
|
|
}
|
2022-04-18 10:12:25 -06:00
|
|
|
hsBytes, err = hs.Marshal()
|
2019-11-19 10:00:20 -07:00
|
|
|
|
|
|
|
if err != nil {
|
2021-11-03 19:54:04 -06:00
|
|
|
f.l.WithError(err).WithField("vpnIp", vpnIp).
|
2019-11-19 10:00:20 -07:00
|
|
|
WithField("handshake", m{"stage": 0, "style": "ix_psk0"}).Error("Failed to marshal handshake message")
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
2021-11-03 19:54:04 -06:00
|
|
|
h := header.Encode(make([]byte, header.Len), header.Version, header.Handshake, header.HandshakeIXPSK0, 0, 1)
|
2022-10-31 11:37:41 -06:00
|
|
|
ci.messageCounter.Add(1)
|
2019-11-19 10:00:20 -07:00
|
|
|
|
2021-11-03 19:54:04 -06:00
|
|
|
msg, _, _, err := ci.H.WriteMessage(h, hsBytes)
|
2019-11-19 10:00:20 -07:00
|
|
|
if err != nil {
|
2021-11-03 19:54:04 -06:00
|
|
|
f.l.WithError(err).WithField("vpnIp", vpnIp).
|
2019-11-19 10:00:20 -07:00
|
|
|
WithField("handshake", m{"stage": 0, "style": "ix_psk0"}).Error("Failed to call noise.WriteMessage")
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
2020-11-16 12:03:08 -07:00
|
|
|
// We are sending handshake packet 1, so we don't expect to receive
|
|
|
|
// handshake packet 1 from the responder
|
2021-03-26 08:46:30 -06:00
|
|
|
ci.window.Update(f.l, 1)
|
2020-11-16 12:03:08 -07:00
|
|
|
|
2019-11-19 10:00:20 -07:00
|
|
|
hostinfo.HandshakePacket[0] = msg
|
|
|
|
hostinfo.HandshakeReady = true
|
|
|
|
hostinfo.handshakeStart = time.Now()
|
|
|
|
}
|
|
|
|
|
2022-06-21 12:35:23 -06:00
|
|
|
func ixHandshakeStage1(f *Interface, addr *udp.Addr, via interface{}, packet []byte, h *header.H) {
|
2021-03-26 08:46:30 -06:00
|
|
|
ci := f.newConnectionState(f.l, false, noise.HandshakeIX, []byte{}, 0)
|
2021-03-12 12:16:25 -07:00
|
|
|
// Mark packet 1 as seen so it doesn't show up as missed
|
2021-03-26 08:46:30 -06:00
|
|
|
ci.window.Update(f.l, 1)
|
2019-11-19 10:00:20 -07:00
|
|
|
|
2021-11-03 19:54:04 -06:00
|
|
|
msg, _, _, err := ci.H.ReadMessage(nil, packet[header.Len:])
|
2021-03-12 12:16:25 -07:00
|
|
|
if err != nil {
|
2021-03-26 08:46:30 -06:00
|
|
|
f.l.WithError(err).WithField("udpAddr", addr).
|
2021-03-12 12:16:25 -07:00
|
|
|
WithField("handshake", m{"stage": 1, "style": "ix_psk0"}).Error("Failed to call noise.ReadMessage")
|
|
|
|
return
|
|
|
|
}
|
2019-11-19 10:00:20 -07:00
|
|
|
|
2021-03-12 12:16:25 -07:00
|
|
|
hs := &NebulaHandshake{}
|
2022-04-18 10:12:25 -06:00
|
|
|
err = hs.Unmarshal(msg)
|
2021-03-12 12:16:25 -07:00
|
|
|
/*
|
|
|
|
l.Debugln("GOT INDEX: ", hs.Details.InitiatorIndex)
|
|
|
|
*/
|
|
|
|
if err != nil || hs.Details == nil {
|
2021-03-26 08:46:30 -06:00
|
|
|
f.l.WithError(err).WithField("udpAddr", addr).
|
2021-03-12 12:16:25 -07:00
|
|
|
WithField("handshake", m{"stage": 1, "style": "ix_psk0"}).Error("Failed unmarshal handshake message")
|
|
|
|
return
|
|
|
|
}
|
2019-11-19 10:00:20 -07:00
|
|
|
|
2021-03-29 11:10:19 -06:00
|
|
|
remoteCert, err := RecombineCertAndValidate(ci.H, hs.Details.Cert, f.caPool)
|
2021-03-12 12:16:25 -07:00
|
|
|
if err != nil {
|
2021-03-26 08:46:30 -06:00
|
|
|
f.l.WithError(err).WithField("udpAddr", addr).
|
2021-03-12 12:16:25 -07:00
|
|
|
WithField("handshake", m{"stage": 1, "style": "ix_psk0"}).WithField("cert", remoteCert).
|
|
|
|
Info("Invalid certificate from host")
|
|
|
|
return
|
|
|
|
}
|
2021-11-03 19:54:04 -06:00
|
|
|
vpnIp := iputil.Ip2VpnIp(remoteCert.Details.Ips[0].IP)
|
2021-03-12 12:16:25 -07:00
|
|
|
certName := remoteCert.Details.Name
|
|
|
|
fingerprint, _ := remoteCert.Sha256Sum()
|
2021-08-30 19:57:38 -06:00
|
|
|
issuer := remoteCert.Details.Issuer
|
2019-11-19 10:00:20 -07:00
|
|
|
|
2021-11-03 19:54:04 -06:00
|
|
|
if vpnIp == f.myVpnIp {
|
|
|
|
f.l.WithField("vpnIp", vpnIp).WithField("udpAddr", addr).
|
2021-03-15 13:58:23 -06:00
|
|
|
WithField("certName", certName).
|
|
|
|
WithField("fingerprint", fingerprint).
|
2021-08-30 19:57:38 -06:00
|
|
|
WithField("issuer", issuer).
|
2021-03-15 13:58:23 -06:00
|
|
|
WithField("handshake", m{"stage": 1, "style": "ix_psk0"}).Error("Refusing to handshake with myself")
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
2022-06-21 12:35:23 -06:00
|
|
|
if addr != nil {
|
|
|
|
if !f.lightHouse.GetRemoteAllowList().Allow(vpnIp, addr.IP) {
|
|
|
|
f.l.WithField("vpnIp", vpnIp).WithField("udpAddr", addr).Debug("lighthouse.remote_allow_list denied incoming handshake")
|
|
|
|
return
|
|
|
|
}
|
2021-10-19 08:54:30 -06:00
|
|
|
}
|
|
|
|
|
2021-03-26 08:46:30 -06:00
|
|
|
myIndex, err := generateIndex(f.l)
|
2021-03-12 12:16:25 -07:00
|
|
|
if err != nil {
|
2021-11-03 19:54:04 -06:00
|
|
|
f.l.WithError(err).WithField("vpnIp", vpnIp).WithField("udpAddr", addr).
|
2021-03-12 12:16:25 -07:00
|
|
|
WithField("certName", certName).
|
|
|
|
WithField("fingerprint", fingerprint).
|
2021-08-30 19:57:38 -06:00
|
|
|
WithField("issuer", issuer).
|
2021-03-12 12:16:25 -07:00
|
|
|
WithField("handshake", m{"stage": 1, "style": "ix_psk0"}).Error("Failed to generate index")
|
|
|
|
return
|
|
|
|
}
|
2019-11-19 10:00:20 -07:00
|
|
|
|
2021-03-12 12:16:25 -07:00
|
|
|
hostinfo := &HostInfo{
|
2021-04-27 20:15:34 -06:00
|
|
|
ConnectionState: ci,
|
|
|
|
localIndexId: myIndex,
|
|
|
|
remoteIndexId: hs.Details.InitiatorIndex,
|
2021-11-03 19:54:04 -06:00
|
|
|
vpnIp: vpnIp,
|
2021-04-27 20:15:34 -06:00
|
|
|
HandshakePacket: make(map[uint8][]byte, 0),
|
|
|
|
lastHandshakeTime: hs.Details.Time,
|
2022-06-21 12:35:23 -06:00
|
|
|
relayState: RelayState{
|
|
|
|
relays: map[iputil.VpnIp]struct{}{},
|
|
|
|
relayForByIp: map[iputil.VpnIp]*Relay{},
|
|
|
|
relayForByIdx: map[uint32]*Relay{},
|
|
|
|
},
|
2021-03-12 12:16:25 -07:00
|
|
|
}
|
2019-11-19 10:00:20 -07:00
|
|
|
|
2021-04-14 12:50:09 -06:00
|
|
|
hostinfo.Lock()
|
|
|
|
defer hostinfo.Unlock()
|
|
|
|
|
2021-11-03 19:54:04 -06:00
|
|
|
f.l.WithField("vpnIp", vpnIp).WithField("udpAddr", addr).
|
2021-03-12 12:16:25 -07:00
|
|
|
WithField("certName", certName).
|
|
|
|
WithField("fingerprint", fingerprint).
|
2021-08-30 19:57:38 -06:00
|
|
|
WithField("issuer", issuer).
|
2021-03-12 12:16:25 -07:00
|
|
|
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")
|
2019-11-19 10:00:20 -07:00
|
|
|
|
2021-03-12 12:16:25 -07:00
|
|
|
hs.Details.ResponderIndex = myIndex
|
|
|
|
hs.Details.Cert = ci.certState.rawCertificateNoKey
|
2021-04-27 20:15:34 -06:00
|
|
|
// Update the time in case their clock is way off from ours
|
2021-05-03 13:10:00 -06:00
|
|
|
hs.Details.Time = uint64(time.Now().UnixNano())
|
2021-03-05 19:18:33 -07:00
|
|
|
|
2022-04-18 10:12:25 -06:00
|
|
|
hsBytes, err := hs.Marshal()
|
2021-03-12 12:16:25 -07:00
|
|
|
if err != nil {
|
2021-11-03 19:54:04 -06:00
|
|
|
f.l.WithError(err).WithField("vpnIp", hostinfo.vpnIp).WithField("udpAddr", addr).
|
2020-04-06 12:34:00 -06:00
|
|
|
WithField("certName", certName).
|
2020-07-31 16:54:51 -06:00
|
|
|
WithField("fingerprint", fingerprint).
|
2021-08-30 19:57:38 -06:00
|
|
|
WithField("issuer", issuer).
|
2021-03-12 12:16:25 -07:00
|
|
|
WithField("handshake", m{"stage": 1, "style": "ix_psk0"}).Error("Failed to marshal handshake message")
|
|
|
|
return
|
|
|
|
}
|
2019-11-19 10:00:20 -07:00
|
|
|
|
2021-11-03 19:54:04 -06:00
|
|
|
nh := header.Encode(make([]byte, header.Len), header.Version, header.Handshake, header.HandshakeIXPSK0, hs.Details.InitiatorIndex, 2)
|
|
|
|
msg, dKey, eKey, err := ci.H.WriteMessage(nh, hsBytes)
|
2021-03-12 12:16:25 -07:00
|
|
|
if err != nil {
|
2021-11-03 19:54:04 -06:00
|
|
|
f.l.WithError(err).WithField("vpnIp", hostinfo.vpnIp).WithField("udpAddr", addr).
|
2021-03-12 12:16:25 -07:00
|
|
|
WithField("certName", certName).
|
|
|
|
WithField("fingerprint", fingerprint).
|
2021-08-30 19:57:38 -06:00
|
|
|
WithField("issuer", issuer).
|
2021-03-12 12:16:25 -07:00
|
|
|
WithField("handshake", m{"stage": 1, "style": "ix_psk0"}).Error("Failed to call noise.WriteMessage")
|
|
|
|
return
|
|
|
|
} else if dKey == nil || eKey == nil {
|
2021-11-03 19:54:04 -06:00
|
|
|
f.l.WithField("vpnIp", hostinfo.vpnIp).WithField("udpAddr", addr).
|
2021-03-12 12:16:25 -07:00
|
|
|
WithField("certName", certName).
|
|
|
|
WithField("fingerprint", fingerprint).
|
2021-08-30 19:57:38 -06:00
|
|
|
WithField("issuer", issuer).
|
2021-03-12 12:16:25 -07:00
|
|
|
WithField("handshake", m{"stage": 1, "style": "ix_psk0"}).Error("Noise did not arrive at a key")
|
|
|
|
return
|
|
|
|
}
|
2019-11-19 10:00:20 -07:00
|
|
|
|
2021-11-03 19:54:04 -06:00
|
|
|
hostinfo.HandshakePacket[0] = make([]byte, len(packet[header.Len:]))
|
|
|
|
copy(hostinfo.HandshakePacket[0], packet[header.Len:])
|
2019-11-19 10:00:20 -07:00
|
|
|
|
2021-03-12 12:16:25 -07:00
|
|
|
// Regardless of whether you are the sender or receiver, you should arrive here
|
|
|
|
// and complete standing up the connection.
|
|
|
|
hostinfo.HandshakePacket[2] = make([]byte, len(msg))
|
|
|
|
copy(hostinfo.HandshakePacket[2], msg)
|
2019-11-19 10:00:20 -07:00
|
|
|
|
2021-03-12 12:16:25 -07:00
|
|
|
// We are sending handshake packet 2, so we don't expect to receive
|
|
|
|
// handshake packet 2 from the initiator.
|
2021-03-26 08:46:30 -06:00
|
|
|
ci.window.Update(f.l, 2)
|
2019-11-19 10:00:20 -07:00
|
|
|
|
2021-03-12 12:16:25 -07:00
|
|
|
ci.peerCert = remoteCert
|
|
|
|
ci.dKey = NewNebulaCipherState(dKey)
|
|
|
|
ci.eKey = NewNebulaCipherState(eKey)
|
2019-11-19 10:00:20 -07:00
|
|
|
|
2021-11-03 19:54:04 -06:00
|
|
|
hostinfo.remotes = f.lightHouse.QueryCache(vpnIp)
|
2021-04-14 12:50:09 -06:00
|
|
|
hostinfo.SetRemote(addr)
|
2021-03-12 12:16:25 -07:00
|
|
|
hostinfo.CreateRemoteCIDR(remoteCert)
|
2019-11-19 10:00:20 -07:00
|
|
|
|
2023-03-13 11:35:14 -06:00
|
|
|
existing, err := f.handshakeManager.CheckAndComplete(hostinfo, 0, f)
|
2021-03-12 12:16:25 -07:00
|
|
|
if err != nil {
|
|
|
|
switch err {
|
|
|
|
case ErrAlreadySeen:
|
2021-10-19 08:53:55 -06:00
|
|
|
// Update remote if preferred (Note we have to switch to locking
|
|
|
|
// the existing hostinfo, and then switch back so the defer Unlock
|
|
|
|
// higher in this function still works)
|
|
|
|
hostinfo.Unlock()
|
|
|
|
existing.Lock()
|
|
|
|
// Update remote if preferred
|
|
|
|
if existing.SetRemoteIfPreferred(f.hostMap, addr) {
|
|
|
|
// Send a test packet to ensure the other side has also switched to
|
|
|
|
// the preferred remote
|
2021-11-03 19:54:04 -06:00
|
|
|
f.SendMessageToVpnIp(header.Test, header.TestRequest, vpnIp, []byte(""), make([]byte, 12, 12), make([]byte, mtu))
|
2021-10-19 08:53:55 -06:00
|
|
|
}
|
|
|
|
existing.Unlock()
|
|
|
|
hostinfo.Lock()
|
|
|
|
|
2021-03-12 12:16:25 -07:00
|
|
|
msg = existing.HandshakePacket[2]
|
2021-11-03 19:54:04 -06:00
|
|
|
f.messageMetrics.Tx(header.Handshake, header.MessageSubType(msg[1]), 1)
|
2022-06-21 12:35:23 -06:00
|
|
|
if addr != nil {
|
|
|
|
err := f.outside.WriteTo(msg, addr)
|
|
|
|
if err != nil {
|
|
|
|
f.l.WithField("vpnIp", existing.vpnIp).WithField("udpAddr", addr).
|
|
|
|
WithField("handshake", m{"stage": 2, "style": "ix_psk0"}).WithField("cached", true).
|
|
|
|
WithError(err).Error("Failed to send handshake message")
|
|
|
|
} else {
|
|
|
|
f.l.WithField("vpnIp", existing.vpnIp).WithField("udpAddr", addr).
|
|
|
|
WithField("handshake", m{"stage": 2, "style": "ix_psk0"}).WithField("cached", true).
|
|
|
|
Info("Handshake message sent")
|
|
|
|
}
|
|
|
|
return
|
2019-11-19 10:00:20 -07:00
|
|
|
} else {
|
2022-06-21 12:35:23 -06:00
|
|
|
via2 := via.(*ViaSender)
|
|
|
|
if via2 == nil {
|
|
|
|
f.l.Error("Handshake send failed: both addr and via are nil.")
|
|
|
|
return
|
|
|
|
}
|
|
|
|
hostinfo.relayState.InsertRelayTo(via2.relayHI.vpnIp)
|
|
|
|
f.SendVia(via2.relayHI, via2.relay, msg, make([]byte, 12), make([]byte, mtu), false)
|
|
|
|
f.l.WithField("vpnIp", existing.vpnIp).WithField("relay", via2.relayHI.vpnIp).
|
2021-03-12 12:16:25 -07:00
|
|
|
WithField("handshake", m{"stage": 2, "style": "ix_psk0"}).WithField("cached", true).
|
2019-11-19 10:00:20 -07:00
|
|
|
Info("Handshake message sent")
|
2022-06-21 12:35:23 -06:00
|
|
|
return
|
2019-11-19 10:00:20 -07:00
|
|
|
}
|
2021-03-12 12:16:25 -07:00
|
|
|
case ErrExistingHostInfo:
|
2021-04-27 20:15:34 -06:00
|
|
|
// This means there was an existing tunnel and this handshake was older than the one we are currently based on
|
2021-11-03 19:54:04 -06:00
|
|
|
f.l.WithField("vpnIp", vpnIp).WithField("udpAddr", addr).
|
2021-03-12 12:16:25 -07:00
|
|
|
WithField("certName", certName).
|
2021-04-27 20:15:34 -06:00
|
|
|
WithField("oldHandshakeTime", existing.lastHandshakeTime).
|
|
|
|
WithField("newHandshakeTime", hostinfo.lastHandshakeTime).
|
2021-03-12 12:16:25 -07:00
|
|
|
WithField("fingerprint", fingerprint).
|
2021-08-30 19:57:38 -06:00
|
|
|
WithField("issuer", issuer).
|
2021-03-12 12:16:25 -07:00
|
|
|
WithField("initiatorIndex", hs.Details.InitiatorIndex).WithField("responderIndex", hs.Details.ResponderIndex).
|
|
|
|
WithField("remoteIndex", h.RemoteIndex).WithField("handshake", m{"stage": 1, "style": "ix_psk0"}).
|
2021-04-27 20:15:34 -06:00
|
|
|
Info("Handshake too old")
|
2019-11-19 10:00:20 -07:00
|
|
|
|
2021-03-12 12:16:25 -07:00
|
|
|
// Send a test packet to trigger an authenticated tunnel test, this should suss out any lingering tunnel issues
|
2021-11-03 19:54:04 -06:00
|
|
|
f.SendMessageToVpnIp(header.Test, header.TestRequest, vpnIp, []byte(""), make([]byte, 12, 12), make([]byte, mtu))
|
2021-03-12 12:16:25 -07:00
|
|
|
return
|
|
|
|
case ErrLocalIndexCollision:
|
|
|
|
// This means we failed to insert because of collision on localIndexId. Just let the next handshake packet retry
|
2021-11-03 19:54:04 -06:00
|
|
|
f.l.WithField("vpnIp", vpnIp).WithField("udpAddr", addr).
|
2021-03-12 12:16:25 -07:00
|
|
|
WithField("certName", certName).
|
|
|
|
WithField("fingerprint", fingerprint).
|
2021-08-30 19:57:38 -06:00
|
|
|
WithField("issuer", issuer).
|
2021-03-12 12:16:25 -07:00
|
|
|
WithField("initiatorIndex", hs.Details.InitiatorIndex).WithField("responderIndex", hs.Details.ResponderIndex).
|
|
|
|
WithField("remoteIndex", h.RemoteIndex).WithField("handshake", m{"stage": 1, "style": "ix_psk0"}).
|
2021-11-03 19:54:04 -06:00
|
|
|
WithField("localIndex", hostinfo.localIndexId).WithField("collision", existing.vpnIp).
|
2021-03-12 12:16:25 -07:00
|
|
|
Error("Failed to add HostInfo due to localIndex collision")
|
|
|
|
return
|
|
|
|
default:
|
|
|
|
// Shouldn't happen, but just in case someone adds a new error type to CheckAndComplete
|
|
|
|
// And we forget to update it here
|
2021-11-03 19:54:04 -06:00
|
|
|
f.l.WithError(err).WithField("vpnIp", vpnIp).WithField("udpAddr", addr).
|
2020-04-06 12:34:00 -06:00
|
|
|
WithField("certName", certName).
|
2020-07-31 16:54:51 -06:00
|
|
|
WithField("fingerprint", fingerprint).
|
2021-08-30 19:57:38 -06:00
|
|
|
WithField("issuer", issuer).
|
2021-03-12 12:16:25 -07:00
|
|
|
WithField("initiatorIndex", hs.Details.InitiatorIndex).WithField("responderIndex", hs.Details.ResponderIndex).
|
|
|
|
WithField("remoteIndex", h.RemoteIndex).WithField("handshake", m{"stage": 1, "style": "ix_psk0"}).
|
|
|
|
Error("Failed to add HostInfo to HostMap")
|
|
|
|
return
|
2019-11-19 10:00:20 -07:00
|
|
|
}
|
2021-03-12 12:16:25 -07:00
|
|
|
}
|
2019-11-19 10:00:20 -07:00
|
|
|
|
2021-03-12 12:16:25 -07:00
|
|
|
// Do the send
|
2021-11-03 19:54:04 -06:00
|
|
|
f.messageMetrics.Tx(header.Handshake, header.MessageSubType(msg[1]), 1)
|
2022-06-21 12:35:23 -06:00
|
|
|
if addr != nil {
|
|
|
|
err = f.outside.WriteTo(msg, addr)
|
|
|
|
if err != nil {
|
|
|
|
f.l.WithField("vpnIp", vpnIp).WithField("udpAddr", addr).
|
|
|
|
WithField("certName", certName).
|
|
|
|
WithField("fingerprint", fingerprint).
|
|
|
|
WithField("issuer", issuer).
|
|
|
|
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 {
|
|
|
|
f.l.WithField("vpnIp", vpnIp).WithField("udpAddr", addr).
|
|
|
|
WithField("certName", certName).
|
|
|
|
WithField("fingerprint", fingerprint).
|
|
|
|
WithField("issuer", issuer).
|
|
|
|
WithField("initiatorIndex", hs.Details.InitiatorIndex).WithField("responderIndex", hs.Details.ResponderIndex).
|
|
|
|
WithField("remoteIndex", h.RemoteIndex).WithField("handshake", m{"stage": 2, "style": "ix_psk0"}).
|
|
|
|
WithField("sentCachedPackets", len(hostinfo.packetStore)).
|
|
|
|
Info("Handshake message sent")
|
|
|
|
}
|
2021-03-12 12:16:25 -07:00
|
|
|
} else {
|
2022-06-21 12:35:23 -06:00
|
|
|
via2 := via.(*ViaSender)
|
|
|
|
if via2 == nil {
|
|
|
|
f.l.Error("Handshake send failed: both addr and via are nil.")
|
|
|
|
return
|
|
|
|
}
|
|
|
|
hostinfo.relayState.InsertRelayTo(via2.relayHI.vpnIp)
|
|
|
|
f.SendVia(via2.relayHI, via2.relay, msg, make([]byte, 12), make([]byte, mtu), false)
|
|
|
|
f.l.WithField("vpnIp", vpnIp).WithField("relay", via2.relayHI.vpnIp).
|
2021-03-12 12:16:25 -07:00
|
|
|
WithField("certName", certName).
|
|
|
|
WithField("fingerprint", fingerprint).
|
2021-08-30 19:57:38 -06:00
|
|
|
WithField("issuer", issuer).
|
2021-03-12 12:16:25 -07:00
|
|
|
WithField("initiatorIndex", hs.Details.InitiatorIndex).WithField("responderIndex", hs.Details.ResponderIndex).
|
|
|
|
WithField("remoteIndex", h.RemoteIndex).WithField("handshake", m{"stage": 2, "style": "ix_psk0"}).
|
2021-04-27 20:23:18 -06:00
|
|
|
WithField("sentCachedPackets", len(hostinfo.packetStore)).
|
2021-03-12 12:16:25 -07:00
|
|
|
Info("Handshake message sent")
|
2019-11-19 10:00:20 -07:00
|
|
|
}
|
|
|
|
|
2023-03-31 14:45:05 -06:00
|
|
|
f.connectionManager.AddTrafficWatch(hostinfo.localIndexId)
|
2021-04-27 20:23:18 -06:00
|
|
|
hostinfo.handshakeComplete(f.l, f.cachedPacketMetrics)
|
2021-03-12 12:16:25 -07:00
|
|
|
|
|
|
|
return
|
2019-11-19 10:00:20 -07:00
|
|
|
}
|
|
|
|
|
2022-06-21 12:35:23 -06:00
|
|
|
func ixHandshakeStage2(f *Interface, addr *udp.Addr, via interface{}, hostinfo *HostInfo, packet []byte, h *header.H) bool {
|
2019-11-19 10:00:20 -07:00
|
|
|
if hostinfo == nil {
|
2021-03-31 09:26:35 -06:00
|
|
|
// Nothing here to tear down, got a bogus stage 2 packet
|
2019-11-19 10:00:20 -07:00
|
|
|
return true
|
|
|
|
}
|
2021-03-31 09:26:35 -06:00
|
|
|
|
2021-03-05 19:18:33 -07:00
|
|
|
hostinfo.Lock()
|
|
|
|
defer hostinfo.Unlock()
|
2019-11-19 10:00:20 -07:00
|
|
|
|
2022-06-21 12:35:23 -06:00
|
|
|
if addr != nil {
|
|
|
|
if !f.lightHouse.GetRemoteAllowList().Allow(hostinfo.vpnIp, addr.IP) {
|
|
|
|
f.l.WithField("vpnIp", hostinfo.vpnIp).WithField("udpAddr", addr).Debug("lighthouse.remote_allow_list denied incoming handshake")
|
|
|
|
return false
|
|
|
|
}
|
2021-10-19 08:54:30 -06:00
|
|
|
}
|
|
|
|
|
2021-03-31 09:26:35 -06:00
|
|
|
ci := hostinfo.ConnectionState
|
|
|
|
if ci.ready {
|
2021-11-03 19:54:04 -06:00
|
|
|
f.l.WithField("vpnIp", hostinfo.vpnIp).WithField("udpAddr", addr).
|
2019-11-19 10:00:20 -07:00
|
|
|
WithField("handshake", m{"stage": 2, "style": "ix_psk0"}).WithField("header", h).
|
2021-03-31 09:26:35 -06:00
|
|
|
Info("Handshake is already complete")
|
|
|
|
|
2021-10-19 08:53:55 -06:00
|
|
|
// Update remote if preferred
|
|
|
|
if hostinfo.SetRemoteIfPreferred(f.hostMap, addr) {
|
|
|
|
// Send a test packet to ensure the other side has also switched to
|
|
|
|
// the preferred remote
|
2021-11-03 19:54:04 -06:00
|
|
|
f.SendMessageToVpnIp(header.Test, header.TestRequest, hostinfo.vpnIp, []byte(""), make([]byte, 12, 12), make([]byte, mtu))
|
2021-10-19 08:53:55 -06:00
|
|
|
}
|
2021-04-14 12:50:09 -06:00
|
|
|
|
2021-03-31 09:26:35 -06:00
|
|
|
// We already have a complete tunnel, there is nothing that can be done by processing further stage 1 packets
|
2019-11-19 10:00:20 -07:00
|
|
|
return false
|
|
|
|
}
|
|
|
|
|
2021-11-03 19:54:04 -06:00
|
|
|
msg, eKey, dKey, err := ci.H.ReadMessage(nil, packet[header.Len:])
|
2019-11-19 10:00:20 -07:00
|
|
|
if err != nil {
|
2021-11-03 19:54:04 -06:00
|
|
|
f.l.WithError(err).WithField("vpnIp", hostinfo.vpnIp).WithField("udpAddr", addr).
|
2019-11-19 10:00:20 -07:00
|
|
|
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
|
2021-03-12 12:16:25 -07:00
|
|
|
} else if dKey == nil || eKey == nil {
|
2021-11-03 19:54:04 -06:00
|
|
|
f.l.WithField("vpnIp", hostinfo.vpnIp).WithField("udpAddr", addr).
|
2021-03-12 12:16:25 -07:00
|
|
|
WithField("handshake", m{"stage": 2, "style": "ix_psk0"}).
|
|
|
|
Error("Noise did not arrive at a key")
|
2021-03-31 09:26:35 -06:00
|
|
|
|
|
|
|
// This should be impossible in IX but just in case, if we get here then there is no chance to recover
|
|
|
|
// the handshake state machine. Tear it down
|
2021-03-12 12:16:25 -07:00
|
|
|
return true
|
2019-11-19 10:00:20 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
hs := &NebulaHandshake{}
|
2022-04-18 10:12:25 -06:00
|
|
|
err = hs.Unmarshal(msg)
|
2019-11-19 10:00:20 -07:00
|
|
|
if err != nil || hs.Details == nil {
|
2021-11-03 19:54:04 -06:00
|
|
|
f.l.WithError(err).WithField("vpnIp", hostinfo.vpnIp).WithField("udpAddr", addr).
|
2019-11-19 10:00:20 -07:00
|
|
|
WithField("handshake", m{"stage": 2, "style": "ix_psk0"}).Error("Failed unmarshal handshake message")
|
2021-03-31 09:26:35 -06:00
|
|
|
|
|
|
|
// The handshake state machine is complete, if things break now there is no chance to recover. Tear down and start again
|
2019-11-19 10:00:20 -07:00
|
|
|
return true
|
|
|
|
}
|
|
|
|
|
2021-03-29 11:10:19 -06:00
|
|
|
remoteCert, err := RecombineCertAndValidate(ci.H, hs.Details.Cert, f.caPool)
|
2019-11-19 10:00:20 -07:00
|
|
|
if err != nil {
|
2021-11-03 19:54:04 -06:00
|
|
|
f.l.WithError(err).WithField("vpnIp", hostinfo.vpnIp).WithField("udpAddr", addr).
|
2019-11-19 10:00:20 -07:00
|
|
|
WithField("cert", remoteCert).WithField("handshake", m{"stage": 2, "style": "ix_psk0"}).
|
|
|
|
Error("Invalid certificate from host")
|
2021-03-31 09:26:35 -06:00
|
|
|
|
|
|
|
// The handshake state machine is complete, if things break now there is no chance to recover. Tear down and start again
|
2019-11-19 10:00:20 -07:00
|
|
|
return true
|
|
|
|
}
|
2021-03-31 09:26:35 -06:00
|
|
|
|
2021-11-03 19:54:04 -06:00
|
|
|
vpnIp := iputil.Ip2VpnIp(remoteCert.Details.Ips[0].IP)
|
2020-04-06 12:34:00 -06:00
|
|
|
certName := remoteCert.Details.Name
|
2020-07-31 16:54:51 -06:00
|
|
|
fingerprint, _ := remoteCert.Sha256Sum()
|
2021-08-30 19:57:38 -06:00
|
|
|
issuer := remoteCert.Details.Issuer
|
2019-11-19 10:00:20 -07:00
|
|
|
|
2021-04-14 12:50:09 -06:00
|
|
|
// Ensure the right host responded
|
2021-11-03 19:54:04 -06:00
|
|
|
if vpnIp != hostinfo.vpnIp {
|
|
|
|
f.l.WithField("intendedVpnIp", hostinfo.vpnIp).WithField("haveVpnIp", vpnIp).
|
2021-03-31 09:26:35 -06:00
|
|
|
WithField("udpAddr", addr).WithField("certName", certName).
|
|
|
|
WithField("handshake", m{"stage": 2, "style": "ix_psk0"}).
|
|
|
|
Info("Incorrect host responded to handshake")
|
|
|
|
|
2021-03-31 12:36:10 -06:00
|
|
|
// Release our old handshake from pending, it should not continue
|
2021-03-31 09:26:35 -06:00
|
|
|
f.handshakeManager.pendingHostMap.DeleteHostInfo(hostinfo)
|
2021-03-31 12:36:10 -06:00
|
|
|
|
|
|
|
// Create a new hostinfo/handshake for the intended vpn ip
|
2021-03-31 09:26:35 -06:00
|
|
|
//TODO: this adds it to the timer wheel in a way that aggressively retries
|
2021-11-03 19:54:04 -06:00
|
|
|
newHostInfo := f.getOrHandshake(hostinfo.vpnIp)
|
2021-03-31 09:26:35 -06:00
|
|
|
newHostInfo.Lock()
|
|
|
|
|
|
|
|
// Block the current used address
|
2021-04-14 12:50:09 -06:00
|
|
|
newHostInfo.remotes = hostinfo.remotes
|
|
|
|
newHostInfo.remotes.BlockRemote(addr)
|
2021-03-31 09:26:35 -06:00
|
|
|
|
2021-04-14 12:50:09 -06:00
|
|
|
// Get the correct remote list for the host we did handshake with
|
2021-11-03 19:54:04 -06:00
|
|
|
hostinfo.remotes = f.lightHouse.QueryCache(vpnIp)
|
2021-03-31 09:26:35 -06:00
|
|
|
|
2021-11-03 19:54:04 -06:00
|
|
|
f.l.WithField("blockedUdpAddrs", newHostInfo.remotes.CopyBlockedRemotes()).WithField("vpnIp", vpnIp).
|
2021-04-14 12:50:09 -06:00
|
|
|
WithField("remotes", newHostInfo.remotes.CopyAddrs(f.hostMap.preferredRanges)).
|
2021-03-31 09:26:35 -06:00
|
|
|
Info("Blocked addresses for handshakes")
|
|
|
|
|
|
|
|
// Swap the packet store to benefit the original intended recipient
|
2021-04-14 12:50:09 -06:00
|
|
|
hostinfo.ConnectionState.queueLock.Lock()
|
2021-03-31 09:26:35 -06:00
|
|
|
newHostInfo.packetStore = hostinfo.packetStore
|
|
|
|
hostinfo.packetStore = []*cachedPacket{}
|
2021-04-14 12:50:09 -06:00
|
|
|
hostinfo.ConnectionState.queueLock.Unlock()
|
2021-03-31 09:26:35 -06:00
|
|
|
|
2021-04-14 12:50:09 -06:00
|
|
|
// Finally, put the correct vpn ip in the host info, tell them to close the tunnel, and return true to tear down
|
2021-11-03 19:54:04 -06:00
|
|
|
hostinfo.vpnIp = vpnIp
|
2021-04-14 12:50:09 -06:00
|
|
|
f.sendCloseTunnel(hostinfo)
|
2021-03-31 09:26:35 -06:00
|
|
|
newHostInfo.Unlock()
|
2021-04-14 12:50:09 -06:00
|
|
|
|
|
|
|
return true
|
2021-03-31 09:26:35 -06:00
|
|
|
}
|
|
|
|
|
|
|
|
// Mark packet 2 as seen so it doesn't show up as missed
|
|
|
|
ci.window.Update(f.l, 2)
|
|
|
|
|
2019-11-19 10:00:20 -07:00
|
|
|
duration := time.Since(hostinfo.handshakeStart).Nanoseconds()
|
2021-11-03 19:54:04 -06:00
|
|
|
f.l.WithField("vpnIp", vpnIp).WithField("udpAddr", addr).
|
2020-04-06 12:34:00 -06:00
|
|
|
WithField("certName", certName).
|
2020-07-31 16:54:51 -06:00
|
|
|
WithField("fingerprint", fingerprint).
|
2021-08-30 19:57:38 -06:00
|
|
|
WithField("issuer", issuer).
|
2019-11-19 10:00:20 -07:00
|
|
|
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).
|
2021-04-27 20:23:18 -06:00
|
|
|
WithField("sentCachedPackets", len(hostinfo.packetStore)).
|
2019-11-19 10:00:20 -07:00
|
|
|
Info("Handshake message received")
|
|
|
|
|
|
|
|
hostinfo.remoteIndexId = hs.Details.ResponderIndex
|
2021-04-27 20:15:34 -06:00
|
|
|
hostinfo.lastHandshakeTime = hs.Details.Time
|
2019-11-19 10:00:20 -07:00
|
|
|
|
2021-03-31 09:26:35 -06:00
|
|
|
// Store their cert and our symmetric keys
|
2021-03-12 12:16:25 -07:00
|
|
|
ci.peerCert = remoteCert
|
|
|
|
ci.dKey = NewNebulaCipherState(dKey)
|
|
|
|
ci.eKey = NewNebulaCipherState(eKey)
|
2019-11-19 10:00:20 -07:00
|
|
|
|
2021-03-31 09:26:35 -06:00
|
|
|
// Make sure the current udpAddr being used is set for responding
|
2022-06-21 12:35:23 -06:00
|
|
|
if addr != nil {
|
|
|
|
hostinfo.SetRemote(addr)
|
|
|
|
} else {
|
|
|
|
via2 := via.(*ViaSender)
|
|
|
|
hostinfo.relayState.InsertRelayTo(via2.relayHI.vpnIp)
|
|
|
|
}
|
2021-03-31 09:26:35 -06:00
|
|
|
|
|
|
|
// Build up the radix for the firewall if we have subnets in the cert
|
2021-03-12 12:16:25 -07:00
|
|
|
hostinfo.CreateRemoteCIDR(remoteCert)
|
2019-11-19 10:00:20 -07:00
|
|
|
|
2021-03-31 09:26:35 -06:00
|
|
|
// Complete our handshake and update metrics, this will replace any existing tunnels for this vpnIp
|
2023-03-31 14:45:05 -06:00
|
|
|
f.handshakeManager.Complete(hostinfo, f)
|
|
|
|
f.connectionManager.AddTrafficWatch(hostinfo.localIndexId)
|
2021-04-27 20:23:18 -06:00
|
|
|
hostinfo.handshakeComplete(f.l, f.cachedPacketMetrics)
|
2021-03-12 12:16:25 -07:00
|
|
|
f.metricHandshakes.Update(duration)
|
2019-11-19 10:00:20 -07:00
|
|
|
|
|
|
|
return false
|
|
|
|
}
|