vtun/cfg_file.y

656 lines
13 KiB
Plaintext
Raw Normal View History

%{
/*
VTun - Virtual Tunnel over TCP/IP network.
Copyright (C) 1998-2000 Maxim Krasnyansky <max_mk@yahoo.com>
VTun has been derived from VPPP package by Maxim Krasnyansky.
This program 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.
This program 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.
*/
/*
* $Id: cfg_file.y,v 1.8.2.1 2007/06/29 05:25:51 mtbishop Exp $
*/
#include "config.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdarg.h>
#include <syslog.h>
#include "compat.h"
#include "vtun.h"
#include "lib.h"
int lineno = 1;
struct vtun_host *parse_host;
extern struct vtun_host default_host;
llist *parse_cmds;
struct vtun_cmd parse_cmd;
llist host_list;
int cfg_error(const char *fmt, ...);
int add_cmd(llist *cmds, char *prog, char *args, int flags);
void *cp_cmd(void *d, void *u);
int free_cmd(void *d, void *u);
void copy_addr(struct vtun_host *to, struct vtun_host *from);
int free_host(void *d, void *u);
void free_addr(struct vtun_host *h);
void free_host_list(void);
int parse_syslog(char *facility);
int yyparse(void);
int yylex(void);
int yyerror(char *s);
#define YYERROR_VERBOSE 1
%}
%union {
char *str;
int num;
struct { int num1; int num2; } dnum;
}
%expect 20
%token K_OPTIONS K_DEFAULT K_PORT K_BINDADDR K_PERSIST K_TIMEOUT
%token K_PASSWD K_PROG K_PPP K_SPEED K_IFCFG K_FWALL K_ROUTE K_DEVICE
%token K_MULTI K_SRCADDR K_IFACE K_ADDR
%token K_TYPE K_PROT K_COMPRESS K_ENCRYPT K_KALIVE K_STAT
%token K_UP K_DOWN K_SYSLOG K_IPROUTE
%token <str> K_HOST K_ERROR
%token <str> WORD PATH STRING
%token <num> NUM
%token <dnum> DNUM
%%
config:
| config statement
;
statement: '\n'
| K_OPTIONS '{' options '}'
| K_DEFAULT {
parse_host = &default_host;
}
'{' host_options '}'
| K_HOST {
if( !(parse_host = malloc(sizeof(struct vtun_host))) ){
yyerror("No memory for the host");
YYABORT;
}
/* Fill new host struct with default values.
* MUST dup strings to be able to reread config.
*/
memcpy(parse_host, &default_host, sizeof(struct vtun_host));
parse_host->host = strdup($1);
parse_host->passwd = NULL;
/* Copy local address */
copy_addr(parse_host, &default_host);
llist_copy(&default_host.up,&parse_host->up,cp_cmd,NULL);
llist_copy(&default_host.down,&parse_host->down,cp_cmd,NULL);
}
'{' host_options '}'
{
/* Check if session definition is complete */
if (!parse_host->passwd) {
cfg_error("Ignored incomplete session definition '%s'", parse_host->host);
free_host(parse_host, NULL);
free(parse_host);
} else {
/* Add host to the list */
llist_add(&host_list, (void *)parse_host);
}
}
| K_ERROR {
cfg_error("Invalid clause '%s'",$1);
YYABORT;
}
;
options:
option
| options option
;
/* Don't override command line options */
option: '\n'
| K_PORT NUM {
if(vtun.bind_addr.port == -1)
vtun.bind_addr.port = $2;
}
| K_BINDADDR '{' bindaddr_option '}'
| K_IFACE STRING {
if(vtun.svr_addr == NULL)
vtun.svr_addr = strdup($2);
}
| K_TYPE NUM {
if(vtun.svr_type == -1)
vtun.svr_type = $2;
}
| K_TIMEOUT NUM {
if(vtun.timeout == -1)
vtun.timeout = $2;
}
| K_PPP PATH {
free(vtun.ppp);
vtun.ppp = strdup($2);
}
| K_IFCFG PATH {
free(vtun.ifcfg);
vtun.ifcfg = strdup($2);
}
| K_ROUTE PATH {
free(vtun.route);
vtun.route = strdup($2);
}
| K_FWALL PATH {
free(vtun.fwall);
vtun.fwall = strdup($2);
}
| K_IPROUTE PATH {
free(vtun.iproute);
vtun.iproute = strdup($2);
}
| K_SYSLOG syslog_opt
| K_ERROR {
cfg_error("Unknown option '%s'",$1);
YYABORT;
}
;
bindaddr_option:
K_ADDR WORD {
vtun.bind_addr.name = strdup($2);
vtun.bind_addr.type = VTUN_ADDR_NAME;
}
| K_IFACE WORD {
vtun.bind_addr.name = strdup($2);
vtun.bind_addr.type = VTUN_ADDR_IFACE;
}
| K_IFACE STRING {
vtun.bind_addr.name = strdup($2);
vtun.bind_addr.type = VTUN_ADDR_IFACE;
}
| K_ERROR {
cfg_error("Unknown option '%s'",$1);
YYABORT;
}
;
syslog_opt:
NUM {
vtun.syslog = $1;
}
| WORD {
if (parse_syslog($1)) {
cfg_error("Unknown syslog facility '%s'", $1);
YYABORT;
}
}
| K_ERROR {
cfg_error("Unknown syslog option '%s'",$1);
YYABORT;
}
;
host_options:
host_option
| host_options host_option
;
/* Host options. Must free strings first, because they
* could be strduped from default_host */
host_option: '\n'
| K_PASSWD WORD {
free(parse_host->passwd);
parse_host->passwd = strdup($2);
}
| K_DEVICE WORD {
free(parse_host->dev);
parse_host->dev = strdup($2);
}
| K_MULTI NUM {
parse_host->multi = $2;
}
| K_TIMEOUT NUM {
parse_host->timeout = $2;
}
| K_SPEED NUM {
if( $2 ){
parse_host->spd_in = parse_host->spd_out = $2;
parse_host->flags |= VTUN_SHAPE;
} else
parse_host->flags &= ~VTUN_SHAPE;
}
| K_SPEED DNUM {
if( yylval.dnum.num1 || yylval.dnum.num2 ){
parse_host->spd_out = yylval.dnum.num1;
parse_host->spd_in = yylval.dnum.num2;
parse_host->flags |= VTUN_SHAPE;
} else
parse_host->flags &= ~VTUN_SHAPE;
}
| K_COMPRESS {
parse_host->flags &= ~(VTUN_ZLIB | VTUN_LZO);
}
compress
| K_ENCRYPT NUM {
if( $2 ){
parse_host->flags |= VTUN_ENCRYPT;
parse_host->cipher = $2;
} else
parse_host->flags &= ~VTUN_ENCRYPT;
}
| K_KALIVE {
parse_host->flags &= ~VTUN_KEEP_ALIVE;
}
keepalive
| K_STAT NUM {
if( $2 )
parse_host->flags |= VTUN_STAT;
else
parse_host->flags &= ~VTUN_STAT;
}
| K_PERSIST NUM {
parse_host->persist = $2;
if(vtun.persist == -1)
vtun.persist = $2;
}
| K_TYPE NUM {
parse_host->flags &= ~VTUN_TYPE_MASK;
parse_host->flags |= $2;
}
| K_PROT NUM {
parse_host->flags &= ~VTUN_PROT_MASK;
parse_host->flags |= $2;
}
| K_SRCADDR '{' srcaddr_options '}'
| K_UP {
parse_cmds = &parse_host->up;
llist_free(parse_cmds, free_cmd, NULL);
} '{' command_options '}'
| K_DOWN {
parse_cmds = &parse_host->down;
llist_free(parse_cmds, free_cmd, NULL);
} '{' command_options '}'
| K_ERROR {
cfg_error("Unknown option '%s'",$1);
YYABORT;
}
;
compress:
NUM {
if( $1 ){
parse_host->flags |= VTUN_ZLIB;
parse_host->zlevel = $1;
}
}
| DNUM {
parse_host->flags |= yylval.dnum.num1;
parse_host->zlevel = yylval.dnum.num2;
}
| K_ERROR {
cfg_error("Unknown compression '%s'",$1);
YYABORT;
}
;
keepalive:
NUM {
if( $1 )
parse_host->flags |= VTUN_KEEP_ALIVE;
}
| DNUM {
if( yylval.dnum.num1 ){
parse_host->flags |= VTUN_KEEP_ALIVE;
parse_host->ka_interval = yylval.dnum.num1;
parse_host->ka_failure = yylval.dnum.num2;
}
}
| K_ERROR {
cfg_error("Unknown keepalive option '%s'",$1);
YYABORT;
}
;
srcaddr_options: /* empty */
| srcaddr_option
| srcaddr_options srcaddr_option
;
srcaddr_option:
K_ADDR WORD {
free_addr(parse_host);
parse_host->src_addr.name = strdup($2);
parse_host->src_addr.type = VTUN_ADDR_NAME;
}
| K_IFACE WORD {
free_addr(parse_host);
parse_host->src_addr.name = strdup($2);
parse_host->src_addr.type = VTUN_ADDR_IFACE;
}
| K_IFACE STRING {
free_addr(parse_host);
parse_host->src_addr.name = strdup($2);
parse_host->src_addr.type = VTUN_ADDR_IFACE;
}
| K_PORT NUM {
parse_host->src_addr.port = $2;
}
| K_ERROR {
cfg_error("Unknown option '%s'",$1);
YYABORT;
}
;
command_options: /* empty */
| command_option
| command_options command_option
;
command_option: '\n'
| K_PROG {
memset(&parse_cmd, 0, sizeof(struct vtun_cmd));
}
prog_options {
add_cmd(parse_cmds, parse_cmd.prog,
parse_cmd.args, parse_cmd.flags);
}
| K_PPP STRING {
add_cmd(parse_cmds, strdup(vtun.ppp), strdup($2),
VTUN_CMD_DELAY);
}
| K_IFCFG STRING {
add_cmd(parse_cmds, strdup(vtun.ifcfg),strdup($2),
VTUN_CMD_WAIT);
}
| K_ROUTE STRING {
add_cmd(parse_cmds, strdup(vtun.route),strdup($2),
VTUN_CMD_WAIT);
}
| K_FWALL STRING {
add_cmd(parse_cmds, strdup(vtun.fwall),strdup($2),
VTUN_CMD_WAIT);
}
| K_IPROUTE STRING {
add_cmd(parse_cmds, strdup(vtun.iproute),strdup($2),
VTUN_CMD_WAIT);
}
| K_ERROR {
cfg_error("Unknown cmd '%s'",$1);
YYABORT;
}
;
prog_options:
prog_option
| prog_options prog_option
;
prog_option:
PATH {
parse_cmd.prog = strdup($1);
}
| STRING {
parse_cmd.args = strdup($1);
}
| NUM {
parse_cmd.flags = $1;
}
;
%%
int yyerror(char *s)
{
vtun_syslog(LOG_ERR, "%s line %d\n", s, lineno);
return 0;
}
int cfg_error(const char *fmt, ...)
{
char buf[255];
va_list ap;
/* print the argument string */
va_start(ap, fmt);
vsnprintf(buf,sizeof(buf),fmt,ap);
va_end(ap);
yyerror(buf);
return 0;
}
int add_cmd(llist *cmds, char *prog, char *args, int flags)
{
struct vtun_cmd *cmd;
if( !(cmd = malloc(sizeof(struct vtun_cmd))) ){
yyerror("No memory for the command");
return -1;
}
memset(cmd, 0, sizeof(struct vtun_cmd));
cmd->prog = prog;
cmd->args = args;
cmd->flags = flags;
llist_add(cmds, cmd);
return 0;
}
void *cp_cmd(void *d, void *u)
{
struct vtun_cmd *cmd = d, *cmd_copy;
if( !(cmd_copy = malloc(sizeof(struct vtun_cmd))) ){
yyerror("No memory to copy the command");
return NULL;
}
cmd_copy->prog = strdup(cmd->prog);
cmd_copy->args = strdup(cmd->args);
cmd_copy->flags = cmd->flags;
return cmd_copy;
}
int free_cmd(void *d, void *u)
{
struct vtun_cmd *cmd = d;
free(cmd->prog);
free(cmd->args);
free(cmd);
return 0;
}
void copy_addr(struct vtun_host *to, struct vtun_host *from)
{
if( from->src_addr.type ){
to->src_addr.type = from->src_addr.type;
to->src_addr.name = strdup(from->src_addr.name);
}
to->src_addr.port = from->src_addr.port;
}
void free_addr(struct vtun_host *h)
{
if( h->src_addr.type ){
h->src_addr.type = 0;
free(h->src_addr.name);
}
}
int free_host(void *d, void *u)
{
struct vtun_host *h = d;
if (u && !strcmp(h->host, u))
return 1;
free(h->host);
free(h->passwd);
llist_free(&h->up, free_cmd, NULL);
llist_free(&h->down, free_cmd, NULL);
free_addr(h);
return 0;
}
/* Find host in the hosts list.
* NOTE: This function can be called only once since it deallocates hosts list.
*/
inline struct vtun_host* find_host(char *host)
{
return (struct vtun_host *)llist_free(&host_list, free_host, host);
}
inline void free_host_list(void)
{
llist_free(&host_list, free_host, NULL);
}
static struct {
char *c_name;
int c_val;
} syslog_names[] = {
{ "auth", LOG_AUTH },
{ "cron", LOG_CRON },
{ "daemon", LOG_DAEMON },
{ "kern", LOG_KERN },
{ "lpr", LOG_LPR },
{ "mail", LOG_MAIL },
{ "news", LOG_NEWS },
{ "syslog", LOG_SYSLOG },
{ "user", LOG_USER },
{ "uucp", LOG_UUCP },
{ "local0", LOG_LOCAL0 },
{ "local1", LOG_LOCAL1 },
{ "local2", LOG_LOCAL2 },
{ "local3", LOG_LOCAL3 },
{ "local4", LOG_LOCAL4 },
{ "local5", LOG_LOCAL5 },
{ "local6", LOG_LOCAL6 },
{ "local7", LOG_LOCAL7 },
{ NULL, -1 }
};
int parse_syslog(char *facility)
{
int i;
for (i=0; syslog_names[i].c_name;i++) {
if (!strcmp(syslog_names[i].c_name, facility)) {
vtun.syslog = syslog_names[i].c_val;
return(0);
}
}
return -1;
}
/*
* Read config file.
*/
int read_config(char *file)
{
static int cfg_loaded = 0;
extern FILE *yyin;
if( cfg_loaded ){
free_host_list();
vtun_syslog(LOG_INFO,"Reloading configuration file");
}
cfg_loaded = 1;
llist_init(&host_list);
if( !(yyin = fopen(file,"r")) ){
vtun_syslog(LOG_ERR,"Can not open %s", file);
return -1;
}
yyparse();
free_host(&default_host, NULL);
fclose(yyin);
return !llist_empty(&host_list);
}