feature/conn25: call AuthReconfigAsync after address assignment
When the client of a connector assigns transit IP addresses for a connector we need to let wireguard know that packets for the transit IPs should be sent to the connector node. We do this by: * keeping a map of node -> transit IPs we've assigned for it * setting a callback hook within wireguard reconfig to ask us for these extra allowed IPs. * forcing wireguard to do a reconfig after we have assigned new transit IPs. And this commit is the last part: forcing the wireguard reconfig after a new address assignment. Fixes tailscale/corp#38124 Signed-off-by: Fran Bull <fran@tailscale.com>
This commit is contained in:
@@ -603,13 +603,22 @@ func (e *extension) sendLoop(ctx context.Context) {
|
|||||||
case <-ctx.Done():
|
case <-ctx.Done():
|
||||||
return
|
return
|
||||||
case as := <-e.conn25.client.addrsCh:
|
case as := <-e.conn25.client.addrsCh:
|
||||||
if err := e.sendAddressAssignment(ctx, as); err != nil {
|
if err := e.handleAddressAssignment(ctx, as); err != nil {
|
||||||
e.conn25.client.logf("error sending transit IP assignment (app: %s, mip: %v, src: %v): %v", as.app, as.magic, as.dst, err)
|
e.conn25.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 {
|
||||||
|
if err := e.sendAddressAssignment(ctx, as); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
// TODO(fran) assign the connector publickey -> transit ip addresses
|
||||||
|
e.host.AuthReconfigAsync()
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
func (c *client) enqueueAddressAssignment(addrs addrs) error {
|
func (c *client) enqueueAddressAssignment(addrs addrs) error {
|
||||||
select {
|
select {
|
||||||
// TODO(fran) investigate the value of waiting for multiple addresses and sending them
|
// TODO(fran) investigate the value of waiting for multiple addresses and sending them
|
||||||
|
|||||||
@@ -798,12 +798,14 @@ func (nb *testNodeBackend) PeerAPIBase(p tailcfg.NodeView) string {
|
|||||||
|
|
||||||
type testHost struct {
|
type testHost struct {
|
||||||
ipnext.Host
|
ipnext.Host
|
||||||
nb ipnext.NodeBackend
|
nb ipnext.NodeBackend
|
||||||
hooks ipnext.Hooks
|
hooks ipnext.Hooks
|
||||||
|
authReconfigAsync func()
|
||||||
}
|
}
|
||||||
|
|
||||||
func (h *testHost) NodeBackend() ipnext.NodeBackend { return h.nb }
|
func (h *testHost) NodeBackend() ipnext.NodeBackend { return h.nb }
|
||||||
func (h *testHost) Hooks() *ipnext.Hooks { return &h.hooks }
|
func (h *testHost) Hooks() *ipnext.Hooks { return &h.hooks }
|
||||||
|
func (h *testHost) AuthReconfigAsync() { h.authReconfigAsync() }
|
||||||
|
|
||||||
type testSafeBackend struct {
|
type testSafeBackend struct {
|
||||||
ipnext.SafeBackend
|
ipnext.SafeBackend
|
||||||
@@ -812,9 +814,11 @@ type testSafeBackend struct {
|
|||||||
|
|
||||||
func (b *testSafeBackend) Sys() *tsd.System { return b.sys }
|
func (b *testSafeBackend) Sys() *tsd.System { return b.sys }
|
||||||
|
|
||||||
// TestEnqueueAddress tests that after enqueueAddress has been called a
|
// TestAddressAssignmentIsHandled tests that after enqueueAddress has been called
|
||||||
// peerapi request is made to a peer.
|
// we handle the assignment asynchronously by:
|
||||||
func TestEnqueueAddress(t *testing.T) {
|
// - making a peerapi request to a peer.
|
||||||
|
// - calling AuthReconfigAsync on the host.
|
||||||
|
func TestAddressAssignmentIsHandled(t *testing.T) {
|
||||||
// make a fake peer to test against
|
// make a fake peer to test against
|
||||||
received := make(chan ConnectorTransitIPRequest, 1)
|
received := make(chan ConnectorTransitIPRequest, 1)
|
||||||
peersAPI := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
peersAPI := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||||
@@ -849,11 +853,15 @@ func TestEnqueueAddress(t *testing.T) {
|
|||||||
conn25: newConn25(logger.Discard),
|
conn25: newConn25(logger.Discard),
|
||||||
backend: &testSafeBackend{sys: sys},
|
backend: &testSafeBackend{sys: sys},
|
||||||
}
|
}
|
||||||
|
authReconfigAsyncCalled := make(chan struct{}, 1)
|
||||||
if err := ext.Init(&testHost{
|
if err := ext.Init(&testHost{
|
||||||
nb: &testNodeBackend{
|
nb: &testNodeBackend{
|
||||||
peers: []tailcfg.NodeView{connectorPeer},
|
peers: []tailcfg.NodeView{connectorPeer},
|
||||||
peerAPIURL: peersAPI.URL,
|
peerAPIURL: peersAPI.URL,
|
||||||
},
|
},
|
||||||
|
authReconfigAsync: func() {
|
||||||
|
authReconfigAsyncCalled <- struct{}{}
|
||||||
|
},
|
||||||
}); err != nil {
|
}); err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
@@ -896,6 +904,11 @@ func TestEnqueueAddress(t *testing.T) {
|
|||||||
case <-time.After(5 * time.Second):
|
case <-time.After(5 * time.Second):
|
||||||
t.Fatal("timed out waiting for connector to receive request")
|
t.Fatal("timed out waiting for connector to receive request")
|
||||||
}
|
}
|
||||||
|
select {
|
||||||
|
case <-authReconfigAsyncCalled:
|
||||||
|
case <-time.After(5 * time.Second):
|
||||||
|
t.Fatal("timed out waiting for AuthReconfigAsync to be called")
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func parseResponse(t *testing.T, buf []byte) ([]dnsmessage.Resource, []dnsmessage.Resource) {
|
func parseResponse(t *testing.T, buf []byte) ([]dnsmessage.Resource, []dnsmessage.Resource) {
|
||||||
|
|||||||
Reference in New Issue
Block a user