From 852ca713c81e951d0e12d276dda1f7ce79cda4d9 Mon Sep 17 00:00:00 2001 From: 9seconds Date: Sun, 15 Feb 2026 23:56:53 +0100 Subject: [PATCH 1/9] Fetch DC ips from Telegram --- go.mod | 29 +++++++ go.sum | 61 +++++++++++++ mtglib/internal/telegram/address_pool.go | 41 --------- mtglib/internal/telegram/dc_addresses.go | 19 +++++ mtglib/internal/telegram/init.go | 60 ++++++------- mtglib/internal/telegram/rpc_client.go | 42 +++++++++ mtglib/internal/telegram/telegram.go | 104 +++++++++++++++++------ mtglib/proxy.go | 5 +- mtglib/proxy_opts.go | 2 + 9 files changed, 262 insertions(+), 101 deletions(-) delete mode 100644 mtglib/internal/telegram/address_pool.go create mode 100644 mtglib/internal/telegram/dc_addresses.go create mode 100644 mtglib/internal/telegram/rpc_client.go diff --git a/go.mod b/go.mod index b9e46e8ca7..55929b98b8 100644 --- a/go.mod +++ b/go.mod @@ -28,23 +28,52 @@ require ( ) require ( + github.com/gotd/td v0.139.0 github.com/txthinking/socks5 v0.0.0-20251011041537-5c31f201a10e github.com/yl2chen/cidranger v1.0.2 ) require ( github.com/beorn7/perks v1.0.1 // indirect + github.com/cenkalti/backoff/v4 v4.3.0 // indirect github.com/cespare/xxhash/v2 v2.3.0 // indirect + github.com/coder/websocket v1.8.14 // indirect github.com/davecgh/go-spew v1.1.1 // indirect + github.com/dlclark/regexp2 v1.11.5 // indirect + github.com/fatih/color v1.18.0 // indirect + github.com/ghodss/yaml v1.0.0 // indirect + github.com/go-faster/errors v0.7.1 // indirect + github.com/go-faster/jx v1.2.0 // indirect + github.com/go-faster/xor v1.0.0 // indirect + github.com/go-faster/yaml v0.4.6 // indirect + github.com/google/uuid v1.6.0 // indirect + github.com/gotd/ige v0.2.2 // indirect + github.com/gotd/neo v0.1.5 // indirect + github.com/klauspost/compress v1.18.3 // indirect github.com/kr/text v0.2.0 // indirect github.com/mattn/go-colorable v0.1.14 // indirect github.com/mattn/go-isatty v0.0.20 // indirect github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // indirect + github.com/ogen-go/ogen v1.16.0 // indirect github.com/patrickmn/go-cache v2.1.0+incompatible // indirect github.com/pmezard/go-difflib v1.0.0 // indirect github.com/prometheus/client_model v0.6.2 // indirect + github.com/segmentio/asm v1.2.1 // indirect + github.com/shopspring/decimal v1.4.0 // indirect github.com/txthinking/runnergroup v0.0.0-20250224021307-5864ffeb65ae // indirect + go.opentelemetry.io/otel v1.40.0 // indirect + go.opentelemetry.io/otel/metric v1.40.0 // indirect + go.opentelemetry.io/otel/trace v1.40.0 // indirect + go.uber.org/atomic v1.11.0 // indirect + go.uber.org/multierr v1.11.0 // indirect + go.uber.org/zap v1.27.1 // indirect go.yaml.in/yaml/v2 v2.4.3 // indirect + golang.org/x/exp v0.0.0-20230725093048-515e97ebf090 // indirect + golang.org/x/mod v0.32.0 // indirect golang.org/x/sync v0.19.0 // indirect + golang.org/x/text v0.34.0 // indirect + golang.org/x/tools v0.41.0 // indirect + gopkg.in/yaml.v2 v2.4.0 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect + rsc.io/qr v0.2.0 // indirect ) diff --git a/go.sum b/go.sum index aac55d1a6d..cf024208f8 100644 --- a/go.sum +++ b/go.sum @@ -14,8 +14,12 @@ github.com/babolivier/go-doh-client v0.0.0-20201028162107-a76cff4cb8b6 h1:4NNbNM github.com/babolivier/go-doh-client v0.0.0-20201028162107-a76cff4cb8b6/go.mod h1:J29hk+f9lJrblVIfiJOtTFk+OblBawmib4uz/VdKzlg= github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM= github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw= +github.com/cenkalti/backoff/v4 v4.3.0 h1:MyRJ/UdXutAwSAT+s3wNd7MfTIcy71VQueUuFK343L8= +github.com/cenkalti/backoff/v4 v4.3.0/go.mod h1:Y3VNntkOUPxTVeUxJ/G5vcM//AlwfmyYozVcomhLiZE= github.com/cespare/xxhash/v2 v2.3.0 h1:UL815xU9SqsFlibzuggzjXhog7bL6oX9BbNZnL2UFvs= github.com/cespare/xxhash/v2 v2.3.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= +github.com/coder/websocket v1.8.14 h1:9L0p0iKiNOibykf283eHkKUHHrpG7f65OE3BhhO7v9g= +github.com/coder/websocket v1.8.14/go.mod h1:NX3SzP+inril6yawo5CQXx8+fk145lPDC6pumgx0mVg= github.com/coreos/go-systemd/v22 v22.5.0/go.mod h1:Y58oyj3AT4RCenI/lSvhwexgC+NSVTIJ3seZv2GcEnc= github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= github.com/d4l3k/messagediff v1.2.1 h1:ZcAIMYsUg0EAp9X+tt8/enBE/Q8Yd5kzPynLyKptt9U= @@ -23,15 +27,40 @@ github.com/d4l3k/messagediff v1.2.1/go.mod h1:Oozbb1TVXFac9FtSIxHBMnBCq2qeH/2KkE github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/dlclark/regexp2 v1.11.5 h1:Q/sSnsKerHeCkc/jSTNq1oCm7KiVgUMZRDUoRu0JQZQ= +github.com/dlclark/regexp2 v1.11.5/go.mod h1:DHkYz0B9wPfa6wondMfaivmHpzrQ3v9q8cnmRbL6yW8= +github.com/fatih/color v1.18.0 h1:S8gINlzdQ840/4pfAwic/ZE0djQEH3wM94VfqLTZcOM= +github.com/fatih/color v1.18.0/go.mod h1:4FelSpRwEGDpQ12mAdzqdOukCy4u8WUtOY6lkT/6HfU= +github.com/ghodss/yaml v1.0.0 h1:wQHKEahhL6wmXdzwWG11gIVCkOv05bNOh+Rxn0yngAk= +github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04= +github.com/go-faster/errors v0.7.1 h1:MkJTnDoEdi9pDabt1dpWf7AA8/BaSYZqibYyhZ20AYg= +github.com/go-faster/errors v0.7.1/go.mod h1:5ySTjWFiphBs07IKuiL69nxdfd5+fzh1u7FPGZP2quo= +github.com/go-faster/jx v1.2.0 h1:T2YHJPrFaYu21fJtUxC9GzmluKu8rVIFDwwGBKTDseI= +github.com/go-faster/jx v1.2.0/go.mod h1:UWLOVDmMG597a5tBFPLIWJdUxz5/2emOpfsj9Neg0PE= +github.com/go-faster/xor v0.3.0/go.mod h1:x5CaDY9UKErKzqfRfFZdfu+OSTfoZny3w5Ak7UxcipQ= +github.com/go-faster/xor v1.0.0 h1:2o8vTOgErSGHP3/7XwA5ib1FTtUsNtwCoLLBjl31X38= +github.com/go-faster/xor v1.0.0/go.mod h1:x5CaDY9UKErKzqfRfFZdfu+OSTfoZny3w5Ak7UxcipQ= +github.com/go-faster/yaml v0.4.6 h1:lOK/EhI04gCpPgPhgt0bChS6bvw7G3WwI8xxVe0sw9I= +github.com/go-faster/yaml v0.4.6/go.mod h1:390dRIvV4zbnO7qC9FGo6YYutc+wyyUSHBgbXL52eXk= github.com/godbus/dbus/v5 v5.0.4/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA= github.com/google/go-cmp v0.7.0 h1:wk8382ETsv4JYUZwIsn6YpYiWiBsYLSJiTsyBybVuN8= github.com/google/go-cmp v0.7.0/go.mod h1:pXiqmnSA92OHEEa9HXL2W4E7lf9JzCmGVUdgjX3N/iU= +github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0= +github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= +github.com/gotd/ige v0.2.2 h1:XQ9dJZwBfDnOGSTxKXBGP4gMud3Qku2ekScRjDWWfEk= +github.com/gotd/ige v0.2.2/go.mod h1:tuCRb+Y5Y3eNTo3ypIfNpQ4MFjrnONiL2jN2AKZXmb0= +github.com/gotd/neo v0.1.5 h1:oj0iQfMbGClP8xI59x7fE/uHoTJD7NZH9oV1WNuPukQ= +github.com/gotd/neo v0.1.5/go.mod h1:9A2a4bn9zL6FADufBdt7tZt+WMhvZoc5gWXihOPoiBQ= +github.com/gotd/td v0.139.0 h1:3viuXqNdC0+mmd5GerDFp/rlII/QcZSzh/pjuG56NSU= +github.com/gotd/td v0.139.0/go.mod h1:nBietiOYxaXEo6PmRp73LL64upWlk9rcFEZSJu6VieY= github.com/hexops/gotextdiff v1.0.3 h1:gitA9+qJrrTCsiCl7+kh75nPqQt1cx4ZkudSTLoUqJM= github.com/hexops/gotextdiff v1.0.3/go.mod h1:pSWU5MAI3yDq+fZBTazCSJysOMbxWL1BSow5/V2vxeg= github.com/jarcoal/httpmock v1.0.8 h1:8kI16SoO6LQKgPE7PvQuV+YuD/inwHd7fOOe2zMbo4k= github.com/jarcoal/httpmock v1.0.8/go.mod h1:ATjnClrvW/3tijVmpL/va5Z3aAyGvqU3gCT8nX0Txik= github.com/klauspost/compress v1.18.0 h1:c/Cqfb0r+Yi+JtIEq73FWXVkRonBlf0CRNYc8Zttxdo= github.com/klauspost/compress v1.18.0/go.mod h1:2Pp+KzxcywXVXMr50+X0Q/Lsb43OQHYWRCY2AiWywWQ= +github.com/klauspost/compress v1.18.3 h1:9PJRvfbmTabkOX8moIpXPbMMbYN60bWImDDU7L+/6zw= +github.com/klauspost/compress v1.18.3/go.mod h1:R0h/fSBs8DE4ENlcrlib3PsXS61voFxhIs2DeRhCvJ4= github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE= github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk= github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= @@ -51,6 +80,8 @@ github.com/miekg/dns v1.1.51 h1:0+Xg7vObnhrz/4ZCZcZh7zPXlmU0aveS2HDBd0m0qSo= github.com/miekg/dns v1.1.51/go.mod h1:2Z9d3CP1LQWihRZUf29mQ19yDThaI4DAYzte2CaQW5c= github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 h1:C3w9PqII01/Oq1c1nUAm88MOHcQC9l5mIlSMApZMrHA= github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822/go.mod h1:+n7T8mK8HuQTcFwEeznm/DIxMOiR9yIdICNftLE1DvQ= +github.com/ogen-go/ogen v1.16.0 h1:fKHEYokW/QrMzVNXId74/6RObRIUs9T2oroGKtR25Iw= +github.com/ogen-go/ogen v1.16.0/go.mod h1:s3nWiMzybSf8fhxckyO+wtto92+QHpEL8FmkPnhL3jI= github.com/panjf2000/ants/v2 v2.11.5 h1:a7LMnMEeux/ebqTux140tRiaqcFTV0q2bEHF03nl6Rg= github.com/panjf2000/ants/v2 v2.11.5/go.mod h1:8u92CYMUc6gyvTIw8Ru7Mt7+/ESnJahz5EVtqfrilek= github.com/patrickmn/go-cache v2.1.0+incompatible h1:HRMgzkcYKYpi3C8ajMPV8OFXaaRUnok+kx1WdO15EQc= @@ -70,9 +101,14 @@ github.com/prometheus/procfs v0.19.2 h1:zUMhqEW66Ex7OXIiDkll3tl9a1ZdilUOd/F6ZXw4 github.com/prometheus/procfs v0.19.2/go.mod h1:M0aotyiemPhBCM0z5w87kL22CxfcH05ZpYlu+b4J7mw= github.com/rogpeppe/go-internal v1.10.0 h1:TMyTOH3F/DB16zRVcYyreMH6GnZZrwQVAoYjRBZyWFQ= github.com/rogpeppe/go-internal v1.10.0/go.mod h1:UQnix2H7Ngw/k4C5ijL5+65zddjncjaFoBhdsK/akog= +github.com/rogpeppe/go-internal v1.14.1 h1:UQB4HGPB6osV0SQTLymcB4TgvyWu6ZyliaW0tI/otEQ= github.com/rs/xid v1.6.0/go.mod h1:7XoLgs4eV+QndskICGsho+ADou8ySMSjJKDIan90Nz0= github.com/rs/zerolog v1.34.0 h1:k43nTLIwcTVQAncfCw4KZ2VY6ukYoZaBPNOE8txlOeY= github.com/rs/zerolog v1.34.0/go.mod h1:bJsvje4Z08ROH4Nhs5iH600c3IkWhwp44iRc54W6wYQ= +github.com/segmentio/asm v1.2.1 h1:DTNbBqs57ioxAD4PrArqftgypG4/qNpXoJx8TVXxPR0= +github.com/segmentio/asm v1.2.1/go.mod h1:BqMnlJP91P8d+4ibuonYZw9mfnzI9HfxselHZr5aAcs= +github.com/shopspring/decimal v1.4.0 h1:bxl37RwXBklmTi0C79JfXCEBD1cqqHt0bbgBAGFp81k= +github.com/shopspring/decimal v1.4.0/go.mod h1:gawqmDU56v4yIKSwfBSFip1HdCCXN8/+DMd9qYNcwME= github.com/smira/go-statsd v1.3.4 h1:kBYWcLSGT+qC6JVbvfz48kX7mQys32fjDOPrfmsSx2c= github.com/smira/go-statsd v1.3.4/go.mod h1:RjdsESPgDODtg1VpVVf9MJrEW2Hw0wtRNbmB1CAhu6A= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= @@ -97,17 +133,33 @@ github.com/tylertreat/BoomFilters v0.0.0-20251117164519-53813c36cc1b/go.mod h1:O github.com/yl2chen/cidranger v1.0.2 h1:lbOWZVCG1tCRX4u24kuM1Tb4nHqWkDxwLdoS+SevawU= github.com/yl2chen/cidranger v1.0.2/go.mod h1:9U1yz7WPYDwf0vpNWFaeRh0bjwz5RVgRy/9UEQfHl0g= github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY= +go.opentelemetry.io/otel v1.40.0 h1:oA5YeOcpRTXq6NN7frwmwFR0Cn3RhTVZvXsP4duvCms= +go.opentelemetry.io/otel v1.40.0/go.mod h1:IMb+uXZUKkMXdPddhwAHm6UfOwJyh4ct1ybIlV14J0g= +go.opentelemetry.io/otel/metric v1.40.0 h1:rcZe317KPftE2rstWIBitCdVp89A2HqjkxR3c11+p9g= +go.opentelemetry.io/otel/metric v1.40.0/go.mod h1:ib/crwQH7N3r5kfiBZQbwrTge743UDc7DTFVZrrXnqc= +go.opentelemetry.io/otel/trace v1.40.0 h1:WA4etStDttCSYuhwvEa8OP8I5EWu24lkOzp+ZYblVjw= +go.opentelemetry.io/otel/trace v1.40.0/go.mod h1:zeAhriXecNGP/s2SEG3+Y8X9ujcJOTqQ5RgdEJcawiA= +go.uber.org/atomic v1.11.0 h1:ZvwS0R+56ePWxUNi+Atn9dWONBPp/AUETXlHW0DxSjE= +go.uber.org/atomic v1.11.0/go.mod h1:LUxbIzbOniOlMKjJjyPfpl4v+PKK2cNJn91OQbhoJI0= go.uber.org/goleak v1.3.0 h1:2K3zAYmnTNqV73imy9J1T3WC+gmCePx2hEGkimedGto= go.uber.org/goleak v1.3.0/go.mod h1:CoHD4mav9JJNrW/WLlf7HGZPjdw8EucARQHekz1X6bE= +go.uber.org/multierr v1.11.0 h1:blXXJkSxSSfBVBlC76pxqeO+LN3aDfLQo+309xJstO0= +go.uber.org/multierr v1.11.0/go.mod h1:20+QtiLqy0Nd6FdQB9TLXag12DsQkrbs3htMFfDN80Y= +go.uber.org/zap v1.27.1 h1:08RqriUEv8+ArZRYSTXy1LeBScaMpVSTBhCeaZYfMYc= +go.uber.org/zap v1.27.1/go.mod h1:GB2qFLM7cTU87MWRP2mPIjqfIDnGu+VIO4V/SdhGo2E= go.yaml.in/yaml/v2 v2.4.3 h1:6gvOSjQoTB3vt1l+CU+tSyi/HOjfOjRLJ4YwYZGwRO0= go.yaml.in/yaml/v2 v2.4.3/go.mod h1:zSxWcmIDjOzPXpjlTTbAsKokqkDNAVtZO0WOMiT90s8= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= golang.org/x/crypto v0.48.0 h1:/VRzVqiRSggnhY7gNRxPauEQ5Drw9haKdM0jqfcCFts= golang.org/x/crypto v0.48.0/go.mod h1:r0kV5h3qnFPlQnBSrULhlsRfryS2pmewsg+XfMgkVos= +golang.org/x/exp v0.0.0-20230725093048-515e97ebf090 h1:Di6/M8l0O2lCLc6VVRWhgCiApHV8MnQurBnFSHsQtNY= +golang.org/x/exp v0.0.0-20230725093048-515e97ebf090/go.mod h1:FXUEEKJgO7OQYeo8N01OfiKP8RXMtf6e8aTskBGqWdc= golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4= golang.org/x/mod v0.7.0 h1:LapD9S96VoQRhi/GrNTqeBJFrUjs5UHCAtTlgwA5oZA= golang.org/x/mod v0.7.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= +golang.org/x/mod v0.32.0 h1:9F4d3PHLljb6x//jOyokMv3eX+YDeepZSEo3mFJy93c= +golang.org/x/mod v0.32.0/go.mod h1:SgipZ/3h2Ci89DlEtEXWUk/HteuRin+HHhN+WbNhguU= golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= @@ -115,6 +167,7 @@ golang.org/x/net v0.2.0/go.mod h1:KqCZLdyyvdV855qA2rE3GC2aiw5xGR5TEjj8smXukLY= golang.org/x/net v0.49.0 h1:eeHFmOGUTtaaPSGNmjBKpbng9MulQsJURQUAfUwY++o= golang.org/x/net v0.49.0/go.mod h1:/ysNB2EvaqvesRkuLAyjI1ycPZlQHM3q01F02UY/MV8= golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20201207232520-09787c993a3a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.19.0 h1:vV+1eWNmZ5geRlYjzm2adRgW2/mcpevXNg50YZtPCE4= @@ -137,11 +190,15 @@ golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= golang.org/x/text v0.4.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= +golang.org/x/text v0.34.0 h1:oL/Qq0Kdaqxa1KbNeMKwQq0reLCCaFtqu2eNuSeNHbk= +golang.org/x/text v0.34.0/go.mod h1:homfLqTYRFyVYemLBFl5GgL/DWEiH5wcsQ5gSh1yziA= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc= golang.org/x/tools v0.3.0 h1:SrNbZl6ECOS1qFzgTdQfWXZM9XBkiA6tkFrH9YSTPHM= golang.org/x/tools v0.3.0/go.mod h1:/rWhSS2+zyEVwoJf8YAX6L2f0ntZ7Kn/mGgAWcipA5k= +golang.org/x/tools v0.41.0 h1:a9b8iMweWG+S0OBnlU36rzLp20z1Rp10w+IY2czHTQc= +golang.org/x/tools v0.41.0/go.mod h1:XSY6eDqxVNiYgezAVqqCeihT4j1U2CCsqvH3WhQpnlg= golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= google.golang.org/protobuf v1.36.11 h1:fV6ZwhNocDyBLK0dj+fg8ektcVegBBuEolpbTQyBNVE= google.golang.org/protobuf v1.36.11/go.mod h1:HTf+CrKn2C3g5S8VImy6tdcUvCska2kB7j23XfzDpco= @@ -149,6 +206,10 @@ gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8 gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk= gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q= gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY= +gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ= gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= +rsc.io/qr v0.2.0 h1:6vBLea5/NRMVTz8V66gipeLycZMl/+UlFmk8DvqQ6WY= +rsc.io/qr v0.2.0/go.mod h1:IF+uZjkb9fqyeF/4tlBoynqmQxUoPfWEKh921coOuXs= diff --git a/mtglib/internal/telegram/address_pool.go b/mtglib/internal/telegram/address_pool.go deleted file mode 100644 index 2a22371a20..0000000000 --- a/mtglib/internal/telegram/address_pool.go +++ /dev/null @@ -1,41 +0,0 @@ -package telegram - -import "math/rand" - -type addressPool struct { - v4 [][]tgAddr - v6 [][]tgAddr -} - -func (a addressPool) isValidDC(dc int) bool { - return dc > 0 && dc <= len(a.v4) && dc <= len(a.v6) -} - -func (a addressPool) getRandomDC() int { - return 1 + rand.Intn(len(a.v4)) -} - -func (a addressPool) getV4(dc int) []tgAddr { - return a.get(a.v4, dc-1) -} - -func (a addressPool) getV6(dc int) []tgAddr { - return a.get(a.v6, dc-1) -} - -func (a addressPool) get(addresses [][]tgAddr, dc int) []tgAddr { - if dc < 0 || dc >= len(addresses) { - return nil - } - - rv := make([]tgAddr, len(addresses[dc])) - copy(rv, addresses[dc]) - - if len(rv) > 1 { - rand.Shuffle(len(rv), func(i, j int) { - rv[i], rv[j] = rv[j], rv[i] - }) - } - - return rv -} diff --git a/mtglib/internal/telegram/dc_addresses.go b/mtglib/internal/telegram/dc_addresses.go new file mode 100644 index 0000000000..e6b0057cac --- /dev/null +++ b/mtglib/internal/telegram/dc_addresses.go @@ -0,0 +1,19 @@ +package telegram + +type dcAddresses struct { + v4 map[int][]tgAddr + v6 map[int][]tgAddr +} + +func (a dcAddresses) getV4(dc int) []tgAddr { + return a.v4[dc] +} + +func (a dcAddresses) getV6(dc int) []tgAddr { + return a.v6[dc] +} + +func (a dcAddresses) isValidDC(dc int) bool { + _, ok := a.v4[dc] + return ok +} diff --git a/mtglib/internal/telegram/init.go b/mtglib/internal/telegram/init.go index 78874dafaa..af7628955f 100644 --- a/mtglib/internal/telegram/init.go +++ b/mtglib/internal/telegram/init.go @@ -3,6 +3,7 @@ package telegram import ( "context" "errors" + "time" "github.com/9seconds/mtg/v2/essentials" ) @@ -18,6 +19,18 @@ const ( preferIPPreferIPv6 ) +const ( + defaultDC = 2 + defaultUpdateDCAddressesEach = time.Hour + defaultAppID = 123456 + defaultAppHash = "" +) + +type loggerInterface interface { + Info(msg string) + WarningError(msg string, err error) +} + type tgAddr struct { network string address string @@ -25,64 +38,41 @@ type tgAddr struct { // https://github.com/telegramdesktop/tdesktop/blob/master/Telegram/SourceFiles/mtproto/mtproto_dc_options.cpp#L30 var ( - productionV4Addresses = [][]tgAddr{ - { // dc1 + defaultV4Addresses = map[int][]tgAddr{ + 1: { {network: "tcp4", address: "149.154.175.50:443"}, }, - { // dc2 + 2: { {network: "tcp4", address: "149.154.167.51:443"}, {network: "tcp4", address: "95.161.76.100:443"}, }, - { // dc3 + 3: { {network: "tcp4", address: "149.154.175.100:443"}, }, - { // dc4 + 4: { {network: "tcp4", address: "149.154.167.91:443"}, }, - { // dc5 + 5: { {network: "tcp4", address: "149.154.171.5:443"}, }, } - productionV6Addresses = [][]tgAddr{ - { // dc1 + defaultV6Addresses = map[int][]tgAddr{ + 1: { {network: "tcp6", address: "[2001:b28:f23d:f001::a]:443"}, }, - { // dc2 + 2: { {network: "tcp6", address: "[2001:67c:04e8:f002::a]:443"}, }, - { // dc3 + 3: { {network: "tcp6", address: "[2001:b28:f23d:f003::a]:443"}, }, - { // dc4 + 4: { {network: "tcp6", address: "[2001:67c:04e8:f004::a]:443"}, }, - { // dc5 + 5: { {network: "tcp6", address: "[2001:b28:f23f:f005::a]:443"}, }, } - - testV4Addresses = [][]tgAddr{ - { // dc1 - {network: "tcp4", address: "149.154.175.10:443"}, - }, - { // dc2 - {network: "tcp4", address: "149.154.167.40:443"}, - }, - { // dc3 - {network: "tcp4", address: "149.154.175.117:443"}, - }, - } - testV6Addresses = [][]tgAddr{ - { // dc1 - {network: "tcp6", address: "[2001:b28:f23d:f001::e]:443"}, - }, - { // dc2 - {network: "tcp6", address: "[2001:67c:04e8:f002::e]:443"}, - }, - { // dc3 - {network: "tcp6", address: "[2001:b28:f23d:f003::e]:443"}, - }, - } ) type Dialer interface { diff --git a/mtglib/internal/telegram/rpc_client.go b/mtglib/internal/telegram/rpc_client.go new file mode 100644 index 0000000000..75965cb4b8 --- /dev/null +++ b/mtglib/internal/telegram/rpc_client.go @@ -0,0 +1,42 @@ +package telegram + +import ( + "context" + "net" + "strconv" + + "github.com/gotd/td/telegram" +) + +type rpcClient struct { + *telegram.Client +} + +func (r rpcClient) getDCAddresses(logger loggerInterface, ctx context.Context) (dcAddresses, error) { + addrs := dcAddresses{ + v4: map[int][]tgAddr{}, + v6: map[int][]tgAddr{}, + } + + err := r.Client.Run(ctx, func(_ context.Context) error { + for _, opt := range r.Client.Config().DCOptions { + addr := net.JoinHostPort(opt.IPAddress, strconv.Itoa(opt.Port)) + + if opt.Ipv6 { + addrs.v6[opt.ID] = append(addrs.v6[opt.ID], tgAddr{ + network: "tcp6", + address: addr, + }) + } else { + addrs.v4[opt.ID] = append(addrs.v4[opt.ID], tgAddr{ + network: "tcp4", + address: addr, + }) + } + } + + return nil + }) + + return addrs, err +} diff --git a/mtglib/internal/telegram/telegram.go b/mtglib/internal/telegram/telegram.go index 926c7a00eb..7f62694861 100644 --- a/mtglib/internal/telegram/telegram.go +++ b/mtglib/internal/telegram/telegram.go @@ -4,29 +4,39 @@ import ( "context" "fmt" "strings" + "sync" + "time" "github.com/9seconds/mtg/v2/essentials" + "github.com/gotd/td/telegram" ) type Telegram struct { - dialer Dialer - preferIP preferIP - pool addressPool + ctx context.Context + ctxCancel context.CancelFunc + lock sync.RWMutex + + dialer Dialer + preferIP preferIP + addresses dcAddresses + rpc rpcClient } -func (t Telegram) Dial(ctx context.Context, dc int) (essentials.Conn, error) { +func (t *Telegram) Dial(ctx context.Context, dc int) (essentials.Conn, error) { var addresses []tgAddr + t.lock.RLock() switch t.preferIP { case preferIPOnlyIPv4: - addresses = t.pool.getV4(dc) + addresses = t.addresses.getV4(dc) case preferIPOnlyIPv6: - addresses = t.pool.getV6(dc) + addresses = t.addresses.getV6(dc) case preferIPPreferIPv4: - addresses = append(t.pool.getV4(dc), t.pool.getV6(dc)...) + addresses = append(t.addresses.getV4(dc), t.addresses.getV6(dc)...) case preferIPPreferIPv6: - addresses = append(t.pool.getV6(dc), t.pool.getV4(dc)...) + addresses = append(t.addresses.getV6(dc), t.addresses.getV4(dc)...) } + t.lock.RUnlock() var conn essentials.Conn @@ -42,15 +52,60 @@ func (t Telegram) Dial(ctx context.Context, dc int) (essentials.Conn, error) { return nil, fmt.Errorf("cannot dial to %d dc: %w", dc, err) } -func (t Telegram) IsKnownDC(dc int) bool { - return t.pool.isValidDC(dc) +func (t *Telegram) IsKnownDC(dc int) bool { + return t.addresses.isValidDC(dc) +} + +func (t *Telegram) GetFallbackDC() int { + return defaultDC +} + +func (t *Telegram) Shutdown() { + t.ctxCancel() +} + +func (t *Telegram) Run(logger loggerInterface, updateEach time.Duration) { + if updateEach == 0 { + updateEach = defaultUpdateDCAddressesEach + } + + t.update(logger) + + ticker := time.NewTicker(updateEach) + defer func() { + ticker.Stop() + + select { + case <-ticker.C: + default: + } + }() + + for { + select { + case <-t.ctx.Done(): + return + case <-ticker.C: + t.update(logger) + } + } } -func (t Telegram) GetFallbackDC() int { - return t.pool.getRandomDC() +func (t *Telegram) update(logger loggerInterface) { + otherAddresses, err := t.rpc.getDCAddresses(logger, t.ctx) + if err != nil { + logger.WarningError("Cannot update DC list", err) + return + } + + t.lock.Lock() + t.addresses = otherAddresses + t.lock.Unlock() + + logger.Info(fmt.Sprintf("DC are updated: %v", t.addresses)) } -func New(dialer Dialer, ipPreference string, useTestDCs bool) (*Telegram, error) { +func New(dialer Dialer, ipPreference string) (*Telegram, error) { var pref preferIP switch strings.ToLower(ipPreference) { @@ -66,18 +121,19 @@ func New(dialer Dialer, ipPreference string, useTestDCs bool) (*Telegram, error) return nil, fmt.Errorf("unknown ip preference %s", ipPreference) } - pool := addressPool{ - v4: productionV4Addresses, - v6: productionV6Addresses, - } - if useTestDCs { - pool.v4 = testV4Addresses - pool.v6 = testV6Addresses - } + ctx, cancel := context.WithCancel(context.Background()) return &Telegram{ - dialer: dialer, - preferIP: pref, - pool: pool, + ctx: ctx, + ctxCancel: cancel, + dialer: dialer, + preferIP: pref, + addresses: dcAddresses{ + v4: defaultV4Addresses, + v6: defaultV6Addresses, + }, + rpc: rpcClient{ + Client: telegram.NewClient(defaultAppID, defaultAppHash, telegram.Options{}), + }, }, nil } diff --git a/mtglib/proxy.go b/mtglib/proxy.go index e63f6ba29f..c95afc6f77 100644 --- a/mtglib/proxy.go +++ b/mtglib/proxy.go @@ -144,6 +144,7 @@ func (p *Proxy) Shutdown() { p.ctxCancel() p.streamWaitGroup.Wait() p.workerPool.Release() + p.telegram.Shutdown() p.allowlist.Shutdown() p.blocklist.Shutdown() @@ -292,7 +293,7 @@ func NewProxy(opts ProxyOpts) (*Proxy, error) { return nil, fmt.Errorf("invalid settings: %w", err) } - tg, err := telegram.New(opts.Network, opts.getPreferIP(), opts.UseTestDCs) + tg, err := telegram.New(opts.Network, opts.getPreferIP()) if err != nil { return nil, fmt.Errorf("cannot build telegram dialer: %w", err) } @@ -314,6 +315,8 @@ func NewProxy(opts ProxyOpts) (*Proxy, error) { telegram: tg, } + go tg.Run(proxy.logger.Named("telegram"), 0) + pool, err := ants.NewPoolWithFunc(opts.getConcurrency(), func(arg interface{}) { proxy.ServeConn(arg.(essentials.Conn)) //nolint: forcetypeassert diff --git a/mtglib/proxy_opts.go b/mtglib/proxy_opts.go index deb3fb0bb2..a966d48df1 100644 --- a/mtglib/proxy_opts.go +++ b/mtglib/proxy_opts.go @@ -110,6 +110,8 @@ type ProxyOpts struct { // Telegram-related projects. // // This is an optional setting. + // + // OBSOLETE and DEPRECATED. Ignored. UseTestDCs bool } From 0a5a45b32d261b9cf2de75105698147b14e9a423 Mon Sep 17 00:00:00 2001 From: 9seconds Date: Mon, 16 Feb 2026 13:39:35 +0100 Subject: [PATCH 2/9] Create internal DC package --- mtglib/internal/dc/addr.go | 10 ++ mtglib/internal/dc/addr_set.go | 33 ++++ mtglib/internal/dc/addr_test.go | 16 ++ mtglib/internal/dc/init.go | 79 +++++++++ mtglib/internal/dc/telegram.go | 160 ++++++++++++++++++ mtglib/internal/dc/view.go | 24 +++ mtglib/internal/dc/view_test.go | 92 ++++++++++ mtglib/internal/telegram/dc_addresses.go | 19 --- mtglib/internal/telegram/init.go | 80 --------- mtglib/internal/telegram/rpc_client.go | 42 ----- mtglib/internal/telegram/telegram.go | 139 --------------- .../telegram/telegram_internal_test.go | 159 ----------------- mtglib/proxy.go | 39 +++-- 13 files changed, 440 insertions(+), 452 deletions(-) create mode 100644 mtglib/internal/dc/addr.go create mode 100644 mtglib/internal/dc/addr_set.go create mode 100644 mtglib/internal/dc/addr_test.go create mode 100644 mtglib/internal/dc/init.go create mode 100644 mtglib/internal/dc/telegram.go create mode 100644 mtglib/internal/dc/view.go create mode 100644 mtglib/internal/dc/view_test.go delete mode 100644 mtglib/internal/telegram/dc_addresses.go delete mode 100644 mtglib/internal/telegram/init.go delete mode 100644 mtglib/internal/telegram/rpc_client.go delete mode 100644 mtglib/internal/telegram/telegram.go delete mode 100644 mtglib/internal/telegram/telegram_internal_test.go diff --git a/mtglib/internal/dc/addr.go b/mtglib/internal/dc/addr.go new file mode 100644 index 0000000000..8e433e3a5f --- /dev/null +++ b/mtglib/internal/dc/addr.go @@ -0,0 +1,10 @@ +package dc + +type Addr struct { + Network string + Address string +} + +func (d Addr) String() string { + return d.Address +} diff --git a/mtglib/internal/dc/addr_set.go b/mtglib/internal/dc/addr_set.go new file mode 100644 index 0000000000..f1229a7a46 --- /dev/null +++ b/mtglib/internal/dc/addr_set.go @@ -0,0 +1,33 @@ +package dc + +import "math/rand/v2" + +type dcAddrSet struct { + v4 map[int][]Addr + v6 map[int][]Addr +} + +func (d dcAddrSet) getV4(dc int) []Addr { + if d.v4 == nil { + return nil + } + return d.get(d.v4[dc]) +} + +func (d dcAddrSet) getV6(dc int) []Addr { + if d.v6 == nil { + return nil + } + return d.get(d.v6[dc]) +} + +func (d dcAddrSet) get(addrs []Addr) []Addr { + otherSet := make([]Addr, 0, len(addrs)) + otherSet = append(otherSet, addrs...) + + rand.Shuffle(len(otherSet), func(i, j int) { + otherSet[i], otherSet[j] = otherSet[j], otherSet[i] + }) + + return otherSet +} diff --git a/mtglib/internal/dc/addr_test.go b/mtglib/internal/dc/addr_test.go new file mode 100644 index 0000000000..c288c0d432 --- /dev/null +++ b/mtglib/internal/dc/addr_test.go @@ -0,0 +1,16 @@ +package dc_test + +import ( + "testing" + + "github.com/9seconds/mtg/v2/mtglib/internal/dc" + "github.com/stretchr/testify/assert" +) + +func TestAddr(t *testing.T) { + t.Parallel() + + addr := dc.Addr{Network: "tcp4", Address: "127.0.0.1:443"} + + assert.Equal(t, "127.0.0.1:443", addr.String()) +} diff --git a/mtglib/internal/dc/init.go b/mtglib/internal/dc/init.go new file mode 100644 index 0000000000..3ae0eba703 --- /dev/null +++ b/mtglib/internal/dc/init.go @@ -0,0 +1,79 @@ +package dc + +import "time" + +type preferIP uint8 + +const ( + preferIPOnlyIPv4 preferIP = iota + preferIPOnlyIPv6 + preferIPPreferIPv4 + preferIPPreferIPv6 +) + +const ( + DefaultDC = 2 + DefaultUpdateDCAddressesEach = time.Hour + + defaultAppID = 123456 + defaultAppHash = "" +) + +type Logger interface { + Info(msg string) + WarningError(msg string, err error) +} + +var ( + // https://github.com/telegramdesktop/tdesktop/blob/master/Telegram/SourceFiles/mtproto/mtproto_dc_options.cpp#L30 + defaultDCAddrSet = dcAddrSet{ + v4: map[int][]Addr{ + 1: { + {Network: "tcp4", Address: "149.154.175.50:443"}, + }, + 2: { + {Network: "tcp4", Address: "149.154.167.51:443"}, + {Network: "tcp4", Address: "95.161.76.100:443"}, + }, + 3: { + {Network: "tcp4", Address: "149.154.175.100:443"}, + }, + 4: { + {Network: "tcp4", Address: "149.154.167.91:443"}, + }, + 5: { + {Network: "tcp4", Address: "149.154.171.5:443"}, + }, + }, + v6: map[int][]Addr{ + 1: { + {Network: "tcp6", Address: "[2001:b28:f23d:f001::a]:443"}, + }, + 2: { + {Network: "tcp6", Address: "[2001:67c:04e8:f002::a]:443"}, + }, + 3: { + {Network: "tcp6", Address: "[2001:b28:f23d:f003::a]:443"}, + }, + 4: { + {Network: "tcp6", Address: "[2001:67c:04e8:f004::a]:443"}, + }, + 5: { + {Network: "tcp6", Address: "[2001:b28:f23f:f005::a]:443"}, + }, + }, + } + + defaultDCOverridesAddrSet = dcAddrSet{ + v4: map[int][]Addr{ + 203: { + {Network: "tcp4", Address: "91.105.192.100:443"}, + }, + }, + v6: map[int][]Addr{ + 203: { + {Network: "tcp6", Address: "[2a0a:f280:0203:000a:5000:0000:0000:0100]:443"}, + }, + }, + } +) diff --git a/mtglib/internal/dc/telegram.go b/mtglib/internal/dc/telegram.go new file mode 100644 index 0000000000..dc50420c5c --- /dev/null +++ b/mtglib/internal/dc/telegram.go @@ -0,0 +1,160 @@ +package dc + +import ( + "context" + "fmt" + "net" + "strconv" + "strings" + "sync" + "time" + + "github.com/gotd/td/telegram" +) + +type Telegram struct { + logger Logger + lock sync.RWMutex + view dcView + preferIP preferIP + client *telegram.Client +} + +func (t *Telegram) GetAddresses(dc int) []Addr { + t.lock.RLock() + defer t.lock.RUnlock() + + switch t.preferIP { + case preferIPOnlyIPv4: + return t.view.getV4(dc) + case preferIPOnlyIPv6: + return t.view.getV4(dc) + case preferIPPreferIPv4: + return append(t.view.getV4(dc), t.view.getV6(dc)...) + } + + return append(t.view.getV6(dc), t.view.getV4(dc)...) +} + +func (t *Telegram) Run(ctx context.Context, updateEach time.Duration) { + if updateEach == 0 { + updateEach = DefaultUpdateDCAddressesEach + } + + t.update(ctx) + + ticker := time.NewTicker(updateEach) + defer func() { + ticker.Stop() + + select { + case <-ctx.Done(): + case <-ticker.C: + default: + } + }() + + for { + select { + case <-ctx.Done(): + return + case <-ticker.C: + t.update(ctx) + } + } +} + +func (t *Telegram) update(ctx context.Context) { + collected := dcAddrSet{ + v4: map[int][]Addr{}, + v6: map[int][]Addr{}, + } + + err := t.client.Run(ctx, func(tgctx context.Context) error { + conf, err := t.client.API().HelpGetConfig(tgctx) + if err != nil { + return err + } + + for _, opt := range conf.DCOptions { + addr := net.JoinHostPort(opt.IPAddress, strconv.Itoa(opt.Port)) + + if opt.Ipv6 { + collected.v6[opt.ID] = append(collected.v6[opt.ID], Addr{ + Network: "tcp6", + Address: addr, + }) + } else { + collected.v4[opt.ID] = append(collected.v4[opt.ID], Addr{ + Network: "tcp4", + Address: addr, + }) + } + } + + return nil + }) + if err != nil { + t.logger.WarningError("update has failed", err) + return + } + + t.lock.Lock() + t.view.collected = collected + t.lock.Unlock() + + t.logger.Info(fmt.Sprintf("updated DC list: %v", collected)) +} + +func New(logger Logger, ipPreference string, userOverrides map[int][]string) (*Telegram, error) { + var pref preferIP + + switch strings.ToLower(ipPreference) { + case "prefer-ipv4": + pref = preferIPPreferIPv4 + case "prefer-ipv6": + pref = preferIPPreferIPv6 + case "only-ipv4": + pref = preferIPOnlyIPv4 + case "only-ipv6": + pref = preferIPOnlyIPv6 + default: + return nil, fmt.Errorf("unknown ip preference %s", ipPreference) + } + + overrides := dcAddrSet{} + for dc, addrs := range userOverrides { + for _, addr := range addrs { + host, _, err := net.SplitHostPort(addr) + if err != nil { + return nil, fmt.Errorf("incorrect host %s: %w", addr, err) + } + + parsed := net.ParseIP(host) + if parsed == nil { + return nil, fmt.Errorf("incorrect host %s", addr) + } + + if parsed.To4() != nil { + overrides.v4[dc] = append(overrides.v4[dc], Addr{ + Network: "tcp4", + Address: addr, + }) + } else { + overrides.v6[dc] = append(overrides.v6[dc], Addr{ + Network: "tcp6", + Address: addr, + }) + } + } + } + + return &Telegram{ + view: dcView{ + overrides: overrides, + }, + logger: logger, + client: telegram.NewClient(defaultAppID, defaultAppHash, telegram.Options{}), + preferIP: pref, + }, nil +} diff --git a/mtglib/internal/dc/view.go b/mtglib/internal/dc/view.go new file mode 100644 index 0000000000..8a3acc1432 --- /dev/null +++ b/mtglib/internal/dc/view.go @@ -0,0 +1,24 @@ +package dc + +type dcView struct { + overrides dcAddrSet + collected dcAddrSet +} + +func (d dcView) getV4(dc int) []Addr { + addrs := d.overrides.getV4(dc) + addrs = append(addrs, defaultDCOverridesAddrSet.getV4(dc)...) + addrs = append(addrs, d.collected.getV4(dc)...) + addrs = append(addrs, defaultDCAddrSet.getV4(dc)...) + + return addrs +} + +func (d dcView) getV6(dc int) []Addr { + addrs := d.overrides.getV6(dc) + addrs = append(addrs, defaultDCOverridesAddrSet.getV6(dc)...) + addrs = append(addrs, d.collected.getV6(dc)...) + addrs = append(addrs, defaultDCAddrSet.getV6(dc)...) + + return addrs +} diff --git a/mtglib/internal/dc/view_test.go b/mtglib/internal/dc/view_test.go new file mode 100644 index 0000000000..842c476ff9 --- /dev/null +++ b/mtglib/internal/dc/view_test.go @@ -0,0 +1,92 @@ +package dc + +import ( + "fmt" + "testing" + + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/suite" +) + +type ViewTestSuite struct { + suite.Suite + + view dcView +} + +func (suite *ViewTestSuite) SetupSuite() { + suite.view = dcView{ + overrides: dcAddrSet{ + v4: map[int][]Addr{ + 111: { + {Network: "tcp4", Address: "127.0.0.1:443"}, + }, + 203: { + {Network: "tcp4", Address: "127.0.0.2:443"}, + }, + }, + v6: map[int][]Addr{ + 203: { + {Network: "tcp6", Address: "xxx"}, + }, + }, + }, + collected: dcAddrSet{ + v4: map[int][]Addr{ + 1: { + {Network: "tcp4", Address: "127.1.0.1:443"}, + }, + }, + }, + } +} + +func (suite *ViewTestSuite) TestGetV4() { + testData := map[int][]Addr{ + 111: { + {"tcp4", "127.0.0.1:443"}, + }, + 203: { + {"tcp4", "127.0.0.2:443"}, + {"tcp4", "91.105.192.100:443"}, + }, + 2: { + {"tcp4", "149.154.167.51:443"}, + {"tcp4", "95.161.76.100:443"}, + }, + 1: { + {"tcp4", "127.1.0.1:443"}, + {"tcp4", "149.154.175.50:443"}, + }, + } + + for dc, addresses := range testData { + suite.T().Run(fmt.Sprintf("dc%d", dc), func(t *testing.T) { + assert.ElementsMatch(t, addresses, suite.view.getV4(dc)) + }) + } +} + +func (suite *ViewTestSuite) TestGetV6() { + testData := map[int][]Addr{ + 111: {}, + 203: { + {"tcp6", "xxx"}, + {"tcp6", "[2a0a:f280:0203:000a:5000:0000:0000:0100]:443"}, + }, + 1: { + {"tcp6", "[2001:b28:f23d:f001::a]:443"}, + }, + } + + for dc, addresses := range testData { + suite.T().Run(fmt.Sprintf("dc%d", dc), func(t *testing.T) { + assert.ElementsMatch(t, addresses, suite.view.getV6(dc)) + }) + } +} + +func TestView(t *testing.T) { + t.Parallel() + suite.Run(t, &ViewTestSuite{}) +} diff --git a/mtglib/internal/telegram/dc_addresses.go b/mtglib/internal/telegram/dc_addresses.go deleted file mode 100644 index e6b0057cac..0000000000 --- a/mtglib/internal/telegram/dc_addresses.go +++ /dev/null @@ -1,19 +0,0 @@ -package telegram - -type dcAddresses struct { - v4 map[int][]tgAddr - v6 map[int][]tgAddr -} - -func (a dcAddresses) getV4(dc int) []tgAddr { - return a.v4[dc] -} - -func (a dcAddresses) getV6(dc int) []tgAddr { - return a.v6[dc] -} - -func (a dcAddresses) isValidDC(dc int) bool { - _, ok := a.v4[dc] - return ok -} diff --git a/mtglib/internal/telegram/init.go b/mtglib/internal/telegram/init.go deleted file mode 100644 index af7628955f..0000000000 --- a/mtglib/internal/telegram/init.go +++ /dev/null @@ -1,80 +0,0 @@ -package telegram - -import ( - "context" - "errors" - "time" - - "github.com/9seconds/mtg/v2/essentials" -) - -var errNoAddresses = errors.New("no addresses") - -type preferIP uint8 - -const ( - preferIPOnlyIPv4 preferIP = iota - preferIPOnlyIPv6 - preferIPPreferIPv4 - preferIPPreferIPv6 -) - -const ( - defaultDC = 2 - defaultUpdateDCAddressesEach = time.Hour - defaultAppID = 123456 - defaultAppHash = "" -) - -type loggerInterface interface { - Info(msg string) - WarningError(msg string, err error) -} - -type tgAddr struct { - network string - address string -} - -// https://github.com/telegramdesktop/tdesktop/blob/master/Telegram/SourceFiles/mtproto/mtproto_dc_options.cpp#L30 -var ( - defaultV4Addresses = map[int][]tgAddr{ - 1: { - {network: "tcp4", address: "149.154.175.50:443"}, - }, - 2: { - {network: "tcp4", address: "149.154.167.51:443"}, - {network: "tcp4", address: "95.161.76.100:443"}, - }, - 3: { - {network: "tcp4", address: "149.154.175.100:443"}, - }, - 4: { - {network: "tcp4", address: "149.154.167.91:443"}, - }, - 5: { - {network: "tcp4", address: "149.154.171.5:443"}, - }, - } - defaultV6Addresses = map[int][]tgAddr{ - 1: { - {network: "tcp6", address: "[2001:b28:f23d:f001::a]:443"}, - }, - 2: { - {network: "tcp6", address: "[2001:67c:04e8:f002::a]:443"}, - }, - 3: { - {network: "tcp6", address: "[2001:b28:f23d:f003::a]:443"}, - }, - 4: { - {network: "tcp6", address: "[2001:67c:04e8:f004::a]:443"}, - }, - 5: { - {network: "tcp6", address: "[2001:b28:f23f:f005::a]:443"}, - }, - } -) - -type Dialer interface { - DialContext(ctx context.Context, network, address string) (essentials.Conn, error) -} diff --git a/mtglib/internal/telegram/rpc_client.go b/mtglib/internal/telegram/rpc_client.go deleted file mode 100644 index 75965cb4b8..0000000000 --- a/mtglib/internal/telegram/rpc_client.go +++ /dev/null @@ -1,42 +0,0 @@ -package telegram - -import ( - "context" - "net" - "strconv" - - "github.com/gotd/td/telegram" -) - -type rpcClient struct { - *telegram.Client -} - -func (r rpcClient) getDCAddresses(logger loggerInterface, ctx context.Context) (dcAddresses, error) { - addrs := dcAddresses{ - v4: map[int][]tgAddr{}, - v6: map[int][]tgAddr{}, - } - - err := r.Client.Run(ctx, func(_ context.Context) error { - for _, opt := range r.Client.Config().DCOptions { - addr := net.JoinHostPort(opt.IPAddress, strconv.Itoa(opt.Port)) - - if opt.Ipv6 { - addrs.v6[opt.ID] = append(addrs.v6[opt.ID], tgAddr{ - network: "tcp6", - address: addr, - }) - } else { - addrs.v4[opt.ID] = append(addrs.v4[opt.ID], tgAddr{ - network: "tcp4", - address: addr, - }) - } - } - - return nil - }) - - return addrs, err -} diff --git a/mtglib/internal/telegram/telegram.go b/mtglib/internal/telegram/telegram.go deleted file mode 100644 index 7f62694861..0000000000 --- a/mtglib/internal/telegram/telegram.go +++ /dev/null @@ -1,139 +0,0 @@ -package telegram - -import ( - "context" - "fmt" - "strings" - "sync" - "time" - - "github.com/9seconds/mtg/v2/essentials" - "github.com/gotd/td/telegram" -) - -type Telegram struct { - ctx context.Context - ctxCancel context.CancelFunc - lock sync.RWMutex - - dialer Dialer - preferIP preferIP - addresses dcAddresses - rpc rpcClient -} - -func (t *Telegram) Dial(ctx context.Context, dc int) (essentials.Conn, error) { - var addresses []tgAddr - - t.lock.RLock() - switch t.preferIP { - case preferIPOnlyIPv4: - addresses = t.addresses.getV4(dc) - case preferIPOnlyIPv6: - addresses = t.addresses.getV6(dc) - case preferIPPreferIPv4: - addresses = append(t.addresses.getV4(dc), t.addresses.getV6(dc)...) - case preferIPPreferIPv6: - addresses = append(t.addresses.getV6(dc), t.addresses.getV4(dc)...) - } - t.lock.RUnlock() - - var conn essentials.Conn - - err := errNoAddresses - - for _, v := range addresses { - conn, err = t.dialer.DialContext(ctx, v.network, v.address) - if err == nil { - return conn, nil - } - } - - return nil, fmt.Errorf("cannot dial to %d dc: %w", dc, err) -} - -func (t *Telegram) IsKnownDC(dc int) bool { - return t.addresses.isValidDC(dc) -} - -func (t *Telegram) GetFallbackDC() int { - return defaultDC -} - -func (t *Telegram) Shutdown() { - t.ctxCancel() -} - -func (t *Telegram) Run(logger loggerInterface, updateEach time.Duration) { - if updateEach == 0 { - updateEach = defaultUpdateDCAddressesEach - } - - t.update(logger) - - ticker := time.NewTicker(updateEach) - defer func() { - ticker.Stop() - - select { - case <-ticker.C: - default: - } - }() - - for { - select { - case <-t.ctx.Done(): - return - case <-ticker.C: - t.update(logger) - } - } -} - -func (t *Telegram) update(logger loggerInterface) { - otherAddresses, err := t.rpc.getDCAddresses(logger, t.ctx) - if err != nil { - logger.WarningError("Cannot update DC list", err) - return - } - - t.lock.Lock() - t.addresses = otherAddresses - t.lock.Unlock() - - logger.Info(fmt.Sprintf("DC are updated: %v", t.addresses)) -} - -func New(dialer Dialer, ipPreference string) (*Telegram, error) { - var pref preferIP - - switch strings.ToLower(ipPreference) { - case "prefer-ipv4": - pref = preferIPPreferIPv4 - case "prefer-ipv6": - pref = preferIPPreferIPv6 - case "only-ipv4": - pref = preferIPOnlyIPv4 - case "only-ipv6": - pref = preferIPOnlyIPv6 - default: - return nil, fmt.Errorf("unknown ip preference %s", ipPreference) - } - - ctx, cancel := context.WithCancel(context.Background()) - - return &Telegram{ - ctx: ctx, - ctxCancel: cancel, - dialer: dialer, - preferIP: pref, - addresses: dcAddresses{ - v4: defaultV4Addresses, - v6: defaultV6Addresses, - }, - rpc: rpcClient{ - Client: telegram.NewClient(defaultAppID, defaultAppHash, telegram.Options{}), - }, - }, nil -} diff --git a/mtglib/internal/telegram/telegram_internal_test.go b/mtglib/internal/telegram/telegram_internal_test.go deleted file mode 100644 index 794e97adc2..0000000000 --- a/mtglib/internal/telegram/telegram_internal_test.go +++ /dev/null @@ -1,159 +0,0 @@ -package telegram - -import ( - "context" - "errors" - "io" - "net" - "strconv" - "testing" - - "github.com/9seconds/mtg/v2/internal/testlib" - "github.com/stretchr/testify/assert" - "github.com/stretchr/testify/mock" - "github.com/stretchr/testify/suite" -) - -type TelegramTestSuite struct { - suite.Suite - - dialerMock *testlib.MtglibNetworkMock - t *Telegram -} - -func (suite *TelegramTestSuite) SetupTest() { - suite.dialerMock = &testlib.MtglibNetworkMock{} - suite.t, _ = New(suite.dialerMock, "prefer-ipv4", false) -} - -func (suite *TelegramTestSuite) TearDownTest() { - suite.dialerMock.AssertExpectations(suite.T()) -} - -func (suite *TelegramTestSuite) TestUnknownDC() { - testData := []int{ - -1, - 0, - 6, - 100, - } - - for _, v := range testData { - value := v - - suite.T().Run(strconv.Itoa(value), func(t *testing.T) { - _, err := suite.t.Dial(context.Background(), value) - assert.Error(t, err) - assert.False(t, suite.t.IsKnownDC(value)) - }) - } -} - -func (suite *TelegramTestSuite) TestDialToCorrectIPs() { - testData := map[int][]tgAddr{} - - for i := 1; i <= 5; i++ { - testData[i] = []tgAddr{} - testData[i] = append(testData[i], productionV4Addresses[i-1]...) - testData[i] = append(testData[i], productionV6Addresses[i-1]...) - } - - for i, v := range testData { - idx := i - addresses := v - - suite.T().Run(strconv.Itoa(idx), func(t *testing.T) { - for _, addr := range addresses { - suite.dialerMock. - On("DialContext", mock.Anything, addr.network, addr.address). - Once(). - Return((*net.TCPConn)(nil), io.EOF) - } - - _, err := suite.t.Dial(context.Background(), idx) - assert.True(t, errors.Is(err, io.EOF)) - assert.True(t, suite.t.IsKnownDC(idx)) - }) - } -} - -func (suite *TelegramTestSuite) TestDialPreferIPRange() { - testData := map[string][]tgAddr{ - "prefer-ipv4": {testV4Addresses[0][0], testV6Addresses[0][0]}, - "prefer-ipv6": {testV6Addresses[0][0], testV4Addresses[0][0]}, - "only-ipv4": {testV4Addresses[0][0]}, - "only-ipv6": {testV6Addresses[0][0]}, - } - - for k, v := range testData { - name := k - addresses := v - - suite.T().Run(name, func(t *testing.T) { - for _, addr := range addresses { - suite.dialerMock. - On("DialContext", mock.Anything, addr.network, addr.address). - Once(). - Return((*net.TCPConn)(nil), io.EOF) - } - - tg, _ := New(suite.dialerMock, name, true) - _, err := tg.Dial(context.Background(), 1) - - assert.True(t, errors.Is(err, io.EOF)) - }) - } -} - -func (suite *TelegramTestSuite) TestDialPreferIPPriority() { - testData := map[string]tgAddr{ - "prefer-ipv4": productionV4Addresses[0][0], - "prefer-ipv6": productionV6Addresses[0][0], - } - - for k, v := range testData { - name := k - addr := v - - suite.T().Run(name, func(t *testing.T) { - conn := &net.TCPConn{} - - suite.dialerMock. - On("DialContext", mock.Anything, addr.network, addr.address). - Once(). - Return(conn, nil) - - tg, _ := New(suite.dialerMock, name, false) - - res, err := tg.Dial(context.Background(), 1) - assert.NoError(t, err) - assert.Equal(t, conn, res) - }) - } -} - -func (suite *TelegramTestSuite) TestUnknownPreferIP() { - _, err := New(suite.dialerMock, "xxx", false) - suite.Error(err) -} - -func (suite *TelegramTestSuite) TestFallbackDC() { - dcs := make([]int, 10) - - for i := 0; i < len(dcs); i++ { - dcs[i] = suite.t.GetFallbackDC() - } - - for _, v := range dcs { - value := v - - suite.T().Run(strconv.Itoa(value), func(t *testing.T) { - assert.True(t, suite.t.IsKnownDC(value)) - }) - } -} - -func TestTelegram(t *testing.T) { - t.Parallel() - suite.Run(t, &TelegramTestSuite{}) -} diff --git a/mtglib/proxy.go b/mtglib/proxy.go index c95afc6f77..ba80d9995a 100644 --- a/mtglib/proxy.go +++ b/mtglib/proxy.go @@ -10,11 +10,11 @@ import ( "time" "github.com/9seconds/mtg/v2/essentials" + "github.com/9seconds/mtg/v2/mtglib/internal/dc" "github.com/9seconds/mtg/v2/mtglib/internal/faketls" "github.com/9seconds/mtg/v2/mtglib/internal/faketls/record" "github.com/9seconds/mtg/v2/mtglib/internal/obfuscated2" "github.com/9seconds/mtg/v2/mtglib/internal/relay" - "github.com/9seconds/mtg/v2/mtglib/internal/telegram" "github.com/panjf2000/ants/v2" ) @@ -28,7 +28,7 @@ type Proxy struct { tolerateTimeSkewness time.Duration domainFrontingPort int workerPool *ants.PoolWithFunc - telegram *telegram.Telegram + telegram *dc.Telegram secret Secret network Network @@ -144,7 +144,6 @@ func (p *Proxy) Shutdown() { p.ctxCancel() p.streamWaitGroup.Wait() p.workerPool.Release() - p.telegram.Shutdown() p.allowlist.Shutdown() p.blocklist.Shutdown() @@ -220,18 +219,26 @@ func (p *Proxy) doObfuscated2Handshake(ctx *streamContext) error { } func (p *Proxy) doTelegramCall(ctx *streamContext) error { - dc := ctx.dc - - if p.allowFallbackOnUnknownDC && !p.telegram.IsKnownDC(dc) { - dc = p.telegram.GetFallbackDC() - ctx.logger = ctx.logger.BindInt("fallback_dc", dc) + dcid := ctx.dc + addresses := p.telegram.GetAddresses(dcid) + if len(addresses) == 0 && p.allowFallbackOnUnknownDC { + ctx.logger = ctx.logger.BindInt("fallback_dc", dc.DefaultDC) ctx.logger.Warning("unknown DC, fallbacks") + addresses = p.telegram.GetAddresses(dc.DefaultDC) } - conn, err := p.telegram.Dial(ctx, dc) + var conn essentials.Conn + var err error + + for _, addr := range addresses { + conn, err = p.network.Dial(addr.Network, addr.Address) + if err == nil { + break + } + } if err != nil { - return fmt.Errorf("cannot dial to Telegram: %w", err) + return fmt.Errorf("no addresses to call: %w", err) } encryptor, decryptor, err := obfuscated2.ServerHandshake(conn) @@ -293,9 +300,15 @@ func NewProxy(opts ProxyOpts) (*Proxy, error) { return nil, fmt.Errorf("invalid settings: %w", err) } - tg, err := telegram.New(opts.Network, opts.getPreferIP()) + logger := opts.getLogger("proxy") + + tg, err := dc.New( + logger.Named("telegram"), + opts.getPreferIP(), + map[int][]string{}, + ) // TODO: propagate value if err != nil { - return nil, fmt.Errorf("cannot build telegram dialer: %w", err) + return nil, fmt.Errorf("cannot build telegram dc fetcher: %w", err) } ctx, cancel := context.WithCancel(context.Background()) @@ -315,7 +328,7 @@ func NewProxy(opts ProxyOpts) (*Proxy, error) { telegram: tg, } - go tg.Run(proxy.logger.Named("telegram"), 0) + go tg.Run(ctx, 0) // TODO: propagate value pool, err := ants.NewPoolWithFunc(opts.getConcurrency(), func(arg interface{}) { From 836a481026fec0c8de8a217448ae8a78a6fb0931 Mon Sep 17 00:00:00 2001 From: 9seconds Date: Mon, 16 Feb 2026 14:48:30 +0100 Subject: [PATCH 3/9] Propagate DCOverrides --- go.mod | 1 + go.sum | 2 + internal/cli/run_proxy.go | 9 ++++ internal/config/config.go | 4 ++ internal/config/parse.go | 6 ++- internal/config/type_dc.go | 41 ++++++++++++++ internal/config/type_dc_test.go | 95 +++++++++++++++++++++++++++++++++ mtglib/proxy.go | 6 +-- mtglib/proxy_opts.go | 6 +++ 9 files changed, 164 insertions(+), 6 deletions(-) create mode 100644 internal/config/type_dc.go create mode 100644 internal/config/type_dc_test.go diff --git a/go.mod b/go.mod index 55929b98b8..cc30b92d13 100644 --- a/go.mod +++ b/go.mod @@ -29,6 +29,7 @@ require ( require ( github.com/gotd/td v0.139.0 + github.com/pelletier/go-toml/v2 v2.2.4 github.com/txthinking/socks5 v0.0.0-20251011041537-5c31f201a10e github.com/yl2chen/cidranger v1.0.2 ) diff --git a/go.sum b/go.sum index cf024208f8..7477545916 100644 --- a/go.sum +++ b/go.sum @@ -88,6 +88,8 @@ github.com/patrickmn/go-cache v2.1.0+incompatible h1:HRMgzkcYKYpi3C8ajMPV8OFXaaR github.com/patrickmn/go-cache v2.1.0+incompatible/go.mod h1:3Qf8kWWT7OJRJbdiICTKqZju1ZixQ/KpMGzzAfe6+WQ= github.com/pelletier/go-toml v1.9.5 h1:4yBQzkHv+7BHq2PQUZF3Mx0IYxG7LsP222s7Agd3ve8= github.com/pelletier/go-toml v1.9.5/go.mod h1:u1nR/EPcESfeI/szUZKdtJ0xRNbUoANCkoOuaOx1Y+c= +github.com/pelletier/go-toml/v2 v2.2.4 h1:mye9XuhQ6gvn5h28+VilKrrPoQVanw5PMw/TB0t5Ec4= +github.com/pelletier/go-toml/v2 v2.2.4/go.mod h1:2gIqNv+qfxSVS7cM2xJQKtLSTLUE9V8t9Stt+h56mCY= github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= diff --git a/internal/cli/run_proxy.go b/internal/cli/run_proxy.go index c8532129a7..5357309ae8 100644 --- a/internal/cli/run_proxy.go +++ b/internal/cli/run_proxy.go @@ -240,6 +240,14 @@ func runProxy(conf *config.Config, version string) error { //nolint: funlen return fmt.Errorf("cannot build ip allowlist: %w", err) } + dcOverrides := map[int][]string{} + for _, override := range conf.DCOverrides { + dcid := override.DC.Get() + for _, addr := range override.IPs { + dcOverrides[dcid] = append(dcOverrides[dcid], addr.Get("")) + } + } + opts := mtglib.ProxyOpts{ Logger: logger, Network: ntw, @@ -254,6 +262,7 @@ func runProxy(conf *config.Config, version string) error { //nolint: funlen AllowFallbackOnUnknownDC: conf.AllowFallbackOnUnknownDC.Get(false), TolerateTimeSkewness: conf.TolerateTimeSkewness.Value, + DCOverrides: dcOverrides, } proxy, err := mtglib.NewProxy(opts) diff --git a/internal/config/config.go b/internal/config/config.go index 9b69a94023..c330a25f87 100644 --- a/internal/config/config.go +++ b/internal/config/config.go @@ -64,6 +64,10 @@ type Config struct { MetricPrefix TypeMetricPrefix `json:"metricPrefix"` } `json:"prometheus"` } `json:"stats"` + DCOverrides []struct { + DC TypeDC + IPs []TypeHostPort `json:"ips"` + } `json:"dc_overrides"` } func (c *Config) Validate() error { diff --git a/internal/config/parse.go b/internal/config/parse.go index 591e6bf1e5..8d056f3d21 100644 --- a/internal/config/parse.go +++ b/internal/config/parse.go @@ -5,7 +5,7 @@ import ( "encoding/json" "fmt" - "github.com/pelletier/go-toml" + "github.com/pelletier/go-toml/v2" ) type tomlConfig struct { @@ -59,6 +59,10 @@ type tomlConfig struct { MetricPrefix string `toml:"metric-prefix" json:"metricPrefix,omitempty"` } `toml:"prometheus" json:"prometheus,omitempty"` } `toml:"stats" json:"stats,omitempty"` + DCOverrides []struct { + DC int `toml:"dc" json:"dc"` + IPs []string `toml:"ips" json:"ips"` + } } func Parse(rawData []byte) (*Config, error) { diff --git a/internal/config/type_dc.go b/internal/config/type_dc.go new file mode 100644 index 0000000000..d3b1257f39 --- /dev/null +++ b/internal/config/type_dc.go @@ -0,0 +1,41 @@ +package config + +import ( + "fmt" + "strconv" +) + +type TypeDC struct { + Value int +} + +func (t *TypeDC) Set(value string) error { + parsed, err := strconv.ParseInt(value, 10, 16) + if err != nil { + return fmt.Errorf("cannot parse dc: %w", err) + } + + if parsed < 0 { + parsed = -parsed + } + + t.Value = int(parsed) + + return nil +} + +func (t *TypeDC) UnmarshalText(data []byte) error { + return t.Set(string(data)) +} + +func (t TypeDC) MarshalText() ([]byte, error) { + return []byte(t.String()), nil +} + +func (t TypeDC) String() string { + return strconv.Itoa(t.Value) +} + +func (t TypeDC) Get() int { + return t.Value +} diff --git a/internal/config/type_dc_test.go b/internal/config/type_dc_test.go new file mode 100644 index 0000000000..b51229c999 --- /dev/null +++ b/internal/config/type_dc_test.go @@ -0,0 +1,95 @@ +package config_test + +import ( + "encoding/json" + "testing" + + "github.com/9seconds/mtg/v2/internal/config" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/suite" +) + +type typeDCTestStruct struct { + Value config.TypeDC `json:"value"` +} + +type TypeDCTestSuite struct { + suite.Suite +} + +func (suite *TypeDCTestSuite) TestUnmarshalFail() { + testData := []string{ + "-1s", + "1202002020202", + "xxx", + "-11111111111111", + "", + } + + for _, v := range testData { + data, err := json.Marshal(map[string]string{ + "value": v, + }) + suite.NoError(err) + + suite.T().Run(v, func(t *testing.T) { + assert.Error(t, json.Unmarshal(data, &typeDCTestStruct{})) + }) + } +} + +func (suite *TypeDCTestSuite) TestUnmarshalOk() { + testData := map[string]int{ + "1": 1, + "-1": 1, + "203": 203, + } + + for value, expected := range testData { + data, err := json.Marshal(map[string]string{ + "value": value, + }) + suite.NoError(err) + + suite.T().Run(value, func(t *testing.T) { + testStruct := &typeDCTestStruct{} + + assert.NoError(t, json.Unmarshal(data, testStruct)) + assert.Equal(t, expected, testStruct.Value.Value) + assert.Equal(t, expected, testStruct.Value.Get()) + }) + } +} + +func (suite *TypeDCTestSuite) TestMarshalOk() { + testData := map[string]string{ + "1": "1", + "203": "203", + } + + for k, v := range testData { + value := k + expected := v + + suite.T().Run(value, func(t *testing.T) { + testStruct := &typeDCTestStruct{} + + assert.NoError(t, testStruct.Value.Set(value)) + + data, err := json.Marshal(testStruct) + assert.NoError(t, err) + + expectedJSON, err := json.Marshal(map[string]string{ + "value": expected, + }) + assert.NoError(t, err) + + assert.JSONEq(t, string(expectedJSON), string(data)) + }) + } +} + +func TestTypeDC(t *testing.T) { + t.Parallel() + suite.Run(t, &TypeDCTestSuite{}) +} diff --git a/mtglib/proxy.go b/mtglib/proxy.go index ba80d9995a..c037a39aab 100644 --- a/mtglib/proxy.go +++ b/mtglib/proxy.go @@ -302,11 +302,7 @@ func NewProxy(opts ProxyOpts) (*Proxy, error) { logger := opts.getLogger("proxy") - tg, err := dc.New( - logger.Named("telegram"), - opts.getPreferIP(), - map[int][]string{}, - ) // TODO: propagate value + tg, err := dc.New(logger.Named("telegram"), opts.getPreferIP(), opts.DCOverrides) if err != nil { return nil, fmt.Errorf("cannot build telegram dc fetcher: %w", err) } diff --git a/mtglib/proxy_opts.go b/mtglib/proxy_opts.go index a966d48df1..53f34348a2 100644 --- a/mtglib/proxy_opts.go +++ b/mtglib/proxy_opts.go @@ -113,6 +113,12 @@ type ProxyOpts struct { // // OBSOLETE and DEPRECATED. Ignored. UseTestDCs bool + + // DCOverrides defines a set of IP addresses that should be used + // with a higher priority to those that are calculated somehow by mtg. + // + // This is an optional setting + DCOverrides map[int][]string } func (p ProxyOpts) valid() error { From 308e372a5d0fa23c74f0e12fa5840d8f41883595 Mon Sep 17 00:00:00 2001 From: 9seconds Date: Mon, 16 Feb 2026 15:05:59 +0100 Subject: [PATCH 4/9] Propagate DcUpdateEach setting --- internal/cli/run_proxy.go | 1 + internal/cli/simple_run.go | 1 + internal/config/config.go | 5 +++-- internal/config/parse.go | 3 ++- mtglib/init.go | 4 ++++ mtglib/internal/dc/init.go | 5 +---- mtglib/internal/dc/telegram.go | 4 ---- mtglib/proxy.go | 7 ++++++- mtglib/proxy_opts.go | 4 ++++ 9 files changed, 22 insertions(+), 12 deletions(-) diff --git a/internal/cli/run_proxy.go b/internal/cli/run_proxy.go index 5357309ae8..7126022788 100644 --- a/internal/cli/run_proxy.go +++ b/internal/cli/run_proxy.go @@ -263,6 +263,7 @@ func runProxy(conf *config.Config, version string) error { //nolint: funlen AllowFallbackOnUnknownDC: conf.AllowFallbackOnUnknownDC.Get(false), TolerateTimeSkewness: conf.TolerateTimeSkewness.Value, DCOverrides: dcOverrides, + DCUpdateEach: conf.DCUpdateEach.Get(0), } proxy, err := mtglib.NewProxy(opts) diff --git a/internal/cli/simple_run.go b/internal/cli/simple_run.go index 02d6dc3328..b8112f0516 100644 --- a/internal/cli/simple_run.go +++ b/internal/cli/simple_run.go @@ -80,6 +80,7 @@ func (s *SimpleRun) Run(cli *CLI, version string) error { //nolint: cyclop,funle conf.Debug.Value = s.Debug conf.AllowFallbackOnUnknownDC.Value = true conf.Defense.AntiReplay.Enabled.Value = true + conf.DCUpdateEach.Value = 0 if err := conf.Validate(); err != nil { return fmt.Errorf("invalid result configuration: %w", err) diff --git a/internal/config/config.go b/internal/config/config.go index c330a25f87..e82addeb9c 100644 --- a/internal/config/config.go +++ b/internal/config/config.go @@ -65,9 +65,10 @@ type Config struct { } `json:"prometheus"` } `json:"stats"` DCOverrides []struct { - DC TypeDC + DC TypeDC `json:"dc"` IPs []TypeHostPort `json:"ips"` - } `json:"dc_overrides"` + } `json:"dcOverrides"` + DCUpdateEach TypeDuration `json:"dcUpdateEach"` } func (c *Config) Validate() error { diff --git a/internal/config/parse.go b/internal/config/parse.go index 8d056f3d21..f317f6564a 100644 --- a/internal/config/parse.go +++ b/internal/config/parse.go @@ -62,7 +62,8 @@ type tomlConfig struct { DCOverrides []struct { DC int `toml:"dc" json:"dc"` IPs []string `toml:"ips" json:"ips"` - } + } `toml:"dc-overrides" json:"dcOverrides,omitempty"` + DCUpdateEach string `toml:"dc-update-each" json:"dcUpdateEach,omitempty"` } func Parse(rawData []byte) (*Config, error) { diff --git a/mtglib/init.go b/mtglib/init.go index 40e3f41260..d354c69433 100644 --- a/mtglib/init.go +++ b/mtglib/init.go @@ -99,6 +99,10 @@ const ( // reads from Telegram after which connection will be terminated. This is // required to abort stale connections. TCPRelayReadTimeout = 20 * time.Second + + // DefaultDCUpdateEach defines a time period that is used to fetch + // a relevant list of DCs to use from Telegram using its own MTPROTO API. + DefaultDCUpdateEach = time.Hour ) // Network defines a knowledge how to work with a network. It may sound fun but diff --git a/mtglib/internal/dc/init.go b/mtglib/internal/dc/init.go index 3ae0eba703..894faa7d4b 100644 --- a/mtglib/internal/dc/init.go +++ b/mtglib/internal/dc/init.go @@ -1,7 +1,5 @@ package dc -import "time" - type preferIP uint8 const ( @@ -12,8 +10,7 @@ const ( ) const ( - DefaultDC = 2 - DefaultUpdateDCAddressesEach = time.Hour + DefaultDC = 2 defaultAppID = 123456 defaultAppHash = "" diff --git a/mtglib/internal/dc/telegram.go b/mtglib/internal/dc/telegram.go index dc50420c5c..0032f54e6b 100644 --- a/mtglib/internal/dc/telegram.go +++ b/mtglib/internal/dc/telegram.go @@ -37,10 +37,6 @@ func (t *Telegram) GetAddresses(dc int) []Addr { } func (t *Telegram) Run(ctx context.Context, updateEach time.Duration) { - if updateEach == 0 { - updateEach = DefaultUpdateDCAddressesEach - } - t.update(ctx) ticker := time.NewTicker(updateEach) diff --git a/mtglib/proxy.go b/mtglib/proxy.go index c037a39aab..b30d50d6cb 100644 --- a/mtglib/proxy.go +++ b/mtglib/proxy.go @@ -324,7 +324,12 @@ func NewProxy(opts ProxyOpts) (*Proxy, error) { telegram: tg, } - go tg.Run(ctx, 0) // TODO: propagate value + dcUpdateEach := opts.DCUpdateEach + if dcUpdateEach == 0 { + dcUpdateEach = DefaultDCUpdateEach + } + + go tg.Run(ctx, dcUpdateEach) pool, err := ants.NewPoolWithFunc(opts.getConcurrency(), func(arg interface{}) { diff --git a/mtglib/proxy_opts.go b/mtglib/proxy_opts.go index 53f34348a2..f78a2f5b8e 100644 --- a/mtglib/proxy_opts.go +++ b/mtglib/proxy_opts.go @@ -119,6 +119,10 @@ type ProxyOpts struct { // // This is an optional setting DCOverrides map[int][]string + + // DCUpdateEach defines a time duration that is used to fetch a list of + // DCs to use from the Telegram. + DCUpdateEach time.Duration } func (p ProxyOpts) valid() error { From 82679ec20f9510e863b4db696e5f55ff0196fcd2 Mon Sep 17 00:00:00 2001 From: 9seconds Date: Mon, 16 Feb 2026 15:22:03 +0100 Subject: [PATCH 5/9] Update config --- example.config.toml | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/example.config.toml b/example.config.toml index bdec7b73f6..98ec78ac66 100644 --- a/example.config.toml +++ b/example.config.toml @@ -71,6 +71,20 @@ tolerate-time-skewness = "5s" # Otherwise, chose a new DC. allow-fallback-on-unknown-dc = false +# Telegram uses different DCs for different purposes. Unfortunately, most of +# DCs are not public, and dependent on a location of the current user, so +# mtg cannot know upfront about all of them, and how to access them. It has +# a default list of DCs, including some CDN IPs, but it is possible that some +# of them are not working for you. In this case, you can override them here. +[[dc-overrides]] +dc = "101" +ips = ["127.0.0.1:443"] + +# mtg periodically updates its list of DCs, fetching them from Telegram itself. +# This is a period of time between updates. Default value is 1h, and usually +# more than enough. +# dc-update-each = "24h" + # network defines different network-related settings [network] # please be aware that mtg needs to do some external requests. For From 8e87405d3eea3f8281553b995f5d61b1786e0436 Mon Sep 17 00:00:00 2001 From: 9seconds Date: Mon, 16 Feb 2026 16:29:45 +0100 Subject: [PATCH 6/9] Remove integration with gotd --- example.config.toml | 7 +-- go.mod | 29 +----------- go.sum | 63 +----------------------- internal/cli/run_proxy.go | 1 - internal/cli/simple_run.go | 1 - internal/config/config.go | 1 - internal/config/parse.go | 3 +- internal/config/type_dc.go | 4 +- mtglib/init.go | 4 -- mtglib/internal/dc/init.go | 3 -- mtglib/internal/dc/telegram.go | 87 ++-------------------------------- mtglib/internal/dc/view.go | 4 +- mtglib/proxy.go | 11 +---- mtglib/proxy_opts.go | 4 -- 14 files changed, 14 insertions(+), 208 deletions(-) diff --git a/example.config.toml b/example.config.toml index 98ec78ac66..ad402ba6e2 100644 --- a/example.config.toml +++ b/example.config.toml @@ -77,14 +77,9 @@ allow-fallback-on-unknown-dc = false # a default list of DCs, including some CDN IPs, but it is possible that some # of them are not working for you. In this case, you can override them here. [[dc-overrides]] -dc = "101" +dc = 101 ips = ["127.0.0.1:443"] -# mtg periodically updates its list of DCs, fetching them from Telegram itself. -# This is a period of time between updates. Default value is 1h, and usually -# more than enough. -# dc-update-each = "24h" - # network defines different network-related settings [network] # please be aware that mtg needs to do some external requests. For diff --git a/go.mod b/go.mod index cc30b92d13..b4c34f76f6 100644 --- a/go.mod +++ b/go.mod @@ -12,7 +12,6 @@ require ( github.com/jarcoal/httpmock v1.0.8 github.com/mccutchen/go-httpbin v1.1.1 github.com/panjf2000/ants/v2 v2.11.5 - github.com/pelletier/go-toml v1.9.5 github.com/prometheus/client_golang v1.23.2 github.com/prometheus/common v0.67.5 // indirect github.com/prometheus/procfs v0.19.2 // indirect @@ -28,7 +27,6 @@ require ( ) require ( - github.com/gotd/td v0.139.0 github.com/pelletier/go-toml/v2 v2.2.4 github.com/txthinking/socks5 v0.0.0-20251011041537-5c31f201a10e github.com/yl2chen/cidranger v1.0.2 @@ -36,45 +34,20 @@ require ( require ( github.com/beorn7/perks v1.0.1 // indirect - github.com/cenkalti/backoff/v4 v4.3.0 // indirect github.com/cespare/xxhash/v2 v2.3.0 // indirect - github.com/coder/websocket v1.8.14 // indirect github.com/davecgh/go-spew v1.1.1 // indirect - github.com/dlclark/regexp2 v1.11.5 // indirect - github.com/fatih/color v1.18.0 // indirect - github.com/ghodss/yaml v1.0.0 // indirect - github.com/go-faster/errors v0.7.1 // indirect - github.com/go-faster/jx v1.2.0 // indirect - github.com/go-faster/xor v1.0.0 // indirect - github.com/go-faster/yaml v0.4.6 // indirect - github.com/google/uuid v1.6.0 // indirect - github.com/gotd/ige v0.2.2 // indirect - github.com/gotd/neo v0.1.5 // indirect github.com/klauspost/compress v1.18.3 // indirect github.com/kr/text v0.2.0 // indirect github.com/mattn/go-colorable v0.1.14 // indirect github.com/mattn/go-isatty v0.0.20 // indirect github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // indirect - github.com/ogen-go/ogen v1.16.0 // indirect github.com/patrickmn/go-cache v2.1.0+incompatible // indirect github.com/pmezard/go-difflib v1.0.0 // indirect github.com/prometheus/client_model v0.6.2 // indirect - github.com/segmentio/asm v1.2.1 // indirect - github.com/shopspring/decimal v1.4.0 // indirect + github.com/rogpeppe/go-internal v1.14.1 // indirect github.com/txthinking/runnergroup v0.0.0-20250224021307-5864ffeb65ae // indirect - go.opentelemetry.io/otel v1.40.0 // indirect - go.opentelemetry.io/otel/metric v1.40.0 // indirect - go.opentelemetry.io/otel/trace v1.40.0 // indirect - go.uber.org/atomic v1.11.0 // indirect - go.uber.org/multierr v1.11.0 // indirect - go.uber.org/zap v1.27.1 // indirect go.yaml.in/yaml/v2 v2.4.3 // indirect - golang.org/x/exp v0.0.0-20230725093048-515e97ebf090 // indirect - golang.org/x/mod v0.32.0 // indirect golang.org/x/sync v0.19.0 // indirect - golang.org/x/text v0.34.0 // indirect golang.org/x/tools v0.41.0 // indirect - gopkg.in/yaml.v2 v2.4.0 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect - rsc.io/qr v0.2.0 // indirect ) diff --git a/go.sum b/go.sum index 7477545916..c7d814b8b9 100644 --- a/go.sum +++ b/go.sum @@ -14,12 +14,8 @@ github.com/babolivier/go-doh-client v0.0.0-20201028162107-a76cff4cb8b6 h1:4NNbNM github.com/babolivier/go-doh-client v0.0.0-20201028162107-a76cff4cb8b6/go.mod h1:J29hk+f9lJrblVIfiJOtTFk+OblBawmib4uz/VdKzlg= github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM= github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw= -github.com/cenkalti/backoff/v4 v4.3.0 h1:MyRJ/UdXutAwSAT+s3wNd7MfTIcy71VQueUuFK343L8= -github.com/cenkalti/backoff/v4 v4.3.0/go.mod h1:Y3VNntkOUPxTVeUxJ/G5vcM//AlwfmyYozVcomhLiZE= github.com/cespare/xxhash/v2 v2.3.0 h1:UL815xU9SqsFlibzuggzjXhog7bL6oX9BbNZnL2UFvs= github.com/cespare/xxhash/v2 v2.3.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= -github.com/coder/websocket v1.8.14 h1:9L0p0iKiNOibykf283eHkKUHHrpG7f65OE3BhhO7v9g= -github.com/coder/websocket v1.8.14/go.mod h1:NX3SzP+inril6yawo5CQXx8+fk145lPDC6pumgx0mVg= github.com/coreos/go-systemd/v22 v22.5.0/go.mod h1:Y58oyj3AT4RCenI/lSvhwexgC+NSVTIJ3seZv2GcEnc= github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= github.com/d4l3k/messagediff v1.2.1 h1:ZcAIMYsUg0EAp9X+tt8/enBE/Q8Yd5kzPynLyKptt9U= @@ -27,38 +23,13 @@ github.com/d4l3k/messagediff v1.2.1/go.mod h1:Oozbb1TVXFac9FtSIxHBMnBCq2qeH/2KkE github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= -github.com/dlclark/regexp2 v1.11.5 h1:Q/sSnsKerHeCkc/jSTNq1oCm7KiVgUMZRDUoRu0JQZQ= -github.com/dlclark/regexp2 v1.11.5/go.mod h1:DHkYz0B9wPfa6wondMfaivmHpzrQ3v9q8cnmRbL6yW8= -github.com/fatih/color v1.18.0 h1:S8gINlzdQ840/4pfAwic/ZE0djQEH3wM94VfqLTZcOM= -github.com/fatih/color v1.18.0/go.mod h1:4FelSpRwEGDpQ12mAdzqdOukCy4u8WUtOY6lkT/6HfU= -github.com/ghodss/yaml v1.0.0 h1:wQHKEahhL6wmXdzwWG11gIVCkOv05bNOh+Rxn0yngAk= -github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04= -github.com/go-faster/errors v0.7.1 h1:MkJTnDoEdi9pDabt1dpWf7AA8/BaSYZqibYyhZ20AYg= -github.com/go-faster/errors v0.7.1/go.mod h1:5ySTjWFiphBs07IKuiL69nxdfd5+fzh1u7FPGZP2quo= -github.com/go-faster/jx v1.2.0 h1:T2YHJPrFaYu21fJtUxC9GzmluKu8rVIFDwwGBKTDseI= -github.com/go-faster/jx v1.2.0/go.mod h1:UWLOVDmMG597a5tBFPLIWJdUxz5/2emOpfsj9Neg0PE= -github.com/go-faster/xor v0.3.0/go.mod h1:x5CaDY9UKErKzqfRfFZdfu+OSTfoZny3w5Ak7UxcipQ= -github.com/go-faster/xor v1.0.0 h1:2o8vTOgErSGHP3/7XwA5ib1FTtUsNtwCoLLBjl31X38= -github.com/go-faster/xor v1.0.0/go.mod h1:x5CaDY9UKErKzqfRfFZdfu+OSTfoZny3w5Ak7UxcipQ= -github.com/go-faster/yaml v0.4.6 h1:lOK/EhI04gCpPgPhgt0bChS6bvw7G3WwI8xxVe0sw9I= -github.com/go-faster/yaml v0.4.6/go.mod h1:390dRIvV4zbnO7qC9FGo6YYutc+wyyUSHBgbXL52eXk= github.com/godbus/dbus/v5 v5.0.4/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA= github.com/google/go-cmp v0.7.0 h1:wk8382ETsv4JYUZwIsn6YpYiWiBsYLSJiTsyBybVuN8= github.com/google/go-cmp v0.7.0/go.mod h1:pXiqmnSA92OHEEa9HXL2W4E7lf9JzCmGVUdgjX3N/iU= -github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0= -github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= -github.com/gotd/ige v0.2.2 h1:XQ9dJZwBfDnOGSTxKXBGP4gMud3Qku2ekScRjDWWfEk= -github.com/gotd/ige v0.2.2/go.mod h1:tuCRb+Y5Y3eNTo3ypIfNpQ4MFjrnONiL2jN2AKZXmb0= -github.com/gotd/neo v0.1.5 h1:oj0iQfMbGClP8xI59x7fE/uHoTJD7NZH9oV1WNuPukQ= -github.com/gotd/neo v0.1.5/go.mod h1:9A2a4bn9zL6FADufBdt7tZt+WMhvZoc5gWXihOPoiBQ= -github.com/gotd/td v0.139.0 h1:3viuXqNdC0+mmd5GerDFp/rlII/QcZSzh/pjuG56NSU= -github.com/gotd/td v0.139.0/go.mod h1:nBietiOYxaXEo6PmRp73LL64upWlk9rcFEZSJu6VieY= github.com/hexops/gotextdiff v1.0.3 h1:gitA9+qJrrTCsiCl7+kh75nPqQt1cx4ZkudSTLoUqJM= github.com/hexops/gotextdiff v1.0.3/go.mod h1:pSWU5MAI3yDq+fZBTazCSJysOMbxWL1BSow5/V2vxeg= github.com/jarcoal/httpmock v1.0.8 h1:8kI16SoO6LQKgPE7PvQuV+YuD/inwHd7fOOe2zMbo4k= github.com/jarcoal/httpmock v1.0.8/go.mod h1:ATjnClrvW/3tijVmpL/va5Z3aAyGvqU3gCT8nX0Txik= -github.com/klauspost/compress v1.18.0 h1:c/Cqfb0r+Yi+JtIEq73FWXVkRonBlf0CRNYc8Zttxdo= -github.com/klauspost/compress v1.18.0/go.mod h1:2Pp+KzxcywXVXMr50+X0Q/Lsb43OQHYWRCY2AiWywWQ= github.com/klauspost/compress v1.18.3 h1:9PJRvfbmTabkOX8moIpXPbMMbYN60bWImDDU7L+/6zw= github.com/klauspost/compress v1.18.3/go.mod h1:R0h/fSBs8DE4ENlcrlib3PsXS61voFxhIs2DeRhCvJ4= github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE= @@ -80,14 +51,10 @@ github.com/miekg/dns v1.1.51 h1:0+Xg7vObnhrz/4ZCZcZh7zPXlmU0aveS2HDBd0m0qSo= github.com/miekg/dns v1.1.51/go.mod h1:2Z9d3CP1LQWihRZUf29mQ19yDThaI4DAYzte2CaQW5c= github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 h1:C3w9PqII01/Oq1c1nUAm88MOHcQC9l5mIlSMApZMrHA= github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822/go.mod h1:+n7T8mK8HuQTcFwEeznm/DIxMOiR9yIdICNftLE1DvQ= -github.com/ogen-go/ogen v1.16.0 h1:fKHEYokW/QrMzVNXId74/6RObRIUs9T2oroGKtR25Iw= -github.com/ogen-go/ogen v1.16.0/go.mod h1:s3nWiMzybSf8fhxckyO+wtto92+QHpEL8FmkPnhL3jI= github.com/panjf2000/ants/v2 v2.11.5 h1:a7LMnMEeux/ebqTux140tRiaqcFTV0q2bEHF03nl6Rg= github.com/panjf2000/ants/v2 v2.11.5/go.mod h1:8u92CYMUc6gyvTIw8Ru7Mt7+/ESnJahz5EVtqfrilek= github.com/patrickmn/go-cache v2.1.0+incompatible h1:HRMgzkcYKYpi3C8ajMPV8OFXaaRUnok+kx1WdO15EQc= github.com/patrickmn/go-cache v2.1.0+incompatible/go.mod h1:3Qf8kWWT7OJRJbdiICTKqZju1ZixQ/KpMGzzAfe6+WQ= -github.com/pelletier/go-toml v1.9.5 h1:4yBQzkHv+7BHq2PQUZF3Mx0IYxG7LsP222s7Agd3ve8= -github.com/pelletier/go-toml v1.9.5/go.mod h1:u1nR/EPcESfeI/szUZKdtJ0xRNbUoANCkoOuaOx1Y+c= github.com/pelletier/go-toml/v2 v2.2.4 h1:mye9XuhQ6gvn5h28+VilKrrPoQVanw5PMw/TB0t5Ec4= github.com/pelletier/go-toml/v2 v2.2.4/go.mod h1:2gIqNv+qfxSVS7cM2xJQKtLSTLUE9V8t9Stt+h56mCY= github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= @@ -101,16 +68,11 @@ github.com/prometheus/common v0.67.5 h1:pIgK94WWlQt1WLwAC5j2ynLaBRDiinoAb86HZHTU github.com/prometheus/common v0.67.5/go.mod h1:SjE/0MzDEEAyrdr5Gqc6G+sXI67maCxzaT3A2+HqjUw= github.com/prometheus/procfs v0.19.2 h1:zUMhqEW66Ex7OXIiDkll3tl9a1ZdilUOd/F6ZXw4Vws= github.com/prometheus/procfs v0.19.2/go.mod h1:M0aotyiemPhBCM0z5w87kL22CxfcH05ZpYlu+b4J7mw= -github.com/rogpeppe/go-internal v1.10.0 h1:TMyTOH3F/DB16zRVcYyreMH6GnZZrwQVAoYjRBZyWFQ= -github.com/rogpeppe/go-internal v1.10.0/go.mod h1:UQnix2H7Ngw/k4C5ijL5+65zddjncjaFoBhdsK/akog= github.com/rogpeppe/go-internal v1.14.1 h1:UQB4HGPB6osV0SQTLymcB4TgvyWu6ZyliaW0tI/otEQ= +github.com/rogpeppe/go-internal v1.14.1/go.mod h1:MaRKkUm5W0goXpeCfT7UZI6fk/L7L7so1lCWt35ZSgc= github.com/rs/xid v1.6.0/go.mod h1:7XoLgs4eV+QndskICGsho+ADou8ySMSjJKDIan90Nz0= github.com/rs/zerolog v1.34.0 h1:k43nTLIwcTVQAncfCw4KZ2VY6ukYoZaBPNOE8txlOeY= github.com/rs/zerolog v1.34.0/go.mod h1:bJsvje4Z08ROH4Nhs5iH600c3IkWhwp44iRc54W6wYQ= -github.com/segmentio/asm v1.2.1 h1:DTNbBqs57ioxAD4PrArqftgypG4/qNpXoJx8TVXxPR0= -github.com/segmentio/asm v1.2.1/go.mod h1:BqMnlJP91P8d+4ibuonYZw9mfnzI9HfxselHZr5aAcs= -github.com/shopspring/decimal v1.4.0 h1:bxl37RwXBklmTi0C79JfXCEBD1cqqHt0bbgBAGFp81k= -github.com/shopspring/decimal v1.4.0/go.mod h1:gawqmDU56v4yIKSwfBSFip1HdCCXN8/+DMd9qYNcwME= github.com/smira/go-statsd v1.3.4 h1:kBYWcLSGT+qC6JVbvfz48kX7mQys32fjDOPrfmsSx2c= github.com/smira/go-statsd v1.3.4/go.mod h1:RjdsESPgDODtg1VpVVf9MJrEW2Hw0wtRNbmB1CAhu6A= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= @@ -135,30 +97,15 @@ github.com/tylertreat/BoomFilters v0.0.0-20251117164519-53813c36cc1b/go.mod h1:O github.com/yl2chen/cidranger v1.0.2 h1:lbOWZVCG1tCRX4u24kuM1Tb4nHqWkDxwLdoS+SevawU= github.com/yl2chen/cidranger v1.0.2/go.mod h1:9U1yz7WPYDwf0vpNWFaeRh0bjwz5RVgRy/9UEQfHl0g= github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY= -go.opentelemetry.io/otel v1.40.0 h1:oA5YeOcpRTXq6NN7frwmwFR0Cn3RhTVZvXsP4duvCms= -go.opentelemetry.io/otel v1.40.0/go.mod h1:IMb+uXZUKkMXdPddhwAHm6UfOwJyh4ct1ybIlV14J0g= -go.opentelemetry.io/otel/metric v1.40.0 h1:rcZe317KPftE2rstWIBitCdVp89A2HqjkxR3c11+p9g= -go.opentelemetry.io/otel/metric v1.40.0/go.mod h1:ib/crwQH7N3r5kfiBZQbwrTge743UDc7DTFVZrrXnqc= -go.opentelemetry.io/otel/trace v1.40.0 h1:WA4etStDttCSYuhwvEa8OP8I5EWu24lkOzp+ZYblVjw= -go.opentelemetry.io/otel/trace v1.40.0/go.mod h1:zeAhriXecNGP/s2SEG3+Y8X9ujcJOTqQ5RgdEJcawiA= -go.uber.org/atomic v1.11.0 h1:ZvwS0R+56ePWxUNi+Atn9dWONBPp/AUETXlHW0DxSjE= -go.uber.org/atomic v1.11.0/go.mod h1:LUxbIzbOniOlMKjJjyPfpl4v+PKK2cNJn91OQbhoJI0= go.uber.org/goleak v1.3.0 h1:2K3zAYmnTNqV73imy9J1T3WC+gmCePx2hEGkimedGto= go.uber.org/goleak v1.3.0/go.mod h1:CoHD4mav9JJNrW/WLlf7HGZPjdw8EucARQHekz1X6bE= -go.uber.org/multierr v1.11.0 h1:blXXJkSxSSfBVBlC76pxqeO+LN3aDfLQo+309xJstO0= -go.uber.org/multierr v1.11.0/go.mod h1:20+QtiLqy0Nd6FdQB9TLXag12DsQkrbs3htMFfDN80Y= -go.uber.org/zap v1.27.1 h1:08RqriUEv8+ArZRYSTXy1LeBScaMpVSTBhCeaZYfMYc= -go.uber.org/zap v1.27.1/go.mod h1:GB2qFLM7cTU87MWRP2mPIjqfIDnGu+VIO4V/SdhGo2E= go.yaml.in/yaml/v2 v2.4.3 h1:6gvOSjQoTB3vt1l+CU+tSyi/HOjfOjRLJ4YwYZGwRO0= go.yaml.in/yaml/v2 v2.4.3/go.mod h1:zSxWcmIDjOzPXpjlTTbAsKokqkDNAVtZO0WOMiT90s8= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= golang.org/x/crypto v0.48.0 h1:/VRzVqiRSggnhY7gNRxPauEQ5Drw9haKdM0jqfcCFts= golang.org/x/crypto v0.48.0/go.mod h1:r0kV5h3qnFPlQnBSrULhlsRfryS2pmewsg+XfMgkVos= -golang.org/x/exp v0.0.0-20230725093048-515e97ebf090 h1:Di6/M8l0O2lCLc6VVRWhgCiApHV8MnQurBnFSHsQtNY= -golang.org/x/exp v0.0.0-20230725093048-515e97ebf090/go.mod h1:FXUEEKJgO7OQYeo8N01OfiKP8RXMtf6e8aTskBGqWdc= golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4= -golang.org/x/mod v0.7.0 h1:LapD9S96VoQRhi/GrNTqeBJFrUjs5UHCAtTlgwA5oZA= golang.org/x/mod v0.7.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= golang.org/x/mod v0.32.0 h1:9F4d3PHLljb6x//jOyokMv3eX+YDeepZSEo3mFJy93c= golang.org/x/mod v0.32.0/go.mod h1:SgipZ/3h2Ci89DlEtEXWUk/HteuRin+HHhN+WbNhguU= @@ -169,7 +116,6 @@ golang.org/x/net v0.2.0/go.mod h1:KqCZLdyyvdV855qA2rE3GC2aiw5xGR5TEjj8smXukLY= golang.org/x/net v0.49.0 h1:eeHFmOGUTtaaPSGNmjBKpbng9MulQsJURQUAfUwY++o= golang.org/x/net v0.49.0/go.mod h1:/ysNB2EvaqvesRkuLAyjI1ycPZlQHM3q01F02UY/MV8= golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.0.0-20201207232520-09787c993a3a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.19.0 h1:vV+1eWNmZ5geRlYjzm2adRgW2/mcpevXNg50YZtPCE4= @@ -192,12 +138,9 @@ golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= golang.org/x/text v0.4.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= -golang.org/x/text v0.34.0 h1:oL/Qq0Kdaqxa1KbNeMKwQq0reLCCaFtqu2eNuSeNHbk= -golang.org/x/text v0.34.0/go.mod h1:homfLqTYRFyVYemLBFl5GgL/DWEiH5wcsQ5gSh1yziA= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc= -golang.org/x/tools v0.3.0 h1:SrNbZl6ECOS1qFzgTdQfWXZM9XBkiA6tkFrH9YSTPHM= golang.org/x/tools v0.3.0/go.mod h1:/rWhSS2+zyEVwoJf8YAX6L2f0ntZ7Kn/mGgAWcipA5k= golang.org/x/tools v0.41.0 h1:a9b8iMweWG+S0OBnlU36rzLp20z1Rp10w+IY2czHTQc= golang.org/x/tools v0.41.0/go.mod h1:XSY6eDqxVNiYgezAVqqCeihT4j1U2CCsqvH3WhQpnlg= @@ -208,10 +151,6 @@ gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8 gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk= gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q= gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= -gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY= -gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ= gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= -rsc.io/qr v0.2.0 h1:6vBLea5/NRMVTz8V66gipeLycZMl/+UlFmk8DvqQ6WY= -rsc.io/qr v0.2.0/go.mod h1:IF+uZjkb9fqyeF/4tlBoynqmQxUoPfWEKh921coOuXs= diff --git a/internal/cli/run_proxy.go b/internal/cli/run_proxy.go index 7126022788..5357309ae8 100644 --- a/internal/cli/run_proxy.go +++ b/internal/cli/run_proxy.go @@ -263,7 +263,6 @@ func runProxy(conf *config.Config, version string) error { //nolint: funlen AllowFallbackOnUnknownDC: conf.AllowFallbackOnUnknownDC.Get(false), TolerateTimeSkewness: conf.TolerateTimeSkewness.Value, DCOverrides: dcOverrides, - DCUpdateEach: conf.DCUpdateEach.Get(0), } proxy, err := mtglib.NewProxy(opts) diff --git a/internal/cli/simple_run.go b/internal/cli/simple_run.go index b8112f0516..02d6dc3328 100644 --- a/internal/cli/simple_run.go +++ b/internal/cli/simple_run.go @@ -80,7 +80,6 @@ func (s *SimpleRun) Run(cli *CLI, version string) error { //nolint: cyclop,funle conf.Debug.Value = s.Debug conf.AllowFallbackOnUnknownDC.Value = true conf.Defense.AntiReplay.Enabled.Value = true - conf.DCUpdateEach.Value = 0 if err := conf.Validate(); err != nil { return fmt.Errorf("invalid result configuration: %w", err) diff --git a/internal/config/config.go b/internal/config/config.go index e82addeb9c..3bab778391 100644 --- a/internal/config/config.go +++ b/internal/config/config.go @@ -68,7 +68,6 @@ type Config struct { DC TypeDC `json:"dc"` IPs []TypeHostPort `json:"ips"` } `json:"dcOverrides"` - DCUpdateEach TypeDuration `json:"dcUpdateEach"` } func (c *Config) Validate() error { diff --git a/internal/config/parse.go b/internal/config/parse.go index f317f6564a..fc1a14845a 100644 --- a/internal/config/parse.go +++ b/internal/config/parse.go @@ -60,10 +60,9 @@ type tomlConfig struct { } `toml:"prometheus" json:"prometheus,omitempty"` } `toml:"stats" json:"stats,omitempty"` DCOverrides []struct { - DC int `toml:"dc" json:"dc"` + DC uint `toml:"dc" json:"dc"` IPs []string `toml:"ips" json:"ips"` } `toml:"dc-overrides" json:"dcOverrides,omitempty"` - DCUpdateEach string `toml:"dc-update-each" json:"dcUpdateEach,omitempty"` } func Parse(rawData []byte) (*Config, error) { diff --git a/internal/config/type_dc.go b/internal/config/type_dc.go index d3b1257f39..1d3beb522f 100644 --- a/internal/config/type_dc.go +++ b/internal/config/type_dc.go @@ -24,11 +24,11 @@ func (t *TypeDC) Set(value string) error { return nil } -func (t *TypeDC) UnmarshalText(data []byte) error { +func (t *TypeDC) UnmarshalJSON(data []byte) error { return t.Set(string(data)) } -func (t TypeDC) MarshalText() ([]byte, error) { +func (t TypeDC) MarshalJSON() ([]byte, error) { return []byte(t.String()), nil } diff --git a/mtglib/init.go b/mtglib/init.go index d354c69433..40e3f41260 100644 --- a/mtglib/init.go +++ b/mtglib/init.go @@ -99,10 +99,6 @@ const ( // reads from Telegram after which connection will be terminated. This is // required to abort stale connections. TCPRelayReadTimeout = 20 * time.Second - - // DefaultDCUpdateEach defines a time period that is used to fetch - // a relevant list of DCs to use from Telegram using its own MTPROTO API. - DefaultDCUpdateEach = time.Hour ) // Network defines a knowledge how to work with a network. It may sound fun but diff --git a/mtglib/internal/dc/init.go b/mtglib/internal/dc/init.go index 894faa7d4b..c253f6e037 100644 --- a/mtglib/internal/dc/init.go +++ b/mtglib/internal/dc/init.go @@ -11,9 +11,6 @@ const ( const ( DefaultDC = 2 - - defaultAppID = 123456 - defaultAppHash = "" ) type Logger interface { diff --git a/mtglib/internal/dc/telegram.go b/mtglib/internal/dc/telegram.go index 0032f54e6b..e9f261f4e1 100644 --- a/mtglib/internal/dc/telegram.go +++ b/mtglib/internal/dc/telegram.go @@ -1,29 +1,17 @@ package dc import ( - "context" "fmt" "net" - "strconv" "strings" - "sync" - "time" - - "github.com/gotd/td/telegram" ) type Telegram struct { - logger Logger - lock sync.RWMutex view dcView preferIP preferIP - client *telegram.Client } func (t *Telegram) GetAddresses(dc int) []Addr { - t.lock.RLock() - defer t.lock.RUnlock() - switch t.preferIP { case preferIPOnlyIPv4: return t.view.getV4(dc) @@ -36,73 +24,7 @@ func (t *Telegram) GetAddresses(dc int) []Addr { return append(t.view.getV6(dc), t.view.getV4(dc)...) } -func (t *Telegram) Run(ctx context.Context, updateEach time.Duration) { - t.update(ctx) - - ticker := time.NewTicker(updateEach) - defer func() { - ticker.Stop() - - select { - case <-ctx.Done(): - case <-ticker.C: - default: - } - }() - - for { - select { - case <-ctx.Done(): - return - case <-ticker.C: - t.update(ctx) - } - } -} - -func (t *Telegram) update(ctx context.Context) { - collected := dcAddrSet{ - v4: map[int][]Addr{}, - v6: map[int][]Addr{}, - } - - err := t.client.Run(ctx, func(tgctx context.Context) error { - conf, err := t.client.API().HelpGetConfig(tgctx) - if err != nil { - return err - } - - for _, opt := range conf.DCOptions { - addr := net.JoinHostPort(opt.IPAddress, strconv.Itoa(opt.Port)) - - if opt.Ipv6 { - collected.v6[opt.ID] = append(collected.v6[opt.ID], Addr{ - Network: "tcp6", - Address: addr, - }) - } else { - collected.v4[opt.ID] = append(collected.v4[opt.ID], Addr{ - Network: "tcp4", - Address: addr, - }) - } - } - - return nil - }) - if err != nil { - t.logger.WarningError("update has failed", err) - return - } - - t.lock.Lock() - t.view.collected = collected - t.lock.Unlock() - - t.logger.Info(fmt.Sprintf("updated DC list: %v", collected)) -} - -func New(logger Logger, ipPreference string, userOverrides map[int][]string) (*Telegram, error) { +func New(ipPreference string, userOverrides map[int][]string) (*Telegram, error) { var pref preferIP switch strings.ToLower(ipPreference) { @@ -118,7 +40,10 @@ func New(logger Logger, ipPreference string, userOverrides map[int][]string) (*T return nil, fmt.Errorf("unknown ip preference %s", ipPreference) } - overrides := dcAddrSet{} + overrides := dcAddrSet{ + v4: map[int][]Addr{}, + v6: map[int][]Addr{}, + } for dc, addrs := range userOverrides { for _, addr := range addrs { host, _, err := net.SplitHostPort(addr) @@ -149,8 +74,6 @@ func New(logger Logger, ipPreference string, userOverrides map[int][]string) (*T view: dcView{ overrides: overrides, }, - logger: logger, - client: telegram.NewClient(defaultAppID, defaultAppHash, telegram.Options{}), preferIP: pref, }, nil } diff --git a/mtglib/internal/dc/view.go b/mtglib/internal/dc/view.go index 8a3acc1432..f4ef7d9850 100644 --- a/mtglib/internal/dc/view.go +++ b/mtglib/internal/dc/view.go @@ -8,7 +8,7 @@ type dcView struct { func (d dcView) getV4(dc int) []Addr { addrs := d.overrides.getV4(dc) addrs = append(addrs, defaultDCOverridesAddrSet.getV4(dc)...) - addrs = append(addrs, d.collected.getV4(dc)...) + // addrs = append(addrs, d.collected.getV4(dc)...) addrs = append(addrs, defaultDCAddrSet.getV4(dc)...) return addrs @@ -17,7 +17,7 @@ func (d dcView) getV4(dc int) []Addr { func (d dcView) getV6(dc int) []Addr { addrs := d.overrides.getV6(dc) addrs = append(addrs, defaultDCOverridesAddrSet.getV6(dc)...) - addrs = append(addrs, d.collected.getV6(dc)...) + // addrs = append(addrs, d.collected.getV6(dc)...) addrs = append(addrs, defaultDCAddrSet.getV6(dc)...) return addrs diff --git a/mtglib/proxy.go b/mtglib/proxy.go index b30d50d6cb..830a2f9af1 100644 --- a/mtglib/proxy.go +++ b/mtglib/proxy.go @@ -300,9 +300,7 @@ func NewProxy(opts ProxyOpts) (*Proxy, error) { return nil, fmt.Errorf("invalid settings: %w", err) } - logger := opts.getLogger("proxy") - - tg, err := dc.New(logger.Named("telegram"), opts.getPreferIP(), opts.DCOverrides) + tg, err := dc.New(opts.getPreferIP(), opts.DCOverrides) if err != nil { return nil, fmt.Errorf("cannot build telegram dc fetcher: %w", err) } @@ -324,13 +322,6 @@ func NewProxy(opts ProxyOpts) (*Proxy, error) { telegram: tg, } - dcUpdateEach := opts.DCUpdateEach - if dcUpdateEach == 0 { - dcUpdateEach = DefaultDCUpdateEach - } - - go tg.Run(ctx, dcUpdateEach) - pool, err := ants.NewPoolWithFunc(opts.getConcurrency(), func(arg interface{}) { proxy.ServeConn(arg.(essentials.Conn)) //nolint: forcetypeassert diff --git a/mtglib/proxy_opts.go b/mtglib/proxy_opts.go index f78a2f5b8e..53f34348a2 100644 --- a/mtglib/proxy_opts.go +++ b/mtglib/proxy_opts.go @@ -119,10 +119,6 @@ type ProxyOpts struct { // // This is an optional setting DCOverrides map[int][]string - - // DCUpdateEach defines a time duration that is used to fetch a list of - // DCs to use from the Telegram. - DCUpdateEach time.Duration } func (p ProxyOpts) valid() error { From 074c4017f5632624124506f658ebb9a4121771de Mon Sep 17 00:00:00 2001 From: 9seconds Date: Mon, 16 Feb 2026 17:10:06 +0100 Subject: [PATCH 7/9] Formatting by gofumpt --- internal/cli/access.go | 2 +- ipblocklist/files/http.go | 2 +- mtglib/internal/relay/relay.go | 4 ++-- stats/statsd_test.go | 2 +- 4 files changed, 5 insertions(+), 5 deletions(-) diff --git a/internal/cli/access.go b/internal/cli/access.go index 766a793f1c..2e99c98adf 100644 --- a/internal/cli/access.go +++ b/internal/cli/access.go @@ -129,7 +129,7 @@ func (a *Access) getIP(ntw mtglib.Network, protocol string) net.IP { defer func() { io.Copy(io.Discard, resp.Body) //nolint: errcheck - resp.Body.Close() //nolint: errcheck + resp.Body.Close() //nolint: errcheck }() data, err := io.ReadAll(resp.Body) diff --git a/ipblocklist/files/http.go b/ipblocklist/files/http.go index 84bbfbce51..40fb6210e2 100644 --- a/ipblocklist/files/http.go +++ b/ipblocklist/files/http.go @@ -23,7 +23,7 @@ func (h httpFile) Open(ctx context.Context) (io.ReadCloser, error) { if err != nil { if response != nil { io.Copy(io.Discard, response.Body) //nolint: errcheck - response.Body.Close() //nolint: errcheck + response.Body.Close() //nolint: errcheck } return nil, fmt.Errorf("cannot get url %s: %w", h.url, err) diff --git a/mtglib/internal/relay/relay.go b/mtglib/internal/relay/relay.go index ac35cf94d3..060a05cd32 100644 --- a/mtglib/internal/relay/relay.go +++ b/mtglib/internal/relay/relay.go @@ -10,7 +10,7 @@ import ( func Relay(ctx context.Context, log Logger, telegramConn, clientConn essentials.Conn) { defer telegramConn.Close() //nolint: errcheck - defer clientConn.Close() //nolint: errcheck + defer clientConn.Close() //nolint: errcheck ctx, cancel := context.WithCancel(ctx) defer cancel() @@ -18,7 +18,7 @@ func Relay(ctx context.Context, log Logger, telegramConn, clientConn essentials. go func() { <-ctx.Done() telegramConn.Close() //nolint: errcheck - clientConn.Close() //nolint: errcheck + clientConn.Close() //nolint: errcheck }() closeChan := make(chan struct{}) diff --git a/stats/statsd_test.go b/stats/statsd_test.go index a8759bacf6..5587345b00 100644 --- a/stats/statsd_test.go +++ b/stats/statsd_test.go @@ -100,7 +100,7 @@ func (suite *StatsdTestSuite) SetupTest() { func (suite *StatsdTestSuite) TearDownTest() { suite.statsd.Shutdown() - suite.factory.Close() //nolint: errcheck + suite.factory.Close() //nolint: errcheck suite.statsdServer.Close() //nolint: errcheck } From 36546cec2f7b6114c5381ec42dbf507fe16fcfa7 Mon Sep 17 00:00:00 2001 From: 9seconds Date: Mon, 16 Feb 2026 17:18:31 +0100 Subject: [PATCH 8/9] Change default DOH to cloudflarte --- README.md | 2 +- example.config.toml | 4 ++-- internal/cli/simple_run.go | 2 +- mtglib/internal/dc/view.go | 3 --- mtglib/internal/dc/view_test.go | 11 ----------- network/init.go | 2 +- 6 files changed, 5 insertions(+), 19 deletions(-) diff --git a/README.md b/README.md index 4c9f22a96b..67b564359e 100644 --- a/README.md +++ b/README.md @@ -275,7 +275,7 @@ Flags: -b, --tcp-buffer="4KB" Size of TCP buffer to use. -i, --prefer-ip="prefer-ipv6" IP preference. By default we prefer IPv6 with fallback to IPv4. -p, --domain-fronting-port=443 A port to access for domain fronting. - -n, --doh-ip=9.9.9.9 IP address of DNS-over-HTTP to use. + -n, --doh-ip=1.1.1.1 IP address of DNS-over-HTTP to use. -t, --timeout=10s Network timeout to use -a, --antireplay-cache-size="1MB" A size of anti-replay cache to use. ``` diff --git a/example.config.toml b/example.config.toml index ad402ba6e2..eb2c62c3db 100644 --- a/example.config.toml +++ b/example.config.toml @@ -93,8 +93,8 @@ ips = ["127.0.0.1:443"] # resolver of the operating system and uses DOH instead. This is a host # it has to access. # -# By default we use Quad9. -doh-ip = "9.9.9.9" +# By default we use Cloudflare. +doh-ip = "1.1.1.1" # mtg can work via proxies (for now, we support only socks5). Proxy # configuration is done via list. So, you can specify many proxies diff --git a/internal/cli/simple_run.go b/internal/cli/simple_run.go index 02d6dc3328..53deb613e9 100644 --- a/internal/cli/simple_run.go +++ b/internal/cli/simple_run.go @@ -18,7 +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 - DOHIP net.IP `kong:"name='doh-ip',short='n',default='9.9.9.9',help='IP address of DNS-over-HTTP to use.'"` //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 AntiReplayCacheSize string `kong:"name='antireplay-cache-size',short='a',default='1MB',help='A size of anti-replay cache to use.'"` //nolint: lll diff --git a/mtglib/internal/dc/view.go b/mtglib/internal/dc/view.go index f4ef7d9850..efee1c031b 100644 --- a/mtglib/internal/dc/view.go +++ b/mtglib/internal/dc/view.go @@ -2,13 +2,11 @@ package dc type dcView struct { overrides dcAddrSet - collected dcAddrSet } func (d dcView) getV4(dc int) []Addr { addrs := d.overrides.getV4(dc) addrs = append(addrs, defaultDCOverridesAddrSet.getV4(dc)...) - // addrs = append(addrs, d.collected.getV4(dc)...) addrs = append(addrs, defaultDCAddrSet.getV4(dc)...) return addrs @@ -17,7 +15,6 @@ func (d dcView) getV4(dc int) []Addr { func (d dcView) getV6(dc int) []Addr { addrs := d.overrides.getV6(dc) addrs = append(addrs, defaultDCOverridesAddrSet.getV6(dc)...) - // addrs = append(addrs, d.collected.getV6(dc)...) addrs = append(addrs, defaultDCAddrSet.getV6(dc)...) return addrs diff --git a/mtglib/internal/dc/view_test.go b/mtglib/internal/dc/view_test.go index 842c476ff9..74d46cb6de 100644 --- a/mtglib/internal/dc/view_test.go +++ b/mtglib/internal/dc/view_test.go @@ -31,13 +31,6 @@ func (suite *ViewTestSuite) SetupSuite() { }, }, }, - collected: dcAddrSet{ - v4: map[int][]Addr{ - 1: { - {Network: "tcp4", Address: "127.1.0.1:443"}, - }, - }, - }, } } @@ -54,10 +47,6 @@ func (suite *ViewTestSuite) TestGetV4() { {"tcp4", "149.154.167.51:443"}, {"tcp4", "95.161.76.100:443"}, }, - 1: { - {"tcp4", "127.1.0.1:443"}, - {"tcp4", "149.154.175.50:443"}, - }, } for dc, addresses := range testData { diff --git a/network/init.go b/network/init.go index 52831c25e7..3baa8b0193 100644 --- a/network/init.go +++ b/network/init.go @@ -63,7 +63,7 @@ const ( // DefaultDOHHostname defines a default IP address for DOH host. Since mtg is // simple, please pass IP address here. We do not have bootstrap servers here // embedded. - DefaultDOHHostname = "9.9.9.9" + DefaultDOHHostname = "1.1.1.1" // DNSTimeout defines a timeout for DNS queries. DNSTimeout = 5 * time.Second From f83ee173614f8f08162509abb46a27c9248e8111 Mon Sep 17 00:00:00 2001 From: 9seconds Date: Mon, 16 Feb 2026 17:30:11 +0100 Subject: [PATCH 9/9] Fix test --- internal/config/type_dc_test.go | 21 +++++++++++---------- 1 file changed, 11 insertions(+), 10 deletions(-) diff --git a/internal/config/type_dc_test.go b/internal/config/type_dc_test.go index b51229c999..ebda9a2bbb 100644 --- a/internal/config/type_dc_test.go +++ b/internal/config/type_dc_test.go @@ -2,6 +2,7 @@ package config_test import ( "encoding/json" + "strconv" "testing" "github.com/9seconds/mtg/v2/internal/config" @@ -39,19 +40,19 @@ func (suite *TypeDCTestSuite) TestUnmarshalFail() { } func (suite *TypeDCTestSuite) TestUnmarshalOk() { - testData := map[string]int{ - "1": 1, - "-1": 1, - "203": 203, + testData := map[int]int{ + 1: 1, + -1: 1, + 203: 203, } for value, expected := range testData { - data, err := json.Marshal(map[string]string{ + data, err := json.Marshal(map[string]int{ "value": value, }) suite.NoError(err) - suite.T().Run(value, func(t *testing.T) { + suite.T().Run(strconv.Itoa(value), func(t *testing.T) { testStruct := &typeDCTestStruct{} assert.NoError(t, json.Unmarshal(data, testStruct)) @@ -62,9 +63,9 @@ func (suite *TypeDCTestSuite) TestUnmarshalOk() { } func (suite *TypeDCTestSuite) TestMarshalOk() { - testData := map[string]string{ - "1": "1", - "203": "203", + testData := map[string]int{ + "1": 1, + "203": 203, } for k, v := range testData { @@ -79,7 +80,7 @@ func (suite *TypeDCTestSuite) TestMarshalOk() { data, err := json.Marshal(testStruct) assert.NoError(t, err) - expectedJSON, err := json.Marshal(map[string]string{ + expectedJSON, err := json.Marshal(map[string]int{ "value": expected, }) assert.NoError(t, err)