Documentation
¶
Overview ¶
Package middleproxy implements the client side of Telegram's MTProto middle proxy (RPC) protocol. It is used to carry a client's traffic through a Telegram middle proxy while advertising a 16-byte ad_tag, which makes a sponsored channel appear in the client. The wire protocol constants and layouts are ported byte-for-byte from 9seconds/mtg v1 (the last mtg version that shipped middle-proxy support) and cross-checked against Telegram's official mtproto-proxy.
Index ¶
Constants ¶
This section is empty.
Variables ¶
This section is empty.
Functions ¶
This section is empty.
Types ¶
type DialParams ¶
type DialParams struct {
DC int
ClientAddr *net.TCPAddr
PublicIPv4 net.IP
PublicIPv6 net.IP
// PaddedIntermediate says the client's transport is 0xdddddddd, the only
// one whose frames carry 0-15 bytes of trailing padding. It drives RPC_F_PAD
// and the alignment trim, both of which are a lie for plain intermediate.
PaddedIntermediate bool
AdvertisedPort int
AdTag [adTagLength]byte
}
DialParams carries the addressing the proxy contributes to a middle-proxy dial. ClientAddr is the real client's address (put in RPC_PROXY_REQ). PublicIPv4 and PublicIPv6 optionally override the address the middle proxy sees as our source (needed on multi-homed hosts); the family matching the dialed socket is used. AdvertisedPort is the port reported as ours in RPC_PROXY_REQ.
type Dialer ¶
type Dialer interface {
Dial(network, address string) (essentials.Conn, error)
}
Dialer is the subset of mtglib.Network the manager needs to reach a middle proxy. It is declared here to keep this internal package free of an import cycle back to mtglib.
type Logger ¶
Logger is the minimal logging surface used by the background refresh loop. mtglib.Logger satisfies it.
type Manager ¶
type Manager struct {
// contains filtered or unexported fields
}
Manager fetches and caches Telegram's proxy secret and middle-proxy address lists, and dials RPC proxy streams that carry an ad_tag. It fetches lazily on first use (so a proxy without advertising never touches the network) and then refreshes hourly. It is safe for concurrent use.
Exactly one fetch is ever in a client's path: the first. Every later one runs in the background, and a dial that arrives while the manager is not ready is told so at once and takes the direct route. This is the whole design: a fetch is three sequential HTTP requests of up to fetchTimeout each against a host the network may well be blocking, and an earlier version queued every ad-tagged dial behind it, so a proxy whose ad-tag was configured on a network that could not reach core.telegram.org held every client for up to ninety seconds, one after another, before letting each one through direct.
func NewManager ¶
func NewManager(ctx context.Context, httpClient *http.Client, logger Logger, preferIP string) *Manager
NewManager builds a Manager. httpClient should be built with the proxy's network settings (e.g. mtglib.Network.MakeHTTPClient) so DNS and upstream proxying apply. preferIP is the proxy's IP connectivity preference. The refresh loop and any in-flight fetches stop when ctx is cancelled.
func (*Manager) DialProxyStream ¶
func (m *Manager) DialProxyStream(dialer Dialer, params DialParams) (essentials.Conn, net.IP, error)
DialProxyStream connects to a middle proxy for params.DC, performs the RPC handshake, and returns an essentials.Conn that transparently carries the client's traffic wrapped in RPC_PROXY_REQ with the ad_tag. It also returns the middle-proxy IP for the connected-to-DC event.