diff options
author | Reyk Floeter <reyk@cvs.openbsd.org> | 2006-12-11 23:10:12 +0000 |
---|---|---|
committer | Reyk Floeter <reyk@cvs.openbsd.org> | 2006-12-11 23:10:12 +0000 |
commit | dca2e871dbaa99af691bb17f8e8d7e3e6dffcc7f (patch) | |
tree | 4b36b889e47396a351e5ac4db4a6a2c53e593d07 /usr.bin | |
parent | f080cb987a578cdd447c3abd1e3772eadb52355e (diff) |
import a looking glass for bgpd(8) (CGI web interface), see the
bgplg(8) and bgplgsh(8) manpages for installation and usage
instructions.
this has been tested by various users and on openbgp route servers in
the DE-CIX.
ok deraadt@ henning@
Diffstat (limited to 'usr.bin')
-rw-r--r-- | usr.bin/bgplg/Makefile | 24 | ||||
-rw-r--r-- | usr.bin/bgplg/bgpctl/Makefile | 14 | ||||
-rw-r--r-- | usr.bin/bgplg/bgplg.8 | 177 | ||||
-rw-r--r-- | usr.bin/bgplg/bgplg.c | 374 | ||||
-rw-r--r-- | usr.bin/bgplg/bgplg.css | 4 | ||||
-rw-r--r-- | usr.bin/bgplg/bgplg.foot | 2 | ||||
-rw-r--r-- | usr.bin/bgplg/bgplg.h | 78 | ||||
-rw-r--r-- | usr.bin/bgplg/bgplg.head | 6 | ||||
-rw-r--r-- | usr.bin/bgplg/bgplg/Makefile | 19 | ||||
-rw-r--r-- | usr.bin/bgplg/bgplgsh.8 | 100 | ||||
-rw-r--r-- | usr.bin/bgplg/bgplgsh.c | 281 | ||||
-rw-r--r-- | usr.bin/bgplg/bgplgsh/Makefile | 18 | ||||
-rw-r--r-- | usr.bin/bgplg/index.html | 5 | ||||
-rw-r--r-- | usr.bin/bgplg/misc.c | 174 | ||||
-rw-r--r-- | usr.bin/bgplg/ping/Makefile | 14 | ||||
-rw-r--r-- | usr.bin/bgplg/traceroute/Makefile | 15 |
16 files changed, 1305 insertions, 0 deletions
diff --git a/usr.bin/bgplg/Makefile b/usr.bin/bgplg/Makefile new file mode 100644 index 00000000000..8342342ab7a --- /dev/null +++ b/usr.bin/bgplg/Makefile @@ -0,0 +1,24 @@ +# $OpenBSD: Makefile,v 1.1 2006/12/11 23:10:10 reyk Exp $ + +.include <bsd.own.mk> + +SUBDIR= bgplg bgplgsh bgpctl ping traceroute + +INCFILES= bgplg.head \ + bgplg.foot \ + bgplg.css + +WWWDIR= ${DESTDIR}/var/www/htdocs/bgplg +WWWFILES= openbgpd.gif \ + index.html + +distribution: + for i in ${INCFILES}; do \ + ${INSTALL} -C -o root -g wheel -m 0644 $$i ${DESTDIR}/var/www/conf/; \ + done + ${INSTALL} -d -o root -g wheel -m 0755 ${WWWDIR} + for i in ${WWWFILES}; do \ + ${INSTALL} -C -o root -g wheel -m 0644 $$i ${WWWDIR}; \ + done + +.include <bsd.subdir.mk> diff --git a/usr.bin/bgplg/bgpctl/Makefile b/usr.bin/bgplg/bgpctl/Makefile new file mode 100644 index 00000000000..a73d283fa95 --- /dev/null +++ b/usr.bin/bgplg/bgpctl/Makefile @@ -0,0 +1,14 @@ +# $OpenBSD: Makefile,v 1.1 2006/12/11 23:10:10 reyk Exp $ + +PROGDIR= ${.CURDIR}/../../../usr.sbin/bgpctl + +LDSTATIC= -static +CFLAGS+= -I${PROGDIR} -I${PROGDIR}/../bgpd +NOMAN= yes + +.include "${PROGDIR}/Makefile" + +BINDIR= /var/www/bin +BINMODE= 000 + +.PATH: ${PROGDIR} ${PROGDIR}/../bgpd diff --git a/usr.bin/bgplg/bgplg.8 b/usr.bin/bgplg/bgplg.8 new file mode 100644 index 00000000000..60c864c4492 --- /dev/null +++ b/usr.bin/bgplg/bgplg.8 @@ -0,0 +1,177 @@ +.\" $OpenBSD: bgplg.8,v 1.1 2006/12/11 23:10:10 reyk Exp $ +.\" +.\" Copyright (c) 2005, 2006 Reyk Floeter <reyk@vantronix.net> +.\" +.\" 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 August 12, 2005 +.Dt BGPLG 8 +.Os +.Sh NAME +.Nm bgplg +.Nd looking glass for the +.Ox +Border Gateway Protocol daemon +.Sh SYNOPSIS +.Nm bgplg +.Sh DESCRIPTION +The +.Nm +CGI program is a looking glass for the +.Xr bgpd 8 +Border Gateway Protocol daemon. +The looking glass will provide a simple web interface with read-only +access to a restricted set of +.Xr bgpd 8 +and system status information, which is typically used on route +servers by Internet Service Providers (ISPs) and Internet eXchange +points (IXs). +It is intended to be used in a +.Xr chroot 2 +environment in +.Pa /var/www . +.Pp +.Nm +is disabled by default. +It requires four steps to enable the looking glass: +.Bl -enum +.It +Update the file permission mode to allow the execution of the +.Nm +CGI program and the additional statically linked programs that have +been installed into the +.Xr chroot 2 +environment. +See the +.Sx FILES +section below for the list of installed programs. +.Pp +For example, +to allow execution of +.Nm +and the statically-linked version of +.Xr bgpctl 8 +(disabled commands like +.Xr ping 8 +and +.Xr traceroute 8 +will be hidden from looking glass command list): +.Bd -literal -offset indent +# chmod 0655 /var/www/cgi-bin/bgplg +# chmod 0655 /var/www/bin/bgpctl +.Ed +.It +The programs +.Xr ping 8 +and +.Xr traceroute 8 +will require a copy of the resolver configuration file +.Xr resolv.conf 5 +in the +.Xr chroot 2 +environment for optional host name lookups. +.Bd -literal -offset indent +# mkdir /var/www/etc +# cp /etc/resolv.conf /var/www/etc +.Ed +.It +Start the Border Gateway Protocol daemon with a second, +restricted, control socket that can be used +from within the +.Xr chroot 2 +environment. +See +.Xr bgpd 8 +for more information. +.Pp +For example, +set the following in +.Pa /etc/rc.conf.local +to start +.Xr bgpd 8 +using the second, restricted, control socket: +.Pp +.Dl bgpd_flags=\&"-r /var/www/logs/bgpd.rsock\&" +.Pp +.It +Start the Apache Hypertext Transfer Protocol Server. +See +.Xr httpd 8 +for more information. +.El +.Sh FILES +.Bl -tag -width "/var/www/conf/bgplg.headXX" -compact +.It Pa /var/www/conf/bgplg.css +Optional +.Nm +CSS style sheet. +.It Pa /var/www/conf/bgplg.head +Optional +.Nm +HTML header. +.It Pa /var/www/conf/bgplg.foot +Optional +.Nm +HTML footer. +.It Pa /var/www/logs/bgpd.rsock +Position of the second, restricted, control socket of +.Xr bgpd 8 . +.El +.Pp +The following statically linked executables have been installed into +the +.Xr chroot 2 +environment of the +.Xr httpd 8 +server. +To enable the corresponding functionality, use the +.Xr chmod 1 +utility to manually set the file permission mode to 0655 or anything +appropriate. +.Pp +.Bl -tag -width "/var/www/bin/tracerouteXX" -compact +.It Pa /var/www/cgi-bin/bgplg +The +.Nm +CGI executable. +.It Pa /var/www/bin/bgpctl +The +.Xr bgpctl 8 +program used to query information from +.Xr bgpd 8 +.It Pa /var/www/bin/ping +The +.Xr ping 8 +program used to send ICMP ECHO_REQUEST packets to network hosts. +.It Pa /var/www/bin/traceroute +The +.Xr traceroute 8 +program used to print the route packets take to network hosts. +.El +.Sh SEE ALSO +.Xr bgpctl 8 , +.Xr bgpd 8 , +.Xr bgplgsh 8 , +.Xr httpd 8 +.Sh HISTORY +The +.Nm +program first appeared in +.Ox 4.1 . +The initial implementation was done in 2005 for DE-CIX, the German +commercial internet exchange point. +.Sh AUTHORS +The +.Nm +program was written by +.An Reyk Floeter Aq reyk@vantronix.net . diff --git a/usr.bin/bgplg/bgplg.c b/usr.bin/bgplg/bgplg.c new file mode 100644 index 00000000000..d08bf08e7a6 --- /dev/null +++ b/usr.bin/bgplg/bgplg.c @@ -0,0 +1,374 @@ +/* $OpenBSD: bgplg.c,v 1.1 2006/12/11 23:10:10 reyk Exp $ */ + +/* + * Copyright (c) 2005, 2006 Reyk Floeter <reyk@vantronix.net> + * + * 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/stat.h> +#include <sys/types.h> +#include <sys/param.h> + +#include <stdio.h> +#include <stdlib.h> +#include <signal.h> +#include <string.h> +#include <unistd.h> +#include <ctype.h> +#include <errno.h> +#include <fcntl.h> + +#include "bgplg.h" + +#define INC_STYLE "/conf/bgplg.css" +#define INC_HEAD "/conf/bgplg.head" +#define INC_FOOT "/conf/bgplg.foot" + +#define BGPDSOCK "/logs/bgpd.rsock" +#define BGPCTL "/bin/bgpctl", "-s", BGPDSOCK +#define PING "/bin/ping" +#define TRACEROUTE "/bin/traceroute" + +static struct cmd cmds[] = CMDS; + +char *lg_getenv(const char *, int *); +void lg_urldecode(char *); +char **lg_arg2argv(char *, int *); +char **lg_argextra(char **, int, struct cmd *); +char *lg_getarg(const char *, char *, int); +int lg_incl(const char *); + +void +lg_urldecode(char *str) +{ + size_t i, c, len; + char code[3]; + long result; + + if (str && *str) { + len = strlen(str); + i = c = 0; + while (i < len) { + if (str[i] == '%' && i <= (len - 2)) { + if (isxdigit(str[i + 1]) && + isxdigit(str[i + 2])) { + code[0] = str[i + 1]; + code[1] = str[i + 2]; + code[2] = 0; + result = strtol(code, NULL, 16); + /* Replace NUL chars with a space */ + if (result == 0) + result = ' '; + str[c++] = result; + i += 3; + } else { + str[c++] = '%'; + i++; + } + } else if (str[i] == '+') { + str[i] = ' '; + } else { + if (c != i) + str[c] = str[i]; + c++; + i++; + } + } + str[c] = 0x0; + } +} + +char * +lg_getenv(const char *name, int *lenp) +{ + size_t len; + u_int i; + char *ptr; + + if ((ptr = getenv(name)) == NULL) + return (NULL); + + lg_urldecode(ptr); + + if (!(len = strlen(ptr))) + return (NULL); + + if (lenp != NULL) + *lenp = len; + +#define allowed_in_string(_x) \ + ((isalnum(_x) || isprint(_x)) && \ + (_x != '%' && _x != '\\' && _x != ';' && _x != '|')) + + for (i = 0; i < len; i++) { + if (!allowed_in_string(ptr[i])) { + printf("invalid character in input\n"); + return (NULL); + } + if (ptr[i] == '&') + ptr[i] = '\0'; + } + + return (ptr); +} + +char * +lg_getarg(const char *name, char *arg, int len) +{ + char *ptr = arg; + size_t namelen, ptrlen; + int i; + + namelen = strlen(name); + + for (i = 0; i < len; i++) { + if (arg[i] == '\0') + continue; + ptr = arg + i; + ptrlen = strlen(ptr); + if (namelen >= ptrlen) + continue; + if (strncmp(name, ptr, namelen) == 0) + return (ptr + namelen); + } + + return (NULL); +} + +char ** +lg_arg2argv(char *arg, int *argc) +{ + char **argv, *ptr = arg; + size_t len; + u_int i, c = 1; + + len = strlen(arg); + + /* Count elements */ + for (i = 0; i < (len - 1); i++) { + if (isspace(arg[i])) { + /* filter out additional options */ + if (arg[i + 1] == '-') { + printf("invalid input\n"); + return (NULL); + } + arg[i] = '\0'; + c++; + } + } + + /* Generate array */ + if ((argv = calloc(c + 1, sizeof(char *))) == NULL) { + printf("fatal error: %s\n", strerror(errno)); + return (NULL); + } + + argv[c] = NULL; + *argc = c; + + /* Fill array */ + for (i = c = 0; i < (len - 1); i++) { + if (arg[i] == '\0' || i == 0) { + if (i != 0) + ptr = &arg[i + 1]; + argv[c++] = ptr; + } + } + + return (argv); +} + +char ** +lg_argextra(char **argv, int argc, struct cmd *cmdp) +{ + char **new_argv; + int i, c = 0; + + /* Count elements */ + for (i = 0; cmdp->earg[i] != NULL; i++) + c++; + + /* Generate array */ + if ((new_argv = calloc(c + argc + 1, sizeof(char *))) == NULL) { + printf("fatal error: %s\n", strerror(errno)); + return (NULL); + } + + /* Fill array */ + for (i = c = 0; cmdp->earg[i] != NULL; i++) + new_argv[c++] = cmdp->earg[i]; + + /* Append old array */ + for (i = 0; i < argc; i++) + new_argv[c++] = argv[i]; + + new_argv[c] = NULL; + + if (argv != NULL) + free(argv); + + return (new_argv); +} + +int +lg_incl(const char *file) +{ + char buf[BUFSIZ]; + int fd, len; + + if ((fd = open(file, O_RDONLY)) == -1) + return (errno); + + do { + len = read(fd, buf, sizeof(buf)); + fwrite(buf, len, 1, stdout); + } while(len == BUFSIZ); + + return (0); +} + +int +main(void) +{ + char *query, *self, *cmd = NULL, *req; + char **argv = NULL; + char myname[MAXHOSTNAMELEN]; + int ret = 1, argc = 0, query_length = 0; + struct stat st; + u_int i; + struct cmd *cmdp = NULL; + + printf("Content-Type: text/html\n" + "Cache-Control: no-cache\n\n" + "<html>\n" + "<head>\n" + "<title>bgplg</title>\n"); + if (stat(INC_STYLE, &st) == 0) { + printf("<style type='text/css'><!--\n"); + lg_incl(INC_STYLE); + printf("--></style>\n"); + } + if (stat(INC_HEAD, &st) != 0 || lg_incl(INC_HEAD) != 0) { + printf("</head>\n" + "<body>\n"); + } + + if (gethostname(myname, sizeof(myname)) != 0) + goto err; + + printf("<h1>%s: %s</h1>\n", NAME, myname); + printf("<h2>%s</h2>\n", BRIEF); + + /* print a form with possible options */ + if ((self = lg_getenv("SCRIPT_NAME", NULL)) == NULL) { + printf("fatal error: invalid request\n"); + goto err; + } + if ((query = lg_getenv("QUERY_STRING", &query_length)) != NULL) + cmd = lg_getarg("cmd=", query, query_length); + printf("<form action='%s'>\n" + "<select name='cmd'>\n", + self); + for (i = 0; cmds[i].name != NULL; i++) { + if (!lg_checkperm(&cmds[i])) + continue; + + if (cmd != NULL && strcmp(cmd, cmds[i].name) == 0) + printf("<option value='%s' selected='selected'>%s" + "</option>\n", + cmds[i].name, cmds[i].name); + else + printf("<option value='%s'>%s</option>\n", + cmds[i].name, cmds[i].name); + } + printf("</select>\n" + "<input type='text' name='req'/>\n" + "<input type='submit' value='submit'/>\n" + "</form>\n" + "<pre>\n"); + fflush(stdout); + +#ifdef DEBUG + if (close(2) == -1 || dup2(1, 2) == -1) +#else + if (close(2) == -1) +#endif + { + printf("fatal error: %s\n", strerror(errno)); + goto err; + } + + if (query == NULL) + goto err; + if (cmd == NULL) { + printf("unspecified command\n"); + goto err; + } + if ((req = lg_getarg("req=", query, query_length)) != NULL) { + /* Could be NULL */ + argv = lg_arg2argv(req, &argc); + } + + for (i = 0; cmds[i].name != NULL; i++) { + if (strcmp(cmd, cmds[i].name) == 0) { + cmdp = &cmds[i]; + break; + } + } + + if (cmdp == NULL) { + printf("invalid command: %s\n", cmd); + goto err; + } + if (argc > cmdp->maxargs) { + printf("superfluous argument(s): %s %s\n", + cmd, cmdp->args ? cmdp->args : ""); + goto err; + } + if (argc < cmdp->minargs) { + printf("missing argument(s): %s %s\n", cmd, cmdp->args); + goto err; + } + + if (cmdp->func != NULL) { + ret = cmdp->func(cmds, argv); + } else { + if ((argv = lg_argextra(argv, argc, cmdp)) == NULL) + goto err; + ret = lg_exec(cmdp->earg[0], argv); + } + if (ret != 0) + printf("\nfailed%s\n", ret == 127 ? ": file not found" : "."); + else + printf("\nsuccess.\n"); + + err: + fflush(stdout); + + if (argv != NULL); + free(argv); + + printf("</pre>\n"); + + if (stat(INC_FOOT, &st) != 0 || lg_incl(INC_FOOT) != 0) + printf("<hr/>\n"); + + printf("<div class='footer'>\n" + "<small>%s - %s<br/>Copyright (c) %s</small>\n" + "</div>\n" + "</body>\n" + "</html>\n", NAME, BRIEF, COPYRIGHT); + + return (ret); +} diff --git a/usr.bin/bgplg/bgplg.css b/usr.bin/bgplg/bgplg.css new file mode 100644 index 00000000000..92a509f140b --- /dev/null +++ b/usr.bin/bgplg/bgplg.css @@ -0,0 +1,4 @@ +.footer { + text-align: left; + width: 100%; +} diff --git a/usr.bin/bgplg/bgplg.foot b/usr.bin/bgplg/bgplg.foot new file mode 100644 index 00000000000..d5ce3a7ed63 --- /dev/null +++ b/usr.bin/bgplg/bgplg.foot @@ -0,0 +1,2 @@ +</div> +<hr/> diff --git a/usr.bin/bgplg/bgplg.h b/usr.bin/bgplg/bgplg.h new file mode 100644 index 00000000000..dd403cb28d2 --- /dev/null +++ b/usr.bin/bgplg/bgplg.h @@ -0,0 +1,78 @@ +/* $OpenBSD: bgplg.h,v 1.1 2006/12/11 23:10:10 reyk Exp $ */ + +/* + * Copyright (c) 2005, 2006 Reyk Floeter <reyk@vantronix.net> + * + * 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. + */ + +#ifndef _BGPLG_H +#define _BGPLG_H + +#define NAME "bgplg" +#define BRIEF "a looking glass for OpenBGPD" +#define COPYRIGHT "2005, 2006 Reyk Floeter (reyk@vantronix.net)" + +#define BGPLG_TIMEOUT 60 /* 60 seconds */ + +struct cmd { + const char *name; + int minargs; + int maxargs; + const char *args; + char *earg[255]; + int (*func)(struct cmd *, char **); +}; + +#define CMDS { \ + { "show ip bgp", 0, 1, NULL, \ + { BGPCTL, "show", "ip", "bgp", NULL } }, \ + { "show ip bgp as", 1, 1, "<asnum>", \ + { BGPCTL, "show", "ip", "bgp", "as", NULL } }, \ + { "show ip bgp source-as", 1, 1, "<asnum>", \ + { BGPCTL, "show", "ip", "bgp", "as", NULL } }, \ + { "show ip bgp transit-as", 1, 1, "<asnum>", \ + { BGPCTL, "show", "ip", "bgp", "transit-as", NULL } }, \ + { "show ip bgp empty-as", 0, 0, NULL, \ + { BGPCTL, "show", "ip", "bgp", "empty-as", NULL } }, \ + { "show ip bgp summary", 0, 0, NULL, \ + { BGPCTL, "show", "ip", "bgp", "summary", NULL } }, \ + { "show ip bgp detail", 0, 1, NULL, \ + { BGPCTL, "show","ip", "bgp", "detail", NULL } }, \ + { "show ip bgp in", 0, 1, NULL, \ + { BGPCTL, "show","ip", "bgp", "in", NULL } }, \ + { "show ip bgp out", 0, 1, NULL, \ + { BGPCTL, "show","ip", "bgp", "out", NULL } }, \ + { "show ip bgp memory", 0, 0, NULL, \ + { BGPCTL, "show", "ip", "bgp", "memory", NULL } }, \ + { "show neighbor", 0, 1, NULL, \ + { BGPCTL, "show", "neighbor", NULL } }, \ + { "show nexthop", 0, 0, NULL, \ + { BGPCTL, "show", "nexthop", NULL } }, \ + { "show version", 0, 0, NULL, { NULL }, lg_show_version }, \ + { "traceroute", 1, 1, "<address>", \ + { TRACEROUTE, "-Sl", NULL } }, \ + { "ping", 1, 1, "<address>", \ + { PING, "-c4", "-w2", NULL } }, \ + { "?", 0, 0, NULL, { NULL }, lg_help }, \ + { NULL } \ +} + +int lg_show_version(struct cmd *, char **); +int lg_help(struct cmd *, char **); +int lg_exec(const char *, char **); +int lg_checkperm(struct cmd *); +void lg_sig_alarm(int); +ssize_t lg_strip(char *); + +#endif /* _BGPLG_H */ diff --git a/usr.bin/bgplg/bgplg.head b/usr.bin/bgplg/bgplg.head new file mode 100644 index 00000000000..85b85a76c62 --- /dev/null +++ b/usr.bin/bgplg/bgplg.head @@ -0,0 +1,6 @@ +</head> +<body style="text-align: center"> +<div style="margin: 0px auto; text-align: left; width: 599px;"> +<a href="http://www.openbgp.org/"> +<img src="/bgplg/openbgpd.gif" border="0"/> +</a> diff --git a/usr.bin/bgplg/bgplg/Makefile b/usr.bin/bgplg/bgplg/Makefile new file mode 100644 index 00000000000..ef2579dc184 --- /dev/null +++ b/usr.bin/bgplg/bgplg/Makefile @@ -0,0 +1,19 @@ +# $OpenBSD: Makefile,v 1.1 2006/12/11 23:10:11 reyk Exp $ + +.PATH: ${.CURDIR}/.. + +PROG= bgplg +SRCS= bgplg.c misc.c +CFLAGS+= -Wall +CFLAGS+= -Wstrict-prototypes -Wmissing-prototypes +CLFAGS+= -Wmissing-declarations -Wredundant-decls +CFLAGS+= -Wshadow -Wpointer-arith -Wcast-qual +CFLAGS+= -Wsign-compare +CFLAGS+= -I${.CURDIR} +LDSTATIC= -static +MAN= bgplg.8 + +BINDIR= /var/www/cgi-bin +BINMODE= 000 + +.include <bsd.prog.mk> diff --git a/usr.bin/bgplg/bgplgsh.8 b/usr.bin/bgplg/bgplgsh.8 new file mode 100644 index 00000000000..6a3d95180aa --- /dev/null +++ b/usr.bin/bgplg/bgplgsh.8 @@ -0,0 +1,100 @@ +.\" $OpenBSD: bgplgsh.8,v 1.1 2006/12/11 23:10:10 reyk Exp $ +.\" +.\" Copyright (c) 2005, 2006 Reyk Floeter <reyk@vantronix.net> +.\" +.\" 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 August 12, 2005 +.Dt BGPLG 8 +.Os +.Sh NAME +.Nm bgplgsh +.Nd looking glass shell for the +.Ox +Border Gateway Protocol daemon +.Sh SYNOPSIS +.Nm bgplgsh +.Sh DESCRIPTION +The +.Nm +program is a looking glass shell for the +.Xr bgpd 8 +Border Gateway Protocol daemon. +The looking glass will provide a simple command line interface +with read-only access to a restricted set of +.Xr bgpd 8 +and system status information, which is typically used on route +servers by Internet Service Providers (ISPs) and Internet eXchange +points (IXs). +.Pp +It requires three steps to enable the looking glass shell: +.Bl -enum +.It +Add +.Nm +as a valid login shell. +See +.Xr shells 5 +for more information. +.Bd -literal -offset indent +# echo /usr/bin/bgplgsh \*(Gt\*(Gt /etc/shells +.Ed +.Pp +.It +Create a new user for restricted looking glass access. +See +.Xr adduser 8 +for more information about system user management. +.Bd -literal -offset indent +# adduser -shell /usr/bin/bgplgsh -batch bgplg +# passwd bgplg +.Ed +.It +Start the Border Gateway Protocol daemon with a second, +restricted, control socket. +See +.Xr bgpd 8 +and +.Xr bgplg 8 +for more information. +.Pp +For example, +set the following in +.Pa /etc/rc.conf.local +to start +.Xr bgpd 8 +using the second, restricted, control socket: +.Pp +.Dl bgpd_flags=\&"-r /var/www/logs/bgpd.rsock\&" +.El +.Sh FILES +.Bl -tag -width "/var/www/conf/bgpd.rsockXX" -compact +.It Pa /var/www/logs/bgpd.rsock +Position of the second, restricted, control socket of +.Xr bgpd 8 . +.El +.Sh SEE ALSO +.Xr bgpd 8 , +.Xr bgplg 8 +.Sh HISTORY +The +.Nm +program first appeared in +.Ox 4.1 . +The initial implementation was done in 2005 for DE-CIX, the German +commercial internet exchange point. +.Sh AUTHORS +The +.Nm +program was written by +.An Reyk Floeter Aq reyk@vantronix.net . diff --git a/usr.bin/bgplg/bgplgsh.c b/usr.bin/bgplg/bgplgsh.c new file mode 100644 index 00000000000..ef719699ce6 --- /dev/null +++ b/usr.bin/bgplg/bgplgsh.c @@ -0,0 +1,281 @@ +/* $OpenBSD: bgplgsh.c,v 1.1 2006/12/11 23:10:10 reyk Exp $ */ + +/* + * Copyright (c) 2005, 2006 Reyk Floeter <reyk@vantronix.net> + * + * 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/stat.h> +#include <sys/types.h> +#include <sys/param.h> + +#include <stdio.h> +#include <stdlib.h> +#include <signal.h> +#include <string.h> +#include <unistd.h> +#include <ctype.h> +#include <errno.h> +#include <fcntl.h> + +#include <readline/readline.h> +#include <readline/history.h> + +#include "bgplg.h" + +#define BGPDSOCK "/var/www/logs/bgpd.rsock" +#define BGPCTL "/usr/sbin/bgpctl", "-s", BGPDSOCK +#define PING "/sbin/ping" +#define TRACEROUTE "/usr/sbin/traceroute" + +static volatile int quit; + +static struct cmd cmds[] = CMDS; + +char **lg_arg2argv(char *, int *); +char **lg_argextra(char **, int, int, struct cmd *); +int lg_checkarg(char *); +int lg_checkcmd(int, char **, int *, struct cmd *); +char *lg_completion(const char *, int); + +int +lg_checkarg(char *arg) +{ + size_t len; + u_int i; + + if (!(len = strlen(arg))) + return (0); + +#define allowed_in_string(_x) \ + ((isalnum(_x) || isprint(_x)) && \ + (_x != '%' && _x != '\\' && _x != ';' && _x != '&' && _x != '|')) + + for (i = 0; i < len; i++) { + if (!allowed_in_string(arg[i])) { + fprintf(stderr, "invalid character in input\n"); + return (EPERM); + } + } + + return (0); +} + +char ** +lg_arg2argv(char *arg, int *argc) +{ + char **argv, *ptr = arg; + size_t len; + u_int i, c = 1; + + if (lg_checkarg(arg) != 0) + return (NULL); + if (!(len = strlen(arg))) + return (NULL); + + /* Count elements */ + for (i = 0; i < len; i++) { + if (isspace(arg[i])) { + /* filter out additional options */ + if (arg[i + 1] == '-') { + printf("invalid input\n"); + return (NULL); + } + arg[i] = '\0'; + c++; + } + } + if (arg[0] == '\0') + return (NULL); + + /* Generate array */ + if ((argv = calloc(c + 1, sizeof(char *))) == NULL) { + printf("fatal error: %s\n", strerror(errno)); + return (NULL); + } + + argv[c] = NULL; + *argc = c; + + /* Fill array */ + for (i = c = 0; i < len; i++) { + if (arg[i] == '\0' || i == 0) { + if (i != 0) + ptr = &arg[i + 1]; + argv[c++] = ptr; + } + } + + return (argv); +} + +char ** +lg_argextra(char **argv, int argc, int off, struct cmd *cmdp) +{ + char **new_argv; + int i, c = 0, n; + + if ((n = argc - off) < 0) + return (NULL); + + /* Count elements */ + for (i = 0; cmdp->earg[i] != NULL; i++) + c++; + + /* Generate array */ + if ((new_argv = calloc(c + n + 1, sizeof(char *))) == NULL) { + printf("fatal error: %s\n", strerror(errno)); + return (NULL); + } + + /* Fill array */ + for (i = c = 0; cmdp->earg[i] != NULL; i++) + new_argv[c++] = cmdp->earg[i]; + + /* Append old array */ + for (i = n; i < argc; i++) + new_argv[c++] = argv[i]; + + new_argv[c] = NULL; + + if (argv != NULL) + free(argv); + + return (new_argv); +} + +int +lg_checkcmd(int argc, char **argv, int *off, struct cmd *cmd) +{ + char **cmdp = NULL, *cmdstr = NULL; + int i, ncmd, v, ret = -1; + + if ((cmdstr = strdup(cmd->name)) == NULL) + goto done; + if ((cmdp = lg_arg2argv(cmdstr, &ncmd)) == NULL) + goto done; + if (ncmd > argc || argc > (ncmd + cmd->maxargs)) + goto done; + + for (i = 0; i < ncmd; i++) + if (strcmp(argv[i], cmdp[i]) != 0) + goto done; + + if ((v = argc - ncmd) < 0 || + (*off != -1 && *off < v)) + goto done; + if (cmd->minargs && v < cmd->minargs) { + ret = EINVAL; + goto done; + } + *off = v; + ret = 0; + + done: + if (cmdp != NULL) + free(cmdp); + if (cmdstr != NULL) + free(cmdstr); + return (ret); +} + +char * +lg_completion(const char *str, int state) +{ + static int lg_complidx, len; + const char *name; + + if (state == 0) { + len = strlen(str); + lg_complidx = 0; + } + while ((name = cmds[lg_complidx].name) != NULL) { + lg_complidx++; + if (strncmp(name, str, len) == 0) + return (strdup(name)); + } + + return (NULL); +} + +int +main(void) +{ + struct cmd *cmd = NULL; + char prompt[MAXHOSTNAMELEN], *line, **argp = NULL; + int ncmd, ret, v = -1; + u_int i; + + rl_readline_name = NAME; + rl_completion_entry_function = lg_completion; + + /* Ignore the whitespace character */ + rl_basic_word_break_characters = "\t\n\"\\'`@$><=;|&{("; + + while (!quit) { + v = -1; + gethostname(prompt, sizeof(prompt) - 2); + strlcat(prompt, "> ", sizeof(prompt)); + + if ((line = readline(prompt)) == NULL) { + printf("\n"); + lg_help(cmds, NULL); + continue; + } + if (!lg_strip(line)) + goto next; + if (strcmp(line, "exit") == 0) { + quit = 1; + goto next; + } + + add_history(line); + + if ((argp = lg_arg2argv(line, &ncmd)) == NULL) + goto next; + + for (i = 0; cmds[i].name != NULL; i++) { + ret = lg_checkcmd(ncmd, argp, &v, &cmds[i]); + if (ret == 0) + cmd = &cmds[i]; + else if (ret == EINVAL) { + printf("invalid number of arguments\n"); + goto next; + } + } + + if (cmd == NULL) { + printf("invalid command\n"); + } else if (cmd->func != NULL) { + cmd->func(cmds, argp); + } else { + if ((argp = lg_argextra(argp, ncmd, v, cmd)) == NULL) + goto next; + lg_exec(cmd->earg[0], argp); + } + + next: + if (argp != NULL) { + free(argp); + argp = NULL; + } + if (line != NULL) { + free(line); + line = NULL; + } + cmd = NULL; + } + + return (0); +} diff --git a/usr.bin/bgplg/bgplgsh/Makefile b/usr.bin/bgplg/bgplgsh/Makefile new file mode 100644 index 00000000000..1f8c96a5c62 --- /dev/null +++ b/usr.bin/bgplg/bgplgsh/Makefile @@ -0,0 +1,18 @@ +# $OpenBSD: Makefile,v 1.1 2006/12/11 23:10:11 reyk Exp $ + +.PATH: ${.CURDIR}/.. + +PROG= bgplgsh +SRCS= bgplgsh.c misc.c +CFLAGS+= -Wall +CFLAGS+= -Wstrict-prototypes -Wmissing-prototypes +CLFAGS+= -Wmissing-declarations -Wredundant-decls +CFLAGS+= -Wshadow -Wpointer-arith -Wcast-qual +CFLAGS+= -Wsign-compare +CFLAGS+= -I${.CURDIR} +LDADD= -ledit -lncurses +MAN= bgplgsh.8 + +BINDIR= /usr/bin + +.include <bsd.prog.mk> diff --git a/usr.bin/bgplg/index.html b/usr.bin/bgplg/index.html new file mode 100644 index 00000000000..743b97512ae --- /dev/null +++ b/usr.bin/bgplg/index.html @@ -0,0 +1,5 @@ +<html> +<head> + <meta http-equiv="refresh" content="1; URL=/cgi-bin/bgplg"/> +</head> +</html> diff --git a/usr.bin/bgplg/misc.c b/usr.bin/bgplg/misc.c new file mode 100644 index 00000000000..f62bf31dd85 --- /dev/null +++ b/usr.bin/bgplg/misc.c @@ -0,0 +1,174 @@ +/* $OpenBSD: misc.c,v 1.1 2006/12/11 23:10:10 reyk Exp $ */ + +/* + * Copyright (c) 2005, 2006 Reyk Floeter <reyk@vantronix.net> + * + * 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/stat.h> +#include <sys/types.h> +#include <sys/utsname.h> +#include <sys/wait.h> +#include <sys/time.h> + +#include <stdio.h> +#include <stdlib.h> +#include <signal.h> +#include <string.h> +#include <unistd.h> +#include <ctype.h> +#include <errno.h> +#include <fcntl.h> + +#include "bgplg.h" + +static volatile pid_t child = -1; + +int +lg_show_version(struct cmd *cmds, char **argv) +{ + struct utsname uts; + if (uname(&uts) == 0) + printf("%s %s (%s)\n\n", uts.sysname, uts.release, uts.machine); + printf("%s - %s\n", NAME, BRIEF); + return (0); +} + +int +lg_checkperm(struct cmd *cmd) +{ + struct stat stbuf; + + /* No external command to execute, this is always valid */ + if (cmd->earg == NULL || cmd->earg[0] == NULL) + return (1); + + /* + * Skip commands if the executable is missing or + * the permission mode has been set to zero (the default + * in a CGI environment). + */ + if (stat(cmd->earg[0], &stbuf) != 0 || + (stbuf.st_mode & ~S_IFMT) == 0) + return (0); + + return (1); +} + +int +lg_help(struct cmd *cmds, char **argv) +{ + u_int i; + + printf("valid commands:\n"); + for (i = 0; cmds[i].name != NULL; i++) { + if (!lg_checkperm(&cmds[i])) + continue; + + printf(" %s", cmds[i].name); + if (cmds[i].minargs > 0) + printf(" { arg }"); + else if (cmds[i].maxargs > 0) + printf(" [ arg ]"); + printf("\n"); + } + return (0); +} + +void +lg_sig_alarm(int sig) +{ + if (child != -1) { + /* Forceibly kill the child, no excuse... */ + kill(child, SIGKILL); + } +} + +int +lg_exec(const char *file, char **new_argv) +{ + int status = 0, ret = 0; + sig_t save_quit, save_int, save_chld; + struct itimerval it; + + if (new_argv == NULL) + return (EFAULT); + + save_quit = signal(SIGQUIT, SIG_IGN); + save_int = signal(SIGINT, SIG_IGN); + save_chld = signal(SIGCHLD, SIG_DFL); + + switch (child = fork()) { + case -1: + ret = errno; + goto done; + case 0: + signal(SIGQUIT, SIG_DFL); + signal(SIGINT, SIG_DFL); + signal(SIGCHLD, SIG_DFL); + + execvp(file, new_argv); + _exit(127); + break; + default: + /* Kill the process after a timeout */ + signal(SIGALRM, lg_sig_alarm); + bzero(&it, sizeof(it)); + it.it_value.tv_sec = BGPLG_TIMEOUT; + setitimer(ITIMER_REAL, &it, NULL); + + waitpid(child, &status, 0); + break; + } + + switch (ret) { + case -1: + ret = ECHILD; + break; + default: + if (WIFEXITED(status)) + ret = WEXITSTATUS(status); + else + ret = ECHILD; + } + + done: + /* Disable the process timeout timer */ + bzero(&it, sizeof(it)); + setitimer(ITIMER_REAL, &it, NULL); + child = -1; + + signal(SIGQUIT, save_quit); + signal(SIGINT, save_int); + signal(SIGCHLD, save_chld); + signal(SIGALRM, SIG_DFL); + + return (ret); +} + +ssize_t +lg_strip(char *str) +{ + size_t len; + + if ((len = strlen(str)) < 1) + return (0); /* XXX EINVAL? */ + + if (isspace(str[len - 1])) { + str[len - 1] = '\0'; + return (lg_strip(str)); + } + + return (strlen(str)); +} diff --git a/usr.bin/bgplg/ping/Makefile b/usr.bin/bgplg/ping/Makefile new file mode 100644 index 00000000000..ede97cb99e2 --- /dev/null +++ b/usr.bin/bgplg/ping/Makefile @@ -0,0 +1,14 @@ +# $OpenBSD: Makefile,v 1.1 2006/12/11 23:10:11 reyk Exp $ + +PROGDIR= ${.CURDIR}/../../../sbin/ping + +LDSTATIC= -static +CFLAGS+= -I${PROGDIR} +NOMAN= yes + +.include "${PROGDIR}/Makefile" + +BINDIR= /var/www/bin +BINMODE= 000 + +.PATH: ${PROGDIR} diff --git a/usr.bin/bgplg/traceroute/Makefile b/usr.bin/bgplg/traceroute/Makefile new file mode 100644 index 00000000000..8942afbac39 --- /dev/null +++ b/usr.bin/bgplg/traceroute/Makefile @@ -0,0 +1,15 @@ +# $OpenBSD: Makefile,v 1.1 2006/12/11 23:10:11 reyk Exp $ + +PROGDIR= ${.CURDIR}/../../../usr.sbin/traceroute + +LDSTATIC= -static +CFLAGS+= -I${PROGDIR} +NOMAN= yes + +.include "${PROGDIR}/Makefile" + +BINDIR= /var/www/bin +BINMODE= 000 + +.PATH: ${PROGDIR} + |