0
0
Fork 0
mirror of https://github.com/slackhq/nebula.git synced 2025-04-14 17:38:30 +00:00

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.
This commit is contained in:
Dave Russell 2020-09-28 22:31:16 +10:00
parent fa034a6d83
commit ae3ee42469
3 changed files with 51 additions and 3 deletions

View file

@ -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)
}

View file

@ -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) {

View file

@ -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")
}