[Pidgin] #16321: various uPnP and STUN and IPv6 issues

Pidgin 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)

 Trying to connect to a SIP (Asterisk) server which has both IPv4 and IPv6

 First up:

 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
 than once).

 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
 timeouts, etc.)

 Someone did suggest an IPv4/IPv6 only command line flag:

Ticket URL: <https://developer.pidgin.im/ticket/16321>
Pidgin <https://pidgin.im>

More information about the Tracker mailing list