#define HAVE_SOCKADDR_STORAGE #define HAVE_AF_INET6 #define HAVE_STRCASESTR #include #include #include #include #include #include #include #include #include "nbase_addrset.h" #define BITVECTOR_BITS (sizeof(bitvector_t) * CHAR_BIT) #define BIT_SET(v, n) ((v)[(n) / BITVECTOR_BITS] |= 1UL << ((n) % BITVECTOR_BITS)) #define BIT_IS_SET(v, n) (((v)[(n) / BITVECTOR_BITS] & 1UL << ((n) % BITVECTOR_BITS)) != 0) using namespace std; extern "C" void addrset_elem_print(const struct addrset_elem *elem); static int match_ipv6_netmask(const struct in6_addr *addr, const struct in6_addr *mask, const struct sockaddr *sa) { const uint8_t *a = addr->s6_addr; const uint8_t *m = mask->s6_addr; const uint8_t *b = ((const struct sockaddr_in6 *) sa)->sin6_addr.s6_addr; int i; if (sa->sa_family != AF_INET6) return 0; for (i = 0; i < 16; i++) { if ((a[i] & m[i]) != (b[i] & m[i])) return 0; } return 1; } class TargetGroup { public: TargetGroup(struct addrset* addrset); int get_next_host(struct sockaddr_storage *ss, size_t *sslen); ~TargetGroup(void); private: struct addrset* target_addrset; struct addrset_elem *cur_elem; /* For ADDRSET_TYPE_IPV4_BITVECTOR. */ u8 begin_ip4[4]; u8 cur_ip4[4]; u8 end_ip4[4]; //u32 b0, b1, b2, b3; /* For ADDRSET_TYPE_IPV6_NETMASK. */ // Something else, not sure yet. /* Current interval of IPv6 ranges. */ /* Current IPv6 address. */ u16 cur_ip6[8]; bool cur_ip6_plusplus(void); bool cur_ip4_plusplus(void); bool cur_elem_finished; bool addrset_finished; }; TargetGroup::TargetGroup(struct addrset* addrset) { this->target_addrset = addrset; this->addrset_finished = false; this->cur_elem = NULL; this->cur_elem_finished = true; } TargetGroup::~TargetGroup() { } bool TargetGroup::cur_ip6_plusplus(void) { for (int i=7; i>=0; i--) { this->cur_ip6[i]++; if (this->cur_ip6[i] != 0) { break; } } struct sockaddr_in6 sock_in6; sock_in6.sin6_family = AF_INET6; u16 *u16_p; u16_p = (u16 *)&sock_in6.sin6_addr; for (int i=7; i>=0; i--) { u16_p[i] = htons(this->cur_ip6[i]); } if (match_ipv6_netmask(&this->cur_elem->u.ipv6.addr, &this->cur_elem->u.ipv6.mask, (const sockaddr*)&sock_in6) == 1) return true; return false; } bool TargetGroup::cur_ip4_plusplus(void) { /* cur_ip4++. */ for (int i = 3; i >= 0; i--) { if (this->cur_ip4[i] < this->end_ip4[i]) { for (int j = this->cur_ip4[i] + 1; j <= this->end_ip4[i]; j++) { if (BIT_IS_SET(this->cur_elem->u.ipv4.bits[i], j)) { this->cur_ip4[i] = j; return true; } } } if (i > 0) this->cur_ip4[i] = this->begin_ip4[i]; } return false; } int TargetGroup::get_next_host(struct sockaddr_storage *ss, size_t *sslen) { if (this->addrset_finished) return -1; int i, j; if (this->cur_elem_finished) { if (this->cur_elem == NULL) this->cur_elem = this->target_addrset->head; else this->cur_elem = this->cur_elem->next; if (this->cur_elem == NULL) { this->addrset_finished = true; return -1; } //Initiate address iterators. if (this->cur_elem->type == ADDRSET_TYPE_IPV4_BITVECTOR) { for (i = 0; i < 4; i++) { for (j = 0; j < 256; j++) { if (BIT_IS_SET(this->cur_elem->u.ipv4.bits[i], j)) { this->cur_ip4[i] = this->begin_ip4[i] = j; break; } } for (j = 255; j >= 0; j--) { if (BIT_IS_SET(this->cur_elem->u.ipv4.bits[i], j)) { this->end_ip4[i] = j; break; } } } this->cur_elem_finished = false; #ifdef HAVE_IPV6 } else if (this->cur_elem->type == ADDRSET_TYPE_IPV6_NETMASK) { addrset_elem_print(this->cur_elem); for (i = 0; i < 8; i++) { this->cur_ip6[i] = ntohs(this->cur_elem->u.ipv6.addr.s6_addr16[i]); } this->cur_elem_finished = false; #endif } } struct sockaddr_in *sin = (struct sockaddr_in *) ss; struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *) ss; assert(ss); assert(sslen); if (this->cur_elem->type == ADDRSET_TYPE_IPV4_BITVECTOR) { memset(sin, 0, sizeof(struct sockaddr_in)); sin->sin_family = AF_INET; *sslen = sizeof(struct sockaddr_in); #if HAVE_SOCKADDR_SA_LEN sin->sin_len = *sslen; #endif /* Set the IP to the current value of everything */ sin->sin_addr.s_addr = htonl(this->cur_ip4[0] << 24 | this->cur_ip4[1] << 16 | this->cur_ip4[2] << 8 | this->cur_ip4[3]); /* cur_ip4++. */ if (this->cur_ip4_plusplus() == false) this->cur_elem_finished = true; #ifdef HAVE_IPV6 } else if (this->cur_elem->type == ADDRSET_TYPE_IPV6_NETMASK) { memset(sin6, 0, sizeof(struct sockaddr_in6)); sin6->sin6_family = AF_INET6; *sslen = sizeof(struct sockaddr_in6); #if HAVE_SOCKADDR_SA_LEN sin6->sin_len = *sslen; #endif /* Set the IPv6 to the current value of everything */ for (j=0; j<8; j++) { sin6->sin6_addr.s6_addr16[j] = htons(this->cur_ip6[j]); } /* cur_ip6++. */ if (this->cur_ip6_plusplus() == false) this->cur_elem_finished = true; #endif } return 1; } static int resolve_name(const char *name, struct addrinfo **result) { struct addrinfo hints = { 0 }; hints.ai_protocol = IPPROTO_TCP; *result = NULL; return getaddrinfo(name, NULL, &hints, result); } /* Run this program like this: ./host-spec-test 1.1.1.1/24 2002::1/120 1-20.5.5.5 */ int main(int argc, char* argv[]) { struct addrset addrset; int i, rc; addrset_init(&addrset); /* Parse command line. */ for (i = 1; i < argc; i++) { rc = addrset_add_spec(&addrset, argv[i], 0, 1); if (rc == 0) { fprintf(stderr, "Error adding spec: \"%s\"\n", argv[i]); exit(1); } } /* Print the addrset. */ //struct addrset_elem* addr = addrset.head; //while (addr != NULL) { // addrset_elem_print(addr); // addr = addr->next; //} /* Now initialize a TargetGroup with addrset. Then use the TargetGroup to list all addresses. */ TargetGroup tg(&addrset); /* struct sockaddr_storage ss; size_t sslen; char addr_string[128]; while (tg.get_next_host(&ss, &sslen) == 1) { if (ss.ss_family == AF_INET) { struct sockaddr_in *sin = (struct sockaddr_in *)&ss; inet_ntop(AF_INET, (void *)&sin->sin_addr, addr_string, sizeof(addr_string)); cout << addr_string << endl; } else if (ss.ss_family == AF_INET6) { struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *)&ss; inet_ntop(AF_INET6, (void *)&sin6->sin6_addr, addr_string, sizeof(addr_string)); cout << addr_string << endl; } } */ char line[1024]; while (fgets(line, sizeof(line), stdin) != NULL) { char *s, *hostname; struct addrinfo *addrs; s = line; while ((hostname = strtok(s, " \t\n")) != NULL) { int rc; s = NULL; rc = resolve_name(hostname, &addrs); if (rc != 0) { fprintf(stderr, "Error resolving \"%s\": %s.\n", hostname, gai_strerror(rc)); continue; } if (addrs == NULL) { fprintf(stderr, "No addresses found for \"%s\".\n", hostname); continue; } /* Check just the first address returned. */ if (addrset_contains(&addrset, addrs->ai_addr)) printf("%s\n", hostname); freeaddrinfo(addrs); } } addrset_free(&addrset); exit(0); }