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

Line Branch Exec Source
1
/*	$OpenBSD: npppd_subr.c,v 1.18 2016/04/05 21:24:02 krw 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
 * This file provides helper functions for npppd.
30
 */
31
32
#include <sys/types.h>
33
#include <sys/socket.h>
34
#include <netinet/in.h>
35
#include <netinet/ip.h>
36
#include <netinet/udp.h>
37
#include <netinet/tcp.h>
38
#include <net/route.h>
39
#include <net/if_dl.h>
40
#include <net/if.h>
41
#include <ifaddrs.h>
42
#include <arpa/inet.h>
43
#include <stdlib.h>
44
#include <fcntl.h>
45
#include <stdio.h>
46
#include <syslog.h>
47
#include <stddef.h>
48
#include <unistd.h>
49
#include <errno.h>
50
#include <ctype.h>
51
#include <string.h>
52
#include <resolv.h>
53
54
#include "debugutil.h"
55
#include "addr_range.h"
56
57
#include "npppd_defs.h"
58
#include "npppd_subr.h"
59
#include "privsep.h"
60
61
#define MINIMUM(a, b)	(((a) < (b)) ? (a) : (b))
62
63
static u_int16_t route_seq = 0;
64
static int  in_route0(int, struct in_addr *, struct in_addr *, struct in_addr *, int, const char *, uint32_t);
65
#define ROUNDUP(a) \
66
	((a) > 0 ? (1 + (((a) - 1) | (sizeof(long) - 1))) : sizeof(long))
67
68
static const char *
69
skip_space(const char *s)
70
{
71
	const char *r;
72
	for (r = s; *r != '\0' && isspace((unsigned char)*r); r++)
73
		;; /* skip */
74
75
	return r;
76
}
77
78
/**
79
 * Read and store IPv4 address of name server from resolv.conf.
80
 * The path of resolv.conf is taken from _PATH_RESCONF in resolv.h.
81
 */
82
int
83
load_resolv_conf(struct in_addr *pri, struct in_addr *sec)
84
{
85
	FILE *filep;
86
	int i;
87
	struct in_addr *addr;
88
	char *ap, *line, buf[BUFSIZ];
89
90
	pri->s_addr = INADDR_NONE;
91
	sec->s_addr = INADDR_NONE;
92
93
	filep = NULL;
94
	if ((filep = priv_fopen(_PATH_RESCONF)) == NULL)
95
		return 1;
96
97
	i = 0;
98
	while (fgets(buf, sizeof(buf), filep) != NULL) {
99
		line = (char *)skip_space(buf);
100
		if (strncmp(line, "nameserver", 10) != 0)
101
			continue;
102
		line += 10;
103
		if (!isspace((unsigned char)*line))
104
			continue;
105
		while ((ap = strsep(&line, " \t\r\n")) != NULL) {
106
			if (*ap == '\0')
107
				continue;
108
			if (i == 0)
109
				addr = pri;
110
			else
111
				addr = sec;
112
			if (inet_aton(ap, addr) != 1) {
113
				/*
114
				 * FIXME: If configured IPv6, it may have IPv6
115
				 * FIXME: address.  For the present, continue.
116
				 */
117
				continue;
118
			}
119
			addr->s_addr = addr->s_addr;
120
			if (++i >= 2)
121
				goto end_loop;
122
		}
123
	}
124
end_loop:
125
	if (filep != NULL)
126
		fclose(filep);
127
128
	return 0;
129
}
130
131
/* Add and delete routing entry. */
132
static int
133
in_route0(int type, struct in_addr *dest, struct in_addr *mask,
134
    struct in_addr *gate, int mtu, const char *ifname, uint32_t rtm_flags)
