hackney icon indicating copy to clipboard operation
hackney copied to clipboard

Why not always use inet:gethostbyname ?

Open an2deg opened this issue 6 months ago • 3 comments

Folks, why not always rely on system hostname resolver? Do I miss some specific usage scenario which requires usage of inet_res?

I believe that https://github.com/benoitc/hackney/blob/436f7b279771100097f967b86d96c55a79c8cc14/src/hackney_happy.erl#L126 could be simplified to just

  case (catch inet:gethostbyname(Hostname, InetType)) of
    {'ok', #hostent{h_addr_list=AddrList}} -> 
      lists:usort(AddrList);
    _ -> 
      []

Here are details on the issue I have: I'm working on organizig local dev environment based on Docker/Podman compose. The problem I'm trying to solve is how to make some services working inside compose environment and outside environment at the same time. Idea is to use magic hostname such as dev.local and use it in URL of all HTTP services, no matters where they are running.

On the dev workstations this magic host is suppose to be added into /etc/hosts

127.0.0.1	dev.local
::1		dev.local

This solution is almost working. The only issue I have is with components based on HTTPoison/hackney. For some reason hackney is trying to resolve host names in URL over DNS first and only then is falling back to the system resolver. And here we come to another "feature" of Docker Desktop: it over its internal DNS server for some reason returns records from the system /etc/hosts. Leading to that the magic host is resolving to 127.0.0.1 over DNS and to 192.168.65.254 over system resolver.

iex(registry@96282b60e624)3> :inet.getaddr(~c'dev.local', :inet)
{:ok, {192, 168, 65, 254}}
iex(registry@d7a9ee9a5a2d)1> :inet_res.getbyname(~c'dev.local', :a)
{:ok, {:hostent, ~c"dev.local", [], :inet, 4, [{127, 0, 0, 1}]}}
iex(registry@d7a9ee9a5a2d)2> 

an2deg avatar Aug 07 '25 11:08 an2deg

I'm having a similar issue where inet_res is not correctly resolving docker hosts while I'm connected to Wi-Fi

Example:

iex(1)> :inet_res.getbyname(~c'auth0', :a)
{:ok,
 {:hostent, ~c"auth0.homenet.telecomitalia.it", [], :inet, 4, [{127, 0, 0, 1}]}}
iex(2)> :inet.getaddr(~c'auth0', :inet)
{:ok, {172, 20, 0, 3}}

This means that while calling curl auth0 (auth0 being the container in the same network) works fine, hackney returns :econnrefused

iex(5)> :hackney.get(~c"http://auth0", [], [], [])
{:error, :econnrefused}

inet_res does work fine if I disable my internet connection though:

iex(1)> :inet_res.getbyname(~c'auth0', :a)
{:ok, {:hostent, ~c"auth0", [], :inet, 4, [{172, 20, 0, 3}]}}

EDIT: From looking at it more closely it seems this is because my router has a search domain (even thought my network settings do not specify one) and it might trip this part of the doc:

This function uses resolver option search that is a list of domain names. If the name to resolve contains no dots, it is prepended to each domain name in the search list, and they are tried in order. If the name contains dots, it is first tried as an absolute name and if that fails, the search list is used. If the name has a trailing dot, it is supposed to be an absolute name and the search list is not used.

Removing the search domain from the router did fix the issue for me, but it still feels like a bug

Hamcha avatar Sep 12 '25 10:09 Hamcha

to handle happy eyeball. I've no issue with docker myself, how do you set networking with docker?

benoitc avatar Oct 27 '25 10:10 benoitc

Hi @benoitc .

My idea was to use special hostname such as dev.local as an unified URL for components running inside compose env and on the host. For this purpuses I'm using extra_hosts pointing to the host-gateway - a magic entry, a feature of Docker Desktop for Mac/Windows - letting containers break trough the host network:

extra_hosts:
      - "dev.local:host-gateway"

Docker desktop is injecting this entry into /etc/hosts in every containers having extra_hosts entry:

root@docker-desktop:/usr/src/app# cat /etc/hosts
127.0.0.1	localhost
::1	localhost ip6-localhost ip6-loopback
fe00::	ip6-localnet
ff00::	ip6-mcastprefix
ff02::1	ip6-allnodes
ff02::2	ip6-allrouters
192.168.65.254	dev.local
root@docker-desktop:/usr/src/app#

Then having

127.0.0.1	dev.local
::1		dev.local

in /etc/hosts on the host makes dev.local :

  1. resolvable as 127.0.0.1 on the host
  2. in a container: 2.1 resolveble as 192.168.65.254 when using :inet.getaddr() (taking this entry from container' /etc/hosts) 2.2 resolveble as 127.0.0.1 over DNS (:inet_res.getbyname() or so on)

an2deg avatar Oct 27 '25 11:10 an2deg