pion webrtc v4 fails to establish a setup:actpass ice negotiation against pexip, when v3 doesn't
Your environment.
- Version: github.com/pion/webrtc/v4 v4.1.6
- Browser: not relevant
- Other Information -
What did you do?
I try to establish a webrtc connection with a pexip server.
The offer comes from the pion side, and the answer from the pexip side.
(The sdp exchange happens through a rest api, same goes for trickling candidates.)
The peerconection is created with webrtc.NewPeerConnection, then it's classical creatoffer / setlocaldescription / get answer over the api /setremotedescription , and inject /forward candidates
Using pion V4, the handshake fails. (see trace further on this ticket)
-> If in the offer I give to pexip (after calling setlocaldescription) I replace the a=setup:actpass with a=setup:active , pexip sdp has "a=setup:passive", the handshake works and i get connected.
Here, munging sdp is necessary for using pexip, because it needs extra attributes on videotracks, and also pexip will blindly reject offers not containg the a=ice-options:trickle attribute , but i'd like to keep it to the minimum..
I then tried to remove this hack and use the api way and calling settingEngine.SetAnsweringDTLSRole(webrtc.DTLSRoleClient )
(I also tried DTLSRoleServer, because the doc of this function mentions constants which don't seem to exist (?) (DTLSRoleActive and DTLSRolePassive) ) None of those solved the handshake issue, but the peer connection created with the api worked if i hacked the sdp.
I then tried with a chrome and the pexip web client, checking the exchanged sdp in the debug tools: When chrome is doing this negotiation, its offers has setup:actpass and the answer coming from pexip is setup:active
So my understanding is that pexip is able to support both active and passive roles, but that there is a problem in the negotiation when pion does it.
I then tried to revert to pion v3. With pion V3, i don't meet any particular problem, no need to play with the setting engine or hack the sdp, the ice connection is established and shortly afterwards the peerconnectionstate goes to connected.
It looks to me there is a regression in the ice part of pion v4.
I'm not sure what I can share more which is relevant to help troubleshoot this issue..
I'll add a trace showing a failing negotiation with pion v4 (happy to reply if you need more information)
What did you expect?
I expected the connection to be established
What happened?
It only worked with pion v3.
Trace of what's happening with default offer from pion
ice TRACE: 18:12:18.126458 agent.go:468: Unset selected candidate pair pc INFO: 2025/11/13 18:12:18 signaling state changed to have-local-offer turnc DEBUG: 18:12:18.128375 client.go:120: Resolved TURN server e2e-turn.pex.me:443 to 91.90.45.34:443 turnc TRACE: 18:12:18.128375 client.go:440: Start Allocate request transaction VqUgRqzn4WTCgBpl to 91.90.45.34:443 ice DEBUG: 18:12:18.148505 gather.go:589: Failed to resolve STUN host: udp6 e2e-turn.pex.me:443: lookup e2e-turn.pex.me: no such host ice DEBUG: 18:12:18.148505 gather.go:589: Failed to resolve STUN host: udp6 e2e-turn.pex.me:443: lookup e2e-turn.pex.me: no such host turnc DEBUG: 18:12:18.171789 client.go:120: Resolved TURN server e2e-turn.pex.me:443 to 91.90.45.34:443 turnc TRACE: 18:12:18.171890 client.go:440: Start Allocate request transaction FBvh1xidCY0Zp3/3 to 91.90.45.34:443 turnc TRACE: 18:12:18.173120 client.go:440: Start Allocate request transaction o8bXQii82CFBEIS7 to 91.90.45.34:443 turnc TRACE: 18:12:18.215596 client.go:440: Start Allocate request transaction zqOs8WszwsDyC8kL to 91.90.45.34:443 turnc DEBUG: 18:12:18.215596 udp_conn.go:66: Initial lifetime: 600 seconds turnc DEBUG: 18:12:18.215596 udp_conn.go:81: Started refresh allocation timer turnc DEBUG: 18:12:18.215596 udp_conn.go:84: Started refresh permission timer turnc DEBUG: 18:12:18.273903 udp_conn.go:66: Initial lifetime: 600 seconds turnc DEBUG: 18:12:18.274902 udp_conn.go:81: Started refresh allocation timer turnc DEBUG: 18:12:18.274902 udp_conn.go:84: Started refresh permission timer pc INFO: 2025/11/13 18:12:18 signaling state changed to stable ice INFO: 2025/11/13 18:12:18 Ignoring remote candidate with tcpType active: tcp4 host 185.35.201.120:45922 (resolved: 185.35.201.120:45922) ice DEBUG: 18:12:18.693237 agent.go:343: Started agent: isControlling? true, remoteUfrag: "J839uimQeQ2iEv15", remotePwd: "C1DnijoeDeC5QhLv+UpS4exT" ice INFO: 2025/11/13 18:12:18 Setting new connection state: Checking pc INFO: 2025/11/13 18:12:18 ICE connection state changed: checking ice TRACE: 18:12:18.693237 agent.go:487: Pinging all candidates pc INFO: 2025/11/13 18:12:18 peer connection state changed: connecting ice TRACE: 18:12:18.694238 agent.go:983: Ping STUN from udp4 host 172.29.16.1:54164 (resolved: 172.29.16.1:54164) to udp4 host 185.35.201.120:45922 (resolved: 185.35.201.120:45922) ice INFO: 2025/11/13 18:12:18 Failed to send packet: write udp 172.29.16.1:54164->185.35.201.120:45922: wsasendto: A socket operation was attempted to an unreachable network. ice TRACE: 18:12:18.694238 agent.go:983: Ping STUN from udp4 host 192.168.10.1:54166 (resolved: 192.168.10.1:54166) to udp4 host 185.35.201.120:45922 (resolved: 185.35.201.120:45922) ice INFO: 2025/11/13 18:12:18 Failed to send packet: write udp 192.168.10.1:54166->185.35.201.120:45922: wsasendto: A socket operation was attempted to an unreachable network. ice TRACE: 18:12:18.694238 agent.go:983: Ping STUN from udp4 host 172.27.32.1:54168 (resolved: 172.27.32.1:54168) to udp4 host 185.35.201.120:45922 (resolved: 185.35.201.120:45922) ice INFO: 2025/11/13 18:12:18 Failed to send packet: write udp 172.27.32.1:54168->185.35.201.120:45922: wsasendto: A socket operation was attempted to an unreachable network. ice TRACE: 18:12:18.694238 agent.go:983: Ping STUN from udp4 host 10.11.91.59:54170 (resolved: 10.11.91.59:54170) to udp4 host 185.35.201.120:45922 (resolved: 185.35.201.120:45922) ice INFO: 2025/11/13 18:12:18 Failed to send packet: write udp 10.11.91.59:54170->185.35.201.120:45922: wsasendto: A socket operation was attempted to an unreachable network. ice TRACE: 18:12:18.694238 agent.go:983: Ping STUN from udp4 host 192.168.1.84:54174 (resolved: 192.168.1.84:54174) to udp4 host 185.35.201.120:45922 (resolved: 185.35.201.120:45922) ice TRACE: 18:12:18.694238 agent.go:983: Ping STUN from udp4 srflx 176.165.95.53:54161 related 0.0.0.0:54161 (resolved: 176.165.95.53:54161) to udp4 host 185.35.201.120:45922 (resolved: 185.35.201.120:45922) ice TRACE: 18:12:18.694238 agent.go:983: Ping STUN from udp4 srflx 176.165.95.53:54163 related 0.0.0.0:54163 (resolved: 176.165.95.53:54163) to udp4 host 185.35.201.120:45922 (resolved: 185.35.201.120:45922) ice TRACE: 18:12:18.694238 agent.go:983: Ping STUN from udp4 relay 91.90.45.34:59495 related 0.0.0.0:54162 (resolved: 91.90.45.34:59495) to udp4 host 185.35.201.120:45922 (resolved: 185.35.201.120:45922) turnc TRACE: 18:12:18.694238 client.go:440: Start CreatePermission request transaction zsydHz+0E0w5QIaf to 91.90.45.34:443 turnc TRACE: 18:12:18.736749 client.go:440: Start ChannelBind request transaction jqEBdy7azZs6Bgil to 91.90.45.34:443 ice TRACE: 18:12:18.736749 agent.go:983: Ping STUN from udp4 relay 91.90.45.34:61751 related 192.168.1.84:59175 (resolved: 91.90.45.34:61751) to udp4 host 185.35.201.120:45922 (resolved: 185.35.201.120:45922) turnc TRACE: 18:12:18.736749 client.go:440: Start CreatePermission request transaction mZ8x51jkG330MuH/ to 91.90.45.34:443 turnc TRACE: 18:12:18.779756 client.go:636: Channel data received from 185.35.201.120:45922 (ch=16384) turnc DEBUG: 18:12:18.779756 udp_conn.go:449: Channel binding successful: 185.35.201.120:45922 16384 turnc TRACE: 18:12:18.780732 client.go:440: Start ChannelBind request transaction FfD3yeYnfbFWI0Xq to 91.90.45.34:443 ice TRACE: 18:12:18.780732 selection.go:154: Inbound STUN (SuccessResponse) from udp4 host 185.35.201.120:45922 (resolved: 185.35.201.120:45922) to udp4 host 192.168.1.84:54174 (resolved: 192.168.1.84:54174) ice TRACE: 18:12:18.780732 selection.go:165: Found valid candidate pair: prio 8774140170971381247 (local, prio 2130706431) udp4 host 192.168.1.84:54174 (resolved: 192.168.1.84:54174) <-> udp4 host 185.35.201.120:45922 (resolved: 185.35.201.120:45922) (remote, prio 2042888703), state: succeeded, nominated: false, nominateOnBindingSuccess: false ice TRACE: 18:12:18.780732 selection.go:154: Inbound STUN (SuccessResponse) from udp4 host 185.35.201.120:45922 (resolved: 185.35.201.120:45922) to udp4 srflx 176.165.95.53:54161 related 0.0.0.0:54161 (resolved: 176.165.95.53:54161) ice TRACE: 18:12:18.780732 selection.go:165: Found valid candidate pair: prio 7277816995927032832 (local, prio 1694498815) udp4 srflx 176.165.95.53:54161 related 0.0.0.0:54161 (resolved: 176.165.95.53:54161) <-> udp4 host 185.35.201.120:45922 (resolved: 185.35.201.120:45922) (remote, prio 2042888703), state: succeeded, nominated: false, nominateOnBindingSuccess: false ice TRACE: 18:12:18.780732 selection.go:154: Inbound STUN (SuccessResponse) from udp4 host 185.35.201.120:45922 (resolved: 185.35.201.120:45922) to udp4 srflx 176.165.95.53:54163 related 0.0.0.0:54163 (resolved: 176.165.95.53:54163) ice TRACE: 18:12:18.780732 selection.go:165: Found valid candidate pair: prio 7277816995927032832 (local, prio 1694498815) udp4 srflx 176.165.95.53:54163 related 0.0.0.0:54163 (resolved: 176.165.95.53:54163) <-> udp4 host 185.35.201.120:45922 (resolved: 185.35.201.120:45922) (remote, prio 2042888703), state: succeeded, nominated: false, nominateOnBindingSuccess: false ice TRACE: 18:12:18.780732 selection.go:154: Inbound STUN (SuccessResponse) from udp4 host 185.35.201.120:45922 (resolved: 185.35.201.120:45922) to udp4 relay 91.90.45.34:59495 related 0.0.0.0:54162 (resolved: 91.90.45.34:59495) ice TRACE: 18:12:18.780732 selection.go:165: Found valid candidate pair: prio 72057593811960832 (local, prio 16777215) udp4 relay 91.90.45.34:59495 related 0.0.0.0:54162 (resolved: 91.90.45.34:59495) <-> udp4 host 185.35.201.120:45922 (resolved: 185.35.201.120:45922) (remote, prio 2042888703), state: succeeded, nominated: false, nominateOnBindingSuccess: false ice TRACE: 18:12:18.780732 agent.go:1117: Inbound STUN (Request) from 185.35.201.120:45922 to udp4 host 192.168.1.84:54174 (resolved: 192.168.1.84:54174), useCandidate: false ice TRACE: 18:12:18.780732 agent.go:1117: Inbound STUN (Request) from 185.35.201.120:45922 to udp4 srflx 176.165.95.53:54163 related 0.0.0.0:54163 (resolved: 176.165.95.53:54163), useCandidate: false ice TRACE: 18:12:18.800239 agent.go:1117: Inbound STUN (Request) from 185.35.201.120:45922 to udp4 srflx 176.165.95.53:54161 related 0.0.0.0:54161 (resolved: 176.165.95.53:54161), useCandidate: false turnc TRACE: 18:12:18.822149 client.go:636: Channel data received from 185.35.201.120:45922 (ch=16384) ice TRACE: 18:12:18.822503 agent.go:1117: Inbound STUN (Request) from 185.35.201.120:45922 to udp4 relay 91.90.45.34:59495 related 0.0.0.0:54162 (resolved: 91.90.45.34:59495), useCandidate: false turnc TRACE: 18:12:18.836722 client.go:636: Channel data received from 185.35.201.120:45922 (ch=16384) turnc DEBUG: 18:12:18.836722 udp_conn.go:449: Channel binding successful: 185.35.201.120:45922 16384 ice TRACE: 18:12:18.836722 selection.go:154: Inbound STUN (SuccessResponse) from udp4 host 185.35.201.120:45922 (resolved: 185.35.201.120:45922) to udp4 relay 91.90.45.34:61751 related 192.168.1.84:59175 (resolved: 91.90.45.34:61751) ice TRACE: 18:12:18.836722 selection.go:165: Found valid candidate pair: prio 72057593811960832 (local, prio 16777215) udp4 relay 91.90.45.34:61751 related 192.168.1.84:59175 (resolved: 91.90.45.34:61751) <-> udp4 host 185.35.201.120:45922 (resolved: 185.35.201.120:45922) (remote, prio 2042888703), state: succeeded, nominated: false, nominateOnBindingSuccess: false turnc TRACE: 18:12:18.840424 client.go:636: Channel data received from 185.35.201.120:45922 (ch=16384) ice TRACE: 18:12:18.840424 agent.go:1117: Inbound STUN (Request) from 185.35.201.120:45922 to udp4 relay 91.90.45.34:61751 related 192.168.1.84:59175 (resolved: 91.90.45.34:61751), useCandidate: false sender_interceptor WARNING: 2025/11/13 18:12:18 failed sending: the DTLS transport has not started yet sender_interceptor WARNING: 2025/11/13 18:12:18 failed sending: the DTLS transport has not started yet ice TRACE: 18:12:18.981130 selection.go:63: Nominatable pair found, nominating (udp4 host 192.168.1.84:54174 (resolved: 192.168.1.84:54174), udp4 host 185.35.201.120:45922 (resolved: 185.35.201.120:45922)) ice TRACE: 18:12:18.981130 selection.go:93: Ping STUN (nominate candidate pair) from udp4 host 192.168.1.84:54174 (resolved: 192.168.1.84:54174) to udp4 host 185.35.201.120:45922 (resolved: 185.35.201.120:45922) ice TRACE: 18:12:18.981130 agent.go:983: Ping STUN from udp4 host 192.168.1.84:54174 (resolved: 192.168.1.84:54174) to udp4 host 185.35.201.120:45922 (resolved: 185.35.201.120:45922) ice TRACE: 18:12:19.022974 selection.go:154: Inbound STUN (SuccessResponse) from udp4 host 185.35.201.120:45922 (resolved: 185.35.201.120:45922) to udp4 host 192.168.1.84:54174 (resolved: 192.168.1.84:54174) ice TRACE: 18:12:19.022974 selection.go:165: Found valid candidate pair: prio 8774140170971381247 (local, prio 2130706431) udp4 host 192.168.1.84:54174 (resolved: 192.168.1.84:54174) <-> udp4 host 185.35.201.120:45922 (resolved: 185.35.201.120:45922) (remote, prio 2042888703), state: succeeded, nominated: true, nominateOnBindingSuccess: false ice TRACE: 18:12:19.022974 agent.go:475: Set selected candidate pair: prio 8774140170971381247 (local, prio 2130706431) udp4 host 192.168.1.84:54174 (resolved: 192.168.1.84:54174) <-> udp4 host 185.35.201.120:45922 (resolved: 185.35.201.120:45922) (remote, prio 2042888703), state: succeeded, nominated: true, nominateOnBindingSuccess: false ice INFO: 2025/11/13 18:12:19 Setting new connection state: Connected pc INFO: 2025/11/13 18:12:19 ICE connection state changed: connected dtls TRACE: 18:12:19.022974 handshaker.go:189: [handshake:server] Flight 0: Preparing dtls TRACE: 18:12:19.022974 handshaker.go:189: [handshake:server] Flight 0: Sending dtls TRACE: 18:12:19.022974 handshaker.go:189: [handshake:server] Flight 0: Waiting ice TRACE: 18:12:19.181273 selection.go:55: Checking keepalive ice TRACE: 18:12:19.181273 agent.go:983: Ping STUN from udp4 host 192.168.1.84:54174 (resolved: 192.168.1.84:54174) to udp4 host 185.35.201.120:45922 (resolved: 185.35.201.120:45922) ice TRACE: 18:12:19.222596 selection.go:154: Inbound STUN (SuccessResponse) from udp4 host 185.35.201.120:45922 (resolved: 185.35.201.120:45922) to udp4 host 192.168.1.84:54174 (resolved: 192.168.1.84:54174) ice TRACE: 18:12:19.222596 selection.go:165: Found valid candidate pair: prio 8774140170971381247 (local, prio 2130706431) udp4 host 192.168.1.84:54174 (resolved: 192.168.1.84:54174) <-> udp4 host 185.35.201.120:45922 (resolved: 185.35.201.120:45922) (remote, prio 2042888703), state: succeeded, nominated: true, nominateOnBindingSuccess: false dtls TRACE: 18:12:19.601121 handshaker.go:313: [handshake:server] Flight 0 -> Flight 2 dtls TRACE: 18:12:19.601121 handshaker.go:189: [handshake:server] Flight 2: Preparing dtls TRACE: 18:12:19.601121 handshaker.go:189: [handshake:server] Flight 2: Sending dtls TRACE: 18:12:19.601121 conn.go:484: [handshake:server] -> HelloVerifyRequest (epoch: 0, seq: 0) dtls TRACE: 18:12:19.601121 handshaker.go:189: [handshake:server] Flight 2: Waiting dtls TRACE: 18:12:19.642918 handshaker.go:313: [handshake:server] Flight 2 -> Flight 4 dtls TRACE: 18:12:19.642918 handshaker.go:189: [handshake:server] Flight 4: Preparing dtls TRACE: 18:12:19.642918 handshaker.go:189: [handshake:server] Flight 4: Sending dtls TRACE: 18:12:19.642918 conn.go:484: [handshake:server] -> ServerHello (epoch: 0, seq: 1) dtls TRACE: 18:12:19.642918 conn.go:484: [handshake:server] -> TypeCertificate (epoch: 0, seq: 2) dtls TRACE: 18:12:19.642918 conn.go:484: [handshake:server] -> ServerKeyExchange (epoch: 0, seq: 3) dtls TRACE: 18:12:19.642918 conn.go:484: [handshake:server] -> CertificateRequest (epoch: 0, seq: 4) dtls TRACE: 18:12:19.642918 conn.go:484: [handshake:server] -> ServerHelloDone (epoch: 0, seq: 5) dtls TRACE: 18:12:19.642918 handshaker.go:189: [handshake:server] Flight 4: Waiting dtls TRACE: 18:12:19.696371 conn.go:984: server: <- Alert Fatal: HandshakeFailure pc INFO: 2025/11/13 18:12:19 Closing PeerConnection from DTLS CloseNotify pc INFO: 2025/11/13 18:12:19 peer connection state changed: closed pc WARNING: 2025/11/13 18:12:19 Failed to start manager: handshake error: alert: Alert Fatal: HandshakeFailure pc WARNING: 2025/11/13 18:12:19 undeclaredMediaProcessor failed to open SrtcpSession: the DTLS transport has not started yet pc WARNING: 2025/11/13 18:12:19 undeclaredMediaProcessor failed to open SrtpSession: the DTLS transport has not started yet turnc DEBUG: 18:12:19.697140 allocation.go:77: Send refresh request (dontWait=true) ice WARNING: 2025/11/13 18:12:19 Failed to read from candidate udp4 relay 91.90.45.34:59495 related 0.0.0.0:54162 (resolved: 91.90.45.34:59495): read udp 91.90.45.34:59495: i/o timeout turnc TRACE: 18:12:19.697140 client.go:440: Start Refresh request transaction M9pFcUjQOAS+WxEU to 91.90.45.34:443 turnc DEBUG: 18:12:19.697140 allocation.go:84: Refresh request sent turnc DEBUG: 18:12:19.697140 client.go:178: Failed to read: read udp4 0.0.0.0:54162: use of closed network connection. Exiting loop ice WARNING: 2025/11/13 18:12:19 Failed to read from candidate udp4 relay 91.90.45.34:61751 related 192.168.1.84:59175 (resolved: 91.90.45.34:61751): read udp 91.90.45.34:61751: use of closed network connection turnc DEBUG: 18:12:19.697140 allocation.go:77: Send refresh request (dontWait=true) turnc TRACE: 18:12:19.697140 client.go:440: Start Refresh request transaction LedHDrKBwJGxbOAI to 91.90.45.34:443 turnc DEBUG: 18:12:19.697140 allocation.go:84: Refresh request sent turnc DEBUG: 18:12:19.697140 client.go:178: Failed to read: read tcp4 192.168.1.84:59175->91.90.45.34:443: use of closed network connection. Exiting loop ice INFO: 2025/11/13 18:12:19 Setting new connection state: Closed pc INFO: 2025/11/13 18:12:19 ICE connection state changed: closed
@Philippe-Torrelli-Ale Hello, thank you for the report and for the detailed logs, do you have a self-contained example that reproduces the issue with pexip included? if so, we can dig in and get it fixed fast.
Hi Joe, sure, yes, I can probably assemble something How should I send it to you ?
Also, I can’t provide you access to the pexip server I am using, will it be a problem ?
Here you are, I hope it helps. I guess you will need to request a free trial account to pexip to try it, else i'll be happy to provide test result if you have suggestions on what to change
hello, don't want to seem pushy, any news on this ? Or is there something i can test to help on this matter ?
@Philippe-Torrelli-Ale ~we're reworking ICE API / interface and this issue is the second on my todo-list for ICE after this is merged https://github.com/pion/ice/pull/834~
Edit: sorry i got confused with another issue.
@Philippe-Torrelli-Ale Sorry i got confused with another issue (ICE issue), This issue is hard because I'm not sure how to test or debug Pexip, I guess i'll try to make a trial account and test it, hopefully it's simple to get one, No promises but I'll try this weekend.
thanks Joe, much appreciated
Hi Joe, i'm trying to obtain some pexip access that i could share with you for that, but so far, no news.
Meanwhile I started to track down when the problem appeared with pion, and found out that it would connect until pion/dtls v3.0.6 .. (i don't know if it means this issue must move to the pion/dtls repo :) )
Commit e3cf6bc seems to have broken the negociation.
I will try to investigate further (if i can figure out how this works) and keep you posted
@Philippe-Torrelli-Ale Thank you for the update, hmm, this seems interesting because that commit just added a safe guard to comply with the spec, maybe it broke it as a side effect, or maybe pexip expects renegotiation_info even tho it doesn't send the extension?
I actually didn't mention it previously because it's really complicated to isolate and even more to describe, but i have the exact same issue when connecting to our janus actually.. Long story short, I'm trying to forward rtp streams between the two entities.
From the pion logs point of view it's the same failure, and also fixed when reverting to pion v3..
The notable difference (from my point of view) being that munging sdp to rewrite actpass as active in the offer i send doesn't make it work. (so maybe it's not the same issue, but i interpreted that like this janus doesn't accept that way of connecting)
Maybe it's related to this? https://datatracker.ietf.org/doc/html/rfc5746#section-3.3 im going to make a PR. will you be able to test a branch?
sure
dope can you try this https://github.com/pion/dtls/pull/761
It fixed the issue, thanks a lot Joe.
Do you need that i post a trace ?
thank you for confirming we'll release this soon, and thank you for the details.
@Philippe-Torrelli-Ale the fix is released in dtls v3.0.9 :) thank you for the details. and sorry that this took too long to trace.
Don't be, that's amazing. Thanks again :)