static int noit_lua_general_config(noit_module_generic_t *self, noit_hash_table *o) { lua_general_conf_t *conf = get_config(self); conf->script_dir = ""; conf->module = NULL; conf->function = NULL; (void)noit_hash_retr_str(o, "directory", strlen("directory"), &conf->script_dir); if(conf->script_dir) conf->script_dir = strdup(conf->script_dir); (void)noit_hash_retr_str(o, "lua_module", strlen("lua_module"), &conf->module); if(conf->module) conf->module = strdup(conf->module); (void)noit_hash_retr_str(o, "lua_function", strlen("lua_function"), &conf->function); if(conf->function) conf->function = strdup(conf->function); return 0; }
static int rest_stream_data(noit_http_rest_closure_t *restc, int npats, char **pats) { /* We're here and want to subvert the rest system */ const char *document_domain = NULL; noit_http_session_ctx *ctx = restc->http_ctx; noit_http_connection *conn = noit_http_session_connection(ctx); eventer_t e; acceptor_closure_t *ac = restc->ac; /* Rewire the handler */ if(ac->service_ctx_free) ac->service_ctx_free(ac->service_ctx); ac->service_ctx = ctx; ac->service_ctx_free = noit_http_ctx_acceptor_free; if(!noit_hash_retr_str(ac->config, "document_domain", strlen("document_domain"), &document_domain)) { noitL(noit_error, "Document domain not set! Realtime streaming will be broken\n"); document_domain = ""; } noit_http_process_querystring(noit_http_session_request(ctx)); /* Rewire the http context */ e = noit_http_connection_event(conn); e->callback = stratcon_realtime_http_handler; noit_http_session_set_dispatcher(ctx, stratcon_request_dispatcher, alloc_realtime_context(document_domain)); return stratcon_request_dispatcher(ctx); }
static void ping_icmp_log_results(noit_module_t *self, noit_check_t *check) { struct check_info *data; double avail = 0.0, min = MAXFLOAT, max = 0.0, avg = 0.0, cnt; int avail_needed = 100; const char *config_val = NULL; int i, points = 0; char human_buffer[256]; struct timeval duration; noit_check_stats_clear(check, &check->stats.inprogress); data = (struct check_info *)check->closure; for(i=0; i<data->expected_count; i++) { if(data->turnaround[i] >= 0.0) { points++; avg += data->turnaround[i]; if(data->turnaround[i] > max) max = data->turnaround[i]; if(data->turnaround[i] < min) min = data->turnaround[i]; } } cnt = data->expected_count; if(points == 0) { min = 0.0 / 0.0; max = 0.0 / 0.0; avg = 0.0 / 0.0; } else { avail = (float)points /cnt; avg /= (float)points; } if(noit_hash_retr_str(check->config, "avail_needed", strlen("avail_needed"), &config_val)) avail_needed = atoi(config_val); snprintf(human_buffer, sizeof(human_buffer), "cnt=%d,avail=%0.0f,min=%0.4f,max=%0.4f,avg=%0.4f", (int)cnt, 100.0*avail, min, max, avg); noitL(nldeb, "ping_icmp(%s) [%s]\n", check->target_ip, human_buffer); gettimeofday(&check->stats.inprogress.whence, NULL); sub_timeval(check->stats.inprogress.whence, check->last_fire_time, &duration); check->stats.inprogress.duration = duration.tv_sec * 1000 + duration.tv_usec / 1000; check->stats.inprogress.available = (avail > 0.0) ? NP_AVAILABLE : NP_UNAVAILABLE; check->stats.inprogress.state = (avail < ((float)avail_needed / 100.0)) ? NP_BAD : NP_GOOD; check->stats.inprogress.status = human_buffer; noit_stats_set_metric(check, &check->stats.inprogress, "count", METRIC_INT32, &data->expected_count); avail *= 100.0; noit_stats_set_metric(check, &check->stats.inprogress, "available", METRIC_DOUBLE, &avail); noit_stats_set_metric(check, &check->stats.inprogress, "minimum", METRIC_DOUBLE, avail > 0.0 ? &min : NULL); noit_stats_set_metric(check, &check->stats.inprogress, "maximum", METRIC_DOUBLE, avail > 0.0 ? &max : NULL); noit_stats_set_metric(check, &check->stats.inprogress, "average", METRIC_DOUBLE, avail > 0.0 ? &avg : NULL); noit_check_set_stats(check, &check->stats.inprogress); noit_check_stats_clear(check, &check->stats.inprogress); }
const char * noit_log_stream_get_property(noit_log_stream_t ls, const char *prop) { const char *v; if(ls && ls->config && noit_hash_retr_str(ls->config, prop, strlen(prop), &v)) return v; return NULL; }
static int check_test_config(noit_module_generic_t *self, noit_hash_table *o) { const char *str; int new_interval = 0; if(noit_hash_retr_str(o, "sweep_interval", strlen("sweep_interval"), &str)) new_interval = atoi(str); if(new_interval > 0) default_sweep_interval = new_interval; return 0; }
static int test_abort_initiate(noit_module_t *self, noit_check_t *check, noit_check_t *cause) { test_abort_check_info_t *ci = check->closure; struct timeval __now; const char *v; noitL(nlerr, "test_abort_initiate\n"); /* We cannot be running */ BAIL_ON_RUNNING_CHECK(check); check->flags |= NP_RUNNING; ci->self = self; ci->check = check; ci->timeout = 30; if(noit_hash_retr_str(check->config, "sleep", strlen("sleep"), &v)) { ci->timeout = atof(v); } ci->ignore_signals = 0; if(noit_hash_retr_str(check->config, "ignore_signals", strlen("ignore_signals"), &v)) { if(!strcmp(v, "true")) ci->ignore_signals = 1; } ci->timed_out = 1; ci->method = 0; if(noit_hash_retr_str(check->config, "method", strlen("method"), &v)) { if(!strcmp(v, "evil")) ci->method = EVENTER_EVIL_BRUTAL; else if(!strcmp(v, "deferred")) ci->method = EVENTER_CANCEL_DEFERRED; else if(!strcmp(v, "asynch")) ci->method = EVENTER_CANCEL_ASYNCH; } gettimeofday(&__now, NULL); memcpy(&check->last_fire_time, &__now, sizeof(__now)); /* Register a handler for the worker */ noit_check_run_full_asynch_opts(check, test_abort_drive_session, ci->method); return 0; }
static int dns_module_init(noit_module_t *self) { const struct dns_nameval *nv; struct dns_ctx *pctx; int i; const char *config_val; dns_mod_config_t *conf; conf = noit_module_get_userdata(self); pthread_mutex_init(&dns_ctx_store_lock, NULL); pthread_mutex_init(&active_events_lock, NULL); conf->contexts = DEFAULT_MAX_CONTEXTS; if(noit_hash_retr_str(conf->options, "contexts", strlen("contexts"), (const char**)&config_val)) { conf->contexts = atoi(config_val); if (conf->contexts <= 0) conf->contexts = DEFAULT_MAX_CONTEXTS; } /* HASH the rr types */ for(i=0, nv = dns_type_index(i); nv->name; nv = dns_type_index(++i)) noit_hash_store(&dns_rtypes, nv->name, strlen(nv->name), (void *)nv); /* HASH the class types */ for(i=0, nv = dns_class_index(i); nv->name; nv = dns_class_index(++i)) noit_hash_store(&dns_ctypes, nv->name, strlen(nv->name), (void *)nv); noit_check_interpolate_register_oper_fn("inaddrarpa", dns_interpolate_inaddr_arpa); noit_check_interpolate_register_oper_fn("reverseip", dns_interpolate_reverse_ip); if (dns_init(NULL, 0) < 0 || (pctx = dns_new(NULL)) == NULL) { noitL(nlerr, "Unable to initialize dns subsystem\n"); return -1; } dns_free(pctx); if(dns_module_dns_ctx_alloc(self, NULL, 0) == NULL) { noitL(nlerr, "Error setting up default dns resolver context.\n"); return -1; } register_console_dns_commands(); return 0; }
static int noit_lua_http_request_querystring(lua_State *L) { noit_hash_table *h; CCALL_DECL(L, noit_http_request, req, 0); h = noit_http_request_querystring_table(req); if(lua_gettop(L) == 1) noit_lua_hash_to_table(L, h); else if(lua_gettop(L) == 2) { const char *key = lua_tostring(L,2), *value; if(key == NULL) lua_pushnil(L); else { if(noit_hash_retr_str(h, key, strlen(key), &value)) lua_pushstring(L, value); else lua_pushnil(L); } } else luaL_error(L, "invalid arguments to noit_http_request:querystring()"); return 1; }
static int noit_lua_http_request_headers(lua_State *L) { noit_hash_table *h; CCALL_DECL(L, noit_http_request, req, 0); h = noit_http_request_headers_table(req); if(lua_gettop(L) == 1) noit_lua_hash_to_table(L, h); else if(lua_gettop(L) == 2) { const char *hdr = lua_tostring(L,2); if(hdr == NULL) lua_pushnil(L); else { char *cp, *lower = alloca(strlen(hdr) + 1); memcpy(lower, hdr, strlen(hdr)+1); for(cp=lower; *cp; cp++) *cp = tolower(*cp); if(noit_hash_retr_str(h, lower, strlen(lower), &hdr)) lua_pushstring(L, hdr); else lua_pushnil(L); } } else luaL_error(L, "invalid arguments to noit_http_request:headers()"); return 1; }
static int external_init(noit_module_t *self) { external_data_t *data; data = noit_module_get_userdata(self); if(!data) data = malloc(sizeof(*data)); data->nlerr = noit_log_stream_find("error/external"); data->nldeb = noit_log_stream_find("debug/external"); data->jobq = calloc(1, sizeof(*data->jobq)); eventer_jobq_init(data->jobq, "external"); data->jobq->backq = eventer_default_backq(); eventer_jobq_increase_concurrency(data->jobq); if(socketpair(AF_UNIX, SOCK_STREAM, 0, data->pipe_n2e) != 0 || socketpair(AF_UNIX, SOCK_STREAM, 0, data->pipe_e2n) != 0) { noitL(noit_error, "external: pipe() failed: %s\n", strerror(errno)); return -1; } data->child = fork(); if(data->child == -1) { /* No child, bail. */ noitL(noit_error, "external: fork() failed: %s\n", strerror(errno)); return -1; } /* parent must close the read side of n2e and the write side of e2n */ /* The child must do the opposite */ close(data->pipe_n2e[(data->child == 0) ? 1 : 0]); close(data->pipe_e2n[(data->child == 0) ? 0 : 1]); /* Now the parent must set its bits non-blocking, the child need not */ if(data->child != 0) { /* in the parent */ if(eventer_set_fd_nonblocking(data->pipe_e2n[0]) == -1) { close(data->pipe_n2e[1]); close(data->pipe_e2n[0]); noitL(noit_error, "external: could not set pipe non-blocking: %s\n", strerror(errno)); return -1; } eventer_t newe; newe = eventer_alloc(); newe->fd = data->pipe_e2n[0]; newe->mask = EVENTER_READ | EVENTER_EXCEPTION; newe->callback = external_handler; newe->closure = self; eventer_add(newe); } else { const char *user = NULL, *group = NULL; if(data->options) { noit_hash_retr_str(data->options, "user", 4, &user); noit_hash_retr_str(data->options, "group", 4, &group); } noit_security_usergroup(user, group, noit_false); exit(external_child(data)); } noit_module_set_userdata(self, data); return 0; }
static int noit_statsd_init(noit_module_t *self) { unsigned short port = 8125; int packets_per_cycle = 100; int payload_len = 256*1024; struct sockaddr_in skaddr; int sockaddr_len; const char *config_val; statsd_mod_config_t *conf; conf = noit_module_get_userdata(self); eventer_name_callback("statsd/statsd_handler", statsd_handler); if(noit_hash_retr_str(conf->options, "check", strlen("check"), (const char **)&config_val)) { if(uuid_parse((char *)config_val, conf->primary) != 0) noitL(noit_error, "statsd check isn't a UUID\n"); conf->primary_active = 1; conf->check = NULL; } if(noit_hash_retr_str(conf->options, "port", strlen("port"), (const char **)&config_val)) { port = atoi(config_val); } conf->port = port; if(noit_hash_retr_str(conf->options, "packets_per_cycle", strlen("packets_per_cycle"), (const char **)&config_val)) { packets_per_cycle = atoi(config_val); } conf->packets_per_cycle = packets_per_cycle; conf->payload_len = payload_len; conf->payload = malloc(conf->payload_len); if(!conf->payload) { noitL(noit_error, "statsd malloc() failed\n"); return -1; } conf->ipv4_fd = socket(PF_INET, NE_SOCK_CLOEXEC|SOCK_DGRAM, IPPROTO_UDP); if(conf->ipv4_fd < 0) { noitL(noit_error, "statsd: socket failed: %s\n", strerror(errno)); return -1; } else { if(eventer_set_fd_nonblocking(conf->ipv4_fd)) { close(conf->ipv4_fd); conf->ipv4_fd = -1; noitL(noit_error, "collectd: could not set socket non-blocking: %s\n", strerror(errno)); return -1; } } memset(&skaddr, 0, sizeof(skaddr)); skaddr.sin_family = AF_INET; skaddr.sin_addr.s_addr = htonl(INADDR_ANY); skaddr.sin_port = htons(conf->port); sockaddr_len = sizeof(skaddr); if(bind(conf->ipv4_fd, (struct sockaddr *)&skaddr, sockaddr_len) < 0) { noitL(noit_error, "bind failed[%d]: %s\n", conf->port, strerror(errno)); close(conf->ipv4_fd); return -1; } if(conf->ipv4_fd >= 0) { eventer_t newe; newe = eventer_alloc(); newe->fd = conf->ipv4_fd; newe->mask = EVENTER_READ | EVENTER_EXCEPTION; newe->callback = statsd_handler; newe->closure = self; eventer_add(newe); } conf->ipv6_fd = socket(AF_INET6, NE_SOCK_CLOEXEC|SOCK_DGRAM, IPPROTO_UDP); if(conf->ipv6_fd < 0) { noitL(noit_error, "statsd: IPv6 socket failed: %s\n", strerror(errno)); } else { if(eventer_set_fd_nonblocking(conf->ipv6_fd)) { close(conf->ipv6_fd); conf->ipv6_fd = -1; noitL(noit_error, "statsd: could not set socket non-blocking: %s\n", strerror(errno)); } else { struct sockaddr_in6 skaddr6; struct in6_addr in6addr_any; sockaddr_len = sizeof(skaddr6); memset(&skaddr6, 0, sizeof(skaddr6)); skaddr6.sin6_family = AF_INET6; memset(&in6addr_any, 0, sizeof(in6addr_any)); skaddr6.sin6_addr = in6addr_any; skaddr6.sin6_port = htons(conf->port); if(bind(conf->ipv6_fd, (struct sockaddr *)&skaddr6, sockaddr_len) < 0) { noitL(noit_error, "bind(IPv6) failed[%d]: %s\n", conf->port, strerror(errno)); close(conf->ipv6_fd); conf->ipv6_fd = -1; } } } if(conf->ipv6_fd >= 0) { eventer_t newe; newe = eventer_alloc(); newe->fd = conf->ipv6_fd; newe->mask = EVENTER_READ | EVENTER_EXCEPTION; newe->callback = statsd_handler; newe->closure = self; eventer_add(newe); } noit_module_set_userdata(self, conf); return 0; }
static int ssh2_initiate(noit_module_t *self, noit_check_t *check, noit_check_t *cause) { ssh2_check_info_t *ci = check->closure; struct timeval p_int, __now; int fd = -1, rv = -1; eventer_t e; union { struct sockaddr_in sin; struct sockaddr_in6 sin6; } sockaddr; socklen_t sockaddr_len; unsigned short ssh_port = DEFAULT_SSH_PORT; const char *port_str = NULL; /* We cannot be running */ BAIL_ON_RUNNING_CHECK(check); check->flags |= NP_RUNNING; ci->self = self; ci->check = check; ci->timed_out = 1; if(ci->timeout_event) { eventer_remove(ci->timeout_event); free(ci->timeout_event->closure); eventer_free(ci->timeout_event); ci->timeout_event = NULL; } gettimeofday(&__now, NULL); memcpy(&check->last_fire_time, &__now, sizeof(__now)); if(check->target_ip[0] == '\0') { ci->error = strdup("name resolution failure"); goto fail; } /* Open a socket */ fd = socket(check->target_family, NE_SOCK_CLOEXEC|SOCK_STREAM, 0); if(fd < 0) goto fail; /* Make it non-blocking */ if(eventer_set_fd_nonblocking(fd)) goto fail; if(noit_hash_retr_str(check->config, "port", strlen("port"), &port_str)) { ssh_port = (unsigned short)atoi(port_str); } #define config_method(a) do { \ const char *v; \ if(noit_hash_retr_str(check->config, "method_" #a, strlen("method_" #a), \ &v)) \ ci->methods.a = strdup(v); \ } while(0) config_method(kex); config_method(hostkey); config_method(crypt_cs); config_method(crypt_sc); config_method(mac_cs); config_method(mac_sc); config_method(comp_cs); config_method(comp_sc); memset(&sockaddr, 0, sizeof(sockaddr)); sockaddr.sin6.sin6_family = check->target_family; if(check->target_family == AF_INET) { memcpy(&sockaddr.sin.sin_addr, &check->target_addr.addr, sizeof(sockaddr.sin.sin_addr)); sockaddr.sin.sin_port = htons(ssh_port); sockaddr_len = sizeof(sockaddr.sin); } else { memcpy(&sockaddr.sin6.sin6_addr, &check->target_addr.addr6, sizeof(sockaddr.sin6.sin6_addr)); sockaddr.sin6.sin6_port = htons(ssh_port); sockaddr_len = sizeof(sockaddr.sin6); } /* Initiate a connection */ rv = connect(fd, (struct sockaddr *)&sockaddr, sockaddr_len); if(rv == -1 && errno != EINPROGRESS) goto fail; /* Register a handler for connection completion */ e = eventer_alloc(); e->fd = fd; e->mask = EVENTER_READ | EVENTER_WRITE | EVENTER_EXCEPTION; e->callback = ssh2_connect_complete; e->closure = ci; ci->synch_fd_event = e; eventer_add(e); e = eventer_alloc(); e->mask = EVENTER_TIMER; e->callback = ssh2_connect_timeout; e->closure = ci; memcpy(&e->whence, &__now, sizeof(__now)); p_int.tv_sec = check->timeout / 1000; p_int.tv_usec = (check->timeout % 1000) * 1000; add_timeval(e->whence, p_int, &e->whence); ci->timeout_event = e; eventer_add(e); return 0; fail: if(fd >= 0) close(fd); ssh2_log_results(ci->self, ci->check); ssh2_cleanup(ci->self, ci->check); check->flags &= ~NP_RUNNING; return -1; }
static int dns_check_send(noit_module_t *self, noit_check_t *check, noit_check_t *cause) { void *vnv_pair = NULL; struct dns_nameval *nv_pair; eventer_t newe; struct timeval p_int, now; struct dns_check_info *ci = check->closure; const char *config_val; const char *rtype = NULL; const char *nameserver = NULL; int port = 0; const char *port_str = NULL; const char *want_sort = NULL; const char *ctype = "IN"; const char *query = NULL; char interpolated_nameserver[1024]; char interpolated_query[1024]; noit_hash_table check_attrs_hash = NOIT_HASH_EMPTY; BAIL_ON_RUNNING_CHECK(check); gettimeofday(&now, NULL); memcpy(&check->last_fire_time, &now, sizeof(now)); ci->current.state = NP_BAD; ci->current.available = NP_UNAVAILABLE; ci->timed_out = 1; ci->nrr = 0; ci->sort = 1; if(!strcmp(check->name, "in-addr.arpa") || (strlen(check->name) >= sizeof("::in-addr.arpa") - 1 && !strcmp(check->name + strlen(check->name) - sizeof("::in-addr.arpa") + 1, "::in-addr.arpa"))) { /* in-addr.arpa defaults: * nameserver to NULL * rtype to PTR * query to %[:inaddrarpa:target] */ nameserver = NULL; rtype = "PTR"; query = "%[:inaddrarpa:target_ip]"; } else { nameserver = "%[target_ip]"; rtype = "A"; query = "%[name]"; } if(noit_hash_retr_str(check->config, "port", strlen("port"), &port_str)) { port = atoi(port_str); } #define CONFIG_OVERRIDE(a) \ if(noit_hash_retr_str(check->config, #a, strlen(#a), \ &config_val) && \ strlen(config_val) > 0) \ a = config_val CONFIG_OVERRIDE(ctype); CONFIG_OVERRIDE(nameserver); CONFIG_OVERRIDE(rtype); CONFIG_OVERRIDE(query); CONFIG_OVERRIDE(want_sort); if(nameserver && !strcmp(nameserver, "default")) nameserver = NULL; if(want_sort && strcasecmp(want_sort, "on") && strcasecmp(want_sort, "true")) ci->sort = 0; noit_check_make_attrs(check, &check_attrs_hash); if(nameserver) { noit_check_interpolate(interpolated_nameserver, sizeof(interpolated_nameserver), nameserver, &check_attrs_hash, check->config); nameserver = interpolated_nameserver; } if(query) { noit_check_interpolate(interpolated_query, sizeof(interpolated_query), query, &check_attrs_hash, check->config); query = interpolated_query; } noit_hash_destroy(&check_attrs_hash, NULL, NULL); check->flags |= NP_RUNNING; noitL(nldeb, "dns_check_send(%p,%s,%s,%s,%s,%s)\n", self, check->target, nameserver ? nameserver : "default", query ? query : "null", ctype, rtype); __activate_ci(ci); /* If this ci has a handle and it isn't the one we need, * we should release it */ if(ci->h && ((ci->h->ns == NULL && nameserver != NULL) || (ci->h->ns != NULL && nameserver == NULL) || (ci->h->ns && strcmp(ci->h->ns, nameserver)))) { dns_ctx_release(ci->h); ci->h = NULL; } /* use the cached one, unless we don't have one */ if(!ci->h) ci->h = dns_ctx_alloc(nameserver, port); if(!ci->h) ci->error = strdup("bad nameserver"); /* Lookup out class */ if(!noit_hash_retrieve(&dns_ctypes, ctype, strlen(ctype), &vnv_pair)) { if(ci->error) free(ci->error); ci->error = strdup("bad class"); } else { nv_pair = (struct dns_nameval *)vnv_pair; ci->query_ctype = nv_pair->val; } /* Lookup out rr type */ if(!noit_hash_retrieve(&dns_rtypes, rtype, strlen(rtype), &vnv_pair)) { if(ci->error) free(ci->error); ci->error = strdup("bad rr type"); } else { nv_pair = (struct dns_nameval *)vnv_pair; ci->query_rtype = nv_pair->val; } if(!ci->error) { /* Submit the query */ int abs; if(!dns_ptodn(query, strlen(query), ci->dn, sizeof(ci->dn), &abs) || !dns_submit_dn(ci->h->ctx, ci->dn, ci->query_ctype, ci->query_rtype, abs | DNS_NOSRCH, NULL, dns_cb, ci)) { ci->error = strdup("submission error"); } else { dns_timeouts(ci->h->ctx, -1, now.tv_sec); } } /* we could have completed by now... if so, we've nothing to do */ if(!__isactive_ci(ci)) return 0; if(ci->error) { /* Errors here are easy, fail and avoid scheduling a timeout */ ci->check->flags &= ~NP_RUNNING; dns_check_log_results(ci); __deactivate_ci(ci); return 0; } newe = eventer_alloc(); newe->mask = EVENTER_TIMER; gettimeofday(&now, NULL); p_int.tv_sec = check->timeout / 1000; p_int.tv_usec = (check->timeout % 1000) * 1000; add_timeval(now, p_int, &newe->whence); newe->closure = ci; newe->callback = dns_check_timeout; ci->timeout_event = newe; eventer_add(newe); return 0; }
int noit_console_handler(eventer_t e, int mask, void *closure, struct timeval *now) { int newmask = EVENTER_READ | EVENTER_EXCEPTION; int keep_going; acceptor_closure_t *ac = closure; noit_console_closure_t ncct = ac->service_ctx; if(mask & EVENTER_EXCEPTION || (ncct && ncct->wants_shutdown)) { socket_error: /* Exceptions cause us to simply snip the connection */ /* This removes the log feed which is important to do before calling close */ eventer_remove_fd(e->fd); if(ncct) noit_console_closure_free(ncct); if(ac) acceptor_closure_free(ac); e->opset->close(e->fd, &newmask, e); return 0; } if(!ac->service_ctx) { ncct = ac->service_ctx = noit_console_closure_alloc(); } if(!ncct->initialized) { ncct->e = e; if(allocate_pty(&ncct->pty_master, &ncct->pty_slave)) { nc_printf(ncct, "Failed to open pty: %s\n", strerror(errno)); ncct->wants_shutdown = 1; goto socket_error; } else { int i; const char *line_protocol; HistEvent ev; ncct->hist = history_init(); history(ncct->hist, &ev, H_SETSIZE, 500); ncct->el = el_init("noitd", ncct->pty_master, NULL, e->fd, e, e->fd, e); if(!ncct->el) goto socket_error; if(el_set(ncct->el, EL_USERDATA, ncct)) { noitL(noit_error, "Cannot set userdata on noitedit session\n"); goto socket_error; } if(el_set(ncct->el, EL_EDITOR, "emacs")) noitL(noit_error, "Cannot set emacs mode on console\n"); if(el_set(ncct->el, EL_HIST, history, ncct->hist)) noitL(noit_error, "Cannot set history on console\n"); el_set(ncct->el, EL_ADDFN, "noit_complete", "auto completion functions for noit", noit_edit_complete); el_set(ncct->el, EL_BIND, "^I", "noit_complete", NULL); for(i=EL_NUM_FCNS; i < ncct->el->el_map.nfunc; i++) { if(ncct->el->el_map.func[i] == noit_edit_complete) { ncct->noit_edit_complete_cmdnum = i; break; } } if(!noit_hash_retr_str(ac->config, "line_protocol", strlen("line_protocol"), &line_protocol)) { line_protocol = NULL; } if(line_protocol && !strcasecmp(line_protocol, "telnet")) { ncct->telnet = noit_console_telnet_alloc(ncct); ncct->output_cooker = nc_telnet_cooker; } noit_console_state_init(ncct); } snprintf(ncct->feed_path, sizeof(ncct->feed_path), "console/%d", e->fd); noit_log_stream_new(ncct->feed_path, "noit_console", ncct->feed_path, ncct, NULL); noit_console_motd(e, ac, ncct); ncct->initialized = 1; } /* If we still have data to send back to the client, this will take * care of that */ if(noit_console_continue_sending(ncct, &newmask) < 0) { if(ncct->wants_shutdown || errno != EAGAIN) goto socket_error; return newmask | EVENTER_EXCEPTION; } for(keep_going=1 ; keep_going ; ) { int len, plen; char sbuf[4096]; const char *buffer; keep_going = 0; buffer = el_gets(ncct->el, &plen); if(!el_eagain(ncct->el)) { if(!buffer) { buffer = "exit"; plen = 4; nc_write(ncct, "\n", 1); } keep_going++; } len = e->opset->read(e->fd, sbuf, sizeof(sbuf)-1, &newmask, e); if(len == 0 || (len < 0 && errno != EAGAIN)) { eventer_remove_fd(e->fd); if(ncct) noit_console_closure_free(ncct); if(ac) acceptor_closure_free(ac); e->opset->close(e->fd, &newmask, e); return 0; } if(len > 0) { keep_going++; sbuf[len] = '\0'; if(ncct->telnet) { noit_console_telnet_telrcv(ncct, sbuf, len); ptyflush(ncct); } else { int written; written = write(ncct->pty_slave, sbuf, len); if(written <= 0) goto socket_error; assert(written == len); } } if(buffer) { char *cmd_buffer; cmd_buffer = malloc(plen+1); memcpy(cmd_buffer, buffer, plen); /* chomp */ cmd_buffer[plen] = '\0'; if(cmd_buffer[plen-1] == '\n') cmd_buffer[plen-1] = '\0'; noitL(noit_debug, "IN[%d]: '%s'\n", plen, cmd_buffer); noit_console_dispatch(e, cmd_buffer, ncct); free(cmd_buffer); } if(noit_console_continue_sending(ncct, &newmask) == -1) { if(ncct->wants_shutdown || errno != EAGAIN) goto socket_error; return newmask | EVENTER_EXCEPTION; } if(ncct->wants_shutdown) goto socket_error; } return newmask | EVENTER_EXCEPTION; }
int noit_check_interpolate(char *buff, int len, const char *fmt, noit_hash_table *attrs, noit_hash_table *config) { char *copy = NULL; char closer; const char *fmte, *key; int replaced_something = 1; int iterations = 3; while(replaced_something && iterations > 0) { char *cp = buff, * const end = buff + len; iterations--; replaced_something = 0; while(*fmt && cp < end) { switch(*fmt) { case '%': if(fmt[1] == '{' || fmt[1] == '[') { closer = (fmt[1] == '{') ? '}' : ']'; fmte = fmt + 2; key = fmte; while(*fmte && *fmte != closer) fmte++; if(*fmte == closer) { /* We have a full key here */ const char *replacement, *oper, *nkey; intperpolate_oper_fn oper_sprint; /* keys can be of the form: :operator:key */ oper = key; if(*oper == ':' && (nkey = strnstrn(":", 1, oper + 1, fmte - key - 1)) != NULL) { void *voper; oper++; /* find oper, nkey-oper */ if(!noit_hash_retrieve(&interpolation_operators, oper, nkey - oper, &voper)) { /* else oper <- copy */ oper_sprint = interpolate_oper_copy; } else oper_sprint = (intperpolate_oper_fn)voper; nkey++; } else { oper_sprint = interpolate_oper_copy; nkey = key; } if(!noit_hash_retr_str((closer == '}') ? config : attrs, nkey, fmte - nkey, &replacement)) replacement = ""; fmt = fmte + 1; /* Format points just after the end of the key */ cp += oper_sprint(cp, end-cp, replacement); *(end-1) = '\0'; /* In case the oper_sprint didn't teminate */ replaced_something = 1; break; } } default: *cp++ = *fmt++; } } *cp = '\0'; if(copy) free(copy); if(replaced_something) copy = strdup(buff); fmt = copy; } return strlen(buff); }
static int external_invoke(noit_module_t *self, noit_check_t *check, noit_check_t *cause) { struct timeval when, p_int; external_closure_t *ecl; struct check_info *ci = (struct check_info *)check->closure; eventer_t newe; external_data_t *data; noit_hash_table check_attrs_hash = NOIT_HASH_EMPTY; int i, klen; noit_hash_iter iter = NOIT_HASH_ITER_ZERO; const char *name, *value; char interp_fmt[4096], interp_buff[4096]; data = noit_module_get_userdata(self); check->flags |= NP_RUNNING; noitL(data->nldeb, "external_invoke(%p,%s)\n", self, check->target); /* remove a timeout if we still have one -- we should unless someone * has set a lower timeout than the period. */ if(ci->timeout_event) { eventer_remove(ci->timeout_event); free(ci->timeout_event->closure); eventer_free(ci->timeout_event); ci->timeout_event = NULL; } check_info_clean(ci); gettimeofday(&when, NULL); memcpy(&check->last_fire_time, &when, sizeof(when)); /* Setup all our check bits */ ci->check_no = noit_atomic_inc64(&data->check_no_seq); ci->check = check; /* We might want to extract metrics */ if(noit_hash_retr_str(check->config, "output_extract", strlen("output_extract"), &value) != 0) { const char *error; int erroffset; ci->matcher = pcre_compile(value, 0, &error, &erroffset, NULL); if(!ci->matcher) { noitL(data->nlerr, "external pcre /%s/ failed @ %d: %s\n", value, erroffset, error); } } noit_check_make_attrs(check, &check_attrs_hash); /* Count the args */ i = 1; while(1) { char argname[10]; snprintf(argname, sizeof(argname), "arg%d", i); if(noit_hash_retr_str(check->config, argname, strlen(argname), &value) == 0) break; i++; } ci->argcnt = i + 1; /* path, arg0, (i-1 more args) */ ci->arglens = calloc(ci->argcnt, sizeof(*ci->arglens)); ci->args = calloc(ci->argcnt, sizeof(*ci->args)); /* Make the command */ if(noit_hash_retr_str(check->config, "command", strlen("command"), &value) == 0) { value = "/bin/true"; } ci->args[0] = strdup(value); ci->arglens[0] = strlen(ci->args[0]) + 1; i = 0; while(1) { char argname[10]; snprintf(argname, sizeof(argname), "arg%d", i); if(noit_hash_retr_str(check->config, argname, strlen(argname), &value) == 0) { if(i == 0) { /* if we don't have arg0, make it last element of path */ char *cp = ci->args[0] + strlen(ci->args[0]); while(cp > ci->args[0] && *(cp-1) != '/') cp--; value = cp; } else break; /* if we don't have argn, we're done */ } noit_check_interpolate(interp_buff, sizeof(interp_buff), value, &check_attrs_hash, check->config); ci->args[i+1] = strdup(interp_buff); ci->arglens[i+1] = strlen(ci->args[i+1]) + 1; i++; } /* Make the environment */ memset(&iter, 0, sizeof(iter)); ci->envcnt = 0; while(noit_hash_next_str(check->config, &iter, &name, &klen, &value)) if(!strncasecmp(name, "env_", 4)) ci->envcnt++; memset(&iter, 0, sizeof(iter)); ci->envlens = calloc(ci->envcnt, sizeof(*ci->envlens)); ci->envs = calloc(ci->envcnt, sizeof(*ci->envs)); ci->envcnt = 0; while(noit_hash_next_str(check->config, &iter, &name, &klen, &value)) if(!strncasecmp(name, "env_", 4)) { snprintf(interp_fmt, sizeof(interp_fmt), "%s=%s", name+4, value); noit_check_interpolate(interp_buff, sizeof(interp_buff), interp_fmt, &check_attrs_hash, check->config); ci->envs[ci->envcnt] = strdup(interp_buff); ci->envlens[ci->envcnt] = strlen(ci->envs[ci->envcnt]) + 1; ci->envcnt++; } noit_hash_destroy(&check_attrs_hash, NULL, NULL); noit_hash_store(&data->external_checks, (const char *)&ci->check_no, sizeof(ci->check_no), ci); /* Setup a timeout */ newe = eventer_alloc(); newe->mask = EVENTER_TIMER; gettimeofday(&when, NULL); p_int.tv_sec = check->timeout / 1000; p_int.tv_usec = (check->timeout % 1000) * 1000; add_timeval(when, p_int, &newe->whence); ecl = calloc(1, sizeof(*ecl)); ecl->self = self; ecl->check = check; newe->closure = ecl; newe->callback = external_timeout; eventer_add(newe); ci->timeout_event = newe; /* Setup push */ newe = eventer_alloc(); newe->mask = EVENTER_ASYNCH; add_timeval(when, p_int, &newe->whence); ecl = calloc(1, sizeof(*ecl)); ecl->self = self; ecl->check = check; newe->closure = ecl; newe->callback = external_enqueue; eventer_add(newe); return 0; }
int noit_rest_simple_file_handler(noit_http_rest_closure_t *restc, int npats, char **pats) { int drlen = 0; const char *document_root = NULL; const char *index_file = NULL; noit_http_session_ctx *ctx = restc->http_ctx; char file[PATH_MAX], rfile[PATH_MAX]; struct stat st; int fd; void *contents = MAP_FAILED; const char *dot = NULL, *slash; const char *content_type = "application/octet-stream"; if(npats != 1 || !noit_hash_retr_str(restc->ac->config, "document_root", strlen("document_root"), &document_root)) { goto not_found; } if(!noit_hash_retr_str(restc->ac->config, "index_file", strlen("index_file"), &index_file)) { index_file = "index.html"; } drlen = strlen(document_root); snprintf(file, sizeof(file), "%s/%s", document_root, pats[0]); if(file[strlen(file) - 1] == '/') { snprintf(file + strlen(file), sizeof(file) - strlen(file), "%s", index_file); } /* resolve */ if(realpath(file, rfile) == NULL) goto not_found; /* restrict */ if(strncmp(rfile, document_root, drlen)) goto denied; if(rfile[drlen] != '/' && rfile[drlen + 1] != '/') goto denied; /* stat */ /* coverity[fs_check_call] */ if(stat(rfile, &st) != 0) { switch (errno) { case EACCES: goto denied; default: goto not_found; } } /* open */ if(st.st_size > 0) { /* coverity[toctou] */ fd = open(rfile, O_RDONLY); if(fd < 0) goto not_found; contents = mmap(NULL, st.st_size, PROT_READ, MAP_SHARED, fd, 0); close(fd); if(contents == MAP_FAILED) goto not_found; } /* set content type */ slash = strchr(rfile, '/'); while(slash) { const char *nslash = strchr(slash+1, '/'); if(!nslash) break; slash = nslash; } if(slash) dot = strchr(slash+1, '.'); while(dot) { const char *ndot = strchr(dot+1, '.'); if(!ndot) break; dot = ndot; } /* If there is no extention, just use the filename */ if(!dot) dot = slash+1; if(dot) { char ext[PATH_MAX]; strlcpy(ext, "mime_type_", sizeof(ext)); strlcpy(ext+strlen(ext), dot+1, sizeof(ext)-strlen(ext)); if(!noit_hash_retr_str(restc->ac->config, ext, strlen(ext), &content_type)) { if(!noit_hash_retr_str(&mime_type_defaults, dot+1, strlen(dot+1), &content_type)) { content_type = "application/octet-stream"; } } } noit_http_response_ok(ctx, content_type); if(st.st_size > 0) { noit_http_response_append(ctx, contents, st.st_size); munmap(contents, st.st_size); } noit_http_response_end(ctx); return 0; denied: noit_http_response_denied(ctx, "text/html"); noit_http_response_end(ctx); return 0; not_found: noit_http_response_not_found(ctx, "text/html"); noit_http_response_end(ctx); return 0; }
int noit_jlog_handler(eventer_t e, int mask, void *closure, struct timeval *now) { eventer_t newe; pthread_t tid; pthread_attr_t tattr; int newmask = EVENTER_READ | EVENTER_EXCEPTION; acceptor_closure_t *ac = closure; noit_jlog_closure_t *jcl = ac->service_ctx; char errbuff[256]; const char *errstr = "unknown error"; if(mask & EVENTER_EXCEPTION || (jcl && jcl->wants_shutdown)) { int len, nlen; socket_error: /* Exceptions cause us to simply snip the connection */ len = strlen(errstr); nlen = htonl(0 - len); e->opset->write(e->fd, &nlen, sizeof(nlen), &newmask, e); e->opset->write(e->fd, errstr, strlen(errstr), &newmask, e); eventer_remove_fd(e->fd); e->opset->close(e->fd, &newmask, e); if(jcl) noit_jlog_closure_free(jcl); acceptor_closure_free(ac); return 0; } if(!ac->service_ctx) { noit_log_stream_t ls; const char *logname, *type; int first_attempt = 1; char path[PATH_MAX], subscriber[256], *sub; jcl = ac->service_ctx = noit_jlog_closure_alloc(); if(!noit_hash_retr_str(ac->config, "log_transit_feed_name", strlen("log_transit_feed_name"), &logname)) { errstr = "No 'log_transit_feed_name' specified in log_transit."; noitL(noit_error, "%s\n", errstr); goto socket_error; } ls = noit_log_stream_find(logname); if(!ls) { snprintf(errbuff, sizeof(errbuff), "Could not find log '%s' for log_transit.", logname); errstr = errbuff; noitL(noit_error, "%s\n", errstr); goto socket_error; } type = noit_log_stream_get_type(ls); if(!type || strcmp(type, "jlog")) { snprintf(errbuff, sizeof(errbuff), "Log '%s' for log_transit is not a jlog.", logname); errstr = errbuff; noitL(noit_error, "%s\n", errstr); goto socket_error; } if(ac->cmd == NOIT_JLOG_DATA_FEED) { if(!ac->remote_cn) { errstr = "jlog transit started to unidentified party."; noitL(noit_error, "%s\n", errstr); goto socket_error; } strlcpy(subscriber, ac->remote_cn, sizeof(subscriber)); jcl->feed_stats = noit_jlog_feed_stats(subscriber); } else { jcl->feed_stats = noit_jlog_feed_stats("~"); snprintf(subscriber, sizeof(subscriber), "~%07d", noit_atomic_inc32(&tmpfeedcounter)); } jcl->subscriber = strdup(subscriber); strlcpy(path, noit_log_stream_get_path(ls), sizeof(path)); sub = strchr(path, '('); if(sub) { char *esub = strchr(sub, ')'); if(esub) { *esub = '\0'; *sub++ = '\0'; } } jcl->jlog = jlog_new(path); if(ac->cmd == NOIT_JLOG_DATA_TEMP_FEED) { add_sub: if(jlog_ctx_add_subscriber(jcl->jlog, jcl->subscriber, JLOG_END) == -1) { snprintf(errbuff, sizeof(errbuff), "jlog reader[%s] error: %s", jcl->subscriber, jlog_ctx_err_string(jcl->jlog)); errstr = errbuff; noitL(noit_error, "%s\n", errstr); } } if(jlog_ctx_open_reader(jcl->jlog, jcl->subscriber) == -1) { if(sub && !strcmp(sub, "*")) { if(first_attempt) { jlog_ctx_close(jcl->jlog); jcl->jlog = jlog_new(path); first_attempt = 0; goto add_sub; } } snprintf(errbuff, sizeof(errbuff), "jlog reader[%s] error: %s", jcl->subscriber, jlog_ctx_err_string(jcl->jlog)); errstr = errbuff; noitL(noit_error, "%s\n", errstr); goto socket_error; } } /* The jlog stuff is disk I/O and can block us. * We'll create a new thread to just handle this connection. */ eventer_remove_fd(e->fd); newe = eventer_alloc(); memcpy(newe, e, sizeof(*e)); pthread_attr_init(&tattr); pthread_attr_setdetachstate(&tattr, PTHREAD_CREATE_DETACHED); gettimeofday(&jcl->feed_stats->last_connection, NULL); noit_atomic_inc32(&jcl->feed_stats->connections); if(pthread_create(&tid, &tattr, noit_jlog_thread_main, newe) == 0) { return 0; } /* Undo our dup */ eventer_free(newe); /* Creating the thread failed, close it down and deschedule. */ e->opset->close(e->fd, &newmask, e); return 0; }
int noit_rest_simple_file_handler(noit_http_rest_closure_t *restc, int npats, char **pats) { int drlen = 0; const char *document_root = NULL; const char *index_file = NULL; noit_http_session_ctx *ctx = restc->http_ctx; char file[PATH_MAX], rfile[PATH_MAX]; struct stat st; int fd; void *contents = MAP_FAILED; if(npats != 1 || !noit_hash_retr_str(restc->ac->config, "document_root", strlen("document_root"), &document_root)) { goto not_found; } if(!noit_hash_retr_str(restc->ac->config, "index_file", strlen("index_file"), &index_file)) { index_file = "index.html"; } drlen = strlen(document_root); snprintf(file, sizeof(file), "%s/%s", document_root, pats[0]); if(file[strlen(file) - 1] == '/') { snprintf(file + strlen(file), sizeof(file) - strlen(file), "%s", index_file); } /* resolve */ if(realpath(file, rfile) == NULL) goto not_found; /* restrict */ if(strncmp(rfile, document_root, drlen)) goto denied; if(rfile[drlen] != '/' && rfile[drlen + 1] != '/') goto denied; /* stat */ if(stat(rfile, &st) != 0) { switch (errno) { case EACCES: goto denied; default: goto not_found; } } /* open */ if(st.st_size > 0) { fd = open(rfile, O_RDONLY); if(fd < 0) goto not_found; contents = mmap(NULL, st.st_size, PROT_READ, MAP_SHARED, fd, 0); close(fd); if(contents == MAP_FAILED) goto not_found; } noit_http_response_ok(ctx, "text/html"); if(st.st_size > 0) { noit_http_response_append(ctx, contents, st.st_size); munmap(contents, st.st_size); } noit_http_response_end(ctx); return 0; denied: noit_http_response_denied(ctx, "text/html"); noit_http_response_end(ctx); return 0; not_found: noit_http_response_not_found(ctx, "text/html"); noit_http_response_end(ctx); return 0; }