|
Packit Service |
5956c7 |
/*
|
|
Packit Service |
5956c7 |
* Soft: Keepalived is a failover program for the LVS project
|
|
Packit Service |
5956c7 |
* <www.linuxvirtualserver.org>. It monitor & manipulate
|
|
Packit Service |
5956c7 |
* a loadbalanced server pool using multi-layer checks.
|
|
Packit Service |
5956c7 |
*
|
|
Packit Service |
5956c7 |
* Part: iprule and iproute parser
|
|
Packit Service |
5956c7 |
*
|
|
Packit Service |
5956c7 |
* Author: Chris Riley, <kernelchris@gmail.com>
|
|
Packit Service |
5956c7 |
*
|
|
Packit Service |
5956c7 |
* This program is distributed in the hope that it will be useful,
|
|
Packit Service |
5956c7 |
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
Packit Service |
5956c7 |
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
|
Packit Service |
5956c7 |
* See the GNU General Public License for more details.
|
|
Packit Service |
5956c7 |
*
|
|
Packit Service |
5956c7 |
* This program is free software; you can redistribute it and/or
|
|
Packit Service |
5956c7 |
* modify it under the terms of the GNU General Public License
|
|
Packit Service |
5956c7 |
* as published by the Free Software Foundation; either version
|
|
Packit Service |
5956c7 |
* 2 of the License, or (at your option) any later version.
|
|
Packit Service |
5956c7 |
*
|
|
Packit Service |
5956c7 |
* Copyright (C) 2015 Chris Riley, <kernelchris@gmail.com>
|
|
Packit Service |
5956c7 |
* Copyright (C) 2016-2017 Alexandre Cassen, <acassen@gmail.com>
|
|
Packit Service |
5956c7 |
*/
|
|
Packit Service |
5956c7 |
|
|
Packit Service |
5956c7 |
#include "config.h"
|
|
Packit Service |
5956c7 |
|
|
Packit Service |
5956c7 |
#include <string.h>
|
|
Packit Service |
5956c7 |
#include <errno.h>
|
|
Packit Service |
5956c7 |
#include <limits.h>
|
|
Packit Service |
5956c7 |
#include <stdlib.h>
|
|
Packit Service |
5956c7 |
#include <math.h>
|
|
Packit Service |
5956c7 |
#include <arpa/inet.h>
|
|
Packit Service |
5956c7 |
#include <stdint.h>
|
|
Packit Service |
5956c7 |
#include <ctype.h>
|
|
Packit Service |
5956c7 |
|
|
Packit Service |
5956c7 |
#include "logger.h"
|
|
Packit Service |
5956c7 |
#include "vrrp_ip_rule_route_parser.h"
|
|
Packit Service |
5956c7 |
#include "rttables.h"
|
|
Packit Service |
5956c7 |
#if HAVE_DECL_RTA_ENCAP
|
|
Packit Service |
5956c7 |
#include "vrrp_iproute.h"
|
|
Packit Service |
5956c7 |
#endif
|
|
Packit Service |
5956c7 |
#include "parser.h"
|
|
Packit Service |
5956c7 |
|
|
Packit Service |
5956c7 |
bool
|
|
Packit Service |
5956c7 |
get_realms(uint32_t *realms, char *str)
|
|
Packit Service |
5956c7 |
{
|
|
Packit Service |
5956c7 |
uint32_t val, val1;
|
|
Packit Service |
5956c7 |
char *end;
|
|
Packit Service |
5956c7 |
|
|
Packit Service |
5956c7 |
if ((end = strchr(str,'/')))
|
|
Packit Service |
5956c7 |
*end = '\0';
|
|
Packit Service |
5956c7 |
|
|
Packit Service |
5956c7 |
if (!find_rttables_realms(str, &val))
|
|
Packit Service |
5956c7 |
goto err;
|
|
Packit Service |
5956c7 |
|
|
Packit Service |
5956c7 |
if (end) {
|
|
Packit Service |
5956c7 |
if (!find_rttables_realms(end + 1, &val1))
|
|
Packit Service |
5956c7 |
goto err;
|
|
Packit Service |
5956c7 |
|
|
Packit Service |
5956c7 |
val <<= 16;
|
|
Packit Service |
5956c7 |
val |= val1;
|
|
Packit Service |
5956c7 |
|
|
Packit Service |
5956c7 |
*end = '/';
|
|
Packit Service |
5956c7 |
}
|
|
Packit Service |
5956c7 |
|
|
Packit Service |
5956c7 |
*realms = val;
|
|
Packit Service |
5956c7 |
|
|
Packit Service |
5956c7 |
return false;
|
|
Packit Service |
5956c7 |
|
|
Packit Service |
5956c7 |
err:
|
|
Packit Service |
5956c7 |
if (end)
|
|
Packit Service |
5956c7 |
*end = '/';
|
|
Packit Service |
5956c7 |
return true;
|
|
Packit Service |
5956c7 |
}
|
|
Packit Service |
5956c7 |
|
|
Packit Service |
5956c7 |
|
|
Packit Service |
5956c7 |
bool
|
|
Packit Service |
5956c7 |
get_u8(uint8_t *val, const char *str, uint8_t max, const char* errmsg)
|
|
Packit Service |
5956c7 |
{
|
|
Packit Service |
5956c7 |
unsigned t_val;
|
|
Packit Service |
5956c7 |
|
|
Packit Service |
5956c7 |
if (read_unsigned(str, &t_val, 0, max, false)) {
|
|
Packit Service |
5956c7 |
*val = (uint8_t)t_val;
|
|
Packit Service |
5956c7 |
return false;
|
|
Packit Service |
5956c7 |
}
|
|
Packit Service |
5956c7 |
|
|
Packit Service |
5956c7 |
report_config_error(CONFIG_GENERAL_ERROR, errmsg, str);
|
|
Packit Service |
5956c7 |
return true;
|
|
Packit Service |
5956c7 |
}
|
|
Packit Service |
5956c7 |
|
|
Packit Service |
5956c7 |
bool
|
|
Packit Service |
5956c7 |
get_u16(uint16_t *val, const char *str, uint16_t max, const char* errmsg)
|
|
Packit Service |
5956c7 |
{
|
|
Packit Service |
5956c7 |
unsigned t_val;
|
|
Packit Service |
5956c7 |
|
|
Packit Service |
5956c7 |
if (read_unsigned(str, &t_val, 0, max, false)) {
|
|
Packit Service |
5956c7 |
*val = (uint16_t)t_val;
|
|
Packit Service |
5956c7 |
return false;
|
|
Packit Service |
5956c7 |
}
|
|
Packit Service |
5956c7 |
|
|
Packit Service |
5956c7 |
report_config_error(CONFIG_GENERAL_ERROR, errmsg, str);
|
|
Packit Service |
5956c7 |
return true;
|
|
Packit Service |
5956c7 |
}
|
|
Packit Service |
5956c7 |
|
|
Packit Service |
5956c7 |
bool
|
|
Packit Service |
5956c7 |
get_u32(uint32_t *val, const char *str, uint32_t max, const char* errmsg)
|
|
Packit Service |
5956c7 |
{
|
|
Packit Service |
5956c7 |
unsigned t_val;
|
|
Packit Service |
5956c7 |
|
|
Packit Service |
5956c7 |
if (read_unsigned(str, &t_val, 0, max, false)) {
|
|
Packit Service |
5956c7 |
*val = (uint32_t)t_val;
|
|
Packit Service |
5956c7 |
return false;
|
|
Packit Service |
5956c7 |
}
|
|
Packit Service |
5956c7 |
|
|
Packit Service |
5956c7 |
report_config_error(CONFIG_GENERAL_ERROR, errmsg, str);
|
|
Packit Service |
5956c7 |
return true;
|
|
Packit Service |
5956c7 |
}
|
|
Packit Service |
5956c7 |
|
|
Packit Service |
5956c7 |
bool
|
|
Packit Service |
5956c7 |
get_u64(uint64_t *val, const char *str, uint64_t max, const char* errmsg)
|
|
Packit Service |
5956c7 |
{
|
|
Packit Service |
5956c7 |
uint64_t t_val;
|
|
Packit Service |
5956c7 |
|
|
Packit Service |
5956c7 |
if (read_unsigned64(str, &t_val, 0, max, false)) {
|
|
Packit Service |
5956c7 |
*val = (uint64_t)t_val;
|
|
Packit Service |
5956c7 |
return false;
|
|
Packit Service |
5956c7 |
}
|
|
Packit Service |
5956c7 |
|
|
Packit Service |
5956c7 |
report_config_error(CONFIG_GENERAL_ERROR, errmsg, str);
|
|
Packit Service |
5956c7 |
return true;
|
|
Packit Service |
5956c7 |
}
|
|
Packit Service |
5956c7 |
|
|
Packit Service |
5956c7 |
bool
|
|
Packit Service |
5956c7 |
get_time_rtt(uint32_t *val, const char *str, bool *raw)
|
|
Packit Service |
5956c7 |
{
|
|
Packit Service |
5956c7 |
double t;
|
|
Packit Service |
5956c7 |
unsigned long res;
|
|
Packit Service |
5956c7 |
char *end;
|
|
Packit Service |
5956c7 |
size_t offset;
|
|
Packit Service |
5956c7 |
|
|
Packit Service |
5956c7 |
errno = 0;
|
|
Packit Service |
5956c7 |
if (strchr(str, '.') ||
|
|
Packit Service |
5956c7 |
(strpbrk(str,"Ee" ) && !strpbrk(str, "xX"))) {
|
|
Packit Service |
5956c7 |
t = strtod(str, &end;;
|
|
Packit Service |
5956c7 |
if (t <= 0.0)
|
|
Packit Service |
5956c7 |
return true;
|
|
Packit Service |
5956c7 |
|
|
Packit Service |
5956c7 |
/* no digits? */
|
|
Packit Service |
5956c7 |
if (end == str)
|
|
Packit Service |
5956c7 |
return true;
|
|
Packit Service |
5956c7 |
|
|
Packit Service |
5956c7 |
/* overflow */
|
|
Packit Service |
5956c7 |
if (t == HUGE_VAL && errno == ERANGE)
|
|
Packit Service |
5956c7 |
return true;
|
|
Packit Service |
5956c7 |
|
|
Packit Service |
5956c7 |
if (t >= UINT32_MAX)
|
|
Packit Service |
5956c7 |
return true;
|
|
Packit Service |
5956c7 |
} else {
|
|
Packit Service |
5956c7 |
/* Skip whitespace */
|
|
Packit Service |
5956c7 |
offset = strspn(str, WHITE_SPACE);
|
|
Packit Service |
5956c7 |
|
|
Packit Service |
5956c7 |
/* strtoul does "nasty" things with negative numbers */
|
|
Packit Service |
5956c7 |
if (str[offset] == '-')
|
|
Packit Service |
5956c7 |
return true;
|
|
Packit Service |
5956c7 |
|
|
Packit Service |
5956c7 |
res = strtoul(str, &end, 0);
|
|
Packit Service |
5956c7 |
|
|
Packit Service |
5956c7 |
/* no digits? */
|
|
Packit Service |
5956c7 |
if (end == str)
|
|
Packit Service |
5956c7 |
return true;
|
|
Packit Service |
5956c7 |
|
|
Packit Service |
5956c7 |
/* overflow */
|
|
Packit Service |
5956c7 |
if (res == ULONG_MAX && errno == ERANGE)
|
|
Packit Service |
5956c7 |
return true;
|
|
Packit Service |
5956c7 |
|
|
Packit Service |
5956c7 |
if (res > UINT32_MAX)
|
|
Packit Service |
5956c7 |
return true;
|
|
Packit Service |
5956c7 |
|
|
Packit Service |
5956c7 |
t = (double)res;
|
|
Packit Service |
5956c7 |
}
|
|
Packit Service |
5956c7 |
|
|
Packit Service |
5956c7 |
if (*end) {
|
|
Packit Service |
5956c7 |
*raw = false;
|
|
Packit Service |
5956c7 |
if (!strcasecmp(end, "s") ||
|
|
Packit Service |
5956c7 |
!strcasecmp(end, "sec") ||
|
|
Packit Service |
5956c7 |
!strcasecmp(end, "secs")) {
|
|
Packit Service |
5956c7 |
if (t >= UINT32_MAX / 1000)
|
|
Packit Service |
5956c7 |
return false;
|
|
Packit Service |
5956c7 |
t *= 1000;
|
|
Packit Service |
5956c7 |
}
|
|
Packit Service |
5956c7 |
else if (strcasecmp(end, "ms") &&
|
|
Packit Service |
5956c7 |
strcasecmp(end, "msec") &&
|
|
Packit Service |
5956c7 |
strcasecmp(end, "msecs"))
|
|
Packit Service |
5956c7 |
return true;
|
|
Packit Service |
5956c7 |
}
|
|
Packit Service |
5956c7 |
else
|
|
Packit Service |
5956c7 |
*raw = true;
|
|
Packit Service |
5956c7 |
|
|
Packit Service |
5956c7 |
*val = (uint32_t)t;
|
|
Packit Service |
5956c7 |
if (*val < t)
|
|
Packit Service |
5956c7 |
(*val)++;
|
|
Packit Service |
5956c7 |
|
|
Packit Service |
5956c7 |
return false;
|
|
Packit Service |
5956c7 |
}
|
|
Packit Service |
5956c7 |
|
|
Packit Service |
5956c7 |
bool
|
|
Packit Service |
5956c7 |
get_addr64(uint64_t *ap, const char *cp)
|
|
Packit Service |
5956c7 |
{
|
|
Packit Service |
5956c7 |
int i;
|
|
Packit Service |
5956c7 |
|
|
Packit Service |
5956c7 |
union {
|
|
Packit Service |
5956c7 |
uint16_t v16[4];
|
|
Packit Service |
5956c7 |
uint64_t v64;
|
|
Packit Service |
5956c7 |
} val;
|
|
Packit Service |
5956c7 |
|
|
Packit Service |
5956c7 |
/* Skip leading whitespace */
|
|
Packit Service |
5956c7 |
cp += strspn(cp, WHITE_SPACE);
|
|
Packit Service |
5956c7 |
|
|
Packit Service |
5956c7 |
val.v64 = 0;
|
|
Packit Service |
5956c7 |
for (i = 0; i < 4; i++) {
|
|
Packit Service |
5956c7 |
unsigned long n;
|
|
Packit Service |
5956c7 |
char *endp;
|
|
Packit Service |
5956c7 |
|
|
Packit Service |
5956c7 |
if (!isxdigit(*cp))
|
|
Packit Service |
5956c7 |
return true; /* Not a hex digit */
|
|
Packit Service |
5956c7 |
|
|
Packit Service |
5956c7 |
n = strtoul(cp, &endp, 16);
|
|
Packit Service |
5956c7 |
if (n > 0xffff)
|
|
Packit Service |
5956c7 |
return true; /* bogus network value */
|
|
Packit Service |
5956c7 |
|
|
Packit Service |
5956c7 |
if (endp == cp) /* no digits */
|
|
Packit Service |
5956c7 |
return true;
|
|
Packit Service |
5956c7 |
|
|
Packit Service |
5956c7 |
val.v16[i] = htons(n);
|
|
Packit Service |
5956c7 |
|
|
Packit Service |
5956c7 |
if (*endp == '\0') {
|
|
Packit Service |
5956c7 |
if (i != 3) /* address too short */
|
|
Packit Service |
5956c7 |
return true;
|
|
Packit Service |
5956c7 |
break;
|
|
Packit Service |
5956c7 |
}
|
|
Packit Service |
5956c7 |
|
|
Packit Service |
5956c7 |
if (i == 3 || *endp != ':')
|
|
Packit Service |
5956c7 |
return true; /* extra characters */
|
|
Packit Service |
5956c7 |
cp = endp + 1;
|
|
Packit Service |
5956c7 |
}
|
|
Packit Service |
5956c7 |
|
|
Packit Service |
5956c7 |
*ap = val.v64;
|
|
Packit Service |
5956c7 |
|
|
Packit Service |
5956c7 |
return false;
|
|
Packit Service |
5956c7 |
}
|
|
Packit Service |
5956c7 |
|
|
Packit Service |
5956c7 |
#if HAVE_DECL_LWTUNNEL_ENCAP_MPLS
|
|
Packit Service |
5956c7 |
bool
|
|
Packit Service |
5956c7 |
parse_mpls_address(const char *str, encap_mpls_t *mpls)
|
|
Packit Service |
5956c7 |
{
|
|
Packit Service |
5956c7 |
char *endp;
|
|
Packit Service |
5956c7 |
unsigned count;
|
|
Packit Service |
5956c7 |
unsigned long label;
|
|
Packit Service |
5956c7 |
|
|
Packit Service |
5956c7 |
mpls->num_labels = 0;
|
|
Packit Service |
5956c7 |
|
|
Packit Service |
5956c7 |
/* Skip leading whitespace */
|
|
Packit Service |
5956c7 |
str += strspn(str, WHITE_SPACE);
|
|
Packit Service |
5956c7 |
|
|
Packit Service |
5956c7 |
for (count = 0; count < MAX_MPLS_LABELS; count++) {
|
|
Packit Service |
5956c7 |
if (str[0] == '-')
|
|
Packit Service |
5956c7 |
return true;
|
|
Packit Service |
5956c7 |
|
|
Packit Service |
5956c7 |
if (strspn(str, WHITE_SPACE)) /* No embedded whitespace */
|
|
Packit Service |
5956c7 |
return true;
|
|
Packit Service |
5956c7 |
|
|
Packit Service |
5956c7 |
label = strtoul(str, &endp, 0);
|
|
Packit Service |
5956c7 |
|
|
Packit Service |
5956c7 |
if (endp == str) /* no digits */
|
|
Packit Service |
5956c7 |
return true;
|
|
Packit Service |
5956c7 |
|
|
Packit Service |
5956c7 |
/* Fail when the label value is out of range */
|
|
Packit Service |
5956c7 |
if (label > UINT32_MAX)
|
|
Packit Service |
5956c7 |
return true;
|
|
Packit Service |
5956c7 |
if (label & ~(MPLS_LS_LABEL_MASK >> MPLS_LS_LABEL_SHIFT))
|
|
Packit Service |
5956c7 |
return true;
|
|
Packit Service |
5956c7 |
|
|
Packit Service |
5956c7 |
mpls->addr[count].entry = htonl((uint32_t)label << MPLS_LS_LABEL_SHIFT);
|
|
Packit Service |
5956c7 |
if (*endp == '\0') {
|
|
Packit Service |
5956c7 |
mpls->addr[count].entry |= htonl(1 << MPLS_LS_S_SHIFT);
|
|
Packit Service |
5956c7 |
mpls->num_labels = count + 1;
|
|
Packit Service |
5956c7 |
return false;
|
|
Packit Service |
5956c7 |
}
|
|
Packit Service |
5956c7 |
|
|
Packit Service |
5956c7 |
/* Bad character in the address */
|
|
Packit Service |
5956c7 |
if (*endp != '/')
|
|
Packit Service |
5956c7 |
return true;
|
|
Packit Service |
5956c7 |
|
|
Packit Service |
5956c7 |
str = endp + 1;
|
|
Packit Service |
5956c7 |
}
|
|
Packit Service |
5956c7 |
|
|
Packit Service |
5956c7 |
/* The address was too long */
|
|
Packit Service |
5956c7 |
return true;
|
|
Packit Service |
5956c7 |
}
|
|
Packit Service |
5956c7 |
#endif
|