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 */
xsetmask(char * mask,unsigned int bits,unsigned int len)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 */
xmatch(const char * addr1,const char * mask1,const char * addr2,int len)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 */
addrlist_match(const pset_h addr_list,const struct sockaddr * addr)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 = CSAIN(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(&CSAIN6(addr)->sin6_addr, &cap->a.addr6))
190 return( u+1 );
191 }
192 else { /* NET_ADDR */
193 if ( xmatch( (const char *)CSAIN6(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( &CSAIN6(addr)->sin6_addr ) )
205 {
206 uint32_t tmp_addr;
207 memcpy(&tmp_addr, &CSAIN6(addr)->sin6_addr.s6_addr[12], sizeof(tmp_addr));
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
addrlist_dump(const pset_h addr_list,int fd)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
addrlist_free(pset_h addr_list)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 */
check_hostname(const char * addr)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 */
add(pset_h addr_list,const struct comp_addr * cap)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 */
xremove(pset_h addr_list,const struct comp_addr * cap)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 */
explicit_mask(const char * str_addr,statfunc op,pset_h addr_list)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 */
net_addr(const char * str_addr,statfunc op,pset_h addr_list)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 */
numeric_addr(const char * str_addr,status_e (* op)(),pset_h addr_list)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 */
host_addr(const char * str_addr,status_e (* op)(),pset_h addr_list)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 */
factorized_addr(const char * str_addr,status_e (* op)(),pset_h addr_list)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 */
addrlist_op(pset_h addr_list,status_e (* op)(),const char * str_addr)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
addrlist_add(pset_h addr_list,const char * str_addr)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
addrlist_remove(pset_h addr_list,const char * str_addr)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
addrlist_copy(const pset_h from,pset_h * to)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
797