freebsd-skq/usr.sbin/rrenumd/parser.y
2002-10-27 17:46:53 +00:00

677 lines
12 KiB
Plaintext

/* $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$
*/
%{
#include <sys/param.h>
#include <sys/ioctl.h>
#include <sys/socket.h>
#include <sys/uio.h>
#include <sys/queue.h>
#include <net/if.h>
#if defined(__FreeBSD__) && __FreeBSD__ >= 3
#include <net/if_var.h>
#endif /* __FreeBSD__ >= 3 */
#include <netinet/in.h>
#include <netinet/in_var.h>
#include <netinet/icmp6.h>
#include <limits.h>
#include <netdb.h>
#include <string.h>
#include <stdio.h>
#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 __P((const char *s));
extern int yylex __P((void));
static struct payload_list * pllist_lookup __P((int seqnum));
static void pllist_enqueue __P((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 <num> 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 <num> DAYS HOURS MINUTES SECONDS INFINITY
%token <num> ON OFF
%token BCL ECL EOS ERROR
%token <cs> NAME HOSTNAME QSTRING DECSTRING
%token <addr4> IPV4ADDR
%token <addr6> IPV6ADDR
%token <num> PREFIXLEN
%type <num> retrynum seqnum rrenum_cmd
%type <num> prefixlen maxlen minlen keeplen vltime pltime
%type <num> lifetime days hours minutes seconds
%type <num> decstring
%type <num> raf_onlink raf_auto raf_decrvalid raf_decrprefd flag
%type <dl> dest_addrs dest_addr sin sin6
%type <pl> rrenum_statement
%type <cs> ifname
%type <prefix> 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;
}