/* $KAME: parser.y,v 1.8 2000/11/08 03:03:34 jinmei Exp $ */ /* * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. Neither the name of the project nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * $FreeBSD: src/usr.sbin/rrenumd/parser.y,v 1.1.2.2 2001/07/03 11:02:10 ume Exp $ * $DragonFly: src/usr.sbin/rrenumd/parser.y,v 1.4 2004/02/10 02:59:43 rob Exp $ */ %{ #include #include #include #include #include #include #if defined(__DragonFly__) #include #endif /* __DragonFly__ */ #include #include #include #include #include #include #include "rrenumd.h" struct config_is_set { u_short cis_dest : 1; } cis; struct dst_list *dl_head; struct payload_list *pl_head, ple_cur; u_int retry; char errbuf[LINE_MAX]; extern int lineno; extern void yyerror(const char *s); extern int yylex(void); static struct payload_list * pllist_lookup(int seqnum); static void pllist_enqueue(struct payload_list *pl_entry); #define MAX_RETRYNUM 10 /* upper limit of retry in this rrenumd program */ #define MAX_SEQNUM 256 /* upper limit of seqnum in this rrenumd program */ #define NOSPEC -1 %} %union { u_long num; struct { char *cp; int len; } cs; struct in_addr addr4; struct in6_addr addr6; struct { struct in6_addr addr; u_char plen; } prefix; struct dst_list *dl; struct payload_list *pl; struct sockaddr *sa; } %token ADD CHANGE SETGLOBAL %token DEBUG_CMD DEST_CMD RETRY_CMD SEQNUM_CMD %token MATCH_PREFIX_CMD MAXLEN_CMD MINLEN_CMD %token USE_PREFIX_CMD KEEPLEN_CMD %token VLTIME_CMD PLTIME_CMD %token RAF_ONLINK_CMD RAF_AUTO_CMD RAF_DECRVALID_CMD RAF_DECRPREFD_CMD %token DAYS HOURS MINUTES SECONDS INFINITY %token ON OFF %token BCL ECL EOS ERROR %token NAME HOSTNAME QSTRING DECSTRING %token IPV4ADDR %token IPV6ADDR %token PREFIXLEN %type retrynum seqnum rrenum_cmd %type prefixlen maxlen minlen keeplen vltime pltime %type lifetime days hours minutes seconds %type decstring %type raf_onlink raf_auto raf_decrvalid raf_decrprefd flag %type
dest_addrs dest_addr sin sin6 %type rrenum_statement %type ifname %type prefixval %% config: /* empty */ | statements ; statements: statement | statements statement ; statement: debug_statement | destination_statement | rrenum_statement_without_seqnum | rrenum_statement_with_seqnum | error EOS { yyerrok; } | EOS ; debug_statement: DEBUG_CMD flag EOS { #ifdef YYDEBUG yydebug = $2; #endif /* YYDEBUG */ } ; destination_statement: DEST_CMD dest_addrs retrynum EOS { dl_head = $2; retry = $3; } ; dest_addrs: dest_addr | dest_addrs dest_addr { $2->dl_next = $1; $$ = $2; } ; dest_addr : sin { with_v4dest = 1; } | sin6 { with_v6dest = 1; } | sin6 ifname { struct sockaddr_in6 *sin6; sin6 = (struct sockaddr_in6 *)$1->dl_dst; sin6->sin6_scope_id = if_nametoindex($2.cp); with_v6dest = 1; $$ = $1; } | HOSTNAME { struct sockaddr_storage *ss; struct addrinfo hints, *res; int error; memset(&hints, 0, sizeof(hints)); hints.ai_flags = AI_CANONNAME; hints.ai_family = AF_UNSPEC; hints.ai_socktype = SOCK_RAW; hints.ai_protocol = 0; error = getaddrinfo($1.cp, 0, &hints, &res); if (error) { snprintf(errbuf, sizeof(errbuf), "name resolution failed for %s:%s", $1.cp, gai_strerror(error)); yyerror(errbuf); } ss = (struct sockaddr_storage *)malloc(sizeof(*ss)); memset(ss, 0, sizeof(*ss)); memcpy(ss, res->ai_addr, res->ai_addr->sa_len); freeaddrinfo(res); $$ = (struct dst_list *) malloc(sizeof(struct dst_list)); memset($$, 0, sizeof(struct dst_list)); $$->dl_dst = (struct sockaddr *)ss; } ; sin: IPV4ADDR { struct sockaddr_in *sin; sin = (struct sockaddr_in *)malloc(sizeof(*sin)); memset(sin, 0, sizeof(*sin)); sin->sin_len = sizeof(*sin); sin->sin_family = AF_INET; sin->sin_addr = $1; $$ = (struct dst_list *) malloc(sizeof(struct dst_list)); memset($$, 0, sizeof(struct dst_list)); $$->dl_dst = (struct sockaddr *)sin; } ; sin6: IPV6ADDR { struct sockaddr_in6 *sin6; sin6 = (struct sockaddr_in6 *)malloc(sizeof(*sin6)); memset(sin6, 0, sizeof(*sin6)); sin6->sin6_len = sizeof(*sin6); sin6->sin6_family = AF_INET6; sin6->sin6_addr = $1; $$ = (struct dst_list *) malloc(sizeof(struct dst_list)); memset($$, 0, sizeof(struct dst_list)); $$->dl_dst = (struct sockaddr *)sin6; } ifname: NAME { $$.cp = strdup($1.cp); $$.len = $1.len; } | QSTRING { $1.cp[$1.len - 1] = 0; $$.cp = strdup(&$1.cp[1]); $$.len = $1.len - 2; } ; retrynum: /* empty */ { $$ = 2; } | RETRY_CMD decstring { if ($2 > MAX_RETRYNUM) $2 = MAX_RETRYNUM; $$ = $2; } ; rrenum_statement_with_seqnum: SEQNUM_CMD seqnum { if (pllist_lookup($2)) { snprintf(errbuf, sizeof(errbuf), "duplicate seqnum %ld specified at %d", $2, lineno); yyerror(errbuf); } } BCL rrenum_statement EOS ECL EOS { $5->pl_irr.rr_seqnum = $2; pllist_enqueue($5); } ; seqnum: /* empty */ { $$ = 0; } | decstring { if ($1 > MAX_SEQNUM) { snprintf(errbuf, sizeof(errbuf), "seqnum %ld is illegal for this program. " "should be between 0 and %d", $1, MAX_SEQNUM); yyerror(errbuf); } $$ = $1; } ; rrenum_statement_without_seqnum: rrenum_statement EOS { if (pllist_lookup(0)) { snprintf(errbuf, sizeof(errbuf), "duplicate seqnum %d specified at %d", 0, lineno); yyerror(errbuf); } $1->pl_irr.rr_seqnum = 0; pllist_enqueue($1); } ; rrenum_statement: match_prefix_definition use_prefix_definition { $$ = (struct payload_list *) malloc(sizeof(struct payload_list)); memcpy($$, &ple_cur, sizeof(ple_cur)); } ; match_prefix_definition: rrenum_cmd MATCH_PREFIX_CMD prefixval maxlen minlen { struct icmp6_router_renum *irr; struct rr_pco_match *rpm; irr = (struct icmp6_router_renum *)&ple_cur.pl_irr; rpm = (struct rr_pco_match *)(irr + 1); memset(rpm, 0, sizeof(*rpm)); rpm->rpm_code = $1; rpm->rpm_prefix = $3.addr; rpm->rpm_matchlen = $3.plen; rpm->rpm_maxlen = $4; rpm->rpm_minlen = $5; } ; rrenum_cmd: /* empty */ { $$ = RPM_PCO_ADD; } | ADD | CHANGE | SETGLOBAL ; prefixval: IPV6ADDR prefixlen { $$.addr = $1; $$.plen = $2; } ; prefixlen: /* empty */ { $$ = 64; } | PREFIXLEN ; maxlen: /* empty */ { $$ = 128; } | MAXLEN_CMD decstring { if ($2 > 128) $2 = 128; $$ = $2; } ; minlen: /* empty */ { $$ = 0; } | MINLEN_CMD decstring { if ($2 > 128) $2 = 128; $$ = $2; } ; use_prefix_definition: /* empty */ { struct icmp6_router_renum *irr; struct rr_pco_match *rpm; struct rr_pco_use *rpu; irr = (struct icmp6_router_renum *)&ple_cur.pl_irr; rpm = (struct rr_pco_match *)(irr + 1); rpu = (struct rr_pco_use *)(rpm + 1); memset(rpu, 0, sizeof(*rpu)); } | USE_PREFIX_CMD prefixval keeplen use_prefix_values { struct icmp6_router_renum *irr; struct rr_pco_match *rpm; struct rr_pco_use *rpu; irr = (struct icmp6_router_renum *)&ple_cur.pl_irr; rpm = (struct rr_pco_match *)(irr + 1); rpu = (struct rr_pco_use *)(rpm + 1); rpu->rpu_prefix = $2.addr; rpu->rpu_uselen = $2.plen; rpu->rpu_keeplen = $3; } ; use_prefix_values: /* empty */ { struct icmp6_router_renum *irr; struct rr_pco_match *rpm; struct rr_pco_use *rpu; irr = (struct icmp6_router_renum *)&ple_cur.pl_irr; rpm = (struct rr_pco_match *)(irr + 1); rpu = (struct rr_pco_use *)(rpm + 1); memset(rpu, 0, sizeof(*rpu)); rpu->rpu_vltime = htonl(DEF_VLTIME); rpu->rpu_pltime = htonl(DEF_PLTIME); rpu->rpu_ramask = 0; rpu->rpu_flags = 0; } | BCL vltime pltime raf_onlink raf_auto raf_decrvalid raf_decrprefd ECL { struct icmp6_router_renum *irr; struct rr_pco_match *rpm; struct rr_pco_use *rpu; irr = (struct icmp6_router_renum *)&ple_cur.pl_irr; rpm = (struct rr_pco_match *)(irr + 1); rpu = (struct rr_pco_use *)(rpm + 1); memset(rpu, 0, sizeof(*rpu)); rpu->rpu_vltime = $2; rpu->rpu_pltime = $3; if ($4 == NOSPEC) { rpu->rpu_ramask &= ~ICMP6_RR_PCOUSE_RAFLAGS_ONLINK; } else { rpu->rpu_ramask |= ICMP6_RR_PCOUSE_RAFLAGS_ONLINK; if ($4 == ON) { rpu->rpu_raflags |= ICMP6_RR_PCOUSE_RAFLAGS_ONLINK; } else { rpu->rpu_raflags &= ~ICMP6_RR_PCOUSE_RAFLAGS_ONLINK; } } if ($5 == NOSPEC) { rpu->rpu_ramask &= ICMP6_RR_PCOUSE_RAFLAGS_AUTO; } else { rpu->rpu_ramask |= ICMP6_RR_PCOUSE_RAFLAGS_AUTO; if ($5 == ON) { rpu->rpu_raflags |= ICMP6_RR_PCOUSE_RAFLAGS_AUTO; } else { rpu->rpu_raflags &= ~ICMP6_RR_PCOUSE_RAFLAGS_AUTO; } } rpu->rpu_flags = 0; if ($6 == ON) { rpu->rpu_flags |= ICMP6_RR_PCOUSE_FLAGS_DECRVLTIME; } if ($7 == ON) { rpu->rpu_flags |= ICMP6_RR_PCOUSE_FLAGS_DECRPLTIME; } } ; keeplen: /* empty */ { $$ = 0; } | KEEPLEN_CMD decstring { if ($2 > 128) $2 = 128; $$ = $2; } ; vltime: /* empty */ { $$ = htonl(DEF_VLTIME); } | VLTIME_CMD lifetime { $$ = htonl($2); } ; pltime: /* empty */ { $$ = htonl(DEF_PLTIME); } | PLTIME_CMD lifetime { $$ = htonl($2); } raf_onlink: /* empty */ { $$ = NOSPEC; } | RAF_ONLINK_CMD flag { $$ = $2; } ; raf_auto: /* empty */ { $$ = NOSPEC; } | RAF_AUTO_CMD flag { $$ = $2; } ; raf_decrvalid: /* empty */ { $$ = NOSPEC; } | RAF_DECRVALID_CMD flag { $$ = $2; } ; raf_decrprefd: /* empty */ { $$ = NOSPEC; } | RAF_DECRPREFD_CMD flag { $$ = $2; } ; flag: ON { $$ = ON; } | OFF { $$ = OFF; } ; lifetime: decstring | INFINITY { $$ = 0xffffffff; } | days hours minutes seconds { int d, h, m, s; d = $1 * 24 * 60 * 60; h = $2 * 60 * 60; m = $3 * 60; s = $4; $$ = d + h + m + s; } ; days: /* empty */ { $$ = 0; } | DAYS ; hours: /* empty */ { $$ = 0; } | HOURS ; minutes: /* empty */ { $$ = 0; } | MINUTES ; seconds: /* empty */ { $$ = 0; } | SECONDS ; decstring: DECSTRING { int dval; dval = atoi($1.cp); $$ = dval; } ; %% static struct payload_list * pllist_lookup(int seqnum) { struct payload_list *pl; for (pl = pl_head; pl && pl->pl_irr.rr_seqnum != seqnum; pl = pl->pl_next) continue; return (pl); } static void pllist_enqueue(struct payload_list *pl_entry) { struct payload_list *pl, *pl_last; pl_last = NULL; for (pl = pl_head; pl && pl->pl_irr.rr_seqnum < pl_entry->pl_irr.rr_seqnum; pl_last = pl, pl = pl->pl_next) continue; if (pl_last) pl_last->pl_next = pl_entry; else pl_head = pl_entry; return; }