No/Invalid host lookup in smtpd_sasl_path parameter

Previous Topic Next Topic
 
classic Classic list List threaded Threaded
6 messages Options
Reply | Threaded
Open this post in threaded view
|

No/Invalid host lookup in smtpd_sasl_path parameter

Lorenzo Bernardi-2
Hi all,

I'm currently trying to dockerize my mail server environment and
encountered a strange issue on which I spent some time to debug.
I have several docker containers running different components:
- postfix (172.20.0.4): postfix 3.1.6-0+deb9u1
- dovecot (172.20.0.5): dovecot 1:2.2.27-3+deb9u1
- antispam (172.20.0.7): amavisd-new 1:2.10.1-4 & spamassassin
3.4.1-6+deb9u1

I setup dovecot to handle SASL and listen on port 12345.
When I use the hostname in postfix configuration, I receive the
following error:
postfix/smtpd[141]: fatal: host/service dovecot/12345 not found: No
address associated with hostname

When using the IP address of the dovecot container, I don't have that
issue and everything runs as expected.
Everything also works correctly if I add the following entry in
/var/spool/postfix/etc/hosts:
172.20.0.5 dovecot

It looks like postfix is not correctly resolving the hostname from the
"smtpd_sasl_path" parameter.

FYI: I connect to the dovecot container using its hostname in the
"mailbox_transport" and "virtual_transport" and those are correctly
resolved, thanks to the "lmtp_host_lookup = dns" parameter.
FYI2: I copied the content of the /etc/resolv.conf file from the postfix
container to the /var/spool/postfix/etc/ in the same container in order
to make the postfix dns resolution work.

After some digging in the source code, I noticed the error should come
from util/inet_connect.c (line 98):

if ((aierr = hostname_to_sockaddr(host, port, SOCK_STREAM, &res0)) != 0)
        msg_fatal("host/service %s/%s not found: %s",
host, port, MAI_STRERROR(aierr));

This calls hostname_to_sockaddr which uses "gethostbyname" in
util/myaddrinfo.c (line 350):

  /*
      * Look up the IPv4 address list.
      */
     if ((hp = gethostbyname(hostname)) == 0)
        return (h_errno == TRY_AGAIN ? EAI_AGAIN : EAI_NODATA);
     if (hp->h_addrtype != AF_INET
        || hp->h_length != sizeof(template.sin.sin_addr))
return (EAI_NODATA);

I was wondering if the hostname lookup was handled differently for the
other parameters, and if it was possible to either fix that behavior or
add an option to do a proper dns lookup and thus correctly resolve the
hostname in the "smtpd_sasl_path" parameter.

Below the relevant part of my postfix main.cf file.
I can provide more logging if needed.

Thanks in advance for your help!

Kind regards,
Lorenzo Bernardi

#### main.cf ####
...
lmtp_host_lookup = dns
...
mailbox_transport = lmtp:inet:dovecot:24
...
smtp_host_lookup = dns
...
smtpd_sasl_path = inet:[dovecot]:12345
smtpd_sasl_type = dovecot
...
virtual_transport = lmtp:inet:dovecot:24
...
#### /main.cf ####
Reply | Threaded
Open this post in threaded view
|

Re: No/Invalid host lookup in smtpd_sasl_path parameter

Wietse Venema
Lorenzo Bernardi:
> I setup dovecot to handle SASL and listen on port 12345.
> When I use the hostname in postfix configuration, I receive the
> following error:
> postfix/smtpd[141]: fatal: host/service dovecot/12345 not found: No
> address associated with hostname

The getaddrinfo() SYSTEM LIBRARY routine, given hostname 'dovecot',
found no IP address. Postfix does not use gethostbyname() except
on systems that are more than 10 years old.

> Everything also works correctly if I add the following entry in
> /var/spool/postfix/etc/hosts:
> 172.20.0.5 dovecot

There should be no need to do that.

According to Docker documentation, "If you want containers to be
able to resolve IP addresses by container name, you should use
user-defined networks instead [of using the default bridge network]".

docs.docker.com/engine/userguide/networking/#the-default-bridge-network

        Wietse
