%{ /* Yacc-style script for parsing DNS zone files. This file is part of WebDNS. */ /* * VSD - Virtual Server Daemon * Copyright (c) 2000 - 2001 Idaya Ltd. * * VSD is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either * version 2 of the License, or (at your option) any later version. * * VSD is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * * You should have received a copy of the GNU General Public License * along with VSD - see the COPYING file; if not, write to the * Free Software Foundation, Inc., 59 Temple Place - Suite 330, * Boston, MA 02111-1307, USA. */ /* * See the AUTHORS file for a list of contributors to VSD. * See the ChangeLog files for a list of changes. */ #include #include #include #include #include #include "vsd.h" #include "bind.h" struct inaddr { unsigned char b1, b2, b3, b4; }; static char token_buffer[256], class[16]; static int origin; #define MAX_STRINGS 16 static char *string_table[MAX_STRINGS]; int yylex (void); void yyerror (const char *msgid); static char *lookup_string (int pos); static int store_string (const char *string); static FILE *lex_input; static struct zonefile *lex_zone_file; #define YYSTYPE int %} %start input %token INCLUDE ORIGIN TTL %token NUM NUMBERS_DOTS %token NAME %token IN %token A CNAME GID HINFO MB MG MINFO MR MX NS NULLRR %token PTR RP SOA TXT UID UINFO WKS AFSDB %token TEXT %% input: /* empty */ | input line ; line: '\n' | statement ; statement: begin_statement | next_statement ; domain_name: NAME { $$ = $1; } | '.' { $$ = store_string ("."); } ; begin_statement: INCLUDE NAME domain_name | INCLUDE NAME | ORIGIN domain_name { zone_set_origin (lookup_string ($2)); } | TTL NUM { lex_zone_file->default_ttl = $2; } ; next_statement: domain_name { origin = $1; } IN { strcpy (class, "IN"); } resource_record | IN { origin = -1; strcpy (class, "IN"); } resource_record | resource_record ; resource_record: A NUMBERS_DOTS { zone_add_resource_record (lex_zone_file, -1, rr_a, lookup_string (origin), class, lookup_string ($2)); } | CNAME NAME { zone_add_resource_record (lex_zone_file, -1, rr_cname, lookup_string (origin), class, lookup_string ($2)); } | GID NUM { zone_add_resource_record (lex_zone_file, -1, rr_gid, lookup_string (origin), class, NULL, $2); } | HINFO NAME NAME { zone_add_resource_record (lex_zone_file, -1, rr_hinfo, lookup_string (origin), class, lookup_string ($2), lookup_string ($3)); } | MB NAME { zone_add_resource_record (lex_zone_file, -1, rr_mb, lookup_string (origin), class, lookup_string ($2)); } | MG NAME { zone_add_resource_record (lex_zone_file, -1, rr_mg, lookup_string (origin), class, lookup_string ($2)); } | MINFO NAME { zone_add_resource_record (lex_zone_file, -1, rr_minfo, lookup_string (origin), class, lookup_string ($2)); } | MR NAME { zone_add_resource_record (lex_zone_file, -1, rr_mr, lookup_string (origin), class, lookup_string ($2)); } | MX NUM NAME { zone_add_resource_record (lex_zone_file, -1, rr_mx, lookup_string (origin), class, lookup_string ($3), $2); } | NS NAME { zone_add_resource_record (lex_zone_file, -1, rr_ns, lookup_string (origin), class, lookup_string ($2)); } | NULLRR { printf ("resource record: NULLRR\n"); } | PTR NAME { zone_add_resource_record (lex_zone_file, -1, rr_ptr, lookup_string (origin), class, lookup_string ($2)); } | RP NAME NAME { printf ("resource record: RP %s\n", lookup_string ($2)); } | AFSDB NUM NAME { printf ("resource record: AFSDB %d %s\n", $2, lookup_string ($3)); } | SOA NAME NAME '(' mline NUM mline NUM mline NUM mline NUM mline NUM mline ')' { zone_add_resource_record (lex_zone_file, -1, rr_soa, lookup_string (origin), class, NULL, lookup_string ($2), lookup_string ($3), $6, $8, $10, $12, $14); } | SOA NAME NAME mline NUM mline NUM mline NUM mline NUM mline NUM mline { zone_add_resource_record (lex_zone_file, -1, rr_soa, lookup_string (origin), class, NULL, lookup_string ($2), lookup_string ($3), $5, $7, $9, $11, $13); } | TXT '"' TEXT '"' { zone_add_resource_record (lex_zone_file, -1, rr_ns, lookup_string (origin), class, lookup_string ($3)); } | UID NUM { zone_add_resource_record (lex_zone_file, -1, rr_uid, lookup_string (origin), class, NULL, $2); } | UINFO '?' { printf ("resource record: UINFO %s\n", lookup_string ($2)); } ; mline: /* empty */ { $$ = 0; } | '\n' { $$ = 1; } ; %% static int store_string (const char *string) { static int pos = 0; pos ++; if (pos >= MAX_STRINGS) pos = 0; if (string_table[pos]) free (string_table[pos]); string_table[pos] = (char *) malloc (strlen (string) + 1); strcpy (string_table[pos], string); return pos; } static char *lookup_string (int pos) { if (pos == -1) return NULL; return string_table[pos]; } void yyparse_init (FILE *input, struct zonefile *zone) { int x; for (x = 0; x < MAX_STRINGS; x++) string_table[x] = NULL; lex_input = input; lex_zone_file = zone; } void yyparse_final (void) { int x; for (x = 0; x < MAX_STRINGS; x++) if (string_table[x]) free (string_table[x]); } void skip_comment (FILE *stream) { int c; do { c = getc (stream); } while (c != EOF && c != '\n'); if (c == '\n') ungetc (c, stream); } int yylex (void) { int c, letter; char *p; try_again: c = getc (lex_input); while (1) switch (c) { case ' ': case '\t': case '\f': case '\v': case '\b': c = getc (lex_input); break; case ';': skip_comment (lex_input); c = getc (lex_input); default: goto found_nonwhite; } found_nonwhite: token_buffer[0] = c; token_buffer[1] = 0; switch (c) { case EOF: token_buffer[0] = 0; return 0; break; case '0': case '1': case '2': case '3': case '4': case '5': case '6': case '7': case '8': case '9': case 'A': case 'B': case 'C': case 'D': case 'E': case 'F': case 'G': case 'H': case 'I': case 'J': case 'K': case 'L': case 'M': case 'N': case 'O': case 'P': case 'Q': case 'R': case 'S': case 'T': case 'U': case 'V': case 'W': case 'X': case 'Y': case 'Z': case 'a': case 'b': case 'c': case 'd': case 'e': case 'f': case 'g': case 'h': case 'i': case 'j': case 'k': case 'l': case 'm': case 'n': case 'o': case 'p': case 'q': case 'r': case 's': case 't': case 'u': case 'v': case 'w': case 'x': case 'y': case 'z': p = token_buffer; letter = 0; while (isalnum (c) || c == '.' || c == '-') { if (isalpha (c)) letter = 1; *p++ = c; c = getc (lex_input); } *p = 0; if (c == ';') skip_comment (lex_input); /* Is it a number or an IP address ? */ if (! letter) { if (strchr (token_buffer, '.')) { /* IP address. */ yylval = store_string (token_buffer); return NUMBERS_DOTS; } else { yylval = atoi (token_buffer); return NUM; } } if (strcmp (token_buffer, "IN") == 0) return IN; if (strcmp (token_buffer, "A") == 0) return A; if (strcmp (token_buffer, "CNAME") == 0) return CNAME; if (strcmp (token_buffer, "GID") == 0) return GID; if (strcmp (token_buffer, "HINFO") == 0) return HINFO; if (strcmp (token_buffer, "MB") == 0) return MB; if (strcmp (token_buffer, "MG") == 0) return MG; if (strcmp (token_buffer, "MINFO") == 0) return MINFO; if (strcmp (token_buffer, "MR") == 0) return MR; if (strcmp (token_buffer, "MX") == 0) return MX; if (strcmp (token_buffer, "NS") == 0) return NS; if (strcmp (token_buffer, "NULLRR") == 0) return NULLRR; if (strcmp (token_buffer, "PTR") == 0) return PTR; if (strcmp (token_buffer, "RP") == 0) return RP; if (strcmp (token_buffer, "AFSDB") == 0) return AFSDB; if (strcmp (token_buffer, "SOA") == 0) return SOA; if (strcmp (token_buffer, "TXT") == 0) return TXT; if (strcmp (token_buffer, "UID") == 0) return UID; if (strcmp (token_buffer, "UINFO") == 0) return UINFO; if (strcmp (token_buffer, "WKS") == 0) return WKS; yylval = store_string (token_buffer); return NAME; break; case '@': yylval = store_string ("@"); return NAME; break; case '.': case '(': case ')': case '\n': return c; break; case ';': skip_comment (lex_input); goto try_again; break; case '$': p = token_buffer; while (isalnum (c) || c == '$') { *p++ = c; c = getc (lex_input); } *p = 0; if (c == ';') skip_comment (lex_input); yylval = store_string (token_buffer); if (strcmp (token_buffer, "$INCLUDE") == 0) return INCLUDE; if (strcmp (token_buffer, "$ORIGIN") == 0) return ORIGIN; if (strcmp (token_buffer, "$TTL") == 0) return TTL; break; case '*': /* Wildcard domain name. */ p = token_buffer; while (isalnum (c) || c == '*') { *p++ = c; c = getc (lex_input); } *p = 0; if (c == ';') skip_comment (lex_input); yylval = store_string (token_buffer); return NAME; break; } return 0; } void yyerror (const char *msgid) { /* printf ("error: %s (%s)\n", msgid, token_buffer); */ }