1 /* $OpenBSD: npppd_pool.c,v 1.7 2012/09/18 13:14:08 yasuoka Exp $ */
4 * Copyright (c) 2009 Internet Initiative Japan Inc.
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
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.
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
29 #include <sys/types.h>
30 #include <sys/socket.h>
31 #include <netinet/in.h>
32 #include <netinet/in_systm.h>
33 #include <net/route.h>
34 #include <netinet/ip.h>
35 #include <arpa/inet.h>
36 #include <net/if_dl.h>
49 #include "debugutil.h"
50 #include "addr_range.h"
52 #include "npppd_local.h"
53 #include "npppd_pool.h"
54 #include "npppd_subr.h"
55 #include "net_utils.h"
57 #ifdef NPPPD_POOL_DEBUG
58 #define NPPPD_POOL_DBG(x) npppd_pool_log x
59 #define NPPPD_POOL_ASSERT(cond) \
62 "\nASSERT(" #cond ") failed on %s() at %s:%d.\n"\
63 , __func__, __FILE__, __LINE__); \
67 #define NPPPD_POOL_ASSERT(cond)
68 #define NPPPD_POOL_DBG(x)
70 #define A(v) ((0xff000000 & (v)) >> 24), ((0x00ff0000 & (v)) >> 16), \
71 ((0x0000ff00 & (v)) >> 8), (0x000000ff & (v))
72 #define SA(sin4) ((struct sockaddr *)(sin4))
74 #define SHUFLLE_MARK 0xffffffffL
75 static int npppd_pool_log
__P((npppd_pool
*, int, const char *, ...)) __printflike(3, 4);
76 static int is_valid_host_address (uint32_t);
77 static int npppd_pool_regist_radish(npppd_pool
*, struct in_addr_range
*,
78 struct sockaddr_npppd
*, int );
81 /***********************************************************************
82 * npppd_pool object management
83 ***********************************************************************/
84 /** Initialize npppd_poll. */
86 npppd_pool_init(npppd_pool
*_this
, npppd
*base
, const char *name
)
88 memset(_this
, 0, sizeof(npppd_pool
));
90 strlcpy(_this
->ipcp_name
, name
, sizeof(_this
->ipcp_name
));
92 slist_init(&_this
->dyna_addrs
);
94 _this
->initialized
= 1;
99 /** Start to use npppd_pool. */
101 npppd_pool_start(npppd_pool
*_this
)
103 return 0; /* nothing to do */
106 /** Finalize npppd_poll. */
108 npppd_pool_uninit(npppd_pool
*_this
)
110 _this
->initialized
= 0;
112 slist_fini(&_this
->dyna_addrs
);
113 if (_this
->addrs
!= NULL
)
116 _this
->addrs_size
= 0;
120 /** Reload configuration. */
122 npppd_pool_reload(npppd_pool
*_this
)
124 int i
, count
, addrs_size
;
125 struct sockaddr_npppd
*addrs
;
126 struct in_addr_range
*pool
, *dyna_pool
, *range
;
127 char buf0
[BUFSIZ
], buf1
[BUFSIZ
];
128 struct ipcpconf
*ipcp
;
135 TAILQ_FOREACH(ipcp
, &_this
->npppd
->conf
.ipcpconfs
, entry
) {
136 if (strcmp(ipcp
->name
, _this
->ipcp_name
) == 0) {
137 dyna_pool
= ipcp
->dynamic_pool
;
138 pool
= ipcp
->static_pool
;
143 for (range
= dyna_pool
; range
!= NULL
; range
= range
->next
)
145 for (range
= pool
; range
!= NULL
; range
= range
->next
)
148 if ((addrs
= calloc(addrs_size
+ 1, sizeof(struct sockaddr_npppd
)))
150 /* addr_size + 1 because of avoiding calloc(0). */
151 npppd_pool_log(_this
, LOG_WARNING
,
152 "calloc() failed in %s: %m", __func__
);
156 /* Register dynamic pool address with RADISH. */
158 for (i
= 0, range
= dyna_pool
; range
!= NULL
; range
= range
->next
, i
++){
159 if (npppd_pool_regist_radish(_this
, range
, &addrs
[count
], 1))
162 strlcat(buf0
, "dyn_pool=[", sizeof(buf0
));
164 strlcat(buf0
, ",", sizeof(buf0
));
165 snprintf(buf1
, sizeof(buf1
), "%d.%d.%d.%d/%d",
166 A(range
->addr
), netmask2prefixlen(range
->mask
));
167 strlcat(buf0
, buf1
, sizeof(buf0
));
171 strlcat(buf0
, "] ", sizeof(buf0
));
173 /* Register static pool address with RADISH. */
174 for (i
= 0, range
= pool
; range
!= NULL
; range
= range
->next
, i
++) {
175 if (npppd_pool_regist_radish(_this
, range
, &addrs
[count
], 0))
178 strlcat(buf0
, "pool=[", sizeof(buf0
));
180 strlcat(buf0
, ",", sizeof(buf0
));
181 snprintf(buf1
, sizeof(buf1
), "%d.%d.%d.%d/%d",
182 A(range
->addr
), netmask2prefixlen(range
->mask
));
183 strlcat(buf0
, buf1
, sizeof(buf0
));
187 strlcat(buf0
, "]", sizeof(buf0
));
189 npppd_pool_log(_this
, LOG_INFO
, "%s", buf0
);
192 slist_add(&_this
->dyna_addrs
, (void *)SHUFLLE_MARK
);
193 for (range
= dyna_pool
; range
!= NULL
; range
= range
->next
) {
194 if (count
>= NPPPD_MAX_POOLED_ADDRS
)
196 for (i
= 0; i
<= ~(range
->mask
); i
++) {
197 if (!is_valid_host_address(range
->addr
+ i
))
199 if (count
>= NPPPD_MAX_POOLED_ADDRS
)
201 slist_add(&_this
->dyna_addrs
,
202 (void *)(uintptr_t)(range
->addr
+ i
));
206 if (_this
->addrs
!= NULL
)
208 _this
->addrs
= addrs
;
209 _this
->addrs_size
= addrs_size
;
220 npppd_pool_regist_radish(npppd_pool
*_this
, struct in_addr_range
*range
,
221 struct sockaddr_npppd
*snp
, int is_dynamic
)
224 struct sockaddr_in sin4a
, sin4b
;
225 struct sockaddr_npppd
*snp0
;
228 memset(&sin4a
, 0, sizeof(sin4a
));
229 memset(&sin4b
, 0, sizeof(sin4b
));
230 sin4a
.sin_len
= sin4b
.sin_len
= sizeof(sin4a
);
231 sin4a
.sin_family
= sin4b
.sin_family
= AF_INET
;
232 sin4a
.sin_addr
.s_addr
= htonl(range
->addr
);
233 sin4b
.sin_addr
.s_addr
= htonl(range
->mask
);
235 snp
->snp_len
= sizeof(struct sockaddr_npppd
);
236 snp
->snp_family
= AF_INET
;
237 snp
->snp_addr
.s_addr
= htonl(range
->addr
);
238 snp
->snp_mask
.s_addr
= htonl(range
->mask
);
239 snp
->snp_data_ptr
= _this
;
241 snp
->snp_type
= SNP_DYN_POOL
;
243 snp
->snp_type
= SNP_POOL
;
245 if ((snp0
= rd_lookup(SA(&sin4a
), SA(&sin4b
),
246 _this
->npppd
->rd
)) != NULL
) {
248 * Immediately after the radish tree is initialized,
249 * assuming that it has only POOL entry.
251 NPPPD_POOL_ASSERT(snp0
->snp_type
!= SNP_PPP
);
252 npool0
= snp0
->snp_data_ptr
;
254 if (!is_dynamic
&& npool0
== _this
)
255 /* Already registered as dynamic pool address. */
258 npppd_pool_log(_this
, LOG_WARNING
,
259 "%d.%d.%d.%d/%d is already defined as '%s'(%s)",
260 A(range
->addr
), netmask2prefixlen(range
->mask
),
261 npool0
->ipcp_name
, (snp0
->snp_type
== SNP_POOL
)
262 ? "static" : "dynamic");
265 if ((rval
= rd_insert(SA(&sin4a
), SA(&sin4b
), _this
->npppd
->rd
,
268 npppd_pool_log(_this
, LOG_WARNING
,
269 "rd_insert(%d.%d.%d.%d/%d) failed: %m",
270 A(range
->addr
), netmask2prefixlen(range
->mask
));
280 /***********************************************************************
282 ***********************************************************************/
283 /** Assign dynamic pool address. */
285 npppd_pool_get_dynamic(npppd_pool
*_this
, npppd_ppp
*ppp
)
288 uintptr_t result
= 0;
289 struct sockaddr_npppd
*snp
;
293 slist_itr_first(&_this
->dyna_addrs
);
294 while (slist_length(&_this
->dyna_addrs
) > 1 &&
295 slist_itr_has_next(&_this
->dyna_addrs
)) {
296 result
= (uintptr_t)slist_itr_next(&_this
->dyna_addrs
);
300 if ((uint32_t)result
== SHUFLLE_MARK
) {
302 * When the free list is empty, SHUFLLE_MARK is
303 * retrieved twice sequentially. This means there is
306 if (shuffle_cnt
++ > 0) {
310 NPPPD_POOL_DBG((_this
, LOG_DEBUG
, "shuffle"));
311 slist_itr_remove(&_this
->dyna_addrs
);
312 slist_shuffle(&_this
->dyna_addrs
);
313 slist_add(&_this
->dyna_addrs
, (void *)result
);
314 slist_itr_first(&_this
->dyna_addrs
);
317 slist_itr_remove(&_this
->dyna_addrs
);
319 switch (npppd_pool_get_assignability(_this
, (uint32_t)result
,
320 0xffffffffL
, &snp
)) {
322 /* only succeed here */
323 return (uint32_t)result
;
326 * Used as a interface address
331 * Used by the previous configuration.
333 NPPPD_POOL_ASSERT(snp
!= NULL
);
334 NPPPD_POOL_ASSERT(snp
->snp_type
== SNP_PPP
);
335 ppp0
= snp
->snp_data_ptr
;
336 ppp0
->assigned_pool
= _this
;
337 ppp0
->assign_dynapool
= 1; /* need to return */
346 npppd_is_ifcace_ip4addr(npppd
*_this
, uint32_t ip4addr
)
350 for (i
= 0; i
< countof(_this
->iface
); i
++) {
351 if (npppd_iface_ip_is_ready(&_this
->iface
[i
]) &&
352 _this
->iface
[i
].ip4addr
.s_addr
== ip4addr
)
359 /** Assign IP address. */
361 npppd_pool_assign_ip(npppd_pool
*_this
, npppd_ppp
*ppp
)
366 struct sockaddr_in addr
= {
367 .sin_family
= AF_INET
,
368 .sin_len
= sizeof(struct sockaddr_in
)
370 .sin_family
= AF_INET
,
371 .sin_len
= sizeof(struct sockaddr_in
),
373 struct sockaddr_npppd
*snp
;
375 ip4
= ntohl(ppp
->ppp_framed_ip_address
.s_addr
);
377 /* If the address contains dynamic pool address list, delete it. */
378 slist_itr_first(&_this
->dyna_addrs
);
379 while (slist_itr_has_next(&_this
->dyna_addrs
)) {
380 if ((uintptr_t)slist_itr_next(&_this
->dyna_addrs
) != ip4
)
382 slist_itr_remove(&_this
->dyna_addrs
);
386 addr
.sin_addr
= ppp
->ppp_framed_ip_address
;
387 mask
.sin_addr
= ppp
->ppp_framed_ip_netmask
;
388 addr
.sin_addr
.s_addr
&= mask
.sin_addr
.s_addr
;
390 if (rd_delete(SA(&addr
), SA(&mask
), _this
->npppd
->rd
, &rtent
) == 0) {
392 /* It has duplicate address entry. change from pool to PPP. */
393 NPPPD_POOL_ASSERT(snp
!= NULL
);
394 NPPPD_POOL_ASSERT(snp
->snp_type
!= SNP_PPP
);
395 ppp
->snp
.snp_next
= snp
;
396 NPPPD_POOL_DBG((_this
, DEBUG_LEVEL_2
,
397 "pool %s/32 => %s(ppp=%d)",
398 inet_ntoa(ppp
->ppp_framed_ip_address
), ppp
->username
,
401 NPPPD_POOL_DBG((_this
, LOG_DEBUG
, "rd_insert(%s) %s",
402 inet_ntoa(addr
.sin_addr
), ppp
->username
));
403 if ((rval
= rd_insert((struct sockaddr
*)&addr
,
404 (struct sockaddr
*)&mask
, _this
->npppd
->rd
, &ppp
->snp
)) != 0) {
406 log_printf(LOG_INFO
, "rd_insert(%s) failed: %m",
407 inet_ntoa(ppp
->ppp_framed_ip_address
));
414 /** Release IP address. */
416 npppd_pool_release_ip(npppd_pool
*_this
, npppd_ppp
*ppp
)
420 struct sockaddr_npppd
*snp
;
421 struct sockaddr_in addr
= {
422 .sin_family
= AF_INET
,
423 .sin_len
= sizeof(struct sockaddr_in
)
425 .sin_family
= AF_INET
,
426 .sin_len
= sizeof(struct sockaddr_in
),
430 * `_this' may be NULL. It was gone because of a configuration change.
432 if (!ppp_ip_assigned(ppp
))
435 addr
.sin_addr
= ppp
->ppp_framed_ip_address
;
436 mask
.sin_addr
= ppp
->ppp_framed_ip_netmask
;
437 addr
.sin_addr
.s_addr
&= mask
.sin_addr
.s_addr
;
439 if ((rval
= rd_delete((struct sockaddr
*)&addr
,
440 (struct sockaddr
*)&mask
, ppp
->pppd
->rd
, &item
)) != 0) {
442 log_printf(LOG_INFO
, "Unexpected error: "
443 "rd_delete(%s) failed: %m",
444 inet_ntoa(ppp
->ppp_framed_ip_address
));
448 if (_this
!= NULL
&& ppp
->assign_dynapool
!= 0) {
449 NPPPD_POOL_ASSERT(_this
== ppp
->assigned_pool
);
450 /* return to dynamic address pool list */
451 slist_add(&((npppd_pool
*)ppp
->assigned_pool
)->dyna_addrs
,
452 (void *)(uintptr_t)ntohl(
453 ppp
->ppp_framed_ip_address
.s_addr
));
456 if (snp
!= NULL
&& snp
->snp_next
!= NULL
) {
458 * The radish entry is registered as a list. Insert the next
459 * of the list to the radish tree.
461 if (rd_insert(SA(&addr
), SA(&mask
), ppp
->pppd
->rd
,
462 snp
->snp_next
) != 0) {
463 log_printf(LOG_INFO
, "Unexpected error: "
464 "rd_insert(%s) failed: %m",
465 inet_ntoa(ppp
->ppp_framed_ip_address
));
467 NPPPD_POOL_DBG((_this
, DEBUG_LEVEL_2
,
468 "pool %s/%d <= %s(ppp=%d)",
469 inet_ntoa(ppp
->ppp_framed_ip_address
),
470 netmask2prefixlen(ntohl(ppp
->ppp_framed_ip_netmask
.s_addr
)),
471 ppp
->username
, ppp
->id
));
472 snp
->snp_next
= NULL
;
477 * Check if specified address is assignable.
478 * @return {@link ::#ADDRESS_OK} or {@link ::#ADDRESS_RESERVED} or
479 * {@link ::#ADDRESS_BUSY} or {@link ::#ADDRESS_INVALID} or
480 * {@link ::#ADDRESS_OUT_OF_POOL}
483 npppd_pool_get_assignability(npppd_pool
*_this
, uint32_t ip4addr
,
484 uint32_t ip4mask
, struct sockaddr_npppd
**psnp
)
486 struct radish
*radish
;
487 struct sockaddr_in sin4
;
488 struct sockaddr_npppd
*snp
;
490 NPPPD_POOL_ASSERT(ip4mask
!= 0);
491 NPPPD_POOL_DBG((_this
, LOG_DEBUG
, "%s(%08x,%08x)", __func__
, ip4addr
,
494 if (netmask2prefixlen(htonl(ip4mask
)) == 32) {
495 if (!is_valid_host_address(ip4addr
))
496 return ADDRESS_INVALID
;
499 memset(&sin4
, 0, sizeof(sin4
));
501 sin4
.sin_len
= sizeof(sin4
);
502 sin4
.sin_family
= AF_INET
;
503 sin4
.sin_addr
.s_addr
= htonl(ip4addr
);
505 if (npppd_is_ifcace_ip4addr(_this
->npppd
, sin4
.sin_addr
.s_addr
))
506 return ADDRESS_RESERVED
;
507 /* Not to assign interface address */
509 if (rd_match(SA(&sin4
), _this
->npppd
->rd
, &radish
)) {
511 snp
= radish
->rd_rtent
;
512 if (snp
->snp_type
== SNP_POOL
||
513 snp
->snp_type
== SNP_DYN_POOL
) {
516 if (snp
->snp_data_ptr
== _this
)
519 return ADDRESS_RESERVED
;
521 if (snp
->snp_type
== SNP_PPP
) {
526 } while (rd_match_next(SA(&sin4
), _this
->npppd
->rd
, &radish
,
530 return ADDRESS_OUT_OF_POOL
;
532 /***********************************************************************
533 * miscellaneous functions
534 ***********************************************************************/
536 * Check if valid host address.
538 * There are some issues that it uses host address as broadcast address
539 * in natural mask, so it is not correct.
540 * The issue is as follows:
541 * (1) BSDs treat the following packet as it is not forwarded and
542 * is received as the packet to myself.
543 * (2) The issue that Windows can't use L2TP/IPsec when Windows is assigned
544 * IP address .255.</pre>
547 is_valid_host_address(uint32_t addr
)
550 return ((IN_CLASSA_HOST
& addr
) == 0 ||
551 (IN_CLASSA_HOST
& addr
) == IN_CLASSA_HOST
)? 0 : 1;
553 return ((IN_CLASSB_HOST
& addr
) == 0 ||
554 (IN_CLASSB_HOST
& addr
) == IN_CLASSB_HOST
)? 0 : 1;
556 return ((IN_CLASSC_HOST
& addr
) == 0 ||
557 (IN_CLASSC_HOST
& addr
) == IN_CLASSC_HOST
)? 0 : 1;
562 /** Record log that begins the label based this instance. */
564 npppd_pool_log(npppd_pool
*_this
, int prio
, const char *fmt
, ...)
571 * npppd_pool_release_ip is called as _this == NULL,
572 * so it can't NPPPD_POOL_ASSERT(_this != NULL).
575 snprintf(logbuf
, sizeof(logbuf
), "ipcp=%s pool %s",
576 (_this
== NULL
)? "null" : _this
->ipcp_name
, fmt
);
577 status
= vlog_printf(prio
, logbuf
, ap
);