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

conn.go 2.7KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121
  1. package wrappers
  2. import (
  3. "net"
  4. "time"
  5. "go.uber.org/zap"
  6. "github.com/9seconds/mtg/stats"
  7. )
  8. // ConnPurpose is intended to be identifier of connection purpose. We
  9. // sometimes want to treat client/telegram connection differently (for
  10. // logging for example).
  11. type ConnPurpose uint8
  12. func (c ConnPurpose) String() string {
  13. switch c {
  14. case ConnPurposeClient:
  15. return "client"
  16. case ConnPurposeTelegram:
  17. return "telegram"
  18. }
  19. return ""
  20. }
  21. // ConnPurpose* define different connection types.
  22. const (
  23. ConnPurposeClient = iota
  24. ConnPurposeTelegram
  25. )
  26. const (
  27. connTimeoutRead = 2 * time.Minute
  28. connTimeoutWrite = 2 * time.Minute
  29. )
  30. // Conn is a basic wrapper for net.Conn providing the most low-level
  31. // logic and management as possible.
  32. type Conn struct {
  33. connID string
  34. conn net.Conn
  35. logger *zap.SugaredLogger
  36. publicIPv4 net.IP
  37. publicIPv6 net.IP
  38. }
  39. func (c *Conn) Write(p []byte) (int, error) {
  40. c.conn.SetWriteDeadline(time.Now().Add(connTimeoutWrite)) // nolint: errcheck
  41. n, err := c.conn.Write(p)
  42. c.logger.Debugw("Write to stream", "bytes", n, "error", err)
  43. stats.EgressTraffic(n)
  44. return n, err
  45. }
  46. func (c *Conn) Read(p []byte) (int, error) {
  47. c.conn.SetReadDeadline(time.Now().Add(connTimeoutRead)) // nolint: errcheck
  48. n, err := c.conn.Read(p)
  49. c.logger.Debugw("Read from stream", "bytes", n, "error", err)
  50. stats.IngressTraffic(n)
  51. return n, err
  52. }
  53. // Close closes underlying net.Conn instance.
  54. func (c *Conn) Close() error {
  55. defer c.logger.Debugw("Close connection")
  56. return c.conn.Close()
  57. }
  58. // Logger returns an instance of the logger for this wrapper.
  59. func (c *Conn) Logger() *zap.SugaredLogger {
  60. return c.logger
  61. }
  62. // LocalAddr returns local address of the underlying net.Conn.
  63. func (c *Conn) LocalAddr() *net.TCPAddr {
  64. addr := c.conn.LocalAddr().(*net.TCPAddr)
  65. newAddr := *addr
  66. if c.RemoteAddr().IP.To4() != nil {
  67. if c.publicIPv4 != nil {
  68. newAddr.IP = c.publicIPv4
  69. }
  70. } else if c.publicIPv6 != nil {
  71. newAddr.IP = c.publicIPv6
  72. }
  73. return &newAddr
  74. }
  75. // RemoteAddr returns remote address of the underlying net.Conn.
  76. func (c *Conn) RemoteAddr() *net.TCPAddr {
  77. return c.conn.RemoteAddr().(*net.TCPAddr)
  78. }
  79. // NewConn initializes Conn wrapper for net.Conn.
  80. func NewConn(conn net.Conn, connID string, purpose ConnPurpose, publicIPv4, publicIPv6 net.IP) StreamReadWriteCloser {
  81. logger := zap.S().With(
  82. "connection_id", connID,
  83. "local_address", conn.LocalAddr(),
  84. "remote_address", conn.RemoteAddr(),
  85. "purpose", purpose,
  86. ).Named("conn")
  87. wrapper := Conn{
  88. logger: logger,
  89. connID: connID,
  90. conn: conn,
  91. publicIPv4: publicIPv4,
  92. publicIPv6: publicIPv6,
  93. }
  94. wrapper.logger = logger.With("faked_local_addr", wrapper.LocalAddr())
  95. return &wrapper
  96. }