nathole.go 6.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263
  1. // Copyright 2023 The frp Authors
  2. //
  3. // Licensed under the Apache License, Version 2.0 (the "License");
  4. // you may not use this file except in compliance with the License.
  5. // You may obtain a copy of the License at
  6. //
  7. // http://www.apache.org/licenses/LICENSE-2.0
  8. //
  9. // Unless required by applicable law or agreed to in writing, software
  10. // distributed under the License is distributed on an "AS IS" BASIS,
  11. // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  12. // See the License for the specific language governing permissions and
  13. // limitations under the License.
  14. package nathole
  15. import (
  16. "bytes"
  17. "fmt"
  18. "net"
  19. "sync"
  20. "time"
  21. "github.com/fatedier/golib/crypto"
  22. "github.com/fatedier/golib/errors"
  23. "github.com/fatedier/golib/pool"
  24. "github.com/fatedier/frp/pkg/msg"
  25. "github.com/fatedier/frp/pkg/util/log"
  26. "github.com/fatedier/frp/pkg/util/util"
  27. )
  28. // NatHoleTimeout seconds.
  29. var NatHoleTimeout int64 = 10
  30. func NewTransactionID() string {
  31. id, _ := util.RandID()
  32. return fmt.Sprintf("%d%s", time.Now().Unix(), id)
  33. }
  34. type SidRequest struct {
  35. Sid string
  36. NotifyCh chan struct{}
  37. }
  38. type Controller struct {
  39. listener *net.UDPConn
  40. clientCfgs map[string]*ClientCfg
  41. sessions map[string]*Session
  42. encryptionKey []byte
  43. mu sync.RWMutex
  44. }
  45. func NewController(udpBindAddr string, encryptionKey []byte) (nc *Controller, err error) {
  46. addr, err := net.ResolveUDPAddr("udp", udpBindAddr)
  47. if err != nil {
  48. return nil, err
  49. }
  50. lconn, err := net.ListenUDP("udp", addr)
  51. if err != nil {
  52. return nil, err
  53. }
  54. nc = &Controller{
  55. listener: lconn,
  56. clientCfgs: make(map[string]*ClientCfg),
  57. sessions: make(map[string]*Session),
  58. encryptionKey: encryptionKey,
  59. }
  60. return nc, nil
  61. }
  62. func (nc *Controller) ListenClient(name string, sk string) (sidCh chan *SidRequest) {
  63. clientCfg := &ClientCfg{
  64. Name: name,
  65. Sk: sk,
  66. SidCh: make(chan *SidRequest),
  67. }
  68. nc.mu.Lock()
  69. nc.clientCfgs[name] = clientCfg
  70. nc.mu.Unlock()
  71. return clientCfg.SidCh
  72. }
  73. func (nc *Controller) CloseClient(name string) {
  74. nc.mu.Lock()
  75. defer nc.mu.Unlock()
  76. delete(nc.clientCfgs, name)
  77. }
  78. func (nc *Controller) Run() {
  79. for {
  80. buf := pool.GetBuf(1024)
  81. n, raddr, err := nc.listener.ReadFromUDP(buf)
  82. if err != nil {
  83. log.Warn("nat hole listener read from udp error: %v", err)
  84. return
  85. }
  86. plain, err := crypto.Decode(buf[:n], nc.encryptionKey)
  87. if err != nil {
  88. log.Warn("nathole listener decode from %s error: %v", raddr.String(), err)
  89. continue
  90. }
  91. rawMsg, err := msg.ReadMsg(bytes.NewReader(plain))
  92. if err != nil {
  93. log.Warn("read nat hole message error: %v", err)
  94. continue
  95. }
  96. switch m := rawMsg.(type) {
  97. case *msg.NatHoleBinding:
  98. go nc.HandleBinding(m, raddr)
  99. case *msg.NatHoleVisitor:
  100. go nc.HandleVisitor(m, raddr)
  101. case *msg.NatHoleClient:
  102. go nc.HandleClient(m, raddr)
  103. default:
  104. log.Trace("unknown nat hole message type")
  105. continue
  106. }
  107. pool.PutBuf(buf)
  108. }
  109. }
  110. func (nc *Controller) GenSid() string {
  111. t := time.Now().Unix()
  112. id, _ := util.RandID()
  113. return fmt.Sprintf("%d%s", t, id)
  114. }
  115. func (nc *Controller) HandleBinding(m *msg.NatHoleBinding, raddr *net.UDPAddr) {
  116. log.Trace("handle binding message from %s", raddr.String())
  117. resp := &msg.NatHoleBindingResp{
  118. TransactionID: m.TransactionID,
  119. Address: raddr.String(),
  120. }
  121. plain, err := msg.Pack(resp)
  122. if err != nil {
  123. log.Error("pack nat hole binding response error: %v", err)
  124. return
  125. }
  126. buf, err := crypto.Encode(plain, nc.encryptionKey)
  127. if err != nil {
  128. log.Error("encode nat hole binding response error: %v", err)
  129. return
  130. }
  131. _, err = nc.listener.WriteToUDP(buf, raddr)
  132. if err != nil {
  133. log.Error("write nat hole binding response to %s error: %v", raddr.String(), err)
  134. return
  135. }
  136. }
  137. func (nc *Controller) HandleVisitor(m *msg.NatHoleVisitor, raddr *net.UDPAddr) {
  138. sid := nc.GenSid()
  139. session := &Session{
  140. Sid: sid,
  141. VisitorAddr: raddr,
  142. NotifyCh: make(chan struct{}),
  143. }
  144. nc.mu.Lock()
  145. clientCfg, ok := nc.clientCfgs[m.ProxyName]
  146. if !ok {
  147. nc.mu.Unlock()
  148. errInfo := fmt.Sprintf("xtcp server for [%s] doesn't exist", m.ProxyName)
  149. log.Debug(errInfo)
  150. _, _ = nc.listener.WriteToUDP(nc.GenNatHoleResponse(nil, errInfo), raddr)
  151. return
  152. }
  153. if m.SignKey != util.GetAuthKey(clientCfg.Sk, m.Timestamp) {
  154. nc.mu.Unlock()
  155. errInfo := fmt.Sprintf("xtcp connection of [%s] auth failed", m.ProxyName)
  156. log.Debug(errInfo)
  157. _, _ = nc.listener.WriteToUDP(nc.GenNatHoleResponse(nil, errInfo), raddr)
  158. return
  159. }
  160. nc.sessions[sid] = session
  161. nc.mu.Unlock()
  162. log.Trace("handle visitor message, sid [%s]", sid)
  163. defer func() {
  164. nc.mu.Lock()
  165. delete(nc.sessions, sid)
  166. nc.mu.Unlock()
  167. }()
  168. err := errors.PanicToError(func() {
  169. clientCfg.SidCh <- &SidRequest{
  170. Sid: sid,
  171. NotifyCh: session.NotifyCh,
  172. }
  173. })
  174. if err != nil {
  175. return
  176. }
  177. // Wait client connections.
  178. select {
  179. case <-session.NotifyCh:
  180. resp := nc.GenNatHoleResponse(session, "")
  181. log.Trace("send nat hole response to visitor")
  182. _, _ = nc.listener.WriteToUDP(resp, raddr)
  183. case <-time.After(time.Duration(NatHoleTimeout) * time.Second):
  184. return
  185. }
  186. }
  187. func (nc *Controller) HandleClient(m *msg.NatHoleClient, raddr *net.UDPAddr) {
  188. nc.mu.RLock()
  189. session, ok := nc.sessions[m.Sid]
  190. nc.mu.RUnlock()
  191. if !ok {
  192. return
  193. }
  194. log.Trace("handle client message, sid [%s]", session.Sid)
  195. session.ClientAddr = raddr
  196. resp := nc.GenNatHoleResponse(session, "")
  197. log.Trace("send nat hole response to client")
  198. _, _ = nc.listener.WriteToUDP(resp, raddr)
  199. }
  200. func (nc *Controller) GenNatHoleResponse(session *Session, errInfo string) []byte {
  201. var (
  202. sid string
  203. visitorAddr string
  204. clientAddr string
  205. )
  206. if session != nil {
  207. sid = session.Sid
  208. visitorAddr = session.VisitorAddr.String()
  209. clientAddr = session.ClientAddr.String()
  210. }
  211. m := &msg.NatHoleResp{
  212. Sid: sid,
  213. VisitorAddr: visitorAddr,
  214. ClientAddr: clientAddr,
  215. Error: errInfo,
  216. }
  217. b := bytes.NewBuffer(nil)
  218. err := msg.WriteMsg(b, m)
  219. if err != nil {
  220. return []byte("")
  221. }
  222. return b.Bytes()
  223. }
  224. type Session struct {
  225. Sid string
  226. VisitorAddr *net.UDPAddr
  227. ClientAddr *net.UDPAddr
  228. NotifyCh chan struct{}
  229. }
  230. type ClientCfg struct {
  231. Name string
  232. Sk string
  233. SidCh chan *SidRequest
  234. }