summaryrefslogtreecommitdiffstats
path: root/libnetdata
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2019-10-13 08:37:32 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2019-10-13 08:38:18 +0000
commitca540a730c0b880922e86074f994a95b8d413bea (patch)
tree1364a1b82cfcc68f51aabf9b2545e6a06059d6bb /libnetdata
parentReleasing debian version 1.17.1-1. (diff)
downloadnetdata-ca540a730c0b880922e86074f994a95b8d413bea.tar.xz
netdata-ca540a730c0b880922e86074f994a95b8d413bea.zip
Merging upstream version 1.18.0.
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'libnetdata')
-rw-r--r--libnetdata/health/health.c3
-rw-r--r--libnetdata/json/jsmn.c10
-rw-r--r--libnetdata/popen/popen.c10
-rw-r--r--libnetdata/socket/socket.c130
-rw-r--r--libnetdata/socket/socket.h11
-rw-r--r--libnetdata/url/url.c17
6 files changed, 130 insertions, 51 deletions
diff --git a/libnetdata/health/health.c b/libnetdata/health/health.c
index b93de8b93..a70f284b1 100644
--- a/libnetdata/health/health.c
+++ b/libnetdata/health/health.c
@@ -136,7 +136,8 @@ int health_silencers_json_read_callback(JSON_ENTRY *e)
else if (!strcmp(e->data.string,"DISABLE")) silencers->stype = STYPE_DISABLE_ALARMS;
} else {
debug(D_HEALTH, "JSON: Adding %s=%s", e->name, e->data.string);
- health_silencers_addparam(e->callback_data, e->name, e->data.string);
+ SILENCER *test = health_silencers_addparam(e->callback_data, e->name, e->data.string);
+ (void)test;
}
break;
diff --git a/libnetdata/json/jsmn.c b/libnetdata/json/jsmn.c
index c8d9e73db..952535897 100644
--- a/libnetdata/json/jsmn.c
+++ b/libnetdata/json/jsmn.c
@@ -301,10 +301,12 @@ jsmnerr_t jsmn_parse(jsmn_parser *parser, const char *js, size_t len,
}
}
- for (i = parser->toknext - 1; i >= 0; i--) {
- /* Unmatched opened object or array */
- if (tokens[i].start != -1 && tokens[i].end == -1) {
- return JSMN_ERROR_PART;
+ if (tokens) {
+ for (i = parser->toknext - 1; i >= 0; i--) {
+ /* Unmatched opened object or array */
+ if (tokens[i].start != -1 && tokens[i].end == -1) {
+ return JSMN_ERROR_PART;
+ }
}
}
diff --git a/libnetdata/popen/popen.c b/libnetdata/popen/popen.c
index 177aebfc0..906b10535 100644
--- a/libnetdata/popen/popen.c
+++ b/libnetdata/popen/popen.c
@@ -68,7 +68,7 @@ static inline FILE *custom_popene(const char *command, volatile pid_t *pidptr, c
int i;
for(i = (int) (sysconf(_SC_OPEN_MAX) - 1); i >= 0; i--)
if(i != STDIN_FILENO && i != STDERR_FILENO)
- fcntl(i, F_SETFD, FD_CLOEXEC);
+ (void)fcntl(i, F_SETFD, FD_CLOEXEC);
if (!posix_spawn_file_actions_init(&fa)) {
// move the pipe to stdout in the child
@@ -97,7 +97,7 @@ static inline FILE *custom_popene(const char *command, volatile pid_t *pidptr, c
debug(D_CHILDS, "Spawned command: '%s' on pid %d from parent pid %d.", command, pid, getpid());
} else {
error("Failed to spawn command: '%s' from parent pid %d.", command, getpid());
- close(pipefd[PIPE_READ]);
+ fclose(fp);
fp = NULL;
}
close(pipefd[PIPE_WRITE]);
@@ -116,7 +116,11 @@ error_after_posix_spawn_file_actions_init:
if (posix_spawn_file_actions_destroy(&fa))
error("posix_spawn_file_actions_destroy");
error_after_pipe:
- close(pipefd[PIPE_READ]);
+ if (fp)
+ fclose(fp);
+ else
+ close(pipefd[PIPE_READ]);
+
close(pipefd[PIPE_WRITE]);
return NULL;
}
diff --git a/libnetdata/socket/socket.c b/libnetdata/socket/socket.c
index 22abb47f4..fa1414dc0 100644
--- a/libnetdata/socket/socket.c
+++ b/libnetdata/socket/socket.c
@@ -995,21 +995,103 @@ int accept4(int sock, struct sockaddr *addr, socklen_t *addrlen, int flags) {
}
#endif
+/*
+ * ---------------------------------------------------------------------------------------------------------------------
+ * connection_allowed() - if there is an access list then check the connection matches a pattern.
+ * Numeric patterns are checked against the IP address first, only if they
+ * do not match is the hostname resolved (reverse-DNS) and checked. If the
+ * hostname matches then we perform forward DNS resolution to check the IP
+ * is really associated with the DNS record. This call is repeatable: the
+ * web server may check more refined matches against the connection. Will
+ * update the client_host if uninitialized - ensure the hostsize is the number
+ * of *writable* bytes (i.e. be aware of the strdup used to compact the pollinfo).
+ */
+extern int connection_allowed(int fd, char *client_ip, char *client_host, size_t hostsize, SIMPLE_PATTERN *access_list,
+ const char *patname) {
+ if (!access_list)
+ return 1;
+ if (simple_pattern_matches(access_list, client_ip))
+ return 1;
+ // If the hostname is unresolved (and needed) then attempt the DNS lookups.
+ if (client_host[0]==0)
+ {
+ struct sockaddr_storage sadr;
+ socklen_t addrlen = sizeof(sadr);
+ int err = getpeername(fd, (struct sockaddr*)&sadr, &addrlen);
+ if (err != 0 ||
+ (err = getnameinfo((struct sockaddr *)&sadr, addrlen, client_host, (socklen_t)hostsize,
+ NULL, 0, NI_NAMEREQD)) != 0) {
+ error("Incoming connection on '%s' does not match a numeric pattern, "
+ "and host could not be resolved (err=%s)", client_ip, gai_strerror(err));
+ if (hostsize >= 8)
+ strcpy(client_host,"UNKNOWN");
+ return 0;
+ }
+ struct addrinfo *addr_infos = NULL;
+ if (getaddrinfo(client_host, NULL, NULL, &addr_infos) !=0 ) {
+ error("LISTENER: cannot validate hostname '%s' from '%s' by resolving it",
+ client_host, client_ip);
+ if (hostsize >= 8)
+ strcpy(client_host,"UNKNOWN");
+ return 0;
+ }
+ struct addrinfo *scan = addr_infos;
+ int validated = 0;
+ while (scan) {
+ char address[INET6_ADDRSTRLEN];
+ address[0] = 0;
+ switch (scan->ai_addr->sa_family) {
+ case AF_INET:
+ inet_ntop(AF_INET, &((struct sockaddr_in*)(scan->ai_addr))->sin_addr, address, INET6_ADDRSTRLEN);
+ break;
+ case AF_INET6:
+ inet_ntop(AF_INET6, &((struct sockaddr_in6*)(scan->ai_addr))->sin6_addr, address, INET6_ADDRSTRLEN);
+ break;
+ }
+ debug(D_LISTENER, "Incoming ip %s rev-resolved onto %s, validating against forward-resolution %s",
+ client_ip, client_host, address);
+ if (!strcmp(client_ip, address)) {
+ validated = 1;
+ break;
+ }
+ scan = scan->ai_next;
+ }
+ if (!validated) {
+ error("LISTENER: Cannot validate '%s' as ip of '%s', not listed in DNS", client_ip, client_host);
+ if (hostsize >= 8)
+ strcpy(client_host,"UNKNOWN");
+ }
+ if (addr_infos!=NULL)
+ freeaddrinfo(addr_infos);
+ }
+ if (!simple_pattern_matches(access_list, client_host)) {
+ debug(D_LISTENER, "Incoming connection on '%s' (%s) does not match allowed pattern for %s",
+ client_ip, client_host, patname);
+ return 0;
+ }
+ return 1;
+}
// --------------------------------------------------------------------------------------------------------------------
// accept_socket() - accept a socket and store client IP and port
-int accept_socket(int fd, int flags, char *client_ip, size_t ipsize, char *client_port, size_t portsize, SIMPLE_PATTERN *access_list) {
+int accept_socket(int fd, int flags, char *client_ip, size_t ipsize, char *client_port, size_t portsize,
+ char *client_host, size_t hostsize, SIMPLE_PATTERN *access_list) {
struct sockaddr_storage sadr;
socklen_t addrlen = sizeof(sadr);
int nfd = accept4(fd, (struct sockaddr *)&sadr, &addrlen, flags);
if (likely(nfd >= 0)) {
- if (getnameinfo((struct sockaddr *)&sadr, addrlen, client_ip, (socklen_t)ipsize, client_port, (socklen_t)portsize, NI_NUMERICHOST | NI_NUMERICSERV) != 0) {
+ if (getnameinfo((struct sockaddr *)&sadr, addrlen, client_ip, (socklen_t)ipsize,
+ client_port, (socklen_t)portsize, NI_NUMERICHOST | NI_NUMERICSERV) != 0) {
error("LISTENER: cannot getnameinfo() on received client connection.");
strncpyz(client_ip, "UNKNOWN", ipsize - 1);
strncpyz(client_port, "UNKNOWN", portsize - 1);
}
+ if(!strcmp(client_ip, "127.0.0.1") || !strcmp(client_ip, "::1")) {
+ strncpy(client_ip, "localhost", ipsize);
+ client_ip[ipsize - 1] = '\0';
+ }
#ifdef __FreeBSD__
if(((struct sockaddr *)&sadr)->sa_family == AF_LOCAL)
@@ -1044,21 +1126,12 @@ int accept_socket(int fd, int flags, char *client_ip, size_t ipsize, char *clien
debug(D_LISTENER, "New UNKNOWN web client from %s port %s on socket %d.", client_ip, client_port, fd);
break;
}
-
- if(access_list) {
- if(!strcmp(client_ip, "127.0.0.1") || !strcmp(client_ip, "::1")) {
- strncpy(client_ip, "localhost", ipsize);
- client_ip[ipsize - 1] = '\0';
- }
-
- if(unlikely(!simple_pattern_matches(access_list, client_ip))) {
- errno = 0;
- debug(D_LISTENER, "Permission denied for client '%s', port '%s'", client_ip, client_port);
- error("DENIED ACCESS to client '%s'", client_ip);
- close(nfd);
- nfd = -1;
- errno = EPERM;
- }
+ if(!connection_allowed(nfd, client_ip, client_host, hostsize, access_list, "connection")) {
+ errno = 0;
+ error("Permission denied for client '%s', port '%s'", client_ip, client_port);
+ close(nfd);
+ nfd = -1;
+ errno = EPERM;
}
}
#ifdef HAVE_ACCEPT4
@@ -1084,6 +1157,7 @@ inline POLLINFO *poll_add_fd(POLLJOB *p
, uint32_t flags
, const char *client_ip
, const char *client_port
+ , const char *client_host
, void *(*add_callback)(POLLINFO * /*pi*/, short int * /*events*/, void * /*data*/)
, void (*del_callback)(POLLINFO * /*pi*/)
, int (*rcv_callback)(POLLINFO * /*pi*/, short int * /*events*/)
@@ -1123,6 +1197,7 @@ inline POLLINFO *poll_add_fd(POLLJOB *p
p->inf[i].client_ip = NULL;
p->inf[i].client_port = NULL;
+ p->inf[i].client_host = NULL;
p->inf[i].del_callback = p->del_callback;
p->inf[i].rcv_callback = p->rcv_callback;
p->inf[i].snd_callback = p->snd_callback;
@@ -1153,8 +1228,9 @@ inline POLLINFO *poll_add_fd(POLLJOB *p
pi->port_acl = port_acl;
pi->flags = flags;
pi->next = NULL;
- pi->client_ip = strdupz(client_ip);
+ pi->client_ip = strdupz(client_ip);
pi->client_port = strdupz(client_port);
+ pi->client_host = strdupz(client_host);
pi->del_callback = del_callback;
pi->rcv_callback = rcv_callback;
@@ -1224,6 +1300,9 @@ inline void poll_close_fd(POLLINFO *pi) {
freez(pi->client_port);
pi->client_port = NULL;
+ freez(pi->client_host);
+ pi->client_host = NULL;
+
pi->next = p->first_free;
p->first_free = pi;
@@ -1356,13 +1435,16 @@ static void poll_events_process(POLLJOB *p, POLLINFO *pi, struct pollfd *pf, sho
int nfd;
do {
- char client_ip[NI_MAXHOST + 1];
- char client_port[NI_MAXSERV + 1];
- client_ip[0] = 0x00;
- client_port[0] = 0x00;
+ char client_ip[INET6_ADDRSTRLEN];
+ char client_port[NI_MAXSERV];
+ char client_host[NI_MAXHOST];
+ client_host[0] = 0;
+ client_ip[0] = 0;
+ client_port[0] = 0;
debug(D_POLLFD, "POLLFD: LISTENER: calling accept4() slot %zu (fd %d)", i, fd);
- nfd = accept_socket(fd, SOCK_NONBLOCK, client_ip, NI_MAXHOST + 1, client_port, NI_MAXSERV + 1, p->access_list);
+ nfd = accept_socket(fd, SOCK_NONBLOCK, client_ip, INET6_ADDRSTRLEN, client_port, NI_MAXSERV,
+ client_host, NI_MAXHOST, p->access_list);
if (unlikely(nfd < 0)) {
// accept failed
@@ -1387,6 +1469,7 @@ static void poll_events_process(POLLJOB *p, POLLINFO *pi, struct pollfd *pf, sho
, POLLINFO_FLAG_CLIENT_SOCKET
, client_ip
, client_port
+ , client_host
, p->add_callback
, p->del_callback
, p->rcv_callback
@@ -1530,6 +1613,7 @@ void poll_events(LISTEN_SOCKETS *sockets
, POLLINFO_FLAG_SERVER_SOCKET
, (sockets->fds_names[i])?sockets->fds_names[i]:"UNKNOWN"
, ""
+ , ""
, p.add_callback
, p.del_callback
, p.rcv_callback
diff --git a/libnetdata/socket/socket.h b/libnetdata/socket/socket.h
index 76b15def5..227f05434 100644
--- a/libnetdata/socket/socket.h
+++ b/libnetdata/socket/socket.h
@@ -72,7 +72,10 @@ extern int sock_setreuse_port(int fd, int reuse);
extern int sock_enlarge_in(int fd);
extern int sock_enlarge_out(int fd);
-extern int accept_socket(int fd, int flags, char *client_ip, size_t ipsize, char *client_port, size_t portsize, SIMPLE_PATTERN *access_list);
+extern int connection_allowed(int fd, char *client_ip, char *client_host, size_t hostsize,
+ SIMPLE_PATTERN *access_list, const char *patname);
+extern int accept_socket(int fd, int flags, char *client_ip, size_t ipsize, char *client_port, size_t portsize,
+ char *client_host, size_t hostsize, SIMPLE_PATTERN *access_list);
#ifndef HAVE_ACCEPT4
extern int accept4(int sock, struct sockaddr *addr, socklen_t *addrlen, int flags);
@@ -104,8 +107,9 @@ typedef struct pollinfo {
int fd; // the file descriptor
int socktype; // the client socket type
WEB_CLIENT_ACL port_acl; // the access lists permitted on this web server port (it's -1 for client sockets)
- char *client_ip; // the connected client IP
- char *client_port; // the connected client port
+ char *client_ip; // Max INET6_ADDRSTRLEN bytes
+ char *client_port; // Max NI_MAXSERV bytes
+ char *client_host; // Max NI_MAXHOST bytes
time_t connected_t; // the time the socket connected
time_t last_received_t; // the time the socket last received data
@@ -173,6 +177,7 @@ extern POLLINFO *poll_add_fd(POLLJOB *p
, uint32_t flags
, const char *client_ip
, const char *client_port
+ , const char *client_host
, void *(*add_callback)(POLLINFO *pi, short int *events, void *data)
, void (*del_callback)(POLLINFO *pi)
, int (*rcv_callback)(POLLINFO *pi, short int *events)
diff --git a/libnetdata/url/url.c b/libnetdata/url/url.c
index 7df9faaf0..d1d508139 100644
--- a/libnetdata/url/url.c
+++ b/libnetdata/url/url.c
@@ -44,23 +44,6 @@ char *url_encode(char *str) {
}
/**
- * URL Decode
- *
- * Returns a url-decoded version of str
- * IMPORTANT: be sure to free() the returned string after use
- *
- * @param str the string that will be decode
- *
- * @return a pointer for the url decoded.
- */
-char *url_decode(char *str) {
- size_t size = strlen(str) + 1;
-
- char *buf = mallocz(size);
- return url_decode_r(buf, str, size);
-}
-
-/**
* Percentage escape decode
*
* Decode %XX character or return 0 if cannot