Преглед изворни кода

Warn about SNI/IP mismatch at mtg run startup

The SNI-DNS validation that exists in 'mtg doctor' is now also run at
proxy startup.  If the secret hostname does not resolve to the server's
public IP, a warning is logged so that operators notice the
misconfiguration before DPI silently blocks the proxy.

The check is best-effort: if the public IP cannot be detected or the
hostname cannot be resolved, a brief warning is emitted and the proxy
starts normally.

Refs: #444, #458
pull/461/head
dolonet пре 3 недеља
родитељ
комит
1f8f063ec3
1 измењених фајлова са 64 додато и 1 уклоњено
  1. 64
    1
      internal/cli/run_proxy.go

+ 64
- 1
internal/cli/run_proxy.go Прегледај датотеку

@@ -5,6 +5,7 @@ import (
5 5
 	"fmt"
6 6
 	"net"
7 7
 	"os"
8
+	"strings"
8 9
 
9 10
 	"github.com/9seconds/mtg/v2/antireplay"
10 11
 	"github.com/9seconds/mtg/v2/events"
@@ -207,7 +208,67 @@ func makeEventStream(conf *config.Config, logger mtglib.Logger) (mtglib.EventStr
207 208
 	return events.NewNoopStream(), nil
208 209
 }
209 210
 
210
-func runProxy(conf *config.Config, version string) error { //nolint: funlen
211
+func warnSNIMismatch(conf *config.Config, ntw mtglib.Network, log mtglib.Logger) {
212
+	host := conf.Secret.Host
213
+	if host == "" {
214
+		return
215
+	}
216
+
217
+	addresses, err := net.DefaultResolver.LookupIPAddr(context.Background(), host)
218
+	if err != nil {
219
+		log.BindStr("hostname", host).
220
+			WarningError("SNI-DNS check: cannot resolve secret hostname", err)
221
+		return
222
+	}
223
+
224
+	ourIP4 := conf.PublicIPv4.Get(nil)
225
+	if ourIP4 == nil {
226
+		ourIP4 = getIP(ntw, "tcp4")
227
+	}
228
+
229
+	ourIP6 := conf.PublicIPv6.Get(nil)
230
+	if ourIP6 == nil {
231
+		ourIP6 = getIP(ntw, "tcp6")
232
+	}
233
+
234
+	if ourIP4 == nil && ourIP6 == nil {
235
+		log.Warning("SNI-DNS check: cannot detect public IP address; set public-ipv4/public-ipv6 in config or run 'mtg doctor'")
236
+		return
237
+	}
238
+
239
+	for _, addr := range addresses {
240
+		if (ourIP4 != nil && addr.IP.String() == ourIP4.String()) ||
241
+			(ourIP6 != nil && addr.IP.String() == ourIP6.String()) {
242
+			return
243
+		}
244
+	}
245
+
246
+	resolved := make([]string, 0, len(addresses))
247
+	for _, addr := range addresses {
248
+		resolved = append(resolved, addr.IP.String())
249
+	}
250
+
251
+	our := ""
252
+	if ourIP4 != nil {
253
+		our = ourIP4.String()
254
+	}
255
+
256
+	if ourIP6 != nil {
257
+		if our != "" {
258
+			our += "/"
259
+		}
260
+
261
+		our += ourIP6.String()
262
+	}
263
+
264
+	log.BindStr("hostname", host).
265
+		BindStr("resolved", strings.Join(resolved, ", ")).
266
+		BindStr("public_ip", our).
267
+		Warning("SNI-DNS mismatch: secret hostname does not resolve to this server's public IP. " +
268
+			"DPI may detect and block the proxy. See 'mtg doctor' for details")
269
+}
270
+
271
+func runProxy(conf *config.Config, version string) error { //nolint: funlen, cyclop
211 272
 	logger := makeLogger(conf)
212 273
 
213 274
 	logger.BindJSON("configuration", conf.String()).Debug("configuration")
@@ -222,6 +283,8 @@ func runProxy(conf *config.Config, version string) error { //nolint: funlen
222 283
 		return fmt.Errorf("cannot build network: %w", err)
223 284
 	}
224 285
 
286
+	warnSNIMismatch(conf, ntw, logger)
287
+
225 288
 	blocklist, err := makeIPBlocklist(
226 289
 		conf.Defense.Blocklist,
227 290
 		logger.Named("blocklist"),

Loading…
Откажи
Сачувај