fixes init script for non ipv6 enabled systems #472755
[packages/xinetd.git] / xinetd / addr.c
1 /*
2  * (c) Copyright 1992 by Panagiotis Tsirigotis
3  * (c) Sections Copyright 1998-2001 by Rob Braun
4  * All rights reserved.  The file named COPYRIGHT specifies the terms 
5  * and conditions for redistribution.
6  */
7
8
9 #include "config.h"
10 #include <sys/types.h>
11 #include <sys/socket.h>
12 #include <netinet/in.h>
13 #include <syslog.h>
14 #include <netdb.h>
15 #include <memory.h>
16 #include <ctype.h>
17 #include <stdio.h>
18 #include <stdlib.h>
19 #include <unistd.h>
20 #include <sys/param.h>
21 #include <string.h>
22 #ifdef HAVE_NETDB_H
23 #include <netdb.h>
24 #endif
25
26 #if defined(HAVE_ARPA_INET_H)
27 #include <arpa/inet.h>
28 #endif
29 #include <netinet/in.h>
30
31 #include "sio.h"
32 #include "str.h"
33 #include "addr.h"
34 #include "msg.h"
35 #include "util.h"
36 #include "xtimer.h"
37 #include "libportable.h"
38
39 #define OPEN_CURLY_BRACKET      '{'
40 #define CLOSED_CURLY_BRACKET    '}'
41 #define COMMA                   ','
42 #define DOT                     '.'
43
44 typedef enum { CANT_PARSE, PARSED, ERROR } result_e ;
45 typedef enum {   NUMERIC_ADDR, NET_ADDR, HOST_ADDR } address_e ;
46
47 /*
48  * address types denote how the actual numeric address was obtained.
49  * Currently they are only useful for debugging.
50  * Note that NUMERIC_ADDR includes both simple (e.g. 128.138.91.1) and
51  * factorized symbolic addresses (e.g. 128.138.91.{1,2,3}).
52  */
53 struct comp_addr
54 {
55    address_e       addr_type ;
56    char            name[MAXHOSTNAMELEN+1] ;
57    char            version;   /* v4 vs. v6 addresses/masks */
58    union {
59       struct in6_addr addr6 ;
60       uint32_t        addr ;  /* host byte order */
61    } a;
62    union {
63       struct in6_addr mask6 ;
64       uint32_t        mask ;
65    } m;
66 } ;
67
68 #define CAP( p )                ( (struct comp_addr *) (p) )
69 #define NEW_CAP()               NEW( struct comp_addr )
70 #define FREE_CAP( cap )         FREE( cap )
71
72
73 /* The addrlist_match function sets the mask for IPv6 addresses.
74  * mask is a pointer to the in6_addr structure, bits is the
75  * number of bits to set in the mask, and len is the length of mask.
76  */
77 static void xsetmask(char *mask, unsigned int bits, unsigned int len)
78 {
79    int i;
80    int bytes = bits/8;
81    int remain = bits - (bytes * 8);
82    
83    memset(mask, 0, len);
84
85    /* This may be wrong for bigendian... */
86    for(i=0; i < bytes; i++ ) {
87       mask[i] = 0xFF;
88    }
89
90    if( remain > 0 )
91       mask[i] = ( 0xFF << (8-remain) );
92
93    return;
94 }
95
96
97 /* This is a helper function to make address matching with mask
98  * work ok w/ipv6. The len parameter is in bytes, not bits. 
99  * Returns TRUE if addr1&mask1 == addr2
100  */
101 static bool_int xmatch(const char *addr1, const char *mask1, 
102                        const char *addr2, int len)
103 {
104    int i;
105
106    for(i=0; i < len; i++ ) {
107       if( (addr1[i] & mask1[i]) != ( addr2[i] & mask1[i] ) ) 
108          return( FALSE );
109    }
110    return TRUE;
111
112
113
114 /*
115 *   This function returns 0 if no match and the offset+1
116 *   to list which element in the list matched. The elements
117 *   in the addr_list are expected to be comp_addr structs.
118 */
119 int addrlist_match( const pset_h addr_list, 
120                     const struct sockaddr *addr )
121 {
122    unsigned u, addr_count, length;
123    char hname[NI_MAXHOST] ;
124
125    if ( addr == NULL )
126            return 0;
127
128    length = (addr->sa_family == AF_INET) ? sizeof(struct sockaddr_in) : 
129            sizeof(struct sockaddr_in6);
130
131    addr_count = pset_count( addr_list );
132    if (addr_count == 0)
133       return 0;
134    
135    hname[0] = 0;
136       
137    for ( u = 0 ; u < addr_count ; u++ ) 
138    {
139       struct comp_addr *cap = CAP( pset_pointer( addr_list, u ) ) ;
140       if ( cap == NULL )
141          continue ;
142  
143       if( (cap->addr_type == HOST_ADDR) ) 
144       {
145          char *tmpname = NULL;
146          if ( hname[0] == 0 ) 
147          {
148             memset(hname, 0, NI_MAXHOST);
149             if ( getnameinfo(addr, length, hname, NI_MAXHOST, 
150                  NULL, 0, NI_NAMEREQD) )
151             {  /* 
152                 * Name cannot be looked up if here. We should continue 
153                 * searching the list in case a IP address or net mask agrees 
154                 */
155                 hname[0] = 0;
156                 continue ;
157             }
158          }
159
160          /* Parse the address as a domain portion */
161          if( cap->name[0] == '.' )
162          {
163             tmpname = str_casefind( hname, cap->name );
164             if( tmpname != NULL ) 
165             {
166                if( strlen(cap->name) == strlen(tmpname) )
167                   return( u+1 );
168             }
169          } 
170          else 
171          {
172             if( (strlen(hname) == strlen(cap->name)) && 
173                 (str_casefind( hname, cap->name ) == (char *)hname) )
174                return( u+1 );
175          }
176       } /* End HOST_ADDR */ 
177       else 
178       { /* NUMERIC or NET addresses */ 
179          if( (addr->sa_family == AF_INET) && (cap->version == 4) ) 
180          {
181             const struct sockaddr_in *inp = SAIN(addr);
182             if( ( ntohl(inp->sin_addr.s_addr) & cap->m.mask ) == 
183                             ( cap->a.addr & cap->m.mask ) ) 
184                return (u+1) ;
185          } 
186          else if( (addr->sa_family == AF_INET6) && (cap->version == 6)) 
187          {
188             if (cap->addr_type == NUMERIC_ADDR) {
189                if (IN6_ARE_ADDR_EQUAL(&SAIN6(addr)->sin6_addr, &cap->a.addr6))
190                   return( u+1 );
191             }
192             else {  /* NET_ADDR */ 
193                if ( xmatch( (const char *)SAIN6(addr)->sin6_addr.s6_addr, 
194                         (const char *)&(cap->m.mask6), 
195                         (const char *)&(cap->a.addr6), 16) == TRUE )
196                   return( u+1 );
197             }
198          } 
199          else if (((addr->sa_family) == AF_INET6) && (cap->version == 4))
200          {  /* 
201              * If it's a mapped address, and a v4 address is specified, see
202              * if the mapped address matches the v4 equivalent.
203              */
204             if( IN6_IS_ADDR_V4MAPPED( &SAIN6(addr)->sin6_addr ) ) 
205             {
206                uint32_t *tmp_addr = 
207                           (uint32_t *)&SAIN6(addr)->sin6_addr.s6_addr[12];
208                if( (ntohl(*tmp_addr) & cap->m.mask)
209                                == ( cap->a.addr & cap->m.mask ) )
210                   return (u+1);
211             }
212          }
213       } /* End NUMERIC or NET address check */
214    } /* End for loop */
215    return ( 0 );
216 }
217
218
219 void addrlist_dump( const pset_h addr_list, int fd )
220 {
221    unsigned u, num ;
222    char addrstring[1025];
223    char maskstring[1025];
224
225    num = pset_count( addr_list );
226    for ( u = 0 ; u < num ; u++ )
227    {
228       struct comp_addr *cap = CAP( pset_pointer( addr_list, u ) ) ;
229       const char *type ;
230
231       if ( cap->addr_type == NUMERIC_ADDR )
232          type = "NUMERIC" ;
233       else if ( cap->addr_type == NET_ADDR )
234          type = "NET" ;
235       else if ( cap->addr_type == HOST_ADDR )
236          type = "HOST" ;
237       else
238          type = "BAD" ;
239       
240       memset(addrstring, 0, sizeof(addrstring));
241       memset(maskstring, 0, sizeof(maskstring));
242       if( cap->version == 4 ) {
243          uint32_t addr = htonl(cap->a.addr);
244          uint32_t mask = htonl(cap->m.mask);
245          inet_ntop(AF_INET, &addr, addrstring, sizeof(addrstring));
246          inet_ntop(AF_INET, &mask, maskstring, sizeof(maskstring));
247       }
248       else if( cap->version == 6 ) {
249          inet_ntop(AF_INET6, &cap->a.addr6, addrstring, sizeof(addrstring));
250          inet_ntop(AF_INET6, &cap->m.mask6, maskstring, sizeof(maskstring));
251       }
252
253       if ( cap->addr_type == NET_ADDR )
254          Sprint(fd, " %s/%s(%s)", addrstring, maskstring, type);
255       else if ( cap->addr_type == HOST_ADDR )
256          Sprint( fd, " %s(%s)",  cap->name, type ) ;
257       else
258          Sprint( fd, " %s(%s)", addrstring, type ) ;
259    }
260 }
261
262
263 void addrlist_free( pset_h addr_list )
264 {
265    pset_apply( addr_list, free, NULL ) ;
266 }
267
268
269 /*
270  * Verify's an address has more than numbers & dots. 
271  * Returns 0 if numbers & dots, 1 otherwise.
272  */
273 int check_hostname( const char *addr )
274 {
275    int i;
276
277    for (i = 0; addr[i]; ++i)
278    {
279       if ( !isdigit(addr[i]) && (addr[i] != '.') )
280          return 1;
281    }
282    return 0;
283 }
284
285
286 /*
287  * Add an address to the address list
288  */
289 static status_e add( pset_h addr_list, const struct comp_addr *cap )
290 {
291    struct comp_addr *new_cap = NULL;
292    const char *func = "add" ;
293
294    new_cap = NEW_CAP() ;
295    if ( new_cap == NULL )
296    {
297       out_of_memory( func ) ;
298       return( FAILED ) ;
299    }
300
301    *new_cap = *cap ;
302    if ( pset_add( addr_list, new_cap ) == NULL )
303    {
304       out_of_memory( func ) ;
305       FREE_CAP( new_cap ) ;
306       return( FAILED ) ;
307    }
308    return( OK ) ;
309 }
310
311
312 /*
313  * Find the address and remove it from the list
314  * Since there is no check when we add entries that an
315  * address is not entered twice, in this function we remove all
316  * addresses that match.
317  *
318  * XXX: we need to work on the way two cap's are considered equal
319  */
320 static status_e xremove( pset_h addr_list, const struct comp_addr *cap )
321 {
322    unsigned u = 0 ;
323    struct comp_addr *old_cap ;
324
325    for ( u = 0 ; u < pset_count( addr_list ) ; u++ )
326    {
327       old_cap = CAP( pset_pointer( addr_list, u ) ) ;
328
329       if ( (cap->addr_type == HOST_ADDR) && ( old_cap->addr_type == HOST_ADDR ))
330       {
331          if ( EQ(cap->name, old_cap->name) )
332          {
333             pset_pointer( addr_list, u ) = NULL ;
334             FREE_CAP( old_cap ) ;
335          }
336       }
337       /* If the versions are the same, and the v6 addresses are the same,
338        * or the v4 addresses are the same, then one's a dup. 
339        */
340       else if ( (old_cap->version == cap->version) && 
341         (((old_cap->version == 6) && 
342          (IN6_ARE_ADDR_EQUAL( &(old_cap->a.addr6), &(cap->a.addr6))) && 
343          (IN6_ARE_ADDR_EQUAL( &(old_cap->m.mask6), &(cap->m.mask6))) ) ||
344          ((old_cap->version == cap->version) && (old_cap->version == 4) && 
345          old_cap->a.addr == cap->a.addr && old_cap->m.mask == cap->m.mask)) )
346       {
347          pset_pointer( addr_list, u ) = NULL ;
348          FREE_CAP( old_cap ) ;
349       }
350    }
351    pset_compact( addr_list ) ;
352    return( OK ) ;
353 }
354
355 /*
356  * Function allows the use of 0.0.0.0/24 style address ranges for access cntl.
357  *   --bbraun 10/26/98
358  *
359  * Updated to handle ::/46 style address ranges for access cntl.
360  */
361 static result_e explicit_mask( const char *str_addr, statfunc op, 
362                                pset_h addr_list)
363 {
364    struct comp_addr         ca ;
365    int val;
366    unsigned mask;
367    struct addrinfo hints, *res;
368    char saddr[INET6_ADDRSTRLEN];
369
370    memset(saddr, 0, INET6_ADDRSTRLEN);
371
372    if (strchr(str_addr, OPEN_CURLY_BRACKET))  /* Don't even try factorized */
373       return CANT_PARSE ;
374
375    if (sizeof(saddr) < 46)
376       return CANT_PARSE ;
377    val = sscanf(str_addr, "%45[^/]/%u", saddr, &mask);
378    if( val < 2 ) 
379       return CANT_PARSE ;
380
381    memset(&hints, 0, sizeof(hints));
382    hints.ai_family = PF_UNSPEC;
383    hints.ai_flags = AI_NUMERICHOST;
384    if( getaddrinfo(saddr, NULL, &hints, &res) ) {
385       return CANT_PARSE;
386    }
387
388    if( res->ai_family == AF_INET ) {
389       ca.version = 4;
390       ca.a.addr = ntohl( SAIN(res->ai_addr)->sin_addr.s_addr );
391       if(mask == 32) {
392          ca.addr_type = NUMERIC_ADDR;
393          ca.m.mask      = 0xFFFFFFFF;
394       } else {
395          uint32_t i;
396          unsigned n;
397    
398          ca.addr_type = NET_ADDR ;
399       
400          i = 0x80000000U;
401          ca.m.mask = 0;
402          /* Go through and set each bit to 1 */
403          for( n=mask; n != 0 ; n--)
404          {
405             ca.m.mask |= i;
406             i /= 2;
407          }
408       }
409    } /* PF_INET */
410
411    else if( res->ai_family == AF_INET6 ) {
412       ca.version = 6;
413       if( mask >= 128 ) {
414          ca.addr_type = HOST_ADDR;
415       } else {
416          ca.addr_type = NET_ADDR;
417       }
418       memcpy( &ca.a.addr6, &(SAIN6(res->ai_addr)->sin6_addr), 
419             sizeof(struct in6_addr) );
420       xsetmask((char *)&ca.m.mask6, mask, sizeof(ca.m.mask6));
421    } /* PF_INET6 */
422
423    freeaddrinfo(res);
424
425    return( ( (*op)( addr_list, &ca ) == OK ) ? PARSED : ERROR ) ;
426 }
427
428 /*
429  * Try to parse 'str_addr' as a symbolic net name
430  * 
431  * NOTE: This doesn't work with IPv6 addresses.
432  */
433 static result_e net_addr( const char *str_addr, statfunc op, pset_h addr_list )
434 {
435    /*
436     *
437     *  The following table demonstrates how the mask is determined
438     *  given a net number N and following the relation:
439     *     net #1 <= N <= #2
440     *
441     *     net #1      net #2      mask
442     *        0           0        FFFFFFFF    (this should be rejected)
443     *        1           FF       FF000000
444     *        100         FFFF     FFFF0000
445     *        10000       FFFFFF   FFFFFF00
446     *        1000000     FFFFFFFF FFFFFFFF
447     */
448    static struct { uint32_t lim, mask, shift ; } net_to_mask[] =
449    {
450       { 0,            0xFF000000,   24  },
451       { 0xFF,         0xFFFF0000,   16  },
452       { 0xFFFF,       0xFFFFFF00,   8   },
453       { 0xFFFFFF,     0xFFFFFFFF,   0   },
454       { 0xFFFFFFFF,   0,            0   }
455    } ;
456    struct comp_addr         ca ;
457    struct netent            *nep ;
458    uint32_t                 net_num ;
459    int                      i ;
460    const char              *func = "net_addr" ;
461
462    nep = getnetbyname( str_addr ) ;
463    if ( nep == NULL || nep->n_addrtype != AF_INET || nep->n_net == 0 )
464       return( CANT_PARSE ) ;
465
466    for ( i = 0, net_num = (uint32_t) nep->n_net ;; i++ )
467    {
468       if ( net_to_mask[ i ].mask == 0 )
469       {
470          msg( LOG_CRIT, func,
471             "INTERNAL ERROR: Cannot process net number %u", net_num ) ;
472          return( ERROR ) ;
473       }
474       if ( net_to_mask[i].lim < net_num && net_num <= net_to_mask[i+1].lim )
475       {
476          ca.addr_type = NET_ADDR ;
477          ca.a.addr = net_num << net_to_mask[ i ].shift ;
478          ca.m.mask = net_to_mask[ i ].mask ;
479          ca.version = 4;
480          return( ( (*op)( addr_list, &ca ) == OK ) ? PARSED : ERROR ) ;
481       }
482    }
483 }
484
485
486 /*
487  * Try to parse 'str_addr' as a numeric address
488  */
489 static result_e numeric_addr( const char *str_addr, 
490                                status_e (*op)(), 
491                                pset_h addr_list )
492 {
493    struct comp_addr ca ;
494    struct addrinfo hints, *res = NULL;
495    struct in6_addr zero;
496    uint32_t mask, addr;
497
498    if (strchr(str_addr, '/')) /* Don't even try explicit masks */
499       return CANT_PARSE;
500    if(strchr(str_addr, OPEN_CURLY_BRACKET))  /* Don't even try factorized */
501       return CANT_PARSE;
502    
503    memset(&zero, 0, sizeof(zero));
504    memset(&hints, 0, sizeof(hints));
505
506    hints.ai_flags = AI_NUMERICHOST;
507    if (strchr(str_addr, ':'))
508       hints.ai_family = PF_INET6;
509    else
510       hints.ai_family = PF_INET;
511
512    if( getaddrinfo(str_addr, NULL, &hints, &res) != 0 ) 
513       return CANT_PARSE;
514
515    if ( res == NULL )
516       return CANT_PARSE;
517
518    if ( res->ai_addr == NULL ) {
519       freeaddrinfo(res);
520       return CANT_PARSE;
521    }
522
523    if( res->ai_family == AF_INET6 ) {
524       ca.version = 6;
525       ca.addr_type = NUMERIC_ADDR;
526       if( memcmp( &(SAIN6(res->ai_addr)->sin6_addr), &zero, 
527             sizeof(struct in6_addr) ) == 0 ) {
528          memset( &ca.a.addr6, 0, sizeof(struct in6_addr) );
529          memset( &ca.m.mask6, 0, sizeof(struct in6_addr) );
530       } else {
531          memcpy( &ca.a.addr6, &(SAIN6(res->ai_addr)->sin6_addr), 
532             sizeof(struct in6_addr) );
533          memset(&ca.m.mask6, 0xFF, sizeof(struct in6_addr));
534       }
535    } else if( res->ai_family == AF_INET ) {
536       ca.version = 4;
537       ca.addr_type = NUMERIC_ADDR;
538       if( SAIN(res->ai_addr)->sin_addr.s_addr == 0 ) {
539          ca.a.addr = 0;
540          ca.m.mask = 0;
541       } else {
542          addr = (uint32_t) ntohl( SAIN(res->ai_addr)->sin_addr.s_addr );
543          for ( mask = 0xFF ;; )
544          {
545             if ( addr & mask )
546                break ;
547             mask <<= 8 ;
548             mask |= 0xFF ;
549          }
550          mask = ~( mask >> 8 ) ;
551
552          ca.a.addr = addr;
553          ca.m.mask = mask;
554       }
555    
556    }
557
558    freeaddrinfo(res);
559    return( ( (*op)( addr_list, &ca ) == OK ) ? PARSED : ERROR ) ;
560 }
561
562
563 /*
564  * Try to parse 'str_addr' as a symbolic host name
565  * Apply 'op' to the 'addrlist' for *all* IP addresses of the host
566  */
567 static result_e host_addr( const char *str_addr, status_e (*op)(), pset_h addr_list )
568 {
569    struct comp_addr ca;
570    struct addrinfo hints, *res = NULL;
571    char addr[46];
572
573    if (strchr(str_addr, '/')) /* Don't even try explicit masks */
574       return CANT_PARSE;
575    if(strchr(str_addr, OPEN_CURLY_BRACKET))  /* Don't even try factorized */
576       return CANT_PARSE;
577
578    if( str_addr[0] == '.' ) 
579    {
580       if ( check_hostname(str_addr) )
581       {
582          ca.version = 0xFF;
583          ca.addr_type = HOST_ADDR;
584          /* XXX: does this really need to be NUL-padded? */
585          strncpy(ca.name, str_addr, sizeof(ca.name)-1) ;
586          ca.name[sizeof(ca.name)-1] = '\0';
587          if ( (*op)( addr_list, &ca ) == FAILED )
588             return ERROR ;
589          return PARSED ;
590       }
591       else
592          return CANT_PARSE;
593    }
594
595    memset(&hints, 0, sizeof(hints));
596    memset(addr, 0, sizeof(addr));
597
598    hints.ai_flags = AI_CANONNAME;
599    hints.ai_family = PF_UNSPEC;
600
601    if ( getaddrinfo(str_addr, NULL, &hints, &res) != 0 ) 
602       return CANT_PARSE;
603
604    if ( res == NULL )
605       return CANT_PARSE;
606
607    strncpy(ca.name, str_addr, sizeof(ca.name)-1) ;
608    ca.name[sizeof(ca.name)-1] = '\0';
609    ca.addr_type = HOST_ADDR ;
610    ca.version = 0xFF;
611    freeaddrinfo(res);
612
613    if ( (*op)( addr_list, &ca ) == FAILED ) 
614       return ERROR ;
615    else
616       return PARSED ;
617 }
618
619
620 /*
621  * Try to parse 'str_addr' as a factorized address
622  * (for example, 128.138.{200,201})
623  *
624  * XXX: It is unclear whether this function should exist. It is really doing
625  *      the job of a preprocessor.
626  *
627  * This does not work for IPv6 Addresses.
628  */
629 static result_e factorized_addr( const char *str_addr, 
630                                   status_e (*op)(), 
631                                   pset_h addr_list )
632 {
633    int                pass ;
634    char               last   = DOT ;
635    unsigned           num   = 0 ;
636    int                shift = 24 ;   /* because we assume a 32-bit IP address */
637    uint32_t           addr = 0 ;
638    struct comp_addr   ca ;
639    const char        *func = "factorized_addr" ;
640    int                i, j;
641
642    for ( i = 0 ; str_addr[i] != OPEN_CURLY_BRACKET ; last = str_addr[i++] )
643    {
644       if ( isdigit( str_addr[i] ) )
645       {
646          num = num * 10 + str_addr[i] - '0' ;
647          continue ;
648       }
649       switch ( str_addr[i] )
650       {
651          case DOT:
652             if ( last == DOT )
653             {
654                parsemsg( LOG_ERR, func,
655                   "Bad address: %s. Consecutive dots", str_addr ) ;
656                return( ERROR ) ;
657             }
658             addr = addr * 256 + num ;
659             num = 0 ;
660             shift -= 8 ;
661             break ;
662          
663          default:
664             return( CANT_PARSE ) ;
665       }
666    }
667
668    ca.addr_type = NUMERIC_ADDR ;
669    ca.version = 4;
670    if ( addr != 0 )
671       addr <<= ( shift+8 ) ;
672
673    /*
674     * First pass is for syntax checking
675     */
676    j = i;
677    for ( pass = 0 ; pass < 2 ; pass++ )
678    {
679       i = j;
680       num = 0 ;
681       for ( i = i+1, last = COMMA ;; last = str_addr[i++] )
682       {
683          if ( isdigit( str_addr[i] ) )
684          {
685             num = num * 10 + str_addr[i] - '0' ;
686             continue ;
687          }
688          switch ( str_addr[i] )
689          {
690             case COMMA:
691             case CLOSED_CURLY_BRACKET:
692                if ( last == COMMA )
693                {
694                   parsemsg( LOG_ERR, func,
695                      "Bad address: %s. Consecutive commas", str_addr ) ;
696                   return( ERROR ) ;
697                }
698
699                if ( pass == 1 )
700                {
701                   ca.a.addr = addr + ( num << shift ) ;
702                   ca.m.mask = ~( ( 1 << shift ) - 1 ) ;
703                   if ( (*op)( addr_list, &ca ) == FAILED )
704                      return( ERROR ) ;
705                   num = 0 ;
706                }
707                break ;
708             
709             default:
710                parsemsg( LOG_ERR, func, "Bad address: %s", str_addr ) ;
711                return( ERROR ) ;
712          }
713          if ( str_addr[i] == CLOSED_CURLY_BRACKET )
714          {
715             if ( str_addr[i+1] != NUL )
716             {
717                parsemsg( LOG_ERR, func, "Bad address: %s", str_addr ) ;
718                return( ERROR ) ;
719             }
720
721             if ( pass == 0 )
722                break ;
723             else
724                return( PARSED ) ;
725          }
726       }
727    }
728    /* NOTREACHED */
729
730    return( ERROR );
731 }
732
733
734 /*
735  * Try to parse 'str_addr' using all known methods.
736  * Try until one of the methods succeeds.
737  * A successful method will apply 'op' with the parsed address to the 
738  * 'addr_list'. The 'op' can be either 'add' or 'remove'
739  * This means that the parsed address will be either added or removed
740  * from the addr_list.
741  */
742 static status_e addrlist_op( pset_h addr_list, 
743                               status_e (*op)(), 
744                               const char *str_addr )
745 {
746    int i ;
747    static result_e (*addr_parser[])() =
748       {
749          numeric_addr,
750          host_addr,
751          explicit_mask,
752          factorized_addr,
753          net_addr,
754          NULL
755       } ;
756    const char *func = "addrlist_op" ;
757
758    if (str_addr == NULL)
759       return FAILED;
760    
761    if (str_addr[0] == NUL )
762       return OK;
763    
764    for ( i = 0 ; addr_parser[ i ] != NULL ; i++ )
765       switch ( (*addr_parser[ i ])( str_addr, op, addr_list ) )
766       {
767          case PARSED:
768             return OK;
769          case ERROR:
770             return FAILED;
771          case CANT_PARSE:
772             break;
773       }
774
775    parsemsg( LOG_ERR, func, "failed to parse %s", str_addr ) ;
776    return OK;
777 }
778
779
780 status_e addrlist_add( pset_h addr_list, const char *str_addr ) 
781 {
782    return( addrlist_op( addr_list, add, str_addr ) ) ;
783 }
784
785
786 status_e addrlist_remove( pset_h addr_list, const char *str_addr ) 
787 {
788    return( addrlist_op( addr_list, xremove, str_addr ) ) ;
789 }
790
791
792 status_e addrlist_copy( const pset_h from, pset_h *to )
793 {
794    return( copy_pset( from, to, sizeof( struct comp_addr ) ) ) ;
795 }
796