1 /*
2  * Copyright (C) 2013 Nikos Mavrogiannopoulos
3  *
4  * This program is free software; you can redistribute it and/or modify
5  * it under the terms of the GNU General Public License as published by
6  * the Free Software Foundation; either version 2 of the License, or
7  * (at your option) any later version.
8  *
9  * This program is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12  * GNU General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
16  */
17 
18 #include <config.h>
19 #include <stdbool.h>
20 
21 #include <stdio.h>
22 
23 #include <ip-lease.h>
24 #include <main.h>
25 #include <ip-util.h>
26 #include <gnutls/crypto.h>
27 #include <icmp-ping.h>
28 #include <arpa/inet.h>
29 
ip_from_seed(uint8_t * seed,unsigned seed_size,void * ip,size_t ip_size)30 void ip_from_seed(uint8_t *seed, unsigned seed_size,
31 		void *ip, size_t ip_size)
32 {
33 	uint8_t digest[20];
34 	int ret;
35 
36 	if (ip_size > sizeof(digest)) {
37 		syslog(LOG_ERR, "too large IP!");
38 		abort();
39 	}
40 
41 	ret = gnutls_hash_fast(GNUTLS_DIG_SHA1, seed, seed_size, digest);
42 	if (ret < 0) {
43 		syslog(LOG_ERR, "cannot hash: %s", strerror(ret));
44 		abort();
45 	}
46 
47 	memcpy(ip, digest, ip_size);
48 
49 }
50 
ip_lease_deinit(struct ip_lease_db_st * db)51 void ip_lease_deinit(struct ip_lease_db_st* db)
52 {
53 struct ip_lease_st * cache;
54 struct htable_iter iter;
55 
56 	cache = htable_first(&db->ht, &iter);
57 	while(cache != NULL) {
58 		/* disable the destructor */
59 		cache->db = NULL;
60 		talloc_free(cache);
61 
62 		cache = htable_next(&db->ht, &iter);
63 	}
64 	htable_clear(&db->ht);
65 
66 	return;
67 }
68 
rehash(const void * _e,void * unused)69 static size_t rehash(const void* _e, void* unused)
70 {
71 const struct ip_lease_st * e = _e;
72 
73 	return hash_any(SA_IN_P_GENERIC(&e->sig, e->sig_len), SA_IN_SIZE(e->sig_len), 0);
74 }
75 
ip_lease_init(struct ip_lease_db_st * db)76 void ip_lease_init(struct ip_lease_db_st* db)
77 {
78 	htable_init(&db->ht, rehash, NULL);
79 }
80 
ip_lease_cmp(const void * _c1,void * _c2)81 static bool ip_lease_cmp(const void* _c1, void* _c2)
82 {
83 const struct ip_lease_st* c1 = _c1;
84 struct ip_lease_st* c2 = _c2;
85 
86 	if (c1->sig_len == c2->sig_len &&
87 		ip_cmp(&c1->sig, &c2->sig) == 0)
88 		return 1;
89 
90 	return 0;
91 }
92 
ip_lease_exists(main_server_st * s,struct sockaddr_storage * ip,size_t sockaddrlen)93 static int ip_lease_exists(main_server_st* s, struct sockaddr_storage* ip, size_t sockaddrlen)
94 {
95 struct ip_lease_st t;
96 
97 	t.sig_len = sockaddrlen;
98 	memcpy(&t.sig, ip, sizeof(*ip));
99 
100  	if (htable_get(&s->ip_leases.ht, rehash(&t, NULL), ip_lease_cmp, &t) != 0)
101 		return 1;
102 
103 	return 0;
104 }
105 
steal_ip_leases(struct proc_st * proc,struct proc_st * thief)106 void steal_ip_leases(struct proc_st* proc, struct proc_st *thief)
107 {
108 	/* here we reset the old tun device, and assign the old addresses
109 	 * to a new device. We cannot re-use the old device because the
110 	 * fd is only available to the worker process and not here (main)
111 	 */
112 	reset_tun(proc);
113 
114 	thief->ipv4 = talloc_move(thief, &proc->ipv4);
115 	thief->ipv6 = talloc_move(thief, &proc->ipv6);
116 
117 	/* we make sure that the original client has a copy so that during
118 	 * disconnection the scripts will receive the right information */
119 	if (thief->ipv4) {
120 		proc->ipv4 = talloc_zero(proc, struct ip_lease_st);
121 
122 		if (proc->ipv4 != NULL) {
123 			proc->ipv4->rip_len = thief->ipv4->rip_len;
124 			proc->ipv4->lip_len = thief->ipv4->lip_len;
125 			memcpy(&proc->ipv4->rip, &thief->ipv4->rip, thief->ipv4->rip_len);
126 			memcpy(&proc->ipv4->lip, &thief->ipv4->lip, thief->ipv4->lip_len);
127 			memcpy(&proc->ipv4->sig, &thief->ipv4->sig, thief->ipv4->sig_len);
128 		}
129 	}
130 
131 	if (thief->ipv6) {
132 		proc->ipv6 = talloc_zero(proc, struct ip_lease_st);
133 
134 		if (proc->ipv6 != NULL) {
135 			proc->ipv6->prefix = thief->ipv6->prefix;
136 			proc->ipv6->rip_len = thief->ipv6->rip_len;
137 			proc->ipv6->lip_len = thief->ipv6->lip_len;
138 			memcpy(&proc->ipv6->rip, &thief->ipv6->rip, thief->ipv6->rip_len);
139 			memcpy(&proc->ipv6->lip, &thief->ipv6->lip, thief->ipv6->lip_len);
140 			memcpy(&proc->ipv6->sig, &thief->ipv6->sig, thief->ipv6->sig_len);
141 		}
142 	}
143 }
144 
is_ipv6_ok(main_server_st * s,struct sockaddr_storage * ip,struct sockaddr_storage * net,struct sockaddr_storage * subnet)145 static int is_ipv6_ok(main_server_st *s, struct sockaddr_storage *ip, struct sockaddr_storage *net, struct sockaddr_storage *subnet)
146 {
147 	/* check that IP & mask don't match network - i.e., the network's IP is outside
148 	 * that subnet; we use it in the tun device */
149 	if (memcmp(SA_IN6_U8_P(subnet), SA_IN6_U8_P(net), 16) == 0) {
150 		return 0;
151 	}
152 
153 	/* check that the IP's subnet is not registered already */
154 	if (ip_lease_exists(s, subnet, sizeof(struct sockaddr_in6)) != 0) {
155 		return 0;
156 	}
157 
158 	return 1;
159 }
160 
is_ipv4_ok(main_server_st * s,struct sockaddr_storage * ip,struct sockaddr_storage * net,struct sockaddr_storage * mask)161 static int is_ipv4_ok(main_server_st *s, struct sockaddr_storage *ip, struct sockaddr_storage *net, struct sockaddr_storage *mask)
162 {
163 	struct sockaddr_storage broadcast;
164 	unsigned i;
165 
166 	memcpy(&broadcast, net, sizeof(broadcast));
167 	for (i=0;i<sizeof(struct in_addr);i++) {
168 		SA_IN_U8_P(&broadcast)[i] |= ~(SA_IN_U8_P(mask)[i]);
169 	}
170 
171 	if (ip_lease_exists(s, ip, sizeof(struct sockaddr_in)) != 0 ||
172 	    ip_cmp(ip, net) == 0 ||
173 	    ip_cmp(ip, &broadcast) == 0) {
174 	    return 0;
175 	}
176 	return 1;
177 }
178 
179 #define MAX_IP_TRIES 16
180 #define FIXED_IPS 5
181 
182 static
get_ipv4_lease(main_server_st * s,struct proc_st * proc)183 int get_ipv4_lease(main_server_st* s, struct proc_st* proc)
184 {
185 
186 	struct sockaddr_storage tmp, mask, network, rnd;
187 	unsigned i;
188 	unsigned max_loops = MAX_IP_TRIES;
189 	int ret;
190 	const char *c_network, *c_netmask;
191 	char buf[64];
192 
193 	/* Our IP accounting */
194 	if (proc->config->ipv4_net && proc->config->ipv4_netmask) {
195 		/* We only read from user/group configuration as this
196 		 * is updated with the current vhost information */
197 		c_network = proc->config->ipv4_net;
198 		c_netmask = proc->config->ipv4_netmask;
199 	} else {
200 		c_network = proc->vhost->perm_config.config->network.ipv4;
201 		c_netmask = proc->vhost->perm_config.config->network.ipv4_netmask;
202 	}
203 
204 	if (c_network == NULL || c_netmask == NULL) {
205 		mslog(s, NULL, LOG_DEBUG, "there is no IPv4 network assigned");
206 		return 0;
207 	}
208 
209 	ret =
210 	    inet_pton(AF_INET, c_network, SA_IN_P(&network));
211 	if (ret != 1) {
212 		mslog(s, NULL, LOG_ERR, "error reading IP: %s", c_network);
213 		return -1;
214 	}
215 
216 	ret =
217 	    inet_pton(AF_INET, c_netmask, SA_IN_P(&mask));
218 	if (ret != 1) {
219 		mslog(s, NULL, LOG_ERR, "error reading mask: %s", c_netmask);
220 		return -1;
221 	}
222 
223 	/* mask the network (just in case it is wrong) */
224 	for (i=0;i<sizeof(struct in_addr);i++)
225 		SA_IN_U8_P(&network)[i] &= (SA_IN_U8_P(&mask)[i]);
226        	((struct sockaddr_in*)&network)->sin_family = AF_INET;
227        	((struct sockaddr_in*)&network)->sin_port = 0;
228 
229 	if (proc->config->explicit_ipv4) {
230 		ret =
231 		    inet_pton(AF_INET, proc->config->explicit_ipv4, SA_IN_P(&tmp));
232 
233 		if (ret != 1) {
234 			mslog(s, NULL, LOG_ERR, "error reading explicit IP: %s", proc->config->explicit_ipv4);
235 			return -1;
236 		}
237 
238 		proc->ipv4 = talloc_zero(proc, struct ip_lease_st);
239 		if (proc->ipv4 == NULL)
240 			return ERR_MEM;
241 
242         	((struct sockaddr_in*)&tmp)->sin_family = AF_INET;
243         	((struct sockaddr_in*)&tmp)->sin_port = 0;
244 		memcpy(&proc->ipv4->rip, &tmp, sizeof(struct sockaddr_in));
245        		proc->ipv4->rip_len = sizeof(struct sockaddr_in);
246 
247 		memcpy(&proc->ipv4->sig, &tmp, sizeof(struct sockaddr_in));
248 
249 		if (is_ipv4_ok(s, &proc->ipv4->rip, &network, &mask) == 0) {
250 			mslog(s, proc, LOG_DEBUG, "cannot assign explicit IP %s; it is in use or invalid",
251 			      human_addr((void*)&tmp, sizeof(struct sockaddr_in), buf, sizeof(buf)));
252 			ret = ERR_NO_IP;
253 			goto fail;
254 		}
255 
256 		/* LIP = network address + 1 */
257 		memcpy(&proc->ipv4->lip, &network, sizeof(struct sockaddr_in));
258 		proc->ipv4->lip_len = sizeof(struct sockaddr_in);
259 		SA_IN_U8_P(&proc->ipv4->lip)[3] |= 1;
260 
261 		if (ip_cmp(&proc->ipv4->lip, &proc->ipv4->rip) == 0) {
262 			mslog(s, NULL, LOG_ERR, "cannot assign explicit IP %s; network: %s", proc->config->explicit_ipv4, c_network);
263 			ret = ERR_NO_IP;
264 			goto fail;
265 		}
266 
267 		return 0;
268 	}
269 
270 	/* assign "random" IP */
271 	proc->ipv4 = talloc_zero(proc, struct ip_lease_st);
272 	if (proc->ipv4 == NULL)
273 		return ERR_MEM;
274 	proc->ipv4->db = &s->ip_leases;
275 
276        	memcpy(&tmp, &network, sizeof(tmp));
277      	((struct sockaddr_in*)&tmp)->sin_family = AF_INET;
278 	((struct sockaddr_in*)&tmp)->sin_port = 0;
279 
280 	memset(&rnd, 0, sizeof(rnd));
281 	((struct sockaddr_in*)&rnd)->sin_family = AF_INET;
282 	((struct sockaddr_in*)&rnd)->sin_port = 0;
283 
284 	do {
285 		if (max_loops == 0) {
286 			mslog(s, proc, LOG_ERR, "could not figure out a valid IPv4 IP");
287 			ret = ERR_NO_IP;
288 			goto fail;
289 		}
290 		if (max_loops == MAX_IP_TRIES) {
291 			memcpy(SA_IN_U8_P(&rnd), proc->ipv4_seed, 4);
292 		} else {
293 			if (max_loops < MAX_IP_TRIES-FIXED_IPS) {
294 				ret = gnutls_rnd(GNUTLS_RND_NONCE, SA_IN_U8_P(&rnd), sizeof(struct in_addr));
295 				if (ret < 0) {
296 					mslog(s, proc, LOG_ERR, "error in the random generator: %s", gnutls_strerror(ret));
297 					ret = ERR_NO_IP;
298 					goto fail;
299 				}
300 			} else {
301 				ip_from_seed(SA_IN_U8_P(&rnd), sizeof(struct in_addr),
302 					     SA_IN_U8_P(&rnd), sizeof(struct in_addr));
303 			}
304 		}
305 		max_loops--;
306 
307 		/* Mask the random number with the netmask */
308         	for (i=0;i<sizeof(struct in_addr);i++) {
309         		SA_IN_U8_P(&rnd)[i] &= ~(SA_IN_U8_P(&mask)[i]);
310 		}
311 
312 		/* Now add the IP to the masked random number */
313         	for (i=0;i<sizeof(struct in_addr);i++)
314         		SA_IN_U8_P(&rnd)[i] |= (SA_IN_U8_P(&network)[i]);
315 
316 		/* check if it exists in the hash table */
317 		if (is_ipv4_ok(s, &rnd, &network, &mask) == 0) {
318 			mslog(s, proc, LOG_DEBUG, "cannot assign remote IP %s; it is in use or invalid",
319 			      human_addr((void*)&rnd, sizeof(struct sockaddr_in), buf, sizeof(buf)));
320 			continue;
321 		}
322 
323 		memcpy(&proc->ipv4->rip, &rnd, sizeof(struct sockaddr_in));
324        		proc->ipv4->rip_len = sizeof(struct sockaddr_in);
325 
326 		memcpy(&proc->ipv4->sig, &rnd, sizeof(struct sockaddr_in));
327 
328        		/* LIP = network address + 1 */
329 		memcpy(&proc->ipv4->lip, &network, sizeof(struct sockaddr_in));
330 		proc->ipv4->lip_len = sizeof(struct sockaddr_in);
331 		SA_IN_U8_P(&proc->ipv4->lip)[3] |= 1;
332 
333 		if (memcmp(SA_IN_U8_P(&proc->ipv4->lip), SA_IN_U8_P(&proc->ipv4->rip), sizeof(struct in_addr)) == 0) {
334 			continue;
335 		}
336 
337 		mslog(s, proc, LOG_DEBUG, "selected IP: %s",
338 		      human_addr((void*)&proc->ipv4->rip, proc->ipv4->rip_len, buf, sizeof(buf)));
339 
340        		if (icmp_ping4(s, (void*)&proc->ipv4->rip) == 0)
341        			break;
342 	} while(1);
343 
344 	return 0;
345 
346 fail:
347 	talloc_free(proc->ipv4);
348 	proc->ipv4 = NULL;
349 
350 	return ret;
351 }
352 
353 static
get_ipv6_lease(main_server_st * s,struct proc_st * proc)354 int get_ipv6_lease(main_server_st* s, struct proc_st* proc)
355 {
356 
357 	struct sockaddr_storage tmp, mask, network, rnd, subnet_mask;
358 	unsigned i, max_loops = MAX_IP_TRIES;
359 	const char* c_network = NULL;
360 	unsigned prefix, subnet_prefix ;
361 	int ret;
362 	char buf[64];
363 
364 	if (proc->config->ipv6_net && proc->config->ipv6_subnet_prefix) {
365 		c_network = proc->config->ipv6_net;
366 		prefix = proc->config->ipv6_prefix;
367 		subnet_prefix = proc->config->ipv6_subnet_prefix;
368 	} else {
369 		c_network = proc->vhost->perm_config.config->network.ipv6;
370 		prefix = proc->vhost->perm_config.config->network.ipv6_prefix;
371 		subnet_prefix = proc->vhost->perm_config.config->network.ipv6_subnet_prefix;
372 	}
373 
374 	if (c_network == NULL || prefix == 0 || subnet_prefix == 0) {
375 		return 0;
376 	}
377 
378 	ret = ipv6_prefix_to_mask(SA_IN6_P(&mask), prefix);
379 	if (ret == 0) {
380 		mslog(s, NULL, LOG_ERR, "error reading prefix: %u", prefix);
381 		return -1;
382 	}
383 
384 	ret = ipv6_prefix_to_mask(SA_IN6_P(&subnet_mask), subnet_prefix);
385 	if (ret == 0) {
386 		mslog(s, NULL, LOG_ERR, "error reading prefix: %u", subnet_prefix);
387 		return -1;
388 	}
389 
390 	ret =
391 	    inet_pton(AF_INET6, c_network, SA_IN6_P(&network));
392 	if (ret != 1) {
393 		mslog(s, NULL, LOG_ERR, "error reading IP: %s", c_network);
394 		return -1;
395 	}
396 
397 	/* mask the network */
398 	((struct sockaddr_in6*)&network)->sin6_family = AF_INET6;
399 	((struct sockaddr_in6*)&network)->sin6_port = 0;
400 	for (i=0;i<sizeof(struct in6_addr);i++)
401 		SA_IN6_U8_P(&network)[i] &= (SA_IN6_U8_P(&mask)[i]);
402 
403 
404 	if (proc->config->explicit_ipv6) {
405 		memset(&tmp, 0, sizeof(tmp));
406 		ret =
407 		    inet_pton(AF_INET6, proc->config->explicit_ipv6, SA_IN6_P(&tmp));
408 
409 		if (ret != 1) {
410 			mslog(s, NULL, LOG_ERR, "error reading explicit IP %s", proc->config->explicit_ipv6);
411 			return -1;
412 		}
413 
414 		proc->ipv6 = talloc_zero(proc, struct ip_lease_st);
415 		if (proc->ipv6 == NULL)
416 			return ERR_MEM;
417 
418         	((struct sockaddr_in6*)&tmp)->sin6_family = AF_INET6;
419 		memcpy(&proc->ipv6->rip, &tmp, sizeof(struct sockaddr_in6));
420        		proc->ipv6->rip_len = sizeof(struct sockaddr_in6);
421 
422        		/* create our sig */
423 		for (i=0;i<sizeof(struct in6_addr);i++)
424 			SA_IN6_U8_P(&proc->ipv6->sig)[i] = SA_IN6_U8_P(&proc->ipv6->rip)[i] & SA_IN6_U8_P(&subnet_mask)[i];
425 
426 		if (is_ipv6_ok(s, &tmp, &network, &proc->ipv6->sig) == 0) {
427 			mslog(s, proc, LOG_DEBUG, "cannot assign explicit IP %s; it is in use or invalid",
428 			      human_addr((void*)&tmp, sizeof(struct sockaddr_in6), buf, sizeof(buf)));
429 			ret = ERR_NO_IP;
430 			goto fail;
431 		}
432 
433 		goto finish;
434 	}
435 
436 	/* assign "random" IP */
437 	proc->ipv6 = talloc_zero(proc, struct ip_lease_st);
438 	if (proc->ipv6 == NULL)
439 		return ERR_MEM;
440 	proc->ipv6->db = &s->ip_leases;
441 
442   	memcpy(&tmp, &network, sizeof(tmp));
443        	((struct sockaddr_in6*)&tmp)->sin6_family = AF_INET6;
444        	((struct sockaddr_in6*)&tmp)->sin6_port = 0;
445 
446 	do {
447 		if (max_loops == 0) {
448 			mslog(s, NULL, LOG_ERR, "could not figure out a valid IPv6 IP");
449 			ret = ERR_NO_IP;
450 			goto fail;
451 		}
452 
453 		memset(&rnd, 0, sizeof(rnd));
454 	       	((struct sockaddr_in6*)&rnd)->sin6_family = AF_INET6;
455 
456 		if (max_loops == MAX_IP_TRIES) {
457 			ip_from_seed(proc->ipv4_seed, 4,
458 				     SA_IN6_U8_P(&rnd), sizeof(struct in6_addr));
459 		} else {
460 			if (max_loops < MAX_IP_TRIES-FIXED_IPS) {
461 				ret = gnutls_rnd(GNUTLS_RND_NONCE, SA_IN_U8_P(&rnd), sizeof(struct in6_addr));
462 				if (ret < 0) {
463 					mslog(s, proc, LOG_ERR, "error in the random generator: %s", gnutls_strerror(ret));
464 					ret = ERR_NO_IP;
465 					goto fail;
466 				}
467 			} else {
468 				ip_from_seed(SA_IN6_U8_P(&rnd), sizeof(struct in6_addr),
469 					     SA_IN6_U8_P(&rnd), sizeof(struct in6_addr));
470 			}
471 		}
472 		max_loops--;
473 
474 		/* Mask the random number with the netmask */
475        		for (i=0;i<sizeof(struct in6_addr);i++)
476        			SA_IN6_U8_P(&rnd)[i] &= ~(SA_IN6_U8_P(&mask)[i]);
477 
478 		/* Now add the network to the masked random number */
479        		for (i=0;i<sizeof(struct in6_addr);i++)
480        			SA_IN6_U8_P(&rnd)[i] |= (SA_IN6_U8_P(&network)[i]);
481 
482 		/* make the sig of our subnet */
483 	       	((struct sockaddr_in6*)&proc->ipv6->sig)->sin6_family = AF_INET6;
484 	       	((struct sockaddr_in6*)&proc->ipv6->sig)->sin6_port = 0;
485 		for (i=0;i<sizeof(struct in6_addr);i++) {
486 			SA_IN6_U8_P(&proc->ipv6->sig)[i] = SA_IN6_U8_P(&rnd)[i] & SA_IN6_U8_P(&subnet_mask)[i];
487 		}
488 
489 		/* check if it exists in the hash table */
490 		if (is_ipv6_ok(s, &rnd, &network, &proc->ipv6->sig) == 0) {
491 			mslog(s, proc, LOG_DEBUG, "cannot assign local IP %s; it is in use or invalid",
492 			      human_addr((void*)&rnd, sizeof(struct sockaddr_in6), buf, sizeof(buf)));
493 			continue;
494 		}
495 
496        		proc->ipv6->rip_len = sizeof(struct sockaddr_in6);
497        		memcpy(&proc->ipv6->rip, &rnd, proc->ipv6->rip_len);
498 
499 		mslog(s, proc, LOG_DEBUG, "selected IP: %s",
500 		      human_addr((void*)&proc->ipv6->rip, proc->ipv6->rip_len, buf, sizeof(buf)));
501 
502         	if (proc->ipv6->prefix != 128 || icmp_ping6(s, (void*)&proc->ipv6->rip) == 0)
503         		break;
504         } while(1);
505 
506  finish:
507 	/* LIP = network address + 1 */
508 	memcpy(&proc->ipv6->lip, &network, sizeof(struct sockaddr_in6));
509 	SA_IN6_U8_P(&proc->ipv6->lip)[15] |= 1;
510 
511 	proc->ipv6->lip_len = sizeof(struct sockaddr_in6);
512 
513 	proc->ipv6->prefix = subnet_prefix;
514 
515 	return 0;
516 fail:
517 	talloc_free(proc->ipv6);
518 	proc->ipv6 = NULL;
519 
520 	return ret;
521 
522 }
523 
524 static
unref_ip_lease(struct ip_lease_st * lease)525 int unref_ip_lease(struct ip_lease_st *lease)
526 {
527 	if (lease->db) {
528 		htable_del(&lease->db->ht, rehash(lease, NULL), lease);
529 	}
530 
531 	return 0;
532 }
533 
get_ip_leases(main_server_st * s,struct proc_st * proc)534 int get_ip_leases(main_server_st *s, struct proc_st *proc)
535 {
536 int ret;
537 char buf[128];
538 
539 	if (proc->ipv4 == NULL) {
540 		ret = get_ipv4_lease(s, proc);
541 		if (ret < 0)
542 			return ret;
543 
544 		if (proc->ipv4 && proc->ipv4->db) {
545 			if (htable_add(&s->ip_leases.ht, rehash(proc->ipv4, NULL), proc->ipv4) == 0) {
546 				mslog(s, proc, LOG_ERR, "could not add IPv4 lease to hash table");
547 				return -1;
548 			}
549 			talloc_set_destructor(proc->ipv4, unref_ip_lease);
550 		}
551 	}
552 
553 	if (proc->ipv6 == NULL) {
554 		ret = get_ipv6_lease(s, proc);
555 		if (ret < 0)
556 			return ret;
557 
558 		if (proc->ipv6 && proc->ipv6->db) {
559 			if (htable_add(&s->ip_leases.ht, rehash(proc->ipv6, NULL), proc->ipv6) == 0) {
560 				mslog(s, proc, LOG_ERR, "could not add IPv6 lease to hash table");
561 				return -1;
562 			}
563 			talloc_set_destructor(proc->ipv6, unref_ip_lease);
564 		}
565 	}
566 
567 	if (proc->ipv4 == 0 && proc->ipv6 == 0) {
568 		mslog(s, proc, LOG_ERR, "no IPv4 or IPv6 addresses are configured. Cannot obtain lease");
569 		return -1;
570 	}
571 
572 	if (proc->ipv4)
573 		mslog(s, proc, LOG_DEBUG, "assigned IPv4: %s",
574 			human_addr((void*)&proc->ipv4->rip, proc->ipv4->rip_len, buf, sizeof(buf)));
575 
576 	if (proc->ipv6)
577 		mslog(s, proc, LOG_DEBUG, "assigned IPv6: %s/%u",
578 			human_addr((void*)&proc->ipv6->rip, proc->ipv6->rip_len, buf, sizeof(buf)),
579 			proc->ipv6->prefix);
580 
581 	return 0;
582 }
583 
remove_ip_leases(main_server_st * s,struct proc_st * proc)584 void remove_ip_leases(main_server_st* s, struct proc_st* proc)
585 {
586 	if (proc->ipv4) {
587 		talloc_free(proc->ipv4);
588 		proc->ipv4 = NULL;
589 	}
590 	if (proc->ipv6) {
591 		talloc_free(proc->ipv6);
592 		proc->ipv6 = NULL;
593 	}
594 }
595 
remove_ip_lease(main_server_st * s,struct ip_lease_st * lease)596 void remove_ip_lease(main_server_st* s, struct ip_lease_st * lease)
597 {
598 	talloc_free(lease);
599 }
600