Add implementation of telegram dialer

This commit is contained in:
9seconds
2021-03-22 12:30:23 +03:00
parent 69203f3e23
commit 7108fe99ec
3 changed files with 131 additions and 5 deletions
+53
View File
@@ -0,0 +1,53 @@
package telegram
import (
"context"
"net"
)
type preferIP uint8
const (
preferIPOnlyIPv4 preferIP = iota
preferIPOnlyIPv6
preferIPPreferIPv4
preferIPPreferIPv6
)
type tgAddr struct {
network string
address string
}
// https://github.com/telegramdesktop/tdesktop/blob/master/Telegram/SourceFiles/mtproto/mtproto_dc_options.cpp#L30
var (
v4Addresses = [5][]tgAddr{
{
{network: "tcp4", address: "149.154.175.50:443"},
},
{
{network: "tcp4", address: "149.154.167.51:443"},
{network: "tcp4", address: "95.161.76.100:443"},
},
{
{network: "tcp4", address: "149.154.175.100:443"},
},
{
{network: "tcp4", address: "149.154.167.91:443"},
},
{
{network: "tcp4", address: "149.154.171.5"},
},
}
v6Addresses = [5]tgAddr{
{network: "tcp6", address: "[2001:b28:f23d:f001::a]:443"},
{network: "tcp6", address: "[2001:67c:04e8:f002::a]:443"},
{network: "tcp6", address: "[2001:b28:f23d:f003::a]:443"},
{network: "tcp6", address: "[2001:67c:04e8:f004::a]:443"},
{network: "tcp6", address: "[2001:b28:f23f:f005::a]:443"},
}
)
type Dialer interface {
DialContext(ctx context.Context, network, address string) (net.Conn, error)
}
+75
View File
@@ -0,0 +1,75 @@
package telegram
import (
"context"
"fmt"
"math/rand"
"net"
"strings"
)
type Telegram struct {
dialer Dialer
preferIP preferIP
}
func (t Telegram) Dial(ctx context.Context, dc int) (net.Conn, error) {
if dc < 0 || dc > 4 {
return nil, fmt.Errorf("do not know how to dial to %d", dc)
}
var addresses []tgAddr
if t.preferIP == preferIPOnlyIPv6 {
addresses = []tgAddr{v6Addresses[dc]}
} else {
addresses = append(addresses, v4Addresses[dc]...)
rand.Shuffle(len(addresses), func(i, j int) {
addresses[i], addresses[j] = addresses[j], addresses[i]
})
}
switch t.preferIP {
case preferIPPreferIPv4:
addresses = append(addresses, v6Addresses[dc])
case preferIPPreferIPv6:
addresses = append([]tgAddr{v6Addresses[dc]}, addresses...)
case preferIPOnlyIPv4, preferIPOnlyIPv6:
}
var (
conn net.Conn
err error
)
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 NewTelegramDialer(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)
}
return &Telegram{
dialer: dialer,
preferIP: pref,
}, nil
}
+3 -5
View File
@@ -43,11 +43,9 @@ func (n *network) DialContext(ctx context.Context, protocol, address string) (ne
return nil, fmt.Errorf("cannot resolve dns names: %w", err) return nil, fmt.Errorf("cannot resolve dns names: %w", err)
} }
if len(ips) > 1 { rand.Shuffle(len(ips), func(i, j int) {
rand.Shuffle(len(ips), func(i, j int) { ips[i], ips[j] = ips[j], ips[i]
ips[i], ips[j] = ips[j], ips[i] })
})
}
var conn net.Conn var conn net.Conn
for _, v := range ips { for _, v := range ips {