GCC Code Coverage Report | |||||||||||||||||||||
|
|||||||||||||||||||||
Line | Branch | Exec | Source |
1 |
/* $OpenBSD: parse.y,v 1.216 2017/08/28 06:00:05 florian Exp $ */ |
||
2 |
|||
3 |
/* |
||
4 |
* Copyright (c) 2007 - 2014 Reyk Floeter <reyk@openbsd.org> |
||
5 |
* Copyright (c) 2008 Gilles Chehade <gilles@openbsd.org> |
||
6 |
* Copyright (c) 2006 Pierre-Yves Ritschard <pyr@openbsd.org> |
||
7 |
* Copyright (c) 2004, 2005 Esben Norby <norby@openbsd.org> |
||
8 |
* Copyright (c) 2004 Ryan McBride <mcbride@openbsd.org> |
||
9 |
* Copyright (c) 2002, 2003, 2004 Henning Brauer <henning@openbsd.org> |
||
10 |
* Copyright (c) 2001 Markus Friedl. All rights reserved. |
||
11 |
* Copyright (c) 2001 Daniel Hartmeier. All rights reserved. |
||
12 |
* Copyright (c) 2001 Theo de Raadt. All rights reserved. |
||
13 |
* |
||
14 |
* Permission to use, copy, modify, and distribute this software for any |
||
15 |
* purpose with or without fee is hereby granted, provided that the above |
||
16 |
* copyright notice and this permission notice appear in all copies. |
||
17 |
* |
||
18 |
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES |
||
19 |
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF |
||
20 |
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR |
||
21 |
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES |
||
22 |
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN |
||
23 |
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF |
||
24 |
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. |
||
25 |
*/ |
||
26 |
|||
27 |
%{ |
||
28 |
#include <sys/types.h> |
||
29 |
#include <sys/socket.h> |
||
30 |
#include <sys/stat.h> |
||
31 |
#include <sys/queue.h> |
||
32 |
#include <sys/ioctl.h> |
||
33 |
#include <sys/time.h> |
||
34 |
#include <sys/tree.h> |
||
35 |
|||
36 |
#include <netinet/in.h> |
||
37 |
#include <arpa/inet.h> |
||
38 |
#include <net/if.h> |
||
39 |
#include <net/pfvar.h> |
||
40 |
#include <net/route.h> |
||
41 |
|||
42 |
#include <stdint.h> |
||
43 |
#include <stdarg.h> |
||
44 |
#include <stdio.h> |
||
45 |
#include <unistd.h> |
||
46 |
#include <ctype.h> |
||
47 |
#include <err.h> |
||
48 |
#include <endian.h> |
||
49 |
#include <errno.h> |
||
50 |
#include <limits.h> |
||
51 |
#include <netdb.h> |
||
52 |
#include <string.h> |
||
53 |
#include <ifaddrs.h> |
||
54 |
#include <syslog.h> |
||
55 |
#include <md5.h> |
||
56 |
|||
57 |
#include "relayd.h" |
||
58 |
#include "http.h" |
||
59 |
#include "snmp.h" |
||
60 |
|||
61 |
TAILQ_HEAD(files, file) files = TAILQ_HEAD_INITIALIZER(files); |
||
62 |
static struct file { |
||
63 |
TAILQ_ENTRY(file) entry; |
||
64 |
FILE *stream; |
||
65 |
char *name; |
||
66 |
int lineno; |
||
67 |
int errors; |
||
68 |
} *file, *topfile; |
||
69 |
struct file *pushfile(const char *, int); |
||
70 |
int popfile(void); |
||
71 |
int check_file_secrecy(int, const char *); |
||
72 |
int yyparse(void); |
||
73 |
int yylex(void); |
||
74 |
int yyerror(const char *, ...); |
||
75 |
int kw_cmp(const void *, const void *); |
||
76 |
int lookup(char *); |
||
77 |
int lgetc(int); |
||
78 |
int lungetc(int); |
||
79 |
int findeol(void); |
||
80 |
|||
81 |
TAILQ_HEAD(symhead, sym) symhead = TAILQ_HEAD_INITIALIZER(symhead); |
||
82 |
struct sym { |
||
83 |
TAILQ_ENTRY(sym) entry; |
||
84 |
int used; |
||
85 |
int persist; |
||
86 |
char *nam; |
||
87 |
char *val; |
||
88 |
}; |
||
89 |
int symset(const char *, const char *, int); |
||
90 |
char *symget(const char *); |
||
91 |
|||
92 |
struct relayd *conf = NULL; |
||
93 |
static int errors = 0; |
||
94 |
static int loadcfg = 0; |
||
95 |
objid_t last_rdr_id = 0; |
||
96 |
objid_t last_table_id = 0; |
||
97 |
objid_t last_host_id = 0; |
||
98 |
objid_t last_relay_id = 0; |
||
99 |
objid_t last_proto_id = 0; |
||
100 |
objid_t last_rt_id = 0; |
||
101 |
objid_t last_nr_id = 0; |
||
102 |
objid_t last_key_id = 0; |
||
103 |
|||
104 |
static struct rdr *rdr = NULL; |
||
105 |
static struct table *table = NULL; |
||
106 |
static struct relay *rlay = NULL; |
||
107 |
static struct host *hst = NULL; |
||
108 |
struct relaylist relays; |
||
109 |
static struct protocol *proto = NULL; |
||
110 |
static struct relay_rule *rule = NULL; |
||
111 |
static struct router *router = NULL; |
||
112 |
static int label = 0; |
||
113 |
static int tagged = 0; |
||
114 |
static int tag = 0; |
||
115 |
static in_port_t tableport = 0; |
||
116 |
static int dstmode; |
||
117 |
static enum key_type keytype = KEY_TYPE_NONE; |
||
118 |
static enum direction dir = RELAY_DIR_ANY; |
||
119 |
static char *rulefile = NULL; |
||
120 |
static union hashkey *hashkey = NULL; |
||
121 |
|||
122 |
struct address *host_v4(const char *); |
||
123 |
struct address *host_v6(const char *); |
||
124 |
int host_dns(const char *, struct addresslist *, |
||
125 |
int, struct portrange *, const char *, int); |
||
126 |
int host_if(const char *, struct addresslist *, |
||
127 |
int, struct portrange *, const char *, int); |
||
128 |
int host(const char *, struct addresslist *, |
||
129 |
int, struct portrange *, const char *, int); |
||
130 |
void host_free(struct addresslist *); |
||
131 |
|||
132 |
struct table *table_inherit(struct table *); |
||
133 |
int relay_id(struct relay *); |
||
134 |
struct relay *relay_inherit(struct relay *, struct relay *); |
||
135 |
int getservice(char *); |
||
136 |
int is_if_in_group(const char *, const char *); |
||
137 |
|||
138 |
typedef struct { |
||
139 |
union { |
||
140 |
int64_t number; |
||
141 |
char *string; |
||
142 |
struct host *host; |
||
143 |
struct timeval tv; |
||
144 |
struct table *table; |
||
145 |
struct portrange port; |
||
146 |
struct { |
||
147 |
union hashkey key; |
||
148 |
int keyset; |
||
149 |
} key; |
||
150 |
enum direction dir; |
||
151 |
struct { |
||
152 |
struct sockaddr_storage ss; |
||
153 |
char name[HOST_NAME_MAX+1]; |
||
154 |
} addr; |
||
155 |
struct { |
||
156 |
enum digest_type type; |
||
157 |
char *digest; |
||
158 |
} digest; |
||
159 |
} v; |
||
160 |
int lineno; |
||
161 |
} YYSTYPE; |
||
162 |
|||
163 |
%} |
||
164 |
|||
165 |
%token ALL APPEND BACKLOG BACKUP BUFFER CA CACHE SET CHECK CIPHERS CODE |
||
166 |
%token COOKIE DEMOTE DIGEST DISABLE ERROR EXPECT PASS BLOCK EXTERNAL FILENAME |
||
167 |
%token FORWARD FROM HASH HEADER HOST ICMP INCLUDE INET INET6 INTERFACE |
||
168 |
%token INTERVAL IP LABEL LISTEN VALUE LOADBALANCE LOG LOOKUP METHOD MODE NAT |
||
169 |
%token NO DESTINATION NODELAY NOTHING ON PARENT PATH PFTAG PORT PREFORK |
||
170 |
%token PRIORITY PROTO QUERYSTR REAL REDIRECT RELAY REMOVE REQUEST RESPONSE |
||
171 |
%token RETRY QUICK RETURN ROUNDROBIN ROUTE SACK SCRIPT SEND SESSION SNMP |
||
172 |
%token SOCKET SPLICE SSL STICKYADDR STYLE TABLE TAG TAGGED TCP TIMEOUT TLS TO |
||
173 |
%token ROUTER RTLABEL TRANSPARENT TRAP UPDATES URL VIRTUAL WITH TTL RTABLE |
||
174 |
%token MATCH PARAMS RANDOM LEASTSTATES SRCHASH KEY CERTIFICATE PASSWORD ECDH |
||
175 |
%token EDH CURVE TICKETS |
||
176 |
%token <v.string> STRING |
||
177 |
%token <v.number> NUMBER |
||
178 |
%type <v.string> hostname interface table value optstring |
||
179 |
%type <v.number> http_type loglevel quick trap |
||
180 |
%type <v.number> dstmode flag forwardmode retry |
||
181 |
%type <v.number> opttls opttlsclient |
||
182 |
%type <v.number> redirect_proto relay_proto match |
||
183 |
%type <v.number> action ruleaf key_option |
||
184 |
%type <v.port> port |
||
185 |
%type <v.host> host |
||
186 |
%type <v.addr> address |
||
187 |
%type <v.tv> timeout |
||
188 |
%type <v.digest> digest optdigest |
||
189 |
%type <v.table> tablespec |
||
190 |
%type <v.dir> dir |
||
191 |
%type <v.key> hashkey |
||
192 |
|||
193 |
%% |
||
194 |
|||
195 |
grammar : /* empty */ |
||
196 |
| grammar include '\n' |
||
197 |
| grammar '\n' |
||
198 |
| grammar varset '\n' |
||
199 |
| grammar main '\n' |
||
200 |
| grammar rdr '\n' |
||
201 |
| grammar tabledef '\n' |
||
202 |
| grammar relay '\n' |
||
203 |
| grammar proto '\n' |
||
204 |
| grammar router '\n' |
||
205 |
| grammar error '\n' { file->errors++; } |
||
206 |
; |
||
207 |
|||
208 |
include : INCLUDE STRING { |
||
209 |
struct file *nfile; |
||
210 |
|||
211 |
if ((nfile = pushfile($2, 0)) == NULL) { |
||
212 |
yyerror("failed to include file %s", $2); |
||
213 |
free($2); |
||
214 |
YYERROR; |
||
215 |
} |
||
216 |
free($2); |
||
217 |
|||
218 |
file = nfile; |
||
219 |
lungetc('\n'); |
||
220 |
} |
||
221 |
; |
||
222 |
|||
223 |
ssltls : SSL { |
||
224 |
log_warnx("%s:%d: %s", |
||
225 |
file->name, yylval.lineno, |
||
226 |
"please use the \"tls\" keyword" |
||
227 |
" instead of \"ssl\""); |
||
228 |
} |
||
229 |
| TLS |
||
230 |
; |
||
231 |
|||
232 |
opttls : /*empty*/ { $$ = 0; } |
||
233 |
| ssltls { $$ = 1; } |
||
234 |
; |
||
235 |
|||
236 |
opttlsclient : /*empty*/ { $$ = 0; } |
||
237 |
| WITH ssltls { $$ = 1; } |
||
238 |
; |
||
239 |
|||
240 |
http_type : STRING { |
||
241 |
if (strcmp("https", $1) == 0) { |
||
242 |
$$ = 1; |
||
243 |
} else if (strcmp("http", $1) == 0) { |
||
244 |
$$ = 0; |
||
245 |
} else { |
||
246 |
yyerror("invalid check type: %s", $1); |
||
247 |
free($1); |
||
248 |
YYERROR; |
||
249 |
} |
||
250 |
free($1); |
||
251 |
} |
||
252 |
; |
||
253 |
|||
254 |
hostname : /* empty */ { |
||
255 |
$$ = strdup(""); |
||
256 |
if ($$ == NULL) |
||
257 |
fatal("calloc"); |
||
258 |
} |
||
259 |
| HOST STRING { |
||
260 |
if (asprintf(&$$, "Host: %s\r\nConnection: close\r\n", |
||
261 |
$2) == -1) |
||
262 |
fatal("asprintf"); |
||
263 |
} |
||
264 |
; |
||
265 |
|||
266 |
relay_proto : /* empty */ { $$ = RELAY_PROTO_TCP; } |
||
267 |
| TCP { $$ = RELAY_PROTO_TCP; } |
||
268 |
| STRING { |
||
269 |
if (strcmp("http", $1) == 0) { |
||
270 |
$$ = RELAY_PROTO_HTTP; |
||
271 |
} else if (strcmp("dns", $1) == 0) { |
||
272 |
$$ = RELAY_PROTO_DNS; |
||
273 |
} else { |
||
274 |
yyerror("invalid protocol type: %s", $1); |
||
275 |
free($1); |
||
276 |
YYERROR; |
||
277 |
} |
||
278 |
free($1); |
||
279 |
} |
||
280 |
; |
||
281 |
|||
282 |
redirect_proto : /* empty */ { $$ = IPPROTO_TCP; } |
||
283 |
| TCP { $$ = IPPROTO_TCP; } |
||
284 |
| STRING { |
||
285 |
struct protoent *p; |
||
286 |
|||
287 |
if ((p = getprotobyname($1)) == NULL) { |
||
288 |
yyerror("invalid protocol: %s", $1); |
||
289 |
free($1); |
||
290 |
YYERROR; |
||
291 |
} |
||
292 |
free($1); |
||
293 |
|||
294 |
$$ = p->p_proto; |
||
295 |
} |
||
296 |
; |
||
297 |
|||
298 |
eflags_l : eflags comma eflags_l |
||
299 |
| eflags |
||
300 |
; |
||
301 |
|||
302 |
opteflags : /* nothing */ |
||
303 |
| eflags |
||
304 |
; |
||
305 |
|||
306 |
eflags : STYLE STRING |
||
307 |
{ |
||
308 |
if ((proto->style = strdup($2)) == NULL) |
||
309 |
fatal("out of memory"); |
||
310 |
free($2); |
||
311 |
} |
||
312 |
; |
||
313 |
|||
314 |
port : PORT STRING { |
||
315 |
char *a, *b; |
||
316 |
int p[2]; |
||
317 |
|||
318 |
p[0] = p[1] = 0; |
||
319 |
|||
320 |
a = $2; |
||
321 |
b = strchr($2, ':'); |
||
322 |
if (b == NULL) |
||
323 |
$$.op = PF_OP_EQ; |
||
324 |
else { |
||
325 |
*b++ = '\0'; |
||
326 |
if ((p[1] = getservice(b)) == -1) { |
||
327 |
free($2); |
||
328 |
YYERROR; |
||
329 |
} |
||
330 |
$$.op = PF_OP_RRG; |
||
331 |
} |
||
332 |
if ((p[0] = getservice(a)) == -1) { |
||
333 |
free($2); |
||
334 |
YYERROR; |
||
335 |
} |
||
336 |
$$.val[0] = p[0]; |
||
337 |
$$.val[1] = p[1]; |
||
338 |
free($2); |
||
339 |
} |
||
340 |
| PORT NUMBER { |
||
341 |
if ($2 <= 0 || $2 > (int)USHRT_MAX) { |
||
342 |
yyerror("invalid port: %d", $2); |
||
343 |
YYERROR; |
||
344 |
} |
||
345 |
$$.val[0] = htons($2); |
||
346 |
$$.op = PF_OP_EQ; |
||
347 |
} |
||
348 |
; |
||
349 |
|||
350 |
varset : STRING '=' STRING { |
||
351 |
char *s = $1; |
||
352 |
while (*s++) { |
||
353 |
if (isspace((unsigned char)*s)) { |
||
354 |
yyerror("macro name cannot contain " |
||
355 |
"whitespace"); |
||
356 |
YYERROR; |
||
357 |
} |
||
358 |
} |
||
359 |
if (symset($1, $3, 0) == -1) |
||
360 |
fatal("cannot store variable"); |
||
361 |
free($1); |
||
362 |
free($3); |
||
363 |
} |
||
364 |
; |
||
365 |
|||
366 |
sendbuf : NOTHING { |
||
367 |
table->sendbuf = NULL; |
||
368 |
} |
||
369 |
| STRING { |
||
370 |
table->sendbuf = strdup($1); |
||
371 |
if (table->sendbuf == NULL) |
||
372 |
fatal("out of memory"); |
||
373 |
free($1); |
||
374 |
} |
||
375 |
; |
||
376 |
|||
377 |
main : INTERVAL NUMBER { |
||
378 |
if ((conf->sc_conf.interval.tv_sec = $2) < 0) { |
||
379 |
yyerror("invalid interval: %d", $2); |
||
380 |
YYERROR; |
||
381 |
} |
||
382 |
} |
||
383 |
| LOG loglevel { |
||
384 |
conf->sc_conf.opts |= $2; |
||
385 |
} |
||
386 |
| TIMEOUT timeout { |
||
387 |
bcopy(&$2, &conf->sc_conf.timeout, |
||
388 |
sizeof(struct timeval)); |
||
389 |
} |
||
390 |
| PREFORK NUMBER { |
||
391 |
if ($2 <= 0 || $2 > PROC_MAX_INSTANCES) { |
||
392 |
yyerror("invalid number of preforked " |
||
393 |
"relays: %d", $2); |
||
394 |
YYERROR; |
||
395 |
} |
||
396 |
conf->sc_conf.prefork_relay = $2; |
||
397 |
} |
||
398 |
| SNMP trap optstring { |
||
399 |
conf->sc_conf.flags |= F_SNMP; |
||
400 |
if ($2) |
||
401 |
conf->sc_conf.flags |= F_SNMP_TRAPONLY; |
||
402 |
if ($3) { |
||
403 |
if (strlcpy(conf->sc_conf.snmp_path, |
||
404 |
$3, sizeof(conf->sc_conf.snmp_path)) >= |
||
405 |
sizeof(conf->sc_conf.snmp_path)) { |
||
406 |
yyerror("snmp path truncated"); |
||
407 |
free($3); |
||
408 |
YYERROR; |
||
409 |
} |
||
410 |
free($3); |
||
411 |
} else |
||
412 |
(void)strlcpy(conf->sc_conf.snmp_path, |
||
413 |
AGENTX_SOCKET, |
||
414 |
sizeof(conf->sc_conf.snmp_path)); |
||
415 |
} |
||
416 |
; |
||
417 |
|||
418 |
trap : /* nothing */ { $$ = 0; } |
||
419 |
| TRAP { $$ = 1; } |
||
420 |
|||
421 |
loglevel : UPDATES { $$ = RELAYD_OPT_LOGUPDATE; } |
||
422 |
| ALL { $$ = RELAYD_OPT_LOGALL; } |
||
423 |
; |
||
424 |
|||
425 |
rdr : REDIRECT STRING { |
||
426 |
struct rdr *srv; |
||
427 |
|||
428 |
conf->sc_conf.flags |= F_NEEDPF; |
||
429 |
|||
430 |
if (!loadcfg) { |
||
431 |
free($2); |
||
432 |
YYACCEPT; |
||
433 |
} |
||
434 |
|||
435 |
TAILQ_FOREACH(srv, conf->sc_rdrs, entry) |
||
436 |
if (!strcmp(srv->conf.name, $2)) |
||
437 |
break; |
||
438 |
if (srv != NULL) { |
||
439 |
yyerror("redirection %s defined twice", $2); |
||
440 |
free($2); |
||
441 |
YYERROR; |
||
442 |
} |
||
443 |
if ((srv = calloc(1, sizeof (*srv))) == NULL) |
||
444 |
fatal("out of memory"); |
||
445 |
|||
446 |
if (strlcpy(srv->conf.name, $2, |
||
447 |
sizeof(srv->conf.name)) >= |
||
448 |
sizeof(srv->conf.name)) { |
||
449 |
yyerror("redirection name truncated"); |
||
450 |
free($2); |
||
451 |
free(srv); |
||
452 |
YYERROR; |
||
453 |
} |
||
454 |
free($2); |
||
455 |
srv->conf.id = ++last_rdr_id; |
||
456 |
srv->conf.timeout.tv_sec = RELAY_TIMEOUT; |
||
457 |
if (last_rdr_id == INT_MAX) { |
||
458 |
yyerror("too many redirections defined"); |
||
459 |
free(srv); |
||
460 |
YYERROR; |
||
461 |
} |
||
462 |
rdr = srv; |
||
463 |
} '{' optnl rdropts_l '}' { |
||
464 |
if (rdr->table == NULL) { |
||
465 |
yyerror("redirection %s has no table", |
||
466 |
rdr->conf.name); |
||
467 |
YYERROR; |
||
468 |
} |
||
469 |
if (TAILQ_EMPTY(&rdr->virts)) { |
||
470 |
yyerror("redirection %s has no virtual ip", |
||
471 |
rdr->conf.name); |
||
472 |
YYERROR; |
||
473 |
} |
||
474 |
conf->sc_rdrcount++; |
||
475 |
if (rdr->backup == NULL) { |
||
476 |
rdr->conf.backup_id = |
||
477 |
conf->sc_empty_table.conf.id; |
||
478 |
rdr->backup = &conf->sc_empty_table; |
||
479 |
} else if (rdr->backup->conf.port != |
||
480 |
rdr->table->conf.port) { |
||
481 |
yyerror("redirection %s uses two different " |
||
482 |
"ports for its table and backup table", |
||
483 |
rdr->conf.name); |
||
484 |
YYERROR; |
||
485 |
} |
||
486 |
if (!(rdr->conf.flags & F_DISABLE)) |
||
487 |
rdr->conf.flags |= F_ADD; |
||
488 |
TAILQ_INSERT_TAIL(conf->sc_rdrs, rdr, entry); |
||
489 |
tableport = 0; |
||
490 |
rdr = NULL; |
||
491 |
} |
||
492 |
; |
||
493 |
|||
494 |
rdropts_l : rdropts_l rdroptsl nl |
||
495 |
| rdroptsl optnl |
||
496 |
; |
||
497 |
|||
498 |
rdroptsl : forwardmode TO tablespec interface { |
||
499 |
if (hashkey != NULL) { |
||
500 |
memcpy(&rdr->conf.key, |
||
501 |
hashkey, sizeof(rdr->conf.key)); |
||
502 |
rdr->conf.flags |= F_HASHKEY; |
||
503 |
free(hashkey); |
||
504 |
hashkey = NULL; |
||
505 |
} |
||
506 |
|||
507 |
switch ($1) { |
||
508 |
case FWD_NORMAL: |
||
509 |
if ($4 == NULL) |
||
510 |
break; |
||
511 |
yyerror("superfluous interface"); |
||
512 |
free($4); |
||
513 |
YYERROR; |
||
514 |
case FWD_ROUTE: |
||
515 |
if ($4 != NULL) |
||
516 |
break; |
||
517 |
yyerror("missing interface to route to"); |
||
518 |
free($4); |
||
519 |
YYERROR; |
||
520 |
case FWD_TRANS: |
||
521 |
yyerror("no transparent forward here"); |
||
522 |
if ($4 != NULL) |
||
523 |
free($4); |
||
524 |
YYERROR; |
||
525 |
} |
||
526 |
if ($4 != NULL) { |
||
527 |
if (strlcpy($3->conf.ifname, $4, |
||
528 |
sizeof($3->conf.ifname)) >= |
||
529 |
sizeof($3->conf.ifname)) { |
||
530 |
yyerror("interface name truncated"); |
||
531 |
free($4); |
||
532 |
YYERROR; |
||
533 |
} |
||
534 |
free($4); |
||
535 |
} |
||
536 |
|||
537 |
if ($3->conf.check == CHECK_NOCHECK) { |
||
538 |
yyerror("table %s has no check", $3->conf.name); |
||
539 |
purge_table(conf, conf->sc_tables, $3); |
||
540 |
YYERROR; |
||
541 |
} |
||
542 |
if (rdr->backup) { |
||
543 |
yyerror("only one backup table is allowed"); |
||
544 |
purge_table(conf, conf->sc_tables, $3); |
||
545 |
YYERROR; |
||
546 |
} |
||
547 |
if (rdr->table) { |
||
548 |
rdr->backup = $3; |
||
549 |
rdr->conf.backup_id = $3->conf.id; |
||
550 |
if (dstmode != rdr->conf.mode) { |
||
551 |
yyerror("backup table for %s with " |
||
552 |
"different mode", rdr->conf.name); |
||
553 |
YYERROR; |
||
554 |
} |
||
555 |
} else { |
||
556 |
rdr->table = $3; |
||
557 |
rdr->conf.table_id = $3->conf.id; |
||
558 |
rdr->conf.mode = dstmode; |
||
559 |
} |
||
560 |
$3->conf.fwdmode = $1; |
||
561 |
$3->conf.rdrid = rdr->conf.id; |
||
562 |
$3->conf.flags |= F_USED; |
||
563 |
} |
||
564 |
| LISTEN ON STRING redirect_proto port interface { |
||
565 |
if (host($3, &rdr->virts, |
||
566 |
SRV_MAX_VIRTS, &$5, $6, $4) <= 0) { |
||
567 |
yyerror("invalid virtual ip: %s", $3); |
||
568 |
free($3); |
||
569 |
free($6); |
||
570 |
YYERROR; |
||
571 |
} |
||
572 |
free($3); |
||
573 |
free($6); |
||
574 |
if (rdr->conf.port == 0) |
||
575 |
rdr->conf.port = $5.val[0]; |
||
576 |
tableport = rdr->conf.port; |
||
577 |
} |
||
578 |
| DISABLE { rdr->conf.flags |= F_DISABLE; } |
||
579 |
| STICKYADDR { rdr->conf.flags |= F_STICKY; } |
||
580 |
| match PFTAG STRING { |
||
581 |
conf->sc_conf.flags |= F_NEEDPF; |
||
582 |
if (strlcpy(rdr->conf.tag, $3, |
||
583 |
sizeof(rdr->conf.tag)) >= |
||
584 |
sizeof(rdr->conf.tag)) { |
||
585 |
yyerror("redirection tag name truncated"); |
||
586 |
free($3); |
||
587 |
YYERROR; |
||
588 |
} |
||
589 |
if ($1) |
||
590 |
rdr->conf.flags |= F_MATCH; |
||
591 |
free($3); |
||
592 |
} |
||
593 |
| SESSION TIMEOUT NUMBER { |
||
594 |
if ((rdr->conf.timeout.tv_sec = $3) < 0) { |
||
595 |
yyerror("invalid timeout: %lld", $3); |
||
596 |
YYERROR; |
||
597 |
} |
||
598 |
if (rdr->conf.timeout.tv_sec > INT_MAX) { |
||
599 |
yyerror("timeout too large: %lld", $3); |
||
600 |
YYERROR; |
||
601 |
} |
||
602 |
} |
||
603 |
| include |
||
604 |
; |
||
605 |
|||
606 |
match : /* empty */ { $$ = 0; } |
||
607 |
| MATCH { $$ = 1; } |
||
608 |
; |
||
609 |
|||
610 |
forwardmode : FORWARD { $$ = FWD_NORMAL; } |
||
611 |
| ROUTE { $$ = FWD_ROUTE; } |
||
612 |
| TRANSPARENT FORWARD { $$ = FWD_TRANS; } |
||
613 |
; |
||
614 |
|||
615 |
table : '<' STRING '>' { |
||
616 |
if (strlen($2) >= TABLE_NAME_SIZE) { |
||
617 |
yyerror("invalid table name"); |
||
618 |
free($2); |
||
619 |
YYERROR; |
||
620 |
} |
||
621 |
$$ = $2; |
||
622 |
} |
||
623 |
; |
||
624 |
|||
625 |
tabledef : TABLE table { |
||
626 |
struct table *tb; |
||
627 |
|||
628 |
if (!loadcfg) { |
||
629 |
free($2); |
||
630 |
YYACCEPT; |
||
631 |
} |
||
632 |
|||
633 |
TAILQ_FOREACH(tb, conf->sc_tables, entry) |
||
634 |
if (!strcmp(tb->conf.name, $2)) |
||
635 |
break; |
||
636 |
if (tb != NULL) { |
||
637 |
yyerror("table %s defined twice", $2); |
||
638 |
free($2); |
||
639 |
YYERROR; |
||
640 |
} |
||
641 |
|||
642 |
if ((tb = calloc(1, sizeof (*tb))) == NULL) |
||
643 |
fatal("out of memory"); |
||
644 |
|||
645 |
if (strlcpy(tb->conf.name, $2, |
||
646 |
sizeof(tb->conf.name)) >= sizeof(tb->conf.name)) { |
||
647 |
yyerror("table name truncated"); |
||
648 |
free($2); |
||
649 |
YYERROR; |
||
650 |
} |
||
651 |
free($2); |
||
652 |
|||
653 |
tb->conf.id = 0; /* will be set later */ |
||
654 |
bcopy(&conf->sc_conf.timeout, &tb->conf.timeout, |
||
655 |
sizeof(struct timeval)); |
||
656 |
TAILQ_INIT(&tb->hosts); |
||
657 |
table = tb; |
||
658 |
dstmode = RELAY_DSTMODE_DEFAULT; |
||
659 |
} tabledefopts_l { |
||
660 |
if (TAILQ_EMPTY(&table->hosts)) { |
||
661 |
yyerror("table %s has no hosts", |
||
662 |
table->conf.name); |
||
663 |
YYERROR; |
||
664 |
} |
||
665 |
conf->sc_tablecount++; |
||
666 |
TAILQ_INSERT_TAIL(conf->sc_tables, table, entry); |
||
667 |
} |
||
668 |
; |
||
669 |
|||
670 |
tabledefopts_l : tabledefopts_l tabledefopts |
||
671 |
| tabledefopts |
||
672 |
; |
||
673 |
|||
674 |
tabledefopts : DISABLE { table->conf.flags |= F_DISABLE; } |
||
675 |
| '{' optnl tablelist_l '}' |
||
676 |
; |
||
677 |
|||
678 |
tablelist_l : tablelist comma tablelist_l |
||
679 |
| tablelist optnl |
||
680 |
; |
||
681 |
|||
682 |
tablelist : host { |
||
683 |
$1->conf.tableid = table->conf.id; |
||
684 |
$1->tablename = table->conf.name; |
||
685 |
TAILQ_INSERT_TAIL(&table->hosts, $1, entry); |
||
686 |
} |
||
687 |
| include |
||
688 |
; |
||
689 |
|||
690 |
tablespec : table { |
||
691 |
struct table *tb; |
||
692 |
if ((tb = calloc(1, sizeof (*tb))) == NULL) |
||
693 |
fatal("out of memory"); |
||
694 |
if (strlcpy(tb->conf.name, $1, |
||
695 |
sizeof(tb->conf.name)) >= sizeof(tb->conf.name)) { |
||
696 |
yyerror("table name truncated"); |
||
697 |
free($1); |
||
698 |
YYERROR; |
||
699 |
} |
||
700 |
free($1); |
||
701 |
table = tb; |
||
702 |
dstmode = RELAY_DSTMODE_DEFAULT; |
||
703 |
hashkey = NULL; |
||
704 |
} tableopts_l { |
||
705 |
struct table *tb; |
||
706 |
if (table->conf.port == 0) |
||
707 |
table->conf.port = tableport; |
||
708 |
else |
||
709 |
table->conf.flags |= F_PORT; |
||
710 |
if ((tb = table_inherit(table)) == NULL) |
||
711 |
YYERROR; |
||
712 |
$$ = tb; |
||
713 |
} |
||
714 |
; |
||
715 |
|||
716 |
tableopts_l : tableopts tableopts_l |
||
717 |
| tableopts |
||
718 |
; |
||
719 |
|||
720 |
tableopts : CHECK tablecheck |
||
721 |
| port { |
||
722 |
if ($1.op != PF_OP_EQ) { |
||
723 |
yyerror("invalid port"); |
||
724 |
YYERROR; |
||
725 |
} |
||
726 |
table->conf.port = $1.val[0]; |
||
727 |
} |
||
728 |
| TIMEOUT timeout { |
||
729 |
bcopy(&$2, &table->conf.timeout, |
||
730 |
sizeof(struct timeval)); |
||
731 |
} |
||
732 |
| DEMOTE STRING { |
||
733 |
table->conf.flags |= F_DEMOTE; |
||
734 |
if (strlcpy(table->conf.demote_group, $2, |
||
735 |
sizeof(table->conf.demote_group)) |
||
736 |
>= sizeof(table->conf.demote_group)) { |
||
737 |
yyerror("yyparse: demote group name too long"); |
||
738 |
free($2); |
||
739 |
YYERROR; |
||
740 |
} |
||
741 |
free($2); |
||
742 |
if (carp_demote_init(table->conf.demote_group, 1) |
||
743 |
== -1) { |
||
744 |
yyerror("yyparse: error initializing group " |
||
745 |
"'%s'", table->conf.demote_group); |
||
746 |
YYERROR; |
||
747 |
} |
||
748 |
} |
||
749 |
| INTERVAL NUMBER { |
||
750 |
if ($2 < conf->sc_conf.interval.tv_sec || |
||
751 |
$2 % conf->sc_conf.interval.tv_sec) { |
||
752 |
yyerror("table interval must be " |
||
753 |
"divisible by global interval"); |
||
754 |
YYERROR; |
||
755 |
} |
||
756 |
table->conf.skip_cnt = |
||
757 |
($2 / conf->sc_conf.interval.tv_sec) - 1; |
||
758 |
} |
||
759 |
| MODE dstmode hashkey { |
||
760 |
switch ($2) { |
||
761 |
case RELAY_DSTMODE_LOADBALANCE: |
||
762 |
case RELAY_DSTMODE_HASH: |
||
763 |
case RELAY_DSTMODE_SRCHASH: |
||
764 |
if (hashkey != NULL) { |
||
765 |
yyerror("key already specified"); |
||
766 |
free(hashkey); |
||
767 |
YYERROR; |
||
768 |
} |
||
769 |
if ((hashkey = calloc(1, |
||
770 |
sizeof(*hashkey))) == NULL) |
||
771 |
fatal("out of memory"); |
||
772 |
memcpy(hashkey, &$3.key, sizeof(*hashkey)); |
||
773 |
break; |
||
774 |
default: |
||
775 |
if ($3.keyset) { |
||
776 |
yyerror("key not supported by mode"); |
||
777 |
YYERROR; |
||
778 |
} |
||
779 |
hashkey = NULL; |
||
780 |
break; |
||
781 |
} |
||
782 |
|||
783 |
switch ($2) { |
||
784 |
case RELAY_DSTMODE_LOADBALANCE: |
||
785 |
case RELAY_DSTMODE_HASH: |
||
786 |
if (rdr != NULL) { |
||
787 |
yyerror("mode not supported " |
||
788 |
"for redirections"); |
||
789 |
YYERROR; |
||
790 |
} |
||
791 |
/* FALLTHROUGH */ |
||
792 |
case RELAY_DSTMODE_RANDOM: |
||
793 |
case RELAY_DSTMODE_ROUNDROBIN: |
||
794 |
case RELAY_DSTMODE_SRCHASH: |
||
795 |
dstmode = $2; |
||
796 |
break; |
||
797 |
case RELAY_DSTMODE_LEASTSTATES: |
||
798 |
if (rdr == NULL) { |
||
799 |
yyerror("mode not supported " |
||
800 |
"for relays"); |
||
801 |
YYERROR; |
||
802 |
} |
||
803 |
dstmode = $2; |
||
804 |
break; |
||
805 |
} |
||
806 |
} |
||
807 |
; |
||
808 |
|||
809 |
/* should be in sync with sbin/pfctl/parse.y's hashkey */ |
||
810 |
hashkey : /* empty */ { |
||
811 |
$$.keyset = 0; |
||
812 |
$$.key.data[0] = arc4random(); |
||
813 |
$$.key.data[1] = arc4random(); |
||
814 |
$$.key.data[2] = arc4random(); |
||
815 |
$$.key.data[3] = arc4random(); |
||
816 |
} |
||
817 |
| STRING { |
||
818 |
/* manual key configuration */ |
||
819 |
$$.keyset = 1; |
||
820 |
|||
821 |
if (!strncmp($1, "0x", 2)) { |
||
822 |
if (strlen($1) != 34) { |
||
823 |
free($1); |
||
824 |
yyerror("hex key must be 128 bits " |
||
825 |
"(32 hex digits) long"); |
||
826 |
YYERROR; |
||
827 |
} |
||
828 |
|||
829 |
if (sscanf($1, "0x%8x%8x%8x%8x", |
||
830 |
&$$.key.data[0], &$$.key.data[1], |
||
831 |
&$$.key.data[2], &$$.key.data[3]) != 4) { |
||
832 |
free($1); |
||
833 |
yyerror("invalid hex key"); |
||
834 |
YYERROR; |
||
835 |
} |
||
836 |
} else { |
||
837 |
MD5_CTX context; |
||
838 |
|||
839 |
MD5Init(&context); |
||
840 |
MD5Update(&context, (unsigned char *)$1, |
||
841 |
strlen($1)); |
||
842 |
MD5Final((unsigned char *)$$.key.data, |
||
843 |
&context); |
||
844 |
HTONL($$.key.data[0]); |
||
845 |
HTONL($$.key.data[1]); |
||
846 |
HTONL($$.key.data[2]); |
||
847 |
HTONL($$.key.data[3]); |
||
848 |
} |
||
849 |
free($1); |
||
850 |
} |
||
851 |
; |
||
852 |
|||
853 |
tablecheck : ICMP { table->conf.check = CHECK_ICMP; } |
||
854 |
| TCP { table->conf.check = CHECK_TCP; } |
||
855 |
| ssltls { |
||
856 |
table->conf.check = CHECK_TCP; |
||
857 |
conf->sc_conf.flags |= F_TLS; |
||
858 |
table->conf.flags |= F_TLS; |
||
859 |
} |
||
860 |
| http_type STRING hostname CODE NUMBER { |
||
861 |
if ($1) { |
||
862 |
conf->sc_conf.flags |= F_TLS; |
||
863 |
table->conf.flags |= F_TLS; |
||
864 |
} |
||
865 |
table->conf.check = CHECK_HTTP_CODE; |
||
866 |
if ((table->conf.retcode = $5) <= 0) { |
||
867 |
yyerror("invalid HTTP code: %d", $5); |
||
868 |
free($2); |
||
869 |
free($3); |
||
870 |
YYERROR; |
||
871 |
} |
||
872 |
if (asprintf(&table->sendbuf, |
||
873 |
"HEAD %s HTTP/1.%c\r\n%s\r\n", |
||
874 |
$2, strlen($3) ? '1' : '0', $3) == -1) |
||
875 |
fatal("asprintf"); |
||
876 |
free($2); |
||
877 |
free($3); |
||
878 |
if (table->sendbuf == NULL) |
||
879 |
fatal("out of memory"); |
||
880 |
} |
||
881 |
| http_type STRING hostname digest { |
||
882 |
if ($1) { |
||
883 |
conf->sc_conf.flags |= F_TLS; |
||
884 |
table->conf.flags |= F_TLS; |
||
885 |
} |
||
886 |
table->conf.check = CHECK_HTTP_DIGEST; |
||
887 |
if (asprintf(&table->sendbuf, |
||
888 |
"GET %s HTTP/1.%c\r\n%s\r\n", |
||
889 |
$2, strlen($3) ? '1' : '0', $3) == -1) |
||
890 |
fatal("asprintf"); |
||
891 |
free($2); |
||
892 |
free($3); |
||
893 |
if (table->sendbuf == NULL) |
||
894 |
fatal("out of memory"); |
||
895 |
if (strlcpy(table->conf.digest, $4.digest, |
||
896 |
sizeof(table->conf.digest)) >= |
||
897 |
sizeof(table->conf.digest)) { |
||
898 |
yyerror("digest truncated"); |
||
899 |
free($4.digest); |
||
900 |
YYERROR; |
||
901 |
} |
||
902 |
table->conf.digest_type = $4.type; |
||
903 |
free($4.digest); |
||
904 |
} |
||
905 |
| SEND sendbuf EXPECT STRING opttls { |
||
906 |
table->conf.check = CHECK_SEND_EXPECT; |
||
907 |
if ($5) { |
||
908 |
conf->sc_conf.flags |= F_TLS; |
||
909 |
table->conf.flags |= F_TLS; |
||
910 |
} |
||
911 |
if (strlcpy(table->conf.exbuf, $4, |
||
912 |
sizeof(table->conf.exbuf)) |
||
913 |
>= sizeof(table->conf.exbuf)) { |
||
914 |
yyerror("yyparse: expect buffer truncated"); |
||
915 |
free($4); |
||
916 |
YYERROR; |
||
917 |
} |
||
918 |
translate_string(table->conf.exbuf); |
||
919 |
free($4); |
||
920 |
} |
||
921 |
| SCRIPT STRING { |
||
922 |
table->conf.check = CHECK_SCRIPT; |
||
923 |
if (strlcpy(table->conf.path, $2, |
||
924 |
sizeof(table->conf.path)) >= |
||
925 |
sizeof(table->conf.path)) { |
||
926 |
yyerror("script path truncated"); |
||
927 |
free($2); |
||
928 |
YYERROR; |
||
929 |
} |
||
930 |
conf->sc_conf.flags |= F_SCRIPT; |
||
931 |
free($2); |
||
932 |
} |
||
933 |
; |
||
934 |
|||
935 |
digest : DIGEST STRING |
||
936 |
{ |
||
937 |
switch (strlen($2)) { |
||
938 |
case 40: |
||
939 |
$$.type = DIGEST_SHA1; |
||
940 |
break; |
||
941 |
case 32: |
||
942 |
$$.type = DIGEST_MD5; |
||
943 |
break; |
||
944 |
default: |
||
945 |
yyerror("invalid http digest"); |
||
946 |
free($2); |
||
947 |
YYERROR; |
||
948 |
} |
||
949 |
$$.digest = $2; |
||
950 |
} |
||
951 |
; |
||
952 |
|||
953 |
optdigest : digest { |
||
954 |
$$.digest = $1.digest; |
||
955 |
$$.type = $1.type; |
||
956 |
} |
||
957 |
| STRING { |
||
958 |
$$.digest = $1; |
||
959 |
$$.type = DIGEST_NONE; |
||
960 |
} |
||
961 |
; |
||
962 |
|||
963 |
proto : relay_proto PROTO STRING { |
||
964 |
struct protocol *p; |
||
965 |
|||
966 |
if (!loadcfg) { |
||
967 |
free($3); |
||
968 |
YYACCEPT; |
||
969 |
} |
||
970 |
|||
971 |
if (strcmp($3, "default") == 0) { |
||
972 |
p = &conf->sc_proto_default; |
||
973 |
} else { |
||
974 |
TAILQ_FOREACH(p, conf->sc_protos, entry) |
||
975 |
if (!strcmp(p->name, $3)) |
||
976 |
break; |
||
977 |
} |
||
978 |
if (p != NULL) { |
||
979 |
yyerror("protocol %s defined twice", $3); |
||
980 |
free($3); |
||
981 |
YYERROR; |
||
982 |
} |
||
983 |
if ((p = calloc(1, sizeof (*p))) == NULL) |
||
984 |
fatal("out of memory"); |
||
985 |
|||
986 |
if (strlcpy(p->name, $3, sizeof(p->name)) >= |
||
987 |
sizeof(p->name)) { |
||
988 |
yyerror("protocol name truncated"); |
||
989 |
free($3); |
||
990 |
free(p); |
||
991 |
YYERROR; |
||
992 |
} |
||
993 |
free($3); |
||
994 |
p->id = ++last_proto_id; |
||
995 |
p->type = $1; |
||
996 |
p->tcpflags = TCPFLAG_DEFAULT; |
||
997 |
p->tlsflags = TLSFLAG_DEFAULT; |
||
998 |
p->tcpbacklog = RELAY_BACKLOG; |
||
999 |
TAILQ_INIT(&p->rules); |
||
1000 |
(void)strlcpy(p->tlsciphers, TLSCIPHERS_DEFAULT, |
||
1001 |
sizeof(p->tlsciphers)); |
||
1002 |
(void)strlcpy(p->tlsecdhcurve, TLSECDHCURVE_DEFAULT, |
||
1003 |
sizeof(p->tlsecdhcurve)); |
||
1004 |
(void)strlcpy(p->tlsdhparams, TLSDHPARAM_DEFAULT, |
||
1005 |
sizeof(p->tlsdhparams)); |
||
1006 |
if (last_proto_id == INT_MAX) { |
||
1007 |
yyerror("too many protocols defined"); |
||
1008 |
free(p); |
||
1009 |
YYERROR; |
||
1010 |
} |
||
1011 |
proto = p; |
||
1012 |
} protopts_n { |
||
1013 |
conf->sc_protocount++; |
||
1014 |
|||
1015 |
if ((proto->tlsflags & TLSFLAG_VERSION) == 0) { |
||
1016 |
yyerror("invalid TLS protocol"); |
||
1017 |
YYERROR; |
||
1018 |
} |
||
1019 |
|||
1020 |
TAILQ_INSERT_TAIL(conf->sc_protos, proto, entry); |
||
1021 |
} |
||
1022 |
; |
||
1023 |
|||
1024 |
protopts_n : /* empty */ |
||
1025 |
| '{' '}' |
||
1026 |
| '{' optnl protopts_l '}' |
||
1027 |
; |
||
1028 |
|||
1029 |
protopts_l : protopts_l protoptsl nl |
||
1030 |
| protoptsl optnl |
||
1031 |
; |
||
1032 |
|||
1033 |
protoptsl : ssltls tlsflags |
||
1034 |
| ssltls '{' tlsflags_l '}' |
||
1035 |
| TCP tcpflags |
||
1036 |
| TCP '{' tcpflags_l '}' |
||
1037 |
| RETURN ERROR opteflags { proto->flags |= F_RETURN; } |
||
1038 |
| RETURN ERROR '{' eflags_l '}' { proto->flags |= F_RETURN; } |
||
1039 |
| filterrule |
||
1040 |
| include |
||
1041 |
; |
||
1042 |
|||
1043 |
tcpflags_l : tcpflags comma tcpflags_l |
||
1044 |
| tcpflags |
||
1045 |
; |
||
1046 |
|||
1047 |
tcpflags : SACK { proto->tcpflags |= TCPFLAG_SACK; } |
||
1048 |
| NO SACK { proto->tcpflags |= TCPFLAG_NSACK; } |
||
1049 |
| NODELAY { proto->tcpflags |= TCPFLAG_NODELAY; } |
||
1050 |
| NO NODELAY { proto->tcpflags |= TCPFLAG_NNODELAY; } |
||
1051 |
| SPLICE { /* default */ } |
||
1052 |
| NO SPLICE { proto->tcpflags |= TCPFLAG_NSPLICE; } |
||
1053 |
| BACKLOG NUMBER { |
||
1054 |
if ($2 < 0 || $2 > RELAY_MAX_SESSIONS) { |
||
1055 |
yyerror("invalid backlog: %d", $2); |
||
1056 |
YYERROR; |
||
1057 |
} |
||
1058 |
proto->tcpbacklog = $2; |
||
1059 |
} |
||
1060 |
| SOCKET BUFFER NUMBER { |
||
1061 |
proto->tcpflags |= TCPFLAG_BUFSIZ; |
||
1062 |
if ((proto->tcpbufsiz = $3) < 0) { |
||
1063 |
yyerror("invalid socket buffer size: %d", $3); |
||
1064 |
YYERROR; |
||
1065 |
} |
||
1066 |
} |
||
1067 |
| IP STRING NUMBER { |
||
1068 |
if ($3 < 0) { |
||
1069 |
yyerror("invalid ttl: %d", $3); |
||
1070 |
free($2); |
||
1071 |
YYERROR; |
||
1072 |
} |
||
1073 |
if (strcasecmp("ttl", $2) == 0) { |
||
1074 |
proto->tcpflags |= TCPFLAG_IPTTL; |
||
1075 |
proto->tcpipttl = $3; |
||
1076 |
} else if (strcasecmp("minttl", $2) == 0) { |
||
1077 |
proto->tcpflags |= TCPFLAG_IPMINTTL; |
||
1078 |
proto->tcpipminttl = $3; |
||
1079 |
} else { |
||
1080 |
yyerror("invalid TCP/IP flag: %s", $2); |
||
1081 |
free($2); |
||
1082 |
YYERROR; |
||
1083 |
} |
||
1084 |
free($2); |
||
1085 |
} |
||
1086 |
; |
||
1087 |
|||
1088 |
tlsflags_l : tlsflags comma tlsflags_l |
||
1089 |
| tlsflags |
||
1090 |
; |
||
1091 |
|||
1092 |
tlsflags : SESSION TICKETS { proto->tickets = 1; } |
||
1093 |
| NO SESSION TICKETS { proto->tickets = 0; } |
||
1094 |
| CIPHERS STRING { |
||
1095 |
if (strlcpy(proto->tlsciphers, $2, |
||
1096 |
sizeof(proto->tlsciphers)) >= |
||
1097 |
sizeof(proto->tlsciphers)) { |
||
1098 |
yyerror("tlsciphers truncated"); |
||
1099 |
free($2); |
||
1100 |
YYERROR; |
||
1101 |
} |
||
1102 |
free($2); |
||
1103 |
} |
||
1104 |
| NO EDH { |
||
1105 |
(void)strlcpy(proto->tlsdhparams, "none", |
||
1106 |
sizeof(proto->tlsdhparams)); |
||
1107 |
} |
||
1108 |
| EDH { |
||
1109 |
(void)strlcpy(proto->tlsdhparams, "auto", |
||
1110 |
sizeof(proto->tlsdhparams)); |
||
1111 |
} |
||
1112 |
| EDH PARAMS STRING { |
||
1113 |
struct tls_config *tls_cfg; |
||
1114 |
if ((tls_cfg = tls_config_new()) == NULL) { |
||
1115 |
yyerror("tls_config_new failed"); |
||
1116 |
free($3); |
||
1117 |
YYERROR; |
||
1118 |
} |
||
1119 |
if (tls_config_set_dheparams(tls_cfg, $3) != 0) { |
||
1120 |
yyerror("tls edh params %s: %s", $3, |
||
1121 |
tls_config_error(tls_cfg)); |
||
1122 |
tls_config_free(tls_cfg); |
||
1123 |
free($3); |
||
1124 |
YYERROR; |
||
1125 |
} |
||
1126 |
tls_config_free(tls_cfg); |
||
1127 |
if (strlcpy(proto->tlsdhparams, $3, |
||
1128 |
sizeof(proto->tlsdhparams)) >= |
||
1129 |
sizeof(proto->tlsdhparams)) { |
||
1130 |
yyerror("tls edh truncated"); |
||
1131 |
free($3); |
||
1132 |
YYERROR; |
||
1133 |
} |
||
1134 |
free($3); |
||
1135 |
} |
||
1136 |
| NO ECDH { |
||
1137 |
(void)strlcpy(proto->tlsecdhcurve, "none", |
||
1138 |
sizeof(proto->tlsecdhcurve)); |
||
1139 |
} |
||
1140 |
| ECDH { |
||
1141 |
(void)strlcpy(proto->tlsecdhcurve, "auto", |
||
1142 |
sizeof(proto->tlsecdhcurve)); |
||
1143 |
} |
||
1144 |
| ECDH CURVE STRING { |
||
1145 |
struct tls_config *tls_cfg; |
||
1146 |
if ((tls_cfg = tls_config_new()) == NULL) { |
||
1147 |
yyerror("tls_config_new failed"); |
||
1148 |
free($3); |
||
1149 |
YYERROR; |
||
1150 |
} |
||
1151 |
if (tls_config_set_ecdhecurve(tls_cfg, $3) != 0) { |
||
1152 |
yyerror("tls ecdh curve %s: %s", $3, |
||
1153 |
tls_config_error(tls_cfg)); |
||
1154 |
tls_config_free(tls_cfg); |
||
1155 |
free($3); |
||
1156 |
YYERROR; |
||
1157 |
} |
||
1158 |
tls_config_free(tls_cfg); |
||
1159 |
if (strlcpy(proto->tlsecdhcurve, $3, |
||
1160 |
sizeof(proto->tlsecdhcurve)) >= |
||
1161 |
sizeof(proto->tlsecdhcurve)) { |
||
1162 |
yyerror("tls ecdh truncated"); |
||
1163 |
free($3); |
||
1164 |
YYERROR; |
||
1165 |
} |
||
1166 |
free($3); |
||
1167 |
} |
||
1168 |
| CA FILENAME STRING { |
||
1169 |
if (strlcpy(proto->tlsca, $3, |
||
1170 |
sizeof(proto->tlsca)) >= |
||
1171 |
sizeof(proto->tlsca)) { |
||
1172 |
yyerror("tlsca truncated"); |
||
1173 |
free($3); |
||
1174 |
YYERROR; |
||
1175 |
} |
||
1176 |
free($3); |
||
1177 |
} |
||
1178 |
| CA KEY STRING PASSWORD STRING { |
||
1179 |
if (strlcpy(proto->tlscakey, $3, |
||
1180 |
sizeof(proto->tlscakey)) >= |
||
1181 |
sizeof(proto->tlscakey)) { |
||
1182 |
yyerror("tlscakey truncated"); |
||
1183 |
free($3); |
||
1184 |
free($5); |
||
1185 |
YYERROR; |
||
1186 |
} |
||
1187 |
if ((proto->tlscapass = strdup($5)) == NULL) { |
||
1188 |
yyerror("tlscapass"); |
||
1189 |
free($3); |
||
1190 |
free($5); |
||
1191 |
YYERROR; |
||
1192 |
} |
||
1193 |
free($3); |
||
1194 |
free($5); |
||
1195 |
} |
||
1196 |
| CA CERTIFICATE STRING { |
||
1197 |
if (strlcpy(proto->tlscacert, $3, |
||
1198 |
sizeof(proto->tlscacert)) >= |
||
1199 |
sizeof(proto->tlscacert)) { |
||
1200 |
yyerror("tlscacert truncated"); |
||
1201 |
free($3); |
||
1202 |
YYERROR; |
||
1203 |
} |
||
1204 |
free($3); |
||
1205 |
} |
||
1206 |
| NO flag { proto->tlsflags &= ~($2); } |
||
1207 |
| flag { proto->tlsflags |= $1; } |
||
1208 |
; |
||
1209 |
|||
1210 |
flag : STRING { |
||
1211 |
if (strcmp("sslv3", $1) == 0) |
||
1212 |
$$ = TLSFLAG_SSLV3; |
||
1213 |
else if (strcmp("tlsv1", $1) == 0) |
||
1214 |
$$ = TLSFLAG_TLSV1; |
||
1215 |
else if (strcmp("tlsv1.0", $1) == 0) |
||
1216 |
$$ = TLSFLAG_TLSV1_0; |
||
1217 |
else if (strcmp("tlsv1.1", $1) == 0) |
||
1218 |
$$ = TLSFLAG_TLSV1_1; |
||
1219 |
else if (strcmp("tlsv1.2", $1) == 0) |
||
1220 |
$$ = TLSFLAG_TLSV1_2; |
||
1221 |
else if (strcmp("cipher-server-preference", $1) == 0) |
||
1222 |
$$ = TLSFLAG_CIPHER_SERVER_PREF; |
||
1223 |
else if (strcmp("client-renegotiation", $1) == 0) |
||
1224 |
$$ = TLSFLAG_CLIENT_RENEG; |
||
1225 |
else { |
||
1226 |
yyerror("invalid TLS flag: %s", $1); |
||
1227 |
free($1); |
||
1228 |
YYERROR; |
||
1229 |
} |
||
1230 |
free($1); |
||
1231 |
} |
||
1232 |
; |
||
1233 |
|||
1234 |
filterrule : action dir quick ruleaf rulesrc ruledst { |
||
1235 |
if ((rule = calloc(1, sizeof(*rule))) == NULL) |
||
1236 |
fatal("out of memory"); |
||
1237 |
|||
1238 |
rule->rule_action = $1; |
||
1239 |
rule->rule_proto = proto->type; |
||
1240 |
rule->rule_dir = $2; |
||
1241 |
rule->rule_flags |= $3; |
||
1242 |
rule->rule_af = $4; |
||
1243 |
|||
1244 |
rulefile = NULL; |
||
1245 |
} ruleopts_l { |
||
1246 |
if (rule_add(proto, rule, rulefile) == -1) { |
||
1247 |
if (rulefile == NULL) { |
||
1248 |
yyerror("failed to load rule"); |
||
1249 |
} else { |
||
1250 |
yyerror("failed to load rules from %s", |
||
1251 |
rulefile); |
||
1252 |
free(rulefile); |
||
1253 |
} |
||
1254 |
rule_free(rule); |
||
1255 |
free(rule); |
||
1256 |
YYERROR; |
||
1257 |
} |
||
1258 |
if (rulefile) |
||
1259 |
free(rulefile); |
||
1260 |
rulefile = NULL; |
||
1261 |
rule = NULL; |
||
1262 |
keytype = KEY_TYPE_NONE; |
||
1263 |
} |
||
1264 |
; |
||
1265 |
|||
1266 |
action : PASS { $$ = RULE_ACTION_PASS; } |
||
1267 |
| BLOCK { $$ = RULE_ACTION_BLOCK; } |
||
1268 |
| MATCH { $$ = RULE_ACTION_MATCH; } |
||
1269 |
; |
||
1270 |
|||
1271 |
dir : /* empty */ { |
||
1272 |
$$ = dir = RELAY_DIR_REQUEST; |
||
1273 |
} |
||
1274 |
| REQUEST { |
||
1275 |
$$ = dir = RELAY_DIR_REQUEST; |
||
1276 |
} |
||
1277 |
| RESPONSE { |
||
1278 |
$$ = dir = RELAY_DIR_RESPONSE; |
||
1279 |
} |
||
1280 |
; |
||
1281 |
|||
1282 |
quick : /* empty */ { $$ = 0; } |
||
1283 |
| QUICK { $$ = RULE_FLAG_QUICK; } |
||
1284 |
; |
||
1285 |
|||
1286 |
ruleaf : /* empty */ { $$ = AF_UNSPEC; } |
||
1287 |
| INET6 { $$ = AF_INET6; } |
||
1288 |
| INET { $$ = AF_INET; } |
||
1289 |
; |
||
1290 |
|||
1291 |
rulesrc : /* XXX */ |
||
1292 |
; |
||
1293 |
|||
1294 |
ruledst : /* XXX */ |
||
1295 |
; |
||
1296 |
|||
1297 |
ruleopts_l : /* empty */ |
||
1298 |
| ruleopts_t |
||
1299 |
; |
||
1300 |
|||
1301 |
ruleopts_t : ruleopts ruleopts_t |
||
1302 |
| ruleopts |
||
1303 |
; |
||
1304 |
|||
1305 |
ruleopts : METHOD STRING { |
||
1306 |
u_int id; |
||
1307 |
if ((id = relay_httpmethod_byname($2)) == |
||
1308 |
HTTP_METHOD_NONE) { |
||
1309 |
yyerror("unknown HTTP method currently not " |
||
1310 |
"supported"); |
||
1311 |
free($2); |
||
1312 |
YYERROR; |
||
1313 |
} |
||
1314 |
rule->rule_method = id; |
||
1315 |
free($2); |
||
1316 |
} |
||
1317 |
| COOKIE key_option STRING value { |
||
1318 |
keytype = KEY_TYPE_COOKIE; |
||
1319 |
rule->rule_kv[keytype].kv_key = strdup($3); |
||
1320 |
rule->rule_kv[keytype].kv_option = $2; |
||
1321 |
rule->rule_kv[keytype].kv_value = (($4 != NULL) ? |
||
1322 |
strdup($4) : strdup("*")); |
||
1323 |
if (rule->rule_kv[keytype].kv_key == NULL || |
||
1324 |
rule->rule_kv[keytype].kv_value == NULL) |
||
1325 |
fatal("out of memory"); |
||
1326 |
free($3); |
||
1327 |
if ($4) |
||
1328 |
free($4); |
||
1329 |
rule->rule_kv[keytype].kv_type = keytype; |
||
1330 |
} |
||
1331 |
| COOKIE key_option { |
||
1332 |
keytype = KEY_TYPE_COOKIE; |
||
1333 |
rule->rule_kv[keytype].kv_option = $2; |
||
1334 |
rule->rule_kv[keytype].kv_type = keytype; |
||
1335 |
} |
||
1336 |
| HEADER key_option STRING value { |
||
1337 |
keytype = KEY_TYPE_HEADER; |
||
1338 |
memset(&rule->rule_kv[keytype], 0, |
||
1339 |
sizeof(rule->rule_kv[keytype])); |
||
1340 |
rule->rule_kv[keytype].kv_option = $2; |
||
1341 |
rule->rule_kv[keytype].kv_key = strdup($3); |
||
1342 |
rule->rule_kv[keytype].kv_value = (($4 != NULL) ? |
||
1343 |
strdup($4) : strdup("*")); |
||
1344 |
if (rule->rule_kv[keytype].kv_key == NULL || |
||
1345 |
rule->rule_kv[keytype].kv_value == NULL) |
||
1346 |
fatal("out of memory"); |
||
1347 |
free($3); |
||
1348 |
if ($4) |
||
1349 |
free($4); |
||
1350 |
rule->rule_kv[keytype].kv_type = keytype; |
||
1351 |
} |
||
1352 |
| HEADER key_option { |
||
1353 |
keytype = KEY_TYPE_HEADER; |
||
1354 |
rule->rule_kv[keytype].kv_option = $2; |
||
1355 |
rule->rule_kv[keytype].kv_type = keytype; |
||
1356 |
} |
||
1357 |
| PATH key_option STRING value { |
||
1358 |
keytype = KEY_TYPE_PATH; |
||
1359 |
rule->rule_kv[keytype].kv_option = $2; |
||
1360 |
rule->rule_kv[keytype].kv_key = strdup($3); |
||
1361 |
rule->rule_kv[keytype].kv_value = (($4 != NULL) ? |
||
1362 |
strdup($4) : strdup("*")); |
||
1363 |
if (rule->rule_kv[keytype].kv_key == NULL || |
||
1364 |
rule->rule_kv[keytype].kv_value == NULL) |
||
1365 |
fatal("out of memory"); |
||
1366 |
free($3); |
||
1367 |
if ($4) |
||
1368 |
free($4); |
||
1369 |
rule->rule_kv[keytype].kv_type = keytype; |
||
1370 |
} |
||
1371 |
| PATH key_option { |
||
1372 |
keytype = KEY_TYPE_PATH; |
||
1373 |
rule->rule_kv[keytype].kv_option = $2; |
||
1374 |
rule->rule_kv[keytype].kv_type = keytype; |
||
1375 |
} |
||
1376 |
| QUERYSTR key_option STRING value { |
||
1377 |
switch ($2) { |
||
1378 |
case KEY_OPTION_APPEND: |
||
1379 |
case KEY_OPTION_SET: |
||
1380 |
case KEY_OPTION_REMOVE: |
||
1381 |
yyerror("combining query type and the given " |
||
1382 |
"option is not supported"); |
||
1383 |
free($3); |
||
1384 |
if ($4) |
||
1385 |
free($4); |
||
1386 |
YYERROR; |
||
1387 |
break; |
||
1388 |
} |
||
1389 |
keytype = KEY_TYPE_QUERY; |
||
1390 |
rule->rule_kv[keytype].kv_option = $2; |
||
1391 |
rule->rule_kv[keytype].kv_key = strdup($3); |
||
1392 |
rule->rule_kv[keytype].kv_value = (($4 != NULL) ? |
||
1393 |
strdup($4) : strdup("*")); |
||
1394 |
if (rule->rule_kv[keytype].kv_key == NULL || |
||
1395 |
rule->rule_kv[keytype].kv_value == NULL) |
||
1396 |
fatal("out of memory"); |
||
1397 |
free($3); |
||
1398 |
if ($4) |
||
1399 |
free($4); |
||
1400 |
rule->rule_kv[keytype].kv_type = keytype; |
||
1401 |
} |
||
1402 |
| QUERYSTR key_option { |
||
1403 |
switch ($2) { |
||
1404 |
case KEY_OPTION_APPEND: |
||
1405 |
case KEY_OPTION_SET: |
||
1406 |
case KEY_OPTION_REMOVE: |
||
1407 |
yyerror("combining query type and the given " |
||
1408 |
"option is not supported"); |
||
1409 |
YYERROR; |
||
1410 |
break; |
||
1411 |
} |
||
1412 |
keytype = KEY_TYPE_QUERY; |
||
1413 |
rule->rule_kv[keytype].kv_option = $2; |
||
1414 |
rule->rule_kv[keytype].kv_type = keytype; |
||
1415 |
} |
||
1416 |
| URL key_option optdigest value { |
||
1417 |
switch ($2) { |
||
1418 |
case KEY_OPTION_APPEND: |
||
1419 |
case KEY_OPTION_SET: |
||
1420 |
case KEY_OPTION_REMOVE: |
||
1421 |
yyerror("combining url type and the given " |
||
1422 |
"option is not supported"); |
||
1423 |
free($3.digest); |
||
1424 |
free($4); |
||
1425 |
YYERROR; |
||
1426 |
break; |
||
1427 |
} |
||
1428 |
keytype = KEY_TYPE_URL; |
||
1429 |
rule->rule_kv[keytype].kv_option = $2; |
||
1430 |
rule->rule_kv[keytype].kv_key = strdup($3.digest); |
||
1431 |
rule->rule_kv[keytype].kv_digest = $3.type; |
||
1432 |
rule->rule_kv[keytype].kv_value = (($4 != NULL) ? |
||
1433 |
strdup($4) : strdup("*")); |
||
1434 |
if (rule->rule_kv[keytype].kv_key == NULL || |
||
1435 |
rule->rule_kv[keytype].kv_value == NULL) |
||
1436 |
fatal("out of memory"); |
||
1437 |
free($3.digest); |
||
1438 |
if ($4) |
||
1439 |
free($4); |
||
1440 |
rule->rule_kv[keytype].kv_type = keytype; |
||
1441 |
} |
||
1442 |
| URL key_option { |
||
1443 |
switch ($2) { |
||
1444 |
case KEY_OPTION_APPEND: |
||
1445 |
case KEY_OPTION_SET: |
||
1446 |
case KEY_OPTION_REMOVE: |
||
1447 |
yyerror("combining url type and the given " |
||
1448 |
"option is not supported"); |
||
1449 |
YYERROR; |
||
1450 |
break; |
||
1451 |
} |
||
1452 |
keytype = KEY_TYPE_URL; |
||
1453 |
rule->rule_kv[keytype].kv_option = $2; |
||
1454 |
rule->rule_kv[keytype].kv_type = keytype; |
||
1455 |
} |
||
1456 |
| FORWARD TO table { |
||
1457 |
if (table_findbyname(conf, $3) == NULL) { |
||
1458 |
yyerror("undefined forward table"); |
||
1459 |
free($3); |
||
1460 |
YYERROR; |
||
1461 |
} |
||
1462 |
if (strlcpy(rule->rule_tablename, $3, |
||
1463 |
sizeof(rule->rule_tablename)) >= |
||
1464 |
sizeof(rule->rule_tablename)) { |
||
1465 |
yyerror("invalid forward table name"); |
||
1466 |
free($3); |
||
1467 |
YYERROR; |
||
1468 |
} |
||
1469 |
free($3); |
||
1470 |
} |
||
1471 |
| TAG STRING { |
||
1472 |
tag = tag_name2id($2); |
||
1473 |
if (rule->rule_tag) { |
||
1474 |
yyerror("tag already defined"); |
||
1475 |
free($2); |
||
1476 |
rule_free(rule); |
||
1477 |
free(rule); |
||
1478 |
YYERROR; |
||
1479 |
} |
||
1480 |
if (tag == 0) { |
||
1481 |
yyerror("invalid tag"); |
||
1482 |
free($2); |
||
1483 |
rule_free(rule); |
||
1484 |
free(rule); |
||
1485 |
YYERROR; |
||
1486 |
} |
||
1487 |
rule->rule_tag = tag; |
||
1488 |
if (strlcpy(rule->rule_tagname, $2, |
||
1489 |
sizeof(rule->rule_tagname)) >= |
||
1490 |
sizeof(rule->rule_tagname)) { |
||
1491 |
yyerror("tag truncated"); |
||
1492 |
free($2); |
||
1493 |
rule_free(rule); |
||
1494 |
free(rule); |
||
1495 |
YYERROR; |
||
1496 |
} |
||
1497 |
free($2); |
||
1498 |
} |
||
1499 |
| NO TAG { |
||
1500 |
if (tag == 0) { |
||
1501 |
yyerror("no tag defined"); |
||
1502 |
YYERROR; |
||
1503 |
} |
||
1504 |
rule->rule_tag = -1; |
||
1505 |
memset(rule->rule_tagname, 0, |
||
1506 |
sizeof(rule->rule_tagname)); |
||
1507 |
} |
||
1508 |
| TAGGED STRING { |
||
1509 |
tagged = tag_name2id($2); |
||
1510 |
if (rule->rule_tagged) { |
||
1511 |
yyerror("tagged already defined"); |
||
1512 |
free($2); |
||
1513 |
rule_free(rule); |
||
1514 |
free(rule); |
||
1515 |
YYERROR; |
||
1516 |
} |
||
1517 |
if (tagged == 0) { |
||
1518 |
yyerror("invalid tag"); |
||
1519 |
free($2); |
||
1520 |
rule_free(rule); |
||
1521 |
free(rule); |
||
1522 |
YYERROR; |
||
1523 |
} |
||
1524 |
rule->rule_tagged = tagged; |
||
1525 |
if (strlcpy(rule->rule_taggedname, $2, |
||
1526 |
sizeof(rule->rule_taggedname)) >= |
||
1527 |
sizeof(rule->rule_taggedname)) { |
||
1528 |
yyerror("tagged truncated"); |
||
1529 |
free($2); |
||
1530 |
rule_free(rule); |
||
1531 |
free(rule); |
||
1532 |
YYERROR; |
||
1533 |
} |
||
1534 |
free($2); |
||
1535 |
} |
||
1536 |
| LABEL STRING { |
||
1537 |
label = label_name2id($2); |
||
1538 |
if (rule->rule_label) { |
||
1539 |
yyerror("label already defined"); |
||
1540 |
free($2); |
||
1541 |
rule_free(rule); |
||
1542 |
free(rule); |
||
1543 |
YYERROR; |
||
1544 |
} |
||
1545 |
if (label == 0) { |
||
1546 |
yyerror("invalid label"); |
||
1547 |
free($2); |
||
1548 |
rule_free(rule); |
||
1549 |
free(rule); |
||
1550 |
YYERROR; |
||
1551 |
} |
||
1552 |
rule->rule_label = label; |
||
1553 |
if (strlcpy(rule->rule_labelname, $2, |
||
1554 |
sizeof(rule->rule_labelname)) >= |
||
1555 |
sizeof(rule->rule_labelname)) { |
||
1556 |
yyerror("label truncated"); |
||
1557 |
free($2); |
||
1558 |
rule_free(rule); |
||
1559 |
free(rule); |
||
1560 |
YYERROR; |
||
1561 |
} |
||
1562 |
free($2); |
||
1563 |
} |
||
1564 |
| NO LABEL { |
||
1565 |
if (label == 0) { |
||
1566 |
yyerror("no label defined"); |
||
1567 |
YYERROR; |
||
1568 |
} |
||
1569 |
rule->rule_label = -1; |
||
1570 |
memset(rule->rule_labelname, 0, |
||
1571 |
sizeof(rule->rule_labelname)); |
||
1572 |
} |
||
1573 |
| FILENAME STRING value { |
||
1574 |
if (rulefile != NULL) { |
||
1575 |
yyerror("only one file per rule supported"); |
||
1576 |
free($2); |
||
1577 |
free($3); |
||
1578 |
rule_free(rule); |
||
1579 |
free(rule); |
||
1580 |
YYERROR; |
||
1581 |
} |
||
1582 |
if ($3) { |
||
1583 |
if ((rule->rule_kv[keytype].kv_value = |
||
1584 |
strdup($3)) == NULL) |
||
1585 |
fatal("out of memory"); |
||
1586 |
free($3); |
||
1587 |
} else |
||
1588 |
rule->rule_kv[keytype].kv_value = NULL; |
||
1589 |
rulefile = $2; |
||
1590 |
} |
||
1591 |
; |
||
1592 |
|||
1593 |
value : /* empty */ { $$ = NULL; } |
||
1594 |
| VALUE STRING { $$ = $2; } |
||
1595 |
; |
||
1596 |
|||
1597 |
key_option : /* empty */ { $$ = KEY_OPTION_NONE; } |
||
1598 |
| APPEND { $$ = KEY_OPTION_APPEND; } |
||
1599 |
| SET { $$ = KEY_OPTION_SET; } |
||
1600 |
| REMOVE { $$ = KEY_OPTION_REMOVE; } |
||
1601 |
| HASH { $$ = KEY_OPTION_HASH; } |
||
1602 |
| LOG { $$ = KEY_OPTION_LOG; } |
||
1603 |
; |
||
1604 |
|||
1605 |
relay : RELAY STRING { |
||
1606 |
struct relay *r; |
||
1607 |
|||
1608 |
if (!loadcfg) { |
||
1609 |
free($2); |
||
1610 |
YYACCEPT; |
||
1611 |
} |
||
1612 |
|||
1613 |
TAILQ_FOREACH(r, conf->sc_relays, rl_entry) |
||
1614 |
if (!strcmp(r->rl_conf.name, $2)) |
||
1615 |
break; |
||
1616 |
if (r != NULL) { |
||
1617 |
yyerror("relay %s defined twice", $2); |
||
1618 |
free($2); |
||
1619 |
YYERROR; |
||
1620 |
} |
||
1621 |
TAILQ_INIT(&relays); |
||
1622 |
|||
1623 |
if ((r = calloc(1, sizeof (*r))) == NULL) |
||
1624 |
fatal("out of memory"); |
||
1625 |
|||
1626 |
if (strlcpy(r->rl_conf.name, $2, |
||
1627 |
sizeof(r->rl_conf.name)) >= |
||
1628 |
sizeof(r->rl_conf.name)) { |
||
1629 |
yyerror("relay name truncated"); |
||
1630 |
free($2); |
||
1631 |
free(r); |
||
1632 |
YYERROR; |
||
1633 |
} |
||
1634 |
free($2); |
||
1635 |
if (relay_id(r) == -1) { |
||
1636 |
yyerror("too many relays defined"); |
||
1637 |
free(r); |
||
1638 |
YYERROR; |
||
1639 |
} |
||
1640 |
r->rl_conf.timeout.tv_sec = RELAY_TIMEOUT; |
||
1641 |
r->rl_proto = NULL; |
||
1642 |
r->rl_conf.proto = EMPTY_ID; |
||
1643 |
r->rl_conf.dstretry = 0; |
||
1644 |
TAILQ_INIT(&r->rl_tables); |
||
1645 |
if (last_relay_id == INT_MAX) { |
||
1646 |
yyerror("too many relays defined"); |
||
1647 |
free(r); |
||
1648 |
YYERROR; |
||
1649 |
} |
||
1650 |
dstmode = RELAY_DSTMODE_DEFAULT; |
||
1651 |
rlay = r; |
||
1652 |
} '{' optnl relayopts_l '}' { |
||
1653 |
struct relay *r; |
||
1654 |
|||
1655 |
if (rlay->rl_conf.ss.ss_family == AF_UNSPEC) { |
||
1656 |
yyerror("relay %s has no listener", |
||
1657 |
rlay->rl_conf.name); |
||
1658 |
YYERROR; |
||
1659 |
} |
||
1660 |
if ((rlay->rl_conf.flags & (F_NATLOOK|F_DIVERT)) == |
||
1661 |
(F_NATLOOK|F_DIVERT)) { |
||
1662 |
yyerror("relay %s with conflicting nat lookup " |
||
1663 |
"and peer options", rlay->rl_conf.name); |
||
1664 |
YYERROR; |
||
1665 |
} |
||
1666 |
if ((rlay->rl_conf.flags & (F_NATLOOK|F_DIVERT)) == 0 && |
||
1667 |
rlay->rl_conf.dstss.ss_family == AF_UNSPEC && |
||
1668 |
TAILQ_EMPTY(&rlay->rl_tables)) { |
||
1669 |
yyerror("relay %s has no target, rdr, " |
||
1670 |
"or table", rlay->rl_conf.name); |
||
1671 |
YYERROR; |
||
1672 |
} |
||
1673 |
if (rlay->rl_conf.proto == EMPTY_ID) { |
||
1674 |
rlay->rl_proto = &conf->sc_proto_default; |
||
1675 |
rlay->rl_conf.proto = conf->sc_proto_default.id; |
||
1676 |
} |
||
1677 |
if (relay_load_certfiles(rlay) == -1) { |
||
1678 |
yyerror("cannot load certificates for relay %s", |
||
1679 |
rlay->rl_conf.name); |
||
1680 |
YYERROR; |
||
1681 |
} |
||
1682 |
conf->sc_relaycount++; |
||
1683 |
SPLAY_INIT(&rlay->rl_sessions); |
||
1684 |
TAILQ_INSERT_TAIL(conf->sc_relays, rlay, rl_entry); |
||
1685 |
|||
1686 |
tableport = 0; |
||
1687 |
|||
1688 |
while ((r = TAILQ_FIRST(&relays)) != NULL) { |
||
1689 |
TAILQ_REMOVE(&relays, r, rl_entry); |
||
1690 |
if (relay_inherit(rlay, r) == NULL) { |
||
1691 |
YYERROR; |
||
1692 |
} |
||
1693 |
} |
||
1694 |
rlay = NULL; |
||
1695 |
} |
||
1696 |
; |
||
1697 |
|||
1698 |
relayopts_l : relayopts_l relayoptsl nl |
||
1699 |
| relayoptsl optnl |
||
1700 |
; |
||
1701 |
|||
1702 |
relayoptsl : LISTEN ON STRING port opttls { |
||
1703 |
struct addresslist al; |
||
1704 |
struct address *h; |
||
1705 |
struct relay *r; |
||
1706 |
|||
1707 |
if (rlay->rl_conf.ss.ss_family != AF_UNSPEC) { |
||
1708 |
if ((r = calloc(1, sizeof (*r))) == NULL) |
||
1709 |
fatal("out of memory"); |
||
1710 |
TAILQ_INSERT_TAIL(&relays, r, rl_entry); |
||
1711 |
} else |
||
1712 |
r = rlay; |
||
1713 |
if ($4.op != PF_OP_EQ) { |
||
1714 |
yyerror("invalid port"); |
||
1715 |
free($3); |
||
1716 |
YYERROR; |
||
1717 |
} |
||
1718 |
|||
1719 |
TAILQ_INIT(&al); |
||
1720 |
if (host($3, &al, 1, &$4, NULL, -1) <= 0) { |
||
1721 |
yyerror("invalid listen ip: %s", $3); |
||
1722 |
free($3); |
||
1723 |
YYERROR; |
||
1724 |
} |
||
1725 |
free($3); |
||
1726 |
h = TAILQ_FIRST(&al); |
||
1727 |
bcopy(&h->ss, &r->rl_conf.ss, sizeof(r->rl_conf.ss)); |
||
1728 |
r->rl_conf.port = h->port.val[0]; |
||
1729 |
if ($5) { |
||
1730 |
r->rl_conf.flags |= F_TLS; |
||
1731 |
conf->sc_conf.flags |= F_TLS; |
||
1732 |
} |
||
1733 |
tableport = h->port.val[0]; |
||
1734 |
host_free(&al); |
||
1735 |
} |
||
1736 |
| forwardmode opttlsclient TO forwardspec dstaf { |
||
1737 |
rlay->rl_conf.fwdmode = $1; |
||
1738 |
if ($1 == FWD_ROUTE) { |
||
1739 |
yyerror("no route for relays"); |
||
1740 |
YYERROR; |
||
1741 |
} |
||
1742 |
if ($2) { |
||
1743 |
rlay->rl_conf.flags |= F_TLSCLIENT; |
||
1744 |
conf->sc_conf.flags |= F_TLSCLIENT; |
||
1745 |
} |
||
1746 |
} |
||
1747 |
| SESSION TIMEOUT NUMBER { |
||
1748 |
if ((rlay->rl_conf.timeout.tv_sec = $3) < 0) { |
||
1749 |
yyerror("invalid timeout: %lld", $3); |
||
1750 |
YYERROR; |
||
1751 |
} |
||
1752 |
if (rlay->rl_conf.timeout.tv_sec > INT_MAX) { |
||
1753 |
yyerror("timeout too large: %lld", $3); |
||
1754 |
YYERROR; |
||
1755 |
} |
||
1756 |
} |
||
1757 |
| PROTO STRING { |
||
1758 |
struct protocol *p; |
||
1759 |
|||
1760 |
TAILQ_FOREACH(p, conf->sc_protos, entry) |
||
1761 |
if (!strcmp(p->name, $2)) |
||
1762 |
break; |
||
1763 |
if (p == NULL) { |
||
1764 |
yyerror("no such protocol: %s", $2); |
||
1765 |
free($2); |
||
1766 |
YYERROR; |
||
1767 |
} |
||
1768 |
p->flags |= F_USED; |
||
1769 |
rlay->rl_conf.proto = p->id; |
||
1770 |
rlay->rl_proto = p; |
||
1771 |
free($2); |
||
1772 |
} |
||
1773 |
| DISABLE { rlay->rl_conf.flags |= F_DISABLE; } |
||
1774 |
| include |
||
1775 |
; |
||
1776 |
|||
1777 |
forwardspec : STRING port retry { |
||
1778 |
struct addresslist al; |
||
1779 |
struct address *h; |
||
1780 |
|||
1781 |
if (rlay->rl_conf.dstss.ss_family != AF_UNSPEC) { |
||
1782 |
yyerror("relay %s target or redirection " |
||
1783 |
"already specified", rlay->rl_conf.name); |
||
1784 |
free($1); |
||
1785 |
YYERROR; |
||
1786 |
} |
||
1787 |
if ($2.op != PF_OP_EQ) { |
||
1788 |
yyerror("invalid port"); |
||
1789 |
free($1); |
||
1790 |
YYERROR; |
||
1791 |
} |
||
1792 |
|||
1793 |
TAILQ_INIT(&al); |
||
1794 |
if (host($1, &al, 1, &$2, NULL, -1) <= 0) { |
||
1795 |
yyerror("invalid listen ip: %s", $1); |
||
1796 |
free($1); |
||
1797 |
YYERROR; |
||
1798 |
} |
||
1799 |
free($1); |
||
1800 |
h = TAILQ_FIRST(&al); |
||
1801 |
bcopy(&h->ss, &rlay->rl_conf.dstss, |
||
1802 |
sizeof(rlay->rl_conf.dstss)); |
||
1803 |
rlay->rl_conf.dstport = h->port.val[0]; |
||
1804 |
rlay->rl_conf.dstretry = $3; |
||
1805 |
host_free(&al); |
||
1806 |
} |
||
1807 |
| NAT LOOKUP retry { |
||
1808 |
conf->sc_conf.flags |= F_NEEDPF; |
||
1809 |
rlay->rl_conf.flags |= F_NATLOOK; |
||
1810 |
rlay->rl_conf.dstretry = $3; |
||
1811 |
} |
||
1812 |
| DESTINATION retry { |
||
1813 |
conf->sc_conf.flags |= F_NEEDPF; |
||
1814 |
rlay->rl_conf.flags |= F_DIVERT; |
||
1815 |
rlay->rl_conf.dstretry = $2; |
||
1816 |
} |
||
1817 |
| tablespec { |
||
1818 |
struct relay_table *rlt; |
||
1819 |
|||
1820 |
if ((rlt = calloc(1, sizeof(*rlt))) == NULL) { |
||
1821 |
yyerror("failed to allocate table reference"); |
||
1822 |
YYERROR; |
||
1823 |
} |
||
1824 |
|||
1825 |
rlt->rlt_table = $1; |
||
1826 |
rlt->rlt_table->conf.flags |= F_USED; |
||
1827 |
rlt->rlt_mode = dstmode; |
||
1828 |
rlt->rlt_flags = F_USED; |
||
1829 |
if (!TAILQ_EMPTY(&rlay->rl_tables)) |
||
1830 |
rlt->rlt_flags |= F_BACKUP; |
||
1831 |
|||
1832 |
if (hashkey != NULL && |
||
1833 |
(rlay->rl_conf.flags & F_HASHKEY) == 0) { |
||
1834 |
memcpy(&rlay->rl_conf.hashkey, |
||
1835 |
hashkey, sizeof(rlay->rl_conf.hashkey)); |
||
1836 |
rlay->rl_conf.flags |= F_HASHKEY; |
||
1837 |
} |
||
1838 |
free(hashkey); |
||
1839 |
hashkey = NULL; |
||
1840 |
|||
1841 |
TAILQ_INSERT_TAIL(&rlay->rl_tables, rlt, rlt_entry); |
||
1842 |
} |
||
1843 |
; |
||
1844 |
|||
1845 |
dstmode : /* empty */ { $$ = RELAY_DSTMODE_DEFAULT; } |
||
1846 |
| LOADBALANCE { $$ = RELAY_DSTMODE_LOADBALANCE; } |
||
1847 |
| ROUNDROBIN { $$ = RELAY_DSTMODE_ROUNDROBIN; } |
||
1848 |
| HASH { $$ = RELAY_DSTMODE_HASH; } |
||
1849 |
| LEASTSTATES { $$ = RELAY_DSTMODE_LEASTSTATES; } |
||
1850 |
| SRCHASH { $$ = RELAY_DSTMODE_SRCHASH; } |
||
1851 |
| RANDOM { $$ = RELAY_DSTMODE_RANDOM; } |
||
1852 |
; |
||
1853 |
|||
1854 |
router : ROUTER STRING { |
||
1855 |
struct router *rt = NULL; |
||
1856 |
|||
1857 |
if (!loadcfg) { |
||
1858 |
free($2); |
||
1859 |
YYACCEPT; |
||
1860 |
} |
||
1861 |
|||
1862 |
conf->sc_conf.flags |= F_NEEDRT; |
||
1863 |
TAILQ_FOREACH(rt, conf->sc_rts, rt_entry) |
||
1864 |
if (!strcmp(rt->rt_conf.name, $2)) |
||
1865 |
break; |
||
1866 |
if (rt != NULL) { |
||
1867 |
yyerror("router %s defined twice", $2); |
||
1868 |
free($2); |
||
1869 |
YYERROR; |
||
1870 |
} |
||
1871 |
|||
1872 |
if ((rt = calloc(1, sizeof (*rt))) == NULL) |
||
1873 |
fatal("out of memory"); |
||
1874 |
|||
1875 |
if (strlcpy(rt->rt_conf.name, $2, |
||
1876 |
sizeof(rt->rt_conf.name)) >= |
||
1877 |
sizeof(rt->rt_conf.name)) { |
||
1878 |
yyerror("router name truncated"); |
||
1879 |
free(rt); |
||
1880 |
YYERROR; |
||
1881 |
} |
||
1882 |
free($2); |
||
1883 |
rt->rt_conf.id = ++last_rt_id; |
||
1884 |
if (last_rt_id == INT_MAX) { |
||
1885 |
yyerror("too many routers defined"); |
||
1886 |
free(rt); |
||
1887 |
YYERROR; |
||
1888 |
} |
||
1889 |
TAILQ_INIT(&rt->rt_netroutes); |
||
1890 |
router = rt; |
||
1891 |
|||
1892 |
tableport = -1; |
||
1893 |
} '{' optnl routeopts_l '}' { |
||
1894 |
if (!router->rt_conf.nroutes) { |
||
1895 |
yyerror("router %s without routes", |
||
1896 |
router->rt_conf.name); |
||
1897 |
free(router); |
||
1898 |
router = NULL; |
||
1899 |
YYERROR; |
||
1900 |
} |
||
1901 |
|||
1902 |
conf->sc_routercount++; |
||
1903 |
TAILQ_INSERT_TAIL(conf->sc_rts, router, rt_entry); |
||
1904 |
router = NULL; |
||
1905 |
|||
1906 |
tableport = 0; |
||
1907 |
} |
||
1908 |
; |
||
1909 |
|||
1910 |
routeopts_l : routeopts_l routeoptsl nl |
||
1911 |
| routeoptsl optnl |
||
1912 |
; |
||
1913 |
|||
1914 |
routeoptsl : ROUTE address '/' NUMBER { |
||
1915 |
struct netroute *nr; |
||
1916 |
|||
1917 |
if (router->rt_conf.af == AF_UNSPEC) |
||
1918 |
router->rt_conf.af = $2.ss.ss_family; |
||
1919 |
else if (router->rt_conf.af != $2.ss.ss_family) { |
||
1920 |
yyerror("router %s address family mismatch", |
||
1921 |
router->rt_conf.name); |
||
1922 |
YYERROR; |
||
1923 |
} |
||
1924 |
|||
1925 |
if ((router->rt_conf.af == AF_INET && |
||
1926 |
($4 > 32 || $4 < 0)) || |
||
1927 |
(router->rt_conf.af == AF_INET6 && |
||
1928 |
($4 > 128 || $4 < 0))) { |
||
1929 |
yyerror("invalid prefixlen %d", $4); |
||
1930 |
YYERROR; |
||
1931 |
} |
||
1932 |
|||
1933 |
if ((nr = calloc(1, sizeof(*nr))) == NULL) |
||
1934 |
fatal("out of memory"); |
||
1935 |
|||
1936 |
nr->nr_conf.id = ++last_nr_id; |
||
1937 |
if (last_nr_id == INT_MAX) { |
||
1938 |
yyerror("too many routes defined"); |
||
1939 |
free(nr); |
||
1940 |
YYERROR; |
||
1941 |
} |
||
1942 |
nr->nr_conf.prefixlen = $4; |
||
1943 |
nr->nr_conf.routerid = router->rt_conf.id; |
||
1944 |
nr->nr_router = router; |
||
1945 |
bcopy(&$2.ss, &nr->nr_conf.ss, sizeof($2.ss)); |
||
1946 |
|||
1947 |
router->rt_conf.nroutes++; |
||
1948 |
conf->sc_routecount++; |
||
1949 |
TAILQ_INSERT_TAIL(&router->rt_netroutes, nr, nr_entry); |
||
1950 |
TAILQ_INSERT_TAIL(conf->sc_routes, nr, nr_route); |
||
1951 |
} |
||
1952 |
| FORWARD TO tablespec { |
||
1953 |
free(hashkey); |
||
1954 |
hashkey = NULL; |
||
1955 |
|||
1956 |
if (router->rt_gwtable) { |
||
1957 |
yyerror("router %s table already specified", |
||
1958 |
router->rt_conf.name); |
||
1959 |
purge_table(conf, conf->sc_tables, $3); |
||
1960 |
YYERROR; |
||
1961 |
} |
||
1962 |
router->rt_gwtable = $3; |
||
1963 |
router->rt_gwtable->conf.flags |= F_USED; |
||
1964 |
router->rt_conf.gwtable = $3->conf.id; |
||
1965 |
router->rt_conf.gwport = $3->conf.port; |
||
1966 |
} |
||
1967 |
| RTABLE NUMBER { |
||
1968 |
if (router->rt_conf.rtable) { |
||
1969 |
yyerror("router %s rtable already specified", |
||
1970 |
router->rt_conf.name); |
||
1971 |
YYERROR; |
||
1972 |
} |
||
1973 |
if ($2 < 0 || $2 > RT_TABLEID_MAX) { |
||
1974 |
yyerror("invalid rtable id %d", $2); |
||
1975 |
YYERROR; |
||
1976 |
} |
||
1977 |
router->rt_conf.rtable = $2; |
||
1978 |
} |
||
1979 |
| RTLABEL STRING { |
||
1980 |
if (strlcpy(router->rt_conf.label, $2, |
||
1981 |
sizeof(router->rt_conf.label)) >= |
||
1982 |
sizeof(router->rt_conf.label)) { |
||
1983 |
yyerror("route label truncated"); |
||
1984 |
free($2); |
||
1985 |
YYERROR; |
||
1986 |
} |
||
1987 |
free($2); |
||
1988 |
} |
||
1989 |
| DISABLE { rlay->rl_conf.flags |= F_DISABLE; } |
||
1990 |
| include |
||
1991 |
; |
||
1992 |
|||
1993 |
dstaf : /* empty */ { |
||
1994 |
rlay->rl_conf.dstaf.ss_family = AF_UNSPEC; |
||
1995 |
} |
||
1996 |
| INET { |
||
1997 |
rlay->rl_conf.dstaf.ss_family = AF_INET; |
||
1998 |
} |
||
1999 |
| INET6 STRING { |
||
2000 |
struct sockaddr_in6 *sin6; |
||
2001 |
|||
2002 |
sin6 = (struct sockaddr_in6 *)&rlay->rl_conf.dstaf; |
||
2003 |
if (inet_pton(AF_INET6, $2, &sin6->sin6_addr) == -1) { |
||
2004 |
yyerror("invalid ipv6 address %s", $2); |
||
2005 |
free($2); |
||
2006 |
YYERROR; |
||
2007 |
} |
||
2008 |
free($2); |
||
2009 |
|||
2010 |
sin6->sin6_family = AF_INET6; |
||
2011 |
sin6->sin6_len = sizeof(*sin6); |
||
2012 |
} |
||
2013 |
; |
||
2014 |
|||
2015 |
interface : /* empty */ { $$ = NULL; } |
||
2016 |
| INTERFACE STRING { $$ = $2; } |
||
2017 |
; |
||
2018 |
|||
2019 |
host : address { |
||
2020 |
if ((hst = calloc(1, sizeof(*(hst)))) == NULL) |
||
2021 |
fatal("out of memory"); |
||
2022 |
|||
2023 |
if (strlcpy(hst->conf.name, $1.name, |
||
2024 |
sizeof(hst->conf.name)) >= sizeof(hst->conf.name)) { |
||
2025 |
yyerror("host name truncated"); |
||
2026 |
free(hst); |
||
2027 |
YYERROR; |
||
2028 |
} |
||
2029 |
bcopy(&$1.ss, &hst->conf.ss, sizeof($1.ss)); |
||
2030 |
hst->conf.id = 0; /* will be set later */ |
||
2031 |
SLIST_INIT(&hst->children); |
||
2032 |
} opthostflags { |
||
2033 |
$$ = hst; |
||
2034 |
hst = NULL; |
||
2035 |
} |
||
2036 |
; |
||
2037 |
|||
2038 |
opthostflags : /* empty */ |
||
2039 |
| hostflags_l |
||
2040 |
; |
||
2041 |
|||
2042 |
hostflags_l : hostflags hostflags_l |
||
2043 |
| hostflags |
||
2044 |
; |
||
2045 |
|||
2046 |
hostflags : RETRY NUMBER { |
||
2047 |
if (hst->conf.retry) { |
||
2048 |
yyerror("retry value already set"); |
||
2049 |
YYERROR; |
||
2050 |
} |
||
2051 |
if ($2 < 0) { |
||
2052 |
yyerror("invalid retry value: %d\n", $2); |
||
2053 |
YYERROR; |
||
2054 |
} |
||
2055 |
hst->conf.retry = $2; |
||
2056 |
} |
||
2057 |
| PARENT NUMBER { |
||
2058 |
if (hst->conf.parentid) { |
||
2059 |
yyerror("parent value already set"); |
||
2060 |
YYERROR; |
||
2061 |
} |
||
2062 |
if ($2 < 0) { |
||
2063 |
yyerror("invalid parent value: %d\n", $2); |
||
2064 |
YYERROR; |
||
2065 |
} |
||
2066 |
hst->conf.parentid = $2; |
||
2067 |
} |
||
2068 |
| PRIORITY NUMBER { |
||
2069 |
if (hst->conf.priority) { |
||
2070 |
yyerror("priority already set"); |
||
2071 |
YYERROR; |
||
2072 |
} |
||
2073 |
if ($2 < 0 || $2 > RTP_MAX) { |
||
2074 |
yyerror("invalid priority value: %d\n", $2); |
||
2075 |
YYERROR; |
||
2076 |
} |
||
2077 |
hst->conf.priority = $2; |
||
2078 |
} |
||
2079 |
| IP TTL NUMBER { |
||
2080 |
if (hst->conf.ttl) { |
||
2081 |
yyerror("ttl value already set"); |
||
2082 |
YYERROR; |
||
2083 |
} |
||
2084 |
if ($3 < 0) { |
||
2085 |
yyerror("invalid ttl value: %d\n", $3); |
||
2086 |
YYERROR; |
||
2087 |
} |
||
2088 |
hst->conf.ttl = $3; |
||
2089 |
} |
||
2090 |
; |
||
2091 |
|||
2092 |
address : STRING { |
||
2093 |
struct address *h; |
||
2094 |
struct addresslist al; |
||
2095 |
|||
2096 |
if (strlcpy($$.name, $1, |
||
2097 |
sizeof($$.name)) >= sizeof($$.name)) { |
||
2098 |
yyerror("host name truncated"); |
||
2099 |
free($1); |
||
2100 |
YYERROR; |
||
2101 |
} |
||
2102 |
|||
2103 |
TAILQ_INIT(&al); |
||
2104 |
if (host($1, &al, 1, NULL, NULL, -1) <= 0) { |
||
2105 |
yyerror("invalid host %s", $1); |
||
2106 |
free($1); |
||
2107 |
YYERROR; |
||
2108 |
} |
||
2109 |
free($1); |
||
2110 |
h = TAILQ_FIRST(&al); |
||
2111 |
memcpy(&$$.ss, &h->ss, sizeof($$.ss)); |
||
2112 |
host_free(&al); |
||
2113 |
} |
||
2114 |
; |
||
2115 |
|||
2116 |
retry : /* empty */ { $$ = 0; } |
||
2117 |
| RETRY NUMBER { |
||
2118 |
if (($$ = $2) < 0) { |
||
2119 |
yyerror("invalid retry value: %d\n", $2); |
||
2120 |
YYERROR; |
||
2121 |
} |
||
2122 |
} |
||
2123 |
; |
||
2124 |
|||
2125 |
timeout : NUMBER |
||
2126 |
{ |
||
2127 |
if ($1 < 0) { |
||
2128 |
yyerror("invalid timeout: %d\n", $1); |
||
2129 |
YYERROR; |
||
2130 |
} |
||
2131 |
$$.tv_sec = $1 / 1000; |
||
2132 |
$$.tv_usec = ($1 % 1000) * 1000; |
||
2133 |
} |
||
2134 |
; |
||
2135 |
|||
2136 |
comma : ',' |
||
2137 |
| nl |
||
2138 |
| /* empty */ |
||
2139 |
; |
||
2140 |
|||
2141 |
optnl : '\n' optnl |
||
2142 |
| |
||
2143 |
; |
||
2144 |
|||
2145 |
nl : '\n' optnl |
||
2146 |
; |
||
2147 |
|||
2148 |
optstring : STRING { $$ = $1; } |
||
2149 |
| /* nothing */ { $$ = NULL; } |
||
2150 |
; |
||
2151 |
%% |
||
2152 |
|||
2153 |
struct keywords { |
||
2154 |
const char *k_name; |
||
2155 |
int k_val; |
||
2156 |
}; |
||
2157 |
|||
2158 |
int |
||
2159 |
yyerror(const char *fmt, ...) |
||
2160 |
{ |
||
2161 |
28 |
va_list ap; |
|
2162 |
14 |
char *msg; |
|
2163 |
|||
2164 |
14 |
file->errors++; |
|
2165 |
14 |
va_start(ap, fmt); |
|
2166 |
✗✓ | 14 |
if (vasprintf(&msg, fmt, ap) == -1) |
2167 |
fatalx("yyerror vasprintf"); |
||
2168 |
14 |
va_end(ap); |
|
2169 |
14 |
logit(LOG_CRIT, "%s:%d: %s", file->name, yylval.lineno, msg); |
|
2170 |
14 |
free(msg); |
|
2171 |
14 |
return (0); |
|
2172 |
14 |
} |
|
2173 |
|||
2174 |
int |
||
2175 |
kw_cmp(const void *k, const void *e) |
||
2176 |
{ |
||
2177 |
416436 |
return (strcmp(k, ((const struct keywords *)e)->k_name)); |
|
2178 |
} |
||
2179 |
|||
2180 |
int |
||
2181 |
lookup(char *s) |
||
2182 |
{ |
||
2183 |
/* this has to be sorted always */ |
||
2184 |
static const struct keywords keywords[] = { |
||
2185 |
{ "all", ALL }, |
||
2186 |
{ "append", APPEND }, |
||
2187 |
{ "backlog", BACKLOG }, |
||
2188 |
{ "backup", BACKUP }, |
||
2189 |
{ "block", BLOCK }, |
||
2190 |
{ "buffer", BUFFER }, |
||
2191 |
{ "ca", CA }, |
||
2192 |
{ "cache", CACHE }, |
||
2193 |
{ "cert", CERTIFICATE }, |
||
2194 |
{ "check", CHECK }, |
||
2195 |
{ "ciphers", CIPHERS }, |
||
2196 |
{ "code", CODE }, |
||
2197 |
{ "cookie", COOKIE }, |
||
2198 |
{ "curve", CURVE }, |
||
2199 |
{ "demote", DEMOTE }, |
||
2200 |
{ "destination", DESTINATION }, |
||
2201 |
{ "digest", DIGEST }, |
||
2202 |
{ "disable", DISABLE }, |
||
2203 |
{ "ecdh", ECDH }, |
||
2204 |
{ "edh", EDH }, |
||
2205 |
{ "error", ERROR }, |
||
2206 |
{ "expect", EXPECT }, |
||
2207 |
{ "external", EXTERNAL }, |
||
2208 |
{ "file", FILENAME }, |
||
2209 |
{ "forward", FORWARD }, |
||
2210 |
{ "from", FROM }, |
||
2211 |
{ "hash", HASH }, |
||
2212 |
{ "header", HEADER }, |
||
2213 |
{ "host", HOST }, |
||
2214 |
{ "icmp", ICMP }, |
||
2215 |
{ "include", INCLUDE }, |
||
2216 |
{ "inet", INET }, |
||
2217 |
{ "inet6", INET6 }, |
||
2218 |
{ "interface", INTERFACE }, |
||
2219 |
{ "interval", INTERVAL }, |
||
2220 |
{ "ip", IP }, |
||
2221 |
{ "key", KEY }, |
||
2222 |
{ "label", LABEL }, |
||
2223 |
{ "least-states", LEASTSTATES }, |
||
2224 |
{ "listen", LISTEN }, |
||
2225 |
{ "loadbalance", LOADBALANCE }, |
||
2226 |
{ "log", LOG }, |
||
2227 |
{ "lookup", LOOKUP }, |
||
2228 |
{ "match", MATCH }, |
||
2229 |
{ "method", METHOD }, |
||
2230 |
{ "mode", MODE }, |
||
2231 |
{ "nat", NAT }, |
||
2232 |
{ "no", NO }, |
||
2233 |
{ "nodelay", NODELAY }, |
||
2234 |
{ "nothing", NOTHING }, |
||
2235 |
{ "on", ON }, |
||
2236 |
{ "params", PARAMS }, |
||
2237 |
{ "parent", PARENT }, |
||
2238 |
{ "pass", PASS }, |
||
2239 |
{ "password", PASSWORD }, |
||
2240 |
{ "path", PATH }, |
||
2241 |
{ "pftag", PFTAG }, |
||
2242 |
{ "port", PORT }, |
||
2243 |
{ "prefork", PREFORK }, |
||
2244 |
{ "priority", PRIORITY }, |
||
2245 |
{ "protocol", PROTO }, |
||
2246 |
{ "query", QUERYSTR }, |
||
2247 |
{ "quick", QUICK }, |
||
2248 |
{ "random", RANDOM }, |
||
2249 |
{ "real", REAL }, |
||
2250 |
{ "redirect", REDIRECT }, |
||
2251 |
{ "relay", RELAY }, |
||
2252 |
{ "remove", REMOVE }, |
||
2253 |
{ "request", REQUEST }, |
||
2254 |
{ "response", RESPONSE }, |
||
2255 |
{ "retry", RETRY }, |
||
2256 |
{ "return", RETURN }, |
||
2257 |
{ "roundrobin", ROUNDROBIN }, |
||
2258 |
{ "route", ROUTE }, |
||
2259 |
{ "router", ROUTER }, |
||
2260 |
{ "rtable", RTABLE }, |
||
2261 |
{ "rtlabel", RTLABEL }, |
||
2262 |
{ "sack", SACK }, |
||
2263 |
{ "script", SCRIPT }, |
||
2264 |
{ "send", SEND }, |
||
2265 |
{ "session", SESSION }, |
||
2266 |
{ "set", SET }, |
||
2267 |
{ "snmp", SNMP }, |
||
2268 |
{ "socket", SOCKET }, |
||
2269 |
{ "source-hash", SRCHASH }, |
||
2270 |
{ "splice", SPLICE }, |
||
2271 |
{ "ssl", SSL }, |
||
2272 |
{ "sticky-address", STICKYADDR }, |
||
2273 |
{ "style", STYLE }, |
||
2274 |
{ "table", TABLE }, |
||
2275 |
{ "tag", TAG }, |
||
2276 |
{ "tagged", TAGGED }, |
||
2277 |
{ "tcp", TCP }, |
||
2278 |
{ "tickets", TICKETS }, |
||
2279 |
{ "timeout", TIMEOUT }, |
||
2280 |
{ "tls", TLS }, |
||
2281 |
{ "to", TO }, |
||
2282 |
{ "transparent", TRANSPARENT }, |
||
2283 |
{ "trap", TRAP }, |
||
2284 |
{ "ttl", TTL }, |
||
2285 |
{ "updates", UPDATES }, |
||
2286 |
{ "url", URL }, |
||
2287 |
{ "value", VALUE }, |
||
2288 |
{ "virtual", VIRTUAL }, |
||
2289 |
{ "with", WITH } |
||
2290 |
}; |
||
2291 |
const struct keywords *p; |
||
2292 |
|||
2293 |
66516 |
p = bsearch(s, keywords, sizeof(keywords)/sizeof(keywords[0]), |
|
2294 |
sizeof(keywords[0]), kw_cmp); |
||
2295 |
|||
2296 |
✓✓ | 33258 |
if (p) |
2297 |
24876 |
return (p->k_val); |
|
2298 |
else |
||
2299 |
8382 |
return (STRING); |
|
2300 |
33258 |
} |
|
2301 |
|||
2302 |
#define MAXPUSHBACK 128 |
||
2303 |
|||
2304 |
u_char *parsebuf; |
||
2305 |
int parseindex; |
||
2306 |
u_char pushback_buffer[MAXPUSHBACK]; |
||
2307 |
int pushback_index = 0; |
||
2308 |
|||
2309 |
int |
||
2310 |
lgetc(int quotec) |
||
2311 |
{ |
||
2312 |
int c, next; |
||
2313 |
|||
2314 |
✗✓ | 743120 |
if (parsebuf) { |
2315 |
/* Read character from the parsebuffer instead of input. */ |
||
2316 |
if (parseindex >= 0) { |
||
2317 |
c = parsebuf[parseindex++]; |
||
2318 |
if (c != '\0') |
||
2319 |
return (c); |
||
2320 |
parsebuf = NULL; |
||
2321 |
} else |
||
2322 |
parseindex++; |
||
2323 |
} |
||
2324 |
|||
2325 |
✓✓ | 371560 |
if (pushback_index) |
2326 |
42962 |
return (pushback_buffer[--pushback_index]); |
|
2327 |
|||
2328 |
✓✓ | 328598 |
if (quotec) { |
2329 |
✓✗✗✓ ✗✓ |
29624 |
if ((c = getc(file->stream)) == EOF) { |
2330 |
yyerror("reached end of file while parsing " |
||
2331 |
"quoted string"); |
||
2332 |
if (file == topfile || popfile() == EOF) |
||
2333 |
return (EOF); |
||
2334 |
return (quotec); |
||
2335 |
} |
||
2336 |
7406 |
return (c); |
|
2337 |
} |
||
2338 |
|||
2339 |
✓✗✓✓ ✓✓ |
1285118 |
while ((c = getc(file->stream)) == '\\') { |
2340 |
✓✗✗✓ |
280 |
next = getc(file->stream); |
2341 |
✗✓ | 70 |
if (next != '\n') { |
2342 |
c = next; |
||
2343 |
break; |
||
2344 |
} |
||
2345 |
70 |
yylval.lineno = file->lineno; |
|
2346 |
70 |
file->lineno++; |
|
2347 |
} |
||
2348 |
|||
2349 |
✓✓ | 321192 |
while (c == EOF) { |
2350 |
✗✓✗✗ |
962 |
if (file == topfile || popfile() == EOF) |
2351 |
962 |
return (EOF); |
|
2352 |
c = getc(file->stream); |
||
2353 |
} |
||
2354 |
320230 |
return (c); |
|
2355 |
371560 |
} |
|
2356 |
|||
2357 |
int |
||
2358 |
lungetc(int c) |
||
2359 |
{ |
||
2360 |
✗✓ | 85952 |
if (c == EOF) |
2361 |
return (EOF); |
||
2362 |
✗✓ | 42976 |
if (parsebuf) { |
2363 |
parseindex--; |
||
2364 |
if (parseindex >= 0) |
||
2365 |
return (c); |
||
2366 |
} |
||
2367 |
✓✗ | 42976 |
if (pushback_index < MAXPUSHBACK-1) |
2368 |
42976 |
return (pushback_buffer[pushback_index++] = c); |
|
2369 |
else |
||
2370 |
return (EOF); |
||
2371 |
42976 |
} |
|
2372 |
|||
2373 |
int |
||
2374 |
findeol(void) |
||
2375 |
{ |
||
2376 |
int c; |
||
2377 |
|||
2378 |
parsebuf = NULL; |
||
2379 |
|||
2380 |
/* skip to either EOF or the first real EOL */ |
||
2381 |
while (1) { |
||
2382 |
if (pushback_index) |
||
2383 |
c = pushback_buffer[--pushback_index]; |
||
2384 |
else |
||
2385 |
c = lgetc(0); |
||
2386 |
if (c == '\n') { |
||
2387 |
file->lineno++; |
||
2388 |
break; |
||
2389 |
} |
||
2390 |
if (c == EOF) |
||
2391 |
break; |
||
2392 |
} |
||
2393 |
return (ERROR); |
||
2394 |
} |
||
2395 |
|||
2396 |
int |
||
2397 |
yylex(void) |
||
2398 |
{ |
||
2399 |
112764 |
u_char buf[8096]; |
|
2400 |
u_char *p, *val; |
||
2401 |
int quotec, next, c; |
||
2402 |
56382 |
int token; |
|
2403 |
|||
2404 |
top: |
||
2405 |
56382 |
p = buf; |
|
2406 |
✓✓ | 147170 |
while ((c = lgetc(0)) == ' ' || c == '\t') |
2407 |
; /* nothing */ |
||
2408 |
|||
2409 |
56382 |
yylval.lineno = file->lineno; |
|
2410 |
✗✓ | 56382 |
if (c == '#') |
2411 |
while ((c = lgetc(0)) != '\n' && c != EOF) |
||
2412 |
; /* nothing */ |
||
2413 |
✗✓ | 56382 |
if (c == '$' && parsebuf == NULL) { |
2414 |
while (1) { |
||
2415 |
if ((c = lgetc(0)) == EOF) |
||
2416 |
return (0); |
||
2417 |
|||
2418 |
if (p + 1 >= buf + sizeof(buf) - 1) { |
||
2419 |
yyerror("string too long"); |
||
2420 |
return (findeol()); |
||
2421 |
} |
||
2422 |
if (isalnum(c) || c == '_') { |
||
2423 |
*p++ = c; |
||
2424 |
continue; |
||
2425 |
} |
||
2426 |
*p = '\0'; |
||
2427 |
lungetc(c); |
||
2428 |
break; |
||
2429 |
} |
||
2430 |
val = symget(buf); |
||
2431 |
if (val == NULL) { |
||
2432 |
yyerror("macro '%s' not defined", buf); |
||
2433 |
return (findeol()); |
||
2434 |
} |
||
2435 |
parsebuf = val; |
||
2436 |
parseindex = 0; |
||
2437 |
goto top; |
||
2438 |
} |
||
2439 |
|||
2440 |
✗✓✓ | 56382 |
switch (c) { |
2441 |
case '\'': |
||
2442 |
case '"': |
||
2443 |
quotec = c; |
||
2444 |
7406 |
while (1) { |
|
2445 |
✗✓ | 7406 |
if ((c = lgetc(quotec)) == EOF) |
2446 |
return (0); |
||
2447 |
✗✓ | 7406 |
if (c == '\n') { |
2448 |
file->lineno++; |
||
2449 |
continue; |
||
2450 |
✗✓ | 7406 |
} else if (c == '\\') { |
2451 |
if ((next = lgetc(quotec)) == EOF) |
||
2452 |
return (0); |
||
2453 |
if (next == quotec || c == ' ' || c == '\t') |
||
2454 |
c = next; |
||
2455 |
else if (next == '\n') { |
||
2456 |
file->lineno++; |
||
2457 |
continue; |
||
2458 |
} else |
||
2459 |
lungetc(next); |
||
2460 |
✓✓ | 7406 |
} else if (c == quotec) { |
2461 |
966 |
*p = '\0'; |
|
2462 |
break; |
||
2463 |
✗✓ | 6440 |
} else if (c == '\0') { |
2464 |
yyerror("syntax error"); |
||
2465 |
return (findeol()); |
||
2466 |
} |
||
2467 |
✗✓ | 6440 |
if (p + 1 >= buf + sizeof(buf) - 1) { |
2468 |
yyerror("string too long"); |
||
2469 |
return (findeol()); |
||
2470 |
} |
||
2471 |
6440 |
*p++ = c; |
|
2472 |
} |
||
2473 |
966 |
yylval.v.string = strdup(buf); |
|
2474 |
✗✓ | 966 |
if (yylval.v.string == NULL) |
2475 |
err(1, "yylex: strdup"); |
||
2476 |
966 |
return (STRING); |
|
2477 |
} |
||
2478 |
|||
2479 |
#define allowed_to_end_number(x) \ |
||
2480 |
(isspace(x) || x == ')' || x ==',' || x == '/' || x == '}' || x == '=') |
||
2481 |
|||
2482 |
✓✗✓✓ |
110832 |
if (c == '-' || isdigit(c)) { |
2483 |
do { |
||
2484 |
17126 |
*p++ = c; |
|
2485 |
✗✓ | 17126 |
if ((unsigned)(p-buf) >= sizeof(buf)) { |
2486 |
yyerror("string too long"); |
||
2487 |
return (findeol()); |
||
2488 |
} |
||
2489 |
✓✗✓✓ |
34252 |
} while ((c = lgetc(0)) != EOF && isdigit(c)); |
2490 |
5870 |
lungetc(c); |
|
2491 |
✓✓✓✗ |
7878 |
if (p == buf + 1 && buf[0] == '-') |
2492 |
goto nodigits; |
||
2493 |
✓✗✓✓ |
11740 |
if (c == EOF || allowed_to_end_number(c)) { |
2494 |
3932 |
const char *errstr = NULL; |
|
2495 |
|||
2496 |
3932 |
*p = '\0'; |
|
2497 |
3932 |
yylval.v.number = strtonum(buf, LLONG_MIN, |
|
2498 |
LLONG_MAX, &errstr); |
||
2499 |
✗✓ | 3932 |
if (errstr) { |
2500 |
yyerror("\"%s\" invalid number: %s", |
||
2501 |
buf, errstr); |
||
2502 |
return (findeol()); |
||
2503 |
} |
||
2504 |
3932 |
return (NUMBER); |
|
2505 |
3932 |
} else { |
|
2506 |
nodigits: |
||
2507 |
✓✓ | 9634 |
while (p > buf + 1) |
2508 |
3848 |
lungetc(*--p); |
|
2509 |
c = *--p; |
||
2510 |
✗✓ | 1938 |
if (c == '-') |
2511 |
return (c); |
||
2512 |
} |
||
2513 |
} |
||
2514 |
|||
2515 |
#define allowed_in_string(x) \ |
||
2516 |
(isalnum(x) || (ispunct(x) && x != '(' && x != ')' && \ |
||
2517 |
x != '{' && x != '}' && x != '<' && x != '>' && \ |
||
2518 |
x != '!' && x != '=' && x != '#' && \ |
||
2519 |
x != ',' && x != '/')) |
||
2520 |
|||
2521 |
✓✓ | 51484 |
if (isalnum(c) || c == ':' || c == '_') { |
2522 |
do { |
||
2523 |
256240 |
*p++ = c; |
|
2524 |
✗✓ | 256240 |
if ((unsigned)(p-buf) >= sizeof(buf)) { |
2525 |
yyerror("string too long"); |
||
2526 |
return (findeol()); |
||
2527 |
} |
||
2528 |
✓✗✓✓ ✓✓ |
568066 |
} while ((c = lgetc(0)) != EOF && (allowed_in_string(c))); |
2529 |
33258 |
lungetc(c); |
|
2530 |
33258 |
*p = '\0'; |
|
2531 |
✓✓ | 33258 |
if ((token = lookup(buf)) == STRING) |
2532 |
✗✓ | 8382 |
if ((yylval.v.string = strdup(buf)) == NULL) |
2533 |
err(1, "yylex: strdup"); |
||
2534 |
33258 |
return (token); |
|
2535 |
} |
||
2536 |
✓✓ | 18226 |
if (c == '\n') { |
2537 |
13276 |
yylval.lineno = file->lineno; |
|
2538 |
13276 |
file->lineno++; |
|
2539 |
13276 |
} |
|
2540 |
✓✓ | 18226 |
if (c == EOF) |
2541 |
962 |
return (0); |
|
2542 |
17264 |
return (c); |
|
2543 |
56382 |
} |
|
2544 |
|||
2545 |
int |
||
2546 |
check_file_secrecy(int fd, const char *fname) |
||
2547 |
{ |
||
2548 |
struct stat st; |
||
2549 |
|||
2550 |
if (fstat(fd, &st)) { |
||
2551 |
log_warn("cannot stat %s", fname); |
||
2552 |
return (-1); |
||
2553 |
} |
||
2554 |
if (st.st_uid != 0 && st.st_uid != getuid()) { |
||
2555 |
log_warnx("%s: owner not root or current user", fname); |
||
2556 |
return (-1); |
||
2557 |
} |
||
2558 |
if (st.st_mode & (S_IWGRP | S_IXGRP | S_IRWXO)) { |
||
2559 |
log_warnx("%s: group writable or world read/writable", fname); |
||
2560 |
return (-1); |
||
2561 |
} |
||
2562 |
return (0); |
||
2563 |
} |
||
2564 |
|||
2565 |
struct file * |
||
2566 |
pushfile(const char *name, int secret) |
||
2567 |
{ |
||
2568 |
struct file *nfile; |
||
2569 |
|||
2570 |
✗✓ | 3876 |
if ((nfile = calloc(1, sizeof(struct file))) == NULL) { |
2571 |
log_warn("%s: malloc", __func__); |
||
2572 |
return (NULL); |
||
2573 |
} |
||
2574 |
✗✓ | 1938 |
if ((nfile->name = strdup(name)) == NULL) { |
2575 |
log_warn("%s: malloc", __func__); |
||
2576 |
free(nfile); |
||
2577 |
return (NULL); |
||
2578 |
} |
||
2579 |
✗✓ | 1938 |
if ((nfile->stream = fopen(nfile->name, "r")) == NULL) { |
2580 |
log_warn("%s: %s", __func__, nfile->name); |
||
2581 |
free(nfile->name); |
||
2582 |
free(nfile); |
||
2583 |
return (NULL); |
||
2584 |
✗✓✗✗ |
1938 |
} else if (secret && |
2585 |
check_file_secrecy(fileno(nfile->stream), nfile->name)) { |
||
2586 |
fclose(nfile->stream); |
||
2587 |
free(nfile->name); |
||
2588 |
free(nfile); |
||
2589 |
return (NULL); |
||
2590 |
} |
||
2591 |
1938 |
nfile->lineno = 1; |
|
2592 |
1938 |
TAILQ_INSERT_TAIL(&files, nfile, entry); |
|
2593 |
1938 |
return (nfile); |
|
2594 |
1938 |
} |
|
2595 |
|||
2596 |
int |
||
2597 |
popfile(void) |
||
2598 |
{ |
||
2599 |
struct file *prev; |
||
2600 |
|||
2601 |
✗✓ | 3876 |
if ((prev = TAILQ_PREV(file, files, entry)) != NULL) |
2602 |
prev->errors += file->errors; |
||
2603 |
|||
2604 |
✗✓ | 3876 |
TAILQ_REMOVE(&files, file, entry); |
2605 |
1938 |
fclose(file->stream); |
|
2606 |
1938 |
free(file->name); |
|
2607 |
1938 |
free(file); |
|
2608 |
1938 |
file = prev; |
|
2609 |
1938 |
return (file ? 0 : EOF); |
|
2610 |
} |
||
2611 |
|||
2612 |
int |
||
2613 |
parse_config(const char *filename, struct relayd *x_conf) |
||
2614 |
{ |
||
2615 |
struct sym *sym, *next; |
||
2616 |
|||
2617 |
1952 |
conf = x_conf; |
|
2618 |
✗✓ | 976 |
if (config_init(conf) == -1) { |
2619 |
log_warn("%s: cannot initialize configuration", __func__); |
||
2620 |
return (-1); |
||
2621 |
} |
||
2622 |
|||
2623 |
976 |
errors = 0; |
|
2624 |
|||
2625 |
✗✓ | 976 |
if ((file = pushfile(filename, 0)) == NULL) |
2626 |
return (-1); |
||
2627 |
|||
2628 |
976 |
topfile = file; |
|
2629 |
976 |
setservent(1); |
|
2630 |
|||
2631 |
976 |
yyparse(); |
|
2632 |
976 |
errors = file->errors; |
|
2633 |
976 |
popfile(); |
|
2634 |
|||
2635 |
976 |
endservent(); |
|
2636 |
976 |
endprotoent(); |
|
2637 |
|||
2638 |
/* Free macros */ |
||
2639 |
✗✓ | 1952 |
TAILQ_FOREACH_SAFE(sym, &symhead, entry, next) { |
2640 |
if (!sym->persist) { |
||
2641 |
free(sym->nam); |
||
2642 |
free(sym->val); |
||
2643 |
TAILQ_REMOVE(&symhead, sym, entry); |
||
2644 |
free(sym); |
||
2645 |
} |
||
2646 |
} |
||
2647 |
|||
2648 |
976 |
return (errors ? -1 : 0); |
|
2649 |
976 |
} |
|
2650 |
|||
2651 |
int |
||
2652 |
load_config(const char *filename, struct relayd *x_conf) |
||
2653 |
{ |
||
2654 |
struct sym *sym, *next; |
||
2655 |
struct table *nexttb; |
||
2656 |
struct host *h, *ph; |
||
2657 |
struct relay_table *rlt; |
||
2658 |
|||
2659 |
1924 |
conf = x_conf; |
|
2660 |
962 |
conf->sc_conf.flags = 0; |
|
2661 |
|||
2662 |
962 |
loadcfg = 1; |
|
2663 |
962 |
errors = 0; |
|
2664 |
962 |
last_host_id = last_table_id = last_rdr_id = last_proto_id = |
|
2665 |
962 |
last_relay_id = last_rt_id = last_nr_id = 0; |
|
2666 |
|||
2667 |
962 |
rdr = NULL; |
|
2668 |
962 |
table = NULL; |
|
2669 |
962 |
rlay = NULL; |
|
2670 |
962 |
proto = NULL; |
|
2671 |
962 |
router = NULL; |
|
2672 |
|||
2673 |
✗✓ | 962 |
if ((file = pushfile(filename, 0)) == NULL) |
2674 |
return (-1); |
||
2675 |
|||
2676 |
962 |
topfile = file; |
|
2677 |
962 |
setservent(1); |
|
2678 |
|||
2679 |
962 |
yyparse(); |
|
2680 |
962 |
errors = file->errors; |
|
2681 |
962 |
popfile(); |
|
2682 |
|||
2683 |
962 |
endservent(); |
|
2684 |
962 |
endprotoent(); |
|
2685 |
|||
2686 |
/* Free macros and check which have not been used. */ |
||
2687 |
✗✓ | 1924 |
for (sym = TAILQ_FIRST(&symhead); sym != NULL; sym = next) { |
2688 |
next = TAILQ_NEXT(sym, entry); |
||
2689 |
if ((conf->sc_conf.opts & RELAYD_OPT_VERBOSE) && !sym->used) |
||
2690 |
fprintf(stderr, "warning: macro '%s' not " |
||
2691 |
"used\n", sym->nam); |
||
2692 |
if (!sym->persist) { |
||
2693 |
free(sym->nam); |
||
2694 |
free(sym->val); |
||
2695 |
TAILQ_REMOVE(&symhead, sym, entry); |
||
2696 |
free(sym); |
||
2697 |
} |
||
2698 |
} |
||
2699 |
|||
2700 |
✓✗✗✗ |
962 |
if (TAILQ_EMPTY(conf->sc_rdrs) && |
2701 |
✗✓ | 962 |
TAILQ_EMPTY(conf->sc_relays) && |
2702 |
TAILQ_EMPTY(conf->sc_rts)) { |
||
2703 |
log_warnx("no actions, nothing to do"); |
||
2704 |
errors++; |
||
2705 |
} |
||
2706 |
|||
2707 |
/* Cleanup relay list to inherit */ |
||
2708 |
✗✓ | 962 |
while ((rlay = TAILQ_FIRST(&relays)) != NULL) { |
2709 |
TAILQ_REMOVE(&relays, rlay, rl_entry); |
||
2710 |
while ((rlt = TAILQ_FIRST(&rlay->rl_tables))) { |
||
2711 |
TAILQ_REMOVE(&rlay->rl_tables, rlt, rlt_entry); |
||
2712 |
free(rlt); |
||
2713 |
} |
||
2714 |
free(rlay); |
||
2715 |
} |
||
2716 |
|||
2717 |
✗✓✗✗ ✗✓ |
1924 |
if (timercmp(&conf->sc_conf.timeout, &conf->sc_conf.interval, >=)) { |
2718 |
log_warnx("global timeout exceeds interval"); |
||
2719 |
errors++; |
||
2720 |
} |
||
2721 |
|||
2722 |
/* Verify that every table is used */ |
||
2723 |
✓✓ | 1980 |
for (table = TAILQ_FIRST(conf->sc_tables); table != NULL; |
2724 |
table = nexttb) { |
||
2725 |
28 |
nexttb = TAILQ_NEXT(table, entry); |
|
2726 |
✓✓ | 28 |
if (table->conf.port == 0) { |
2727 |
✓✗ | 42 |
TAILQ_REMOVE(conf->sc_tables, table, entry); |
2728 |
✓✓ | 56 |
while ((h = TAILQ_FIRST(&table->hosts)) != NULL) { |
2729 |
✗✓ | 42 |
TAILQ_REMOVE(&table->hosts, h, entry); |
2730 |
14 |
free(h); |
|
2731 |
} |
||
2732 |
✗✓ | 14 |
if (table->sendbuf != NULL) |
2733 |
free(table->sendbuf); |
||
2734 |
14 |
free(table); |
|
2735 |
14 |
continue; |
|
2736 |
} |
||
2737 |
|||
2738 |
✓✓ | 56 |
TAILQ_FOREACH(h, &table->hosts, entry) { |
2739 |
✗✓ | 14 |
if (h->conf.parentid) { |
2740 |
ph = host_find(conf, h->conf.parentid); |
||
2741 |
|||
2742 |
/* Validate the parent id */ |
||
2743 |
if (h->conf.id == h->conf.parentid || |
||
2744 |
ph == NULL || ph->conf.parentid) |
||
2745 |
ph = NULL; |
||
2746 |
|||
2747 |
if (ph == NULL) { |
||
2748 |
log_warnx("host parent id %d invalid", |
||
2749 |
h->conf.parentid); |
||
2750 |
errors++; |
||
2751 |
} else |
||
2752 |
SLIST_INSERT_HEAD(&ph->children, |
||
2753 |
h, child); |
||
2754 |
} |
||
2755 |
} |
||
2756 |
|||
2757 |
✗✓ | 14 |
if (!(table->conf.flags & F_USED)) { |
2758 |
log_warnx("unused table: %s", table->conf.name); |
||
2759 |
errors++; |
||
2760 |
} |
||
2761 |
✗✓✗✗ ✗✓ |
28 |
if (timercmp(&table->conf.timeout, |
2762 |
&conf->sc_conf.interval, >=)) { |
||
2763 |
log_warnx("table timeout exceeds interval: %s", |
||
2764 |
table->conf.name); |
||
2765 |
errors++; |
||
2766 |
} |
||
2767 |
} |
||
2768 |
|||
2769 |
/* Verify that every non-default protocol is used */ |
||
2770 |
✓✓ | 3848 |
TAILQ_FOREACH(proto, conf->sc_protos, entry) { |
2771 |
✗✓ | 962 |
if (!(proto->flags & F_USED)) { |
2772 |
log_warnx("unused protocol: %s", proto->name); |
||
2773 |
} |
||
2774 |
} |
||
2775 |
|||
2776 |
962 |
return (errors ? -1 : 0); |
|
2777 |
962 |
} |
|
2778 |
|||
2779 |
int |
||
2780 |
symset(const char *nam, const char *val, int persist) |
||
2781 |
{ |
||
2782 |
struct sym *sym; |
||
2783 |
|||
2784 |
TAILQ_FOREACH(sym, &symhead, entry) { |
||
2785 |
if (strcmp(nam, sym->nam) == 0) |
||
2786 |
break; |
||
2787 |
} |
||
2788 |
|||
2789 |
if (sym != NULL) { |
||
2790 |
if (sym->persist == 1) |
||
2791 |
return (0); |
||
2792 |
else { |
||
2793 |
free(sym->nam); |
||
2794 |
free(sym->val); |
||
2795 |
TAILQ_REMOVE(&symhead, sym, entry); |
||
2796 |
free(sym); |
||
2797 |
} |
||
2798 |
} |
||
2799 |
if ((sym = calloc(1, sizeof(*sym))) == NULL) |
||
2800 |
return (-1); |
||
2801 |
|||
2802 |
sym->nam = strdup(nam); |
||
2803 |
if (sym->nam == NULL) { |
||
2804 |
free(sym); |
||
2805 |
return (-1); |
||
2806 |
} |
||
2807 |
sym->val = strdup(val); |
||
2808 |
if (sym->val == NULL) { |
||
2809 |
free(sym->nam); |
||
2810 |
free(sym); |
||
2811 |
return (-1); |
||
2812 |
} |
||
2813 |
sym->used = 0; |
||
2814 |
sym->persist = persist; |
||
2815 |
TAILQ_INSERT_TAIL(&symhead, sym, entry); |
||
2816 |
return (0); |
||
2817 |
} |
||
2818 |
|||
2819 |
int |
||
2820 |
cmdline_symset(char *s) |
||
2821 |
{ |
||
2822 |
char *sym, *val; |
||
2823 |
int ret; |
||
2824 |
size_t len; |
||
2825 |
|||
2826 |
if ((val = strrchr(s, '=')) == NULL) |
||
2827 |
return (-1); |
||
2828 |
|||
2829 |
len = strlen(s) - strlen(val) + 1; |
||
2830 |
if ((sym = malloc(len)) == NULL) |
||
2831 |
errx(1, "cmdline_symset: malloc"); |
||
2832 |
|||
2833 |
(void)strlcpy(sym, s, len); |
||
2834 |
|||
2835 |
ret = symset(sym, val + 1, 1); |
||
2836 |
free(sym); |
||
2837 |
|||
2838 |
return (ret); |
||
2839 |
} |
||
2840 |
|||
2841 |
char * |
||
2842 |
symget(const char *nam) |
||
2843 |
{ |
||
2844 |
struct sym *sym; |
||
2845 |
|||
2846 |
TAILQ_FOREACH(sym, &symhead, entry) { |
||
2847 |
if (strcmp(nam, sym->nam) == 0) { |
||
2848 |
sym->used = 1; |
||
2849 |
return (sym->val); |
||
2850 |
} |
||
2851 |
} |
||
2852 |
return (NULL); |
||
2853 |
} |
||
2854 |
|||
2855 |
struct address * |
||
2856 |
host_v4(const char *s) |
||
2857 |
{ |
||
2858 |
3848 |
struct in_addr ina; |
|
2859 |
struct sockaddr_in *sain; |
||
2860 |
struct address *h; |
||
2861 |
|||
2862 |
1924 |
bzero(&ina, sizeof(ina)); |
|
2863 |
✗✓ | 1924 |
if (inet_pton(AF_INET, s, &ina) != 1) |
2864 |
return (NULL); |
||
2865 |
|||
2866 |
✗✓ | 1924 |
if ((h = calloc(1, sizeof(*h))) == NULL) |
2867 |
fatal(__func__); |
||
2868 |
1924 |
sain = (struct sockaddr_in *)&h->ss; |
|
2869 |
1924 |
sain->sin_len = sizeof(struct sockaddr_in); |
|
2870 |
1924 |
sain->sin_family = AF_INET; |
|
2871 |
1924 |
sain->sin_addr.s_addr = ina.s_addr; |
|
2872 |
|||
2873 |
1924 |
return (h); |
|
2874 |
1924 |
} |
|
2875 |
|||
2876 |
struct address * |
||
2877 |
host_v6(const char *s) |
||
2878 |
{ |
||
2879 |
struct addrinfo hints, *res; |
||
2880 |
struct sockaddr_in6 *sa_in6; |
||
2881 |
struct address *h = NULL; |
||
2882 |
|||
2883 |
bzero(&hints, sizeof(hints)); |
||
2884 |
hints.ai_family = AF_INET6; |
||
2885 |
hints.ai_socktype = SOCK_DGRAM; /* dummy */ |
||
2886 |
hints.ai_flags = AI_NUMERICHOST; |
||
2887 |
if (getaddrinfo(s, "0", &hints, &res) == 0) { |
||
2888 |
if ((h = calloc(1, sizeof(*h))) == NULL) |
||
2889 |
fatal(__func__); |
||
2890 |
sa_in6 = (struct sockaddr_in6 *)&h->ss; |
||
2891 |
sa_in6->sin6_len = sizeof(struct sockaddr_in6); |
||
2892 |
sa_in6->sin6_family = AF_INET6; |
||
2893 |
memcpy(&sa_in6->sin6_addr, |
||
2894 |
&((struct sockaddr_in6 *)res->ai_addr)->sin6_addr, |
||
2895 |
sizeof(sa_in6->sin6_addr)); |
||
2896 |
sa_in6->sin6_scope_id = |
||
2897 |
((struct sockaddr_in6 *)res->ai_addr)->sin6_scope_id; |
||
2898 |
|||
2899 |
freeaddrinfo(res); |
||
2900 |
} |
||
2901 |
|||
2902 |
return (h); |
||
2903 |
} |
||
2904 |
|||
2905 |
int |
||
2906 |
host_dns(const char *s, struct addresslist *al, int max, |
||
2907 |
struct portrange *port, const char *ifname, int ipproto) |
||
2908 |
{ |
||
2909 |
struct addrinfo hints, *res0, *res; |
||
2910 |
int error, cnt = 0; |
||
2911 |
struct sockaddr_in *sain; |
||
2912 |
struct sockaddr_in6 *sin6; |
||
2913 |
struct address *h; |
||
2914 |
|||
2915 |
if ((cnt = host_if(s, al, max, port, ifname, ipproto)) != 0) |
||
2916 |
return (cnt); |
||
2917 |
|||
2918 |
bzero(&hints, sizeof(hints)); |
||
2919 |
hints.ai_family = PF_UNSPEC; |
||
2920 |
hints.ai_socktype = SOCK_DGRAM; /* DUMMY */ |
||
2921 |
hints.ai_flags = AI_ADDRCONFIG; |
||
2922 |
error = getaddrinfo(s, NULL, &hints, &res0); |
||
2923 |
if (error == EAI_AGAIN || error == EAI_NODATA || error == EAI_NONAME) |
||
2924 |
return (0); |
||
2925 |
if (error) { |
||
2926 |
log_warnx("%s: could not parse \"%s\": %s", __func__, s, |
||
2927 |
gai_strerror(error)); |
||
2928 |
return (-1); |
||
2929 |
} |
||
2930 |
|||
2931 |
for (res = res0; res && cnt < max; res = res->ai_next) { |
||
2932 |
if (res->ai_family != AF_INET && |
||
2933 |
res->ai_family != AF_INET6) |
||
2934 |
continue; |
||
2935 |
if ((h = calloc(1, sizeof(*h))) == NULL) |
||
2936 |
fatal(__func__); |
||
2937 |
|||
2938 |
if (port != NULL) |
||
2939 |
bcopy(port, &h->port, sizeof(h->port)); |
||
2940 |
if (ifname != NULL) { |
||
2941 |
if (strlcpy(h->ifname, ifname, sizeof(h->ifname)) >= |
||
2942 |
sizeof(h->ifname)) |
||
2943 |
log_warnx("%s: interface name truncated", |
||
2944 |
__func__); |
||
2945 |
freeaddrinfo(res0); |
||
2946 |
free(h); |
||
2947 |
return (-1); |
||
2948 |
} |
||
2949 |
if (ipproto != -1) |
||
2950 |
h->ipproto = ipproto; |
||
2951 |
h->ss.ss_family = res->ai_family; |
||
2952 |
|||
2953 |
if (res->ai_family == AF_INET) { |
||
2954 |
sain = (struct sockaddr_in *)&h->ss; |
||
2955 |
sain->sin_len = sizeof(struct sockaddr_in); |
||
2956 |
sain->sin_addr.s_addr = ((struct sockaddr_in *) |
||
2957 |
res->ai_addr)->sin_addr.s_addr; |
||
2958 |
} else { |
||
2959 |
sin6 = (struct sockaddr_in6 *)&h->ss; |
||
2960 |
sin6->sin6_len = sizeof(struct sockaddr_in6); |
||
2961 |
memcpy(&sin6->sin6_addr, &((struct sockaddr_in6 *) |
||
2962 |
res->ai_addr)->sin6_addr, sizeof(struct in6_addr)); |
||
2963 |
} |
||
2964 |
|||
2965 |
TAILQ_INSERT_HEAD(al, h, entry); |
||
2966 |
cnt++; |
||
2967 |
} |
||
2968 |
if (cnt == max && res) { |
||
2969 |
log_warnx("%s: %s resolves to more than %d hosts", __func__, |
||
2970 |
s, max); |
||
2971 |
} |
||
2972 |
freeaddrinfo(res0); |
||
2973 |
return (cnt); |
||
2974 |
} |
||
2975 |
|||
2976 |
int |
||
2977 |
host_if(const char *s, struct addresslist *al, int max, |
||
2978 |
struct portrange *port, const char *ifname, int ipproto) |
||
2979 |
{ |
||
2980 |
struct ifaddrs *ifap, *p; |
||
2981 |
struct sockaddr_in *sain; |
||
2982 |
struct sockaddr_in6 *sin6; |
||
2983 |
struct address *h; |
||
2984 |
int cnt = 0, af; |
||
2985 |
|||
2986 |
if (getifaddrs(&ifap) == -1) |
||
2987 |
fatal("getifaddrs"); |
||
2988 |
|||
2989 |
/* First search for IPv4 addresses */ |
||
2990 |
af = AF_INET; |
||
2991 |
|||
2992 |
nextaf: |
||
2993 |
for (p = ifap; p != NULL && cnt < max; p = p->ifa_next) { |
||
2994 |
if (p->ifa_addr->sa_family != af || |
||
2995 |
(strcmp(s, p->ifa_name) != 0 && |
||
2996 |
!is_if_in_group(p->ifa_name, s))) |
||
2997 |
continue; |
||
2998 |
if ((h = calloc(1, sizeof(*h))) == NULL) |
||
2999 |
fatal("calloc"); |
||
3000 |
|||
3001 |
if (port != NULL) |
||
3002 |
bcopy(port, &h->port, sizeof(h->port)); |
||
3003 |
if (ifname != NULL) { |
||
3004 |
if (strlcpy(h->ifname, ifname, sizeof(h->ifname)) >= |
||
3005 |
sizeof(h->ifname)) |
||
3006 |
log_warnx("%s: interface name truncated", |
||
3007 |
__func__); |
||
3008 |
freeifaddrs(ifap); |
||
3009 |
return (-1); |
||
3010 |
} |
||
3011 |
if (ipproto != -1) |
||
3012 |
h->ipproto = ipproto; |
||
3013 |
h->ss.ss_family = af; |
||
3014 |
|||
3015 |
if (af == AF_INET) { |
||
3016 |
sain = (struct sockaddr_in *)&h->ss; |
||
3017 |
sain->sin_len = sizeof(struct sockaddr_in); |
||
3018 |
sain->sin_addr.s_addr = ((struct sockaddr_in *) |
||
3019 |
p->ifa_addr)->sin_addr.s_addr; |
||
3020 |
} else { |
||
3021 |
sin6 = (struct sockaddr_in6 *)&h->ss; |
||
3022 |
sin6->sin6_len = sizeof(struct sockaddr_in6); |
||
3023 |
memcpy(&sin6->sin6_addr, &((struct sockaddr_in6 *) |
||
3024 |
p->ifa_addr)->sin6_addr, sizeof(struct in6_addr)); |
||
3025 |
sin6->sin6_scope_id = ((struct sockaddr_in6 *) |
||
3026 |
p->ifa_addr)->sin6_scope_id; |
||
3027 |
} |
||
3028 |
|||
3029 |
TAILQ_INSERT_HEAD(al, h, entry); |
||
3030 |
cnt++; |
||
3031 |
} |
||
3032 |
if (af == AF_INET) { |
||
3033 |
/* Next search for IPv6 addresses */ |
||
3034 |
af = AF_INET6; |
||
3035 |
goto nextaf; |
||
3036 |
} |
||
3037 |
|||
3038 |
if (cnt > max) { |
||
3039 |
log_warnx("%s: %s resolves to more than %d hosts", __func__, |
||
3040 |
s, max); |
||
3041 |
} |
||
3042 |
freeifaddrs(ifap); |
||
3043 |
return (cnt); |
||
3044 |
} |
||
3045 |
|||
3046 |
int |
||
3047 |
host(const char *s, struct addresslist *al, int max, |
||
3048 |
struct portrange *port, const char *ifname, int ipproto) |
||
3049 |
{ |
||
3050 |
struct address *h; |
||
3051 |
|||
3052 |
3848 |
h = host_v4(s); |
|
3053 |
|||
3054 |
/* IPv6 address? */ |
||
3055 |
✗✓ | 1924 |
if (h == NULL) |
3056 |
h = host_v6(s); |
||
3057 |
|||
3058 |
✓✗ | 1924 |
if (h != NULL) { |
3059 |
✓✓ | 1924 |
if (port != NULL) |
3060 |
1910 |
bcopy(port, &h->port, sizeof(h->port)); |
|
3061 |
✗✓ | 1924 |
if (ifname != NULL) { |
3062 |
if (strlcpy(h->ifname, ifname, sizeof(h->ifname)) >= |
||
3063 |
sizeof(h->ifname)) { |
||
3064 |
log_warnx("%s: interface name truncated", |
||
3065 |
__func__); |
||
3066 |
free(h); |
||
3067 |
return (-1); |
||
3068 |
} |
||
3069 |
} |
||
3070 |
✗✓ | 1924 |
if (ipproto != -1) |
3071 |
h->ipproto = ipproto; |
||
3072 |
|||
3073 |
✗✓ | 5772 |
TAILQ_INSERT_HEAD(al, h, entry); |
3074 |
1924 |
return (1); |
|
3075 |
} |
||
3076 |
|||
3077 |
return (host_dns(s, al, max, port, ifname, ipproto)); |
||
3078 |
1924 |
} |
|
3079 |
|||
3080 |
void |
||
3081 |
host_free(struct addresslist *al) |
||
3082 |
{ |
||
3083 |
struct address *h; |
||
3084 |
|||
3085 |
✓✓ | 9620 |
while ((h = TAILQ_FIRST(al)) != NULL) { |
3086 |
✗✓ | 5772 |
TAILQ_REMOVE(al, h, entry); |
3087 |
1924 |
free(h); |
|
3088 |
} |
||
3089 |
1924 |
} |
|
3090 |
|||
3091 |
struct table * |
||
3092 |
table_inherit(struct table *tb) |
||
3093 |
{ |
||
3094 |
28 |
char pname[TABLE_NAME_SIZE + 6]; |
|
3095 |
struct host *h, *dsth; |
||
3096 |
struct table *dsttb, *oldtb; |
||
3097 |
|||
3098 |
/* Get the table or table template */ |
||
3099 |
✗✓ | 14 |
if ((dsttb = table_findbyname(conf, tb->conf.name)) == NULL) { |
3100 |
yyerror("unknown table %s", tb->conf.name); |
||
3101 |
goto fail; |
||
3102 |
} |
||
3103 |
✗✓ | 14 |
if (dsttb->conf.port != 0) |
3104 |
fatal("invalid table"); /* should not happen */ |
||
3105 |
|||
3106 |
✗✓ | 14 |
if (tb->conf.port == 0) { |
3107 |
yyerror("invalid port"); |
||
3108 |
goto fail; |
||
3109 |
} |
||
3110 |
|||
3111 |
/* Check if a matching table already exists */ |
||
3112 |
✗✓ | 42 |
if (snprintf(pname, sizeof(pname), "%s:%u", |
3113 |
28 |
tb->conf.name, ntohs(tb->conf.port)) >= (int)sizeof(pname)) { |
|
3114 |
yyerror("invalid table name"); |
||
3115 |
goto fail; |
||
3116 |
} |
||
3117 |
✗✓ | 14 |
if (strlcpy(tb->conf.name, pname, sizeof(tb->conf.name)) >= |
3118 |
sizeof(tb->conf.name)) { |
||
3119 |
yyerror("invalid table mame"); |
||
3120 |
goto fail; |
||
3121 |
} |
||
3122 |
✗✓ | 14 |
if ((oldtb = table_findbyconf(conf, tb)) != NULL) { |
3123 |
purge_table(conf, NULL, tb); |
||
3124 |
return (oldtb); |
||
3125 |
} |
||
3126 |
|||
3127 |
/* Create a new table */ |
||
3128 |
14 |
tb->conf.id = ++last_table_id; |
|
3129 |
✗✓ | 14 |
if (last_table_id == INT_MAX) { |
3130 |
yyerror("too many tables defined"); |
||
3131 |
goto fail; |
||
3132 |
} |
||
3133 |
14 |
tb->conf.flags |= dsttb->conf.flags; |
|
3134 |
|||
3135 |
/* Inherit global table options */ |
||
3136 |
✓✗✓✗ |
28 |
if (tb->conf.timeout.tv_sec == 0 && tb->conf.timeout.tv_usec == 0) |
3137 |
14 |
bcopy(&dsttb->conf.timeout, &tb->conf.timeout, |
|
3138 |
sizeof(struct timeval)); |
||
3139 |
|||
3140 |
/* Copy the associated hosts */ |
||
3141 |
14 |
TAILQ_INIT(&tb->hosts); |
|
3142 |
✓✓ | 56 |
TAILQ_FOREACH(dsth, &dsttb->hosts, entry) { |
3143 |
✗✓ | 28 |
if ((h = (struct host *) |
3144 |
28 |
calloc(1, sizeof (*h))) == NULL) |
|
3145 |
fatal("out of memory"); |
||
3146 |
14 |
bcopy(dsth, h, sizeof(*h)); |
|
3147 |
14 |
h->conf.id = ++last_host_id; |
|
3148 |
✗✓ | 14 |
if (last_host_id == INT_MAX) { |
3149 |
yyerror("too many hosts defined"); |
||
3150 |
free(h); |
||
3151 |
goto fail; |
||
3152 |
} |
||
3153 |
14 |
h->conf.tableid = tb->conf.id; |
|
3154 |
14 |
h->tablename = tb->conf.name; |
|
3155 |
14 |
SLIST_INIT(&h->children); |
|
3156 |
14 |
TAILQ_INSERT_TAIL(&tb->hosts, h, entry); |
|
3157 |
14 |
TAILQ_INSERT_TAIL(&conf->sc_hosts, h, globalentry); |
|
3158 |
} |
||
3159 |
|||
3160 |
14 |
conf->sc_tablecount++; |
|
3161 |
14 |
TAILQ_INSERT_TAIL(conf->sc_tables, tb, entry); |
|
3162 |
|||
3163 |
14 |
return (tb); |
|
3164 |
|||
3165 |
fail: |
||
3166 |
purge_table(conf, NULL, tb); |
||
3167 |
return (NULL); |
||
3168 |
14 |
} |
|
3169 |
|||
3170 |
int |
||
3171 |
relay_id(struct relay *rl) |
||
3172 |
{ |
||
3173 |
1924 |
rl->rl_conf.id = ++last_relay_id; |
|
3174 |
962 |
rl->rl_conf.tls_keyid = ++last_key_id; |
|
3175 |
962 |
rl->rl_conf.tls_cakeyid = ++last_key_id; |
|
3176 |
|||
3177 |
✗✓ | 962 |
if (last_relay_id == INT_MAX || last_key_id == INT_MAX) |
3178 |
return (-1); |
||
3179 |
|||
3180 |
962 |
return (0); |
|
3181 |
962 |
} |
|
3182 |
|||
3183 |
struct relay * |
||
3184 |
relay_inherit(struct relay *ra, struct relay *rb) |
||
3185 |
{ |
||
3186 |
struct relay_config rc; |
||
3187 |
struct relay_table *rta, *rtb; |
||
3188 |
|||
3189 |
bcopy(&rb->rl_conf, &rc, sizeof(rc)); |
||
3190 |
bcopy(ra, rb, sizeof(*rb)); |
||
3191 |
|||
3192 |
bcopy(&rc.ss, &rb->rl_conf.ss, sizeof(rb->rl_conf.ss)); |
||
3193 |
rb->rl_conf.port = rc.port; |
||
3194 |
rb->rl_conf.flags = |
||
3195 |
(ra->rl_conf.flags & ~F_TLS) | (rc.flags & F_TLS); |
||
3196 |
if (!(rb->rl_conf.flags & F_TLS)) { |
||
3197 |
rb->rl_tls_cert = NULL; |
||
3198 |
rb->rl_conf.tls_cert_len = 0; |
||
3199 |
rb->rl_tls_key = NULL; |
||
3200 |
rb->rl_conf.tls_key_len = 0; |
||
3201 |
} |
||
3202 |
TAILQ_INIT(&rb->rl_tables); |
||
3203 |
|||
3204 |
if (relay_id(rb) == -1) { |
||
3205 |
yyerror("too many relays defined"); |
||
3206 |
goto err; |
||
3207 |
} |
||
3208 |
|||
3209 |
if (snprintf(rb->rl_conf.name, sizeof(rb->rl_conf.name), "%s%u:%u", |
||
3210 |
ra->rl_conf.name, rb->rl_conf.id, ntohs(rc.port)) >= |
||
3211 |
(int)sizeof(rb->rl_conf.name)) { |
||
3212 |
yyerror("invalid relay name"); |
||
3213 |
goto err; |
||
3214 |
} |
||
3215 |
|||
3216 |
if (relay_findbyname(conf, rb->rl_conf.name) != NULL || |
||
3217 |
relay_findbyaddr(conf, &rb->rl_conf) != NULL) { |
||
3218 |
yyerror("relay %s defined twice", rb->rl_conf.name); |
||
3219 |
goto err; |
||
3220 |
} |
||
3221 |
if (relay_load_certfiles(rb) == -1) { |
||
3222 |
yyerror("cannot load certificates for relay %s", |
||
3223 |
rb->rl_conf.name); |
||
3224 |
goto err; |
||
3225 |
} |
||
3226 |
|||
3227 |
TAILQ_FOREACH(rta, &ra->rl_tables, rlt_entry) { |
||
3228 |
if ((rtb = calloc(1, sizeof(*rtb))) == NULL) { |
||
3229 |
yyerror("cannot allocate relay table"); |
||
3230 |
goto err; |
||
3231 |
} |
||
3232 |
rtb->rlt_table = rta->rlt_table; |
||
3233 |
rtb->rlt_mode = rta->rlt_mode; |
||
3234 |
rtb->rlt_flags = rta->rlt_flags; |
||
3235 |
|||
3236 |
TAILQ_INSERT_TAIL(&rb->rl_tables, rtb, rlt_entry); |
||
3237 |
} |
||
3238 |
|||
3239 |
conf->sc_relaycount++; |
||
3240 |
SPLAY_INIT(&rlay->rl_sessions); |
||
3241 |
TAILQ_INSERT_TAIL(conf->sc_relays, rb, rl_entry); |
||
3242 |
|||
3243 |
return (rb); |
||
3244 |
|||
3245 |
err: |
||
3246 |
while ((rtb = TAILQ_FIRST(&rb->rl_tables))) { |
||
3247 |
TAILQ_REMOVE(&rb->rl_tables, rtb, rlt_entry); |
||
3248 |
free(rtb); |
||
3249 |
} |
||
3250 |
free(rb); |
||
3251 |
return (NULL); |
||
3252 |
} |
||
3253 |
|||
3254 |
int |
||
3255 |
getservice(char *n) |
||
3256 |
{ |
||
3257 |
struct servent *s; |
||
3258 |
const char *errstr; |
||
3259 |
long long llval; |
||
3260 |
|||
3261 |
llval = strtonum(n, 0, UINT16_MAX, &errstr); |
||
3262 |
if (errstr) { |
||
3263 |
s = getservbyname(n, "tcp"); |
||
3264 |
if (s == NULL) |
||
3265 |
s = getservbyname(n, "udp"); |
||
3266 |
if (s == NULL) { |
||
3267 |
yyerror("unknown port %s", n); |
||
3268 |
return (-1); |
||
3269 |
} |
||
3270 |
return (s->s_port); |
||
3271 |
} |
||
3272 |
|||
3273 |
return (htons((u_short)llval)); |
||
3274 |
} |
||
3275 |
|||
3276 |
int |
||
3277 |
is_if_in_group(const char *ifname, const char *groupname) |
||
3278 |
{ |
||
3279 |
unsigned int len; |
||
3280 |
struct ifgroupreq ifgr; |
||
3281 |
struct ifg_req *ifg; |
||
3282 |
int s; |
||
3283 |
int ret = 0; |
||
3284 |
|||
3285 |
if ((s = socket(AF_INET, SOCK_DGRAM, 0)) < 0) |
||
3286 |
err(1, "socket"); |
||
3287 |
|||
3288 |
memset(&ifgr, 0, sizeof(ifgr)); |
||
3289 |
if (strlcpy(ifgr.ifgr_name, ifname, IFNAMSIZ) >= IFNAMSIZ) |
||
3290 |
err(1, "IFNAMSIZ"); |
||
3291 |
if (ioctl(s, SIOCGIFGROUP, (caddr_t)&ifgr) == -1) { |
||
3292 |
if (errno == EINVAL || errno == ENOTTY) |
||
3293 |
goto end; |
||
3294 |
err(1, "SIOCGIFGROUP"); |
||
3295 |
} |
||
3296 |
|||
3297 |
len = ifgr.ifgr_len; |
||
3298 |
ifgr.ifgr_groups = calloc(len / sizeof(struct ifg_req), |
||
3299 |
sizeof(struct ifg_req)); |
||
3300 |
if (ifgr.ifgr_groups == NULL) |
||
3301 |
err(1, "getifgroups"); |
||
3302 |
if (ioctl(s, SIOCGIFGROUP, (caddr_t)&ifgr) == -1) |
||
3303 |
err(1, "SIOCGIFGROUP"); |
||
3304 |
|||
3305 |
ifg = ifgr.ifgr_groups; |
||
3306 |
for (; ifg && len >= sizeof(struct ifg_req); ifg++) { |
||
3307 |
len -= sizeof(struct ifg_req); |
||
3308 |
if (strcmp(ifg->ifgrq_group, groupname) == 0) { |
||
3309 |
ret = 1; |
||
3310 |
break; |
||
3311 |
} |
||
3312 |
} |
||
3313 |
free(ifgr.ifgr_groups); |
||
3314 |
|||
3315 |
end: |
||
3316 |
close(s); |
||
3317 |
return (ret); |
||
3318 |
} |
Generated by: GCOVR (Version 3.3) |