uhttpd: rework CyaSSL and OpenSSL integration; move protected recv() and send() operations below the ssl layer - fixes hangs when accessing via https
SVN-Revision: 28761
This commit is contained in:
parent
297ac9a7f1
commit
3d035a6f6a
5 changed files with 210 additions and 51 deletions
|
@ -65,14 +65,16 @@ endef
|
||||||
|
|
||||||
UHTTPD_TLS:=
|
UHTTPD_TLS:=
|
||||||
TLS_CFLAGS:=
|
TLS_CFLAGS:=
|
||||||
|
TLS_LDFLAGS:=
|
||||||
|
|
||||||
ifneq ($(CONFIG_PACKAGE_uhttpd-mod-tls_cyassl),)
|
ifneq ($(CONFIG_PACKAGE_uhttpd-mod-tls_cyassl),)
|
||||||
UHTTPD_TLS:=cyassl
|
UHTTPD_TLS:=cyassl
|
||||||
TLS_CFLAGS:=-I$(STAGING_DIR)/usr/include/cyassl
|
TLS_CFLAGS:=-I$(STAGING_DIR)/usr/include/cyassl -DTLS_IS_CYASSL
|
||||||
endif
|
endif
|
||||||
|
|
||||||
ifneq ($(CONFIG_PACKAGE_uhttpd-mod-tls_openssl),)
|
ifneq ($(CONFIG_PACKAGE_uhttpd-mod-tls_openssl),)
|
||||||
UHTTPD_TLS:=openssl
|
UHTTPD_TLS:=openssl
|
||||||
|
TLS_CFLAGS:=-DTLS_IS_OPENSSL
|
||||||
endif
|
endif
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -3,19 +3,17 @@ LUA_SUPPORT ?= 1
|
||||||
TLS_SUPPORT ?= 1
|
TLS_SUPPORT ?= 1
|
||||||
UHTTPD_TLS ?= cyassl
|
UHTTPD_TLS ?= cyassl
|
||||||
|
|
||||||
CFLAGS ?= -I./lua-5.1.4/src -I$(TLS_INCLUDE_DIR) -O0 -ggdb3
|
CFLAGS ?= -I./lua-5.1.4/src $(TLS_CFLAGS) -O0 -ggdb3
|
||||||
LDFLAGS ?= -L./lua-5.1.4/src -L$(TLS_LIB_DIR)
|
LDFLAGS ?= -L./lua-5.1.4/src $(TLS_LDFLAGS)
|
||||||
|
|
||||||
CFLAGS += -Wall --std=gnu99
|
CFLAGS += -Wall --std=gnu99
|
||||||
|
|
||||||
ifeq ($(UHTTPD_TLS),openssl)
|
ifeq ($(UHTTPD_TLS),openssl)
|
||||||
TLS_LDFLAGS := -lssl
|
TLS_LDFLAGS := -L./openssl-0.9.8m -lssl
|
||||||
TLS_INCLUDE_DIR := ./openssl-0.9.8m/include
|
TLS_CFLAGS := -I./openssl-0.9.8m/include -DTLS_IS_OPENSSL
|
||||||
TLS_LIB_DIR := ./openssl-0.9.8m
|
|
||||||
else
|
else
|
||||||
TLS_LDFLAGS := -lcyassl
|
TLS_LDFLAGS := -L./cyassl-1.4.0/src/.libs -lcyassl
|
||||||
TLS_INCLUDE_DIR := ./cyassl-1.4.0/include
|
TLS_CFLAGS := -I./cyassl-1.4.0/include -DTLS_IS_CYASSL
|
||||||
TLS_LIB_DIR := ./cyassl-1.4.0/src/.libs
|
|
||||||
endif
|
endif
|
||||||
|
|
||||||
OBJ := uhttpd.o uhttpd-file.o uhttpd-utils.o
|
OBJ := uhttpd.o uhttpd-file.o uhttpd-utils.o
|
||||||
|
@ -31,15 +29,26 @@ ifeq ($(HAVE_SHADOW),yes)
|
||||||
CFLAGS += -DHAVE_SHADOW
|
CFLAGS += -DHAVE_SHADOW
|
||||||
endif
|
endif
|
||||||
|
|
||||||
world: compile
|
ifeq ($(TLS_SUPPORT),1)
|
||||||
|
CFLAGS += -DHAVE_TLS
|
||||||
|
endif
|
||||||
|
|
||||||
ifeq ($(CGI_SUPPORT),1)
|
ifeq ($(CGI_SUPPORT),1)
|
||||||
OBJ += uhttpd-cgi.o
|
|
||||||
CFLAGS += -DHAVE_CGI
|
CFLAGS += -DHAVE_CGI
|
||||||
endif
|
endif
|
||||||
|
|
||||||
ifeq ($(LUA_SUPPORT),1)
|
ifeq ($(LUA_SUPPORT),1)
|
||||||
CFLAGS += -DHAVE_LUA
|
CFLAGS += -DHAVE_LUA
|
||||||
|
endif
|
||||||
|
|
||||||
|
|
||||||
|
world: compile
|
||||||
|
|
||||||
|
ifeq ($(CGI_SUPPORT),1)
|
||||||
|
OBJ += uhttpd-cgi.o
|
||||||
|
endif
|
||||||
|
|
||||||
|
ifeq ($(LUA_SUPPORT),1)
|
||||||
LUALIB := uhttpd_lua.so
|
LUALIB := uhttpd_lua.so
|
||||||
|
|
||||||
$(LUALIB): uhttpd-lua.c
|
$(LUALIB): uhttpd-lua.c
|
||||||
|
@ -49,12 +58,11 @@ ifeq ($(LUA_SUPPORT),1)
|
||||||
endif
|
endif
|
||||||
|
|
||||||
ifeq ($(TLS_SUPPORT),1)
|
ifeq ($(TLS_SUPPORT),1)
|
||||||
CFLAGS += -DHAVE_TLS
|
|
||||||
TLSLIB := uhttpd_tls.so
|
TLSLIB := uhttpd_tls.so
|
||||||
|
|
||||||
$(TLSLIB): uhttpd-tls.c
|
$(TLSLIB): uhttpd-tls.c
|
||||||
$(CC) $(CFLAGS) $(LDFLAGS) $(FPIC) \
|
$(CC) $(CFLAGS) $(LDFLAGS) $(FPIC) \
|
||||||
-shared $(TLS_LDFLAGS) \
|
-shared \
|
||||||
-o $(TLSLIB) uhttpd-tls.c
|
-o $(TLSLIB) uhttpd-tls.c
|
||||||
endif
|
endif
|
||||||
|
|
||||||
|
|
|
@ -20,6 +20,143 @@
|
||||||
#include "uhttpd-tls.h"
|
#include "uhttpd-tls.h"
|
||||||
#include "uhttpd-utils.h"
|
#include "uhttpd-utils.h"
|
||||||
|
|
||||||
|
#include <syslog.h>
|
||||||
|
#define dbg(...) syslog(LOG_INFO, __VA_ARGS__)
|
||||||
|
|
||||||
|
#ifdef TLS_IS_CYASSL
|
||||||
|
static int uh_cyassl_recv_cb(char *buf, int sz, void *ctx)
|
||||||
|
{
|
||||||
|
int rv;
|
||||||
|
int socket = *(int *)ctx;
|
||||||
|
struct client *cl;
|
||||||
|
|
||||||
|
if (!(cl = uh_client_lookup(socket)))
|
||||||
|
return -1; /* unexpected error */
|
||||||
|
|
||||||
|
rv = uh_tcp_recv_lowlevel(cl, buf, sz);
|
||||||
|
|
||||||
|
if (rv < 0)
|
||||||
|
return -4; /* interrupted */
|
||||||
|
|
||||||
|
if (rv == 0)
|
||||||
|
return -5; /* connection closed */
|
||||||
|
|
||||||
|
return rv;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int uh_cyassl_send_cb(char *buf, int sz, void *ctx)
|
||||||
|
{
|
||||||
|
int rv;
|
||||||
|
int socket = *(int *)ctx;
|
||||||
|
struct client *cl;
|
||||||
|
|
||||||
|
if (!(cl = uh_client_lookup(socket)))
|
||||||
|
return -1; /* unexpected error */
|
||||||
|
|
||||||
|
rv = uh_tcp_send_lowlevel(cl, buf, sz);
|
||||||
|
|
||||||
|
if (rv <= 0)
|
||||||
|
return -5; /* connection dead */
|
||||||
|
|
||||||
|
return rv;
|
||||||
|
}
|
||||||
|
|
||||||
|
void SetCallbackIORecv_Ctx(SSL_CTX*, int (*)(char *, int, void *));
|
||||||
|
void SetCallbackIOSend_Ctx(SSL_CTX*, int (*)(char *, int, void *));
|
||||||
|
|
||||||
|
static void uh_tls_ctx_setup(SSL_CTX *ctx)
|
||||||
|
{
|
||||||
|
SSL_CTX_set_verify(ctx, SSL_VERIFY_NONE, NULL);
|
||||||
|
SetCallbackIORecv_Ctx(ctx, uh_cyassl_recv_cb);
|
||||||
|
SetCallbackIOSend_Ctx(ctx, uh_cyassl_send_cb);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int uh_tls_client_ctx_setup(SSL *ssl, int socket)
|
||||||
|
{
|
||||||
|
return SSL_set_fd(ssl, socket);
|
||||||
|
}
|
||||||
|
#endif /* TLS_IS_CYASSL */
|
||||||
|
|
||||||
|
#ifdef TLS_IS_OPENSSL
|
||||||
|
static long uh_openssl_bio_ctrl_cb(BIO *b, int cmd, long num, void *ptr)
|
||||||
|
{
|
||||||
|
long rv = 1;
|
||||||
|
|
||||||
|
switch (cmd)
|
||||||
|
{
|
||||||
|
case BIO_C_SET_FD:
|
||||||
|
b->num = *((int *)ptr);
|
||||||
|
b->shutdown = (int)num;
|
||||||
|
b->init = 1;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case BIO_C_GET_FD:
|
||||||
|
if (!b->init)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
if (ptr)
|
||||||
|
*((int *)ptr) = b->num;
|
||||||
|
|
||||||
|
rv = b->num;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
return rv;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int uh_openssl_bio_read_cb(BIO *b, char *out, int outl)
|
||||||
|
{
|
||||||
|
int rv = 0;
|
||||||
|
struct client *cl;
|
||||||
|
|
||||||
|
if (!(cl = uh_client_lookup(b->num)))
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
if (out != NULL)
|
||||||
|
rv = uh_tcp_recv_lowlevel(cl, out, outl);
|
||||||
|
|
||||||
|
return rv;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int uh_openssl_bio_write_cb(BIO *b, const char *in, int inl)
|
||||||
|
{
|
||||||
|
struct client *cl;
|
||||||
|
|
||||||
|
if (!(cl = uh_client_lookup(b->num)))
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
return uh_tcp_send_lowlevel(cl, in, inl);
|
||||||
|
}
|
||||||
|
|
||||||
|
static BIO_METHOD uh_openssl_bio_methods = {
|
||||||
|
.type = BIO_TYPE_SOCKET,
|
||||||
|
.name = "uhsocket",
|
||||||
|
.ctrl = uh_openssl_bio_ctrl_cb,
|
||||||
|
.bwrite = uh_openssl_bio_write_cb,
|
||||||
|
.bread = uh_openssl_bio_read_cb
|
||||||
|
};
|
||||||
|
|
||||||
|
static void uh_tls_ctx_setup(SSL_CTX *ctx)
|
||||||
|
{
|
||||||
|
SSL_CTX_set_verify(ctx, SSL_VERIFY_NONE, NULL);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int uh_tls_client_ctx_setup(SSL *ssl, int socket)
|
||||||
|
{
|
||||||
|
BIO *b;
|
||||||
|
|
||||||
|
if (!(b = BIO_new(&uh_openssl_bio_methods)))
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
BIO_set_fd(b, socket, BIO_NOCLOSE);
|
||||||
|
SSL_set_bio(ssl, b, b);
|
||||||
|
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
#endif /* TLS_IS_OPENSSL */
|
||||||
|
|
||||||
|
|
||||||
SSL_CTX * uh_tls_ctx_init()
|
SSL_CTX * uh_tls_ctx_init()
|
||||||
{
|
{
|
||||||
|
@ -28,8 +165,8 @@ SSL_CTX * uh_tls_ctx_init()
|
||||||
SSL_load_error_strings();
|
SSL_load_error_strings();
|
||||||
SSL_library_init();
|
SSL_library_init();
|
||||||
|
|
||||||
if( (c = SSL_CTX_new(TLSv1_server_method())) != NULL )
|
if ((c = SSL_CTX_new(TLSv1_server_method())) != NULL)
|
||||||
SSL_CTX_set_verify(c, SSL_VERIFY_NONE, NULL);
|
uh_tls_ctx_setup(c);
|
||||||
|
|
||||||
return c;
|
return c;
|
||||||
}
|
}
|
||||||
|
@ -69,8 +206,9 @@ int uh_tls_client_accept(struct client *c)
|
||||||
c->tls = SSL_new(c->server->tls);
|
c->tls = SSL_new(c->server->tls);
|
||||||
if( c->tls )
|
if( c->tls )
|
||||||
{
|
{
|
||||||
if( (rv = SSL_set_fd(c->tls, c->socket)) < 1 )
|
if( (rv = uh_tls_client_ctx_setup(c->tls, c->socket)) < 1 )
|
||||||
goto cleanup;
|
goto cleanup;
|
||||||
|
|
||||||
if( (rv = SSL_accept(c->tls)) < 1 )
|
if( (rv = SSL_accept(c->tls)) < 1 )
|
||||||
goto cleanup;
|
goto cleanup;
|
||||||
}
|
}
|
||||||
|
|
|
@ -124,7 +124,7 @@ int select_intr(int n, fd_set *r, fd_set *w, fd_set *e, struct timeval *t)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
int uh_tcp_send(struct client *cl, const char *buf, int len)
|
int uh_tcp_send_lowlevel(struct client *cl, const char *buf, int len)
|
||||||
{
|
{
|
||||||
fd_set writer;
|
fd_set writer;
|
||||||
struct timeval timeout;
|
struct timeval timeout;
|
||||||
|
@ -135,21 +135,28 @@ int uh_tcp_send(struct client *cl, const char *buf, int len)
|
||||||
timeout.tv_sec = cl->server->conf->network_timeout;
|
timeout.tv_sec = cl->server->conf->network_timeout;
|
||||||
timeout.tv_usec = 0;
|
timeout.tv_usec = 0;
|
||||||
|
|
||||||
if( select(cl->socket + 1, NULL, &writer, NULL, &timeout) > 0 )
|
if (select(cl->socket + 1, NULL, &writer, NULL, &timeout) > 0)
|
||||||
{
|
return send(cl->socket, buf, len, 0);
|
||||||
#ifdef HAVE_TLS
|
|
||||||
if( cl->tls )
|
|
||||||
return cl->server->conf->tls_send(cl, (void *)buf, len);
|
|
||||||
else
|
|
||||||
#endif
|
|
||||||
return send(cl->socket, buf, len, 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int uh_tcp_send(struct client *cl, const char *buf, int len)
|
||||||
|
{
|
||||||
|
#ifdef HAVE_TLS
|
||||||
|
if (cl->tls)
|
||||||
|
return cl->server->conf->tls_send(cl, (void *)buf, len);
|
||||||
|
else
|
||||||
|
#endif
|
||||||
|
return uh_tcp_send_lowlevel(cl, buf, len);
|
||||||
|
}
|
||||||
|
|
||||||
int uh_tcp_peek(struct client *cl, char *buf, int len)
|
int uh_tcp_peek(struct client *cl, char *buf, int len)
|
||||||
{
|
{
|
||||||
|
/* sanity check, prevent overflowing peek buffer */
|
||||||
|
if (len > sizeof(cl->peekbuf))
|
||||||
|
return -1;
|
||||||
|
|
||||||
int sz = uh_tcp_recv(cl, buf, len);
|
int sz = uh_tcp_recv(cl, buf, len);
|
||||||
|
|
||||||
/* store received data in peek buffer */
|
/* store received data in peek buffer */
|
||||||
|
@ -162,49 +169,51 @@ int uh_tcp_peek(struct client *cl, char *buf, int len)
|
||||||
return sz;
|
return sz;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int uh_tcp_recv_lowlevel(struct client *cl, char *buf, int len)
|
||||||
|
{
|
||||||
|
fd_set reader;
|
||||||
|
struct timeval timeout;
|
||||||
|
|
||||||
|
FD_ZERO(&reader);
|
||||||
|
FD_SET(cl->socket, &reader);
|
||||||
|
|
||||||
|
timeout.tv_sec = cl->server->conf->network_timeout;
|
||||||
|
timeout.tv_usec = 0;
|
||||||
|
|
||||||
|
if (select(cl->socket + 1, &reader, NULL, NULL, &timeout) > 0)
|
||||||
|
return recv(cl->socket, buf, len, 0);
|
||||||
|
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
int uh_tcp_recv(struct client *cl, char *buf, int len)
|
int uh_tcp_recv(struct client *cl, char *buf, int len)
|
||||||
{
|
{
|
||||||
int sz = 0;
|
int sz = 0;
|
||||||
int rsz = 0;
|
int rsz = 0;
|
||||||
|
|
||||||
fd_set reader;
|
|
||||||
struct timeval timeout;
|
|
||||||
|
|
||||||
/* first serve data from peek buffer */
|
/* first serve data from peek buffer */
|
||||||
if( cl->peeklen > 0 )
|
if (cl->peeklen > 0)
|
||||||
{
|
{
|
||||||
sz = min(cl->peeklen, len);
|
sz = min(cl->peeklen, len);
|
||||||
len -= sz; cl->peeklen -= sz;
|
len -= sz; cl->peeklen -= sz;
|
||||||
|
|
||||||
memcpy(buf, cl->peekbuf, sz);
|
memcpy(buf, cl->peekbuf, sz);
|
||||||
memmove(cl->peekbuf, &cl->peekbuf[sz], cl->peeklen);
|
memmove(cl->peekbuf, &cl->peekbuf[sz], cl->peeklen);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* caller wants more */
|
/* caller wants more */
|
||||||
if( len > 0 )
|
if (len > 0)
|
||||||
{
|
{
|
||||||
FD_ZERO(&reader);
|
|
||||||
FD_SET(cl->socket, &reader);
|
|
||||||
|
|
||||||
timeout.tv_sec = cl->server->conf->network_timeout;
|
|
||||||
timeout.tv_usec = 0;
|
|
||||||
|
|
||||||
if( select(cl->socket + 1, &reader, NULL, NULL, &timeout) > 0 )
|
|
||||||
{
|
|
||||||
#ifdef HAVE_TLS
|
#ifdef HAVE_TLS
|
||||||
if( cl->tls )
|
if (cl->tls)
|
||||||
rsz = cl->server->conf->tls_recv(cl, (void *)&buf[sz], len);
|
rsz = cl->server->conf->tls_recv(cl, (void *)&buf[sz], len);
|
||||||
else
|
else
|
||||||
#endif
|
#endif
|
||||||
rsz = recv(cl->socket, (void *)&buf[sz], len, 0);
|
rsz = uh_tcp_recv_lowlevel(cl, (void *)&buf[sz], len);
|
||||||
|
|
||||||
if( (sz == 0) || (rsz > 0) )
|
if (rsz < 0)
|
||||||
sz += rsz;
|
return rsz;
|
||||||
}
|
|
||||||
else if( sz == 0 )
|
sz += rsz;
|
||||||
{
|
|
||||||
sz = -1;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return sz;
|
return sz;
|
||||||
|
|
|
@ -67,8 +67,10 @@ char *strfind(char *haystack, int hslen, const char *needle, int ndlen);
|
||||||
int select_intr(int n, fd_set *r, fd_set *w, fd_set *e, struct timeval *t);
|
int select_intr(int n, fd_set *r, fd_set *w, fd_set *e, struct timeval *t);
|
||||||
|
|
||||||
int uh_tcp_send(struct client *cl, const char *buf, int len);
|
int uh_tcp_send(struct client *cl, const char *buf, int len);
|
||||||
|
int uh_tcp_send_lowlevel(struct client *cl, const char *buf, int len);
|
||||||
int uh_tcp_peek(struct client *cl, char *buf, int len);
|
int uh_tcp_peek(struct client *cl, char *buf, int len);
|
||||||
int uh_tcp_recv(struct client *cl, char *buf, int len);
|
int uh_tcp_recv(struct client *cl, char *buf, int len);
|
||||||
|
int uh_tcp_recv_lowlevel(struct client *cl, char *buf, int len);
|
||||||
|
|
||||||
int uh_http_sendhf(
|
int uh_http_sendhf(
|
||||||
struct client *cl, int code, const char *summary,
|
struct client *cl, int code, const char *summary,
|
||||||
|
|
Loading…
Reference in a new issue