78d51c7b15
Sponsored by: Nginx, Inc.
674 lines
12 KiB
Plaintext
674 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>
|
|
|
|
#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(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 <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;
|
|
}
|