Bladeren bron

Deprecate "ip" in favour of "host" for domain fronting

Per review on #480: warn-and-ignore for the IP-shaped paths,
mirroring the net.Dialer.DualStack precedent — a config that
sets only "ip" will warn at startup and effectively disable
domain-fronting until the user switches to "host".

- mtglib.ProxyOpts: add DomainFrontingHost; mark DomainFrontingIP
  Deprecated and warn-and-drop in NewProxy.
- internal/config: GetDomainFrontingHost returns only
  [domain-fronting].host; deprecated keys are no longer used to
  derive the dial target. runProxy logs a startup warning per
  deprecated key that is set.
- internal/cli: add --domain-fronting-host; --domain-fronting-ip
  flag is parsed only so the runtime warning can fire.
- internal/cli/doctor: redirect the existing 2.3.0 entry at "host"
  and add a 2.4.0 entry for [domain-fronting].ip.
- example.config.toml: mark # ip = ... as deprecated.
pull/480/head
Alexey Dolotov 1 dag geleden
bovenliggende
commit
a7ede7c7ac

+ 5
- 2
example.config.toml Bestand weergeven

@@ -118,13 +118,16 @@ allow-fallback-on-unknown-dc = false
118 118
 #
119 119
 # Use `host` — accepts a hostname or a literal IP. Hostnames are resolved
120 120
 # at dial time, so a dual-stack DNS record can reach the right backend
121
-# address family for IPv4 or IPv6 clients. `ip` is kept for backward
122
-# compatibility (literal IP only). Setting both is an error.
121
+# address family for IPv4 or IPv6 clients.
123 122
 #
124 123
 # The hostname from the secret is still used for SNI in the TLS handshake.
125 124
 #
126 125
 # default value is not set (the secret's hostname is used).
127 126
 # host = "fronting-backend"
127
+
128
+# Deprecated: use `host`. If `ip` is set, mtg logs a warning at startup
129
+# and ignores the value (domain-fronting falls back to the secret's
130
+# hostname unless `host` is also set).
128 131
 # ip = "10.10.10.11"
129 132
 
130 133
 # FakeTLS uses domain fronting protection. So it needs to know a port to

+ 12
- 1
internal/cli/doctor.go Bestand weergeven

@@ -140,7 +140,18 @@ func (d *Doctor) checkDeprecatedConfig() bool {
140 140
 			"when":        "2.3.0",
141 141
 			"old":         "domain-fronting-ip",
142 142
 			"old_section": "",
143
-			"new":         "ip",
143
+			"new":         "host",
144
+			"new_section": "domain-fronting",
145
+		})
146
+	}
147
+
148
+	if d.conf.DomainFronting.IP.Value != nil {
149
+		ok = false
150
+		tplWDeprecatedConfig.Execute(os.Stdout, map[string]string{ //nolint: errcheck
151
+			"when":        "2.4.0",
152
+			"old":         "ip",
153
+			"old_section": "domain-fronting",
154
+			"new":         "host",
144 155
 			"new_section": "domain-fronting",
145 156
 		})
146 157
 	}

+ 13
- 1
internal/cli/run_proxy.go Bestand weergeven

@@ -287,11 +287,23 @@ func warnSNIMismatch(conf *config.Config, ntw mtglib.Network, log mtglib.Logger)
287 287
 		"DPI may detect and block the proxy. See 'mtg doctor' for details")
288 288
 }
289 289
 
290
+func warnDeprecatedDomainFronting(conf *config.Config, log mtglib.Logger) {
291
+	if conf.DomainFrontingIP.Value != nil {
292
+		log.Warning(`config option "domain-fronting-ip" is deprecated and ignored; use "host" in [domain-fronting] instead`)
293
+	}
294
+
295
+	if conf.DomainFronting.IP.Value != nil {
296
+		log.Warning(`config option "ip" in [domain-fronting] is deprecated and ignored; use "host" instead`)
297
+	}
298
+}
299
+
290 300
 func runProxy(conf *config.Config, version string) error { //nolint: funlen, cyclop
291 301
 	logger := makeLogger(conf)
292 302
 
293 303
 	logger.BindJSON("configuration", conf.String()).Debug("configuration")
294 304
 
305
+	warnDeprecatedDomainFronting(conf, logger)
306
+
295 307
 	eventStream, err := makeEventStream(conf, logger)
296 308
 	if err != nil {
297 309
 		return fmt.Errorf("cannot build event stream: %w", err)
@@ -343,7 +355,7 @@ func runProxy(conf *config.Config, version string) error { //nolint: funlen, cyc
343 355
 		Secret:                      conf.Secret,
344 356
 		Concurrency:                 conf.GetConcurrency(mtglib.DefaultConcurrency),
345 357
 		DomainFrontingPort:          conf.GetDomainFrontingPort(mtglib.DefaultDomainFrontingPort),
346
-		DomainFrontingIP:            conf.GetDomainFrontingHost(),
358
+		DomainFrontingHost:          conf.GetDomainFrontingHost(),
347 359
 		DomainFrontingProxyProtocol: conf.GetDomainFrontingProxyProtocol(false),
348 360
 		PreferIP:                    conf.PreferIP.Get(mtglib.DefaultPreferIP),
349 361
 		AutoUpdate:                  conf.AutoUpdate.Get(false),

+ 12
- 2
internal/cli/simple_run.go Bestand weergeven

@@ -17,8 +17,9 @@ type SimpleRun struct {
17 17
 	Concurrency         uint64        `kong:"name='concurrency',short='c',default='8192',help='Max number of concurrent connection to proxy.'"`                        //nolint: lll
18 18
 	TCPBuffer           string        `kong:"name='tcp-buffer',short='b',default='4KB',help='Deprecated and ignored'"`                                                 //nolint: lll
19 19
 	PreferIP            string        `kong:"name='prefer-ip',short='i',default='prefer-ipv6',help='IP preference. By default we prefer IPv6 with fallback to IPv4.'"` //nolint: lll
20
-	DomainFrontingPort  uint64        `kong:"name='domain-fronting-port',short='p',default='443',help='A port to access for domain fronting.'"`                        //nolint: lll
21
-	DomainFrontingIP    string        `kong:"name='domain-fronting-ip',help='An IP address to use for domain fronting instead of resolving the hostname via DNS.'"`    //nolint: lll
20
+	DomainFrontingPort  uint64        `kong:"name='domain-fronting-port',short='p',default='443',help='A port to access for domain fronting.'"`                                                                  //nolint: lll
21
+	DomainFrontingHost  string        `kong:"name='domain-fronting-host',help='Hostname or IP to dial for domain fronting instead of resolving the secret hostname.'"`                                           //nolint: lll
22
+	DomainFrontingIP    string        `kong:"name='domain-fronting-ip',help='Deprecated: use --domain-fronting-host. Setting this flag logs a warning at startup and the value is ignored.'"`                    //nolint: lll
22 23
 	DOHIP               net.IP        `kong:"name='doh-ip',short='n',default='1.1.1.1',help='IP address of DNS-over-HTTP to use.'"`                                    //nolint: lll
23 24
 	Timeout             time.Duration `kong:"name='timeout',short='t',default='10s',help='Network timeout to use'"`                                                    //nolint: lll
24 25
 	Socks5Proxies       []string      `kong:"name='socks5-proxy',short='s',help='Socks5 proxies to use for network access.'"`                                          //nolint: lll
@@ -48,6 +49,15 @@ func (s *SimpleRun) Run(cli *CLI, version string) error { //nolint: cyclop,funle
48 49
 		return fmt.Errorf("incorrect domain-fronting-port: %w", err)
49 50
 	}
50 51
 
52
+	if s.DomainFrontingHost != "" {
53
+		if err := conf.DomainFronting.Host.Set(s.DomainFrontingHost); err != nil {
54
+			return fmt.Errorf("incorrect domain-fronting-host: %w", err)
55
+		}
56
+	}
57
+
58
+	// --domain-fronting-ip is deprecated; the value is parsed only so the
59
+	// runtime check in runProxy can detect it and emit the warn-and-ignore
60
+	// log message. The value never reaches the dial path.
51 61
 	if s.DomainFrontingIP != "" {
52 62
 		if err := conf.DomainFrontingIP.Set(s.DomainFrontingIP); err != nil {
53 63
 			return fmt.Errorf("incorrect domain-fronting-ip: %w", err)

+ 1
- 14
internal/config/config.go Bestand weergeven

@@ -118,16 +118,7 @@ func (c *Config) GetDomainFrontingPort(defaultValue uint) uint {
118 118
 }
119 119
 
120 120
 func (c *Config) GetDomainFrontingHost() string {
121
-	if host := c.DomainFronting.Host.Get(""); host != "" {
122
-		return host
123
-	}
124
-	if ip := c.DomainFronting.IP.Get(nil); ip != nil {
125
-		return ip.String()
126
-	}
127
-	if ip := c.DomainFrontingIP.Get(nil); ip != nil {
128
-		return ip.String()
129
-	}
130
-	return ""
121
+	return c.DomainFronting.Host.Get("")
131 122
 }
132 123
 
133 124
 func (c *Config) GetDomainFrontingProxyProtocol(defaultValue bool) bool {
@@ -143,10 +134,6 @@ func (c *Config) Validate() error {
143 134
 		return fmt.Errorf("incorrect bind-to parameter %s", c.BindTo.String())
144 135
 	}
145 136
 
146
-	if c.DomainFronting.Host.Get("") != "" && c.DomainFronting.IP.Get(nil) != nil {
147
-		return fmt.Errorf("[domain-fronting] host and ip are mutually exclusive; pick one")
148
-	}
149
-
150 137
 	return nil
151 138
 }
152 139
 

+ 8
- 4
internal/config/config_test.go Bestand weergeven

@@ -74,13 +74,14 @@ func (suite *ConfigTestSuite) TestString() {
74 74
 	suite.NotEmpty(conf.String())
75 75
 }
76 76
 
77
-func (suite *ConfigTestSuite) TestDomainFrontingHostAndIPMutuallyExclusive() {
77
+func (suite *ConfigTestSuite) TestDomainFrontingIPIgnoredWhenHostSet() {
78 78
 	conf, err := config.Parse(suite.ReadConfig("minimal.toml"))
79 79
 	suite.NoError(err)
80 80
 
81 81
 	suite.NoError(conf.DomainFronting.Host.Set("fronting-backend"))
82 82
 	suite.NoError(conf.DomainFronting.IP.Set("10.0.0.10"))
83
-	suite.Error(conf.Validate())
83
+	suite.NoError(conf.Validate())
84
+	suite.Equal("fronting-backend", conf.GetDomainFrontingHost())
84 85
 }
85 86
 
86 87
 func (suite *ConfigTestSuite) TestDomainFrontingHostFromTOML() {
@@ -97,11 +98,14 @@ func (suite *ConfigTestSuite) TestDomainFrontingHostAcceptsLiteralIP() {
97 98
 	suite.Equal("10.0.0.1", conf.GetDomainFrontingHost())
98 99
 }
99 100
 
100
-func (suite *ConfigTestSuite) TestDomainFrontingIPFromTOML() {
101
+func (suite *ConfigTestSuite) TestDomainFrontingIPIgnoredFromTOML() {
101 102
 	conf, err := config.Parse(suite.ReadConfig("domain_fronting_ip.toml"))
102 103
 	suite.NoError(err)
103 104
 	suite.NoError(conf.Validate())
104
-	suite.Equal("10.0.0.10", conf.GetDomainFrontingHost())
105
+	// Deprecated [domain-fronting].ip is parsed but never used to derive
106
+	// the dial target — the user must migrate to [domain-fronting].host.
107
+	suite.NotNil(conf.DomainFronting.IP.Get(nil))
108
+	suite.Equal("", conf.GetDomainFrontingHost())
105 109
 }
106 110
 
107 111
 func (suite *ConfigTestSuite) TestDomainFrontingNotSet() {

+ 5
- 1
mtglib/proxy.go Bestand weergeven

@@ -344,6 +344,10 @@ func NewProxy(opts ProxyOpts) (*Proxy, error) {
344 344
 	logger := opts.getLogger("proxy")
345 345
 	updatersLogger := logger.Named("telegram-updaters")
346 346
 
347
+	if opts.DomainFrontingIP != "" {
348
+		logger.Warning("mtglib.ProxyOpts.DomainFrontingIP is deprecated and ignored; use DomainFrontingHost instead")
349
+	}
350
+
347 351
 	proxy := &Proxy{
348 352
 		ctx:                      ctx,
349 353
 		ctxCancel:                cancel,
@@ -355,7 +359,7 @@ func NewProxy(opts ProxyOpts) (*Proxy, error) {
355 359
 		eventStream:              opts.EventStream,
356 360
 		logger:                   logger,
357 361
 		domainFrontingPort:       opts.getDomainFrontingPort(),
358
-		domainFrontingHost:       opts.DomainFrontingIP,
362
+		domainFrontingHost:       opts.DomainFrontingHost,
359 363
 		tolerateTimeSkewness:     opts.getTolerateTimeSkewness(),
360 364
 		idleTimeout:              opts.getIdleTimeout(),
361 365
 		handshakeTimeout:         opts.getHandshakeTimeout(),

+ 12
- 4
mtglib/proxy_opts.go Bestand weergeven

@@ -105,16 +105,24 @@ type ProxyOpts struct {
105 105
 	// This is an optional setting.
106 106
 	DomainFrontingPort uint
107 107
 
108
-	// DomainFrontingIP is the address to use when connecting to the fronting
109
-	// domain instead of resolving the hostname from the secret via DNS. It
110
-	// can be a literal IP or a hostname; hostnames are resolved at dial time
111
-	// via the native dialer (which honours dual-stack and Happy Eyeballs).
108
+	// DomainFrontingHost is the address to use when connecting to the
109
+	// fronting domain instead of resolving the hostname from the secret via
110
+	// DNS. It can be a literal IP or a hostname; hostnames are resolved at
111
+	// dial time via the native dialer (which honours dual-stack and Happy
112
+	// Eyeballs).
112 113
 	//
113 114
 	// This is useful when DNS resolution of the secret's hostname is blocked
114 115
 	// or loops back to this server. The hostname from the secret is still
115 116
 	// used for SNI in the TLS handshake.
116 117
 	//
117 118
 	// This is an optional setting.
119
+	DomainFrontingHost string
120
+
121
+	// DomainFrontingIP previously held the dial target for the fronting
122
+	// domain. The setting is no longer honoured: setting it logs a warning
123
+	// at proxy startup and the value is dropped.
124
+	//
125
+	// Deprecated: use DomainFrontingHost. Setting this field has no effect.
118 126
 	DomainFrontingIP string
119 127
 
120 128
 	// DomainFrontingProxyProtocol is used if communication between upstream

Laden…
Annuleren
Opslaan