[Pidgin] #16321: various uPnP and STUN and IPv6 issues
trac at pidgin.im
Tue Aug 19 11:34:56 EDT 2014
#16321: various uPnP and STUN and IPv6 issues
Reporter: dohmniq | Owner:
Type: patch | Status: new
Milestone: | Component: libpurple
Version: 2.10.9 | Keywords: uPnP STUN IPv6 SIMPLE
I'm using FreeBSD 10 with Pidgin 2.10.9. My one network interface (re0)
has one link-local IPv6 address and one private 10.x.x.x IPv4 address.
Router is DDWRT with uPnP. Upstream of that is a modem (192.168.x.1) with
DMZ to the router (192.168.x.2). Public IP is (for example) 126.96.36.199
Trying to connect to a SIP (Asterisk) server which has both IPv4 and IPv6
uPnP: there's a race condition in purple_upnp_discover_send_broadcast()
The input read handler is set up AFTER the packet is sent. On my network
the uPnP response arrives BEFORE this handler is set up and so is lost.
This is made worse because only the initial discover packet has a request
for WANIPConnection (which my router responds to) whereas subsequent
requests are all WANPPPConnection.
To fix this I moved the call to purple_input_add() from inside the
"if(sentSuccess)" block to before the for() loop and added a corresponding
purple_input_remove(dd->inpa) to after the for() loop. Note: this won't
fix the situation where the initial WANIPConnection packet is simply
lost/garbled on the network. (Maybe the simplest patch for that is to up
NUM_UDP_ATTEMPTS to 7 so that the "dd->retry_count % 2" part fires more
STUN: Lack of checking of return result of first sendto() causes STUN to
It's quite possible for the first sendto() to return EAGAIN (or
EWOULDBLOCK) - this is what happens for me and so STUN is aborted. My fix
is to check for a return of -1 and errno not EAGAIN or EWOULDBLOCK. The
next sendto() after the timeout sends OK and STUN works.
Could well be the fix for this ticket too as before my fix all I saw was
STUN retrying but with no actual output onto the wire:
STUN: listen() is given an IPv6 address if it occurs first
As far as I know, STUN is only useful for IPv4 because there is no NAT for
IPv6 due to the number of addresses. stun.c calls
purple_network_listen_range() which in turn calls getaddrinfo() with
AF_UNSPEC. On my machine this returns an IPv6 address first. If a listen
socket is set up with an IPv6 address then STUN fails because it's trying
to send a packet to an IPv4 address. I changed
purple_network_listen_range() to purple_network_listen_range_family() and
added the AF_INET arg.
This leads on to...
NETWORK: purple_network_listen_range_family() seems to ignore passed
This function calls purple_network_do_listen() with AF_UNSPEC - I replaced
this with socket_family.
Still can't connect to my SIP/Asterisk server as SIMPLE wants to use the
IPv6 address but I only my IPv4 address is usable. I suppose the solution
here is to try each of the IPs for the server in turn (with retries and
Someone did suggest an IPv4/IPv6 only command line flag:
Ticket URL: <https://developer.pidgin.im/ticket/16321>
More information about the Tracker