nathole.go 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440
  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. "context"
  17. "fmt"
  18. "math/rand/v2"
  19. "net"
  20. "slices"
  21. "strconv"
  22. "strings"
  23. "time"
  24. "github.com/fatedier/golib/pool"
  25. "golang.org/x/net/ipv4"
  26. "k8s.io/apimachinery/pkg/util/sets"
  27. "github.com/fatedier/frp/pkg/msg"
  28. "github.com/fatedier/frp/pkg/transport"
  29. "github.com/fatedier/frp/pkg/util/xlog"
  30. )
  31. var (
  32. // mode 0: simple detect mode, usually for both EasyNAT or HardNAT & EasyNAT(Public Network)
  33. // a. receiver sends detect message with low TTL
  34. // b. sender sends normal detect message to receiver
  35. // c. receiver receives detect message and sends back a message to sender
  36. //
  37. // mode 1: For HardNAT & EasyNAT, send detect messages to multiple guessed ports.
  38. // Usually applicable to scenarios where port changes are regular.
  39. // Most of the steps are the same as mode 0, but EasyNAT is fixed as the receiver and will send detect messages
  40. // with low TTL to multiple guessed ports of the sender.
  41. //
  42. // mode 2: For HardNAT & EasyNAT, ports changes are not regular.
  43. // a. HardNAT machine will listen on multiple ports and send detect messages with low TTL to EasyNAT machine
  44. // b. EasyNAT machine will send detect messages to random ports of HardNAT machine.
  45. //
  46. // mode 3: For HardNAT & HardNAT, both changes in the ports are regular.
  47. // Most of the steps are the same as mode 1, but the sender also needs to send detect messages to multiple guessed
  48. // ports of the receiver.
  49. //
  50. // mode 4: For HardNAT & HardNAT, one of the changes in the ports is regular.
  51. // Regular port changes are usually on the sender side.
  52. // a. Receiver listens on multiple ports and sends detect messages with low TTL to the sender's guessed range ports.
  53. // b. Sender sends detect messages to random ports of the receiver.
  54. SupportedModes = []int{DetectMode0, DetectMode1, DetectMode2, DetectMode3, DetectMode4}
  55. SupportedRoles = []string{DetectRoleSender, DetectRoleReceiver}
  56. DetectMode0 = 0
  57. DetectMode1 = 1
  58. DetectMode2 = 2
  59. DetectMode3 = 3
  60. DetectMode4 = 4
  61. DetectRoleSender = "sender"
  62. DetectRoleReceiver = "receiver"
  63. )
  64. type PrepareResult struct {
  65. Addrs []string
  66. AssistedAddrs []string
  67. ListenConn *net.UDPConn
  68. NatType string
  69. Behavior string
  70. }
  71. // PreCheck is used to check if the proxy is ready for penetration.
  72. // Call this function before calling Prepare to avoid unnecessary preparation work.
  73. func PreCheck(
  74. ctx context.Context, transporter transport.MessageTransporter,
  75. proxyName string, timeout time.Duration,
  76. ) error {
  77. timeoutCtx, cancel := context.WithTimeout(ctx, timeout)
  78. defer cancel()
  79. var natHoleRespMsg *msg.NatHoleResp
  80. transactionID := NewTransactionID()
  81. m, err := transporter.Do(timeoutCtx, &msg.NatHoleVisitor{
  82. TransactionID: transactionID,
  83. ProxyName: proxyName,
  84. PreCheck: true,
  85. }, transactionID, msg.TypeNameNatHoleResp)
  86. if err != nil {
  87. return fmt.Errorf("get natHoleRespMsg error: %v", err)
  88. }
  89. mm, ok := m.(*msg.NatHoleResp)
  90. if !ok {
  91. return fmt.Errorf("get natHoleRespMsg error: invalid message type")
  92. }
  93. natHoleRespMsg = mm
  94. if natHoleRespMsg.Error != "" {
  95. return fmt.Errorf("%s", natHoleRespMsg.Error)
  96. }
  97. return nil
  98. }
  99. // Prepare is used to do some preparation work before penetration.
  100. func Prepare(stunServers []string) (*PrepareResult, error) {
  101. // discover for Nat type
  102. addrs, localAddr, err := Discover(stunServers, "")
  103. if err != nil {
  104. return nil, fmt.Errorf("discover error: %v", err)
  105. }
  106. if len(addrs) < 2 {
  107. return nil, fmt.Errorf("discover error: not enough addresses")
  108. }
  109. localIPs, _ := ListLocalIPsForNatHole(10)
  110. natFeature, err := ClassifyNATFeature(addrs, localIPs)
  111. if err != nil {
  112. return nil, fmt.Errorf("classify nat feature error: %v", err)
  113. }
  114. laddr, err := net.ResolveUDPAddr("udp4", localAddr.String())
  115. if err != nil {
  116. return nil, fmt.Errorf("resolve local udp addr error: %v", err)
  117. }
  118. listenConn, err := net.ListenUDP("udp4", laddr)
  119. if err != nil {
  120. return nil, fmt.Errorf("listen local udp addr error: %v", err)
  121. }
  122. assistedAddrs := make([]string, 0, len(localIPs))
  123. for _, ip := range localIPs {
  124. assistedAddrs = append(assistedAddrs, net.JoinHostPort(ip, strconv.Itoa(laddr.Port)))
  125. }
  126. return &PrepareResult{
  127. Addrs: addrs,
  128. AssistedAddrs: assistedAddrs,
  129. ListenConn: listenConn,
  130. NatType: natFeature.NatType,
  131. Behavior: natFeature.Behavior,
  132. }, nil
  133. }
  134. // ExchangeInfo is used to exchange information between client and visitor.
  135. // 1. Send input message to server by msgTransporter.
  136. // 2. Server will gather information from client and visitor and analyze it. Then send back a NatHoleResp message to them to tell them how to do next.
  137. // 3. Receive NatHoleResp message from server.
  138. func ExchangeInfo(
  139. ctx context.Context, transporter transport.MessageTransporter,
  140. laneKey string, m msg.Message, timeout time.Duration,
  141. ) (*msg.NatHoleResp, error) {
  142. timeoutCtx, cancel := context.WithTimeout(ctx, timeout)
  143. defer cancel()
  144. var natHoleRespMsg *msg.NatHoleResp
  145. m, err := transporter.Do(timeoutCtx, m, laneKey, msg.TypeNameNatHoleResp)
  146. if err != nil {
  147. return nil, fmt.Errorf("get natHoleRespMsg error: %v", err)
  148. }
  149. mm, ok := m.(*msg.NatHoleResp)
  150. if !ok {
  151. return nil, fmt.Errorf("get natHoleRespMsg error: invalid message type")
  152. }
  153. natHoleRespMsg = mm
  154. if natHoleRespMsg.Error != "" {
  155. return nil, fmt.Errorf("natHoleRespMsg get error info: %s", natHoleRespMsg.Error)
  156. }
  157. if len(natHoleRespMsg.CandidateAddrs) == 0 {
  158. return nil, fmt.Errorf("natHoleRespMsg get empty candidate addresses")
  159. }
  160. return natHoleRespMsg, nil
  161. }
  162. // MakeHole is used to make a NAT hole between client and visitor.
  163. func MakeHole(ctx context.Context, listenConn *net.UDPConn, m *msg.NatHoleResp, key []byte) (*net.UDPConn, *net.UDPAddr, error) {
  164. xl := xlog.FromContextSafe(ctx)
  165. transactionID := NewTransactionID()
  166. sendToRangePortsFunc := func(conn *net.UDPConn, addr string) error {
  167. return sendSidMessage(ctx, conn, m.Sid, transactionID, addr, key, m.DetectBehavior.TTL)
  168. }
  169. listenConns := []*net.UDPConn{listenConn}
  170. var detectAddrs []string
  171. if m.DetectBehavior.Role == DetectRoleSender {
  172. // sender
  173. if m.DetectBehavior.SendDelayMs > 0 {
  174. time.Sleep(time.Duration(m.DetectBehavior.SendDelayMs) * time.Millisecond)
  175. }
  176. detectAddrs = m.AssistedAddrs
  177. detectAddrs = append(detectAddrs, m.CandidateAddrs...)
  178. } else {
  179. // receiver
  180. if len(m.DetectBehavior.CandidatePorts) == 0 {
  181. detectAddrs = m.CandidateAddrs
  182. }
  183. if m.DetectBehavior.ListenRandomPorts > 0 {
  184. for i := 0; i < m.DetectBehavior.ListenRandomPorts; i++ {
  185. tmpConn, err := net.ListenUDP("udp4", nil)
  186. if err != nil {
  187. xl.Warnf("listen random udp addr error: %v", err)
  188. continue
  189. }
  190. listenConns = append(listenConns, tmpConn)
  191. }
  192. }
  193. }
  194. detectAddrs = slices.Compact(detectAddrs)
  195. for _, detectAddr := range detectAddrs {
  196. for _, conn := range listenConns {
  197. if err := sendSidMessage(ctx, conn, m.Sid, transactionID, detectAddr, key, m.DetectBehavior.TTL); err != nil {
  198. xl.Tracef("send sid message from %s to %s error: %v", conn.LocalAddr(), detectAddr, err)
  199. }
  200. }
  201. }
  202. if len(m.DetectBehavior.CandidatePorts) > 0 {
  203. for _, conn := range listenConns {
  204. sendSidMessageToRangePorts(ctx, conn, m.CandidateAddrs, m.DetectBehavior.CandidatePorts, sendToRangePortsFunc)
  205. }
  206. }
  207. if m.DetectBehavior.SendRandomPorts > 0 {
  208. ctx, cancel := context.WithCancel(ctx)
  209. defer cancel()
  210. for i := range listenConns {
  211. go sendSidMessageToRandomPorts(ctx, listenConns[i], m.CandidateAddrs, m.DetectBehavior.SendRandomPorts, sendToRangePortsFunc)
  212. }
  213. }
  214. timeout := 5 * time.Second
  215. if m.DetectBehavior.ReadTimeoutMs > 0 {
  216. timeout = time.Duration(m.DetectBehavior.ReadTimeoutMs) * time.Millisecond
  217. }
  218. if len(listenConns) == 1 {
  219. raddr, err := waitDetectMessage(ctx, listenConns[0], m.Sid, key, timeout, m.DetectBehavior.Role)
  220. if err != nil {
  221. return nil, nil, fmt.Errorf("wait detect message error: %v", err)
  222. }
  223. return listenConns[0], raddr, nil
  224. }
  225. type result struct {
  226. lConn *net.UDPConn
  227. raddr *net.UDPAddr
  228. }
  229. resultCh := make(chan result)
  230. for _, conn := range listenConns {
  231. go func(lConn *net.UDPConn) {
  232. addr, err := waitDetectMessage(ctx, lConn, m.Sid, key, timeout, m.DetectBehavior.Role)
  233. if err != nil {
  234. lConn.Close()
  235. return
  236. }
  237. select {
  238. case resultCh <- result{lConn: lConn, raddr: addr}:
  239. default:
  240. lConn.Close()
  241. }
  242. }(conn)
  243. }
  244. select {
  245. case result := <-resultCh:
  246. return result.lConn, result.raddr, nil
  247. case <-time.After(timeout):
  248. return nil, nil, fmt.Errorf("wait detect message timeout")
  249. case <-ctx.Done():
  250. return nil, nil, fmt.Errorf("wait detect message canceled")
  251. }
  252. }
  253. func waitDetectMessage(
  254. ctx context.Context, conn *net.UDPConn, sid string, key []byte,
  255. timeout time.Duration, role string,
  256. ) (*net.UDPAddr, error) {
  257. xl := xlog.FromContextSafe(ctx)
  258. for {
  259. buf := pool.GetBuf(1024)
  260. _ = conn.SetReadDeadline(time.Now().Add(timeout))
  261. n, raddr, err := conn.ReadFromUDP(buf)
  262. _ = conn.SetReadDeadline(time.Time{})
  263. if err != nil {
  264. return nil, err
  265. }
  266. xl.Debugf("get udp message local %s, from %s", conn.LocalAddr(), raddr)
  267. var m msg.NatHoleSid
  268. if err := DecodeMessageInto(buf[:n], key, &m); err != nil {
  269. xl.Warnf("decode sid message error: %v", err)
  270. continue
  271. }
  272. pool.PutBuf(buf)
  273. if m.Sid != sid {
  274. xl.Warnf("get sid message with wrong sid: %s, expect: %s", m.Sid, sid)
  275. continue
  276. }
  277. if !m.Response {
  278. // only wait for response messages if we are a sender
  279. if role == DetectRoleSender {
  280. continue
  281. }
  282. m.Response = true
  283. buf2, err := EncodeMessage(&m, key)
  284. if err != nil {
  285. xl.Warnf("encode sid message error: %v", err)
  286. continue
  287. }
  288. _, _ = conn.WriteToUDP(buf2, raddr)
  289. }
  290. return raddr, nil
  291. }
  292. }
  293. func sendSidMessage(
  294. ctx context.Context, conn *net.UDPConn,
  295. sid string, transactionID string, addr string, key []byte, ttl int,
  296. ) error {
  297. xl := xlog.FromContextSafe(ctx)
  298. ttlStr := ""
  299. if ttl > 0 {
  300. ttlStr = fmt.Sprintf(" with ttl %d", ttl)
  301. }
  302. xl.Tracef("send sid message from %s to %s%s", conn.LocalAddr(), addr, ttlStr)
  303. raddr, err := net.ResolveUDPAddr("udp4", addr)
  304. if err != nil {
  305. return err
  306. }
  307. if transactionID == "" {
  308. transactionID = NewTransactionID()
  309. }
  310. m := &msg.NatHoleSid{
  311. TransactionID: transactionID,
  312. Sid: sid,
  313. Response: false,
  314. Nonce: strings.Repeat("0", rand.IntN(20)),
  315. }
  316. buf, err := EncodeMessage(m, key)
  317. if err != nil {
  318. return err
  319. }
  320. if ttl > 0 {
  321. uConn := ipv4.NewConn(conn)
  322. original, err := uConn.TTL()
  323. if err != nil {
  324. xl.Tracef("get ttl error %v", err)
  325. return err
  326. }
  327. xl.Tracef("original ttl %d", original)
  328. err = uConn.SetTTL(ttl)
  329. if err != nil {
  330. xl.Tracef("set ttl error %v", err)
  331. } else {
  332. defer func() {
  333. _ = uConn.SetTTL(original)
  334. }()
  335. }
  336. }
  337. if _, err := conn.WriteToUDP(buf, raddr); err != nil {
  338. return err
  339. }
  340. return nil
  341. }
  342. func sendSidMessageToRangePorts(
  343. ctx context.Context, conn *net.UDPConn, addrs []string, ports []msg.PortsRange,
  344. sendFunc func(*net.UDPConn, string) error,
  345. ) {
  346. xl := xlog.FromContextSafe(ctx)
  347. for _, ip := range slices.Compact(parseIPs(addrs)) {
  348. for _, portsRange := range ports {
  349. for i := portsRange.From; i <= portsRange.To; i++ {
  350. detectAddr := net.JoinHostPort(ip, strconv.Itoa(i))
  351. if err := sendFunc(conn, detectAddr); err != nil {
  352. xl.Tracef("send sid message from %s to %s error: %v", conn.LocalAddr(), detectAddr, err)
  353. }
  354. time.Sleep(2 * time.Millisecond)
  355. }
  356. }
  357. }
  358. }
  359. func sendSidMessageToRandomPorts(
  360. ctx context.Context, conn *net.UDPConn, addrs []string, count int,
  361. sendFunc func(*net.UDPConn, string) error,
  362. ) {
  363. xl := xlog.FromContextSafe(ctx)
  364. used := sets.New[int]()
  365. getUnusedPort := func() int {
  366. for i := 0; i < 10; i++ {
  367. port := rand.IntN(65535-1024) + 1024
  368. if !used.Has(port) {
  369. used.Insert(port)
  370. return port
  371. }
  372. }
  373. return 0
  374. }
  375. for i := 0; i < count; i++ {
  376. select {
  377. case <-ctx.Done():
  378. return
  379. default:
  380. }
  381. port := getUnusedPort()
  382. if port == 0 {
  383. continue
  384. }
  385. for _, ip := range slices.Compact(parseIPs(addrs)) {
  386. detectAddr := net.JoinHostPort(ip, strconv.Itoa(port))
  387. if err := sendFunc(conn, detectAddr); err != nil {
  388. xl.Tracef("send sid message from %s to %s error: %v", conn.LocalAddr(), detectAddr, err)
  389. }
  390. time.Sleep(time.Millisecond * 15)
  391. }
  392. }
  393. }
  394. func parseIPs(addrs []string) []string {
  395. var ips []string
  396. for _, addr := range addrs {
  397. if ip, _, err := net.SplitHostPort(addr); err == nil {
  398. ips = append(ips, ip)
  399. }
  400. }
  401. return ips
  402. }