diff --git a/handler.go b/handler.go new file mode 100644 index 0000000..45c75dc --- /dev/null +++ b/handler.go @@ -0,0 +1,86 @@ +package nebula + +func (f *Interface) handleMessagePacket(hostInfo *HostInfo, ci *ConnectionState, addr *udpAddr, header *Header, out []byte, packet []byte, fwPacket *FirewallPacket, nb []byte) { + if !f.handleEncrypted(ci, addr, header) { + return + } + + f.decryptToTun(hostInfo, header.MessageCounter, out, packet, fwPacket, nb) + + f.handleHostRoaming(hostInfo, addr) + f.connectionManager.In(hostInfo.hostId) +} + +func (f *Interface) handleLighthousePacket(hostInfo *HostInfo, ci *ConnectionState, addr *udpAddr, header *Header, out []byte, packet []byte, fwPacket *FirewallPacket, nb []byte) { + f.messageMetrics.Rx(header.Type, header.Subtype, 1) + if !f.handleEncrypted(ci, addr, header) { + return + } + + d, err := f.decrypt(hostInfo, header.MessageCounter, out, packet, header, nb) + if err != nil { + hostInfo.logger().WithError(err).WithField("udpAddr", addr). + 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 + } + + f.lightHouse.HandleRequest(addr, hostInfo.hostId, d, hostInfo.GetCert(), f) + + f.handleHostRoaming(hostInfo, addr) + f.connectionManager.In(hostInfo.hostId) +} + +func (f *Interface) handleTestPacket(hostInfo *HostInfo, ci *ConnectionState, addr *udpAddr, header *Header, out []byte, packet []byte, fwPacket *FirewallPacket, nb []byte) { + f.messageMetrics.Rx(header.Type, header.Subtype, 1) + if !f.handleEncrypted(ci, addr, header) { + return + } + + d, err := f.decrypt(hostInfo, header.MessageCounter, out, packet, header, nb) + if err != nil { + hostInfo.logger().WithError(err).WithField("udpAddr", addr). + 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) + } + + f.handleHostRoaming(hostInfo, addr) + f.connectionManager.In(hostInfo.hostId) +} + +func (f *Interface) handleHandshakePacket(hostInfo *HostInfo, ci *ConnectionState, addr *udpAddr, header *Header, out []byte, packet []byte, fwPacket *FirewallPacket, nb []byte) { + f.messageMetrics.Rx(header.Type, header.Subtype, 1) + HandleIncomingHandshake(f, addr, packet, header, hostInfo) +} + +func (f *Interface) handleRecvErrorPacket(hostInfo *HostInfo, ci *ConnectionState, addr *udpAddr, header *Header, out []byte, packet []byte, fwPacket *FirewallPacket, nb []byte) { + f.messageMetrics.Rx(header.Type, header.Subtype, 1) + // TODO: Remove this with recv_error deprecation + f.handleRecvError(addr, header) +} + +func (f *Interface) handleCloseTunnelPacket(hostInfo *HostInfo, ci *ConnectionState, addr *udpAddr, header *Header, out []byte, packet []byte, fwPacket *FirewallPacket, nb []byte) { + f.messageMetrics.Rx(header.Type, header.Subtype, 1) + if !f.handleEncrypted(ci, addr, header) { + return + } + + hostInfo.logger().WithField("udpAddr", addr). + Info("Close tunnel received, tearing down.") + + f.closeTunnel(hostInfo) +} diff --git a/header.go b/header.go index 3f15faa..291e650 100644 --- a/header.go +++ b/header.go @@ -54,6 +54,7 @@ var typeMap = map[NebulaMessageType]string{ } const ( + subTypeNone NebulaMessageSubType = 0 testRequest NebulaMessageSubType = 0 testReply NebulaMessageSubType = 1 ) diff --git a/interface.go b/interface.go index ee90657..3a80838 100644 --- a/interface.go +++ b/interface.go @@ -20,6 +20,8 @@ type Inside interface { WriteRaw([]byte) error } +type InsideHandler func(hostInfo *HostInfo, ci *ConnectionState, addr *udpAddr, header *Header, out []byte, packet []byte, fp *FirewallPacket, nb []byte) + type InterfaceConfig struct { HostMap *HostMap Outside *udpConn @@ -61,6 +63,9 @@ type Interface struct { tunQueues int version string + // handlers are mapped by protocol version -> type -> subtype + handlers map[uint8]map[NebulaMessageType]map[NebulaMessageSubType]InsideHandler + metricHandshakes metrics.Histogram messageMetrics *MessageMetrics } @@ -103,6 +108,29 @@ func NewInterface(c *InterfaceConfig) (*Interface, error) { } ifce.connectionManager = newConnectionManager(ifce, c.checkInterval, c.pendingDeletionInterval) + ifce.handlers = map[uint8]map[NebulaMessageType]map[NebulaMessageSubType]InsideHandler{ + Version: { + handshake: { + handshakeIXPSK0: ifce.handleHandshakePacket, + }, + message: { + subTypeNone: ifce.handleMessagePacket, + }, + recvError: { + subTypeNone: ifce.handleRecvErrorPacket, + }, + lightHouse: { + subTypeNone: ifce.handleLighthousePacket, + }, + test: { + testRequest: ifce.handleTestPacket, + testReply: ifce.handleTestPacket, + }, + closeTunnel: { + subTypeNone: ifce.handleCloseTunnelPacket, + }, + }, + } return ifce, nil } diff --git a/outside.go b/outside.go index 166bd5d..4ea1943 100644 --- a/outside.go +++ b/outside.go @@ -39,98 +39,15 @@ func (f *Interface) readOutsidePackets(addr *udpAddr, out []byte, packet []byte, ci = hostinfo.ConnectionState } - switch header.Type { - case message: - if !f.handleEncrypted(ci, addr, header) { - return - } + handle := f.handlers[header.Version][header.Type][header.Subtype] - f.decryptToTun(hostinfo, header.MessageCounter, out, packet, fwPacket, nb) - - // Fallthrough to the bottom to record incoming traffic - - case lightHouse: - f.messageMetrics.Rx(header.Type, header.Subtype, 1) - if !f.handleEncrypted(ci, addr, header) { - return - } - - d, err := f.decrypt(hostinfo, header.MessageCounter, out, packet, header, nb) - if err != nil { - hostinfo.logger().WithError(err).WithField("udpAddr", addr). - 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 - } - - f.lightHouse.HandleRequest(addr, hostinfo.hostId, d, hostinfo.GetCert(), f) - - // Fallthrough to the bottom to record incoming traffic - - case test: - f.messageMetrics.Rx(header.Type, header.Subtype, 1) - if !f.handleEncrypted(ci, addr, header) { - return - } - - d, err := f.decrypt(hostinfo, header.MessageCounter, out, packet, header, nb) - if err != nil { - hostinfo.logger().WithError(err).WithField("udpAddr", addr). - 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: - f.messageMetrics.Rx(header.Type, header.Subtype, 1) - HandleIncomingHandshake(f, addr, packet, header, hostinfo) - return - - case recvError: - f.messageMetrics.Rx(header.Type, header.Subtype, 1) - // TODO: Remove this with recv_error deprecation - f.handleRecvError(addr, header) - return - - case closeTunnel: - f.messageMetrics.Rx(header.Type, header.Subtype, 1) - if !f.handleEncrypted(ci, addr, header) { - return - } - - hostinfo.logger().WithField("udpAddr", addr). - Info("Close tunnel received, tearing down.") - - f.closeTunnel(hostinfo) - return - - default: + if handle == nil { f.messageMetrics.Rx(header.Type, header.Subtype, 1) hostinfo.logger().Debugf("Unexpected packet received from %s", addr) return } - f.handleHostRoaming(hostinfo, addr) - - f.connectionManager.In(hostinfo.hostId) + handle(hostinfo, ci, addr, header, out, packet, fwPacket, nb) } func (f *Interface) closeTunnel(hostInfo *HostInfo) {