From c6e6d2852303ab491badd3af5571af0f36f67cc5 Mon Sep 17 00:00:00 2001 From: Stef Walter Date: Sat, 15 Mar 2008 19:18:33 +0000 Subject: * Add counter for number of processes in jail * Add configurable refresh interval for jail data * Don't list jails without any processes. * Fix crasher when a jail quits. * Report jailCount correctly after jails quit. --- module/bsnmp-jails.c | 182 +++++++++++++++++++++++++++++++++++++++++++-------- 1 file changed, 153 insertions(+), 29 deletions(-) (limited to 'module/bsnmp-jails.c') diff --git a/module/bsnmp-jails.c b/module/bsnmp-jails.c index 8fbefb2..9e88d5f 100644 --- a/module/bsnmp-jails.c +++ b/module/bsnmp-jails.c @@ -42,22 +42,27 @@ #include #include +#include #include #include #include #include #include +#include #include #include #include #include -#include -#include -#include #include #include +#include +#include +#include +#include +#include +#include #include #include @@ -101,6 +106,7 @@ struct jaildat { int mark; /* Configuration */ + int jailid; char *host; char *path; struct sockaddr_in addr; @@ -113,6 +119,7 @@ struct jaildat { uint64_t in_packets; uint64_t out_octets; uint64_t out_packets; + uint32_t n_processes; }; TAILQ_HEAD(jaildat_list, jaildat); @@ -129,12 +136,20 @@ static hsh_t *jaildat_by_host = NULL; /* Hash of jail structures by address */ static hsh_t *jaildat_by_address = NULL; +/* Hash of jail structures by id */ +static hsh_t *jaildat_by_id = NULL; + /* Timer for refreshing the jaildat info */ static void *timer_refresh = NULL; /* The monitor network filter */ static u_char *network_filter = NULL; +/* The KVM interface handle */ +static kvm_t *kvm_handle = NULL; + +/* Refresh interval in SNMP ticks */ +static int refresh_interval = 300; /* ----------------------------------------------------------------------------- * HELPERS @@ -245,7 +260,7 @@ struct ip6hdr { #pragma pack() static void -process_ip4 (const struct ip4hdr *hdr, uint32_t octets) +calculate_ip4 (const struct ip4hdr *hdr, uint32_t octets) { struct sockaddr_in addr; struct jaildat *jail; @@ -278,7 +293,7 @@ process_ip4 (const struct ip4hdr *hdr, uint32_t octets) } static void -process_ip6 (const struct ip6hdr *hdr, uint32_t octets) +calculate_ip6 (const struct ip6hdr *hdr, uint32_t octets) { struct sockaddr_in6 addr; struct jaildat *jail; @@ -330,7 +345,7 @@ monitor_packet (u_char *data, const struct pcap_pkthdr *hdr, const u_char *bytes minlen = (sizeof (struct ethhdr) + sizeof (struct ip4hdr)); if (hdr->len >= minlen) { ASSERT (hdr->caplen >= minlen); - process_ip4 ((const struct ip4hdr*)bytes, octets); + calculate_ip4 ((const struct ip4hdr*)bytes, octets); } /* IPv6 packet? */ @@ -338,7 +353,7 @@ monitor_packet (u_char *data, const struct pcap_pkthdr *hdr, const u_char *bytes minlen = (sizeof (struct ethhdr) + sizeof (struct ip6hdr)); if (hdr->len >= minlen) { ASSERT (hdr->caplen >= minlen); - process_ip6 ((const struct ip6hdr*)bytes, octets); + calculate_ip6 ((const struct ip6hdr*)bytes, octets); } } } @@ -531,6 +546,41 @@ monitor_test_filter (const char *filter) return ret; } +/* ----------------------------------------------------------------------------- + * PROCESS LOOKUPS + */ + +static void +process_refresh_all (void) +{ + struct jaildat *jail; + struct kinfo_proc *kp; + int nentries, i, id; + + /* Get a process listing */ + kp = kvm_getprocs (kvm_handle, KERN_PROC_PROC, 0, &nentries); + if (kp == NULL) { + emsg ("couldn't lookup process list: %s", kvm_geterr (kvm_handle)); + return; + } + + /* Clear process counts for each jail */ + TAILQ_FOREACH (jail, &jaildats, link) + jail->n_processes = 0; + + /* Okay now loop and add to each process's jail */ + for (i = 0; i < nentries; i++) { + + id = kp[i].ki_jid; + if (id == 0) + continue; + + jail = hsh_get (jaildat_by_id, &id, sizeof (id)); + if (jail) + jail->n_processes++; + } +} + /* ----------------------------------------------------------------------------- * JAIL LOOKUPS */ @@ -540,9 +590,16 @@ jail_free (struct jaildat *jail) { ASSERT (jail); - if (jail->host) + if (jail->jailid) + hsh_rem (jaildat_by_id, &jail->jailid, sizeof (jail->jailid)); + + if (jail->host) { + hsh_rem (jaildat_by_host, jail->host, HSH_KEY_STRING); free (jail->host); - jail->host = NULL; + jail->host = NULL; + } + + hsh_rem (jaildat_by_address, &(jail->addr), jail->addr.sin_len); if (jail->path) free (jail->path); @@ -552,14 +609,16 @@ jail_free (struct jaildat *jail) monitor_unref (jail->monitor); jail->monitor = NULL; - if (jail->index) + if (jail->index) { TAILQ_REMOVE (&jaildats, jail, link); + jaildat_count--; + } free (jail); } static int -jail_update (struct jaildat *jail, const char *host, +jail_update (struct jaildat *jail, int jailid, const char *host, const char *path, struct in_addr *addr) { struct monitor *mon; @@ -567,6 +626,12 @@ jail_update (struct jaildat *jail, const char *host, ASSERT (jail); + if (jail->jailid != jailid) { + hsh_rem (jaildat_by_id, &jail->jailid, sizeof (jail->jailid)); + jail->jailid = jailid; + hsh_set (jaildat_by_id, &jail->jailid, sizeof (jail->jailid), jail); + } + if (!host) host = ""; @@ -615,7 +680,7 @@ jail_update (struct jaildat *jail, const char *host, } static struct jaildat* -jail_alloc (const char *host, const char *path, struct in_addr *addr) +jail_alloc (int jailid, const char *host, const char *path, struct in_addr *addr) { struct jaildat *jail; @@ -623,7 +688,7 @@ jail_alloc (const char *host, const char *path, struct in_addr *addr) if (!jail) return NULL; - if (jail_update (jail, host, path, addr) < 0) { + if (jail_update (jail, jailid, host, path, addr) < 0) { jail_free (jail); return NULL; } @@ -690,9 +755,9 @@ jail_refresh_all (void* unused) in.s_addr = ntohl (xp->pr_ip); jail = hsh_get (jaildat_by_host, xp->pr_host, HSH_KEY_STRING); if (!jail) - jail = jail_alloc (xp->pr_host, xp->pr_path, &in); + jail = jail_alloc (xp->pr_id, xp->pr_host, xp->pr_path, &in); else - jail_update (jail, xp->pr_host, xp->pr_path, &in); + jail_update (jail, xp->pr_id, xp->pr_host, xp->pr_path, &in); jail->mark = 0; xp++; @@ -705,6 +770,14 @@ jail_refresh_all (void* unused) } free (sxp); + + process_refresh_all (); + + /* Remove any jails that have no processes (kernel anomally) */ + TAILQ_FOREACH_SAFE (jail, &jaildats, link, tmp) { + if (!jail->n_processes) + jail_free (jail); + } } /* ----------------------------------------------------------------------------- @@ -718,16 +791,25 @@ op_jailconfig (struct snmp_context *ctx, struct snmp_value *value, asn_subid_t which = value->var.subs[sub - 1]; int r = SNMP_ERR_NOERROR; - switch (which) { - case LEAF_jailNetworkFilter: - - if (op == SNMP_OP_GET) + if (op == SNMP_OP_GET) { + switch (which) { + case LEAF_jailNetworkFilter: return string_get (value, network_filter, -1); + case LEAF_jailRefreshInterval: + value->v.uint32 = refresh_interval; + return SNMP_ERR_NOERROR; + default: + ASSERT (0); + return -1; + }; + } - /* Remainder only at initialization */ - if (community != COMM_INITIALIZE) - return SNMP_ERR_NOT_WRITEABLE; + /* Remainder only at initialization */ + if (community != COMM_INITIALIZE) + return SNMP_ERR_NOT_WRITEABLE; + switch (which) { + case LEAF_jailNetworkFilter: switch (op) { case SNMP_OP_SET: if ((r = string_save (value, ctx, -1, &network_filter)) == SNMP_ERR_NOERROR) { @@ -744,18 +826,34 @@ op_jailconfig (struct snmp_context *ctx, struct snmp_value *value, string_rollback (ctx, &network_filter); break; default: - ASSERT(0); - break; + ASSERT (0); + return SNMP_ERR_GENERR; }; + break; - return r; + case LEAF_jailRefreshInterval: + switch (op) { + case SNMP_OP_SET: + ctx->scratch->int1 = refresh_interval; + refresh_interval = value->v.uint32; + return SNMP_ERR_NOERROR; + case SNMP_OP_ROLLBACK: + refresh_interval = ctx->scratch->int1; + return SNMP_ERR_NOERROR; + case SNMP_OP_COMMIT: + return SNMP_ERR_NOERROR; + default: + ASSERT (0); + return SNMP_ERR_GENERR; + }; + break; default: - break; + ASSERT (0); + return SNMP_ERR_GENERR; }; - ASSERT(0); - return -1; + return r; } int @@ -806,6 +904,9 @@ op_jailentry (struct snmp_context *ctx, struct snmp_value *value, case LEAF_jailOutPackets: value->v.uint32 = jail->out_packets; return SNMP_ERR_NOERROR; + case LEAF_jailProcesses: + value->v.integer = jail->n_processes; + return SNMP_ERR_NOERROR; default: ASSERT (0); return SNMP_ERR_NOSUCHNAME; @@ -862,10 +963,17 @@ module_fini (void) if (reg_index) or_unregister (reg_index); + if (kvm_handle) + kvm_close (kvm_handle); + if (network_filter) free (network_filter); network_filter = NULL; + if (jaildat_by_id) + hsh_free (jaildat_by_id); + jaildat_by_id = NULL; + if (jaildat_by_address) hsh_free (jaildat_by_address); jaildat_by_address = NULL; @@ -892,6 +1000,7 @@ static int module_init (struct lmodule *mod, int argc, char *argv[]) { int success = 0; + char errbuf[_POSIX2_LINE_MAX]; module = mod; @@ -900,10 +1009,24 @@ module_init (struct lmodule *mod, int argc, char *argv[]) return EINVAL; } + /* Open the kernel interface */ + kvm_handle = kvm_openfiles (_PATH_DEVNULL, _PATH_DEVNULL, _PATH_DEVNULL, + O_RDONLY, errbuf); + if (kvm_handle == NULL) { + syslog (LOG_ERR, "couldn't open kvm interface: %s", errbuf); + return ENOENT; + } + + /* Setup all our own structures */ + network_filter = strdup ("ip or ip6"); if (!network_filter) goto cleanup; + jaildat_by_id = hsh_create (); + if (!jaildat_by_id) + goto cleanup; + jaildat_by_host = hsh_create (); if (!jaildat_by_host) goto cleanup; @@ -932,7 +1055,8 @@ module_start (void) jail_refresh_all (NULL); - timer_refresh = timer_start_repeat (500, 500, jail_refresh_all, NULL, module); + timer_refresh = timer_start_repeat (refresh_interval, refresh_interval, + jail_refresh_all, NULL, module); if (!timer_refresh) emsg ("couldn't setup timer to refresh jails"); } -- cgit v1.2.3