network.go 4.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169
  1. package client
  2. import (
  3. "bytes"
  4. "encoding/binary"
  5. "fmt"
  6. "gopkg.in/jcmturner/gokrb5.v1/iana/errorcode"
  7. "gopkg.in/jcmturner/gokrb5.v1/messages"
  8. "io"
  9. "math/rand"
  10. "net"
  11. "time"
  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. var kdcs []string
  17. for _, r := range cl.Config.Realms {
  18. if r.Realm == realm {
  19. kdcs = r.KDC
  20. break
  21. }
  22. }
  23. if len(kdcs) < 1 {
  24. return rb, fmt.Errorf("No KDCs defined in configuration for realm: %v", cl.Config.LibDefaults.DefaultRealm)
  25. }
  26. var kdc string
  27. if len(kdcs) > 1 {
  28. //Select one of the KDCs at random
  29. kdc = kdcs[rand.Intn(len(kdcs))]
  30. } else {
  31. kdc = kdcs[0]
  32. }
  33. if cl.Config.LibDefaults.UDPPreferenceLimit == 1 {
  34. //1 means we should always use TCP
  35. rb, errtcp := sendTCP(kdc, b)
  36. if errtcp != nil {
  37. if e, ok := errtcp.(messages.KRBError); ok {
  38. return rb, e
  39. }
  40. return rb, fmt.Errorf("Failed to communicate with KDC %v via TCP (%v)", kdc, errtcp)
  41. }
  42. if len(rb) < 1 {
  43. return rb, fmt.Errorf("No response data from KDC %v", kdc)
  44. }
  45. return rb, nil
  46. }
  47. if len(b) <= cl.Config.LibDefaults.UDPPreferenceLimit {
  48. //Try UDP first, TCP second
  49. rb, errudp := sendUDP(kdc, b)
  50. if errudp != nil {
  51. if e, ok := errudp.(messages.KRBError); ok && e.ErrorCode != errorcode.KRB_ERR_RESPONSE_TOO_BIG {
  52. // Got a KRBError from KDC
  53. // If this is not a KRB_ERR_RESPONSE_TOO_BIG we will return immediately otherwise will try TCP.
  54. return rb, e
  55. }
  56. // Try TCP
  57. r, errtcp := sendTCP(kdc, b)
  58. if errtcp != nil {
  59. if e, ok := errtcp.(messages.KRBError); ok {
  60. // Got a KRBError
  61. return r, e
  62. }
  63. return r, fmt.Errorf("Failed to communicate with KDC %v. Attempts made with UDP (%v) and then TCP (%v)", kdc, errudp, errtcp)
  64. }
  65. rb = r
  66. }
  67. if len(rb) < 1 {
  68. return rb, fmt.Errorf("No response data from KDC %v", kdc)
  69. }
  70. return rb, nil
  71. }
  72. //Try TCP first, UDP second
  73. rb, errtcp := sendTCP(kdc, b)
  74. if errtcp != nil {
  75. if e, ok := errtcp.(messages.KRBError); ok {
  76. // Got a KRBError from KDC so returning and not trying UDP.
  77. return rb, e
  78. }
  79. rb, errudp := sendUDP(kdc, b)
  80. if errudp != nil {
  81. if e, ok := errudp.(messages.KRBError); ok {
  82. // Got a KRBError
  83. return rb, e
  84. }
  85. return rb, fmt.Errorf("Failed to communicate with KDC %v. Attempts made with TCP (%v) and then UDP (%v)", kdc, errtcp, errudp)
  86. }
  87. }
  88. if len(rb) < 1 {
  89. return rb, fmt.Errorf("No response data from KDC %v", kdc)
  90. }
  91. return rb, nil
  92. }
  93. // Send the bytes to the KDC over UDP.
  94. func sendUDP(kdc string, b []byte) ([]byte, error) {
  95. var r []byte
  96. udpAddr, err := net.ResolveUDPAddr("udp", kdc)
  97. if err != nil {
  98. return r, fmt.Errorf("Error resolving KDC address: %v", err)
  99. }
  100. conn, err := net.DialUDP("udp", nil, udpAddr)
  101. if err != nil {
  102. return r, fmt.Errorf("Error establishing connection to KDC: %v", err)
  103. }
  104. defer conn.Close()
  105. conn.SetDeadline(time.Now().Add(time.Duration(5 * time.Second)))
  106. _, err = conn.Write(b)
  107. if err != nil {
  108. return r, fmt.Errorf("Error sending to KDC: %v", err)
  109. }
  110. udpbuf := make([]byte, 4096)
  111. n, _, err := conn.ReadFrom(udpbuf)
  112. r = udpbuf[:n]
  113. if err != nil {
  114. return r, fmt.Errorf("Sending over UDP failed: %v", err)
  115. }
  116. return checkForKRBError(r)
  117. }
  118. // Send the bytes to the KDC over TCP.
  119. func sendTCP(kdc string, b []byte) ([]byte, error) {
  120. var r []byte
  121. tcpAddr, err := net.ResolveTCPAddr("tcp", kdc)
  122. if err != nil {
  123. return r, fmt.Errorf("Error resolving KDC address: %v", err)
  124. }
  125. conn, err := net.DialTCP("tcp", nil, tcpAddr)
  126. if err != nil {
  127. return r, fmt.Errorf("Error establishing connection to KDC: %v", err)
  128. }
  129. defer conn.Close()
  130. conn.SetDeadline(time.Now().Add(time.Duration(5 * time.Second)))
  131. /*
  132. RFC https://tools.ietf.org/html/rfc4120#section-7.2.2
  133. Each request (KRB_KDC_REQ) and response (KRB_KDC_REP or KRB_ERROR)
  134. sent over the TCP stream is preceded by the length of the request as
  135. 4 octets in network byte order. The high bit of the length is
  136. reserved for future expansion and MUST currently be set to zero. If
  137. a KDC that does not understand how to interpret a set high bit of the
  138. length encoding receives a request with the high order bit of the
  139. length set, it MUST return a KRB-ERROR message with the error
  140. KRB_ERR_FIELD_TOOLONG and MUST close the TCP stream.
  141. NB: network byte order == big endian
  142. */
  143. var buf bytes.Buffer
  144. binary.Write(&buf, binary.BigEndian, uint32(len(b)))
  145. b = append(buf.Bytes(), b...)
  146. _, err = conn.Write(b)
  147. if err != nil {
  148. return r, fmt.Errorf("Error sending to KDC: %v", err)
  149. }
  150. var rBuf bytes.Buffer
  151. io.Copy(&rBuf, conn)
  152. r = rBuf.Bytes()
  153. return checkForKRBError(r[4:])
  154. }
  155. func checkForKRBError(b []byte) ([]byte, error) {
  156. var KRBErr messages.KRBError
  157. if err := KRBErr.Unmarshal(b); err == nil {
  158. return b, KRBErr
  159. }
  160. return b, nil
  161. }