xref: /openbsd-src/usr.sbin/bgplgd/bgplgd.c (revision 5ffbcedbb1322a9a65053657189069e328d0b289)
1 /*	$OpenBSD: bgplgd.c,v 1.4 2024/12/03 10:38:06 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	5
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 	{ "/rib/in", { "show", "rib", "in", "detail", NULL }, QS_MASK_ADJRIB },
45 	{ "/rib/out", { "show", "rib", "out", "detail", NULL }, QS_MASK_ADJRIB },
46 	{ "/rtr", { "show", "rtr", NULL }, 0 },
47 	{ "/sets", { "show", "sets", NULL }, 0 },
48 	{ "/summary", { "show", NULL }, 0 },
49 	{ "/metrics", { "show", "metrics", NULL }, 0, 0, OMETRIC_TYPE },
50 	{ NULL }
51 };
52 
53 static int
54 command_from_path(const char *path, struct lg_ctx *ctx)
55 {
56 	size_t i;
57 
58 	for (i = 0; cmds[i].path != NULL; i++) {
59 		if (strcmp(cmds[i].path, path) == 0) {
60 			ctx->command = &cmds[i];
61 			ctx->qs_mask = cmds[i].qs_mask;
62 			return 0;
63 		}
64 	}
65 	return 404;
66 }
67 
68 /*
69  * Prepare a request into a context to call bgpctl.
70  * Parse method, path and querystring. On failure return the correct
71  * HTTP error code. On success 0 is returned.
72  */
73 int
74 prep_request(struct lg_ctx *ctx, const char *meth, const char *path,
75     const char *qs)
76 {
77 	if (meth == NULL || path == NULL)
78 		return 500;
79 	if (strcmp(meth, "GET") != 0)
80 		return 405;
81 	if (command_from_path(path, ctx) != 0)
82 		return 404;
83 	if (parse_querystring(qs, ctx) != 0)
84 		return 400;
85 
86 	return 0;
87 }
88 
89 /*
90  * Entry point from the FastCGI handler.
91  * This runs as an own process and must use STDOUT and STDERR.
92  * The log functions should no longer be used here.
93  */
94 void
95 bgpctl_call(struct lg_ctx *ctx)
96 {
97 	char *argv[64];
98 	size_t i, argc = 0;
99 
100 	argv[argc++] = bgpctlpath;
101 	argv[argc++] = "-j";
102 	argv[argc++] = "-s";
103 	argv[argc++] = bgpctlsock;
104 
105 	for (i = 0; ctx->command->args[i] != NULL; i++)
106 		argv[argc++] = ctx->command->args[i];
107 
108 	argc = qs_argv(argv, argc, sizeof(argv) / sizeof(argv[0]), ctx,
109 	    ctx->command->barenbr);
110 
111 	argv[argc++] = NULL;
112 
113 	signal(SIGPIPE, SIG_DFL);
114 
115 	/* Write server header first */
116 	if (ctx->command->content_type == NULL)
117 		printf("Content-type: application/json\r\n\r\n");
118 	else
119 		printf("Content-type: %s\r\n\r\n", ctx->command->content_type);
120 	fflush(stdout);
121 
122 	execvp(bgpctlpath, argv);
123 
124 	err(1, "failed to execute %s", bgpctlpath);
125 }
126