#118 milter binds to localhost with inet6 specified

opendkim (95)

I noticed something very, very odd with opendkim and the milter interface.

If I specify that opendkim should use inet6:localhost:port, and I have both and ::1 defined as localhost in /etc/hosts, OpenDKIM will bind to as tcp6.

root@mbx2:~# netstat -a | grep 8465
tcp6 0 0 localhost:8465 [::]:* LISTEN

root@mbx2:~# grep localhost /etc/hosts localhost
::1 localhost ip6-localhost ip6-loopback

root@mbx2:~# telnet localhost 8465
Trying ::1...
Connected to localhost.
Escape character is '^]'.

root@mbx2:~# telnet ::1 8465
Trying ::1...
telnet: Unable to connect to remote host: Connection refused

root@mbx2:~# telnet 8465
Connected to
Escape character is '^]'.

root@mbx2:~# grep inet6 /opt/zimbra/conf/opendkim.conf
Socket inet6:8465@localhost

This seems like utterly broken behavior on the part of OpenDKIM. If I specify inet6, it should not be looking at the ipv4 interface at all.


    • milestone: --> 2.6.0
    • assigned_to: nobody --> cm-msk
    • priority: 5 --> 6
  • OpenDKIM passes the socket parameter through to libmilter without touching it. If there's a bug here, I don't think it's ours.

    I'll try to reproduce it.

    • status: open --> pending
  • With 2.6.0 and this configuration:

    Background No
    Socket inet6:8846@localhost
    Mode v

    I run it, and I see:

    medusa[4]% !net
    netstat -an | fgrep 8846
    tcp6 0 0 ::1.8846 *.* LISTEN

    medusa[7]% telnet localhost 8846
    Trying ::1...
    Connected to localhost.blackops.org.
    Escape character is '^]'.
    telnet> close
    Connection closed.
    medusa[8]% telnet 8846
    telnet: connect to address Connection refused
    telnet: Unable to connect to remote host

    Seems right to me.

    Was your libmilter compiled with IPv6 support?

    • status: pending --> open
  • yes, libmilter was compiled with ipv6. Changing the Socket to inet6:8465@[::1] resolved the issue for me.

    In your test, you don't note if /etc/hosts has as a valid interface, or if the loopback or similar is bound to


    • status: open --> pending
  • I have:

    medusa[1339]% fgrep localhost /etc/hosts
    ::1 localhost.blackops.org localhost localhost.blackops.org localhost

    ...but this would normally be handled by the resolver, I would think. So if you said "inet6", libmilter would use getipnodebyname() to resolve it to an IP address. I don't know what lookup strategy that function uses or what flags libmilter might be passing to it.

    In any event, the Socket setting is passed directly through to libmilter, so this isn't specifically an opendkim problem. However, if there's a bug in libmilter, we can certainly bring it to Sendmail's attention.

    • priority: 6 --> 5
  • A. Schulze
    A. Schulze

    I have related/similiar experiences. Looks like two bugs in libmilter.
    assume this Socketdescription: "inet6:12345:milter.example.org"

    Libmilter take the dnsname an resolv the name via old gethostbyname.
    if ther is only a AAAA record in dns an no A record, any milter will fail to start
    because libmilter issue a dns query for the a record first and immediately an second aaaa query.
    Because the A query results in nxdomain, the milter fail. The answer to the second query is ignored by libmilter.
    -> first bug

    Solution: add "option inet6" to /etc/resolv.conf. That forces the stubresolver to first query aaaa records and the first answer has success.

    In the case of localhost the resolver tries to lookup /etc/hosts. Here on most systems localhost is defined twice.
    So the "query for the a record of localhost" will have success and libmilter will bind to it.
    -> second bug

  • These are still libmilter problems, not problems opendkim can solve. It's libmilter that translates that string.

    • status: pending --> open
  • Yeah, this needs to be sent up to sendmail

  • I've forwarded the problem report to Sendmail. I'll report back when I hear something.

  • Reply from Sendmail:

    > Is this a bug?

    I don't think so. I just read the code again and it all looks
    correct. The only reasons an IPv4 address would be used are
    (from most likely to least likely):

    1. There system host resolution order is dns before hosts and a DNS
    lookup for localhost only returns an A record:

    % dig +noall +answer AAAA localhost
    % dig +noall +answer A localhost
    localhost. 600 IN A

    Note how the AAAA lookup didn't return anything.

    If that is the case, their DNS is misconfigured as they should be
    getting a reply for AAAA localhost lookups. They can either fix
    DNS or change their host resolution order.

    2. They don't have an IPv6 address assigned to a usuable network
    interface (unlikely) as we call getipnodebyname() with the flag
    AI_ADDRCONFIG which:

    o The AI_ADDRCONFIG flag specifies that a query for AAAA records
    should occur only if the node has at least one IPv6 source address
    configured and a query for A records should occur only if the node
    has at least one IPv4 source address configured.

    3. Their OS does not provide a getipnodebyname() and that OS's
    gethostbyname() doesn't honor the '_res.options |= RES_USE_INET6;'
    we do in our compat routine. If their OS supports IPv6, then
    they likely have a getipnodebyname() call. Note that Linux
    is the only platform in which we define NEEDSGETIPNODE.

    4. Their OS provides a broken getipnodebyname().

  • A. Schulze
    A. Schulze

    If one still uses gethostbyname() and getipnodebyname() it's not a bug:
    It's imperceptible far behind the horizon!

    But the world turns further.
    getipnodebyname() *IS* deprecated today. Everybody is advised to use getaddrinfo() and getnameinfo().

    • assigned_to: cm-msk --> nobody
    • status: open --> pending
  • Quanah, any comments on Sendmail's response?

    • status: pending --> closed-out-of-date