webrtc.go 75 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736173717381739174017411742174317441745174617471748174917501751175217531754175517561757175817591760176117621763176417651766176717681769177017711772177317741775177617771778177917801781178217831784178517861787178817891790179117921793179417951796179717981799180018011802180318041805180618071808180918101811181218131814181518161817181818191820182118221823182418251826182718281829183018311832183318341835183618371838183918401841184218431844184518461847184818491850185118521853185418551856185718581859186018611862186318641865186618671868186918701871187218731874187518761877187818791880188118821883188418851886188718881889189018911892189318941895189618971898189919001901190219031904190519061907190819091910191119121913191419151916191719181919192019211922192319241925192619271928192919301931193219331934193519361937193819391940194119421943194419451946194719481949195019511952195319541955195619571958195919601961196219631964196519661967196819691970197119721973197419751976197719781979198019811982198319841985198619871988198919901991199219931994199519961997199819992000200120022003200420052006200720082009201020112012201320142015201620172018201920202021202220232024202520262027202820292030203120322033203420352036203720382039204020412042204320442045204620472048204920502051205220532054205520562057205820592060206120622063206420652066206720682069207020712072207320742075207620772078207920802081208220832084208520862087208820892090209120922093209420952096209720982099210021012102210321042105210621072108210921102111211221132114211521162117211821192120212121222123212421252126212721282129213021312132213321342135213621372138213921402141214221432144214521462147214821492150215121522153215421552156215721582159216021612162216321642165216621672168216921702171217221732174217521762177217821792180218121822183218421852186218721882189219021912192219321942195219621972198219922002201220222032204220522062207220822092210221122122213221422152216221722182219222022212222222322242225222622272228222922302231223222332234223522362237223822392240224122422243224422452246224722482249225022512252225322542255225622572258225922602261226222632264226522662267226822692270227122722273227422752276227722782279228022812282228322842285228622872288228922902291229222932294229522962297229822992300230123022303230423052306230723082309231023112312231323142315231623172318231923202321232223232324232523262327232823292330233123322333233423352336233723382339234023412342234323442345234623472348234923502351
  1. //go:build PSIPHON_ENABLE_INPROXY
  2. /*
  3. * Copyright (c) 2023, Psiphon Inc.
  4. * All rights reserved.
  5. *
  6. * This program is free software: you can redistribute it and/or modify
  7. * it under the terms of the GNU General Public License as published by
  8. * the Free Software Foundation, either version 3 of the License, or
  9. * (at your option) any later version.
  10. *
  11. * This program is distributed in the hope that it will be useful,
  12. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  13. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  14. * GNU General Public License for more details.
  15. *
  16. * You should have received a copy of the GNU General Public License
  17. * along with this program. If not, see <http://www.gnu.org/licenses/>.
  18. *
  19. */
  20. package inproxy
  21. import (
  22. "bytes"
  23. "context"
  24. "encoding/binary"
  25. std_errors "errors"
  26. "fmt"
  27. "net"
  28. "strconv"
  29. "strings"
  30. "sync"
  31. "sync/atomic"
  32. "time"
  33. "github.com/Psiphon-Labs/psiphon-tunnel-core/psiphon/common"
  34. "github.com/Psiphon-Labs/psiphon-tunnel-core/psiphon/common/errors"
  35. inproxy_dtls "github.com/Psiphon-Labs/psiphon-tunnel-core/psiphon/common/inproxy/dtls"
  36. "github.com/Psiphon-Labs/psiphon-tunnel-core/psiphon/common/prng"
  37. "github.com/Psiphon-Labs/psiphon-tunnel-core/psiphon/common/stacktrace"
  38. "github.com/pion/datachannel"
  39. "github.com/pion/dtls/v2"
  40. "github.com/pion/ice/v2"
  41. pion_logging "github.com/pion/logging"
  42. "github.com/pion/sdp/v3"
  43. "github.com/pion/stun"
  44. "github.com/pion/transport/v2"
  45. "github.com/pion/webrtc/v3"
  46. "github.com/wlynxg/anet"
  47. )
  48. const (
  49. portMappingAwaitTimeout = 2 * time.Second
  50. dataChannelAwaitTimeout = 20 * time.Second
  51. dataChannelBufferedAmountLowThreshold uint64 = 512 * 1024
  52. dataChannelMaxBufferedAmount uint64 = 1024 * 1024
  53. dataChannelMaxMessageSize = 65536
  54. dataChannelMaxLabelLength = 512
  55. // Psiphon uses a fork of github.com/pion/dtls/v2, selected with go mod
  56. // replace, which has an idential API apart from dtls.IsPsiphon. If
  57. // dtls.IsPsiphon is undefined, the build is not using the fork.
  58. //
  59. // Limitation: this doesn't check that the vendored code is exactly the
  60. // same code as the fork.
  61. assertDTLSFork = dtls.IsPsiphon
  62. // Similarly, check for the fork of github.com/pion/ice/v2.
  63. assertICEFork = ice.IsPsiphon
  64. // Note that Psiphon also uses a fork of github.com/pion/webrtc/v3, but it
  65. // has an API change which will cause builds to fail when not present.
  66. )
  67. // webRTCConn is a WebRTC connection between two peers, with a data channel
  68. // used to relay streams or packets between them. WebRTCConn implements the
  69. // net.Conn interface.
  70. type webRTCConn struct {
  71. config *webRTCConfig
  72. trafficShapingParameters *DataChannelTrafficShapingParameters
  73. mutex sync.Mutex
  74. udpConn net.PacketConn
  75. portMapper *portMapper
  76. isClosed bool
  77. closedSignal chan struct{}
  78. peerConnection *webrtc.PeerConnection
  79. dataChannel *webrtc.DataChannel
  80. dataChannelConn datachannel.ReadWriteCloser
  81. dataChannelOpenedSignal chan struct{}
  82. dataChannelOpenedOnce sync.Once
  83. dataChannelWriteBufferSignal chan struct{}
  84. decoyDone bool
  85. iceCandidatePairMetrics common.LogFields
  86. readMutex sync.Mutex
  87. readBuffer []byte
  88. readOffset int
  89. readLength int
  90. readError error
  91. peerPaddingDone bool
  92. writeMutex sync.Mutex
  93. trafficShapingPRNG *prng.PRNG
  94. trafficShapingBuffer *bytes.Buffer
  95. paddedMessageCount int
  96. decoyMessageCount int
  97. trafficShapingDone bool
  98. paddedMessagesSent int32
  99. paddedMessagesReceived int32
  100. decoyMessagesSent int32
  101. decoyMessagesReceived int32
  102. }
  103. // webRTCConfig specifies the configuration for a WebRTC dial.
  104. type webRTCConfig struct {
  105. // Logger is used to log events.
  106. Logger common.Logger
  107. // EnableDebugLogging indicates whether to log pion/webrtc debug and trace
  108. // events. When enabled, these events will be logged to the specified
  109. // Logger at a Debug log level.
  110. EnableDebugLogging bool
  111. // WebRTCDialCoordinator specifies specific WebRTC dial strategies and
  112. // settings; WebRTCDialCoordinator also facilities dial replay by
  113. // receiving callbacks when individual dial steps succeed or fail.
  114. WebRTCDialCoordinator WebRTCDialCoordinator
  115. // ClientRootObfuscationSecret is generated (or replayed) by the client
  116. // and sent to the proxy and used to drive obfuscation operations.
  117. ClientRootObfuscationSecret ObfuscationSecret
  118. // DoDTLSRandomization indicates whether to perform DTLS randomization.
  119. DoDTLSRandomization bool
  120. // TrafficShapingParameters indicates whether and how to perform data channel traffic shaping.
  121. TrafficShapingParameters *DataChannelTrafficShapingParameters
  122. // ReliableTransport indicates whether to configure the WebRTC data
  123. // channel to use reliable transport. Set ReliableTransport when proxying
  124. // a TCP stream, and unset it when proxying a UDP packets flow with its
  125. // own reliability later, such as QUIC.
  126. ReliableTransport bool
  127. }
  128. // newWebRTCConnWithOffer initiates a new WebRTC connection. An offer SDP is
  129. // returned, to be sent to the peer. After the offer SDP is forwarded and an
  130. // answer SDP received in response, call SetRemoteSDP with the answer SDP and
  131. // then call AwaitInitialDataChannel to await the eventual WebRTC connection
  132. // establishment.
  133. func newWebRTCConnForOffer(
  134. ctx context.Context,
  135. config *webRTCConfig,
  136. hasPersonalCompartmentIDs bool) (
  137. *webRTCConn, WebRTCSessionDescription, *webRTCSDPMetrics, error) {
  138. conn, SDP, metrics, err := newWebRTCConn(
  139. ctx, config, nil, hasPersonalCompartmentIDs)
  140. if err != nil {
  141. return nil, WebRTCSessionDescription{}, nil, errors.Trace(err)
  142. }
  143. return conn, *SDP, metrics, nil
  144. }
  145. // newWebRTCConnWithAnswer creates a new WebRTC connection initiated by a peer
  146. // that provided an offer SDP. An answer SDP is returned to be sent to the
  147. // peer. After the answer SDP is forwarded, call AwaitInitialDataChannel to
  148. // await the eventual WebRTC connection establishment.
  149. func newWebRTCConnForAnswer(
  150. ctx context.Context,
  151. config *webRTCConfig,
  152. peerSDP WebRTCSessionDescription,
  153. hasPersonalCompartmentIDs bool) (
  154. *webRTCConn, WebRTCSessionDescription, *webRTCSDPMetrics, error) {
  155. conn, SDP, metrics, err := newWebRTCConn(
  156. ctx, config, &peerSDP, hasPersonalCompartmentIDs)
  157. if err != nil {
  158. return nil, WebRTCSessionDescription{}, nil, errors.Trace(err)
  159. }
  160. return conn, *SDP, metrics, nil
  161. }
  162. func newWebRTCConn(
  163. ctx context.Context,
  164. config *webRTCConfig,
  165. peerSDP *WebRTCSessionDescription,
  166. hasPersonalCompartmentIDs bool) (
  167. retconn *webRTCConn,
  168. retSDP *WebRTCSessionDescription,
  169. retMetrics *webRTCSDPMetrics,
  170. retErr error) {
  171. isOffer := peerSDP == nil
  172. udpConn, err := config.WebRTCDialCoordinator.UDPListen(ctx)
  173. if err != nil {
  174. return nil, nil, nil, errors.Trace(err)
  175. }
  176. // Initialize WebRTC
  177. // There is no explicit anti-probing measures for the proxy side of the
  178. // WebRTC connection, since each proxy "listener" is ephemeral, and since
  179. // the WebRTC data channel protocol authenticates peers with
  180. // certificates, so even if a probe were to find an ephemeral proxy
  181. // listener, the listener can respond the same as a normal WebRTC end
  182. // point would respond to a peer that doesn't have the correct credentials.
  183. //
  184. // pion's Mux API is used, as it enables providing a pre-created UDP
  185. // socket which is configured with necessary BindToDevice settings. We do
  186. // not actually multiplex multiple client connections on a single proxy
  187. // connection. As a proxy creates a new UDP socket and Mux for each
  188. // client, this currently open issue should not impact our
  189. // implementation: "Listener doesn't process parallel handshakes",
  190. // https://github.com/pion/dtls/issues/279.
  191. //
  192. // We detach data channels in order to use the standard Read/Write APIs.
  193. // As detaching avoids using the pion DataChannel read loop, this
  194. // currently open issue should not impact our
  195. // implementation: "DataChannel.readLoop goroutine leak",
  196. // https://github.com/pion/webrtc/issues/2098.
  197. // UDPMux Limitations:
  198. //
  199. // For Psiphon, WebRTCDialCoordinator.UDPListen will call
  200. // https://pkg.go.dev/net#ListenUDP with an unspecified IP address, in
  201. // order to listen on all available interfaces, both IPv4 and IPv6.
  202. // However, using webrtc.NewICEUDPMux and a UDP conn with an unspecified
  203. // IP address results in this log warning: "UDPMuxDefault should not
  204. // listening on unspecified address, use NewMultiUDPMuxFromPort instead".
  205. //
  206. // With NewICEUDPMux and an unspecified IP address, pion currently
  207. // enumerates local, active interfaces and derives a list of listening
  208. // addresses, combining each interface's IP addresses with the assigned
  209. // port:
  210. // https://github.com/pion/ice/blob/8c5b0991ef3bb070e47afda96faf090e8bf94be6/net.go#L35.
  211. // While this works ok in many cases, this PR,
  212. // https://github.com/pion/ice/pull/475, indicates the nature of the
  213. // issue with UDPMuxDefault:
  214. //
  215. // > When we have multiple host candidates and been mux to a single port,
  216. // > if these candidates share a same conn (either tcp or udp), they
  217. // > might read other's [messages causing failure].
  218. //
  219. // This PR, https://github.com/pion/ice/pull/473, also describes the issue:
  220. //
  221. // > When using UDPMux and UniversalUDPMux, it is possible that a
  222. // > registerConnForAddress() could be called twice or more for the same
  223. // > remote candidate (endpoint) by different candidates. E.g., when
  224. // > different HOST candidates ping the same remote candidate, the
  225. // > udpMuxedConn gets stored once. The second candidate will never
  226. // > receive a response. This is also the case when a single socket is
  227. // > used for gathering SRFLX and HOST candidates.
  228. //
  229. // PR 475 introduced MultiUDPMuxDefault to address the issue. However, at
  230. // this time, https://github.com/pion/ice/releases/tag/v2.3.6, there's an
  231. // open bug with MultiUDPMuxDefault
  232. // https://github.com/pion/ice/issues/507: "Multi UDP Mux can't works
  233. // when remote also enables Multi UDP Mux". Running the test program
  234. // attached to the bug confirms that no data channel is established;
  235. // while switching the test code to use NewICEUDPMux results in a
  236. // successful data channel connection. Since we need to use a Mux API on
  237. // both clients and proxies, we can't yet use MultiUDPMux.
  238. //
  239. // We patch pion/webrtc to add the SetICEUDPMuxSrflx functionality from
  240. // the currently unmerged https://github.com/pion/webrtc/pull/2298.
  241. // Without SetICEUDPMuxSrflx, STUN operations don't use the mux.
  242. //
  243. // We patch pion/ice gatherCandidatesSrflxUDPMux vendor patch to include
  244. // only the correct network type (IPv4 or IPv6) address candidates.
  245. // Without this patch, we observed up to 2x duplicate/redundant STUN
  246. // candidates.
  247. //
  248. // TODO: implement and try using transport.Net UDP dial functions in place
  249. // of NewICEUDPMux and pre-dialed UDP conn; track all dialed UDP
  250. // connections to close on WebRTCConn.Close; this approach would require
  251. // an alternative approach to injecting port mapping candidates, which
  252. // currently depends on the mux UDP socket being available outside of pion.
  253. // Another limitation and issue with NewICEUDPMux is that its enumeration
  254. // of all local interfaces and IPs includes many IPv6 addresses for
  255. // certain interfaces. For example, on macOS,
  256. // https://apple.stackexchange.com/a/371661, there are "secured" IPv6
  257. // addresses and many "temporary" IPv6 addresses, with all but one
  258. // temporary address being "deprecated". Instead of a full enumeration,
  259. // we should select only the non-deprecated temporary IPv6 address --
  260. // both for performance (avoid excess STUN requests) and privacy.
  261. //
  262. // Go has a proposal to expose the necessary IPv6 address information:
  263. // https://github.com/golang/go/issues/42694. However, as of Android SDK
  264. // 30, Go's net.InterfaceAddrs doesn't work at all:
  265. // https://github.com/pion/transport/issues/228,
  266. // https://github.com/golang/go/issues/40569.
  267. //
  268. // Note that it's not currently possible to
  269. // webrtc.SettingEngine.SetIPFilter to limit IPv6 selection to a single
  270. // candidate; that IP filter is not passed through to localInterfaces in
  271. // the NewUDPMuxDefault case. And even if it were, there's no guarantee
  272. // that the the first IPv6 address passed to the filter would be the
  273. // non-deprecated temporary address.
  274. //
  275. // To workaround net.Interface issues, we use SettingEngine.SetNet to plug
  276. // in an alternative implementation of net.Interface which selects only
  277. // one IPv4 and one IPv6 active interface and IP address and uses the
  278. // anet package for Android. See pionNetwork for more details.
  279. deadline, _ := ctx.Deadline()
  280. TTL := time.Until(deadline)
  281. pionLoggerFactory := newPionLoggerFactory(
  282. config.Logger,
  283. config.EnableDebugLogging)
  284. pionNetwork := newPionNetwork(
  285. ctx, pionLoggerFactory.NewLogger("net"), config.WebRTCDialCoordinator)
  286. udpMux := webrtc.NewICEUniversalUDPMux(
  287. pionLoggerFactory.NewLogger("mux"), udpConn, TTL, pionNetwork)
  288. settingEngine := webrtc.SettingEngine{
  289. LoggerFactory: pionLoggerFactory,
  290. }
  291. settingEngine.SetNet(pionNetwork)
  292. settingEngine.DetachDataChannels()
  293. settingEngine.SetICEMulticastDNSMode(ice.MulticastDNSModeDisabled)
  294. settingEngine.SetICEUDPMux(udpMux)
  295. settingEngine.SetICEUDPMuxSrflx(udpMux)
  296. // Set this behavior to look like common web browser WebRTC stacks.
  297. settingEngine.SetDTLSInsecureSkipHelloVerify(true)
  298. settingEngine.EnableSCTPZeroChecksum(true)
  299. // Timeout, retry, and delay adjustments
  300. //
  301. // - Add some jitter to timed operations to avoid a trivial pion timing
  302. // fingerprint.
  303. //
  304. // - Reduce the wait time for STUN and peer reflexive candidates from the
  305. // default 500ms and 1s.
  306. //
  307. // - Reduce keepalives from the default 2s to +/-15s and increase
  308. // disconnect timeout from the default 5s to 3x15s.
  309. //
  310. // TODO:
  311. //
  312. // - Configuration via tactics.
  313. //
  314. // - While the RFC,
  315. // https://datatracker.ietf.org/doc/html/rfc5245#section-10, calls for
  316. // keep alives no less than 15s, implementations such as Chrome send
  317. // keep alives much more frequently,
  318. // https://issues.webrtc.org/issues/42221718.
  319. //
  320. // - Varying the period bewteen each keepalive, as is done with SSH via
  321. // SSHKeepAlivePeriodMin/Max, requires changes to pion/dtls.
  322. //
  323. // - Some traffic-related timeouts are not yet exposed via settingEngine,
  324. // including ice.defaultSTUNGatherTimeout, ice.maxBindingRequestTimeout.
  325. settingEngine.SetDTLSRetransmissionInterval(prng.JitterDuration(100*time.Millisecond, 0.1))
  326. settingEngine.SetHostAcceptanceMinWait(0)
  327. settingEngine.SetSrflxAcceptanceMinWait(prng.JitterDuration(100*time.Millisecond, 0.1))
  328. settingEngine.SetPrflxAcceptanceMinWait(prng.JitterDuration(200*time.Millisecond, 0.1))
  329. settingEngine.SetICETimeouts(45*time.Second, 0, prng.JitterDuration(15*time.Second, 0.2))
  330. settingEngine.SetICEMaxBindingRequests(10)
  331. // Initialize data channel obfuscation
  332. config.Logger.WithTraceFields(common.LogFields{
  333. "dtls_randomization": config.DoDTLSRandomization,
  334. "data_channel_traffic_shaping": config.TrafficShapingParameters != nil,
  335. }).Info("webrtc_data_channel_obfuscation")
  336. // Facilitate DTLS Client/ServerHello randomization. The client decides
  337. // whether to do DTLS randomization and generates and the proxy receives
  338. // ClientRootObfuscationSecret, so the client can orchestrate replay on
  339. // both ends of the connection by reusing an obfuscation secret. Derive a
  340. // secret specific to DTLS. SetDTLSSeed will futher derive a secure PRNG
  341. // seed specific to either the client or proxy end of the connection
  342. // (so each peer's randomization will be distinct).
  343. //
  344. // To avoid forking many pion repos in order to pass the seed through to
  345. // the DTLS implementation, SetDTLSSeed attaches the seed to the DTLS
  346. // dial context.
  347. //
  348. // Either SetDTLSSeed or SetNoDTLSSeed should be set for each conn, as the
  349. // pion/dtl fork treats no-seed as an error, as a check against the
  350. // context value mechanism.
  351. var dtlsCtx context.Context
  352. if config.DoDTLSRandomization {
  353. dtlsObfuscationSecret, err := deriveObfuscationSecret(
  354. config.ClientRootObfuscationSecret, "in-proxy-DTLS-seed")
  355. if err != nil {
  356. return nil, nil, nil, errors.Trace(err)
  357. }
  358. baseSeed := prng.Seed(dtlsObfuscationSecret)
  359. dtlsCtx, err = inproxy_dtls.SetDTLSSeed(ctx, &baseSeed, isOffer)
  360. if err != nil {
  361. return nil, nil, nil, errors.Trace(err)
  362. }
  363. } else {
  364. dtlsCtx = inproxy_dtls.SetNoDTLSSeed(ctx)
  365. }
  366. settingEngine.SetDTLSConnectContextMaker(func() (context.Context, func()) {
  367. return context.WithCancel(dtlsCtx)
  368. })
  369. // Configure traffic shaping, which adds random padding and decoy messages
  370. // to data channel message flows.
  371. var trafficShapingPRNG *prng.PRNG
  372. trafficShapingBuffer := new(bytes.Buffer)
  373. paddedMessageCount := 0
  374. decoyMessageCount := 0
  375. if config.TrafficShapingParameters != nil {
  376. // TODO: also use pion/dtls.Config.PaddingLengthGenerator?
  377. trafficShapingContext := "in-proxy-data-channel-traffic-shaping-offer"
  378. if !isOffer {
  379. trafficShapingContext = "in-proxy-data-channel-traffic-shaping-answer"
  380. }
  381. trafficShapingObfuscationSecret, err := deriveObfuscationSecret(
  382. config.ClientRootObfuscationSecret, trafficShapingContext)
  383. if err != nil {
  384. return nil, nil, nil, errors.Trace(err)
  385. }
  386. seed := prng.Seed(trafficShapingObfuscationSecret)
  387. trafficShapingPRNG = prng.NewPRNGWithSeed(&seed)
  388. paddedMessageCount = trafficShapingPRNG.Range(
  389. config.TrafficShapingParameters.MinPaddedMessages,
  390. config.TrafficShapingParameters.MaxPaddedMessages)
  391. decoyMessageCount = trafficShapingPRNG.Range(
  392. config.TrafficShapingParameters.MinDecoyMessages,
  393. config.TrafficShapingParameters.MaxDecoyMessages)
  394. }
  395. // NAT traversal setup
  396. // When DisableInboundForMobileNetworks is set, skip both STUN and port
  397. // mapping for mobile networks. Most mobile networks use CGNAT and
  398. // neither STUN nor port mapping will be effective. It's faster to not
  399. // wait for something that ultimately won't work.
  400. disableInbound := config.WebRTCDialCoordinator.DisableInboundForMobileNetworks() &&
  401. config.WebRTCDialCoordinator.NetworkType() == NetworkTypeMobile
  402. // Try to establish a port mapping (UPnP-IGD, PCP, or NAT-PMP), using port
  403. // mapping services previously found and recorded in PortMappingProbe.
  404. // Note that portMapper may perform additional probes. portMapper.start
  405. // launches the process of creating a new port mapping and does not
  406. // block. Port mappings are not part of the WebRTC standard, or supported
  407. // by pion/webrtc. Instead, if a port mapping is established, it's edited
  408. // into the SDP as a new host-type ICE candidate.
  409. portMappingProbe := config.WebRTCDialCoordinator.PortMappingProbe()
  410. doPortMapping := !disableInbound &&
  411. !config.WebRTCDialCoordinator.DisablePortMapping() &&
  412. portMappingProbe != nil
  413. var portMapper *portMapper
  414. if doPortMapping {
  415. localPort := udpConn.LocalAddr().(*net.UDPAddr).Port
  416. portMapper, err = newPortMapper(config.Logger, portMappingProbe, localPort)
  417. if err != nil {
  418. config.Logger.WithTraceFields(common.LogFields{
  419. "error": err,
  420. }).Warning("newPortMapper failed")
  421. // Continue without port mapper
  422. } else {
  423. portMapper.start()
  424. // On early return, portMapper will be closed by the following
  425. // deferred conn.Close.
  426. }
  427. }
  428. // Select a STUN server for ICE hole punching. The STUN server to be used
  429. // needs only support bind and not full RFC5780 NAT discovery.
  430. //
  431. // Each dial trys only one STUN server; in Psiphon tunnel establishment,
  432. // other, concurrent in-proxy dials may select alternative STUN servers
  433. // via WebRTCDialCoordinator. When the STUN server operation is successful,
  434. // WebRTCDialCoordinator will be signaled so that it may configure the STUN
  435. // server selection for replay.
  436. //
  437. // The STUN server will observe proxy IP addresses. Enumeration is
  438. // mitigated by using various public STUN servers, including Psiphon STUN
  439. // servers for proxies in non-censored regions. Proxies are also more
  440. // ephemeral than Psiphon servers.
  441. RFC5780 := false
  442. stunServerAddress := config.WebRTCDialCoordinator.STUNServerAddress(RFC5780)
  443. // Proceed even when stunServerAddress is "" and !DisableSTUN, as ICE may
  444. // find other host candidates.
  445. doSTUN := stunServerAddress != "" && !disableInbound && !config.WebRTCDialCoordinator.DisableSTUN()
  446. var ICEServers []webrtc.ICEServer
  447. if doSTUN {
  448. // stunServerAddress domain names are resolved with the Psiphon custom
  449. // resolver via pionNetwork.ResolveUDPAddr
  450. ICEServers = []webrtc.ICEServer{{URLs: []string{"stun:" + stunServerAddress}}}
  451. }
  452. conn := &webRTCConn{
  453. config: config,
  454. udpConn: udpConn,
  455. portMapper: portMapper,
  456. closedSignal: make(chan struct{}),
  457. dataChannelOpenedSignal: make(chan struct{}),
  458. dataChannelWriteBufferSignal: make(chan struct{}, 1),
  459. // A data channel uses SCTP and is message oriented. The maximum
  460. // message size supported by pion/webrtc is 65536:
  461. // https://github.com/pion/webrtc/blob/dce970438344727af9c9965f88d958c55d32e64d/datachannel.go#L19.
  462. // This read buffer must be as large as the maximum message size or
  463. // else a read may fail with io.ErrShortBuffer.
  464. readBuffer: make([]byte, dataChannelMaxMessageSize),
  465. trafficShapingPRNG: trafficShapingPRNG,
  466. trafficShapingBuffer: trafficShapingBuffer,
  467. paddedMessageCount: paddedMessageCount,
  468. decoyMessageCount: decoyMessageCount,
  469. }
  470. defer func() {
  471. if retErr != nil {
  472. // Cleanup on early return
  473. conn.Close()
  474. // Notify the WebRTCDialCoordinator that the operation failed so
  475. // that it can clear replay for that STUN server selection.
  476. //
  477. // Limitation: the error here may be due to failures unrelated to
  478. // the STUN server.
  479. if ctx.Err() == nil && doSTUN {
  480. config.WebRTCDialCoordinator.STUNServerAddressFailed(RFC5780, stunServerAddress)
  481. }
  482. }
  483. }()
  484. settingEngine.SetICEBindingRequestHandler(conn.onICEBindingRequest)
  485. // All settingEngine configuration must be done before calling NewAPI.
  486. webRTCAPI := webrtc.NewAPI(webrtc.WithSettingEngine(settingEngine))
  487. conn.peerConnection, err = webRTCAPI.NewPeerConnection(
  488. webrtc.Configuration{
  489. ICEServers: ICEServers,
  490. })
  491. if err != nil {
  492. return nil, nil, nil, errors.Trace(err)
  493. }
  494. conn.peerConnection.OnConnectionStateChange(conn.onConnectionStateChange)
  495. conn.peerConnection.OnICECandidate(conn.onICECandidate)
  496. conn.peerConnection.OnICEConnectionStateChange(conn.onICEConnectionStateChange)
  497. conn.peerConnection.OnICEGatheringStateChange(conn.onICEGatheringStateChange)
  498. conn.peerConnection.OnNegotiationNeeded(conn.onNegotiationNeeded)
  499. conn.peerConnection.OnSignalingStateChange(conn.onSignalingStateChange)
  500. conn.peerConnection.OnDataChannel(conn.onDataChannel)
  501. // As a future enhancement, consider using media channels instead of data
  502. // channels, as media channels may be more common. Proxied QUIC would
  503. // work over an unreliable media channel. Note that a media channel is
  504. // still prefixed with STUN and DTLS exchanges before SRTP begins, so the
  505. // first few packets are the same as a data channel.
  506. // The offer sets the data channel configuration.
  507. if isOffer {
  508. dataChannelInit := &webrtc.DataChannelInit{}
  509. if !config.ReliableTransport {
  510. ordered := false
  511. dataChannelInit.Ordered = &ordered
  512. maxRetransmits := uint16(0)
  513. dataChannelInit.MaxRetransmits = &maxRetransmits
  514. }
  515. // Generate a random length label, to vary the DATA_CHANNEL_OPEN
  516. // message length. The label is derived from and replayed via
  517. // ClientRootObfuscationSecret.
  518. labelObfuscationSecret, err := deriveObfuscationSecret(
  519. config.ClientRootObfuscationSecret, "in-proxy-data-channel-label")
  520. if err != nil {
  521. return nil, nil, nil, errors.Trace(err)
  522. }
  523. seed := prng.Seed(labelObfuscationSecret)
  524. labelPRNG := prng.NewPRNGWithSeed(&seed)
  525. dataChannelLabel := labelPRNG.HexString(
  526. labelPRNG.Range(1, dataChannelMaxLabelLength/2))
  527. dataChannel, err := conn.peerConnection.CreateDataChannel(
  528. dataChannelLabel, dataChannelInit)
  529. if err != nil {
  530. return nil, nil, nil, errors.Trace(err)
  531. }
  532. conn.setDataChannel(dataChannel)
  533. }
  534. // Prepare to await full ICE completion, including STUN candidates.
  535. // Trickle ICE is not used, simplifying the broker API. It's expected
  536. // that most clients and proxies will be behind a NAT, and not have
  537. // publicly addressable host candidates. TURN is not used. So most
  538. // candidates will be STUN, or server-reflexive, candidates.
  539. //
  540. // Later, the first to complete out of ICE or port mapping is used.
  541. //
  542. // TODO: stop waiting if an IPv6 host candidate is found?
  543. iceComplete := webrtc.GatheringCompletePromise(conn.peerConnection)
  544. // Create an offer, or input a peer's offer to create an answer.
  545. if isOffer {
  546. offer, err := conn.peerConnection.CreateOffer(nil)
  547. if err != nil {
  548. return nil, nil, nil, errors.Trace(err)
  549. }
  550. err = conn.peerConnection.SetLocalDescription(offer)
  551. if err != nil {
  552. return nil, nil, nil, errors.Trace(err)
  553. }
  554. } else {
  555. SDP := peerSDP.SDP
  556. if hasPersonalCompartmentIDs {
  557. // In personal pairing mode, the peer SDP may include private IP
  558. // addresses. To avoid unnecessary network traffic, filter out
  559. // any peer private IP addresses for which there is no
  560. // corresponding local, active interface.
  561. errorOnNoCandidates := false
  562. allowPrivateIPAddressCandidates := true
  563. filterPrivateIPAddressCandidates := true
  564. adjustedSDP, _, err := filterSDPAddresses(
  565. []byte(peerSDP.SDP),
  566. errorOnNoCandidates,
  567. nil,
  568. common.GeoIPData{},
  569. allowPrivateIPAddressCandidates,
  570. filterPrivateIPAddressCandidates)
  571. if err != nil {
  572. return nil, nil, nil, errors.Trace(err)
  573. }
  574. SDP = string(adjustedSDP)
  575. }
  576. pionSessionDescription := webrtc.SessionDescription{
  577. Type: webrtc.SDPType(peerSDP.Type),
  578. SDP: SDP,
  579. }
  580. err = conn.peerConnection.SetRemoteDescription(pionSessionDescription)
  581. if err != nil {
  582. return nil, nil, nil, errors.Trace(err)
  583. }
  584. answer, err := conn.peerConnection.CreateAnswer(nil)
  585. if err != nil {
  586. return nil, nil, nil, errors.Trace(err)
  587. }
  588. err = conn.peerConnection.SetLocalDescription(answer)
  589. if err != nil {
  590. return nil, nil, nil, errors.Trace(err)
  591. }
  592. }
  593. // Await either ICE or port mapping completion.
  594. // As a future enhancement, track which of ICE or port mapping succeeds
  595. // and is then followed by a failed WebRTC dial; stop trying the method
  596. // that often fails.
  597. iceCompleted := false
  598. portMappingExternalAddr := ""
  599. if portMapper == nil {
  600. select {
  601. case <-iceComplete:
  602. iceCompleted = true
  603. case <-ctx.Done():
  604. return nil, nil, nil, errors.Trace(ctx.Err())
  605. }
  606. } else {
  607. select {
  608. case <-iceComplete:
  609. iceCompleted = true
  610. case portMappingExternalAddr = <-portMapper.portMappingExternalAddress():
  611. case <-ctx.Done():
  612. return nil, nil, nil, errors.Trace(ctx.Err())
  613. }
  614. // When STUN is skipped and a port mapping is expected to be
  615. // available, await a port mapping for a short period. In this
  616. // scenario, pion ICE gathering may complete first, since it's only
  617. // gathering local host candidates.
  618. //
  619. // It remains possible that these local candidates are sufficient, if
  620. // they are public IPs or private IPs on the same LAN as the peer in
  621. // the case of personal pairing. For that reason, the await timeout
  622. // should be no more than a couple of seconds.
  623. //
  624. // TODO: also await port mappings when doSTUN, in case there are no
  625. // STUN candidates; see hasServerReflexive check below; as it stands,
  626. // in this case, it's more likely that port mapping won the previous
  627. // select race.
  628. if iceCompleted && portMappingExternalAddr == "" && !doSTUN && doPortMapping {
  629. timer := time.NewTimer(
  630. common.ValueOrDefault(
  631. config.WebRTCDialCoordinator.WebRTCAwaitPortMappingTimeout(),
  632. portMappingAwaitTimeout))
  633. defer timer.Stop()
  634. select {
  635. case portMappingExternalAddr = <-portMapper.portMappingExternalAddress():
  636. case <-timer.C:
  637. // Continue without port mapping
  638. case <-ctx.Done():
  639. return nil, nil, nil, errors.Trace(ctx.Err())
  640. }
  641. timer.Stop()
  642. }
  643. if portMapper != nil && portMappingExternalAddr == "" {
  644. // Release any port mapping resources when not using it.
  645. portMapper.close()
  646. conn.portMapper = nil
  647. } else if portMappingExternalAddr != "" {
  648. // Update responding port mapping types for metrics.
  649. //
  650. // Limitation: if there are multiple responding protocol types, it's
  651. // not known here which was used for this dial.
  652. config.WebRTCDialCoordinator.SetPortMappingTypes(
  653. getRespondingPortMappingTypes(config.WebRTCDialCoordinator.NetworkID()))
  654. }
  655. }
  656. config.Logger.WithTraceFields(common.LogFields{
  657. "ice_completed": iceCompleted,
  658. "port_mapping": portMappingExternalAddr != "",
  659. }).Info("webrtc_candidates_gathered")
  660. // Get the offer or answer, now populated with any ICE candidates.
  661. localDescription := conn.peerConnection.LocalDescription()
  662. // Adjust the SDP, removing local network addresses and adding any
  663. // port mapping candidate. Clients (offer) are permitted to have
  664. // no ICE candidates but proxies (answer) must have at least one
  665. //candidate.
  666. errorOnNoCandidates := !isOffer
  667. adjustedSDP, metrics, err := prepareSDPAddresses(
  668. []byte(localDescription.SDP),
  669. errorOnNoCandidates,
  670. portMappingExternalAddr,
  671. config.WebRTCDialCoordinator.DisableIPv6ICECandidates(),
  672. hasPersonalCompartmentIDs)
  673. if err != nil {
  674. return nil, nil, nil, errors.Trace(err)
  675. }
  676. // When STUN was attempted, ICE completed, and a STUN server-reflexive
  677. // candidate is present, notify the WebRTCDialCoordinator so that it can
  678. // set replay for that STUN server selection.
  679. if iceCompleted && doSTUN {
  680. hasServerReflexive := false
  681. for _, candidateType := range metrics.iceCandidateTypes {
  682. if candidateType == ICECandidateServerReflexive {
  683. hasServerReflexive = true
  684. }
  685. }
  686. if hasServerReflexive {
  687. config.WebRTCDialCoordinator.STUNServerAddressSucceeded(RFC5780, stunServerAddress)
  688. } else {
  689. config.WebRTCDialCoordinator.STUNServerAddressFailed(RFC5780, stunServerAddress)
  690. }
  691. }
  692. // The WebRTCConn is prepared, but the data channel is not yet connected.
  693. // On the offer end, the peer's following answer must be input to
  694. // SetRemoteSDP. And both ends must call AwaitInitialDataChannel to await
  695. // the data channel establishment.
  696. return conn,
  697. &WebRTCSessionDescription{
  698. Type: int(localDescription.Type),
  699. SDP: string(adjustedSDP),
  700. },
  701. metrics,
  702. nil
  703. }
  704. func (conn *webRTCConn) setDataChannel(dataChannel *webrtc.DataChannel) {
  705. // Assumes the caller holds conn.mutex, or is newWebRTCConn, creating the
  706. // conn.
  707. conn.dataChannel = dataChannel
  708. conn.dataChannel.OnOpen(conn.onDataChannelOpen)
  709. conn.dataChannel.OnClose(conn.onDataChannelClose)
  710. // Set up flow control (see comment in conn.Write)
  711. conn.dataChannel.SetBufferedAmountLowThreshold(dataChannelBufferedAmountLowThreshold)
  712. conn.dataChannel.OnBufferedAmountLow(func() {
  713. select {
  714. case conn.dataChannelWriteBufferSignal <- struct{}{}:
  715. default:
  716. }
  717. })
  718. }
  719. // SetRemoteSDP takes the answer SDP that is received in response to an offer
  720. // SDP. SetRemoteSDP initiates the WebRTC connection establishment on the
  721. // offer end.
  722. func (conn *webRTCConn) SetRemoteSDP(
  723. peerSDP WebRTCSessionDescription,
  724. hasPersonalCompartmentIDs bool) error {
  725. conn.mutex.Lock()
  726. defer conn.mutex.Unlock()
  727. SDP := peerSDP.SDP
  728. if hasPersonalCompartmentIDs {
  729. // In personal pairing mode, the peer SDP may include private IP
  730. // addresses. To avoid unnecessary network traffic, filter out any
  731. // peer private IP addresses for which there is no corresponding
  732. // local, active interface.
  733. errorOnNoCandidates := false
  734. allowPrivateIPAddressCandidates := true
  735. filterPrivateIPAddressCandidates := true
  736. adjustedSDP, _, err := filterSDPAddresses(
  737. []byte(peerSDP.SDP),
  738. errorOnNoCandidates,
  739. nil,
  740. common.GeoIPData{},
  741. allowPrivateIPAddressCandidates,
  742. filterPrivateIPAddressCandidates)
  743. if err != nil {
  744. return errors.Trace(err)
  745. }
  746. SDP = string(adjustedSDP)
  747. }
  748. pionSessionDescription := webrtc.SessionDescription{
  749. Type: webrtc.SDPType(peerSDP.Type),
  750. SDP: SDP,
  751. }
  752. err := conn.peerConnection.SetRemoteDescription(pionSessionDescription)
  753. if err != nil {
  754. return errors.Trace(err)
  755. }
  756. return nil
  757. }
  758. // AwaitInitialDataChannel returns when the data channel is established, or
  759. // when an error has occured.
  760. func (conn *webRTCConn) AwaitInitialDataChannel(ctx context.Context) error {
  761. // Don't lock the mutex, or else necessary operations will deadlock.
  762. select {
  763. case <-conn.dataChannelOpenedSignal:
  764. // The data channel is connected.
  765. err := conn.recordSelectedICECandidateStats()
  766. if err != nil {
  767. conn.config.Logger.WithTraceFields(common.LogFields{
  768. "error": err.Error()}).Warning("recordCandidateStats failed")
  769. // Continue without log
  770. }
  771. case <-ctx.Done():
  772. return errors.Tracef("with ICE candidate pairs %s: %w",
  773. conn.getICECandidatePairsSummary(),
  774. ctx.Err())
  775. case <-conn.closedSignal:
  776. return errors.TraceNew("connection has closed")
  777. }
  778. return nil
  779. }
  780. func (conn *webRTCConn) getICECandidatePairsSummary() string {
  781. conn.mutex.Lock()
  782. defer conn.mutex.Unlock()
  783. stateCounts := map[webrtc.StatsICECandidatePairState]int{}
  784. statsReport := conn.peerConnection.GetStats()
  785. for key, stats := range statsReport {
  786. // Uses the pion StatsReport key formats "candidate:<ID>"
  787. // and "candidate:<ID>-candidate:<ID>"
  788. key, found := strings.CutPrefix(key, "candidate:")
  789. if !found {
  790. continue
  791. }
  792. candidateIDs := strings.Split(key, "-candidate:")
  793. if len(candidateIDs) != 2 {
  794. continue
  795. }
  796. candidatePairStats, ok := stats.(webrtc.ICECandidatePairStats)
  797. if !ok {
  798. continue
  799. }
  800. stateCounts[candidatePairStats.State] += 1
  801. }
  802. if len(stateCounts) == 0 {
  803. return "(none)"
  804. }
  805. var strs []string
  806. for state, count := range stateCounts {
  807. strs = append(strs, fmt.Sprintf("%s(%d)", state, count))
  808. }
  809. return strings.Join(strs, ", ")
  810. }
  811. func (conn *webRTCConn) recordSelectedICECandidateStats() error {
  812. conn.mutex.Lock()
  813. defer conn.mutex.Unlock()
  814. statsReport := conn.peerConnection.GetStats()
  815. foundNominatedPair := false
  816. for key, stats := range statsReport {
  817. // Uses the pion StatsReport key formats "candidate:<ID>"
  818. // and "candidate:<ID>-candidate:<ID>"
  819. key, found := strings.CutPrefix(key, "candidate:")
  820. if !found {
  821. continue
  822. }
  823. candidateIDs := strings.Split(key, "-candidate:")
  824. if len(candidateIDs) != 2 {
  825. continue
  826. }
  827. candidatePairStats, ok := stats.(webrtc.ICECandidatePairStats)
  828. if !ok ||
  829. candidatePairStats.State != webrtc.StatsICECandidatePairStateSucceeded ||
  830. !candidatePairStats.Nominated {
  831. continue
  832. }
  833. localKey := fmt.Sprintf("candidate:%s", candidateIDs[0])
  834. stats, ok := statsReport[localKey]
  835. if !ok {
  836. return errors.TraceNew("missing local ICECandidateStats")
  837. }
  838. localCandidateStats, ok := stats.(webrtc.ICECandidateStats)
  839. if !ok {
  840. return errors.TraceNew("unexpected local ICECandidateStats")
  841. }
  842. remoteKey := fmt.Sprintf("candidate:%s", candidateIDs[1])
  843. stats, ok = statsReport[remoteKey]
  844. if !ok {
  845. return errors.TraceNew("missing remote ICECandidateStats")
  846. }
  847. remoteCandidateStats, ok := stats.(webrtc.ICECandidateStats)
  848. if !ok {
  849. return errors.TraceNew("unexpected remote ICECandidateStats")
  850. }
  851. // Use the same ICE candidate type names as logged in broker logs.
  852. logCandidateType := func(
  853. iceCandidateType webrtc.ICECandidateType) string {
  854. logType := ICECandidateUnknown
  855. switch iceCandidateType {
  856. case webrtc.ICECandidateTypeHost:
  857. logType = ICECandidateHost
  858. case webrtc.ICECandidateTypeSrflx:
  859. logType = ICECandidateServerReflexive
  860. case webrtc.ICECandidateTypePrflx:
  861. logType = ICECandidatePeerReflexive
  862. }
  863. return logType.String()
  864. }
  865. conn.iceCandidatePairMetrics = common.LogFields{}
  866. // TODO: log which of local/remote candidate is initiator
  867. conn.iceCandidatePairMetrics["inproxy_webrtc_local_ice_candidate_type"] =
  868. logCandidateType(localCandidateStats.CandidateType)
  869. localIP := net.ParseIP(localCandidateStats.IP)
  870. isIPv6 := "0"
  871. if localIP != nil && localIP.To4() == nil {
  872. isIPv6 = "1"
  873. }
  874. isPrivate := "0"
  875. if localIP != nil && localIP.IsPrivate() {
  876. isPrivate = "1"
  877. }
  878. conn.iceCandidatePairMetrics["inproxy_webrtc_local_ice_candidate_is_IPv6"] =
  879. isIPv6
  880. conn.iceCandidatePairMetrics["inproxy_webrtc_local_ice_candidate_is_private_IP"] =
  881. isPrivate
  882. conn.iceCandidatePairMetrics["inproxy_webrtc_local_ice_candidate_port"] =
  883. localCandidateStats.Port
  884. conn.iceCandidatePairMetrics["inproxy_webrtc_remote_ice_candidate_type"] =
  885. logCandidateType(remoteCandidateStats.CandidateType)
  886. remoteIP := net.ParseIP(remoteCandidateStats.IP)
  887. isIPv6 = "0"
  888. if remoteIP != nil && remoteIP.To4() == nil {
  889. isIPv6 = "1"
  890. }
  891. isPrivate = "0"
  892. if remoteIP != nil && remoteIP.IsPrivate() {
  893. isPrivate = "1"
  894. }
  895. conn.iceCandidatePairMetrics["inproxy_webrtc_remote_ice_candidate_is_IPv6"] =
  896. isIPv6
  897. conn.iceCandidatePairMetrics["inproxy_webrtc_remote_ice_candidate_is_private_IP"] =
  898. isPrivate
  899. conn.iceCandidatePairMetrics["inproxy_webrtc_remote_ice_candidate_port"] =
  900. remoteCandidateStats.Port
  901. foundNominatedPair = true
  902. break
  903. }
  904. if !foundNominatedPair {
  905. return errors.TraceNew("missing nominated ICECandidateStatsPair")
  906. }
  907. return nil
  908. }
  909. func (conn *webRTCConn) Close() error {
  910. conn.mutex.Lock()
  911. defer conn.mutex.Unlock()
  912. if conn.isClosed {
  913. return nil
  914. }
  915. if conn.portMapper != nil {
  916. conn.portMapper.close()
  917. }
  918. if conn.dataChannelConn != nil {
  919. conn.dataChannelConn.Close()
  920. }
  921. if conn.dataChannel != nil {
  922. conn.dataChannel.Close()
  923. }
  924. if conn.peerConnection != nil {
  925. conn.peerConnection.Close()
  926. }
  927. // Close the udpConn to interrupt any blocking DTLS handshake:
  928. // https://github.com/pion/webrtc/blob/c1467e4871c78ee3f463b50d858d13dc6f2874a4/dtlstransport.go#L334-L340
  929. //
  930. // Limitation: there is no guarantee that pion sends any closing packets
  931. // before the UDP socket is closed here.
  932. if conn.udpConn != nil {
  933. conn.udpConn.Close()
  934. }
  935. close(conn.closedSignal)
  936. conn.isClosed = true
  937. return nil
  938. }
  939. func (conn *webRTCConn) IsClosed() bool {
  940. conn.mutex.Lock()
  941. defer conn.mutex.Unlock()
  942. return conn.isClosed
  943. }
  944. func (conn *webRTCConn) Read(p []byte) (int, error) {
  945. for {
  946. n, err := conn.readMessage(p)
  947. if err != nil || n > 0 {
  948. return n, err
  949. }
  950. // A decoy message was read; discard and read again.
  951. }
  952. }
  953. func (conn *webRTCConn) readMessage(p []byte) (int, error) {
  954. // Don't hold this lock, or else concurrent Writes will be blocked.
  955. conn.mutex.Lock()
  956. isClosed := conn.isClosed
  957. dataChannelConn := conn.dataChannelConn
  958. decoyDone := conn.decoyDone
  959. conn.mutex.Unlock()
  960. if isClosed {
  961. return 0, errors.TraceNew("closed")
  962. }
  963. if dataChannelConn == nil {
  964. return 0, errors.TraceNew("no data channel")
  965. }
  966. // The input read buffer, p, may not be the same length as the message
  967. // read from the data channel. Buffer the read message if another Read
  968. // call is necessary to consume it. As per https://pkg.go.dev/io#Reader,
  969. // dataChannelConn bytes read are processed even when
  970. // dataChannelConn.Read returns an error; the error value is stored and
  971. // returned with the Read call that consumes the end of the message buffer.
  972. conn.readMutex.Lock()
  973. defer conn.readMutex.Unlock()
  974. if conn.readOffset == conn.readLength {
  975. n, err := dataChannelConn.Read(conn.readBuffer)
  976. conn.readOffset = 0
  977. conn.readLength = n
  978. conn.readError = err
  979. // Skip over padding.
  980. if n > 0 && !conn.peerPaddingDone {
  981. paddingSize, n := binary.Varint(conn.readBuffer[0:conn.readLength])
  982. if (paddingSize == 0 && n <= 0) || paddingSize >= int64(conn.readLength) {
  983. return 0, errors.TraceNew("invalid padding")
  984. }
  985. if paddingSize < 0 {
  986. // When the padding header indicates a padding size of -1, the
  987. // peer is indicating that padding is done. Subsequent
  988. // messages will have no padding header or padding bytes.
  989. conn.peerPaddingDone = true
  990. conn.readOffset += n
  991. } else {
  992. conn.readOffset += n + int(paddingSize)
  993. atomic.AddInt32(&conn.paddedMessagesReceived, 1)
  994. if conn.readOffset == conn.readLength {
  995. atomic.AddInt32(&conn.decoyMessagesReceived, 1)
  996. }
  997. }
  998. }
  999. }
  1000. n := copy(p, conn.readBuffer[conn.readOffset:conn.readLength])
  1001. conn.readOffset += n
  1002. var err error
  1003. if conn.readOffset == conn.readLength {
  1004. err = conn.readError
  1005. }
  1006. // When decoy messages are enabled, periodically response to an incoming
  1007. // messages with an immediate outbound decoy message. This is similar to
  1008. // the design here:
  1009. // https://github.com/Psiphon-Labs/psiphon-tunnel-core/blob/c4f6a593a645db4479a7032a9e97d3c0b905cdfc/psiphon/common/quic/obfuscator.go#L361-L409
  1010. //
  1011. // writeMessage handles conn.decoyMessageCount, which is syncronized with
  1012. // conn.WriteMutex, as well as other specific logic. Here we just signal
  1013. // writeMessage based on the read event.
  1014. //
  1015. // When the data channel already has buffered writes in excess of a decoy
  1016. // message size, the writeMessage skips the decoy message and returns
  1017. // without blocking, so Read calls will not block.
  1018. if !decoyDone {
  1019. _, _ = conn.writeMessage(nil, true)
  1020. }
  1021. return n, errors.Trace(err)
  1022. }
  1023. func (conn *webRTCConn) Write(p []byte) (int, error) {
  1024. return conn.writeMessage(p, false)
  1025. }
  1026. func (conn *webRTCConn) writeMessage(p []byte, decoy bool) (int, error) {
  1027. if p != nil && decoy {
  1028. return 0, errors.TraceNew("invalid write parameters")
  1029. }
  1030. // pion/sctp doesn't handle 0-byte writes correctly, so drop/skip at this level.
  1031. //
  1032. // Testing shows that the SCTP connection stalls after a 0-byte write. In
  1033. // the pion/sctp implementation,
  1034. // https://github.com/pion/sctp/blob/v1.8.8/stream.go#L254-L278 and
  1035. // https://github.com/pion/sctp/blob/v1.8.8/stream.go#L280-L336, it
  1036. // appears that a zero-byte write won't send an SCTP messages but does
  1037. // increment a sequence number.
  1038. if len(p) == 0 && !decoy {
  1039. return 0, nil
  1040. }
  1041. // Don't hold this lock, or else concurrent Reads will be blocked.
  1042. conn.mutex.Lock()
  1043. isClosed := conn.isClosed
  1044. bufferedAmount := conn.dataChannel.BufferedAmount()
  1045. dataChannelConn := conn.dataChannelConn
  1046. conn.mutex.Unlock()
  1047. if isClosed {
  1048. return 0, errors.TraceNew("closed")
  1049. }
  1050. if dataChannelConn == nil {
  1051. return 0, errors.TraceNew("no data channel")
  1052. }
  1053. // Only proceed with a decoy message when no pending writes are buffered.
  1054. //
  1055. // This check is made before acquiring conn.writeMutex so that, in most
  1056. // cases, writeMessage won't block Read calls when a concurrent Write is
  1057. // holding conn.writeMutex and potentially blocking on flow control.
  1058. // There's still a chance that this test passes, and a concurrent Write
  1059. // arrives at the same time.
  1060. if decoy && bufferedAmount > 0 {
  1061. return 0, nil
  1062. }
  1063. conn.writeMutex.Lock()
  1064. defer conn.writeMutex.Unlock()
  1065. writeSize := len(p)
  1066. // Determine padding size and padding header size.
  1067. doPadding := false
  1068. paddingSize := 0
  1069. var paddingHeader [binary.MaxVarintLen32]byte
  1070. paddingHeaderSize := 0
  1071. if decoy {
  1072. if conn.decoyMessageCount < 1 {
  1073. return 0, nil
  1074. }
  1075. if !conn.trafficShapingPRNG.FlipWeightedCoin(
  1076. conn.config.TrafficShapingParameters.DecoyMessageProbability) {
  1077. return 0, nil
  1078. }
  1079. conn.decoyMessageCount -= 1
  1080. decoySize := conn.trafficShapingPRNG.Range(
  1081. conn.config.TrafficShapingParameters.MinDecoySize,
  1082. conn.config.TrafficShapingParameters.MaxDecoySize)
  1083. // When sending a decoy message, the entire message is padding.
  1084. doPadding = true
  1085. paddingSize = decoySize
  1086. if conn.decoyMessageCount == 0 {
  1087. // Set the shared flag that readMessage uses to stop invoking
  1088. // writeMessage for decoy events.
  1089. conn.mutex.Lock()
  1090. conn.decoyDone = true
  1091. conn.mutex.Unlock()
  1092. }
  1093. } else if conn.paddedMessageCount > 0 {
  1094. // Add padding to a normal write.
  1095. conn.paddedMessageCount -= 1
  1096. doPadding = true
  1097. paddingSize = prng.Range(
  1098. conn.config.TrafficShapingParameters.MinPaddingSize,
  1099. conn.config.TrafficShapingParameters.MaxPaddingSize)
  1100. } else if conn.decoyMessageCount > 0 {
  1101. // Padding normal messages is done, but there are still outstanding
  1102. // decoy messages, so add a padding header indicating padding size 0
  1103. // to this normal message.
  1104. doPadding = true
  1105. paddingSize = 0
  1106. } else if !conn.trafficShapingDone {
  1107. // Padding normal messages is done and all decoy messages are sent, so
  1108. // send a special padding header with padding size -1, signaling the
  1109. // peer that no additional padding will be performed and no
  1110. // subsequent messages will contain a padding header.
  1111. doPadding = true
  1112. paddingSize = -1
  1113. }
  1114. if doPadding {
  1115. if paddingSize > 0 {
  1116. // Reduce, if necessary, to stay within the maximum data channel
  1117. // message size. This is not expected to happen for the io.Copy use
  1118. // case, with 32K message size, plus reasonable padding sizes.
  1119. if writeSize+binary.MaxVarintLen32+paddingSize > dataChannelMaxMessageSize {
  1120. paddingSize -= (writeSize + binary.MaxVarintLen32 + paddingSize) - dataChannelMaxMessageSize
  1121. if paddingSize < 0 {
  1122. paddingSize = 0
  1123. }
  1124. }
  1125. // Add padding overhead to total writeSize before the flow control check.
  1126. writeSize += paddingSize
  1127. }
  1128. paddingHeaderSize = binary.PutVarint(paddingHeader[:], int64(paddingSize))
  1129. writeSize += paddingHeaderSize
  1130. }
  1131. if writeSize > dataChannelMaxMessageSize {
  1132. return 0, errors.TraceNew("write too large")
  1133. }
  1134. // Flow control is required to ensure that Write calls don't result in
  1135. // unbounded buffering in pion/webrtc. Use similar logic and the same
  1136. // buffer size thresholds as the pion sample code.
  1137. //
  1138. // https://github.com/pion/webrtc/tree/master/examples/data-channels-flow-control#when-do-we-need-it:
  1139. // > Send or SendText methods are called on DataChannel to send data to
  1140. // > the connected peer. The methods return immediately, but it does not
  1141. // > mean the data was actually sent onto the wire. Instead, it is
  1142. // > queued in a buffer until it actually gets sent out to the wire.
  1143. // >
  1144. // > When you have a large amount of data to send, it is an application's
  1145. // > responsibility to control the buffered amount in order not to
  1146. // > indefinitely grow the buffer size to eventually exhaust the memory.
  1147. // If the pion write buffer is too full, wait for a signal that sufficient
  1148. // write data has been consumed before writing more.
  1149. if !isClosed && bufferedAmount+uint64(writeSize) > dataChannelMaxBufferedAmount {
  1150. select {
  1151. case <-conn.dataChannelWriteBufferSignal:
  1152. case <-conn.closedSignal:
  1153. return 0, errors.TraceNew("connection has closed")
  1154. }
  1155. }
  1156. if conn.trafficShapingDone {
  1157. // When traffic shaping is done, p is written directly without the
  1158. // additional trafficShapingBuffer copy.
  1159. // Limitation: if len(p) > 65536, the dataChannelConn.Write will fail. In
  1160. // practise, this is not expected to happen with typical use cases such
  1161. // as io.Copy, which uses a 32K buffer.
  1162. n, err := dataChannelConn.Write(p)
  1163. return n, errors.Trace(err)
  1164. }
  1165. conn.trafficShapingBuffer.Reset()
  1166. conn.trafficShapingBuffer.Write(paddingHeader[:paddingHeaderSize])
  1167. if paddingSize > 0 {
  1168. conn.trafficShapingBuffer.Write(prng.Bytes(paddingSize))
  1169. }
  1170. conn.trafficShapingBuffer.Write(p)
  1171. // Limitation: see above; len(p) + padding must be <= 65536.
  1172. _, err := dataChannelConn.Write(conn.trafficShapingBuffer.Bytes())
  1173. if decoy {
  1174. atomic.AddInt32(&conn.decoyMessagesSent, 1)
  1175. } else if doPadding && paddingSize > 0 {
  1176. atomic.AddInt32(&conn.paddedMessagesSent, 1)
  1177. }
  1178. if conn.paddedMessageCount == 0 && conn.decoyMessageCount == 0 && paddingSize == -1 {
  1179. // Set flag indicating -1 padding size was sent and release traffic
  1180. // shaping resources.
  1181. conn.trafficShapingDone = true
  1182. conn.trafficShapingPRNG = nil
  1183. conn.trafficShapingBuffer = nil
  1184. }
  1185. return len(p), errors.Trace(err)
  1186. }
  1187. func (conn *webRTCConn) LocalAddr() net.Addr {
  1188. conn.mutex.Lock()
  1189. defer conn.mutex.Unlock()
  1190. // This is the local UDP socket address, not the external, public address.
  1191. return conn.udpConn.LocalAddr()
  1192. }
  1193. func (conn *webRTCConn) RemoteAddr() net.Addr {
  1194. conn.mutex.Lock()
  1195. defer conn.mutex.Unlock()
  1196. // Not supported.
  1197. return nil
  1198. }
  1199. func (conn *webRTCConn) SetDeadline(t time.Time) error {
  1200. conn.mutex.Lock()
  1201. defer conn.mutex.Unlock()
  1202. return errors.TraceNew("not supported")
  1203. }
  1204. func (conn *webRTCConn) SetReadDeadline(t time.Time) error {
  1205. conn.mutex.Lock()
  1206. defer conn.mutex.Unlock()
  1207. if conn.isClosed {
  1208. return errors.TraceNew("closed")
  1209. }
  1210. readDeadliner, ok := conn.dataChannelConn.(datachannel.ReadDeadliner)
  1211. if !ok {
  1212. return errors.TraceNew("no data channel")
  1213. }
  1214. return readDeadliner.SetReadDeadline(t)
  1215. }
  1216. func (conn *webRTCConn) SetWriteDeadline(t time.Time) error {
  1217. conn.mutex.Lock()
  1218. defer conn.mutex.Unlock()
  1219. return errors.TraceNew("not supported")
  1220. }
  1221. // GetMetrics implements the common.MetricsSource interface and returns log
  1222. // fields detailing the WebRTC dial parameters.
  1223. func (conn *webRTCConn) GetMetrics() common.LogFields {
  1224. conn.mutex.Lock()
  1225. defer conn.mutex.Unlock()
  1226. logFields := make(common.LogFields)
  1227. logFields.Add(conn.iceCandidatePairMetrics)
  1228. randomizeDTLS := "0"
  1229. if conn.config.DoDTLSRandomization {
  1230. randomizeDTLS = "1"
  1231. }
  1232. logFields["inproxy_webrtc_randomize_dtls"] = randomizeDTLS
  1233. logFields["inproxy_webrtc_padded_messages_sent"] = atomic.LoadInt32(&conn.paddedMessagesSent)
  1234. logFields["inproxy_webrtc_padded_messages_received"] = atomic.LoadInt32(&conn.paddedMessagesReceived)
  1235. logFields["inproxy_webrtc_decoy_messages_sent"] = atomic.LoadInt32(&conn.decoyMessagesSent)
  1236. logFields["inproxy_webrtc_decoy_messages_received"] = atomic.LoadInt32(&conn.decoyMessagesReceived)
  1237. return logFields
  1238. }
  1239. func (conn *webRTCConn) onConnectionStateChange(state webrtc.PeerConnectionState) {
  1240. // Close the WebRTCConn when the connection is no longer connected. Close
  1241. // will lock conn.mutex, so do lot aquire the lock here.
  1242. //
  1243. // Currently, ICE Restart is not used, and there is no transition from
  1244. // Disconnected back to Connected.
  1245. switch state {
  1246. case webrtc.PeerConnectionStateDisconnected,
  1247. webrtc.PeerConnectionStateFailed,
  1248. webrtc.PeerConnectionStateClosed:
  1249. conn.Close()
  1250. }
  1251. conn.config.Logger.WithTraceFields(common.LogFields{
  1252. "state": state.String(),
  1253. }).Info("peer connection state changed")
  1254. }
  1255. func (conn *webRTCConn) onICECandidate(candidate *webrtc.ICECandidate) {
  1256. if candidate == nil {
  1257. return
  1258. }
  1259. conn.config.Logger.WithTraceFields(common.LogFields{
  1260. "candidate": candidate.String(),
  1261. }).Info("new ICE candidate")
  1262. }
  1263. func (conn *webRTCConn) onICEBindingRequest(m *stun.Message, local, remote ice.Candidate, pair *ice.CandidatePair) bool {
  1264. // SetICEBindingRequestHandler is used to hook onICEBindingRequest into
  1265. // STUN bind events for logging. The return values is always false as
  1266. // this callback makes no adjustments to ICE candidate selection. When
  1267. // the data channel has already opened, skip logging events, as this
  1268. // callback appears to be invoked for keepalive pings.
  1269. if local == nil || remote == nil {
  1270. return false
  1271. }
  1272. select {
  1273. case <-conn.dataChannelOpenedSignal:
  1274. return false
  1275. default:
  1276. }
  1277. conn.config.Logger.WithTraceFields(common.LogFields{
  1278. "local_candidate": local.String(),
  1279. "remote_candidate": remote.String(),
  1280. }).Info("new ICE STUN binding request")
  1281. return false
  1282. }
  1283. func (conn *webRTCConn) onICEConnectionStateChange(state webrtc.ICEConnectionState) {
  1284. conn.config.Logger.WithTraceFields(common.LogFields{
  1285. "state": state.String(),
  1286. }).Info("ICE connection state changed")
  1287. }
  1288. func (conn *webRTCConn) onICEGatheringStateChange(state webrtc.ICEGathererState) {
  1289. conn.config.Logger.WithTraceFields(common.LogFields{
  1290. "state": state.String(),
  1291. }).Info("ICE gathering state changed")
  1292. }
  1293. func (conn *webRTCConn) onNegotiationNeeded() {
  1294. conn.config.Logger.WithTrace().Info("negotiation needed")
  1295. }
  1296. func (conn *webRTCConn) onSignalingStateChange(state webrtc.SignalingState) {
  1297. conn.config.Logger.WithTraceFields(common.LogFields{
  1298. "state": state.String(),
  1299. }).Info("signaling state changed")
  1300. }
  1301. func (conn *webRTCConn) onDataChannel(dataChannel *webrtc.DataChannel) {
  1302. conn.mutex.Lock()
  1303. defer conn.mutex.Unlock()
  1304. conn.setDataChannel(dataChannel)
  1305. conn.config.Logger.WithTraceFields(common.LogFields{
  1306. "label": dataChannel.Label(),
  1307. "ID": dataChannel.ID(),
  1308. }).Info("new data channel")
  1309. }
  1310. func (conn *webRTCConn) onDataChannelOpen() {
  1311. conn.mutex.Lock()
  1312. defer conn.mutex.Unlock()
  1313. dataChannelConn, err := conn.dataChannel.Detach()
  1314. if err == nil {
  1315. conn.dataChannelConn = dataChannelConn
  1316. // TODO: can a data channel be connected, disconnected, and then
  1317. // reestablished in one session?
  1318. conn.dataChannelOpenedOnce.Do(func() { close(conn.dataChannelOpenedSignal) })
  1319. }
  1320. conn.config.Logger.WithTraceFields(common.LogFields{
  1321. "detachError": err,
  1322. }).Info("data channel open")
  1323. }
  1324. func (conn *webRTCConn) onDataChannelClose() {
  1325. // Close the WebRTCConn when the data channel is closed. Close will lock
  1326. // conn.mutex, so do lot aquire the lock here.
  1327. conn.Close()
  1328. conn.config.Logger.WithTrace().Info("data channel closed")
  1329. }
  1330. // prepareSDPAddresses adjusts the SDP, pruning local network addresses and
  1331. // adding any port mapping as a host candidate.
  1332. func prepareSDPAddresses(
  1333. encodedSDP []byte,
  1334. errorOnNoCandidates bool,
  1335. portMappingExternalAddr string,
  1336. disableIPv6Candidates bool,
  1337. allowPrivateIPAddressCandidates bool) ([]byte, *webRTCSDPMetrics, error) {
  1338. modifiedSDP, metrics, err := processSDPAddresses(
  1339. encodedSDP,
  1340. errorOnNoCandidates,
  1341. portMappingExternalAddr,
  1342. disableIPv6Candidates,
  1343. allowPrivateIPAddressCandidates,
  1344. false,
  1345. nil,
  1346. common.GeoIPData{})
  1347. return modifiedSDP, metrics, errors.Trace(err)
  1348. }
  1349. // filterSDPAddresses checks that the SDP does not contain an empty list of
  1350. // candidates, bogon candidates, or candidates outside of the country and ASN
  1351. // for the specified expectedGeoIPData. Invalid candidates are stripped and a
  1352. // filtered SDP is returned.
  1353. func filterSDPAddresses(
  1354. encodedSDP []byte,
  1355. errorOnNoCandidates bool,
  1356. lookupGeoIP LookupGeoIP,
  1357. expectedGeoIPData common.GeoIPData,
  1358. allowPrivateIPAddressCandidates bool,
  1359. filterPrivateIPAddressCandidates bool) ([]byte, *webRTCSDPMetrics, error) {
  1360. filteredSDP, metrics, err := processSDPAddresses(
  1361. encodedSDP,
  1362. errorOnNoCandidates,
  1363. "",
  1364. false,
  1365. allowPrivateIPAddressCandidates,
  1366. filterPrivateIPAddressCandidates,
  1367. lookupGeoIP,
  1368. expectedGeoIPData)
  1369. return filteredSDP, metrics, errors.Trace(err)
  1370. }
  1371. // webRTCSDPMetrics are network capability metrics values for an SDP.
  1372. type webRTCSDPMetrics struct {
  1373. iceCandidateTypes []ICECandidateType
  1374. hasIPv6 bool
  1375. hasPrivateIP bool
  1376. filteredICECandidates []string
  1377. }
  1378. // processSDPAddresses is based on snowflake/common/util.StripLocalAddresses
  1379. // https://gitlab.torproject.org/tpo/anti-censorship/pluggable-transports/snowflake/-/blob/v2.5.1/common/util/util.go#L70-99
  1380. /*
  1381. This file contains the license for "Snowflake"
  1382. a free software project which provides a WebRTC pluggable transport.
  1383. ================================================================================
  1384. Copyright (c) 2016, Serene Han, Arlo Breault
  1385. Copyright (c) 2019-2020, The Tor Project, Inc
  1386. Redistribution and use in source and binary forms, with or without modification,
  1387. are permitted provided that the following conditions are met:
  1388. * Redistributions of source code must retain the above copyright notice, this
  1389. list of conditions and the following disclaimer.
  1390. * Redistributions in binary form must reproduce the above copyright notice,
  1391. this list of conditions and the following disclaimer in the documentation and/or
  1392. other materials provided with the distribution.
  1393. * Neither the names of the copyright owners nor the names of its
  1394. contributors may be used to endorse or promote products derived from this
  1395. software without specific prior written permission.
  1396. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
  1397. ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
  1398. WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
  1399. DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
  1400. ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
  1401. (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
  1402. LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
  1403. ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
  1404. (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
  1405. SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  1406. ================================================================================
  1407. */
  1408. func processSDPAddresses(
  1409. encodedSDP []byte,
  1410. errorOnNoCandidates bool,
  1411. portMappingExternalAddr string,
  1412. disableIPv6Candidates bool,
  1413. allowPrivateIPAddressCandidates bool,
  1414. filterPrivateIPAddressCandidates bool,
  1415. lookupGeoIP LookupGeoIP,
  1416. expectedGeoIPData common.GeoIPData) ([]byte, *webRTCSDPMetrics, error) {
  1417. var sessionDescription sdp.SessionDescription
  1418. err := sessionDescription.Unmarshal(encodedSDP)
  1419. if err != nil {
  1420. return nil, nil, errors.Trace(err)
  1421. }
  1422. candidateTypes := map[ICECandidateType]bool{}
  1423. hasIPv6 := false
  1424. hasPrivateIP := false
  1425. filteredCandidateReasons := make(map[string]int)
  1426. var portMappingICECandidates []sdp.Attribute
  1427. if portMappingExternalAddr != "" {
  1428. // Prepare ICE candidate attibute pair for the port mapping, modeled
  1429. // after the definition of host candidates.
  1430. host, portStr, err := net.SplitHostPort(portMappingExternalAddr)
  1431. if err != nil {
  1432. return nil, nil, errors.Trace(err)
  1433. }
  1434. port, err := strconv.Atoi(portStr)
  1435. if err != nil {
  1436. return nil, nil, errors.Trace(err)
  1437. }
  1438. // Only IPv4 port mapping addresses are supported due to the
  1439. // NewCandidateHost limitation noted below. It is expected that port
  1440. // mappings will be IPv4, as NAT and IPv6 is not a typical combination.
  1441. hostIP := net.ParseIP(host)
  1442. if hostIP != nil && hostIP.To4() != nil {
  1443. for _, component := range []webrtc.ICEComponent{webrtc.ICEComponentRTP, webrtc.ICEComponentRTCP} {
  1444. // The candidate ID is generated and the priority and foundation
  1445. // use the default for hosts.
  1446. //
  1447. // Limitation: NewCandidateHost initializes the networkType to
  1448. // NetworkTypeUDP4, and this field is not-exported.
  1449. // https://github.com/pion/ice/blob/6d301287654b05a36248842c278d58d501454bff/candidate_host.go#L27-L64
  1450. iceCandidate, err := ice.NewCandidateHost(&ice.CandidateHostConfig{
  1451. Network: "udp",
  1452. Address: host,
  1453. Port: port,
  1454. Component: uint16(component),
  1455. })
  1456. if err != nil {
  1457. return nil, nil, errors.Trace(err)
  1458. }
  1459. portMappingICECandidates = append(
  1460. portMappingICECandidates,
  1461. sdp.Attribute{Key: "candidate", Value: iceCandidate.Marshal()})
  1462. }
  1463. candidateTypes[ICECandidatePortMapping] = true
  1464. }
  1465. }
  1466. candidateCount := len(portMappingICECandidates)
  1467. for _, mediaDescription := range sessionDescription.MediaDescriptions {
  1468. addPortMappingCandidates := len(portMappingICECandidates) > 0
  1469. var attributes []sdp.Attribute
  1470. for _, attribute := range mediaDescription.Attributes {
  1471. // Insert the port mapping candidate either before the
  1472. // first "a=candidate", or before "a=end-of-candidates"(there may
  1473. // be no "a=candidate" attributes).
  1474. if addPortMappingCandidates &&
  1475. (attribute.IsICECandidate() || attribute.Key == sdp.AttrKeyEndOfCandidates) {
  1476. attributes = append(attributes, portMappingICECandidates...)
  1477. addPortMappingCandidates = false
  1478. }
  1479. if attribute.IsICECandidate() {
  1480. candidate, err := ice.UnmarshalCandidate(attribute.Value)
  1481. if err != nil {
  1482. return nil, nil, errors.Trace(err)
  1483. }
  1484. candidateIP := net.ParseIP(candidate.Address())
  1485. if candidateIP == nil {
  1486. return nil, nil, errors.TraceNew("unexpected non-IP")
  1487. }
  1488. candidateIsIPv6 := false
  1489. if candidateIP.To4() == nil {
  1490. if disableIPv6Candidates {
  1491. reason := fmt.Sprintf("disabled %s IPv6",
  1492. candidate.Type().String())
  1493. filteredCandidateReasons[reason] += 1
  1494. continue
  1495. }
  1496. candidateIsIPv6 = true
  1497. }
  1498. // Strip non-routable bogons, including RFC 1918/4193 private
  1499. // IP addresses. Same-LAN client/proxy hops are not expected
  1500. // to be useful, and this also avoids unnecessary network traffic.
  1501. //
  1502. // Well-behaved clients and proxies should strip these values;
  1503. // the broker enforces this with filtering.
  1504. //
  1505. // In personal pairing mode, private IP addresses are allowed,
  1506. // as connection may be made between devices the same LAN and
  1507. // not all routers support NAT hairpinning.
  1508. candidateIsPrivateIP := candidateIP.IsPrivate()
  1509. if !GetAllowBogonWebRTCConnections() &&
  1510. !(candidateIsPrivateIP && allowPrivateIPAddressCandidates) &&
  1511. common.IsBogon(candidateIP) {
  1512. version := "IPv4"
  1513. if candidateIsIPv6 {
  1514. version = "IPv6"
  1515. }
  1516. reason := fmt.Sprintf("bogon %s %s",
  1517. candidate.Type().String(), version)
  1518. filteredCandidateReasons[reason] += 1
  1519. continue
  1520. }
  1521. // In personal pairing mode, filter out any private IP
  1522. // addresses for which there is no corresponding local,
  1523. // active interface. This avoids unnecessary network traffic.
  1524. // This filtering option is applied post-broker exchange,
  1525. // with the SDP received, via the broker, from the peer.
  1526. if candidateIsPrivateIP && filterPrivateIPAddressCandidates {
  1527. if !hasInterfaceForPrivateIPAddress(candidateIP) {
  1528. continue
  1529. }
  1530. }
  1531. // The broker will check that clients and proxies specify only
  1532. // candidates that map to the same GeoIP country and ASN as
  1533. // the client/proxy connection to the broker. This limits
  1534. // misuse of candidates to connect to other locations.
  1535. // Legitimate candidates will not all have the exact same IP
  1536. // address, as there could be a mix of IPv4 and IPv6, as well
  1537. // as potentially different NAT paths.
  1538. //
  1539. // In some cases, legitimate clients and proxies may
  1540. // unintentionally submit candidates with mismatching GeoIP.
  1541. // This can occur, for example, when a STUN candidate is only
  1542. // a partial hole punch through double NAT, and when internal
  1543. // network addresses misuse non-private IP ranges (so are
  1544. // technically not bogons). Instead of outright rejecting
  1545. // SDPs containing unexpected GeoIP candidates, they are
  1546. // instead stripped out and the resulting filtered SDP is
  1547. // used.
  1548. if lookupGeoIP != nil {
  1549. candidateGeoIPData := lookupGeoIP(candidate.Address())
  1550. if candidateGeoIPData.Country != expectedGeoIPData.Country ||
  1551. candidateGeoIPData.ASN != expectedGeoIPData.ASN {
  1552. version := "IPv4"
  1553. if candidateIsIPv6 {
  1554. version = "IPv6"
  1555. }
  1556. reason := fmt.Sprintf(
  1557. "unexpected GeoIP %s %s: %s/%s",
  1558. candidate.Type().String(),
  1559. version,
  1560. candidateGeoIPData.Country,
  1561. candidateGeoIPData.ASN)
  1562. filteredCandidateReasons[reason] += 1
  1563. continue
  1564. }
  1565. }
  1566. if candidateIsIPv6 {
  1567. hasIPv6 = true
  1568. }
  1569. if candidateIsPrivateIP {
  1570. hasPrivateIP = true
  1571. }
  1572. // These types are not reported:
  1573. // - CandidateTypeRelay: TURN servers are not used.
  1574. // - CandidateTypePeerReflexive: this candidate type only
  1575. // emerges later in the connection process.
  1576. switch candidate.Type() {
  1577. case ice.CandidateTypeHost:
  1578. candidateTypes[ICECandidateHost] = true
  1579. case ice.CandidateTypeServerReflexive:
  1580. candidateTypes[ICECandidateServerReflexive] = true
  1581. }
  1582. candidateCount += 1
  1583. }
  1584. attributes = append(attributes, attribute)
  1585. }
  1586. mediaDescription.Attributes = attributes
  1587. }
  1588. if errorOnNoCandidates && candidateCount == 0 {
  1589. return nil, nil, errors.TraceNew("no candidates")
  1590. }
  1591. encodedSDP, err = sessionDescription.Marshal()
  1592. if err != nil {
  1593. return nil, nil, errors.Trace(err)
  1594. }
  1595. metrics := &webRTCSDPMetrics{
  1596. hasIPv6: hasIPv6,
  1597. hasPrivateIP: hasPrivateIP,
  1598. }
  1599. for candidateType := range candidateTypes {
  1600. metrics.iceCandidateTypes = append(metrics.iceCandidateTypes, candidateType)
  1601. }
  1602. for reason, count := range filteredCandidateReasons {
  1603. metrics.filteredICECandidates = append(metrics.filteredICECandidates,
  1604. fmt.Sprintf("%s: %d", reason, count))
  1605. }
  1606. return encodedSDP, metrics, nil
  1607. }
  1608. type pionLoggerFactory struct {
  1609. logger common.Logger
  1610. debugLogging bool
  1611. }
  1612. func newPionLoggerFactory(logger common.Logger, debugLogging bool) *pionLoggerFactory {
  1613. return &pionLoggerFactory{
  1614. logger: logger,
  1615. debugLogging: debugLogging,
  1616. }
  1617. }
  1618. func (f *pionLoggerFactory) NewLogger(scope string) pion_logging.LeveledLogger {
  1619. return newPionLogger(scope, f.logger, f.debugLogging)
  1620. }
  1621. // pionLogger wraps common.Logger and implements
  1622. // https://pkg.go.dev/github.com/pion/logging#LeveledLogger for passing into
  1623. // pion.
  1624. type pionLogger struct {
  1625. scope string
  1626. logger common.Logger
  1627. debugLogging bool
  1628. warnNoPairs int32
  1629. }
  1630. func newPionLogger(scope string, logger common.Logger, debugLogging bool) *pionLogger {
  1631. return &pionLogger{
  1632. scope: scope,
  1633. logger: logger,
  1634. debugLogging: debugLogging,
  1635. }
  1636. }
  1637. func (l *pionLogger) Trace(msg string) {
  1638. if !l.debugLogging {
  1639. return
  1640. }
  1641. l.logger.WithTrace().Debug(fmt.Sprintf("webRTC: %s: %s", l.scope, msg))
  1642. }
  1643. func (l *pionLogger) Tracef(format string, args ...interface{}) {
  1644. if !l.debugLogging {
  1645. return
  1646. }
  1647. l.logger.WithTrace().Debug(fmt.Sprintf("webRTC: %s: %s", l.scope, fmt.Sprintf(format, args...)))
  1648. }
  1649. func (l *pionLogger) Debug(msg string) {
  1650. if !l.debugLogging {
  1651. return
  1652. }
  1653. l.logger.WithTrace().Debug(fmt.Sprintf("[webRTC: %s: %s", l.scope, msg))
  1654. }
  1655. func (l *pionLogger) Debugf(format string, args ...interface{}) {
  1656. if !l.debugLogging {
  1657. return
  1658. }
  1659. l.logger.WithTrace().Debug(fmt.Sprintf("webRTC: %s: %s", l.scope, fmt.Sprintf(format, args...)))
  1660. }
  1661. func (l *pionLogger) Info(msg string) {
  1662. l.logger.WithTrace().Info(fmt.Sprintf("webRTC: %s: %s", l.scope, msg))
  1663. }
  1664. func (l *pionLogger) Infof(format string, args ...interface{}) {
  1665. l.logger.WithTrace().Info(fmt.Sprintf("webRTC: %s: %s", l.scope, fmt.Sprintf(format, args...)))
  1666. }
  1667. func (l *pionLogger) Warn(msg string) {
  1668. // To reduce diagnostic log noise, only log this message once per dial attempt.
  1669. if msg == "Failed to ping without candidate pairs. Connection is not possible yet." &&
  1670. !atomic.CompareAndSwapInt32(&l.warnNoPairs, 0, 1) {
  1671. return
  1672. }
  1673. l.logger.WithTrace().Warning(fmt.Sprintf("webRTC: %s: %s", l.scope, msg))
  1674. }
  1675. func (l *pionLogger) Warnf(format string, args ...interface{}) {
  1676. l.logger.WithTrace().Warning(fmt.Sprintf("webRTC: %s: %s", l.scope, fmt.Sprintf(format, args...)))
  1677. }
  1678. func (l *pionLogger) Error(msg string) {
  1679. l.logger.WithTrace().Error(fmt.Sprintf("webRTC: %s: %s", l.scope, msg))
  1680. }
  1681. func (l *pionLogger) Errorf(format string, args ...interface{}) {
  1682. l.logger.WithTrace().Error(fmt.Sprintf("webRTC: %s: %s", l.scope, fmt.Sprintf(format, args...)))
  1683. }
  1684. func hasInterfaceForPrivateIPAddress(IP net.IP) bool {
  1685. if !IP.IsPrivate() {
  1686. return false
  1687. }
  1688. // The anet package is used to work around net.Interfaces not working on
  1689. // Android at this time: https://github.com/golang/go/issues/40569.
  1690. //
  1691. // Any errors are silently dropped; the caller will proceed without using
  1692. // the input private IP; and equivilent anet calls are made in
  1693. // pionNetwork.Interfaces, with errors logged.
  1694. netInterfaces, err := anet.Interfaces()
  1695. if err != nil {
  1696. return false
  1697. }
  1698. for _, netInterface := range netInterfaces {
  1699. // Note: don't exclude interfaces with the net.FlagPointToPoint flag,
  1700. // which is set for certain mobile networks
  1701. if netInterface.Flags&net.FlagUp == 0 {
  1702. continue
  1703. }
  1704. addrs, err := anet.InterfaceAddrsByInterface(&netInterface)
  1705. if err != nil {
  1706. continue
  1707. }
  1708. for _, addr := range addrs {
  1709. _, IPNet, err := net.ParseCIDR(addr.String())
  1710. if err != nil {
  1711. continue
  1712. }
  1713. if IPNet.Contains(IP) {
  1714. return true
  1715. }
  1716. }
  1717. }
  1718. return false
  1719. }
  1720. // pionNetwork implements pion/transport.Net.
  1721. //
  1722. // Via the SettingsEngine, pion is configured to use a pionNetwork instance,
  1723. // which providing alternative implementations for various network functions.
  1724. // The Interfaces implementation provides a workaround for Android
  1725. // net.Interfaces issues and reduces the number of IPv6 candidates to avoid
  1726. // excess STUN requests; and the ResolveUDPAddr implementation hooks into the
  1727. // Psiphon custom resolver.
  1728. type pionNetwork struct {
  1729. dialCtx context.Context
  1730. logger pion_logging.LeveledLogger
  1731. webRTCDialCoordinator WebRTCDialCoordinator
  1732. }
  1733. func newPionNetwork(
  1734. dialCtx context.Context,
  1735. logger pion_logging.LeveledLogger,
  1736. webRTCDialCoordinator WebRTCDialCoordinator) *pionNetwork {
  1737. return &pionNetwork{
  1738. dialCtx: dialCtx,
  1739. logger: logger,
  1740. webRTCDialCoordinator: webRTCDialCoordinator,
  1741. }
  1742. }
  1743. func (p *pionNetwork) Interfaces() ([]*transport.Interface, error) {
  1744. // To determine the active IPv4 and IPv6 interfaces, let the OS bind IPv4
  1745. // and IPv6 UDP sockets with a specified external destination address.
  1746. // Then iterate over all interfaces, but return interface info for only
  1747. // the interfaces those sockets were bound to.
  1748. //
  1749. // The destination IPs are the IPs that currently resolve for example.com.
  1750. // No actual traffic to these IPs or example.com is sent, as the UDP
  1751. // sockets are not used to send any packets.
  1752. //
  1753. // This scheme should select just one IPv4 and one IPv6 address, which
  1754. // should be the active, externally routable addresses, and the IPv6
  1755. // address should be the preferred, non-deprecated temporary IPv6 address.
  1756. //
  1757. // In post-ICE gathering processing, processSDPAddresses will also strip
  1758. // all bogon addresses, so there is no explicit bogon check here.
  1759. //
  1760. // Limitations:
  1761. //
  1762. // - The active interface could change between the socket operation and
  1763. // iterating over all interfaces. Higher-level code is expected to
  1764. // react to active network changes.
  1765. //
  1766. // - The public IPs for example.com may not be robust in all routing
  1767. // situations. Alternatively, we could use the configured STUN server
  1768. // as the test destination, but the STUN server domain is not resolved
  1769. // at this point and STUN is not always configured and used.
  1770. //
  1771. // - The results could be cached and reused.
  1772. var defaultIPv4, defaultIPv6 net.IP
  1773. udpConnIPv4, err := p.webRTCDialCoordinator.UDPConn(
  1774. context.Background(), "udp4", "93.184.216.34:3478")
  1775. if err == nil {
  1776. defaultIPv4 = udpConnIPv4.LocalAddr().(*net.UDPAddr).IP
  1777. udpConnIPv4.Close()
  1778. }
  1779. udpConnIPv6, err := p.webRTCDialCoordinator.UDPConn(
  1780. context.Background(), "udp6", "[2606:2800:220:1:248:1893:25c8:1946]:3478")
  1781. if err == nil {
  1782. defaultIPv6 = udpConnIPv6.LocalAddr().(*net.UDPAddr).IP
  1783. udpConnIPv6.Close()
  1784. }
  1785. // The anet package is used to work around net.Interfaces not working on
  1786. // Android at this time: https://github.com/golang/go/issues/40569.
  1787. transportInterfaces := []*transport.Interface{}
  1788. netInterfaces, err := anet.Interfaces()
  1789. if err != nil {
  1790. return nil, errors.Trace(err)
  1791. }
  1792. for _, netInterface := range netInterfaces {
  1793. // Note: don't exclude interfaces with the net.FlagPointToPoint flag,
  1794. // which is set for certain mobile networks
  1795. if (netInterface.Flags&net.FlagUp == 0) ||
  1796. (!GetAllowBogonWebRTCConnections() && (netInterface.Flags&net.FlagLoopback != 0)) {
  1797. continue
  1798. }
  1799. addrs, err := anet.InterfaceAddrsByInterface(&netInterface)
  1800. if err != nil {
  1801. return nil, errors.Trace(err)
  1802. }
  1803. var transportInterface *transport.Interface
  1804. for _, addr := range addrs {
  1805. IP, _, err := net.ParseCIDR(addr.String())
  1806. if err != nil {
  1807. return nil, errors.Trace(err)
  1808. }
  1809. if IP.Equal(defaultIPv4) || IP.Equal(defaultIPv6) ||
  1810. (GetAllowBogonWebRTCConnections() && (netInterface.Flags&net.FlagLoopback != 0)) {
  1811. if transportInterface == nil {
  1812. transportInterface = transport.NewInterface(netInterface)
  1813. }
  1814. transportInterface.AddAddress(addr)
  1815. }
  1816. }
  1817. if transportInterface != nil {
  1818. transportInterfaces = append(transportInterfaces, transportInterface)
  1819. }
  1820. }
  1821. return transportInterfaces, nil
  1822. }
  1823. func (p *pionNetwork) ResolveUDPAddr(network, address string) (retAddr *net.UDPAddr, retErr error) {
  1824. defer func() {
  1825. if retErr != nil {
  1826. // Explicitly log an error since certain pion operations -- e.g.,
  1827. // ICE gathering -- don't propagate all pion/transport.Net errors.
  1828. p.logger.Errorf("pionNetwork.ResolveUDPAddr failed: %v", retErr)
  1829. }
  1830. }()
  1831. // Currently, pion appears to call ResolveUDPAddr with "udp4"/udp6"
  1832. // instead of "ip4"/"ip6", as expected by, e.g., net.Resolver.LookupIP.
  1833. // Convert to "ip4"/"ip6".
  1834. // Specifying v4/v6 ensures that the resolved IP address is the correct
  1835. // type. In the case of STUN servers, the correct type is required in
  1836. // order to create the correct IPv4 or IPv6 whole punch address.
  1837. switch network {
  1838. case "udp4", "tcp4":
  1839. network = "ip4"
  1840. case "udp6", "tcp6":
  1841. network = "ip6"
  1842. default:
  1843. network = "ip"
  1844. }
  1845. // Currently, pion appears to call ResolveUDPAddr with an improperly
  1846. // formatted address, <IPv6>:443 not [<IPv6>]:443; handle this case.
  1847. index := strings.LastIndex(address, ":")
  1848. if index != -1 {
  1849. address = net.JoinHostPort(address[:index], address[index+1:])
  1850. }
  1851. // Use the Psiphon custom resolver to resolve any STUN server domains.
  1852. resolvedAddress, err := p.webRTCDialCoordinator.ResolveAddress(
  1853. p.dialCtx, network, address)
  1854. if err != nil {
  1855. return nil, errors.Trace(err)
  1856. }
  1857. IPStr, portStr, err := net.SplitHostPort(resolvedAddress)
  1858. if err != nil {
  1859. return nil, errors.Trace(err)
  1860. }
  1861. IP := net.ParseIP(IPStr)
  1862. if IP == nil {
  1863. return nil, errors.TraceNew("invalid IP address")
  1864. }
  1865. port, err := strconv.Atoi(portStr)
  1866. if err != nil {
  1867. return nil, errors.Trace(err)
  1868. }
  1869. return &net.UDPAddr{IP: IP, Port: port}, nil
  1870. }
  1871. var errNotSupported = std_errors.New("not supported")
  1872. func (p *pionNetwork) ListenPacket(network string, address string) (net.PacketConn, error) {
  1873. // Explicitly log an error since certain pion operations -- e.g., ICE
  1874. // gathering -- don't propagate all pion/transport.Net errors.
  1875. p.logger.Errorf("unexpected pionNetwork.ListenPacket call from %s", stacktrace.GetParentFunctionName())
  1876. return nil, errors.Trace(errNotSupported)
  1877. }
  1878. func (p *pionNetwork) ListenUDP(network string, locAddr *net.UDPAddr) (transport.UDPConn, error) {
  1879. p.logger.Errorf("unexpected pionNetwork.ListenUDP call from %s", stacktrace.GetParentFunctionName())
  1880. return nil, errors.Trace(errNotSupported)
  1881. }
  1882. func (p *pionNetwork) ListenTCP(network string, laddr *net.TCPAddr) (transport.TCPListener, error) {
  1883. p.logger.Errorf("unexpected pionNetwork.ListenTCP call from %s", stacktrace.GetParentFunctionName())
  1884. return nil, errors.Trace(errNotSupported)
  1885. }
  1886. func (p *pionNetwork) Dial(network, address string) (net.Conn, error) {
  1887. p.logger.Errorf("unexpected pionNetwork.Dial call from %s", stacktrace.GetParentFunctionName())
  1888. return nil, errors.Trace(errNotSupported)
  1889. }
  1890. func (p *pionNetwork) DialUDP(network string, laddr, raddr *net.UDPAddr) (transport.UDPConn, error) {
  1891. p.logger.Errorf("unexpected pionNetwork.DialUDP call from %s", stacktrace.GetParentFunctionName())
  1892. return nil, errors.Trace(errNotSupported)
  1893. }
  1894. func (p *pionNetwork) DialTCP(network string, laddr, raddr *net.TCPAddr) (transport.TCPConn, error) {
  1895. p.logger.Errorf("unexpected pionNetwork.DialTCP call from %s", stacktrace.GetParentFunctionName())
  1896. return nil, errors.Trace(errNotSupported)
  1897. }
  1898. func (p *pionNetwork) ResolveIPAddr(network, address string) (*net.IPAddr, error) {
  1899. p.logger.Errorf("unexpected pionNetwork.ResolveIPAddr call from %s", stacktrace.GetParentFunctionName())
  1900. return nil, errors.Trace(errNotSupported)
  1901. }
  1902. func (p *pionNetwork) ResolveTCPAddr(network, address string) (*net.TCPAddr, error) {
  1903. p.logger.Errorf("unexpected pionNetwork.ResolveTCPAddr call from %s", stacktrace.GetParentFunctionName())
  1904. return nil, errors.Trace(errNotSupported)
  1905. }
  1906. func (p *pionNetwork) InterfaceByIndex(index int) (*transport.Interface, error) {
  1907. p.logger.Errorf("unexpected pionNetwork.InterfaceByIndex call from %s", stacktrace.GetParentFunctionName())
  1908. return nil, errors.Trace(errNotSupported)
  1909. }
  1910. func (p *pionNetwork) InterfaceByName(name string) (*transport.Interface, error) {
  1911. p.logger.Errorf("unexpected pionNetwork.InterfaceByName call from %s", stacktrace.GetParentFunctionName())
  1912. return nil, errors.Trace(errNotSupported)
  1913. }
  1914. func (p *pionNetwork) CreateDialer(dialer *net.Dialer) transport.Dialer {
  1915. return &pionNetworkDialer{pionNetwork: p}
  1916. }
  1917. type pionNetworkDialer struct {
  1918. pionNetwork *pionNetwork
  1919. }
  1920. func (d pionNetworkDialer) Dial(network, address string) (net.Conn, error) {
  1921. d.pionNetwork.logger.Errorf("unexpected pionNetworkDialer.Dial call from %s", stacktrace.GetParentFunctionName())
  1922. return nil, errors.Trace(errNotSupported)
  1923. }