X-Git-Url: https://git.octo.it/?a=blobdiff_plain;f=src%2Ftcpconns.c;h=e74e4bc8856d6360472a44d52a7dae93a3586ca2;hb=7535ee83bf0b12a168cee3c70e5fb97ed6dfc96c;hp=bf07a2a28b99f69c6c135bec7a1fb55872b7161a;hpb=c1219a1c9db2e8400e2ee94b87f86ccd441485d5;p=collectd.git diff --git a/src/tcpconns.c b/src/tcpconns.c index bf07a2a2..e74e4bc8 100644 --- a/src/tcpconns.c +++ b/src/tcpconns.c @@ -17,7 +17,7 @@ * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * * Author: - * Florian octo Forster + * Florian octo Forster * Michael Stapelberg **/ @@ -58,6 +58,7 @@ */ #include "collectd.h" + #include "common.h" #include "plugin.h" @@ -71,13 +72,10 @@ #if KERNEL_LINUX # include -/* sys/socket.h is necessary to compile when using netlink on older systems. */ -# include # include #if HAVE_LINUX_INET_DIAG_H # include #endif -# include # include /* #endif KERNEL_LINUX */ @@ -90,9 +88,6 @@ #if HAVE_SYS_TYPES_H # include #endif -#if HAVE_SYS_SOCKET_H -# include -#endif #if HAVE_NET_IF_H # include #endif @@ -113,7 +108,6 @@ /* This is for OpenBSD and NetBSD. */ #elif HAVE_LIBKVM_NLIST # include -# include # include # include # include @@ -219,13 +213,13 @@ static const char *tcp_state[] = "CLOSED", "LISTEN", "SYN_SENT", - "SYN_RCVD", + "SYN_RECV", "ESTABLISHED", "CLOSE_WAIT", - "FIN_WAIT_1", + "FIN_WAIT1", "CLOSING", "LAST_ACK", - "FIN_WAIT_2", + "FIN_WAIT2", "TIME_WAIT" }; @@ -272,12 +266,15 @@ static const char *config_keys[] = { "ListeningPorts", "LocalPort", - "RemotePort" + "RemotePort", + "AllPortsSummary" }; static int config_keys_num = STATIC_ARRAY_SIZE (config_keys); static int port_collect_listening = 0; +static int port_collect_total = 0; static port_entry_t *port_list_head = NULL; +static uint32_t count_total[TCP_STATE_MAX + 1]; #if KERNEL_LINUX #if HAVE_STRUCT_LINUX_INET_DIAG_REQ @@ -287,7 +284,7 @@ static port_entry_t *port_list_head = NULL; static uint32_t sequence_number = 0; #endif -enum +static enum { SRC_DUNNO, SRC_NETLINK, @@ -295,17 +292,21 @@ enum } linux_source = SRC_DUNNO; #endif +static void conn_prepare_vl (value_list_t *vl, value_t *values) +{ + vl->values = values; + vl->values_len = 1; + sstrncpy (vl->host, hostname_g, sizeof (vl->host)); + sstrncpy (vl->plugin, "tcpconns", sizeof (vl->plugin)); + sstrncpy (vl->type, "tcp_connections", sizeof (vl->type)); +} + static void conn_submit_port_entry (port_entry_t *pe) { value_t values[1]; value_list_t vl = VALUE_LIST_INIT; - int i; - vl.values = values; - vl.values_len = 1; - sstrncpy (vl.host, hostname_g, sizeof (vl.host)); - sstrncpy (vl.plugin, "tcpconns", sizeof (vl.plugin)); - sstrncpy (vl.type, "tcp_connections", sizeof (vl.type)); + conn_prepare_vl (&vl, values); if (((port_collect_listening != 0) && (pe->flags & PORT_IS_LISTENING)) || (pe->flags & PORT_COLLECT_LOCAL)) @@ -313,7 +314,7 @@ static void conn_submit_port_entry (port_entry_t *pe) ssnprintf (vl.plugin_instance, sizeof (vl.plugin_instance), "%"PRIu16"-local", pe->port); - for (i = 1; i <= TCP_STATE_MAX; i++) + for (int i = 1; i <= TCP_STATE_MAX; i++) { vl.values[0].gauge = pe->count_local[i]; @@ -328,7 +329,7 @@ static void conn_submit_port_entry (port_entry_t *pe) ssnprintf (vl.plugin_instance, sizeof (vl.plugin_instance), "%"PRIu16"-remote", pe->port); - for (i = 1; i <= TCP_STATE_MAX; i++) + for (int i = 1; i <= TCP_STATE_MAX; i++) { vl.values[0].gauge = pe->count_remote[i]; @@ -339,11 +340,31 @@ static void conn_submit_port_entry (port_entry_t *pe) } } /* void conn_submit */ +static void conn_submit_port_total (void) +{ + value_t values[1]; + value_list_t vl = VALUE_LIST_INIT; + + conn_prepare_vl (&vl, values); + + sstrncpy (vl.plugin_instance, "all", sizeof (vl.plugin_instance)); + + for (int i = 1; i <= TCP_STATE_MAX; i++) + { + vl.values[0].gauge = count_total[i]; + + sstrncpy (vl.type_instance, tcp_state[i], sizeof (vl.type_instance)); + + plugin_dispatch_values (&vl); + } +} + static void conn_submit_all (void) { - port_entry_t *pe; + if (port_collect_total) + conn_submit_port_total (); - for (pe = port_list_head; pe != NULL; pe = pe->next) + for (port_entry_t *pe = port_list_head; pe != NULL; pe = pe->next) conn_submit_port_entry (pe); } /* void conn_submit_all */ @@ -361,10 +382,9 @@ static port_entry_t *conn_get_port_entry (uint16_t port, int create) if ((ret == NULL) && (create != 0)) { - ret = (port_entry_t *) malloc (sizeof (port_entry_t)); + ret = calloc (1, sizeof (*ret)); if (ret == NULL) return (NULL); - memset (ret, '\0', sizeof (port_entry_t)); ret->port = port; ret->next = port_list_head; @@ -381,6 +401,8 @@ static void conn_reset_port_entry (void) port_entry_t *prev = NULL; port_entry_t *pe = port_list_head; + memset (&count_total, '\0', sizeof(count_total)); + while (pe != NULL) { /* If this entry was created while reading the files (ant not when handling @@ -429,6 +451,8 @@ static int conn_handle_ports (uint16_t port_local, uint16_t port_remote, uint8_t return (-1); } + count_total[state]++; + /* Listening sockets */ if ((state == TCP_STATE_LISTEN) && (port_collect_listening != 0)) { @@ -458,10 +482,6 @@ static int conn_read_netlink (void) { #if HAVE_STRUCT_LINUX_INET_DIAG_REQ int fd; - struct sockaddr_nl nladdr; - struct nlreq req; - struct msghdr msg; - struct iovec iov; struct inet_diag_msg *r; char buf[8192]; @@ -476,34 +496,38 @@ static int conn_read_netlink (void) return (-1); } - memset(&nladdr, 0, sizeof(nladdr)); - nladdr.nl_family = AF_NETLINK; - - memset(&req, 0, sizeof(req)); - req.nlh.nlmsg_len = sizeof(req); - req.nlh.nlmsg_type = TCPDIAG_GETSOCK; - /* NLM_F_ROOT: return the complete table instead of a single entry. - * NLM_F_MATCH: return all entries matching criteria (not implemented) - * NLM_F_REQUEST: must be set on all request messages */ - req.nlh.nlmsg_flags = NLM_F_ROOT | NLM_F_MATCH | NLM_F_REQUEST; - req.nlh.nlmsg_pid = 0; - /* The sequence_number is used to track our messages. Since netlink is not - * reliable, we don't want to end up with a corrupt or incomplete old - * message in case the system is/was out of memory. */ - req.nlh.nlmsg_seq = ++sequence_number; - req.r.idiag_family = AF_INET; - req.r.idiag_states = 0xfff; - req.r.idiag_ext = 0; - - memset(&iov, 0, sizeof(iov)); - iov.iov_base = &req; - iov.iov_len = sizeof(req); - - memset(&msg, 0, sizeof(msg)); - msg.msg_name = (void*)&nladdr; - msg.msg_namelen = sizeof(nladdr); - msg.msg_iov = &iov; - msg.msg_iovlen = 1; + struct sockaddr_nl nladdr = { + .nl_family = AF_NETLINK + }; + + struct nlreq req = { + .nlh.nlmsg_len = sizeof(req), + .nlh.nlmsg_type = TCPDIAG_GETSOCK, + /* NLM_F_ROOT: return the complete table instead of a single entry. + * NLM_F_MATCH: return all entries matching criteria (not implemented) + * NLM_F_REQUEST: must be set on all request messages */ + .nlh.nlmsg_flags = NLM_F_ROOT | NLM_F_MATCH | NLM_F_REQUEST, + .nlh.nlmsg_pid = 0, + /* The sequence_number is used to track our messages. Since netlink is not + * reliable, we don't want to end up with a corrupt or incomplete old + * message in case the system is/was out of memory. */ + .nlh.nlmsg_seq = ++sequence_number, + .r.idiag_family = AF_INET, + .r.idiag_states = 0xfff, + .r.idiag_ext = 0 + }; + + struct iovec iov = { + .iov_base = &req, + .iov_len = sizeof(req) + }; + + struct msghdr msg = { + .msg_name = (void*)&nladdr, + .msg_namelen = sizeof(nladdr), + .msg_iov = &iov, + .msg_iovlen = 1 + }; if (sendmsg (fd, &msg, 0) < 0) { @@ -705,6 +729,13 @@ static int conn_config (const char *key, const char *value) else pe->flags |= PORT_COLLECT_REMOTE; } + else if (strcasecmp (key, "AllPortsSummary") == 0) + { + if (IS_TRUE (value)) + port_collect_total = 1; + else + port_collect_total = 0; + } else { return (-1); @@ -716,7 +747,7 @@ static int conn_config (const char *key, const char *value) #if KERNEL_LINUX static int conn_init (void) { - if (port_list_head == NULL) + if (port_collect_total == 0 && port_list_head == NULL) port_collect_listening = 1; return (0); @@ -797,7 +828,7 @@ static int conn_read (void) return (-1); } - buffer = (char *) malloc (buffer_len); + buffer = malloc (buffer_len); if (buffer == NULL) { ERROR ("tcpconns plugin: malloc failed."); @@ -910,7 +941,9 @@ static int conn_init (void) static int conn_read (void) { struct inpcbtable table; +#if !defined(__OpenBSD__) && (defined(__NetBSD_Version__) && __NetBSD_Version__ <= 699002700) struct inpcb *head; +#endif struct inpcb *next; struct inpcb inpcb; struct tcpcb tcpcb; @@ -923,12 +956,19 @@ static int conn_read (void) if (status != 0) return (-1); +#if defined(__OpenBSD__) || (defined(__NetBSD_Version__) && __NetBSD_Version__ > 699002700) + /* inpt_queue is a TAILQ on OpenBSD */ + /* Get the first pcb */ + next = (struct inpcb *)TAILQ_FIRST (&table.inpt_queue); + while (next) +#else /* Get the `head' pcb */ head = (struct inpcb *) &(inpcbtable_ptr->inpt_queue); /* Get the first pcb */ next = (struct inpcb *)CIRCLEQ_FIRST (&table.inpt_queue); while (next != head) +#endif { /* Read the pcb pointed to by `next' into `inpcb' */ status = kread ((u_long) next, &inpcb, sizeof (inpcb)); @@ -936,7 +976,12 @@ static int conn_read (void) return (-1); /* Advance `next' */ +#if defined(__OpenBSD__) || (defined(__NetBSD_Version__) && __NetBSD_Version__ > 699002700) + /* inpt_queue is a TAILQ on OpenBSD */ + next = (struct inpcb *)TAILQ_NEXT (&inpcb, inp_queue); +#else next = (struct inpcb *)CIRCLEQ_NEXT (&inpcb, inp_queue); +#endif /* Ignore sockets, that are not connected. */ #ifdef __NetBSD__ @@ -968,7 +1013,6 @@ static int conn_read (void) static int conn_read (void) { int size; - int i; int nconn; void *data; struct netinfo_header *header; @@ -1010,7 +1054,7 @@ static int conn_read (void) nconn = header->size; conn = (struct netinfo_conn *)(data + sizeof(struct netinfo_header)); - for (i=0; i < nconn; conn++, i++) + for (int i = 0; i < nconn; conn++, i++) { conn_handle_ports (conn->srcport, conn->dstport, conn->tcp_state); }