Project

General

Profile

Bug #3858

DynDNS errno 47: Address family not supported by protocol family

Added by Robbie Trencheny about 5 years ago. Updated about 4 years ago.

Status:
Resolved
Priority:
Normal
Category:
Dynamic DNS
Target version:
Start date:
09/11/2014
Due date:
% Done:

0%

Estimated time:
Affected Version:
All
Affected Architecture:

Description

I'm on pfSense 2.1.3-RELEASE amd64 (seems to be missing from affected version). Upon configuring the custom (v4, not v6, although v6 had the same issue) DynDNS service, I was met with the following in my logs (when verbose logging was enabled, and yes, I masked the full script URL and my IP address):

Sep 10 23:14:41    php: /services_dyndns_edit.php: DynDns: updatedns() starting
Sep 10 23:14:41    php: /services_dyndns_edit.php: DynDns (): XX.XXX.XX.XXX extracted from local system.
Sep 10 23:14:41    php: /services_dyndns_edit.php: DynDNS (): running get_failover_interface for wan. found em1
Sep 10 23:14:41    php: /services_dyndns_edit.php: DynDNS (): DynDns _update() starting.
Sep 10 23:14:41    php: /services_dyndns_edit.php: Custom DDNS (): DNS update() starting.
Sep 10 23:14:41    php: /services_dyndns_edit.php: Sending request to: http://myhost.example.com/dyndns/index.php?type=v4&ip=67.169.59.123
Sep 10 23:14:41    php: /services_dyndns_edit.php: DynDNS (): DynDns _checkStatus() starting.
Sep 10 23:14:41    php: /services_dyndns_edit.php: DynDNS (): Current Service: custom
Sep 10 23:14:41    php: /services_dyndns_edit.php: Curl error occurred: bind failed with errno 47: Address family not supported by protocol family

and the request would fail to complete. I started digging around, and found that if I commented line 277 (https://github.com/pfsense/pfsense/blob/master/etc/inc/dyndns.class#L277) of /etc/inc/dyndns.class, the request would complete. I checked the output of $this->_dnsRequestIfIP and found that it correctly output the IPv4 address assigned to my em1 interface (I only have a simple single WAN/single LAN setup). I checked the PHP Curl documentation, which stated that CURLOPT_INTERFACE will accept an IP address or interface name. I tried giving it em1 instead of the IP address provided in $this->_dnsRequestIfIP but that hung the webconfigurator.

So, current easiest fix is commenting line 277, because PHP is unable to send the request if bound to a specific interface.

Associated revisions

Revision 23ec30ee (diff)
Added by Chris Buechler about 4 years ago

Where doing a dynamic DNS update on IPv4, force curl to resolve IPv4 IPs. Ticket #3858

Revision becd6caa (diff)
Added by Chris Buechler about 4 years ago

Where doing a dynamic DNS update on IPv4, force curl to resolve IPv4 IPs. Ticket #3858

History

#1 Updated by Chris Buechler over 4 years ago

  • Status changed from New to Confirmed
  • Target version set to 2.3
  • Affected Version changed from 2.1.2 to All
  • Affected Architecture deleted (amd64)

that's what happens when you're dual stack, the URL has an AAAA, and it's updating a v4 IP.

#2 Updated by Jonathon Reinhart over 4 years ago

Chris Buechler wrote:

that's what happens when you're dual stack, the URL has an AAAA, and it's updating a v4 IP.

I'm still trying to understand what exactly is going on this bug. Clearly it's an issue for people, as IPv6 becomes more prevalent.

For the record, the line Robbie commented out is here :

curl_setopt($ch, CURLOPT_INTERFACE, $this->_dnsRequestIfIP);

which comes from:

$this->_dnsRequestIfIP = get_interface_ip($dnsRequestIf);

So I'm guessing that we're binding to the IPv4 address of the interface, but the URL has an AAAA, so we're trying to connect() to an IPv6 address, and curl doesn't like that?

I'm curious why Robbie's method of passing the interface name doesn't seem to work. I'm also curious why we even have to bind to an interface at all?

#3 Updated by Jonathon Reinhart over 4 years ago

I put together a quick test on Linux (using pycurl) that basically does:

c = pycurl.Curl()
c.setopt(c.INTERFACE, my_interface_ipv4_addr)
c.setopt(c.URL, 'http://[' + google_ipv6_addr + ']/')

to try and force a situation like you've described. (When I tried it with just the URL it worked just fine, and connect()ed to an IPv4 address).

Interestingly, I see the following in strace:

socket(PF_INET6, SOCK_STREAM, IPPROTO_IP) = 3
...
bind(3, {sa_family=AF_UNSPEC, sa_data="\0\0\0\0\0\0\0\0\0\0\0\0\0\0"}, 28) = -1 EAFNOSUPPORT (Address family not supported by protocol)

Why is curl trying to bind() to an AF_UNSPEC address? Seems like a bug in curl.

#4 Updated by Chris Buechler about 4 years ago

  • Status changed from Confirmed to Feedback
  • Target version changed from 2.3 to 2.2.5

It's bound to an interface name to ensure it egresses via its associated interface (ensures reachability where system routing table wouldn't, because of 'pass out ... route-to ...').

This should just need CURL_IPRESOLVE_V4 set in these cases. That wasn't being done for the dynamic DNS updates. What I just pushed should resolve this.

#5 Updated by Chris Buechler about 4 years ago

  • Assignee set to Chris Buechler

#6 Updated by Chris Buechler about 4 years ago

  • Status changed from Feedback to Resolved

confirmed fixed

Also available in: Atom PDF