dns cache: fix manually inserted SRV record order
authorMiklos Tirpak <miklos@iptel.org>
Wed, 18 Aug 2010 13:32:36 +0000 (15:32 +0200)
committerMiklos Tirpak <miklos@iptel.org>
Wed, 18 Aug 2010 13:44:40 +0000 (15:44 +0200)
The manually inserted SRV records thought the RPC interface
were not ordered by their priority and weight which resulted in
wrong SRV look-ups, i.e. not the highest priority record
was chosen first.

dns_cache.c

index 182e61f..ef3a986 100644 (file)
@@ -4221,6 +4221,8 @@ int dns_cache_add_record(unsigned short type,
        ticks_t expire;
        int err, h;
        int size;
+       struct dns_rr   *new_rr, **rr_p, **rr_iter;
+       struct srv_rdata        *srv_rd;
 
        /* eliminate gcc warnings */
        ip_addr = 0;
@@ -4358,6 +4360,7 @@ int dns_cache_add_record(unsigned short type,
                                /* let the rr point to the new structure */
                                rr = (struct dns_rr*)translate_pointer((char*)new, (char*)old,
                                                                                                                (char*)rr);
+                               new_rr = rr;
 
                                if (type == T_SRV) {
                                        /* fix the priority, weight, and port */
@@ -4392,6 +4395,7 @@ int dns_cache_add_record(unsigned short type,
                                                        "DNS cache entry\n");
                                        goto error;
                                }
+                               new_rr = rr;
 
                                switch(type) {
                                case T_A:
@@ -4409,6 +4413,46 @@ int dns_cache_add_record(unsigned short type,
                                /* maximum expire value has been already fixed by 
                                 * dns_cache_clone_entry() */
                        }
+
+                       if (type == T_SRV) {
+                               /* SRV records must be ordered by their priority and weight.
+                                * With modifying an exising rr, or adding new rr to the DNS entry,
+                                * the ordered list might got broken which needs to be fixed.
+                                */
+                               rr_p = NULL;
+                               for (   rr_iter = &new->rr_lst;
+                                       *rr_iter;
+                                       rr_iter = &((*rr_iter)->next)
+                               ) {
+                                       if (*rr_iter == new_rr) {
+                                               rr_p = rr_iter;
+                                               continue;
+                                       }
+                                       srv_rd = (struct srv_rdata*)(*rr_iter)->rdata;
+                                       if ((priority < srv_rd->priority) ||
+                                               ((priority == srv_rd->priority) && (weight > srv_rd->weight))
+                                       )
+                                               break; /* insert here */
+                               }
+
+                               if (!rr_p)
+                                       for (   rr_p = rr_iter;
+                                               *rr_p && (*rr_p != new_rr);
+                                               rr_p = &((*rr_p)->next)
+                                       );
+                               if (!rr_p) {
+                                       LOG(L_ERR, "ERROR: Failed to correct the orderd list of SRV resource records\n");
+                                       goto error;
+                               }
+
+                               if (*rr_iter != new_rr->next) {
+                                       /* unlink rr from the list */
+                                       *rr_p = (*rr_p)->next;
+                                       /* link it before *rr_iter */
+                                       new_rr->next = *rr_iter;
+                                       *rr_iter = new_rr;
+                               }
+                       }
                }
        }