Просмотр исходного кода

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 день назад
Родитель
Сommit
a7ede7c7ac

+ 5
- 2
example.config.toml Просмотреть файл

118
 #
118
 #
119
 # Use `host` — accepts a hostname or a literal IP. Hostnames are resolved
119
 # Use `host` — accepts a hostname or a literal IP. Hostnames are resolved
120
 # at dial time, so a dual-stack DNS record can reach the right backend
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
 # The hostname from the secret is still used for SNI in the TLS handshake.
123
 # The hostname from the secret is still used for SNI in the TLS handshake.
125
 #
124
 #
126
 # default value is not set (the secret's hostname is used).
125
 # default value is not set (the secret's hostname is used).
127
 # host = "fronting-backend"
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
 # ip = "10.10.10.11"
131
 # ip = "10.10.10.11"
129
 
132
 
130
 # FakeTLS uses domain fronting protection. So it needs to know a port to
133
 # FakeTLS uses domain fronting protection. So it needs to know a port to

+ 12
- 1
internal/cli/doctor.go Просмотреть файл

140
 			"when":        "2.3.0",
140
 			"when":        "2.3.0",
141
 			"old":         "domain-fronting-ip",
141
 			"old":         "domain-fronting-ip",
142
 			"old_section": "",
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
 			"new_section": "domain-fronting",
155
 			"new_section": "domain-fronting",
145
 		})
156
 		})
146
 	}
157
 	}

+ 13
- 1
internal/cli/run_proxy.go Просмотреть файл

