Imported Upstream version 2.88
[platform/upstream/dnsmasq.git] / src / domain-match.c
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   if (nlow == nhigh)
257     return 0;
258
259   return 1;
260 }
261
262 /* Return first server in group of equivalent servers; this is the "master" record. */
263 int server_samegroup(struct server *a, struct server *b)
264 {
265   return order_servers(a, b) == 0;
266 }
267
268 int filter_servers(int seed, int flags, int *lowout, int *highout)
269 {
270   int nlow = seed, nhigh = seed;
271   int i;
272   
273   /* expand nlow and nhigh to cover all the records with the same domain 
274      nlow is the first, nhigh - 1 is the last. nlow=nhigh means no servers,
275      which can happen below. */
276   while (nlow > 0 && order_servers(daemon->serverarray[nlow-1], daemon->serverarray[nlow]) == 0)
277     nlow--;
278   
279   while (nhigh < daemon->serverarraysz-1 && order_servers(daemon->serverarray[nhigh], daemon->serverarray[nhigh+1]) == 0)
280     nhigh++;
281   
282   nhigh++;
283   
284 #define SERV_LOCAL_ADDRESS (SERV_6ADDR | SERV_4ADDR | SERV_ALL_ZEROS)
285   
286   if (flags & F_CONFIG)
287     {
288       /* We're just lookin for any matches that return an RR. */
289       for (i = nlow; i < nhigh; i++)
290         if (daemon->serverarray[i]->flags & SERV_LOCAL_ADDRESS)
291           break;
292       
293       /* failed, return failure. */
294       if (i == nhigh)
295         nhigh = nlow;
296     }
297   else
298     {
299       /* Now the servers are on order between low and high, in the order
300          IPv6 addr, IPv4 addr, return zero for both, resolvconf servers, send upstream, no-data return.
301          
302          See which of those match our query in that priority order and narrow (low, high) */
303       
304       for (i = nlow; i < nhigh && (daemon->serverarray[i]->flags & SERV_6ADDR); i++);
305       
306       if (!(flags & F_SERVER) && i != nlow && (flags & F_IPV6))
307         nhigh = i;
308       else
309         {
310           nlow = i;
311           
312           for (i = nlow; i < nhigh && (daemon->serverarray[i]->flags & SERV_4ADDR); i++);
313           
314           if (!(flags & F_SERVER) && i != nlow && (flags & F_IPV4))
315             nhigh = i;
316           else
317             {
318               nlow = i;
319               
320               for (i = nlow; i < nhigh && (daemon->serverarray[i]->flags & SERV_ALL_ZEROS); i++);
321               
322               if (!(flags & F_SERVER) && i != nlow && (flags & (F_IPV4 | F_IPV6)))
323                 nhigh = i;
324               else
325                 {
326                   nlow = i;
327                   
328                   /* Short to resolv.conf servers */
329                   for (i = nlow; i < nhigh && (daemon->serverarray[i]->flags & SERV_USE_RESOLV); i++);
330                   
331                   if (i != nlow)
332                     nhigh = i;
333                   else
334                     {
335                       /* now look for a server */
336                       for (i = nlow; i < nhigh && !(daemon->serverarray[i]->flags & SERV_LITERAL_ADDRESS); i++);
337                       
338                       if (i != nlow)
339                         {
340                           /* If we want a server that can do DNSSEC, and this one can't, 
341                              return nothing, similarly if were looking only for a server
342                              for a particular domain. */
343                           if ((flags & F_DNSSECOK) && !(daemon->serverarray[nlow]->flags & SERV_DO_DNSSEC))
344                             nlow = nhigh;
345                           else if ((flags & F_DOMAINSRV) && daemon->serverarray[nlow]->domain_len == 0)
346                             nlow = nhigh;
347                           else
348                             nhigh = i;
349                         }
350                       else
351                         {
352                           /* --local=/domain/, only return if we don't need a server. */
353                           if (flags & (F_DNSSECOK | F_DOMAINSRV | F_SERVER))
354                             nhigh = i;
355                         }
356                     }
357                 }
358             }
359         }
360     }
361
362   *lowout = nlow;
363   *highout = nhigh;
364   
365   return (nlow != nhigh);
366 }
367
368 int is_local_answer(time_t now, int first, char *name)
369 {
370   int flags = 0;
371   int rc = 0;
372   
373   if ((flags = daemon->serverarray[first]->flags) & SERV_LITERAL_ADDRESS)
374     {
375       if (flags & SERV_4ADDR)
376         rc = F_IPV4;
377       else if (flags & SERV_6ADDR)
378         rc = F_IPV6;
379       else if (flags & SERV_ALL_ZEROS)
380         rc = F_IPV4 | F_IPV6;
381       else
382         {
383           /* argument first is the first struct server which matches the query type;
384              now roll back to the server which is just the same domain, to check if that 
385              provides an answer of a different type. */
386
387           for (;first > 0 && order_servers(daemon->serverarray[first-1], daemon->serverarray[first]) == 0; first--);
388           
389           if ((daemon->serverarray[first]->flags & SERV_LOCAL_ADDRESS) ||
390               check_for_local_domain(name, now))
391             rc = F_NOERR;
392           else
393             rc = F_NXDOMAIN;
394         }
395     }
396
397   return rc;
398 }
399
400 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)
401 {
402   int trunc = 0, anscount = 0;
403   unsigned char *p;
404   int start;
405   union all_addr addr;
406   
407   if (flags & (F_NXDOMAIN | F_NOERR))
408     log_query(flags | gotname | F_NEG | F_CONFIG | F_FORWARD, name, NULL, NULL, 0);
409           
410   setup_reply(header, flags, ede);
411           
412   if (!(p = skip_questions(header, size)))
413     return 0;
414           
415   if (flags & gotname & F_IPV4)
416     for (start = first; start != last; start++)
417       {
418         struct serv_addr4 *srv = (struct serv_addr4 *)daemon->serverarray[start];
419
420         if (srv->flags & SERV_ALL_ZEROS)
421           memset(&addr, 0, sizeof(addr));
422         else
423           addr.addr4 = srv->addr;
424         
425         if (add_resource_record(header, limit, &trunc, sizeof(struct dns_header), &p, daemon->local_ttl, NULL, T_A, C_IN, "4", &addr))
426           anscount++;
427         log_query((flags | F_CONFIG | F_FORWARD) & ~F_IPV6, name, (union all_addr *)&addr, NULL, 0);
428       }
429   
430   if (flags & gotname & F_IPV6)
431     for (start = first; start != last; start++)
432       {
433         struct serv_addr6 *srv = (struct serv_addr6 *)daemon->serverarray[start];
434
435         if (srv->flags & SERV_ALL_ZEROS)
436           memset(&addr, 0, sizeof(addr));
437         else
438           addr.addr6 = srv->addr;
439         
440         if (add_resource_record(header, limit, &trunc, sizeof(struct dns_header), &p, daemon->local_ttl, NULL, T_AAAA, C_IN, "6", &addr))
441           anscount++;
442         log_query((flags | F_CONFIG | F_FORWARD) & ~F_IPV4, name, (union all_addr *)&addr, NULL, 0);
443       }
444
445   if (trunc)
446     header->hb3 |= HB3_TC;
447   header->ancount = htons(anscount);
448   
449   return p - (unsigned char *)header;
450 }
451
452 #ifdef HAVE_DNSSEC
453 int dnssec_server(struct server *server, char *keyname, int *firstp, int *lastp)
454 {
455   int first, last, index;
456
457   /* Find server to send DNSSEC query to. This will normally be the 
458      same as for the original query, but may be another if
459      servers for domains are involved. */                     
460   if (!lookup_domain(keyname, F_DNSSECOK, &first, &last))
461     return -1;
462
463   for (index = first; index != last; index++)
464     if (daemon->serverarray[index] == server)
465       break;
466               
467   /* No match to server used for original query.
468      Use newly looked up set. */
469   if (index == last)
470     index =  daemon->serverarray[first]->last_server == -1 ?
471       first : daemon->serverarray[first]->last_server;
472
473   if (firstp)
474     *firstp = first;
475
476   if (lastp)
477     *lastp = last;
478    
479   return index;
480 }
481 #endif
482
483 /* order by size, then by dictionary order */
484 static int order(char *qdomain, size_t qlen, struct server *serv)
485 {
486   size_t dlen = 0;
487     
488   /* servers for dotless names always sort last 
489      searched for name is never dotless. */
490   if (serv->flags & SERV_FOR_NODOTS)
491     return -1;
492
493   dlen = serv->domain_len;
494   
495   if (qlen < dlen)
496     return 1;
497   
498   if (qlen > dlen)
499     return -1;
500
501   return hostname_order(qdomain, serv->domain);
502 }
503
504 static int order_servers(struct server *s1, struct server *s2)
505 {
506   int rc;
507
508   /* need full comparison of dotless servers in 
509      order_qsort() and filter_servers() */
510
511   if (s1->flags & SERV_FOR_NODOTS)
512      return (s2->flags & SERV_FOR_NODOTS) ? 0 : 1;
513    
514   if ((rc = order(s1->domain, s1->domain_len, s2)) != 0)
515     return rc;
516
517   /* For identical domains, sort wildcard ones first */
518   if (s1->flags & SERV_WILDCARD)
519     return (s2->flags & SERV_WILDCARD) ? 0 : 1;
520
521   return (s2->flags & SERV_WILDCARD) ? -1 : 0;
522 }
523   
524 static int order_qsort(const void *a, const void *b)
525 {
526   int rc;
527   
528   struct server *s1 = *((struct server **)a);
529   struct server *s2 = *((struct server **)b);
530   
531   rc = order_servers(s1, s2);
532
533   /* Sort all literal NODATA and local IPV4 or IPV6 responses together,
534      in a very specific order. We flip the SERV_LITERAL_ADDRESS bit
535      so the order is IPv6 literal, IPv4 literal, all-zero literal, 
536      unqualified servers, upstream server, NXDOMAIN literal. */
537   if (rc == 0)
538     rc = ((s2->flags & (SERV_LITERAL_ADDRESS | SERV_4ADDR | SERV_6ADDR | SERV_USE_RESOLV | SERV_ALL_ZEROS)) ^ SERV_LITERAL_ADDRESS) -
539       ((s1->flags & (SERV_LITERAL_ADDRESS | SERV_4ADDR | SERV_6ADDR | SERV_USE_RESOLV | SERV_ALL_ZEROS)) ^ SERV_LITERAL_ADDRESS);
540
541   /* Finally, order by appearance in /etc/resolv.conf etc, for --strict-order */
542   if (rc == 0)
543     if (!(s1->flags & SERV_LITERAL_ADDRESS))
544       rc = s1->serial - s2->serial;
545
546   return rc;
547 }
548
549
550 /* When loading large numbers of server=.... lines during startup,
551    there's no possibility that there will be server records that can be reused, but
552    searching a long list for each server added grows as O(n^2) and slows things down.
553    This flag is set only if is known there may be free server records that can be reused.
554    There's a call to mark_servers(0) in read_opts() to reset the flag before
555    main config read. */
556
557 static int maybe_free_servers = 0;
558
559 /* Must be called before  add_update_server() to set daemon->servers_tail */
560 void mark_servers(int flag)
561 {
562   struct server *serv, *next, **up;
563
564   maybe_free_servers = !!flag;
565   
566   daemon->servers_tail = NULL;
567   
568   /* mark everything with argument flag */
569   for (serv = daemon->servers; serv; serv = serv->next)
570     {
571       if (serv->flags & flag)
572         serv->flags |= SERV_MARK;
573       else
574         serv->flags &= ~SERV_MARK;
575
576       daemon->servers_tail = serv;
577     }
578   
579   /* --address etc is different: since they are expected to be 
580      1) numerous and 2) not reloaded often. We just delete 
581      and recreate. */
582   if (flag)
583     for (serv = daemon->local_domains, up = &daemon->local_domains; serv; serv = next)
584       {
585         next = serv->next;
586
587         if (serv->flags & flag)
588           {
589             *up = next;
590             free(serv->domain);
591             free(serv);
592           }
593         else 
594           up = &serv->next;
595       }
596 }
597
598 void cleanup_servers(void)
599 {
600   struct server *serv, *tmp, **up;
601
602   /* unlink and free anything still marked. */
603   for (serv = daemon->servers, up = &daemon->servers, daemon->servers_tail = NULL; serv; serv = tmp) 
604     {
605       tmp = serv->next;
606       if (serv->flags & SERV_MARK)
607        {
608          server_gone(serv);
609          *up = serv->next;
610          free(serv->domain);
611          free(serv);
612        }
613       else 
614         {
615           up = &serv->next;
616           daemon->servers_tail = serv;
617         }
618     }
619 }
620
621 int add_update_server(int flags,
622                       union mysockaddr *addr,
623                       union mysockaddr *source_addr,
624                       const char *interface,
625                       const char *domain,
626                       union all_addr *local_addr)
627 {
628   struct server *serv = NULL;
629   char *alloc_domain;
630   
631   if (!domain)
632     domain = "";
633
634   /* .domain == domain, for historical reasons. */
635   if (*domain == '.')
636     while (*domain == '.') domain++;
637   else if (*domain == '*')
638     {
639       domain++;
640       if (*domain != 0)
641         flags |= SERV_WILDCARD;
642     }
643   
644   if (*domain == 0)
645     alloc_domain = whine_malloc(1);
646   else
647     alloc_domain = canonicalise((char *)domain, NULL);
648
649   if (!alloc_domain)
650     return 0;
651
652   if (flags & SERV_IS_LOCAL)
653     {
654       size_t size;
655       
656       if (flags & SERV_6ADDR)
657         size = sizeof(struct serv_addr6);
658       else if (flags & SERV_4ADDR)
659         size = sizeof(struct serv_addr4);
660       else
661         size = sizeof(struct serv_local);
662       
663       if (!(serv = whine_malloc(size)))
664         {
665           free(alloc_domain);
666           return 0;
667         }
668       
669       serv->next = daemon->local_domains;
670       daemon->local_domains = serv;
671       
672       if (flags & SERV_4ADDR)
673         ((struct serv_addr4*)serv)->addr = local_addr->addr4;
674       
675       if (flags & SERV_6ADDR)
676         ((struct serv_addr6*)serv)->addr = local_addr->addr6;
677     }
678   else
679     { 
680       /* Upstream servers. See if there is a suitable candidate, if so unmark
681          and move to the end of the list, for order. The entry found may already
682          be at the end. */
683       struct server **up, *tmp;
684
685       serv = NULL;
686       
687       if (maybe_free_servers)
688         for (serv = daemon->servers, up = &daemon->servers; serv; serv = tmp)
689           {
690             tmp = serv->next;
691             if ((serv->flags & SERV_MARK) &&
692                 hostname_isequal(alloc_domain, serv->domain))
693               {
694                 /* Need to move down? */
695                 if (serv->next)
696                   {
697                     *up = serv->next;
698                     daemon->servers_tail->next = serv;
699                     daemon->servers_tail = serv;
700                     serv->next = NULL;
701                   }
702                 break;
703               }
704             else
705               up = &serv->next;
706           }
707       
708       if (serv)
709         {
710           free(alloc_domain);
711           alloc_domain = serv->domain;
712         }
713       else
714         {
715           if (!(serv = whine_malloc(sizeof(struct server))))
716             {
717               free(alloc_domain);
718               return 0;
719             }
720           
721           memset(serv, 0, sizeof(struct server));
722           
723           /* Add to the end of the chain, for order */
724           if (daemon->servers_tail)
725             daemon->servers_tail->next = serv;
726           else
727             daemon->servers = serv;
728           daemon->servers_tail = serv;
729         }
730       
731 #ifdef HAVE_LOOP
732       serv->uid = rand32();
733 #endif      
734           
735       if (interface)
736         safe_strncpy(serv->interface, interface, sizeof(serv->interface));
737       if (addr)
738         serv->addr = *addr;
739       if (source_addr)
740         serv->source_addr = *source_addr;
741     }
742     
743   serv->flags = flags;
744   serv->domain = alloc_domain;
745   serv->domain_len = strlen(alloc_domain);
746   
747   return 1;
748 }
749