summaryrefslogtreecommitdiff
path: root/lib/libfrr.c
diff options
context:
space:
mode:
authorDavid Lamparter <equinox@opensourcerouting.org>2017-08-06 07:35:50 +0200
committerDavid Lamparter <equinox@opensourcerouting.org>2017-08-08 11:14:05 +0200
commit689f5a8c84b95dbd31ecab481f8f2977965fe741 (patch)
tree7c2a2b69908b3c3ac60e0de41b5a3f85caec2ef5 /lib/libfrr.c
parent00857b241e6c27efad54a19b4226c37f04d80bf5 (diff)
*: remove --enable-tcp-zebra, rework ZAPI path
This adds "@tcp" as new choice on the -z option present in zebra and the protocol daemons. The --enable-tcp-zebra option on configure is no longer needed, both UNIX and TCP socket support is always available. Note that @tcp should not be used by default (e.g. in an init script), and --enable-tcp-zebra should never have been in any distro package builds, because **** TCP-ZEBRA IS A SECURITY PROBLEM **** It allows arbitrary local users to mess with the routing table and inject bogus data -- and also ZAPI is not designed to be robust against attacks. Signed-off-by: David Lamparter <equinox@opensourcerouting.org>
Diffstat (limited to 'lib/libfrr.c')
-rw-r--r--lib/libfrr.c107
1 files changed, 106 insertions, 1 deletions
diff --git a/lib/libfrr.c b/lib/libfrr.c
index 022296b3fb..e92456cf77 100644
--- a/lib/libfrr.c
+++ b/lib/libfrr.c
@@ -19,6 +19,7 @@
*/
#include <zebra.h>
+#include <sys/un.h>
#include "libfrr.h"
#include "getopt.h"
@@ -40,6 +41,7 @@ char frr_protoname[256] = "NONE";
char frr_protonameinst[256] = "NONE";
char config_default[256];
+char frr_zclientpath[256];
static char pidfile_default[256];
static char vtypath_default[256];
@@ -127,6 +129,100 @@ static const struct optspec os_user = {"u:g:",
lo_user};
+bool frr_zclient_addr(struct sockaddr_storage *sa, socklen_t *sa_len,
+ const char *path)
+{
+ memset(sa, 0, sizeof(*sa));
+
+ if (!path)
+ path = ZEBRA_SERV_PATH;
+
+ if (!strncmp(path, ZAPI_TCP_PATHNAME, strlen(ZAPI_TCP_PATHNAME))) {
+ int af;
+ int port = ZEBRA_PORT;
+ char *err = NULL;
+ struct sockaddr_in *sin = NULL;
+ struct sockaddr_in6 *sin6 = NULL;
+
+ path += strlen(ZAPI_TCP_PATHNAME);
+
+ switch (path[0]) {
+ case '4':
+ path++;
+ af = AF_INET;
+ break;
+ case '6':
+ path++;
+ /* fallthrough */
+ default:
+ af = AF_INET6;
+ break;
+ }
+
+ switch (path[0]) {
+ case '\0':
+ break;
+ case ':':
+ path++;
+ port = strtoul(path, &err, 10);
+ if (*err || !*path)
+ return false;
+ break;
+ default:
+ return false;
+ }
+
+ sa->ss_family = af;
+ switch (af) {
+ case AF_INET:
+ sin = (struct sockaddr_in *)sa;
+ sin->sin_port = htons(port);
+ sin->sin_addr.s_addr = htonl(INADDR_LOOPBACK);
+ *sa_len = sizeof(struct sockaddr_in);
+#ifdef HAVE_STRUCT_SOCKADDR_IN_SIN_LEN
+ sin->sin_len = *sa_len;
+#endif
+ break;
+ case AF_INET6:
+ sin6 = (struct sockaddr_in6 *)sa;
+ sin6->sin6_port = htons(port);
+ inet_pton(AF_INET6, "::1", &sin6->sin6_addr);
+ *sa_len = sizeof(struct sockaddr_in6);
+#ifdef SIN6_LEN
+ sin6->sin6_len = *sa_len;
+#endif
+ break;
+ }
+ } else {
+ /* "sun" is a #define on solaris */
+ struct sockaddr_un *suna = (struct sockaddr_un *)sa;
+
+ suna->sun_family = AF_UNIX;
+ strlcpy(suna->sun_path, path, sizeof(suna->sun_path));
+#ifdef HAVE_STRUCT_SOCKADDR_UN_SUN_LEN
+ *sa_len = suna->sun_len = SUN_LEN(suna);
+#else
+ *sa_len = sizeof(suna->sun_family) + strlen(suna->sun_path);
+#endif /* HAVE_STRUCT_SOCKADDR_UN_SUN_LEN */
+#if 0
+ /* this is left here for future reference; Linux abstract
+ * socket namespace support can be enabled by replacing
+ * above #if 0 with #ifdef GNU_LINUX.
+ *
+ * THIS IS A SECURITY ISSUE, the abstract socket namespace
+ * does not have user/group permission control on sockets.
+ * we'd need to implement SCM_CREDENTIALS support first to
+ * check that only proper users can connect to abstract
+ * sockets. (same problem as tcp-zebra, except there is a
+ * fix with SCM_CREDENTIALS. tcp-zebra has no such fix.)
+ */
+ if (suna->sun_path[0] == '@')
+ suna->sun_path[0] = '\0';
+#endif
+ }
+ return true;
+}
+
static struct frr_daemon_info *di = NULL;
void frr_preinit(struct frr_daemon_info *daemon, int argc, char **argv)
@@ -156,6 +252,8 @@ void frr_preinit(struct frr_daemon_info *daemon, int argc, char **argv)
strlcpy(frr_protoname, di->logname, sizeof(frr_protoname));
strlcpy(frr_protonameinst, di->logname, sizeof(frr_protonameinst));
+
+ strlcpy(frr_zclientpath, ZEBRA_SERV_PATH, sizeof(frr_zclientpath));
}
void frr_opt_add(const char *optstr, const struct option *longopts,
@@ -233,7 +331,7 @@ static int frr_opt(int opt)
case 'z':
if (di->flags & FRR_NO_ZCLIENT)
return 1;
- zclient_serv_path_set(optarg);
+ strlcpy(frr_zclientpath, optarg, sizeof(frr_zclientpath));
break;
case 'A':
if (di->flags & FRR_NO_TCPVTY)
@@ -341,6 +439,13 @@ struct thread_master *frr_init(void)
zlog_set_level(ZLOG_DEST_SYSLOG, zlog_default->default_lvl);
#endif
+ if (!frr_zclient_addr(&zclient_addr, &zclient_addr_len,
+ frr_zclientpath)) {
+ fprintf(stderr, "Invalid zserv socket path: %s\n",
+ frr_zclientpath);
+ exit(1);
+ }
+
frrmod_init(di->module);
while (modules) {
modules = (oc = modules)->next;