xref: /openbsd/usr.sbin/eigrpctl/parser.c (revision 956c66a0)
1*956c66a0Srenato /*	$OpenBSD: parser.c,v 1.4 2016/01/15 12:57:49 renato Exp $ */
2e2656810Srenato 
3e2656810Srenato /*
4e2656810Srenato  * Copyright (c) 2015 Renato Westphal <renato@openbsd.org>
5e2656810Srenato  * Copyright (c) 2004 Esben Norby <norby@openbsd.org>
6e2656810Srenato  * Copyright (c) 2003, 2004 Henning Brauer <henning@openbsd.org>
7e2656810Srenato  *
8e2656810Srenato  * Permission to use, copy, modify, and distribute this software for any
9e2656810Srenato  * purpose with or without fee is hereby granted, provided that the above
10e2656810Srenato  * copyright notice and this permission notice appear in all copies.
11e2656810Srenato  *
12e2656810Srenato  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
13e2656810Srenato  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
14e2656810Srenato  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
15e2656810Srenato  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
16e2656810Srenato  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
17e2656810Srenato  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
18e2656810Srenato  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
19e2656810Srenato  */
20e2656810Srenato 
21e2656810Srenato #include <sys/types.h>
22e2656810Srenato #include <sys/socket.h>
23e2656810Srenato #include <netinet/in.h>
24e2656810Srenato #include <arpa/inet.h>
25e2656810Srenato #include <err.h>
26e2656810Srenato #include <errno.h>
27e2656810Srenato #include <limits.h>
28e2656810Srenato #include <stdio.h>
29e2656810Srenato #include <stdlib.h>
30e2656810Srenato #include <string.h>
31e2656810Srenato #include <netdb.h>
32e2656810Srenato 
33e2656810Srenato #include "eigrpd.h"
34e2656810Srenato 
35e2656810Srenato #include "parser.h"
36e2656810Srenato 
37e2656810Srenato enum token_type {
38e2656810Srenato 	NOTOKEN,
39e2656810Srenato 	ENDTOKEN,
40e2656810Srenato 	KEYWORD,
41e2656810Srenato 	FAMILY,
42e2656810Srenato 	ASNUM,
43e2656810Srenato 	ADDRESS,
44e2656810Srenato 	FLAG,
45e2656810Srenato 	PREFIX,
46e2656810Srenato 	IFNAME
47e2656810Srenato };
48e2656810Srenato 
49e2656810Srenato struct token {
50e2656810Srenato 	enum token_type		 type;
51e2656810Srenato 	const char		*keyword;
52e2656810Srenato 	int			 value;
53e2656810Srenato 	const struct token	*next;
54e2656810Srenato };
55e2656810Srenato 
56e2656810Srenato static const struct token t_main[];
57e2656810Srenato static const struct token t_fib[];
58e2656810Srenato static const struct token t_show[];
59e2656810Srenato static const struct token t_show_iface[];
60e2656810Srenato static const struct token t_show_iface_af[];
61e2656810Srenato static const struct token t_show_iface_as[];
62e2656810Srenato static const struct token t_show_nbr[];
63e2656810Srenato static const struct token t_show_nbr_af[];
64e2656810Srenato static const struct token t_show_nbr_as[];
65e2656810Srenato static const struct token t_show_topology[];
66e2656810Srenato static const struct token t_show_topology_af[];
67e2656810Srenato static const struct token t_show_topology_as[];
68e2656810Srenato static const struct token t_show_fib[];
69e2656810Srenato static const struct token t_show_fib_af[];
70dcfaa8d4Srenato static const struct token t_show_stats[];
71dcfaa8d4Srenato static const struct token t_show_stats_af[];
72dcfaa8d4Srenato static const struct token t_show_stats_as[];
73e2656810Srenato static const struct token t_log[];
74*956c66a0Srenato static const struct token t_clear[];
75*956c66a0Srenato static const struct token t_clear_nbr[];
76*956c66a0Srenato static const struct token t_clear_nbr_af[];
77*956c66a0Srenato static const struct token t_clear_nbr_as[];
78e2656810Srenato 
79e2656810Srenato static const struct token t_main[] = {
80e2656810Srenato 	{KEYWORD,	"reload",	RELOAD,		NULL},
81e2656810Srenato 	{KEYWORD,	"fib",		FIB,		t_fib},
82e2656810Srenato 	{KEYWORD,	"show",		SHOW,		t_show},
83*956c66a0Srenato 	{KEYWORD,	"clear",	NONE,		t_clear},
84e2656810Srenato 	{KEYWORD,	"log",		NONE,		t_log},
85e2656810Srenato 	{ENDTOKEN,	"",		NONE,		NULL}
86e2656810Srenato };
87e2656810Srenato 
88e2656810Srenato static const struct token t_fib[] = {
89e2656810Srenato 	{ KEYWORD,	"couple",	FIB_COUPLE,	NULL},
90e2656810Srenato 	{ KEYWORD,	"decouple",	FIB_DECOUPLE,	NULL},
91e2656810Srenato 	{ ENDTOKEN,	"",		NONE,		NULL}
92e2656810Srenato };
93e2656810Srenato 
94e2656810Srenato static const struct token t_show[] = {
95e2656810Srenato 	{NOTOKEN,	"",		NONE,		NULL},
96e2656810Srenato 	{KEYWORD,	"interfaces",	SHOW_IFACE,	t_show_iface},
97e2656810Srenato 	{KEYWORD,	"neighbor",	SHOW_NBR,	t_show_nbr},
98e2656810Srenato 	{KEYWORD,	"topology",	SHOW_TOPOLOGY,	t_show_topology},
99e2656810Srenato 	{KEYWORD,	"fib",		SHOW_FIB,	t_show_fib},
100dcfaa8d4Srenato 	{KEYWORD,	"traffic",	SHOW_STATS,	t_show_stats},
101e2656810Srenato 	{ENDTOKEN,	"",		NONE,		NULL}
102e2656810Srenato };
103e2656810Srenato 
104e2656810Srenato static const struct token t_show_iface[] = {
105e2656810Srenato 	{NOTOKEN,	"",		NONE,			NULL},
106e2656810Srenato 	{KEYWORD,	"family",	NONE,			t_show_iface_af},
107e2656810Srenato 	{KEYWORD,	"as",		NONE,			t_show_iface_as},
108e2656810Srenato 	{KEYWORD,	"detail",	SHOW_IFACE_DTAIL,	NULL},
109e2656810Srenato 	{IFNAME,	"",		SHOW_IFACE_DTAIL,	NULL},
110e2656810Srenato 	{ENDTOKEN,	"",		NONE,			NULL}
111e2656810Srenato };
112e2656810Srenato 
113e2656810Srenato static const struct token t_show_iface_af[] = {
114e2656810Srenato 	{FAMILY,	"",		NONE,		t_show_iface},
115e2656810Srenato 	{ENDTOKEN,	"",		NONE,		NULL}
116e2656810Srenato };
117e2656810Srenato 
118e2656810Srenato static const struct token t_show_iface_as[] = {
119e2656810Srenato 	{ASNUM,		"",		NONE,		t_show_iface},
120e2656810Srenato 	{ENDTOKEN,	"",		NONE,		NULL}
121e2656810Srenato };
122e2656810Srenato 
123e2656810Srenato static const struct token t_show_nbr[] = {
124e2656810Srenato 	{NOTOKEN,	"",		NONE,		NULL},
125e2656810Srenato 	{KEYWORD,	"family",	NONE,		t_show_nbr_af},
126e2656810Srenato 	{KEYWORD,	"as",		NONE,		t_show_nbr_as},
127e2656810Srenato 	{ENDTOKEN,	"",		NONE,		NULL}
128e2656810Srenato };
129e2656810Srenato 
130e2656810Srenato static const struct token t_show_nbr_af[] = {
131e2656810Srenato 	{FAMILY,	"",		NONE,		t_show_nbr},
132e2656810Srenato 	{ENDTOKEN,	"",		NONE,		NULL}
133e2656810Srenato };
134e2656810Srenato 
135e2656810Srenato static const struct token t_show_nbr_as[] = {
136e2656810Srenato 	{ASNUM,		"",		NONE,		t_show_nbr},
137e2656810Srenato 	{ENDTOKEN,	"",		NONE,		NULL}
138e2656810Srenato };
139e2656810Srenato 
140e2656810Srenato static const struct token t_show_topology[] = {
141e2656810Srenato 	{NOTOKEN,	"",		NONE,		NULL},
142e2656810Srenato 	{KEYWORD,	"family",	NONE,		t_show_topology_af},
143e2656810Srenato 	{KEYWORD,	"as",		NONE,		t_show_topology_as},
144e2656810Srenato 	{PREFIX,	"",		NONE,		NULL},
145de19ae2eSjsg 	{FLAG,		"active",	F_CTL_ACTIVE,	NULL},
146de19ae2eSjsg 	{FLAG,		"all-links",	F_CTL_ALLLINKS,	NULL},
147e2656810Srenato 	{ENDTOKEN,	"",		NONE,		NULL}
148e2656810Srenato };
149e2656810Srenato 
150e2656810Srenato static const struct token t_show_topology_af[] = {
151e2656810Srenato 	{FAMILY,	"",		NONE,		t_show_topology},
152e2656810Srenato 	{ENDTOKEN,	"",		NONE,		NULL}
153e2656810Srenato };
154e2656810Srenato 
155e2656810Srenato static const struct token t_show_topology_as[] = {
156e2656810Srenato 	{ASNUM,		"",		NONE,		t_show_topology},
157e2656810Srenato 	{ENDTOKEN,	"",		NONE,		NULL}
158e2656810Srenato };
159e2656810Srenato 
160e2656810Srenato static const struct token t_show_fib[] = {
161e2656810Srenato 	{NOTOKEN,	"",		NONE,			NULL},
162e2656810Srenato 	{KEYWORD,	"family",	NONE,			t_show_fib_af},
163e2656810Srenato 	{KEYWORD,	"interface",	SHOW_FIB_IFACE,		t_show_iface},
164e2656810Srenato 	{FLAG,		"connected",	F_CONNECTED,		t_show_fib},
165e2656810Srenato 	{FLAG,		"static",	F_STATIC,		t_show_fib},
166e2656810Srenato 	{FLAG,		"eigrp",	F_EIGRPD_INSERTED,	t_show_fib},
167e2656810Srenato 	{ENDTOKEN,	"",		NONE,			NULL}
168e2656810Srenato };
169e2656810Srenato 
170e2656810Srenato static const struct token t_show_fib_af[] = {
171e2656810Srenato 	{FAMILY,	"",		NONE,		t_show_fib},
172e2656810Srenato 	{ENDTOKEN,	"",		NONE,		NULL}
173e2656810Srenato };
174e2656810Srenato 
175dcfaa8d4Srenato 
176dcfaa8d4Srenato static const struct token t_show_stats[] = {
177dcfaa8d4Srenato 	{NOTOKEN,	"",		NONE,		NULL},
178dcfaa8d4Srenato 	{KEYWORD,	"family",	NONE,		t_show_stats_af},
179dcfaa8d4Srenato 	{KEYWORD,	"as",		NONE,		t_show_stats_as},
180dcfaa8d4Srenato 	{ENDTOKEN,	"",		NONE,		NULL}
181dcfaa8d4Srenato };
182dcfaa8d4Srenato 
183dcfaa8d4Srenato static const struct token t_show_stats_af[] = {
184dcfaa8d4Srenato 	{FAMILY,	"",		NONE,		t_show_stats},
185dcfaa8d4Srenato 	{ENDTOKEN,	"",		NONE,		NULL}
186dcfaa8d4Srenato };
187dcfaa8d4Srenato 
188dcfaa8d4Srenato static const struct token t_show_stats_as[] = {
189dcfaa8d4Srenato 	{ASNUM,		"",		NONE,		t_show_stats},
190dcfaa8d4Srenato 	{ENDTOKEN,	"",		NONE,		NULL}
191dcfaa8d4Srenato };
192dcfaa8d4Srenato 
193*956c66a0Srenato static const struct token t_clear[] = {
194*956c66a0Srenato 	{KEYWORD,	"neighbors",	CLEAR_NBR,	t_clear_nbr},
195*956c66a0Srenato 	{ENDTOKEN,	"",		NONE,		NULL}
196*956c66a0Srenato };
197*956c66a0Srenato 
198*956c66a0Srenato static const struct token t_clear_nbr[] = {
199*956c66a0Srenato 	{NOTOKEN,	"",		NONE,		NULL},
200*956c66a0Srenato 	{KEYWORD,	"as",		NONE,		t_clear_nbr_as},
201*956c66a0Srenato 	{KEYWORD,	"family",	NONE,		t_clear_nbr_af},
202*956c66a0Srenato 	{ADDRESS,	"",		NONE,		NULL},
203*956c66a0Srenato 	{ENDTOKEN,	"",		NONE,		NULL}
204*956c66a0Srenato };
205*956c66a0Srenato 
206*956c66a0Srenato static const struct token t_clear_nbr_af[] = {
207*956c66a0Srenato 	{FAMILY,	"",		NONE,		t_clear_nbr},
208*956c66a0Srenato 	{ENDTOKEN,	"",		NONE,		NULL}
209*956c66a0Srenato };
210*956c66a0Srenato 
211*956c66a0Srenato static const struct token t_clear_nbr_as[] = {
212*956c66a0Srenato 	{ASNUM,		"",		NONE,		t_clear_nbr},
213*956c66a0Srenato 	{ENDTOKEN,	"",		NONE,		NULL}
214*956c66a0Srenato };
215*956c66a0Srenato 
216e2656810Srenato static const struct token t_log[] = {
217e2656810Srenato 	{KEYWORD,	"verbose",	LOG_VERBOSE,		NULL},
218e2656810Srenato 	{KEYWORD,	"brief",	LOG_BRIEF,		NULL},
219e2656810Srenato 	{ENDTOKEN,	"",		NONE,			NULL}
220e2656810Srenato };
221e2656810Srenato 
222e2656810Srenato static const struct token *match_token(const char *, const struct token *,
223e2656810Srenato     struct parse_result *);
224e2656810Srenato static void show_valid_args(const struct token *);
225e2656810Srenato 
226e2656810Srenato struct parse_result *
parse(int argc,char * argv[])227e2656810Srenato parse(int argc, char *argv[])
228e2656810Srenato {
229e2656810Srenato 	static struct parse_result	res;
230e2656810Srenato 	const struct token	*table = t_main;
231e2656810Srenato 	const struct token	*match;
232e2656810Srenato 
233e2656810Srenato 	memset(&res, 0, sizeof(res));
234e2656810Srenato 
235e2656810Srenato 	while (argc >= 0) {
236e2656810Srenato 		if ((match = match_token(argv[0], table, &res)) == NULL) {
237e2656810Srenato 			fprintf(stderr, "valid commands/args:\n");
238e2656810Srenato 			show_valid_args(table);
239e2656810Srenato 			return (NULL);
240e2656810Srenato 		}
241e2656810Srenato 
242e2656810Srenato 		argc--;
243e2656810Srenato 		argv++;
244e2656810Srenato 
245e2656810Srenato 		if (match->type == NOTOKEN || match->next == NULL)
246e2656810Srenato 			break;
247e2656810Srenato 
248e2656810Srenato 		table = match->next;
249e2656810Srenato 	}
250e2656810Srenato 
251e2656810Srenato 	if (argc > 0) {
252e2656810Srenato 		fprintf(stderr, "superfluous argument: %s\n", argv[0]);
253e2656810Srenato 		return (NULL);
254e2656810Srenato 	}
255e2656810Srenato 
256e2656810Srenato 	return (&res);
257e2656810Srenato }
258e2656810Srenato 
259e2656810Srenato static const struct token *
match_token(const char * word,const struct token * table,struct parse_result * res)260e2656810Srenato match_token(const char *word, const struct token *table,
261e2656810Srenato     struct parse_result *res)
262e2656810Srenato {
263e2656810Srenato 	unsigned int		 i, match;
264e2656810Srenato 	const struct token	*t = NULL;
265e2656810Srenato 
266e2656810Srenato 	match = 0;
267e2656810Srenato 
268e2656810Srenato 	for (i = 0; table[i].type != ENDTOKEN; i++) {
269e2656810Srenato 		switch (table[i].type) {
270e2656810Srenato 		case NOTOKEN:
271e2656810Srenato 			if (word == NULL || strlen(word) == 0) {
272e2656810Srenato 				match++;
273e2656810Srenato 				t = &table[i];
274e2656810Srenato 			}
275e2656810Srenato 			break;
276e2656810Srenato 		case KEYWORD:
277e2656810Srenato 			if (word != NULL && strncmp(word, table[i].keyword,
278e2656810Srenato 			    strlen(word)) == 0) {
279e2656810Srenato 				match++;
280e2656810Srenato 				t = &table[i];
281e2656810Srenato 				if (t->value)
282e2656810Srenato 					res->action = t->value;
283e2656810Srenato 			}
284e2656810Srenato 			break;
285e2656810Srenato 		case FLAG:
286e2656810Srenato 			if (word != NULL && strncmp(word, table[i].keyword,
287e2656810Srenato 			    strlen(word)) == 0) {
288e2656810Srenato 				match++;
289e2656810Srenato 				t = &table[i];
290e2656810Srenato 				res->flags |= t->value;
291e2656810Srenato 			}
292e2656810Srenato 			break;
293e2656810Srenato 		case FAMILY:
294e2656810Srenato 			if (word == NULL)
295e2656810Srenato 				break;
296e2656810Srenato 			if (!strcmp(word, "inet") ||
297e2656810Srenato 			    !strcasecmp(word, "IPv4")) {
298e2656810Srenato 				match++;
299e2656810Srenato 				t = &table[i];
300e2656810Srenato 				res->family = AF_INET;
301e2656810Srenato 			}
302e2656810Srenato 			if (!strcmp(word, "inet6") ||
303e2656810Srenato 			    !strcasecmp(word, "IPv6")) {
304e2656810Srenato 				match++;
305e2656810Srenato 				t = &table[i];
306e2656810Srenato 				res->family = AF_INET6;
307e2656810Srenato 			}
308e2656810Srenato 			break;
309e2656810Srenato 		case ASNUM:
310e2656810Srenato 			if (parse_asnum(word, &res->as)) {
311e2656810Srenato 				match++;
312e2656810Srenato 				t = &table[i];
313e2656810Srenato 			}
314e2656810Srenato 			break;
315e2656810Srenato 		case ADDRESS:
316e2656810Srenato 			if (parse_addr(word, &res->family, &res->addr)) {
317e2656810Srenato 				match++;
318e2656810Srenato 				t = &table[i];
319e2656810Srenato 				if (t->value)
320e2656810Srenato 					res->action = t->value;
321e2656810Srenato 			}
322e2656810Srenato 			break;
323e2656810Srenato 		case PREFIX:
324e2656810Srenato 			if (parse_prefix(word, &res->family, &res->addr,
325e2656810Srenato 			    &res->prefixlen)) {
326e2656810Srenato 				match++;
327e2656810Srenato 				t = &table[i];
328e2656810Srenato 				if (t->value)
329e2656810Srenato 					res->action = t->value;
330e2656810Srenato 			}
331e2656810Srenato 			break;
332e2656810Srenato 		case IFNAME:
333e2656810Srenato 			if (!match && word != NULL && strlen(word) > 0) {
334e2656810Srenato 				if (strlcpy(res->ifname, word,
335e2656810Srenato 				    sizeof(res->ifname)) >=
336e2656810Srenato 				    sizeof(res->ifname))
337e2656810Srenato 					err(1, "interface name too long");
338e2656810Srenato 				match++;
339e2656810Srenato 				t = &table[i];
340e2656810Srenato 				if (t->value)
341e2656810Srenato 					res->action = t->value;
342e2656810Srenato 			}
343e2656810Srenato 			break;
344e2656810Srenato 
345e2656810Srenato 		case ENDTOKEN:
346e2656810Srenato 			break;
347e2656810Srenato 		}
348e2656810Srenato 	}
349e2656810Srenato 
350e2656810Srenato 	if (match != 1) {
351e2656810Srenato 		if (word == NULL)
352e2656810Srenato 			fprintf(stderr, "missing argument:\n");
353e2656810Srenato 		else if (match > 1)
354e2656810Srenato 			fprintf(stderr, "ambiguous argument: %s\n", word);
355e2656810Srenato 		else if (match < 1)
356e2656810Srenato 			fprintf(stderr, "unknown argument: %s\n", word);
357e2656810Srenato 		return (NULL);
358e2656810Srenato 	}
359e2656810Srenato 
360e2656810Srenato 	return (t);
361e2656810Srenato }
362e2656810Srenato 
363e2656810Srenato static void
show_valid_args(const struct token * table)364e2656810Srenato show_valid_args(const struct token *table)
365e2656810Srenato {
366e2656810Srenato 	int	i;
367e2656810Srenato 
368e2656810Srenato 	for (i = 0; table[i].type != ENDTOKEN; i++) {
369e2656810Srenato 		switch (table[i].type) {
370e2656810Srenato 		case NOTOKEN:
371e2656810Srenato 			fprintf(stderr, "  <cr>\n");
372e2656810Srenato 			break;
373e2656810Srenato 		case KEYWORD:
374e2656810Srenato 		case FLAG:
375e2656810Srenato 			fprintf(stderr, "  %s\n", table[i].keyword);
376e2656810Srenato 			break;
377e2656810Srenato 		case FAMILY:
378e2656810Srenato 			fprintf(stderr, "  [ inet | inet6 | IPv4 | IPv6 ]\n");
379e2656810Srenato 			break;
380e2656810Srenato 		case ASNUM:
381e2656810Srenato 			fprintf(stderr, "  <asnum>\n");
382e2656810Srenato 			break;
383e2656810Srenato 		case ADDRESS:
384e2656810Srenato 			fprintf(stderr, "  <address>\n");
385e2656810Srenato 			break;
386e2656810Srenato 		case PREFIX:
387e2656810Srenato 			fprintf(stderr, "  <address>[/<len>]\n");
388e2656810Srenato 			break;
389e2656810Srenato 		case IFNAME:
390e2656810Srenato 			fprintf(stderr, "  <interface>\n");
391e2656810Srenato 			break;
392e2656810Srenato 		case ENDTOKEN:
393e2656810Srenato 			break;
394e2656810Srenato 		}
395e2656810Srenato 	}
396e2656810Srenato }
397e2656810Srenato 
398e2656810Srenato int
parse_asnum(const char * word,uint16_t * asnum)399e2656810Srenato parse_asnum(const char *word, uint16_t *asnum)
400e2656810Srenato {
401e2656810Srenato 	const char	*errstr;
402e2656810Srenato 	uint32_t	 uval;
403e2656810Srenato 
404e2656810Srenato 	if (word == NULL)
405e2656810Srenato 		return (0);
406e2656810Srenato 
407e2656810Srenato 	uval = strtonum(word, EIGRP_MIN_AS, EIGRP_MAX_AS, &errstr);
408e2656810Srenato 	if (errstr)
409e2656810Srenato 		errx(1, "AS number is %s: %s", errstr, word);
410e2656810Srenato 
411e2656810Srenato 	*asnum = uval;
412e2656810Srenato 	return (1);
413e2656810Srenato }
414e2656810Srenato 
415e2656810Srenato int
parse_addr(const char * word,int * family,union eigrpd_addr * addr)416e2656810Srenato parse_addr(const char *word, int *family, union eigrpd_addr *addr)
417e2656810Srenato {
418e2656810Srenato 	struct in_addr		 ina;
419e2656810Srenato 	struct addrinfo		 hints, *r;
420e2656810Srenato 	struct sockaddr_in6	*sa_in6;
421e2656810Srenato 
422e2656810Srenato 	if (word == NULL)
423e2656810Srenato 		return (0);
424e2656810Srenato 
425e2656810Srenato 	memset(addr, 0, sizeof(union eigrpd_addr));
426e2656810Srenato 	memset(&ina, 0, sizeof(ina));
427e2656810Srenato 
428e2656810Srenato 	if (inet_net_pton(AF_INET, word, &ina, sizeof(ina)) != -1) {
429e2656810Srenato 		*family = AF_INET;
430e2656810Srenato 		addr->v4.s_addr = ina.s_addr;
431e2656810Srenato 		return (1);
432e2656810Srenato 	}
433e2656810Srenato 
434e2656810Srenato 	memset(&hints, 0, sizeof(hints));
435e2656810Srenato 	hints.ai_family = AF_INET6;
436e2656810Srenato 	hints.ai_socktype = SOCK_DGRAM; /*dummy*/
437e2656810Srenato 	hints.ai_flags = AI_NUMERICHOST;
438e2656810Srenato 	if (getaddrinfo(word, "0", &hints, &r) == 0) {
439e2656810Srenato 		sa_in6 = (struct sockaddr_in6 *)r->ai_addr;
440e2656810Srenato 		*family = AF_INET6;
441e2656810Srenato 		addr->v6 = sa_in6->sin6_addr;
442e2656810Srenato 		freeaddrinfo(r);
443e2656810Srenato 		return (1);
444e2656810Srenato 	}
445e2656810Srenato 
446e2656810Srenato 	return (0);
447e2656810Srenato }
448e2656810Srenato 
449e2656810Srenato int
parse_prefix(const char * word,int * family,union eigrpd_addr * addr,uint8_t * prefixlen)450e2656810Srenato parse_prefix(const char *word, int *family, union eigrpd_addr *addr,
451e2656810Srenato     uint8_t *prefixlen)
452e2656810Srenato {
453e2656810Srenato 	char		*p, *ps;
454e2656810Srenato 	const char	*errstr;
455e2656810Srenato 	size_t		 wordlen;
456e2656810Srenato 	int		 mask = -1;
457e2656810Srenato 
458e2656810Srenato 	if (word == NULL)
459e2656810Srenato 		return (0);
460e2656810Srenato 	wordlen = strlen(word);
461e2656810Srenato 
462e2656810Srenato 	memset(addr, 0, sizeof(union eigrpd_addr));
463e2656810Srenato 
464e2656810Srenato 	if ((p = strrchr(word, '/')) != NULL) {
465e2656810Srenato 		size_t plen = strlen(p);
466e2656810Srenato 		mask = strtonum(p + 1, 0, 128, &errstr);
467e2656810Srenato 		if (errstr)
468e2656810Srenato 			errx(1, "netmask %s", errstr);
469e2656810Srenato 
470e2656810Srenato 		if ((ps = malloc(wordlen - plen + 1)) == NULL)
471e2656810Srenato 			err(1, "parse_prefix: malloc");
472e2656810Srenato 		strlcpy(ps, word, wordlen - plen + 1);
473e2656810Srenato 
474e2656810Srenato 		if (parse_addr(ps, family, addr) == 0) {
475e2656810Srenato 			free(ps);
476e2656810Srenato 			return (0);
477e2656810Srenato 		}
478e2656810Srenato 
479e2656810Srenato 		free(ps);
480e2656810Srenato 	} else
481e2656810Srenato 		if (parse_addr(word, family, addr) == 0)
482e2656810Srenato 			return (0);
483e2656810Srenato 
484e2656810Srenato 	switch (*family) {
485e2656810Srenato 	case AF_INET:
486e2656810Srenato 		if (mask == UINT8_MAX)
487e2656810Srenato 			mask = 32;
488e2656810Srenato 		if (mask > 32)
489e2656810Srenato 			errx(1, "invalid netmask: too large");
490e2656810Srenato 		break;
491e2656810Srenato 	case AF_INET6:
492e2656810Srenato 		if (mask == UINT8_MAX)
493e2656810Srenato 			mask = 128;
494e2656810Srenato 		if (mask > 128)
495e2656810Srenato 			errx(1, "invalid netmask: too large");
496e2656810Srenato 		break;
497e2656810Srenato 	default:
498e2656810Srenato 		return (0);
499e2656810Srenato 	}
500e2656810Srenato 	eigrp_applymask(*family, addr, addr, mask);
501e2656810Srenato 	*prefixlen = mask;
502e2656810Srenato 
503e2656810Srenato 	return (1);
504e2656810Srenato }
505