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:=
|
||||
TLS_CFLAGS:=
|
||||
TLS_LDFLAGS:=
|
||||
|
||||
ifneq ($(CONFIG_PACKAGE_uhttpd-mod-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
|
||||
|
||||
ifneq ($(CONFIG_PACKAGE_uhttpd-mod-tls_openssl),)
|
||||
UHTTPD_TLS:=openssl
|
||||
TLS_CFLAGS:=-DTLS_IS_OPENSSL
|
||||
endif
|
||||
|
||||
|
||||
|
|
|
@ -3,19 +3,17 @@ LUA_SUPPORT ?= 1
|
|||
TLS_SUPPORT ?= 1
|
||||
UHTTPD_TLS ?= cyassl
|
||||
|
||||
CFLAGS ?= -I./lua-5.1.4/src -I$(TLS_INCLUDE_DIR) -O0 -ggdb3
|
||||
LDFLAGS ?= -L./lua-5.1.4/src -L$(TLS_LIB_DIR)
|
||||
CFLAGS ?= -I./lua-5.1.4/src $(TLS_CFLAGS) -O0 -ggdb3
|
||||
LDFLAGS ?= -L./lua-5.1.4/src $(TLS_LDFLAGS)
|
||||
|
||||
CFLAGS += -Wall --std=gnu99
|
||||
|
||||
ifeq ($(UHTTPD_TLS),openssl)
|
||||
TLS_LDFLAGS := -lssl
|
||||
TLS_INCLUDE_DIR := ./openssl-0.9.8m/include
|
||||
TLS_LIB_DIR := ./openssl-0.9.8m
|
||||
TLS_LDFLAGS := -L./openssl-0.9.8m -lssl
|
||||
TLS_CFLAGS := -I./openssl-0.9.8m/include -DTLS_IS_OPENSSL
|
||||
else
|
||||
TLS_LDFLAGS := -lcyassl
|
||||
TLS_INCLUDE_DIR := ./cyassl-1.4.0/include
|
||||
TLS_LIB_DIR := ./cyassl-1.4.0/src/.libs
|
||||
TLS_LDFLAGS := -L./cyassl-1.4.0/src/.libs -lcyassl
|
||||
TLS_CFLAGS := -I./cyassl-1.4.0/include -DTLS_IS_CYASSL
|
||||
endif
|
||||
|
||||
OBJ := uhttpd.o uhttpd-file.o uhttpd-utils.o
|
||||
|
@ -31,15 +29,26 @@ ifeq ($(HAVE_SHADOW),yes)
|
|||
CFLAGS += -DHAVE_SHADOW
|
||||
endif
|
||||
|
||||
world: compile
|
||||
ifeq ($(TLS_SUPPORT),1)
|
||||
CFLAGS += -DHAVE_TLS
|
||||
endif
|
||||
|
||||
ifeq ($(CGI_SUPPORT),1)
|
||||
OBJ += uhttpd-cgi.o
|
||||
CFLAGS += -DHAVE_CGI
|
||||
endif
|
||||
|
||||
ifeq ($(LUA_SUPPORT),1)
|
||||
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.c
|
||||
|
@ -49,12 +58,11 @@ ifeq ($(LUA_SUPPORT),1)
|
|||
endif
|
||||
|
||||
ifeq ($(TLS_SUPPORT),1)
|
||||
CFLAGS += -DHAVE_TLS
|
||||
TLSLIB := uhttpd_tls.so
|
||||
|
||||
$(TLSLIB): uhttpd-tls.c
|
||||
$(CC) $(CFLAGS) $(LDFLAGS) $(FPIC) \
|
||||
-shared $(TLS_LDFLAGS) \
|
||||
-shared \
|
||||
-o $(TLSLIB) uhttpd-tls.c
|
||||
endif
|
||||
|
||||
|
|
|
@ -20,6 +20,143 @@
|
|||
#include "uhttpd-tls.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()
|
||||
{
|
||||
|
@ -28,8 +165,8 @@ SSL_CTX * uh_tls_ctx_init()
|
|||
SSL_load_error_strings();
|
||||
SSL_library_init();
|
||||
|
||||
if( (c = SSL_CTX_new(TLSv1_server_method())) != NULL )
|
||||
SSL_CTX_set_verify(c, SSL_VERIFY_NONE, NULL);
|
||||
if ((c = SSL_CTX_new(TLSv1_server_method())) != NULL)
|
||||
uh_tls_ctx_setup(c);
|
||||
|
||||
return c;
|
||||
}
|
||||
|
@ -69,8 +206,9 @@ int uh_tls_client_accept(struct client *c)
|
|||
c->tls = SSL_new(c->server->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;
|
||||
|
||||
if( (rv = SSL_accept(c->tls)) < 1 )
|
||||
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;
|
||||
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_usec = 0;
|
||||
|
||||
if( select(cl->socket + 1, NULL, &writer, NULL, &timeout) > 0 )
|
||||
{
|
||||
#ifdef HAVE_TLS
|
||||
if( cl->tls )
|
||||
return cl->server->conf->tls_send(cl, (void *)buf, len);
|
||||
else
|
||||
#endif
|
||||
if (select(cl->socket + 1, NULL, &writer, NULL, &timeout) > 0)
|
||||
return send(cl->socket, buf, len, 0);
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
/* sanity check, prevent overflowing peek buffer */
|
||||
if (len > sizeof(cl->peekbuf))
|
||||
return -1;
|
||||
|
||||
int sz = uh_tcp_recv(cl, buf, len);
|
||||
|
||||
/* store received data in peek buffer */
|
||||
|
@ -162,50 +169,52 @@ int uh_tcp_peek(struct client *cl, char *buf, int len)
|
|||
return sz;
|
||||
}
|
||||
|
||||
int uh_tcp_recv(struct client *cl, char *buf, int len)
|
||||
int uh_tcp_recv_lowlevel(struct client *cl, char *buf, int len)
|
||||
{
|
||||
int sz = 0;
|
||||
int rsz = 0;
|
||||
|
||||
fd_set reader;
|
||||
struct timeval timeout;
|
||||
|
||||
/* first serve data from peek buffer */
|
||||
if( cl->peeklen > 0 )
|
||||
{
|
||||
sz = min(cl->peeklen, len);
|
||||
len -= sz; cl->peeklen -= sz;
|
||||
|
||||
memcpy(buf, cl->peekbuf, sz);
|
||||
memmove(cl->peekbuf, &cl->peekbuf[sz], cl->peeklen);
|
||||
}
|
||||
|
||||
/* caller wants more */
|
||||
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 )
|
||||
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 sz = 0;
|
||||
int rsz = 0;
|
||||
|
||||
/* first serve data from peek buffer */
|
||||
if (cl->peeklen > 0)
|
||||
{
|
||||
sz = min(cl->peeklen, len);
|
||||
len -= sz; cl->peeklen -= sz;
|
||||
memcpy(buf, cl->peekbuf, sz);
|
||||
memmove(cl->peekbuf, &cl->peekbuf[sz], cl->peeklen);
|
||||
}
|
||||
|
||||
/* caller wants more */
|
||||
if (len > 0)
|
||||
{
|
||||
#ifdef HAVE_TLS
|
||||
if( cl->tls )
|
||||
if (cl->tls)
|
||||
rsz = cl->server->conf->tls_recv(cl, (void *)&buf[sz], len);
|
||||
else
|
||||
#endif
|
||||
rsz = recv(cl->socket, (void *)&buf[sz], len, 0);
|
||||
rsz = uh_tcp_recv_lowlevel(cl, (void *)&buf[sz], len);
|
||||
|
||||
if (rsz < 0)
|
||||
return rsz;
|
||||
|
||||
if( (sz == 0) || (rsz > 0) )
|
||||
sz += rsz;
|
||||
}
|
||||
else if( sz == 0 )
|
||||
{
|
||||
sz = -1;
|
||||
}
|
||||
}
|
||||
|
||||
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 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_recv(struct client *cl, char *buf, int len);
|
||||
int uh_tcp_recv_lowlevel(struct client *cl, char *buf, int len);
|
||||
|
||||
int uh_http_sendhf(
|
||||
struct client *cl, int code, const char *summary,
|
||||
|
|
Loading…
Reference in a new issue