static int is_ipv6_ok(main_server_st *s, struct sockaddr_storage *ip, struct sockaddr_storage *net, struct sockaddr_storage *mask) { if (ip_lease_exists(s, ip, sizeof(struct sockaddr_in6)) != 0 || ip_cmp(ip, net) == 0) { return 0; } return 1; }
static int is_ipv4_ok(main_server_st *s, struct sockaddr_storage *ip, struct sockaddr_storage *net, struct sockaddr_storage *mask) { struct sockaddr_storage broadcast; unsigned i; memcpy(&broadcast, net, sizeof(broadcast)); for (i=0;i<sizeof(struct in_addr);i++) { SA_IN_U8_P(&broadcast)[i] |= ~(SA_IN_U8_P(&mask)[i]); } if (ip_lease_exists(s, ip, sizeof(struct sockaddr_in)) != 0 || ip_cmp(ip, net) == 0 || ip_cmp(ip, &broadcast) == 0) { return 0; } return 1; }
static int get_ipv6_lease(main_server_st* s, struct proc_st* proc) { struct sockaddr_storage tmp, mask, network, rnd; unsigned i, max_loops = MAX_IP_TRIES; int ret; const char* c_network, *c_netmask; char buf[64]; if (proc->config.ipv6_network && proc->config.ipv6_netmask) { c_network = proc->config.ipv6_network; c_netmask = proc->config.ipv6_netmask; } else { c_network = s->config->network.ipv6; c_netmask = s->config->network.ipv6_netmask; } if (c_network && c_netmask) { ret = inet_pton(AF_INET6, c_network, SA_IN6_P(&network)); if (ret != 1) { mslog(s, NULL, LOG_ERR, "error reading IP: %s", c_network); return -1; } ret = inet_pton(AF_INET6, c_netmask, SA_IN6_P(&mask)); if (ret != 1) { mslog(s, NULL, LOG_ERR, "error reading mask: %s", c_netmask); return -1; } proc->ipv6 = calloc(1, sizeof(*proc->ipv6)); if (proc->ipv6 == NULL) return ERR_MEM; /* mask the network */ for (i=0;i<sizeof(struct in6_addr);i++) SA_IN6_U8_P(&network)[i] &= (SA_IN6_U8_P(&mask)[i]); ((struct sockaddr_in6*)&network)->sin6_family = AF_INET6; ((struct sockaddr_in6*)&network)->sin6_port = 0; memcpy(&tmp, &network, sizeof(tmp)); ((struct sockaddr_in6*)&tmp)->sin6_family = AF_INET6; ((struct sockaddr_in6*)&tmp)->sin6_port = AF_INET6; ((struct sockaddr_in6*)&rnd)->sin6_family = AF_INET6; ((struct sockaddr_in6*)&rnd)->sin6_port = AF_INET6; do { if (max_loops == 0) { mslog(s, NULL, LOG_ERR, "could not figure out a valid IPv6 IP."); ret = ERR_NO_IP; goto fail; } if (max_loops == MAX_IP_TRIES) { uint32_t t = hash_any(proc->username, strlen(proc->username), 0); memset(SA_IN6_U8_P(&rnd), 0, sizeof(struct in6_addr)); memcpy(SA_IN6_U8_P(&rnd)+sizeof(struct in6_addr)-5, &t, 4); } else gnutls_rnd(GNUTLS_RND_NONCE, SA_IN6_U8_P(&rnd), sizeof(struct in6_addr)); max_loops--; /* Mask the random number with the netmask */ for (i=0;i<sizeof(struct in6_addr);i++) SA_IN6_U8_P(&rnd)[i] &= ~(SA_IN6_U8_P(&mask)[i]); SA_IN6_U8_P(&rnd)[sizeof(struct in6_addr)-1] &= 0xFE; /* Now add the network to the masked random number */ for (i=0;i<sizeof(struct in6_addr);i++) SA_IN6_U8_P(&rnd)[i] |= (SA_IN6_U8_P(&network)[i]); /* check if it exists in the hash table */ if (ip_lease_exists(s, &rnd, sizeof(struct sockaddr_in6)) != 0) { mslog(s, proc, LOG_DEBUG, "cannot assign local IP %s to '%s'; it is in use.", human_addr((void*)&rnd, sizeof(struct sockaddr_in6), buf, sizeof(buf)), proc->username); continue; } proc->ipv6->lip_len = sizeof(struct sockaddr_in6); memcpy(&proc->ipv6->lip, &rnd, proc->ipv6->lip_len); /* RIP = LIP + 1 */ memcpy(&tmp, &proc->ipv6->lip, proc->ipv6->rip_len); bignum_add(SA_IN6_U8_P(&tmp), sizeof(struct in6_addr), 1); /* check if it exists in the hash table */ if (ip_lease_exists(s, &tmp, sizeof(struct sockaddr_in6)) != 0) { mslog(s, proc, LOG_DEBUG, "cannot assign remote IP %s to '%s'; it is in use.", human_addr((void*)&tmp, sizeof(struct sockaddr_in6), buf, sizeof(buf)), proc->username); continue; } proc->ipv6->rip_len = sizeof(struct sockaddr_in6); memcpy(&proc->ipv6->rip, &tmp, proc->ipv6->rip_len); /* mask the last IP with the netmask */ for (i=0;i<sizeof(struct in6_addr);i++) SA_IN6_U8_P(&tmp)[i] &= (SA_IN6_U8_P(&mask)[i]); /* the result should match the network */ if (memcmp(SA_IN6_U8_P(&network), SA_IN6_U8_P(&tmp), sizeof(struct in6_addr)) != 0) { continue; } mslog(s, proc, LOG_DEBUG, "selected IP for '%s': %s", proc->username, human_addr((void*)&proc->ipv6->lip, proc->ipv6->lip_len, buf, sizeof(buf))); if (icmp_ping6(s, (void*)&proc->ipv6->lip, (void*)&proc->ipv6->rip) == 0) break; } while(1); } return 0; fail: free(proc->ipv6); proc->ipv6 = NULL; return ret; }