1 /*
2 * Copyright (c) 2017 by Internet Systems Consortium, Inc. ("ISC")
3 *
4 * Permission to use, copy, modify, and distribute this software for any
5 * purpose with or without fee is hereby granted, provided that the above
6 * copyright notice and this permission notice appear in all copies.
7 *
8 * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES
9 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
10 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR
11 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
12 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
13 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
14 * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
15 *
16 * Internet Systems Consortium, Inc.
17 * 950 Charter Street
18 * Redwood City, CA 94063
19 * <info@isc.org>
20 * https://www.isc.org/
21 *
22 */
23
24 /* From common/conflex.c */
25
26 #include "keama.h"
27
28 #include <sys/types.h>
29 #include <sys/stat.h>
30 #include <sys/mman.h>
31 #include <assert.h>
32 #include <ctype.h>
33 #include <fcntl.h>
34 #include <stdlib.h>
35 #include <string.h>
36 #include <unistd.h>
37
38 static int get_char(struct parse *);
39 static void unget_char(struct parse *, int);
40 static void skip_to_eol(struct parse *);
41 static enum dhcp_token read_whitespace(int c, struct parse *cfile);
42 static enum dhcp_token read_string(struct parse *);
43 static enum dhcp_token read_number(int, struct parse *);
44 static enum dhcp_token read_num_or_name(int, struct parse *);
45 static enum dhcp_token intern(char *, enum dhcp_token);
46
47 struct parse *
new_parse(int file,char * inbuf,size_t buflen,const char * name,int eolp)48 new_parse(int file, char *inbuf, size_t buflen, const char *name, int eolp)
49 {
50 struct parse *tmp;
51
52 tmp = (struct parse *)malloc(sizeof(struct parse));
53 assert(tmp != NULL);
54 memset(tmp, 0, sizeof(struct parse));
55
56 TAILQ_INSERT_TAIL(&parses, tmp);
57
58 tmp->tlname = name;
59 tmp->lpos = tmp->line = 1;
60 tmp->cur_line = tmp->line1;
61 tmp->prev_line = tmp->line2;
62 tmp->token_line = tmp->cur_line;
63 tmp->cur_line[0] = tmp->prev_line[0] = 0;
64 tmp->file = file;
65 tmp->eol_token = eolp;
66 TAILQ_INIT(&tmp->comments);
67
68 if (inbuf != NULL) {
69 tmp->inbuf = inbuf;
70 tmp->buflen = buflen;
71 tmp->bufsiz = 0;
72 } else {
73 struct stat sb;
74
75 if (fstat(file, &sb) < 0) {
76 fprintf(stderr, "can't stat input\n");
77 exit(1);
78 }
79
80 if (sb.st_size == 0)
81 return tmp;
82
83 tmp->bufsiz = tmp->buflen = (size_t) sb.st_size;
84 tmp->inbuf = mmap(NULL, tmp->bufsiz, PROT_READ, MAP_SHARED,
85 file, 0);
86
87 if (tmp->inbuf == MAP_FAILED) {
88 fprintf(stderr, "can't map input\n");
89 exit(1);
90 }
91 }
92
93 return tmp;
94 }
95
96 void
end_parse(struct parse * cfile)97 end_parse(struct parse *cfile)
98 {
99 /* "Memory" config files have no file. */
100 if (cfile->file != -1) {
101 munmap(cfile->inbuf, cfile->bufsiz);
102 close(cfile->file);
103 }
104
105 while (TAILQ_NEXT(cfile) != NULL) {
106 struct parse *saved_state;
107
108 saved_state = TAILQ_NEXT(cfile);
109 TAILQ_REMOVE(&parses, saved_state);
110 free(saved_state);
111 }
112
113 cfile->stack_size = 0;
114 if (cfile->stack != NULL)
115 free(cfile->stack);
116 cfile->stack = NULL;
117 TAILQ_REMOVE(&parses, cfile);
118 free(cfile);
119 }
120
121 /*
122 * Save the current state of the parser.
123 *
124 * Only one state may be saved. Any previous saved state is
125 * lost.
126 */
127 void
save_parse_state(struct parse * cfile)128 save_parse_state(struct parse *cfile) {
129 struct parse *tmp;
130
131 /*
132 * Free any previous saved states.
133 */
134 while (TAILQ_NEXT(cfile) != NULL) {
135 struct parse *saved_state;
136
137 saved_state = TAILQ_NEXT(cfile);
138 TAILQ_REMOVE(&parses, saved_state);
139 free(saved_state);
140 }
141
142 /*
143 * Save our current state.
144 */
145 tmp = (struct parse *)malloc(sizeof(struct parse));
146 if (tmp == NULL)
147 parse_error(cfile, "can't allocate state to be saved");
148 memset(tmp, 0, sizeof(struct parse));
149 /* save up to comments field */
150 memcpy(tmp, cfile, (size_t)&(((struct parse *)0)->comments));
151 TAILQ_INSERT_AFTER(&parses, cfile, tmp);
152 }
153
154 /*
155 * Return the parser to the previous saved state.
156 *
157 * You must call save_parse_state() every time before calling
158 * restore_parse_state().
159 */
160 void
restore_parse_state(struct parse * cfile)161 restore_parse_state(struct parse *cfile) {
162 struct parse *saved_state;
163
164 if (TAILQ_NEXT(cfile) == NULL)
165 parse_error(cfile, "can't find saved state");
166
167 saved_state = TAILQ_NEXT(cfile);
168 TAILQ_REMOVE(&parses, saved_state);
169 /* restore up to comments field */
170 memcpy(cfile, saved_state, (size_t)&(((struct parse *)0)->comments));
171 free(saved_state);
172 }
173
174 static int
get_char(struct parse * cfile)175 get_char(struct parse *cfile)
176 {
177 /* My kingdom for WITH... */
178 int c;
179
180 if (cfile->bufix == cfile->buflen) {
181 c = EOF;
182 } else {
183 c = cfile->inbuf[cfile->bufix];
184 cfile->bufix++;
185 }
186
187 if (!cfile->ugflag) {
188 if (c == EOL) {
189 if (cfile->cur_line == cfile->line1) {
190 cfile->cur_line = cfile->line2;
191 cfile->prev_line = cfile->line1;
192 } else {
193 cfile->cur_line = cfile->line1;
194 cfile->prev_line = cfile->line2;
195 }
196 cfile->line++;
197 cfile->lpos = 1;
198 cfile->cur_line[0] = 0;
199 } else if (c != EOF) {
200 if (cfile->lpos <= 80) {
201 cfile->cur_line[cfile->lpos - 1] = c;
202 cfile->cur_line[cfile->lpos] = 0;
203 }
204 cfile->lpos++;
205 }
206 } else
207 cfile->ugflag = 0;
208 return c;
209 }
210
211 /*
212 * Return a character to our input buffer.
213 */
214 static void
unget_char(struct parse * cfile,int c)215 unget_char(struct parse *cfile, int c) {
216 if (c != EOF) {
217 cfile->bufix--;
218 cfile->ugflag = 1; /* do not put characters into
219 our error buffer on the next
220 call to get_char() */
221 }
222 }
223
224 /*
225 * GENERAL NOTE ABOUT TOKENS
226 *
227 * We normally only want non-whitespace tokens. There are some
228 * circumstances where we *do* want to see whitespace (for example
229 * when parsing IPv6 addresses).
230 *
231 * Generally we use the next_token() function to read tokens. This
232 * in turn calls get_next_token, which does *not* return tokens for
233 * whitespace. Rather, it skips these.
234 *
235 * When we need to see whitespace, we us next_raw_token(), which also
236 * returns the WHITESPACE token.
237 *
238 * The peek_token() and peek_raw_token() functions work as expected.
239 *
240 * Warning: if you invoke peek_token(), then if there is a whitespace
241 * token, it will be lost, and subsequent use of next_raw_token() or
242 * peek_raw_token() will NOT see it.
243 */
244
245 static enum dhcp_token
get_raw_token(struct parse * cfile)246 get_raw_token(struct parse *cfile) {
247 int c;
248 enum dhcp_token ttok;
249 static char tb[2];
250 int l, p;
251
252 for (;;) {
253 l = cfile->line;
254 p = cfile->lpos;
255
256 c = get_char(cfile);
257 if (!((c == '\n') && cfile->eol_token) &&
258 isascii(c) && isspace(c)) {
259 ttok = read_whitespace(c, cfile);
260 break;
261 }
262 if (c == '#') {
263 skip_to_eol(cfile);
264 continue;
265 }
266 if (c == '"') {
267 cfile->lexline = l;
268 cfile->lexchar = p;
269 ttok = read_string(cfile);
270 break;
271 }
272 if ((isascii(c) && isdigit(c)) || c == '-') {
273 cfile->lexline = l;
274 cfile->lexchar = p;
275 ttok = read_number(c, cfile);
276 break;
277 } else if (isascii(c) && isalpha(c)) {
278 cfile->lexline = l;
279 cfile->lexchar = p;
280 ttok = read_num_or_name(c, cfile);
281 break;
282 } else if (c == EOF) {
283 ttok = END_OF_FILE;
284 cfile->tlen = 0;
285 break;
286 } else {
287 cfile->lexline = l;
288 cfile->lexchar = p;
289 tb[0] = c;
290 tb[1] = 0;
291 cfile->tval = tb;
292 cfile->tlen = 1;
293 ttok = c;
294 break;
295 }
296 }
297 return ttok;
298 }
299
300 /*
301 * The get_next_token() function consumes the next token and
302 * returns it to the caller.
303 *
304 * Since the code is almost the same for "normal" and "raw"
305 * input, we pass a flag to alter the way it works.
306 */
307
308 static enum dhcp_token
get_next_token(const char ** rval,unsigned * rlen,struct parse * cfile,isc_boolean_t raw)309 get_next_token(const char **rval, unsigned *rlen,
310 struct parse *cfile, isc_boolean_t raw) {
311 int rv;
312
313 if (cfile->token) {
314 if (cfile->lexline != cfile->tline)
315 cfile->token_line = cfile->cur_line;
316 cfile->lexchar = cfile->tlpos;
317 cfile->lexline = cfile->tline;
318 rv = cfile->token;
319 cfile->token = 0;
320 } else {
321 rv = get_raw_token(cfile);
322 cfile->token_line = cfile->cur_line;
323 }
324
325 if (!raw) {
326 while (rv == WHITESPACE) {
327 rv = get_raw_token(cfile);
328 cfile->token_line = cfile->cur_line;
329 }
330 }
331
332 if (rval)
333 *rval = cfile->tval;
334 if (rlen)
335 *rlen = cfile->tlen;
336 return rv;
337 }
338
339 /*
340 * Get the next token from cfile and return it.
341 *
342 * If rval is non-NULL, set the pointer it contains to
343 * the contents of the token.
344 *
345 * If rlen is non-NULL, set the integer it contains to
346 * the length of the token.
347 */
348
349 enum dhcp_token
next_token(const char ** rval,unsigned * rlen,struct parse * cfile)350 next_token(const char **rval, unsigned *rlen, struct parse *cfile) {
351 return get_next_token(rval, rlen, cfile, ISC_FALSE);
352 }
353
354
355 /*
356 * The same as the next_token() function above, but will return space
357 * as the WHITESPACE token.
358 */
359
360 enum dhcp_token
next_raw_token(const char ** rval,unsigned * rlen,struct parse * cfile)361 next_raw_token(const char **rval, unsigned *rlen, struct parse *cfile) {
362 return get_next_token(rval, rlen, cfile, ISC_TRUE);
363 }
364
365
366 /*
367 * The do_peek_token() function checks the next token without
368 * consuming it, and returns it to the caller.
369 *
370 * Since the code is almost the same for "normal" and "raw"
371 * input, we pass a flag to alter the way it works. (See the
372 * warning in the GENERAL NOTES ABOUT TOKENS above though.)
373 */
374
375 enum dhcp_token
do_peek_token(const char ** rval,unsigned int * rlen,struct parse * cfile,isc_boolean_t raw)376 do_peek_token(const char **rval, unsigned int *rlen,
377 struct parse *cfile, isc_boolean_t raw) {
378 int x;
379
380 if (!cfile->token || (!raw && (cfile->token == WHITESPACE))) {
381 cfile->tlpos = cfile->lexchar;
382 cfile->tline = cfile->lexline;
383
384 do {
385 cfile->token = get_raw_token(cfile);
386 } while (!raw && (cfile->token == WHITESPACE));
387
388 if (cfile->lexline != cfile->tline)
389 cfile->token_line = cfile->prev_line;
390
391 x = cfile->lexchar;
392 cfile->lexchar = cfile->tlpos;
393 cfile->tlpos = x;
394
395 x = cfile->lexline;
396 cfile->lexline = cfile->tline;
397 cfile->tline = x;
398 }
399 if (rval)
400 *rval = cfile->tval;
401 if (rlen)
402 *rlen = cfile->tlen;
403 return cfile->token;
404 }
405
406
407 /*
408 * Get the next token from cfile and return it, leaving it for a
409 * subsequent call to next_token().
410 *
411 * Note that it WILL consume whitespace tokens.
412 *
413 * If rval is non-NULL, set the pointer it contains to
414 * the contents of the token.
415 *
416 * If rlen is non-NULL, set the integer it contains to
417 * the length of the token.
418 */
419
420 enum dhcp_token
peek_token(const char ** rval,unsigned * rlen,struct parse * cfile)421 peek_token(const char **rval, unsigned *rlen, struct parse *cfile) {
422 return do_peek_token(rval, rlen, cfile, ISC_FALSE);
423 }
424
425
426 /*
427 * The same as the peek_token() function above, but will return space
428 * as the WHITESPACE token.
429 */
430
431 enum dhcp_token
peek_raw_token(const char ** rval,unsigned * rlen,struct parse * cfile)432 peek_raw_token(const char **rval, unsigned *rlen, struct parse *cfile) {
433 return do_peek_token(rval, rlen, cfile, ISC_TRUE);
434 }
435
436 /*
437 * The comment up to but not including EOL is saved.
438 */
439
440 static void
skip_to_eol(struct parse * cfile)441 skip_to_eol(struct parse *cfile)
442 {
443 char buf[128];
444 unsigned cc = 0;
445 struct comment *comment;
446
447 memset(buf, 0, sizeof(buf));
448 buf[0] = '#';
449 for (;;) {
450 int c;
451
452 c = get_char(cfile);
453 if (c == EOF)
454 break;
455 if (c == EOL) {
456 break;
457 }
458 if (++cc < sizeof(buf) - 1)
459 buf[cc] = c;
460 }
461 comment = createComment(buf);
462 TAILQ_INSERT_TAIL(&cfile->comments, comment);
463 }
464
465 static enum dhcp_token
read_whitespace(int c,struct parse * cfile)466 read_whitespace(int c, struct parse *cfile) {
467 int ofs;
468
469 /*
470 * Read as much whitespace as we have available.
471 */
472 ofs = 0;
473 do {
474 if (ofs >= (sizeof(cfile->tokbuf) - 1)) {
475 /*
476 * As the file includes a huge amount of whitespace,
477 * it's probably broken.
478 * Print out a warning and bail out.
479 */
480 parse_error(cfile,
481 "whitespace too long, buffer overflow.");
482 }
483 cfile->tokbuf[ofs++] = c;
484 c = get_char(cfile);
485 if (c == EOF)
486 return END_OF_FILE;
487 } while (!((c == '\n') && cfile->eol_token) &&
488 isascii(c) && isspace(c));
489
490 /*
491 * Put the last (non-whitespace) character back.
492 */
493 unget_char(cfile, c);
494
495 /*
496 * Return our token.
497 */
498 cfile->tokbuf[ofs] = '\0';
499 cfile->tlen = ofs;
500 cfile->tval = cfile->tokbuf;
501 return WHITESPACE;
502 }
503
504 static enum dhcp_token
read_string(struct parse * cfile)505 read_string(struct parse *cfile)
506 {
507 unsigned i;
508 int bs = 0;
509 int c;
510 int value = 0;
511 int hex = 0;
512
513 for (i = 0; i < sizeof(cfile->tokbuf); i++) {
514 again:
515 c = get_char(cfile);
516 if (c == EOF)
517 parse_error(cfile, "eof in string constant");
518 if (bs == 1) {
519 switch (c) {
520 case 't':
521 cfile->tokbuf[i] = '\t';
522 break;
523 case 'r':
524 cfile->tokbuf[i] = '\r';
525 break;
526 case 'n':
527 cfile->tokbuf[i] = '\n';
528 break;
529 case 'b':
530 cfile->tokbuf[i] = '\b';
531 break;
532 case '0':
533 case '1':
534 case '2':
535 case '3':
536 hex = 0;
537 value = c - '0';
538 ++bs;
539 goto again;
540 case 'x':
541 hex = 1;
542 value = 0;
543 ++bs;
544 goto again;
545 default:
546 cfile->tokbuf[i] = c;
547 break;
548 }
549 bs = 0;
550 } else if (bs > 1) {
551 if (hex) {
552 if (c >= '0' && c <= '9') {
553 value = value * 16 + (c - '0');
554 } else if (c >= 'a' && c <= 'f') {
555 value = value * 16 + (c - 'a' + 10);
556 } else if (c >= 'A' && c <= 'F') {
557 value = value * 16 + (c - 'A' + 10);
558 } else
559 parse_error(cfile,
560 "invalid hex digit: %x",
561 c);
562 if (++bs == 4) {
563 cfile->tokbuf[i] = value;
564 bs = 0;
565 } else
566 goto again;
567 } else {
568 if (c >= '0' && c <= '7') {
569 value = value * 8 + (c - '0');
570 } else {
571 if (value != 0)
572 parse_error(cfile,
573 "invalid octal digit %x",
574 c);
575 else
576 cfile->tokbuf[i] = 0;
577 bs = 0;
578 }
579 if (++bs == 4) {
580 cfile->tokbuf[i] = value;
581 bs = 0;
582 } else
583 goto again;
584 }
585 } else if (c == '\\') {
586 bs = 1;
587 goto again;
588 } else if (c == '"')
589 break;
590 else
591 cfile->tokbuf[i] = c;
592 }
593 /* Normally, I'd feel guilty about this, but we're talking about
594 strings that'll fit in a DHCP packet here... */
595 if (i == sizeof(cfile->tokbuf))
596 parse_error(cfile,
597 "string constant larger than internal buffer");
598 cfile->tokbuf[i] = 0;
599 cfile->tlen = i;
600 cfile->tval = cfile->tokbuf;
601 return STRING;
602 }
603
604 static enum dhcp_token
read_number(int c,struct parse * cfile)605 read_number(int c, struct parse *cfile)
606 {
607 unsigned i = 0;
608 int token = NUMBER;
609
610 cfile->tokbuf[i++] = c;
611 for (; i < sizeof(cfile->tokbuf); i++) {
612 c = get_char(cfile);
613
614 /* Promote NUMBER->NUMBER_OR_NAME->NAME, never demote.
615 * Except in the case of '0x' syntax hex, which gets called
616 * a NAME at '0x', and returned to NUMBER_OR_NAME once it's
617 * verified to be at least 0xf or less.
618 */
619 switch (isascii(c) ? token : BREAK) {
620 case NUMBER:
621 if (isdigit(c))
622 break;
623 /* FALLTHROUGH */
624 case NUMBER_OR_NAME:
625 if (isxdigit(c)) {
626 token = NUMBER_OR_NAME;
627 break;
628 }
629 /* FALLTHROUGH */
630 case NAME:
631 if ((i == 2) && isxdigit(c) &&
632 (cfile->tokbuf[0] == '0') &&
633 ((cfile->tokbuf[1] == 'x') ||
634 (cfile->tokbuf[1] == 'X'))) {
635 token = NUMBER_OR_NAME;
636 break;
637 } else if (((c == '-') || (c == '_') || isalnum(c))) {
638 token = NAME;
639 break;
640 }
641 /* FALLTHROUGH */
642 case BREAK:
643 /* At this point c is either EOF or part of the next
644 * token. If not EOF, rewind the file one byte so
645 * the next token is read from there.
646 */
647 unget_char(cfile, c);
648 goto end_read;
649
650 default:
651 parse_error(cfile,
652 "read_number(): impossible case");
653 }
654
655 cfile->tokbuf[i] = c;
656 }
657
658 if (i == sizeof(cfile->tokbuf))
659 parse_error(cfile,
660 "numeric token larger than internal buffer");
661
662 end_read:
663 cfile->tokbuf[i] = 0;
664 cfile->tlen = i;
665 cfile->tval = cfile->tokbuf;
666
667 /*
668 * If this entire token from start to finish was "-", such as
669 * the middle parameter in "42 - 7", return just the MINUS token.
670 */
671 if ((i == 1) && (cfile->tokbuf[i] == '-'))
672 return MINUS;
673 else
674 return token;
675 }
676
677 static enum dhcp_token
read_num_or_name(int c,struct parse * cfile)678 read_num_or_name(int c, struct parse *cfile)
679 {
680 unsigned i = 0;
681 enum dhcp_token rv = NUMBER_OR_NAME;
682
683 cfile->tokbuf[i++] = c;
684 for (; i < sizeof(cfile->tokbuf); i++) {
685 c = get_char(cfile);
686 if (!isascii(c) ||
687 (c != '-' && c != '_' && !isalnum(c))) {
688 unget_char(cfile, c);
689 break;
690 }
691 if (!isxdigit(c))
692 rv = NAME;
693 cfile->tokbuf[i] = c;
694 }
695 if (i == sizeof(cfile->tokbuf))
696 parse_error(cfile, "token larger than internal buffer");
697 cfile->tokbuf[i] = 0;
698 cfile->tlen = i;
699 cfile->tval = cfile->tokbuf;
700 return intern(cfile->tval, rv);
701 }
702
703 static enum dhcp_token
intern(char * atom,enum dhcp_token dfv)704 intern(char *atom, enum dhcp_token dfv) {
705 if (!isascii(atom[0]))
706 return dfv;
707
708 switch (tolower((unsigned char)atom[0])) {
709 case '-':
710 if (atom [1] == 0)
711 return MINUS;
712 break;
713
714 case 'a':
715 if (!strcasecmp(atom + 1, "bandoned"))
716 return TOKEN_ABANDONED;
717 if (!strcasecmp(atom + 1, "ctive"))
718 return TOKEN_ACTIVE;
719 if (!strncasecmp(atom + 1, "dd", 2)) {
720 if (atom[3] == '\0')
721 return TOKEN_ADD;
722 else if (!strcasecmp(atom + 3, "ress"))
723 return ADDRESS;
724 break;
725 }
726 if (!strcasecmp(atom + 1, "fter"))
727 return AFTER;
728 if (isascii(atom[1]) &&
729 (tolower((unsigned char)atom[1]) == 'l')) {
730 if (!strcasecmp(atom + 2, "gorithm"))
731 return ALGORITHM;
732 if (!strcasecmp(atom + 2, "ias"))
733 return ALIAS;
734 if (isascii(atom[2]) &&
735 (tolower((unsigned char)atom[2]) == 'l')) {
736 if (atom[3] == '\0')
737 return ALL;
738 else if (!strcasecmp(atom + 3, "ow"))
739 return ALLOW;
740 break;
741 }
742 if (!strcasecmp(atom + 2, "so"))
743 return TOKEN_ALSO;
744 break;
745 }
746 if (isascii(atom[1]) &&
747 (tolower((unsigned char)atom[1]) == 'n')) {
748 if (!strcasecmp(atom + 2, "d"))
749 return AND;
750 if (!strcasecmp(atom + 2, "ycast-mac"))
751 return ANYCAST_MAC;
752 break;
753 }
754 if (!strcasecmp(atom + 1, "ppend"))
755 return APPEND;
756 if (!strcasecmp(atom + 1, "rray"))
757 return ARRAY;
758 if (isascii(atom[1]) &&
759 (tolower((unsigned char)atom[1]) == 't')) {
760 if (atom[2] == '\0')
761 return AT;
762 if (!strcasecmp(atom + 2, "sfp"))
763 return ATSFP;
764 break;
765 }
766 if (!strcasecmp(atom + 1, "uthoring-byte-order"))
767 return AUTHORING_BYTE_ORDER;
768 if (!strncasecmp(atom + 1, "ut", 2)) {
769 if (isascii(atom[3]) &&
770 (tolower((unsigned char)atom[3]) == 'h')) {
771 if (!strncasecmp(atom + 4, "enticat", 7)) {
772 if (!strcasecmp(atom + 11, "ed"))
773 return AUTHENTICATED;
774 if (!strcasecmp(atom + 11, "ion"))
775 return AUTHENTICATION;
776 break;
777 }
778 if (!strcasecmp(atom + 4, "oritative"))
779 return AUTHORITATIVE;
780 break;
781 }
782 if (!strcasecmp(atom + 3, "o-partner-down"))
783 return AUTO_PARTNER_DOWN;
784 break;
785 }
786 break;
787 case 'b':
788 if (!strcasecmp(atom + 1, "ackup"))
789 return TOKEN_BACKUP;
790 if (!strcasecmp(atom + 1, "ootp"))
791 return TOKEN_BOOTP;
792 if (!strcasecmp(atom + 1, "inding"))
793 return BINDING;
794 if (!strcasecmp(atom + 1, "inary-to-ascii"))
795 return BINARY_TO_ASCII;
796 if (!strcasecmp(atom + 1, "ackoff-cutoff"))
797 return BACKOFF_CUTOFF;
798 if (!strcasecmp(atom + 1, "ooting"))
799 return BOOTING;
800 if (!strcasecmp(atom + 1, "oot-unknown-clients"))
801 return BOOT_UNKNOWN_CLIENTS;
802 if (!strcasecmp(atom + 1, "reak"))
803 return BREAK;
804 if (!strcasecmp(atom + 1, "illing"))
805 return BILLING;
806 if (!strcasecmp(atom + 1, "oolean"))
807 return BOOLEAN;
808 if (!strcasecmp(atom + 1, "alance"))
809 return BALANCE;
810 if (!strcasecmp(atom + 1, "ound"))
811 return BOUND;
812 if (!strcasecmp(atom+1, "ig-endian")) {
813 return TOKEN_BIG_ENDIAN;
814 }
815 break;
816 case 'c':
817 if (!strcasecmp(atom + 1, "ase"))
818 return CASE;
819 if (!strcasecmp(atom + 1, "heck"))
820 return CHECK;
821 if (!strcasecmp(atom + 1, "iaddr"))
822 return CIADDR;
823 if (isascii(atom[1]) &&
824 tolower((unsigned char)atom[1]) == 'l') {
825 if (!strcasecmp(atom + 2, "ass"))
826 return CLASS;
827 if (!strncasecmp(atom + 2, "ient", 4)) {
828 if (!strcasecmp(atom + 6, "s"))
829 return CLIENTS;
830 if (atom[6] == '-') {
831 if (!strcasecmp(atom + 7, "hostname"))
832 return CLIENT_HOSTNAME;
833 if (!strcasecmp(atom + 7, "identifier"))
834 return CLIENT_IDENTIFIER;
835 if (!strcasecmp(atom + 7, "state"))
836 return CLIENT_STATE;
837 if (!strcasecmp(atom + 7, "updates"))
838 return CLIENT_UPDATES;
839 break;
840 }
841 break;
842 }
843 if (!strcasecmp(atom + 2, "ose"))
844 return TOKEN_CLOSE;
845 if (!strcasecmp(atom + 2, "tt"))
846 return CLTT;
847 break;
848 }
849 if (isascii(atom[1]) &&
850 tolower((unsigned char)atom[1]) == 'o') {
851 if (!strcasecmp(atom + 2, "de"))
852 return CODE;
853 if (isascii(atom[2]) &&
854 tolower((unsigned char)atom[2]) == 'm') {
855 if (!strcasecmp(atom + 3, "mit"))
856 return COMMIT;
857 if (!strcasecmp(atom + 3,
858 "munications-interrupted"))
859 return COMMUNICATIONS_INTERRUPTED;
860 if (!strcasecmp(atom + 3, "pressed"))
861 return COMPRESSED;
862 break;
863 }
864 if (isascii(atom[2]) &&
865 tolower((unsigned char)atom[2]) == 'n') {
866 if (!strcasecmp(atom + 3, "cat"))
867 return CONCAT;
868 if (!strcasecmp(atom + 3, "fig-option"))
869 return CONFIG_OPTION;
870 if (!strcasecmp(atom + 3, "flict-done"))
871 return CONFLICT_DONE;
872 if (!strcasecmp(atom + 3, "nect"))
873 return CONNECT;
874 break;
875 }
876 break;
877 }
878 if (!strcasecmp(atom + 1, "reate"))
879 return TOKEN_CREATE;
880 break;
881 case 'd':
882 if (!strcasecmp(atom + 1, "b-time-format"))
883 return DB_TIME_FORMAT;
884 if (!strcasecmp(atom + 1, "omain"))
885 return DOMAIN;
886 if (!strncasecmp(atom + 1, "omain-", 6)) {
887 if (!strcasecmp(atom + 7, "name"))
888 return DOMAIN_NAME;
889 if (!strcasecmp(atom + 7, "list"))
890 return DOMAIN_LIST;
891 }
892 if (!strcasecmp(atom + 1, "o-forward-updates"))
893 return DO_FORWARD_UPDATE;
894 /* do-forward-update is included for historical reasons */
895 if (!strcasecmp(atom + 1, "o-forward-update"))
896 return DO_FORWARD_UPDATE;
897 if (!strcasecmp(atom + 1, "ebug"))
898 return TOKEN_DEBUG;
899 if (!strcasecmp(atom + 1, "eny"))
900 return DENY;
901 if (!strcasecmp(atom + 1, "eleted"))
902 return TOKEN_DELETED;
903 if (!strcasecmp(atom + 1, "elete"))
904 return TOKEN_DELETE;
905 if (!strncasecmp(atom + 1, "efault", 6)) {
906 if (!atom [7])
907 return DEFAULT;
908 if (!strcasecmp(atom + 7, "-duid"))
909 return DEFAULT_DUID;
910 if (!strcasecmp(atom + 7, "-lease-time"))
911 return DEFAULT_LEASE_TIME;
912 break;
913 }
914 if (!strncasecmp(atom + 1, "ynamic", 6)) {
915 if (!atom [7])
916 return DYNAMIC;
917 if (!strncasecmp(atom + 7, "-bootp", 6)) {
918 if (!atom [13])
919 return DYNAMIC_BOOTP;
920 if (!strcasecmp(atom + 13, "-lease-cutoff"))
921 return DYNAMIC_BOOTP_LEASE_CUTOFF;
922 if (!strcasecmp(atom + 13, "-lease-length"))
923 return DYNAMIC_BOOTP_LEASE_LENGTH;
924 break;
925 }
926 }
927 if (!strcasecmp(atom + 1, "uplicates"))
928 return DUPLICATES;
929 if (!strcasecmp(atom + 1, "eclines"))
930 return DECLINES;
931 if (!strncasecmp(atom + 1, "efine", 5)) {
932 if (!strcasecmp(atom + 6, "d"))
933 return DEFINED;
934 if (!atom [6])
935 return DEFINE;
936 }
937 break;
938 case 'e':
939 if (isascii(atom [1]) &&
940 tolower((unsigned char)atom[1]) == 'x') {
941 if (!strcasecmp(atom + 2, "tract-int"))
942 return EXTRACT_INT;
943 if (!strcasecmp(atom + 2, "ists"))
944 return EXISTS;
945 if (!strcasecmp(atom + 2, "piry"))
946 return EXPIRY;
947 if (!strcasecmp(atom + 2, "pire"))
948 return EXPIRE;
949 if (!strcasecmp(atom + 2, "pired"))
950 return TOKEN_EXPIRED;
951 }
952 if (!strcasecmp(atom + 1, "ncode-int"))
953 return ENCODE_INT;
954 if (!strcasecmp(atom + 1, "poch"))
955 return EPOCH;
956 if (!strcasecmp(atom + 1, "thernet"))
957 return ETHERNET;
958 if (!strcasecmp(atom + 1, "nds"))
959 return ENDS;
960 if (!strncasecmp(atom + 1, "ls", 2)) {
961 if (!strcasecmp(atom + 3, "e"))
962 return ELSE;
963 if (!strcasecmp(atom + 3, "if"))
964 return ELSIF;
965 break;
966 }
967 if (!strcasecmp(atom + 1, "rror"))
968 return ERROR;
969 if (!strcasecmp(atom + 1, "val"))
970 return EVAL;
971 if (!strcasecmp(atom + 1, "ncapsulate"))
972 return ENCAPSULATE;
973 if (!strcasecmp(atom + 1, "xecute"))
974 return EXECUTE;
975 if (!strcasecmp(atom+1, "n")) {
976 return EN;
977 }
978 break;
979 case 'f':
980 if (!strcasecmp(atom + 1, "atal"))
981 return FATAL;
982 if (!strcasecmp(atom + 1, "ilename"))
983 return FILENAME;
984 if (!strcasecmp(atom + 1, "ixed-address"))
985 return FIXED_ADDR;
986 if (!strcasecmp(atom + 1, "ixed-address6"))
987 return FIXED_ADDR6;
988 if (!strcasecmp(atom + 1, "ixed-prefix6"))
989 return FIXED_PREFIX6;
990 if (!strcasecmp(atom + 1, "ddi"))
991 return TOKEN_FDDI;
992 if (!strcasecmp(atom + 1, "ormerr"))
993 return NS_FORMERR;
994 if (!strcasecmp(atom + 1, "unction"))
995 return FUNCTION;
996 if (!strcasecmp(atom + 1, "ailover"))
997 return FAILOVER;
998 if (!strcasecmp(atom + 1, "ree"))
999 return TOKEN_FREE;
1000 break;
1001 case 'g':
1002 if (!strncasecmp(atom + 1, "et", 2)) {
1003 if (!strcasecmp(atom + 3, "-lease-hostnames"))
1004 return GET_LEASE_HOSTNAMES;
1005 if (!strcasecmp(atom + 3, "hostbyname"))
1006 return GETHOSTBYNAME;
1007 if (!strcasecmp(atom + 3, "hostname"))
1008 return GETHOSTNAME;
1009 break;
1010 }
1011 if (!strcasecmp(atom + 1, "iaddr"))
1012 return GIADDR;
1013 if (!strcasecmp(atom + 1, "roup"))
1014 return GROUP;
1015 break;
1016 case 'h':
1017 if (!strcasecmp(atom + 1, "ash"))
1018 return HASH;
1019 if (!strcasecmp(atom + 1, "ba"))
1020 return HBA;
1021 if (!strcasecmp(atom + 1, "ost"))
1022 return HOST;
1023 if (!strcasecmp(atom + 1, "ost-decl-name"))
1024 return HOST_DECL_NAME;
1025 if (!strcasecmp(atom + 1, "ost-identifier"))
1026 return HOST_IDENTIFIER;
1027 if (!strcasecmp(atom + 1, "ardware"))
1028 return HARDWARE;
1029 if (!strcasecmp(atom + 1, "ostname"))
1030 return HOSTNAME;
1031 if (!strcasecmp(atom + 1, "elp"))
1032 return TOKEN_HELP;
1033 if (!strcasecmp(atom + 1, "ex")) {
1034 return TOKEN_HEX;
1035 }
1036 break;
1037 case 'i':
1038 if (!strcasecmp(atom+1, "a-na"))
1039 return IA_NA;
1040 if (!strcasecmp(atom+1, "a-ta"))
1041 return IA_TA;
1042 if (!strcasecmp(atom+1, "a-pd"))
1043 return IA_PD;
1044 if (!strcasecmp(atom+1, "aaddr"))
1045 return IAADDR;
1046 if (!strcasecmp(atom+1, "aprefix"))
1047 return IAPREFIX;
1048 if (!strcasecmp(atom + 1, "nclude"))
1049 return INCLUDE;
1050 if (!strcasecmp(atom + 1, "nteger"))
1051 return INTEGER;
1052 if (!strcasecmp(atom + 1, "nfiniband"))
1053 return TOKEN_INFINIBAND;
1054 if (!strcasecmp(atom + 1, "nfinite"))
1055 return INFINITE;
1056 if (!strcasecmp(atom + 1, "nfo"))
1057 return INFO;
1058 if (!strcasecmp(atom + 1, "p-address"))
1059 return IP_ADDRESS;
1060 if (!strcasecmp(atom + 1, "p6-address"))
1061 return IP6_ADDRESS;
1062 if (!strcasecmp(atom + 1, "nitial-interval"))
1063 return INITIAL_INTERVAL;
1064 if (!strcasecmp(atom + 1, "nitial-delay"))
1065 return INITIAL_DELAY;
1066 if (!strcasecmp(atom + 1, "nterface"))
1067 return INTERFACE;
1068 if (!strcasecmp(atom + 1, "dentifier"))
1069 return IDENTIFIER;
1070 if (!strcasecmp(atom + 1, "f"))
1071 return IF;
1072 if (!strcasecmp(atom + 1, "s"))
1073 return IS;
1074 if (!strcasecmp(atom + 1, "gnore"))
1075 return IGNORE;
1076 break;
1077 case 'k':
1078 if (!strncasecmp(atom + 1, "nown", 4)) {
1079 if (!strcasecmp(atom + 5, "-clients"))
1080 return KNOWN_CLIENTS;
1081 if (!atom[5])
1082 return KNOWN;
1083 break;
1084 }
1085 if (!strcasecmp(atom + 1, "ey"))
1086 return KEY;
1087 if (!strcasecmp (atom + 1, "ey-algorithm"))
1088 return KEY_ALGORITHM;
1089 break;
1090 case 'l':
1091 if (!strcasecmp(atom + 1, "case"))
1092 return LCASE;
1093 if (!strcasecmp(atom + 1, "ease"))
1094 return LEASE;
1095 if (!strcasecmp(atom + 1, "ease6"))
1096 return LEASE6;
1097 if (!strcasecmp(atom + 1, "eased-address"))
1098 return LEASED_ADDRESS;
1099 if (!strcasecmp(atom + 1, "ease-time"))
1100 return LEASE_TIME;
1101 if (!strcasecmp(atom + 1, "easequery"))
1102 return LEASEQUERY;
1103 if (!strcasecmp(atom + 1, "ength"))
1104 return LENGTH;
1105 if (!strcasecmp(atom + 1, "imit"))
1106 return LIMIT;
1107 if (!strcasecmp(atom + 1, "et"))
1108 return LET;
1109 if (!strcasecmp(atom + 1, "oad"))
1110 return LOAD;
1111 if (!strcasecmp(atom + 1, "ocal"))
1112 return LOCAL;
1113 if (!strcasecmp(atom + 1, "og"))
1114 return LOG;
1115 if (!strcasecmp(atom+1, "lt")) {
1116 return LLT;
1117 }
1118 if (!strcasecmp(atom+1, "l")) {
1119 return LL;
1120 }
1121 if (!strcasecmp(atom+1, "ittle-endian")) {
1122 return TOKEN_LITTLE_ENDIAN;
1123 }
1124 if (!strcasecmp(atom + 1, "ease-id-format")) {
1125 return LEASE_ID_FORMAT;
1126 }
1127 break;
1128 case 'm':
1129 if (!strncasecmp(atom + 1, "ax", 2)) {
1130 if (!atom [3])
1131 return TOKEN_MAX;
1132 if (!strcasecmp(atom + 3, "-balance"))
1133 return MAX_BALANCE;
1134 if (!strncasecmp(atom + 3, "-lease-", 7)) {
1135 if (!strcasecmp(atom + 10, "misbalance"))
1136 return MAX_LEASE_MISBALANCE;
1137 if (!strcasecmp(atom + 10, "ownership"))
1138 return MAX_LEASE_OWNERSHIP;
1139 if (!strcasecmp(atom + 10, "time"))
1140 return MAX_LEASE_TIME;
1141 }
1142 if (!strcasecmp(atom + 3, "-life"))
1143 return MAX_LIFE;
1144 if (!strcasecmp(atom + 3, "-transmit-idle"))
1145 return MAX_TRANSMIT_IDLE;
1146 if (!strcasecmp(atom + 3, "-response-delay"))
1147 return MAX_RESPONSE_DELAY;
1148 if (!strcasecmp(atom + 3, "-unacked-updates"))
1149 return MAX_UNACKED_UPDATES;
1150 }
1151 if (!strncasecmp(atom + 1, "in-", 3)) {
1152 if (!strcasecmp(atom + 4, "balance"))
1153 return MIN_BALANCE;
1154 if (!strcasecmp(atom + 4, "lease-time"))
1155 return MIN_LEASE_TIME;
1156 if (!strcasecmp(atom + 4, "secs"))
1157 return MIN_SECS;
1158 break;
1159 }
1160 if (!strncasecmp(atom + 1, "edi", 3)) {
1161 if (!strcasecmp(atom + 4, "a"))
1162 return MEDIA;
1163 if (!strcasecmp(atom + 4, "um"))
1164 return MEDIUM;
1165 break;
1166 }
1167 if (!strcasecmp(atom + 1, "atch"))
1168 return MATCH;
1169 if (!strcasecmp(atom + 1, "embers"))
1170 return MEMBERS;
1171 if (!strcasecmp(atom + 1, "y"))
1172 return MY;
1173 if (!strcasecmp(atom + 1, "clt"))
1174 return MCLT;
1175 break;
1176 case 'n':
1177 if (!strcasecmp(atom + 1, "ormal"))
1178 return NORMAL;
1179 if (!strcasecmp(atom + 1, "ameserver"))
1180 return NAMESERVER;
1181 if (!strcasecmp(atom + 1, "etmask"))
1182 return NETMASK;
1183 if (!strcasecmp(atom + 1, "ever"))
1184 return NEVER;
1185 if (!strcasecmp(atom + 1, "ext-server"))
1186 return NEXT_SERVER;
1187 if (!strcasecmp(atom + 1, "ot"))
1188 return TOKEN_NOT;
1189 if (!strcasecmp(atom + 1, "o"))
1190 return TOKEN_NO;
1191 if (!strcasecmp(atom + 1, "oerror"))
1192 return NS_NOERROR;
1193 if (!strcasecmp(atom + 1, "otauth"))
1194 return NS_NOTAUTH;
1195 if (!strcasecmp(atom + 1, "otimp"))
1196 return NS_NOTIMP;
1197 if (!strcasecmp(atom + 1, "otzone"))
1198 return NS_NOTZONE;
1199 if (!strcasecmp(atom + 1, "xdomain"))
1200 return NS_NXDOMAIN;
1201 if (!strcasecmp(atom + 1, "xrrset"))
1202 return NS_NXRRSET;
1203 if (!strcasecmp(atom + 1, "ull"))
1204 return TOKEN_NULL;
1205 if (!strcasecmp(atom + 1, "ext"))
1206 return TOKEN_NEXT;
1207 if (!strcasecmp(atom + 1, "ew"))
1208 return TOKEN_NEW;
1209 break;
1210 case 'o':
1211 if (!strcasecmp(atom + 1, "mapi"))
1212 return OMAPI;
1213 if (!strcasecmp(atom + 1, "r"))
1214 return OR;
1215 if (!strcasecmp(atom + 1, "n"))
1216 return ON;
1217 if (!strcasecmp(atom + 1, "pen"))
1218 return TOKEN_OPEN;
1219 if (!strcasecmp(atom + 1, "ption"))
1220 return OPTION;
1221 if (!strcasecmp(atom + 1, "ne-lease-per-client"))
1222 return ONE_LEASE_PER_CLIENT;
1223 if (!strcasecmp(atom + 1, "f"))
1224 return OF;
1225 if (!strcasecmp(atom + 1, "wner"))
1226 return OWNER;
1227 if (!strcasecmp(atom + 1, "ctal")) {
1228 return TOKEN_OCTAL;
1229 }
1230 break;
1231 case 'p':
1232 if (!strcasecmp(atom + 1, "arse-vendor-option"))
1233 return PARSE_VENDOR_OPT;
1234 if (!strcasecmp(atom + 1, "repend"))
1235 return PREPEND;
1236 if (!strcasecmp(atom + 1, "referred-life"))
1237 return PREFERRED_LIFE;
1238 if (!strcasecmp(atom + 1, "acket"))
1239 return PACKET;
1240 if (!strcasecmp(atom + 1, "ool"))
1241 return POOL;
1242 if (!strcasecmp(atom + 1, "ool6"))
1243 return POOL6;
1244 if (!strcasecmp(atom + 1, "refix6"))
1245 return PREFIX6;
1246 if (!strcasecmp(atom + 1, "seudo"))
1247 return PSEUDO;
1248 if (!strcasecmp(atom + 1, "eer"))
1249 return PEER;
1250 if (!strcasecmp(atom + 1, "rimary"))
1251 return PRIMARY;
1252 if (!strcasecmp(atom + 1, "rimary6"))
1253 return PRIMARY6;
1254 if (!strncasecmp(atom + 1, "artner", 6)) {
1255 if (!atom [7])
1256 return PARTNER;
1257 if (!strcasecmp(atom + 7, "-down"))
1258 return PARTNER_DOWN;
1259 }
1260 if (!strcasecmp(atom + 1, "ort"))
1261 return PORT;
1262 if (!strcasecmp(atom + 1, "otential-conflict"))
1263 return POTENTIAL_CONFLICT;
1264 if (!strcasecmp(atom + 1, "ick-first-value") ||
1265 !strcasecmp(atom + 1, "ick"))
1266 return PICK;
1267 if (!strcasecmp(atom + 1, "aused"))
1268 return PAUSED;
1269 break;
1270 case 'r':
1271 if (!strcasecmp(atom + 1, "ange"))
1272 return RANGE;
1273 if (!strcasecmp(atom + 1, "ange6"))
1274 return RANGE6;
1275 if (isascii(atom[1]) &&
1276 (tolower((unsigned char)atom[1]) == 'e')) {
1277 if (!strcasecmp(atom + 2, "bind"))
1278 return REBIND;
1279 if (!strcasecmp(atom + 2, "boot"))
1280 return REBOOT;
1281 if (!strcasecmp(atom + 2, "contact-interval"))
1282 return RECONTACT_INTERVAL;
1283 if (!strncasecmp(atom + 2, "cover", 5)) {
1284 if (atom[7] == '\0')
1285 return RECOVER;
1286 if (!strcasecmp(atom + 7, "-done"))
1287 return RECOVER_DONE;
1288 if (!strcasecmp(atom + 7, "-wait"))
1289 return RECOVER_WAIT;
1290 break;
1291 }
1292 if (!strcasecmp(atom + 2, "fresh"))
1293 return REFRESH;
1294 if (!strcasecmp(atom + 2, "fused"))
1295 return NS_REFUSED;
1296 if (!strcasecmp(atom + 2, "ject"))
1297 return REJECT;
1298 if (!strcasecmp(atom + 2, "lease"))
1299 return RELEASE;
1300 if (!strcasecmp(atom + 2, "leased"))
1301 return TOKEN_RELEASED;
1302 if (!strcasecmp(atom + 2, "move"))
1303 return REMOVE;
1304 if (!strcasecmp(atom + 2, "new"))
1305 return RENEW;
1306 if (!strcasecmp(atom + 2, "quest"))
1307 return REQUEST;
1308 if (!strcasecmp(atom + 2, "quire"))
1309 return REQUIRE;
1310 if (isascii(atom[2]) &&
1311 (tolower((unsigned char)atom[2]) == 's')) {
1312 if (!strcasecmp(atom + 3, "erved"))
1313 return TOKEN_RESERVED;
1314 if (!strcasecmp(atom + 3, "et"))
1315 return TOKEN_RESET;
1316 if (!strcasecmp(atom + 3,
1317 "olution-interrupted"))
1318 return RESOLUTION_INTERRUPTED;
1319 break;
1320 }
1321 if (!strcasecmp(atom + 2, "try"))
1322 return RETRY;
1323 if (!strcasecmp(atom + 2, "turn"))
1324 return RETURN;
1325 if (!strcasecmp(atom + 2, "verse"))
1326 return REVERSE;
1327 if (!strcasecmp(atom + 2, "wind"))
1328 return REWIND;
1329 break;
1330 }
1331 break;
1332 case 's':
1333 if (!strcasecmp(atom + 1, "cript"))
1334 return SCRIPT;
1335 if (isascii(atom[1]) &&
1336 tolower((unsigned char)atom[1]) == 'e') {
1337 if (!strcasecmp(atom + 2, "arch"))
1338 return SEARCH;
1339 if (isascii(atom[2]) &&
1340 tolower((unsigned char)atom[2]) == 'c') {
1341 if (!strncasecmp(atom + 3, "ond", 3)) {
1342 if (!strcasecmp(atom + 6, "ary"))
1343 return SECONDARY;
1344 if (!strcasecmp(atom + 6, "ary6"))
1345 return SECONDARY6;
1346 if (!strcasecmp(atom + 6, "s"))
1347 return SECONDS;
1348 break;
1349 }
1350 if (!strcasecmp(atom + 3, "ret"))
1351 return SECRET;
1352 break;
1353 }
1354 if (!strncasecmp(atom + 2, "lect", 4)) {
1355 if (atom[6] == '\0')
1356 return SELECT;
1357 if (!strcasecmp(atom + 6, "-timeout"))
1358 return SELECT_TIMEOUT;
1359 break;
1360 }
1361 if (!strcasecmp(atom + 2, "nd"))
1362 return SEND;
1363 if (!strncasecmp(atom + 2, "rv", 2)) {
1364 if (!strncasecmp(atom + 4, "er", 2)) {
1365 if (atom[6] == '\0')
1366 return TOKEN_SERVER;
1367 if (atom[6] == '-') {
1368 if (!strcasecmp(atom + 7,
1369 "duid"))
1370 return SERVER_DUID;
1371 if (!strcasecmp(atom + 7,
1372 "name"))
1373 return SERVER_NAME;
1374 if (!strcasecmp(atom + 7,
1375 "identifier"))
1376 return SERVER_IDENTIFIER;
1377 break;
1378 }
1379 break;
1380 }
1381 if (!strcasecmp(atom + 4, "fail"))
1382 return NS_SERVFAIL;
1383 break;
1384 }
1385 if (!strcasecmp(atom + 2, "t"))
1386 return TOKEN_SET;
1387 break;
1388 }
1389 if (isascii(atom[1]) &&
1390 tolower((unsigned char)atom[1]) == 'h') {
1391 if (!strcasecmp(atom + 2, "ared-network"))
1392 return SHARED_NETWORK;
1393 if (!strcasecmp(atom + 2, "utdown"))
1394 return SHUTDOWN;
1395 break;
1396 }
1397 if (isascii(atom[1]) &&
1398 tolower((unsigned char)atom[1]) == 'i') {
1399 if (!strcasecmp(atom + 2, "addr"))
1400 return SIADDR;
1401 if (!strcasecmp(atom + 2, "gned"))
1402 return SIGNED;
1403 if (!strcasecmp(atom + 2, "ze"))
1404 return SIZE;
1405 break;
1406 }
1407 if (isascii(atom[1]) &&
1408 tolower((unsigned char)atom[1]) == 'p') {
1409 if (isascii(atom[2]) &&
1410 tolower((unsigned char)atom[2]) == 'a') {
1411 if (!strcasecmp(atom + 3, "ce"))
1412 return SPACE;
1413 if (!strcasecmp(atom + 3, "wn"))
1414 return SPAWN;
1415 break;
1416 }
1417 if (!strcasecmp(atom + 2, "lit"))
1418 return SPLIT;
1419 break;
1420 }
1421 if (isascii(atom[1]) &&
1422 tolower((unsigned char)atom[1]) == 't') {
1423 if (isascii(atom[2]) &&
1424 tolower((unsigned char)atom[2]) == 'a') {
1425 if (!strncasecmp(atom + 3, "rt", 2)) {
1426 if (!strcasecmp(atom + 5, "s"))
1427 return STARTS;
1428 if (!strcasecmp(atom + 5, "up"))
1429 return STARTUP;
1430 break;
1431 }
1432 if (isascii(atom[3]) &&
1433 tolower((unsigned char)atom[3]) == 't') {
1434 if (!strcasecmp(atom + 4, "e"))
1435 return STATE;
1436 if (!strcasecmp(atom + 4, "ic"))
1437 return STATIC;
1438 break;
1439 }
1440 }
1441 if (!strcasecmp(atom + 2, "ring"))
1442 return STRING_TOKEN;
1443 break;
1444 }
1445 if (!strncasecmp(atom + 1, "ub", 2)) {
1446 if (!strcasecmp(atom + 3, "class"))
1447 return SUBCLASS;
1448 if (!strcasecmp(atom + 3, "net"))
1449 return SUBNET;
1450 if (!strcasecmp(atom + 3, "net6"))
1451 return SUBNET6;
1452 if (!strcasecmp(atom + 3, "string"))
1453 return SUBSTRING;
1454 break;
1455 }
1456 if (isascii(atom[1]) &&
1457 tolower((unsigned char)atom[1]) == 'u') {
1458 if (!strcasecmp(atom + 2, "ffix"))
1459 return SUFFIX;
1460 if (!strcasecmp(atom + 2, "persede"))
1461 return SUPERSEDE;
1462 }
1463 if (!strcasecmp(atom + 1, "witch"))
1464 return SWITCH;
1465 break;
1466 case 't':
1467 if (!strcasecmp(atom + 1, "imestamp"))
1468 return TIMESTAMP;
1469 if (!strcasecmp(atom + 1, "imeout"))
1470 return TIMEOUT;
1471 if (!strcasecmp(atom + 1, "oken-ring"))
1472 return TOKEN_RING;
1473 if (!strcasecmp(atom + 1, "ext"))
1474 return TEXT;
1475 if (!strcasecmp(atom + 1, "stp"))
1476 return TSTP;
1477 if (!strcasecmp(atom + 1, "sfp"))
1478 return TSFP;
1479 if (!strcasecmp(atom + 1, "ransmission"))
1480 return TRANSMISSION;
1481 if (!strcasecmp(atom + 1, "emporary"))
1482 return TEMPORARY;
1483 break;
1484 case 'u':
1485 if (!strcasecmp(atom + 1, "case"))
1486 return UCASE;
1487 if (!strcasecmp(atom + 1, "nset"))
1488 return UNSET;
1489 if (!strcasecmp(atom + 1, "nsigned"))
1490 return UNSIGNED;
1491 if (!strcasecmp(atom + 1, "id"))
1492 return UID;
1493 if (!strncasecmp(atom + 1, "se", 2)) {
1494 if (!strcasecmp(atom + 3, "r-class"))
1495 return USER_CLASS;
1496 if (!strcasecmp(atom + 3, "-host-decl-names"))
1497 return USE_HOST_DECL_NAMES;
1498 if (!strcasecmp(atom + 3,
1499 "-lease-addr-for-default-route"))
1500 return USE_LEASE_ADDR_FOR_DEFAULT_ROUTE;
1501 break;
1502 }
1503 if (!strncasecmp(atom + 1, "nknown", 6)) {
1504 if (!strcasecmp(atom + 7, "-clients"))
1505 return UNKNOWN_CLIENTS;
1506 if (!strcasecmp(atom + 7, "-state"))
1507 return UNKNOWN_STATE;
1508 if (!atom [7])
1509 return UNKNOWN;
1510 break;
1511 }
1512 if (!strcasecmp(atom + 1, "nauthenticated"))
1513 return UNAUTHENTICATED;
1514 if (!strcasecmp(atom + 1, "pdate"))
1515 return UPDATE;
1516 break;
1517 case 'v':
1518 if (!strcasecmp(atom + 1, "6relay"))
1519 return V6RELAY;
1520 if (!strcasecmp(atom + 1, "6relopt"))
1521 return V6RELOPT;
1522 if (!strcasecmp(atom + 1, "endor-class"))
1523 return VENDOR_CLASS;
1524 if (!strcasecmp(atom + 1, "endor"))
1525 return VENDOR;
1526 break;
1527 case 'w':
1528 if (!strcasecmp(atom + 1, "ith"))
1529 return WITH;
1530 if (!strcasecmp(atom + 1, "idth"))
1531 return WIDTH;
1532 break;
1533 case 'y':
1534 if (!strcasecmp(atom + 1, "iaddr"))
1535 return YIADDR;
1536 if (!strcasecmp(atom + 1, "xdomain"))
1537 return NS_YXDOMAIN;
1538 if (!strcasecmp(atom + 1, "xrrset"))
1539 return NS_YXRRSET;
1540 break;
1541 case 'z':
1542 if (!strcasecmp(atom + 1, "erolen"))
1543 return ZEROLEN;
1544 if (!strcasecmp(atom + 1, "one"))
1545 return ZONE;
1546 break;
1547 }
1548 return dfv;
1549 }
1550
1551