135
{
136
	struct rt_msghdr *rtm;
137
	struct sockaddr_in sdest, smask, sgate;
138
	struct sockaddr_dl *sdl;
139
	char dl_buf[512];	/* enough size */
140
	char *cp, buf[sizeof(*rtm) + sizeof(struct sockaddr_in) * 3 +
141
	    sizeof(dl_buf) + 128];
142
	const char *strtype;
143
	int rval, flags, sock;
144
145
	sock = -1;
146
147
	ASSERT(type == RTM_ADD || type == RTM_DELETE);
148
	if(type == RTM_ADD)
149
		strtype = "RTM_ADD";
150
	else
151
		strtype = "RTM_DELETE";
152
153
	memset(buf, 0, sizeof(buf));
154
	memset(&sdest, 0, sizeof(sdest));
155
	memset(&smask, 0, sizeof(smask));
156
	memset(&sgate, 0, sizeof(sgate));
157
	memset(&dl_buf, 0, sizeof(dl_buf));
158
159
	sdl = (struct sockaddr_dl *)dl_buf;
160
161
	sdest.sin_addr = *dest;
162
	if (mask != NULL)
163
		smask.sin_addr = *mask;
164
	if (gate != NULL)
165
		sgate.sin_addr = *gate;
166
167
	sdest.sin_family = smask.sin_family = sgate.sin_family = AF_INET;
168
	sdest.sin_len = smask.sin_len = sgate.sin_len = sizeof(sgate);
169
170
	rtm = (struct rt_msghdr *)buf;
171
172
	rtm->rtm_version = RTM_VERSION;
173
	rtm->rtm_type = type;
174
	rtm->rtm_flags = rtm_flags;
175
	if (gate != NULL)
176
		rtm->rtm_flags |= RTF_GATEWAY;
177
	if (mask == NULL)
178
		rtm->rtm_flags |= RTF_HOST;
179
180
	if (type == RTM_ADD && mtu > 0) {
181
		rtm->rtm_inits = RTV_MTU;
182
		rtm->rtm_rmx.rmx_mtu = mtu;
183
	}
184
185
	if (type == RTM_ADD)
186
		rtm->rtm_flags |= RTF_UP;
187
188
	rtm->rtm_addrs = RTA_DST;
189
	if (gate != NULL)
190
		rtm->rtm_addrs |= RTA_GATEWAY;
191
	if (mask != NULL)
192
		rtm->rtm_addrs |= RTA_NETMASK;
193
#ifdef RTA_IFP
194
	if (ifname != NULL)
195
		rtm->rtm_addrs |= RTA_IFP;
196
#endif
197
198
	rtm->rtm_pid = getpid();
199
	route_seq = ((route_seq + 1)&0x0000ffff);
200
	rtm->rtm_seq = route_seq;
201
202
	cp = (char *)rtm;
203
	cp += ROUNDUP(sizeof(*rtm));
204
205
	memcpy(cp, &sdest, sdest.sin_len);
206
	cp += ROUNDUP(sdest.sin_len);
207
	if (gate != NULL) {
208
		memcpy(cp, &sgate, sgate.sin_len);
209
		cp += ROUNDUP(sgate.sin_len);
210
	}
211
	if (mask != NULL) {
212
		memcpy(cp, &smask, smask.sin_len);
213
		cp += ROUNDUP(smask.sin_len);
214
	}
215
#ifdef RTA_IFP
216
	if (ifname != NULL) {
217
		strlcpy(sdl->sdl_data, ifname, IFNAMSIZ);
218
		sdl->sdl_family = AF_LINK;
219
		sdl->sdl_len = offsetof(struct sockaddr_dl, sdl_data) +IFNAMSIZ;
220
		sdl->sdl_index = if_nametoindex(ifname);
221
		memcpy(cp, sdl, sdl->sdl_len);
222
		cp += ROUNDUP(sdl->sdl_len);
223
	}
224
#endif
225
226
	rtm->rtm_msglen = cp - buf;
227
228
	if ((sock = priv_socket(PF_ROUTE, SOCK_RAW, AF_UNSPEC)) < 0) {
229
		log_printf(LOG_ERR, "socket() failed in %s() on %s : %m",
230
		    __func__, strtype);
231
		goto fail;
232
	}
233
234
	if ((flags = fcntl(sock, F_GETFL)) < 0) {
235
		log_printf(LOG_ERR, "fcntl(,F_GETFL) failed on %s : %m",
236
		    __func__);
237
		goto fail;
238
	}
239
240
	if (fcntl(sock, F_SETFL, flags | O_NONBLOCK) < 0) {
241
		log_printf(LOG_ERR, "fcntl(,F_SETFL) failed on %s : %m",
242
		    __func__);
243
		goto fail;
244
	}
245
246
	if ((rval = priv_send(sock, buf, rtm->rtm_msglen, 0)) <= 0) {
247
		if ((type == RTM_DELETE && errno == ESRCH) ||
248
		    (type == RTM_ADD    && errno == EEXIST)) {
249
			log_printf(LOG_DEBUG,
250
			    "write() failed in %s on %s : %m", __func__,
251
			    strtype);
252
		} else {
253
			log_printf(LOG_WARNING,
254
			    "write() failed in %s on %s : %m", __func__,
255
			    strtype);
256
		}
257
		goto fail;
258
	}
259
260
	close(sock);
261
262
	return 0;
263
264
fail:
265
	if (sock >= 0)
266
		close(sock);
267
268
	return 1;
269
}
270
271
/** Add host routing entry. */
272
int
273
in_host_route_add(struct in_addr *dest, struct in_addr *gate,
274
    const char *ifname, int mtu)
