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); }
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); }
static int conn_read (void) { int status; conn_reset_port_entry (); if (linux_source == SRC_NETLINK) { status = conn_read_netlink (); } else if (linux_source == SRC_PROC) { int errors_num = 0; if (conn_read_file ("/proc/net/tcp") != 0) errors_num++; if (conn_read_file ("/proc/net/tcp6") != 0) errors_num++; if (errors_num < 2) status = 0; else status = ENOENT; } else /* if (linux_source == SRC_DUNNO) */ { /* Try to use netlink for getting this data, it is _much_ faster on systems * with a large amount of connections. */ status = conn_read_netlink (); if (status == 0) { INFO ("tcpconns plugin: Reading from netlink succeeded. " "Will use the netlink method from now on."); linux_source = SRC_NETLINK; } else { INFO ("tcpconns plugin: Reading from netlink failed. " "Will read from /proc from now on."); linux_source = SRC_PROC; /* return success here to avoid the "plugin failed" message. */ return (0); } } if (status == 0) conn_submit_all (); else return (status); return (0); } /* int conn_read */
static int conn_read (void) { struct inpcbtable table; struct inpcb *head; struct inpcb *next; struct inpcb inpcb; struct tcpcb tcpcb; int status; conn_reset_port_entry (); /* Read the pcbtable from the kernel */ status = kread (inpcbtable_off, &table, sizeof (table)); if (status != 0) return (-1); /* 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) { /* Read the pcb pointed to by `next' into `inpcb' */ kread ((u_long) next, &inpcb, sizeof (inpcb)); /* Advance `next' */ 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); } /* while (next != head) */ conn_submit_all (); return (0); }
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 */
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(); 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 = 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(ntohs(inp->inp_lport), ntohs(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 */
/* Returns zero on success, less than zero on socket error and greater than * zero on other errors. */ static int conn_read_netlink(void) { #if HAVE_STRUCT_LINUX_INET_DIAG_REQ int fd; struct inet_diag_msg *r; char buf[8192]; /* If this fails, it's likely a permission problem. We'll fall back to * reading this information from files below. */ fd = socket(AF_NETLINK, SOCK_RAW, NETLINK_INET_DIAG); if (fd < 0) { ERROR("tcpconns plugin: conn_read_netlink: socket(AF_NETLINK, SOCK_RAW, " "NETLINK_INET_DIAG) failed: %s", sstrerror(errno, buf, sizeof(buf))); return (-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) { ERROR("tcpconns plugin: conn_read_netlink: sendmsg(2) failed: %s", sstrerror(errno, buf, sizeof(buf))); close(fd); return (-1); } iov.iov_base = buf; iov.iov_len = sizeof(buf); while (1) { int status; struct nlmsghdr *h; memset(&msg, 0, sizeof(msg)); msg.msg_name = (void *)&nladdr; msg.msg_namelen = sizeof(nladdr); msg.msg_iov = &iov; msg.msg_iovlen = 1; status = recvmsg(fd, (void *)&msg, /* flags = */ 0); if (status < 0) { if ((errno == EINTR) || (errno == EAGAIN)) continue; ERROR("tcpconns plugin: conn_read_netlink: recvmsg(2) failed: %s", sstrerror(errno, buf, sizeof(buf))); close(fd); return (-1); } else if (status == 0) { close(fd); DEBUG("tcpconns plugin: conn_read_netlink: Unexpected zero-sized " "reply from netlink socket."); return (0); } h = (struct nlmsghdr *)buf; while (NLMSG_OK(h, status)) { if (h->nlmsg_seq != sequence_number) { h = NLMSG_NEXT(h, status); continue; } if (h->nlmsg_type == NLMSG_DONE) { close(fd); return (0); } else if (h->nlmsg_type == NLMSG_ERROR) { struct nlmsgerr *msg_error; msg_error = NLMSG_DATA(h); WARNING("tcpconns plugin: conn_read_netlink: Received error %i.", msg_error->error); close(fd); return (1); } r = NLMSG_DATA(h); /* This code does not (need to) distinguish between IPv4 and IPv6. */ conn_handle_ports(ntohs(r->id.idiag_sport), ntohs(r->id.idiag_dport), r->idiag_state); h = NLMSG_NEXT(h, status); } /* while (NLMSG_OK) */ } /* while (1) */ /* Not reached because the while() loop above handles the exit condition. */ return (0); #else return (1); #endif /* HAVE_STRUCT_LINUX_INET_DIAG_REQ */ } /* int conn_read_netlink */ static int conn_handle_line(char *buffer) { char *fields[32]; int fields_len; char *endptr; char *port_local_str; char *port_remote_str; uint16_t port_local; uint16_t port_remote; uint8_t state; int buffer_len = strlen(buffer); while ((buffer_len > 0) && (buffer[buffer_len - 1] < 32)) buffer[--buffer_len] = '\0'; if (buffer_len <= 0) 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); } port_local_str = strchr(fields[1], ':'); port_remote_str = strchr(fields[2], ':'); if ((port_local_str == NULL) || (port_remote_str == NULL)) return (-1); port_local_str++; port_remote_str++; if ((*port_local_str == '\0') || (*port_remote_str == '\0')) return (-1); endptr = NULL; port_local = (uint16_t)strtol(port_local_str, &endptr, 16); if ((endptr == NULL) || (*endptr != '\0')) return (-1); endptr = NULL; port_remote = (uint16_t)strtol(port_remote_str, &endptr, 16); if ((endptr == NULL) || (*endptr != '\0')) return (-1); endptr = NULL; state = (uint8_t)strtol(fields[3], &endptr, 16); if ((endptr == NULL) || (*endptr != '\0')) return (-1); return (conn_handle_ports(port_local, port_remote, state)); } /* int conn_handle_line */ static int conn_read_file(const char *file) { FILE *fh; char buffer[1024]; fh = fopen(file, "r"); if (fh == NULL) return (-1); while (fgets(buffer, sizeof(buffer), fh) != NULL) { conn_handle_line(buffer); } /* while (fgets) */ fclose(fh); return (0); } /* int conn_read_file */ /* #endif KERNEL_LINUX */ #elif HAVE_SYSCTLBYNAME /* #endif HAVE_SYSCTLBYNAME */ #elif HAVE_LIBKVM_NLIST #endif /* HAVE_LIBKVM_NLIST */ static int conn_config(const char *key, const char *value) { if (strcasecmp(key, "ListeningPorts") == 0) { if (IS_TRUE(value)) port_collect_listening = 1; else port_collect_listening = 0; } else if ((strcasecmp(key, "LocalPort") == 0) || (strcasecmp(key, "RemotePort") == 0)) { port_entry_t *pe; int port = atoi(value); if ((port < 1) || (port > 65535)) { ERROR("tcpconns plugin: Invalid port: %i", port); 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); } if (strcasecmp(key, "LocalPort") == 0) pe->flags |= PORT_COLLECT_LOCAL; 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); } return (0); } /* int conn_config */ #if KERNEL_LINUX static int conn_init(void) { if (port_collect_total == 0 && port_list_head == NULL) port_collect_listening = 1; return (0); } /* int conn_init */ static int conn_read(void) { int status; conn_reset_port_entry(); if (linux_source == SRC_NETLINK) { status = conn_read_netlink(); } else if (linux_source == SRC_PROC) { int errors_num = 0; if (conn_read_file("/proc/net/tcp") != 0) errors_num++; if (conn_read_file("/proc/net/tcp6") != 0) errors_num++; if (errors_num < 2) status = 0; else status = ENOENT; } else /* if (linux_source == SRC_DUNNO) */ { /* Try to use netlink for getting this data, it is _much_ faster on systems * with a large amount of connections. */ status = conn_read_netlink(); if (status == 0) { INFO("tcpconns plugin: Reading from netlink succeeded. " "Will use the netlink method from now on."); linux_source = SRC_NETLINK; } else { INFO("tcpconns plugin: Reading from netlink failed. " "Will read from /proc from now on."); linux_source = SRC_PROC; /* return success here to avoid the "plugin failed" message. */ return (0); } } if (status == 0) conn_submit_all(); else return (status); return (0); } /* int conn_read */