From 57225a2c6a43099da67f0a99e21efde8bb26acee Mon Sep 17 00:00:00 2001 From: Nikos Mavrogiannopoulos Date: Wed, 11 Feb 2015 09:32:02 +0100 Subject: [PATCH] reserve the first address of the network to be set as the local part in our tun devices That is used only when explicit IP addresses are set. That way we don't need to separate addresses into odd and even. --- src/ip-lease.c | 501 ++++++++++++++++++++++++------------------------- 1 file changed, 250 insertions(+), 251 deletions(-) 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);