Annotation of embedaddon/dnsmasq/src/domain-match.c, revision 1.1.1.1

1.1       misho       1: /* dnsmasq is Copyright (c) 2000-2022 Simon Kelley
                      2: 
                      3:    This program is free software; you can redistribute it and/or modify
                      4:    it under the terms of the GNU General Public License as published by
                      5:    the Free Software Foundation; version 2 dated June, 1991, or
                      6:    (at your option) version 3 dated 29 June, 2007.
                      7:  
                      8:    This program is distributed in the hope that it will be useful,
                      9:    but WITHOUT ANY WARRANTY; without even the implied warranty of
                     10:    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
                     11:    GNU General Public License for more details.
                     12:      
                     13:    You should have received a copy of the GNU General Public License
                     14:    along with this program.  If not, see <http://www.gnu.org/licenses/>.
                     15: */
                     16: 
                     17: #include "dnsmasq.h"
                     18: 
                     19: static int order(char *qdomain, size_t qlen, struct server *serv);
                     20: static int order_qsort(const void *a, const void *b);
                     21: static int order_servers(struct server *s, struct server *s2);
                     22: 
                     23: /* If the server is USE_RESOLV or LITERAL_ADDRES, it lives on the local_domains chain. */
                     24: #define SERV_IS_LOCAL (SERV_USE_RESOLV | SERV_LITERAL_ADDRESS)
                     25: 
                     26: void build_server_array(void)
                     27: {
                     28:   struct server *serv;
                     29:   int count = 0;
                     30:   
                     31:   for (serv = daemon->servers; serv; serv = serv->next)
                     32: #ifdef HAVE_LOOP
                     33:     if (!(serv->flags & SERV_LOOP))
                     34: #endif
                     35:       {
                     36:        count++;
                     37:        if (serv->flags & SERV_WILDCARD)
                     38:          daemon->server_has_wildcard = 1;
                     39:       }
                     40:   
                     41:   for (serv = daemon->local_domains; serv; serv = serv->next)
                     42:     {
                     43:       count++;
                     44:       if (serv->flags & SERV_WILDCARD)
                     45:        daemon->server_has_wildcard = 1;
                     46:     }
                     47:   
                     48:   daemon->serverarraysz = count;
                     49: 
                     50:   if (count > daemon->serverarrayhwm)
                     51:     {
                     52:       struct server **new;
                     53: 
                     54:       count += 10; /* A few extra without re-allocating. */
                     55: 
                     56:       if ((new = whine_malloc(count * sizeof(struct server *))))
                     57:        {
                     58:          if (daemon->serverarray)
                     59:            free(daemon->serverarray);
                     60:          
                     61:          daemon->serverarray = new;
                     62:          daemon->serverarrayhwm = count;
                     63:        }
                     64:     }
                     65: 
                     66:   count = 0;
                     67:   
                     68:   for (serv = daemon->servers; serv; serv = serv->next)
                     69: #ifdef HAVE_LOOP
                     70:     if (!(serv->flags & SERV_LOOP))
                     71: #endif
                     72:       {
                     73:        daemon->serverarray[count] = serv;
                     74:        serv->serial = count;
                     75:        serv->last_server = -1;
                     76:        count++;
                     77:       }
                     78:   
                     79:   for (serv = daemon->local_domains; serv; serv = serv->next, count++)
                     80:     daemon->serverarray[count] = serv;
                     81:   
                     82:   qsort(daemon->serverarray, daemon->serverarraysz, sizeof(struct server *), order_qsort);
                     83:   
                     84:   /* servers need the location in the array to find all the whole
                     85:      set of equivalent servers from a pointer to a single one. */
                     86:   for (count = 0; count < daemon->serverarraysz; count++)
                     87:     if (!(daemon->serverarray[count]->flags & SERV_IS_LOCAL))
                     88:       daemon->serverarray[count]->arrayposn = count;
                     89: }
                     90: 
                     91: /* we're looking for the server whose domain is the longest exact match
                     92:    to the RH end of qdomain, or a local address if the flags match.
                     93:    Add '.' to the LHS of the query string so
                     94:    server=/.example.com/ works.
                     95: 
                     96:    A flag of F_SERVER returns an upstream server only.
                     97:    A flag of F_DNSSECOK returns a DNSSEC capable server only and
                     98:    also disables NODOTS servers from consideration.
                     99:    A flag of F_DOMAINSRV returns a domain-specific server only.
                    100:    A flag of F_CONFIG returns anything that generates a local
                    101:    reply of IPv4 or IPV6.
                    102:    return 0 if nothing found, 1 otherwise.
                    103: */
                    104: int lookup_domain(char *domain, int flags, int *lowout, int *highout)
                    105: {
                    106:   int rc, crop_query, nodots;
                    107:   ssize_t qlen;
                    108:   int try, high, low = 0;
                    109:   int nlow = 0, nhigh = 0;
                    110:   char *cp, *qdomain = domain;
                    111: 
                    112:   /* may be no configured servers. */
                    113:   if (daemon->serverarraysz == 0)
                    114:     return 0;
                    115:   
                    116:   /* find query length and presence of '.' */
                    117:   for (cp = qdomain, nodots = 1, qlen = 0; *cp; qlen++, cp++)
                    118:     if (*cp == '.')
                    119:       nodots = 0;
                    120: 
                    121:   /* Handle empty name, and searches for DNSSEC queries without
                    122:      diverting to NODOTS servers. */
                    123:   if (qlen == 0 || flags & F_DNSSECOK)
                    124:     nodots = 0;
                    125: 
                    126:   /* Search shorter and shorter RHS substrings for a match */
                    127:   while (qlen >= 0)
                    128:     {
                    129:       /* Note that when we chop off a label, all the possible matches
                    130:         MUST be at a larger index than the nearest failing match with one more
                    131:         character, since the array is sorted longest to smallest. Hence 
                    132:         we don't reset low to zero here, we can go further below and crop the 
                    133:         search string to the size of the largest remaining server
                    134:         when this match fails. */
                    135:       high = daemon->serverarraysz;
                    136:       crop_query = 1;
                    137:       
                    138:       /* binary search */
                    139:       while (1) 
                    140:        {
                    141:          try = (low + high)/2;
                    142: 
                    143:          if ((rc = order(qdomain, qlen, daemon->serverarray[try])) == 0)
                    144:            break;
                    145:          
                    146:          if (rc < 0)
                    147:            {
                    148:              if (high == try)
                    149:                {
                    150:                  /* qdomain is longer or same length as longest domain, and try == 0 
                    151:                     crop the query to the longest domain. */
                    152:                  crop_query = qlen - daemon->serverarray[try]->domain_len;
                    153:                  break;
                    154:                }
                    155:              high = try;
                    156:            }
                    157:          else
                    158:            {
                    159:              if (low == try)
                    160:                {
                    161:                  /* try now points to the last domain that sorts before the query, so 
                    162:                     we know that a substring of the query shorter than it is required to match, so
                    163:                     find the largest domain that's shorter than try. Note that just going to
                    164:                     try+1 is not optimal, consider searching bbb in (aaa,ccc,bb). try will point
                    165:                     to aaa, since ccc sorts after bbb, but the first domain that has a chance to 
                    166:                     match is bb. So find the length of the first domain later than try which is
                    167:                     is shorter than it. 
                    168:                     There's a nasty edge case when qdomain sorts before _any_ of the 
                    169:                     server domains, where try _doesn't point_ to the last domain that sorts
                    170:                     before the query, since no such domain exists. In that case, the loop 
                    171:                     exits via the rc < 0 && high == try path above and this code is
                    172:                     not executed. */
                    173:                  ssize_t len, old = daemon->serverarray[try]->domain_len;
                    174:                  while (++try != daemon->serverarraysz)
                    175:                    {
                    176:                      if (old != (len = daemon->serverarray[try]->domain_len))
                    177:                        {
                    178:                          crop_query = qlen - len;
                    179:                          break;
                    180:                        }
                    181:                    }
                    182:                  break;
                    183:                }
                    184:              low = try;
                    185:            }
                    186:        };
                    187:       
                    188:       if (rc == 0)
                    189:        {
                    190:          int found = 1;
                    191: 
                    192:          if (daemon->server_has_wildcard)
                    193:            {
                    194:              /* if we have example.com and *example.com we need to check against *example.com, 
                    195:                 but the binary search may have found either. Use the fact that example.com is sorted before *example.com
                    196:                 We favour example.com in the case that both match (ie www.example.com) */
                    197:              while (try != 0 && order(qdomain, qlen, daemon->serverarray[try-1]) == 0)
                    198:                try--;
                    199:              
                    200:              if (!(qdomain == domain || *qdomain == 0 || *(qdomain-1) == '.'))
                    201:                {
                    202:                  while (try < daemon->serverarraysz-1 && order(qdomain, qlen, daemon->serverarray[try+1]) == 0)
                    203:                    try++;
                    204:                  
                    205:                  if (!(daemon->serverarray[try]->flags & SERV_WILDCARD))
                    206:                     found = 0;
                    207:                }
                    208:            }
                    209:          
                    210:          if (found && filter_servers(try, flags, &nlow, &nhigh))
                    211:            /* We have a match, but it may only be (say) an IPv6 address, and
                    212:               if the query wasn't for an AAAA record, it's no good, and we need
                    213:               to continue generalising */
                    214:            {
                    215:              /* We've matched a setting which says to use servers without a domain.
                    216:                 Continue the search with empty query. We set the F_SERVER flag
                    217:                 so that --address=/#/... doesn't match. */
                    218:              if (daemon->serverarray[nlow]->flags & SERV_USE_RESOLV)
                    219:                {
                    220:                  crop_query = qlen;
                    221:                  flags |= F_SERVER;
                    222:                }
                    223:              else
                    224:                break;
                    225:            }
                    226:        }
                    227:       
                    228:       /* crop_query must be at least one always. */
                    229:       if (crop_query == 0)
                    230:        crop_query = 1;
                    231: 
                    232:       /* strip chars off the query based on the largest possible remaining match,
                    233:         then continue to the start of the next label unless we have a wildcard
                    234:         domain somewhere, in which case we have to go one at a time. */
                    235:       qlen -= crop_query;
                    236:       qdomain += crop_query;
                    237:       if (!daemon->server_has_wildcard)
                    238:        while (qlen > 0 &&  (*(qdomain-1) != '.'))
                    239:          qlen--, qdomain++;
                    240:     }
                    241: 
                    242:   /* domain has no dots, and we have at least one server configured to handle such,
                    243:      These servers always sort to the very end of the array. 
                    244:      A configured server eg server=/lan/ will take precdence. */
                    245:   if (nodots &&
                    246:       (daemon->serverarray[daemon->serverarraysz-1]->flags & SERV_FOR_NODOTS) &&
                    247:       (nlow == nhigh || daemon->serverarray[nlow]->domain_len == 0))
                    248:     filter_servers(daemon->serverarraysz-1, flags, &nlow, &nhigh);
                    249:   
                    250:   if (lowout)
                    251:     *lowout = nlow;
                    252:   
                    253:   if (highout)
                    254:     *highout = nhigh;
                    255: 
                    256:   /* qlen == -1 when we failed to match even an empty query, if there are no default servers. */
                    257:   if (nlow == nhigh || qlen == -1)
                    258:     return 0;
                    259:   
                    260:   return 1;
                    261: }
                    262: 
                    263: /* Return first server in group of equivalent servers; this is the "master" record. */
                    264: int server_samegroup(struct server *a, struct server *b)
                    265: {
                    266:   return order_servers(a, b) == 0;
                    267: }
                    268: 
                    269: int filter_servers(int seed, int flags, int *lowout, int *highout)
                    270: {
                    271:   int nlow = seed, nhigh = seed;
                    272:   int i;
                    273:   
                    274:   /* expand nlow and nhigh to cover all the records with the same domain 
                    275:      nlow is the first, nhigh - 1 is the last. nlow=nhigh means no servers,
                    276:      which can happen below. */
                    277:   while (nlow > 0 && order_servers(daemon->serverarray[nlow-1], daemon->serverarray[nlow]) == 0)
                    278:     nlow--;
                    279:   
                    280:   while (nhigh < daemon->serverarraysz-1 && order_servers(daemon->serverarray[nhigh], daemon->serverarray[nhigh+1]) == 0)
                    281:     nhigh++;
                    282:   
                    283:   nhigh++;
                    284:   
                    285: #define SERV_LOCAL_ADDRESS (SERV_6ADDR | SERV_4ADDR | SERV_ALL_ZEROS)
                    286:   
                    287:   if (flags & F_CONFIG)
                    288:     {
                    289:       /* We're just lookin for any matches that return an RR. */
                    290:       for (i = nlow; i < nhigh; i++)
                    291:        if (daemon->serverarray[i]->flags & SERV_LOCAL_ADDRESS)
                    292:          break;
                    293:       
                    294:       /* failed, return failure. */
                    295:       if (i == nhigh)
                    296:        nhigh = nlow;
                    297:     }
                    298:   else
                    299:     {
                    300:       /* Now the servers are on order between low and high, in the order
                    301:         IPv6 addr, IPv4 addr, return zero for both, resolvconf servers, send upstream, no-data return.
                    302:         
                    303:         See which of those match our query in that priority order and narrow (low, high) */
                    304:       
                    305:       for (i = nlow; i < nhigh && (daemon->serverarray[i]->flags & SERV_6ADDR); i++);
                    306:       
                    307:       if (!(flags & F_SERVER) && i != nlow && (flags & F_IPV6))
                    308:        nhigh = i;
                    309:       else
                    310:        {
                    311:          nlow = i;
                    312:          
                    313:          for (i = nlow; i < nhigh && (daemon->serverarray[i]->flags & SERV_4ADDR); i++);
                    314:          
                    315:          if (!(flags & F_SERVER) && i != nlow && (flags & F_IPV4))
                    316:            nhigh = i;
                    317:          else
                    318:            {
                    319:              nlow = i;
                    320:              
                    321:              for (i = nlow; i < nhigh && (daemon->serverarray[i]->flags & SERV_ALL_ZEROS); i++);
                    322:              
                    323:              if (!(flags & F_SERVER) && i != nlow && (flags & (F_IPV4 | F_IPV6)))
                    324:                nhigh = i;
                    325:              else
                    326:                {
                    327:                  nlow = i;
                    328:                  
                    329:                  /* Short to resolv.conf servers */
                    330:                  for (i = nlow; i < nhigh && (daemon->serverarray[i]->flags & SERV_USE_RESOLV); i++);
                    331:                  
                    332:                  if (i != nlow)
                    333:                    nhigh = i;
                    334:                  else
                    335:                    {
                    336:                      /* now look for a server */
                    337:                      for (i = nlow; i < nhigh && !(daemon->serverarray[i]->flags & SERV_LITERAL_ADDRESS); i++);
                    338:                      
                    339:                      if (i != nlow)
                    340:                        {
                    341:                          /* If we want a server that can do DNSSEC, and this one can't, 
                    342:                             return nothing, similarly if were looking only for a server
                    343:                             for a particular domain. */
                    344:                          if ((flags & F_DNSSECOK) && !(daemon->serverarray[nlow]->flags & SERV_DO_DNSSEC))
                    345:                            nlow = nhigh;
                    346:                          else if ((flags & F_DOMAINSRV) && daemon->serverarray[nlow]->domain_len == 0)
                    347:                            nlow = nhigh;
                    348:                          else
                    349:                            nhigh = i;
                    350:                        }
                    351:                      else
                    352:                        {
                    353:                          /* --local=/domain/, only return if we don't need a server. */
                    354:                          if (flags & (F_DNSSECOK | F_DOMAINSRV | F_SERVER))
                    355:                            nhigh = i;
                    356:                        }
                    357:                    }
                    358:                }
                    359:            }
                    360:        }
                    361:     }
                    362: 
                    363:   *lowout = nlow;
                    364:   *highout = nhigh;
                    365:   
                    366:   return (nlow != nhigh);
                    367: }
                    368: 
                    369: int is_local_answer(time_t now, int first, char *name)
                    370: {
                    371:   int flags = 0;
                    372:   int rc = 0;
                    373:   
                    374:   if ((flags = daemon->serverarray[first]->flags) & SERV_LITERAL_ADDRESS)
                    375:     {
                    376:       if (flags & SERV_4ADDR)
                    377:        rc = F_IPV4;
                    378:       else if (flags & SERV_6ADDR)
                    379:        rc = F_IPV6;
                    380:       else if (flags & SERV_ALL_ZEROS)
                    381:        rc = F_IPV4 | F_IPV6;
                    382:       else
                    383:        {
                    384:          /* argument first is the first struct server which matches the query type;
                    385:             now roll back to the server which is just the same domain, to check if that 
                    386:             provides an answer of a different type. */
                    387: 
                    388:          for (;first > 0 && order_servers(daemon->serverarray[first-1], daemon->serverarray[first]) == 0; first--);
                    389:          
                    390:          if ((daemon->serverarray[first]->flags & SERV_LOCAL_ADDRESS) ||
                    391:              check_for_local_domain(name, now))
                    392:            rc = F_NOERR;
                    393:          else
                    394:            rc = F_NXDOMAIN;
                    395:        }
                    396:     }
                    397: 
                    398:   return rc;
                    399: }
                    400: 
                    401: size_t make_local_answer(int flags, int gotname, size_t size, struct dns_header *header, char *name, char *limit, int first, int last, int ede)
                    402: {
                    403:   int trunc = 0, anscount = 0;
                    404:   unsigned char *p;
                    405:   int start;
                    406:   union all_addr addr;
                    407:   
                    408:   if (flags & (F_NXDOMAIN | F_NOERR))
                    409:     log_query(flags | gotname | F_NEG | F_CONFIG | F_FORWARD, name, NULL, NULL, 0);
                    410:          
                    411:   setup_reply(header, flags, ede);
                    412:          
                    413:   if (!(p = skip_questions(header, size)))
                    414:     return 0;
                    415:          
                    416:   if (flags & gotname & F_IPV4)
                    417:     for (start = first; start != last; start++)
                    418:       {
                    419:        struct serv_addr4 *srv = (struct serv_addr4 *)daemon->serverarray[start];
                    420: 
                    421:        if (srv->flags & SERV_ALL_ZEROS)
                    422:          memset(&addr, 0, sizeof(addr));
                    423:        else
                    424:          addr.addr4 = srv->addr;
                    425:        
                    426:        if (add_resource_record(header, limit, &trunc, sizeof(struct dns_header), &p, daemon->local_ttl, NULL, T_A, C_IN, "4", &addr))
                    427:          anscount++;
                    428:        log_query((flags | F_CONFIG | F_FORWARD) & ~F_IPV6, name, (union all_addr *)&addr, NULL, 0);
                    429:       }
                    430:   
                    431:   if (flags & gotname & F_IPV6)
                    432:     for (start = first; start != last; start++)
                    433:       {
                    434:        struct serv_addr6 *srv = (struct serv_addr6 *)daemon->serverarray[start];
                    435: 
                    436:        if (srv->flags & SERV_ALL_ZEROS)
                    437:          memset(&addr, 0, sizeof(addr));
                    438:        else
                    439:          addr.addr6 = srv->addr;
                    440:        
                    441:        if (add_resource_record(header, limit, &trunc, sizeof(struct dns_header), &p, daemon->local_ttl, NULL, T_AAAA, C_IN, "6", &addr))
                    442:          anscount++;
                    443:        log_query((flags | F_CONFIG | F_FORWARD) & ~F_IPV4, name, (union all_addr *)&addr, NULL, 0);
                    444:       }
                    445: 
                    446:   if (trunc)
                    447:     header->hb3 |= HB3_TC;
                    448:   header->ancount = htons(anscount);
                    449:   
                    450:   return p - (unsigned char *)header;
                    451: }
                    452: 
                    453: #ifdef HAVE_DNSSEC
                    454: int dnssec_server(struct server *server, char *keyname, int *firstp, int *lastp)
                    455: {
                    456:   int first, last, index;
                    457: 
                    458:   /* Find server to send DNSSEC query to. This will normally be the 
                    459:      same as for the original query, but may be another if
                    460:      servers for domains are involved. */                    
                    461:   if (!lookup_domain(keyname, F_DNSSECOK, &first, &last))
                    462:     return -1;
                    463: 
                    464:   for (index = first; index != last; index++)
                    465:     if (daemon->serverarray[index] == server)
                    466:       break;
                    467:              
                    468:   /* No match to server used for original query.
                    469:      Use newly looked up set. */
                    470:   if (index == last)
                    471:     index =  daemon->serverarray[first]->last_server == -1 ?
                    472:       first : daemon->serverarray[first]->last_server;
                    473: 
                    474:   if (firstp)
                    475:     *firstp = first;
                    476: 
                    477:   if (lastp)
                    478:     *lastp = last;
                    479:    
                    480:   return index;
                    481: }
                    482: #endif
                    483: 
                    484: /* order by size, then by dictionary order */
                    485: static int order(char *qdomain, size_t qlen, struct server *serv)
                    486: {
                    487:   size_t dlen = 0;
                    488:     
                    489:   /* servers for dotless names always sort last 
                    490:      searched for name is never dotless. */
                    491:   if (serv->flags & SERV_FOR_NODOTS)
                    492:     return -1;
                    493: 
                    494:   dlen = serv->domain_len;
                    495:   
                    496:   if (qlen < dlen)
                    497:     return 1;
                    498:   
                    499:   if (qlen > dlen)
                    500:     return -1;
                    501: 
                    502:   return hostname_order(qdomain, serv->domain);
                    503: }
                    504: 
                    505: static int order_servers(struct server *s1, struct server *s2)
                    506: {
                    507:   int rc;
                    508: 
                    509:   /* need full comparison of dotless servers in 
                    510:      order_qsort() and filter_servers() */
                    511: 
                    512:   if (s1->flags & SERV_FOR_NODOTS)
                    513:      return (s2->flags & SERV_FOR_NODOTS) ? 0 : 1;
                    514:    
                    515:   if ((rc = order(s1->domain, s1->domain_len, s2)) != 0)
                    516:     return rc;
                    517: 
                    518:   /* For identical domains, sort wildcard ones first */
                    519:   if (s1->flags & SERV_WILDCARD)
                    520:     return (s2->flags & SERV_WILDCARD) ? 0 : 1;
                    521: 
                    522:   return (s2->flags & SERV_WILDCARD) ? -1 : 0;
                    523: }
                    524:   
                    525: static int order_qsort(const void *a, const void *b)
                    526: {
                    527:   int rc;
                    528:   
                    529:   struct server *s1 = *((struct server **)a);
                    530:   struct server *s2 = *((struct server **)b);
                    531:   
                    532:   rc = order_servers(s1, s2);
                    533: 
                    534:   /* Sort all literal NODATA and local IPV4 or IPV6 responses together,
                    535:      in a very specific order. We flip the SERV_LITERAL_ADDRESS bit
                    536:      so the order is IPv6 literal, IPv4 literal, all-zero literal, 
                    537:      unqualified servers, upstream server, NXDOMAIN literal. */
                    538:   if (rc == 0)
                    539:     rc = ((s2->flags & (SERV_LITERAL_ADDRESS | SERV_4ADDR | SERV_6ADDR | SERV_USE_RESOLV | SERV_ALL_ZEROS)) ^ SERV_LITERAL_ADDRESS) -
                    540:       ((s1->flags & (SERV_LITERAL_ADDRESS | SERV_4ADDR | SERV_6ADDR | SERV_USE_RESOLV | SERV_ALL_ZEROS)) ^ SERV_LITERAL_ADDRESS);
                    541: 
                    542:   /* Finally, order by appearance in /etc/resolv.conf etc, for --strict-order */
                    543:   if (rc == 0)
                    544:     if (!(s1->flags & SERV_LITERAL_ADDRESS))
                    545:       rc = s1->serial - s2->serial;
                    546: 
                    547:   return rc;
                    548: }
                    549: 
                    550: 
                    551: /* When loading large numbers of server=.... lines during startup,
                    552:    there's no possibility that there will be server records that can be reused, but
                    553:    searching a long list for each server added grows as O(n^2) and slows things down.
                    554:    This flag is set only if is known there may be free server records that can be reused.
                    555:    There's a call to mark_servers(0) in read_opts() to reset the flag before
                    556:    main config read. */
                    557: 
                    558: static int maybe_free_servers = 0;
                    559: 
                    560: /* Must be called before  add_update_server() to set daemon->servers_tail */
                    561: void mark_servers(int flag)
                    562: {
                    563:   struct server *serv, *next, **up;
                    564: 
                    565:   maybe_free_servers = !!flag;
                    566:   
                    567:   daemon->servers_tail = NULL;
                    568:   
                    569:   /* mark everything with argument flag */
                    570:   for (serv = daemon->servers; serv; serv = serv->next)
                    571:     {
                    572:       if (serv->flags & flag)
                    573:        serv->flags |= SERV_MARK;
                    574:       else
                    575:        serv->flags &= ~SERV_MARK;
                    576: 
                    577:       daemon->servers_tail = serv;
                    578:     }
                    579:   
                    580:   /* --address etc is different: since they are expected to be 
                    581:      1) numerous and 2) not reloaded often. We just delete 
                    582:      and recreate. */
                    583:   if (flag)
                    584:     for (serv = daemon->local_domains, up = &daemon->local_domains; serv; serv = next)
                    585:       {
                    586:        next = serv->next;
                    587: 
                    588:        if (serv->flags & flag)
                    589:          {
                    590:            *up = next;
                    591:            free(serv->domain);
                    592:            free(serv);
                    593:          }
                    594:        else 
                    595:          up = &serv->next;
                    596:       }
                    597: }
                    598: 
                    599: void cleanup_servers(void)
                    600: {
                    601:   struct server *serv, *tmp, **up;
                    602: 
                    603:   /* unlink and free anything still marked. */
                    604:   for (serv = daemon->servers, up = &daemon->servers, daemon->servers_tail = NULL; serv; serv = tmp) 
                    605:     {
                    606:       tmp = serv->next;
                    607:       if (serv->flags & SERV_MARK)
                    608:        {
                    609:          server_gone(serv);
                    610:          *up = serv->next;
                    611:         free(serv->domain);
                    612:         free(serv);
                    613:        }
                    614:       else 
                    615:        {
                    616:          up = &serv->next;
                    617:          daemon->servers_tail = serv;
                    618:        }
                    619:     }
                    620: }
                    621: 
                    622: int add_update_server(int flags,
                    623:                      union mysockaddr *addr,
                    624:                      union mysockaddr *source_addr,
                    625:                      const char *interface,
                    626:                      const char *domain,
                    627:                      union all_addr *local_addr)
                    628: {
                    629:   struct server *serv = NULL;
                    630:   char *alloc_domain;
                    631:   
                    632:   if (!domain)
                    633:     domain = "";
                    634: 
                    635:   /* .domain == domain, for historical reasons. */
                    636:   if (*domain == '.')
                    637:     while (*domain == '.') domain++;
                    638:   else if (*domain == '*')
                    639:     {
                    640:       domain++;
                    641:       if (*domain != 0)
                    642:        flags |= SERV_WILDCARD;
                    643:     }
                    644:   
                    645:   if (*domain == 0)
                    646:     alloc_domain = whine_malloc(1);
                    647:   else
                    648:     alloc_domain = canonicalise((char *)domain, NULL);
                    649: 
                    650:   if (!alloc_domain)
                    651:     return 0;
                    652: 
                    653:   if (flags & SERV_IS_LOCAL)
                    654:     {
                    655:       size_t size;
                    656:       
                    657:       if (flags & SERV_6ADDR)
                    658:        size = sizeof(struct serv_addr6);
                    659:       else if (flags & SERV_4ADDR)
                    660:        size = sizeof(struct serv_addr4);
                    661:       else
                    662:        size = sizeof(struct serv_local);
                    663:       
                    664:       if (!(serv = whine_malloc(size)))
                    665:        {
                    666:          free(alloc_domain);
                    667:          return 0;
                    668:        }
                    669:       
                    670:       serv->next = daemon->local_domains;
                    671:       daemon->local_domains = serv;
                    672:       
                    673:       if (flags & SERV_4ADDR)
                    674:        ((struct serv_addr4*)serv)->addr = local_addr->addr4;
                    675:       
                    676:       if (flags & SERV_6ADDR)
                    677:        ((struct serv_addr6*)serv)->addr = local_addr->addr6;
                    678:     }
                    679:   else
                    680:     { 
                    681:       /* Upstream servers. See if there is a suitable candidate, if so unmark
                    682:         and move to the end of the list, for order. The entry found may already
                    683:         be at the end. */
                    684:       struct server **up, *tmp;
                    685: 
                    686:       serv = NULL;
                    687:       
                    688:       if (maybe_free_servers)
                    689:        for (serv = daemon->servers, up = &daemon->servers; serv; serv = tmp)
                    690:          {
                    691:            tmp = serv->next;
                    692:            if ((serv->flags & SERV_MARK) &&
                    693:                hostname_isequal(alloc_domain, serv->domain))
                    694:              {
                    695:                /* Need to move down? */
                    696:                if (serv->next)
                    697:                  {
                    698:                    *up = serv->next;
                    699:                    daemon->servers_tail->next = serv;
                    700:                    daemon->servers_tail = serv;
                    701:                    serv->next = NULL;
                    702:                  }
                    703:                break;
                    704:              }
                    705:            else
                    706:              up = &serv->next;
                    707:          }
                    708:       
                    709:       if (serv)
                    710:        {
                    711:          free(alloc_domain);
                    712:          alloc_domain = serv->domain;
                    713:        }
                    714:       else
                    715:        {
                    716:          if (!(serv = whine_malloc(sizeof(struct server))))
                    717:            {
                    718:              free(alloc_domain);
                    719:              return 0;
                    720:            }
                    721:          
                    722:          memset(serv, 0, sizeof(struct server));
                    723:          
                    724:          /* Add to the end of the chain, for order */
                    725:          if (daemon->servers_tail)
                    726:            daemon->servers_tail->next = serv;
                    727:          else
                    728:            daemon->servers = serv;
                    729:          daemon->servers_tail = serv;
                    730:        }
                    731:       
                    732: #ifdef HAVE_LOOP
                    733:       serv->uid = rand32();
                    734: #endif      
                    735:          
                    736:       if (interface)
                    737:        safe_strncpy(serv->interface, interface, sizeof(serv->interface));
                    738:       if (addr)
                    739:        serv->addr = *addr;
                    740:       if (source_addr)
                    741:        serv->source_addr = *source_addr;
                    742:     }
                    743:     
                    744:   serv->flags = flags;
                    745:   serv->domain = alloc_domain;
                    746:   serv->domain_len = strlen(alloc_domain);
                    747:   
                    748:   return 1;
                    749: }
                    750: 

FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>