275
{
276
	return in_route0(RTM_ADD, dest, NULL, gate, mtu, ifname, 0);
277
}
278
279
/** Delete host routing entry. */
280
int
281
in_host_route_delete(struct in_addr *dest, struct in_addr *gate)
282
{
283
	return in_route0(RTM_DELETE, dest, NULL, gate, 0, NULL, 0);
284
}
285
286
/** Add network routing entry. */
287
int
288
in_route_add(struct in_addr *dest, struct in_addr *mask, struct in_addr *gate,
289
    const char *ifname, uint32_t rtm_flags, int mtu)
290
{
291
	return in_route0(RTM_ADD, dest, mask, gate, mtu, ifname, rtm_flags);
292
}
293
294
/** Delete network routing entry. */
295
int
296
in_route_delete(struct in_addr *dest, struct in_addr *mask,
297
    struct in_addr *gate, uint32_t rtm_flags)
298
{
299
	return in_route0(RTM_DELETE, dest, mask, gate, 0, NULL, rtm_flags);
300
}
301
302
/**
303
 *  Check whether a packet should reset idle timer
304
 *  Returns 1 to don't reset timer (i.e. the packet is "idle" packet)
305
 */
306
int
307
ip_is_idle_packet(const struct ip * pip, int len)
308
{
309
	u_int16_t ip_off;
310
	const struct udphdr *uh;
311
312
	/*
313
         * Fragmented packet is not idle packet.
314
         * (Long packet which needs to fragment is not idle packet.)
315
         */
316
	ip_off = ntohs(pip->ip_off);
317
	if ((ip_off & IP_MF) || ((ip_off & IP_OFFMASK) != 0))
318
		return 0;
319
320
	switch (pip->ip_p) {
321
	case IPPROTO_IGMP:
322
		return 1;
323
	case IPPROTO_ICMP:
324
		/* Is length enough? */
325
		if (pip->ip_hl * 4 + 8 > len)
326
			return 1;
327
328
		switch (((unsigned char *) pip)[pip->ip_hl * 4]) {
329
		case 0:	/* Echo Reply */
330
		case 8:	/* Echo Request */
331
			return 0;
332
		default:
333
			return 1;
334
		}
335
	case IPPROTO_UDP:
336
	case IPPROTO_TCP:
337
		/*
338
		 * The place of port number of UDP and TCP is the same,
339
		 * so can be shared.
340
		 */
341
		uh = (const struct udphdr *) (((const char *) pip) +
342
		    (pip->ip_hl * 4));
343
344
		/* Is length enough? */
345
		if (pip->ip_hl * 4 + sizeof(struct udphdr) > len)
346
			return 1;
347
348
		switch (ntohs(uh->uh_sport)) {
349
		case 53:	/* DOMAIN */
350
		case 67:	/* BOOTPS */
351
		case 68:	/* BOOTPC */
352
		case 123:	/* NTP */
353
		case 137:	/* NETBIOS-NS */
354
		case 520:	/* RIP */
355
			return 1;
356
		}
357
		switch (ntohs(uh->uh_dport)) {
358
		case 53:	/* DOMAIN */
359
		case 67:	/* BOOTPS */
360
		case 68:	/* BOOTPC */
361
		case 123:	/* NTP */
362
		case 137:	/* NETBIOS-NS */
363
		case 520:	/* RIP */
364
			return 1;
365
		}
366
		return 0;
367
	default:
368
		return 0;
369
	}
370
}
371
372
/***********************************************************************
373
 * Add and delete routing entry for the pool address.
374
 ***********************************************************************/
