Commit cfdd430b authored by Sergey Lyubka's avatar Sergey Lyubka

Added hexdump_file option

parent a6c05a9e
...@@ -100,6 +100,7 @@ typedef unsigned __int64 uint64_t; ...@@ -100,6 +100,7 @@ typedef unsigned __int64 uint64_t;
typedef __int64 int64_t; typedef __int64 int64_t;
typedef SOCKET sock_t; typedef SOCKET sock_t;
#else #else
#include <dlfcn.h>
#include <errno.h> #include <errno.h>
#include <fcntl.h> #include <fcntl.h>
#include <netdb.h> #include <netdb.h>
...@@ -148,6 +149,7 @@ union socket_address { ...@@ -148,6 +149,7 @@ union socket_address {
#endif #endif
}; };
// IO buffers interface
struct iobuf { struct iobuf {
char *buf; char *buf;
int len; int len;
...@@ -159,13 +161,23 @@ void iobuf_free(struct iobuf *); ...@@ -159,13 +161,23 @@ void iobuf_free(struct iobuf *);
int iobuf_append(struct iobuf *, const void *data, int data_size); int iobuf_append(struct iobuf *, const void *data, int data_size);
void iobuf_remove(struct iobuf *, int data_size); void iobuf_remove(struct iobuf *, int data_size);
// Net skeleton interface
enum ns_event {
NS_POLL, // Sent to each connection on each call to ns_server_poll()
NS_ACCEPT, // Listening socket accept()-ed new connection
NS_CONNECT, // Connection made by ns_connect() succeeded or failed
NS_RECV, // Data has benn received
NS_SEND, // Data has been written to a socket
NS_CLOSE // Connection is closed
};
// Callback function (event handler) prototype, must be defined by user.
// Net skeleton will call event handler, passing events defined above.
struct ns_connection; struct ns_connection;
enum ns_event { NS_POLL, NS_ACCEPT, NS_CONNECT, NS_RECV, NS_SEND, NS_CLOSE };
typedef void (*ns_callback_t)(struct ns_connection *, enum ns_event, void *); typedef void (*ns_callback_t)(struct ns_connection *, enum ns_event, void *);
struct ns_server { struct ns_server {
void *server_data; void *server_data;
union socket_address listening_sa;
sock_t listening_sock; sock_t listening_sock;
struct ns_connection *active_connections; struct ns_connection *active_connections;
ns_callback_t callback; ns_callback_t callback;
...@@ -177,12 +189,13 @@ struct ns_server { ...@@ -177,12 +189,13 @@ struct ns_server {
struct ns_connection { struct ns_connection {
struct ns_connection *prev, *next; struct ns_connection *prev, *next;
struct ns_server *server; struct ns_server *server;
void *connection_data;
time_t last_io_time;
sock_t sock; sock_t sock;
union socket_address sa;
struct iobuf recv_iobuf; struct iobuf recv_iobuf;
struct iobuf send_iobuf; struct iobuf send_iobuf;
SSL *ssl; SSL *ssl;
void *connection_data;
time_t last_io_time;
unsigned int flags; unsigned int flags;
#define NSF_FINISHED_SENDING_DATA (1 << 0) #define NSF_FINISHED_SENDING_DATA (1 << 0)
#define NSF_BUFFER_BUT_DONT_SEND (1 << 1) #define NSF_BUFFER_BUT_DONT_SEND (1 << 1)
...@@ -216,6 +229,8 @@ int ns_vprintf(struct ns_connection *, const char *fmt, va_list ap); ...@@ -216,6 +229,8 @@ int ns_vprintf(struct ns_connection *, const char *fmt, va_list ap);
void *ns_start_thread(void *(*f)(void *), void *p); void *ns_start_thread(void *(*f)(void *), void *p);
int ns_socketpair(sock_t [2]); int ns_socketpair(sock_t [2]);
void ns_set_close_on_exec(sock_t); void ns_set_close_on_exec(sock_t);
void ns_sock_to_str(sock_t sock, char *buf, size_t len, int add_port);
int ns_hexdump(const void *buf, int len, char *dst, int dst_len);
#ifdef __cplusplus #ifdef __cplusplus
} }
...@@ -542,13 +557,14 @@ int ns_set_ssl_cert(struct ns_server *server, const char *cert) { ...@@ -542,13 +557,14 @@ int ns_set_ssl_cert(struct ns_server *server, const char *cert) {
} }
int ns_bind(struct ns_server *server, const char *str) { int ns_bind(struct ns_server *server, const char *str) {
ns_parse_port_string(str, &server->listening_sa); union socket_address sa;
ns_parse_port_string(str, &sa);
if (server->listening_sock != INVALID_SOCKET) { if (server->listening_sock != INVALID_SOCKET) {
closesocket(server->listening_sock); closesocket(server->listening_sock);
} }
server->listening_sock = ns_open_listening_socket(&server->listening_sa); server->listening_sock = ns_open_listening_socket(&sa);
return server->listening_sock == INVALID_SOCKET ? -1 : return server->listening_sock == INVALID_SOCKET ? -1 :
(int) ntohs(server->listening_sa.sin.sin_port); (int) ntohs(sa.sin.sin_port);
} }
...@@ -598,49 +614,52 @@ static int ns_is_error(int n) { ...@@ -598,49 +614,52 @@ static int ns_is_error(int n) {
); );
} }
#ifdef NS_ENABLE_HEXDUMP void ns_sock_to_str(sock_t sock, char *buf, size_t len, int add_port) {
static void ns_hexdump(const struct ns_connection *conn, const void *buf, union socket_address sa;
int len, const char *marker) { socklen_t slen = sizeof(sa);
const unsigned char *p = (const unsigned char *) buf;
char path[500], date[100], ascii[17];
FILE *fp;
#if 0
if (!match_prefix(NS_ENABLE_HEXDUMP, strlen(NS_ENABLE_HEXDUMP),
conn->remote_ip)) {
return;
}
snprintf(path, sizeof(path), "%s.%hu.txt", if (buf != NULL && len > 0) {
conn->mg_conn.remote_ip, conn->mg_conn.remote_port); buf[0] = '\0';
memset(&sa, 0, sizeof(sa));
getsockname(sock, &sa.sa, &slen);
#if defined(NS_ENABLE_IPV6)
inet_ntop(sa.sa.sa_family, sa.sa.sa_family == AF_INET ?
(void *) &sa.sin.sin_addr :
(void *) &sa.sin6.sin6_addr, buf, len);
#elif defined(_WIN32)
// Only Windoze Vista (and newer) have inet_ntop()
strncpy(buf, inet_ntoa(sa.sin.sin_addr), len);
#else
inet_ntop(sa.sa.sa_family, (void *) &sa.sin.sin_addr, buf, len);
#endif #endif
snprintf(path, sizeof(path), "%p.txt", conn); if (add_port) {
snprintf(buf + strlen(buf), len - (strlen(buf) + 1), ":%d",
if ((fp = fopen(path, "a")) != NULL) { (int) ntohs(sa.sin.sin_port));
time_t cur_time = time(NULL); }
int i, idx; }
}
strftime(date, sizeof(date), "%d/%b/%Y %H:%M:%S", localtime(&cur_time));
fprintf(fp, "%s %s %d bytes\n", marker, date, len);
for (i = 0; i < len; i++) { int ns_hexdump(const void *buf, int len, char *dst, int dst_len) {
idx = i % 16; const unsigned char *p = (const unsigned char *) buf;
if (idx == 0) { char ascii[17] = "";
if (i > 0) fprintf(fp, " %s\n", ascii); int i, idx, n = 0;
fprintf(fp, "%04x ", i);
} for (i = 0; i < len; i++) {
fprintf(fp, " %02x", p[i]); idx = i % 16;
ascii[idx] = p[i] < 0x20 || p[i] > 0x7e ? '.' : p[i]; if (idx == 0) {
ascii[idx + 1] = '\0'; if (i > 0) n += snprintf(dst + n, dst_len - n, " %s\n", ascii);
n += snprintf(dst + n, dst_len - n, "%04x ", i);
} }
n += snprintf(dst + n, dst_len - n, " %02x", p[i]);
ascii[idx] = p[i] < 0x20 || p[i] > 0x7e ? '.' : p[i];
ascii[idx + 1] = '\0';
}
while (i++ % 16) fprintf(fp, "%s", " "); while (i++ % 16) n += snprintf(dst + n, dst_len - n, "%s", " ");
fprintf(fp, " %s\n\n", ascii); n += snprintf(dst + n, dst_len - n, " %s\n\n", ascii);
fclose(fp); return n;
}
} }
#endif
static void ns_read_from_socket(struct ns_connection *conn) { static void ns_read_from_socket(struct ns_connection *conn) {
char buf[2048]; char buf[2048];
...@@ -656,10 +675,10 @@ static void ns_read_from_socket(struct ns_connection *conn) { ...@@ -656,10 +675,10 @@ static void ns_read_from_socket(struct ns_connection *conn) {
if (ret == 0 && ok == 0 && conn->ssl != NULL) { if (ret == 0 && ok == 0 && conn->ssl != NULL) {
int res = SSL_connect(conn->ssl); int res = SSL_connect(conn->ssl);
int ssl_err = SSL_get_error(conn->ssl, res); int ssl_err = SSL_get_error(conn->ssl, res);
DBG(("%p SSL_connect %d %d", conn, res, ssl_err)); DBG(("%p res %d %d", conn, res, ssl_err));
if (res == 1) { if (res == 1) {
conn->flags = NSF_SSL_HANDSHAKE_DONE; conn->flags = NSF_SSL_HANDSHAKE_DONE;
} else if (ssl_err == 2 || ssl_err == 3) { } else if (res == 0 || ssl_err == 2 || ssl_err == 3) {
return; // Call us again return; // Call us again
} else { } else {
ok = 1; ok = 1;
...@@ -682,10 +701,10 @@ static void ns_read_from_socket(struct ns_connection *conn) { ...@@ -682,10 +701,10 @@ static void ns_read_from_socket(struct ns_connection *conn) {
} else { } else {
int res = SSL_accept(conn->ssl); int res = SSL_accept(conn->ssl);
int ssl_err = SSL_get_error(conn->ssl, res); int ssl_err = SSL_get_error(conn->ssl, res);
DBG(("%p SSL_accept %d %d", conn, res, ssl_err)); DBG(("%p res %d %d", conn, res, ssl_err));
if (res == 1) { if (res == 1) {
conn->flags |= NSF_SSL_HANDSHAKE_DONE; conn->flags |= NSF_SSL_HANDSHAKE_DONE;
} else if (ssl_err == 2 || ssl_err == 3) { } else if (res == 0 || ssl_err == 2 || ssl_err == 3) {
return; // Call us again return; // Call us again
} else { } else {
conn->flags |= NSF_CLOSE_IMMEDIATELY; conn->flags |= NSF_CLOSE_IMMEDIATELY;
...@@ -698,10 +717,6 @@ static void ns_read_from_socket(struct ns_connection *conn) { ...@@ -698,10 +717,6 @@ static void ns_read_from_socket(struct ns_connection *conn) {
n = recv(conn->sock, buf, sizeof(buf), 0); n = recv(conn->sock, buf, sizeof(buf), 0);
} }
#ifdef NS_ENABLE_HEXDUMP
ns_hexdump(conn, buf, n, "<-");
#endif
DBG(("%p <- %d bytes [%.*s%s]", DBG(("%p <- %d bytes [%.*s%s]",
conn, n, n < 40 ? n : 40, buf, n < 40 ? "" : "...")); conn, n, n < 40 ? n : 40, buf, n < 40 ? "" : "..."));
...@@ -724,27 +739,19 @@ static void ns_write_to_socket(struct ns_connection *conn) { ...@@ -724,27 +739,19 @@ static void ns_write_to_socket(struct ns_connection *conn) {
#endif #endif
{ n = send(conn->sock, io->buf, io->len, 0); } { n = send(conn->sock, io->buf, io->len, 0); }
DBG(("%p -> %d bytes [%.*s%s]", conn, n, io->len < 40 ? io->len : 40,
#ifdef NS_ENABLE_HEXDUMP
ns_hexdump(conn, io->buf, n, "->");
#endif
DBG(("%p -> %d bytes %d [%.*s%s]", conn, n, conn->flags,
io->len < 40 ? io->len : 40,
io->buf, io->len < 40 ? "" : "...")); io->buf, io->len < 40 ? "" : "..."));
ns_call(conn, NS_SEND, &n);
if (ns_is_error(n)) { if (ns_is_error(n)) {
conn->flags |= NSF_CLOSE_IMMEDIATELY; conn->flags |= NSF_CLOSE_IMMEDIATELY;
} else if (n > 0) { } else if (n > 0) {
iobuf_remove(io, n); iobuf_remove(io, n);
//conn->num_bytes_sent += n;
} }
if (io->len == 0 && conn->flags & NSF_FINISHED_SENDING_DATA) { if (io->len == 0 && conn->flags & NSF_FINISHED_SENDING_DATA) {
conn->flags |= NSF_CLOSE_IMMEDIATELY; conn->flags |= NSF_CLOSE_IMMEDIATELY;
} }
ns_call(conn, NS_SEND, NULL);
} }
int ns_send(struct ns_connection *conn, const void *buf, int len) { int ns_send(struct ns_connection *conn, const void *buf, int len) {
...@@ -769,7 +776,7 @@ int ns_server_poll(struct ns_server *server, int milli) { ...@@ -769,7 +776,7 @@ int ns_server_poll(struct ns_server *server, int milli) {
time_t current_time = time(NULL); time_t current_time = time(NULL);
if (server->listening_sock == INVALID_SOCKET && if (server->listening_sock == INVALID_SOCKET &&
server->active_connections == NULL) return -1; server->active_connections == NULL) return 0;
FD_ZERO(&read_set); FD_ZERO(&read_set);
FD_ZERO(&write_set); FD_ZERO(&write_set);
...@@ -851,6 +858,7 @@ struct ns_connection *ns_connect(struct ns_server *server, const char *host, ...@@ -851,6 +858,7 @@ struct ns_connection *ns_connect(struct ns_server *server, const char *host,
int connect_ret_val; int connect_ret_val;
(void) use_ssl; (void) use_ssl;
if (host == NULL || (he = gethostbyname(host)) == NULL || if (host == NULL || (he = gethostbyname(host)) == NULL ||
(sock = socket(AF_INET, SOCK_STREAM, 0)) == INVALID_SOCKET) { (sock = socket(AF_INET, SOCK_STREAM, 0)) == INVALID_SOCKET) {
DBG(("gethostbyname(%s) failed: %s", host, strerror(errno))); DBG(("gethostbyname(%s) failed: %s", host, strerror(errno)));
...@@ -1093,6 +1101,7 @@ enum { ...@@ -1093,6 +1101,7 @@ enum {
GLOBAL_AUTH_FILE, GLOBAL_AUTH_FILE,
#endif #endif
HIDE_FILES_PATTERN, HIDE_FILES_PATTERN,
HEXDUMP_FILE,
#ifndef MONGOOSE_NO_FILESYSTEM #ifndef MONGOOSE_NO_FILESYSTEM
INDEX_FILES, INDEX_FILES,
#endif #endif
...@@ -1132,6 +1141,7 @@ static const char *static_config_options[] = { ...@@ -1132,6 +1141,7 @@ static const char *static_config_options[] = {
"global_auth_file", NULL, "global_auth_file", NULL,
#endif #endif
"hide_files_patterns", NULL, "hide_files_patterns", NULL,
"hexdump_file", NULL,
#ifndef MONGOOSE_NO_FILESYSTEM #ifndef MONGOOSE_NO_FILESYSTEM
"index_files","index.html,index.htm,index.shtml,index.cgi,index.php,index.lp", "index_files","index.html,index.htm,index.shtml,index.cgi,index.php,index.lp",
#endif #endif
...@@ -2027,21 +2037,6 @@ static int check_acl(const char *acl, uint32_t remote_ip) { ...@@ -2027,21 +2037,6 @@ static int check_acl(const char *acl, uint32_t remote_ip) {
return allowed == '+'; return allowed == '+';
} }
static void sockaddr_to_string(char *buf, size_t len,
const union socket_address *usa) {
buf[0] = '\0';
#if defined(NS_ENABLE_IPV6)
inet_ntop(usa->sa.sa_family, usa->sa.sa_family == AF_INET ?
(void *) &usa->sin.sin_addr :
(void *) &usa->sin6.sin6_addr, buf, len);
#elif defined(_WIN32)
// Only Windoze Vista (and newer) have inet_ntop()
strncpy(buf, inet_ntoa(usa->sin.sin_addr), len);
#else
inet_ntop(usa->sa.sa_family, (void *) &usa->sin.sin_addr, buf, len);
#endif
}
// Protect against directory disclosure attack by removing '..', // Protect against directory disclosure attack by removing '..',
// excessive '/' and '\' characters // excessive '/' and '\' characters
static void remove_double_dots_and_double_slashes(char *s) { static void remove_double_dots_and_double_slashes(char *s) {
...@@ -4416,8 +4411,8 @@ const char *mg_set_option(struct mg_server *server, const char *name, ...@@ -4416,8 +4411,8 @@ const char *mg_set_option(struct mg_server *server, const char *name,
if (port < 0) { if (port < 0) {
error_msg = "Cannot bind to port"; error_msg = "Cannot bind to port";
} else { } else {
sockaddr_to_string(server->local_ip, sizeof(server->local_ip), ns_sock_to_str(server->ns_server.listening_sock, server->local_ip,
&server->ns_server.listening_sa); sizeof(server->local_ip), 0);
if (!strcmp(value, "0")) { if (!strcmp(value, "0")) {
char buf[10]; char buf[10];
mg_snprintf(buf, sizeof(buf), "%d", port); mg_snprintf(buf, sizeof(buf), "%d", port);
...@@ -4462,14 +4457,13 @@ static void on_accept(struct ns_connection *nc, union socket_address *sa) { ...@@ -4462,14 +4457,13 @@ static void on_accept(struct ns_connection *nc, union socket_address *sa) {
(conn = (struct connection *) calloc(1, sizeof(*conn))) == NULL) { (conn = (struct connection *) calloc(1, sizeof(*conn))) == NULL) {
nc->flags |= NSF_CLOSE_IMMEDIATELY; nc->flags |= NSF_CLOSE_IMMEDIATELY;
} else { } else {
conn->server = (struct mg_server *) nc->server; conn->server = server;
sockaddr_to_string(conn->mg_conn.remote_ip, ns_sock_to_str(nc->sock, conn->mg_conn.remote_ip,
sizeof(conn->mg_conn.remote_ip), sa); sizeof(conn->mg_conn.remote_ip), 0);
conn->mg_conn.remote_port = ntohs(sa->sin.sin_port); conn->mg_conn.remote_port = ntohs(sa->sin.sin_port);
conn->mg_conn.server_param = nc->server->server_data; conn->mg_conn.server_param = nc->server->server_data;
conn->mg_conn.local_ip = server->local_ip; conn->mg_conn.local_ip = server->local_ip;
conn->mg_conn.local_port = conn->mg_conn.local_port = ntohs(server->lsa.sin.sin_port);
ntohs(server->ns_server.listening_sa.sin.sin_port);
// Circularly link two connection structures // Circularly link two connection structures
nc->connection_data = conn; nc->connection_data = conn;
...@@ -4477,8 +4471,33 @@ static void on_accept(struct ns_connection *nc, union socket_address *sa) { ...@@ -4477,8 +4471,33 @@ static void on_accept(struct ns_connection *nc, union socket_address *sa) {
} }
} }
static void hexdump(struct ns_connection *nc, const char *path,
int num_bytes, int is_sent) {
struct connection *mc = (struct connection *) nc->connection_data;
const struct iobuf *io = is_sent ? &nc->send_iobuf : &nc->recv_iobuf;
FILE *fp;
char *buf;
int buf_size = num_bytes * 5 + 100;
if (path != NULL && num_bytes > 0 && (fp = fopen(path, "a")) != NULL) {
fprintf(fp, "%lu %s:%d %s %s:%d %d\n", (unsigned long) time(NULL),
mc->mg_conn.local_ip, mc->mg_conn.local_port,
is_sent ? "->" : "<-",
mc->mg_conn.remote_ip, mc->mg_conn.remote_port,
num_bytes);
if ((buf = malloc(buf_size)) != NULL) {
ns_hexdump(io->buf + (is_sent ? 0 : io->len) - (is_sent ? 0 : num_bytes),
num_bytes, buf, buf_size);
fprintf(fp, "%s", buf);
free(buf);
}
fclose(fp);
}
}
static void mg_ev_handler(struct ns_connection *nc, enum ns_event ev, void *p) { static void mg_ev_handler(struct ns_connection *nc, enum ns_event ev, void *p) {
struct connection *conn = (struct connection *) nc->connection_data; struct connection *conn = (struct connection *) nc->connection_data;
struct mg_server *server = (struct mg_server *) nc->server;
switch (ev) { switch (ev) {
case NS_ACCEPT: case NS_ACCEPT:
...@@ -4494,6 +4513,7 @@ static void mg_ev_handler(struct ns_connection *nc, enum ns_event ev, void *p) { ...@@ -4494,6 +4513,7 @@ static void mg_ev_handler(struct ns_connection *nc, enum ns_event ev, void *p) {
break; break;
case NS_RECV: case NS_RECV:
hexdump(nc, server->config_options[HEXDUMP_FILE], * (int *) p, 0);
if (nc->flags & NSF_ACCEPTED) { if (nc->flags & NSF_ACCEPTED) {
process_request(conn); process_request(conn);
#ifndef MONGOOSE_NO_CGI #ifndef MONGOOSE_NO_CGI
...@@ -4506,6 +4526,7 @@ static void mg_ev_handler(struct ns_connection *nc, enum ns_event ev, void *p) { ...@@ -4506,6 +4526,7 @@ static void mg_ev_handler(struct ns_connection *nc, enum ns_event ev, void *p) {
break; break;
case NS_SEND: case NS_SEND:
hexdump(nc, server->config_options[HEXDUMP_FILE], * (int *) p, 1);
break; break;
case NS_CLOSE: case NS_CLOSE:
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment