GCC Code Coverage Report
Directory: ./ Exec Total Coverage
File: usr.bin/bgplg/bgpctl/../../../usr.sbin/bgpctl/irr_parser.c Lines: 0 177 0.0 %
Date: 2017-11-07 Branches: 0 239 0.0 %

Line Branch Exec Source
1
/*	$OpenBSD: irr_parser.c,v 1.14 2015/04/25 21:44:26 phessler Exp $ */
2
3
/*
4
 * Copyright (c) 2007 Henning Brauer <henning@openbsd.org>
5
 *
6
 * Permission to use, copy, modify, and distribute this software for any
7
 * purpose with or without fee is hereby granted, provided that the above
8
 * copyright notice and this permission notice appear in all copies.
9
 *
10
 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
11
 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
12
 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
13
 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
14
 * WHATSOEVER RESULTING FROM LOSS OF MIND, USE, DATA OR PROFITS, WHETHER IN
15
 * AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
16
 * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17
 */
18
19
#include <sys/types.h>
20
#include <ctype.h>
21
#include <err.h>
22
#include <stdio.h>
23
#include <stdlib.h>
24
#include <string.h>
25
#include <unistd.h>
26
#include <limits.h>
27
28
#include "irrfilter.h"
29
30
#define PARSEBUF_INCREMENT 4096
31
32
int	 lineno;
33
char	*parsebuf = NULL;
34
size_t	 parsebuflen = 0;
35
36
void	 grow_parsebuf(void);
37
char	*irr_getln(FILE *f);
38
int	 parse_policy(char *, char *);
39
int	 policy_additem(char *, struct policy_item *);
40
int	 parse_asset(char *, char *);
41
int	 parse_route(char *, char *);
42
43
/*
44
 * parse_response() return values:
45
 * -1	error
46
 * 0	object not found
47
 * >0	number of lines matched plus 1
48
 */
49
int
50
parse_response(FILE *f, enum qtype qtype)
51
{
52
	char	*key, *val;
53
	int	 cnt, n;
54
55
	lineno = 1;
56
	cnt = 1;
57
	while ((val = irr_getln(f)) != NULL) {
58
		if (!strncmp(val, "%ERROR:101:", 11))	/* no entries found */
59
			return (0);
60
61
		if (val[0] == '%') {
62
			warnx("message from whois server: %s", val);
63
			return (-1);
64
		}
65
66
		key = strsep(&val, ":");
67
		if (val == NULL) {
68
			warnx("%u: %s", lineno, key);
69
			warnx("no \":\" found!");
70
			return (-1);
71
		}
72
		EATWS(val);
73
74
		switch (qtype) {
75
		case QTYPE_OWNAS:
76
			if ((n = parse_policy(key, val)) == -1)
77
				return (-1);
78
			break;
79
		case QTYPE_ASSET:
80
			if ((n = parse_asset(key, val)) == -1)
81
				return (-1);
82
			break;
83
		case QTYPE_ROUTE:
84
		case QTYPE_ROUTE6:
85
			if ((n = parse_route(key, val)) == -1)
86
				return (-1);
87
			break;
88
		default:
89
			err(1, "king bula suffers from dementia");
90
		}
91
		cnt += n;
92
	}
93
94
	return (cnt);
95
}
96
97
void
98
grow_parsebuf(void)
99
{
100
	char	*p;
101
	size_t	 newlen;
102
103
	newlen = parsebuflen + PARSEBUF_INCREMENT;
104
	if ((p = realloc(parsebuf, newlen)) == NULL)
105
		err(1, "grow_parsebuf realloc");
106
	parsebuf = p;
107
	parsebuflen = newlen;
108
109
	if (0)
110
		fprintf(stderr, "parsebuf now %lu bytes\n", (ulong)parsebuflen);
111
}
112
113
char *
114
irr_getln(FILE *f)
115
{
116
	int	 c, next, last;
117
	char	*p;
118
119
	if (parsebuf == NULL)
120
		grow_parsebuf();
121
	p = parsebuf;
122
	last = -1;
123
124
	do {
125
		c = getc(f);
126
127
		if (p == parsebuf) {	/* beginning of new line */
128
			if (c == '%') {
129
				next = getc(f);
130
				switch (next) {
131
				case ' ':		/* comment. skip over */
132
					while ((c = getc(f)) != '\n' &&
133
					    c != EOF)
134
						; /* nothing */
135
					break;
136
				case '\n':
137
				case EOF:
138
					c = next;
139
					break;
140
				default:
141
					ungetc(next, f);
142
					break;
143
				}
144
			}
145
		}
146
147
		if (c == '#') /* skip until \n */
148
			while ((c = getc(f)) != '\n' && c != EOF)
149
				; /* nothing */
150
151
		if (c == '\n') {
152
			lineno++;
153
			next = getc(f);
154
			if (next == '+')	/* continuation, skip the + */
155
				c = getc(f);
156
			else if (ISWS(next))	/* continuation */
157
				c = next;
158
			else
159
				ungetc(next, f);
160
		}
161
162
163
		if (c == '\n' || c == EOF) {
164
			if (c == EOF)
165
				if (ferror(f))
166
					err(1, "ferror");
167
			if (p > parsebuf) {
168
				*p = '\0';
169
				return (parsebuf);
170
			}
171
		} else {
172
			if (!(ISWS(c) && ISWS(last))) {
173
				if (p + 1 >= parsebuf + parsebuflen - 1) {
174
					size_t	offset;
175
176
					offset = p - parsebuf;
177
					grow_parsebuf();
178
					p = parsebuf + offset;
179
				}
180
				if (ISWS(c)) /* equal opportunity whitespace */
181
					*p++ = ' ';
182
				else
183
					*p++ = (char)c;
184
			}
185
			last = c;
186
		}
187
	} while (c != EOF);
188
189
	return (NULL);
190
}
191
192
/*
193
 * parse the policy from an aut-num object
194
 */
