537 lines
11 KiB
C
537 lines
11 KiB
C
/* $OpenBSD: ripctl.c,v 1.17 2016/08/02 16:05:32 jca Exp $
|
|
*
|
|
* Copyright (c) 2006 Michele Marchetto <mydecay@openbeer.it>
|
|
* Copyright (c) 2005 Claudio Jeker <claudio@openbsd.org>
|
|
* Copyright (c) 2004, 2005 Esben Norby <norby@openbsd.org>
|
|
* Copyright (c) 2003 Henning Brauer <henning@openbsd.org>
|
|
*
|
|
* Permission to use, copy, modify, and distribute this software for any
|
|
* purpose with or without fee is hereby granted, provided that the above
|
|
* copyright notice and this permission notice appear in all copies.
|
|
*
|
|
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
|
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
|
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
|
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
|
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
|
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
|
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
|
*/
|
|
|
|
#include <sys/types.h>
|
|
#include <sys/socket.h>
|
|
#include <sys/un.h>
|
|
#include <netinet/in.h>
|
|
#include <arpa/inet.h>
|
|
#include <net/if_media.h>
|
|
#include <net/if_types.h>
|
|
|
|
#include <err.h>
|
|
#include <errno.h>
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#include <string.h>
|
|
#include <unistd.h>
|
|
|
|
#include "rip.h"
|
|
#include "ripd.h"
|
|
#include "ripe.h"
|
|
#include "parser.h"
|
|
|
|
__dead void usage(void);
|
|
const char *fmt_timeframe_core(time_t);
|
|
const char *get_linkstate(uint8_t, int);
|
|
int show_interface_msg(struct imsg *);
|
|
uint64_t get_ifms_type(uint8_t);
|
|
int show_rib_msg(struct imsg *);
|
|
int show_nbr_msg(struct imsg *);
|
|
void show_fib_head(void);
|
|
int show_fib_msg(struct imsg *);
|
|
void show_interface_head(void);
|
|
int show_fib_interface_msg(struct imsg *);
|
|
const char *get_media_descr(uint64_t);
|
|
void print_baudrate(uint64_t);
|
|
|
|
struct imsgbuf *ibuf;
|
|
|
|
__dead void
|
|
usage(void)
|
|
{
|
|
extern char *__progname;
|
|
|
|
fprintf(stderr, "usage: %s [-s socket] command [argument ...]\n",
|
|
__progname);
|
|
exit(1);
|
|
}
|
|
|
|
int
|
|
main(int argc, char *argv[])
|
|
{
|
|
struct sockaddr_un sun;
|
|
struct parse_result *res;
|
|
struct imsg imsg;
|
|
unsigned int ifidx = 0;
|
|
int ctl_sock;
|
|
int done = 0, verbose = 0;
|
|
int n;
|
|
int ch;
|
|
char *sockname = RIPD_SOCKET;
|
|
|
|
while ((ch = getopt(argc, argv, "s:")) != -1) {
|
|
switch (ch) {
|
|
case 's':
|
|
sockname = optarg;
|
|
break;
|
|
default:
|
|
usage();
|
|
/* NOTREACHED */
|
|
}
|
|
}
|
|
|
|
argc -= optind;
|
|
argv += optind;
|
|
|
|
/* parse options */
|
|
if ((res = parse(argc, argv)) == NULL)
|
|
exit(1);
|
|
|
|
/* connect to ripd control socket */
|
|
if ((ctl_sock = socket(AF_UNIX, SOCK_STREAM, 0)) == -1)
|
|
err(1, "socket");
|
|
|
|
bzero(&sun, sizeof(sun));
|
|
sun.sun_family = AF_UNIX;
|
|
strlcpy(sun.sun_path, sockname, sizeof(sun.sun_path));
|
|
if (connect(ctl_sock, (struct sockaddr *)&sun, sizeof(sun)) == -1)
|
|
err(1, "connect: %s", sockname);
|
|
|
|
if (pledge("stdio", NULL) == -1)
|
|
err(1, "pledge");
|
|
|
|
if ((ibuf = malloc(sizeof(struct imsgbuf))) == NULL)
|
|
err(1, NULL);
|
|
imsg_init(ibuf, ctl_sock);
|
|
done = 0;
|
|
|
|
/* process user request */
|
|
switch (res->action) {
|
|
case NONE:
|
|
usage();
|
|
/* not reached */
|
|
case SHOW:
|
|
case SHOW_IFACE:
|
|
printf("%-11s %-18s %-10s %-10s %-8s\n",
|
|
"Interface", "Address", "State", "Linkstate",
|
|
"Uptime");
|
|
if (*res->ifname) {
|
|
ifidx = if_nametoindex(res->ifname);
|
|
if (ifidx == 0)
|
|
errx(1, "no such interface %s", res->ifname);
|
|
}
|
|
imsg_compose(ibuf, IMSG_CTL_SHOW_INTERFACE, 0, 0, -1,
|
|
&ifidx, sizeof(ifidx));
|
|
break;
|
|
case SHOW_NBR:
|
|
printf("%-15s %-15s %-15s %-9s %-10s\n", "ID",
|
|
"State", "Address", "Iface", "Uptime");
|
|
imsg_compose(ibuf, IMSG_CTL_SHOW_NBR, 0, 0, -1, NULL, 0);
|
|
break;
|
|
case SHOW_RIB:
|
|
printf("%-20s %-17s %-7s\n", "Destination",
|
|
"Nexthop", "Cost");
|
|
imsg_compose(ibuf, IMSG_CTL_SHOW_RIB, 0, 0, -1, NULL, 0);
|
|
break;
|
|
case SHOW_FIB:
|
|
if (!res->addr.s_addr)
|
|
imsg_compose(ibuf, IMSG_CTL_KROUTE, 0, 0, -1,
|
|
&res->flags, sizeof(res->flags));
|
|
else
|
|
imsg_compose(ibuf, IMSG_CTL_KROUTE_ADDR, 0, 0, -1,
|
|
&res->addr, sizeof(res->addr));
|
|
show_fib_head();
|
|
break;
|
|
case SHOW_FIB_IFACE:
|
|
if (*res->ifname)
|
|
imsg_compose(ibuf, IMSG_CTL_IFINFO, 0, 0, -1,
|
|
res->ifname, sizeof(res->ifname));
|
|
else
|
|
imsg_compose(ibuf, IMSG_CTL_IFINFO, 0, 0, -1, NULL, 0);
|
|
show_interface_head();
|
|
break;
|
|
case FIB:
|
|
errx(1, "fib couple|decouple");
|
|
break;
|
|
case FIB_COUPLE:
|
|
imsg_compose(ibuf, IMSG_CTL_FIB_COUPLE, 0, 0, -1, NULL, 0);
|
|
printf("couple request sent.\n");
|
|
done = 1;
|
|
break;
|
|
case FIB_DECOUPLE:
|
|
imsg_compose(ibuf, IMSG_CTL_FIB_DECOUPLE, 0, 0, -1, NULL, 0);
|
|
printf("decouple request sent.\n");
|
|
done = 1;
|
|
break;
|
|
case LOG_VERBOSE:
|
|
verbose = 1;
|
|
/* FALLTHROUGH */
|
|
case LOG_BRIEF:
|
|
imsg_compose(ibuf, IMSG_CTL_LOG_VERBOSE, 0, 0, -1,
|
|
&verbose, sizeof(verbose));
|
|
printf("logging request sent.\n");
|
|
done = 1;
|
|
break;
|
|
case RELOAD:
|
|
imsg_compose(ibuf, IMSG_CTL_RELOAD, 0, 0, -1, NULL, 0);
|
|
printf("reload request sent.\n");
|
|
done = 1;
|
|
break;
|
|
}
|
|
|
|
while (ibuf->w.queued)
|
|
if (msgbuf_write(&ibuf->w) <= 0 && errno != EAGAIN)
|
|
err(1, "write error");
|
|
|
|
while (!done) {
|
|
if ((n = imsg_read(ibuf)) == -1 && errno != EAGAIN)
|
|
errx(1, "imsg_read error");
|
|
if (n == 0)
|
|
errx(1, "pipe closed");
|
|
|
|
while (!done) {
|
|
if ((n = imsg_get(ibuf, &imsg)) == -1)
|
|
errx(1, "imsg_get error");
|
|
if (n == 0)
|
|
break;
|
|
switch (res->action) {
|
|
case SHOW:
|
|
case SHOW_IFACE:
|
|
done = show_interface_msg(&imsg);
|
|
break;
|
|
case SHOW_NBR:
|
|
done = show_nbr_msg(&imsg);
|
|
break;
|
|
case SHOW_RIB:
|
|
done = show_rib_msg(&imsg);
|
|
break;
|
|
case SHOW_FIB:
|
|
done = show_fib_msg(&imsg);
|
|
break;
|
|
case SHOW_FIB_IFACE:
|
|
done = show_fib_interface_msg(&imsg);
|
|
break;
|
|
case NONE:
|
|
case FIB:
|
|
case FIB_COUPLE:
|
|
case FIB_DECOUPLE:
|
|
case LOG_VERBOSE:
|
|
case LOG_BRIEF:
|
|
case RELOAD:
|
|
break;
|
|
}
|
|
imsg_free(&imsg);
|
|
}
|
|
}
|
|
close(ctl_sock);
|
|
free(ibuf);
|
|
|
|
return (0);
|
|
}
|
|
|
|
uint64_t
|
|
get_ifms_type(uint8_t if_type)
|
|
{
|
|
switch (if_type) {
|
|
case IFT_ETHER:
|
|
return (IFM_ETHER);
|
|
break;
|
|
case IFT_FDDI:
|
|
return (IFM_FDDI);
|
|
break;
|
|
case IFT_CARP:
|
|
return (IFM_CARP);
|
|
break;
|
|
default:
|
|
return (0);
|
|
break;
|
|
}
|
|
}
|
|
|
|
#define TF_BUFS 8
|
|
#define TF_LEN 9
|
|
|
|
const char *
|
|
fmt_timeframe_core(time_t t)
|
|
{
|
|
char *buf;
|
|
static char tfbuf[TF_BUFS][TF_LEN]; /* ring buffer */
|
|
static int idx = 0;
|
|
unsigned int sec, min, hrs, day;
|
|
unsigned long long week;
|
|
|
|
if (t == 0)
|
|
return ("Stopped");
|
|
|
|
buf = tfbuf[idx++];
|
|
if (idx == TF_BUFS)
|
|
idx = 0;
|
|
|
|
week = t;
|
|
|
|
sec = week % 60;
|
|
week /= 60;
|
|
min = week % 60;
|
|
week /= 60;
|
|
hrs = week % 24;
|
|
week /= 24;
|
|
day = week % 7;
|
|
week /= 7;
|
|
|
|
if (week > 0)
|
|
snprintf(buf, TF_LEN, "%02lluw%01ud%02uh", week, day, hrs);
|
|
else if (day > 0)
|
|
snprintf(buf, TF_LEN, "%01ud%02uh%02um", day, hrs, min);
|
|
else
|
|
snprintf(buf, TF_LEN, "%02u:%02u:%02u", hrs, min, sec);
|
|
|
|
return (buf);
|
|
}
|
|
|
|
/* prototype defined in ripd.h and shared with the kroute.c version */
|
|
u_int8_t
|
|
mask2prefixlen(in_addr_t ina)
|
|
{
|
|
if (ina == 0)
|
|
return (0);
|
|
else
|
|
return (33 - ffs(ntohl(ina)));
|
|
}
|
|
|
|
int
|
|
show_interface_msg(struct imsg *imsg)
|
|
{
|
|
struct ctl_iface *iface;
|
|
char *netid;
|
|
|
|
switch (imsg->hdr.type) {
|
|
case IMSG_CTL_SHOW_IFACE:
|
|
iface = imsg->data;
|
|
|
|
if (asprintf(&netid, "%s/%d", inet_ntoa(iface->addr),
|
|
mask2prefixlen(iface->mask.s_addr)) == -1)
|
|
err(1, NULL);
|
|
printf("%-11s %-18s %-10s %-10s %-8s\n",
|
|
iface->name, netid, if_state_name(iface->state),
|
|
get_linkstate(iface->if_type, iface->linkstate),
|
|
iface->uptime == 0 ? "00:00:00" :
|
|
fmt_timeframe_core(iface->uptime));
|
|
free(netid);
|
|
break;
|
|
case IMSG_CTL_END:
|
|
printf("\n");
|
|
return (1);
|
|
default:
|
|
break;
|
|
}
|
|
|
|
return (0);
|
|
}
|
|
|
|
int
|
|
show_rib_msg(struct imsg *imsg)
|
|
{
|
|
struct ctl_rt *rt;
|
|
char *dstnet;
|
|
|
|
switch (imsg->hdr.type) {
|
|
case IMSG_CTL_SHOW_RIB:
|
|
rt = imsg->data;
|
|
if (asprintf(&dstnet, "%s/%d", inet_ntoa(rt->prefix),
|
|
mask2prefixlen(rt->netmask.s_addr)) == -1)
|
|
err(1, NULL);
|
|
|
|
printf("%-20s %-17s %-7d\n", dstnet,
|
|
inet_ntoa(rt->nexthop),
|
|
rt->metric);
|
|
free(dstnet);
|
|
|
|
break;
|
|
case IMSG_CTL_END:
|
|
printf("\n");
|
|
return (1);
|
|
default:
|
|
break;
|
|
}
|
|
|
|
return (0);
|
|
}
|
|
|
|
int
|
|
show_nbr_msg(struct imsg *imsg)
|
|
{
|
|
struct ctl_nbr *nbr;
|
|
char *state;
|
|
|
|
switch (imsg->hdr.type) {
|
|
case IMSG_CTL_SHOW_NBR:
|
|
nbr = imsg->data;
|
|
if (asprintf(&state, "%s/%s", nbr_state_name(nbr->nbr_state),
|
|
if_state_name(nbr->iface_state)) == -1)
|
|
err(1, NULL);
|
|
printf("%-15s %-16s", inet_ntoa(nbr->id),
|
|
state);
|
|
printf("%-15s %-10s", inet_ntoa(nbr->addr), nbr->name);
|
|
printf("%-15s\n", nbr->uptime == 0 ? "-" :
|
|
fmt_timeframe_core(nbr->uptime));
|
|
free(state);
|
|
break;
|
|
case IMSG_CTL_END:
|
|
printf("\n");
|
|
return (1);
|
|
default:
|
|
break;
|
|
}
|
|
|
|
return (0);
|
|
}
|
|
|
|
void
|
|
show_fib_head(void)
|
|
{
|
|
printf("flags: * = valid, R = RIP, C = Connected, S = Static\n");
|
|
printf("%-6s %-20s %-17s\n", "Flags", "Destination", "Nexthop");
|
|
}
|
|
|
|
int
|
|
show_fib_msg(struct imsg *imsg)
|
|
{
|
|
struct kroute *k;
|
|
char *p;
|
|
|
|
switch (imsg->hdr.type) {
|
|
case IMSG_CTL_KROUTE:
|
|
if (imsg->hdr.len < IMSG_HEADER_SIZE + sizeof(struct kroute))
|
|
errx(1, "wrong imsg len");
|
|
k = imsg->data;
|
|
|
|
if (k->flags & F_DOWN)
|
|
printf(" ");
|
|
else
|
|
printf("*");
|
|
|
|
if (k->flags & F_RIPD_INSERTED)
|
|
printf("R");
|
|
else if (k->flags & F_CONNECTED)
|
|
printf("C");
|
|
else if (k->flags & F_STATIC)
|
|
printf("S");
|
|
else
|
|
printf(" ");
|
|
|
|
printf(" ");
|
|
if (asprintf(&p, "%s/%u", inet_ntoa(k->prefix),
|
|
mask2prefixlen(k->netmask.s_addr)) == -1)
|
|
err(1, NULL);
|
|
printf("%-20s ", p);
|
|
free(p);
|
|
|
|
if (k->nexthop.s_addr)
|
|
printf("%s", inet_ntoa(k->nexthop));
|
|
else if (k->flags & F_CONNECTED)
|
|
printf("link#%u", k->ifindex);
|
|
printf("\n");
|
|
|
|
break;
|
|
case IMSG_CTL_END:
|
|
printf("\n");
|
|
return (1);
|
|
default:
|
|
break;
|
|
}
|
|
|
|
return (0);
|
|
}
|
|
|
|
void
|
|
show_interface_head(void)
|
|
{
|
|
printf("%-15s%-15s%s\n", "Interface", "Flags",
|
|
"Link state");
|
|
}
|
|
|
|
int
|
|
show_fib_interface_msg(struct imsg *imsg)
|
|
{
|
|
struct kif *k;
|
|
uint64_t ifms_type;
|
|
|
|
switch (imsg->hdr.type) {
|
|
case IMSG_CTL_IFINFO:
|
|
k = imsg->data;
|
|
printf("%-15s", k->ifname);
|
|
printf("%-15s", k->flags & IFF_UP ? "UP" : "");
|
|
ifms_type = get_ifms_type(k->if_type);
|
|
if (ifms_type)
|
|
printf("%s, ", get_media_descr(ifms_type));
|
|
|
|
printf("%s", get_linkstate(k->if_type, k->link_state));
|
|
|
|
if (k->link_state != LINK_STATE_DOWN && k->baudrate > 0) {
|
|
printf(", ");
|
|
print_baudrate(k->baudrate);
|
|
}
|
|
printf("\n");
|
|
break;
|
|
case IMSG_CTL_END:
|
|
printf("\n");
|
|
return (1);
|
|
default:
|
|
break;
|
|
}
|
|
|
|
return (0);
|
|
}
|
|
|
|
const struct if_status_description
|
|
if_status_descriptions[] = LINK_STATE_DESCRIPTIONS;
|
|
const struct ifmedia_description
|
|
ifm_type_descriptions[] = IFM_TYPE_DESCRIPTIONS;
|
|
|
|
const char *
|
|
get_media_descr(uint64_t media_type)
|
|
{
|
|
const struct ifmedia_description *p;
|
|
|
|
for (p = ifm_type_descriptions; p->ifmt_string != NULL; p++)
|
|
if (media_type == p->ifmt_word)
|
|
return (p->ifmt_string);
|
|
|
|
return ("unknown");
|
|
}
|
|
|
|
const char *
|
|
get_linkstate(uint8_t if_type, int link_state)
|
|
{
|
|
const struct if_status_description *p;
|
|
static char buf[8];
|
|
|
|
for (p = if_status_descriptions; p->ifs_string != NULL; p++) {
|
|
if (LINK_STATE_DESC_MATCH(p, if_type, link_state))
|
|
return (p->ifs_string);
|
|
}
|
|
snprintf(buf, sizeof(buf), "[#%d]", link_state);
|
|
return (buf);
|
|
}
|
|
|
|
void
|
|
print_baudrate(uint64_t baudrate)
|
|
{
|
|
if (baudrate > IF_Gbps(1))
|
|
printf("%llu GBit/s", baudrate / IF_Gbps(1));
|
|
else if (baudrate > IF_Mbps(1))
|
|
printf("%llu MBit/s", baudrate / IF_Mbps(1));
|
|
else if (baudrate > IF_Kbps(1))
|
|
printf("%llu KBit/s", baudrate / IF_Kbps(1));
|
|
else
|
|
printf("%llu Bit/s", baudrate);
|
|
}
|