candidate_base.go 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565
  1. // SPDX-FileCopyrightText: 2023 The Pion community <https://pion.ly>
  2. // SPDX-License-Identifier: MIT
  3. package ice
  4. import (
  5. "context"
  6. "errors"
  7. "fmt"
  8. "hash/crc32"
  9. "io"
  10. "net"
  11. "strconv"
  12. "strings"
  13. "sync/atomic"
  14. "time"
  15. "github.com/pion/stun"
  16. )
  17. type candidateBase struct {
  18. id string
  19. networkType NetworkType
  20. candidateType CandidateType
  21. component uint16
  22. address string
  23. port int
  24. relatedAddress *CandidateRelatedAddress
  25. tcpType TCPType
  26. resolvedAddr net.Addr
  27. lastSent atomic.Int64
  28. lastReceived atomic.Int64
  29. conn net.PacketConn
  30. currAgent *Agent
  31. closeCh chan struct{}
  32. closedCh chan struct{}
  33. foundationOverride string
  34. priorityOverride uint32
  35. remoteCandidateCaches map[AddrPort]Candidate
  36. }
  37. // Done implements context.Context
  38. func (c *candidateBase) Done() <-chan struct{} {
  39. return c.closeCh
  40. }
  41. // Err implements context.Context
  42. func (c *candidateBase) Err() error {
  43. select {
  44. case <-c.closedCh:
  45. return ErrRunCanceled
  46. default:
  47. return nil
  48. }
  49. }
  50. // Deadline implements context.Context
  51. func (c *candidateBase) Deadline() (deadline time.Time, ok bool) {
  52. return time.Time{}, false
  53. }
  54. // Value implements context.Context
  55. func (c *candidateBase) Value(interface{}) interface{} {
  56. return nil
  57. }
  58. // ID returns Candidate ID
  59. func (c *candidateBase) ID() string {
  60. return c.id
  61. }
  62. func (c *candidateBase) Foundation() string {
  63. if c.foundationOverride != "" {
  64. return c.foundationOverride
  65. }
  66. return fmt.Sprintf("%d", crc32.ChecksumIEEE([]byte(c.Type().String()+c.address+c.networkType.String())))
  67. }
  68. // Address returns Candidate Address
  69. func (c *candidateBase) Address() string {
  70. return c.address
  71. }
  72. // Port returns Candidate Port
  73. func (c *candidateBase) Port() int {
  74. return c.port
  75. }
  76. // Type returns candidate type
  77. func (c *candidateBase) Type() CandidateType {
  78. return c.candidateType
  79. }
  80. // NetworkType returns candidate NetworkType
  81. func (c *candidateBase) NetworkType() NetworkType {
  82. return c.networkType
  83. }
  84. // Component returns candidate component
  85. func (c *candidateBase) Component() uint16 {
  86. return c.component
  87. }
  88. func (c *candidateBase) SetComponent(component uint16) {
  89. c.component = component
  90. }
  91. // LocalPreference returns the local preference for this candidate
  92. func (c *candidateBase) LocalPreference() uint16 {
  93. if c.NetworkType().IsTCP() {
  94. // RFC 6544, section 4.2
  95. //
  96. // In Section 4.1.2.1 of [RFC5245], a recommended formula for UDP ICE
  97. // candidate prioritization is defined. For TCP candidates, the same
  98. // formula and candidate type preferences SHOULD be used, and the
  99. // RECOMMENDED type preferences for the new candidate types defined in
  100. // this document (see Section 5) are 105 for NAT-assisted candidates and
  101. // 75 for UDP-tunneled candidates.
  102. //
  103. // (...)
  104. //
  105. // With TCP candidates, the local preference part of the recommended
  106. // priority formula is updated to also include the directionality
  107. // (active, passive, or simultaneous-open) of the TCP connection. The
  108. // RECOMMENDED local preference is then defined as:
  109. //
  110. // local preference = (2^13) * direction-pref + other-pref
  111. //
  112. // The direction-pref MUST be between 0 and 7 (both inclusive), with 7
  113. // being the most preferred. The other-pref MUST be between 0 and 8191
  114. // (both inclusive), with 8191 being the most preferred. It is
  115. // RECOMMENDED that the host, UDP-tunneled, and relayed TCP candidates
  116. // have the direction-pref assigned as follows: 6 for active, 4 for
  117. // passive, and 2 for S-O. For the NAT-assisted and server reflexive
  118. // candidates, the RECOMMENDED values are: 6 for S-O, 4 for active, and
  119. // 2 for passive.
  120. //
  121. // (...)
  122. //
  123. // If any two candidates have the same type-preference and direction-
  124. // pref, they MUST have a unique other-pref. With this specification,
  125. // this usually only happens with multi-homed hosts, in which case
  126. // other-pref is the preference for the particular IP address from which
  127. // the candidate was obtained. When there is only a single IP address,
  128. // this value SHOULD be set to the maximum allowed value (8191).
  129. var otherPref uint16 = 8191
  130. directionPref := func() uint16 {
  131. switch c.Type() {
  132. case CandidateTypeHost, CandidateTypeRelay:
  133. switch c.tcpType {
  134. case TCPTypeActive:
  135. return 6
  136. case TCPTypePassive:
  137. return 4
  138. case TCPTypeSimultaneousOpen:
  139. return 2
  140. case TCPTypeUnspecified:
  141. return 0
  142. }
  143. case CandidateTypePeerReflexive, CandidateTypeServerReflexive:
  144. switch c.tcpType {
  145. case TCPTypeSimultaneousOpen:
  146. return 6
  147. case TCPTypeActive:
  148. return 4
  149. case TCPTypePassive:
  150. return 2
  151. case TCPTypeUnspecified:
  152. return 0
  153. }
  154. case CandidateTypeUnspecified:
  155. return 0
  156. }
  157. return 0
  158. }()
  159. return (1<<13)*directionPref + otherPref
  160. }
  161. return defaultLocalPreference
  162. }
  163. // RelatedAddress returns *CandidateRelatedAddress
  164. func (c *candidateBase) RelatedAddress() *CandidateRelatedAddress {
  165. return c.relatedAddress
  166. }
  167. func (c *candidateBase) TCPType() TCPType {
  168. return c.tcpType
  169. }
  170. // start runs the candidate using the provided connection
  171. func (c *candidateBase) start(a *Agent, conn net.PacketConn, initializedCh <-chan struct{}) {
  172. if c.conn != nil {
  173. c.agent().log.Warn("Can't start already started candidateBase")
  174. return
  175. }
  176. c.currAgent = a
  177. c.conn = conn
  178. c.closeCh = make(chan struct{})
  179. c.closedCh = make(chan struct{})
  180. go c.recvLoop(initializedCh)
  181. }
  182. func (c *candidateBase) recvLoop(initializedCh <-chan struct{}) {
  183. a := c.agent()
  184. defer close(c.closedCh)
  185. select {
  186. case <-initializedCh:
  187. case <-c.closeCh:
  188. return
  189. }
  190. buf := make([]byte, receiveMTU)
  191. for {
  192. n, srcAddr, err := c.conn.ReadFrom(buf)
  193. if err != nil {
  194. if !(errors.Is(err, io.EOF) || errors.Is(err, net.ErrClosed)) {
  195. a.log.Warnf("Failed to read from candidate %s: %v", c, err)
  196. }
  197. return
  198. }
  199. c.handleInboundPacket(buf[:n], srcAddr)
  200. }
  201. }
  202. func (c *candidateBase) validateSTUNTrafficCache(addr net.Addr) bool {
  203. if candidate, ok := c.remoteCandidateCaches[toAddrPort(addr)]; ok {
  204. candidate.seen(false)
  205. return true
  206. }
  207. return false
  208. }
  209. func (c *candidateBase) addRemoteCandidateCache(candidate Candidate, srcAddr net.Addr) {
  210. if c.validateSTUNTrafficCache(srcAddr) {
  211. return
  212. }
  213. c.remoteCandidateCaches[toAddrPort(srcAddr)] = candidate
  214. }
  215. func (c *candidateBase) handleInboundPacket(buf []byte, srcAddr net.Addr) {
  216. a := c.agent()
  217. if stun.IsMessage(buf) {
  218. m := &stun.Message{
  219. Raw: make([]byte, len(buf)),
  220. }
  221. // Explicitly copy raw buffer so Message can own the memory.
  222. copy(m.Raw, buf)
  223. if err := m.Decode(); err != nil {
  224. a.log.Warnf("Failed to handle decode ICE from %s to %s: %v", c.addr(), srcAddr, err)
  225. return
  226. }
  227. if err := a.run(c, func(ctx context.Context, a *Agent) {
  228. // nolint: contextcheck
  229. a.handleInbound(m, c, srcAddr)
  230. }); err != nil {
  231. a.log.Warnf("Failed to handle message: %v", err)
  232. }
  233. return
  234. }
  235. if !c.validateSTUNTrafficCache(srcAddr) {
  236. remoteCandidate, valid := a.validateNonSTUNTraffic(c, srcAddr) //nolint:contextcheck
  237. if !valid {
  238. a.log.Warnf("Discarded message from %s, not a valid remote candidate", c.addr())
  239. return
  240. }
  241. c.addRemoteCandidateCache(remoteCandidate, srcAddr)
  242. }
  243. // Note: This will return packetio.ErrFull if the buffer ever manages to fill up.
  244. if _, err := a.buf.Write(buf); err != nil {
  245. a.log.Warnf("Failed to write packet: %s", err)
  246. return
  247. }
  248. }
  249. // close stops the recvLoop
  250. func (c *candidateBase) close() error {
  251. // If conn has never been started will be nil
  252. if c.Done() == nil {
  253. return nil
  254. }
  255. // Assert that conn has not already been closed
  256. select {
  257. case <-c.Done():
  258. return nil
  259. default:
  260. }
  261. var firstErr error
  262. // Unblock recvLoop
  263. close(c.closeCh)
  264. if err := c.conn.SetDeadline(time.Now()); err != nil {
  265. firstErr = err
  266. }
  267. // Close the conn
  268. if err := c.conn.Close(); err != nil && firstErr == nil {
  269. firstErr = err
  270. }
  271. if firstErr != nil {
  272. return firstErr
  273. }
  274. // Wait until the recvLoop is closed
  275. <-c.closedCh
  276. return nil
  277. }
  278. func (c *candidateBase) writeTo(raw []byte, dst Candidate) (int, error) {
  279. n, err := c.conn.WriteTo(raw, dst.addr())
  280. if err != nil {
  281. // If the connection is closed, we should return the error
  282. if errors.Is(err, io.ErrClosedPipe) {
  283. return n, err
  284. }
  285. c.agent().log.Infof("Failed to send packet: %v", err)
  286. return n, nil
  287. }
  288. c.seen(true)
  289. return n, nil
  290. }
  291. // TypePreference returns the type preference for this candidate
  292. func (c *candidateBase) TypePreference() uint16 {
  293. pref := c.Type().Preference()
  294. if pref == 0 {
  295. return 0
  296. }
  297. if c.NetworkType().IsTCP() {
  298. var tcpPriorityOffset uint16 = defaultTCPPriorityOffset
  299. if c.agent() != nil {
  300. tcpPriorityOffset = c.agent().tcpPriorityOffset
  301. }
  302. pref -= tcpPriorityOffset
  303. }
  304. return pref
  305. }
  306. // Priority computes the priority for this ICE Candidate
  307. // See: https://www.rfc-editor.org/rfc/rfc8445#section-5.1.2.1
  308. func (c *candidateBase) Priority() uint32 {
  309. if c.priorityOverride != 0 {
  310. return c.priorityOverride
  311. }
  312. // The local preference MUST be an integer from 0 (lowest preference) to
  313. // 65535 (highest preference) inclusive. When there is only a single IP
  314. // address, this value SHOULD be set to 65535. If there are multiple
  315. // candidates for a particular component for a particular data stream
  316. // that have the same type, the local preference MUST be unique for each
  317. // one.
  318. return (1<<24)*uint32(c.TypePreference()) +
  319. (1<<8)*uint32(c.LocalPreference()) +
  320. (1<<0)*uint32(256-c.Component())
  321. }
  322. // Equal is used to compare two candidateBases
  323. func (c *candidateBase) Equal(other Candidate) bool {
  324. return c.NetworkType() == other.NetworkType() &&
  325. c.Type() == other.Type() &&
  326. c.Address() == other.Address() &&
  327. c.Port() == other.Port() &&
  328. c.TCPType() == other.TCPType() &&
  329. c.RelatedAddress().Equal(other.RelatedAddress())
  330. }
  331. // String makes the candidateBase printable
  332. func (c *candidateBase) String() string {
  333. return fmt.Sprintf("%s %s %s%s", c.NetworkType(), c.Type(), net.JoinHostPort(c.Address(), strconv.Itoa(c.Port())), c.relatedAddress)
  334. }
  335. // LastReceived returns a time.Time indicating the last time
  336. // this candidate was received
  337. func (c *candidateBase) LastReceived() time.Time {
  338. if lastReceived := c.lastReceived.Load(); lastReceived != 0 {
  339. return time.Unix(0, lastReceived)
  340. }
  341. return time.Time{}
  342. }
  343. func (c *candidateBase) setLastReceived(t time.Time) {
  344. c.lastReceived.Store(t.UnixNano())
  345. }
  346. // LastSent returns a time.Time indicating the last time
  347. // this candidate was sent
  348. func (c *candidateBase) LastSent() time.Time {
  349. if lastSent := c.lastSent.Load(); lastSent != 0 {
  350. return time.Unix(0, lastSent)
  351. }
  352. return time.Time{}
  353. }
  354. func (c *candidateBase) setLastSent(t time.Time) {
  355. c.lastSent.Store(t.UnixNano())
  356. }
  357. func (c *candidateBase) seen(outbound bool) {
  358. if outbound {
  359. c.setLastSent(time.Now())
  360. } else {
  361. c.setLastReceived(time.Now())
  362. }
  363. }
  364. func (c *candidateBase) addr() net.Addr {
  365. return c.resolvedAddr
  366. }
  367. func (c *candidateBase) agent() *Agent {
  368. return c.currAgent
  369. }
  370. func (c *candidateBase) context() context.Context {
  371. return c
  372. }
  373. func (c *candidateBase) copy() (Candidate, error) {
  374. return UnmarshalCandidate(c.Marshal())
  375. }
  376. // Marshal returns the string representation of the ICECandidate
  377. func (c *candidateBase) Marshal() string {
  378. val := c.Foundation()
  379. if val == " " {
  380. val = ""
  381. }
  382. val = fmt.Sprintf("%s %d %s %d %s %d typ %s",
  383. val,
  384. c.Component(),
  385. c.NetworkType().NetworkShort(),
  386. c.Priority(),
  387. c.Address(),
  388. c.Port(),
  389. c.Type())
  390. if c.tcpType != TCPTypeUnspecified {
  391. val += fmt.Sprintf(" tcptype %s", c.tcpType.String())
  392. }
  393. if r := c.RelatedAddress(); r != nil && r.Address != "" && r.Port != 0 {
  394. val = fmt.Sprintf("%s raddr %s rport %d",
  395. val,
  396. r.Address,
  397. r.Port)
  398. }
  399. return val
  400. }
  401. // UnmarshalCandidate creates a Candidate from its string representation
  402. func UnmarshalCandidate(raw string) (Candidate, error) {
  403. split := strings.Fields(raw)
  404. // Foundation not specified: not RFC 8445 compliant but seen in the wild
  405. if len(raw) != 0 && raw[0] == ' ' {
  406. split = append([]string{" "}, split...)
  407. }
  408. if len(split) < 8 {
  409. return nil, fmt.Errorf("%w (%d)", errAttributeTooShortICECandidate, len(split))
  410. }
  411. // Foundation
  412. foundation := split[0]
  413. // Component
  414. rawComponent, err := strconv.ParseUint(split[1], 10, 16)
  415. if err != nil {
  416. return nil, fmt.Errorf("%w: %v", errParseComponent, err) //nolint:errorlint
  417. }
  418. component := uint16(rawComponent)
  419. // Protocol
  420. protocol := split[2]
  421. // Priority
  422. priorityRaw, err := strconv.ParseUint(split[3], 10, 32)
  423. if err != nil {
  424. return nil, fmt.Errorf("%w: %v", errParsePriority, err) //nolint:errorlint
  425. }
  426. priority := uint32(priorityRaw)
  427. // Address
  428. address := split[4]
  429. // Port
  430. rawPort, err := strconv.ParseUint(split[5], 10, 16)
  431. if err != nil {
  432. return nil, fmt.Errorf("%w: %v", errParsePort, err) //nolint:errorlint
  433. }
  434. port := int(rawPort)
  435. typ := split[7]
  436. relatedAddress := ""
  437. relatedPort := 0
  438. tcpType := TCPTypeUnspecified
  439. if len(split) > 8 {
  440. split = split[8:]
  441. if split[0] == "raddr" {
  442. if len(split) < 4 {
  443. return nil, fmt.Errorf("%w: incorrect length", errParseRelatedAddr)
  444. }
  445. // RelatedAddress
  446. relatedAddress = split[1]
  447. // RelatedPort
  448. rawRelatedPort, parseErr := strconv.ParseUint(split[3], 10, 16)
  449. if parseErr != nil {
  450. return nil, fmt.Errorf("%w: %v", errParsePort, parseErr) //nolint:errorlint
  451. }
  452. relatedPort = int(rawRelatedPort)
  453. } else if split[0] == "tcptype" {
  454. if len(split) < 2 {
  455. return nil, fmt.Errorf("%w: incorrect length", errParseTCPType)
  456. }
  457. tcpType = NewTCPType(split[1])
  458. }
  459. }
  460. switch typ {
  461. case "host":
  462. return NewCandidateHost(&CandidateHostConfig{"", protocol, address, port, component, priority, foundation, tcpType})
  463. case "srflx":
  464. return NewCandidateServerReflexive(&CandidateServerReflexiveConfig{"", protocol, address, port, component, priority, foundation, relatedAddress, relatedPort})
  465. case "prflx":
  466. return NewCandidatePeerReflexive(&CandidatePeerReflexiveConfig{"", protocol, address, port, component, priority, foundation, relatedAddress, relatedPort})
  467. case "relay":
  468. return NewCandidateRelay(&CandidateRelayConfig{"", protocol, address, port, component, priority, foundation, relatedAddress, relatedPort, "", nil})
  469. default:
  470. }
  471. return nil, fmt.Errorf("%w (%s)", ErrUnknownCandidateTyp, typ)
  472. }