Building problems with evhtp
This commit is contained in:
parent
c7e7598e3b
commit
e9df7b81f2
10 changed files with 134 additions and 109 deletions
|
|
@ -12,9 +12,9 @@ There are two installation instructions: for libevhtp and nginx.
|
|||
|
||||
Download, build and install libevhtp from source. Prereqs: libevent and cmake.
|
||||
```
|
||||
git clone https://github.com/clicon/libevhtp.git
|
||||
cd libevhtp/build
|
||||
cmake -DEVHTP_DISABLE_REGEX=ON -DEVHTP_DISABLE_EVTHR=ON ..
|
||||
sudo git clone https://github.com/clicon/clixon-libevhtp.git
|
||||
cd clixon-libevhtp
|
||||
./configure --libdir=/usr/lib
|
||||
make
|
||||
sudo make install
|
||||
```
|
||||
|
|
|
|||
|
|
@ -50,6 +50,9 @@
|
|||
#include <openssl/err.h>
|
||||
|
||||
/* evhtp */
|
||||
#define EVHTP_DISABLE_REGEX
|
||||
#define EVHTP_DISABLE_EVTHR
|
||||
#define EVHTP_EXPORT
|
||||
#include <evhtp/evhtp.h>
|
||||
|
||||
/* cligen */
|
||||
|
|
|
|||
|
|
@ -134,6 +134,7 @@
|
|||
#include <pwd.h>
|
||||
#include <ctype.h>
|
||||
#include <assert.h>
|
||||
#include <signal.h>
|
||||
#include <sys/stat.h>
|
||||
#include <sys/socket.h>
|
||||
#include <arpa/inet.h>
|
||||
|
|
@ -151,6 +152,9 @@
|
|||
|
||||
/* evhtp */
|
||||
#include <event2/buffer.h> /* evbuffer */
|
||||
#define EVHTP_DISABLE_REGEX
|
||||
#define EVHTP_DISABLE_EVTHR
|
||||
#define EVHTP_EXPORT
|
||||
#include <evhtp/evhtp.h>
|
||||
#include <evhtp/sslutils.h> /* XXX inline this / use SSL directly */
|
||||
|
||||
|
|
@ -213,28 +217,24 @@ openspec_handle_set(clicon_handle h,
|
|||
* see also this function in restcont_api_openssl.c
|
||||
*/
|
||||
static ssize_t
|
||||
evbuf_write(struct evbuffer *ev,
|
||||
int s,
|
||||
SSL *ssl)
|
||||
buf_write(char *buf,
|
||||
size_t buflen,
|
||||
int s,
|
||||
SSL *ssl)
|
||||
{
|
||||
ssize_t retval = -1;
|
||||
size_t buflen;
|
||||
unsigned char *buf;
|
||||
int ret;
|
||||
|
||||
if ((buflen = evbuffer_get_length(ev)) > 0){
|
||||
buf = evbuffer_pullup(ev, -1);
|
||||
if (ssl){
|
||||
if ((ret = SSL_write(ssl, buf, buflen)) <= 0){
|
||||
clicon_err(OE_SSL, 0, "SSL_write");
|
||||
goto done;
|
||||
}
|
||||
if (ssl){
|
||||
if ((ret = SSL_write(ssl, buf, buflen)) <= 0){
|
||||
clicon_err(OE_SSL, 0, "SSL_write");
|
||||
goto done;
|
||||
}
|
||||
else{
|
||||
if (write(s, buf, buflen) < 0){
|
||||
clicon_err(OE_UNIX, errno, "write");
|
||||
goto done;
|
||||
}
|
||||
}
|
||||
else{
|
||||
if (write(s, buf, buflen) < 0){
|
||||
clicon_err(OE_UNIX, errno, "write");
|
||||
goto done;
|
||||
}
|
||||
}
|
||||
retval = 0;
|
||||
|
|
@ -787,6 +787,25 @@ close_openssl_socket(int s,
|
|||
return retval;
|
||||
}
|
||||
|
||||
/*! Send initial bad request reply before actual packet received, just after accept
|
||||
* @param[in] ssl if set, it will be freed
|
||||
*/
|
||||
static int
|
||||
accept_badrequest(clicon_handle h,
|
||||
int s,
|
||||
SSL *ssl)
|
||||
{
|
||||
int retval = -1;
|
||||
char *buf = "HTTP/1.1 400 Bad Request\r\nConnection: close\r\nContent-Length: 0\r\nContent-Type: text/plain\r\n\r\n";
|
||||
|
||||
clicon_debug(1, "%s", __FUNCTION__);
|
||||
if (buf_write(buf, strlen(buf)+1, s, ssl) < 0)
|
||||
goto done;
|
||||
retval = 0;
|
||||
done:
|
||||
return retval;
|
||||
}
|
||||
|
||||
/*! New data connection after accept, receive and reply on data sockte
|
||||
*
|
||||
* @param[in] s Socket where message arrived. read from this.
|
||||
|
|
@ -798,7 +817,7 @@ close_openssl_socket(int s,
|
|||
*/
|
||||
static int
|
||||
restconf_connection(int s,
|
||||
void* arg)
|
||||
void *arg)
|
||||
{
|
||||
int retval = -1;
|
||||
evhtp_connection_t *conn = NULL;
|
||||
|
|
@ -830,6 +849,7 @@ restconf_connection(int s,
|
|||
}
|
||||
}
|
||||
if (n == 0){
|
||||
clicon_debug(1, "%s n=0 closing socket", __FUNCTION__);
|
||||
ssl = conn->ssl;
|
||||
conn->ssl = NULL;
|
||||
evhtp_connection_free(conn); /* evhtp */
|
||||
|
|
@ -841,27 +861,43 @@ restconf_connection(int s,
|
|||
* signature:
|
||||
*/
|
||||
if (connection_parse_nobev(buf, n, conn) < 0){
|
||||
evhtp_request_t *er;
|
||||
er = evhtp_request_new(NULL, NULL);
|
||||
er->conn = conn;
|
||||
conn->request = er;
|
||||
htparser_set_major(conn->parser, '\1');
|
||||
htparser_set_minor(conn->parser, '\1');
|
||||
if (restconf_badrequest(h, er) < 0)
|
||||
clicon_debug(1, "%s connection_parse error", __FUNCTION__);
|
||||
if (accept_badrequest(h, s, conn->ssl) < 0)
|
||||
goto done;
|
||||
if (conn->bev != NULL)
|
||||
if (evbuf_write(bufferevent_get_output(conn->bev), s, NULL) < 0)
|
||||
goto done;
|
||||
evhtp_connection_free(conn);
|
||||
SSL_free(ssl);
|
||||
if (close_openssl_socket(s, NULL) < 0)
|
||||
goto done;
|
||||
conn->ssl = NULL;
|
||||
evhtp_connection_free(conn);
|
||||
goto ok;
|
||||
}
|
||||
if (conn->bev != NULL){
|
||||
/* This is for 100 Continue, typically bev is set but output is empty
|
||||
* if sent by fini callback
|
||||
*/
|
||||
if (evbuf_write(bufferevent_get_output(conn->bev), conn->sock, conn->ssl) < 0)
|
||||
char *buf = NULL;
|
||||
size_t buflen;
|
||||
struct evbuffer *ev;
|
||||
|
||||
if ((ev = bufferevent_get_output(conn->bev)) != NULL){
|
||||
buf = (char*)evbuffer_pullup(ev, -1);
|
||||
buflen = evbuffer_get_length(ev);
|
||||
if (buflen){
|
||||
if (buf_write(buf, buflen, conn->sock, conn->ssl) < 0)
|
||||
goto done;
|
||||
}
|
||||
else{
|
||||
clicon_debug(1, "%s bev is NULL 1", __FUNCTION__);
|
||||
if (accept_badrequest(h, s, conn->ssl) < 0) /* actually error */
|
||||
goto done;
|
||||
}
|
||||
}
|
||||
else{
|
||||
clicon_debug(1, "%s bev is NULL 2", __FUNCTION__);
|
||||
if (accept_badrequest(h, s, conn->ssl) < 0) /* actually error */
|
||||
goto done;
|
||||
}
|
||||
}
|
||||
else{
|
||||
clicon_debug(1, "%s bev is NULL 3", __FUNCTION__);
|
||||
if (accept_badrequest(h, s, conn->ssl) < 0) /* actually error */
|
||||
goto done;
|
||||
}
|
||||
ok:
|
||||
|
|
@ -935,43 +971,6 @@ restconf_checkcert_file(cxobj *xrestconf,
|
|||
return retval;
|
||||
}
|
||||
|
||||
/*! Send initial bad request reply before actual packet received, just after accept
|
||||
* @param[in] ssl if set, it will be freed
|
||||
*/
|
||||
static int
|
||||
accept_badrequest(clicon_handle h,
|
||||
int s,
|
||||
SSL *ssl,
|
||||
evhtp_connection_t *conn)
|
||||
{
|
||||
int retval = -1;
|
||||
evhtp_request_t *er;
|
||||
|
||||
/*
|
||||
* Since message has not been read, the reply is constructed manually
|
||||
* using http 1.1
|
||||
* See note (1) http to https port:
|
||||
*/
|
||||
er = evhtp_request_new(NULL, NULL);
|
||||
er->conn = conn;
|
||||
conn->request = er;
|
||||
conn->ssl = NULL;
|
||||
htparser_set_major(conn->parser, '\1');
|
||||
htparser_set_minor(conn->parser, '\1');
|
||||
if (restconf_badrequest(h, er) < 0)
|
||||
goto done;
|
||||
/* XXX: should there be a body? */
|
||||
if (conn->bev != NULL)
|
||||
if (evbuf_write(bufferevent_get_output(conn->bev), s, ssl) < 0)
|
||||
goto done;
|
||||
evhtp_connection_free(conn);
|
||||
if (close_openssl_socket(s, ssl) < 0)
|
||||
goto done;
|
||||
retval = 0;
|
||||
done:
|
||||
return retval;
|
||||
}
|
||||
|
||||
/*! Accept new socket client
|
||||
* @param[in] fd Socket (unix or ip)
|
||||
* @param[in] arg typecast clicon_handle
|
||||
|
|
@ -993,7 +992,8 @@ restconf_accept_client(int fd,
|
|||
int ret;
|
||||
evhtp_t *evhtp = NULL;
|
||||
evhtp_connection_t *conn;
|
||||
|
||||
int e;
|
||||
|
||||
clicon_debug(1, "%s %d", __FUNCTION__, fd);
|
||||
if (rsock == NULL){
|
||||
clicon_err(OE_YANG, EINVAL, "rsock is NULL");
|
||||
|
|
@ -1052,17 +1052,23 @@ restconf_accept_client(int fd,
|
|||
* Both error cases: Call SSL_get_error() with the return value ret
|
||||
*/
|
||||
if ((ret = SSL_accept(ssl)) != 1) {
|
||||
int e = SSL_get_error(ssl, ret);
|
||||
e = SSL_get_error(ssl, ret);
|
||||
|
||||
switch (e){
|
||||
case SSL_ERROR_SSL: { /* 1 */
|
||||
if (accept_badrequest(h, s, NULL, conn) < 0)
|
||||
case SSL_ERROR_SSL: /* 1 */
|
||||
clicon_debug(1, "%s SSL_ERROR_SSL (not ssl mesage on ssl socket)", __FUNCTION__);
|
||||
if (accept_badrequest(h, s, NULL) < 0)
|
||||
goto done;
|
||||
SSL_free(ssl);
|
||||
if (close_openssl_socket(s, NULL) < 0)
|
||||
goto done;
|
||||
conn->ssl = NULL;
|
||||
evhtp_connection_free(conn);
|
||||
goto ok;
|
||||
}
|
||||
break;
|
||||
case SSL_ERROR_SYSCALL: /* 5 */
|
||||
/* look at error stack/return value/errno */
|
||||
clicon_debug(1, "%s SSL_ERROR_SYSCALL", __FUNCTION__);
|
||||
SSL_free(ssl);
|
||||
if (close_openssl_socket(s, NULL) < 0)
|
||||
goto done;
|
||||
|
|
@ -1092,8 +1098,18 @@ restconf_accept_client(int fd,
|
|||
*/
|
||||
if (restconf_auth_type_get(h) == CLIXON_AUTH_CLIENT_CERTIFICATE &&
|
||||
SSL_get_peer_certificate(ssl) == NULL) { /* Get certificates (if available) */
|
||||
if (accept_badrequest(h, s, ssl, conn) < 0)
|
||||
if (accept_badrequest(h, s, ssl) < 0)
|
||||
goto done;
|
||||
if (ssl){
|
||||
if ((ret = SSL_shutdown(ssl)) < 0){
|
||||
int e = SSL_get_error(ssl, ret);
|
||||
clicon_err(OE_SSL, 0, "SSL_shutdown, err:%d", e);
|
||||
goto done;
|
||||
}
|
||||
SSL_free(ssl);
|
||||
}
|
||||
// close(s); Error (56 != 0) in Test14 [No cert: certificate required]:
|
||||
// clixon_event_unreg_fd(s, restconf_connection);
|
||||
goto ok;
|
||||
}
|
||||
/* Get the actual peer, XXX this maybe could be done in ca-auth client-cert code ?
|
||||
|
|
|
|||
10
configure
vendored
10
configure
vendored
|
|
@ -4992,7 +4992,6 @@ else
|
|||
with_restconf=fcgi
|
||||
fi
|
||||
|
||||
|
||||
# Actions for each specific package
|
||||
if test "x${with_restconf}" == xfcgi; then
|
||||
# Lives in libfcgi-dev
|
||||
|
|
@ -5187,7 +5186,12 @@ fi
|
|||
|
||||
for ac_header in evhtp/evhtp.h
|
||||
do :
|
||||
ac_fn_c_check_header_mongrel "$LINENO" "evhtp/evhtp.h" "ac_cv_header_evhtp_evhtp_h" "$ac_includes_default"
|
||||
ac_fn_c_check_header_compile "$LINENO" "evhtp/evhtp.h" "ac_cv_header_evhtp_evhtp_h" "$ac_includes_default
|
||||
#define EVHTP_DISABLE_REGEX
|
||||
#define EVHTP_DISABLE_EVTHR
|
||||
#define EVHTP_EXPORT
|
||||
|
||||
"
|
||||
if test "x$ac_cv_header_evhtp_evhtp_h" = xyes; then :
|
||||
cat >>confdefs.h <<_ACEOF
|
||||
#define HAVE_EVHTP_EVHTP_H 1
|
||||
|
|
@ -5246,7 +5250,6 @@ else
|
|||
as_fn_error $? "libevhtp missing" "$LINENO" 5
|
||||
fi
|
||||
|
||||
|
||||
elif test "x${with_restconf}" == xno; then
|
||||
# Cant get around "no" as an answer for --without-restconf that is reset here to undefined
|
||||
with_restconf=
|
||||
|
|
@ -5254,6 +5257,7 @@ else
|
|||
as_fn_error $? "No such restconf package: ${with_restconf}" "$LINENO" 5
|
||||
fi
|
||||
|
||||
|
||||
if test "x${with_restconf}" != "x"; then
|
||||
# This is so it appears in config.h
|
||||
|
||||
|
|
|
|||
12
configure.ac
12
configure.ac
|
|
@ -205,7 +205,6 @@ AC_ARG_WITH([restconf],
|
|||
AS_HELP_STRING([--with-restconf=fcgi],[FCGI interface for stand-alone web rev-proxy eg nginx (default)]),
|
||||
,
|
||||
[with_restconf=fcgi])
|
||||
|
||||
# Actions for each specific package
|
||||
if test "x${with_restconf}" == xfcgi; then
|
||||
# Lives in libfcgi-dev
|
||||
|
|
@ -214,9 +213,15 @@ elif test "x${with_restconf}" == xevhtp; then
|
|||
AC_CHECK_LIB(ssl, OPENSSL_init_ssl ,, AC_MSG_ERROR([libssl missing]))
|
||||
AC_CHECK_LIB(crypto, CRYPTO_new_ex_data, , AC_MSG_ERROR([libcrypto missing]))
|
||||
AC_CHECK_LIB(event, event_init,, AC_MSG_ERROR([libevent missing]))
|
||||
AC_CHECK_HEADERS(evhtp/evhtp.h,, AC_MSG_ERROR([evhtp header missing. See https://github.com/clicon/libevhtp]))
|
||||
AC_CHECK_HEADERS(evhtp/evhtp.h,
|
||||
[],
|
||||
AC_MSG_ERROR([evhtp header missing. See https://github.com/clicon/libevhtp]),
|
||||
[AC_INCLUDES_DEFAULT[
|
||||
#define EVHTP_DISABLE_REGEX
|
||||
#define EVHTP_DISABLE_EVTHR
|
||||
#define EVHTP_EXPORT
|
||||
]])
|
||||
AC_CHECK_LIB(evhtp, evhtp_new,, AC_MSG_ERROR([libevhtp missing]),[-lpthread -levent -levent_openssl -lssl -lcrypto])
|
||||
|
||||
elif test "x${with_restconf}" == xno; then
|
||||
# Cant get around "no" as an answer for --without-restconf that is reset here to undefined
|
||||
with_restconf=
|
||||
|
|
@ -224,6 +229,7 @@ else
|
|||
AC_MSG_ERROR([No such restconf package: ${with_restconf}])
|
||||
fi
|
||||
|
||||
|
||||
if test "x${with_restconf}" != "x"; then
|
||||
# This is so it appears in config.h
|
||||
AC_DEFINE_UNQUOTED(WITH_RESTCONF, ${with_restconf}, [Restconf package])
|
||||
|
|
|
|||
|
|
@ -41,15 +41,15 @@ RUN apk add --update git make build-base gcc flex bison curl-dev
|
|||
# Create a directory to hold source-code, dependencies etc
|
||||
RUN mkdir /clixon
|
||||
|
||||
# libevht
|
||||
# evhtp
|
||||
# dependencies
|
||||
RUN apk add --update libevent cmake libevent-dev
|
||||
RUN apk add --update libevent libevent-dev
|
||||
|
||||
# clone libevhtp
|
||||
WORKDIR /clixon
|
||||
|
||||
RUN git clone https://github.com/clicon/clixon-libevhtp.git
|
||||
WORKDIR /clixon/libevhtp
|
||||
WORKDIR /clixon/clixon-libevhtp
|
||||
RUN ./configure
|
||||
|
||||
RUN make
|
||||
|
|
|
|||
|
|
@ -254,7 +254,7 @@ example_basic_auth(clicon_handle h,
|
|||
user=NULL; /* to avoid free below */
|
||||
retval = 1;
|
||||
done: /* error */
|
||||
clicon_debug(1, "%s retval:%d authp:%s", __FUNCTION__, retval, *authp);
|
||||
clicon_debug(1, "%s retval:%d authp:%s", __FUNCTION__, retval, authp?"":*authp);
|
||||
if (user)
|
||||
free(user);
|
||||
if (cb)
|
||||
|
|
@ -324,7 +324,7 @@ example_no_auth(clicon_handle h,
|
|||
user=NULL; /* to avoid free below */
|
||||
retval = 1;
|
||||
done: /* error */
|
||||
clicon_debug(1, "%s retval:%d authp:%s", __FUNCTION__, retval, *authp);
|
||||
clicon_debug(1, "%s retval:%d authp:%s", __FUNCTION__, retval, authp?"":*authp);
|
||||
if (user)
|
||||
free(user);
|
||||
if (cb)
|
||||
|
|
|
|||
|
|
@ -105,10 +105,9 @@ EOF
|
|||
|
||||
new "wait backend"
|
||||
wait_backend
|
||||
else
|
||||
new "Restart backend as eg follows: -Ff $cfg -s $db"
|
||||
sleep 2
|
||||
fi
|
||||
new "wait backend"
|
||||
wait_backend
|
||||
|
||||
if [ $RC -ne 0 ]; then # Bring your own restconf
|
||||
new "kill old restconf daemon"
|
||||
|
|
@ -116,10 +115,9 @@ EOF
|
|||
|
||||
new "start restconf daemon"
|
||||
start_restconf -f $cfg
|
||||
|
||||
new "wait restconf"
|
||||
wait_restconf
|
||||
fi
|
||||
new "wait restconf"
|
||||
wait_restconf
|
||||
|
||||
# Use POST (instead of startup)
|
||||
# Note this only works because CLICON_NACM_DISABLED_ON_EMPTY is true
|
||||
|
|
@ -177,9 +175,12 @@ EOF
|
|||
status="HTTP/1.1 200 OK"
|
||||
;;
|
||||
esac
|
||||
|
||||
new "get 99"
|
||||
expectpart "$(curl -u guest:bar $CURLOPTS -X GET $RCPROTO://localhost/restconf/data/nacm-example:x)" 0 "$status" "$ret"
|
||||
|
||||
sleep $DEMSLEEP
|
||||
|
||||
if [ $RC -ne 0 ]; then # Bring your own restconf
|
||||
new "Kill restconf daemon"
|
||||
stop_restconf
|
||||
|
|
|
|||
|
|
@ -184,10 +184,10 @@ nacm
|
|||
# delete | p/d | xp/dx | p/d
|
||||
|
||||
# replace all, then must include NACM rules as well
|
||||
# This usually triggers a 'HTTP/1.1 100 Continue' from curl as well
|
||||
MSG="<data>$RULES</data>"
|
||||
new "update root list permit"
|
||||
expectpart "$(curl -u andy:bar $CURLOPTS -H 'Content-Type: application/yang-data+xml' -X PUT $RCPROTO://localhost/restconf/data -d "$MSG")" 0 'HTTP/1.1 204 No Content'
|
||||
# Usually a 'HTTP/1.1 100 Continue' as well
|
||||
|
||||
new "delete root list deny"
|
||||
expectpart "$(curl -u wilma:bar $CURLOPTS -X DELETE $RCPROTO://localhost/restconf/data)" 0 'HTTP/1.1 403 Forbidden' '{"ietf-restconf:errors":{"error":{"error-type":"application","error-tag":"access-denied","error-severity":"error","error-message":"default deny"}}}
'
|
||||
|
|
|
|||
|
|
@ -97,7 +97,6 @@ system=$($sshcmd uname) # we use the release "hack" instead
|
|||
|
||||
# Some release have packages, some need to be built from source
|
||||
buildfcgi=false
|
||||
buildevhtp=false
|
||||
case $release in
|
||||
openbsd)
|
||||
# packages for building
|
||||
|
|
@ -130,7 +129,7 @@ case $release in
|
|||
$sshcmd sudo pkg install -y fcgi-devkit nginx
|
||||
;;
|
||||
evhtp)
|
||||
$sshcmd sudo pkg install -y libevent libevhtp
|
||||
$sshcmd sudo pkg install -y libevent
|
||||
;;
|
||||
esac
|
||||
;;
|
||||
|
|
@ -157,7 +156,6 @@ case $release in
|
|||
;;
|
||||
evhtp)
|
||||
$sshcmd sudo yum install -y libevent openssl
|
||||
buildevhtp=true
|
||||
$sshcmd sudo yum install -y libevent-devel openssl-devel
|
||||
;;
|
||||
esac
|
||||
|
|
@ -203,7 +201,6 @@ case $release in
|
|||
;;
|
||||
evhtp)
|
||||
# $sshcmd sudo apt install -y libevent-2.1
|
||||
buildevhtp=true
|
||||
$sshcmd sudo apt install -y libevent-dev libssl-dev
|
||||
;;
|
||||
esac
|
||||
|
|
@ -257,15 +254,13 @@ case ${with_restconf} in
|
|||
. ./nginx.sh $dir $idfile $port $wwwuser
|
||||
;;
|
||||
evhtp)
|
||||
if $buildevhtp; then
|
||||
$sshcmd << 'EOF'
|
||||
test -d libevhtp || git clone https://github.com/clicon/libevhtp.git
|
||||
cd libevhtp;
|
||||
./configure --libdir=/usr/lib # otherwise in /usr/local/lib where RH dont look
|
||||
make
|
||||
sudo make install
|
||||
$sshcmd << 'EOF'
|
||||
test -d clixon-libevhtp || git clone https://github.com/clicon/clixon-libevhtp.git
|
||||
cd clixon-libevhtp;
|
||||
./configure --libdir=/usr/lib # otherwise in /usr/local/lib where RH dont look
|
||||
make
|
||||
sudo make install
|
||||
EOF
|
||||
fi
|
||||
;;
|
||||
esac
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue