Merge branch 'collectd-5.7'
authorRuben Kerkhof <ruben@rubenkerkhof.com>
Sun, 2 Jul 2017 18:52:18 +0000 (20:52 +0200)
committerRuben Kerkhof <ruben@rubenkerkhof.com>
Sun, 2 Jul 2017 18:52:18 +0000 (20:52 +0200)
1  2 
src/tcpconns.c

diff --combined src/tcpconns.c
  #include "common.h"
  #include "plugin.h"
  
 -#if defined(__OpenBSD__) || defined(__NetBSD__)
 +#if defined(__OpenBSD__)
 +#define HAVE_KVM_GETFILES 1
 +#endif
 +
 +#if defined(__NetBSD__)
  #undef HAVE_SYSCTLBYNAME /* force HAVE_LIBKVM_NLIST path */
  #endif
  
 -#if !KERNEL_LINUX && !HAVE_SYSCTLBYNAME && !HAVE_LIBKVM_NLIST && !KERNEL_AIX
 +#if !KERNEL_LINUX && !HAVE_SYSCTLBYNAME && !HAVE_KVM_GETFILES && !HAVE_LIBKVM_NLIST && !KERNEL_AIX
  #error "No applicable input method."
  #endif
  
  #include <netinet/tcpip.h>
  /* #endif HAVE_SYSCTLBYNAME */
  
 -/* This is for OpenBSD and NetBSD. */
 +#elif HAVE_KVM_GETFILES
 +#include <sys/types.h>
 +#include <sys/sysctl.h>
 +#define _KERNEL /* for DTYPE_SOCKET */
 +#include <sys/file.h>
 +#undef _KERNEL
 +
 +#include <netinet/in.h>
 +
 +#include <kvm.h>
 +/* #endif HAVE_KVM_GETFILES */
 +
 +/* This is for NetBSD. */
  #elif HAVE_LIBKVM_NLIST
  #include <arpa/inet.h>
  #include <net/route.h>
  #include <netdb.h>
  #include <netinet/in.h>
 +#include <netinet/ip.h>
  #include <netinet/in_pcb.h>
  #include <netinet/in_systm.h>
 -#include <netinet/ip.h>
  #include <netinet/ip_var.h>
  #include <netinet/tcp.h>
  #include <netinet/tcp_timer.h>
@@@ -185,19 -169,6 +185,19 @@@ static const char *tcp_state[] = {"CLOS
  #define TCP_STATE_MAX 10
  /* #endif HAVE_SYSCTLBYNAME */
  
 +#elif HAVE_KVM_GETFILES
 +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
 +
 +static kvm_t *kvmd;
 +/* #endif HAVE_KVM_GETFILES */
 +
  #elif HAVE_LIBKVM_NLIST
  static const char *tcp_state[] = {"CLOSED",    "LISTEN",      "SYN_SENT",
                                    "SYN_RECV",  "ESTABLISHED", "CLOSE_WAIT",
@@@ -356,14 -327,14 +356,14 @@@ static port_entry_t *conn_get_port_entr
    if ((ret == NULL) && (create != 0)) {
      ret = calloc(1, sizeof(*ret));
      if (ret == NULL)
 -      return (NULL);
 +      return NULL;
  
      ret->port = port;
      ret->next = port_list_head;
      port_list_head = ret;
    }
  
 -  return (ret);
 +  return ret;
  } /* port_entry_t *conn_get_port_entry */
  
  /* Removes ports that were added automatically due to the `ListeningPorts'
@@@ -417,7 -388,7 +417,7 @@@ static int conn_handle_ports(uint16_t p
      NOTICE("tcpconns plugin: Ignoring connection with "
             "unknown state 0x%02" PRIx8 ".",
             state);
 -    return (-1);
 +    return -1;
    }
  
    count_total[state]++;
    if (pe != NULL)
      pe->count_remote[state]++;
  
 -  return (0);
 +  return 0;
  } /* int conn_handle_ports */
  
  #if KERNEL_LINUX
@@@ -459,7 -430,7 +459,7 @@@ static int conn_read_netlink(void) 
      ERROR("tcpconns plugin: conn_read_netlink: socket(AF_NETLINK, SOCK_RAW, "
            "NETLINK_INET_DIAG) failed: %s",
            sstrerror(errno, buf, sizeof(buf)));
 -    return (-1);
 +    return -1;
    }
  
    struct sockaddr_nl nladdr = {.nl_family = AF_NETLINK};
      ERROR("tcpconns plugin: conn_read_netlink: sendmsg(2) failed: %s",
            sstrerror(errno, buf, sizeof(buf)));
      close(fd);
 -    return (-1);
 +    return -1;
    }
  
    iov.iov_base = buf;
        ERROR("tcpconns plugin: conn_read_netlink: recvmsg(2) failed: %s",
              sstrerror(errno, buf, sizeof(buf)));
        close(fd);
 -      return (-1);
 +      return -1;
      } else if (status == 0) {
        close(fd);
        DEBUG("tcpconns plugin: conn_read_netlink: Unexpected zero-sized "
              "reply from netlink socket.");
 -      return (0);
 +      return 0;
      }
  
      h = (struct nlmsghdr *)buf;
  
        if (h->nlmsg_type == NLMSG_DONE) {
          close(fd);
 -        return (0);
 +        return 0;
        } else if (h->nlmsg_type == NLMSG_ERROR) {
          struct nlmsgerr *msg_error;
  
                  msg_error->error);
  
          close(fd);
 -        return (1);
 +        return 1;
        }
  
        r = NLMSG_DATA(h);
    }   /* while (1) */
  
    /* Not reached because the while() loop above handles the exit condition. */
 -  return (0);
 +  return 0;
  #else
 -  return (1);
 +  return 1;
  #endif /* HAVE_STRUCT_LINUX_INET_DIAG_REQ */
  } /* int conn_read_netlink */
  
@@@ -579,40 -550,40 +579,40 @@@ static int conn_handle_line(char *buffe
    while ((buffer_len > 0) && (buffer[buffer_len - 1] < 32))
      buffer[--buffer_len] = '\0';
    if (buffer_len <= 0)
 -    return (-1);
 +    return -1;
  
    fields_len = strsplit(buffer, fields, STATIC_ARRAY_SIZE(fields));
    if (fields_len < 12) {
      DEBUG("tcpconns plugin: Got %i fields, expected at least 12.", fields_len);
 -    return (-1);
 +    return -1;
    }
  
    port_local_str = strchr(fields[1], ':');
    port_remote_str = strchr(fields[2], ':');
  
    if ((port_local_str == NULL) || (port_remote_str == NULL))
 -    return (-1);
 +    return -1;
    port_local_str++;
    port_remote_str++;
    if ((*port_local_str == '\0') || (*port_remote_str == '\0'))
 -    return (-1);
 +    return -1;
  
    endptr = NULL;
    port_local = (uint16_t)strtol(port_local_str, &endptr, 16);
    if ((endptr == NULL) || (*endptr != '\0'))
 -    return (-1);
 +    return -1;
  
    endptr = NULL;
    port_remote = (uint16_t)strtol(port_remote_str, &endptr, 16);
    if ((endptr == NULL) || (*endptr != '\0'))
 -    return (-1);
 +    return -1;
  
    endptr = NULL;
    state = (uint8_t)strtol(fields[3], &endptr, 16);
    if ((endptr == NULL) || (*endptr != '\0'))
 -    return (-1);
 +    return -1;
  
 -  return (conn_handle_ports(port_local, port_remote, state));
 +  return conn_handle_ports(port_local, port_remote, state);
  } /* int conn_handle_line */
  
  static int conn_read_file(const char *file) {
  
    fh = fopen(file, "r");
    if (fh == NULL)
 -    return (-1);
 +    return -1;
  
    while (fgets(buffer, sizeof(buffer), fh) != NULL) {
      conn_handle_line(buffer);
  
    fclose(fh);
  
 -  return (0);
 +  return 0;
  } /* int conn_read_file */
  /* #endif KERNEL_LINUX */
  
@@@ -652,13 -623,13 +652,13 @@@ static int conn_config(const char *key
  
      if ((port < 1) || (port > 65535)) {
        ERROR("tcpconns plugin: Invalid port: %i", port);
 -      return (1);
 +      return 1;
      }
  
      pe = conn_get_port_entry((uint16_t)port, 1 /* create */);
      if (pe == NULL) {
        ERROR("tcpconns plugin: conn_get_port_entry failed.");
 -      return (1);
 +      return 1;
      }
  
      if (strcasecmp(key, "LocalPort") == 0)
      else
        port_collect_total = 0;
    } else {
 -    return (-1);
 +    return -1;
    }
  
 -  return (0);
 +  return 0;
  } /* int conn_config */
  
  #if KERNEL_LINUX
