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.

shadowsocks.go 1.7KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475
  1. package network
  2. import (
  3. "context"
  4. "encoding/base64"
  5. "fmt"
  6. "net"
  7. "net/url"
  8. "strings"
  9. "time"
  10. shadowsocks "github.com/shadowsocks/go-shadowsocks2/core"
  11. "golang.org/x/net/proxy"
  12. )
  13. type shadowsocksDialer struct {
  14. Dialer
  15. cipher shadowsocks.StreamConnCipher
  16. }
  17. func (s *shadowsocksDialer) Dial(network, address string) (net.Conn, error) {
  18. return s.DialContext(context.Background(), network, address)
  19. }
  20. func (s *shadowsocksDialer) DialContext(ctx context.Context,
  21. network, address string) (net.Conn, error) {
  22. conn, err := s.Dialer.DialContext(ctx, network, address)
  23. if err != nil {
  24. return nil, err // nolint: wrapcheck
  25. }
  26. return s.cipher.StreamConn(conn), nil
  27. }
  28. func NewShadowsocksDialer(proxyURL *url.URL,
  29. timeout time.Duration, bufferSize int) (Dialer, error) {
  30. username := proxyURL.User.Username()
  31. decoded, err := base64.RawURLEncoding.DecodeString(username)
  32. if err != nil {
  33. return nil, fmt.Errorf("cannot decode payload: %w", err)
  34. }
  35. chunks := strings.SplitN(string(decoded), ":", 2)
  36. if len(chunks) != 2 {
  37. return nil, fmt.Errorf("incorrect payload %s", username)
  38. }
  39. cipher, err := shadowsocks.PickCipher(chunks[0], nil, chunks[1])
  40. if err != nil {
  41. return nil, fmt.Errorf("cannot initialize shadowsocks cipher: %w", err)
  42. }
  43. socks5URL := *proxyURL
  44. socks5URL.Scheme = "socks5"
  45. socks5URL.User = nil
  46. dialer, err := NewDefaultDialer(timeout, bufferSize)
  47. if err != nil {
  48. return nil, fmt.Errorf("cannot initialize a base dialer: %w", err)
  49. }
  50. ssDialer := &shadowsocksDialer{
  51. Dialer: dialer,
  52. cipher: cipher,
  53. }
  54. rv, err := proxy.FromURL(&socks5URL, ssDialer)
  55. if err != nil {
  56. return nil, fmt.Errorf("cannot initialize ss proxy dialer: %w", err)
  57. }
  58. return rv.(Dialer), nil
  59. }