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