195
196
enum policy_parser_st {
197
	PO_NONE,
198
	PO_PEER_KEY,
199
	PO_PEER_AS,
200
	PO_PEER_ADDR,
201
	PO_RTR_KEY,
202
	PO_RTR_ADDR,
203
	PO_ACTION_KEY,
204
	PO_ACTION_SPEC,
205
	PO_FILTER_KEY,
206
	PO_FILTER_SPEC
207
};
208
209
int
210
parse_policy(char *key, char *val)
211
{
212
	struct policy_item	*pi;
213
	enum pdir		 dir;
214
	enum policy_parser_st	 st = PO_NONE, nextst;
215
	char			*tok, *router = "", *p;
216
217
	if (!strcmp(key, "import"))
218
		dir = IMPORT;
219
	else if (!strcmp(key, "export"))
220
		dir = EXPORT;
221
	else				/* ignore! */
222
		return (0);
223
224
	if (dir == EXPORT && (irrflags & F_IMPORTONLY))
225
		return (0);
226
227
	if ((pi = calloc(1, sizeof(*pi))) == NULL)
228
		err(1, "parse_policy calloc");
229
	pi->dir = dir;
230
231
	while ((tok = strsep(&val, " ")) != NULL) {
232
		nextst = PO_NONE;
233
		if (dir == IMPORT) {
234
			if (!strcasecmp(tok, "from"))
235
				nextst = PO_PEER_KEY;
236
			else if (!strcasecmp(tok, "at"))
237
				nextst = PO_RTR_KEY;
238
			else if (!strcasecmp(tok, "action"))
239
				nextst = PO_ACTION_KEY;
240
			else if (!strcasecmp(tok, "accept"))
241
				nextst = PO_FILTER_KEY;
242
		} else if (dir == EXPORT) {
243
			if (!strcasecmp(tok, "to"))
244
				nextst = PO_PEER_KEY;
245
			else if (!strcasecmp(tok, "at"))
246
				nextst = PO_RTR_KEY;
247
			else if (!strcasecmp(tok, "action"))
248
				nextst = PO_ACTION_KEY;
249
			else if (!strcasecmp(tok, "announce"))
250
				nextst = PO_FILTER_KEY;
251
		}
252
253
		if (nextst == PO_FILTER_KEY) /* rest is filter spec */
254
			if ((pi->filter = strdup(val)) == NULL)
255
				err(1, NULL);
256
257
		if (nextst == PO_ACTION_KEY) {
258
			/* action list. ends after last ; */
259
			p = strrchr(val, ';');
260
			if (p == NULL || !ISWS(*++p))
261
				errx(1, "syntax error in action spec");
262
			*p = '\0';
263
			if ((pi->action = strdup(val)) == NULL)
264
				err(1, NULL);
265
			val = ++p;
266
			while (ISWS(*p))
267
				p++;
268
		}
269
270
		switch (st) {
271
		case PO_NONE:
272
			if (nextst != PO_PEER_KEY)
273
				goto ppoerr;
274
			st = nextst;
275
			break;
276
		case PO_PEER_KEY:
277
			if (pi->peer_as == 0) {
278
				const char	*errstr;
279
280
				if (nextst != PO_NONE)
281
					goto ppoerr;
282
				if (strlen(tok) < 3 ||
283
				    strncasecmp(tok, "AS", 2) ||
284
				    !isdigit((unsigned char)tok[2]))
285
					errx(1, "peering spec \"%s\": format "
286
					    "error, AS expected", tok);
287
				pi->peer_as = strtonum(tok + 2, 1, UINT_MAX,
288
				    &errstr);
289
				if (errstr)
290
					errx(1, "peering spec \"%s\": format "
291
					    "error: %s", tok, errstr);
292
			} else {
293
				switch (nextst) {
294
				case PO_NONE:
295
					if (!strcasecmp(tok, "and") ||
296
					    !strcasecmp(tok, "or") ||
297
					    !strcasecmp(tok, "not"))
298
						fprintf(stderr, "compound "
299
						    "peering statements are "
300
						    "not supported");
301
					 else	/* peer address */
302
						if ((pi->peer_addr =
303
						    strdup(tok)) == NULL)
304
							err(1, NULL);
305
					break;
306
				case PO_RTR_KEY:
307
				case PO_ACTION_KEY:
308
				case PO_FILTER_KEY:
309
					st = nextst;
310
					break;
311
				default:
312
					goto ppoerr;
313
				}
314
			}
315
			break;
316
		case PO_PEER_AS:
317
		case PO_PEER_ADDR:
318
			err(1, "state error");
319
			break;
320
		case PO_RTR_KEY:
321
			if (nextst != PO_NONE)
322
				goto ppoerr;
323
			/* rtr address */
324
			if ((router = strdup(tok)) == NULL)
325
				err(1, NULL);
326
			st = PO_RTR_ADDR;
327
			break;
328
		case PO_RTR_ADDR:
329
			if (nextst != PO_ACTION_KEY &&
330
			    nextst != PO_FILTER_KEY)
331
				goto ppoerr;
332
			st = nextst;
333
			break;
334
		case PO_ACTION_KEY:
335
			/* already handled, next must be FILTER_KEY */
336
			if (nextst != PO_FILTER_KEY)
337
				goto ppoerr;
338
			st = nextst;
339
			break;
340
		case PO_FILTER_KEY:
341
			/* already handled */
342
			break;
343
		case PO_ACTION_SPEC:
344
		case PO_FILTER_SPEC:
345
			err(1, "state error");
346
			break;
347
		}
348
	}
349
350
	if (st != PO_FILTER_KEY)
351
		err(1, "state error");
352
353
	if (policy_additem(router, pi) == -1)
354
		return (-1);
355
356
	return (1);
357
358
ppoerr:
359
	free(pi);
360
	fprintf(stderr, "%u: parse error\n", lineno);
361
	return (-1);
362
}
363
364
int
365
policy_additem(char *router, struct policy_item *pi)
366
{
367
	struct router	*r;
368
369
	for (r = TAILQ_FIRST(&router_head); r != NULL &&
370
	    strcmp(r->address, router); r = TAILQ_NEXT(r, entry))
371
		; /* nothing */
372
373
	if (r == NULL) {
374
		if ((r = calloc(1, sizeof(*r))) == NULL ||
375
		    (r->address = strdup(router)) == NULL)
376
			err(1, NULL);
377
		TAILQ_INIT(&r->policy_h);
378
		TAILQ_INSERT_TAIL(&router_head, r, entry);
379
	}
380
381
	TAILQ_INSERT_TAIL(&r->policy_h, pi, entry);
382
383
	return (0);
384
}
385
386
/*
387
 * parse as-set: get members
388
 */
389
390
int
391
parse_asset(char *key, char *val)
392
{
393
	char	*tok;
394
395
	if (strcmp(key, "members"))	/* ignore everything else */
396
		return (0);
397
398
	while ((tok = strsep(&val, ",")) != NULL) {
399
		EATWS(tok);
400
		if (tok[0] != '\0')
401
			asset_addmember(tok);
402
	}
403
404
	return (1);
405
}
406
407
/*
408
 * parse route obj: just get the prefix
409
 */
410
int
411
parse_route(char *key, char *val)
412
{
413
	if (strcmp(key, "route") && strcmp(key, "route6"))
414
		/* ignore everything else */
415
		return (0);
416
417
	/* route is single-value, but seen trailing , and \r in the wild */
418
	if (strlen(val) > 0 && (val[strlen(val) - 1] == ',' ||
419
	    val[strlen(val) - 1] == '\r'))
420
		val[strlen(val) - 1] = '\0';
421
422
	return (prefixset_addmember(val));
423
}