@@@ -682,7 -653,7 +682,7 @@@ static int conn_init(void) 
    if (port_collect_total == 0 && port_list_head == NULL)
      port_collect_listening = 1;
  
 -  return (0);
 +  return 0;
  } /* int conn_init */
  
  static int conn_read(void) {
        linux_source = SRC_PROC;
  
        /* return success here to avoid the "plugin failed" message. */
 -      return (0);
 +      return 0;
      }
    }
  
    if (status == 0)
      conn_submit_all();
    else
 -    return (status);
 +    return status;
  
 -  return (0);
 +  return 0;
  } /* int conn_read */
  /* #endif KERNEL_LINUX */
  
@@@ -748,35 -719,41 +748,41 @@@ static int conn_read(void) 
    status = sysctlbyname("net.inet.tcp.pcblist", NULL, &buffer_len, 0, 0);
    if (status < 0) {
      ERROR("tcpconns plugin: sysctlbyname failed.");
 -    return (-1);
 +    return -1;
    }
  
    buffer = malloc(buffer_len);
    if (buffer == NULL) {
      ERROR("tcpconns plugin: malloc failed.");
 -    return (-1);
 +    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);
 +    return -1;
    }
  
    if (buffer_len <= sizeof(struct xinpgen)) {
      ERROR("tcpconns plugin: (buffer_len <= sizeof (struct xinpgen))");
      sfree(buffer);
 -    return (-1);
 +    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)) {
+ #if __FreeBSD_version >= 1200026
+     struct xtcpcb *tp = (struct xtcpcb *)in_ptr;
+     struct xinpcb *inp = &tp->xt_inp;
+     struct xsocket *so = &inp->xi_socket;
+ #else
      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;
+ #endif
  
      /* Ignore non-TCP sockets */
      if (so->xso_protocol != IPPROTO_TCP)
  
    conn_submit_all();
  
 -  return (0);
 +  return 0;
  } /* int conn_read */
    /* #endif HAVE_SYSCTLBYNAME */
  
 +#elif HAVE_KVM_GETFILES
 +
 +static int conn_init(void) {
 +  char buf[_POSIX2_LINE_MAX];
 +
 +  kvmd = kvm_openfiles(NULL, NULL, NULL, KVM_NO_FILES, buf);
 +  if (kvmd == NULL) {
 +    ERROR("tcpconns plugin: kvm_openfiles failed: %s", buf);
 +    return -1;
 +  }
 +
 +  return 0;
 +} /* int conn_init */
 +
 +static int conn_read(void) {
 +  struct kinfo_file *kf;
 +  int i, fcnt;
 +
 +  conn_reset_port_entry();
 +
 +  kf = kvm_getfiles(kvmd, KERN_FILE_BYFILE, DTYPE_SOCKET,
 +                  sizeof(*kf), &fcnt);
 +  if (kf == NULL) {
 +    ERROR("tcpconns plugin: kvm_getfiles failed.");
 +    return -1;
 +  }
 +
 +  for (i = 0; i < fcnt; i++) {
 +    if (kf[i].so_protocol != IPPROTO_TCP)
 +      continue;
 +    if (kf[i].inp_fport == 0)
 +      continue;
 +    conn_handle_ports(ntohs(kf[i].inp_lport), ntohs(kf[i].inp_fport),
 +                      kf[i].t_state);
 +  }
 +
 +  conn_submit_all();
 +
 +  return 0;
 +}
 +/* int conn_read */
 +/* #endif HAVE_KVM_GETFILES */
 +
  #elif HAVE_LIBKVM_NLIST
  static int kread(u_long addr, void *buf, int size) {
    int status;
    if (status != size) {
      ERROR("tcpconns plugin: kvm_read failed (got %i, expected %i): %s\n",
            status, size, kvm_geterr(kvmd));
 -    return (-1);
 +    return -1;
    }
 -  return (0);
 +  return 0;
  } /* int kread */
  
  static int conn_init(void) {
    kvmd = kvm_openfiles(NULL, NULL, NULL, O_RDONLY, buf);
    if (kvmd == NULL) {
      ERROR("tcpconns plugin: kvm_openfiles failed: %s", buf);
 -    return (-1);
 +    return -1;
    }
  
    status = kvm_nlist(kvmd, nl);
    if (status < 0) {
      ERROR("tcpconns plugin: kvm_nlist failed with status %i.", status);
 -    return (-1);
 +    return -1;
    }
  
    if (nl[N_TCBTABLE].n_type == 0) {
      ERROR("tcpconns plugin: Error looking up kernel's namelist: "
            "N_TCBTABLE is invalid.");
 -    return (-1);
 +    return -1;
    }
  
    inpcbtable_off = (u_long)nl[N_TCBTABLE].n_value;
    inpcbtable_ptr = (struct inpcbtable *)nl[N_TCBTABLE].n_value;
  
 -  return (0);
 +  return 0;
  } /* int conn_init */
  
  static int conn_read(void) {
    /* Read the pcbtable from the kernel */
    status = kread(inpcbtable_off, &table, sizeof(table));
    if (status != 0)
 -    return (-1);
 +    return -1;
  
  #if defined(__OpenBSD__) ||                                                    \
      (defined(__NetBSD_Version__) && __NetBSD_Version__ > 699002700)
      /* Read the pcb pointed to by `next' into `inpcb' */
      status = kread((u_long)next, &inpcb, sizeof(inpcb));
      if (status != 0)
 -      return (-1);
 +      return -1;
  
  /* Advance `next' */
  #if defined(__OpenBSD__) ||                                                    \
  
      status = kread((u_long)inpcb.inp_ppcb, &tcpcb, sizeof(tcpcb));
      if (status != 0)
 -      return (-1);
 +      return -1;
      conn_handle_ports(ntohs(inpcb.inp_lport), ntohs(inpcb.inp_fport),
                        tcpcb.t_state);
    } /* while (next != head) */
  
    conn_submit_all();
  
 -  return (0);
 +  return 0;
  }
  /* #endif HAVE_LIBKVM_NLIST */
  
