From 323368f677fc1590fc887c4468ecba4def391d75 Mon Sep 17 00:00:00 2001 From: lmb Date: Tue, 10 Sep 2013 09:30:19 +0200 Subject: [PATCH] Add Maximum Fragment Length support This is based on the pull request in https://github.com/Voxer/stud/pull/2. --- configuration.c | 21 ++++++++++++++++++++- configuration.h | 1 + stud.c | 29 +++++++++++++++++++++++++++++ 3 files changed, 50 insertions(+), 1 deletion(-) diff --git a/configuration.c b/configuration.c index a1ab1b8..ffe7aa3 100644 --- a/configuration.c +++ b/configuration.c @@ -35,6 +35,7 @@ #define CFG_WORKERS "workers" #define CFG_BACKLOG "backlog" #define CFG_KEEPALIVE "keepalive" +#define CFG_MAX_SEND_FRAGMENT "max-send-fragment" #define CFG_CHROOT "chroot" #define CFG_USER "user" #define CFG_GROUP "group" @@ -153,6 +154,7 @@ stud_config * config_new (void) { r->TCP_KEEPALIVE_TIME = 3600; r->DAEMONIZE = 0; r->PREFER_SERVER_CIPHERS = 0; + r->MAX_SEND_FRAGMENT = 0; return r; } @@ -579,6 +581,13 @@ void config_param_validate (char *k, char *v, stud_config *cfg, char *file, int else if (strcmp(k, CFG_KEEPALIVE) == 0) { r = config_param_val_int_pos(v, &cfg->TCP_KEEPALIVE_TIME); } + else if (strcmp(k, CFG_MAX_SEND_FRAGMENT) == 0) { + r = config_param_val_int(v, &cfg->MAX_SEND_FRAGMENT); + if (r && cfg->MAX_SEND_FRAGMENT < 0) { + config_error_set("Maximum send fragment must be >= 0"); + r = 0; + } + } #ifdef USE_SHARED_CACHE else if (strcmp(k, CFG_SHARED_CACHE) == 0) { r = config_param_val_int(v, &cfg->SHARED_CACHE); @@ -1042,6 +1051,12 @@ void config_print_default (FILE *fd, stud_config *cfg) { fprintf(fd, FMT_ISTR, CFG_KEEPALIVE, cfg->TCP_KEEPALIVE_TIME); fprintf(fd, "\n"); + fprintf(fd, "# SSL maximum fragment size\n"); + fprintf(fd, "#\n"); + fprintf(fd, "# type: integer\n"); + fprintf(fd, FMT_ISTR, CFG_MAX_SEND_FRAGMENT, cfg->MAX_SEND_FRAGMENT); + fprintf(fd, "\n"); + #ifdef USE_SHARED_CACHE fprintf(fd, "# SSL session cache size\n"); fprintf(fd, "#\n"); @@ -1204,6 +1219,7 @@ void config_parse_cli(int argc, char **argv, stud_config *cfg) { { CFG_SHARED_CACHE_MCASTIF, 1, NULL, 'M' }, #endif { CFG_KEEPALIVE, 1, NULL, 'k' }, + { CFG_MAX_SEND_FRAGMENT, 1, NULL, 'F' }, { CFG_CHROOT, 1, NULL, 'r' }, { CFG_USER, 1, NULL, 'u' }, { CFG_GROUP, 1, NULL, 'g' }, @@ -1229,7 +1245,7 @@ void config_parse_cli(int argc, char **argv, stud_config *cfg) { int option_index = 0; c = getopt_long( argc, argv, - "c:e:Ob:f:n:B:C:U:P:M:k:r:u:g:qstVh", + "c:e:Ob:f:n:B:C:U:P:M:k:F:r:u:g:qstVh", long_options, &option_index ); @@ -1290,6 +1306,9 @@ void config_parse_cli(int argc, char **argv, stud_config *cfg) { case 'k': config_param_validate(CFG_KEEPALIVE, optarg, cfg, NULL, 0); break; + case 'F': + config_param_validate(CFG_MAX_SEND_FRAGMENT, optarg, cfg, NULL, 0); + break; case 'r': config_param_validate(CFG_CHROOT, optarg, cfg, NULL, 0); break; diff --git a/configuration.h b/configuration.h index 7406f06..3b1f174 100644 --- a/configuration.h +++ b/configuration.h @@ -72,6 +72,7 @@ struct __stud_config { int TCP_KEEPALIVE_TIME; int DAEMONIZE; int PREFER_SERVER_CIPHERS; + int MAX_SEND_FRAGMENT; }; typedef struct __stud_config stud_config; diff --git a/stud.c b/stud.c index 56ef6d9..16d4eaa 100644 --- a/stud.c +++ b/stud.c @@ -663,6 +663,13 @@ SSL_CTX *make_ctx(const char *pemfile) { SSL_CTX_set_options(ctx, SSL_OP_CIPHER_SERVER_PREFERENCE); } +#if defined(SSL_CTX_set_max_send_fragment) + if (CONFIG->MAX_SEND_FRAGMENT) { + LOG("{core} Fragment size is %d\n", CONFIG->MAX_SEND_FRAGMENT); + SSL_CTX_set_max_send_fragment(ctx, CONFIG->MAX_SEND_FRAGMENT); + } +#endif /* defined(SSL_CTX_set_max_send_fragment) */ + if (CONFIG->PMODE == SSL_CLIENT) { return ctx; } @@ -1453,9 +1460,27 @@ static void ssl_write(struct ev_loop *loop, ev_io *w, int revents) { proxystate *ps = (proxystate *)w->data; assert(!ringbuffer_is_empty(&ps->ring_clear2ssl)); char * next = ringbuffer_read_next(&ps->ring_clear2ssl, &sz); + +#if !defined(SSL_CTX_set_max_send_fragment) + int orig_sz = sz; + + do { + if (CONFIG->MAX_SEND_FRAGMENT && sz > CONFIG->MAX_SEND_FRAGMENT) + sz = CONFIG->MAX_SEND_FRAGMENT; +#endif /* defined(SSL_CTX_set_max_send_fragment) */ + t = SSL_write(ps->ssl, next, sz); if (t > 0) { if (t == sz) { +#if !defined(SSL_CTX_set_max_send_fragment) + if (orig_sz > sz) { + orig_sz -= t; + next += t; + ringbuffer_read_skip(&ps->ring_clear2ssl, t); + sz = orig_sz; + continue; + } +#endif /* defined(SSL_CTX_set_max_send_fragment) */ ringbuffer_read_pop(&ps->ring_clear2ssl); if (ps->clear_connected) safe_enable_io(ps, &ps->ev_r_clear); // can be re-enabled b/c we've popped @@ -1480,6 +1505,10 @@ static void ssl_write(struct ev_loop *loop, ev_io *w, int revents) { else handle_fatal_ssl_error(ps, err, w->fd == ps->fd_up ? 0 : 1); } + +#if !defined(SSL_CTX_set_max_send_fragment) + } while(0); +#endif /* defined(SSL_CTX_set_max_send_fragment) */ } /* libev read handler for the bound socket. Socket is accepted,