📄 mod_whatkilledus.c
字号:
/* Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. *//* * Documentation: * * mod_whatkilledus is an experimental module for Apache httpd 1.3 which * tracks the current request and logs a report of the active request * when a child process crashes. You should verify that it works reasonably * on your system before putting it in production. * * mod_whatkilledus is called during request processing to save information * about the current request. It also implements a fatal exception hook * that will be called when a child process crashes. * * Apache httpd requirements for mod_whatkilledus: * * Apache httpd >= 1.3.30 must be built with the AP_ENABLE_EXCEPTION_HOOK * symbol defined and mod_so enabled. AP_ENABLE_EXCEPTION_HOOK is already * defined in ap_config.h for some platforms, including AIX, Linux, * Solaris, and HP-UX. It can be enabled for other platforms by including * -DAP_ENABLE_EXCEPTION_HOOK in CFLAGS when the configure script is * invoked. * * Compiling mod_whatkilledus: * * AIX: * apxs -ci -I/path/to/apache/src/main -Wl,-bE:mod_whatkilledus.exp mod_whatkilledus.c * * other: * apxs -ci -I/path/to/apache/src/main mod_whatkilledus.c * * Activating mod_whatkilledus: * * 1. Load it like any other DSO, but the AddModule should come * last so that if another module causes a crash early in * request processing mod_whatkilledus will have already * had a chance to save information about the request. * * LoadModule whatkilledus_module libexec/mod_whatkilledus.so * ... * AddModule mod_whatkilledus.c * * 2. Enable exception hooks for modules like mod_whatkilledus: * EnableExceptionHook On * * 3. Choose where the report on current activity should be written. If * you want it reported to some place other than the error log, use the * WhatKilledUsLog directive to specify a fully-qualified filename for * the log. Note that the web server user id (e.g., "nobody") must * be able to create or append to this log file, as the log file is * not opened until a crash occurs. */#include "httpd.h"#include "http_config.h"#include "http_log.h"#include "test_char.h" /* an odd one since it is not installed *//* this module is not thread-safe; it is intended for Apache 1.3 on * platforms that use single-threaded child processes for handling * client connections */static char *log_fname;static char *local_addr;static char *remote_addr;static char *request_plus_headers;static char buffer[2048];static void exception_hook(ap_exception_info_t *ei){ int msg_len; int logfd; char msg_prefix[60]; time_t now; char *newline; int using_errorlog = 1; time(&now); ap_snprintf(msg_prefix, sizeof msg_prefix, "[%s pid %ld mod_whatkilledus", asctime(localtime(&now)), (long)getpid()); newline = strchr(msg_prefix, '\n'); /* dang asctime() */ if (newline) { /* silly we are */ *newline = ']'; } if (log_fname) { logfd = open(log_fname, O_WRONLY|O_APPEND|O_CREAT, 0644); if (logfd == -1) { logfd = 2; /* unix, so fd 2 is the web server error log */ ap_snprintf(buffer, sizeof buffer, "%s error %d opening %s\n", msg_prefix, errno, log_fname); write(logfd, buffer, strlen(buffer)); } else { using_errorlog = 0; } } else { logfd = 2; } msg_len = ap_snprintf(buffer, sizeof buffer, "%s sig %d crash\n", msg_prefix, ei->sig); write(logfd, buffer, msg_len); if (local_addr) { msg_len = ap_snprintf(buffer, sizeof buffer, "%s active connection: %s->%s\n", msg_prefix, remote_addr, local_addr); } else { msg_len = ap_snprintf(buffer, sizeof buffer, "%s no active connection at crash\n", msg_prefix); } write(logfd, buffer, msg_len); if (request_plus_headers) { msg_len = ap_snprintf(buffer, sizeof buffer, "%s active request:\n", msg_prefix); write(logfd, buffer, msg_len); write(logfd, request_plus_headers, strlen(request_plus_headers)); } else { msg_len = ap_snprintf(buffer, sizeof buffer, "%s no request active at crash\n", msg_prefix); write(logfd, buffer, msg_len); } msg_len = ap_snprintf(buffer, sizeof buffer, "%s end of report\n", msg_prefix); write(logfd, buffer, msg_len); if (!using_errorlog) { close(logfd); }}static void init(server_rec *s, pool *p){ int rc = ap_add_fatal_exception_hook(exception_hook); if (rc) { ap_log_error(APLOG_MARK, APLOG_ALERT|APLOG_NOERRNO, s, "fatal exception hooks are not enabled; please " "enable them with the EnableExceptionHook directive " "or disable mod_whatkilledus"); }}static void clear_conn_info(void *ignored){ local_addr = remote_addr = NULL;}static void save_conn_info(request_rec *r){ conn_rec *c = r->connection; local_addr = ap_psprintf(c->pool, "%pI", &c->local_addr); remote_addr = ap_psprintf(c->pool, "%pI", &c->remote_addr); ap_register_cleanup(c->pool, NULL, clear_conn_info, ap_null_cleanup);}static void clear_req_info(void *ignored){ request_plus_headers = NULL;}#define FIELD_SEPARATOR "|"#define KEYVAL_SEPARATOR ":"/* graciously lifted from mod_log_forensic */static int count_string(const char *p){ int n; for (n = 0; *p; ++p, ++n) { if (test_char_table[*(unsigned char *)p] & T_ESCAPE_FORENSIC) { n += 2; } } return n;}static int count_headers(void *in_len, const char *key, const char *value){ int *len = in_len; *len += strlen(FIELD_SEPARATOR); *len += count_string(key); *len += strlen(KEYVAL_SEPARATOR); *len += count_string(value); return 1;}static char *copy_and_escape(char *loc, const char *str) { /* mod_log_forensic will SIGABRT here if it messed up the count * and overflowed; mod_whatkilledus will segfault here or will * SIGABRT back in the caller if that happens */ for ( ; *str; ++str) { if (test_char_table[*(unsigned char *)str] & T_ESCAPE_FORENSIC) { *loc++ = '%'; sprintf(loc, "%02x", *(unsigned char *)str); loc += 2; } else { *loc++ = *str; } } *loc = '\0'; return loc;}static int copy_headers(void *in_ch, const char *key, const char *value){ char **ch = in_ch; strcpy(*ch, FIELD_SEPARATOR); *ch += strlen(FIELD_SEPARATOR); *ch = copy_and_escape(*ch, key); strcpy(*ch, KEYVAL_SEPARATOR); *ch += strlen(KEYVAL_SEPARATOR); *ch = copy_and_escape(*ch, value); return 1;}static void save_req_info(request_rec *r){ /* to save for the request: * r->the_request + * foreach header: * '|' + header field */ int len = strlen(r->the_request); char *ch; ap_table_do(count_headers, &len, r->headers_in, NULL); request_plus_headers = ap_palloc(r->pool, len + 2 /* 2 for the '\n' + '\0' at end */); ch = request_plus_headers; strcpy(ch, r->the_request); ch += strlen(ch); ap_table_do(copy_headers, &ch, r->headers_in, NULL); *ch = '\n'; *(ch + 1) = '\0'; ap_assert(ch == request_plus_headers + len); ap_register_cleanup(r->pool, NULL, clear_req_info, ap_null_cleanup);}static int post_read(request_rec *r){ if (r->prev) { /* we were already called for this internal redirect */ return DECLINED; } /* save whatever info, like client, which vhost, which port * (to know SSL or not), etc. */ if (!local_addr) { /* first request on this connection */ save_conn_info(r); } save_req_info(r); return DECLINED;}static const char *cmd_file(cmd_parms *cmd, void *dconf, char *fname){ log_fname = ap_pstrdup(cmd->pool, fname); return NULL;}static const command_rec command_table[] = { { "WhatKilledUsLog", cmd_file, NULL, RSRC_CONF, TAKE1, "the fully-qualified filename of the mod_whatkilledus logfile" } , { NULL }};module MODULE_VAR_EXPORT whatkilledus_module = { STANDARD_MODULE_STUFF, init, /* initializer */ NULL, /* create per-dir config */ NULL, /* merge per-dir config */ NULL, /* server config */ NULL, /* merge server config */ command_table, /* command table */ NULL, /* handlers */ NULL, /* filename translation */ NULL, /* check_user_id */ NULL, /* check auth */ NULL, /* check access */ NULL, /* type_checker */ NULL, /* fixups */ NULL, /* logger */ NULL, /* header parser */ NULL, /* child_init */ NULL, /* child_exit */ post_read /* post read-request */};
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -