Merge branch 'collectd-5.0' into collectd-5.1
[collectd.git] / src / tcpconns.c
index d53cb5a..3c8fc72 100644 (file)
@@ -1,6 +1,7 @@
 /**
  * collectd - src/tcpconns.c
- * Copyright (C) 2007  Florian octo Forster
+ * Copyright (C) 2007,2008  Florian octo Forster
+ * Copyright (C) 2008       Michael Stapelberg
  *
  * This program is free software; you can redistribute it and/or modify it
  * under the terms of the GNU General Public License as published by the
  *
  * Author:
  *   Florian octo Forster <octo at verplant.org>
+ *   Michael Stapelberg <michael+git at stapelberg.de>
  **/
 
 /**
- * Code within `__OpenBSD__' blocks is provided under the following license:
+ * Code within `HAVE_LIBKVM_NLIST' blocks is provided under the following
+ * license:
  *
  * $collectd: parts of tcpconns.c, 2008/08/08 03:48:30 Michael Stapelberg $
  * $OpenBSD: inet.c,v 1.100 2007/06/19 05:28:30 ray Exp $
 #include "common.h"
 #include "plugin.h"
 
-#if !KERNEL_LINUX && !HAVE_SYSCTLBYNAME && !__OpenBSD__
+#if defined(__OpenBSD__) || defined(__NetBSD__)
+#undef HAVE_SYSCTLBYNAME /* force HAVE_LIBKVM_NLIST path */
+#endif
+
+#if !KERNEL_LINUX && !HAVE_SYSCTLBYNAME && !HAVE_LIBKVM_NLIST && !KERNEL_AIX
 # error "No applicable input method."
 #endif
 
 # include <netinet/tcp_var.h>
 /* #endif HAVE_SYSCTLBYNAME */
 
-#elif __OpenBSD__
+/* This is for OpenBSD and NetBSD. */
+#elif HAVE_LIBKVM_NLIST
 # include <sys/queue.h>
 # include <sys/socket.h>
 # include <net/route.h>
 # include <netinet/in.h>
 # include <netinet/in_systm.h>
 # include <netinet/ip.h>
+# include <netinet/ip_var.h>
 # include <netinet/in_pcb.h>
 # include <netinet/tcp.h>
 # include <netinet/tcp_timer.h>
 # include <netinet/tcp_var.h>
 # include <netdb.h>
 # include <arpa/inet.h>
-# include <nlist.h>
+# if !defined(HAVE_BSD_NLIST_H) || !HAVE_BSD_NLIST_H
+#  include <nlist.h>
+# else /* HAVE_BSD_NLIST_H */
+#  include <bsd/nlist.h>
+# endif
 # include <kvm.h>
-#endif /* __OpenBSD__ */
+/* #endif HAVE_LIBKVM_NLIST */
+
+#elif KERNEL_AIX
+# include <arpa/inet.h>
+# include <sys/socketvar.h>
+#endif /* KERNEL_AIX */
 
 #if KERNEL_LINUX
 static const char *tcp_state[] =
@@ -154,7 +172,7 @@ static const char *tcp_state[] =
 # define TCP_STATE_MAX 10
 /* #endif HAVE_SYSCTLBYNAME */
 
-#elif __OpenBSD__
+#elif HAVE_LIBKVM_NLIST
 static const char *tcp_state[] =
 {
   "CLOSED",
@@ -177,7 +195,49 @@ struct inpcbtable *inpcbtable_ptr = NULL;
 # define TCP_STATE_LISTEN 1
 # define TCP_STATE_MIN 1
 # define TCP_STATE_MAX 10
-#endif /* __OpenBSD__ */
+/* #endif HAVE_LIBKVM_NLIST */
+
+#elif KERNEL_AIX
+static const char *tcp_state[] =
+{
+  "CLOSED",
+  "LISTEN",
+  "SYN_SENT",
+  "SYN_RCVD",
+  "ESTABLISHED",
+  "CLOSE_WAIT",
+  "FIN_WAIT_1",
+  "CLOSING",
+  "LAST_ACK",
+  "FIN_WAIT_2",
+  "TIME_WAIT"
+};
+
+# define TCP_STATE_LISTEN 1
+# define TCP_STATE_MIN 0
+# define TCP_STATE_MAX 10
+
+struct netinfo_conn {
+  uint32_t unknow1[2];
+  uint16_t dstport;
+  uint16_t unknow2;
+  struct in6_addr dstaddr;
+  uint16_t srcport;
+  uint16_t unknow3;
+  struct in6_addr srcaddr;
+  uint32_t unknow4[36];
+  uint16_t tcp_state;
+  uint16_t unknow5[7];
+};
+
+struct netinfo_header {
+  unsigned int proto;
+  unsigned int size;
+};
+
+# define NETINFO_TCP 3
+extern int netinfo (int proto, void *data, int *size,  int n);
+#endif /* KERNEL_AIX */
 
 #define PORT_COLLECT_LOCAL  0x01
 #define PORT_COLLECT_REMOTE 0x02
@@ -211,7 +271,6 @@ static void conn_submit_port_entry (port_entry_t *pe)
 
   vl.values = values;
   vl.values_len = 1;
-  vl.time = time (NULL);
   sstrncpy (vl.host, hostname_g, sizeof (vl.host));
   sstrncpy (vl.plugin, "tcpconns", sizeof (vl.plugin));
   sstrncpy (vl.type, "tcp_connections", sizeof (vl.type));
@@ -439,16 +498,14 @@ static int conn_read_file (const char *file)
 #elif HAVE_SYSCTLBYNAME
 /* #endif HAVE_SYSCTLBYNAME */
 
-#elif __OpenBSD__
-#endif /* __OpenBSD__ */
+#elif HAVE_LIBKVM_NLIST
+#endif /* HAVE_LIBKVM_NLIST */
 
 static int conn_config (const char *key, const char *value)
 {
   if (strcasecmp (key, "ListeningPorts") == 0)
   {
-    if ((strcasecmp (value, "Yes") == 0)
-       || (strcasecmp (value, "True") == 0)
-       || (strcasecmp (value, "On") == 0))
+    if (IS_TRUE (value))
       port_collect_listening = 1;
     else
       port_collect_listening = 0;
@@ -583,7 +640,8 @@ static int conn_read (void)
        && ((inp->inp_vflag & INP_IPV6) == 0))
       continue;
 
-    conn_handle_ports (inp->inp_lport, inp->inp_fport, tp->t_state);
+    conn_handle_ports (ntohs (inp->inp_lport), ntohs (inp->inp_fport),
+       tp->t_state);
   } /* for (in_ptr) */
 
   in_orig = NULL;
@@ -596,7 +654,7 @@ static int conn_read (void)
 } /* int conn_read */
 /* #endif HAVE_SYSCTLBYNAME */
 
-#elif __OpenBSD__
+#elif HAVE_LIBKVM_NLIST
 static int kread (u_long addr, void *buf, int size)
 {
   int status;
@@ -668,7 +726,7 @@ static int conn_read (void)
   /* Get the `head' pcb */
   head = (struct inpcb *) &(inpcbtable_ptr->inpt_queue);
   /* Get the first pcb */
-  next = CIRCLEQ_FIRST (&table.inpt_queue);
+  next = (struct inpcb *)CIRCLEQ_FIRST (&table.inpt_queue);
 
   while (next != head)
   {
@@ -676,15 +734,20 @@ static int conn_read (void)
     kread ((u_long) next, &inpcb, sizeof (inpcb));
 
     /* Advance `next' */
-    next = CIRCLEQ_NEXT (&inpcb, inp_queue);
+    next = (struct inpcb *)CIRCLEQ_NEXT (&inpcb, inp_queue);
 
     /* Ignore sockets, that are not connected. */
+#ifdef __NetBSD__
+    if (inpcb.inp_af == AF_INET6)
+      continue; /* XXX see netbsd/src/usr.bin/netstat/inet6.c */
+#else
     if (!(inpcb.inp_flags & INP_IPV6)
        && (inet_lnaof(inpcb.inp_laddr) == INADDR_ANY))
       continue;
     if ((inpcb.inp_flags & INP_IPV6)
        && IN6_IS_ADDR_UNSPECIFIED (&inpcb.inp_laddr6))
       continue;
+#endif
 
     kread ((u_long) inpcb.inp_ppcb, &tcpcb, sizeof (tcpcb));
     conn_handle_ports (ntohs(inpcb.inp_lport), ntohs(inpcb.inp_fport), tcpcb.t_state);
@@ -694,7 +757,67 @@ static int conn_read (void)
 
   return (0);
 }
-#endif /* __OpenBSD__ */
+/* #endif HAVE_LIBKVM_NLIST */
+
+#elif KERNEL_AIX
+
+static int conn_read (void)
+{
+  int size;
+  int i;
+  int nconn;
+  void *data;
+  struct netinfo_header *header;
+  struct netinfo_conn *conn;
+
+  conn_reset_port_entry ();
+
+  size = netinfo(NETINFO_TCP, 0, 0, 0);
+  if (size < 0)
+  {
+    ERROR ("tcpconns plugin: netinfo failed return: %i", size);
+    return (-1);
+  }
+
+  if (size == 0)
+    return (0);
+
+  if ((size - sizeof (struct netinfo_header)) % sizeof (struct netinfo_conn))
+  {
+    ERROR ("tcpconns plugin: invalid buffer size");
+    return (-1);
+  }
+
+  data = malloc(size);
+  if (data == NULL)
+  {
+    ERROR ("tcpconns plugin: malloc failed");
+    return (-1);
+  }
+
+  if (netinfo(NETINFO_TCP, data, &size, 0) < 0)
+  {
+    ERROR ("tcpconns plugin: netinfo failed");
+    free(data);
+    return (-1);
+  }
+
+  header = (struct netinfo_header *)data;
+  nconn = header->size;
+  conn = (struct netinfo_conn *)(data + sizeof(struct netinfo_header));
+
+  for (i=0; i < nconn; conn++, i++)
+  {
+    conn_handle_ports (conn->srcport, conn->dstport, conn->tcp_state);
+  }
+
+  free(data);
+
+  conn_submit_all ();
+
+  return (0);
+}
+#endif /* KERNEL_AIX */
 
 void module_register (void)
 {
@@ -704,8 +827,10 @@ void module_register (void)
        plugin_register_init ("tcpconns", conn_init);
 #elif HAVE_SYSCTLBYNAME
        /* no initialization */
-#elif __OpenBSD__
+#elif HAVE_LIBKVM_NLIST
        plugin_register_init ("tcpconns", conn_init);
+#elif KERNEL_AIX
+       /* no initialization */
 #endif
        plugin_register_read ("tcpconns", conn_read);
 } /* void module_register */