2019-11-19 18:00:20 +01:00
|
|
|
package nebula
|
|
|
|
|
|
|
|
import (
|
|
|
|
"encoding/binary"
|
2020-07-01 00:53:30 +02:00
|
|
|
"errors"
|
|
|
|
"fmt"
|
|
|
|
"time"
|
2019-11-19 18:00:20 +01:00
|
|
|
|
|
|
|
"github.com/flynn/noise"
|
|
|
|
"github.com/golang/protobuf/proto"
|
|
|
|
"github.com/sirupsen/logrus"
|
|
|
|
"github.com/slackhq/nebula/cert"
|
|
|
|
"golang.org/x/net/ipv4"
|
|
|
|
)
|
|
|
|
|
|
|
|
const (
|
|
|
|
minFwPacketLen = 4
|
|
|
|
)
|
|
|
|
|
2021-03-02 01:52:17 +01:00
|
|
|
func (f *Interface) readOutsidePackets(addr *udpAddr, out []byte, packet []byte, header *Header, fwPacket *FirewallPacket, lhh *LightHouseHandler, nb []byte, q int, localCache ConntrackCache) {
|
2019-11-19 18:00:20 +01:00
|
|
|
err := header.Parse(packet)
|
|
|
|
if err != nil {
|
|
|
|
// TODO: best if we return this and let caller log
|
|
|
|
// TODO: Might be better to send the literal []byte("holepunch") packet and ignore that?
|
|
|
|
// Hole punch packets are 0 or 1 byte big, so lets ignore printing those errors
|
|
|
|
if len(packet) > 1 {
|
2021-03-26 15:46:30 +01:00
|
|
|
f.l.WithField("packet", packet).Infof("Error while parsing inbound packet from %s: %s", addr, err)
|
2019-11-19 18:00:20 +01:00
|
|
|
}
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
//l.Error("in packet ", header, packet[HeaderLen:])
|
|
|
|
|
|
|
|
// verify if we've seen this index before, otherwise respond to the handshake initiation
|
|
|
|
hostinfo, err := f.hostMap.QueryIndex(header.RemoteIndex)
|
|
|
|
|
|
|
|
var ci *ConnectionState
|
|
|
|
if err == nil {
|
|
|
|
ci = hostinfo.ConnectionState
|
|
|
|
}
|
|
|
|
|
|
|
|
switch header.Type {
|
|
|
|
case message:
|
|
|
|
if !f.handleEncrypted(ci, addr, header) {
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
2021-03-02 01:52:17 +01:00
|
|
|
f.decryptToTun(hostinfo, header.MessageCounter, out, packet, fwPacket, nb, q, localCache)
|
2019-11-19 18:00:20 +01:00
|
|
|
|
|
|
|
// Fallthrough to the bottom to record incoming traffic
|
|
|
|
|
|
|
|
case lightHouse:
|
2020-06-26 19:45:48 +02:00
|
|
|
f.messageMetrics.Rx(header.Type, header.Subtype, 1)
|
2019-11-19 18:00:20 +01:00
|
|
|
if !f.handleEncrypted(ci, addr, header) {
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
d, err := f.decrypt(hostinfo, header.MessageCounter, out, packet, header, nb)
|
|
|
|
if err != nil {
|
2021-03-26 15:46:30 +01:00
|
|
|
hostinfo.logger(f.l).WithError(err).WithField("udpAddr", addr).
|
2019-11-19 18:00:20 +01:00
|
|
|
WithField("packet", packet).
|
|
|
|
Error("Failed to decrypt lighthouse packet")
|
|
|
|
|
|
|
|
//TODO: maybe after build 64 is out? 06/14/2018 - NB
|
|
|
|
//f.sendRecvError(net.Addr(addr), header.RemoteIndex)
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
2021-04-01 00:32:02 +02:00
|
|
|
lhh.HandleRequest(addr, hostinfo.hostId, d, f)
|
2019-11-19 18:00:20 +01:00
|
|
|
|
|
|
|
// Fallthrough to the bottom to record incoming traffic
|
|
|
|
|
|
|
|
case test:
|
2020-06-26 19:45:48 +02:00
|
|
|
f.messageMetrics.Rx(header.Type, header.Subtype, 1)
|
2019-11-19 18:00:20 +01:00
|
|
|
if !f.handleEncrypted(ci, addr, header) {
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
d, err := f.decrypt(hostinfo, header.MessageCounter, out, packet, header, nb)
|
|
|
|
if err != nil {
|
2021-03-26 15:46:30 +01:00
|
|
|
hostinfo.logger(f.l).WithError(err).WithField("udpAddr", addr).
|
2019-11-19 18:00:20 +01:00
|
|
|
WithField("packet", packet).
|
|
|
|
Error("Failed to decrypt test packet")
|
|
|
|
|
|
|
|
//TODO: maybe after build 64 is out? 06/14/2018 - NB
|
|
|
|
//f.sendRecvError(net.Addr(addr), header.RemoteIndex)
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
if header.Subtype == testRequest {
|
|
|
|
// This testRequest might be from TryPromoteBest, so we should roam
|
|
|
|
// to the new IP address before responding
|
|
|
|
f.handleHostRoaming(hostinfo, addr)
|
|
|
|
f.send(test, testReply, ci, hostinfo, hostinfo.remote, d, nb, out)
|
|
|
|
}
|
|
|
|
|
|
|
|
// Fallthrough to the bottom to record incoming traffic
|
|
|
|
|
|
|
|
// Non encrypted messages below here, they should not fall through to avoid tracking incoming traffic since they
|
|
|
|
// are unauthenticated
|
|
|
|
|
|
|
|
case handshake:
|
2020-06-26 19:45:48 +02:00
|
|
|
f.messageMetrics.Rx(header.Type, header.Subtype, 1)
|
2019-11-19 18:00:20 +01:00
|
|
|
HandleIncomingHandshake(f, addr, packet, header, hostinfo)
|
|
|
|
return
|
|
|
|
|
|
|
|
case recvError:
|
2020-06-26 19:45:48 +02:00
|
|
|
f.messageMetrics.Rx(header.Type, header.Subtype, 1)
|
2019-11-19 18:00:20 +01:00
|
|
|
f.handleRecvError(addr, header)
|
|
|
|
return
|
|
|
|
|
|
|
|
case closeTunnel:
|
2020-06-26 19:45:48 +02:00
|
|
|
f.messageMetrics.Rx(header.Type, header.Subtype, 1)
|
2019-11-19 18:00:20 +01:00
|
|
|
if !f.handleEncrypted(ci, addr, header) {
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
2021-03-26 15:46:30 +01:00
|
|
|
hostinfo.logger(f.l).WithField("udpAddr", addr).
|
2019-11-19 18:00:20 +01:00
|
|
|
Info("Close tunnel received, tearing down.")
|
|
|
|
|
2021-04-26 17:42:24 +02:00
|
|
|
f.closeTunnel(hostinfo, false)
|
2019-11-19 18:00:20 +01:00
|
|
|
return
|
|
|
|
|
|
|
|
default:
|
2020-06-26 19:45:48 +02:00
|
|
|
f.messageMetrics.Rx(header.Type, header.Subtype, 1)
|
2021-03-26 15:46:30 +01:00
|
|
|
hostinfo.logger(f.l).Debugf("Unexpected packet received from %s", addr)
|
2019-11-19 18:00:20 +01:00
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
f.handleHostRoaming(hostinfo, addr)
|
|
|
|
|
|
|
|
f.connectionManager.In(hostinfo.hostId)
|
|
|
|
}
|
|
|
|
|
2021-04-14 20:50:09 +02:00
|
|
|
// closeTunnel closes a tunnel locally, it does not send a closeTunnel packet to the remote
|
2021-04-26 17:42:24 +02:00
|
|
|
func (f *Interface) closeTunnel(hostInfo *HostInfo, hasHostMapLock bool) {
|
2019-11-19 18:00:20 +01:00
|
|
|
//TODO: this would be better as a single function in ConnectionManager that handled locks appropriately
|
|
|
|
f.connectionManager.ClearIP(hostInfo.hostId)
|
|
|
|
f.connectionManager.ClearPendingDeletion(hostInfo.hostId)
|
|
|
|
f.lightHouse.DeleteVpnIP(hostInfo.hostId)
|
2021-04-26 17:42:24 +02:00
|
|
|
|
|
|
|
if hasHostMapLock {
|
|
|
|
f.hostMap.unlockedDeleteHostInfo(hostInfo)
|
|
|
|
} else {
|
|
|
|
f.hostMap.DeleteHostInfo(hostInfo)
|
|
|
|
}
|
2019-11-19 18:00:20 +01:00
|
|
|
}
|
|
|
|
|
2021-04-14 20:50:09 +02:00
|
|
|
// sendCloseTunnel is a helper function to send a proper close tunnel packet to a remote
|
|
|
|
func (f *Interface) sendCloseTunnel(h *HostInfo) {
|
|
|
|
f.send(closeTunnel, 0, h.ConnectionState, h, h.remote, []byte{}, make([]byte, 12, 12), make([]byte, mtu))
|
|
|
|
}
|
|
|
|
|
2019-11-19 18:00:20 +01:00
|
|
|
func (f *Interface) handleHostRoaming(hostinfo *HostInfo, addr *udpAddr) {
|
|
|
|
if hostDidRoam(hostinfo.remote, addr) {
|
2021-10-19 16:54:30 +02:00
|
|
|
if !f.lightHouse.remoteAllowList.Allow(hostinfo.hostId, addr.IP) {
|
2021-03-26 15:46:30 +01:00
|
|
|
hostinfo.logger(f.l).WithField("newAddr", addr).Debug("lighthouse.remote_allow_list denied roaming")
|
Add lighthouse.{remoteAllowList,localAllowList} (#217)
These settings make it possible to blacklist / whitelist IP addresses
that are used for remote connections.
`lighthouse.remoteAllowList` filters which remote IPs are allow when
fetching from the lighthouse (or, if you are the lighthouse, which IPs
you store and forward to querying hosts). By default, any remote IPs are
allowed. You can provide CIDRs here with `true` to allow and `false` to
deny. The most specific CIDR rule applies to each remote. If all rules
are "allow", the default will be "deny", and vice-versa. If both "allow"
and "deny" rules are present, then you MUST set a rule for "0.0.0.0/0"
as the default.
lighthouse:
remoteAllowList:
# Example to block IPs from this subnet from being used for remote IPs.
"172.16.0.0/12": false
# A more complicated example, allow public IPs but only private IPs from a specific subnet
"0.0.0.0/0": true
"10.0.0.0/8": false
"10.42.42.0/24": true
`lighthouse.localAllowList` has the same logic as above, but it applies
to the local addresses we advertise to the lighthouse. Additionally, you
can specify an `interfaces` map of regular expressions to match against
interface names. The regexp must match the entire name. All interface
rules must be either true or false (and the default rule will be the
inverse). CIDR rules are matched after interface name rules.
Default is all local IP addresses.
lighthouse:
localAllowList:
# Example to blacklist docker interfaces.
interfaces:
'docker.*': false
# Example to only advertise IPs in this subnet to the lighthouse.
"10.0.0.0/8": true
2020-04-08 21:36:43 +02:00
|
|
|
return
|
|
|
|
}
|
2021-03-01 17:14:34 +01:00
|
|
|
if !hostinfo.lastRoam.IsZero() && addr.Equals(hostinfo.lastRoamRemote) && time.Since(hostinfo.lastRoam) < RoamingSuppressSeconds*time.Second {
|
2021-03-26 15:46:30 +01:00
|
|
|
if f.l.Level >= logrus.DebugLevel {
|
|
|
|
hostinfo.logger(f.l).WithField("udpAddr", hostinfo.remote).WithField("newAddr", addr).
|
2021-03-01 17:14:34 +01:00
|
|
|
Debugf("Suppressing roam back to previous remote for %d seconds", RoamingSuppressSeconds)
|
2019-11-19 18:00:20 +01:00
|
|
|
}
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
2021-03-26 15:46:30 +01:00
|
|
|
hostinfo.logger(f.l).WithField("udpAddr", hostinfo.remote).WithField("newAddr", addr).
|
2019-11-19 18:00:20 +01:00
|
|
|
Info("Host roamed to new udp ip/port.")
|
|
|
|
hostinfo.lastRoam = time.Now()
|
|
|
|
remoteCopy := *hostinfo.remote
|
|
|
|
hostinfo.lastRoamRemote = &remoteCopy
|
2021-03-19 02:37:24 +01:00
|
|
|
hostinfo.SetRemote(addr)
|
2019-11-19 18:00:20 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
func (f *Interface) handleEncrypted(ci *ConnectionState, addr *udpAddr, header *Header) bool {
|
|
|
|
// If connectionstate exists and the replay protector allows, process packet
|
|
|
|
// Else, send recv errors for 300 seconds after a restart to allow fast reconnection.
|
2021-03-26 15:46:30 +01:00
|
|
|
if ci == nil || !ci.window.Check(f.l, header.MessageCounter) {
|
2019-11-19 18:00:20 +01:00
|
|
|
f.sendRecvError(addr, header.RemoteIndex)
|
|
|
|
return false
|
|
|
|
}
|
|
|
|
|
|
|
|
return true
|
|
|
|
}
|
|
|
|
|
|
|
|
// newPacket validates and parses the interesting bits for the firewall out of the ip and sub protocol headers
|
|
|
|
func newPacket(data []byte, incoming bool, fp *FirewallPacket) error {
|
|
|
|
// Do we at least have an ipv4 header worth of data?
|
|
|
|
if len(data) < ipv4.HeaderLen {
|
|
|
|
return fmt.Errorf("packet is less than %v bytes", ipv4.HeaderLen)
|
|
|
|
}
|
|
|
|
|
|
|
|
// Is it an ipv4 packet?
|
|
|
|
if int((data[0]>>4)&0x0f) != 4 {
|
|
|
|
return fmt.Errorf("packet is not ipv4, type: %v", int((data[0]>>4)&0x0f))
|
|
|
|
}
|
|
|
|
|
|
|
|
// Adjust our start position based on the advertised ip header length
|
|
|
|
ihl := int(data[0]&0x0f) << 2
|
|
|
|
|
|
|
|
// Well formed ip header length?
|
|
|
|
if ihl < ipv4.HeaderLen {
|
|
|
|
return fmt.Errorf("packet had an invalid header length: %v", ihl)
|
|
|
|
}
|
|
|
|
|
|
|
|
// Check if this is the second or further fragment of a fragmented packet.
|
|
|
|
flagsfrags := binary.BigEndian.Uint16(data[6:8])
|
|
|
|
fp.Fragment = (flagsfrags & 0x1FFF) != 0
|
|
|
|
|
|
|
|
// Firewall handles protocol checks
|
|
|
|
fp.Protocol = data[9]
|
|
|
|
|
|
|
|
// Accounting for a variable header length, do we have enough data for our src/dst tuples?
|
|
|
|
minLen := ihl
|
|
|
|
if !fp.Fragment && fp.Protocol != fwProtoICMP {
|
|
|
|
minLen += minFwPacketLen
|
|
|
|
}
|
|
|
|
if len(data) < minLen {
|
|
|
|
return fmt.Errorf("packet is less than %v bytes, ip header len: %v", minLen, ihl)
|
|
|
|
}
|
|
|
|
|
|
|
|
// Firewall packets are locally oriented
|
|
|
|
if incoming {
|
|
|
|
fp.RemoteIP = binary.BigEndian.Uint32(data[12:16])
|
|
|
|
fp.LocalIP = binary.BigEndian.Uint32(data[16:20])
|
|
|
|
if fp.Fragment || fp.Protocol == fwProtoICMP {
|
|
|
|
fp.RemotePort = 0
|
|
|
|
fp.LocalPort = 0
|
|
|
|
} else {
|
|
|
|
fp.RemotePort = binary.BigEndian.Uint16(data[ihl : ihl+2])
|
|
|
|
fp.LocalPort = binary.BigEndian.Uint16(data[ihl+2 : ihl+4])
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
fp.LocalIP = binary.BigEndian.Uint32(data[12:16])
|
|
|
|
fp.RemoteIP = binary.BigEndian.Uint32(data[16:20])
|
|
|
|
if fp.Fragment || fp.Protocol == fwProtoICMP {
|
|
|
|
fp.RemotePort = 0
|
|
|
|
fp.LocalPort = 0
|
|
|
|
} else {
|
|
|
|
fp.LocalPort = binary.BigEndian.Uint16(data[ihl : ihl+2])
|
|
|
|
fp.RemotePort = binary.BigEndian.Uint16(data[ihl+2 : ihl+4])
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
|
|
|
func (f *Interface) decrypt(hostinfo *HostInfo, mc uint64, out []byte, packet []byte, header *Header, nb []byte) ([]byte, error) {
|
|
|
|
var err error
|
|
|
|
out, err = hostinfo.ConnectionState.dKey.DecryptDanger(out, packet[:HeaderLen], packet[HeaderLen:], mc, nb)
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
2021-03-26 15:46:30 +01:00
|
|
|
if !hostinfo.ConnectionState.window.Update(f.l, mc) {
|
|
|
|
hostinfo.logger(f.l).WithField("header", header).
|
2019-11-19 18:00:20 +01:00
|
|
|
Debugln("dropping out of window packet")
|
|
|
|
return nil, errors.New("out of window packet")
|
|
|
|
}
|
|
|
|
|
|
|
|
return out, nil
|
|
|
|
}
|
|
|
|
|
2021-03-02 01:52:17 +01:00
|
|
|
func (f *Interface) decryptToTun(hostinfo *HostInfo, messageCounter uint64, out []byte, packet []byte, fwPacket *FirewallPacket, nb []byte, q int, localCache ConntrackCache) {
|
2019-11-19 18:00:20 +01:00
|
|
|
var err error
|
|
|
|
|
|
|
|
out, err = hostinfo.ConnectionState.dKey.DecryptDanger(out, packet[:HeaderLen], packet[HeaderLen:], messageCounter, nb)
|
|
|
|
if err != nil {
|
2021-03-26 15:46:30 +01:00
|
|
|
hostinfo.logger(f.l).WithError(err).Error("Failed to decrypt packet")
|
2019-11-19 18:00:20 +01:00
|
|
|
//TODO: maybe after build 64 is out? 06/14/2018 - NB
|
|
|
|
//f.sendRecvError(hostinfo.remote, header.RemoteIndex)
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
err = newPacket(out, true, fwPacket)
|
|
|
|
if err != nil {
|
2021-03-26 15:46:30 +01:00
|
|
|
hostinfo.logger(f.l).WithError(err).WithField("packet", out).
|
2019-11-19 18:00:20 +01:00
|
|
|
Warnf("Error while validating inbound packet")
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
2021-03-26 15:46:30 +01:00
|
|
|
if !hostinfo.ConnectionState.window.Update(f.l, messageCounter) {
|
|
|
|
hostinfo.logger(f.l).WithField("fwPacket", fwPacket).
|
2019-11-19 18:00:20 +01:00
|
|
|
Debugln("dropping out of window packet")
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
2021-03-29 19:10:19 +02:00
|
|
|
dropReason := f.firewall.Drop(out, *fwPacket, true, hostinfo, f.caPool, localCache)
|
2020-06-10 23:55:49 +02:00
|
|
|
if dropReason != nil {
|
2021-03-26 15:46:30 +01:00
|
|
|
if f.l.Level >= logrus.DebugLevel {
|
|
|
|
hostinfo.logger(f.l).WithField("fwPacket", fwPacket).
|
2020-06-10 23:55:49 +02:00
|
|
|
WithField("reason", dropReason).
|
|
|
|
Debugln("dropping inbound packet")
|
|
|
|
}
|
2019-11-19 18:00:20 +01:00
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
f.connectionManager.In(hostinfo.hostId)
|
2021-02-25 21:01:14 +01:00
|
|
|
_, err = f.readers[q].Write(out)
|
2019-11-19 18:00:20 +01:00
|
|
|
if err != nil {
|
2021-03-26 15:46:30 +01:00
|
|
|
f.l.WithError(err).Error("Failed to write to tun")
|
2019-11-19 18:00:20 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
func (f *Interface) sendRecvError(endpoint *udpAddr, index uint32) {
|
2020-06-26 19:45:48 +02:00
|
|
|
f.messageMetrics.Tx(recvError, 0, 1)
|
2019-11-19 18:00:20 +01:00
|
|
|
|
|
|
|
//TODO: this should be a signed message so we can trust that we should drop the index
|
|
|
|
b := HeaderEncode(make([]byte, HeaderLen), Version, uint8(recvError), 0, index, 0)
|
|
|
|
f.outside.WriteTo(b, endpoint)
|
2021-03-26 15:46:30 +01:00
|
|
|
if f.l.Level >= logrus.DebugLevel {
|
|
|
|
f.l.WithField("index", index).
|
2019-11-19 18:00:20 +01:00
|
|
|
WithField("udpAddr", endpoint).
|
|
|
|
Debug("Recv error sent")
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
func (f *Interface) handleRecvError(addr *udpAddr, h *Header) {
|
2021-03-26 15:46:30 +01:00
|
|
|
if f.l.Level >= logrus.DebugLevel {
|
|
|
|
f.l.WithField("index", h.RemoteIndex).
|
2019-11-19 18:00:20 +01:00
|
|
|
WithField("udpAddr", addr).
|
|
|
|
Debug("Recv error received")
|
|
|
|
}
|
|
|
|
|
2021-03-01 18:40:46 +01:00
|
|
|
// First, clean up in the pending hostmap
|
|
|
|
f.handshakeManager.pendingHostMap.DeleteReverseIndex(h.RemoteIndex)
|
|
|
|
|
2019-11-19 18:00:20 +01:00
|
|
|
hostinfo, err := f.hostMap.QueryReverseIndex(h.RemoteIndex)
|
|
|
|
if err != nil {
|
2021-03-26 15:46:30 +01:00
|
|
|
f.l.Debugln(err, ": ", h.RemoteIndex)
|
2019-11-19 18:00:20 +01:00
|
|
|
return
|
|
|
|
}
|
|
|
|
|
2021-03-09 15:27:02 +01:00
|
|
|
hostinfo.Lock()
|
|
|
|
defer hostinfo.Unlock()
|
|
|
|
|
2019-11-19 18:00:20 +01:00
|
|
|
if !hostinfo.RecvErrorExceeded() {
|
|
|
|
return
|
|
|
|
}
|
2021-06-03 19:04:04 +02:00
|
|
|
if hostinfo.remote != nil && !hostinfo.remote.Equals(addr) {
|
2021-03-26 15:46:30 +01:00
|
|
|
f.l.Infoln("Someone spoofing recv_errors? ", addr, hostinfo.remote)
|
2019-11-19 18:00:20 +01:00
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
// We delete this host from the main hostmap
|
2020-11-23 20:51:16 +01:00
|
|
|
f.hostMap.DeleteHostInfo(hostinfo)
|
2019-11-19 18:00:20 +01:00
|
|
|
// We also delete it from pending to allow for
|
|
|
|
// fast reconnect. We must null the connectionstate
|
|
|
|
// or a counter reuse may happen
|
|
|
|
hostinfo.ConnectionState = nil
|
2020-11-23 20:51:16 +01:00
|
|
|
f.handshakeManager.DeleteHostInfo(hostinfo)
|
2019-11-19 18:00:20 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
func (f *Interface) sendMeta(ci *ConnectionState, endpoint *net.UDPAddr, meta *NebulaMeta) {
|
|
|
|
if ci.eKey != nil {
|
|
|
|
//TODO: log error?
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
msg, err := proto.Marshal(meta)
|
|
|
|
if err != nil {
|
|
|
|
l.Debugln("failed to encode header")
|
|
|
|
}
|
|
|
|
|
|
|
|
c := ci.messageCounter
|
|
|
|
b := HeaderEncode(nil, Version, uint8(metadata), 0, hostinfo.remoteIndexId, c)
|
|
|
|
ci.messageCounter++
|
|
|
|
|
|
|
|
msg := ci.eKey.EncryptDanger(b, nil, msg, c)
|
|
|
|
//msg := ci.eKey.EncryptDanger(b, nil, []byte(fmt.Sprintf("%d", counter)), c)
|
|
|
|
f.outside.WriteTo(msg, endpoint)
|
|
|
|
}
|
|
|
|
*/
|
|
|
|
|
2021-03-29 19:10:19 +02:00
|
|
|
func RecombineCertAndValidate(h *noise.HandshakeState, rawCertBytes []byte, caPool *cert.NebulaCAPool) (*cert.NebulaCertificate, error) {
|
2019-11-19 18:00:20 +01:00
|
|
|
pk := h.PeerStatic()
|
|
|
|
|
|
|
|
if pk == nil {
|
|
|
|
return nil, errors.New("no peer static key was present")
|
|
|
|
}
|
|
|
|
|
|
|
|
if rawCertBytes == nil {
|
|
|
|
return nil, errors.New("provided payload was empty")
|
|
|
|
}
|
|
|
|
|
|
|
|
r := &cert.RawNebulaCertificate{}
|
|
|
|
err := proto.Unmarshal(rawCertBytes, r)
|
|
|
|
if err != nil {
|
|
|
|
return nil, fmt.Errorf("error unmarshaling cert: %s", err)
|
|
|
|
}
|
|
|
|
|
|
|
|
// If the Details are nil, just exit to avoid crashing
|
|
|
|
if r.Details == nil {
|
|
|
|
return nil, fmt.Errorf("certificate did not contain any details")
|
|
|
|
}
|
|
|
|
|
|
|
|
r.Details.PublicKey = pk
|
|
|
|
recombined, err := proto.Marshal(r)
|
|
|
|
if err != nil {
|
|
|
|
return nil, fmt.Errorf("error while recombining certificate: %s", err)
|
|
|
|
}
|
|
|
|
|
|
|
|
c, _ := cert.UnmarshalNebulaCertificate(recombined)
|
2021-03-29 19:10:19 +02:00
|
|
|
isValid, err := c.Verify(time.Now(), caPool)
|
2019-11-19 18:00:20 +01:00
|
|
|
if err != nil {
|
|
|
|
return c, fmt.Errorf("certificate validation failed: %s", err)
|
|
|
|
} else if !isValid {
|
|
|
|
// This case should never happen but here's to defensive programming!
|
|
|
|
return c, errors.New("certificate validation failed but did not return an error")
|
|
|
|
}
|
|
|
|
|
|
|
|
return c, nil
|
|
|
|
}
|