summaryrefslogtreecommitdiff
path: root/lib
diff options
context:
space:
mode:
Diffstat (limited to 'lib')
-rw-r--r--lib/libfrr.c123
-rw-r--r--lib/libfrr.h4
-rw-r--r--lib/zclient.c114
-rw-r--r--lib/zclient.h10
4 files changed, 149 insertions, 102 deletions
diff --git a/lib/libfrr.c b/lib/libfrr.c
index 31d93009fa..e5573da900 100644
--- a/lib/libfrr.c
+++ b/lib/libfrr.c
@@ -19,6 +19,7 @@
*/
#include <zebra.h>
+#include <sys/un.h>
#include <sys/types.h>
#include <sys/wait.h>
@@ -45,6 +46,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];
@@ -135,6 +137,116 @@ 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))) {
+ /* note: this functionality is disabled at bottom */
+ 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;
+ }
+
+#if 1
+ /* force-disable this path, because tcp-zebra is a
+ * SECURITY ISSUE. there are no checks at all against
+ * untrusted users on the local system connecting on TCP
+ * and injecting bogus routing data into the entire routing
+ * domain.
+ *
+ * The functionality is only left here because it may be
+ * useful during development, in order to be able to get
+ * tcpdump or wireshark watching ZAPI as TCP. If you want
+ * to do that, flip the #if 1 above to #if 0. */
+ memset(sa, 0, sizeof(*sa));
+ return false;
+#endif
+ } 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)
@@ -164,6 +276,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,
@@ -246,7 +360,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)
@@ -399,6 +513,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);
+ }
+
/* don't mkdir these as root... */
if (!(di->flags & FRR_NO_PRIVSEP)) {
if (!di->pid_file || !di->vty_path)
diff --git a/lib/libfrr.h b/lib/libfrr.h
index 238a6f976d..1710fc9a84 100644
--- a/lib/libfrr.h
+++ b/lib/libfrr.h
@@ -101,7 +101,11 @@ extern void frr_vty_serv(void);
/* note: contains call to frr_vty_serv() */
extern void frr_run(struct thread_master *master);
+extern bool frr_zclient_addr(struct sockaddr_storage *sa, socklen_t *sa_len,
+ const char *path);
+
extern char config_default[256];
+extern char frr_zclientpath[256];
extern const char frr_sysconfdir[];
extern const char frr_vtydir[];
extern const char frr_moduledir[];
diff --git a/lib/zclient.c b/lib/zclient.c
index 893d769e3a..24cb699196 100644
--- a/lib/zclient.c
+++ b/lib/zclient.c
@@ -45,7 +45,8 @@ enum event { ZCLIENT_SCHEDULE, ZCLIENT_READ, ZCLIENT_CONNECT };
/* Prototype for event manager. */
static void zclient_event(enum event, struct zclient *);
-const char *zclient_serv_path = NULL;
+struct sockaddr_storage zclient_addr;
+socklen_t zclient_addr_len;
/* This file local debug flag. */
int zclient_debug = 0;
@@ -183,31 +184,28 @@ void zclient_reset(struct zclient *zclient)
zclient_init(zclient, zclient->redist_default, zclient->instance);
}
-#ifdef HAVE_TCP_ZEBRA
-
-/* Make socket to zebra daemon. Return zebra socket. */
-static int zclient_socket(void)
+/**
+ * Connect to zebra daemon.
+ * @param zclient a pointer to zclient structure
+ * @return socket fd just to make sure that connection established
+ * @see zclient_init
+ * @see zclient_new
+ */
+int zclient_socket_connect(struct zclient *zclient)
{
int sock;
int ret;
- struct sockaddr_in serv;
/* We should think about IPv6 connection. */
- sock = socket(AF_INET, SOCK_STREAM, 0);
+ sock = socket(zclient_addr.ss_family, SOCK_STREAM, 0);
if (sock < 0)
return -1;
- /* Make server socket. */
- memset(&serv, 0, sizeof(struct sockaddr_in));
- serv.sin_family = AF_INET;
- serv.sin_port = htons(ZEBRA_PORT);
-#ifdef HAVE_STRUCT_SOCKADDR_IN_SIN_LEN
- serv.sin_len = sizeof(struct sockaddr_in);
-#endif /* HAVE_STRUCT_SOCKADDR_IN_SIN_LEN */
- serv.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
+ set_cloexec(sock);
/* Connect to zebra. */
- ret = connect(sock, (struct sockaddr *)&serv, sizeof(serv));
+ ret = connect(sock, (struct sockaddr *)&zclient_addr,
+ zclient_addr_len);
if (ret < 0) {
if (zclient_debug)
zlog_warn("%s connect failure: %d(%s)",
@@ -216,65 +214,11 @@ static int zclient_socket(void)
close(sock);
return -1;
}
- return sock;
-}
-#else
-
-/* For sockaddr_un. */
-#include <sys/un.h>
-
-static int zclient_socket_un(const char *path)
-{
- int ret;
- int sock, len;
- struct sockaddr_un addr;
-
- sock = socket(AF_UNIX, SOCK_STREAM, 0);
- if (sock < 0)
- return -1;
-
- /* Make server socket. */
- memset(&addr, 0, sizeof(struct sockaddr_un));
- addr.sun_family = AF_UNIX;
- strncpy(addr.sun_path, path, strlen(path));
-#ifdef HAVE_STRUCT_SOCKADDR_UN_SUN_LEN
- len = addr.sun_len = SUN_LEN(&addr);
-#else
- len = sizeof(addr.sun_family) + strlen(addr.sun_path);
-#endif /* HAVE_STRUCT_SOCKADDR_UN_SUN_LEN */
-
- ret = connect(sock, (struct sockaddr *)&addr, len);
- if (ret < 0) {
- if (zclient_debug)
- zlog_warn("%s connect failure: %d(%s)",
- __PRETTY_FUNCTION__, errno,
- safe_strerror(errno));
- close(sock);
- return -1;
- }
+ zclient->sock = sock;
return sock;
}
-#endif /* HAVE_TCP_ZEBRA */
-
-/**
- * Connect to zebra daemon.
- * @param zclient a pointer to zclient structure
- * @return socket fd just to make sure that connection established
- * @see zclient_init
- * @see zclient_new
- */
-int zclient_socket_connect(struct zclient *zclient)
-{
-#ifdef HAVE_TCP_ZEBRA
- zclient->sock = zclient_socket();
-#else
- zclient->sock = zclient_socket_un(zclient_serv_path_get());
-#endif
- return zclient->sock;
-}
-
static int zclient_failed(struct zclient *zclient)
{
zclient->fail++;
@@ -2225,34 +2169,6 @@ static void zclient_event(enum event event, struct zclient *zclient)
}
}
-const char *zclient_serv_path_get()
-{
- return zclient_serv_path ? zclient_serv_path : ZEBRA_SERV_PATH;
-}
-
-void zclient_serv_path_set(char *path)
-{
- struct stat sb;
-
- /* reset */
- zclient_serv_path = NULL;
-
- /* test if `path' is socket. don't set it otherwise. */
- if (stat(path, &sb) == -1) {
- zlog_warn("%s: zebra socket `%s' does not exist", __func__,
- path);
- return;
- }
-
- if ((sb.st_mode & S_IFMT) != S_IFSOCK) {
- zlog_warn("%s: `%s' is not unix socket, sir", __func__, path);
- return;
- }
-
- /* it seems that path is unix socket */
- zclient_serv_path = path;
-}
-
void zclient_interface_set_master(struct zclient *client,
struct interface *master,
struct interface *slave)
diff --git a/lib/zclient.h b/lib/zclient.h
index 8a2729543f..5edb56f517 100644
--- a/lib/zclient.h
+++ b/lib/zclient.h
@@ -42,6 +42,14 @@
/* Zebra header size. */
#define ZEBRA_HEADER_SIZE 8
+/* special socket path name to use TCP
+ * @ is used as first character because that's abstract socket names on Linux
+ */
+#define ZAPI_TCP_PATHNAME "@tcp"
+
+extern struct sockaddr_storage zclient_addr;
+extern socklen_t zclient_addr_len;
+
/* Zebra message types. */
typedef enum {
ZEBRA_INTERFACE_ADD,
@@ -306,8 +314,6 @@ extern void zclient_reset(struct zclient *);
extern void zclient_free(struct zclient *);
extern int zclient_socket_connect(struct zclient *);
-extern void zclient_serv_path_set(char *path);
-extern const char *zclient_serv_path_get(void);
extern u_short *redist_check_instance(struct redist_proto *, u_short);
extern void redist_add_instance(struct redist_proto *, u_short);