123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174 |
- package nebula
- 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
- if !(len(b) >= 28 && len(b) <= mtu && 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)
- }
|