瀏覽代碼

Provide hooks for custom message packet handlers

This commit augments the Control API by providing new methods to
inject message packets destined peer nodes, and/or to intercept
message packets of a custom message subtype that are received from
peer nodes.
Dave Russell 4 年之前
父節點
當前提交
ae3ee42469
共有 3 個文件被更改,包括 51 次插入3 次删除
  1. 41 0
      control.go
  2. 8 1
      handler.go
  3. 2 2
      outside.go

+ 41 - 0
control.go

@@ -1,6 +1,8 @@
 package nebula
 
 import (
+	"encoding/binary"
+	"fmt"
 	"net"
 	"os"
 	"os/signal"
@@ -8,6 +10,7 @@ import (
 
 	"github.com/sirupsen/logrus"
 	"github.com/slackhq/nebula/cert"
+	"golang.org/x/net/ipv4"
 )
 
 // Every interaction here needs to take extra care to copy memory and not return or use arguments "as is" when touching
@@ -167,3 +170,41 @@ func copyHostInfo(h *HostInfo) ControlHostInfo {
 
 	return chi
 }
+
+// Hook provides the ability to hook into the network path for a particular
+// message sub type. Any received message of that subtype that is allowed by
+// the firewall will be written to the provided write func instead of the
+// inside interface.
+// TODO: make this an io.Writer
+func (c *Control) Hook(t NebulaMessageSubType, w func([]byte) error) error {
+	if t == 0 {
+		return fmt.Errorf("non-default message subtype must be specified")
+	}
+	if _, ok := c.f.handlers[Version][message][t]; ok {
+		return fmt.Errorf("message subtype %d already hooked", t)
+	}
+
+	c.f.handlers[Version][message][t] = c.f.newHook(w)
+	return nil
+}
+
+// Send provides the ability to send arbitrary message packets to peer nodes.
+// The provided payload will be encapsulated in an IPv4 packet from the
+// node IP to the provided destination nebula IP. Any protocol handling
+// above layer 3 (IP) must be managed by the caller.
+func (c *Control) Send(ip uint32, t NebulaMessageSubType, payload []byte) {
+	hostinfo := c.f.getOrHandshake(ip)
+	ci := hostinfo.ConnectionState
+
+	length := ipv4.HeaderLen + len(payload)
+	packet := make([]byte, length)
+	packet[0] = 0x45
+	binary.BigEndian.PutUint16(packet[2:4], uint16(length))
+	binary.BigEndian.PutUint32(packet[12:16], ip2int(c.f.inside.CidrNet().IP.To4()))
+	binary.BigEndian.PutUint32(packet[16:20], ip)
+	copy(packet[ipv4.HeaderLen:], payload)
+
+	nb := make([]byte, 12)
+	out := make([]byte, mtu)
+	c.f.sendNoMetrics(message, t, ci, hostinfo, hostinfo.remote, packet, nb, out)
+}

+ 8 - 1
handler.go

@@ -1,5 +1,12 @@
 package nebula
 
+func (f *Interface) newHook(w func([]byte) error) InsideHandler {
+	fn := func(hostInfo *HostInfo, ci *ConnectionState, addr *udpAddr, header *Header, out []byte, packet []byte, fwPacket *FirewallPacket, nb []byte) {
+		f.decryptTo(w, hostInfo, header.MessageCounter, out, packet, fwPacket, nb)
+	}
+	return f.encrypted(fn)
+}
+
 func (f *Interface) encrypted(h InsideHandler) InsideHandler {
 	return func(hostInfo *HostInfo, ci *ConnectionState, addr *udpAddr, header *Header, out []byte, packet []byte, fwPacket *FirewallPacket, nb []byte) {
 		if !f.handleEncrypted(ci, addr, header) {
@@ -21,7 +28,7 @@ func (f *Interface) rxMetrics(h InsideHandler) InsideHandler {
 }
 
 func (f *Interface) handleMessagePacket(hostInfo *HostInfo, ci *ConnectionState, addr *udpAddr, header *Header, out []byte, packet []byte, fwPacket *FirewallPacket, nb []byte) {
-	f.decryptToTun(hostInfo, header.MessageCounter, out, packet, fwPacket, nb)
+	f.decryptTo(f.inside.WriteRaw, hostInfo, header.MessageCounter, out, packet, fwPacket, nb)
 }
 
 func (f *Interface) handleLighthousePacket(hostInfo *HostInfo, ci *ConnectionState, addr *udpAddr, header *Header, out []byte, packet []byte, fwPacket *FirewallPacket, nb []byte) {

+ 2 - 2
outside.go

@@ -175,7 +175,7 @@ func (f *Interface) decrypt(hostinfo *HostInfo, mc uint64, out []byte, packet []
 	return out, nil
 }
 
-func (f *Interface) decryptToTun(hostinfo *HostInfo, messageCounter uint64, out []byte, packet []byte, fwPacket *FirewallPacket, nb []byte) {
+func (f *Interface) decryptTo(write func([]byte) error, hostinfo *HostInfo, messageCounter uint64, out []byte, packet []byte, fwPacket *FirewallPacket, nb []byte) {
 	var err error
 
 	out, err = hostinfo.ConnectionState.dKey.DecryptDanger(out, packet[:HeaderLen], packet[HeaderLen:], messageCounter, nb)
@@ -210,7 +210,7 @@ func (f *Interface) decryptToTun(hostinfo *HostInfo, messageCounter uint64, out
 	}
 
 	f.connectionManager.In(hostinfo.hostId)
-	err = f.inside.WriteRaw(out)
+	err = write(out)
 	if err != nil {
 		l.WithError(err).Error("Failed to write to tun")
 	}