Blame keepalived/vrrp/vrrp_ip_rule_route_parser.c

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