From c13c28b96f351d5708258b3220f0a25caec8847f Mon Sep 17 00:00:00 2001 From: hugsy Date: Mon, 25 May 2015 14:39:37 +1000 Subject: [PATCH 01/18] ssl : fixed serial and bad cert issues --- docs/compil.md | 6 +++--- http.c | 7 +------ keys/openssl.cnf | 6 +++--- main.c | 2 ++ minica.c | 36 +++++++++++++++++++++------------ minica.h | 3 ++- ssl.c | 52 ++++++++++++++++++++++++++++++++---------------- ssl.h | 2 +- 8 files changed, 70 insertions(+), 44 deletions(-) diff --git a/docs/compil.md b/docs/compil.md index 17854e0..ffbd09d 100644 --- a/docs/compil.md +++ b/docs/compil.md @@ -12,9 +12,9 @@ thoroughly documented) API. Installing PolarSSL library is pretty straight-forward. Here with an example with version 1.3.9: ``` bash -~$ curl -s https://github.com/polarssl/polarssl/archive/polarssl-1.3.9.tar.gz | tar xfz - -~$ cd polarssl-1.3.9 -~$ make && sudo make install +$ curl -fsSL https://github.com/polarssl/polarssl/archive/polarssl-1.3.9.tar.gz | tar xfz - +$ cd polarssl-1.3.9 +$ make && sudo make install ``` For most distro, a simple diff --git a/http.c b/http.c index 4713bbe..0d06434 100644 --- a/http.c +++ b/http.c @@ -561,14 +561,9 @@ int create_http_socket(request_t* req, sock_t* server_sock, sock_t* client_sock, } if (req->do_intercept) { - proxenet_ssl_buf_t serial; - - if(proxenet_get_cert_serial(&(ssl_ctx->client), &serial)<0){ - return -1; - } /* 2. set up proxy->browser ssl session with hostname */ - if(proxenet_ssl_init_server_context(&(ssl_ctx->server), http_infos->hostname, serial) < 0) { + if(proxenet_ssl_init_server_context(&(ssl_ctx->server), http_infos->hostname) < 0) { return -1; } diff --git a/keys/openssl.cnf b/keys/openssl.cnf index b11e69d..467e5cf 100644 --- a/keys/openssl.cnf +++ b/keys/openssl.cnf @@ -60,8 +60,8 @@ commonName_max = 64 0.organizationName_default = World Domination Corp. organizationalUnitName_default = BlackHats -localityName_default = bleh -stateOrProvinceName_default = blah +localityName_default = proxenet +stateOrProvinceName_default = proxenet countryName_default = FR emailAddress_default = proxenet@worldomination.corp commonName_default = proxenet @@ -74,5 +74,5 @@ subjectKeyIdentifier = hash authorityKeyIdentifier = keyid:always,issuer:always [ v3_req ] -basicConstraints = CA:FALSE +basicConstraints = CA:TRUE subjectKeyIdentifier = hash diff --git a/main.c b/main.c index 08b01be..f17afcf 100644 --- a/main.c +++ b/main.c @@ -519,6 +519,8 @@ int main (int argc, char **argv, char **envp) if (retcode<0) return EXIT_FAILURE; + srand(time(0)); + serial_base = rand(); #ifdef _PERL_PLUGIN /* perform plugin pre-initialisation -- currently done only for Perl */ diff --git a/minica.c b/minica.c index e4a8352..d1cd042 100644 --- a/minica.c +++ b/minica.c @@ -141,7 +141,7 @@ static int ca_generate_csr(ctr_drbg_context *ctr_drbg, char* hostname, unsigned /* set the subject name */ snprintf(subj_name, sizeof(subj_name), PROXENET_CERT_SUBJECT, hostname); - retcode = x509write_csr_set_subject_name( &csr, subj_name); + retcode = x509write_csr_set_subject_name( &csr, subj_name ); if( retcode < 0 ) { xlog(LOG_ERROR, "x509write_csr_set_subject_name() returned %d\n", retcode); retcode = -1; @@ -171,12 +171,13 @@ static int ca_generate_csr(ctr_drbg_context *ctr_drbg, char* hostname, unsigned * * @return 0 if successful, -1 otherwise */ -static int ca_generate_crt(ctr_drbg_context *ctr_drbg, unsigned char* csrbuf, size_t csrbuf_len, unsigned char* crtbuf, size_t crtbuf_len, proxenet_ssl_buf_t serial_buf) +static int ca_generate_crt(ctr_drbg_context *ctr_drbg, unsigned char* csrbuf, size_t csrbuf_len, unsigned char* crtbuf, size_t crtbuf_len) { int retcode = -1; - char errbuf[128] = {0, }; - char subject_name[128] = {0, }; - char issuer_name[128] = {0, }; + char errbuf[256] = {0, }; + char subject_name[256] = {0, }; + char issuer_name[256] = {0, }; + char serial_str[32] = {0, }; x509_csr csr; x509_crt issuer_crt; @@ -184,7 +185,7 @@ static int ca_generate_crt(ctr_drbg_context *ctr_drbg, unsigned char* csrbuf, si x509write_cert crt; mpi serial; -#ifdef DEBUG_SSL +#ifdef DEBUG xlog(LOG_DEBUG, "%s\n", "CRT init structs"); #endif @@ -196,11 +197,12 @@ static int ca_generate_crt(ctr_drbg_context *ctr_drbg, unsigned char* csrbuf, si pk_init( &issuer_key ); mpi_init( &serial ); -#ifdef DEBUG_SSL +#ifdef DEBUG xlog(LOG_DEBUG, "%s\n", "CRT load cert & key"); #endif - retcode = mpi_read_binary(&serial, serial_buf.p, serial_buf.len); + snprintf(serial_str, sizeof(serial_str), "%u", ++serial_base); + retcode = mpi_read_string(&serial, 10, serial_str); if(retcode < 0) { polarssl_strerror(retcode, errbuf, sizeof(errbuf)); xlog(LOG_ERROR, "mpi_read_string() returned -0x%02x - %s\n", -retcode, errbuf); @@ -247,7 +249,7 @@ static int ca_generate_crt(ctr_drbg_context *ctr_drbg, unsigned char* csrbuf, si goto exit; } -#ifdef DEBUG_SSL +#ifdef DEBUG xlog(LOG_DEBUG, "%s\n", "CRT fill new crt fields"); #endif @@ -304,6 +306,14 @@ static int ca_generate_crt(ctr_drbg_context *ctr_drbg, unsigned char* csrbuf, si goto exit; } + retcode = x509write_crt_set_ns_cert_type( &crt, NS_CERT_TYPE_SSL_SERVER ); + if(retcode < 0) { + polarssl_strerror(retcode, errbuf, sizeof(errbuf)); + xlog(LOG_ERROR, "x509write_crt_set_ns_cert_type() returned -0x%02x - %s\n", -retcode, errbuf ); + goto exit; + } + + /* write CRT in buffer */ retcode = x509write_crt_pem(&crt, crtbuf, crtbuf_len, ctr_drbg_random, ctr_drbg); if( retcode < 0 ){ @@ -329,7 +339,7 @@ static int ca_generate_crt(ctr_drbg_context *ctr_drbg, unsigned char* csrbuf, si * * @return 0 if successful, -1 otherwise */ -static int create_crt(char* hostname, proxenet_ssl_buf_t serial, char* crtpath) +static int create_crt(char* hostname, char* crtpath) { int retcode, fd; unsigned char csrbuf[4096]={0, }; @@ -359,7 +369,7 @@ static int create_crt(char* hostname, proxenet_ssl_buf_t serial, char* crtpath) xlog(LOG_DEBUG, "Signing CSR for '%s' with '%s'(key='%s')\n", hostname, cfg->cafile, cfg->keyfile); #endif - retcode = ca_generate_crt(&ctr_drbg, csrbuf, sizeof(csrbuf), crtbuf, sizeof(crtbuf), serial); + retcode = ca_generate_crt(&ctr_drbg, csrbuf, sizeof(csrbuf), crtbuf, sizeof(crtbuf)); if(retcode<0) goto exit; @@ -407,7 +417,7 @@ static int create_crt(char* hostname, proxenet_ssl_buf_t serial, char* crtpath) * * @return 0 if successful, -1 otherwise */ -int proxenet_lookup_crt(char* hostname, proxenet_ssl_buf_t serial, char** crtpath) +int proxenet_lookup_crt(char* hostname, char** crtpath) { int retcode, n; char buf[PATH_MAX]; @@ -473,7 +483,7 @@ int proxenet_lookup_crt(char* hostname, proxenet_ssl_buf_t serial, char** crtpat } /* if not, create && release lock && returns */ - retcode = create_crt(hostname, serial, crt_realpath); + retcode = create_crt(hostname, crt_realpath); if (retcode < 0){ xlog(LOG_ERROR, "create_crt(hostname='%s', crt='%s') has failed\n", hostname, crt_realpath); diff --git a/minica.h b/minica.h index 8cc8e7a..c814caa 100644 --- a/minica.h +++ b/minica.h @@ -7,8 +7,9 @@ #define PROXENET_CERT_MAX_PATHLEN -1 #define PROXENET_CERT_SUBJECT "CN=%s,OU=BlackHats,O=World Domination Corp.,C=US" +int serial_base; int proxenet_get_cert_serial(ssl_atom_t* ssl, proxenet_ssl_buf_t* dst); -int proxenet_lookup_crt(char* hostname, proxenet_ssl_buf_t serial, char** crtpath); +int proxenet_lookup_crt(char* hostname, char** crtpath); #endif /* _MINICA_H */ diff --git a/ssl.c b/ssl.c index 1ee7ae7..404a805 100644 --- a/ssl.c +++ b/ssl.c @@ -66,7 +66,7 @@ static void proxenet_ssl_debug(void *who, int level, const char *str ) /** * */ -static inline int _proxenet_ssl_init_context(ssl_atom_t* ssl_atom, int type, char* hostname, proxenet_ssl_buf_t serial) +static inline int _proxenet_ssl_init_context(ssl_atom_t* ssl_atom, int type, char* hostname) { int retcode = -1; char ssl_error_buffer[128] = {0, }; @@ -80,7 +80,7 @@ static inline int _proxenet_ssl_init_context(ssl_atom_t* ssl_atom, int type, cha /* We only define a certificate if we're a server, or the user requested SSL cert auth */ if (type==SSL_IS_SERVER) { - if (proxenet_lookup_crt(hostname, serial, &certfile) < 0){ + if (proxenet_lookup_crt(hostname, &certfile) < 0){ xlog(LOG_ERROR, "proxenet_lookup_crt() failed for '%s'\n", hostname); return -1; } @@ -174,24 +174,27 @@ static inline int _proxenet_ssl_init_context(ssl_atom_t* ssl_atom, int type, cha goto end_init; } - ssl_set_endpoint(context, type ); + ssl_set_endpoint(context, type); ssl_set_rng(context, ctr_drbg_random, &(ssl_atom->ctr_drbg) ); switch(type) { case SSL_IS_SERVER: ssl_set_ca_chain(context, &(ssl_atom->ca), NULL, hostname); ssl_set_own_cert(context, &(ssl_atom->cert), &(ssl_atom->pkey)); - ssl_set_authmode(context, SSL_VERIFY_OPTIONAL); + ssl_set_authmode(context, SSL_VERIFY_NONE); ssl_set_min_version(context, SSL_MAJOR_VERSION_3, SSL_MINOR_VERSION_1); // TLSv1.0+ break; case SSL_IS_CLIENT: ssl_set_ca_chain(context, &(ssl_atom->cert), NULL, NULL); + ssl_set_authmode(context, SSL_VERIFY_NONE); if(use_ssl_client_auth){ ssl_set_hostname( context, domain ); ssl_set_own_cert(context, &(ssl_atom->cert), &(ssl_atom->pkey)); + } else { + ssl_set_hostname( context, hostname ); } - ssl_set_authmode(context, SSL_VERIFY_OPTIONAL); + break; default: @@ -218,9 +221,9 @@ static inline int _proxenet_ssl_init_context(ssl_atom_t* ssl_atom, int type, cha /** * */ -int proxenet_ssl_init_server_context(ssl_atom_t *server, char* hostname, proxenet_ssl_buf_t serial) +int proxenet_ssl_init_server_context(ssl_atom_t *server, char* hostname) { - return _proxenet_ssl_init_context(server, SSL_IS_SERVER, hostname, serial); + return _proxenet_ssl_init_context(server, SSL_IS_SERVER, hostname); } @@ -229,8 +232,7 @@ int proxenet_ssl_init_server_context(ssl_atom_t *server, char* hostname, proxene */ int proxenet_ssl_init_client_context(ssl_atom_t* client, char* hostname) { - proxenet_ssl_buf_t serial; - return _proxenet_ssl_init_context(client, SSL_IS_CLIENT, hostname, serial); + return _proxenet_ssl_init_context(client, SSL_IS_CLIENT, hostname); } @@ -249,7 +251,7 @@ void proxenet_ssl_wrap_socket(proxenet_ssl_context_t* ctx, sock_t* sock) int proxenet_ssl_handshake(proxenet_ssl_context_t* ctx) { int retcode = -1; - char ssl_strerror[512]; + char ssl_strerror[4096]; do { retcode = ssl_handshake( ctx ); @@ -258,9 +260,7 @@ int proxenet_ssl_handshake(proxenet_ssl_context_t* ctx) if(retcode!=POLARSSL_ERR_NET_WANT_READ && \ retcode!=POLARSSL_ERR_NET_WANT_WRITE) { - proxenet_xzero(ssl_strerror, sizeof(ssl_strerror)); - error_strerror(retcode, ssl_strerror, 127); - xlog(LOG_ERROR, "SSL handshake failed (returns %#x): %s\n", -retcode, ssl_strerror); + xlog(LOG_ERROR, "SSL handshake failed (returns %#x)\n", -retcode); break; } @@ -270,17 +270,35 @@ int proxenet_ssl_handshake(proxenet_ssl_context_t* ctx) if (cfg->verbose){ proxenet_xzero(ssl_strerror, sizeof(ssl_strerror)); - if (retcode) { + if (retcode){ snprintf(ssl_strerror, sizeof(ssl_strerror)-1, "SSL Handshake: "RED"fail"NOCOLOR" [%d]", retcode); - } else { + xlog(LOG_ERROR, "%s\n", ssl_strerror); + + if (cfg->verbose > 1){ + proxenet_xzero(ssl_strerror, sizeof(ssl_strerror)-1); + polarssl_strerror(retcode, ssl_strerror, sizeof(ssl_strerror)); + xlog(LOG_ERROR, "Details: %s\n", ssl_strerror); + } + } + else + { snprintf(ssl_strerror, sizeof(ssl_strerror)-1, "SSL Handshake: "GREEN"success"NOCOLOR" [proto='%s',cipher='%s']", ssl_get_version( ctx ), ssl_get_ciphersuite( ctx ) ); + xlog(LOG_INFO, "%s\n", ssl_strerror); + + if (cfg->verbose>1){ + if(ssl_get_peer_cert( ctx ) != NULL){ + proxenet_xzero(ssl_strerror, sizeof(ssl_strerror)); + x509_crt_info( ssl_strerror, sizeof(ssl_strerror)-1, + " ", ssl_get_peer_cert( ctx ) ); + xlog(LOG_INFO, "Peer SSL certificate info:\n%s", ssl_strerror); + } + } } - xlog(LOG_INFO, "%s\n", ssl_strerror); } @@ -394,7 +412,7 @@ static ssize_t proxenet_ssl_ioctl(int (*func)(), void *buf, size_t count, proxen break; if (retcode <= 0) { - char ssl_strerror[128] = {0, }; + char ssl_strerror[256] = {0, }; switch(retcode) { case POLARSSL_ERR_SSL_PEER_CLOSE_NOTIFY : diff --git a/ssl.h b/ssl.h index da95e9c..0380ac8 100644 --- a/ssl.h +++ b/ssl.h @@ -31,7 +31,7 @@ typedef struct __ssl_context_t { #include "socket.h" #include "utils.h" -int proxenet_ssl_init_server_context(ssl_atom_t* server, char* hostname, proxenet_ssl_buf_t serial); +int proxenet_ssl_init_server_context(ssl_atom_t* server, char* hostname); int proxenet_ssl_init_client_context(ssl_atom_t* client, char* hostname); void proxenet_ssl_wrap_socket(proxenet_ssl_context_t* s, sock_t* sock); From 45e594e8dbca8413872d4bd381588ac9d65ccfba Mon Sep 17 00:00:00 2001 From: hugsy Date: Mon, 25 May 2015 22:00:58 +1000 Subject: [PATCH 02/18] [docs] added precision for creating java plugins --- docs/plugins/java.md | 8 ++++++++ proxenet-plugins | 2 +- 2 files changed, 9 insertions(+), 1 deletion(-) diff --git a/docs/plugins/java.md b/docs/plugins/java.md index 70ce398..962f844 100644 --- a/docs/plugins/java.md +++ b/docs/plugins/java.md @@ -28,6 +28,14 @@ public class MyPlugin } ``` +`proxenet` cannot compile by itself to Java bytecode. So you need to generate +the .class file, like this: +```bash +$ javac MyPlugin.java +``` + +And copy the new `MyPlugin.class` to the *proxenet-plugins* directory. + ## Example diff --git a/proxenet-plugins b/proxenet-plugins index e756e27..933c0e0 160000 --- a/proxenet-plugins +++ b/proxenet-plugins @@ -1 +1 @@ -Subproject commit e756e27ddea0d778ede48499afbe07a8d65254be +Subproject commit 933c0e0cb66d05df501c1648dc80841dd8966d07 From 610adf82939ae0b4c9d4b862ace5721182bf44d7 Mon Sep 17 00:00:00 2001 From: hugsy Date: Tue, 26 May 2015 10:02:04 +1000 Subject: [PATCH 03/18] [docs] added precision for writing C plugin --- docs/plugins/c.md | 29 +++++++++++++++++++++++------ docs/plugins/java.md | 4 ++-- proxenet-plugins | 2 +- 3 files changed, 26 insertions(+), 9 deletions(-) diff --git a/docs/plugins/c.md b/docs/plugins/c.md index 38c41b0..c7be980 100644 --- a/docs/plugins/c.md +++ b/docs/plugins/c.md @@ -5,16 +5,18 @@ This page will explain how to write a C plugin for `proxenet`. ## Plugin skeleton + ```c +#include -struct info { +typedef struct info { const char* AUTHOR; const char* PLUGIN_NAME; -}; +} c_plugin_info_t; -struct info MyPlugin = { - .AUTHOR = ""; - .PLUGIN_NAME = ""; +c_plugin_info_t MyPlugin = { + .AUTHOR = "", + .PLUGIN_NAME = "" }; @@ -35,7 +37,20 @@ int main(int argc, char** argv, char** envp) return 0; } ``` - +_Note_: As you may have noticed, the definitions for the functions +`proxenet_request_hook()` and `proxenet_response_hook()` have an extra +argument. This argument, `buflen` is a pointer to a `size_t` variable, which +will contain the size of the request. Every plugin that modifies the length of +the request/response **MUST** update this value. See the example below for +demonstration. + +`proxenet` does not recognize plain C files so it should be compiled first as a +[shared object](tldp.org/HOWTO/Program-Library-HOWTO/shared-libraries.html). The +following command might just do the trick: + +```bash +$ cc -Wall -Werror -fPIC -shared -o MyPlugin.o MyPlugin.c +``` ## Example @@ -43,6 +58,7 @@ int main(int argc, char** argv, char** envp) #include #include #include +#include struct info { const char* AUTHOR; @@ -62,6 +78,7 @@ char* proxenet_request_hook(unsigned long request_id, char *request, char* uri, memcpy(newReq, request, *buflen-2); memcpy(newReq + (*buflen-2), header, strlen(header)); free(request); + *buflen = *buflen + strlen(header) + 2; return newReq; } diff --git a/docs/plugins/java.md b/docs/plugins/java.md index 962f844..1b67ec6 100644 --- a/docs/plugins/java.md +++ b/docs/plugins/java.md @@ -1,4 +1,4 @@ -# java plugin +# Java plugin This page will explain how to write a java plugin for `proxenet`. @@ -29,7 +29,7 @@ public class MyPlugin ``` `proxenet` cannot compile by itself to Java bytecode. So you need to generate -the .class file, like this: +the `.class` file, like this: ```bash $ javac MyPlugin.java ``` diff --git a/proxenet-plugins b/proxenet-plugins index 933c0e0..e756e27 160000 --- a/proxenet-plugins +++ b/proxenet-plugins @@ -1 +1 @@ -Subproject commit 933c0e0cb66d05df501c1648dc80841dd8966d07 +Subproject commit e756e27ddea0d778ede48499afbe07a8d65254be From 23fd0ab223654a26b846f48e8d303520e8ceff92 Mon Sep 17 00:00:00 2001 From: crazy rabbidz Date: Tue, 26 May 2015 10:58:44 +1000 Subject: [PATCH 04/18] Update c.md --- docs/plugins/c.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/plugins/c.md b/docs/plugins/c.md index c7be980..3a73467 100644 --- a/docs/plugins/c.md +++ b/docs/plugins/c.md @@ -45,7 +45,7 @@ the request/response **MUST** update this value. See the example below for demonstration. `proxenet` does not recognize plain C files so it should be compiled first as a -[shared object](tldp.org/HOWTO/Program-Library-HOWTO/shared-libraries.html). The +[shared object](http://tldp.org/HOWTO/Program-Library-HOWTO/shared-libraries.html). The following command might just do the trick: ```bash From 3ad044459ad19d1f4b94f36602026d7803ffc0d6 Mon Sep 17 00:00:00 2001 From: hugsy Date: Tue, 26 May 2015 15:14:06 +1000 Subject: [PATCH 05/18] [c] fixed invalid interpreter deref --- plugin-c.c | 12 +++++++++--- proxenet-plugins | 2 +- 2 files changed, 10 insertions(+), 4 deletions(-) diff --git a/plugin-c.c b/plugin-c.c index 8139ba3..7a0acd3 100644 --- a/plugin-c.c +++ b/plugin-c.c @@ -79,6 +79,13 @@ int proxenet_c_initialize_function(plugin_t* plugin, req_t type) { void *interpreter; + if (plugin->interpreter==NULL || plugin->interpreter->ready==false){ + xlog(LOG_ERROR, "%s\n", "[c] not ready (dlopen() failed?)"); + return -1; + } + + interpreter = (void *) plugin->interpreter->vm; + /* if already initialized, return ok */ if (plugin->pre_function && type==REQUEST) return 0; @@ -86,7 +93,6 @@ int proxenet_c_initialize_function(plugin_t* plugin, req_t type) if (plugin->post_function && type==RESPONSE) return 0; - interpreter = (void *) plugin->interpreter; if (type == REQUEST) { plugin->pre_function = dlsym(interpreter, CFG_REQUEST_PLUGIN_FUNCTION); @@ -157,11 +163,11 @@ char* proxenet_c_plugin(plugin_t *plugin, request_t *request) goto end_exec_c_plugin; } - request->data = proxenet_xstrdup(request->data, buflen); + request->data = proxenet_xstrdup(bufres, buflen); request->size = buflen; end_exec_c_plugin: - return bufres; + return request->data; } #endif diff --git a/proxenet-plugins b/proxenet-plugins index e756e27..933c0e0 160000 --- a/proxenet-plugins +++ b/proxenet-plugins @@ -1 +1 @@ -Subproject commit e756e27ddea0d778ede48499afbe07a8d65254be +Subproject commit 933c0e0cb66d05df501c1648dc80841dd8966d07 From 75cb4173ae4b2133fe22c7452b080faca1ce71ef Mon Sep 17 00:00:00 2001 From: hugsy Date: Tue, 26 May 2015 18:15:20 +1000 Subject: [PATCH 06/18] [control-server] formatting output to json --- control-server.c | 53 ++++++++++++++++++++++++++++++++---------------- control-web.py | 2 ++ 2 files changed, 38 insertions(+), 17 deletions(-) diff --git a/control-server.c b/control-server.c index a491039..53f6df4 100644 --- a/control-server.c +++ b/control-server.c @@ -53,7 +53,7 @@ static void _send_threads_info(sock_t fd) int i, n; n = snprintf(msg, sizeof(msg), - "- Running/Max threads: %d/%d\n", + "{ Running/Max threads: %d/%d\n", get_active_threads_size(), cfg->nb_threads); proxenet_write(fd, (void*)msg, n); @@ -142,23 +142,24 @@ void pause_cmd(sock_t fd, char *options, unsigned int nb_options) void info_cmd(sock_t fd, char *options, unsigned int nb_options) { char msg[BUFSIZE] = {0, }; - int n; + int i, n; (void) options; (void) nb_options; /* generic info */ n = snprintf(msg, sizeof(msg), - "Configuration:\n" - "- Listening interface: %s/%s\n" - "- Supported IP version: %s\n" - "- Logging to %s\n" - "- SSL private key: %s\n" - "- SSL certificate: %s\n" - "- Proxy: %s [%s]\n" - "- Plugins directory: %s\n" - "- Autoloading plugins directory: %s\n" - "- Number of requests treated: %lu\n" + "{'info':" + " {'Configuration':[" + " {'Listening interface':'%s/%s'}," + " {'Supported IP version':'%s'}," + " {'Logging file': '%s'}," + " {'SSL private key': '%s'}," + " {'SSL certificate': '%s'}," + " {'Proxy': '%s [%s]'}," + " {'Plugins directory': '%s'}," + " {'Autoloading plugins directory': '%s'}," + " {'Number of requests treated':'%lu'}," , cfg->iface, cfg->port, (cfg->ip_version==AF_INET)? "IPv4": (cfg->ip_version==AF_INET6)?"IPv6": "ANY", @@ -174,15 +175,30 @@ void info_cmd(sock_t fd, char *options, unsigned int nb_options) proxenet_write(fd, (void*)msg, n); /* threads info */ - _send_threads_info(fd); + /* _send_threads_info(fd); */ + n = snprintf(msg, sizeof(msg), "{'Running/Max threads': '%d/%d'},", + get_active_threads_size(), cfg->nb_threads); + proxenet_write(fd, (void*)msg, n); + + proxenet_write(fd, "{'Threads':[", 12); + for (i=0; i < cfg->nb_threads; i++) { + if (!is_thread_active(i)) continue; + memset(msg, 0, sizeof(msg)); + n = snprintf(msg, sizeof(msg), "{'Thread-%d':'%lu'},", i, threads[i]); + proxenet_write(fd, (void*)msg, n); + } + proxenet_write(fd, "]},", 3); /* plugins info */ + proxenet_write(fd, "{'Plugins':[", 12); if (proxenet_plugin_list_size()) { proxenet_print_plugins_list(fd); } else { - proxenet_write(fd, (void*)"No plugin loaded\n", 17); + proxenet_write(fd, (void*)"{'No plugin loaded':''}", 23); } + proxenet_write(fd, "]},", 3); + proxenet_write(fd, "]}}", 3); return; } @@ -393,6 +409,7 @@ static int plugin_cmd_load(sock_t fd, char *options) int ret, n; char msg[BUFSIZE] = {0, }; char *ptr; + size_t l; ptr = strtok(options, " \n"); if (!ptr){ @@ -400,7 +417,11 @@ static int plugin_cmd_load(sock_t fd, char *options) return -1; } - plugin_name=proxenet_xstrdup2(ptr); + l = strlen(ptr); + plugin_name = alloca(l+1); + proxenet_xzero(plugin_name, l+1); + memcpy(plugin_name, ptr, l); + if ( plugin_name==NULL ){ n = sprintf(msg, "proxenet_xstrdup2() failed: %s\n", strerror(errno)); proxenet_write(fd, (void*)msg, n); @@ -411,7 +432,6 @@ static int plugin_cmd_load(sock_t fd, char *options) if(ret<0){ n = snprintf(msg, sizeof(msg)-1, "Error while loading plugin '%s'\n", plugin_name); proxenet_write(fd, (void*)msg, n); - proxenet_xfree(plugin_name); return -1; } @@ -424,7 +444,6 @@ static int plugin_cmd_load(sock_t fd, char *options) /* plugin list must be reinitialized since we dynamically load VMs only if plugins are found */ proxenet_initialize_plugins(); - proxenet_xfree(plugin_name); return 0; } diff --git a/control-web.py b/control-web.py index 8c8a69d..f145753 100755 --- a/control-web.py +++ b/control-web.py @@ -1,5 +1,6 @@ #!/usr/bin/env python2.7 import os, sys, socket, argparse +import json try: from bottle import request, route, template, run, static_file @@ -90,6 +91,7 @@ def info(): if not is_proxenet_running(): return build_html(body=not_running_html()) res = sr("info") fmt = format_result(res) + # fmt = json.loads( res ) return build_html(body=fmt, title="Info page", page="info") From 1299bc26772ee96b3e030a833772dcfba1873991 Mon Sep 17 00:00:00 2001 From: crazy rabbidz Date: Wed, 27 May 2015 08:38:38 +1000 Subject: [PATCH 07/18] Update control-server.c json ' -> " --- control-server.c | 47 ++++++++++++++++++++++++----------------------- 1 file changed, 24 insertions(+), 23 deletions(-) diff --git a/control-server.c b/control-server.c index 53f6df4..737a784 100644 --- a/control-server.c +++ b/control-server.c @@ -53,7 +53,7 @@ static void _send_threads_info(sock_t fd) int i, n; n = snprintf(msg, sizeof(msg), - "{ Running/Max threads: %d/%d\n", + "- Running/Max threads: %d/%d\n", get_active_threads_size(), cfg->nb_threads); proxenet_write(fd, (void*)msg, n); @@ -149,18 +149,18 @@ void info_cmd(sock_t fd, char *options, unsigned int nb_options) /* generic info */ n = snprintf(msg, sizeof(msg), - "{'info':" - " {'Configuration':[" - " {'Listening interface':'%s/%s'}," - " {'Supported IP version':'%s'}," - " {'Logging file': '%s'}," - " {'SSL private key': '%s'}," - " {'SSL certificate': '%s'}," - " {'Proxy': '%s [%s]'}," - " {'Plugins directory': '%s'}," - " {'Autoloading plugins directory': '%s'}," - " {'Number of requests treated':'%lu'}," - , + "{\"info\":[" + " {\"Configuration\":[" + " {\"Listening interface\": \"%s/%s\"}," + " {\"Supported IP version\": \"%s\"}," + " {\"Logging file\": \"%s\"}," + " {\"SSL private key\": \"%s\"}," + " {\"SSL certificate\": \"%s\"}," + " {\"Proxy\": \"%s [%s]\"}," + " {\"Plugins directory\": \"%s\"}," + " {\"Autoloading plugins directory\": \"%s\"}," + " {\"Number of requests treated\":\"%lu\"}" + " ]},", cfg->iface, cfg->port, (cfg->ip_version==AF_INET)? "IPv4": (cfg->ip_version==AF_INET6)?"IPv6": "ANY", (cfg->logfile)?cfg->logfile:"stdout", @@ -175,30 +175,31 @@ void info_cmd(sock_t fd, char *options, unsigned int nb_options) proxenet_write(fd, (void*)msg, n); /* threads info */ - /* _send_threads_info(fd); */ - n = snprintf(msg, sizeof(msg), "{'Running/Max threads': '%d/%d'},", + proxenet_write(fd, "{\"Threads\":[", 12); + n = snprintf(msg, sizeof(msg), "{\"Running/Max threads\": \"%d/%d\"},", get_active_threads_size(), cfg->nb_threads); proxenet_write(fd, (void*)msg, n); - proxenet_write(fd, "{'Threads':[", 12); + proxenet_write(fd, "{\"Details\":[", 12); for (i=0; i < cfg->nb_threads; i++) { if (!is_thread_active(i)) continue; memset(msg, 0, sizeof(msg)); - n = snprintf(msg, sizeof(msg), "{'Thread-%d':'%lu'},", i, threads[i]); + n = snprintf(msg, sizeof(msg), "{\"Thread-%d\": \"%lu\"},", i, threads[i]); proxenet_write(fd, (void*)msg, n); } - proxenet_write(fd, "]},", 3); - + proxenet_write(fd, "]}", 2); + proxenet_write(fd, "]},", 3); + /* plugins info */ - proxenet_write(fd, "{'Plugins':[", 12); + proxenet_write(fd, "{\"Plugins\": [", 12); if (proxenet_plugin_list_size()) { proxenet_print_plugins_list(fd); } else { - proxenet_write(fd, (void*)"{'No plugin loaded':''}", 23); + proxenet_write(fd, (void*)"{\"No plugin loaded\": \"\"}", 23); } - proxenet_write(fd, "]},", 3); + proxenet_write(fd, "]}", 2); - proxenet_write(fd, "]}}", 3); + proxenet_write(fd, "]}", 2); return; } From ca6db358bcdf97af3079a667e5dd310ba784aeee Mon Sep 17 00:00:00 2001 From: hugsy Date: Wed, 27 May 2015 18:25:22 +1000 Subject: [PATCH 08/18] improved control-web: control-server returns json as output --- control-server.c | 190 +++++++++++++++++++++++++++++++++++------------ control-web.py | 86 +++++++++++++++++---- plugin.c | 69 ++--------------- plugin.h | 4 +- 4 files changed, 222 insertions(+), 127 deletions(-) diff --git a/control-server.c b/control-server.c index 737a784..e8f41dc 100644 --- a/control-server.c +++ b/control-server.c @@ -8,6 +8,8 @@ #include #include #include +#include +#include #ifdef __LINUX__ #include @@ -23,6 +25,7 @@ #include "core.h" #include "socket.h" #include "utils.h" +#include "plugin.h" #define BUFSIZE 2048 @@ -51,24 +54,68 @@ static void _send_threads_info(sock_t fd) { char msg[BUFSIZE] = {0,}; int i, n; + bool first_item = true; n = snprintf(msg, sizeof(msg), - "- Running/Max threads: %d/%d\n", - get_active_threads_size(), - cfg->nb_threads); - proxenet_write(fd, (void*)msg, n); + "{\"Threads\":{" + "\"Max threads\": %d," + "\"Running threads\": %d,", + cfg->nb_threads, get_active_threads_size()); + proxenet_write(fd, msg, n); + proxenet_write(fd, "\"Details\": {", 12); for (i=0; i < cfg->nb_threads; i++) { if (!is_thread_active(i)) continue; + if (first_item) first_item=false; + else proxenet_write(fd, ",", 1); memset(msg, 0, sizeof(msg)); - n = snprintf(msg, sizeof(msg), "\t- Thread %d (%lu)\n", i, threads[i]); + n = snprintf(msg, sizeof(msg), "\"Thread-%d\": %lu", i, threads[i]); proxenet_write(fd, (void*)msg, n); } + proxenet_write(fd, "}", 1); + proxenet_write(fd, "}}", 2); return; } +/** + * Enumerate all plugins loaded + */ +static int plugin_cmd_list_json(sock_t fd, bool only_loaded) +{ + plugin_t *p; + bool first_iter=true; + char msg[BUFSIZE] = {0, }; + int n; + + for (p=plugins_list; p; p=p->next) { + if (only_loaded && p->state!=INACTIVE) + continue; + + if(first_iter) first_iter=false; + else proxenet_write(fd, ",", 1); + + memset(msg, 0, sizeof(msg)); + n = snprintf(msg, sizeof(msg), + "\"%s\": {" + "\"id\": %d," + "\"priority\": %d," + "\"type\": \"%s [0x%x]\"," + "\"state\": \"%sACTIVE\"}", + p->name, + p->id, + p->priority, + supported_plugins_str[p->type], + p->type, + (p->state==ACTIVE?"":"IN")); + proxenet_write(fd, msg, n); + } + + return 0; +} + + /** * This command will try to kill gracefully the running process of proxenet */ @@ -149,18 +196,18 @@ void info_cmd(sock_t fd, char *options, unsigned int nb_options) /* generic info */ n = snprintf(msg, sizeof(msg), - "{\"info\":[" - " {\"Configuration\":[" - " {\"Listening interface\": \"%s/%s\"}," - " {\"Supported IP version\": \"%s\"}," - " {\"Logging file\": \"%s\"}," - " {\"SSL private key\": \"%s\"}," - " {\"SSL certificate\": \"%s\"}," - " {\"Proxy\": \"%s [%s]\"}," - " {\"Plugins directory\": \"%s\"}," - " {\"Autoloading plugins directory\": \"%s\"}," - " {\"Number of requests treated\":\"%lu\"}" - " ]},", + "{\"info\":" + " {\"Configuration\":{" + " \"Listening interface\": \"%s/%s\"," + " \"Supported IP version\": \"%s\"," + " \"Logging file\": \"%s\"," + " \"SSL private key\": \"%s\"," + " \"SSL certificate\": \"%s\"," + " \"Proxy\": \"%s [%s]\"," + " \"Plugins directory\": \"%s\"," + " \"Autoloading plugins directory\": \"%s\"," + " \"Number of requests treated\":\"%lu\"" + " },", cfg->iface, cfg->port, (cfg->ip_version==AF_INET)? "IPv4": (cfg->ip_version==AF_INET6)?"IPv6": "ANY", (cfg->logfile)?cfg->logfile:"stdout", @@ -175,31 +222,30 @@ void info_cmd(sock_t fd, char *options, unsigned int nb_options) proxenet_write(fd, (void*)msg, n); /* threads info */ - proxenet_write(fd, "{\"Threads\":[", 12); - n = snprintf(msg, sizeof(msg), "{\"Running/Max threads\": \"%d/%d\"},", + proxenet_write(fd, "\"Threads\": {", 12); + n = snprintf(msg, sizeof(msg), "\"Running/Max threads\": \"%d/%d\",", get_active_threads_size(), cfg->nb_threads); proxenet_write(fd, (void*)msg, n); - proxenet_write(fd, "{\"Details\":[", 12); + proxenet_write(fd, "\"Details\": {", 12); for (i=0; i < cfg->nb_threads; i++) { if (!is_thread_active(i)) continue; memset(msg, 0, sizeof(msg)); - n = snprintf(msg, sizeof(msg), "{\"Thread-%d\": \"%lu\"},", i, threads[i]); + n = snprintf(msg, sizeof(msg), "\"Thread-%d\": \"%lu\",", i, threads[i]); proxenet_write(fd, (void*)msg, n); } - proxenet_write(fd, "]}", 2); - proxenet_write(fd, "]},", 3); - + proxenet_write(fd, "}},", 3); + /* plugins info */ - proxenet_write(fd, "{\"Plugins\": [", 12); + proxenet_write(fd, "\"Plugins\": {", 12); if (proxenet_plugin_list_size()) { - proxenet_print_plugins_list(fd); + plugin_cmd_list_json(fd, false); } else { - proxenet_write(fd, (void*)"{\"No plugin loaded\": \"\"}", 23); + proxenet_write(fd, "\"info\": \"No plugin loaded\"", 26); } - proxenet_write(fd, "]}", 2); + proxenet_write(fd, "}", 1); - proxenet_write(fd, "]}", 2); + proxenet_write(fd, "}}", 2); return; } @@ -211,24 +257,30 @@ void verbose_cmd(sock_t fd, char *options, unsigned int nb_options) { char msg[BUFSIZE] = {0, }; char *ptr; - int n; + int n, level; (void) options; (void) nb_options; ptr = strtok(options, " \n"); if (!ptr){ - n = snprintf(msg, BUFSIZE, "Verbose level is at %d\n", cfg->verbose); + n = snprintf(msg, BUFSIZE, "{\"verbose\": \"current level is %d\"}", + cfg->verbose); proxenet_write(fd, (void*)msg, n); return; } - if (strcmp(ptr, "inc")==0 && cfg->verboseverbose); + if ( (level=atoi(ptr)) > 0 && levelverbose = level; + n = snprintf(msg, BUFSIZE, "{\"verbose\": \"level is set to %d\"}", + cfg->verbose); + } + else if (strcmp(ptr, "inc")==0 && cfg->verboseverbose); else if (strcmp(ptr, "dec")==0 && cfg->verbose>0) - n = snprintf(msg, BUFSIZE, "Verbose level is now %d\n", --cfg->verbose); + n = snprintf(msg, BUFSIZE, "{\"verbose\": \"level is now %d\"}", --cfg->verbose); else - n = snprintf(msg, BUFSIZE, "Invalid action\n Syntax\n verbose (inc|dec)\n"); + n = snprintf(msg, BUFSIZE, "{\"error\": \"Invalid action\"}"); proxenet_write(fd, (void*)msg, n); @@ -306,22 +358,64 @@ void threads_cmd(sock_t fd, char *options, unsigned int nb_options) } -/** - * Enumerate all plugins loaded - */ -static int plugin_cmd_list_loaded(sock_t fd) -{ - proxenet_print_plugins_list(fd); - return 0; -} - - /** * Enumerate all plugins available in the plugins directory */ static int plugin_cmd_list_available(sock_t fd) { - proxenet_print_all_plugins(fd); + struct dirent *dir_ptr=NULL; + DIR *dir = NULL; + char* name = NULL; + char msg[2048] = {0, }; + int n, type; + bool first_iter = true; + + dir = opendir(cfg->plugins_path); + if (dir == NULL) { + xlog(LOG_ERROR, "Failed to open '%s': %s\n", cfg->plugins_path, strerror(errno)); + n = snprintf(msg, sizeof(msg), "{\"Error\": \"Cannot open '%s': %s\"}", + cfg->plugins_path, strerror(errno)); + proxenet_write(fd, msg, n); + return -1; + } + + n = snprintf(msg, sizeof(msg),"{\"Plugins available in %s\": {", + cfg->plugins_path); + proxenet_write(fd, msg, n); + while ((dir_ptr=readdir(dir))) { + type = -1; + name = dir_ptr->d_name; + if (!strcmp(name,".") || !strcmp(name,"..")) + continue; + + type = proxenet_get_plugin_type(name); + if (type < 0) + continue; + + /* this is only to avoid breaking json syntax */ + if (!first_iter) + proxenet_write(fd, ",", 1); + else + first_iter = false; + + + proxenet_xzero(msg, sizeof(msg)); + n = snprintf(msg, sizeof(msg), "\"%s\": [\"%s\", %d]", + name, supported_plugins_str[type], + proxenet_is_plugin_loaded(name)?1:0); + + proxenet_write(fd, msg, n); + } + proxenet_write(fd, "}}", 2); + + if (closedir(dir) < 0){ + xlog(LOG_ERROR, "Failed to close '%s': %s\n", cfg->plugins_path, strerror(errno)); + n = snprintf(msg, sizeof(msg), "{\"Error\": \"Cannot close dir '%s': %s\"", + cfg->plugins_path, strerror(errno)); + proxenet_write(fd, msg, n); + return -1; + } + return 0; } @@ -392,8 +486,6 @@ static int plugin_cmd_set(sock_t fd, char *options) return 0; } - - n = snprintf(msg, BUFSIZE, "Unknown action '%s' for plugin %d\n", ptr, plugin_id); proxenet_write(fd, (void*)msg, n); @@ -505,7 +597,7 @@ void plugin_cmd(sock_t fd, char *options, unsigned int nb_options) goto invalid_plugin_action; if (strcmp(ptr, "list") == 0) { - plugin_cmd_list_loaded(fd); + plugin_cmd_list_json(fd, true); return; } if (strcmp(ptr, "list-all") == 0) { diff --git a/control-web.py b/control-web.py index f145753..0c634d2 100755 --- a/control-web.py +++ b/control-web.py @@ -3,7 +3,7 @@ import json try: - from bottle import request, route, template, run, static_file + from bottle import request, route, get, post, run, static_file except ImportError: sys.stderr.write("Missing package `bottle`\n") exit(1) @@ -26,6 +26,11 @@ def is_proxenet_running(): def not_running_html(): return """""" +def format_result(res): + d = res.replace('\n', "
") + d = d[:-4] + return d + def recv_until(sock, pattern=">>> "): data = "" while True: @@ -44,12 +49,8 @@ def sr(msg): s.send( msg.strip() + '\n' ) res = recv_until(s) s.close() - return res + return format_result(res) -def format_result(res): - d = res.replace('\n', "
") - d = d[:-4] - return d def build_html(**kwargs): header = """ @@ -66,10 +67,9 @@ def build_html(**kwargs): body += """
  • Quit
  • """ body += """ +

    -
    -
    {}
    -
    +
    {}
    """.format( kwargs.get("body", "") ) footer = """""" return header + body + footer @@ -79,6 +79,7 @@ def build_html(**kwargs): def logo(): return static_file("/proxenet-logo.png", root="./docs/img") + @route('/quit') def quit(): if not is_proxenet_running(): return build_html(body=not_running_html()) @@ -86,13 +87,28 @@ def quit(): msg = """""" return build_html(body=msg) + @route('/info') def info(): if not is_proxenet_running(): return build_html(body=not_running_html()) res = sr("info") - fmt = format_result(res) - # fmt = json.loads( res ) - return build_html(body=fmt, title="Info page", page="info") + info = json.loads( res )['info'] + html = "" + for section in info.keys(): + html += """
    """ + html += """

    {}

    """.format(section) + + html += """
      """ + for k,v in info[section].iteritems(): + if type(v).__name__ == "dict": + html += "
    • {}:
        ".format(k) + for a,b in v.iteritems(): html += "
      1. {}: {}
      2. ".format(a,b) + html += "
    • " + else: + html += "
    • {}: {}
    • ".format(k, v) + html += "
    """ + + return build_html(body=html, title="Info page", page="info") @route('/') @@ -101,9 +117,51 @@ def index(): return info() +@get('/plugin') +def plugin(): + if not is_proxenet_running(): return build_html(body=not_running_html()) + res = sr("plugin list-all") + js = json.loads( res ) + title = js.keys()[0] + html = """
    """ + html += """

    {}

    """.format(title) + html += """""" + html += "" + for k,v in js[title].iteritems(): + _type, _is_loaded = v + html += "".format(k, _type, " Loaded" if _is_loaded else "") + html += "
    NameType
    {}{}{}
    """ + + return build_html(body=html, title="List all plugins available", page="plugin") + + +@get('/threads') +def threads(): + if not is_proxenet_running(): return build_html(body=not_running_html()) + res = sr("threads") + js = json.loads( res ) + title = js.keys()[0] + html = """
    """ + html += """

    {}

    """.format(title) + html += """
      """ + for k,v in js[title].iteritems(): html += "
    • {}: {}
    • ".format(k, v) + html += "
    """ + + html += """
    + + +
    +
    + + + +
    """ + + return build_html(body=html, title="Get information on Threads", page="threads") + + if __name__ == "__main__": - parser = argparse.ArgumentParser(usage = __usage__, - description = __desc__) + parser = argparse.ArgumentParser(usage = __usage__, description = __desc__) parser.add_argument("-v", "--verbose", default=False, action="store_true", dest="verbose", help="Increments verbosity") diff --git a/plugin.c b/plugin.c index a3eff36..4814e40 100644 --- a/plugin.c +++ b/plugin.c @@ -255,9 +255,13 @@ void proxenet_print_plugins_list(int fd) /** + * Get the proxenet type associated to a specific file name. The type + * is guessed by the filename extension. * + * @param the file name of the plugin + * @return the type (int) of the file name if found, -1 otherwise */ -static int proxenet_get_plugin_type(char* filename) +int proxenet_get_plugin_type(char* filename) { unsigned short type; bool is_valid = false; @@ -284,7 +288,7 @@ static int proxenet_get_plugin_type(char* filename) * @param name : plugin name to look up * @return true if a match is found, false in any other case */ -static bool is_plugin_loaded(char* name) +bool proxenet_is_plugin_loaded(char* name) { plugin_t* p; for(p=plugins_list; p!=NULL; p=p->next){ @@ -297,67 +301,6 @@ static bool is_plugin_loaded(char* name) } -/** - * Print all plugins available in the plugin directory - * - * @param fd file descriptor to write output on - */ -void proxenet_print_all_plugins(int fd) -{ - struct dirent *dir_ptr=NULL; - DIR *dir = NULL; - char* name = NULL; - char msg[2048] = {0, }; - int n, type; - - dir = opendir(cfg->plugins_path); - if (dir == NULL) { - xlog(LOG_ERROR, "Failed to open '%s': %s\n", cfg->plugins_path, strerror(errno)); - n = snprintf(msg, sizeof(msg), "Error while opening dir '%s': %s\n", cfg->plugins_path, strerror(errno)); - proxenet_write(fd, msg, n); - return; - } - - n = snprintf(msg, sizeof(msg), - "Enumerating all plugins in "BLUE"%s"NOCOLOR"\n", - cfg->plugins_path); - proxenet_write(fd, msg, n); - - while ((dir_ptr=readdir(dir))) { - type = -1; - name = dir_ptr->d_name; - if (!strcmp(name,".") || !strcmp(name,"..")) - continue; - - type = proxenet_get_plugin_type(name); - if (type < 0) - continue; - - if (is_plugin_loaded(name)) { - n = snprintf(msg, sizeof(msg), - "[*] "GREEN"%s"NOCOLOR" ("RED"%s"NOCOLOR") - already loaded\n", - name, supported_plugins_str[type]); - } else { - n = snprintf(msg, sizeof(msg), - "[*] "CYAN"%s"NOCOLOR" ("RED"%s"NOCOLOR")\n", - name, supported_plugins_str[type]); - } - - proxenet_write(fd, msg, n); - proxenet_xzero(msg, sizeof(msg)); - } - - if (closedir(dir) < 0){ - xlog(LOG_ERROR, "Failed to close '%s': %s\n", cfg->plugins_path, strerror(errno)); - n = snprintf(msg, sizeof(msg), "Error while closing dir '%s': %s\n", cfg->plugins_path, strerror(errno)); - proxenet_write(fd, msg, n); - return; - } - - return; -} - - /** * Plugin name structure *MUST* be `PLUGIN_DIR/[].` * is an int in [1, 9]. If is found as the first char of the diff --git a/plugin.h b/plugin.h index ee9f52a..16585e8 100644 --- a/plugin.h +++ b/plugin.h @@ -164,14 +164,16 @@ typedef struct _plugin_type { #include "http.h" unsigned int proxenet_plugin_list_size(); +bool proxenet_is_plugin_loaded(char*); +int proxenet_get_plugin_type(char*); unsigned int count_plugins_by_type(supported_plugins_t); unsigned int count_initialized_plugins_by_type(supported_plugins_t); int proxenet_add_new_plugins(char*, char*); void proxenet_free_plugin(plugin_t*); void proxenet_free_all_plugins(); void proxenet_print_plugins_list(); -void proxenet_print_all_plugins(); plugin_t* proxenet_get_plugin_by_id(unsigned short); +int proxenet_get_plugin_type(char*); int proxenet_plugin_set_state(unsigned short, proxenet_state); int proxenet_plugin_set_prority(unsigned short, unsigned short); From 9a6b7c7ebf72f7198759968eace6993b9267dab6 Mon Sep 17 00:00:00 2001 From: hugsy Date: Wed, 27 May 2015 23:59:22 +1000 Subject: [PATCH 09/18] [control-web] plugin load and enable/disable work --- control-server.c | 19 ++++++------ control-web.py | 75 ++++++++++++++++++++++++++++++++++++++++-------- 2 files changed, 72 insertions(+), 22 deletions(-) diff --git a/control-server.c b/control-server.c index e8f41dc..c0514cf 100644 --- a/control-server.c +++ b/control-server.c @@ -89,6 +89,8 @@ static int plugin_cmd_list_json(sock_t fd, bool only_loaded) char msg[BUFSIZE] = {0, }; int n; + proxenet_write(fd, "{", 1); + for (p=plugins_list; p; p=p->next) { if (only_loaded && p->state!=INACTIVE) continue; @@ -112,6 +114,8 @@ static int plugin_cmd_list_json(sock_t fd, bool only_loaded) proxenet_write(fd, msg, n); } + proxenet_write(fd, "}", 1); + return 0; } @@ -170,10 +174,10 @@ void pause_cmd(sock_t fd, char *options, unsigned int nb_options) (void) nb_options; if (proxy_state==SLEEPING) { - msg = "sleep-mode -> 0\n"; + msg = "{\"sleep-mode\": 0}"; proxy_state = ACTIVE; } else { - msg = "sleep-mode -> 1\n"; + msg = "{\"sleep-mode\": 1}"; proxy_state = SLEEPING; } @@ -237,13 +241,8 @@ void info_cmd(sock_t fd, char *options, unsigned int nb_options) proxenet_write(fd, "}},", 3); /* plugins info */ - proxenet_write(fd, "\"Plugins\": {", 12); - if (proxenet_plugin_list_size()) { - plugin_cmd_list_json(fd, false); - } else { - proxenet_write(fd, "\"info\": \"No plugin loaded\"", 26); - } - proxenet_write(fd, "}", 1); + proxenet_write(fd, "\"Plugins\": ", 11); + plugin_cmd_list_json(fd, false); proxenet_write(fd, "}}", 2); return; @@ -597,7 +596,7 @@ void plugin_cmd(sock_t fd, char *options, unsigned int nb_options) goto invalid_plugin_action; if (strcmp(ptr, "list") == 0) { - plugin_cmd_list_json(fd, true); + plugin_cmd_list_json(fd, false); return; } if (strcmp(ptr, "list-all") == 0) { diff --git a/control-web.py b/control-web.py index 0c634d2..548b596 100755 --- a/control-web.py +++ b/control-web.py @@ -1,9 +1,9 @@ #!/usr/bin/env python2.7 import os, sys, socket, argparse -import json +import json, cgi,time try: - from bottle import request, route, get, post, run, static_file + from bottle import request, route, get, post, run, static_file, redirect except ImportError: sys.stderr.write("Missing package `bottle`\n") exit(1) @@ -126,13 +126,54 @@ def plugin(): html = """
    """ html += """

    {}

    """.format(title) html += """""" - html += "" + html += "" for k,v in js[title].iteritems(): _type, _is_loaded = v - html += "".format(k, _type, " Loaded" if _is_loaded else "") + html += "".format(k, _type) + if _is_loaded: + html += """""" + else: + html += """""".format(k) html += "
    NameType
    NameTypeStatus
    {}{}{}
    {}{}
    """ - return build_html(body=html, title="List all plugins available", page="plugin") + time.sleep(0.5) + res = sr("plugin list") + js = json.loads( res ) + html += """
    """ + html += """

    Plugins loaded

    """ + html += """""" + html += "" + for name in js.keys(): + p = js[name] + html += "".format(p['id'], name, p['priority'], p['state']) + if p['state']=="INACTIVE": + html += """""" + else: + html += """""" + html += "" + + html += """" + return build_html(body=html, title="Plugins detail", page="plugin") + + +@get('/plugin/load/') +def plugin_load(fname): + if not is_proxenet_running(): return build_html(body=not_running_html()) + res = sr("plugin load {}".format(fname)) + if "error" in res: + return build_html(body="""""".format(cgi.escape(fname))) + else: + return build_html(body="""""".format(cgi.escape(fname))) + + +@get('/plugin//') +def plugin_toggle(id,action): + if not is_proxenet_running(): return build_html(body=not_running_html()) + res = sr("plugin set {} toggle".format(id)) + if "error" in res: + return build_html(body="""""".format(id)) + else: + return build_html(body="""""".format(id)) @get('/threads') @@ -148,18 +189,28 @@ def threads(): html += """" html += """
    - - + +
    - - - -
    """ - +
    + + + + """ return build_html(body=html, title="Get information on Threads", page="threads") +@get('/threads/') +def threads_set(word): + if not is_proxenet_running(): return build_html(body=not_running_html()) + if word not in ("inc", "dec", "set"): + return "Error" + res = sr("threads {}".format(word)) + redirect("/threads") + return + + if __name__ == "__main__": parser = argparse.ArgumentParser(usage = __usage__, description = __desc__) From ce72a92f0b7e3b6c15dfd8ab94bc228df6e7190e Mon Sep 17 00:00:00 2001 From: hugsy Date: Thu, 28 May 2015 16:44:35 +1000 Subject: [PATCH 10/18] [control-server] formatting output to json --- control-server.c | 33 +++++++++++---------------------- 1 file changed, 11 insertions(+), 22 deletions(-) diff --git a/control-server.c b/control-server.c index c0514cf..4cd77b4 100644 --- a/control-server.c +++ b/control-server.c @@ -50,14 +50,14 @@ static struct command_t known_commands[] = { * * @param fd the socket to send data to */ -static void _send_threads_info(sock_t fd) +static void send_threads_list_as_json(sock_t fd) { char msg[BUFSIZE] = {0,}; int i, n; bool first_item = true; n = snprintf(msg, sizeof(msg), - "{\"Threads\":{" + "\"Threads\":{" "\"Max threads\": %d," "\"Running threads\": %d,", cfg->nb_threads, get_active_threads_size()); @@ -72,8 +72,6 @@ static void _send_threads_info(sock_t fd) n = snprintf(msg, sizeof(msg), "\"Thread-%d\": %lu", i, threads[i]); proxenet_write(fd, (void*)msg, n); } - proxenet_write(fd, "}", 1); - proxenet_write(fd, "}}", 2); return; } @@ -82,7 +80,7 @@ static void _send_threads_info(sock_t fd) /** * Enumerate all plugins loaded */ -static int plugin_cmd_list_json(sock_t fd, bool only_loaded) +static int send_plugin_list_as_json(sock_t fd, bool only_loaded) { plugin_t *p; bool first_iter=true; @@ -193,7 +191,7 @@ void pause_cmd(sock_t fd, char *options, unsigned int nb_options) void info_cmd(sock_t fd, char *options, unsigned int nb_options) { char msg[BUFSIZE] = {0, }; - int i, n; + int n; (void) options; (void) nb_options; @@ -226,23 +224,12 @@ void info_cmd(sock_t fd, char *options, unsigned int nb_options) proxenet_write(fd, (void*)msg, n); /* threads info */ - proxenet_write(fd, "\"Threads\": {", 12); - n = snprintf(msg, sizeof(msg), "\"Running/Max threads\": \"%d/%d\",", - get_active_threads_size(), cfg->nb_threads); - proxenet_write(fd, (void*)msg, n); - - proxenet_write(fd, "\"Details\": {", 12); - for (i=0; i < cfg->nb_threads; i++) { - if (!is_thread_active(i)) continue; - memset(msg, 0, sizeof(msg)); - n = snprintf(msg, sizeof(msg), "\"Thread-%d\": \"%lu\",", i, threads[i]); - proxenet_write(fd, (void*)msg, n); - } - proxenet_write(fd, "}},", 3); + send_threads_list_as_json(fd); + proxenet_write(fd, ",", 1); /* plugins info */ proxenet_write(fd, "\"Plugins\": ", 11); - plugin_cmd_list_json(fd, false); + send_plugin_list_as_json(fd, false); proxenet_write(fd, "}}", 2); return; @@ -340,7 +327,9 @@ void threads_cmd(sock_t fd, char *options, unsigned int nb_options) ptr = strtok(options, " \n"); if (!ptr){ - _send_threads_info(fd); + proxenet_write(fd, "{", 1); + send_threads_list_as_json(fd); + proxenet_write(fd, "}", 1); return; } @@ -596,7 +585,7 @@ void plugin_cmd(sock_t fd, char *options, unsigned int nb_options) goto invalid_plugin_action; if (strcmp(ptr, "list") == 0) { - plugin_cmd_list_json(fd, false); + send_plugin_list_as_json(fd, false); return; } if (strcmp(ptr, "list-all") == 0) { From 5eabe691b9c4739d12f792ca59bd63cf1f8cc618 Mon Sep 17 00:00:00 2001 From: hugsy Date: Thu, 28 May 2015 22:49:00 +1000 Subject: [PATCH 11/18] [control-server] moar formatting --- control-client.py | 12 ++- control-server.c | 220 ++++++++++++++++++++++++---------------------- control-web.py | 10 +++ docs/plugins/c.md | 17 ++-- 4 files changed, 137 insertions(+), 122 deletions(-) diff --git a/control-client.py b/control-client.py index 127940d..7cc257f 100755 --- a/control-client.py +++ b/control-client.py @@ -2,12 +2,7 @@ # -*- coding: utf-8 -*- # -*- mode: python -*- -import argparse -import socket -import datetime -import os -import rlcompleter -import readline +import argparse, socket, datetime, os, json, rlcompleter, readline __author__ = "hugsy" @@ -84,7 +79,10 @@ def recv_until(sock, pattern=">>> "): recv_until(cli) break - cmd = raw_input( recv_until(cli) ) + res = recv_until(cli) + data, prompt = res[:-4], res[-4:] + print data + cmd = raw_input( prompt ) cli.send(cmd.strip()+"\n") if cmd.strip() == "quit": do_loop = False diff --git a/control-server.c b/control-server.c index 4cd77b4..1f365f2 100644 --- a/control-server.c +++ b/control-server.c @@ -33,13 +33,11 @@ static struct command_t known_commands[] = { { "quit", 0, &quit_cmd, "Make "PROGNAME" leave kindly" }, { "help", 0, &help_cmd, "Show this menu" }, - { "pause", 0, &pause_cmd, "Toggle pause" }, { "info", 0, &info_cmd, "Display information about environment" }, - { "verbose", 1, &verbose_cmd, "Get/Set verbose level"}, { "reload", 0, &reload_cmd, "Reload the plugins" }, { "threads", 0, &threads_cmd, "Show info about threads" }, { "plugin", 1, &plugin_cmd, "Get/Set info about plugin"}, - { "config", 1, &config_cmd, "Edit configuration at runtime"}, + { "config", 1, &config_cmd, "Edit configuration at runtime"}, { NULL, 0, NULL, NULL} }; @@ -141,46 +139,20 @@ void quit_cmd(sock_t fd, char *options, unsigned int nb_options) void help_cmd(sock_t fd, char *options, unsigned int nb_options) { struct command_t *cmd; - char *msg; - unsigned int msglen = 20 + 80 + 3; + char msg[BUFSIZE]; + int n; (void) options; (void) nb_options; - msg = "Command list:\n"; - proxenet_write(fd, (void*)msg, strlen(msg)); - + proxenet_write(fd, "{\"Command list\":{", 17); for (cmd=known_commands; cmd && cmd->name; cmd++) { - msg = alloca(msglen+1); - proxenet_xzero(msg, msglen+1); - snprintf(msg, msglen+1, "%-15s\t%s\n", cmd->name, cmd->desc); - proxenet_write(fd, (void*)msg, strlen(msg)); - } - - return; -} - - -/** - * (De)-Activate pause mode (suspend and block interception) - */ -void pause_cmd(sock_t fd, char *options, unsigned int nb_options) -{ - char *msg; - - (void) options; - (void) nb_options; - - if (proxy_state==SLEEPING) { - msg = "{\"sleep-mode\": 0}"; - proxy_state = ACTIVE; - } else { - msg = "{\"sleep-mode\": 1}"; - proxy_state = SLEEPING; + proxenet_xzero(msg, sizeof(msg)); + n = snprintf(msg, sizeof(msg), "\"%s\": \"%s\",", cmd->name, cmd->desc); + proxenet_write(fd, msg, n); } + proxenet_write(fd, "\"\":\"\"}", 6); - xlog(LOG_INFO, "%s", msg); - proxenet_write(fd, (void*)msg, strlen(msg)); return; } @@ -236,43 +208,6 @@ void info_cmd(sock_t fd, char *options, unsigned int nb_options) } -/** - * Increase/Decrease verbosity of proxenet (useful for logging/debugging) - */ -void verbose_cmd(sock_t fd, char *options, unsigned int nb_options) -{ - char msg[BUFSIZE] = {0, }; - char *ptr; - int n, level; - - (void) options; - (void) nb_options; - - ptr = strtok(options, " \n"); - if (!ptr){ - n = snprintf(msg, BUFSIZE, "{\"verbose\": \"current level is %d\"}", - cfg->verbose); - proxenet_write(fd, (void*)msg, n); - return; - } - - if ( (level=atoi(ptr)) > 0 && levelverbose = level; - n = snprintf(msg, BUFSIZE, "{\"verbose\": \"level is set to %d\"}", - cfg->verbose); - } - else if (strcmp(ptr, "inc")==0 && cfg->verboseverbose); - else if (strcmp(ptr, "dec")==0 && cfg->verbose>0) - n = snprintf(msg, BUFSIZE, "{\"verbose\": \"level is now %d\"}", --cfg->verbose); - else - n = snprintf(msg, BUFSIZE, "{\"error\": \"Invalid action\"}"); - - proxenet_write(fd, (void*)msg, n); - - return; -} - /** * Reload proxenet @@ -352,25 +287,25 @@ void threads_cmd(sock_t fd, char *options, unsigned int nb_options) static int plugin_cmd_list_available(sock_t fd) { struct dirent *dir_ptr=NULL; - DIR *dir = NULL; - char* name = NULL; + DIR *dir = NULL; + char* name = NULL; char msg[2048] = {0, }; int n, type; bool first_iter = true; dir = opendir(cfg->plugins_path); - if (dir == NULL) { - xlog(LOG_ERROR, "Failed to open '%s': %s\n", cfg->plugins_path, strerror(errno)); + if (dir == NULL) { + xlog(LOG_ERROR, "Failed to open '%s': %s\n", cfg->plugins_path, strerror(errno)); n = snprintf(msg, sizeof(msg), "{\"Error\": \"Cannot open '%s': %s\"}", cfg->plugins_path, strerror(errno)); proxenet_write(fd, msg, n); - return -1; - } + return -1; + } n = snprintf(msg, sizeof(msg),"{\"Plugins available in %s\": {", cfg->plugins_path); proxenet_write(fd, msg, n); - while ((dir_ptr=readdir(dir))) { + while ((dir_ptr=readdir(dir))) { type = -1; name = dir_ptr->d_name; if (!strcmp(name,".") || !strcmp(name,"..")) @@ -637,14 +572,102 @@ void plugin_cmd(sock_t fd, char *options, unsigned int nb_options) } +/** + * Increase/Decrease verbosity of proxenet (useful for logging/debugging) + */ +static void config_verbose_cmd(sock_t fd, char *options) +{ + char msg[BUFSIZE] = {0, }; + char *ptr; + int n, level; + + ptr = strtok(options, " \n"); + if (!ptr){ + n = snprintf(msg, BUFSIZE, "{\"verbose\": \"current level is %d\"}", + cfg->verbose); + proxenet_write(fd, (void*)msg, n); + return; + } + + if ( (level=atoi(ptr)) > 0 && levelverbose = level; + n = snprintf(msg, BUFSIZE, "{\"verbose\": \"level is set to %d\"}", + cfg->verbose); + } + else if (strcmp(ptr, "inc")==0 && cfg->verboseverbose); + else if (strcmp(ptr, "dec")==0 && cfg->verbose>0) + n = snprintf(msg, BUFSIZE, "{\"verbose\": \"level is now %d\"}", --cfg->verbose); + else + n = snprintf(msg, BUFSIZE, "{\"error\": \"Invalid action\"}"); + + proxenet_write(fd, (void*)msg, n); + + return; +} + + +/** + * (De)-Activate pause mode (suspend and block interception) + */ +static void config_pause_cmd(sock_t fd, char *options) +{ + char *msg; + + (void) options; + + if (proxy_state==SLEEPING) { + msg = "{\"sleep-mode\": 0}"; + proxy_state = ACTIVE; + } else { + msg = "{\"sleep-mode\": 1}"; + proxy_state = SLEEPING; + } + + xlog(LOG_INFO, "%s\n", msg); + proxenet_write(fd, (void*)msg, strlen(msg)); + return; +} + + +/** + * (De)-Activate SSL interception mode + */ +static void config_ssl_intercept_cmd(sock_t fd, char* options) +{ + char *ptr; + + (void) options; + + /* shift argument */ + ptr = strtok(NULL, " \n"); + if (!ptr){ + xlog(LOG_ERROR, "%s\n", "Failed to get argument"); + return; + } + + if ( strcasecmp(ptr, "true") == 0){ + cfg->ssl_intercept = true; + if (cfg->verbose) + xlog(LOG_INFO, "%s\n", "[config] Enabled SSL intercept"); + proxenet_write(fd, "{\"SSL intercept\": \"enabled\"}", 28); + return; + } else if ( strcasecmp(ptr, "false") == 0){ + cfg->ssl_intercept = false; + if (cfg->verbose) + xlog(LOG_INFO, "%s\n", "[config] Disabled SSL intercept"); + proxenet_write(fd, "{\"SSL intercept\": \"disabled\"}", 29); + return; + } +} + + /** * Edit configuration */ void config_cmd(sock_t fd, char *options, unsigned int nb_options) { - char msg[BUFSIZE] = {0, }; char *ptr; - int n; (void) options; (void) nb_options; @@ -654,34 +677,17 @@ void config_cmd(sock_t fd, char *options, unsigned int nb_options) if (!ptr) goto invalid_config_action; - if (strcmp(ptr, "ssl-intercept") == 0) { - /* shift argument */ - ptr = strtok(NULL, " \n"); - if (!ptr){ - xlog(LOG_ERROR, "%s\n", "Failed to get argument"); - return; - } + if (strcmp(ptr, "ssl-intercept") == 0) + return config_ssl_intercept_cmd(fd, ptr); - if ( strcasecmp(ptr, "true") == 0){ - cfg->ssl_intercept = true; - if (cfg->verbose) - xlog(LOG_INFO, "%s\n", "[config] Enabled SSL intercept"); - proxenet_write(fd, "SSL intercept enabled\n", 22); - return; - } else if ( strcasecmp(ptr, "false") == 0){ - cfg->ssl_intercept = false; - if (cfg->verbose) - xlog(LOG_INFO, "%s\n", "[config] Disabled SSL intercept"); - proxenet_write(fd, "SSL intercept disabled\n", 23); - return; - } - } + if (strcmp(ptr, "pause") == 0) + return config_pause_cmd(fd, ptr); + + if (strcmp(ptr, "verbose") == 0) + return config_verbose_cmd(fd, ptr); invalid_config_action: - n = snprintf(msg, BUFSIZE, - "Invalid action.\nSyntax\n" - "config [ssl-intercept true|false]\n"); - proxenet_write(fd, (void*)msg, n); + proxenet_write(fd, "{\"error\": \"Invalid action.\"}", 28); return; } diff --git a/control-web.py b/control-web.py index 548b596..8955d2d 100755 --- a/control-web.py +++ b/control-web.py @@ -211,6 +211,16 @@ def threads_set(word): return +@route('/config') +def config(): + if not is_proxenet_running(): return build_html(body=not_running_html()) + html = """
    """ + html += """

    Configuration

    """ + html += """
      """ + html += "
    """ + return build_html(body=html, title="proxenet Configuration", page="config") + + if __name__ == "__main__": parser = argparse.ArgumentParser(usage = __usage__, description = __desc__) diff --git a/docs/plugins/c.md b/docs/plugins/c.md index 3a73467..98d51e8 100644 --- a/docs/plugins/c.md +++ b/docs/plugins/c.md @@ -49,7 +49,7 @@ demonstration. following command might just do the trick: ```bash -$ cc -Wall -Werror -fPIC -shared -o MyPlugin.o MyPlugin.c +$ cc -Wall -Werror -fPIC -shared -o MyPlugin.so MyPlugin.c ``` ## Example @@ -60,14 +60,15 @@ $ cc -Wall -Werror -fPIC -shared -o MyPlugin.o MyPlugin.c #include #include -struct info { - const char* AUTHOR; - const char* PLUGIN_NAME; -}; +typedef struct info { + const char* AUTHOR; + const char* PLUGIN_NAME; +} c_plugin_info_t; + -struct info AddHeader = { - .AUTHOR = "hugsy"; - .PLUGIN_NAME = "AddHeader"; +c_plugin_info_t MyPlugin = { + .AUTHOR = "hugsy", + .PLUGIN_NAME = "AddHeader" }; From 8f5eb5342fe730fbebe8b1af4cdc2f790e4f5f52 Mon Sep 17 00:00:00 2001 From: hugsy Date: Thu, 28 May 2015 22:50:31 +1000 Subject: [PATCH 12/18] [plugin-ruby] removed useless warning --- plugin-ruby.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/plugin-ruby.c b/plugin-ruby.c index e284162..a9200f7 100644 --- a/plugin-ruby.c +++ b/plugin-ruby.c @@ -177,7 +177,6 @@ int proxenet_ruby_initialize_function(plugin_t* plugin, req_t type) switch(type) { case REQUEST: if (plugin->pre_function) { - xlog(LOG_WARNING, "Pre-hook function already defined for '%s'\n", plugin->name); return 0; } @@ -192,7 +191,6 @@ int proxenet_ruby_initialize_function(plugin_t* plugin, req_t type) case RESPONSE: if (plugin->post_function) { - xlog(LOG_WARNING, "Post-hook function already defined for '%s'\n", plugin->name); return 0; } From 3139ecaf52bfbf6a22e3a16516f42890ebb571d7 Mon Sep 17 00:00:00 2001 From: hugsy Date: Sat, 30 May 2015 10:14:57 +1000 Subject: [PATCH 13/18] * fixed some params checking in FindPolarSSL * added docs for building proxenet on OSX & FreeBSD --- cmake/FindPolarSSL.cmake | 7 ++-- docs/compil.md | 78 ++++++++++++++++++++++++++++++---------- 2 files changed, 62 insertions(+), 23 deletions(-) diff --git a/cmake/FindPolarSSL.cmake b/cmake/FindPolarSSL.cmake index f452c50..a23b65d 100644 --- a/cmake/FindPolarSSL.cmake +++ b/cmake/FindPolarSSL.cmake @@ -24,11 +24,10 @@ if(NOT ${POLARSSL_LIBRARIES}) find_library(POLARSSL_LIBRARIES NAMES polarssl) endif() -find_package_handle_standard_args(POLARSSL REQUIRED_VARS - POLARSSL_INCLUDE_DIR POLARSSL_LIBRARIES) +find_package_handle_standard_args(POLARSSL REQUIRED_VARS POLARSSL_INCLUDE_DIR POLARSSL_LIBRARIES) -if(!POLARSSL_INCLUDE_DIR AND !POLARSSL_LIBRARIES) - message(FATAL_ERROR "Cannot find PolarSSL library") +if( ${POLARSSL_LIBRARIES-NOTFOUND} ) + message(FATAL_ERROR "Failed to get info from PolarSSL library, check your PolarSSL installation") set(POLARSSL_FOUND False) return() endif() diff --git a/docs/compil.md b/docs/compil.md index ffbd09d..62ea63d 100644 --- a/docs/compil.md +++ b/docs/compil.md @@ -2,6 +2,40 @@ ### Pre-requisites +`proxenet` requires: + +1. `cmake` as a building engine +2. `polarssl` for the SSL library + + +#### CMake + +##### Linux + +Most distributions will provide `cmake` with their main packaging system. + +If you don't have it, just run +```bash +$ apt-get install cmake # for Debian-based Linux +or +$ yum install cmake # for RedHat-based Linux +``` + +##### Mac OSX + +The best and easiest way to have `cmake` on OSX is through `brew`. +```bash +$ brew install cmake +``` + +##### FreeBSD + +From FreeBSD 10 and up, `cmake` is provided through `pkg` +```bash +$ pkg install cmake +``` + +#### PolarSSL `proxenet` requires a recent version of [PolarSSL library](https://polarssl.org/source-code), on version 1.3 and up. Support for version 1.2.x was definitively abandonned. @@ -10,46 +44,52 @@ The choice for PolarSSL as main SSL development library came because of its easy integration in multi-threaded environment, along with a simple (but yet thoroughly documented) API. -Installing PolarSSL library is pretty straight-forward. Here with an example with version 1.3.9: -``` bash -$ curl -fsSL https://github.com/polarssl/polarssl/archive/polarssl-1.3.9.tar.gz | tar xfz - -$ cd polarssl-1.3.9 -$ make && sudo make install -``` +##### Pre-compiled For most distro, a simple ```bash $ apt-get install libpolarssl-dev # for Debian-based Linux or $ yum install libpolarssl-devel # for RedHat-based Linux +or +$ brew install polarssl # for Mac OSX ``` will be enough. +*Note*: FreeBSD provides by default an old version of PolarSSL (1.2 + branch). This branch is not supported any more, so please install from source + as explained below. -### Compilation -In order to build `proxenet` you will need to have -[CMake](http://www.cmake.org). -If you don't have it, just run -```bash -$ apt-get install cmake # for Debian-based Linux -or -$ yum install cmake # for RedHat-based Linux +##### From source + +Installing PolarSSL library from source is pretty straight-forward. Here with an +example with version 1.3.9: +``` bash +$ curl -fsSL https://github.com/polarssl/polarssl/archive/polarssl-1.3.9.tar.gz | tar xfz - +$ cd mbedtls-polarssl-1.3.9 && cmake . && sudo make install ``` -Then, you can proceed with the compilation. + +### Compilation +In order to build `proxenet` make sure you have [CMake](http://www.cmake.org) +version 3.0+. + +You can proceed with the compilation like this: ```bash -~$ git clone https://github.com/hugsy/proxenet.git -~$ cd proxenet && cmake . && make +$ git clone https://github.com/hugsy/proxenet.git +$ cd proxenet && cmake . && make ``` `cmake` will generate the `Makefile` accordingly to your configuration and libraries availableon your system. If you want to explicity enable/disable scripting supports, use the option `-D` -when using `cmake`. For example, to disable C script support, simply type +when using `cmake`. For example, ```bash -~$ cmake -DUSE_C_PLUGIN=OFF . && make +$ cmake . -DUSE_C_PLUGIN=OFF && make # to disable C script support +or +$ cmake . -DUSE_PYTHON_PLUGIN=OFF && make # to disable Python script support ``` ### Setup the environment From c57271984222dc76025b0cd732bd77074fa0c39f Mon Sep 17 00:00:00 2001 From: hugsy Date: Sat, 30 May 2015 11:08:43 +1000 Subject: [PATCH 14/18] * [socket] added a max connect attempt * [http] fixed transparent (for @lanjelot) --- core.c | 5 +++-- http.c | 38 +++++++++++++++++++++++++++----------- socket.c | 21 ++++++++++++--------- socket.h | 1 + 4 files changed, 43 insertions(+), 22 deletions(-) diff --git a/core.c b/core.c index b2e14aa..9024f36 100644 --- a/core.c +++ b/core.c @@ -695,9 +695,10 @@ void proxenet_process_http_request(sock_t server_socket) retcode = update_http_infos(&req); } else { /* - * Some browsers send plain HTTP requests like this + * Format requests * GET http://foo/bar.blah HTTP/1.1 ... - * Format those kinds of requests stripping out proto & hostname + * into + * GET /bar.blah HTTP/1.1 ... */ retcode = format_http_request(&req.data, &req.size); } diff --git a/http.c b/http.c index 0d06434..773a5f2 100644 --- a/http.c +++ b/http.c @@ -192,33 +192,49 @@ static int get_hostname_from_header(request_t *req) /** * Modifies the HTTP request to strip out the protocol and hostname + * If successful, the request will be modified on output of this function as a + * valid HTTP request : + * METHOD /PATH HTTP/1.1[...] * * @return 0 if no error was encountered, -1 otherwise. */ int format_http_request(char** request, size_t* request_len) { size_t new_request_len = 0; - char *old_ptr, *new_ptr; + char *old_ptr, *new_ptr, *ptr; unsigned int i; int offlen; offlen = -1; old_ptr = new_ptr = NULL; - old_ptr = strstr(*request, HTTP_PROTO_STRING); - if (old_ptr) - offlen = 7; - else { - old_ptr = strstr(*request, HTTPS_PROTO_STRING); - if (old_ptr) - offlen = 8; - } - if (offlen < 0) { + /* Move to beginning of URL */ + for(ptr=*request; ptr && *ptr!=' ' && *ptr!='\x00'; ptr++); + + if(*ptr!=' '){ + xlog(LOG_ERROR, "%s\n", "HTTP request has incorrect format"); + return -1; + } + + ++ptr; + if(*ptr=='/'){ + /* this indicates that the request is well formed already */ + /* this case would happen only when using in transparent mode */ + return 0; + } + + if( strncmp(ptr, HTTP_PROTO_STRING, sizeof(HTTP_PROTO_STRING)-1)==0 ){ + offlen = sizeof(HTTP_PROTO_STRING)-1; // -1 because of \x00 added by sizeof + } else if( strncmp(ptr, HTTPS_PROTO_STRING, sizeof(HTTP_PROTO_STRING)-1)==0 ){ + offlen = sizeof(HTTPS_PROTO_STRING)-1; + } else { xlog(LOG_ERROR, "Cannot find protocol (%s|%s) in request:\n%s\n", HTTP_STRING, HTTPS_STRING, *request); return -1; } + /* here offlen > 0 */ + old_ptr = ptr; new_ptr = strchr(old_ptr + offlen, '/'); if (!new_ptr) { xlog(LOG_ERROR, "%s\n", "Cannot find path (must not be implicit)"); @@ -475,7 +491,7 @@ int create_http_socket(request_t* req, sock_t* server_sock, sock_t* client_sock, } #ifdef DEBUG - xlog(LOG_DEBUG, "Socket to %s '%s:%s' : %d\n", + xlog(LOG_DEBUG, "Socket to %s '%s:%s': fd=%d\n", use_proxy?"proxy":"server", host, port, retcode); diff --git a/socket.c b/socket.c index 377ff92..be91356 100644 --- a/socket.c +++ b/socket.c @@ -121,6 +121,7 @@ sock_t create_connect_socket(char *host, char* port) sock_t sock; struct addrinfo hostinfo, *res, *ll; int retcode, keepalive_val; + unsigned short num_attempt = 0; sock = -1; memset(&hostinfo, 0, sizeof(struct addrinfo)); @@ -147,9 +148,8 @@ sock_t create_connect_socket(char *host, char* port) if (sock == -1) continue; /* setting socket as keep-alive */ - keepalive_val = 1; - retcode = setsockopt(sock, SOL_SOCKET, SO_KEEPALIVE, - &keepalive_val, sizeof(keepalive_val)); + keepalive_val = true; + retcode = setsockopt(sock, SOL_SOCKET, SO_KEEPALIVE, &keepalive_val, sizeof(keepalive_val)); if (retcode < 0){ xlog(LOG_ERROR, "setsockopt(SO_KEEPALIVE) failed: %s\n", strerror(retcode)); @@ -157,8 +157,7 @@ sock_t create_connect_socket(char *host, char* port) } /* setting receive timeout */ - retcode = setsockopt(sock, SOL_SOCKET, SO_RCVTIMEO, - &timeout, sizeof(timeout)); + retcode = setsockopt(sock, SOL_SOCKET, SO_RCVTIMEO, &timeout, sizeof(timeout)); if (retcode < 0){ xlog(LOG_ERROR, "setsockopt(SO_RCVTIMEO) failed: %s\n", strerror(retcode)); @@ -166,8 +165,7 @@ sock_t create_connect_socket(char *host, char* port) } /* setting sending timeout */ - retcode = setsockopt(sock, SOL_SOCKET, SO_SNDTIMEO, - &timeout, sizeof(timeout)); + retcode = setsockopt(sock, SOL_SOCKET, SO_SNDTIMEO, &timeout, sizeof(timeout)); if (retcode < 0){ xlog(LOG_ERROR, "setsockopt(SO_SNDTIMEO) failed: %s\n", strerror(retcode)); @@ -181,8 +179,13 @@ sock_t create_connect_socket(char *host, char* port) host, port, sock); break; } else { - xlog(LOG_ERROR, "connect to '%s:%s' failed: %s\n", - host, port, strerror(errno)); + num_attempt++; + xlog(LOG_ERROR, "connect to '%s:%s' failed (%d/%d): %s\n", + host, port, num_attempt, MAX_CONNECT_ATTEMPT, strerror(errno)); + if(num_attempt==MAX_CONNECT_ATTEMPT){ + sock = -1; + break; + } } close(sock); diff --git a/socket.h b/socket.h index af23dfb..2ec5615 100644 --- a/socket.h +++ b/socket.h @@ -5,6 +5,7 @@ typedef int sock_t; #define MAX_CONN_SIZE 10 #define MAX_READ_SIZE 4095 +#define MAX_CONNECT_ATTEMPT 5 #define ECONNREFUSED_MSG "Server refused connection (closed port?)" #define EHOSTUNREACH_MSG "Server is not reachable" From 86caf22cd57903bb5e41604040e2e7ecc8b2ff09 Mon Sep 17 00:00:00 2001 From: hugsy Date: Sat, 30 May 2015 11:40:29 +1000 Subject: [PATCH 15/18] * [http] added pretty html for error page --- .travis.yml | 2 +- http.c | 230 ++++++++++++++++++++++++++-------------------------- 2 files changed, 118 insertions(+), 114 deletions(-) diff --git a/.travis.yml b/.travis.yml index fc0ccec..1e54845 100644 --- a/.travis.yml +++ b/.travis.yml @@ -9,7 +9,7 @@ before_script: - sudo apt-get install -qq cmake python python-dev liblua5.2-dev ruby ruby-dev libperl-dev tcl-dev default-jdk - curl --silent https://codeload.github.com/ARMmbed/mbedtls/tar.gz/polarssl-1.3.9 | tar xfz - && cd mbedtls-polarssl-1.3.9 && make SHARED=1 && sudo make install DESTDIR=/usr && cd .. -script: cmake . -DDEBUG=on && make +script: cmake . -DDEBUG=on && make && make clean && cmake . -DDEBUG=off && make after_script: ./proxenet --help diff --git a/http.c b/http.c index 773a5f2..2bd17cd 100644 --- a/http.c +++ b/http.c @@ -27,23 +27,27 @@ */ void generic_http_error_page(sock_t sock, char* msg) { - char* html_header = "

    proxenet error page


    "; - char* html_footer = ""; - - if (write(sock, html_header, strlen(html_header)) < 0) { - xlog(LOG_ERROR, "Failed to write error HTML header: %s\n", strerror(errno)); + const char* html_header = "" + ""PROGNAME": ERROR!" + "

    Error

    " + PROGNAME" encountered an error when loading your page

    " + "The following message was returned:

    "; + const char* html_footer = "
    "; + + if (write(sock, html_header, strlen(html_header)) < 0) { + xlog(LOG_ERROR, "Failed to write error HTML header: %s\n", strerror(errno)); return; - } + } - if(write(sock, msg, strlen(msg)) < 0){ - xlog(LOG_ERROR, "Failed to write error HTML page: %s\n", strerror(errno)); + if(write(sock, msg, strlen(msg)) < 0){ + xlog(LOG_ERROR, "Failed to write error HTML page: %s\n", strerror(errno)); return; - } + } - if(write(sock, html_footer, strlen(html_footer)) < 0){ - xlog(LOG_ERROR, "Failed to write error HTML footer: %s\n", strerror(errno)); + if(write(sock, html_footer, strlen(html_footer)) < 0){ + xlog(LOG_ERROR, "Failed to write error HTML footer: %s\n", strerror(errno)); return; - } + } return; } @@ -54,24 +58,24 @@ void generic_http_error_page(sock_t sock, char* msg) */ static char* get_request_full_uri(request_t* req) { - char* uri; - http_request_t* http_infos = &req->http_infos; - size_t len; + char* uri; + http_request_t* http_infos = &req->http_infos; + size_t len; - if (!req || !http_infos) + if (!req || !http_infos) return NULL; - len = sizeof(HTTPS_PROTO_STRING) + strlen(http_infos->hostname) + sizeof(":") + sizeof("65535"); - len+= strlen(http_infos->path); - uri = (char*)proxenet_xmalloc(len+1); + len = sizeof(HTTPS_PROTO_STRING) + strlen(http_infos->hostname) + sizeof(":") + sizeof("65535"); + len+= strlen(http_infos->path); + uri = (char*)proxenet_xmalloc(len+1); - snprintf(uri, len, "%s%s:%d%s", - req->is_ssl?HTTPS_PROTO_STRING:HTTP_PROTO_STRING, - http_infos->hostname, - http_infos->port, - http_infos->path); + snprintf(uri, len, "%s%s:%d%s", + req->is_ssl?HTTPS_PROTO_STRING:HTTP_PROTO_STRING, + http_infos->hostname, + http_infos->port, + http_infos->path); - return uri; + return uri; } @@ -94,20 +98,20 @@ static int get_hostname_from_uri(request_t* req, int offset) buf = req->data + offset; /* isolate the whole block 'IP:PORT' */ - ptr = strchr(buf, ' '); - if (!ptr){ + ptr = strchr(buf, ' '); + if (!ptr){ xlog(LOG_ERROR, "%s\n", "Invalid URI block"); return -1; } c = *ptr; - *ptr = '\0'; + *ptr = '\0'; buf = proxenet_xstrdup2(buf); /* host and port */ ptr = strchr(buf, ':'); - if (ptr){ + if (ptr){ /* explicit port */ req->http_infos.port = (unsigned short)atoi(ptr+1); *ptr = '\0'; @@ -115,7 +119,7 @@ static int get_hostname_from_uri(request_t* req, int offset) req->http_infos.hostname = proxenet_xstrdup2(buf); - *ptr = c; + *ptr = c; proxenet_xfree(buf); return 0; @@ -151,7 +155,7 @@ static char* get_header_by_name(char* request, const char* header_name) *ptr2 = '\0'; /* copy the value */ - header_value = proxenet_xstrdup2(ptr); + header_value = proxenet_xstrdup2(ptr); if (!header_value){ xlog(LOG_ERROR, "strdup(header '%s') failed.\n", header_name); return NULL; @@ -169,7 +173,7 @@ static int get_hostname_from_header(request_t *req) { char *ptr, *header; - header = get_header_by_name(req->data, "Host: "); + header = get_header_by_name(req->data, "Host: "); if (!header){ return -1; } @@ -200,13 +204,13 @@ static int get_hostname_from_header(request_t *req) */ int format_http_request(char** request, size_t* request_len) { - size_t new_request_len = 0; - char *old_ptr, *new_ptr, *ptr; - unsigned int i; - int offlen; + size_t new_request_len = 0; + char *old_ptr, *new_ptr, *ptr; + unsigned int i; + int offlen; offlen = -1; - old_ptr = new_ptr = NULL; + old_ptr = new_ptr = NULL; /* Move to beginning of URL */ for(ptr=*request; ptr && *ptr!=' ' && *ptr!='\x00'; ptr++); @@ -223,38 +227,38 @@ int format_http_request(char** request, size_t* request_len) return 0; } - if( strncmp(ptr, HTTP_PROTO_STRING, sizeof(HTTP_PROTO_STRING)-1)==0 ){ - offlen = sizeof(HTTP_PROTO_STRING)-1; // -1 because of \x00 added by sizeof + if( strncmp(ptr, HTTP_PROTO_STRING, sizeof(HTTP_PROTO_STRING)-1)==0 ){ + offlen = sizeof(HTTP_PROTO_STRING)-1; // -1 because of \x00 added by sizeof } else if( strncmp(ptr, HTTPS_PROTO_STRING, sizeof(HTTP_PROTO_STRING)-1)==0 ){ offlen = sizeof(HTTPS_PROTO_STRING)-1; - } else { - xlog(LOG_ERROR, "Cannot find protocol (%s|%s) in request:\n%s\n", + } else { + xlog(LOG_ERROR, "Cannot find protocol (%s|%s) in request:\n%s\n", HTTP_STRING, HTTPS_STRING, *request); - return -1; - } + return -1; + } /* here offlen > 0 */ old_ptr = ptr; - new_ptr = strchr(old_ptr + offlen, '/'); - if (!new_ptr) { - xlog(LOG_ERROR, "%s\n", "Cannot find path (must not be implicit)"); - return -1; - } + new_ptr = strchr(old_ptr + offlen, '/'); + if (!new_ptr) { + xlog(LOG_ERROR, "%s\n", "Cannot find path (must not be implicit)"); + return -1; + } - new_request_len = *request_len - (new_ptr-old_ptr); + new_request_len = *request_len - (new_ptr-old_ptr); #ifdef DEBUG - xlog(LOG_DEBUG, "Formatting HTTP request (%dB->%dB)\n", *request_len, new_request_len); + xlog(LOG_DEBUG, "Formatting HTTP request (%dB->%dB)\n", *request_len, new_request_len); #endif - for (i=0; idata; + buf = req->data; - /* method */ - ptr = strchr(buf, ' '); - if (!ptr){ + /* method */ + ptr = strchr(buf, ' '); + if (!ptr){ xlog(LOG_ERROR, "%s\n", "Cannot find HTTP method in request"); if (cfg->verbose) xlog(LOG_ERROR, "Buffer sent:\n%s\n", buf); return -1; } - c = *ptr; - *ptr = '\0'; - req->http_infos.method = proxenet_xstrdup2(buf); + c = *ptr; + *ptr = '\0'; + req->http_infos.method = proxenet_xstrdup2(buf); if (!req->http_infos.method){ xlog(LOG_ERROR, "%s\n", "strdup(method) failed, cannot pursue..."); return -1; } - *ptr = c; + *ptr = c; if (!strcmp(req->http_infos.method, "CONNECT")){ int offset; @@ -330,46 +334,46 @@ int update_http_infos(request_t *req) } - /* path */ + /* path */ buf = ptr+1; if (!strncmp(buf, HTTP_PROTO_STRING, strlen(HTTP_PROTO_STRING))){ buf = strchr(buf + 8, '/'); } - ptr = strchr(buf, ' '); - if (!ptr){ + ptr = strchr(buf, ' '); + if (!ptr){ xlog(LOG_ERROR, "%s\n", "Cannot find HTTP path in request"); goto failed_path; } - c = *ptr; - *ptr = '\0'; - req->http_infos.path = proxenet_xstrdup2(buf); + c = *ptr; + *ptr = '\0'; + req->http_infos.path = proxenet_xstrdup2(buf); if (!req->http_infos.path){ xlog(LOG_ERROR, "%s\n", "strdup(path) failed, cannot pursue..."); goto failed_path; } - *ptr = c; + *ptr = c; - buf = ptr+1; + buf = ptr+1; - /* version */ - ptr = strchr(req->data, '\r'); - if (!ptr){ + /* version */ + ptr = strchr(req->data, '\r'); + if (!ptr){ xlog(LOG_ERROR, "%s\n", "Cannot find HTTP version"); goto failed_version; } - c = *ptr; - *ptr = '\0'; - req->http_infos.version = proxenet_xstrdup2(buf); + c = *ptr; + *ptr = '\0'; + req->http_infos.version = proxenet_xstrdup2(buf); if (!req->http_infos.version){ xlog(LOG_ERROR, "%s\n", "strdup(version) failed, cannot pursue..."); goto failed_version; } - *ptr = c; + *ptr = c; /* refresh uri */ @@ -448,28 +452,28 @@ void free_http_infos(http_request_t *hi) */ int create_http_socket(request_t* req, sock_t* server_sock, sock_t* client_sock, ssl_context_t* ssl_ctx) { - int retcode; - char *host, *port; - char sport[6] = {0, }; - http_request_t* http_infos = &req->http_infos; - bool use_proxy = (cfg->proxy.host != NULL) ; + int retcode; + char *host, *port; + char sport[6] = {0, }; + http_request_t* http_infos = &req->http_infos; + bool use_proxy = (cfg->proxy.host != NULL) ; if (update_http_infos(req) < 0){ xlog(LOG_ERROR, "%s\n", "Failed to extract valid parameters from URL."); - return -1; - } + return -1; + } - ssl_ctx->use_ssl = req->is_ssl; - snprintf(sport, 5, "%u", http_infos->port); + ssl_ctx->use_ssl = req->is_ssl; + snprintf(sport, 5, "%u", http_infos->port); - /* do we forward to another proxy ? */ - if (use_proxy) { - host = cfg->proxy.host; - port = cfg->proxy.port; - } else { - host = http_infos->hostname; - port = sport; - } + /* do we forward to another proxy ? */ + if (use_proxy) { + host = cfg->proxy.host; + port = cfg->proxy.port; + } else { + host = http_infos->hostname; + port = sport; + } #ifdef DEBUG @@ -478,8 +482,8 @@ int create_http_socket(request_t* req, sock_t* server_sock, sock_t* client_sock, host, port); #endif - retcode = create_connect_socket(host, port); - if (retcode < 0) { + retcode = create_connect_socket(host, port); + if (retcode < 0) { char msg[512]={0,}; snprintf(msg, sizeof(msg), "Cannot connect to %s:%s

    Reason: %s", @@ -487,8 +491,8 @@ int create_http_socket(request_t* req, sock_t* server_sock, sock_t* client_sock, errno?strerror(errno):"Unknown error in create_connect_socket"); generic_http_error_page(*server_sock, msg); - return -1; - } + return -1; + } #ifdef DEBUG xlog(LOG_DEBUG, "Socket to %s '%s:%s': fd=%d\n", @@ -596,23 +600,23 @@ int create_http_socket(request_t* req, sock_t* server_sock, sock_t* client_sock, } - return retcode; + return retcode; } /** - ***************************************************************************************** - * EXPERIMENTAL - * PARTIALLY TESTED - ***************************************************************************************** - * - * - * Add old IE support (Compatibility View) for POST requests by forcing a 2nd read on the - * server socket, to make IE send the POST body. - * DO NOT use this mode if you are using anything but IE < 10 - * - * @return 0 if successful, -1 otherwise - */ +***************************************************************************************** +* EXPERIMENTAL +* PARTIALLY TESTED +***************************************************************************************** +* +* +* Add old IE support (Compatibility View) for POST requests by forcing a 2nd read on the +* server socket, to make IE send the POST body. +* DO NOT use this mode if you are using anything but IE < 10 +* +* @return 0 if successful, -1 otherwise +*/ int ie_compat_read_post_body(sock_t sock, request_t* req, proxenet_ssl_context_t* sslctx) { int nb; From 76c25a4efb3ea4b84183a698e051a215ebd23db3 Mon Sep 17 00:00:00 2001 From: hugsy Date: Sat, 30 May 2015 14:06:11 +1000 Subject: [PATCH 16/18] [control-server] finished migrating output to json --- control-server.c | 87 ++++++++++++++++++++++-------------------------- control-server.h | 12 +------ 2 files changed, 41 insertions(+), 58 deletions(-) diff --git a/control-server.c b/control-server.c index 1f365f2..5704863 100644 --- a/control-server.c +++ b/control-server.c @@ -27,8 +27,15 @@ #include "utils.h" #include "plugin.h" -#define BUFSIZE 2048 +#define BUFSIZE 4096 +static void quit_cmd(sock_t fd, char *options, unsigned int nb_options); +static void help_cmd(sock_t fd, char *options, unsigned int nb_options); +static void info_cmd(sock_t fd, char *options, unsigned int nb_options); +static void reload_cmd(sock_t fd, char *options, unsigned int nb_options); +static void threads_cmd(sock_t fd, char *options, unsigned int nb_options); +static void plugin_cmd(sock_t fd, char *options, unsigned int nb_options); +static void config_cmd(sock_t fd, char *options, unsigned int nb_options); static struct command_t known_commands[] = { { "quit", 0, &quit_cmd, "Make "PROGNAME" leave kindly" }, @@ -37,7 +44,7 @@ static struct command_t known_commands[] = { { "reload", 0, &reload_cmd, "Reload the plugins" }, { "threads", 0, &threads_cmd, "Show info about threads" }, { "plugin", 1, &plugin_cmd, "Get/Set info about plugin"}, - { "config", 1, &config_cmd, "Edit configuration at runtime"}, + { "config", 1, &config_cmd, "Edit configuration at runtime"}, { NULL, 0, NULL, NULL} }; @@ -119,7 +126,7 @@ static int send_plugin_list_as_json(sock_t fd, bool only_loaded) /** * This command will try to kill gracefully the running process of proxenet */ -void quit_cmd(sock_t fd, char *options, unsigned int nb_options) +static void quit_cmd(sock_t fd, char *options, unsigned int nb_options) { char *msg = "Leaving gracefully\n"; @@ -136,7 +143,7 @@ void quit_cmd(sock_t fd, char *options, unsigned int nb_options) /** * The famous help menu */ -void help_cmd(sock_t fd, char *options, unsigned int nb_options) +static void help_cmd(sock_t fd, char *options, unsigned int nb_options) { struct command_t *cmd; char msg[BUFSIZE]; @@ -160,7 +167,7 @@ void help_cmd(sock_t fd, char *options, unsigned int nb_options) /** * Get information about proxenet state. */ -void info_cmd(sock_t fd, char *options, unsigned int nb_options) +static void info_cmd(sock_t fd, char *options, unsigned int nb_options) { char msg[BUFSIZE] = {0, }; int n; @@ -208,11 +215,10 @@ void info_cmd(sock_t fd, char *options, unsigned int nb_options) } - /** * Reload proxenet */ -void reload_cmd(sock_t fd, char *options, unsigned int nb_options) +static void reload_cmd(sock_t fd, char *options, unsigned int nb_options) { char *msg; @@ -220,7 +226,7 @@ void reload_cmd(sock_t fd, char *options, unsigned int nb_options) (void) nb_options; if (get_active_threads_size() > 0) { - msg = "Threads still active, cannot reload\n"; + msg = "{\"error\": \"Threads still active, cannot reload\"}"; proxenet_write(fd, (void*)msg, strlen(msg)); return; } @@ -231,7 +237,7 @@ void reload_cmd(sock_t fd, char *options, unsigned int nb_options) proxenet_free_all_plugins(); if( proxenet_initialize_plugins_list() < 0) { - msg = "Failed to reinitilize plugins\n"; + msg = "{\"error\": \"Failed to reinitilize plugins\"}"; proxenet_write(fd, (void*)msg, strlen(msg)); proxy_state = INACTIVE; return; @@ -241,7 +247,7 @@ void reload_cmd(sock_t fd, char *options, unsigned int nb_options) proxy_state = ACTIVE; - msg = "Plugins list successfully reloaded\n"; + msg = "{\"success\": \"Plugins list successfully reloaded\"}"; proxenet_write(fd, (void*)msg, strlen(msg)); return; @@ -251,7 +257,7 @@ void reload_cmd(sock_t fd, char *options, unsigned int nb_options) /** * Get information about the threads */ -void threads_cmd(sock_t fd, char *options, unsigned int nb_options) +static void threads_cmd(sock_t fd, char *options, unsigned int nb_options) { char msg[BUFSIZE] = {0, }; char *ptr; @@ -302,18 +308,15 @@ static int plugin_cmd_list_available(sock_t fd) return -1; } - n = snprintf(msg, sizeof(msg),"{\"Plugins available in %s\": {", - cfg->plugins_path); + n = snprintf(msg, sizeof(msg),"{\"Plugins available in '%s'\": {", cfg->plugins_path); proxenet_write(fd, msg, n); while ((dir_ptr=readdir(dir))) { type = -1; name = dir_ptr->d_name; - if (!strcmp(name,".") || !strcmp(name,"..")) - continue; + if (!strcmp(name,".") || !strcmp(name,"..")) continue; type = proxenet_get_plugin_type(name); - if (type < 0) - continue; + if (type < 0) continue; /* this is only to avoid breaking json syntax */ if (!first_iter) @@ -354,15 +357,14 @@ static int plugin_cmd_set(sock_t fd, char *options) unsigned int plugin_id; plugin_id = (unsigned int)atoi(options); - if (plugin_id > proxenet_plugin_list_size()) { - n = sprintf(msg, "Invalid plugin id\n"); - proxenet_write(fd, (void*)msg, n); + if ( proxenet_get_plugin_by_id( plugin_id )==NULL ) { + proxenet_write(fd, "{\"error\": \"Invalid plugin id\"}", 30); return -1; } ptr = strtok(NULL, " \n"); if(!ptr){ - n = snprintf(msg, BUFSIZE, "Invalid set command syntax: plugin set %d \n", plugin_id); + n = snprintf(msg, BUFSIZE, "{\"error\": \"Invalid syntax: plugin set %d \"}", plugin_id); proxenet_write(fd, (void*)msg, n); return -1; } @@ -370,12 +372,12 @@ static int plugin_cmd_set(sock_t fd, char *options) if (!strcmp(ptr, "toggle")){ ret = proxenet_toggle_plugin(plugin_id); if (ret < 0){ - n = snprintf(msg, BUFSIZE, "Failed to toggle plugin %d\n", plugin_id); + n = snprintf(msg, BUFSIZE, "{\"error\": \"Failed to toggle plugin %d\"}", plugin_id); proxenet_write(fd, (void*)msg, n); return -1; } - n = snprintf(msg, BUFSIZE, "Plugin %d is now %sACTIVE\n", plugin_id, ret?"":"IN"); + n = snprintf(msg, BUFSIZE, "{\"success\": \"Plugin %d is now %sACTIVE\"}", plugin_id, ret?"":"IN"); proxenet_write(fd, (void*)msg, n); return 0; } @@ -384,7 +386,7 @@ static int plugin_cmd_set(sock_t fd, char *options) ptr = strtok(NULL, " \n"); if(!ptr){ n = snprintf(msg, BUFSIZE, - "Missing priority argument: plugin set %d prority \n", + "{\"error\": \"Invalid syntax: plugin set %d prority \"}", plugin_id); proxenet_write(fd, (void*)msg, n); return -1; @@ -392,24 +394,24 @@ static int plugin_cmd_set(sock_t fd, char *options) n = atoi(ptr); if (n==0){ - proxenet_write(fd, (void*)"Invalid priority\n", 17); + proxenet_write(fd, "{\"error\": \"Invalid priority\"}", 29); return -1; } if (proxenet_plugin_set_prority(plugin_id, n) < 0){ n = snprintf(msg, BUFSIZE, - "An error occured during priority update for plugin %d\n", + "{\"error\": \"An error occured during priority update for plugin %d\"}", plugin_id); proxenet_write(fd, (void*)msg, n); return -1; } - n = snprintf(msg, BUFSIZE, "Plugin %d priority is now %d\n", plugin_id, n); + n = snprintf(msg, BUFSIZE, "{\"success\": \"Plugin %d priority is now %d\"}", plugin_id, n); proxenet_write(fd, (void*)msg, n); return 0; } - n = snprintf(msg, BUFSIZE, "Unknown action '%s' for plugin %d\n", ptr, plugin_id); + n = snprintf(msg, BUFSIZE, "{\"error\": \"Unknown action '%s' for plugin %d\"}", ptr, plugin_id); proxenet_write(fd, (void*)msg, n); return -1; @@ -429,7 +431,7 @@ static int plugin_cmd_load(sock_t fd, char *options) ptr = strtok(options, " \n"); if (!ptr){ - proxenet_write(fd, (void*)"Missing plugin name\n", 20); + proxenet_write(fd, "{\"error\": \"Missing plugin name\"}", 32); return -1; } @@ -438,27 +440,22 @@ static int plugin_cmd_load(sock_t fd, char *options) proxenet_xzero(plugin_name, l+1); memcpy(plugin_name, ptr, l); - if ( plugin_name==NULL ){ - n = sprintf(msg, "proxenet_xstrdup2() failed: %s\n", strerror(errno)); - proxenet_write(fd, (void*)msg, n); - return -1; - } - ret = proxenet_add_new_plugins(cfg->plugins_path, plugin_name); if(ret<0){ - n = snprintf(msg, sizeof(msg)-1, "Error while loading plugin '%s'\n", plugin_name); + n = snprintf(msg, sizeof(msg)-1, "{\"error\": \"Error while loading plugin '%s'\"}", plugin_name); proxenet_write(fd, (void*)msg, n); return -1; } if(ret) - n = snprintf(msg, sizeof(msg)-1, "Plugin '%s' added successfully\n", plugin_name); + n = snprintf(msg, sizeof(msg)-1, "{\"success\": \"Plugin '%s' added successfully\"}", plugin_name); else - n = snprintf(msg, sizeof(msg)-1, "File '%s' has not been added\n", plugin_name); + n = snprintf(msg, sizeof(msg)-1, "{\"error\": \"File '%s' has not been added\"}", plugin_name); proxenet_write(fd, (void*)msg, n); /* plugin list must be reinitialized since we dynamically load VMs only if plugins are found */ - proxenet_initialize_plugins(); + if(ret) + proxenet_initialize_plugins(); return 0; } @@ -504,11 +501,10 @@ static int plugin_cmd_change_all_status(proxenet_state new_state) /** * Handle plugins (list/activate/deactivate/load) */ -void plugin_cmd(sock_t fd, char *options, unsigned int nb_options) +static void plugin_cmd(sock_t fd, char *options, unsigned int nb_options) { - char msg[BUFSIZE] = {0, }; char *ptr; - int n, res; + int res; (void) options; (void) nb_options; @@ -564,10 +560,7 @@ void plugin_cmd(sock_t fd, char *options, unsigned int nb_options) invalid_plugin_action: - n = snprintf(msg, BUFSIZE, - "Invalid action.\nSyntax\n" - "plugin [list][list-all][enable-all][disable-all][set toggle][load <0PluginName.ext>]\n"); - proxenet_write(fd, (void*)msg, n); + proxenet_write(fd, "{\"error\": \"Invalid action\"}", 27); return; } @@ -665,7 +658,7 @@ static void config_ssl_intercept_cmd(sock_t fd, char* options) /** * Edit configuration */ -void config_cmd(sock_t fd, char *options, unsigned int nb_options) +static void config_cmd(sock_t fd, char *options, unsigned int nb_options) { char *ptr; diff --git a/control-server.h b/control-server.h index ff318ff..43049d0 100644 --- a/control-server.h +++ b/control-server.h @@ -9,7 +9,7 @@ #define CONTROL_SOCK_PATH "/tmp/proxenet-control-socket" #define CONTROL_MOTD "Welcome on "PROGNAME" control interface\nType `help` to list available commands\n" #define CONTROL_PROMPT ">>> " -#define CONTROL_INVALID "Invalid command\n" +#define CONTROL_INVALID "{\"error\": \"Invalid command\"}" struct command_t { char *name; @@ -18,16 +18,6 @@ struct command_t { const char *desc; }; -void quit_cmd(sock_t fd, char *options, unsigned int nb_options); -void help_cmd(sock_t fd, char *options, unsigned int nb_options); -void pause_cmd(sock_t fd, char *options, unsigned int nb_options); -void info_cmd(sock_t fd, char *options, unsigned int nb_options); -void verbose_cmd(sock_t fd, char *options, unsigned int nb_options); -void reload_cmd(sock_t fd, char *options, unsigned int nb_options); -void threads_cmd(sock_t fd, char *options, unsigned int nb_options); -void plugin_cmd(sock_t fd, char *options, unsigned int nb_options); -void config_cmd(sock_t fd, char *options, unsigned int nb_options); - int proxenet_handle_control_event(sock_t*); #endif /* _CONTROL_SERVER_H */ From 2b602297880dde49c0bf0c09036bcff5dc2abbe6 Mon Sep 17 00:00:00 2001 From: hugsy Date: Sat, 30 May 2015 17:34:25 +1000 Subject: [PATCH 17/18] [control-server] added config mode for the web server --- control-server.c | 173 +++++++++++++++++++++++------------------------ control-web.py | 24 +++++-- 2 files changed, 104 insertions(+), 93 deletions(-) diff --git a/control-server.c b/control-server.c index 5704863..6d4ffc7 100644 --- a/control-server.c +++ b/control-server.c @@ -29,6 +29,9 @@ #define BUFSIZE 4096 +#define ERR_INVALID_SYNTAX_JSON(x) { proxenet_write(x, "{\"error\": \"Invalid syntax\"}", 27); } +#define ERR_MISSING_ARGUMENT_JSON(x) { proxenet_write(x, "{\"error\": \"Missing argument\"}", 29); } + static void quit_cmd(sock_t fd, char *options, unsigned int nb_options); static void help_cmd(sock_t fd, char *options, unsigned int nb_options); static void info_cmd(sock_t fd, char *options, unsigned int nb_options); @@ -178,7 +181,7 @@ static void info_cmd(sock_t fd, char *options, unsigned int nb_options) /* generic info */ n = snprintf(msg, sizeof(msg), "{\"info\":" - " {\"Configuration\":{" + " {\"Information\":{" " \"Listening interface\": \"%s/%s\"," " \"Supported IP version\": \"%s\"," " \"Logging file\": \"%s\"," @@ -566,122 +569,116 @@ static void plugin_cmd(sock_t fd, char *options, unsigned int nb_options) /** - * Increase/Decrease verbosity of proxenet (useful for logging/debugging) + * List configuration settings */ -static void config_verbose_cmd(sock_t fd, char *options) +static void plugin_config_cmd_list(sock_t fd) { - char msg[BUFSIZE] = {0, }; - char *ptr; - int n, level; - - ptr = strtok(options, " \n"); - if (!ptr){ - n = snprintf(msg, BUFSIZE, "{\"verbose\": \"current level is %d\"}", - cfg->verbose); - proxenet_write(fd, (void*)msg, n); - return; - } - - if ( (level=atoi(ptr)) > 0 && levelverbose = level; - n = snprintf(msg, BUFSIZE, "{\"verbose\": \"level is set to %d\"}", - cfg->verbose); - } - else if (strcmp(ptr, "inc")==0 && cfg->verboseverbose); - else if (strcmp(ptr, "dec")==0 && cfg->verbose>0) - n = snprintf(msg, BUFSIZE, "{\"verbose\": \"level is now %d\"}", --cfg->verbose); - else - n = snprintf(msg, BUFSIZE, "{\"error\": \"Invalid action\"}"); + char msg[BUFSIZE]; + int n; - proxenet_write(fd, (void*)msg, n); + n = snprintf(msg, BUFSIZE, + "{\"Configuration parameters\":" + "{" + " \"verbose\": %d," + " \"state\": \"%s\"," + " \"logfile\": \"%s\"," + " \"intercept_pattern\": \"%s\"," + " \"ssl_intercept\": \"%s\"" + "}" + "}" + , + cfg->verbose, + proxy_state==SLEEPING?"SLEEPING":"ACTIVE", + (cfg->logfile)?cfg->logfile:"stdout", + cfg->intercept_pattern, + cfg->ssl_intercept?"true":"false" + ); + proxenet_write(fd, msg, n); return; } /** - * (De)-Activate pause mode (suspend and block interception) + * View or edit configuration */ -static void config_pause_cmd(sock_t fd, char *options) +static void config_cmd(sock_t fd, char *options, unsigned int nb_options) { - char *msg; + char *ptr; + char msg[BUFSIZE]={0,}; + bool edit; + int n; (void) options; + (void) nb_options; - if (proxy_state==SLEEPING) { - msg = "{\"sleep-mode\": 0}"; - proxy_state = ACTIVE; - } else { - msg = "{\"sleep-mode\": 1}"; - proxy_state = SLEEPING; + /* usage */ + ptr = strtok(options, " \n"); + if (!ptr){ + ERR_INVALID_SYNTAX_JSON(fd); + return; } - xlog(LOG_INFO, "%s\n", msg); - proxenet_write(fd, (void*)msg, strlen(msg)); - return; -} - - -/** - * (De)-Activate SSL interception mode - */ -static void config_ssl_intercept_cmd(sock_t fd, char* options) -{ - char *ptr; + if (strcmp(ptr, "list")==0) + return plugin_config_cmd_list(fd); - (void) options; + if (strcmp(ptr, "set")==0) + edit = true; + else if (strcmp(ptr, "get")==0) + edit = false; + else { + ERR_INVALID_SYNTAX_JSON(fd); + return; + } - /* shift argument */ - ptr = strtok(NULL, " \n"); + ptr = strtok(options, " \n"); if (!ptr){ - xlog(LOG_ERROR, "%s\n", "Failed to get argument"); + ERR_MISSING_ARGUMENT_JSON(fd); return; } - if ( strcasecmp(ptr, "true") == 0){ - cfg->ssl_intercept = true; - if (cfg->verbose) - xlog(LOG_INFO, "%s\n", "[config] Enabled SSL intercept"); - proxenet_write(fd, "{\"SSL intercept\": \"enabled\"}", 28); - return; - } else if ( strcasecmp(ptr, "false") == 0){ - cfg->ssl_intercept = false; - if (cfg->verbose) - xlog(LOG_INFO, "%s\n", "[config] Disabled SSL intercept"); - proxenet_write(fd, "{\"SSL intercept\": \"disabled\"}", 29); + if (!strcmp(ptr, "intercept_pattern")){ + ptr = strtok(options, " \n"); + if (!ptr){ ERR_MISSING_ARGUMENT_JSON(fd); return; } + proxenet_xfree( cfg->intercept_pattern ); + cfg->intercept_pattern = proxenet_xstrdup2(ptr); + n = snprintf(msg, sizeof(msg), "{\"success\": \"Intercept pattern is now '%s'\" }", cfg->intercept_pattern); + proxenet_write(fd, msg, n); return; } -} - - -/** - * Edit configuration - */ -static void config_cmd(sock_t fd, char *options, unsigned int nb_options) -{ - char *ptr; - - (void) options; - (void) nb_options; - /* usage */ - ptr = strtok(options, " \n"); - if (!ptr) - goto invalid_config_action; + if (!strcmp(ptr, "verbose")){ + ptr = strtok(options, " \n"); + if (!ptr){ ERR_MISSING_ARGUMENT_JSON(fd); return; } + cfg->verbose = atoi(ptr); + n = snprintf(msg, sizeof(msg), "{\"success\": \"Verbose is now '%d'\" }", cfg->verbose); + proxenet_write(fd, msg, n); + return; + } - if (strcmp(ptr, "ssl-intercept") == 0) - return config_ssl_intercept_cmd(fd, ptr); + if (!strcmp(ptr, "ssl_intercept")){ + ptr = strtok(options, " \n"); + if (!ptr){ ERR_MISSING_ARGUMENT_JSON(fd); return; } + cfg->ssl_intercept = strcasecmp(ptr,"true")==0?true:false; + n = snprintf(msg, sizeof(msg), "{\"success\": \"SSL Intercept is set to %d\" }", cfg->ssl_intercept); + proxenet_write(fd, msg, n); + return; + } - if (strcmp(ptr, "pause") == 0) - return config_pause_cmd(fd, ptr); + if (!strcmp(ptr, "pause")){ + proxy_state = SLEEPING; + n = snprintf(msg, sizeof(msg), "{\"success\": \""PROGNAME" is paused\" }"); + proxenet_write(fd, msg, n); + return; + } - if (strcmp(ptr, "verbose") == 0) - return config_verbose_cmd(fd, ptr); + if (!strcmp(ptr, "unpause")){ + proxy_state = ACTIVE; + n = snprintf(msg, sizeof(msg), "{\"success\": \""PROGNAME" is unpaused\" }"); + proxenet_write(fd, msg, n); + return; + } -invalid_config_action: - proxenet_write(fd, "{\"error\": \"Invalid action.\"}", 28); - return; } diff --git a/control-web.py b/control-web.py index 8955d2d..b675c50 100755 --- a/control-web.py +++ b/control-web.py @@ -185,7 +185,13 @@ def threads(): html = """
    """ html += """

    {}

    """.format(title) html += """
      """ - for k,v in js[title].iteritems(): html += "
    • {}: {}
    • ".format(k, v) + for k,v in js[title].iteritems(): + if v.__class__.__name__ == "dict": + html += "
    • {}:
        ".format(k) + for a,b in v.iteritems(): html += "
      1. {} → {}
      2. ".format(a,b) + html += "" + else: + html += "
      3. {}: {}
      4. ".format(k, v) html += "
    """ html += """
    @@ -214,10 +220,18 @@ def threads_set(word): @route('/config') def config(): if not is_proxenet_running(): return build_html(body=not_running_html()) - html = """
    """ - html += """

    Configuration

    """ - html += """
      """ - html += "
    """ + res = sr("config list") + js = json.loads( res ) + title = js.keys()[0] + values = js[title] + html = """
    """ + html += """

    {}

    """.format( title ) + html += """
    """ + html += """
    IdNamePriorityStatusAction
    {}{}{}{}
    """ + html += """""" + for k,v in values.iteritems(): html += "".format(k,v) + html += "
    SettingValue
    {}{}
    """ + return build_html(body=html, title="proxenet Configuration", page="config") From 490fbb6d11e67c1d6fb0f334497aa5d648bae2ac Mon Sep 17 00:00:00 2001 From: hugsy Date: Sat, 30 May 2015 18:54:17 +1000 Subject: [PATCH 18/18] [control-server] finish config integration --- config.h.in | 1 + control-client.py | 15 +++++++++--- control-server.c | 61 ++++++++++++++++++++++++++--------------------- control-server.h | 3 +-- control-web.py | 31 ++++++++++++++++++++++-- core.c | 2 +- socket.c | 3 ++- 7 files changed, 80 insertions(+), 36 deletions(-) diff --git a/config.h.in b/config.h.in index 68253cc..2920606 100644 --- a/config.h.in +++ b/config.h.in @@ -39,6 +39,7 @@ #define CFG_RESPONSE_PLUGIN_FUNCTION "proxenet_response_hook" // default name for hooking response function #define CFG_DEFAULT_SSL_CLIENT_DOMAIN "*" // default domain to use the SSL client certificate (* means any) #define CFG_DEFAULT_INTERCEPT_PATTERN "*" // default pattern to intercept (all) +#define CFG_CONTROL_SOCK_PATH "/tmp/proxenet-control-socket" /******************************************************************************** diff --git a/control-client.py b/control-client.py index 7cc257f..ecfdab6 100755 --- a/control-client.py +++ b/control-client.py @@ -2,7 +2,7 @@ # -*- coding: utf-8 -*- # -*- mode: python -*- -import argparse, socket, datetime, os, json, rlcompleter, readline +import argparse, socket, datetime, os, json, rlcompleter, readline, pprint __author__ = "hugsy" @@ -15,7 +15,7 @@ syntax: {3} [options] args """.format(__version__, __licence__, __author__, __file__) -# the socket path can be modified in control-server.h +# the socket path can be modified in config.h.in PROXENET_SOCKET_PATH = "/tmp/proxenet-control-socket" def now(): @@ -81,7 +81,16 @@ def recv_until(sock, pattern=">>> "): res = recv_until(cli) data, prompt = res[:-4], res[-4:] - print data + try: + js = json.loads( data ) + for k,v in js.iteritems(): + if v.__class__.__name__ == "dict": + print("{}".format(k)) + for a,b in v.iteritems(): print("\t{} -> {}".format(a,b)) + else: + print("{} -> {}".format(k,v)) + except: + print(data) cmd = raw_input( prompt ) cli.send(cmd.strip()+"\n") if cmd.strip() == "quit": diff --git a/control-server.c b/control-server.c index 6d4ffc7..40c50b1 100644 --- a/control-server.c +++ b/control-server.c @@ -151,18 +151,20 @@ static void help_cmd(sock_t fd, char *options, unsigned int nb_options) struct command_t *cmd; char msg[BUFSIZE]; int n; + bool first_iter = true; (void) options; (void) nb_options; proxenet_write(fd, "{\"Command list\":{", 17); for (cmd=known_commands; cmd && cmd->name; cmd++) { + if(first_iter) first_iter=false; + else proxenet_write(fd, ",", 1); proxenet_xzero(msg, sizeof(msg)); - n = snprintf(msg, sizeof(msg), "\"%s\": \"%s\",", cmd->name, cmd->desc); + n = snprintf(msg, sizeof(msg), "\"%s\": \"%s\"", cmd->name, cmd->desc); proxenet_write(fd, msg, n); } - proxenet_write(fd, "\"\":\"\"}", 6); - + proxenet_write(fd, "}}", 2); return; } @@ -579,11 +581,11 @@ static void plugin_config_cmd_list(sock_t fd) n = snprintf(msg, BUFSIZE, "{\"Configuration parameters\":" "{" - " \"verbose\": %d," - " \"state\": \"%s\"," - " \"logfile\": \"%s\"," - " \"intercept_pattern\": \"%s\"," - " \"ssl_intercept\": \"%s\"" + " \"verbose\": {\"value\": %d, \"type\": \"int\" }," + " \"state\": {\"value\": \"%s\", \"type\": \"int\" }," + " \"logfile\": {\"value\": \"%s\", \"type\": \"None\" }," + " \"intercept_pattern\": {\"value\": \"%s\", \"type\": \"str\" }," + " \"ssl_intercept\": {\"value\": \"%s\", \"type\": \"bool\" }" "}" "}" , @@ -631,14 +633,11 @@ static void config_cmd(sock_t fd, char *options, unsigned int nb_options) return; } - ptr = strtok(options, " \n"); - if (!ptr){ - ERR_MISSING_ARGUMENT_JSON(fd); - return; - } + ptr = strtok(NULL, " \n"); + if (!ptr){ ERR_MISSING_ARGUMENT_JSON(fd); return; } if (!strcmp(ptr, "intercept_pattern")){ - ptr = strtok(options, " \n"); + ptr = strtok(NULL, " \n"); if (!ptr){ ERR_MISSING_ARGUMENT_JSON(fd); return; } proxenet_xfree( cfg->intercept_pattern ); cfg->intercept_pattern = proxenet_xstrdup2(ptr); @@ -648,7 +647,7 @@ static void config_cmd(sock_t fd, char *options, unsigned int nb_options) } if (!strcmp(ptr, "verbose")){ - ptr = strtok(options, " \n"); + ptr = strtok(NULL, " \n"); if (!ptr){ ERR_MISSING_ARGUMENT_JSON(fd); return; } cfg->verbose = atoi(ptr); n = snprintf(msg, sizeof(msg), "{\"success\": \"Verbose is now '%d'\" }", cfg->verbose); @@ -657,7 +656,7 @@ static void config_cmd(sock_t fd, char *options, unsigned int nb_options) } if (!strcmp(ptr, "ssl_intercept")){ - ptr = strtok(options, " \n"); + ptr = strtok(NULL, " \n"); if (!ptr){ ERR_MISSING_ARGUMENT_JSON(fd); return; } cfg->ssl_intercept = strcasecmp(ptr,"true")==0?true:false; n = snprintf(msg, sizeof(msg), "{\"success\": \"SSL Intercept is set to %d\" }", cfg->ssl_intercept); @@ -665,20 +664,28 @@ static void config_cmd(sock_t fd, char *options, unsigned int nb_options) return; } - if (!strcmp(ptr, "pause")){ - proxy_state = SLEEPING; - n = snprintf(msg, sizeof(msg), "{\"success\": \""PROGNAME" is paused\" }"); - proxenet_write(fd, msg, n); - return; - } + if (!strcmp(ptr, "state")){ + ptr = strtok(NULL, " \n"); + if (!ptr){ ERR_MISSING_ARGUMENT_JSON(fd); return; } + if (strcasecmp(ptr, "sleeping")==0 && proxy_state==ACTIVE){ + proxy_state = SLEEPING; + n = snprintf(msg, sizeof(msg), "{\"success\": \""PROGNAME" is paused\" }"); + proxenet_write(fd, msg, n); + return; + } else if (strcasecmp(ptr, "active")==0 && proxy_state==SLEEPING){ + proxy_state = ACTIVE; + n = snprintf(msg, sizeof(msg), "{\"success\": \""PROGNAME" is unpaused\" }"); + proxenet_write(fd, msg, n); + return; + } else { + n = snprintf(msg, sizeof(msg), "{\"success\": \"nothing to do\" }"); + proxenet_write(fd, msg, n); + return; + } - if (!strcmp(ptr, "unpause")){ - proxy_state = ACTIVE; - n = snprintf(msg, sizeof(msg), "{\"success\": \""PROGNAME" is unpaused\" }"); - proxenet_write(fd, msg, n); - return; } + } diff --git a/control-server.h b/control-server.h index 43049d0..c2ddc1d 100644 --- a/control-server.h +++ b/control-server.h @@ -1,12 +1,11 @@ #ifndef _CONTROL_SERVER_H #define _CONTROL_SERVER_H +#include "config.h" #include "core.h" #include "socket.h" #define MAX_CMD_LEN 1024 - -#define CONTROL_SOCK_PATH "/tmp/proxenet-control-socket" #define CONTROL_MOTD "Welcome on "PROGNAME" control interface\nType `help` to list available commands\n" #define CONTROL_PROMPT ">>> " #define CONTROL_INVALID "{\"error\": \"Invalid command\"}" diff --git a/control-web.py b/control-web.py index b675c50..6d6a41e 100755 --- a/control-web.py +++ b/control-web.py @@ -224,16 +224,43 @@ def config(): js = json.loads( res ) title = js.keys()[0] values = js[title] + + # view config html = """
    """ html += """

    {}

    """.format( title ) html += """
    """ html += """""" - html += """""" - for k,v in values.iteritems(): html += "".format(k,v) + html += """""" + for k,v in values.iteritems(): + _val, _type = v["value"], v["type"] + html += "".format(k,_val,_type) html += "
    SettingValue
    {}{}
    SettingValueType
    {}{}{}
    """ + # edit config + html += """
    """ + html += """

    Change Value

    """ + html += """
    """ + html += """
    """ + html += """
    """ + return build_html(body=html, title="proxenet Configuration", page="config") +@route('/config/set') +def config_set(): + if not is_proxenet_running(): return build_html(body=not_running_html()) + param = request.params.get("setting") + value = request.params.get("value") + print param, value + res = sr("config set {} {}".format(param, value)) + js = json.loads( res ) + retcode = js.keys()[0] + if retcode == "error": + return """""".format(res[retcode]) + redirect("/config") + return if __name__ == "__main__": parser = argparse.ArgumentParser(usage = __usage__, description = __desc__) diff --git a/core.c b/core.c index 9024f36..ea9f9f0 100644 --- a/core.c +++ b/core.c @@ -1479,6 +1479,6 @@ int proxenet_start() close_socket(listening_socket); close_socket(control_socket); - unlink(CONTROL_SOCK_PATH); + unlink(CFG_CONTROL_SOCK_PATH); return 0; } diff --git a/socket.c b/socket.c index be91356..bf1962b 100644 --- a/socket.c +++ b/socket.c @@ -12,6 +12,7 @@ #include "errno.h" #include "main.h" #include "control-server.h" +#include "config.h" /** @@ -31,7 +32,7 @@ sock_t create_control_socket() } sun_local.sun_family = AF_UNIX; - strcpy(sun_local.sun_path, CONTROL_SOCK_PATH); + strcpy(sun_local.sun_path, CFG_CONTROL_SOCK_PATH); unlink(sun_local.sun_path); /* and bind+listen */