Lease a single IPv6.

This commit is contained in:
Nikos Mavrogiannopoulos
2014-01-29 18:36:03 +01:00
parent b7a4a098a3
commit a3889c9053
+120 -85
View File
@@ -32,8 +32,7 @@ static void bignum_add (uint8_t * num, unsigned size, unsigned step)
register int i;
register unsigned tmp, y;
for (i = size-1; i >= 0; i--)
{
for (i = size - 1; i >= 0; i--) {
tmp = num[i];
num[i] += step;
@@ -47,7 +46,6 @@ static void bignum_add (uint8_t * num, unsigned size, unsigned step)
}
}
void ip_lease_deinit(struct ip_lease_db_st *db)
{
struct ip_lease_st *cache;
@@ -89,20 +87,21 @@ struct ip_lease_st* c2 = _c2;
return 0;
}
static int ip_lease_exists(main_server_st* s, struct sockaddr_storage* ip, size_t sockaddrlen)
static int ip_lease_exists(main_server_st * s, struct sockaddr_storage *ip,
size_t sockaddrlen)
{
struct ip_lease_st t;
t.rip_len = sockaddrlen;
memcpy(&t.rip, ip, sizeof(*ip));
if (htable_get(&s->ip_leases.ht, rehash(&t, NULL), ip_lease_cmp, &t) != 0)
if (htable_get(&s->ip_leases.ht, rehash(&t, NULL), ip_lease_cmp, &t) !=
0)
return 1;
return 0;
}
#define MAX_IP_TRIES 16
static
@@ -125,19 +124,19 @@ int get_ipv4_lease(main_server_st* s, struct proc_st* proc)
}
if (c_network && c_netmask) {
ret =
inet_pton(AF_INET, c_network, SA_IN_P(&network));
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);
mslog(s, NULL, LOG_ERR, "error reading IP: %s",
c_network);
return -1;
}
ret =
inet_pton(AF_INET, c_netmask, SA_IN_P(&mask));
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 mask: %s",
c_netmask);
return -1;
}
@@ -161,23 +160,29 @@ int get_ipv4_lease(main_server_st* s, struct proc_st* proc)
do {
if (max_loops == 0) {
mslog(s, proc, LOG_ERR, "could not figure out a valid IPv4 IP.");
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) {
if (proc->seeds_are_set) {
memcpy(SA_IN_U8_P(&rnd), proc->ipv4_seed, 4);
memcpy(SA_IN_U8_P(&rnd),
proc->ipv4_seed, 4);
} else {
uint32_t t = hash_any(proc->username, strlen(proc->username), 0);
uint32_t t =
hash_any(proc->username,
strlen(proc->username), 0);
memcpy(SA_IN_U8_P(&rnd), &t, 4);
}
} else
gnutls_rnd(GNUTLS_RND_NONCE, SA_IN_U8_P(&rnd), sizeof(struct in_addr));
gnutls_rnd(GNUTLS_RND_NONCE, SA_IN_U8_P(&rnd),
sizeof(struct in_addr));
max_loops--;
if (SA_IN_U8_P(&rnd)[3] == 255) /* broadcast */
bignum_add(SA_IN_U8_P(&rnd), sizeof(struct in_addr), 1);
bignum_add(SA_IN_U8_P(&rnd),
sizeof(struct in_addr), 1);
/* Mask the random number with the netmask */
for (i = 0; i < sizeof(struct in_addr); i++) {
@@ -188,32 +193,44 @@ int get_ipv4_lease(main_server_st* s, struct proc_st* proc)
/* Now add the IP to the masked random number */
for (i = 0; i < sizeof(struct in_addr); i++)
SA_IN_U8_P(&rnd)[i] |= (SA_IN_U8_P(&network)[i]);
SA_IN_U8_P(&rnd)[i] |=
(SA_IN_U8_P(&network)[i]);
/* check if it exists in the hash table */
if (ip_lease_exists(s, &rnd, sizeof(struct sockaddr_in)) != 0) {
mslog(s, proc, LOG_DEBUG, "cannot assign remote IP %s to '%s'; it is in use.",
human_addr((void*)&rnd, sizeof(struct sockaddr_in), buf, sizeof(buf)),
if (ip_lease_exists(s, &rnd, sizeof(struct sockaddr_in))
!= 0) {
mslog(s, proc, LOG_DEBUG,
"cannot assign remote IP %s to '%s'; it is in use.",
human_addr((void *)&rnd,
sizeof(struct sockaddr_in),
buf, sizeof(buf)),
proc->username);
continue;
}
memcpy(&proc->ipv4->lip, &rnd, sizeof(struct sockaddr_in));
memcpy(&proc->ipv4->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));
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 to '%s'; it is in use.",
human_addr((void*)&tmp, sizeof(struct sockaddr_in), buf, sizeof(buf)),
if (ip_lease_exists(s, &tmp, sizeof(struct sockaddr_in))
!= 0) {
mslog(s, proc, LOG_DEBUG,
"cannot assign remote IP %s to '%s'; it is in use.",
human_addr((void *)&tmp,
sizeof(struct sockaddr_in),
buf, sizeof(buf)),
proc->username);
continue;
}
memcpy(&proc->ipv4->rip, &tmp, sizeof(struct sockaddr_in));
memcpy(&proc->ipv4->rip, &tmp,
sizeof(struct sockaddr_in));
proc->ipv4->rip_len = sizeof(struct sockaddr_in);
/* mask the last IP with the netmask */
@@ -221,14 +238,21 @@ int get_ipv4_lease(main_server_st* s, struct proc_st* proc)
SA_IN_U8_P(&tmp)[i] &= (SA_IN_U8_P(&mask)[i]);
/* the result should match the network */
if (memcmp(SA_IN_U8_P(&network), SA_IN_U8_P(&tmp), sizeof(struct in_addr)) != 0) {
if (memcmp
(SA_IN_U8_P(&network), SA_IN_U8_P(&tmp),
sizeof(struct in_addr)) != 0) {
continue;
}
mslog(s, proc, LOG_DEBUG, "selected IP for '%s': %s", proc->username,
human_addr((void*)&proc->ipv4->lip, proc->ipv4->lip_len, buf, sizeof(buf)));
mslog(s, proc, LOG_DEBUG, "selected IP for '%s': %s",
proc->username,
human_addr((void *)&proc->ipv4->lip,
proc->ipv4->lip_len, buf,
sizeof(buf)));
if (icmp_ping4(s, (void*)&proc->ipv4->lip, (void*)&proc->ipv4->rip) == 0)
if (icmp_ping4
(s, (void *)&proc->ipv4->lip,
(void *)&proc->ipv4->rip) == 0)
break;
} while (1);
}
@@ -261,19 +285,19 @@ int get_ipv6_lease(main_server_st* s, struct proc_st* proc)
}
if (c_network && c_netmask) {
ret =
inet_pton(AF_INET6, c_network, SA_IN6_P(&network));
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);
mslog(s, NULL, LOG_ERR, "error reading IP: %s",
c_network);
return -1;
}
ret =
inet_pton(AF_INET6, c_netmask, SA_IN6_P(&mask));
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);
mslog(s, NULL, LOG_ERR, "error reading mask: %s",
c_netmask);
return -1;
}
@@ -296,37 +320,52 @@ int get_ipv6_lease(main_server_st* s, struct proc_st* proc)
do {
if (max_loops == 0) {
mslog(s, NULL, LOG_ERR, "could not figure out a valid IPv6 IP.");
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));
memset(SA_IN6_U8_P(&rnd), 0,
sizeof(struct in6_addr));
if (proc->seeds_are_set) {
memcpy(SA_IN6_U8_P(&rnd)+sizeof(struct in6_addr)-5, proc->ipv4_seed, 4);
memcpy(SA_IN6_U8_P(&rnd) +
sizeof(struct in6_addr) - 5,
proc->ipv4_seed, 4);
} else {
uint32_t t = hash_any(proc->username, strlen(proc->username), 0);
memcpy(SA_IN6_U8_P(&rnd)+sizeof(struct in6_addr)-5, &t, 4);
uint32_t t =
hash_any(proc->username,
strlen(proc->username), 0);
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));
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)[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]);
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)),
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;
}
@@ -334,35 +373,18 @@ int get_ipv6_lease(main_server_st* s, struct proc_st* proc)
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, sizeof(tmp));
/* RIP = LIP in IPv6 */
memcpy(&proc->ipv6->rip, &proc->ipv6->lip,
sizeof(proc->ipv6->lip));
proc->ipv6->rip_len = proc->ipv6->lip_len;
bignum_add(SA_IN6_U8_P(&tmp), sizeof(struct in6_addr), 1);
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)));
/* 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;
}
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)
if (icmp_ping6(s, (void *)&proc->ipv6->lip) == 0)
break;
} while (1);
}
@@ -387,8 +409,11 @@ char buf[128];
return ret;
if (proc->ipv4) {
if (htable_add(&s->ip_leases.ht, rehash(proc->ipv4, NULL), proc->ipv4) == 0) {
mslog(s, proc, LOG_ERR, "could not add IPv4 lease to hash table.");
if (htable_add
(&s->ip_leases.ht, rehash(proc->ipv4, NULL),
proc->ipv4) == 0) {
mslog(s, proc, LOG_ERR,
"could not add IPv4 lease to hash table.");
return -1;
}
}
@@ -400,25 +425,33 @@ char buf[128];
return ret;
if (proc->ipv6) {
if (htable_add(&s->ip_leases.ht, rehash(proc->ipv6, NULL), proc->ipv6) == 0) {
mslog(s, proc, LOG_ERR, "could not add IPv6 lease to hash table.");
if (htable_add
(&s->ip_leases.ht, rehash(proc->ipv6, NULL),
proc->ipv6) == 0) {
mslog(s, proc, LOG_ERR,
"could not add IPv6 lease to hash table.");
return -1;
}
}
}
if (proc->ipv4 == 0 && proc->ipv6 == 0) {
mslog(s, proc, LOG_ERR, "no IPv4 or IPv6 addresses are configured. Cannot obtain lease.");
mslog(s, proc, LOG_ERR,
"no IPv4 or IPv6 addresses are configured. Cannot obtain lease.");
return -1;
}
if (proc->ipv4)
mslog(s, proc, LOG_INFO, "assigned IPv4 to '%s': %s", proc->username,
human_addr((void*)&proc->ipv4->rip, proc->ipv4->rip_len, buf, sizeof(buf)));
mslog(s, proc, LOG_INFO, "assigned IPv4 to '%s': %s",
proc->username, human_addr((void *)&proc->ipv4->rip,
proc->ipv4->rip_len, buf,
sizeof(buf)));
if (proc->ipv6)
mslog(s, proc, LOG_INFO, "assigned IPv6 to '%s': %s", proc->username,
human_addr((void*)&proc->ipv6->rip, proc->ipv6->rip_len, buf, sizeof(buf)));
mslog(s, proc, LOG_INFO, "assigned IPv6 to '%s': %s",
proc->username, human_addr((void *)&proc->ipv6->rip,
proc->ipv6->rip_len, buf,
sizeof(buf)));
return 0;
}
@@ -426,12 +459,14 @@ char buf[128];
void remove_ip_leases(main_server_st * s, struct proc_st *proc)
{
if (proc->ipv4) {
htable_del(&s->ip_leases.ht, rehash(proc->ipv4, NULL), proc->ipv4);
htable_del(&s->ip_leases.ht, rehash(proc->ipv4, NULL),
proc->ipv4);
free(proc->ipv4);
proc->ipv4 = NULL;
}
if (proc->ipv6) {
htable_del(&s->ip_leases.ht, rehash(proc->ipv6, NULL), proc->ipv6);
htable_del(&s->ip_leases.ht, rehash(proc->ipv6, NULL),
proc->ipv6);
free(proc->ipv6);
proc->ipv6 = NULL;
}