1 /* $OpenBSD: npppd_pool.c,v 1.11 2022/08/29 02:58:13 jsg Exp $ */
2
3 /*-
4 * Copyright (c) 2009 Internet Initiative Japan Inc.
5 * All rights reserved.
6 *
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
9 * are met:
10 * 1. Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in the
14 * documentation and/or other materials provided with the distribution.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
17 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
20 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
21 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
22 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
23 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
24 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
25 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
26 * SUCH DAMAGE.
27 */
28 /**@file */
29 #include <sys/types.h>
30 #include <sys/socket.h>
31 #include <netinet/in.h>
32 #include <net/route.h>
33 #include <netinet/ip.h>
34 #include <arpa/inet.h>
35 #include <net/if_dl.h>
36 #include <stdio.h>
37 #include <time.h>
38 #include <event.h>
39 #include <string.h>
40 #include <errno.h>
41 #include <unistd.h>
42 #include <syslog.h>
43 #include <stdlib.h>
44 #include <stdarg.h>
45 #include <netdb.h>
46
47 #include "slist.h"
48 #include "debugutil.h"
49 #include "addr_range.h"
50 #include "radish.h"
51 #include "npppd_local.h"
52 #include "npppd_pool.h"
53 #include "npppd_subr.h"
54 #include "net_utils.h"
55
56 #ifdef NPPPD_POOL_DEBUG
57 #define NPPPD_POOL_DBG(x) npppd_pool_log x
58 #define NPPPD_POOL_ASSERT(cond) \
59 if (!(cond)) { \
60 fprintf(stderr, \
61 "\nASSERT(" #cond ") failed on %s() at %s:%d.\n"\
62 , __func__, __FILE__, __LINE__); \
63 abort(); \
64 }
65 #else
66 #define NPPPD_POOL_ASSERT(cond)
67 #define NPPPD_POOL_DBG(x)
68 #endif
69 #define A(v) ((0xff000000 & (v)) >> 24), ((0x00ff0000 & (v)) >> 16), \
70 ((0x0000ff00 & (v)) >> 8), (0x000000ff & (v))
71 #define SA(sin4) ((struct sockaddr *)(sin4))
72
73 #define SHUFLLE_MARK 0xffffffffL
74 static int npppd_pool_log(npppd_pool *, int, const char *, ...) __printflike(3, 4);
75 static int is_valid_host_address (uint32_t);
76 static int npppd_pool_regist_radish(npppd_pool *, struct in_addr_range *,
77 struct sockaddr_npppd *, int );
78
79
80 /***********************************************************************
81 * npppd_pool object management
82 ***********************************************************************/
83 /** Initialize npppd_poll. */
84 int
npppd_pool_init(npppd_pool * _this,npppd * base,const char * name)85 npppd_pool_init(npppd_pool *_this, npppd *base, const char *name)
86 {
87 memset(_this, 0, sizeof(npppd_pool));
88
89 strlcpy(_this->ipcp_name, name, sizeof(_this->ipcp_name));
90 _this->npppd = base;
91 slist_init(&_this->dyna_addrs);
92
93 _this->initialized = 1;
94
95 return 0;
96 }
97
98 /** Start to use npppd_pool. */
99 int
npppd_pool_start(npppd_pool * _this)100 npppd_pool_start(npppd_pool *_this)
101 {
102 return 0; /* nothing to do */
103 }
104
105 /** Finalize npppd_poll. */
106 void
npppd_pool_uninit(npppd_pool * _this)107 npppd_pool_uninit(npppd_pool *_this)
108 {
109 _this->initialized = 0;
110
111 slist_fini(&_this->dyna_addrs);
112 free(_this->addrs);
113 _this->addrs = NULL;
114 _this->addrs_size = 0;
115 _this->npppd = NULL;
116 }
117
118 /** Reload configuration. */
119 int
npppd_pool_reload(npppd_pool * _this)120 npppd_pool_reload(npppd_pool *_this)
121 {
122 int i, count, addrs_size;
123 struct sockaddr_npppd *addrs;
124 struct in_addr_range *pool, *dyna_pool, *range;
125 char buf0[BUFSIZ], buf1[BUFSIZ];
126 struct ipcpconf *ipcp;
127
128 addrs = NULL;
129 pool = NULL;
130 dyna_pool = NULL;
131 buf0[0] = '\0';
132
133 TAILQ_FOREACH(ipcp, &_this->npppd->conf.ipcpconfs, entry) {
134 if (strcmp(ipcp->name, _this->ipcp_name) == 0) {
135 dyna_pool = ipcp->dynamic_pool;
136 pool = ipcp->static_pool;
137 }
138 }
139
140 addrs_size = 0;
141 for (range = dyna_pool; range != NULL; range = range->next)
142 addrs_size++;
143 for (range = pool; range != NULL; range = range->next)
144 addrs_size++;
145
146 if ((addrs = calloc(addrs_size + 1, sizeof(struct sockaddr_npppd)))
147 == NULL) {
148 /* addr_size + 1 because of avoiding calloc(0). */
149 npppd_pool_log(_this, LOG_WARNING,
150 "calloc() failed in %s: %m", __func__);
151 goto fail;
152 }
153
154 /* Register dynamic pool address with RADISH. */
155 count = 0;
156 for (i = 0, range = dyna_pool; range != NULL; range = range->next, i++){
157 if (npppd_pool_regist_radish(_this, range, &addrs[count], 1))
158 goto fail;
159 if (count == 0)
160 strlcat(buf0, "dyn_pool=[", sizeof(buf0));
161 else
162 strlcat(buf0, ",", sizeof(buf0));
163 snprintf(buf1, sizeof(buf1), "%d.%d.%d.%d/%d",
164 A(range->addr), netmask2prefixlen(range->mask));
165 strlcat(buf0, buf1, sizeof(buf0));
166 count++;
167 }
168 if (i > 0)
169 strlcat(buf0, "] ", sizeof(buf0));
170
171 /* Register static pool address with RADISH. */
172 for (i = 0, range = pool; range != NULL; range = range->next, i++) {
173 if (npppd_pool_regist_radish(_this, range, &addrs[count], 0))
174 goto fail;
175 if (i == 0)
176 strlcat(buf0, "pool=[", sizeof(buf0));
177 else
178 strlcat(buf0, ",", sizeof(buf0));
179 snprintf(buf1, sizeof(buf1), "%d.%d.%d.%d/%d",
180 A(range->addr), netmask2prefixlen(range->mask));
181 strlcat(buf0, buf1, sizeof(buf0));
182 count++;
183 }
184 if (i > 0)
185 strlcat(buf0, "]", sizeof(buf0));
186
187 npppd_pool_log(_this, LOG_INFO, "%s", buf0);
188
189 count = 0;
190 slist_add(&_this->dyna_addrs, (void *)SHUFLLE_MARK);
191 for (range = dyna_pool; range != NULL; range = range->next) {
192 if (count >= NPPPD_MAX_POOLED_ADDRS)
193 break;
194 for (i = 0; i <= ~(range->mask); i++) {
195 if (!is_valid_host_address(range->addr + i))
196 continue;
197 if (count >= NPPPD_MAX_POOLED_ADDRS)
198 break;
199 slist_add(&_this->dyna_addrs,
200 (void *)(uintptr_t)(range->addr + i));
201 count++;
202 }
203 }
204 free(_this->addrs);
205 _this->addrs = addrs;
206 _this->addrs_size = addrs_size;
207
208 return 0;
209 fail:
210 free(addrs);
211
212 return 1;
213 }
214
215 static int
npppd_pool_regist_radish(npppd_pool * _this,struct in_addr_range * range,struct sockaddr_npppd * snp,int is_dynamic)216 npppd_pool_regist_radish(npppd_pool *_this, struct in_addr_range *range,
217 struct sockaddr_npppd *snp, int is_dynamic)
218 {
219 int rval;
220 struct sockaddr_in sin4a, sin4b;
221 struct sockaddr_npppd *snp0;
222 npppd_pool *npool0;
223
224 memset(&sin4a, 0, sizeof(sin4a));
225 memset(&sin4b, 0, sizeof(sin4b));
226 sin4a.sin_len = sin4b.sin_len = sizeof(sin4a);
227 sin4a.sin_family = sin4b.sin_family = AF_INET;
228 sin4a.sin_addr.s_addr = htonl(range->addr);
229 sin4b.sin_addr.s_addr = htonl(range->mask);
230
231 snp->snp_len = sizeof(struct sockaddr_npppd);
232 snp->snp_family = AF_INET;
233 snp->snp_addr.s_addr = htonl(range->addr);
234 snp->snp_mask.s_addr = htonl(range->mask);
235 snp->snp_data_ptr = _this;
236 if (is_dynamic)
237 snp->snp_type = SNP_DYN_POOL;
238 else
239 snp->snp_type = SNP_POOL;
240
241 if ((snp0 = rd_lookup(SA(&sin4a), SA(&sin4b),
242 _this->npppd->rd)) != NULL) {
243 /*
244 * Immediately after the radish tree is initialized,
245 * assuming that it has only POOL entry.
246 */
247 NPPPD_POOL_ASSERT(snp0->snp_type != SNP_PPP);
248 npool0 = snp0->snp_data_ptr;
249
250 if (!is_dynamic && npool0 == _this)
251 /* Already registered as dynamic pool address. */
252 return 0;
253
254 npppd_pool_log(_this, LOG_WARNING,
255 "%d.%d.%d.%d/%d is already defined as '%s'(%s)",
256 A(range->addr), netmask2prefixlen(range->mask),
257 npool0->ipcp_name, (snp0->snp_type == SNP_POOL)
258 ? "static" : "dynamic");
259 goto fail;
260 }
261 if ((rval = rd_insert(SA(&sin4a), SA(&sin4b), _this->npppd->rd,
262 snp)) != 0) {
263 errno = rval;
264 npppd_pool_log(_this, LOG_WARNING,
265 "rd_insert(%d.%d.%d.%d/%d) failed: %m",
266 A(range->addr), netmask2prefixlen(range->mask));
267 goto fail;
268 }
269
270 return 0;
271 fail:
272 return 1;
273
274 }
275
276 /***********************************************************************
277 * API
278 ***********************************************************************/
279 /** Assign dynamic pool address. */
280 uint32_t
npppd_pool_get_dynamic(npppd_pool * _this,npppd_ppp * ppp)281 npppd_pool_get_dynamic(npppd_pool *_this, npppd_ppp *ppp)
282 {
283 int shuffle_cnt;
284 uintptr_t result = 0;
285 struct sockaddr_npppd *snp;
286 npppd_ppp *ppp0;
287
288 shuffle_cnt = 0;
289 slist_itr_first(&_this->dyna_addrs);
290 while (slist_length(&_this->dyna_addrs) > 1 &&
291 slist_itr_has_next(&_this->dyna_addrs)) {
292 result = (uintptr_t)slist_itr_next(&_this->dyna_addrs);
293 if (result == 0)
294 break;
295 /* shuffle */
296 if ((uint32_t)result == SHUFLLE_MARK) {
297 /*
298 * When the free list is empty, SHUFLLE_MARK is
299 * retrieved twice sequentially. This means there is
300 * no address to use.
301 */
302 if (shuffle_cnt++ > 0) {
303 result = 0;
304 break;
305 }
306 NPPPD_POOL_DBG((_this, LOG_DEBUG, "shuffle"));
307 slist_itr_remove(&_this->dyna_addrs);
308 slist_shuffle(&_this->dyna_addrs);
309 slist_add(&_this->dyna_addrs, (void *)result);
310 slist_itr_first(&_this->dyna_addrs);
311 continue;
312 }
313 slist_itr_remove(&_this->dyna_addrs);
314
315 switch (npppd_pool_get_assignability(_this, (uint32_t)result,
316 0xffffffffL, &snp)) {
317 case ADDRESS_OK:
318 /* only succeed here */
319 return (uint32_t)result;
320 default:
321 /*
322 * Used as a interface address
323 */
324 continue;
325 case ADDRESS_BUSY:
326 /*
327 * Used by the previous configuration.
328 */
329 NPPPD_POOL_ASSERT(snp != NULL);
330 NPPPD_POOL_ASSERT(snp->snp_type == SNP_PPP);
331 ppp0 = snp->snp_data_ptr;
332 ppp0->assigned_pool = _this;
333 ppp0->assign_dynapool = 1; /* need to return */
334 continue;
335 }
336 break;
337 }
338 return (uint32_t)0;
339 }
340
341 static inline int
npppd_is_ifcace_ip4addr(npppd * _this,uint32_t ip4addr)342 npppd_is_ifcace_ip4addr(npppd *_this, uint32_t ip4addr)
343 {
344 int i;
345
346 for (i = 0; i < countof(_this->iface); i++) {
347 if (npppd_iface_ip_is_ready(&_this->iface[i]) &&
348 _this->iface[i].ip4addr.s_addr == ip4addr)
349 return 1;
350 }
351
352 return 0;
353 }
354
355 /** Assign IP address. */
356 int
npppd_pool_assign_ip(npppd_pool * _this,npppd_ppp * ppp)357 npppd_pool_assign_ip(npppd_pool *_this, npppd_ppp *ppp)
358 {
359 int rval;
360 uint32_t ip4;
361 void *rtent;
362 struct sockaddr_in addr = {
363 .sin_family = AF_INET,
364 .sin_len = sizeof(struct sockaddr_in)
365 }, mask = {
366 .sin_family = AF_INET,
367 .sin_len = sizeof(struct sockaddr_in),
368 };
369 struct sockaddr_npppd *snp;
370
371 ip4 = ntohl(ppp->ppp_framed_ip_address.s_addr);
372
373 /* If the address contains dynamic pool address list, delete it. */
374 slist_itr_first(&_this->dyna_addrs);
375 while (slist_itr_has_next(&_this->dyna_addrs)) {
376 if ((uintptr_t)slist_itr_next(&_this->dyna_addrs) != ip4)
377 continue;
378 slist_itr_remove(&_this->dyna_addrs);
379 break;
380 }
381
382 addr.sin_addr = ppp->ppp_framed_ip_address;
383 mask.sin_addr = ppp->ppp_framed_ip_netmask;
384 addr.sin_addr.s_addr &= mask.sin_addr.s_addr;
385
386 if (rd_delete(SA(&addr), SA(&mask), _this->npppd->rd, &rtent) == 0) {
387 snp = rtent;
388 /* It has duplicate address entry. change from pool to PPP. */
389 NPPPD_POOL_ASSERT(snp != NULL);
390 NPPPD_POOL_ASSERT(snp->snp_type != SNP_PPP);
391 ppp->snp.snp_next = snp;
392 NPPPD_POOL_DBG((_this, DEBUG_LEVEL_2,
393 "pool %s/32 => %s(ppp=%d)",
394 inet_ntoa(ppp->ppp_framed_ip_address), ppp->username,
395 ppp->id));
396 }
397 NPPPD_POOL_DBG((_this, LOG_DEBUG, "rd_insert(%s) %s",
398 inet_ntoa(addr.sin_addr), ppp->username));
399 if ((rval = rd_insert((struct sockaddr *)&addr,
400 (struct sockaddr *)&mask, _this->npppd->rd, &ppp->snp)) != 0) {
401 errno = rval;
402 log_printf(LOG_INFO, "rd_insert(%s) failed: %m",
403 inet_ntoa(ppp->ppp_framed_ip_address));
404 return 1;
405 }
406
407 return 0;
408 }
409
410 /** Release IP address. */
411 void
npppd_pool_release_ip(npppd_pool * _this,npppd_ppp * ppp)412 npppd_pool_release_ip(npppd_pool *_this, npppd_ppp *ppp)
413 {
414 void *item;
415 int rval;
416 struct sockaddr_npppd *snp;
417 struct sockaddr_in addr = {
418 .sin_family = AF_INET,
419 .sin_len = sizeof(struct sockaddr_in)
420 }, mask = {
421 .sin_family = AF_INET,
422 .sin_len = sizeof(struct sockaddr_in),
423 };
424
425 /*
426 * `_this' may be NULL. It was gone because of a configuration change.
427 */
428 if (!ppp_ip_assigned(ppp))
429 return;
430
431 addr.sin_addr = ppp->ppp_framed_ip_address;
432 mask.sin_addr = ppp->ppp_framed_ip_netmask;
433 addr.sin_addr.s_addr &= mask.sin_addr.s_addr;
434
435 if ((rval = rd_delete((struct sockaddr *)&addr,
436 (struct sockaddr *)&mask, ppp->pppd->rd, &item)) != 0) {
437 errno = rval;
438 log_printf(LOG_INFO, "Unexpected error: "
439 "rd_delete(%s) failed: %m",
440 inet_ntoa(ppp->ppp_framed_ip_address));
441 }
442 snp = item;
443
444 if (_this != NULL && ppp->assign_dynapool != 0) {
445 NPPPD_POOL_ASSERT(_this == ppp->assigned_pool);
446 /* return to dynamic address pool list */
447 slist_add(&((npppd_pool *)ppp->assigned_pool)->dyna_addrs,
448 (void *)(uintptr_t)ntohl(
449 ppp->ppp_framed_ip_address.s_addr));
450 }
451
452 if (snp != NULL && snp->snp_next != NULL) {
453 /*
454 * The radish entry is registered as a list. Insert the next
455 * of the list to the radish tree.
456 */
457 if (rd_insert(SA(&addr), SA(&mask), ppp->pppd->rd,
458 snp->snp_next) != 0) {
459 log_printf(LOG_INFO, "Unexpected error: "
460 "rd_insert(%s) failed: %m",
461 inet_ntoa(ppp->ppp_framed_ip_address));
462 }
463 NPPPD_POOL_DBG((_this, DEBUG_LEVEL_2,
464 "pool %s/%d <= %s(ppp=%d)",
465 inet_ntoa(ppp->ppp_framed_ip_address),
466 netmask2prefixlen(ntohl(ppp->ppp_framed_ip_netmask.s_addr)),
467 ppp->username, ppp->id));
468 snp->snp_next = NULL;
469 }
470 }
471
472 /**
473 * Check if specified address is assignable.
474 * @return {@link ::#ADDRESS_OK} or {@link ::#ADDRESS_RESERVED} or
475 * {@link ::#ADDRESS_BUSY} or {@link ::#ADDRESS_INVALID} or
476 * {@link ::#ADDRESS_OUT_OF_POOL}
477 */
478 int
npppd_pool_get_assignability(npppd_pool * _this,uint32_t ip4addr,uint32_t ip4mask,struct sockaddr_npppd ** psnp)479 npppd_pool_get_assignability(npppd_pool *_this, uint32_t ip4addr,
480 uint32_t ip4mask, struct sockaddr_npppd **psnp)
481 {
482 struct radish *radish;
483 struct sockaddr_in sin4;
484 struct sockaddr_npppd *snp;
485
486 NPPPD_POOL_ASSERT(ip4mask != 0);
487 NPPPD_POOL_DBG((_this, LOG_DEBUG, "%s(%08x,%08x)", __func__, ip4addr,
488 ip4mask));
489
490 if (netmask2prefixlen(htonl(ip4mask)) == 32) {
491 if (!is_valid_host_address(ip4addr))
492 return ADDRESS_INVALID;
493 }
494
495 memset(&sin4, 0, sizeof(sin4));
496
497 sin4.sin_len = sizeof(sin4);
498 sin4.sin_family = AF_INET;
499 sin4.sin_addr.s_addr = htonl(ip4addr);
500
501 if (npppd_is_ifcace_ip4addr(_this->npppd, sin4.sin_addr.s_addr))
502 return ADDRESS_RESERVED;
503 /* Not to assign interface address */
504
505 if (rd_match(SA(&sin4), _this->npppd->rd, &radish)) {
506 do {
507 snp = radish->rd_rtent;
508 if (snp->snp_type == SNP_POOL ||
509 snp->snp_type == SNP_DYN_POOL) {
510 if (psnp != NULL)
511 *psnp = snp;
512 if (snp->snp_data_ptr == _this)
513 return ADDRESS_OK;
514 else
515 return ADDRESS_RESERVED;
516 }
517 if (snp->snp_type == SNP_PPP) {
518 if (psnp != NULL)
519 *psnp = snp;
520 return ADDRESS_BUSY;
521 }
522 } while (rd_match_next(SA(&sin4), _this->npppd->rd, &radish,
523 radish));
524 }
525
526 return ADDRESS_OUT_OF_POOL;
527 }
528 /***********************************************************************
529 * miscellaneous functions
530 ***********************************************************************/
531 /**
532 * Check if valid host address.
533 * <pre>
534 * There are some issues that it uses host address as broadcast address
535 * in natural mask, so it is not correct.
536 * The issue is as follows:
537 * (1) BSDs treat the following packet as it is not forwarded and
538 * is received as the packet to myself.
539 * (2) The issue that Windows can't use L2TP/IPsec when Windows is assigned
540 * IP address .255.</pre>
541 */
542 static int
is_valid_host_address(uint32_t addr)543 is_valid_host_address(uint32_t addr)
544 {
545 if (IN_CLASSA(addr))
546 return ((IN_CLASSA_HOST & addr) == 0 ||
547 (IN_CLASSA_HOST & addr) == IN_CLASSA_HOST)? 0 : 1;
548 if (IN_CLASSB(addr))
549 return ((IN_CLASSB_HOST & addr) == 0 ||
550 (IN_CLASSB_HOST & addr) == IN_CLASSB_HOST)? 0 : 1;
551 if (IN_CLASSC(addr))
552 return ((IN_CLASSC_HOST & addr) == 0 ||
553 (IN_CLASSC_HOST & addr) == IN_CLASSC_HOST)? 0 : 1;
554
555 return 0;
556 }
557
558 /** Record log that begins the label based this instance. */
559 static int
npppd_pool_log(npppd_pool * _this,int prio,const char * fmt,...)560 npppd_pool_log(npppd_pool *_this, int prio, const char *fmt, ...)
561 {
562 int status;
563 char logbuf[BUFSIZ];
564 va_list ap;
565
566 /*
567 * npppd_pool_release_ip is called as _this == NULL,
568 * so it can't NPPPD_POOL_ASSERT(_this != NULL).
569 */
570 va_start(ap, fmt);
571 snprintf(logbuf, sizeof(logbuf), "ipcp=%s pool %s",
572 (_this == NULL)? "null" : _this->ipcp_name, fmt);
573 status = vlog_printf(prio, logbuf, ap);
574 va_end(ap);
575
576 return status;
577 }
578