cmd/sniproxy: add support for sniproxy as subnet router

This PR adds the ability to pass in an --advertise-routes flag
to the sniproxy so that the sniproxy itself will also act as a
subnet router. This, alongside approving a Tailnet for extraRecords,
will allow 4via6, essentially pointing domains to a IPv6 address
that the sniproxy is advertising.

Updates #15372

Signed-off-by: Richard Castro <richard@tailscale.com>
This commit is contained in:
Richard Castro 2023-10-24 11:45:20 -07:00
parent 46fd488a6d
commit f1d9d6315f
2 changed files with 25 additions and 4 deletions

View File

@ -25,6 +25,7 @@ import (
"tailscale.com/client/tailscale"
"tailscale.com/hostinfo"
"tailscale.com/ipn"
"tailscale.com/net/netutil"
"tailscale.com/tailcfg"
"tailscale.com/tsnet"
"tailscale.com/tsweb"
@ -77,6 +78,7 @@ func main() {
promoteHTTPS = fs.Bool("promote-https", true, "promote HTTP to HTTPS")
debugPort = fs.Int("debug-port", 8893, "Listening port for debug/metrics endpoint")
hostname = fs.String("hostname", "", "Hostname to register the service under")
routes = fs.String("advertise-routes", "", "comma-separated list of IPs or prefixes to advertise as routes")
)
err := ff.Parse(fs, os.Args[1:], ff.WithEnvVarPrefix("TS_APPC"))
if err != nil {
@ -88,11 +90,11 @@ func main() {
ctx, cancel := context.WithCancel(context.Background())
defer cancel()
run(ctx, &ts, *wgPort, *hostname, *promoteHTTPS, *debugPort, *ports, *forwards)
run(ctx, &ts, *wgPort, *hostname, *promoteHTTPS, *debugPort, *ports, *forwards, *routes)
}
// run actually runs the sniproxy. Its separate from main() to assist in testing.
func run(ctx context.Context, ts *tsnet.Server, wgPort int, hostname string, promoteHTTPS bool, debugPort int, ports, forwards string) {
func run(ctx context.Context, ts *tsnet.Server, wgPort int, hostname string, promoteHTTPS bool, debugPort int, ports, forwards string, routes string) {
// Wire up Tailscale node + app connector server
hostinfo.SetApp("sniproxy")
var s sniproxy
@ -105,6 +107,25 @@ func run(ctx context.Context, ts *tsnet.Server, wgPort int, hostname string, pro
if err != nil {
log.Fatalf("LocalClient() failed: %v", err)
}
// Temporary 4via6 solution for request coalescing
if routes != "" {
editRoutes := new(ipn.MaskedPrefs)
editRoutes.AdvertiseRoutesSet = true
advertisedRoutes, err := netutil.CalcAdvertiseRoutes(routes, false)
if err != nil {
log.Fatal(err)
}
editRoutes.Prefs = ipn.Prefs{
AdvertiseRoutes: advertisedRoutes,
}
_, err = lc.EditPrefs(ctx, editRoutes)
// Throw error if subnet router setup fails
if err != nil {
log.Fatal(err)
}
}
s.lc = lc
s.ts.RegisterFallbackTCPHandler(s.srv.HandleTCPFlow)

View File

@ -124,7 +124,7 @@ func TestSNIProxyWithNetmapConfig(t *testing.T) {
// Start sniproxy
sni, nodeKey, ip := startNode(t, ctx, controlURL, "snitest")
go run(ctx, sni, 0, sni.Hostname, false, 0, "", "")
go run(ctx, sni, 0, sni.Hostname, false, 0, "", "", "")
// Configure the mock coordination server to send down app connector config.
config := &appctype.AppConnectorConfig{
@ -202,7 +202,7 @@ func TestSNIProxyWithFlagConfig(t *testing.T) {
// Start sniproxy
sni, _, ip := startNode(t, ctx, controlURL, "snitest")
go run(ctx, sni, 0, sni.Hostname, false, 0, "", fmt.Sprintf("tcp/%d/localhost", ln.Addr().(*net.TCPAddr).Port))
go run(ctx, sni, 0, sni.Hostname, false, 0, "", fmt.Sprintf("tcp/%d/localhost", ln.Addr().(*net.TCPAddr).Port), "")
// Lets spin up a second node (to represent the client).
client, _, _ := startNode(t, ctx, controlURL, "client")