socks.go 3.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151
  1. // Package socks contains protocol definition and io lib for SOCKS5 protocol
  2. package socks
  3. import (
  4. "encoding/binary"
  5. "fmt"
  6. "io"
  7. )
  8. const (
  9. socksVersion = uint8(5)
  10. )
  11. // Authentication request header of Socks5 protocol
  12. type Socks5AuthenticationRequest struct {
  13. version byte
  14. nMethods byte
  15. authMethods [256]byte
  16. }
  17. func ReadAuthentication(reader io.Reader) (auth Socks5AuthenticationRequest, err error) {
  18. buffer := make([]byte, 2)
  19. nBytes, err := reader.Read(buffer)
  20. if err != nil {
  21. return
  22. }
  23. if nBytes < 2 {
  24. err = fmt.Errorf("Expected 2 bytes read, but actaully %d bytes read", nBytes)
  25. return
  26. }
  27. auth.version = buffer[0]
  28. if auth.version != socksVersion {
  29. err = fmt.Errorf("Unknown SOCKS version %d", auth.version)
  30. return
  31. }
  32. auth.nMethods = buffer[1]
  33. if auth.nMethods <= 0 {
  34. err = fmt.Errorf("Zero length of authentication methods")
  35. return
  36. }
  37. buffer = make([]byte, auth.nMethods)
  38. nBytes, err = reader.Read(buffer)
  39. if err != nil {
  40. return
  41. }
  42. if nBytes != int(auth.nMethods) {
  43. err = fmt.Errorf("Unmatching number of auth methods, expecting %d, but got %d", auth.nMethods, nBytes)
  44. return
  45. }
  46. copy(auth.authMethods[:nBytes], buffer)
  47. return
  48. }
  49. type Socks5AuthenticationResponse struct {
  50. version byte
  51. authMethod byte
  52. }
  53. func (r *Socks5AuthenticationResponse) ToBytes() []byte {
  54. buffer := make([]byte, 2 /* size of Socks5AuthenticationResponse */)
  55. buffer[0] = r.version
  56. buffer[1] = r.authMethod
  57. return buffer
  58. }
  59. func WriteAuthentication(writer io.Writer, response Socks5AuthenticationResponse) error {
  60. _, err := writer.Write(response.ToBytes())
  61. if err != nil {
  62. return err
  63. }
  64. return nil
  65. }
  66. type Socks5Request struct {
  67. version byte
  68. command byte
  69. addrType byte
  70. ipv4 [4]byte
  71. domain string
  72. ipv6 [16]byte
  73. port uint16
  74. }
  75. func ReadRequest(reader io.Reader) (request *Socks5Request, err error) {
  76. request = new(Socks5Request)
  77. buffer := make([]byte, 4)
  78. nBytes, err := reader.Read(buffer)
  79. if err != nil {
  80. return
  81. }
  82. if nBytes < len(buffer) {
  83. err = fmt.Errorf("Unable to read request.")
  84. return
  85. }
  86. request.version = buffer[0]
  87. request.command = buffer[1]
  88. // buffer[2] is a reserved field
  89. request.addrType = buffer[3]
  90. switch request.addrType {
  91. case 0x01:
  92. nBytes, err = reader.Read(request.ipv4[:])
  93. if err != nil {
  94. return
  95. }
  96. if nBytes != 4 {
  97. err = fmt.Errorf("Unable to read IPv4 address.")
  98. return
  99. }
  100. case 0x03:
  101. buffer = make([]byte, 257)
  102. nBytes, err = reader.Read(buffer)
  103. if err != nil {
  104. return
  105. }
  106. domainLength := buffer[0]
  107. if nBytes != int(domainLength)+1 {
  108. err = fmt.Errorf("Unable to read domain")
  109. return
  110. }
  111. request.domain = string(buffer[1 : domainLength+1])
  112. case 0x04:
  113. nBytes, err = reader.Read(request.ipv6[:])
  114. if err != nil {
  115. return
  116. }
  117. if nBytes != 16 {
  118. err = fmt.Errorf("Unable to read IPv4 address.")
  119. return
  120. }
  121. default:
  122. err = fmt.Errorf("Unexpected address type %d", request.addrType)
  123. return
  124. }
  125. buffer = make([]byte, 2)
  126. nBytes, err = reader.Read(buffer)
  127. if err != nil {
  128. return
  129. }
  130. if nBytes != 2 {
  131. err = fmt.Errorf("Unable to read port.")
  132. return
  133. }
  134. request.port = binary.BigEndian.Uint16(buffer)
  135. return
  136. }