commit f943f99c53a154c97b93aaff0c6147d40bd8de82 from: Stefan Sperling date: Wed May 31 19:37:23 2023 UTC add bgpnsh "please commit" chris@ commit - 2cbf96e394f7a7decbae2f8a6829b8cddd03536b commit + f943f99c53a154c97b93aaff0c6147d40bd8de82 blob - cb93dae29f883f57ee923b60a332edcaf8749fa6 blob + d0ea33ff297130b499703d8f068c954783abcdb3 --- Makefile +++ Makefile @@ -1,6 +1,8 @@ # PROG= nsh +SUBDIR += bgpnsh + .PHONY: release dist .include "nsh-version.mk" @@ -23,11 +25,12 @@ CFLAGS?=-O CFLAGS+=-Wmissing-prototypes -Wformat -Wall -Wbad-function-cast -I/usr/local/include #-W -Wpointer-arith CPPFLAGS+=-DNSH_VERSION=${NSH_VERSION} -DNSH_REXEC_PATH=${NSH_REXEC_PATH} -SRCS=arp.c compile.c main.c genget.c commands.c stats.c kroute.c +SRCS=arp.c compile.c main.c genget.c commands.c bgpcommands.c stats.c kroute.c SRCS+=ctl.c show.c if.c version.c route.c conf.c complete.c ieee80211.c SRCS+=bridge.c tunnel.c media.c sysctl.c passwd.c pfsync.c carp.c -SRCS+=trunk.c who.c more.c stringlist.c utils.c sqlite3.c ppp.c -SRCS+=nopt.c pflow.c wg.c nameserver.c ndp.c umb.c utf8.c +SRCS+=trunk.c who.c more.c stringlist.c utils.c sqlite3.c ppp.c prompt.c +SRCS+=nopt.c pflow.c wg.c nameserver.c ndp.c umb.c utf8.c cmdargs.c ctlargs.c +SRCS+=helpcommands.c makeargv.c CLEANFILES+=compile.c LDADD=-lutil -ledit -ltermcap -lsqlite3 -L/usr/local/lib #-static @@ -55,3 +58,4 @@ dist: clean rm ${.CURDIR}/nsh-dist.txt.new .include +.include blob - /dev/null blob + 1f466aefdc939449c3b12b9646e9c5a6a53a1353 (mode 644) --- /dev/null +++ bgpcommands.c @@ -0,0 +1,58 @@ +/* + * Copyright (c) 2008-2009 Chris Cappuccio + * Copyright (c) 2023 Stefan Sperling + * + * 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 /* MAXHOSTNAMELEN */ +#include /* IFNAMSIZ */ + +#include + +#include +#include + +#include "externs.h" +#include "commands.h" +#include "ctl.h" + +char bgpd_socket_path[PATH_MAX]; + +#define BGPSOCK "-s", bgpd_socket_path + +struct prot1 bgcs[] = { + { "announced", "All announced networks", + { BGPCTL, BGPSOCK, "network", "show", OPT, NULL } }, + { "interfaces", "Interface states", + { BGPCTL, BGPSOCK, "show", "interfaces", NULL } }, + { "nexthop", "BGP nexthop routes", + { BGPCTL, BGPSOCK, "show", "nexthop", NULL } }, + { "summary", "Neighbor session states and counters", + { BGPCTL, BGPSOCK, "show", "summary", OPT, NULL } }, + { "rib", "Routing Information Base", + { BGPCTL, BGPSOCK, "show", "rib", OPT, OPT, OPT, NULL } }, + { "neighbor", "Detailed peer", + { BGPCTL, BGPSOCK, "show", "neighbor", REQ, OPT, NULL } }, + { "ip", "IP BGP", + { BGPCTL, BGPSOCK, "show", "ip", "bgp", OPT, OPT, OPT, NULL } }, + { 0, 0, { 0 } } +}; + +/* Initialize the globally stored BGPD socket path. */ +void +init_bgpd_socket_path(int rtable) +{ + snprintf(bgpd_socket_path, sizeof(bgpd_socket_path), + "%s.%d", BGPD_SOCKET_PATH, rtable); +} blob - /dev/null blob + 66fa671ac5ac8390f2891dc49b5bc3f1b2b477f3 (mode 644) --- /dev/null +++ bgpnsh/.gitignore @@ -0,0 +1 @@ +obj/** blob - /dev/null blob + d4f2f7232f6db50ce16ca840c67378a609085eb5 (mode 644) --- /dev/null +++ bgpnsh/Makefile @@ -0,0 +1,32 @@ +# +PROG= bgpnsh + +.PATH=${.CURDIR}/.. + +.include "../nsh-version.mk" + +.if ${NSH_RELEASE} != Yes +DEBUG?=-O0 -g +.endif + +.if make(install) +DESTDIR?=/usr/local +BINDIR?=/bin +MANDIR?=/man/man +.endif + +CFLAGS+=-Wmissing-prototypes -Wformat -Wall -Wbad-function-cast +CPPFLAGS+=-DNSH_VERSION=${NSH_VERSION} + +SRCS=bgpnsh.c compile.c bgpcommands.c complete.c genget.c more.c \ + stringlist.c utf8.c stubs.c cmdargs.c ctlargs.c prompt.c \ + helpcommands.c makeargv.c +CLEANFILES+=compile.c +LDADD=-lutil -ledit -ltermcap + +MAN=bgpnsh.8 + +compile.c: compile.sh + sh ${.CURDIR}/../compile.sh + +.include blob - /dev/null blob + 526a5088941e553ced275539ec25a922a24d03d6 (mode 644) --- /dev/null +++ bgpnsh/bgpnsh.8 @@ -0,0 +1,64 @@ + +.\" Copyright (c) 2023 Stefan Sperling +.\" +.\" 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. +.\" +.Dd $Mdocdate$ +.Dt BGPNSH 1 +.Os +.Sh NAME +.Nm bgpnsh +.Nd BGP Looking Glass Network Shell +.Sh SYNOPSIS +.Nm +.Sh DESCRIPTION +.Nm +is a command interpreter intended for interactive use as a BGP +Looking Glass shell for routers running +.Xr bgpd 8 . +.Pp +.Nm +is an alternative to +.Xr bgplgsh 1 +with a user interface that matches the user interface of +.Xr nsh 8 . +.Pp +All functionality of +.Nm +is also available in +.Xr nsh 8 . +Unlike +.Xr nsh 8 , +.Nm +restricts users to commands which obtain BGP routing information for +diagnostic purposes. +.Pp +.Nm +will usually be configured as the login shell for dedicated user accounts +which are used to obtain BGP routing information from the system. +See +.Xr shells 5 +for more information. +.Sh ENVIRONMENT +.Bl -tag -width BGPNSH_SOCKET +.It Ev BGPNSH_SOCKET +Sets an alternative path to the restricted control socket of +.Xr bgpd 8 . +The default path is +.Pa /var/www/run/bgpd.rsock . +.Sh SEE ALSO +.Xr bgplgsh 1 , +.Xr shells 5 , +.Xr bgpd 8 , +.Xr bgplg 8 , +.Xr nsh 8 blob - /dev/null blob + fe3730444452dde0891c8c67fdb741b605e6f00c (mode 644) --- /dev/null +++ bgpnsh/bgpnsh.c @@ -0,0 +1,221 @@ +/* + * Copyright (c) 2023 Stefan Sperling + * + * 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 /* MAXHOSTNAMELEN */ +#include /* IFNAMSIZ */ + +#include +#include +#include +#include +#include +#include +#include + +#include "../externs.h" +#include "../editing.h" +#include "../commands.h" +#include "../ctl.h" + +#define BGPNSH_SOCKET "/var/www/run/bgpd.rsock" /* restricted socket */ + +History *histc = NULL; +History *histi = NULL; +HistEvent ev; +EditLine *elc = NULL; +EditLine *eli = NULL; +EditLine *elp = NULL; +char *cursor_pos = NULL; + +pid_t child; + +void sigalarm(int signo) +{ + if (child != -1) { + kill(child, SIGKILL); + } +} + +int editing = 1, config_mode = 0; +int cli_rtable; +int bridge; +size_t Intlist_nitems = 0, Bridgelist_nitems = 0; +int priv; + +char hbuf[MAXHOSTNAMELEN]; /* host name */ +char ifname[IFNAMSIZ]; /* interface name */ + +struct intlist *whichlist; + +extern struct prot1 bgcs[]; + +struct prot prots[] = { + { "bgp", bgcs }, +}; + +Menu showlist[] = { + { "bgp", "BGP information", + CMPL(ta) (char **)bgcs, sizeof(struct prot1), 0, 4, pr_prot1 }, + { 0, 0, 0, 0, 0 } +}; + +static int +showcmd(int argc, char **argv) +{ + Menu *s; /* pointer to current command */ + + if (argc < 2) { + show_help(argc, argv); + return 0; + } + + /* + * Validate show argument + */ + s = (Menu *) genget(argv[1], (char **) showlist, sizeof(Menu)); + if (s == 0) { + printf("%% Invalid argument %s\n", argv[1]); + return 0; + } else if (Ambiguous(s)) { + printf("%% Ambiguous argument %s\n", argv[1]); + return 0; + } + if (((s->minarg + 2) > argc) || ((s->maxarg + 2) < argc)) { + printf("%% Wrong number of argument%s to 'show %s' command" + " (min %i, max %i)\n", argc <= 2 ? "" : "s", s->name, + s->minarg, s->maxarg); + return 0; + } + + (*s->handler)(argc, argv, NULL); + return 0; +} + +int +quit(void) +{ + printf("%% Session terminated.\n"); + exit(0); + return 0; +} + +Command cmdtab[] = { + { "show", "Show system information", + CMPL(ta) (char **)showlist, sizeof(Menu), showcmd, 0, 0, 0, 0 }, + { "quit", "Close current connection", + CMPL0 0, 0, quit, 0, 0, 0, 0 }, + { "help", 0, + CMPL(c) 0, 0, help, 0, 0, 0, 0 }, + { 0, 0, CMPL0 0, 0, 0, 0, 0, 0, 0 } +}; +size_t cmdtab_nitems = nitems(cmdtab); + +Command * +getcmd(char *name) +{ + Command *cm; + + cm = (Command *) genget(name, (char **) cmdtab, sizeof(Command)); + return cm; +} + +void +command(void) +{ + Command *c; + u_int num; + + for (;;) { + const char *buf; + cursor_pos = NULL; + + if ((buf = el_gets(elc, &num)) == NULL || num == 0) + break; + + if (buf[--num] == '\n') { + if (num == 0) + break; + } + if (num >= sizeof(line)) { + printf("%% Input exceeds permitted length\n"); + break; + } + memcpy(line, buf, (size_t)num); + line[num] = '\0'; + history(histc, &ev, H_ENTER, buf); + + if (line[0] == 0) + break; + makeargv(); + if (margv[0] == 0) { + break; + } + + c = getcmd(margv[0]); + if (Ambiguous(c)) { + printf("%% Ambiguous command\n"); + continue; + } + if (c == 0) { + int val = el_burrito(elc, margc, margv); + if (val) + printf("%% Invalid command\n"); + continue; + } + if (NO_ARG(margv[0]) && ! c->nocmd) { + printf("%% Invalid command: %s %s\n", margv[0], + margv[1]); + continue; + } + + if ((*c->handler) (margc, margv, 0)) + break; + } +} + +int +main(int argc, char *argv[]) +{ + char *socket_path; + + if (argc != 1) { + fprintf(stderr, "usage: %s\n", getprogname()); + return 1; + } + + inithist(); + initedit(); + + if (unveil(BGPCTL, "x") == -1) + err(1, "unveil %s", BGPCTL); + + if (unveil(NULL, NULL) == -1) + err(1, "unveil"); + + if (pledge("stdio tty proc exec", NULL) == -1) + err(1, "pledge"); + + socket_path = getenv("BGPNSH_SOCKET"); + if (socket_path == NULL) + socket_path = BGPNSH_SOCKET; + if (strlcpy(bgpd_socket_path, socket_path, sizeof(bgpd_socket_path)) >= + sizeof(bgpd_socket_path)) + err(1, "bgpd socket path too long"); + + command(); + + return 0; +} blob - /dev/null blob + 452b80c34d3ec3eb9123284e8a249c1af6874380 (mode 644) --- /dev/null +++ bgpnsh/stubs.c @@ -0,0 +1,34 @@ +/* + * Copyright (c) 2023 Stefan Sperling + * + * 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. + */ + +/* These functions are stubbed out in bgpnsh but required for linking. */ + +#include "../stringlist.h" + +int is_bridge(int, char *); +int db_select_rtable_rtables(StringList *); + +int +is_bridge(int s, char *brdg) +{ + return 0; +} + +int +db_select_rtable_rtables(StringList *words) +{ + return -1; +} blob - eebb73667f75dda726d8e045bee3e25554254690 blob + 4a9419a0ddac0891c65b10ea7ab7e5150a51e051 --- commands.c +++ commands.c @@ -68,22 +68,11 @@ #include "sysctl.h" #include "ctl.h" -char prompt[128]; -char saved_prompt[sizeof(prompt)]; - -char line[1024]; -char saveline[1024]; -int margc; char hname[HSIZE]; -static char hbuf[MAXHOSTNAMELEN]; /* host name */ -static char ifname[IFNAMSIZ]; /* interface name */ +char hbuf[MAXHOSTNAMELEN]; /* host name */ +char ifname[IFNAMSIZ]; /* interface name */ struct intlist *whichlist; -#define NARGS sizeof(line)/2 /* max arguments in char line[] */ -char *margv[NARGS]; /* argv storage */ -size_t cursor_argc; /* location of cursor in margv */ -size_t cursor_argo; /* offset of cursor margv[cursor_argc] */ - pid_t child; static int disable(void); @@ -93,14 +82,12 @@ static int doconfig(int, char**); static int exitconfig(int, char**); int rtable(int, char**); int group(int, char**); -static int nsh_setrtable(int); static int pr_routes(int, char **); static int pr_routes6(int, char **); static int pr_arp(int, char **); static int pr_ndp(int, char **); static int pr_sadb(int, char **); static int pr_kernel(int, char **); -static int pr_prot1(int, char **); static int pr_dhcp(int, char **); static int pr_conf(int, char **); static int pr_s_conf(int, char **); @@ -109,7 +96,6 @@ static int pr_conf_diff(int, char **); static int show_hostname(int, char **); static int wr_startup(void); static int wr_conf(char *); -static int show_help(int, char **); static int sysctlhelp(int, char **, char **, int); static int flush_pf(char *); static int flush_help(void); @@ -135,9 +121,7 @@ static int int_manual(char *, int, int, char **); static int int_shell(char *, int, int, char **); static int int_help(void); static int int_exit(void); -static int el_burrito(EditLine *, int, char **); static int hostname(int, char **); -static int help(int, char**); static int manual(int, char**); static int nocmd(int, char **); static int docmd(int, char **); @@ -152,9 +136,7 @@ static int telnet(int, char*[]); static int nreboot(void); static int halt(void); static int powerdown(void); -static Command *getcmd(char *); static void pf_stats(void); -static void sigalarm(int); #include "commands.h" @@ -165,6 +147,230 @@ void sigalarm(int blahfart) } } +static struct fpf { + char *name; + char *help; + char *cmd; + char *arg; +} fpfs[] = { + { "all", "all PF elements", PFCTL, "-Fall" }, + { "nat", "NAT rules", PFCTL, "-Fnat" }, + { "queue", "queue rules", PFCTL, "-Fqueue" }, + { "filter", "filter rules", PFCTL, "-Frules" }, + { "states", "NAT/filter states", PFCTL, "-Fstate" }, + { "stats", "PF statistics", PFCTL, "-Finfo" }, + { "tables", "PF address tables", PFCTL, "-FTables" }, + { 0, 0, 0, 0 } +}; + +static struct stt { + char *name; + char *help; + void (*handler) (); +} stts[] = { + { "ip", "Internet Protocol", ip_stats }, + { "ah", "Authentication Header", ah_stats }, + { "esp", "Encapsulated Security Payload", esp_stats }, + { "tcp", "Transmission Control Protocol", tcp_stats }, + { "udp", "Unreliable Datagram Protocol", udp_stats }, + { "icmp", "Internet Control Message Protocol", icmp_stats }, + { "igmp", "Internet Group Management Protocol", igmp_stats }, + { "ipcomp", "IP Compression", ipcomp_stats }, + { "route", "Routing", rt_stats }, + { "carp", "Common Address Redundancy Protocol", carp_stats }, + { "mbuf", "Packet memory buffer", mbpr }, + { "pf", "Packet Filter", pf_stats }, + { 0, 0, 0 } +}; + + +struct prot1 oscs[] = { + { "fib", "Forward Information Base", + { OSPFCTL, "show", "fib", OPT, OPT, NULL } }, + { "database", "Link State Database", + { OSPFCTL, "show", "database", OPT, OPT, NULL } }, + { "interfaces", "Interface", + { OSPFCTL, "show", "interfaces", OPT, NULL } }, + { "neighbor", "Neighbor", + { OSPFCTL, "show", "neighbor", OPT, NULL } }, + { "rib", "Routing Information Base", + { OSPFCTL, "show", "rib", OPT, NULL } }, + { "summary", "Summary", + { OSPFCTL, "show", "summary", NULL } }, + { 0, 0, { 0 } } +}; + +struct prot1 os6cs[] = { + { "fib", "Forward Information Base", + { OSPF6CTL, "show", "fib", OPT, OPT, NULL } }, + { "database", "Link State Database", + { OSPF6CTL, "show", "database", OPT, OPT, NULL } }, + { "interfaces", "Interface", + { OSPF6CTL, "show", "interfaces", OPT, NULL } }, + { "neighbor", "Neighbor", + { OSPF6CTL, "show", "neighbor", OPT, NULL } }, + { "rib", "Routing Information Base", + { OSPF6CTL, "show", "rib", OPT, NULL } }, + { "summary", "Summary", + { OSPF6CTL, "show", "summary", NULL } }, + { 0, 0, { 0 } } +}; + +struct prot1 pfcs[] = { + { "all", "all pf info except fingerprints and interfaces", + { PFCTL, "-sall", NULL, NULL, NULL, NULL } }, + { "anchors", "currently loaded anchors in main pf ruleset", + { PFCTL, "-sAnchors", NULL, NULL, NULL } }, + { "info ", "pf filter statistics, counters and tracking", + { PFCTL, "-sinfo", "-v", NULL, NULL, NULL } }, + { "labels", "per rule stats (bytes, packets and states)", + { PFCTL, "-slabels", NULL, NULL, NULL, NULL } }, + { "memory", "current pf pool memory hard limit", + { PFCTL, "-smemory", NULL, NULL, NULL, NULL } }, + { "queues", "currently loaded pf queue definition", + { PFCTL, "-squeue", "-v", NULL, NULL, NULL } }, + { "rules", "active pf firewall rule", + { PFCTL, "-srules", NULL, NULL, NULL, NULL } }, + { "sources", "contents of the pf source tracking table", + { PFCTL, "-sSources", NULL, NULL, NULL, NULL } }, + { "states", "contents of the pf state table", + { PFCTL, "-sstates", NULL, NULL, NULL, NULL } }, + { "tables", "pf table", + { PFCTL, "-sTables", NULL, NULL, NULL, NULL } }, + { "timeouts", "current pf global timeout", + { PFCTL, "-stimeouts", NULL, NULL, NULL, NULL } }, + { "osfingerprint", "pf Operating System fingerprint", + { PFCTL, "-sosfp", NULL, NULL, NULL, NULL } }, + { "interfaces", "pf usable interfaces/ interface group", + { PFCTL, "-sInterfaces", NULL, NULL, NULL, NULL } }, + { 0, 0, { 0 } } +}; +struct prot1 eics[] = { + { "interfaces", "Interface", + { EIGRPCTL, "show", "interfaces", OPT, OPT, NULL } }, + { "neighbor", "Neighbor", + { EIGRPCTL, "show", "neighbor", OPT, OPT, NULL } }, + { "topology", "Topology", + { EIGRPCTL, "show", "topology", OPT, OPT, NULL } }, + { "traffic", "Traffic", + { EIGRPCTL, "show", "traffic", OPT, OPT, NULL } }, + { 0, 0, { 0 } } +}; + +struct prot1 rics[] = { + { "fib", "Forward Information Base", + { RIPCTL, "show", "fib", OPT, NULL } }, + { "interfaces", "Interfaces", + { RIPCTL, "show", "interfaces", NULL } }, + { "neighbor", "Neighbor", + { RIPCTL, "show", "neighbor", NULL } }, + { "rib", "Routing Information Base", + { RIPCTL, "show", "rib", NULL } }, + { 0, 0, { 0 } } +}; + +struct prot1 lics[] = { + { "fib", "Forward Information Base", + { LDPCTL, "show", "fib", OPT, NULL } }, + { "interfaces", "Interfaces", + { LDPCTL, "show", "interfaces", NULL } }, + { "neighbor", "Neighbors", + { LDPCTL, "show", "neighbor", NULL } }, + { "lib", "Label Information Base", + { LDPCTL, "show", "lib", NULL } }, + { "discovery", "Adjacencies", + { LDPCTL, "show", "discovery", NULL } }, + { "l2vpn", "Pseudowire", + { LDPCTL, "show", "l2vpn", OPT, NULL } }, + { 0, 0, { 0 } } +}; + +struct prot1 iscs[] = { + { "flows", "Display IPsec flows", + { IPSECCTL, "-sf", NULL } }, + { "sadb", "Display SADB", + { IPSECCTL, "-ss", NULL } }, + { 0, 0, { 0 } } +}; + +struct prot1 ikcs[] = { + { "monitor", "Monitor internal iked messages", + { IKECTL, "monitor", NULL } }, + { 0, 0, { 0 } } +}; + +struct prot1 dvcs[] = { + { "igmp", "Internet Group Message Protocol", + { DVMRPCTL, "show", "igmp", NULL } }, + { "interfaces", "Interfaces", + { DVMRPCTL, "show", "interfaces", OPT, NULL } }, + { "mfc", "Multicast Forwarding Cache", + { DVMRPCTL, "show", "mfc", OPT, NULL } }, + { "neighbor", "Neighbor", + { DVMRPCTL, "show", "neighbor", OPT, NULL } }, + { "rib", "Routing Information Base", + { DVMRPCTL, "show", "rib", OPT, NULL } }, + { "summary", "Summary", + { DVMRPCTL, "show", "summary", NULL } }, + { 0, 0, { 0 } } +}; + +struct prot1 rlcs[] = { + { "hosts", "hosts", + { RELAYCTL, "show", "hosts", NULL } }, + { "redirects", "redirects", + { RELAYCTL, "show", "redirects", NULL } }, + { "status", "status", + { RELAYCTL, "show", "relays", NULL } }, + { "sessions", "sessions", + { RELAYCTL, "show", "sessions", NULL } }, + { "summary", "summary", + { RELAYCTL, "show", "summary", NULL } }, + { 0, 0, { 0 } } +}; + +struct prot1 smcs[] = { + { "queue", "envelopes in queue", + { SMTPCTL, "show", "queue", NULL } }, + { "runqueue", "envelopes scheduled for delivery", + { SMTPCTL, "show", "runqueue", NULL } }, + { "stats", "runtime statistics", + { SMTPCTL, "show", "stats", NULL } }, + { 0, 0, { 0 } } +}; + +struct prot1 dhcs[] = { + { "leases", "leases", { 0 } }, + { 0, 0, { 0 } } +}; + +struct prot1 ldcs[] = { + { "stats", "statistics counters", + { LDAPCTL, "stats", NULL } }, + { 0, 0, { 0 } } +}; + +extern struct prot1 bgcs[]; + +/* show yyy zzz */ +struct prot prots[] = { + { "bgp", bgcs }, + { "ospf", oscs }, + { "ospf6", os6cs }, + { "pf", pfcs }, + { "eigrp", eics }, + { "rip", rics }, + { "ike", ikcs }, + { "ipsec", iscs }, + { "ldp", lics }, + { "dvmrp", dvcs }, + { "relay", rlcs }, + { "smtp", smcs }, + { "ldap", ldcs }, + { 0, 0 } +}; + + /* * Quit command */ @@ -343,27 +549,6 @@ done: if (unlink(outpath) == -1) printf("%% unlink %s: %s\n", outpath, strerror(errno)); return(error); -} - -static int -show_help(int argc, char **argv) -{ - Menu *s; /* pointer to current command */ - u_int z = 0; - - printf("%% Commands may be abbreviated.\n"); - printf("%% 'show' commands are:\n\n"); - - for (s = showlist; s->name; s++) { - if (strlen(s->name) > z) - z = strlen(s->name); - } - - for (s = showlist; s->name; s++) { - if (s->help) - printf(" %-*s %s\n", z, s->name, s->help); - } - return 0; } /* @@ -1801,74 +1986,13 @@ getcmd(char *name) } void -makeargv() -{ - char *cp, *cp2, *base, c; - char **argp = margv; - - margc = 0; - cp = line; - if (*cp == '!') { /* Special case shell escape */ - /* save for shell command */ - strlcpy(saveline, line, sizeof(saveline)); - - *argp++ = "!"; /* No room in string to get this */ - margc++; - cp++; - } - while ((c = *cp)) { - int inquote = 0; - while (isspace((unsigned char)c)) - c = *++cp; - if (c == '\0') - break; - *argp++ = cp; - cursor_argc = margc += 1; - base = cp; - for (cursor_argo = 0, cp2 = cp; c != '\0'; - cursor_argo = (cp + 1) - base, c = *++cp) { - if (inquote) { - if (c == inquote) { - inquote = 0; - continue; - } - } else { - if (c == '\\') { - if ((c = *++cp) == '\0') - break; - } else if (c == '"') { - inquote = '"'; - continue; - } else if (c == '\'') { - inquote = '\''; - continue; - } else if (isspace((unsigned char)c)) { - cursor_argo = 0; - break; - } - } - *cp2++ = c; - } - *cp2 = '\0'; - if (c == '\0') { - cursor_argc--; - break; - } - cp++; - } - *argp++ = 0; - if (cursor_pos == line) { - cursor_argc = 0; - cursor_argo = 0; - } -} - -void command() { Command *c; u_int num; + init_bgpd_socket_path(getrtable()); + if (editing) { inithist(); initedit(); @@ -1950,46 +2074,6 @@ command() } /* - * Help command. - */ -static int -help(int argc, char **argv) -{ - Command *c; - - if (argc == 1) { - u_int z = 0; - - printf("%% Commands may be abbreviated.\n"); - printf("%% Commands are:\n\n"); - - for (c = cmdtab; c->name; c++) - if (((c->needpriv && priv) || !c->needpriv) - && strlen(c->name) > z) - z = strlen(c->name); - for (c = cmdtab; c->name; c++) { - if (c->help && - ((c->needpriv && priv) || !c->needpriv) && - ((c->needconfig && config_mode) || !c->needconfig)) - printf(" %-*s %s\n", z, c->name, c->help); - } - return 0; - } - while (--argc > 0) { - char *arg; - arg = *++argv; - c = getcmd(arg); - if (Ambiguous(c)) - printf("%% Ambiguous help command %s\n", arg); - else if (c == (Command *)0) - printf("%% Invalid help command %s\n", arg); - else - printf("%% %s: %s\n", arg, c->help); - } - return 0; -} - -/* * Manual command. */ @@ -2117,28 +2201,6 @@ int show_hostname(int argc, char **argv) printf("%s\n", hbuf); return 0; -} - -int -nsh_setrtable(int rtableid) -{ - int cur_rtable; - errno = 0; - - cur_rtable = getrtable(); - if (cur_rtable != rtableid && setrtable(rtableid) < 0) - switch(errno) { - case EINVAL: - printf("%% rtable %d not initialized\n", - cli_rtable); - break; - case EPERM: - printf("%% nsh not running as root?\n"); - break; - default: - printf("%% setrtable failed: %d\n", errno); - } - return(errno); } /* @@ -2516,91 +2578,6 @@ group(int argc, char **argv) } return 0; -} - -/* - * cmd, multiple args - * - * If no error occurs then return the program's exit code (>= 0). - * Return -1 on error to run the program or if the program was - * terminated in an abnormal way, such as being killed by a signal. - */ -int -cmdargs(char *cmd, char *arg[]) -{ - return cmdargs_output(cmd, arg, -1, -1); -} - -/* - * cmd, multiple args, capture stdout and stderr output - * - * If no error occurs then return the program's exit code (>= 0). - * Return -1 on error to run the program or if the program was - * terminated in an abnormal way, such as being killed by a signal. - */ -int -cmdargs_output(char *cmd, char *arg[], int stdoutfd, int stderrfd) -{ - sig_t sigint, sigquit, sigchld; - int status = -1; - - sigint = signal(SIGINT, SIG_IGN); - sigquit = signal(SIGQUIT, SIG_IGN); - sigchld = signal(SIGCHLD, SIG_DFL); - - switch (child = fork()) { - case -1: - printf("%% fork failed: %s\n", strerror(errno)); - return -1; - - case 0: - { - char *shellp = cmd; - - signal(SIGQUIT, SIG_DFL); - signal(SIGINT, SIG_DFL); - signal(SIGCHLD, SIG_DFL); - - if (cli_rtable != 0 && nsh_setrtable(cli_rtable)) - _exit(0); - - if (stdoutfd != -1) { - if (stdoutfd != STDOUT_FILENO && - dup2(stdoutfd, STDOUT_FILENO) == -1) { - printf("%% dup2: %s\n", - strerror(errno)); - _exit(0); - } - } - if (stderrfd != -1) { - if (stderrfd != STDERR_FILENO && - dup2(stderrfd, STDERR_FILENO) == -1) { - printf("%% dup2 failed: %s\n", - strerror(errno)); - _exit(0); - } - } - - execv(shellp, arg); - printf("%% execv failed: %s\n", strerror(errno)); - _exit(127); /* same as what ksh(1) would do here */ - } - break; - default: - signal(SIGALRM, sigalarm); - wait(&status); /* Wait for cmd to complete */ - if (WIFEXITED(status)) /* normal exit? */ - status = WEXITSTATUS(status); /* exit code */ - break; - } - - signal(SIGINT, sigint); - signal(SIGQUIT, sigquit); - signal(SIGCHLD, sigchld); - signal(SIGALRM, SIG_DFL); - child = -1; - - return status; } /* @@ -2709,32 +2686,6 @@ flush_history(void) initedit(); return(0); -} - -void -gen_help(char **x, char *cmdprefix, char *descrsuffix, int szstruct) -{ - /* only for structures starting with char *name; char *help; !! */ - char **y = x; - struct ghs *ghs; - int z = 0; - - printf("%% Arguments may be abbreviated\n\n"); - - while (*y != 0) { - if (strlen(*y) > z) - z = strlen(*y); - y = (char **)((char *)y + szstruct); - } - - while (*x != 0) { - ghs = (struct ghs *)x; - if (ghs->help) - printf(" %s %-*s %s %s\n", cmdprefix, z, *x, - ghs->help, descrsuffix); - x = (char **)((char *)x + szstruct); - } - return; } /* @@ -2781,6 +2732,8 @@ cmdrc(char rcname[FILENAME_MAX]) unsigned int lnum; /* line number */ u_int z = 0; /* max length of cmdtab argument */ + init_bgpd_socket_path(getrtable()); + if ((rcfile = fopen(rcname, "r")) == 0) { printf("%% Unable to open %s: %s\n", rcname, strerror(errno)); return 1; @@ -2900,90 +2853,7 @@ p_argv(int argc, char **argv) return; } -/* - * for the purpose of interface handler routines, 1 here is failure and - * 0 is success - */ int -el_burrito(EditLine *el, int argc, char **argv) -{ - char *colon; - int val; - - if (!editing) /* Nothing to parse, fail */ - return(1); - - /* - * el_parse will always return a non-error status if someone specifies - * argv[0] with a colon. The idea of the colon is to allow host- - * specific commands, which is really only useful in .editrc, so - * it is invalid here. - */ - colon = strchr(argv[0], ':'); - if (colon) - return(1); - - val = el_parse(el, argc, (const char **)argv); - - if (val == 0) - return(0); - else - return(1); -} - -char * -cprompt(void) -{ - int pr; - char tmp[4]; - - if (cli_rtable) - snprintf(tmp, sizeof(tmp), "%d", cli_rtable); - - gethostname(hbuf, sizeof(hbuf)); - pr = priv | cli_rtable | config_mode; - snprintf(prompt, sizeof(prompt), "%s%s%s%s%s%s%s%s%s/", hbuf, - pr ? "(" : "", - config_mode ? "config" : "", - config_mode && priv ? "-" : "", - priv ? "p" : "", - (( priv && cli_rtable) || (config_mode && cli_rtable)) ? "-" : "", - cli_rtable ? "rtable " : "", cli_rtable ? tmp : "", - pr ?")" : ""); - - return(prompt); -} - -char * -iprompt(void) -{ - gethostname(hbuf, sizeof(hbuf)); - snprintf(prompt, sizeof(prompt), "%s(%s-%s)/", hbuf, - bridge ? "bridge" : "interface", ifname); - - return(prompt); -} - -char * -pprompt(void) -{ - return(prompt); -} - -static void -setprompt(const char *s) -{ - strlcpy(saved_prompt, prompt, sizeof(saved_prompt)); - strlcpy(prompt, s, sizeof(prompt)); -} - -static void -restoreprompt(void) -{ - strlcpy(prompt, saved_prompt, sizeof(prompt)); -} - -int wr_startup(void) { char *argv[] = { SAVESCRIPT, NSHRC_TEMP, NULL }; @@ -3453,109 +3323,8 @@ pf_stats(void) cmdargs(PFCTL, argv); return; -} - -int -pr_prot1(int argc, char **argv) -{ - struct prot1 *x; - struct prot *prot; - char *args[NOPTFILL] = { NULL, NULL, NULL, NULL, NULL, NULL, NULL }; - char **fillargs; - char prefix[64]; - - /* loop protocol list to find table pointer */ - prot = (struct prot *) genget(argv[1], (char **)prots, - sizeof(struct prot)); - if (prot == 0) { - printf("%% Internal error - Invalid argument %s\n", argv[1]); - return 0; - } else if (Ambiguous(prot)) { - printf("%% Internal error - Ambiguous argument %s\n", argv[1]); - return 0; - } - - snprintf(prefix, sizeof(prefix), "show %s", prot->name); - - /* no clue? we can help */ - if (argc < 3 || argv[2][0] == '?') { - gen_help((char **)prot->table, prefix, "information", - sizeof(struct prot1)); - return 0; - } - x = (struct prot1 *) genget(argv[2], (char **)prot->table, - sizeof(struct prot1)); - if (x == 0) { - printf("%% Invalid argument %s\n", argv[2]); - return 0; - } else if (Ambiguous(x)) { - printf("%% Ambiguous argument %s\n", argv[2]); - return 0; - } - - fillargs = step_optreq(x->args, args, argc, argv, 3); - if (fillargs == NULL) - return 0; - - cmdargs(fillargs[0], fillargs); - - return 1; } -char ** -step_optreq(char **xargs, char **args, int argc, char **argv, int skip) -{ - int i; - int fill = 0; /* total fillable arguments */ - int flc = 0; /* number of filled arguments */ - - /* count fillable arguments */ - for (i = 0; i < NOPTFILL - 1; i++) { - if (xargs[i] == OPT || xargs[i] == REQ) - fill++; - if (xargs[i] == NULL) - break; - } - - if (argc - skip > fill) { - printf("%% Superfluous argument: %s\n", argv[skip + fill]); - return NULL; - } - - /* copy xargs to args, replace OPT/REQ args with argv past skip */ - for (i = 0; i < NOPTFILL - 2; i++) { - if (xargs[i] == NULL) { - args[i] = NULL; - if (i > 1) - /* - * all **args passed must have at least two arguments - * and a terminating NULL. the point of this check - * is to allow the first two arguments to be NULL but - * still fill in fillargs[x] with corresponding NULL - */ - break; - } - if (xargs[i] == OPT || xargs[i] == REQ) { - /* copy from argv to args */ - if (argc - skip - flc > 0) { - args[i] = argv[skip + flc]; - flc++; - } else if (xargs[i] == REQ) { - printf("%% Missing required argument\n"); - return NULL; - } else { - args[i] = NULL; - break; - } - } else { - /* copy from xargs to args */ - args[i] = xargs[i]; - } - } - - return(args); -} - int pr_dhcp(int argc, char **argv) { blob - 264b9b5372a9039445ca747b326559f4b291a05f blob + 538228794818b95a085bd5e3aa46337a017832b2 --- commands.h +++ commands.h @@ -14,42 +14,6 @@ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ -static struct fpf { - char *name; - char *help; - char *cmd; - char *arg; -} fpfs[] = { - { "all", "all PF elements", PFCTL, "-Fall" }, - { "nat", "NAT rules", PFCTL, "-Fnat" }, - { "queue", "queue rules", PFCTL, "-Fqueue" }, - { "filter", "filter rules", PFCTL, "-Frules" }, - { "states", "NAT/filter states", PFCTL, "-Fstate" }, - { "stats", "PF statistics", PFCTL, "-Finfo" }, - { "tables", "PF address tables", PFCTL, "-FTables" }, - { 0, 0, 0, 0 } -}; - -static struct stt { - char *name; - char *help; - void (*handler) (); -} stts[] = { - { "ip", "Internet Protocol", ip_stats }, - { "ah", "Authentication Header", ah_stats }, - { "esp", "Encapsulated Security Payload", esp_stats }, - { "tcp", "Transmission Control Protocol", tcp_stats }, - { "udp", "Unreliable Datagram Protocol", udp_stats }, - { "icmp", "Internet Control Message Protocol", icmp_stats }, - { "igmp", "Internet Group Management Protocol", igmp_stats }, - { "ipcomp", "IP Compression", ipcomp_stats }, - { "route", "Routing", rt_stats }, - { "carp", "Common Address Redundancy Protocol", carp_stats }, - { "mbuf", "Packet memory buffer", mbpr }, - { "pf", "Packet Filter", pf_stats }, - { 0, 0, 0 } -}; - struct prot1 { char *name; char *help; @@ -61,204 +25,17 @@ struct prot { struct prot1 *table; }; -struct prot1 bgcs[] = { - { "announced", "All announced networks", - { BGPCTL, "network", "show", OPT, NULL } }, - { "interfaces", "Interface states", - { BGPCTL, "show", "interfaces", NULL } }, - { "nexthop", "BGP nexthop routes", - { BGPCTL, "show", "nexthop", NULL } }, - { "summary", "Neighbor session states and counters", - { BGPCTL, "show", "summary", OPT, NULL } }, - { "rib", "Routing Information Base", - { BGPCTL, "show", "rib", OPT, OPT, OPT, NULL } }, - { "neighbor", "Detailed peer", - { BGPCTL, "show", "neighbor", REQ, OPT, NULL } }, - { "ip", "IP BGP", - { BGPCTL, "show", "ip", "bgp", OPT, OPT, OPT, NULL } }, - { 0, 0, { 0 } } -}; - -struct prot1 oscs[] = { - { "fib", "Forward Information Base", - { OSPFCTL, "show", "fib", OPT, OPT, NULL } }, - { "database", "Link State Database", - { OSPFCTL, "show", "database", OPT, OPT, NULL } }, - { "interfaces", "Interface", - { OSPFCTL, "show", "interfaces", OPT, NULL } }, - { "neighbor", "Neighbor", - { OSPFCTL, "show", "neighbor", OPT, NULL } }, - { "rib", "Routing Information Base", - { OSPFCTL, "show", "rib", OPT, NULL } }, - { "summary", "Summary", - { OSPFCTL, "show", "summary", NULL } }, - { 0, 0, { 0 } } -}; - -struct prot1 os6cs[] = { - { "fib", "Forward Information Base", - { OSPF6CTL, "show", "fib", OPT, OPT, NULL } }, - { "database", "Link State Database", - { OSPF6CTL, "show", "database", OPT, OPT, NULL } }, - { "interfaces", "Interface", - { OSPF6CTL, "show", "interfaces", OPT, NULL } }, - { "neighbor", "Neighbor", - { OSPF6CTL, "show", "neighbor", OPT, NULL } }, - { "rib", "Routing Information Base", - { OSPF6CTL, "show", "rib", OPT, NULL } }, - { "summary", "Summary", - { OSPF6CTL, "show", "summary", NULL } }, - { 0, 0, { 0 } } -}; - -struct prot1 pfcs[] = { - { "all", "all pf info except fingerprints and interfaces", - { PFCTL, "-sall", NULL, NULL, NULL, NULL } }, - { "anchors", "currently loaded anchors in main pf ruleset", - { PFCTL, "-sAnchors", NULL, NULL, NULL } }, - { "info ", "pf filter statistics, counters and tracking", - { PFCTL, "-sinfo", "-v", NULL, NULL, NULL } }, - { "labels", "per rule stats (bytes, packets and states)", - { PFCTL, "-slabels", NULL, NULL, NULL, NULL } }, - { "memory", "current pf pool memory hard limit", - { PFCTL, "-smemory", NULL, NULL, NULL, NULL } }, - { "queues", "currently loaded pf queue definition", - { PFCTL, "-squeue", "-v", NULL, NULL, NULL } }, - { "rules", "active pf firewall rule", - { PFCTL, "-srules", NULL, NULL, NULL, NULL } }, - { "sources", "contents of the pf source tracking table", - { PFCTL, "-sSources", NULL, NULL, NULL, NULL } }, - { "states", "contents of the pf state table", - { PFCTL, "-sstates", NULL, NULL, NULL, NULL } }, - { "tables", "pf table", - { PFCTL, "-sTables", NULL, NULL, NULL, NULL } }, - { "timeouts", "current pf global timeout", - { PFCTL, "-stimeouts", NULL, NULL, NULL, NULL } }, - { "osfingerprint", "pf Operating System fingerprint", - { PFCTL, "-sosfp", NULL, NULL, NULL, NULL } }, - { "interfaces", "pf usable interfaces/ interface group", - { PFCTL, "-sInterfaces", NULL, NULL, NULL, NULL } }, - { 0, 0, { 0 } } -}; -struct prot1 eics[] = { - { "interfaces", "Interface", - { EIGRPCTL, "show", "interfaces", OPT, OPT, NULL } }, - { "neighbor", "Neighbor", - { EIGRPCTL, "show", "neighbor", OPT, OPT, NULL } }, - { "topology", "Topology", - { EIGRPCTL, "show", "topology", OPT, OPT, NULL } }, - { "traffic", "Traffic", - { EIGRPCTL, "show", "traffic", OPT, OPT, NULL } }, - { 0, 0, { 0 } } -}; - -struct prot1 rics[] = { - { "fib", "Forward Information Base", - { RIPCTL, "show", "fib", OPT, NULL } }, - { "interfaces", "Interfaces", - { RIPCTL, "show", "interfaces", NULL } }, - { "neighbor", "Neighbor", - { RIPCTL, "show", "neighbor", NULL } }, - { "rib", "Routing Information Base", - { RIPCTL, "show", "rib", NULL } }, - { 0, 0, { 0 } } -}; - -struct prot1 lics[] = { - { "fib", "Forward Information Base", - { LDPCTL, "show", "fib", OPT, NULL } }, - { "interfaces", "Interfaces", - { LDPCTL, "show", "interfaces", NULL } }, - { "neighbor", "Neighbors", - { LDPCTL, "show", "neighbor", NULL } }, - { "lib", "Label Information Base", - { LDPCTL, "show", "lib", NULL } }, - { "discovery", "Adjacencies", - { LDPCTL, "show", "discovery", NULL } }, - { "l2vpn", "Pseudowire", - { LDPCTL, "show", "l2vpn", OPT, NULL } }, - { 0, 0, { 0 } } -}; - -struct prot1 iscs[] = { - { "flows", "Display IPsec flows", - { IPSECCTL, "-sf", NULL } }, - { "sadb", "Display SADB", - { IPSECCTL, "-ss", NULL } }, - { 0, 0, { 0 } } -}; - -struct prot1 ikcs[] = { - { "monitor", "Monitor internal iked messages", - { IKECTL, "monitor", NULL } }, - { 0, 0, { 0 } } -}; - -struct prot1 dvcs[] = { - { "igmp", "Internet Group Message Protocol", - { DVMRPCTL, "show", "igmp", NULL } }, - { "interfaces", "Interfaces", - { DVMRPCTL, "show", "interfaces", OPT, NULL } }, - { "mfc", "Multicast Forwarding Cache", - { DVMRPCTL, "show", "mfc", OPT, NULL } }, - { "neighbor", "Neighbor", - { DVMRPCTL, "show", "neighbor", OPT, NULL } }, - { "rib", "Routing Information Base", - { DVMRPCTL, "show", "rib", OPT, NULL } }, - { "summary", "Summary", - { DVMRPCTL, "show", "summary", NULL } }, - { 0, 0, { 0 } } -}; - -struct prot1 rlcs[] = { - { "hosts", "hosts", - { RELAYCTL, "show", "hosts", NULL } }, - { "redirects", "redirects", - { RELAYCTL, "show", "redirects", NULL } }, - { "status", "status", - { RELAYCTL, "show", "relays", NULL } }, - { "sessions", "sessions", - { RELAYCTL, "show", "sessions", NULL } }, - { "summary", "summary", - { RELAYCTL, "show", "summary", NULL } }, - { 0, 0, { 0 } } -}; - -struct prot1 smcs[] = { - { "queue", "envelopes in queue", - { SMTPCTL, "show", "queue", NULL } }, - { "runqueue", "envelopes scheduled for delivery", - { SMTPCTL, "show", "runqueue", NULL } }, - { "stats", "runtime statistics", - { SMTPCTL, "show", "stats", NULL } }, - { 0, 0, { 0 } } -}; - -struct prot1 dhcs[] = { - { "leases", "leases", { 0 } }, - { 0, 0, { 0 } } -}; - -struct prot1 ldcs[] = { - { "stats", "statistics counters", - { LDAPCTL, "stats", NULL } }, - { 0, 0, { 0 } } -}; - -/* show yyy zzz */ -struct prot prots[] = { - { "bgp", bgcs }, - { "ospf", oscs }, - { "ospf6", os6cs }, - { "pf", pfcs }, - { "eigrp", eics }, - { "rip", rics }, - { "ike", ikcs }, - { "ipsec", iscs }, - { "ldp", lics }, - { "dvmrp", dvcs }, - { "relay", rlcs }, - { "smtp", smcs }, - { "ldap", ldcs }, - { 0, 0 } -}; +#define BGPD_SOCKET_PATH "/var/run/bgpd.sock" +extern char bgpd_socket_path[PATH_MAX]; +void init_bgpd_socket_path(int); +extern struct prot prots[]; +int show_help(int, char **); +Command *getcmd(char *); +extern Menu showlist[]; +void makeargv(void); +extern pid_t child; +extern int nsh_setrtable(int); +extern void sigalarm(int); +extern char hbuf[MAXHOSTNAMELEN]; +extern char ifname[IFNAMSIZ]; +int help(int, char**); blob - /dev/null blob + 7d771aecb5d74acb2b75f635b6d2b242448eb42a (mode 644) --- /dev/null +++ cmdargs.c @@ -0,0 +1,144 @@ +/* + * Copyright (c) 2008-2009 Chris Cappuccio + * Copyright (c) 2023 Stefan Sperling + * + * 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 /* MAXHOSTNAMELEN */ +#include /* IFNAMSIZ */ + +#include +#include +#include + +#include +#include +#include +#include +#include + +#include "externs.h" +#include "commands.h" + +/* + * cmd, multiple args + * + * If no error occurs then return the program's exit code (>= 0). + * Return -1 on error to run the program or if the program was + * terminated in an abnormal way, such as being killed by a signal. + */ +int +cmdargs(char *cmd, char *arg[]) +{ + return cmdargs_output(cmd, arg, -1, -1); +} + +/* + * cmd, multiple args, capture stdout and stderr output + * + * If no error occurs then return the program's exit code (>= 0). + * Return -1 on error to run the program or if the program was + * terminated in an abnormal way, such as being killed by a signal. + */ +int +cmdargs_output(char *cmd, char *arg[], int stdoutfd, int stderrfd) +{ + sig_t sigint, sigquit, sigchld; + int status = -1; + + sigint = signal(SIGINT, SIG_IGN); + sigquit = signal(SIGQUIT, SIG_IGN); + sigchld = signal(SIGCHLD, SIG_DFL); + + switch (child = fork()) { + case -1: + printf("%% fork failed: %s\n", strerror(errno)); + return -1; + + case 0: + { + char *shellp = cmd; + + signal(SIGQUIT, SIG_DFL); + signal(SIGINT, SIG_DFL); + signal(SIGCHLD, SIG_DFL); + + if (cli_rtable != 0 && nsh_setrtable(cli_rtable)) + _exit(0); + + if (stdoutfd != -1) { + if (stdoutfd != STDOUT_FILENO && + dup2(stdoutfd, STDOUT_FILENO) == -1) { + printf("%% dup2: %s\n", + strerror(errno)); + _exit(0); + } + } + if (stderrfd != -1) { + if (stderrfd != STDERR_FILENO && + dup2(stderrfd, STDERR_FILENO) == -1) { + printf("%% dup2 failed: %s\n", + strerror(errno)); + _exit(0); + } + } + + execv(shellp, arg); + printf("%% execv failed: %s\n", strerror(errno)); + _exit(127); /* same as what ksh(1) would do here */ + } + break; + default: + signal(SIGALRM, sigalarm); + wait(&status); /* Wait for cmd to complete */ + if (WIFEXITED(status)) /* normal exit? */ + status = WEXITSTATUS(status); /* exit code */ + break; + } + + signal(SIGINT, sigint); + signal(SIGQUIT, sigquit); + signal(SIGCHLD, sigchld); + signal(SIGALRM, SIG_DFL); + child = -1; + + return status; +} + +int +nsh_setrtable(int rtableid) +{ + int ret = 0; + + if (getrtable() == rtableid) + return 0; + + if (setrtable(rtableid) < 0) { + ret = errno; + switch(errno) { + case EINVAL: + printf("%% rtable %d not initialized\n", + cli_rtable); + break; + case EPERM: + printf("%% nsh not running as root?\n"); + break; + default: + printf("%% setrtable failed: %d\n", errno); + } + } else + init_bgpd_socket_path(rtableid); + + return(ret); +} blob - 5e3fe1c55c3a61150359610b85098421e3d2cb8e blob + 1aa4e516adf58328b4cf0e36ccae19bbe005a6cc --- complete.c +++ complete.c @@ -1012,3 +1012,34 @@ endedit() eli = NULL; } } + +/* + * for the purpose of interface handler routines, 1 here is failure and + * 0 is success + */ +int +el_burrito(EditLine *el, int argc, char **argv) +{ + char *colon; + int val; + + if (!editing) /* Nothing to parse, fail */ + return(1); + + /* + * el_parse will always return a non-error status if someone specifies + * argv[0] with a colon. The idea of the colon is to allow host- + * specific commands, which is really only useful in .editrc, so + * it is invalid here. + */ + colon = strchr(argv[0], ':'); + if (colon) + return(1); + + val = el_parse(el, argc, (const char **)argv); + + if (val == 0) + return(0); + else + return(1); +} blob - 136e119c84cf7769ae95dad3ae5cf92c014581d5 blob + e9b851d07ca29dd0a429191bc48990f82b492690 --- editing.h +++ editing.h @@ -8,3 +8,5 @@ extern History *histi; /* interface() editline(3) sta extern char *cursor_pos; /* cursor position we're looking for */ extern size_t cursor_argc; /* location of cursor in margv */ extern size_t cursor_argo; /* offset of cursor in margv[cursor_argc] */ + +int el_burrito(EditLine *, int, char **); blob - 0be9d4e399ef96e55a54cac6c8dd39ed4b847d08 blob + 610184e1adf628ff1d5a11f25b77b38f302ad923 --- externs.h +++ externs.h @@ -26,6 +26,7 @@ struct rtdump { extern char *__progname; /* duh */ extern char *vers; /* the version of nsh */ extern char saveline[1024]; /* command line */ +#define NARGS (sizeof(line)/2) /* max arguments in char line[] */ extern char line[1024]; /* command line for makeargv() */ extern int margc; /* makeargv() arg count */ extern char *margv[]; /* makeargv() args */ @@ -147,7 +148,13 @@ extern char metricnames[]; /* ctl.c declarations moved to ctl.h */ +/* cmdargs.c */ +int cmdargs_output(char *, char **, int, int); +int cmdargs(char *, char **); +int nsh_setrtable(int); + /* commands.c */ +extern pid_t child; #define NOPTFILL 7 #define DEFAULT_EDITOR "/usr/bin/vi" #define NSHRC_TEMP "/var/run/nshrc" @@ -169,15 +176,20 @@ extern char metricnames[]; #define DHCPLEASES "/var/db/dhcpd.leases" #endif int quit(void); +void sigalarm(int); void command(void); -char **step_optreq(char **, char **, int, char **, int); int argvtostring(int, char **, char *, int); int cmdrc(char rcname[FILENAME_MAX]); -int cmdargs_output(char *, char **, int, int); -int cmdargs(char *, char **); + +/* prompt.c */ char *iprompt(void); char *cprompt(void); char *pprompt(void); +void setprompt(const char *); +void restoreprompt(void); +extern char prompt[128]; +extern char saved_prompt[sizeof(prompt)]; + int group (int, char **); void gen_help(char **, char *, char *, int); void makeargv(void); @@ -546,3 +558,7 @@ void show_umb(int, char *, FILE *); int mbs2ws(wchar_t **, size_t *, const char *); #endif int mbsavis(char**, int *, const char *); + +/* ctlargs.c */ +int pr_prot1(int, char **); +char **step_optreq(char **, char **, int, char **, int); blob - /dev/null blob + 5d373722a7134a484dfb1355223c8f59b95898cd (mode 644) --- /dev/null +++ ctlargs.c @@ -0,0 +1,127 @@ +/* + * Copyright (c) 2008 Chris Cappuccio + * + * 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 /* MAXHOSTNAMELEN */ +#include /* IFNAMSIZ */ + +#include + +#include + +#include "externs.h" +#include "commands.h" +#include "ctl.h" + +int +pr_prot1(int argc, char **argv) +{ + struct prot1 *x; + struct prot *prot; + char *args[NOPTFILL] = { NULL, NULL, NULL, NULL, NULL, NULL, NULL }; + char **fillargs; + char prefix[64]; + + /* loop protocol list to find table pointer */ + prot = (struct prot *) genget(argv[1], (char **)prots, + sizeof(struct prot)); + if (prot == 0) { + printf("%% Internal error - Invalid argument %s\n", argv[1]); + return 0; + } else if (Ambiguous(prot)) { + printf("%% Internal error - Ambiguous argument %s\n", argv[1]); + return 0; + } + + snprintf(prefix, sizeof(prefix), "show %s", prot->name); + + /* no clue? we can help */ + if (argc < 3 || argv[2][0] == '?') { + gen_help((char **)prot->table, prefix, "information", + sizeof(struct prot1)); + return 0; + } + x = (struct prot1 *) genget(argv[2], (char **)prot->table, + sizeof(struct prot1)); + if (x == 0) { + printf("%% Invalid argument %s\n", argv[2]); + return 0; + } else if (Ambiguous(x)) { + printf("%% Ambiguous argument %s\n", argv[2]); + return 0; + } + + fillargs = step_optreq(x->args, args, argc, argv, 3); + if (fillargs == NULL) + return 0; + + cmdargs(fillargs[0], fillargs); + + return 1; +} + +char ** +step_optreq(char **xargs, char **args, int argc, char **argv, int skip) +{ + int i; + int fill = 0; /* total fillable arguments */ + int flc = 0; /* number of filled arguments */ + + /* count fillable arguments */ + for (i = 0; i < NOPTFILL - 1; i++) { + if (xargs[i] == OPT || xargs[i] == REQ) + fill++; + if (xargs[i] == NULL) + break; + } + + if (argc - skip > fill) { + printf("%% Superfluous argument: %s\n", argv[skip + fill]); + return NULL; + } + + /* copy xargs to args, replace OPT/REQ args with argv past skip */ + for (i = 0; i < NOPTFILL - 2; i++) { + if (xargs[i] == NULL) { + args[i] = NULL; + if (i > 1) + /* + * all **args passed must have at least two arguments + * and a terminating NULL. the point of this check + * is to allow the first two arguments to be NULL but + * still fill in fillargs[x] with corresponding NULL + */ + break; + } + if (xargs[i] == OPT || xargs[i] == REQ) { + /* copy from argv to args */ + if (argc - skip - flc > 0) { + args[i] = argv[skip + flc]; + flc++; + } else if (xargs[i] == REQ) { + printf("%% Missing required argument\n"); + return NULL; + } else { + args[i] = NULL; + break; + } + } else { + /* copy from xargs to args */ + args[i] = xargs[i]; + } + } + + return(args); +} blob - /dev/null blob + 9564ad11cfdf44c8f81f31ff2f0d694bd6248954 (mode 644) --- /dev/null +++ helpcommands.c @@ -0,0 +1,114 @@ +/* + * Copyright (c) 2002-2008 Chris Cappuccio + * + * 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 /* MAXHOSTNAMELEN */ +#include /* IFNAMSIZ */ + +#include + +#include +#include +#include + +#include "externs.h" +#include "commands.h" + +int +show_help(int argc, char **argv) +{ + Menu *s; /* pointer to current command */ + u_int z = 0; + + printf("%% Commands may be abbreviated.\n"); + printf("%% 'show' commands are:\n\n"); + + for (s = showlist; s->name; s++) { + if (strlen(s->name) > z) + z = strlen(s->name); + } + + for (s = showlist; s->name; s++) { + if (s->help) + printf(" %-*s %s\n", z, s->name, s->help); + } + return 0; +} + +void +gen_help(char **x, char *cmdprefix, char *descrsuffix, int szstruct) +{ + /* only for structures starting with char *name; char *help; !! */ + char **y = x; + struct ghs *ghs; + int z = 0; + + printf("%% Arguments may be abbreviated\n\n"); + + while (*y != 0) { + if (strlen(*y) > z) + z = strlen(*y); + y = (char **)((char *)y + szstruct); + } + + while (*x != 0) { + ghs = (struct ghs *)x; + if (ghs->help) + printf(" %s %-*s %s %s\n", cmdprefix, z, *x, + ghs->help, descrsuffix); + x = (char **)((char *)x + szstruct); + } + return; +} + +/* + * Help command. + */ +int +help(int argc, char **argv) +{ + Command *c; + + if (argc == 1) { + u_int z = 0; + + printf("%% Commands may be abbreviated.\n"); + printf("%% Commands are:\n\n"); + + for (c = cmdtab; c->name; c++) + if (((c->needpriv && priv) || !c->needpriv) + && strlen(c->name) > z) + z = strlen(c->name); + for (c = cmdtab; c->name; c++) { + if (c->help && + ((c->needpriv && priv) || !c->needpriv) && + ((c->needconfig && config_mode) || !c->needconfig)) + printf(" %-*s %s\n", z, c->name, c->help); + } + return 0; + } + while (--argc > 0) { + char *arg; + arg = *++argv; + c = getcmd(arg); + if (Ambiguous(c)) + printf("%% Ambiguous help command %s\n", arg); + else if (c == (Command *)0) + printf("%% Invalid help command %s\n", arg); + else + printf("%% %s: %s\n", arg, c->help); + } + return 0; +} blob - /dev/null blob + a4984bcc41ea04e1e693647e0d98fe6a2f50308a (mode 644) --- /dev/null +++ makeargv.c @@ -0,0 +1,95 @@ +/* + * Copyright (c) 2002-2008 Chris Cappuccio + * + * 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 + +#include +#include +#include + +#include "externs.h" +#include "editing.h" + +char line[1024]; +char saveline[1024]; +int margc; + +char *margv[NARGS]; /* argv storage */ +size_t cursor_argc; /* location of cursor in margv */ +size_t cursor_argo; /* offset of cursor margv[cursor_argc] */ + +void +makeargv(void) +{ + char *cp, *cp2, *base, c; + char **argp = margv; + + margc = 0; + cp = line; + if (*cp == '!') { /* Special case shell escape */ + /* save for shell command */ + strlcpy(saveline, line, sizeof(saveline)); + + *argp++ = "!"; /* No room in string to get this */ + margc++; + cp++; + } + while ((c = *cp)) { + int inquote = 0; + while (isspace((unsigned char)c)) + c = *++cp; + if (c == '\0') + break; + *argp++ = cp; + cursor_argc = margc += 1; + base = cp; + for (cursor_argo = 0, cp2 = cp; c != '\0'; + cursor_argo = (cp + 1) - base, c = *++cp) { + if (inquote) { + if (c == inquote) { + inquote = 0; + continue; + } + } else { + if (c == '\\') { + if ((c = *++cp) == '\0') + break; + } else if (c == '"') { + inquote = '"'; + continue; + } else if (c == '\'') { + inquote = '\''; + continue; + } else if (isspace((unsigned char)c)) { + cursor_argo = 0; + break; + } + } + *cp2++ = c; + } + *cp2 = '\0'; + if (c == '\0') { + cursor_argc--; + break; + } + cp++; + } + *argp++ = 0; + if (cursor_pos == line) { + cursor_argc = 0; + cursor_argo = 0; + } +} blob - /dev/null blob + a5c39ddcf37cedf5347166188640b610e796ba30 (mode 644) --- /dev/null +++ prompt.c @@ -0,0 +1,83 @@ +/* + * Copyright (c) 2008-2009 Chris Cappuccio + * Copyright (c) 2023 Stefan Sperling + * + * 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 /* MAXHOSTNAMELEN */ +#include /* IFNAMSIZ */ + +#include + +#include +#include +#include + +#include "externs.h" +#include "commands.h" + +char prompt[128]; +char saved_prompt[sizeof(prompt)]; + +char * +cprompt(void) +{ + int pr; + char tmp[4]; + + if (cli_rtable) + snprintf(tmp, sizeof(tmp), "%d", cli_rtable); + + gethostname(hbuf, sizeof(hbuf)); + pr = priv | cli_rtable | config_mode; + snprintf(prompt, sizeof(prompt), "%s%s%s%s%s%s%s%s%s/", hbuf, + pr ? "(" : "", + config_mode ? "config" : "", + config_mode && priv ? "-" : "", + priv ? "p" : "", + (( priv && cli_rtable) || (config_mode && cli_rtable)) ? "-" : "", + cli_rtable ? "rtable " : "", cli_rtable ? tmp : "", + pr ?")" : ""); + + return(prompt); +} + +char * +iprompt(void) +{ + gethostname(hbuf, sizeof(hbuf)); + snprintf(prompt, sizeof(prompt), "%s(%s-%s)/", hbuf, + bridge ? "bridge" : "interface", ifname); + + return(prompt); +} + +char * +pprompt(void) +{ + return(prompt); +} + +void +setprompt(const char *s) +{ + strlcpy(saved_prompt, prompt, sizeof(saved_prompt)); + strlcpy(prompt, s, sizeof(prompt)); +} + +void +restoreprompt(void) +{ + strlcpy(prompt, saved_prompt, sizeof(prompt)); +}