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