2015-09-10 00:45:29 +02:00
|
|
|
/*
|
|
|
|
* vrrp_options.c
|
|
|
|
*
|
|
|
|
* Copyright (C) 2014 Arnaud Andre
|
|
|
|
*
|
|
|
|
* This file is part of uvrrpd.
|
|
|
|
*
|
|
|
|
* uvrrpd is free software: you can redistribute it and/or modify
|
|
|
|
* it under the terms of the GNU General Public License as published by
|
|
|
|
* the Free Software Foundation, either version 3 of the License, or
|
|
|
|
* (at your option) any later version.
|
|
|
|
*
|
|
|
|
* uvrrpd is distributed in the hope that it will be useful,
|
|
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
|
|
* GNU General Public License for more details.
|
|
|
|
*
|
|
|
|
* You should have received a copy of the GNU General Public License
|
|
|
|
* along with uvrrpd. If not, see <http://www.gnu.org/licenses/>.
|
|
|
|
*/
|
|
|
|
|
|
|
|
#include <stdio.h>
|
|
|
|
#include <unistd.h>
|
|
|
|
#include <getopt.h>
|
|
|
|
#include <string.h>
|
|
|
|
|
|
|
|
#include "vrrp.h"
|
|
|
|
#include "vrrp_net.h"
|
|
|
|
#include "vrrp_options.h"
|
|
|
|
#include "common.h"
|
|
|
|
#include "log.h"
|
|
|
|
|
|
|
|
/* from uvrrpd.c */
|
|
|
|
extern int background;
|
|
|
|
extern char *loglevel;
|
2015-09-16 01:21:42 +02:00
|
|
|
extern char *pidfile_name;
|
2016-01-18 11:45:38 +01:00
|
|
|
extern char *ctrlfile_name;
|
2015-09-10 00:45:29 +02:00
|
|
|
|
|
|
|
/**
|
|
|
|
* vrrp_usage()
|
|
|
|
*/
|
|
|
|
static void vrrp_usage(void)
|
|
|
|
{
|
|
|
|
fprintf(stdout,
|
|
|
|
"Usage: uvrrpd -v vrid -i ifname [OPTIONS] VIP1 [… VIPn]\n\n"
|
|
|
|
"Mandatory options:\n"
|
|
|
|
" -v, --vrid vrid Virtual router identifier\n"
|
|
|
|
" -i, --interface iface Interface\n"
|
|
|
|
" VIP Virtual IP(s), 1 to 255 VIPs\n\n"
|
|
|
|
"Optional arguments:\n"
|
|
|
|
" -p, --priority prio Priority of VRRP Instance, (0-255, default 100)\n"
|
|
|
|
" -t, --time delay Time interval between advertisements\n"
|
|
|
|
" Seconds in VRRPv2 (default 1s),\n"
|
|
|
|
" Centiseconds in VRRPv3 (default 100cs)\n"
|
|
|
|
" -P, --preempt on|off Switch preempt (default on)\n"
|
|
|
|
" -r, --rfc version Specify protocol 'version'\n"
|
|
|
|
" 2 (VRRPv2, RFC3768) by default,\n"
|
|
|
|
" 3 (VRRPv3, RFC5798)\n"
|
|
|
|
" -6, --ipv6 IPv6 support, (only in VRRPv3)\n"
|
|
|
|
" -a, --auth pass Simple text password (only in VRRPv2)\n"
|
|
|
|
" -f, --foreground Execute uvrrpd in foreground\n"
|
2015-12-31 14:43:07 +01:00
|
|
|
" -s, --script Path of hook script (default "stringify(PATH)"/vrrp-switch.sh)\n"
|
2016-01-18 11:45:38 +01:00
|
|
|
" -F --pidfile name Change pid file 'name'\n"
|
2015-12-31 14:43:07 +01:00
|
|
|
" Default "stringify(PATHRUN)"/uvrrp_${vrid}.pid\n"
|
2016-01-18 11:45:38 +01:00
|
|
|
" -C --control name Change control file 'name'\n"
|
|
|
|
" Default "stringify(PATHRUN)"/uvrrpd_ctrl.${vrid}\n"
|
2015-09-10 00:45:29 +02:00
|
|
|
" -d, --debug\n" " -h, --help\n");
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* vrrp_options() - Parse command line options
|
|
|
|
*/
|
|
|
|
int vrrp_options(struct vrrp *vrrp, struct vrrp_net *vnet, int argc,
|
|
|
|
char *argv[])
|
|
|
|
{
|
2015-12-22 09:22:14 +01:00
|
|
|
int optc, err;
|
2015-09-10 00:45:29 +02:00
|
|
|
unsigned long opt; /* strtoul */
|
|
|
|
|
|
|
|
static struct option const opts[] = {
|
|
|
|
{"vrid", required_argument, 0, 'v'},
|
|
|
|
{"interface", required_argument, 0, 'i'},
|
|
|
|
{"priority", required_argument, 0, 'p'},
|
|
|
|
{"time", required_argument, 0, 't'},
|
|
|
|
{"preempt", required_argument, 0, 'P'},
|
|
|
|
{"rfc", required_argument, 0, 'r'},
|
|
|
|
{"ipv6", no_argument, 0, '6'},
|
|
|
|
{"auth", required_argument, 0, 'a'},
|
|
|
|
{"foreground", no_argument, 0, 'f'},
|
|
|
|
{"script", required_argument, 0, 's'},
|
2015-09-16 01:21:42 +02:00
|
|
|
{"pidfile", required_argument, 0, 'F'},
|
2016-01-18 11:45:38 +01:00
|
|
|
{"control", required_argument, 0, 'C'},
|
2015-09-10 00:45:29 +02:00
|
|
|
{"debug", no_argument, 0, 'd'},
|
|
|
|
{"help", no_argument, 0, 'h'},
|
|
|
|
{NULL, 0, 0, 0}
|
|
|
|
};
|
|
|
|
|
|
|
|
while ((optc =
|
2016-01-18 11:45:38 +01:00
|
|
|
getopt_long(argc, argv, "v:i:p:t:P:r:6a:fs:F:C:dh", opts,
|
2015-09-10 00:45:29 +02:00
|
|
|
NULL)) != EOF) {
|
|
|
|
switch (optc) {
|
|
|
|
|
|
|
|
/* vrid */
|
|
|
|
case 'v':
|
2015-12-22 09:22:14 +01:00
|
|
|
err = mystrtoul(&opt, optarg, VRID_MAX);
|
|
|
|
if (err == -ERANGE || (err == 0 && opt == 0)) {
|
2015-09-10 00:45:29 +02:00
|
|
|
fprintf(stderr, "1 < vrid < 255\n");
|
|
|
|
vrrp_usage();
|
2015-12-22 09:22:14 +01:00
|
|
|
return err;
|
2015-09-10 00:45:29 +02:00
|
|
|
}
|
2015-12-22 09:22:14 +01:00
|
|
|
if (err == -EINVAL) {
|
|
|
|
fprintf(stderr,
|
|
|
|
"Error parsing \"%s\" as a number\n",
|
|
|
|
optarg);
|
|
|
|
vrrp_usage();
|
|
|
|
return err;
|
|
|
|
}
|
|
|
|
|
2015-09-10 00:45:29 +02:00
|
|
|
vrrp->vrid = vnet->vrid = (uint8_t) opt;
|
|
|
|
break;
|
|
|
|
|
|
|
|
/* interface */
|
|
|
|
case 'i':
|
|
|
|
vnet->vif.ifname = strndup(optarg, IFNAMSIZ);
|
|
|
|
if (vnet->vif.ifname == NULL) {
|
|
|
|
perror("strndup");
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
|
|
|
/* priority */
|
|
|
|
case 'p':
|
2015-12-22 09:22:14 +01:00
|
|
|
err = mystrtoul(&opt, optarg, VRRP_PRIO_MAX);
|
|
|
|
if (err == -ERANGE) {
|
2015-09-10 00:45:29 +02:00
|
|
|
fprintf(stderr, "0 < priority < 255\n");
|
|
|
|
vrrp_usage();
|
|
|
|
return -1;
|
|
|
|
}
|
2015-12-22 09:22:14 +01:00
|
|
|
if (err == -EINVAL) {
|
|
|
|
fprintf(stderr,
|
|
|
|
"Error parsing \"%s\" as a number\n",
|
|
|
|
optarg);
|
|
|
|
vrrp_usage();
|
|
|
|
return err;
|
|
|
|
}
|
|
|
|
|
2015-09-10 00:45:29 +02:00
|
|
|
vrrp->priority = (uint8_t) opt;
|
|
|
|
break;
|
|
|
|
|
|
|
|
/* delay */
|
|
|
|
case 't':
|
2015-12-22 09:22:14 +01:00
|
|
|
err = mystrtoul(&opt, optarg, ADVINT_MAX);
|
|
|
|
if (err == -ERANGE) {
|
2015-09-10 00:45:29 +02:00
|
|
|
vrrp_usage();
|
|
|
|
return -1;
|
|
|
|
}
|
2015-12-22 09:22:14 +01:00
|
|
|
if (err == -EINVAL) {
|
|
|
|
fprintf(stderr,
|
|
|
|
"Error parsing \"%s\" as a number\n",
|
|
|
|
optarg);
|
|
|
|
vrrp_usage();
|
|
|
|
return err;
|
|
|
|
}
|
|
|
|
|
2015-09-10 00:45:29 +02:00
|
|
|
vrrp->adv_int = (uint16_t) opt;
|
|
|
|
break;
|
|
|
|
|
|
|
|
/* preempt mode */
|
|
|
|
case 'P':
|
|
|
|
if (matches(optarg, "on"))
|
|
|
|
vrrp->preempt = TRUE;
|
|
|
|
else if (matches(optarg, "off"))
|
|
|
|
vrrp->preempt = FALSE;
|
|
|
|
else {
|
|
|
|
fprintf(stderr,
|
|
|
|
"preempt mode 'on' or 'off', by default 'on'\n");
|
|
|
|
vrrp_usage();
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
|
|
|
/* RFC - version */
|
|
|
|
case 'r':
|
2015-12-22 09:22:14 +01:00
|
|
|
err = mystrtoul(&opt, optarg, RFC5798);
|
|
|
|
if (err == -ERANGE || (err == 0 && opt < RFC3768)) {
|
|
|
|
fprintf(stderr, "Version 2 or 3 : %s\n", optarg);
|
2015-09-10 00:45:29 +02:00
|
|
|
vrrp_usage();
|
|
|
|
return -1;
|
|
|
|
}
|
2015-12-22 09:22:14 +01:00
|
|
|
if (err == -EINVAL) {
|
|
|
|
fprintf(stderr,
|
|
|
|
"Error parsing \"%s\" as a number\n",
|
|
|
|
optarg);
|
|
|
|
vrrp_usage();
|
|
|
|
return err;
|
|
|
|
}
|
|
|
|
|
2015-09-10 00:45:29 +02:00
|
|
|
vrrp->version = (uint8_t) opt;
|
|
|
|
break;
|
|
|
|
|
|
|
|
/* IPv6 */
|
|
|
|
case '6': /* Force RFC5798/VRRPv3 */
|
|
|
|
vrrp->version = RFC5798;
|
|
|
|
vnet->family = AF_INET6;
|
|
|
|
break;
|
|
|
|
|
|
|
|
/* auth */
|
|
|
|
case 'a': /* only SIMPLE password supported */
|
|
|
|
if (strlen(optarg) > VRRP_AUTH_PASS_LEN) {
|
|
|
|
fprintf(stderr,
|
|
|
|
"Password too long (8 char max)\n");
|
|
|
|
vrrp_usage();
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
vrrp->auth_data = strndup(optarg, VRRP_AUTH_PASS_LEN);
|
|
|
|
vrrp->auth_type = SIMPLE;
|
|
|
|
/* hide passwd from ps */
|
|
|
|
strncpy(optarg, "********", strlen(optarg));
|
|
|
|
break;
|
|
|
|
|
|
|
|
/* foreground */
|
|
|
|
case 'f':
|
|
|
|
background = 0;
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
|
|
/* script */
|
|
|
|
case 's':
|
|
|
|
vrrp->scriptname = strndup(optarg, VRRP_SCRIPT_MAX);
|
|
|
|
if (vrrp->scriptname == NULL) {
|
|
|
|
perror("strndup");
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
2015-09-16 01:21:42 +02:00
|
|
|
/* pidfile */
|
|
|
|
case 'F':
|
|
|
|
pidfile_name = strndup(optarg, NAME_MAX + PATH_MAX);
|
|
|
|
break;
|
|
|
|
|
2016-01-18 11:45:38 +01:00
|
|
|
/* control file (fifo) */
|
|
|
|
case 'C':
|
|
|
|
ctrlfile_name = strndup(optarg, NAME_MAX + PATH_MAX);
|
|
|
|
break;
|
|
|
|
|
2015-09-10 00:45:29 +02:00
|
|
|
/* debug */
|
|
|
|
case 'd':
|
|
|
|
loglevel = strndup("debug", 6);
|
|
|
|
break;
|
|
|
|
|
|
|
|
/* help */
|
|
|
|
case 'h':
|
|
|
|
default:
|
|
|
|
vrrp_usage();
|
|
|
|
return -1;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Fetch virtual IP addresses */
|
|
|
|
if (optind == argc) {
|
|
|
|
fprintf(stderr, "Specify at least one virtual IP addr !\n");
|
|
|
|
vrrp_usage();
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Number of IP addresses */
|
|
|
|
vrrp->naddr = vnet->naddr = argc - optind;
|
|
|
|
|
|
|
|
/* Register vrrp_vip addresses */
|
|
|
|
while (optind != argc) {
|
|
|
|
if (vrrp_net_vip_set(vnet, argv[optind]) != 0) {
|
|
|
|
fprintf(stderr, "Invalid IP\n");
|
|
|
|
vrrp_usage();
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
++optind;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* minimal configuration */
|
|
|
|
if (vrrp->vrid == 0) {
|
|
|
|
fprintf(stderr, "Specify VRRP id\n");
|
|
|
|
vrrp_usage();
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
if (vnet->vif.ifname == NULL) {
|
|
|
|
fprintf(stderr, "Specify VRRP interface\n");
|
|
|
|
vrrp_usage();
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* default adv int */
|
|
|
|
if ((vrrp->version == RFC3768) && (vrrp->adv_int == 0))
|
|
|
|
vrrp->adv_int = 1;
|
2015-09-15 18:34:08 +02:00
|
|
|
else if ((vrrp->version == RFC5798) && (vrrp->adv_int == 0))
|
2015-09-10 00:45:29 +02:00
|
|
|
vrrp->adv_int = 100;
|
|
|
|
|
|
|
|
/* Get IP addresse from interface name */
|
|
|
|
return vrrp_net_vif_getaddr(vnet);
|
|
|
|
}
|