| | 316 | @param token first keyword |
| | 317 | @param leftover rest of the line |
| | 318 | */ |
| | 319 | #define TO_NEXT_WORD(s, e) do { \ |
| | 320 | while (*s != '\0' && !isblank(*s)) { \ |
| | 321 | s++; \ |
| | 322 | } \ |
| | 323 | if (*s != '\0') { \ |
| | 324 | *s = '\0'; \ |
| | 325 | s++; \ |
| | 326 | while (isblank(*s)) \ |
| | 327 | s++; \ |
| | 328 | } else { \ |
| | 329 | e = 1; \ |
| | 330 | } \ |
| | 331 | } while (0) |
| | 332 | |
| | 333 | static int |
| | 334 | parse_firewall_rule(char *token, char *leftover) |
| | 335 | { |
| | 336 | int i; |
| | 337 | int block_allow = 0; /**< 0 == block, 1 == allow */ |
| | 338 | int all_nums = 1; /**< If 0, port contained non-numerics */ |
| | 339 | int finished = 0; /**< reached end of line */ |
| | 340 | char *port = NULL; /**< port to open/block */ |
| | 341 | char *protocol = NULL; /**< protocol to block, tcp/udp/icmp */ |
| | 342 | char *mask = NULL; /**< Netmask */ |
| | 343 | char *other_kw = NULL; /**< other key word */ |
| | 344 | t_firewall_rule *tmp; |
| | 345 | t_firewall_rule *tmp2; |
| | 346 | |
| | 347 | debug(LOG_DEBUG, "leftover: %s", ++leftover); |
| | 348 | debug(LOG_DEBUG, "token: %s", token); |
| | 349 | |
| | 350 | /* lower case */ |
| | 351 | for (i = 0; *(leftover + i) != '\0' |
| | 352 | && (*(leftover + i) = tolower(*(leftover + i))); i++); |
| | 353 | |
| | 354 | /* Parse token */ |
| | 355 | if (!strcasecmp(token, "block")) { |
| | 356 | block_allow = 0; |
| | 357 | } else if (!strcasecmp(token, "allow")) { |
| | 358 | block_allow = 1; |
| | 359 | } else { |
| | 360 | debug(LOG_ERR, "Invalid rule type %s, expecting " |
| | 361 | "\"block\" or \"allow\"", token); |
| | 362 | return -1; |
| | 363 | } |
| | 364 | |
| | 365 | /* Parse the remainder */ |
| | 366 | /* Get the protocol */ |
| | 367 | protocol = leftover; |
| | 368 | TO_NEXT_WORD(leftover, finished); |
| | 369 | if (strcmp(protocol, "tcp") && strcmp(protocol, "udp") |
| | 370 | && strcmp(protocol, "icmp") || finished) { |
| | 371 | debug(LOG_ERR, "Invalid protocol %s in FirewallRule", |
| | 372 | protocol); |
| | 373 | return -1; /*< Fail */ |
| | 374 | } |
| | 375 | |
| | 376 | /* should be exactly "port" */ |
| | 377 | other_kw = leftover; |
| | 378 | TO_NEXT_WORD(leftover, finished); |
| | 379 | if (strcmp(other_kw, "port") || finished) { |
| | 380 | debug(LOG_ERR, "Invalid or unexpected keyword %s, " |
| | 381 | "expecting \"port\"", other_kw); |
| | 382 | return -2; /*< Fail */ |
| | 383 | } |
| | 384 | |
| | 385 | /* Get port now */ |
| | 386 | port = leftover; |
| | 387 | TO_NEXT_WORD(leftover, finished); |
| | 388 | for (i = 0; *(port + i) != '\0'; i++) |
| | 389 | if (!isdigit(*(port + i))) |
| | 390 | all_nums = 0; /*< No longer only digits */ |
| | 391 | if (!all_nums) { |
| | 392 | debug(LOG_ERR, "Invalid port %s", port); |
| | 393 | return -3; /*< Fail */ |
| | 394 | } |
| | 395 | |
| | 396 | /* Now, further stuff is optional */ |
| | 397 | if (!finished) { |
| | 398 | /* should be exactly "to" */ |
| | 399 | other_kw = leftover; |
| | 400 | TO_NEXT_WORD(leftover, finished); |
| | 401 | if (strcmp(other_kw, "to") || finished) { |
| | 402 | debug(LOG_ERR, "Invalid or unexpected keyword %s, " |
| | 403 | "expecting \"to\"", other_kw); |
| | 404 | return -4; /*< Fail */ |
| | 405 | } |
| | 406 | |
| | 407 | /* Get port now */ |
| | 408 | mask = leftover; |
| | 409 | TO_NEXT_WORD(leftover, finished); |
| | 410 | all_nums = 1; |
| | 411 | for (i = 0; *(mask + i) != '\0'; i++) |
| | 412 | if (!isdigit(*(mask + i)) && (*(mask + i) != '.') |
| | 413 | && (*(mask + i) != '/')) |
| | 414 | all_nums = 0; /*< No longer only digits */ |
| | 415 | if (!all_nums) { |
| | 416 | debug(LOG_ERR, "Invalid mask %s", mask); |
| | 417 | return -3; /*< Fail */ |
| | 418 | } |
| | 419 | } |
| | 420 | |
| | 421 | /* Generate rule record */ |
| | 422 | tmp = (t_firewall_rule *)malloc(sizeof(t_firewall_rule)); |
| | 423 | memset((void *)tmp, 0, sizeof(t_firewall_rule)); |
| | 424 | tmp->block_allow = block_allow; |
| | 425 | tmp->protocol = strdup(protocol); |
| | 426 | tmp->port = strdup(port); |
| | 427 | if (mask == NULL) |
| | 428 | tmp->mask = strdup("0.0.0.0/0"); |
| | 429 | else |
| | 430 | tmp->mask = strdup(mask); |
| | 431 | |
| | 432 | debug(LOG_DEBUG, "Adding Firewall Rule %s %s port %s to %s", |
| | 433 | token, tmp->protocol, tmp->port, tmp->mask); |
| | 434 | |
| | 435 | /* Append the rule record */ |
| | 436 | if (config.rules == NULL) { |
| | 437 | config.rules = tmp; |
| | 438 | } else { |
| | 439 | tmp2 = config.rules; |
| | 440 | while (tmp2->next != NULL) |
| | 441 | tmp2 = tmp2->next; |
| | 442 | tmp2->next = tmp; |
| | 443 | } |
| | 444 | |
| | 445 | return 1; |
| | 446 | } |
| | 447 | |
| | 448 | /** |