summaryrefslogtreecommitdiff
path: root/usr.sbin/mrouted/cfparse.y
diff options
context:
space:
mode:
authorTheo de Raadt <deraadt@cvs.openbsd.org>1995-10-18 08:53:40 +0000
committerTheo de Raadt <deraadt@cvs.openbsd.org>1995-10-18 08:53:40 +0000
commitd6583bb2a13f329cf0332ef2570eb8bb8fc0e39c (patch)
treeece253b876159b39c620e62b6c9b1174642e070e /usr.sbin/mrouted/cfparse.y
initial import of NetBSD tree
Diffstat (limited to 'usr.sbin/mrouted/cfparse.y')
-rw-r--r--usr.sbin/mrouted/cfparse.y512
1 files changed, 512 insertions, 0 deletions
diff --git a/usr.sbin/mrouted/cfparse.y b/usr.sbin/mrouted/cfparse.y
new file mode 100644
index 00000000000..9538200f814
--- /dev/null
+++ b/usr.sbin/mrouted/cfparse.y
@@ -0,0 +1,512 @@
+%{
+/* $NetBSD: cfparse.y,v 1.3 1995/10/09 03:51:35 thorpej Exp $ */
+
+/*
+ * Configuration file parser for mrouted.
+ *
+ * Written by Bill Fenner, NRL, 1994
+ */
+#include <stdio.h>
+#include <string.h>
+#include <varargs.h>
+#include "defs.h"
+
+static FILE *f;
+
+extern int udp_socket;
+char *configfilename = _PATH_MROUTED_CONF;
+
+extern int cache_lifetime;
+extern int max_prune_lifetime;
+
+static int lineno;
+static struct ifreq ifbuf[32];
+static struct ifconf ifc;
+
+static struct uvif *v;
+
+static int order;
+
+struct addrmask {
+ u_int32_t addr;
+ int mask;
+};
+
+struct boundnam {
+ char *name;
+ struct addrmask bound;
+};
+
+#define MAXBOUNDS 20
+
+struct boundnam boundlist[MAXBOUNDS]; /* Max. of 20 named boundaries */
+int numbounds = 0; /* Number of named boundaries */
+
+%}
+
+%union
+{
+ int num;
+ char *ptr;
+ struct addrmask addrmask;
+ u_int32_t addr;
+};
+
+%token CACHE_LIFETIME PRUNING
+%token PHYINT TUNNEL NAME
+%token DISABLE METRIC THRESHOLD RATE_LIMIT SRCRT BOUNDARY NETMASK ALTNET
+%token <num> BOOLEAN
+%token <num> NUMBER
+%token <ptr> STRING
+%token <addrmask> ADDRMASK
+%token <addr> ADDR
+
+%type <addr> interface
+%type <addrmask> bound boundary addrmask
+
+%start conf
+
+%%
+
+conf : stmts
+ ;
+
+stmts : /* Empty */
+ | stmts stmt
+ ;
+
+stmt : error
+ | PHYINT interface {
+
+ vifi_t vifi;
+
+ if (order)
+ fatal("phyints must appear before tunnels");
+
+ for (vifi = 0, v = uvifs;
+ vifi < numvifs;
+ ++vifi, ++v)
+ if (!(v->uv_flags & VIFF_TUNNEL) &&
+ $2 == v->uv_lcl_addr)
+ break;
+
+ if (vifi == numvifs)
+ fatal("%s is not a configured interface",
+ inet_fmt($2,s1));
+
+ /*log(LOG_INFO, 0, "phyint: %x\n", v);*/
+ }
+ ifmods
+ | TUNNEL interface ADDR {
+
+ struct ifreq *ifr;
+ struct ifreq ffr;
+ vifi_t vifi;
+
+ order++;
+
+ ifr = ifconfaddr(&ifc, $2);
+ if (ifr == 0)
+ fatal("Tunnel local address %s is not mine",
+ inet_fmt($2, s1));
+
+ strncpy(ffr.ifr_name, ifr->ifr_name, IFNAMSIZ);
+ if (ioctl(udp_socket, SIOCGIFFLAGS, (char *)&ffr)<0)
+ fatal("ioctl SIOCGIFFLAGS on %s",ffr.ifr_name);
+ if (ffr.ifr_flags & IFF_LOOPBACK)
+ fatal("Tunnel local address %s is a loopback interface",
+ inet_fmt($2, s1));
+
+ if (ifconfaddr(&ifc, $3) != 0)
+ fatal("Tunnel remote address %s is one of mine",
+ inet_fmt($3, s1));
+
+ for (vifi = 0, v = uvifs;
+ vifi < numvifs;
+ ++vifi, ++v)
+ if (v->uv_flags & VIFF_TUNNEL) {
+ if ($3 == v->uv_rmt_addr)
+ fatal("Duplicate tunnel to %s",
+ inet_fmt($3, s1));
+ } else if (!(v->uv_flags & VIFF_DISABLED)) {
+ if (($3 & v->uv_subnetmask) == v->uv_subnet)
+ fatal("Unnecessary tunnel to %s",
+ inet_fmt($3,s1));
+ }
+
+ if (numvifs == MAXVIFS)
+ fatal("too many vifs");
+
+ v = &uvifs[numvifs];
+ v->uv_flags = VIFF_TUNNEL;
+ v->uv_metric = DEFAULT_METRIC;
+ v->uv_rate_limit= DEFAULT_TUN_RATE_LIMIT;
+ v->uv_threshold = DEFAULT_THRESHOLD;
+ v->uv_lcl_addr = $2;
+ v->uv_rmt_addr = $3;
+ v->uv_subnet = 0;
+ v->uv_subnetmask= 0;
+ v->uv_subnetbcast= 0;
+ strncpy(v->uv_name, ffr.ifr_name, IFNAMSIZ);
+ v->uv_groups = NULL;
+ v->uv_neighbors = NULL;
+ v->uv_acl = NULL;
+ v->uv_addrs = NULL;
+
+ if (!(ffr.ifr_flags & IFF_UP)) {
+ v->uv_flags |= VIFF_DOWN;
+ vifs_down = TRUE;
+ }
+ /*log(LOG_INFO, 0, "tunnel: %x\n", v);*/
+ }
+ tunnelmods
+ {
+ log(LOG_INFO, 0,
+ "installing tunnel from %s to %s as vif #%u - rate=%d",
+ inet_fmt($2, s1), inet_fmt($3, s2),
+ numvifs, v->uv_rate_limit);
+
+ ++numvifs;
+ }
+ | PRUNING BOOLEAN { pruning = $2; }
+ | CACHE_LIFETIME NUMBER { cache_lifetime = $2;
+ max_prune_lifetime = cache_lifetime * 2;
+ }
+ | NAME STRING boundary { if (numbounds >= MAXBOUNDS) {
+ fatal("Too many named boundaries (max %d)", MAXBOUNDS);
+ }
+
+ boundlist[numbounds].name = malloc(strlen($2) + 1);
+ strcpy(boundlist[numbounds].name, $2);
+ boundlist[numbounds++].bound = $3;
+ }
+ ;
+
+tunnelmods : /* empty */
+ | tunnelmods /*{ log(LOG_INFO, 0, "tunnelmod: %x", v); }*/ tunnelmod
+ ;
+
+tunnelmod : mod
+ | SRCRT { fatal("Source-route tunnels not supported"); }
+ ;
+
+ifmods : /* empty */
+ | ifmods /*{ log(LOG_INFO, 0, "ifmod: %x", v); }*/ ifmod
+ ;
+
+ifmod : mod
+ | DISABLE { v->uv_flags |= VIFF_DISABLED; }
+ | NETMASK ADDR { v->uv_subnetmask = $2; }
+ | ALTNET addrmask {
+
+ struct phaddr *ph;
+
+ ph = (struct phaddr *)malloc(sizeof(struct phaddr));
+ if (ph == NULL)
+ fatal("out of memory");
+ if ($2.mask) {
+ VAL_TO_MASK(ph->pa_mask, $2.mask);
+ } else
+ ph->pa_mask = v->uv_subnetmask;
+ ph->pa_addr = $2.addr & ph->pa_mask;
+ if ($2.addr & ~ph->pa_mask)
+ warn("Extra addr %s/%d has host bits set",
+ inet_fmt($2.addr,s1), $2.mask);
+ ph->pa_next = v->uv_addrs;
+ v->uv_addrs = ph;
+
+ }
+ ;
+
+mod : THRESHOLD NUMBER { if ($2 < 1 || $2 > 255)
+ fatal("Invalid threshold %d",$2);
+ v->uv_threshold = $2;
+ }
+ | THRESHOLD {
+
+ warn("Expected number after threshold keyword");
+
+ }
+ | METRIC NUMBER { if ($2 < 1 || $2 > UNREACHABLE)
+ fatal("Invalid metric %d",$2);
+ v->uv_metric = $2;
+ }
+ | METRIC {
+
+ warn("Expected number after metric keyword");
+
+ }
+ | RATE_LIMIT NUMBER { if ($2 > MAX_RATE_LIMIT)
+ fatal("Invalid rate_limit %d",$2);
+ v->uv_rate_limit = $2;
+ }
+ | RATE_LIMIT {
+
+ warn("Expected number after rate_limit keyword");
+
+ }
+ | BOUNDARY bound {
+
+ struct vif_acl *v_acl;
+
+ v_acl = (struct vif_acl *)malloc(sizeof(struct vif_acl));
+ if (v_acl == NULL)
+ fatal("out of memory");
+ VAL_TO_MASK(v_acl->acl_mask, $2.mask);
+ v_acl->acl_addr = $2.addr & v_acl->acl_mask;
+ if ($2.addr & ~v_acl->acl_mask)
+ warn("Boundary spec %s/%d has host bits set",
+ inet_fmt($2.addr,s1),$2.mask);
+ v_acl->acl_next = v->uv_acl;
+ v->uv_acl = v_acl;
+
+ }
+ | BOUNDARY {
+
+ warn("Expected boundary spec after boundary keyword");
+
+ }
+ ;
+
+interface : ADDR { $$ = $1; }
+ | STRING {
+ $$ = valid_if($1);
+ if ($$ == 0)
+ fatal("Invalid interface name %s",$1);
+ }
+ ;
+
+bound : boundary { $$ = $1; }
+ | STRING { int i;
+
+ for (i=0; i < numbounds; i++) {
+ if (!strcmp(boundlist[i].name, $1)) {
+ $$ = boundlist[i].bound;
+ break;
+ }
+ }
+ if (i == numbounds) {
+ fatal("Invalid boundary name %s",$1);
+ }
+ }
+ ;
+
+boundary : ADDRMASK {
+
+ if ((ntohl($1.addr) & 0xff000000) != 0xef000000) {
+ fatal("Boundaries must be 239.x.x.x, not %s/%d",
+ inet_fmt($1.addr, s1), $1.mask);
+ }
+ $$ = $1;
+
+ }
+ ;
+
+addrmask : ADDRMASK { $$ = $1; }
+ | ADDR { $$.addr = $1; $$.mask = 0; }
+ ;
+%%
+/*VARARGS1*/
+static void fatal(fmt, va_alist)
+char *fmt;
+va_dcl
+{
+ va_list ap;
+ char buf[200];
+
+ va_start(ap);
+ vsprintf(buf, fmt, ap);
+ va_end(ap);
+
+ log(LOG_ERR,0,"%s: %s near line %d", configfilename, buf, lineno);
+}
+
+/*VARARGS1*/
+static void warn(fmt, va_alist)
+char *fmt;
+va_dcl
+{
+ va_list ap;
+ char buf[200];
+
+ va_start(ap);
+ vsprintf(buf, fmt, ap);
+ va_end(ap);
+
+ log(LOG_WARNING,0,"%s: %s near line %d", configfilename, buf, lineno);
+}
+
+void yyerror(s)
+char *s;
+{
+ log(LOG_ERR, 0, "%s: %s near line %d", configfilename, s, lineno);
+}
+
+char *next_word()
+{
+ static char buf[1024];
+ static char *p=NULL;
+ extern FILE *f;
+ char *q;
+
+ while (1) {
+ if (!p || !*p) {
+ lineno++;
+ if (fgets(buf, sizeof(buf), f) == NULL)
+ return NULL;
+ p = buf;
+ }
+ while (*p && (*p == ' ' || *p == '\t')) /* skip whitespace */
+ p++;
+ if (*p == '#') {
+ p = NULL; /* skip comments */
+ continue;
+ }
+ q = p;
+ while (*p && *p != ' ' && *p != '\t' && *p != '\n')
+ p++; /* find next whitespace */
+ *p++ = '\0'; /* null-terminate string */
+
+ if (!*q) {
+ p = NULL;
+ continue; /* if 0-length string, read another line */
+ }
+
+ return q;
+ }
+}
+
+int yylex()
+{
+ int n;
+ u_int32_t addr;
+ char *q;
+
+ if ((q = next_word()) == NULL) {
+ return 0;
+ }
+
+ if (!strcmp(q,"cache_lifetime"))
+ return CACHE_LIFETIME;
+ if (!strcmp(q,"pruning"))
+ return PRUNING;
+ if (!strcmp(q,"phyint"))
+ return PHYINT;
+ if (!strcmp(q,"tunnel"))
+ return TUNNEL;
+ if (!strcmp(q,"disable"))
+ return DISABLE;
+ if (!strcmp(q,"metric"))
+ return METRIC;
+ if (!strcmp(q,"threshold"))
+ return THRESHOLD;
+ if (!strcmp(q,"rate_limit"))
+ return RATE_LIMIT;
+ if (!strcmp(q,"srcrt") || !strcmp(q,"sourceroute"))
+ return SRCRT;
+ if (!strcmp(q,"boundary"))
+ return BOUNDARY;
+ if (!strcmp(q,"netmask"))
+ return NETMASK;
+ if (!strcmp(q,"name"))
+ return NAME;
+ if (!strcmp(q,"altnet"))
+ return ALTNET;
+ if (!strcmp(q,"on") || !strcmp(q,"yes")) {
+ yylval.num = 1;
+ return BOOLEAN;
+ }
+ if (!strcmp(q,"off") || !strcmp(q,"no")) {
+ yylval.num = 0;
+ return BOOLEAN;
+ }
+ if (sscanf(q,"%[.0-9]/%d%c",s1,&n,s2) == 2) {
+ if ((addr = inet_parse(s1)) != 0xffffffff) {
+ yylval.addrmask.mask = n;
+ yylval.addrmask.addr = addr;
+ return ADDRMASK;
+ }
+ /* fall through to returning STRING */
+ }
+ if (sscanf(q,"%[.0-9]%c",s1,s2) == 1) {
+ if ((addr = inet_parse(s1)) != 0xffffffff &&
+ inet_valid_host(addr)) {
+ yylval.addr = addr;
+ return ADDR;
+ }
+ }
+ if (sscanf(q,"0x%8x%c",&n,s1) == 1) {
+ yylval.addr = n;
+ return ADDR;
+ }
+ if (sscanf(q,"%d%c",&n,s1) == 1) {
+ yylval.num = n;
+ return NUMBER;
+ }
+ yylval.ptr = q;
+ return STRING;
+}
+
+void config_vifs_from_file()
+{
+ extern FILE *f;
+
+ order = 0;
+ numbounds = 0;
+ lineno = 0;
+
+ if ((f = fopen(configfilename, "r")) == NULL) {
+ if (errno != ENOENT)
+ log(LOG_ERR, errno, "can't open %s", configfilename);
+ return;
+ }
+
+ ifc.ifc_buf = (char *)ifbuf;
+ ifc.ifc_len = sizeof(ifbuf);
+ if (ioctl(udp_socket, SIOCGIFCONF, (char *)&ifc) < 0)
+ log(LOG_ERR, errno, "ioctl SIOCGIFCONF");
+
+ yyparse();
+
+ close(f);
+}
+
+static u_int32_t
+valid_if(s)
+char *s;
+{
+ register vifi_t vifi;
+ register struct uvif *v;
+
+ for (vifi=0, v=uvifs; vifi<numvifs; vifi++, v++)
+ if (!strcmp(v->uv_name, s))
+ return v->uv_lcl_addr;
+
+ return 0;
+}
+
+static struct ifreq *
+ifconfaddr(ifcp, a)
+ struct ifconf *ifcp;
+ u_int32_t a;
+{
+ int n;
+ struct ifreq *ifrp = (struct ifreq *)ifcp->ifc_buf;
+ struct ifreq *ifend = (struct ifreq *)((char *)ifrp + ifcp->ifc_len);
+
+ while (ifrp < ifend) {
+ if (ifrp->ifr_addr.sa_family == AF_INET &&
+ ((struct sockaddr_in *)&ifrp->ifr_addr)->sin_addr.s_addr == a)
+ return (ifrp);
+#if (defined(BSD) && (BSD >= 199006))
+ n = ifrp->ifr_addr.sa_len + sizeof(ifrp->ifr_name);
+ if (n < sizeof(*ifrp))
+ ++ifrp;
+ else
+ ifrp = (struct ifreq *)((char *)ifrp + n);
+#else
+ ++ifrp;
+#endif
+ }
+ return (0);
+}