Edit

IABSD.fr/src/usr.sbin/ripctl/ripctl.c

Branch :

  • Show log

    Commit

  • Author : jca
    Date : 2016-08-02 16:05:32
    Hash : 3dabc796
    Message : Allow specifying an alternate socket path. This allows one to run multiple ripd instances, for example to serve multiple rdomains. Diff from Nima GHOTBI, ok claudio@ florian@ benno@

  • usr.sbin/ripctl/ripctl.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);
    }