@@@ -978,27 -912,27 +984,27 @@@ static int conn_read(void) 
    size = netinfo(NETINFO_TCP, 0, 0, 0);
    if (size < 0) {
      ERROR("tcpconns plugin: netinfo failed return: %i", size);
 -    return (-1);
 +    return -1;
    }
  
    if (size == 0)
 -    return (0);
 +    return 0;
  
    if ((size - sizeof(struct netinfo_header)) % sizeof(struct netinfo_conn)) {
      ERROR("tcpconns plugin: invalid buffer size");
 -    return (-1);
 +    return -1;
    }
  
    data = malloc(size);
    if (data == NULL) {
      ERROR("tcpconns plugin: malloc failed");
 -    return (-1);
 +    return -1;
    }
  
    if (netinfo(NETINFO_TCP, data, &size, 0) < 0) {
      ERROR("tcpconns plugin: netinfo failed");
      free(data);
 -    return (-1);
 +    return -1;
    }
  
    header = (struct netinfo_header *)data;
  
    conn_submit_all();
  
 -  return (0);
 +  return 0;
  }
  #endif /* KERNEL_AIX */
  
@@@ -1030,3 -964,7 +1036,3 @@@ void module_register(void) 
  #endif
    plugin_register_read("tcpconns", conn_read);
  } /* void module_register */
 -
 -/*
 - * vim: set shiftwidth=2 softtabstop=2 tabstop=8 fdm=marker :
 - */