375
void
376
in_addr_range_add_route(struct in_addr_range *range)
377
{
378
	struct in_addr_range *range0;
379
	struct in_addr dest, mask, loop;
380
381
	for (range0 = range; range0 != NULL; range0 = range0->next){
382
		dest.s_addr = htonl(range0->addr);
383
		mask.s_addr = htonl(range0->mask);
384
		loop.s_addr = htonl(INADDR_LOOPBACK);
385
		in_route_add(&dest, &mask, &loop, LOOPBACK_IFNAME,
386
		    RTF_BLACKHOLE, 0);
387
	}
388
	log_printf(LOG_INFO, "Added routes for pooled addresses");
389
}
390
391
void
392
in_addr_range_delete_route(struct in_addr_range *range)
393
{
394
	struct in_addr_range *range0;
395
	struct in_addr dest, mask, loop;
396
397
	for (range0 = range; range0 != NULL; range0 = range0->next){
398
		dest.s_addr = htonl(range0->addr);
399
		mask.s_addr = htonl(range0->mask);
400
		loop.s_addr = htonl(INADDR_LOOPBACK);
401
402
		in_route_delete(&dest, &mask, &loop, RTF_BLACKHOLE);
403
	}
404
	log_printf(LOG_NOTICE, "Deleted routes for pooled addresses");
405
}
406
407
408
/* GETSHORT is also defined in #inlude <arpa/nameser_compat.h>. */
409
#undef	GETCHAR
410
#undef	GETSHORT
411
#undef	PUTSHORT
412
413
#define GETCHAR(c, cp) { (c) = *(cp)++; }
414
#define GETSHORT(s, cp) { \
415
	(s) = *(cp)++ << 8; \
416
	(s) |= *(cp)++; \
417
}
418
#define PUTSHORT(s, cp) { \
419
	*(cp)++ = (u_char) ((s) >> 8); \
420
	*(cp)++ = (u_char) (s); \
421
}
422
#define TCP_OPTLEN_IN_SEGMENT	12	/* timestamp option and padding */
423
#define MAXMSS(mtu) (mtu - sizeof(struct ip) - sizeof(struct tcphdr) - \
424
    TCP_OPTLEN_IN_SEGMENT)
425
426
/* adapted from FreeBSD:src/usr.sbin/ppp/tcpmss.c */
427
/*
428
 * Copyright (c) 2000 Ruslan Ermilov and Brian Somers <brian@Awfulhak.org>
429
 * All rights reserved.
430
 *
431
 * Redistribution and use in source and binary forms, with or without
432
 * modification, are permitted provided that the following conditions
433
 * are met:
434
 * 1. Redistributions of source code must retain the above copyright
435
 *    notice, this list of conditions and the following disclaimer.
436
 * 2. Redistributions in binary form must reproduce the above copyright
437
 *    notice, this list of conditions and the following disclaimer in the
438
 *    documentation and/or other materials provided with the distribution.
439
 *
440
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
441
 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
442
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
443
 * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
444
 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
445
 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
446
 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
447
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
448
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
449
 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
450
 * SUCH DAMAGE.
451
 *
452
 * $FreeBSD: src/usr.sbin/ppp/tcpmss.c,v 1.1.4.3 2001/07/19 11:39:54 brian Exp $
453
 */
