#include <sys/types.h>
#include <sys/socket.h>
#include <sys/un.h>
#include <netinet/in.h>
#include <netinet/ip_mroute.h>
#include <arpa/inet.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 "igmp.h"
#include "dvmrp.h"
#include "dvmrpd.h"
#include "dvmrpe.h"
#include "parser.h"
#include "log.h"
__dead void usage(void);
int show_summary_msg(struct imsg *);
int show_interface_msg(struct imsg *);
int show_interface_detail_msg(struct imsg *);
int show_igmp_msg(struct imsg *);
const char *print_if_type(enum iface_type type);
const char *print_nbr_state(int);
const char *print_link(int);
const char *fmt_timeframe(time_t t);
const char *fmt_timeframe_core(time_t t);
int show_nbr_msg(struct imsg *);
const char *print_dvmrp_options(u_int8_t);
int show_nbr_detail_msg(struct imsg *);
int show_rib_msg(struct imsg *);
int show_rib_detail_msg(struct imsg *);
int show_mfc_msg(struct imsg *);
int show_mfc_detail_msg(struct imsg *);
const char * get_linkstate(uint8_t, int);
struct imsgbuf *ibuf;
__dead void
usage(void)
{
extern char *__progname;
fprintf(stderr, "usage: %s 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;
if ((res = parse(argc - 1, argv + 1)) == NULL)
exit(1);
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, DVMRPD_SOCKET, sizeof(sun.sun_path));
if (connect(ctl_sock, (struct sockaddr *)&sun, sizeof(sun)) == -1)
err(1, "connect: %s", DVMRPD_SOCKET);
if (pledge("stdio", NULL) == -1)
err(1, "pledge");
if ((ibuf = malloc(sizeof(struct imsgbuf))) == NULL)
fatal(NULL);
if (imsgbuf_init(ibuf, ctl_sock) == -1)
fatal(NULL);
done = 0;
switch (res->action) {
case NONE:
usage();
case SHOW:
case SHOW_SUM:
imsg_compose(ibuf, IMSG_CTL_SHOW_SUM, 0, 0, -1, NULL, 0);
break;
case SHOW_IFACE:
printf("%-11s %-18s %-10s %-10s %-10s %-8s %s\n",
"Interface", "Address", "State", "ProbeTimer", "Linkstate",
"Uptime", "Groups");
case SHOW_IFACE_DTAIL:
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_IFACE, 0, 0, -1, &ifidx,
sizeof(ifidx));
break;
case SHOW_IGMP:
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_IGMP, 0, 0, -1, &ifidx,
sizeof(ifidx));
break;
case SHOW_NBR:
printf("%-15s %-10s %-9s %-15s %-11s %-8s\n", "ID", "State",
"DeadTime", "Address", "Interface", "Uptime");
case SHOW_NBR_DTAIL:
imsg_compose(ibuf, IMSG_CTL_SHOW_NBR, 0, 0, -1, NULL, 0);
break;
case SHOW_RIB:
printf("%-20s %-17s %-7s %-10s %-s\n", "Destination", "Nexthop",
"Cost", "Uptime", "Expire");
case SHOW_RIB_DTAIL:
imsg_compose(ibuf, IMSG_CTL_SHOW_RIB, 0, 0, -1, NULL, 0);
break;
case SHOW_MFC:
printf("%-16s %-16s %-9s %-9s %-4s %-10s %-10s\n", "Group",
"Origin", "Incoming", "Outgoing", "TTL", "Uptime",
"Expire");
case SHOW_MFC_DTAIL:
imsg_compose(ibuf, IMSG_CTL_SHOW_MFC, 0, 0, -1, NULL, 0);
break;
case LOG_VERBOSE:
verbose = 1;
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;
}
if (imsgbuf_flush(ibuf) == -1)
err(1, "write error");
while (!done) {
if ((n = imsgbuf_read(ibuf)) == -1)
err(1, "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_SUM:
done = show_summary_msg(&imsg);
break;
case SHOW_IFACE:
done = show_interface_msg(&imsg);
break;
case SHOW_IFACE_DTAIL:
done = show_interface_detail_msg(&imsg);
break;
case SHOW_IGMP:
done = show_igmp_msg(&imsg);
break;
case SHOW_NBR:
done = show_nbr_msg(&imsg);
break;
case SHOW_NBR_DTAIL:
done = show_nbr_detail_msg(&imsg);
break;
case SHOW_RIB:
done = show_rib_msg(&imsg);
break;
case SHOW_RIB_DTAIL:
done = show_rib_detail_msg(&imsg);
break;
case SHOW_MFC:
done = show_mfc_msg(&imsg);
break;
case SHOW_MFC_DTAIL:
done = show_mfc_detail_msg(&imsg);
break;
case NONE:
case LOG_VERBOSE:
case LOG_BRIEF:
case RELOAD:
break;
}
imsg_free(&imsg);
}
}
close(ctl_sock);
free(ibuf);
return (0);
}
int
show_summary_msg(struct imsg *imsg)
{
struct ctl_sum *sum;
switch (imsg->hdr.type) {
case IMSG_CTL_SHOW_SUM:
sum = imsg->data;
printf("Router ID: %s\n", inet_ntoa(sum->rtr_id));
printf("Hold time is %d sec(s)\n", sum->hold_time);
break;
case IMSG_CTL_END:
printf("\n");
return (1);
default:
break;
}
return (0);
}
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 %-10s %-8s %5d\n",
iface->name, netid, if_state_name(iface->state),
iface->probe_timer == 0 ? "00:00:00" :
fmt_timeframe_core(iface->probe_timer),
get_linkstate(iface->if_type, iface->linkstate),
iface->uptime == 0 ? "00:00:00" :
fmt_timeframe_core(iface->uptime), iface->group_cnt);
free(netid);
break;
case IMSG_CTL_END:
printf("\n");
return (1);
default:
break;
}
return (0);
}
int
show_interface_detail_msg(struct imsg *imsg)
{
struct ctl_iface *iface;
switch (imsg->hdr.type) {
case IMSG_CTL_SHOW_IFACE:
iface = imsg->data;
printf("\n");
printf("Interface %s, line protocol is %s\n",
iface->name, print_link(iface->flags));
printf(" Internet address %s/%d\n",
inet_ntoa(iface->addr),
mask2prefixlen(iface->mask.s_addr));
printf(" Linkstate %s\n",
get_linkstate(iface->if_type, iface->linkstate));
printf(" Network type %s, cost: %d\n",
if_type_name(iface->type), iface->metric);
printf(" State %s, querier ", if_state_name(iface->state));
if (iface->state == IF_STA_QUERIER)
printf("%s\n", inet_ntoa(iface->addr));
else
printf("%s\n", inet_ntoa(iface->querier));
printf(" Generation ID %d\n", iface->gen_id);
printf(" Timer intervals configured, "
"probe %d, dead %d\n", iface->probe_interval,
iface->dead_interval);
if (iface->passive)
printf(" Passive interface (No Hellos)\n");
else if (iface->probe_timer < 0)
printf(" Hello timer not running\n");
else
printf(" Hello timer due in %s\n",
fmt_timeframe_core(iface->probe_timer));
printf(" Uptime %s\n", iface->uptime == 0 ?
"00:00:00" : fmt_timeframe_core(iface->uptime));
printf(" Adjacent neighbor count is "
"%d\n", iface->adj_cnt);
break;
case IMSG_CTL_END:
printf("\n");
return (1);
default:
break;
}
return (0);
}
int
show_igmp_msg(struct imsg *imsg)
{
struct ctl_iface *iface;
struct ctl_group *group;
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("\nInterface %s, address %s, state %s, groups %d\n",
iface->name, netid, if_state_name(iface->state),
iface->group_cnt);
free(netid);
printf(" %-16s %-10s %-10s %-10s\n", "Group", "State",
"DeadTimer", "Uptime");
break;
case IMSG_CTL_SHOW_IGMP:
group = imsg->data;
printf(" %-16s %-10s %-10s %-10s\n", inet_ntoa(group->addr),
group_state_name(group->state),
group->dead_timer == 0 ? "00:00:00" :
fmt_timeframe_core(group->dead_timer),
group->uptime == 0 ? "00:00:00" :
fmt_timeframe_core(group->uptime));
break;
case IMSG_CTL_END:
printf("\n");
return (1);
default:
break;
}
return (0);
}
const char *
print_if_type(enum iface_type type)
{
switch (type) {
case IF_TYPE_POINTOPOINT:
return ("POINTOPOINT");
case IF_TYPE_BROADCAST:
return ("BROADCAST");
default:
return ("UNKNOWN");
}
}
const char *
print_nbr_state(int state)
{
switch (state) {
case NBR_STA_DOWN:
return ("DOWN");
case NBR_STA_1_WAY:
return ("1-WAY");
case NBR_STA_2_WAY:
return ("2-WAY");
default:
return ("UNKNOWN");
}
}
const char *
print_link(int state)
{
if (state & IFF_UP)
return ("UP");
else
return ("DOWN");
}
#define TF_BUFS 8
#define TF_LEN 9
const char *
fmt_timeframe(time_t t)
{
if (t == 0)
return ("Never");
else
return (fmt_timeframe_core(time(NULL) - t));
}
const char *
fmt_timeframe_core(time_t t)
{
char *buf;
static char tfbuf[TF_BUFS][TF_LEN];
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);
}
u_int8_t
mask2prefixlen(in_addr_t ina)
{
if (ina == 0)
return (0);
else
return (33 - ffs(ntohl(ina)));
}
int
show_nbr_msg(struct imsg *imsg)
{
struct ctl_nbr *nbr;
switch (imsg->hdr.type) {
case IMSG_CTL_SHOW_NBR:
nbr = imsg->data;
printf("%-15s %-10s %-10s", inet_ntoa(nbr->id),
print_nbr_state(nbr->state),
fmt_timeframe_core(nbr->dead_timer));
printf("%-15s %-11s %s\n", inet_ntoa(nbr->addr),
nbr->name, fmt_timeframe_core(nbr->uptime));
break;
case IMSG_CTL_END:
printf("\n");
return (1);
default:
break;
}
return (0);
}
const char *
print_dvmrp_options(u_int8_t opts)
{
static char optbuf[32];
snprintf(optbuf, sizeof(optbuf), "*|*|%s|%s|%s|%s|%s|%s",
opts & DVMRP_CAP_NETMASK ? "N" : "-",
opts & DVMRP_CAP_SNMP ? "S" : "-",
opts & DVMRP_CAP_MTRACE ? "M" : "-",
opts & DVMRP_CAP_GENID ? "G" : "-",
opts & DVMRP_CAP_PRUNE ? "P" : "-",
opts & DVMRP_CAP_LEAF ? "L" : "-");
return (optbuf);
}
int
show_nbr_detail_msg(struct imsg *imsg)
{
switch (imsg->hdr.type) {
case IMSG_CTL_SHOW_NBR:
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),
rt->prefixlen) == -1)
err(1, NULL);
printf("%-20s %-17s %-7d %-9s %9s\n", dstnet,
inet_ntoa(rt->nexthop),
rt->cost, rt->uptime == 0 ? "-" :
fmt_timeframe_core(rt->uptime),
rt->expire == 0 ? "00:00:00" :
fmt_timeframe_core(rt->expire));
free(dstnet);
break;
case IMSG_CTL_END:
printf("\n");
return (1);
default:
break;
}
return (0);
}
int
show_rib_detail_msg(struct imsg *imsg)
{
switch (imsg->hdr.type) {
case IMSG_CTL_SHOW_RIB:
break;
case IMSG_CTL_END:
printf("\n");
return (1);
default:
break;
}
return (0);
}
int
show_mfc_msg(struct imsg *imsg)
{
char iname[IF_NAMESIZE];
char oname[IF_NAMESIZE] = "-";
struct ctl_mfc *mfc;
int i;
switch (imsg->hdr.type) {
case IMSG_CTL_SHOW_MFC:
mfc = imsg->data;
if_indextoname(mfc->ifindex, iname);
for (i = 0; i < MAXVIFS; i++) {
if (mfc->ttls[i] > 0) {
if_indextoname(i, oname);
i++;
break;
}
}
printf("%-16s ", inet_ntoa(mfc->group));
printf("%-16s %-9s %-9s %-4d %-10s %-10s\n",
inet_ntoa(mfc->origin), iname, oname, mfc->ttls[i - 1],
mfc->uptime == 0 ? "-" : fmt_timeframe_core(mfc->uptime),
mfc->expire == 0 ? "-" : fmt_timeframe_core(mfc->expire));
for (; i < MAXVIFS; i++) {
if (mfc->ttls[i] > 0) {
if_indextoname(i, oname);
printf("%43s %-9s %-4d\n", " ", oname,
mfc->ttls[i]);
}
}
break;
case IMSG_CTL_END:
printf("\n");
return (1);
default:
break;
}
return (0);
}
int
show_mfc_detail_msg(struct imsg *imsg)
{
switch (imsg->hdr.type) {
case IMSG_CTL_SHOW_MFC:
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 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);
}