RFC 2132 "DHCP Options and BOOTP Vendor Extensions"
3.8. Domain Name Server Option says:

   The domain name server option specifies a list of Domain Name System
   (STD 13, RFC 1035 [8]) name servers available to the client.  Servers
   SHOULD be listed in order of preference.

I'm on a wifi with three name servers in its DHCP OFFER, which tcpdump',
`route monitor' and and `dhcpleasctl -l athn0' show in the same order.

But in my case, resolvd writes them in reverse order, making our
resolver query the least preferred one first as per resolv.conf(5):

        Up to ASR_MAXNS (currently 5) name servers may be listed, one
        per line.  If there are multiple servers, the resolver
        library queries them in the order listed.

I have yet into a specific problem due to this, but this behaviour did
surprise me.

Looking at resolvd(8), this is because it sorts the list of name servers
by prio (makes sense) as well as IP (why?).

If I sort them only by prio and switch to mergesort(3) to have a stable
function, the resulting order in resolv.conf is exactly what I see in
the DHCP OFFER, as expected.

So why do we sort them by IP?


Index: resolvd.c
===================================================================
RCS file: /cvs/src/sbin/resolvd/resolvd.c,v
retrieving revision 1.28
diff -u -p -r1.28 resolvd.c
--- resolvd.c   2 Sep 2022 09:39:55 -0000       1.28
+++ resolvd.c   3 Nov 2022 22:25:30 -0000
@@ -503,8 +503,8 @@ handle_route_message(struct rt_msghdr *r
                return;
        }
 
-       /* Sort proposals, based upon priority and IP */
-       qsort(learning, ASR_MAXNS, sizeof(learning[0]), cmp);
+       /* Sort proposals, based upon priority */
+       mergesort(learning, ASR_MAXNS, sizeof(learning[0]), cmp);
 
        /* Eliminate duplicates */
        for (i = 0; i < ASR_MAXNS - 1; i++) {
@@ -694,10 +694,7 @@ cmp(const void *a, const void *b)
 {
        const struct rdns_proposal      *rpa = a, *rpb = b;
 
-       if (rpa->prio == rpb->prio)
-               return strcmp(rpa->ip, rpb->ip);
-       else
-               return rpa->prio < rpb->prio ? -1 : 1;
+       return rpa->prio < rpb->prio ? -1 : rpa->prio > rpb->prio;
 }
 
 #ifndef SMALL

Reply via email to