feature/conn25: use new pool nodeattr
We have been reading the pool config from the app nodeattr, but it is global config, not per app, so it needs to be its own thing. Updates tailscale/corp#39999 Signed-off-by: Fran Bull <fran@tailscale.com>
This commit is contained in:
+31
-27
@@ -547,6 +547,7 @@ type ConnectorTransitIPResponse struct {
|
||||
}
|
||||
|
||||
const AppConnectorsExperimentalAttrName = "tailscale.com/app-connectors-experimental"
|
||||
const AppConnectorsExperimentalIPPoolsAttrName = "tailscale.com/app-connectors-experimental-ippools"
|
||||
|
||||
// ipSets wraps all the IPSets the config needs.
|
||||
type ipSets struct {
|
||||
@@ -586,6 +587,14 @@ func configFromNodeView(n tailcfg.NodeView) (*config, error) {
|
||||
if len(apps) == 0 {
|
||||
return &config{}, nil
|
||||
}
|
||||
poolsSlice, err := tailcfg.UnmarshalNodeCapViewJSON[appctype.Conn25PoolsAttr](n.CapMap(), AppConnectorsExperimentalIPPoolsAttrName)
|
||||
if err != nil {
|
||||
return &config{}, err
|
||||
}
|
||||
if len(poolsSlice) != 1 {
|
||||
return &config{}, errors.New("must be one conn25 pools nodeattr")
|
||||
}
|
||||
pools := poolsSlice[0]
|
||||
selfTags := set.SetOf(n.Tags().AsSlice())
|
||||
cfg := &config{
|
||||
isConfigured: true,
|
||||
@@ -620,34 +629,29 @@ func configFromNodeView(n tailcfg.NodeView) (*config, error) {
|
||||
|
||||
}
|
||||
|
||||
// TODO(fran) 2026-03-18 we don't yet have a proper way to communicate the
|
||||
// global IP pool config. For now just take it from the first app.
|
||||
if len(apps) != 0 {
|
||||
app := apps[0]
|
||||
v4Mipp, err := ipSetFromIPRanges(app.V4MagicIPPool)
|
||||
if err != nil {
|
||||
return &config{}, err
|
||||
}
|
||||
v4Tipp, err := ipSetFromIPRanges(app.V4TransitIPPool)
|
||||
if err != nil {
|
||||
return &config{}, err
|
||||
}
|
||||
v6Mipp, err := ipSetFromIPRanges(app.V6MagicIPPool)
|
||||
if err != nil {
|
||||
return &config{}, err
|
||||
}
|
||||
v6Tipp, err := ipSetFromIPRanges(app.V6TransitIPPool)
|
||||
if err != nil {
|
||||
return &config{}, err
|
||||
}
|
||||
ipSets := ipSets{
|
||||
v4Magic: v4Mipp,
|
||||
v4Transit: v4Tipp,
|
||||
v6Magic: v6Mipp,
|
||||
v6Transit: v6Tipp,
|
||||
}
|
||||
cfg.ipSets = ipSets
|
||||
v4Mipp, err := ipSetFromIPRanges(pools.V4MagicIPPool)
|
||||
if err != nil {
|
||||
return &config{}, err
|
||||
}
|
||||
v4Tipp, err := ipSetFromIPRanges(pools.V4TransitIPPool)
|
||||
if err != nil {
|
||||
return &config{}, err
|
||||
}
|
||||
v6Mipp, err := ipSetFromIPRanges(pools.V6MagicIPPool)
|
||||
if err != nil {
|
||||
return &config{}, err
|
||||
}
|
||||
v6Tipp, err := ipSetFromIPRanges(pools.V6TransitIPPool)
|
||||
if err != nil {
|
||||
return &config{}, err
|
||||
}
|
||||
ipSets := ipSets{
|
||||
v4Magic: v4Mipp,
|
||||
v4Transit: v4Tipp,
|
||||
v6Magic: v6Mipp,
|
||||
v6Transit: v6Tipp,
|
||||
}
|
||||
cfg.ipSets = ipSets
|
||||
return cfg, nil
|
||||
}
|
||||
|
||||
|
||||
+108
-55
@@ -458,6 +458,9 @@ func TestReconfig(t *testing.T) {
|
||||
tailcfg.NodeCapability(AppConnectorsExperimentalAttrName): []tailcfg.RawMessage{
|
||||
tailcfg.RawMessage(rawCfg),
|
||||
},
|
||||
tailcfg.NodeCapability(AppConnectorsExperimentalIPPoolsAttrName): []tailcfg.RawMessage{
|
||||
tailcfg.RawMessage("{}"),
|
||||
},
|
||||
}
|
||||
|
||||
c := newConn25(logger.Discard)
|
||||
@@ -485,11 +488,26 @@ func TestReconfig(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func getRawMessages[T any](t *testing.T, attrs []T) []tailcfg.RawMessage {
|
||||
t.Helper()
|
||||
toRet := make([]tailcfg.RawMessage, 0, len(attrs))
|
||||
for _, attr := range attrs {
|
||||
bs, err := json.Marshal(attr)
|
||||
if err != nil {
|
||||
t.Fatalf("unexpected error in test setup: %v", err)
|
||||
}
|
||||
toRet = append(toRet, tailcfg.RawMessage(bs))
|
||||
}
|
||||
return toRet
|
||||
}
|
||||
|
||||
func TestConfigFromNodeView(t *testing.T) {
|
||||
for _, tt := range []struct {
|
||||
name string
|
||||
rawCfg string
|
||||
cfg []appctype.Conn25Attr
|
||||
rawAppCfg string
|
||||
appCfg []appctype.Conn25Attr
|
||||
rawPoolsCfg string
|
||||
poolsCfg []appctype.Conn25PoolsAttr
|
||||
tags []string
|
||||
wantErr bool
|
||||
wantAppsByDomain map[dnsname.FQDN][]string
|
||||
@@ -497,17 +515,27 @@ func TestConfigFromNodeView(t *testing.T) {
|
||||
wantSelfAppNames set.Set[string]
|
||||
}{
|
||||
{
|
||||
name: "bad-config",
|
||||
rawCfg: `bad`,
|
||||
wantErr: true,
|
||||
name: "bad-app-config",
|
||||
rawAppCfg: `bad`,
|
||||
rawPoolsCfg: "{}",
|
||||
wantErr: true,
|
||||
},
|
||||
{
|
||||
name: "bad-pool-config",
|
||||
appCfg: []appctype.Conn25Attr{
|
||||
{Name: "one", Domains: []string{"a.example.com"}, Connectors: []string{"tag:one"}},
|
||||
},
|
||||
rawPoolsCfg: "bad",
|
||||
wantErr: true,
|
||||
},
|
||||
{
|
||||
name: "simple",
|
||||
cfg: []appctype.Conn25Attr{
|
||||
appCfg: []appctype.Conn25Attr{
|
||||
{Name: "one", Domains: []string{"a.example.com"}, Connectors: []string{"tag:one"}},
|
||||
{Name: "two", Domains: []string{"b.example.com"}, Connectors: []string{"tag:two"}},
|
||||
},
|
||||
tags: []string{"tag:one"},
|
||||
rawPoolsCfg: "{}",
|
||||
tags: []string{"tag:one"},
|
||||
wantAppsByDomain: map[dnsname.FQDN][]string{
|
||||
"a.example.com.": {"one"},
|
||||
"b.example.com.": {"two"},
|
||||
@@ -517,13 +545,14 @@ func TestConfigFromNodeView(t *testing.T) {
|
||||
},
|
||||
{
|
||||
name: "more-complex-with-connector-self-domains",
|
||||
cfg: []appctype.Conn25Attr{
|
||||
appCfg: []appctype.Conn25Attr{
|
||||
{Name: "one", Domains: []string{"1.a.example.com", "1.b.example.com"}, Connectors: []string{"tag:one", "tag:onea"}},
|
||||
{Name: "two", Domains: []string{"2.b.example.com", "2.c.example.com"}, Connectors: []string{"tag:two", "tag:twoa"}},
|
||||
{Name: "three", Domains: []string{"1.b.example.com", "1.c.example.com"}, Connectors: []string{}},
|
||||
{Name: "four", Domains: []string{"4.b.example.com", "4.d.example.com"}, Connectors: []string{"tag:four"}},
|
||||
},
|
||||
tags: []string{"tag:onea", "tag:four", "tag:unrelated"},
|
||||
rawPoolsCfg: "{}",
|
||||
tags: []string{"tag:onea", "tag:four", "tag:unrelated"},
|
||||
wantAppsByDomain: map[dnsname.FQDN][]string{
|
||||
"1.a.example.com.": {"one"},
|
||||
"1.b.example.com.": {"one", "three"},
|
||||
@@ -538,11 +567,12 @@ func TestConfigFromNodeView(t *testing.T) {
|
||||
},
|
||||
{
|
||||
name: "eligible-connector-no-matching-tag-no-self-domains",
|
||||
cfg: []appctype.Conn25Attr{
|
||||
appCfg: []appctype.Conn25Attr{
|
||||
{Name: "one", Domains: []string{"a.example.com"}, Connectors: []string{"tag:one"}},
|
||||
{Name: "two", Domains: []string{"b.example.com"}, Connectors: []string{"tag:two"}},
|
||||
},
|
||||
tags: []string{"tag:unrelated"},
|
||||
rawPoolsCfg: "{}",
|
||||
tags: []string{"tag:unrelated"},
|
||||
wantAppsByDomain: map[dnsname.FQDN][]string{
|
||||
"a.example.com.": {"one"},
|
||||
"b.example.com.": {"two"},
|
||||
@@ -550,11 +580,12 @@ func TestConfigFromNodeView(t *testing.T) {
|
||||
wantAppsByWCDomain: map[dnsname.FQDN][]string{}},
|
||||
{
|
||||
name: "wildcard-collapse-and-deduplication",
|
||||
cfg: []appctype.Conn25Attr{
|
||||
appCfg: []appctype.Conn25Attr{
|
||||
{Name: "one", Domains: []string{"*.example.com", "example.com"}, Connectors: []string{"tag:one"}},
|
||||
{Name: "two", Domains: []string{"example.com", "sub.example.com"}, Connectors: []string{"tag:two"}},
|
||||
},
|
||||
tags: []string{"tag:one", "tag:two"},
|
||||
rawPoolsCfg: "{}",
|
||||
tags: []string{"tag:one", "tag:two"},
|
||||
wantAppsByDomain: map[dnsname.FQDN][]string{
|
||||
"example.com.": {"one", "two"},
|
||||
"sub.example.com.": {"two"},
|
||||
@@ -569,10 +600,11 @@ func TestConfigFromNodeView(t *testing.T) {
|
||||
// domain and the app name must appear exactly once in appNamesByDomain,
|
||||
// not once per case variant.
|
||||
name: "case-variant-exact-domains-deduplicated-within-app",
|
||||
cfg: []appctype.Conn25Attr{
|
||||
appCfg: []appctype.Conn25Attr{
|
||||
{Name: "one", Domains: []string{"EXAMPLE.com", "example.COM", "Example.COM"}, Connectors: []string{"tag:one"}},
|
||||
},
|
||||
tags: []string{"tag:one"},
|
||||
rawPoolsCfg: "{}",
|
||||
tags: []string{"tag:one"},
|
||||
wantAppsByDomain: map[dnsname.FQDN][]string{
|
||||
"example.com.": {"one"},
|
||||
},
|
||||
@@ -583,29 +615,39 @@ func TestConfigFromNodeView(t *testing.T) {
|
||||
// Same as above but for wildcard domains: *.EXAMPLE.com and *.example.COM
|
||||
// must collapse to a single entry in appNamesByWCDomain.
|
||||
name: "case-variant-wildcard-domains-deduplicated-within-app",
|
||||
cfg: []appctype.Conn25Attr{
|
||||
appCfg: []appctype.Conn25Attr{
|
||||
{Name: "one", Domains: []string{"*.EXAMPLE.com", "*.example.COM"}, Connectors: []string{"tag:one"}},
|
||||
},
|
||||
rawPoolsCfg: "{}",
|
||||
tags: []string{"tag:one"},
|
||||
wantAppsByDomain: map[dnsname.FQDN][]string{},
|
||||
wantAppsByWCDomain: map[dnsname.FQDN][]string{"example.com.": {"one"}},
|
||||
wantSelfAppNames: set.SetOf([]string{"one"}),
|
||||
},
|
||||
{
|
||||
name: "too-many-pools",
|
||||
appCfg: []appctype.Conn25Attr{
|
||||
{Name: "one", Domains: []string{"a.example.com"}, Connectors: []string{"tag:one"}},
|
||||
},
|
||||
poolsCfg: []appctype.Conn25PoolsAttr{
|
||||
{},
|
||||
{},
|
||||
},
|
||||
wantErr: true,
|
||||
},
|
||||
} {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
cfg := []tailcfg.RawMessage{tailcfg.RawMessage(tt.rawCfg)}
|
||||
if tt.cfg != nil {
|
||||
cfg = []tailcfg.RawMessage{}
|
||||
for _, attr := range tt.cfg {
|
||||
bs, err := json.Marshal(attr)
|
||||
if err != nil {
|
||||
t.Fatalf("unexpected error in test setup: %v", err)
|
||||
}
|
||||
cfg = append(cfg, tailcfg.RawMessage(bs))
|
||||
}
|
||||
appCfg := []tailcfg.RawMessage{tailcfg.RawMessage(tt.rawAppCfg)}
|
||||
if tt.appCfg != nil {
|
||||
appCfg = getRawMessages(t, tt.appCfg)
|
||||
}
|
||||
poolsCfg := []tailcfg.RawMessage{tailcfg.RawMessage(tt.rawPoolsCfg)}
|
||||
if tt.poolsCfg != nil {
|
||||
poolsCfg = getRawMessages(t, tt.poolsCfg)
|
||||
}
|
||||
capMap := tailcfg.NodeCapMap{
|
||||
tailcfg.NodeCapability(AppConnectorsExperimentalAttrName): cfg,
|
||||
tailcfg.NodeCapability(AppConnectorsExperimentalAttrName): appCfg,
|
||||
tailcfg.NodeCapability(AppConnectorsExperimentalIPPoolsAttrName): poolsCfg,
|
||||
}
|
||||
sn := (&tailcfg.Node{
|
||||
CapMap: capMap,
|
||||
@@ -639,6 +681,7 @@ func TestGetAppsForDomainName(t *testing.T) {
|
||||
{Name: "four", Domains: []string{"a.sub.example.com"}, Connectors: []string{"tag:four"}},
|
||||
{Name: "self-routed", Domains: []string{"*.wildcard.com", "exact-match.com"}, Connectors: []string{"tag:self-routed"}},
|
||||
},
|
||||
appctype.Conn25PoolsAttr{},
|
||||
[]string{"tag:self-routed"},
|
||||
)
|
||||
|
||||
@@ -732,7 +775,7 @@ func TestGetAppsForDomainName(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func makeSelfNode(t *testing.T, attrs []appctype.Conn25Attr, tags []string) tailcfg.NodeView {
|
||||
func makeSelfNode(t *testing.T, attrs []appctype.Conn25Attr, pools appctype.Conn25PoolsAttr, tags []string) tailcfg.NodeView {
|
||||
t.Helper()
|
||||
cfg := make([]tailcfg.RawMessage, 0, len(attrs))
|
||||
for i, attr := range attrs {
|
||||
@@ -742,8 +785,13 @@ func makeSelfNode(t *testing.T, attrs []appctype.Conn25Attr, tags []string) tail
|
||||
}
|
||||
cfg = append(cfg, tailcfg.RawMessage(bs))
|
||||
}
|
||||
poolsBytes, err := json.Marshal(pools)
|
||||
if err != nil {
|
||||
t.Fatalf("unexpected error marshaling pools in test setup: %v", err)
|
||||
}
|
||||
capMap := tailcfg.NodeCapMap{
|
||||
tailcfg.NodeCapability(AppConnectorsExperimentalAttrName): cfg,
|
||||
tailcfg.NodeCapability(AppConnectorsExperimentalAttrName): cfg,
|
||||
tailcfg.NodeCapability(AppConnectorsExperimentalIPPoolsAttrName): {tailcfg.RawMessage(poolsBytes)},
|
||||
}
|
||||
|
||||
return (&tailcfg.Node{
|
||||
@@ -1095,14 +1143,15 @@ func TestMapDNSResponseAssignsAddrs(t *testing.T) {
|
||||
dnsResp = makeV6DNSResponse(t, tt.domain, tt.v6Addrs)
|
||||
}
|
||||
sn := makeSelfNode(t, []appctype.Conn25Attr{{
|
||||
Name: "app1",
|
||||
Connectors: []string{"tag:woo"},
|
||||
Domains: tt.appDomains,
|
||||
Name: "app1",
|
||||
Connectors: []string{"tag:woo"},
|
||||
Domains: tt.appDomains,
|
||||
}}, appctype.Conn25PoolsAttr{
|
||||
V4MagicIPPool: []netipx.IPRange{v4RangeFrom("0", "10"), v4RangeFrom("20", "30")},
|
||||
V6MagicIPPool: []netipx.IPRange{v6RangeFrom("0", "10"), v6RangeFrom("20", "30")},
|
||||
V4TransitIPPool: []netipx.IPRange{v4RangeFrom("40", "50")},
|
||||
V6TransitIPPool: []netipx.IPRange{v6RangeFrom("40", "50")},
|
||||
}}, tt.selfTags)
|
||||
}, tt.selfTags)
|
||||
|
||||
c := newConn25(logger.Discard)
|
||||
cfg := mustConfig(t, sn)
|
||||
@@ -1128,14 +1177,15 @@ func TestMapDNSResponseSetsExpiryBasedOnTTL(t *testing.T) {
|
||||
domainName := configuredDomain + "."
|
||||
dnsMessageName := dnsmessage.MustNewName(domainName)
|
||||
sn := makeSelfNode(t, []appctype.Conn25Attr{{
|
||||
Name: "app1",
|
||||
Connectors: []string{"tag:woo"},
|
||||
Domains: []string{configuredDomain},
|
||||
Name: "app1",
|
||||
Connectors: []string{"tag:woo"},
|
||||
Domains: []string{configuredDomain},
|
||||
}}, appctype.Conn25PoolsAttr{
|
||||
V4MagicIPPool: []netipx.IPRange{v4RangeFrom("0", "10")},
|
||||
V4TransitIPPool: []netipx.IPRange{v4RangeFrom("40", "50")},
|
||||
V6MagicIPPool: []netipx.IPRange{netipx.IPRangeFrom(netip.MustParseAddr("2606:4700::6812:100"), netip.MustParseAddr("2606:4700::6812:1ff"))},
|
||||
V6TransitIPPool: []netipx.IPRange{netipx.IPRangeFrom(netip.MustParseAddr("2606:4700::6813:100"), netip.MustParseAddr("2606:4700::6813:1ff"))},
|
||||
}}, nil)
|
||||
}, nil)
|
||||
|
||||
c := newConn25(logger.Discard)
|
||||
clock := tstest.NewClock(tstest.ClockOpts{Start: time.Now()})
|
||||
@@ -1410,7 +1460,7 @@ func TestAddressAssignmentIsHandled(t *testing.T) {
|
||||
Name: "app1",
|
||||
Connectors: []string{"tag:woo"},
|
||||
Domains: []string{"example.com"},
|
||||
}}, []string{})
|
||||
}}, appctype.Conn25PoolsAttr{}, []string{})
|
||||
|
||||
cfg := mustConfig(t, sn)
|
||||
ext.conn25.reconfig(cfg)
|
||||
@@ -1484,14 +1534,15 @@ func TestMapDNSResponseRewritesResponses(t *testing.T) {
|
||||
domainName := configuredDomain + "."
|
||||
dnsMessageName := dnsmessage.MustNewName(domainName)
|
||||
sn := makeSelfNode(t, []appctype.Conn25Attr{{
|
||||
Name: "app1",
|
||||
Connectors: []string{"tag:connector"},
|
||||
Domains: []string{configuredDomain},
|
||||
Name: "app1",
|
||||
Connectors: []string{"tag:connector"},
|
||||
Domains: []string{configuredDomain},
|
||||
}}, appctype.Conn25PoolsAttr{
|
||||
V4MagicIPPool: []netipx.IPRange{v4RangeFrom("0", "10")},
|
||||
V4TransitIPPool: []netipx.IPRange{v4RangeFrom("40", "50")},
|
||||
V6MagicIPPool: []netipx.IPRange{netipx.IPRangeFrom(netip.MustParseAddr("2606:4700::6812:100"), netip.MustParseAddr("2606:4700::6812:1ff"))},
|
||||
V6TransitIPPool: []netipx.IPRange{netipx.IPRangeFrom(netip.MustParseAddr("2606:4700::6813:100"), netip.MustParseAddr("2606:4700::6813:1ff"))},
|
||||
}}, []string{})
|
||||
}, []string{})
|
||||
|
||||
cfg := mustConfig(t, sn)
|
||||
|
||||
@@ -2011,7 +2062,7 @@ func TestHandleAddressAssignmentStoresTransitIPs(t *testing.T) {
|
||||
Connectors: []string{"tag:hoo"},
|
||||
Domains: []string{"hoo.example.com"},
|
||||
},
|
||||
}, []string{})
|
||||
}, appctype.Conn25PoolsAttr{}, []string{})
|
||||
|
||||
cfg := mustConfig(t, sn)
|
||||
ext.conn25.reconfig(cfg)
|
||||
@@ -2187,10 +2238,10 @@ func TestTransitIPConnMapping(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestClientTransitIPForMagicIP(t *testing.T) {
|
||||
sn := makeSelfNode(t, []appctype.Conn25Attr{{
|
||||
sn := makeSelfNode(t, []appctype.Conn25Attr{{Name: "app1"}}, appctype.Conn25PoolsAttr{
|
||||
V4MagicIPPool: []netipx.IPRange{v4RangeFrom("0", "10")}, // 100.64.0.0 - 100.64.0.10
|
||||
V6MagicIPPool: []netipx.IPRange{v6RangeFrom("0", "10")},
|
||||
}}, []string{})
|
||||
}, []string{})
|
||||
cfg := mustConfig(t, sn)
|
||||
|
||||
mappedMip := netip.MustParseAddr("100.64.0.0")
|
||||
@@ -2278,9 +2329,9 @@ func TestClientTransitIPForMagicIP(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestConnectorRealIPForTransitIPConnection(t *testing.T) {
|
||||
sn := makeSelfNode(t, []appctype.Conn25Attr{{
|
||||
sn := makeSelfNode(t, []appctype.Conn25Attr{{Name: "app1"}}, appctype.Conn25PoolsAttr{
|
||||
V4TransitIPPool: []netipx.IPRange{v4RangeFrom("40", "50")}, // 100.64.0.40 - 100.64.0.50
|
||||
}}, []string{})
|
||||
}, []string{})
|
||||
cfg := mustConfig(t, sn)
|
||||
|
||||
mappedSrc := netip.MustParseAddr("100.0.0.1")
|
||||
@@ -2421,12 +2472,13 @@ func TestConnectorPacketFilterAllow(t *testing.T) {
|
||||
|
||||
func TestGetMagicRange(t *testing.T) {
|
||||
sn := makeSelfNode(t, []appctype.Conn25Attr{{
|
||||
Name: "app1",
|
||||
Connectors: []string{"tag:woo"},
|
||||
Domains: []string{"example.com"},
|
||||
Name: "app1",
|
||||
Connectors: []string{"tag:woo"},
|
||||
Domains: []string{"example.com"},
|
||||
}}, appctype.Conn25PoolsAttr{
|
||||
V4MagicIPPool: []netipx.IPRange{netipx.IPRangeFrom(netip.MustParseAddr("0.0.0.1"), netip.MustParseAddr("0.0.0.3"))},
|
||||
V6MagicIPPool: []netipx.IPRange{netipx.IPRangeFrom(netip.MustParseAddr("::1"), netip.MustParseAddr("::3"))},
|
||||
}}, []string{})
|
||||
}, []string{})
|
||||
cfg := mustConfig(t, sn)
|
||||
c := newConn25(t.Logf)
|
||||
c.reconfig(cfg)
|
||||
@@ -2479,14 +2531,15 @@ func TestReconfigDoesNotReissueInUseAddresses(t *testing.T) {
|
||||
afterRangeV6 := mustRange("::4", "::7")
|
||||
makeNodeFromMagicRange := func(v4, v6 netipx.IPRange) tailcfg.NodeView {
|
||||
return makeSelfNode(t, []appctype.Conn25Attr{{
|
||||
Name: appName,
|
||||
Connectors: []string{"tag:woo"},
|
||||
Domains: []string{"example.com"},
|
||||
Name: appName,
|
||||
Connectors: []string{"tag:woo"},
|
||||
Domains: []string{"example.com"},
|
||||
}}, appctype.Conn25PoolsAttr{
|
||||
V4MagicIPPool: []netipx.IPRange{v4},
|
||||
V6MagicIPPool: []netipx.IPRange{v6},
|
||||
V4TransitIPPool: []netipx.IPRange{mustRange("169.254.0.0", "169.254.0.10")},
|
||||
V6TransitIPPool: []netipx.IPRange{mustRange("fd7a:115c:a1e0:a99c:0200::", "fd7a:115c:a1e0:a99c:0200::10")},
|
||||
}}, []string{})
|
||||
}, []string{})
|
||||
}
|
||||
domain := must.Get(dnsname.ToFQDN("example.com."))
|
||||
|
||||
|
||||
@@ -104,7 +104,10 @@ type Conn25Attr struct {
|
||||
// Connectors enumerates the app connectors which service these domains.
|
||||
// These can either be "*" to match any advertising connector, or a
|
||||
// tag of the form tag:<tag-name>.
|
||||
Connectors []string `json:"connectors,omitempty"`
|
||||
Connectors []string `json:"connectors,omitempty"`
|
||||
}
|
||||
|
||||
type Conn25PoolsAttr struct {
|
||||
V4MagicIPPool []netipx.IPRange `json:"v4MagicIPPool,omitempty"`
|
||||
V4TransitIPPool []netipx.IPRange `json:"v4TransitIPPool,omitempty"`
|
||||
V6MagicIPPool []netipx.IPRange `json:"v6MagicIPPool,omitempty"`
|
||||
|
||||
Reference in New Issue
Block a user