Highly-opinionated (ex-bullshit-free) MTPROTO proxy for Telegram. If you use v1.0 or upgrade broke you proxy, please read the chapter Version 2
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

sni_check.go 2.6KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112
  1. package cli
  2. import (
  3. "context"
  4. "net"
  5. "sync"
  6. "github.com/9seconds/mtg/v2/internal/config"
  7. "github.com/9seconds/mtg/v2/mtglib"
  8. )
  9. // sniCheckResult captures the outcome of comparing the secret hostname's DNS
  10. // records with this server's public IP addresses.
  11. //
  12. // IPv4Match/IPv6Match are true when either a matching record was found, or
  13. // when the corresponding public IP could not be detected — in which case
  14. // there is nothing to compare against.
  15. type sniCheckResult struct {
  16. Host string
  17. Resolved []net.IP
  18. OurIPv4 net.IP
  19. OurIPv6 net.IP
  20. IPv4Match bool
  21. IPv6Match bool
  22. ResolveErr error
  23. }
  24. // Known reports whether at least one public IP family was detected.
  25. func (r sniCheckResult) Known() bool {
  26. return r.OurIPv4 != nil || r.OurIPv6 != nil
  27. }
  28. // OK reports whether the check produced a clean result: the hostname was
  29. // resolved, at least one public IP family is known, and every known family
  30. // matches a resolved record.
  31. func (r sniCheckResult) OK() bool {
  32. if r.Host == "" {
  33. return true
  34. }
  35. if r.ResolveErr != nil || !r.Known() {
  36. return false
  37. }
  38. return r.IPv4Match && r.IPv6Match
  39. }
  40. // runSNICheck resolves conf.Secret.Host and compares the result with the
  41. // server's public IPv4 and IPv6. Public IPs come from config first and fall
  42. // back to on-the-fly detection via ntw. IP detection for the two families
  43. // runs concurrently and honors ctx — callers should supply a deadline,
  44. // since the HTTP fallback can otherwise block startup indefinitely.
  45. func runSNICheck(ctx context.Context,
  46. resolver *net.Resolver,
  47. conf *config.Config,
  48. ntw mtglib.Network,
  49. ) sniCheckResult {
  50. res := sniCheckResult{Host: conf.Secret.Host}
  51. if res.Host == "" {
  52. res.IPv4Match = true
  53. res.IPv6Match = true
  54. return res
  55. }
  56. addrs, err := resolver.LookupIPAddr(ctx, res.Host)
  57. if err != nil {
  58. res.ResolveErr = err
  59. return res
  60. }
  61. res.Resolved = make([]net.IP, 0, len(addrs))
  62. for _, a := range addrs {
  63. res.Resolved = append(res.Resolved, a.IP)
  64. }
  65. endpoints := resolvePublicIPEndpoints(conf.Network.PublicIPEndpoints)
  66. wg := sync.WaitGroup{}
  67. wg.Go(func() {
  68. res.OurIPv4 = conf.PublicIPv4.Get(nil)
  69. if res.OurIPv4 == nil {
  70. res.OurIPv4 = getIP(ctx, ntw, "tcp4", endpoints)
  71. }
  72. })
  73. wg.Go(func() {
  74. res.OurIPv6 = conf.PublicIPv6.Get(nil)
  75. if res.OurIPv6 == nil {
  76. res.OurIPv6 = getIP(ctx, ntw, "tcp6", endpoints)
  77. }
  78. })
  79. wg.Wait()
  80. res.IPv4Match = res.OurIPv4 == nil
  81. res.IPv6Match = res.OurIPv6 == nil
  82. for _, ip := range res.Resolved {
  83. if res.OurIPv4 != nil && ip.String() == res.OurIPv4.String() {
  84. res.IPv4Match = true
  85. }
  86. if res.OurIPv6 != nil && ip.String() == res.OurIPv6.String() {
  87. res.IPv6Match = true
  88. }
  89. }
  90. return res
  91. }