diff --git a/src/ip-lease.c b/src/ip-lease.c index 7944bf10..27b83e93 100644 --- a/src/ip-lease.c +++ b/src/ip-lease.c @@ -142,42 +142,6 @@ int get_ipv4_lease(main_server_st* s, struct proc_st* proc) const char* c_network, *c_netmask; char buf[64]; - if (proc->config.explicit_ipv4) { - /* if an explicit IP is given for that client, then - * do implicit IP accounting. Require the address - * to be odd, so we use the next even address as PtP. */ - ret = - inet_pton(AF_INET, proc->config.explicit_ipv4, SA_IN_P(&network)); - - if (ret != 1) { - mslog(s, NULL, LOG_ERR, "error reading explicit IP: %s", proc->config.explicit_ipv4); - return -1; - } - - if (((uint8_t*)SA_IN_P(&network))[3] % 2 == 0) { - mslog(s, NULL, LOG_ERR, "we only assign odd IP addresses: %s", proc->config.explicit_ipv4); - return ERR_NO_IP; - } - - proc->ipv4 = talloc_zero(proc, struct ip_lease_st); - if (proc->ipv4 == NULL) - return ERR_MEM; - - ((struct sockaddr_in*)&network)->sin_family = AF_INET; - ((struct sockaddr_in*)&network)->sin_port = 0; - memcpy(&proc->ipv4->rip, &network, sizeof(struct sockaddr_in)); - proc->ipv4->rip_len = sizeof(struct sockaddr_in); - - /* LIP = RIP + 1 */ - memcpy(&tmp, &proc->ipv4->rip, sizeof(struct sockaddr_in)); - bignum_add(SA_IN_U8_P(&tmp), sizeof(struct in_addr), 1); - - memcpy(&proc->ipv4->lip, &tmp, sizeof(struct sockaddr_in)); - proc->ipv4->lip_len = sizeof(struct sockaddr_in); - - return 0; - } - /* Our IP accounting */ if (proc->config.ipv4_network && proc->config.ipv4_netmask) { c_network = proc->config.ipv4_network; @@ -187,111 +151,146 @@ int get_ipv4_lease(main_server_st* s, struct proc_st* proc) c_netmask = s->config->network.ipv4_netmask; } - if (c_network && c_netmask) { + if (c_network == NULL || c_netmask == NULL) { + mslog(s, NULL, LOG_ERR, "there is no IPv4 network assigned"); + return -1; + } + + ret = + inet_pton(AF_INET, c_network, SA_IN_P(&network)); + if (ret != 1) { + mslog(s, NULL, LOG_ERR, "error reading IP: %s", c_network); + return -1; + } + + ret = + inet_pton(AF_INET, c_netmask, SA_IN_P(&mask)); + if (ret != 1) { + mslog(s, NULL, LOG_ERR, "error reading mask: %s", c_netmask); + return -1; + } + + /* mask the network (just in case it is wrong) */ + for (i=0;isin_family = AF_INET; + ((struct sockaddr_in*)&network)->sin_port = 0; + + if (proc->config.explicit_ipv4) { + /* if an explicit IP is given for that client, then + * do implicit IP accounting. Require the address + * to be odd, so we use the next even address as PtP. */ ret = - inet_pton(AF_INET, c_network, SA_IN_P(&network)); + inet_pton(AF_INET, proc->config.explicit_ipv4, SA_IN_P(&tmp)); if (ret != 1) { - mslog(s, NULL, LOG_ERR, "error reading IP: %s", c_network); - return -1; - } - - ret = - inet_pton(AF_INET, c_netmask, SA_IN_P(&mask)); - - if (ret != 1) { - mslog(s, NULL, LOG_ERR, "error reading mask: %s", c_netmask); + mslog(s, NULL, LOG_ERR, "error reading explicit IP: %s", proc->config.explicit_ipv4); return -1; } proc->ipv4 = talloc_zero(proc, struct ip_lease_st); if (proc->ipv4 == NULL) return ERR_MEM; - proc->ipv4->db = &s->ip_leases; - /* mask the network (just in case it is wrong) */ - for (i=0;isin_family = AF_INET; - ((struct sockaddr_in*)&network)->sin_port = 0; + ((struct sockaddr_in*)&tmp)->sin_family = AF_INET; + ((struct sockaddr_in*)&tmp)->sin_port = 0; + memcpy(&proc->ipv4->rip, &tmp, sizeof(struct sockaddr_in)); + proc->ipv4->rip_len = sizeof(struct sockaddr_in); - memcpy(&tmp, &network, sizeof(tmp)); - ((struct sockaddr_in*)&tmp)->sin_family = AF_INET; - ((struct sockaddr_in*)&tmp)->sin_port = 0; + /* LIP = 1st network address */ + memcpy(&proc->ipv4->lip, &network, sizeof(struct sockaddr_in)); + proc->ipv4->lip_len = sizeof(struct sockaddr_in); - memset(&rnd, 0, sizeof(rnd)); - ((struct sockaddr_in*)&rnd)->sin_family = AF_INET; - ((struct sockaddr_in*)&rnd)->sin_port = 0; + if (memcmp(SA_IN_U8_P(&proc->ipv4->lip), SA_IN_U8_P(&proc->ipv4->rip), sizeof(struct in_addr)) == 0) { + mslog(s, NULL, LOG_ERR, "cannot assign explicit IP: %s (net: %s)", proc->config.explicit_ipv4, c_network); + return ERR_NO_IP; + } - do { - if (max_loops == 0) { - mslog(s, proc, LOG_ERR, "could not figure out a valid IPv4 IP."); - ret = ERR_NO_IP; - goto fail; - } - if (max_loops == MAX_IP_TRIES) { - memcpy(SA_IN_U8_P(&rnd), proc->ipv4_seed, 4); - } else { - ip_from_seed(SA_IN_U8_P(&rnd), sizeof(struct in_addr), - SA_IN_U8_P(&rnd), sizeof(struct in_addr)); - } - max_loops--; - - if (SA_IN_U8_P(&rnd)[3] == 255 || SA_IN_U8_P(&rnd)[3] == 254) /* avoid broadcast */ - bignum_add(SA_IN_U8_P(&rnd), sizeof(struct in_addr), 1); - - /* Mask the random number with the netmask */ - for (i=0;iipv4->lip, &rnd, sizeof(struct sockaddr_in)); - proc->ipv4->lip_len = sizeof(struct sockaddr_in); - - /* RIP = LIP + 1 */ - memcpy(&tmp, &proc->ipv4->lip, sizeof(struct sockaddr_in)); - bignum_add(SA_IN_U8_P(&tmp), sizeof(struct in_addr), 1); - - /* check if it exists in the hash table */ - if (ip_lease_exists(s, &tmp, sizeof(struct sockaddr_in)) != 0) { - mslog(s, proc, LOG_DEBUG, "cannot assign remote IP %s; it is in use.", - human_addr((void*)&tmp, sizeof(struct sockaddr_in), buf, sizeof(buf))); - continue; - } - - memcpy(&proc->ipv4->rip, &tmp, sizeof(struct sockaddr_in)); - proc->ipv4->rip_len = sizeof(struct sockaddr_in); - - /* mask the last IP with the netmask */ - for (i=0;iipv4->lip, proc->ipv4->lip_len, buf, sizeof(buf))); - - if (icmp_ping4(s, (void*)&proc->ipv4->lip, (void*)&proc->ipv4->rip) == 0) - break; - } while(1); + return 0; } + /* assign "random" IP */ + proc->ipv4 = talloc_zero(proc, struct ip_lease_st); + if (proc->ipv4 == NULL) + return ERR_MEM; + proc->ipv4->db = &s->ip_leases; + + memcpy(&tmp, &network, sizeof(tmp)); + ((struct sockaddr_in*)&tmp)->sin_family = AF_INET; + ((struct sockaddr_in*)&tmp)->sin_port = 0; + + memset(&rnd, 0, sizeof(rnd)); + ((struct sockaddr_in*)&rnd)->sin_family = AF_INET; + ((struct sockaddr_in*)&rnd)->sin_port = 0; + + do { + if (max_loops == 0) { + mslog(s, proc, LOG_ERR, "could not figure out a valid IPv4 IP."); + ret = ERR_NO_IP; + goto fail; + } + if (max_loops == MAX_IP_TRIES) { + memcpy(SA_IN_U8_P(&rnd), proc->ipv4_seed, 4); + } else { + ip_from_seed(SA_IN_U8_P(&rnd), sizeof(struct in_addr), + SA_IN_U8_P(&rnd), sizeof(struct in_addr)); + } + max_loops--; + + if (SA_IN_U8_P(&rnd)[3] == 255 || SA_IN_U8_P(&rnd)[3] == 254) /* avoid broadcast */ + bignum_add(SA_IN_U8_P(&rnd), sizeof(struct in_addr), 1); + + /* Mask the random number with the netmask */ + for (i=0;iipv4->lip, &rnd, sizeof(struct sockaddr_in)); + proc->ipv4->lip_len = sizeof(struct sockaddr_in); + + /* RIP = LIP + 1 */ + memcpy(&tmp, &proc->ipv4->lip, sizeof(struct sockaddr_in)); + bignum_add(SA_IN_U8_P(&tmp), sizeof(struct in_addr), 1); + + /* check if it exists in the hash table */ + if (ip_lease_exists(s, &tmp, sizeof(struct sockaddr_in)) != 0) { + mslog(s, proc, LOG_DEBUG, "cannot assign remote IP %s; it is in use.", + human_addr((void*)&tmp, sizeof(struct sockaddr_in), buf, sizeof(buf))); + continue; + } + + memcpy(&proc->ipv4->rip, &tmp, sizeof(struct sockaddr_in)); + proc->ipv4->rip_len = sizeof(struct sockaddr_in); + + /* mask the last IP with the netmask */ + for (i=0;iipv4->lip, proc->ipv4->lip_len, buf, sizeof(buf))); + + if (icmp_ping4(s, (void*)&proc->ipv4->lip, (void*)&proc->ipv4->rip) == 0) + break; + } while(1); + return 0; fail: @@ -312,42 +311,6 @@ int get_ipv6_lease(main_server_st* s, struct proc_st* proc) char *c_netmask = NULL; char buf[64]; - if (proc->config.explicit_ipv6) { - /* if an explicit IP is given for that client, then - * do implicit IP accounting. Require the address - * to be odd, so we use the next even address as PtP. */ - ret = - inet_pton(AF_INET6, proc->config.explicit_ipv6, SA_IN6_P(&network)); - - if (ret != 1) { - mslog(s, NULL, LOG_ERR, "error reading explicit IP: %s", proc->config.explicit_ipv6); - return -1; - } - - if (((uint8_t*)SA_IN6_P(&network))[15] % 2 == 0) { - mslog(s, NULL, LOG_ERR, "we only assign odd IP addresses: %s", proc->config.explicit_ipv6); - return ERR_NO_IP; - } - - proc->ipv6 = talloc_zero(proc, struct ip_lease_st); - if (proc->ipv6 == NULL) - return ERR_MEM; - - ((struct sockaddr_in6*)&network)->sin6_family = AF_INET6; - ((struct sockaddr_in6*)&network)->sin6_port = 0; - memcpy(&proc->ipv6->rip, &network, sizeof(struct sockaddr_in6)); - proc->ipv6->rip_len = sizeof(struct sockaddr_in6); - - /* LIP = RIP + 1 */ - memcpy(&tmp, &proc->ipv6->rip, sizeof(struct sockaddr_in6)); - bignum_add(SA_IN6_U8_P(&tmp), sizeof(struct in6_addr), 1); - - memcpy(&proc->ipv6->lip, &tmp, sizeof(struct sockaddr_in6)); - proc->ipv6->lip_len = sizeof(struct sockaddr_in6); - - return 0; - } - if (proc->config.ipv6_network && proc->config.ipv6_prefix) { c_network = proc->config.ipv6_network; c_netmask = ipv6_prefix_to_mask(proc, proc->config.ipv6_prefix); @@ -356,109 +319,145 @@ int get_ipv6_lease(main_server_st* s, struct proc_st* proc) c_netmask = ipv6_prefix_to_mask(proc, s->config->network.ipv6_prefix); } - 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 (c_network == NULL || c_netmask == NULL) { + mslog(s, NULL, LOG_ERR, "there is no IPv6 network assigned"); + return -1; + } + 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; + } + + /* mask the network */ + for (i=0;isin6_family = AF_INET6; + ((struct sockaddr_in6*)&network)->sin6_port = 0; + + if (proc->config.explicit_ipv6) { + /* if an explicit IP is given for that client, then + * do implicit IP accounting. Require the address + * to be odd, so we use the next even address as PtP. */ + ret = + inet_pton(AF_INET6, proc->config.explicit_ipv6, SA_IN6_P(&tmp)); + if (ret != 1) { - mslog(s, NULL, LOG_ERR, "error reading mask: %s", c_netmask); + mslog(s, NULL, LOG_ERR, "error reading explicit IP: %s", proc->config.explicit_ipv6); return -1; } - + proc->ipv6 = talloc_zero(proc, struct ip_lease_st); if (proc->ipv6 == NULL) return ERR_MEM; - proc->ipv6->db = &s->ip_leases; - /* mask the network */ - for (i=0;isin6_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 = 0; + memcpy(&proc->ipv6->rip, &tmp, sizeof(struct sockaddr_in6)); + proc->ipv6->rip_len = sizeof(struct sockaddr_in6); + + /* LIP = 1st network address */ + memcpy(&proc->ipv6->lip, &network, sizeof(struct sockaddr_in6)); + proc->ipv6->lip_len = sizeof(struct sockaddr_in6); - ((struct sockaddr_in6*)&rnd)->sin6_family = AF_INET6; - ((struct sockaddr_in6*)&rnd)->sin6_port = 0; + if (memcmp(SA_IN6_U8_P(&proc->ipv6->lip), SA_IN6_U8_P(&proc->ipv6->rip), sizeof(struct in6_addr)) == 0) { + mslog(s, NULL, LOG_ERR, "cannot assign explicit IP: %s (net: %s)", proc->config.explicit_ipv6, c_network); + return ERR_NO_IP; + } - 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) { - memset(SA_IN6_U8_P(&rnd), 0, sizeof(struct in6_addr)); - memcpy(SA_IN6_U8_P(&rnd)+sizeof(struct in6_addr)-5, proc->ipv4_seed, 4); - } else { - ip_from_seed(SA_IN6_U8_P(&rnd), sizeof(struct in6_addr), - SA_IN6_U8_P(&rnd), sizeof(struct in6_addr)); - } - max_loops--; - - /* Mask the random number with the netmask */ - for (i=0;iipv6->lip_len = sizeof(struct sockaddr_in6); - memcpy(&proc->ipv6->lip, &rnd, proc->ipv6->lip_len); - - /* RIP = LIP + 1 */ - memcpy(&tmp, &proc->ipv6->lip, sizeof(tmp)); - proc->ipv6->rip_len = proc->ipv6->lip_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; it is in use.", - human_addr((void*)&tmp, sizeof(struct sockaddr_in6), buf, sizeof(buf))); - continue; - } - - memcpy(&proc->ipv6->rip, &tmp, proc->ipv6->rip_len); - - /* mask the last IP with the netmask */ - for (i=0;iipv6->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; } + /* assign "random" IP */ + proc->ipv6 = talloc_zero(proc, struct ip_lease_st); + if (proc->ipv6 == NULL) + return ERR_MEM; + proc->ipv6->db = &s->ip_leases; + + memcpy(&tmp, &network, sizeof(tmp)); + ((struct sockaddr_in6*)&tmp)->sin6_family = AF_INET6; + ((struct sockaddr_in6*)&tmp)->sin6_port = 0; + + ((struct sockaddr_in6*)&rnd)->sin6_family = AF_INET6; + ((struct sockaddr_in6*)&rnd)->sin6_port = 0; + + 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) { + memset(SA_IN6_U8_P(&rnd), 0, sizeof(struct in6_addr)); + memcpy(SA_IN6_U8_P(&rnd)+sizeof(struct in6_addr)-5, proc->ipv4_seed, 4); + } else { + ip_from_seed(SA_IN6_U8_P(&rnd), sizeof(struct in6_addr), + SA_IN6_U8_P(&rnd), sizeof(struct in6_addr)); + } + max_loops--; + + /* Mask the random number with the netmask */ + for (i=0;iipv6->lip_len = sizeof(struct sockaddr_in6); + memcpy(&proc->ipv6->lip, &rnd, proc->ipv6->lip_len); + + /* RIP = LIP + 1 */ + memcpy(&tmp, &proc->ipv6->lip, sizeof(tmp)); + proc->ipv6->rip_len = proc->ipv6->lip_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; it is in use.", + human_addr((void*)&tmp, sizeof(struct sockaddr_in6), buf, sizeof(buf))); + continue; + } + + memcpy(&proc->ipv6->rip, &tmp, proc->ipv6->rip_len); + + /* mask the last IP with the netmask */ + for (i=0;iipv6->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: talloc_free(proc->ipv6);