request_handler.go 2.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107
  1. package socks
  2. import (
  3. "fmt"
  4. "io"
  5. "strings"
  6. )
  7. // RequestHandler is the functions needed to handle a SOCKS5 command
  8. type RequestHandler interface {
  9. Handle(*Request, io.ReadWriter) error
  10. }
  11. // StandardRequestHandler implements the base socks5 command processing
  12. type StandardRequestHandler struct {
  13. dialer Dialer
  14. }
  15. // NewRequestHandler creates a standard SOCKS5 request handler
  16. // This handles the SOCKS5 commands and proxies them to their destination
  17. func NewRequestHandler(dialer Dialer) RequestHandler {
  18. return &StandardRequestHandler{
  19. dialer: dialer,
  20. }
  21. }
  22. // Handle processes and responds to socks5 commands
  23. func (h *StandardRequestHandler) Handle(req *Request, conn io.ReadWriter) error {
  24. switch req.Command {
  25. case connectCommand:
  26. return h.handleConnect(conn, req)
  27. case bindCommand:
  28. return h.handleBind(conn, req)
  29. case associateCommand:
  30. return h.handleAssociate(conn, req)
  31. default:
  32. if err := sendReply(conn, commandNotSupported, nil); err != nil {
  33. return fmt.Errorf("Failed to send reply: %v", err)
  34. }
  35. return fmt.Errorf("Unsupported command: %v", req.Command)
  36. }
  37. }
  38. // handleConnect is used to handle a connect command
  39. func (h *StandardRequestHandler) handleConnect(conn io.ReadWriter, req *Request) error {
  40. target, localAddr, err := h.dialer.Dial(req.DestAddr.Address())
  41. if err != nil {
  42. msg := err.Error()
  43. resp := hostUnreachable
  44. if strings.Contains(msg, "refused") {
  45. resp = connectionRefused
  46. } else if strings.Contains(msg, "network is unreachable") {
  47. resp = networkUnreachable
  48. }
  49. if err := sendReply(conn, resp, nil); err != nil {
  50. return fmt.Errorf("Failed to send reply: %v", err)
  51. }
  52. return fmt.Errorf("Connect to %v failed: %v", req.DestAddr, err)
  53. }
  54. defer target.Close()
  55. // Send success
  56. if err := sendReply(conn, successReply, localAddr); err != nil {
  57. return fmt.Errorf("Failed to send reply: %v", err)
  58. }
  59. // Start proxying
  60. proxyDone := make(chan error, 2)
  61. go func() {
  62. _, e := io.Copy(target, req.bufConn)
  63. proxyDone <- e
  64. }()
  65. go func() {
  66. _, e := io.Copy(conn, target)
  67. proxyDone <- e
  68. }()
  69. // Wait for both
  70. for i := 0; i < 2; i++ {
  71. e := <-proxyDone
  72. if e != nil {
  73. return e
  74. }
  75. }
  76. return nil
  77. }
  78. // handleBind is used to handle a bind command
  79. // TODO: Support bind command
  80. func (h *StandardRequestHandler) handleBind(conn io.ReadWriter, req *Request) error {
  81. if err := sendReply(conn, commandNotSupported, nil); err != nil {
  82. return fmt.Errorf("Failed to send reply: %v", err)
  83. }
  84. return nil
  85. }
  86. // handleAssociate is used to handle a connect command
  87. // TODO: Support associate command
  88. func (h *StandardRequestHandler) handleAssociate(conn io.ReadWriter, req *Request) error {
  89. if err := sendReply(conn, commandNotSupported, nil); err != nil {
  90. return fmt.Errorf("Failed to send reply: %v", err)
  91. }
  92. return nil
  93. }