Change-Id: Ib6804b5c56d8d8da4eb850ef09bc86fc3610ba92
Signed-off-by: Brad Fitzpatrick <bradfitz@tailscale.com>
This commit is contained in:
Brad Fitzpatrick
2024-08-07 12:41:26 -07:00
parent 2e3a896cab
commit 602adde5dc
6 changed files with 375 additions and 27 deletions

View File

@@ -27,6 +27,10 @@ type Config struct {
networks []*Network
}
func (c *Config) NumNodes() int {
return len(c.nodes)
}
// AddNode creates a new node in the world.
//
// The opts may be of the following types:
@@ -110,6 +114,11 @@ type Node struct {
nets []*Network
}
// MAC returns the MAC address of the node.
func (n *Node) MAC() MAC {
return n.mac
}
// Network returns the first network this node is connected to,
// or nil if none.
func (n *Node) Network() *Network {

View File

@@ -271,6 +271,20 @@ func (n *network) acceptTCP(r *tcp.ForwarderRequest) {
return
}
if destPort == 124 {
r.Complete(false)
tc := gonet.NewTCPConn(&wq, ep)
go func() {
defer tc.Close()
bs := bufio.NewScanner(tc)
for bs.Scan() {
line := bs.Text()
log.Printf("LOG from guest: %s", line)
}
}()
return
}
if destPort == 8008 && destIP == fakeTestAgentIP {
r.Complete(false)
tc := gonet.NewTCPConn(&wq, ep)
@@ -448,6 +462,7 @@ func newDERPServer() *derpServer {
type Server struct {
shutdownCtx context.Context
shutdownCancel context.CancelFunc
blendReality bool
derpIPs set.Set[netip.Addr]
@@ -459,12 +474,14 @@ type Server struct {
control *testcontrol.Server
derps []*derpServer
mu sync.Mutex
agentConnWaiter map[*node]chan<- struct{} // signaled after added to set
agentConns set.Set[*agentConn] // not keyed by node; should be small/cheap enough to scan all
agentRoundTripper map[*node]*http.Transport
mu sync.Mutex
agentConnWaiter map[*node]chan<- struct{} // signaled after added to set
agentConns set.Set[*agentConn] // not keyed by node; should be small/cheap enough to scan all
agentDialer map[*node]DialFunc
}
type DialFunc func(ctx context.Context, network, address string) (net.Conn, error)
var derpMap = &tailcfg.DERPMap{
Regions: map[int]*tailcfg.DERPRegion{
1: {
@@ -532,6 +549,10 @@ func New(c *Config) (*Server, error) {
return s, nil
}
func (s *Server) Close() {
s.shutdownCancel()
}
func (s *Server) HWAddr(mac MAC) net.HardwareAddr {
// TODO: cache
return net.HardwareAddr(mac[:])
@@ -655,7 +676,7 @@ func (s *Server) routeUDPPacket(up UDPPacket) {
if up.Dst.Port() == stunPort {
// TODO(bradfitz): fake latency; time.AfterFunc the response
if res, ok := makeSTUNReply(up); ok {
log.Printf("STUN reply: %+v", res)
//log.Printf("STUN reply: %+v", res)
s.routeUDPPacket(res)
} else {
log.Printf("weird: STUN packet not handled")
@@ -1015,15 +1036,18 @@ func (s *Server) shouldInterceptTCP(pkt gopacket.Packet) bool {
if !ok {
return false
}
if tcp.DstPort == 123 {
if tcp.DstPort == 123 || tcp.DstPort == 124 {
return true
}
dstIP, _ := netip.AddrFromSlice(ipv4.DstIP.To4())
if tcp.DstPort == 80 || tcp.DstPort == 443 {
switch dstIP {
case fakeProxyControlplaneIP, fakeControlIP, fakeDERP1IP, fakeDERP2IP:
case fakeControlIP, fakeDERP1IP, fakeDERP2IP:
return true
}
if dstIP == fakeProxyControlplaneIP {
return s.blendReality
}
if s.derpIPs.Contains(dstIP) {
return true
}
@@ -1294,12 +1318,15 @@ func (s *Server) takeAgentConn(ctx context.Context, n *node) (_ *agentConn, ok b
for {
ac, ok := s.takeAgentConnOne(n)
if ok {
log.Printf("got agent conn for %v", n.mac)
return ac, true
}
s.mu.Lock()
ready := make(chan struct{})
mak.Set(&s.agentConnWaiter, n, ready)
s.mu.Unlock()
log.Printf("waiting for agent conn for %v", n.mac)
select {
case <-ctx.Done():
return nil, false
@@ -1318,36 +1345,41 @@ func (s *Server) takeAgentConnOne(n *node) (_ *agentConn, ok bool) {
for ac := range s.agentConns {
if ac.node == n {
s.agentConns.Delete(ac)
log.Printf("XXX takeAgentConnOne HIT for %v", n.mac)
return ac, true
}
}
log.Printf("XXX takeAgentConnOne MISS for %v", n.mac)
return nil, false
}
func (s *Server) NodeAgentRoundTripper(ctx context.Context, n *Node) http.RoundTripper {
func (s *Server) NodeAgentDialer(n *Node) DialFunc {
s.mu.Lock()
defer s.mu.Unlock()
if rt, ok := s.agentRoundTripper[n.n]; ok {
return rt
if d, ok := s.agentDialer[n.n]; ok {
return d
}
var rt = &http.Transport{
DialContext: func(ctx context.Context, network, addr string) (net.Conn, error) {
ac, ok := s.takeAgentConn(ctx, n.n)
if !ok {
return nil, ctx.Err()
}
return ac.tc, nil
},
d := func(ctx context.Context, network, addr string) (net.Conn, error) {
ac, ok := s.takeAgentConn(ctx, n.n)
if !ok {
return nil, ctx.Err()
}
return ac.tc, nil
}
mak.Set(&s.agentDialer, n.n, d)
return d
}
mak.Set(&s.agentRoundTripper, n.n, rt)
return rt
func (s *Server) NodeAgentRoundTripper(n *Node) http.RoundTripper {
return &http.Transport{
DisableKeepAlives: true, // XXX
DialContext: s.NodeAgentDialer(n),
}
}
func (s *Server) NodeStatus(ctx context.Context, n *Node) ([]byte, error) {
rt := s.NodeAgentRoundTripper(ctx, n)
rt := s.NodeAgentRoundTripper(n)
req, err := http.NewRequestWithContext(ctx, "GET", "http://node/status", nil)
if err != nil {
return nil, err