Add domain-fronting-ip option

Allow specifying an explicit IP address for the domain fronting host
instead of relying on DNS resolution. Useful when DNS resolution of
the fronting hostname is blocked.

The hostname from the secret is still used for SNI in TLS handshake.
This commit is contained in:
ivulit
2026-02-20 12:34:17 +03:00
parent 432e530f68
commit bf38f9f8af
6 changed files with 28 additions and 1 deletions
+1
View File
@@ -260,6 +260,7 @@ func runProxy(conf *config.Config, version string) error { //nolint: funlen
Secret: conf.Secret,
DomainFrontingPort: conf.DomainFrontingPort.Get(mtglib.DefaultDomainFrontingPort),
DomainFrontingIP: conf.DomainFrontingIP.String(),
PreferIP: conf.PreferIP.Get(mtglib.DefaultPreferIP),
AllowFallbackOnUnknownDC: conf.AllowFallbackOnUnknownDC.Get(false),
+7
View File
@@ -18,6 +18,7 @@ type SimpleRun struct {
TCPBuffer string `kong:"name='tcp-buffer',short='b',default='4KB',help='Deprecated and ignored'"` //nolint: lll
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
DomainFrontingPort uint64 `kong:"name='domain-fronting-port',short='p',default='443',help='A port to access for domain fronting.'"` //nolint: lll
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
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
Timeout time.Duration `kong:"name='timeout',short='t',default='10s',help='Network timeout to use'"` //nolint: lll
Socks5Proxies []string `kong:"name='socks5-proxy',short='s',help='Socks5 proxies to use for network access.'"` //nolint: lll
@@ -47,6 +48,12 @@ func (s *SimpleRun) Run(cli *CLI, version string) error { //nolint: cyclop,funle
return fmt.Errorf("incorrect domain-fronting-port: %w", err)
}
if s.DomainFrontingIP != "" {
if err := conf.DomainFrontingIP.Set(s.DomainFrontingIP); err != nil {
return fmt.Errorf("incorrect domain-fronting-ip: %w", err)
}
}
if err := conf.Network.DOHIP.Set(s.DOHIP.String()); err != nil {
return fmt.Errorf("incorrect doh-ip: %w", err)
}
+1
View File
@@ -28,6 +28,7 @@ type Config struct {
ProxyProtocolListener TypeBool `json:"proxyProtocolListener"`
PreferIP TypePreferIP `json:"preferIp"`
DomainFrontingPort TypePort `json:"domainFrontingPort"`
DomainFrontingIP TypeIP `json:"domainFrontingIp"`
TolerateTimeSkewness TypeDuration `json:"tolerateTimeSkewness"`
Concurrency TypeConcurrency `json:"concurrency"`
Defense struct {
+1
View File
@@ -16,6 +16,7 @@ type tomlConfig struct {
ProxyProtocolListener bool `toml:"proxy-protocol-listener" json:"proxyProtocolListener"`
PreferIP string `toml:"prefer-ip" json:"preferIp,omitempty"`
DomainFrontingPort uint `toml:"domain-fronting-port" json:"domainFrontingPort,omitempty"`
DomainFrontingIP string `toml:"domain-fronting-ip" json:"domainFrontingIp,omitempty"`
TolerateTimeSkewness string `toml:"tolerate-time-skewness" json:"tolerateTimeSkewness,omitempty"`
Concurrency uint `toml:"concurrency" json:"concurrency,omitempty"`
Defense struct {
+9 -1
View File
@@ -27,6 +27,7 @@ type Proxy struct {
allowFallbackOnUnknownDC bool
tolerateTimeSkewness time.Duration
domainFrontingPort int
domainFrontingIP string
workerPool *ants.PoolWithFunc
telegram *dc.Telegram
@@ -40,8 +41,14 @@ type Proxy struct {
}
// DomainFrontingAddress returns a host:port pair for a fronting domain.
// If DomainFrontingIP is set, it is used instead of resolving the hostname.
func (p *Proxy) DomainFrontingAddress() string {
return net.JoinHostPort(p.secret.Host, strconv.Itoa(p.domainFrontingPort))
host := p.secret.Host
if p.domainFrontingIP != "" {
host = p.domainFrontingIP
}
return net.JoinHostPort(host, strconv.Itoa(p.domainFrontingPort))
}
// ServeConn serves a connection. We do not check IP blocklist and concurrency
@@ -317,6 +324,7 @@ func NewProxy(opts ProxyOpts) (*Proxy, error) {
eventStream: opts.EventStream,
logger: opts.getLogger("proxy"),
domainFrontingPort: opts.getDomainFrontingPort(),
domainFrontingIP: opts.DomainFrontingIP,
tolerateTimeSkewness: opts.getTolerateTimeSkewness(),
allowFallbackOnUnknownDC: opts.AllowFallbackOnUnknownDC,
telegram: tg,
+9
View File
@@ -93,6 +93,15 @@ type ProxyOpts struct {
// This is an optional setting.
DomainFrontingPort uint
// DomainFrontingIP is an IP address to use when connecting to the fronting
// domain instead of resolving the hostname from the secret via DNS.
//
// This is useful when DNS resolution of the fronting host is blocked.
// The hostname from the secret is still used for SNI in the TLS handshake.
//
// This is an optional setting.
DomainFrontingIP string
// AllowFallbackOnUnknownDC defines how proxy behaves if unknown DC was
// requested. If this setting is set to false, then such connection will be
// rejected. Otherwise, proxy will chose any DC.