454
455
/*
456
 * The following macro is used to update an internet checksum.  "acc" is a
457
 * 32-bit accumulation of all the changes to the checksum (adding in old
458
 * 16-bit words and subtracting out new words), and "cksum" is the checksum
459
 * value to be updated.
460
 */
461
#define ADJUST_CHECKSUM(acc, cksum) {			\
462
	acc += cksum;					\
463
	if (acc < 0) {					\
464
		acc = -acc;				\
465
		acc = (acc >> 16) + (acc & 0xffff);	\
466
		acc += acc >> 16;			\
467
		cksum = (u_short) ~acc;			\
468
	} else {					\
469
		acc = (acc >> 16) + (acc & 0xffff);	\
470
		acc += acc >> 16;			\
471
		cksum = (u_short) acc;			\
472
	}						\
473
}
474
475
/**
476
 * Adjust mss to make IP packet be shorter than or equal MTU.
477
 *
478
 * @param	pktp	pointer that indicates IP packet
479
 * @param	lpktp	length
480
 * @param	mtu	MTU
481
 */
482
int
483
adjust_tcp_mss(u_char *pktp, int lpktp, int mtu)
484
{
485
	int opt, optlen, acc, ip_off, mss, maxmss;
486
	struct ip *pip;
487
	struct tcphdr *th;
488
489
	if (lpktp < sizeof(struct ip) + sizeof(struct tcphdr))
490
		return 1;
491
492
	pip = (struct ip *)pktp;
493
	ip_off = ntohs(pip->ip_off);
494
495
	/* exclude non-TCP packet or fragmented packet. */
496
	if (pip->ip_p != IPPROTO_TCP || (ip_off & IP_MF) != 0 ||
497
	    (ip_off & IP_OFFMASK) != 0)
498
		return 0;
499
500
	pktp += pip->ip_hl << 2;
501
	lpktp -= pip->ip_hl << 2;
502
503
	/* broken packet */
504
	if (sizeof(struct tcphdr) > lpktp)
505
		return 1;
506
507
	th = (struct tcphdr *)pktp;
508
	/* MSS is selected only from SYN segment. (See RFC 793) */
509
	if ((th->th_flags & TH_SYN) == 0)
510
		return 0;
511
512
	lpktp = MINIMUM(th->th_off << 4, lpktp);
513
514
	pktp += sizeof(struct tcphdr);
515
	lpktp -= sizeof(struct tcphdr);
516
517
	while (lpktp >= TCPOLEN_MAXSEG) {
518
		GETCHAR(opt, pktp);
519
		switch (opt) {
520
		case TCPOPT_MAXSEG:
521
			GETCHAR(optlen, pktp);
522
			GETSHORT(mss, pktp);
523
			maxmss = MAXMSS(mtu);
524
			if (mss > maxmss) {
525
				pktp-=2;
526
				PUTSHORT(maxmss, pktp);
527
				acc = htons(mss);
528
				acc -= htons(maxmss);
529
				ADJUST_CHECKSUM(acc, th->th_sum);
530
			}
531
			return 0;
532
			/* NOTREACHED */
533
			break;
534
		case TCPOPT_EOL:
535
			return 0;
536
			/* NOTREACHED */
537
			break;
538
		case TCPOPT_NOP:
539
			lpktp--;
540
			break;
541
		default:
542
			GETCHAR(optlen, pktp);
543
			if (optlen < 2)	/* packet is broken */
544
				return 1;
545
			pktp += optlen - 2;
546
			lpktp -= optlen;
547
			break;
548
		}
549
	}
550
	return 0;
551
}