1 /* $NetBSD: parse.y,v 1.3 2020/04/23 00:29:00 joerg Exp $ */ 2 3 /*- 4 * Copyright (c) 2010 The NetBSD Foundation, Inc. 5 * All rights reserved. 6 * 7 * Redistribution and use in source and binary forms, with or without 8 * modification, are permitted provided that the following conditions 9 * are met: 10 * 1. Redistributions of source code must retain the above copyright 11 * notice, this list of conditions and the following disclaimer. 12 * 2. Redistributions in binary form must reproduce the above copyright 13 * notice, this list of conditions and the following disclaimer in the 14 * documentation and/or other materials provided with the distribution. 15 * 16 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 17 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 18 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 19 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 20 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 21 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 22 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 23 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 24 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 25 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 26 * POSSIBILITY OF SUCH DAMAGE. 27 */ 28 29 %{ 30 #include <sys/cdefs.h> 31 32 #ifndef lint 33 __RCSID("$NetBSD: parse.y,v 1.3 2020/04/23 00:29:00 joerg Exp $"); 34 #endif 35 36 #include <stdio.h> 37 #include <stdlib.h> 38 #include <string.h> 39 #include <stdint.h> 40 #include <stdbool.h> 41 #include <inttypes.h> 42 #include <errno.h> 43 44 #include <net/if.h> 45 #include <netinet/in.h> 46 #include <net/pfvar.h> 47 #include <arpa/inet.h> 48 #include <netdb.h> 49 #include <netinet/tcp_fsm.h> 50 51 #include "parser.h" 52 53 int lineno; 54 55 struct pfioc_states* states; 56 size_t allocated; 57 58 // XXX it is really correct ? 59 extern const char * const tcpstates[]; 60 61 62 struct pfsync_state global_state; 63 struct pfsync_state_peer *src_peer, *dst_peer; 64 struct pfsync_state_peer current_peer; 65 66 static void parse_init(void); 67 static void add_state(void); 68 static bool get_pfsync_host(const char*, struct pfsync_state_host*, sa_family_t*); 69 static uint8_t retrieve_peer_state(const char*, int); 70 static bool retrieve_seq(const char*, struct pfsync_state_peer*); 71 static bool strtou32(const char*, uint32_t*); 72 73 %} 74 75 %union { 76 uintmax_t num; 77 char* str; 78 } 79 80 %token STATE 81 %token IN OUT 82 %token ON PROTO 83 %token FROM TO USING 84 %token ID CID EXPIRE TIMEOUT 85 %token SRC DST 86 %token SEQ MAX_WIN WSCALE MSS 87 %token NOSCRUB SCRUB FLAGS TTL MODE 88 %token NUMBER STRING 89 90 %type <str> STRING 91 %type <num> NUMBER 92 %% 93 94 states 95 : /* NOTHING */ 96 | state states { parse_init(); } 97 ; 98 99 state 100 : STATE direction iface proto addrs id cid expire timeout src_peer dst_peer { 101 add_state(); 102 } 103 ; 104 105 direction 106 : IN { 107 global_state.direction = PF_IN; 108 src_peer = &global_state.dst; 109 dst_peer = &global_state.src; 110 } 111 | OUT { 112 global_state.direction = PF_OUT; 113 src_peer = &global_state.src; 114 dst_peer = &global_state.dst; 115 } 116 ; 117 118 iface 119 : ON STRING { 120 strlcpy(global_state.ifname, $2, sizeof(global_state.ifname)); 121 free($2); 122 } 123 ; 124 125 proto 126 : PROTO STRING { 127 struct protoent *p; 128 p = getprotobyname($2); 129 if (p == NULL) 130 yyfatal("Invalid protocol name"); 131 global_state.proto = p->p_proto; 132 free($2); 133 } 134 | PROTO NUMBER { 135 // check that the number may be valid proto ? 136 global_state.proto = $2; 137 } 138 ; 139 140 addrs 141 : FROM STRING TO STRING { 142 get_pfsync_host($2, &global_state.lan, &global_state.af); 143 get_pfsync_host($4, &global_state.ext, &global_state.af); 144 memcpy(&global_state.gwy, &global_state.lan, sizeof(struct pfsync_state_host)); 145 free($2); 146 free($4); 147 } 148 | FROM STRING TO STRING USING STRING { 149 get_pfsync_host($2, &global_state.lan, &global_state.af); 150 get_pfsync_host($4, &global_state.ext, &global_state.af); 151 get_pfsync_host($6, &global_state.gwy, &global_state.af); 152 free($2); 153 free($4); 154 free($6); 155 } 156 ; 157 158 id 159 : ID NUMBER { 160 if ( $2 > UINT64_MAX) 161 yyfatal("id is too big"); 162 uint64_t value = (uint64_t)$2; 163 memcpy(global_state.id, &value, sizeof(global_state.id)); 164 } 165 ; 166 167 cid 168 : CID NUMBER { 169 if ( $2 > UINT32_MAX) 170 yyfatal("creator id is too big"); 171 global_state.creatorid = (uint32_t)$2; 172 } 173 ; 174 175 expire 176 : EXPIRE NUMBER { 177 if ( $2 > UINT32_MAX) 178 yyfatal("expire time is too big"); 179 global_state.expire = (uint32_t) $2; 180 } 181 ; 182 183 timeout 184 : TIMEOUT NUMBER { 185 if ($2 > UINT8_MAX) 186 yyfatal("timeout time is too big"); 187 global_state.timeout = (uint8_t) $2; 188 } 189 ; 190 191 src_peer 192 : SRC peer { 193 memcpy(src_peer, ¤t_peer, sizeof(current_peer)); 194 } 195 ; 196 197 dst_peer 198 : DST peer { 199 memcpy(dst_peer, ¤t_peer, sizeof(current_peer)); 200 } 201 ; 202 203 peer 204 : peer_state scrub 205 | peer_state tcp_options scrub 206 ; 207 208 peer_state 209 : STATE STRING { 210 current_peer.state = retrieve_peer_state($2, global_state.proto); 211 free($2); 212 } 213 | STATE NUMBER { 214 if ( $2 > UINT8_MAX) 215 yyfatal("peer state is too big"); 216 current_peer.state = $2; 217 } 218 ; 219 220 tcp_options 221 : SEQ seqs MAX_WIN NUMBER WSCALE NUMBER { 222 if ($4 > UINT16_MAX) 223 yyfatal("max_win is too big"); 224 current_peer.max_win = $4; 225 226 if ($6 > UINT8_MAX) 227 yyfatal("wscale is too big"); 228 current_peer.wscale = $6; 229 } 230 | SEQ seqs MAX_WIN NUMBER WSCALE NUMBER MSS NUMBER { 231 if ($4 > UINT16_MAX) 232 yyfatal("max_win is too big"); 233 current_peer.max_win = $4; 234 235 if ($6 > UINT8_MAX) 236 yyfatal("wscale is too big"); 237 current_peer.wscale = $6; 238 239 if ($8 > UINT16_MAX) 240 yyfatal("mss is too big"); 241 current_peer.mss = $8; 242 } 243 ; 244 245 seqs 246 : STRING { 247 if (!retrieve_seq($1, ¤t_peer)) 248 yyfatal("invalid seq number"); 249 250 free($1); 251 } 252 ; 253 254 scrub 255 : NOSCRUB { current_peer.scrub.scrub_flag= 0;} 256 | SCRUB FLAGS NUMBER MODE NUMBER TTL NUMBER { 257 current_peer.scrub.scrub_flag= PFSYNC_SCRUB_FLAG_VALID; 258 if ($3 > UINT16_MAX) 259 yyfatal("scrub flags is too big"); 260 current_peer.scrub.pfss_flags = $3; 261 262 if ($5 > UINT32_MAX) 263 yyfatal("scrub mode is too big"); 264 current_peer.scrub.pfss_ts_mod = $5; 265 266 if ($7 > UINT8_MAX) 267 yyfatal("scrub ttl is too big"); 268 current_peer.scrub.pfss_ttl = $7; 269 } 270 ; 271 272 273 %% 274 275 static void 276 parse_init(void) 277 { 278 memset(&global_state, 0, sizeof(global_state)); 279 memset(¤t_peer, 0, sizeof(current_peer)); 280 src_peer = NULL; 281 dst_peer = NULL; 282 } 283 284 static bool 285 get_pfsync_host(const char* str, struct pfsync_state_host* host, sa_family_t* af) 286 { 287 size_t count_colon, addr_len, port_len; 288 const char* p, *last_colon, *first_bracket, *last_bracket; 289 char buf[48]; 290 char buf_port[6]; 291 292 if (str == NULL || *str == '\0') 293 return false; 294 295 p = str; 296 last_colon = NULL; 297 count_colon = 0; 298 299 while (*p != '\0') { 300 if (*p == ':') { 301 count_colon++; 302 last_colon = p; 303 } 304 p++; 305 } 306 307 /* 308 * If no colon, it is not an expected addr 309 * If there are more than one colon, we guess that af = AF_INET6 310 */ 311 312 if (count_colon == 0) 313 return false; 314 315 if (count_colon == 1) 316 *af = AF_INET; 317 else 318 *af = AF_INET6; 319 320 /* 321 * First bracket must be next character after last colon 322 * Last bracket must be the last character 323 * distance between both must be <= 7 324 */ 325 326 if (*(last_colon+1) == '[') 327 first_bracket = last_colon + 1; 328 else 329 return false; 330 331 last_bracket = str + (strlen(str) - 1); 332 if (*last_bracket != ']') 333 return false; 334 335 port_len = last_bracket - first_bracket; 336 if (last_bracket - first_bracket > 7) 337 return false; 338 339 memcpy(buf_port, first_bracket +1, port_len - 1); 340 buf_port[port_len-1]= '\0'; 341 342 addr_len = last_colon - str; 343 if (addr_len >= sizeof(buf)) 344 return false; 345 memcpy(buf, str, addr_len); 346 buf[addr_len] = '\0'; 347 348 if (inet_pton(*af, buf, &host->addr) != 1) 349 return false; 350 351 host->port = htons(atoi(buf_port)); 352 353 return true; 354 } 355 356 static uint8_t 357 retrieve_peer_state(const char* str, int proto) 358 { 359 uint8_t i; 360 361 if (proto == IPPROTO_TCP) { 362 i = 0; 363 while (i < TCP_NSTATES) { 364 if (strcmp(str, tcpstates[i]) == 0) 365 return i; 366 i++; 367 } 368 yyfatal("Invalid peer state"); 369 370 } else { 371 if (proto == IPPROTO_UDP) { 372 const char* mystates[] = PFUDPS_NAMES; 373 i = 0; 374 375 while (i < PFUDPS_NSTATES) { 376 if (strcmp(str, mystates[i]) == 0) 377 return i; 378 i++; 379 } 380 381 yyfatal("Invalid peer state"); 382 } else { 383 const char *mystates[] = PFOTHERS_NAMES; 384 i = 0; 385 386 while (i < PFOTHERS_NSTATES) { 387 if (strcmp(str, mystates[i]) == 0) 388 return i; 389 i++; 390 } 391 392 yyfatal("Invalid peer state"); 393 } 394 } 395 /*NOTREACHED*/ 396 return 0; 397 } 398 399 static bool 400 strtou32(const char* str, uint32_t* res) 401 { 402 uintmax_t u; 403 errno = 0; 404 u = strtoumax(str, NULL, 10); 405 if (errno == ERANGE && u == UINTMAX_MAX) 406 return false; 407 if (u > UINT32_MAX) 408 return false; 409 *res = (uint32_t) u; 410 return true; 411 } 412 413 static bool 414 retrieve_seq(const char* str, struct pfsync_state_peer* peer) 415 { 416 const char* p, *p_colon, *p_comma; 417 char buf[100]; 418 size_t size; 419 420 if (str == NULL || *str == '\0') 421 return false; 422 423 if (*str != '[' || *(str+(strlen(str) -1)) != ']') 424 return false; 425 426 p = str; 427 p_colon = NULL; 428 p_comma = NULL; 429 while (*p != '\0') { 430 if (*p == ':') { 431 if (p_colon !=NULL) 432 return false; 433 else 434 p_colon = p; 435 } 436 437 if (*p == ',') { 438 if (p_comma != NULL) 439 return false; 440 else 441 p_comma = p; 442 } 443 p++; 444 } 445 446 size = p_colon - str; 447 if (size > sizeof(buf)) 448 return false; 449 memcpy(buf, str+1, size-1); 450 buf[size-1] = '\0'; 451 452 if (!strtou32(buf, &peer->seqlo)) 453 return false; 454 455 456 if (p_comma == NULL) 457 size = str + strlen(str) - 1 - p_colon; 458 else 459 size = p_comma - p_colon; 460 461 if (size > sizeof(buf)) 462 return false; 463 memcpy(buf, p_colon+1, size -1); 464 buf[size-1] = '\0'; 465 466 if (!strtou32(buf, &peer->seqhi)) 467 return false; 468 469 if (p_comma == NULL) { 470 peer->seqdiff = 0; 471 } else { 472 size = str + strlen(str) - 1 - p_comma; 473 if (size > sizeof(buf)) 474 return false; 475 memcpy(buf, p_comma +1, size -1); 476 buf[size-1] = '\0'; 477 478 if (!strtou32(buf, &peer->seqdiff)) 479 return false; 480 } 481 482 return true; 483 } 484 485 static void 486 add_state(void) 487 { 488 489 if (allocated == 0) { 490 allocated = 5; 491 states->ps_buf = malloc(allocated * sizeof(struct pfsync_state)); 492 if (states->ps_buf == NULL) 493 yyfatal("Not enougth memory"); 494 } 495 496 if (allocated == (states->ps_len / sizeof(struct pfsync_state))) { 497 void *buf; 498 allocated = allocated * 2 + 1; 499 buf = realloc(states->ps_buf, allocated * sizeof(struct pfsync_state)); 500 if (buf == NULL) { 501 free(states->ps_buf); 502 yyfatal("Not enougth memory"); 503 } 504 states->ps_buf = buf; 505 } 506 507 } 508