|
|
|
@ -13,8 +13,11 @@ package natlab
|
|
|
|
|
|
|
|
|
|
import (
|
|
|
|
|
"context"
|
|
|
|
|
"crypto/sha256"
|
|
|
|
|
"encoding/base64"
|
|
|
|
|
"fmt"
|
|
|
|
|
"net"
|
|
|
|
|
"os"
|
|
|
|
|
"sort"
|
|
|
|
|
"strconv"
|
|
|
|
|
"sync"
|
|
|
|
@ -23,6 +26,25 @@ import (
|
|
|
|
|
"inet.af/netaddr"
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
var traceOn = os.Getenv("NATLAB_TRACE")
|
|
|
|
|
|
|
|
|
|
func trace(p []byte, msg string, args ...interface{}) {
|
|
|
|
|
if traceOn == "" {
|
|
|
|
|
return
|
|
|
|
|
}
|
|
|
|
|
id := packetShort(p)
|
|
|
|
|
as := []interface{}{id}
|
|
|
|
|
as = append(as, args...)
|
|
|
|
|
fmt.Fprintf(os.Stderr, "[%s] "+msg+"\n", as...)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// packetShort returns a short identifier for a packet payload,
|
|
|
|
|
// suitable for pritning trace information.
|
|
|
|
|
func packetShort(p []byte) string {
|
|
|
|
|
s := sha256.Sum256(p)
|
|
|
|
|
return base64.RawStdEncoding.EncodeToString(s[:])[:4]
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func mustPrefix(s string) netaddr.IPPrefix {
|
|
|
|
|
ipp, err := netaddr.ParseIPPrefix(s)
|
|
|
|
|
if err != nil {
|
|
|
|
@ -113,12 +135,13 @@ func (n *Network) write(p []byte, dst, src netaddr.IPPort) (num int, err error)
|
|
|
|
|
defer n.mu.Unlock()
|
|
|
|
|
m, ok := n.machine[dst.IP]
|
|
|
|
|
if !ok {
|
|
|
|
|
// TODO: queue? hang forever? return success? don't fail fast probably.
|
|
|
|
|
return 0, fmt.Errorf("unknown dest IP %v", dst.IP)
|
|
|
|
|
trace(p, "net=%s dropped, no route to %v", n.Name, dst.IP)
|
|
|
|
|
return len(p), nil
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Pretend it went across the network. Make a copy so nobody
|
|
|
|
|
// can later mess with caller's memory.
|
|
|
|
|
trace(p, "net=%s src=%v dst=%v -> mach=%s", n.Name, src, dst, m.name)
|
|
|
|
|
pcopy := append([]byte(nil), p...)
|
|
|
|
|
go m.deliverIncomingPacket(pcopy, dst, src)
|
|
|
|
|
return len(p), nil
|
|
|
|
@ -201,17 +224,21 @@ func (m *Machine) deliverIncomingPacket(p []byte, dst, src netaddr.IPPort) {
|
|
|
|
|
netaddr.IPPort{IP: v6unspec, Port: dst.Port},
|
|
|
|
|
netaddr.IPPort{IP: v4unspec, Port: dst.Port},
|
|
|
|
|
}
|
|
|
|
|
for _, dst := range possibleDsts {
|
|
|
|
|
c, ok := conns[dst]
|
|
|
|
|
for _, dest := range possibleDsts {
|
|
|
|
|
c, ok := conns[dest]
|
|
|
|
|
if !ok {
|
|
|
|
|
continue
|
|
|
|
|
}
|
|
|
|
|
select {
|
|
|
|
|
case c.in <- incomingPacket{src: src, p: p}:
|
|
|
|
|
trace(p, "mach=%s src=%v dst=%v queued to conn", m.name, src, dst)
|
|
|
|
|
default:
|
|
|
|
|
trace(p, "mach=%s src=%v dst=%v dropped, queue overflow", m.name, src, dst)
|
|
|
|
|
// Queue overflow. Just drop it.
|
|
|
|
|
}
|
|
|
|
|
return
|
|
|
|
|
}
|
|
|
|
|
trace(p, "mach=%s src=%v dst=%v dropped, no listening conn", m.name, src, dst)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func unspecOf(ip netaddr.IP) netaddr.IP {
|
|
|
|
@ -283,6 +310,7 @@ var (
|
|
|
|
|
func (m *Machine) writePacket(p []byte, dst, src netaddr.IPPort) (n int, err error) {
|
|
|
|
|
iface, err := m.interfaceForIP(dst.IP)
|
|
|
|
|
if err != nil {
|
|
|
|
|
trace(p, "%v", err)
|
|
|
|
|
return 0, err
|
|
|
|
|
}
|
|
|
|
|
origSrcIP := src.IP
|
|
|
|
@ -298,13 +326,18 @@ func (m *Machine) writePacket(p []byte, dst, src netaddr.IPPort) (n int, err err
|
|
|
|
|
}
|
|
|
|
|
default:
|
|
|
|
|
if !iface.Contains(src.IP) {
|
|
|
|
|
return 0, fmt.Errorf("can't send to %v with src %v on interface %v", dst.IP, src.IP, iface)
|
|
|
|
|
err := fmt.Errorf("can't send to %v with src %v on interface %v", dst.IP, src.IP, iface)
|
|
|
|
|
trace(p, "%v", err)
|
|
|
|
|
return 0, err
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
if src.IP.IsZero() {
|
|
|
|
|
return 0, fmt.Errorf("no matching address for address family for %v", origSrcIP)
|
|
|
|
|
err := fmt.Errorf("no matching address for address family for %v", origSrcIP)
|
|
|
|
|
trace(p, "%v", err)
|
|
|
|
|
return 0, err
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
trace(p, "mach=%s src=%s dst=%s -> net=%s", m.name, src, dst, iface.net.Name)
|
|
|
|
|
return iface.net.write(p, dst, src)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|