mirror of
https://github.com/tailscale/tailscale.git
synced 2026-05-05 04:06:35 +02:00
sketch
This commit is contained in:
parent
47ecbe5845
commit
0db350d1ce
@ -72,9 +72,10 @@ func normalizeDNSName(name string) (dnsname.FQDN, error) {
|
||||
func init() {
|
||||
feature.Register(featureName)
|
||||
ipnext.RegisterExtension(featureName, func(logf logger.Logf, sb ipnext.SafeBackend) (ipnext.Extension, error) {
|
||||
conn25 := newConn25(logger.WithPrefix(logf, "conn25: "))
|
||||
conn25.backend = sb
|
||||
return &extension{
|
||||
conn25: newConn25(logger.WithPrefix(logf, "conn25: ")),
|
||||
backend: sb,
|
||||
conn25: conn25,
|
||||
}, nil
|
||||
})
|
||||
ipnlocal.RegisterPeerAPIHandler("/v0/connector/transit-ip", handleConnectorTransitIP)
|
||||
@ -97,10 +98,7 @@ func handleConnectorTransitIP(h ipnlocal.PeerAPIHandler, w http.ResponseWriter,
|
||||
// extension is an [ipnext.Extension] managing the connector on platforms
|
||||
// that import this package.
|
||||
type extension struct {
|
||||
conn25 *Conn25 // safe for concurrent access and only set at creation
|
||||
backend ipnext.SafeBackend // safe for concurrent access and only set at creation
|
||||
|
||||
host ipnext.Host // set in Init, read-only after
|
||||
conn25 *Conn25 // safe for concurrent access and only set at creation
|
||||
ctxCancel context.CancelCauseFunc // cancels sendLoop goroutine
|
||||
}
|
||||
|
||||
@ -119,7 +117,7 @@ func (e *extension) Init(host ipnext.Host) error {
|
||||
if e.ctxCancel != nil {
|
||||
return nil
|
||||
}
|
||||
e.host = host
|
||||
e.conn25.host = host
|
||||
|
||||
dph := newDatapathHandler(e.conn25, e.conn25.client.logf)
|
||||
if err := e.installHooks(dph); err != nil {
|
||||
@ -129,17 +127,17 @@ func (e *extension) Init(host ipnext.Host) error {
|
||||
|
||||
ctx, cancel := context.WithCancelCause(context.Background())
|
||||
e.ctxCancel = cancel
|
||||
go e.sendLoop(ctx)
|
||||
go e.conn25.sendLoop(ctx)
|
||||
return nil
|
||||
}
|
||||
|
||||
func (e *extension) installHooks(dph *datapathHandler) error {
|
||||
// Make sure we can access the DNS manager and the system tun.
|
||||
dnsManager, ok := e.backend.Sys().DNSManager.GetOK()
|
||||
dnsManager, ok := e.conn25.backend.Sys().DNSManager.GetOK()
|
||||
if !ok {
|
||||
return errors.New("could not access system dns manager")
|
||||
}
|
||||
tun, ok := e.backend.Sys().Tun.GetOK()
|
||||
tun, ok := e.conn25.backend.Sys().Tun.GetOK()
|
||||
if !ok {
|
||||
return errors.New("could not access system tun")
|
||||
}
|
||||
@ -170,15 +168,15 @@ func (e *extension) installHooks(dph *datapathHandler) error {
|
||||
|
||||
// Manage how we react to changes to the current node,
|
||||
// including property changes (e.g. HostInfo, Capabilities, CapMap).
|
||||
e.host.Hooks().OnSelfChange.Add(e.onSelfChange)
|
||||
e.conn25.host.Hooks().OnSelfChange.Add(e.onSelfChange)
|
||||
|
||||
// Manage how we react profile state changes, which include
|
||||
// prefs changes.
|
||||
e.host.Hooks().ProfileStateChange.Add(e.profileStateChange)
|
||||
e.conn25.host.Hooks().ProfileStateChange.Add(e.profileStateChange)
|
||||
|
||||
// Allow the client to send packets with Transit IP destinations
|
||||
// in the link-local space.
|
||||
e.host.Hooks().Filter.LinkLocalAllowHooks.Add(func(p packet.Parsed) (bool, string) {
|
||||
e.conn25.host.Hooks().Filter.LinkLocalAllowHooks.Add(func(p packet.Parsed) (bool, string) {
|
||||
if !e.conn25.isConfigured() {
|
||||
return false, ""
|
||||
}
|
||||
@ -187,7 +185,7 @@ func (e *extension) installHooks(dph *datapathHandler) error {
|
||||
|
||||
// Allow the connector to receive packets with Transit IP destinations
|
||||
// in the link-local space.
|
||||
e.host.Hooks().Filter.LinkLocalAllowHooks.Add(func(p packet.Parsed) (bool, string) {
|
||||
e.conn25.host.Hooks().Filter.LinkLocalAllowHooks.Add(func(p packet.Parsed) (bool, string) {
|
||||
if !e.conn25.isConfigured() {
|
||||
return false, ""
|
||||
}
|
||||
@ -196,7 +194,7 @@ func (e *extension) installHooks(dph *datapathHandler) error {
|
||||
|
||||
// Allow the connector to receive packets with Transit IP destinations
|
||||
// that are not "local" to it, and that it does not advertise.
|
||||
e.host.Hooks().Filter.IngressAllowHooks.Add(func(p packet.Parsed) (bool, string) {
|
||||
e.conn25.host.Hooks().Filter.IngressAllowHooks.Add(func(p packet.Parsed) (bool, string) {
|
||||
if !e.conn25.isConfigured() {
|
||||
return false, ""
|
||||
}
|
||||
@ -204,7 +202,7 @@ func (e *extension) installHooks(dph *datapathHandler) error {
|
||||
})
|
||||
|
||||
// Give the client the Magic IP range to install on the OS.
|
||||
e.host.Hooks().ExtraRouterConfigRoutes.Set(func() views.Slice[netip.Prefix] {
|
||||
e.conn25.host.Hooks().ExtraRouterConfigRoutes.Set(func() views.Slice[netip.Prefix] {
|
||||
if !e.conn25.isConfigured() {
|
||||
return views.Slice[netip.Prefix]{}
|
||||
}
|
||||
@ -212,7 +210,7 @@ func (e *extension) installHooks(dph *datapathHandler) error {
|
||||
})
|
||||
|
||||
// Tell WireGuard what Transit IPs belong to which connector peers.
|
||||
e.host.Hooks().ExtraWireGuardAllowedIPs.Set(func(k key.NodePublic) views.Slice[netip.Prefix] {
|
||||
e.conn25.host.Hooks().ExtraWireGuardAllowedIPs.Set(func(k key.NodePublic) views.Slice[netip.Prefix] {
|
||||
if !e.conn25.isConfigured() {
|
||||
return views.Slice[netip.Prefix]{}
|
||||
}
|
||||
@ -227,7 +225,7 @@ func (e *extension) installHooks(dph *datapathHandler) error {
|
||||
// for Conn25 to be fully configured and ready to use.
|
||||
func (e *extension) seedPrefsConfig() {
|
||||
var cfg config
|
||||
cfg.prefs = configFromPrefs(e.host.Profiles().CurrentPrefs())
|
||||
cfg.prefs = configFromPrefs(e.conn25.host.Profiles().CurrentPrefs())
|
||||
e.conn25.reconfig(cfg)
|
||||
}
|
||||
|
||||
@ -315,7 +313,10 @@ type appAddr struct {
|
||||
|
||||
// Conn25 holds state for routing traffic for a domain via a connector.
|
||||
type Conn25 struct {
|
||||
mu sync.Mutex // mu protects reconfiguration of client and connector
|
||||
mu sync.Mutex // mu protects reconfiguration of client and connector
|
||||
host ipnext.Host
|
||||
backend ipnext.SafeBackend
|
||||
|
||||
client *client
|
||||
connector *connector
|
||||
}
|
||||
@ -778,30 +779,30 @@ func (c *client) addTransitIPForConnector(tip netip.Addr, conn tailcfg.NodeView)
|
||||
return c.assignments.insertTransitConnMapping(tip, conn.Key())
|
||||
}
|
||||
|
||||
func (e *extension) sendLoop(ctx context.Context) {
|
||||
func (c *Conn25) sendLoop(ctx context.Context) {
|
||||
for {
|
||||
select {
|
||||
case <-ctx.Done():
|
||||
return
|
||||
case as := <-e.conn25.client.addrsCh:
|
||||
if err := e.handleAddressAssignment(ctx, as); err != nil {
|
||||
e.conn25.client.logf("error handling transit IP assignment (app: %s, mip: %v, src: %v): %v", as.app, as.magic, as.dst, err)
|
||||
case as := <-c.client.addrsCh:
|
||||
if err := c.handleAddressAssignment(ctx, as); err != nil {
|
||||
c.client.logf("error handling transit IP assignment (app: %s, mip: %v, src: %v): %v", as.app, as.magic, as.dst, err)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (e *extension) handleAddressAssignment(ctx context.Context, as addrs) error {
|
||||
conn, err := e.sendAddressAssignment(ctx, as)
|
||||
func (c *Conn25) handleAddressAssignment(ctx context.Context, as addrs) error {
|
||||
conn, err := c.sendAddressAssignment(ctx, as)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
err = e.conn25.client.addTransitIPForConnector(as.transit, conn)
|
||||
err = c.client.addTransitIPForConnector(as.transit, conn)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
e.host.AuthReconfigAsync()
|
||||
c.host.AuthReconfigAsync()
|
||||
return nil
|
||||
}
|
||||
|
||||
@ -868,14 +869,14 @@ func makePeerAPIReq(ctx context.Context, httpClient *http.Client, urlBase string
|
||||
return nil
|
||||
}
|
||||
|
||||
func (e *extension) sendAddressAssignment(ctx context.Context, as addrs) (tailcfg.NodeView, error) {
|
||||
app, ok := e.conn25.client.getConfig().nv.appsByName[as.app]
|
||||
func (c *Conn25) sendAddressAssignment(ctx context.Context, as addrs) (tailcfg.NodeView, error) {
|
||||
app, ok := c.client.getConfig().nv.appsByName[as.app]
|
||||
if !ok {
|
||||
e.conn25.client.logf("App not found for app: %s (domain: %s)", as.app, as.domain)
|
||||
c.client.logf("App not found for app: %s (domain: %s)", as.app, as.domain)
|
||||
return tailcfg.NodeView{}, errors.New("app not found")
|
||||
}
|
||||
|
||||
nb := e.host.NodeBackend()
|
||||
nb := c.host.NodeBackend()
|
||||
peers := appc.PickConnector(nb, app)
|
||||
var urlBase string
|
||||
var conn tailcfg.NodeView
|
||||
@ -889,7 +890,7 @@ func (e *extension) sendAddressAssignment(ctx context.Context, as addrs) (tailcf
|
||||
if urlBase == "" {
|
||||
return tailcfg.NodeView{}, errors.New("no connector peer found to handle address assignment")
|
||||
}
|
||||
client := e.backend.Sys().Dialer.Get().PeerAPIHTTPClient()
|
||||
client := c.backend.Sys().Dialer.Get().PeerAPIHTTPClient()
|
||||
return conn, makePeerAPIReq(ctx, client, urlBase, as)
|
||||
}
|
||||
|
||||
|
||||
@ -1095,12 +1095,10 @@ func TestAddressAssignmentIsHandled(t *testing.T) {
|
||||
Key: key.NodePublicFromRaw32(mem.B([]byte{0: 0xff, 1: 0xff, 31: 0x01})),
|
||||
}).View()
|
||||
|
||||
ext := &extension{
|
||||
conn25: newConn25(logger.Discard),
|
||||
backend: newTestSafeBackend(),
|
||||
}
|
||||
conn25 := newConn25(logger.Discard)
|
||||
backend := newTestSafeBackend()
|
||||
authReconfigAsyncCalled := make(chan struct{}, 1)
|
||||
if err := ext.Init(&testHost{
|
||||
host := &testHost{
|
||||
nb: &testNodeBackend{
|
||||
peers: []tailcfg.NodeView{connectorPeer},
|
||||
peerAPIURL: peersAPI.URL,
|
||||
@ -1109,10 +1107,10 @@ func TestAddressAssignmentIsHandled(t *testing.T) {
|
||||
authReconfigAsync: func() {
|
||||
authReconfigAsyncCalled <- struct{}{}
|
||||
},
|
||||
}); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
defer ext.Shutdown()
|
||||
conn25.backend = backend
|
||||
conn25.host = host
|
||||
go conn25.sendLoop(t.Context())
|
||||
|
||||
sn := makeSelfNode(t, []appctype.Conn25Attr{{
|
||||
Name: "app1",
|
||||
@ -1121,7 +1119,7 @@ func TestAddressAssignmentIsHandled(t *testing.T) {
|
||||
}}, []string{})
|
||||
|
||||
cfg := mustConfig(t, sn, testPrefsNotConnector)
|
||||
ext.conn25.reconfig(cfg)
|
||||
conn25.reconfig(cfg)
|
||||
|
||||
as := addrs{
|
||||
dst: netip.MustParseAddr("1.2.3.4"),
|
||||
@ -1130,10 +1128,10 @@ func TestAddressAssignmentIsHandled(t *testing.T) {
|
||||
domain: "example.com.",
|
||||
app: "app1",
|
||||
}
|
||||
if err := ext.conn25.client.assignments.insert(as); err != nil {
|
||||
if err := conn25.client.assignments.insert(as); err != nil {
|
||||
t.Fatalf("error inserting address assignments: %v", err)
|
||||
}
|
||||
ext.conn25.client.enqueueAddressAssignment(as)
|
||||
conn25.client.enqueueAddressAssignment(as)
|
||||
|
||||
select {
|
||||
case got := <-received:
|
||||
@ -1521,12 +1519,10 @@ func TestHandleAddressAssignmentStoresTransitIPs(t *testing.T) {
|
||||
}).View(),
|
||||
}
|
||||
|
||||
ext := &extension{
|
||||
conn25: newConn25(logger.Discard),
|
||||
backend: newTestSafeBackend(),
|
||||
}
|
||||
conn25 := newConn25(logger.Discard)
|
||||
backend := newTestSafeBackend()
|
||||
authReconfigAsyncCalled := make(chan struct{}, 1)
|
||||
if err := ext.Init(&testHost{
|
||||
host := &testHost{
|
||||
nb: &testNodeBackend{
|
||||
peers: connectorPeers,
|
||||
peerAPIURL: peersAPI.URL,
|
||||
@ -1535,10 +1531,10 @@ func TestHandleAddressAssignmentStoresTransitIPs(t *testing.T) {
|
||||
authReconfigAsync: func() {
|
||||
authReconfigAsyncCalled <- struct{}{}
|
||||
},
|
||||
}); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
defer ext.Shutdown()
|
||||
conn25.backend = backend
|
||||
conn25.host = host
|
||||
go conn25.sendLoop(t.Context())
|
||||
|
||||
sn := makeSelfNode(t, []appctype.Conn25Attr{
|
||||
{
|
||||
@ -1554,7 +1550,7 @@ func TestHandleAddressAssignmentStoresTransitIPs(t *testing.T) {
|
||||
}, []string{})
|
||||
|
||||
cfg := mustConfig(t, sn, testPrefsNotConnector)
|
||||
ext.conn25.reconfig(cfg)
|
||||
conn25.reconfig(cfg)
|
||||
|
||||
type lookup struct {
|
||||
connKey key.NodePublic
|
||||
@ -1651,10 +1647,10 @@ func TestHandleAddressAssignmentStoresTransitIPs(t *testing.T) {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
// Add and enqueue the addrs, and then wait for the send to complete
|
||||
// (as indicated by authReconfig being called).
|
||||
if err := ext.conn25.client.assignments.insert(tt.as); err != nil {
|
||||
if err := conn25.client.assignments.insert(tt.as); err != nil {
|
||||
t.Fatalf("error inserting address assignment: %v", err)
|
||||
}
|
||||
if err := ext.conn25.client.enqueueAddressAssignment(tt.as); err != nil {
|
||||
if err := conn25.client.enqueueAddressAssignment(tt.as); err != nil {
|
||||
t.Fatalf("error enqueuing address assignment: %v", err)
|
||||
}
|
||||
select {
|
||||
@ -1665,7 +1661,7 @@ func TestHandleAddressAssignmentStoresTransitIPs(t *testing.T) {
|
||||
|
||||
// Check that each of the lookups behaves as expected
|
||||
for i, lu := range tt.lookups {
|
||||
got, ok := ext.conn25.client.assignments.lookupTransitIPsByConnKey(lu.connKey)
|
||||
got, ok := conn25.client.assignments.lookupTransitIPsByConnKey(lu.connKey)
|
||||
if ok != lu.expectedOk {
|
||||
t.Fatalf("unexpected ok result at index %d wanted %v, got %v", i, lu.expectedOk, ok)
|
||||
}
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user