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.
10 #include <sys/types.h>
11 #include <sys/socket.h>
12 #include <netinet/in.h>
20 #include <sys/param.h>
26 #if defined(HAVE_ARPA_INET_H)
27 #include <arpa/inet.h>
29 #include <netinet/in.h>
37 #include "libportable.h"
39 #define OPEN_CURLY_BRACKET '{'
40 #define CLOSED_CURLY_BRACKET '}'
44 typedef enum { CANT_PARSE, PARSED, ERROR } result_e ;
45 typedef enum { NUMERIC_ADDR, NET_ADDR, HOST_ADDR } address_e ;
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}).
56 char name[MAXHOSTNAMELEN+1] ;
57 char version; /* v4 vs. v6 addresses/masks */
59 struct in6_addr addr6 ;
60 uint32_t addr ; /* host byte order */
63 struct in6_addr mask6 ;
68 #define CAP( p ) ( (struct comp_addr *) (p) )
69 #define NEW_CAP() NEW( struct comp_addr )
70 #define FREE_CAP( cap ) FREE( cap )
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.
77 static void xsetmask(char *mask, unsigned int bits, unsigned int len)
81 int remain = bits - (bytes * 8);
85 /* This may be wrong for bigendian... */
86 for(i=0; i < bytes; i++ ) {
91 mask[i] = ( 0xFF << (8-remain) );
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
101 static bool_int xmatch(const char *addr1, const char *mask1,
102 const char *addr2, int len)
106 for(i=0; i < len; i++ ) {
107 if( (addr1[i] & mask1[i]) != ( addr2[i] & mask1[i] ) )
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.
119 int addrlist_match( const pset_h addr_list,
120 const struct sockaddr *addr )
122 unsigned u, addr_count, length;
123 char hname[NI_MAXHOST] ;
128 length = (addr->sa_family == AF_INET) ? sizeof(struct sockaddr_in) :
129 sizeof(struct sockaddr_in6);
131 addr_count = pset_count( addr_list );
137 for ( u = 0 ; u < addr_count ; u++ )
139 struct comp_addr *cap = CAP( pset_pointer( addr_list, u ) ) ;
143 if( (cap->addr_type == HOST_ADDR) )
145 char *tmpname = NULL;
148 memset(hname, 0, NI_MAXHOST);
149 if ( getnameinfo(addr, length, hname, NI_MAXHOST,
150 NULL, 0, NI_NAMEREQD) )
152 * Name cannot be looked up if here. We should continue
153 * searching the list in case a IP address or net mask agrees
160 /* Parse the address as a domain portion */
161 if( cap->name[0] == '.' )
163 tmpname = str_casefind( hname, cap->name );
164 if( tmpname != NULL )
166 if( strlen(cap->name) == strlen(tmpname) )
172 if( (strlen(hname) == strlen(cap->name)) &&
173 (str_casefind( hname, cap->name ) == (char *)hname) )
176 } /* End HOST_ADDR */
178 { /* NUMERIC or NET addresses */
179 if( (addr->sa_family == AF_INET) && (cap->version == 4) )
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 ) )
186 else if( (addr->sa_family == AF_INET6) && (cap->version == 6))
188 if (cap->addr_type == NUMERIC_ADDR) {
189 if (IN6_ARE_ADDR_EQUAL(&SAIN6(addr)->sin6_addr, &cap->a.addr6))
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 )
199 else if (((addr->sa_family) == AF_INET6) && (cap->version == 4))
201 * If it's a mapped address, and a v4 address is specified, see
202 * if the mapped address matches the v4 equivalent.
204 if( IN6_IS_ADDR_V4MAPPED( &SAIN6(addr)->sin6_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 ) )
213 } /* End NUMERIC or NET address check */
219 void addrlist_dump( const pset_h addr_list, int fd )
222 char addrstring[1025];
223 char maskstring[1025];
225 num = pset_count( addr_list );
226 for ( u = 0 ; u < num ; u++ )
228 struct comp_addr *cap = CAP( pset_pointer( addr_list, u ) ) ;
231 if ( cap->addr_type == NUMERIC_ADDR )
233 else if ( cap->addr_type == NET_ADDR )
235 else if ( cap->addr_type == HOST_ADDR )
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));
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));
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 ) ;
258 Sprint( fd, " %s(%s)", addrstring, type ) ;
263 void addrlist_free( pset_h addr_list )
265 pset_apply( addr_list, free, NULL ) ;
270 * Verify's an address has more than numbers & dots.
271 * Returns 0 if numbers & dots, 1 otherwise.
273 int check_hostname( const char *addr )
277 for (i = 0; addr[i]; ++i)
279 if ( !isdigit(addr[i]) && (addr[i] != '.') )
287 * Add an address to the address list
289 static status_e add( pset_h addr_list, const struct comp_addr *cap )
291 struct comp_addr *new_cap = NULL;
292 const char *func = "add" ;
294 new_cap = NEW_CAP() ;
295 if ( new_cap == NULL )
297 out_of_memory( func ) ;
302 if ( pset_add( addr_list, new_cap ) == NULL )
304 out_of_memory( func ) ;
305 FREE_CAP( new_cap ) ;
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.
318 * XXX: we need to work on the way two cap's are considered equal
320 static status_e xremove( pset_h addr_list, const struct comp_addr *cap )
323 struct comp_addr *old_cap ;
325 for ( u = 0 ; u < pset_count( addr_list ) ; u++ )
327 old_cap = CAP( pset_pointer( addr_list, u ) ) ;
329 if ( (cap->addr_type == HOST_ADDR) && ( old_cap->addr_type == HOST_ADDR ))
331 if ( EQ(cap->name, old_cap->name) )
333 pset_pointer( addr_list, u ) = NULL ;
334 FREE_CAP( old_cap ) ;
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.
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)) )
347 pset_pointer( addr_list, u ) = NULL ;
348 FREE_CAP( old_cap ) ;
351 pset_compact( addr_list ) ;
356 * Function allows the use of 0.0.0.0/24 style address ranges for access cntl.
359 * Updated to handle ::/46 style address ranges for access cntl.
361 static result_e explicit_mask( const char *str_addr, statfunc op,
364 struct comp_addr ca ;
367 struct addrinfo hints, *res;
368 char saddr[INET6_ADDRSTRLEN];
370 memset(saddr, 0, INET6_ADDRSTRLEN);
372 if (strchr(str_addr, OPEN_CURLY_BRACKET)) /* Don't even try factorized */
375 if (sizeof(saddr) < 46)
377 val = sscanf(str_addr, "%45[^/]/%u", saddr, &mask);
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) ) {
388 if( res->ai_family == AF_INET ) {
390 ca.a.addr = ntohl( SAIN(res->ai_addr)->sin_addr.s_addr );
392 ca.addr_type = NUMERIC_ADDR;
393 ca.m.mask = 0xFFFFFFFF;
398 ca.addr_type = NET_ADDR ;
402 /* Go through and set each bit to 1 */
403 for( n=mask; n != 0 ; n--)
411 else if( res->ai_family == AF_INET6 ) {
414 ca.addr_type = HOST_ADDR;
416 ca.addr_type = NET_ADDR;
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));
425 return( ( (*op)( addr_list, &ca ) == OK ) ? PARSED : ERROR ) ;
429 * Try to parse 'str_addr' as a symbolic net name
431 * NOTE: This doesn't work with IPv6 addresses.
433 static result_e net_addr( const char *str_addr, statfunc op, pset_h addr_list )
437 * The following table demonstrates how the mask is determined
438 * given a net number N and following the relation:
442 * 0 0 FFFFFFFF (this should be rejected)
445 * 10000 FFFFFF FFFFFF00
446 * 1000000 FFFFFFFF FFFFFFFF
448 static struct { uint32_t lim, mask, shift ; } net_to_mask[] =
450 { 0, 0xFF000000, 24 },
451 { 0xFF, 0xFFFF0000, 16 },
452 { 0xFFFF, 0xFFFFFF00, 8 },
453 { 0xFFFFFF, 0xFFFFFFFF, 0 },
456 struct comp_addr ca ;
460 const char *func = "net_addr" ;
462 nep = getnetbyname( str_addr ) ;
463 if ( nep == NULL || nep->n_addrtype != AF_INET || nep->n_net == 0 )
464 return( CANT_PARSE ) ;
466 for ( i = 0, net_num = (uint32_t) nep->n_net ;; i++ )
468 if ( net_to_mask[ i ].mask == 0 )
471 "INTERNAL ERROR: Cannot process net number %u", net_num ) ;
474 if ( net_to_mask[i].lim < net_num && net_num <= net_to_mask[i+1].lim )
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 ;
480 return( ( (*op)( addr_list, &ca ) == OK ) ? PARSED : ERROR ) ;
487 * Try to parse 'str_addr' as a numeric address
489 static result_e numeric_addr( const char *str_addr,
493 struct comp_addr ca ;
494 struct addrinfo hints, *res = NULL;
495 struct in6_addr zero;
498 if (strchr(str_addr, '/')) /* Don't even try explicit masks */
500 if(strchr(str_addr, OPEN_CURLY_BRACKET)) /* Don't even try factorized */
503 memset(&zero, 0, sizeof(zero));
504 memset(&hints, 0, sizeof(hints));
506 hints.ai_flags = AI_NUMERICHOST;
507 if (strchr(str_addr, ':'))
508 hints.ai_family = PF_INET6;
510 hints.ai_family = PF_INET;
512 if( getaddrinfo(str_addr, NULL, &hints, &res) != 0 )
518 if ( res->ai_addr == NULL ) {
523 if( res->ai_family == AF_INET6 ) {
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) );
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));
535 } else if( res->ai_family == AF_INET ) {
537 ca.addr_type = NUMERIC_ADDR;
538 if( SAIN(res->ai_addr)->sin_addr.s_addr == 0 ) {
542 addr = (uint32_t) ntohl( SAIN(res->ai_addr)->sin_addr.s_addr );
543 for ( mask = 0xFF ;; )
550 mask = ~( mask >> 8 ) ;
559 return( ( (*op)( addr_list, &ca ) == OK ) ? PARSED : ERROR ) ;
564 * Try to parse 'str_addr' as a symbolic host name
565 * Apply 'op' to the 'addrlist' for *all* IP addresses of the host
567 static result_e host_addr( const char *str_addr, status_e (*op)(), pset_h addr_list )
570 struct addrinfo hints, *res = NULL;
573 if (strchr(str_addr, '/')) /* Don't even try explicit masks */
575 if(strchr(str_addr, OPEN_CURLY_BRACKET)) /* Don't even try factorized */
578 if( str_addr[0] == '.' )
580 if ( check_hostname(str_addr) )
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 )
595 memset(&hints, 0, sizeof(hints));
596 memset(addr, 0, sizeof(addr));
598 hints.ai_flags = AI_CANONNAME;
599 hints.ai_family = PF_UNSPEC;
601 if ( getaddrinfo(str_addr, NULL, &hints, &res) != 0 )
607 strncpy(ca.name, str_addr, sizeof(ca.name)-1) ;
608 ca.name[sizeof(ca.name)-1] = '\0';
609 ca.addr_type = HOST_ADDR ;
613 if ( (*op)( addr_list, &ca ) == FAILED )
621 * Try to parse 'str_addr' as a factorized address
622 * (for example, 128.138.{200,201})
624 * XXX: It is unclear whether this function should exist. It is really doing
625 * the job of a preprocessor.
627 * This does not work for IPv6 Addresses.
629 static result_e factorized_addr( const char *str_addr,
636 int shift = 24 ; /* because we assume a 32-bit IP address */
638 struct comp_addr ca ;
639 const char *func = "factorized_addr" ;
642 for ( i = 0 ; str_addr[i] != OPEN_CURLY_BRACKET ; last = str_addr[i++] )
644 if ( isdigit( str_addr[i] ) )
646 num = num * 10 + str_addr[i] - '0' ;
649 switch ( str_addr[i] )
654 parsemsg( LOG_ERR, func,
655 "Bad address: %s. Consecutive dots", str_addr ) ;
658 addr = addr * 256 + num ;
664 return( CANT_PARSE ) ;
668 ca.addr_type = NUMERIC_ADDR ;
671 addr <<= ( shift+8 ) ;
674 * First pass is for syntax checking
677 for ( pass = 0 ; pass < 2 ; pass++ )
681 for ( i = i+1, last = COMMA ;; last = str_addr[i++] )
683 if ( isdigit( str_addr[i] ) )
685 num = num * 10 + str_addr[i] - '0' ;
688 switch ( str_addr[i] )
691 case CLOSED_CURLY_BRACKET:
694 parsemsg( LOG_ERR, func,
695 "Bad address: %s. Consecutive commas", str_addr ) ;
701 ca.a.addr = addr + ( num << shift ) ;
702 ca.m.mask = ~( ( 1 << shift ) - 1 ) ;
703 if ( (*op)( addr_list, &ca ) == FAILED )
710 parsemsg( LOG_ERR, func, "Bad address: %s", str_addr ) ;
713 if ( str_addr[i] == CLOSED_CURLY_BRACKET )
715 if ( str_addr[i+1] != NUL )
717 parsemsg( LOG_ERR, func, "Bad address: %s", str_addr ) ;
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.
742 static status_e addrlist_op( pset_h addr_list,
744 const char *str_addr )
747 static result_e (*addr_parser[])() =
756 const char *func = "addrlist_op" ;
758 if (str_addr == NULL)
761 if (str_addr[0] == NUL )
764 for ( i = 0 ; addr_parser[ i ] != NULL ; i++ )
765 switch ( (*addr_parser[ i ])( str_addr, op, addr_list ) )
775 parsemsg( LOG_ERR, func, "failed to parse %s", str_addr ) ;
780 status_e addrlist_add( pset_h addr_list, const char *str_addr )
782 return( addrlist_op( addr_list, add, str_addr ) ) ;
786 status_e addrlist_remove( pset_h addr_list, const char *str_addr )
788 return( addrlist_op( addr_list, xremove, str_addr ) ) ;
792 status_e addrlist_copy( const pset_h from, pset_h *to )
794 return( copy_pset( from, to, sizeof( struct comp_addr ) ) ) ;