287
 		"DPI may detect and block the proxy. See 'mtg doctor' for details")
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
 func runProxy(conf *config.Config, version string) error { //nolint: funlen, cyclop
300
 func runProxy(conf *config.Config, version string) error { //nolint: funlen, cyclop
291
 	logger := makeLogger(conf)
301
 	logger := makeLogger(conf)
292
 
302
 
293
 	logger.BindJSON("configuration", conf.String()).Debug("configuration")
303
 	logger.BindJSON("configuration", conf.String()).Debug("configuration")
294
 
304
 
305
+	warnDeprecatedDomainFronting(conf, logger)
306
+
295
 	eventStream, err := makeEventStream(conf, logger)
307
 	eventStream, err := makeEventStream(conf, logger)
296
 	if err != nil {
308
 	if err != nil {
297
 		return fmt.Errorf("cannot build event stream: %w", err)
309
 		return fmt.Errorf("cannot build event stream: %w", err)
343
 		Secret:                      conf.Secret,
355
 		Secret:                      conf.Secret,
344
 		Concurrency:                 conf.GetConcurrency(mtglib.DefaultConcurrency),
356
 		Concurrency:                 conf.GetConcurrency(mtglib.DefaultConcurrency),
345
 		DomainFrontingPort:          conf.GetDomainFrontingPort(mtglib.DefaultDomainFrontingPort),
357
 		DomainFrontingPort:          conf.GetDomainFrontingPort(mtglib.DefaultDomainFrontingPort),
346
-		DomainFrontingIP:            conf.GetDomainFrontingHost(),
358
+		DomainFrontingHost:          conf.GetDomainFrontingHost(),
347
 		DomainFrontingProxyProtocol: conf.GetDomainFrontingProxyProtocol(false),
359
 		DomainFrontingProxyProtocol: conf.GetDomainFrontingProxyProtocol(false),
348
 		PreferIP:                    conf.PreferIP.Get(mtglib.DefaultPreferIP),
360
 		PreferIP:                    conf.PreferIP.Get(mtglib.DefaultPreferIP),
349
 		AutoUpdate:                  conf.AutoUpdate.Get(false),
361
 		AutoUpdate:                  conf.AutoUpdate.Get(false),

+ 12
- 2
internal/cli/simple_run.go Просмотреть файл

17
 	Concurrency         uint64        `kong:"name='concurrency',short='c',default='8192',help='Max number of concurrent connection to proxy.'"`                        //nolint: lll
17
 	Concurrency         uint64        `kong:"name='concurrency',short='c',default='8192',help='Max number of concurrent connection to proxy.'"`                        //nolint: lll
18
 	TCPBuffer           string        `kong:"name='tcp-buffer',short='b',default='4KB',help='Deprecated and ignored'"`                                                 //nolint: lll
18
 	TCPBuffer           string        `kong:"name='tcp-buffer',short='b',default='4KB',help='Deprecated and ignored'"`                                                 //nolint: lll
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
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
 	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
 	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
 	Timeout             time.Duration `kong:"name='timeout',short='t',default='10s',help='Network timeout to use'"`                                                    //nolint: lll
24
 	Timeout             time.Duration `kong:"name='timeout',short='t',default='10s',help='Network timeout to use'"`                                                    //nolint: lll
24
 	Socks5Proxies       []string      `kong:"name='socks5-proxy',short='s',help='Socks5 proxies to use for network access.'"`                                          //nolint: lll
25
 	Socks5Proxies       []string      `kong:"name='socks5-proxy',short='s',help='Socks5 proxies to use for network access.'"`                                          //nolint: lll
48
 		return fmt.Errorf("incorrect domain-fronting-port: %w", err)
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
 	if s.DomainFrontingIP != "" {
61
 	if s.DomainFrontingIP != "" {
52
 		if err := conf.DomainFrontingIP.Set(s.DomainFrontingIP); err != nil {
62
 		if err := conf.DomainFrontingIP.Set(s.DomainFrontingIP); err != nil {
53
 			return fmt.Errorf("incorrect domain-fronting-ip: %w", err)
63
 			return fmt.Errorf("incorrect domain-fronting-ip: %w", err)

+ 1
- 14
internal/config/config.go Просмотреть файл

118
 }
118
 }
119
 
119
 
120
 func (c *Config) GetDomainFrontingHost() string {
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
 func (c *Config) GetDomainFrontingProxyProtocol(defaultValue bool) bool {
124
 func (c *Config) GetDomainFrontingProxyProtocol(defaultValue bool) bool {
143
 		return fmt.Errorf("incorrect bind-to parameter %s", c.BindTo.String())
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
 	return nil
137
 	return nil
151
 }
138
 }
152
 
139
 

+ 8
- 4
internal/config/config_test.go Просмотреть файл

74
 	suite.NotEmpty(conf.String())
74
 	suite.NotEmpty(conf.String())
75
 }
75
 }
76
 
76
 
77
-func (suite *ConfigTestSuite) TestDomainFrontingHostAndIPMutuallyExclusive() {
77
+func (suite *ConfigTestSuite) TestDomainFrontingIPIgnoredWhenHostSet() {
78
 	conf, err := config.Parse(suite.ReadConfig("minimal.toml"))
78
 	conf, err := config.Parse(suite.ReadConfig("minimal.toml"))
79
 	suite.NoError(err)
79
 	suite.NoError(err)
80
 
80
 
81
 	suite.NoError(conf.DomainFronting.Host.Set("fronting-backend"))
81
 	suite.NoError(conf.DomainFronting.Host.Set("fronting-backend"))
82
 	suite.NoError(conf.DomainFronting.IP.Set("10.0.0.10"))
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
 func (suite *ConfigTestSuite) TestDomainFrontingHostFromTOML() {
87
 func (suite *ConfigTestSuite) TestDomainFrontingHostFromTOML() {
97
 	suite.Equal("10.0.0.1", conf.GetDomainFrontingHost())
98
 	suite.Equal("10.0.0.1", conf.GetDomainFrontingHost())
98
 }
99
 }
99
 
100
 
100
-func (suite *ConfigTestSuite) TestDomainFrontingIPFromTOML() {
101
+func (suite *ConfigTestSuite) TestDomainFrontingIPIgnoredFromTOML() {
101
 	conf, err := config.Parse(suite.ReadConfig("domain_fronting_ip.toml"))
102
 	conf, err := config.Parse(suite.ReadConfig("domain_fronting_ip.toml"))
102
 	suite.NoError(err)
103
 	suite.NoError(err)
103
 	suite.NoError(conf.Validate())
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
 func (suite *ConfigTestSuite) TestDomainFrontingNotSet() {
111
 func (suite *ConfigTestSuite) TestDomainFrontingNotSet() {

+ 5
- 1
mtglib/proxy.go Просмотреть файл

344
 	logger := opts.getLogger("proxy")
344
 	logger := opts.getLogger("proxy")
345
 	updatersLogger := logger.Named("telegram-updaters")
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
 	proxy := &Proxy{
351
 	proxy := &Proxy{
348
 		ctx:                      ctx,
352
 		ctx:                      ctx,
349
 		ctxCancel:                cancel,
353
 		ctxCancel:                cancel,
355
 		eventStream:              opts.EventStream,
359
 		eventStream:              opts.EventStream,
356
 		logger:                   logger,
360
 		logger:                   logger,
357
 		domainFrontingPort:       opts.getDomainFrontingPort(),
361
 		domainFrontingPort:       opts.getDomainFrontingPort(),
358
-		domainFrontingHost:       opts.DomainFrontingIP,
362
+		domainFrontingHost:       opts.DomainFrontingHost,
359
 		tolerateTimeSkewness:     opts.getTolerateTimeSkewness(),
363
 		tolerateTimeSkewness:     opts.getTolerateTimeSkewness(),
360
 		idleTimeout:              opts.getIdleTimeout(),
364
 		idleTimeout:              opts.getIdleTimeout(),
361
 		handshakeTimeout:         opts.getHandshakeTimeout(),
365
 		handshakeTimeout:         opts.getHandshakeTimeout(),

+ 12
- 4
mtglib/proxy_opts.go Просмотреть файл

105
 	// This is an optional setting.
105
 	// This is an optional setting.
106
 	DomainFrontingPort uint
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
 	// This is useful when DNS resolution of the secret's hostname is blocked
114
 	// This is useful when DNS resolution of the secret's hostname is blocked
114
 	// or loops back to this server. The hostname from the secret is still
115
 	// or loops back to this server. The hostname from the secret is still
115
 	// used for SNI in the TLS handshake.
116
 	// used for SNI in the TLS handshake.
116
 	//
117
 	//
117
 	// This is an optional setting.
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
 	DomainFrontingIP string
126
 	DomainFrontingIP string
119
 
127
 
120
 	// DomainFrontingProxyProtocol is used if communication between upstream
128
 	// DomainFrontingProxyProtocol is used if communication between upstream

Загрузка…
Отмена
Сохранить