Reply | Threaded
Open this post in threaded view
|

Re: No/Invalid host lookup in smtpd_sasl_path parameter

Lorenzo Bernardi-2
Hi Wietse,

Thank you for your answer.

The docker containers are running Debian 9.3 and the postfix package
from the official Debian repository (Version: 3.1.6-0+deb9u1).

As you can see below the source code still contains calls to
gethostbyname():

> postfix-3.1.6~ fgrep gethostbyname . -R -n
> ./proto/stop:603:gethostbyname
> ./auxiliary/name-addr-test/gethostbyname.c:2:  * gethostbyname tester.
> compile with:
> ./auxiliary/name-addr-test/gethostbyname.c:4:  * cc -o gethostbyname
> gethostbyname.c (SunOS 4.x)
> ./auxiliary/name-addr-test/gethostbyname.c:6:  * cc -o gethostbyname
> gethostbyname.c -lnsl (SunOS 5.x)
> ./auxiliary/name-addr-test/gethostbyname.c:8:  * run as: gethostbyname
> hostname
> ./auxiliary/name-addr-test/gethostbyname.c:29:    if (hp =
> gethostbyname(argv[1])) {
> ./src/util/myaddrinfo.c:350:    if ((hp = gethostbyname(hostname)) ==
> 0)
> ./src/util/find_inet.c:69: if ((hp = gethostbyname(host)) == 0)
> ./src/smtp/smtp_addr.c:25:/* getnameinfo() or gethostbyname().
> ./src/local/biff_notify.c:69: if ((hp = gethostbyname("localhost")) ==
> 0) {
> ./HISTORY:103: gethostbyname() to look up its own machine name.  Sites
> ./HISTORY:6720: hostname to "unknown". Some gethostbyname()
> implementations
> ./HISTORY:13578: adding gethostbyname() calls that cause maildir
> delivery
> ./HISTORY:22047: adding code that calls gethostbyname() to determine
> the

Regarding the docker network, I followed the recommendations of the
official website and I'm using a user-defined network, which works with
no issue.
I can correctly resolve the containers when in Debian by just using
their name:

> ~ cat /etc/resolv.conf
> search openstacklocal
> nameserver 127.0.0.11
> options ndots:0

> ~ cat /etc/hosts
> 127.0.0.1 localhost
> ::1 localhost ip6-localhost ip6-loopback
> fe00::0 ip6-localnet
> ff00::0 ip6-mcastprefix
> ff02::1 ip6-allnodes
> ff02::2 ip6-allrouters
> 172.20.0.4 postfix

> ~ ping dovecot -c1
> PING dovecot (172.20.0.5): 56 data bytes
> 64 bytes from 172.20.0.5: icmp_seq=0 ttl=64 time=0.165 ms
> --- dovecot ping statistics ---
> 1 packets transmitted, 1 packets received, 0% packet loss
> round-trip min/avg/max/stddev = 0.165/0.165/0.165/0.000 ms

> ~ nslookup dovecot
> Server: 127.0.0.11
> Address: 127.0.0.11#53
>
> Non-authoritative answer:
> Name: dovecot
> Address: 172.20.0.5

As said before, using the hostname and not the IP address of the dovecot
container in the "virtual_transport" and "mailbox_transport" works:

> # main.cf
> ...
> mailbox_transport = lmtp:inet:dovecot:24
> virtual_transport = lmtp:inet:dovecot:24
> ...

The issue here is the "smtpd_sasl_path " parameter.
When I set it this way, it doesn't resolve the hostname:

> smtpd_sasl_path = inet:[dovecot]:12345

(I tried both with and without [])

But when I directly put the IP address:

> smtpd_sasl_path = inet:[172.20.0.5]:12345

or add an hosts entry in /var/spool/postfix/etc/hosts:

> 172.20.0.5 dovecot

Everything works as expected

Kr,
Lorenzo

---
LORENZO BERNARDI

On 2017-12-27 00:51, [hidden email] wrote:

> Lorenzo Bernardi:
>
>> I setup dovecot to handle SASL and listen on port 12345.
>> When I use the hostname in postfix configuration, I receive the
>> following error:
>> postfix/smtpd[141]: fatal: host/service dovecot/12345 not found: No
>> address associated with hostname
>
> The getaddrinfo() SYSTEM LIBRARY routine, given hostname 'dovecot',
> found no IP address. Postfix does not use gethostbyname() except
> on systems that are more than 10 years old.
>
>> Everything also works correctly if I add the following entry in
>> /var/spool/postfix/etc/hosts:
>> 172.20.0.5 dovecot
>
> There should be no need to do that.
>
> According to Docker documentation, "If you want containers to be
> able to resolve IP addresses by container name, you should use
> user-defined networks instead [of using the default bridge network]".
>
> docs.docker.com/engine/userguide/networking/#the-default-bridge-network
>
> Wietse
Reply | Threaded
Open this post in threaded view
|

Re: No/Invalid host lookup in smtpd_sasl_path parameter

Wietse Venema
Lorenzo Bernardi:
> Hi Wietse,
>
> Thank you for your answer.
>
> The docker containers are running Debian 9.3 and the postfix package
> from the official Debian repository (Version: 3.1.6-0+deb9u1).
>
> As you can see below the source code still contains calls to
> gethostbyname():

Grep does not prove that code is called. The only gethostbyname
calls that are left over in the code are in src/local/biff_notify.c
and in src/util/find_inet.c, and the latter is called only by the
dict_mysql.c module. None of these calls are relevant for the problem
at hand: hooking up Postfix with the Dovecot auth service.

> Regarding the docker network, I followed the recommendations of the
> official website and I'm using a user-defined network, which works with
> no issue.

You made a mistake somewhere, because the SYSTEM LIBRARY FUNCTION
getaddrinfo() is unable to find your dovecot host unless you add
it to /etc/hosts.

To be totally clear about this: Postfix does not look in /etc/hosts,
it is the SYSTEM LIBRARY that reads the file, as configured in the
SYSTEM CONFIGURATION file /etc/nsswitch.conf.

See www.postfix.org/DEBUG_README.html for how to trace a program
with strace and ltrace, then you can see which call is failing and
why.

        Wietse
Reply | Threaded
Open this post in threaded view
|

Re: No/Invalid host lookup in smtpd_sasl_path parameter

Lorenzo Bernardi-2
Thank you Wietse,

I followed your advice and ran a strace on the smtpd process.

Postfix is running in a chroot environment (/var/spool/postfix) and I
noticed the following:

> Dec 27 16:55:05 85b8d58a343c root: open("/etc/resolv.conf",
> O_RDONLY|O_CLOEXEC) = 18
> Dec 27 16:55:05 85b8d58a343c root: fstat(18, {st_mode=S_IFREG|0644,
> st_size=60, ...}) = 0
> Dec 27 16:55:05 85b8d58a343c root: read(18, "search
> openstacklocal\nnameserver 127.0.0.11\noptions ndots:0\n", 4096) = 60
> Dec 27 16:55:05 85b8d58a343c root: read(18, "", 4096)                  
>    = 0
> Dec 27 16:55:05 85b8d58a343c root: close(18)                            
>    = 0
> Dec 27 16:55:05 85b8d58a343c root: open("/etc/host.conf",
> O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory)
> Dec 27 16:55:05 85b8d58a343c root: futex(0x7f9690f79a64,
> FUTEX_WAKE_PRIVATE, 2147483647) = 0
> Dec 27 16:55:05 85b8d58a343c root: open("/etc/hosts",
> O_RDONLY|O_CLOEXEC)  = -1 ENOENT (No such file or directory)
> Dec 27 16:55:05 85b8d58a343c root: open("/etc/ld.so.cache",
> O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory)
> Dec 27 16:55:05 85b8d58a343c root:
> open("/lib/x86_64-linux-gnu/tls/x86_64/libnss_dns.so.2",
> O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory)
> Dec 27 16:55:05 85b8d58a343c root:
> stat("/lib/x86_64-linux-gnu/tls/x86_64", 0x7ffc42960c30) = -1 ENOENT
> (No such file or directory)
> Dec 27 16:55:05 85b8d58a343c root:
> open("/lib/x86_64-linux-gnu/tls/libnss_dns.so.2", O_RDONLY|O_CLOEXEC) =
> -1 ENOENT (No such file or directory)
> Dec 27 16:55:05 85b8d58a343c root: stat("/lib/x86_64-linux-gnu/tls",
> 0x7ffc42960c30) = -1 ENOENT (No such file or directory)
> Dec 27 16:55:05 85b8d58a343c root:
> open("/lib/x86_64-linux-gnu/x86_64/libnss_dns.so.2",
> O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory)
> Dec 27 16:55:05 85b8d58a343c root: stat("/lib/x86_64-linux-gnu/x86_64",
> 0x7ffc42960c30) = -1 ENOENT (No such file or directory)
> Dec 27 16:55:05 85b8d58a343c root:
> open("/lib/x86_64-linux-gnu/libnss_dns.so.2", O_RDONLY|O_CLOEXEC) = -1
> ENOENT (No such file or directory)
> Dec 27 16:55:05 85b8d58a343c root: stat("/lib/x86_64-linux-gnu",
> 0x7ffc42960c30) = -1 ENOENT (No such file or directory)
> Dec 27 16:55:05 85b8d58a343c root:
> open("/usr/lib/x86_64-linux-gnu/tls/x86_64/libnss_dns.so.2",
> O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory)
> Dec 27 16:55:05 85b8d58a343c root:
> stat("/usr/lib/x86_64-linux-gnu/tls/x86_64", 0x7ffc42960c30) = -1
> ENOENT (No such file or directory)
> Dec 27 16:55:05 85b8d58a343c root:
> open("/usr/lib/x86_64-linux-gnu/tls/libnss_dns.so.2",
> O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory)
> Dec 27 16:55:05 85b8d58a343c root:
> stat("/usr/lib/x86_64-linux-gnu/tls", 0x7ffc42960c30) = -1 ENOENT (No
> such file or directory)
> Dec 27 16:55:05 85b8d58a343c root:
> open("/usr/lib/x86_64-linux-gnu/x86_64/libnss_dns.so.2",
> O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory)
> Dec 27 16:55:05 85b8d58a343c root:
> stat("/usr/lib/x86_64-linux-gnu/x86_64", 0x7ffc42960c30) = -1 ENOENT
> (No such file or directory)
> Dec 27 16:55:05 85b8d58a343c root:
> open("/usr/lib/x86_64-linux-gnu/libnss_dns.so.2", O_RDONLY|O_CLOEXEC) =
> -1 ENOENT (No such file or directory)
> Dec 27 16:55:05 85b8d58a343c root: stat("/usr/lib/x86_64-linux-gnu",
> 0x7ffc42960c30) = -1 ENOENT (No such file or directory)
> Dec 27 16:55:05 85b8d58a343c root:
> open("/lib/tls/x86_64/libnss_dns.so.2", O_RDONLY|O_CLOEXEC) = -1 ENOENT
> (No such file or directory)
> Dec 27 16:55:05 85b8d58a343c root: stat("/lib/tls/x86_64",
> 0x7ffc42960c30) = -1 ENOENT (No such file or directory)
> Dec 27 16:55:05 85b8d58a343c root: open("/lib/tls/libnss_dns.so.2",
> O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory)
> Dec 27 16:55:05 85b8d58a343c root: stat("/lib/tls", 0x7ffc42960c30)    
>    = -1 ENOENT (No such file or directory)
> Dec 27 16:55:05 85b8d58a343c root: open("/lib/x86_64/libnss_dns.so.2",
> O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory)
> Dec 27 16:55:05 85b8d58a343c root: stat("/lib/x86_64", 0x7ffc42960c30)  
>    = -1 ENOENT (No such file or directory)
> Dec 27 16:55:05 85b8d58a343c root: open("/lib/libnss_dns.so.2",
> O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory)
> Dec 27 16:55:05 85b8d58a343c root: stat("/lib", {st_mode=S_IFDIR|0755,
> st_size=4096, ...}) = 0
> Dec 27 16:55:05 85b8d58a343c root:
> open("/usr/lib/tls/x86_64/libnss_dns.so.2", O_RDONLY|O_CLOEXEC) = -1
> ENOENT (No such file or directory)
> Dec 27 16:55:05 85b8d58a343c root: stat("/usr/lib/tls/x86_64",
> 0x7ffc42960c30) = -1 ENOENT (No such file or directory)
> Dec 27 16:55:05 85b8d58a343c root: open("/usr/lib/tls/libnss_dns.so.2",
> O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory)
> Dec 27 16:55:05 85b8d58a343c root: stat("/usr/lib/tls", 0x7ffc42960c30)
>    = -1 ENOENT (No such file or directory)
> Dec 27 16:55:05 85b8d58a343c root:
> open("/usr/lib/x86_64/libnss_dns.so.2", O_RDONLY|O_CLOEXEC) = -1 ENOENT
> (No such file or directory)
> Dec 27 16:55:05 85b8d58a343c root: stat("/usr/lib/x86_64",
> 0x7ffc42960c30) = -1 ENOENT (No such file or directory)
> Dec 27 16:55:05 85b8d58a343c root: open("/usr/lib/libnss_dns.so.2",
> O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory)
> Dec 27 16:55:05 85b8d58a343c root: stat("/usr/lib",
> {st_mode=S_IFDIR|0755, st_size=4096, ...}) = 0

It looks like "libnss_dns.so.2" cannot be found due to the chrooted
environment and thus no DNS query can be made (at least for this
specific call).
I fixed it by copying the libraries from /lib/x86_64-linux-gnu/ to
/var/spool/postfix/lib/x86_64-linux-gnu/:

> cp /lib/x86_64-linux-gnu/ /var/spool/postfix/lib/ -R

This apparently worked as postfix is now able to make DNS queries:

> Dec 27 17:05:14 85b8d58a343c root: stat("/etc/resolv.conf",
> {st_mode=S_IFREG|0644, st_size=60, ...}) = 0
> Dec 27 17:05:14 85b8d58a343c root: socket(AF_INET,
> SOCK_DGRAM|SOCK_NONBLOCK, IPPROTO_IP) = 19
> Dec 27 17:05:14 85b8d58a343c root: connect(19, {sa_family=AF_INET,
> sin_port=htons(53), sin_addr=inet_addr("127.0.0.11")}, 16) = 0
> Dec 27 17:05:14 85b8d58a343c root: poll([{fd=19, events=POLLOUT}], 1,
> 0)   = 1 ([{fd=19, revents=POLLOUT}])
> Dec 27 17:05:14 85b8d58a343c root: sendto(19,
> "2-\1\0\0\1\0\0\0\0\0\0\7dovecot\0\0\1\0\1", 25, MSG_NOSIGNAL, NULL, 0)
> = 25
> Dec 27 17:05:14 85b8d58a343c root: poll([{fd=19, events=POLLIN}], 1,
> 5000) = 1 ([{fd=19, revents=POLLIN}])
> Dec 27 17:05:14 85b8d58a343c root: ioctl(19, FIONREAD, [48])            
>    = 0
> Dec 27 17:05:14 85b8d58a343c root: recvfrom(19,
> "2-\201\200\0\1\0\1\0\0\0\0\7dovecot\0\0\1\0\1\7dovecot\0\0\1\0\1\0\0\2X\0\4\254\24\0\5",
> 1024, 0, {sa_family=AF_INET, sin_port=htons(53),
> sin_addr=inet_addr("127.0.0.11")}, [28->16]) = 48
> Dec 27 17:05:14 85b8d58a343c root: close(19)                            
>    = 0
> Dec 27 17:05:14 85b8d58a343c root: socket(AF_INET, SOCK_STREAM,
> IPPROTO_TCP) = 19
> Dec 27 17:05:14 85b8d58a343c root: fcntl(19, F_GETFL)                  
>    = 0x2 (flags O_RDWR)
> Dec 27 17:05:14 85b8d58a343c root: fcntl(19, F_SETFL,
> O_RDWR|O_NONBLOCK)   = 0
> Dec 27 17:05:14 85b8d58a343c root: setsockopt(19, SOL_SOCKET,
> SO_KEEPALIVE, [1], 4) = 0
> Dec 27 17:05:14 85b8d58a343c root: connect(19, {sa_family=AF_INET,
> sin_port=htons(12345), sin_addr=inet_addr("172.20.0.5")}, 16) = -1
> EINPROGRESS (Operation now in progress)
> Dec 27 17:05:14 85b8d58a343c root: poll([{fd=19, events=POLLOUT}], 1,
> 10000) = 1 ([{fd=19, revents=POLLOUT}])
> Dec 27 17:05:14 85b8d58a343c root: getsockopt(19, SOL_SOCKET, SO_ERROR,
> [0], [4]) = 0

Shouldn't this be documented somewhere for other people that might
encounter the issue?

Cheers,
---
LORENZO BERNARDI

On 2017-12-27 16:18, [hidden email] wrote:

> Lorenzo Bernardi:
>
>> Hi Wietse,
>>
>> Thank you for your answer.
>>
>> The docker containers are running Debian 9.3 and the postfix package
>> from the official Debian repository (Version: 3.1.6-0+deb9u1).
>>
>> As you can see below the source code still contains calls to
>> gethostbyname():
>
> Grep does not prove that code is called. The only gethostbyname
> calls that are left over in the code are in src/local/biff_notify.c
> and in src/util/find_inet.c, and the latter is called only by the
> dict_mysql.c module. None of these calls are relevant for the problem
> at hand: hooking up Postfix with the Dovecot auth service.
>
>> Regarding the docker network, I followed the recommendations of the
>> official website and I'm using a user-defined network, which works
>> with
>> no issue.
>
> You made a mistake somewhere, because the SYSTEM LIBRARY FUNCTION
> getaddrinfo() is unable to find your dovecot host unless you add
> it to /etc/hosts.
>
> To be totally clear about this: Postfix does not look in /etc/hosts,
> it is the SYSTEM LIBRARY that reads the file, as configured in the
> SYSTEM CONFIGURATION file /etc/nsswitch.conf.
>
> See www.postfix.org/DEBUG_README.html for how to trace a program
> with strace and ltrace, then you can see which call is failing and
> why.
>
> Wietse
Reply | Threaded
Open this post in threaded view
|

Re: No/Invalid host lookup in smtpd_sasl_path parameter

Wietse Venema
Lorenzo Bernardi:
> It looks like "libnss_dns.so.2" cannot be found due to the chrooted
> environment and thus no DNS query can be made (at least for this
> specific call).
> I fixed it by copying the libraries from /lib/x86_64-linux-gnu/ to
> /var/spool/postfix/lib/x86_64-linux-gnu/:
>
> > cp /lib/x86_64-linux-gnu/ /var/spool/postfix/lib/ -R

The problem with making a copy of libnss_dns.so is that the copy
will become outdated, unless the files are (r)synced at regular
times from the host into /var/spool/postfix. Ditto with /etc/{services,
resolv.conf, nsswitch.conf, host.conf, hosts, localtime} and so on.

> This apparently worked as postfix is now able to make DNS queries:
> Shouldn't this be documented somewhere for other people that might
> encounter the issue?

The chroot feature is documented in the master(5) manpage which
describes the master.cf file format.

   Chroot (default: Postfix >= 3.0: n, Postfix <3.0: y)
          Whether or not the service  runs  chrooted  to  the  mail  queue
          directory (pathname is controlled by the queue_directory config-
          uration variable in the main.cf file).

          Chroot should not be used with the local(8), pipe(8),  spawn(8),
          and virtual(8) daemons.  Although the proxymap(8) server can run
          chrooted, doing so defeats most of the purpose  of  having  that
          service in the first place.

          The files in the examples/chroot-setup subdirectory of the Post-
          fix source archive show set up a Postfix chroot environment on a
          variety  of  systems.  See  also  BASIC_CONFIGURATION_README for
          issues related to running daemons chrooted.

The examples/chroot-setup files have not been updated in many years.
Every system and every version is different, so use this information
as inspiration, not as gospel.

        Wietse