network.go 6.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218
  1. package client
  2. import (
  3. "encoding/binary"
  4. "errors"
  5. "fmt"
  6. "io"
  7. "net"
  8. "strings"
  9. "time"
  10. "github.com/jcmturner/gokrb5/v8/iana/errorcode"
  11. "github.com/jcmturner/gokrb5/v8/messages"
  12. )
  13. // SendToKDC performs network actions to send data to the KDC.
  14. func (cl *Client) sendToKDC(b []byte, realm string) ([]byte, error) {
  15. var rb []byte
  16. if cl.Config.LibDefaults.UDPPreferenceLimit == 1 {
  17. //1 means we should always use TCP
  18. rb, errtcp := cl.sendKDCTCP(realm, b)
  19. if errtcp != nil {
  20. if e, ok := errtcp.(messages.KRBError); ok {
  21. return rb, e
  22. }
  23. return rb, fmt.Errorf("communication error with KDC via TCP: %v", errtcp)
  24. }
  25. return rb, nil
  26. }
  27. if len(b) <= cl.Config.LibDefaults.UDPPreferenceLimit {
  28. //Try UDP first, TCP second
  29. rb, errudp := cl.sendKDCUDP(realm, b)
  30. if errudp != nil {
  31. if e, ok := errudp.(messages.KRBError); ok && e.ErrorCode != errorcode.KRB_ERR_RESPONSE_TOO_BIG {
  32. // Got a KRBError from KDC
  33. // If this is not a KRB_ERR_RESPONSE_TOO_BIG we will return immediately otherwise will try TCP.
  34. return rb, e
  35. }
  36. // Try TCP
  37. r, errtcp := cl.sendKDCTCP(realm, b)
  38. if errtcp != nil {
  39. if e, ok := errtcp.(messages.KRBError); ok {
  40. // Got a KRBError
  41. return r, e
  42. }
  43. return r, fmt.Errorf("failed to communicate with KDC. Attempts made with UDP (%v) and then TCP (%v)", errudp, errtcp)
  44. }
  45. rb = r
  46. }
  47. return rb, nil
  48. }
  49. //Try TCP first, UDP second
  50. rb, errtcp := cl.sendKDCTCP(realm, b)
  51. if errtcp != nil {
  52. if e, ok := errtcp.(messages.KRBError); ok {
  53. // Got a KRBError from KDC so returning and not trying UDP.
  54. return rb, e
  55. }
  56. rb, errudp := cl.sendKDCUDP(realm, b)
  57. if errudp != nil {
  58. if e, ok := errudp.(messages.KRBError); ok {
  59. // Got a KRBError
  60. return rb, e
  61. }
  62. return rb, fmt.Errorf("failed to communicate with KDC. Attempts made with TCP (%v) and then UDP (%v)", errtcp, errudp)
  63. }
  64. }
  65. return rb, nil
  66. }
  67. // sendKDCUDP sends bytes to the KDC via UDP.
  68. func (cl *Client) sendKDCUDP(realm string, b []byte) ([]byte, error) {
  69. var r []byte
  70. _, kdcs, err := cl.Config.GetKDCs(realm, false)
  71. if err != nil {
  72. return r, err
  73. }
  74. r, err = dialSendUDP(kdcs, b)
  75. if err != nil {
  76. return r, err
  77. }
  78. return checkForKRBError(r)
  79. }
  80. // dialSendUDP establishes a UDP connection to a KDC.
  81. func dialSendUDP(kdcs map[int]string, b []byte) ([]byte, error) {
  82. var errs []string
  83. for i := 1; i <= len(kdcs); i++ {
  84. udpAddr, err := net.ResolveUDPAddr("udp", kdcs[i])
  85. if err != nil {
  86. errs = append(errs, fmt.Sprintf("error resolving KDC address: %v", err))
  87. continue
  88. }
  89. conn, err := net.DialTimeout("udp", udpAddr.String(), 5*time.Second)
  90. if err != nil {
  91. errs = append(errs, fmt.Sprintf("error setting dial timeout on connection to %s: %v", kdcs[i], err))
  92. continue
  93. }
  94. if err := conn.SetDeadline(time.Now().Add(5 * time.Second)); err != nil {
  95. errs = append(errs, fmt.Sprintf("error setting deadline on connection to %s: %v", kdcs[i], err))
  96. continue
  97. }
  98. // conn is guaranteed to be a UDPConn
  99. rb, err := sendUDP(conn.(*net.UDPConn), b)
  100. if err != nil {
  101. errs = append(errs, fmt.Sprintf("error sneding to %s: %v", kdcs[i], err))
  102. continue
  103. }
  104. return rb, nil
  105. }
  106. return nil, fmt.Errorf("error sending to a KDC: %s", strings.Join(errs, "; "))
  107. }
  108. // sendUDP sends bytes to connection over UDP.
  109. func sendUDP(conn *net.UDPConn, b []byte) ([]byte, error) {
  110. var r []byte
  111. defer conn.Close()
  112. _, err := conn.Write(b)
  113. if err != nil {
  114. return r, fmt.Errorf("error sending to (%s): %v", conn.RemoteAddr().String(), err)
  115. }
  116. udpbuf := make([]byte, 4096)
  117. n, _, err := conn.ReadFrom(udpbuf)
  118. r = udpbuf[:n]
  119. if err != nil {
  120. return r, fmt.Errorf("sending over UDP failed to %s: %v", conn.RemoteAddr().String(), err)
  121. }
  122. if len(r) < 1 {
  123. return r, fmt.Errorf("no response data from %s", conn.RemoteAddr().String())
  124. }
  125. return r, nil
  126. }
  127. // sendKDCTCP sends bytes to the KDC via TCP.
  128. func (cl *Client) sendKDCTCP(realm string, b []byte) ([]byte, error) {
  129. var r []byte
  130. _, kdcs, err := cl.Config.GetKDCs(realm, true)
  131. if err != nil {
  132. return r, err
  133. }
  134. r, err = dialSendTCP(kdcs, b)
  135. if err != nil {
  136. return r, err
  137. }
  138. return checkForKRBError(r)
  139. }
  140. // dialKDCTCP establishes a TCP connection to a KDC.
  141. func dialSendTCP(kdcs map[int]string, b []byte) ([]byte, error) {
  142. var errs []string
  143. for i := 1; i <= len(kdcs); i++ {
  144. tcpAddr, err := net.ResolveTCPAddr("tcp", kdcs[i])
  145. if err != nil {
  146. errs = append(errs, fmt.Sprintf("error resolving KDC address: %v", err))
  147. continue
  148. }
  149. conn, err := net.DialTimeout("tcp", tcpAddr.String(), 5*time.Second)
  150. if err != nil {
  151. errs = append(errs, fmt.Sprintf("error setting dial timeout on connection to %s: %v", kdcs[i], err))
  152. continue
  153. }
  154. if err := conn.SetDeadline(time.Now().Add(5 * time.Second)); err != nil {
  155. errs = append(errs, fmt.Sprintf("error setting deadline on connection to %s: %v", kdcs[i], err))
  156. continue
  157. }
  158. // conn is guaranteed to be a TCPConn
  159. rb, err := sendTCP(conn.(*net.TCPConn), b)
  160. if err != nil {
  161. errs = append(errs, fmt.Sprintf("error sneding to %s: %v", kdcs[i], err))
  162. continue
  163. }
  164. return rb, nil
  165. }
  166. return nil, errors.New("error in getting a TCP connection to any of the KDCs")
  167. }
  168. // sendTCP sends bytes to connection over TCP.
  169. func sendTCP(conn *net.TCPConn, b []byte) ([]byte, error) {
  170. defer conn.Close()
  171. var r []byte
  172. // RFC 4120 7.2.2 specifies the first 4 bytes indicate the length of the message in big endian order.
  173. hb := make([]byte, 4, 4)
  174. binary.BigEndian.PutUint32(hb, uint32(len(b)))
  175. b = append(hb, b...)
  176. _, err := conn.Write(b)
  177. if err != nil {
  178. return r, fmt.Errorf("error sending to KDC (%s): %v", conn.RemoteAddr().String(), err)
  179. }
  180. sh := make([]byte, 4, 4)
  181. _, err = conn.Read(sh)
  182. if err != nil {
  183. return r, fmt.Errorf("error reading response size header: %v", err)
  184. }
  185. s := binary.BigEndian.Uint32(sh)
  186. rb := make([]byte, s, s)
  187. _, err = io.ReadFull(conn, rb)
  188. if err != nil {
  189. return r, fmt.Errorf("error reading response: %v", err)
  190. }
  191. if len(rb) < 1 {
  192. return r, fmt.Errorf("no response data from KDC %s", conn.RemoteAddr().String())
  193. }
  194. return rb, nil
  195. }
  196. // checkForKRBError checks if the response bytes from the KDC are a KRBError.
  197. func checkForKRBError(b []byte) ([]byte, error) {
  198. var KRBErr messages.KRBError
  199. if err := KRBErr.Unmarshal(b); err == nil {
  200. return b, KRBErr
  201. }
  202. return b, nil
  203. }