X-Git-Url: https://git.octo.it/?a=blobdiff_plain;f=src%2Ftcpconns.c;h=4f46e78abfd7a8cfab390b497957b010a021c4f6;hb=c28bc580c110c78741d0805c7652e05d994b0ff4;hp=108a4e83df9b74af3bea3837c55523a62bf6b7b9;hpb=83149d73b8a3bd4889517a2e4d0adca0a52e7a06;p=collectd.git diff --git a/src/tcpconns.c b/src/tcpconns.c index 108a4e83..4f46e78a 100644 --- a/src/tcpconns.c +++ b/src/tcpconns.c @@ -23,12 +23,84 @@ #include "common.h" #include "plugin.h" -#if !KERNEL_LINUX +#if !KERNEL_LINUX && !HAVE_SYSCTLBYNAME # error "No applicable input method." #endif -#define TCP_STATE_LISTEN 10 -#define TCP_STATE_MAX 11 +#if KERNEL_LINUX +/* #endif KERNEL_LINUX */ + +#elif HAVE_SYSCTLBYNAME +# include +# include + +/* Some includes needed for compiling on FreeBSD */ +#include +#if HAVE_SYS_TYPES_H +# include +#endif +#if HAVE_SYS_SOCKET_H +# include +#endif +#if HAVE_NET_IF_H +# include +#endif + +# include +# include +# include +# include +# include +# include +# include +# include +# include +# include +# include +#endif /* HAVE_SYSCTLBYNAME */ + +#if KERNEL_LINUX +static const char *tcp_state[] = +{ + "", /* 0 */ + "ESTABLISHED", + "SYN_SENT", + "SYN_RECV", + "FIN_WAIT1", + "FIN_WAIT2", + "TIME_WAIT", + "CLOSED", + "CLOSE_WAIT", + "LAST_ACK", + "LISTEN", /* 10 */ + "CLOSING" +}; + +# define TCP_STATE_LISTEN 10 +# define TCP_STATE_MIN 1 +# define TCP_STATE_MAX 11 +/* #endif KERNEL_LINUX */ + +#elif HAVE_SYSCTLBYNAME +static const char *tcp_state[] = +{ + "CLOSED", + "LISTEN", + "SYN_SENT", + "SYN_RECV", + "ESTABLISHED", + "CLOSE_WAIT", + "FIN_WAIT1", + "CLOSING", + "LAST_ACK", + "FIN_WAIT2", + "TIME_WAIT" +}; + +# define TCP_STATE_LISTEN 1 +# define TCP_STATE_MIN 0 +# define TCP_STATE_MAX 10 +#endif /* HAVE_SYSCTLBYNAME */ #define PORT_COLLECT_LOCAL 0x01 #define PORT_COLLECT_REMOTE 0x02 @@ -51,22 +123,6 @@ static const char *config_keys[] = }; static int config_keys_num = STATIC_ARRAY_SIZE (config_keys); -static const char *tcp_state[] = -{ - "", /* 0 */ - "ESTABLISHED", - "SYN_SENT", - "SYN_RECV", - "FIN_WAIT1", - "FIN_WAIT2", - "TIME_WAIT", - "CLOSE", - "CLOSE_WAIT", - "LAST_ACK", - "LISTEN", /* 10 */ - "CLOSING" -}; - static int port_collect_listening = 0; static port_entry_t *port_list_head = NULL; @@ -81,39 +137,36 @@ static void conn_submit_port_entry (port_entry_t *pe) vl.time = time (NULL); strcpy (vl.host, hostname_g); strcpy (vl.plugin, "tcpconns"); + strcpy (vl.type, "tcp_connections"); if (((port_collect_listening != 0) && (pe->flags & PORT_IS_LISTENING)) || (pe->flags & PORT_COLLECT_LOCAL)) { - snprintf (vl.plugin_instance, sizeof (vl.plugin_instance), + ssnprintf (vl.plugin_instance, sizeof (vl.plugin_instance), "%hu-local", pe->port); - vl.plugin_instance[sizeof (vl.plugin_instance) - 1] = '\0'; for (i = 1; i <= TCP_STATE_MAX; i++) { vl.values[0].gauge = pe->count_local[i]; - strncpy (vl.type_instance, tcp_state[i], sizeof (vl.type_instance)); - vl.type_instance[sizeof (vl.type_instance) - 1] = '\0'; + sstrncpy (vl.type_instance, tcp_state[i], sizeof (vl.type_instance)); - plugin_dispatch_values ("tcp_connections", &vl); + plugin_dispatch_values (&vl); } } if (pe->flags & PORT_COLLECT_REMOTE) { - snprintf (vl.plugin_instance, sizeof (vl.plugin_instance), + ssnprintf (vl.plugin_instance, sizeof (vl.plugin_instance), "%hu-remote", pe->port); - vl.plugin_instance[sizeof (vl.plugin_instance) - 1] = '\0'; for (i = 1; i <= TCP_STATE_MAX; i++) { vl.values[0].gauge = pe->count_remote[i]; - strncpy (vl.type_instance, tcp_state[i], sizeof (vl.type_instance)); - vl.type_instance[sizeof (vl.type_instance) - 1] = '\0'; + sstrncpy (vl.type_instance, tcp_state[i], sizeof (vl.type_instance)); - plugin_dispatch_values ("tcp_connections", &vl); + plugin_dispatch_values (&vl); } } } /* void conn_submit */ @@ -196,7 +249,11 @@ static int conn_handle_ports (uint16_t port_local, uint16_t port_remote, uint8_t { port_entry_t *pe = NULL; - if ((state == 0) || (state > TCP_STATE_MAX)) + if ((state > TCP_STATE_MAX) +#if TCP_STATE_MIN > 0 + || (state < TCP_STATE_MIN) +#endif + ) { NOTICE ("tcpconns plugin: Ignoring connection with unknown state 0x%02x.", state); @@ -225,6 +282,7 @@ static int conn_handle_ports (uint16_t port_local, uint16_t port_remote, uint8_t return (0); } /* int conn_handle_ports */ +#if KERNEL_LINUX static int conn_handle_line (char *buffer) { char *fields[32]; @@ -288,12 +346,7 @@ static int conn_read_file (const char *file) fh = fopen (file, "r"); if (fh == NULL) - { - char errbuf[1024]; - ERROR ("tcpconns plugin: fopen (%s) failed: %s", - file, sstrerror (errno, errbuf, sizeof (errbuf))); return (-1); - } while (fgets (buffer, sizeof (buffer), fh) != NULL) { @@ -304,6 +357,10 @@ static int conn_read_file (const char *file) return (0); } /* int conn_read_file */ +/* #endif KERNEL_LINUX */ + +#elif HAVE_SYSCTLBYNAME +#endif /* HAVE_SYSCTLBYNAME */ static int conn_config (const char *key, const char *value) { @@ -348,6 +405,7 @@ static int conn_config (const char *key, const char *value) return (0); } /* int conn_config */ +#if KERNEL_LINUX static int conn_init (void) { if (port_list_head == NULL) @@ -358,21 +416,113 @@ static int conn_init (void) static int conn_read (void) { + int errors_num = 0; + + conn_reset_port_entry (); + + if (conn_read_file ("/proc/net/tcp") != 0) + errors_num++; + if (conn_read_file ("/proc/net/tcp6") != 0) + errors_num++; + + if (errors_num < 2) + { + conn_submit_all (); + } + else + { + ERROR ("tcpconns plugin: Neither /proc/net/tcp nor /proc/net/tcp6 " + "coult be read."); + return (-1); + } + + return (0); +} /* int conn_read */ +/* #endif KERNEL_LINUX */ + +#elif HAVE_SYSCTLBYNAME +static int conn_read (void) +{ + int status; + char *buffer; + size_t buffer_len;; + + struct xinpgen *in_orig; + struct xinpgen *in_ptr; + conn_reset_port_entry (); - conn_read_file ("/proc/net/tcp"); - conn_read_file ("/proc/net/tcp6"); + buffer_len = 0; + status = sysctlbyname ("net.inet.tcp.pcblist", NULL, &buffer_len, 0, 0); + if (status < 0) + { + ERROR ("tcpconns plugin: sysctlbyname failed."); + return (-1); + } + + buffer = (char *) malloc (buffer_len); + if (buffer == NULL) + { + ERROR ("tcpconns plugin: malloc failed."); + return (-1); + } + + status = sysctlbyname ("net.inet.tcp.pcblist", buffer, &buffer_len, 0, 0); + if (status < 0) + { + ERROR ("tcpconns plugin: sysctlbyname failed."); + sfree (buffer); + return (-1); + } + + if (buffer_len <= sizeof (struct xinpgen)) + { + ERROR ("tcpconns plugin: (buffer_len <= sizeof (struct xinpgen))"); + sfree (buffer); + return (-1); + } + + in_orig = (struct xinpgen *) buffer; + for (in_ptr = (struct xinpgen *) (((char *) in_orig) + in_orig->xig_len); + in_ptr->xig_len > sizeof (struct xinpgen); + in_ptr = (struct xinpgen *) (((char *) in_ptr) + in_ptr->xig_len)) + { + struct tcpcb *tp = &((struct xtcpcb *) in_ptr)->xt_tp; + struct inpcb *inp = &((struct xtcpcb *) in_ptr)->xt_inp; + struct xsocket *so = &((struct xtcpcb *) in_ptr)->xt_socket; + + /* Ignore non-TCP sockets */ + if (so->xso_protocol != IPPROTO_TCP) + continue; + + /* Ignore PCBs which were freed during copyout. */ + if (inp->inp_gencnt > in_orig->xig_gen) + continue; + + if (((inp->inp_vflag & INP_IPV4) == 0) + && ((inp->inp_vflag & INP_IPV6) == 0)) + continue; + + conn_handle_ports (inp->inp_lport, inp->inp_fport, tp->t_state); + } /* for (in_ptr) */ + + in_orig = NULL; + in_ptr = NULL; + sfree (buffer); conn_submit_all (); return (0); } /* int conn_read */ +#endif /* HAVE_SYSCTLBYNAME */ void module_register (void) { plugin_register_config ("tcpconns", conn_config, config_keys, config_keys_num); +#if KERNEL_LINUX plugin_register_init ("tcpconns", conn_init); +#endif plugin_register_read ("tcpconns", conn_read); } /* void module_register */