mirror of
https://github.com/slackhq/nebula.git
synced 2025-11-22 08:24:25 +01:00
Move all of tun into overlay (#577)
This commit is contained in:
175
overlay/tun_disabled.go
Normal file
175
overlay/tun_disabled.go
Normal file
@@ -0,0 +1,175 @@
|
||||
package overlay
|
||||
|
||||
import (
|
||||
"encoding/binary"
|
||||
"fmt"
|
||||
"io"
|
||||
"net"
|
||||
"strings"
|
||||
|
||||
"github.com/rcrowley/go-metrics"
|
||||
"github.com/sirupsen/logrus"
|
||||
)
|
||||
|
||||
type disabledTun struct {
|
||||
read chan []byte
|
||||
cidr *net.IPNet
|
||||
|
||||
// Track these metrics since we don't have the tun device to do it for us
|
||||
tx metrics.Counter
|
||||
rx metrics.Counter
|
||||
l *logrus.Logger
|
||||
}
|
||||
|
||||
func newDisabledTun(cidr *net.IPNet, queueLen int, metricsEnabled bool, l *logrus.Logger) *disabledTun {
|
||||
tun := &disabledTun{
|
||||
cidr: cidr,
|
||||
read: make(chan []byte, queueLen),
|
||||
l: l,
|
||||
}
|
||||
|
||||
if metricsEnabled {
|
||||
tun.tx = metrics.GetOrRegisterCounter("messages.tx.message", nil)
|
||||
tun.rx = metrics.GetOrRegisterCounter("messages.rx.message", nil)
|
||||
} else {
|
||||
tun.tx = &metrics.NilCounter{}
|
||||
tun.rx = &metrics.NilCounter{}
|
||||
}
|
||||
|
||||
return tun
|
||||
}
|
||||
|
||||
func (*disabledTun) Activate() error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (t *disabledTun) CidrNet() *net.IPNet {
|
||||
return t.cidr
|
||||
}
|
||||
|
||||
func (*disabledTun) DeviceName() string {
|
||||
return "disabled"
|
||||
}
|
||||
|
||||
func (t *disabledTun) Read(b []byte) (int, error) {
|
||||
r, ok := <-t.read
|
||||
if !ok {
|
||||
return 0, io.EOF
|
||||
}
|
||||
|
||||
if len(r) > len(b) {
|
||||
return 0, fmt.Errorf("packet larger than mtu: %d > %d bytes", len(r), len(b))
|
||||
}
|
||||
|
||||
t.tx.Inc(1)
|
||||
if t.l.Level >= logrus.DebugLevel {
|
||||
t.l.WithField("raw", prettyPacket(r)).Debugf("Write payload")
|
||||
}
|
||||
|
||||
return copy(b, r), nil
|
||||
}
|
||||
|
||||
func (t *disabledTun) handleICMPEchoRequest(b []byte) bool {
|
||||
// Return early if this is not a simple ICMP Echo Request
|
||||
//TODO: make constants out of these
|
||||
if !(len(b) >= 28 && len(b) <= 9001 && b[0] == 0x45 && b[9] == 0x01 && b[20] == 0x08) {
|
||||
return false
|
||||
}
|
||||
|
||||
// We don't support fragmented packets
|
||||
if b[7] != 0 || (b[6]&0x2F != 0) {
|
||||
return false
|
||||
}
|
||||
|
||||
buf := make([]byte, len(b))
|
||||
copy(buf, b)
|
||||
|
||||
// Swap dest / src IPs and recalculate checksum
|
||||
ipv4 := buf[0:20]
|
||||
copy(ipv4[12:16], b[16:20])
|
||||
copy(ipv4[16:20], b[12:16])
|
||||
ipv4[10] = 0
|
||||
ipv4[11] = 0
|
||||
binary.BigEndian.PutUint16(ipv4[10:], ipChecksum(ipv4))
|
||||
|
||||
// Change type to ICMP Echo Reply and recalculate checksum
|
||||
icmp := buf[20:]
|
||||
icmp[0] = 0
|
||||
icmp[2] = 0
|
||||
icmp[3] = 0
|
||||
binary.BigEndian.PutUint16(icmp[2:], ipChecksum(icmp))
|
||||
|
||||
// attempt to write it, but don't block
|
||||
select {
|
||||
case t.read <- buf:
|
||||
default:
|
||||
t.l.Debugf("tun_disabled: dropped ICMP Echo Reply response")
|
||||
}
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
func (t *disabledTun) Write(b []byte) (int, error) {
|
||||
t.rx.Inc(1)
|
||||
|
||||
// Check for ICMP Echo Request before spending time doing the full parsing
|
||||
if t.handleICMPEchoRequest(b) {
|
||||
if t.l.Level >= logrus.DebugLevel {
|
||||
t.l.WithField("raw", prettyPacket(b)).Debugf("Disabled tun responded to ICMP Echo Request")
|
||||
}
|
||||
} else if t.l.Level >= logrus.DebugLevel {
|
||||
t.l.WithField("raw", prettyPacket(b)).Debugf("Disabled tun received unexpected payload")
|
||||
}
|
||||
return len(b), nil
|
||||
}
|
||||
|
||||
func (t *disabledTun) WriteRaw(b []byte) error {
|
||||
_, err := t.Write(b)
|
||||
return err
|
||||
}
|
||||
|
||||
func (t *disabledTun) NewMultiQueueReader() (io.ReadWriteCloser, error) {
|
||||
return t, nil
|
||||
}
|
||||
|
||||
func (t *disabledTun) Close() error {
|
||||
if t.read != nil {
|
||||
close(t.read)
|
||||
t.read = nil
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
type prettyPacket []byte
|
||||
|
||||
func (p prettyPacket) String() string {
|
||||
var s strings.Builder
|
||||
|
||||
for i, b := range p {
|
||||
if i > 0 && i%8 == 0 {
|
||||
s.WriteString(" ")
|
||||
}
|
||||
s.WriteString(fmt.Sprintf("%02x ", b))
|
||||
}
|
||||
|
||||
return s.String()
|
||||
}
|
||||
|
||||
func ipChecksum(b []byte) uint16 {
|
||||
var c uint32
|
||||
sz := len(b) - 1
|
||||
|
||||
for i := 0; i < sz; i += 2 {
|
||||
c += uint32(b[i]) << 8
|
||||
c += uint32(b[i+1])
|
||||
}
|
||||
if sz%2 == 0 {
|
||||
c += uint32(b[sz]) << 8
|
||||
}
|
||||
|
||||
for (c >> 16) > 0 {
|
||||
c = (c & 0xffff) + (c >> 16)
|
||||
}
|
||||
|
||||
return ^uint16(c)
|
||||
}
|
||||
Reference in New Issue
Block a user