GCC Code Coverage Report
Directory: ./ Exec Total Coverage
File: usr.sbin/npppd/npppd/npppd_pool.c Lines: 0 210 0.0 %
Date: 2017-11-07 Branches: 0 119 0.0 %

Line Branch Exec Source
1
/*	$OpenBSD: npppd_pool.c,v 1.10 2017/05/30 17:22:00 yasuoka 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
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
100
npppd_pool_start(npppd_pool *_this)
101
{
102
	return 0;	/* nothing to do */
103
}
104
105
/** Finalize npppd_poll. */
106
void
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
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
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
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
inline static int
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
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
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
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
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
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
}