diff options
| author | David Lamparter <equinox@opensourcerouting.org> | 2017-08-06 07:35:50 +0200 |
|---|---|---|
| committer | David Lamparter <equinox@opensourcerouting.org> | 2017-08-08 11:14:05 +0200 |
| commit | 689f5a8c84b95dbd31ecab481f8f2977965fe741 (patch) | |
| tree | 7c2a2b69908b3c3ac60e0de41b5a3f85caec2ef5 /lib/libfrr.c | |
| parent | 00857b241e6c27efad54a19b4226c37f04d80bf5 (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.c | 107 |
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; |
