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;
typedef __int64 int64_t;
typedef SOCKET sock_t;
#else
#include <dlfcn.h>
#include <errno.h>
#include <fcntl.h>
#include <netdb.h>
......@@ -148,6 +149,7 @@ union socket_address {
#endif
};
// IO buffers interface
struct iobuf {
char *buf;
int len;
......@@ -159,13 +161,23 @@ void iobuf_free(struct iobuf *);
int iobuf_append(struct iobuf *, const void *data, 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;
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 *);
struct ns_server {
void *server_data;
union socket_address listening_sa;
sock_t listening_sock;
struct ns_connection *active_connections;
ns_callback_t callback;
......@@ -177,12 +189,13 @@ struct ns_server {
struct ns_connection {
struct ns_connection *prev, *next;
struct ns_server *server;
void *connection_data;
time_t last_io_time;
sock_t sock;
union socket_address sa;
struct iobuf recv_iobuf;
struct iobuf send_iobuf;
SSL *ssl;
void *connection_data;
time_t last_io_time;
unsigned int flags;
#define NSF_FINISHED_SENDING_DATA (1 << 0)
#define NSF_BUFFER_BUT_DONT_SEND (1 << 1)
......@@ -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);
int ns_socketpair(sock_t [2]);
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
}
......@@ -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) {
ns_parse_port_string(str, &server->listening_sa);
union socket_address sa;
ns_parse_port_string(str, &sa);
if (server->listening_sock != INVALID_SOCKET) {
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 :
(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) {
);
}
#ifdef NS_ENABLE_HEXDUMP
static void ns_hexdump(const struct ns_connection *conn, const void *buf,
int len, const char *marker) {
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;
}
void ns_sock_to_str(sock_t sock, char *buf, size_t len, int add_port) {
union socket_address sa;
socklen_t slen = sizeof(sa);
snprintf(path, sizeof(path), "%s.%hu.txt",
conn->mg_conn.remote_ip, conn->mg_conn.remote_port);
if (buf != NULL && len > 0) {
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
snprintf(path, sizeof(path), "%p.txt", conn);
if ((fp = fopen(path, "a")) != NULL) {
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);
if (add_port) {
snprintf(buf + strlen(buf), len - (strlen(buf) + 1), ":%d",
(int) ntohs(sa.sin.sin_port));
}
}
}
for (i = 0; i < len; i++) {
idx = i % 16;
if (idx == 0) {
if (i > 0) fprintf(fp, " %s\n", ascii);
fprintf(fp, "%04x ", i);
}
fprintf(fp, " %02x", p[i]);
ascii[idx] = p[i] < 0x20 || p[i] > 0x7e ? '.' : p[i];
ascii[idx + 1] = '\0';
int ns_hexdump(const void *buf, int len, char *dst, int dst_len) {
const unsigned char *p = (const unsigned char *) buf;
char ascii[17] = "";
int i, idx, n = 0;
for (i = 0; i < len; i++) {
idx = i % 16;
if (idx == 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", " ");
fprintf(fp, " %s\n\n", ascii);
while (i++ % 16) n += snprintf(dst + n, dst_len - n, "%s", " ");
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) {
char buf[2048];
......@@ -656,10 +675,10 @@ static void ns_read_from_socket(struct ns_connection *conn) {
if (ret == 0 && ok == 0 && conn->ssl != NULL) {
int res = SSL_connect(conn->ssl);
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) {
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
} else {
ok = 1;
......@@ -682,10 +701,10 @@ static void ns_read_from_socket(struct ns_connection *conn) {
} else {
int res = SSL_accept(conn->ssl);
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) {
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
} else {
conn->flags |= NSF_CLOSE_IMMEDIATELY;
......@@ -698,10 +717,6 @@ static void ns_read_from_socket(struct ns_connection *conn) {
n = recv(conn->sock, buf, sizeof(buf), 0);
}
#ifdef NS_ENABLE_HEXDUMP
ns_hexdump(conn, buf, n, "<-");
#endif
DBG(("%p <- %d bytes [%.*s%s]",
conn, n, n < 40 ? n : 40, buf, n < 40 ? "" : "..."));
......@@ -724,27 +739,19 @@ static void ns_write_to_socket(struct ns_connection *conn) {
#endif
{ n = send(conn->sock, io->buf, io->len, 0); }
#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,
DBG(("%p -> %d bytes [%.*s%s]", conn, n, io->len < 40 ? io->len : 40,
io->buf, io->len < 40 ? "" : "..."));
ns_call(conn, NS_SEND, &n);
if (ns_is_error(n)) {
conn->flags |= NSF_CLOSE_IMMEDIATELY;
} else if (n > 0) {
iobuf_remove(io, n);
//conn->num_bytes_sent += n;
}
if (io->len == 0 && conn->flags & NSF_FINISHED_SENDING_DATA) {
conn->flags |= NSF_CLOSE_IMMEDIATELY;
}
ns_call(conn, NS_SEND, NULL);
}
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) {
time_t current_time = time(NULL);
if (server->listening_sock == INVALID_SOCKET &&
server->active_connections == NULL) return -1;
server->active_connections == NULL) return 0;
FD_ZERO(&read_set);
FD_ZERO(&write_set);
......@@ -851,6 +858,7 @@ struct ns_connection *ns_connect(struct ns_server *server, const char *host,
int connect_ret_val;
(void) use_ssl;
if (host == NULL || (he = gethostbyname(host)) == NULL ||
(sock = socket(AF_INET, SOCK_STREAM, 0)) == INVALID_SOCKET) {
DBG(("gethostbyname(%s) failed: %s", host, strerror(errno)));
......@@ -1093,6 +1101,7 @@ enum {
GLOBAL_AUTH_FILE,
#endif
HIDE_FILES_PATTERN,
HEXDUMP_FILE,
#ifndef MONGOOSE_NO_FILESYSTEM
INDEX_FILES,
#endif
......@@ -1132,6 +1141,7 @@ static const char *static_config_options[] = {
"global_auth_file", NULL,
#endif
"hide_files_patterns", NULL,
"hexdump_file", NULL,
#ifndef MONGOOSE_NO_FILESYSTEM
"index_files","index.html,index.htm,index.shtml,index.cgi,index.php,index.lp",
#endif
......@@ -2027,21 +2037,6 @@ static int check_acl(const char *acl, uint32_t remote_ip) {
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 '..',
// excessive '/' and '\' characters
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,
if (port < 0) {
error_msg = "Cannot bind to port";
} else {
sockaddr_to_string(server->local_ip, sizeof(server->local_ip),
&server->ns_server.listening_sa);
ns_sock_to_str(server->ns_server.listening_sock, server->local_ip,
sizeof(server->local_ip), 0);
if (!strcmp(value, "0")) {
char buf[10];
mg_snprintf(buf, sizeof(buf), "%d", port);
......@@ -4462,14 +4457,13 @@ static void on_accept(struct ns_connection *nc, union socket_address *sa) {
(conn = (struct connection *) calloc(1, sizeof(*conn))) == NULL) {
nc->flags |= NSF_CLOSE_IMMEDIATELY;
} else {
conn->server = (struct mg_server *) nc->server;
sockaddr_to_string(conn->mg_conn.remote_ip,
sizeof(conn->mg_conn.remote_ip), sa);
conn->server = server;
ns_sock_to_str(nc->sock, conn->mg_conn.remote_ip,
sizeof(conn->mg_conn.remote_ip), 0);
conn->mg_conn.remote_port = ntohs(sa->sin.sin_port);
conn->mg_conn.server_param = nc->server->server_data;
conn->mg_conn.local_ip = server->local_ip;
conn->mg_conn.local_port =
ntohs(server->ns_server.listening_sa.sin.sin_port);
conn->mg_conn.local_port = ntohs(server->lsa.sin.sin_port);
// Circularly link two connection structures
nc->connection_data = conn;
......@@ -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) {
struct connection *conn = (struct connection *) nc->connection_data;
struct mg_server *server = (struct mg_server *) nc->server;
switch (ev) {
case NS_ACCEPT:
......@@ -4494,6 +4513,7 @@ static void mg_ev_handler(struct ns_connection *nc, enum ns_event ev, void *p) {
break;
case NS_RECV:
hexdump(nc, server->config_options[HEXDUMP_FILE], * (int *) p, 0);
if (nc->flags & NSF_ACCEPTED) {
process_request(conn);
#ifndef MONGOOSE_NO_CGI
......@@ -4506,6 +4526,7 @@ static void mg_ev_handler(struct ns_connection *nc, enum ns_event ev, void *p) {
break;
case NS_SEND:
hexdump(nc, server->config_options[HEXDUMP_FILE], * (int *) p, 1);
break;
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