xref: /openbsd/usr.sbin/bgplgd/bgplgd.c (revision 5dea098c)
1 /*	$OpenBSD: bgplgd.c,v 1.3 2022/10/17 15:42:19 claudio Exp $ */
2 /*
3  * Copyright (c) 2020 Claudio Jeker <claudio@openbsd.org>
4  *
5  * Permission to use, copy, modify, and distribute this software for any
6  * purpose with or without fee is hereby granted, provided that the above
7  * copyright notice and this permission notice appear in all copies.
8  *
9  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
10  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
11  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
12  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
13  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
14  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
15  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
16  */
17 
18 #include <sys/queue.h>
19 #include <err.h>
20 #include <signal.h>
21 #include <stdlib.h>
22 #include <stdio.h>
23 #include <string.h>
24 #include <unistd.h>
25 
26 #include "bgplgd.h"
27 
28 #define NCMDARGS	4
29 #define OMETRIC_TYPE	\
30 	    "application/openmetrics-text; version=1.0.0; charset=utf-8"
31 
32 const struct cmd {
33 	const char	*path;
34 	char		*args[NCMDARGS];
35 	unsigned int	qs_mask;
36 	int		barenbr;
37 	const char	*content_type;
38 } cmds[] = {
39 	{ "/interfaces", { "show", "interfaces", NULL }, 0 },
40 	{ "/memory", { "show", "rib", "memory", NULL }, 0 },
41 	{ "/neighbors", { "show", "neighbor", NULL }, QS_MASK_NEIGHBOR, 1 },
42 	{ "/nexthops", { "show", "nexthop", NULL }, 0 },
43 	{ "/rib", { "show", "rib", "detail", NULL }, QS_MASK_RIB },
44 	{ "/rtr", { "show", "rtr", NULL }, 0 },
45 	{ "/sets", { "show", "sets", NULL }, 0 },
46 	{ "/summary", { "show", NULL }, 0 },
47 	{ "/metrics", { "show", "metrics", NULL }, 0, 0, OMETRIC_TYPE },
48 	{ NULL }
49 };
50 
51 static int
52 command_from_path(const char *path, struct lg_ctx *ctx)
53 {
54 	size_t i;
55 
56 	for (i = 0; cmds[i].path != NULL; i++) {
57 		if (strcmp(cmds[i].path, path) == 0) {
58 			ctx->command = &cmds[i];
59 			ctx->qs_mask = cmds[i].qs_mask;
60 			return 0;
61 		}
62 	}
63 	return 404;
64 }
65 
66 /*
67  * Prepare a request into a context to call bgpctl.
68  * Parse method, path and querystring. On failure return the correct
69  * HTTP error code. On success 0 is returned.
70  */
71 int
72 prep_request(struct lg_ctx *ctx, const char *meth, const char *path,
73     const char *qs)
74 {
75 	if (meth == NULL || path == NULL)
76 		return 500;
77 	if (strcmp(meth, "GET") != 0)
78 		return 405;
79 	if (command_from_path(path, ctx) != 0)
80 		return 404;
81 	if (parse_querystring(qs, ctx) != 0)
82 		return 400;
83 
84 	return 0;
85 }
86 
87 /*
88  * Entry point from the FastCGI handler.
89  * This runs as an own process and must use STDOUT and STDERR.
90  * The log functions should no longer be used here.
91  */
92 void
93 bgpctl_call(struct lg_ctx *ctx)
94 {
95 	char *argv[64];
96 	size_t i, argc = 0;
97 
98 	argv[argc++] = bgpctlpath;
99 	argv[argc++] = "-j";
100 	argv[argc++] = "-s";
101 	argv[argc++] = bgpctlsock;
102 
103 	for (i = 0; ctx->command->args[i] != NULL; i++)
104 		argv[argc++] = ctx->command->args[i];
105 
106 	argc = qs_argv(argv, argc, sizeof(argv) / sizeof(argv[0]), ctx,
107 	    ctx->command->barenbr);
108 
109 	argv[argc++] = NULL;
110 
111 	signal(SIGPIPE, SIG_DFL);
112 
113 	/* Write server header first */
114 	if (ctx->command->content_type == NULL)
115 		printf("Content-type: application/json\r\n\r\n");
116 	else
117 		printf("Content-type: %s\r\n\r\n", ctx->command->content_type);
118 	fflush(stdout);
119 
120 	execvp(bgpctlpath, argv);
121 
122 	err(1, "failed to execute %s", bgpctlpath);
123 }
124