Building problems with evhtp

This commit is contained in:
Olof hagsand 2021-03-31 12:55:38 +02:00
parent c7e7598e3b
commit e9df7b81f2
10 changed files with 134 additions and 109 deletions

View file

@ -12,9 +12,9 @@ There are two installation instructions: for libevhtp and nginx.
Download, build and install libevhtp from source. Prereqs: libevent and cmake. Download, build and install libevhtp from source. Prereqs: libevent and cmake.
``` ```
git clone https://github.com/clicon/libevhtp.git sudo git clone https://github.com/clicon/clixon-libevhtp.git
cd libevhtp/build cd clixon-libevhtp
cmake -DEVHTP_DISABLE_REGEX=ON -DEVHTP_DISABLE_EVTHR=ON .. ./configure --libdir=/usr/lib
make make
sudo make install sudo make install
``` ```

View file

@ -50,6 +50,9 @@
#include <openssl/err.h> #include <openssl/err.h>
/* evhtp */ /* evhtp */
#define EVHTP_DISABLE_REGEX
#define EVHTP_DISABLE_EVTHR
#define EVHTP_EXPORT
#include <evhtp/evhtp.h> #include <evhtp/evhtp.h>
/* cligen */ /* cligen */

View file

@ -134,6 +134,7 @@
#include <pwd.h> #include <pwd.h>
#include <ctype.h> #include <ctype.h>
#include <assert.h> #include <assert.h>
#include <signal.h>
#include <sys/stat.h> #include <sys/stat.h>
#include <sys/socket.h> #include <sys/socket.h>
#include <arpa/inet.h> #include <arpa/inet.h>
@ -151,6 +152,9 @@
/* evhtp */ /* evhtp */
#include <event2/buffer.h> /* evbuffer */ #include <event2/buffer.h> /* evbuffer */
#define EVHTP_DISABLE_REGEX
#define EVHTP_DISABLE_EVTHR
#define EVHTP_EXPORT
#include <evhtp/evhtp.h> #include <evhtp/evhtp.h>
#include <evhtp/sslutils.h> /* XXX inline this / use SSL directly */ #include <evhtp/sslutils.h> /* XXX inline this / use SSL directly */
@ -213,17 +217,14 @@ openspec_handle_set(clicon_handle h,
* see also this function in restcont_api_openssl.c * see also this function in restcont_api_openssl.c
*/ */
static ssize_t static ssize_t
evbuf_write(struct evbuffer *ev, buf_write(char *buf,
size_t buflen,
int s, int s,
SSL *ssl) SSL *ssl)
{ {
ssize_t retval = -1; ssize_t retval = -1;
size_t buflen;
unsigned char *buf;
int ret; int ret;
if ((buflen = evbuffer_get_length(ev)) > 0){
buf = evbuffer_pullup(ev, -1);
if (ssl){ if (ssl){
if ((ret = SSL_write(ssl, buf, buflen)) <= 0){ if ((ret = SSL_write(ssl, buf, buflen)) <= 0){
clicon_err(OE_SSL, 0, "SSL_write"); clicon_err(OE_SSL, 0, "SSL_write");
@ -236,7 +237,6 @@ evbuf_write(struct evbuffer *ev,
goto done; goto done;
} }
} }
}
retval = 0; retval = 0;
done: done:
return retval; return retval;
@ -787,6 +787,25 @@ close_openssl_socket(int s,
return retval; 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 /*! New data connection after accept, receive and reply on data sockte
* *
* @param[in] s Socket where message arrived. read from this. * @param[in] s Socket where message arrived. read from this.
@ -830,6 +849,7 @@ restconf_connection(int s,
} }
} }
if (n == 0){ if (n == 0){
clicon_debug(1, "%s n=0 closing socket", __FUNCTION__);
ssl = conn->ssl; ssl = conn->ssl;
conn->ssl = NULL; conn->ssl = NULL;
evhtp_connection_free(conn); /* evhtp */ evhtp_connection_free(conn); /* evhtp */
@ -841,27 +861,43 @@ restconf_connection(int s,
* signature: * signature:
*/ */
if (connection_parse_nobev(buf, n, conn) < 0){ if (connection_parse_nobev(buf, n, conn) < 0){
evhtp_request_t *er; clicon_debug(1, "%s connection_parse error", __FUNCTION__);
er = evhtp_request_new(NULL, NULL); if (accept_badrequest(h, s, conn->ssl) < 0)
er->conn = conn;
conn->request = er;
htparser_set_major(conn->parser, '\1');
htparser_set_minor(conn->parser, '\1');
if (restconf_badrequest(h, er) < 0)
goto done; goto done;
if (conn->bev != NULL) SSL_free(ssl);
if (evbuf_write(bufferevent_get_output(conn->bev), s, NULL) < 0)
goto done;
evhtp_connection_free(conn);
if (close_openssl_socket(s, NULL) < 0) if (close_openssl_socket(s, NULL) < 0)
goto done; goto done;
conn->ssl = NULL;
evhtp_connection_free(conn);
goto ok; goto ok;
} }
if (conn->bev != NULL){ if (conn->bev != NULL){
/* This is for 100 Continue, typically bev is set but output is empty char *buf = NULL;
* if sent by fini callback size_t buflen;
*/ struct evbuffer *ev;
if (evbuf_write(bufferevent_get_output(conn->bev), conn->sock, conn->ssl) < 0)
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; goto done;
} }
ok: ok:
@ -935,43 +971,6 @@ restconf_checkcert_file(cxobj *xrestconf,
return retval; 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 /*! Accept new socket client
* @param[in] fd Socket (unix or ip) * @param[in] fd Socket (unix or ip)
* @param[in] arg typecast clicon_handle * @param[in] arg typecast clicon_handle
@ -993,6 +992,7 @@ restconf_accept_client(int fd,
int ret; int ret;
evhtp_t *evhtp = NULL; evhtp_t *evhtp = NULL;
evhtp_connection_t *conn; evhtp_connection_t *conn;
int e;
clicon_debug(1, "%s %d", __FUNCTION__, fd); clicon_debug(1, "%s %d", __FUNCTION__, fd);
if (rsock == NULL){ if (rsock == NULL){
@ -1052,17 +1052,23 @@ restconf_accept_client(int fd,
* Both error cases: Call SSL_get_error() with the return value ret * Both error cases: Call SSL_get_error() with the return value ret
*/ */
if ((ret = SSL_accept(ssl)) != 1) { if ((ret = SSL_accept(ssl)) != 1) {
int e = SSL_get_error(ssl, ret); e = SSL_get_error(ssl, ret);
switch (e){ switch (e){
case SSL_ERROR_SSL: { /* 1 */ case SSL_ERROR_SSL: /* 1 */
if (accept_badrequest(h, s, NULL, conn) < 0) clicon_debug(1, "%s SSL_ERROR_SSL (not ssl mesage on ssl socket)", __FUNCTION__);
if (accept_badrequest(h, s, NULL) < 0)
goto done; goto done;
SSL_free(ssl); SSL_free(ssl);
if (close_openssl_socket(s, NULL) < 0)
goto done;
conn->ssl = NULL;
evhtp_connection_free(conn);
goto ok; goto ok;
}
break; break;
case SSL_ERROR_SYSCALL: /* 5 */ case SSL_ERROR_SYSCALL: /* 5 */
/* look at error stack/return value/errno */ /* look at error stack/return value/errno */
clicon_debug(1, "%s SSL_ERROR_SYSCALL", __FUNCTION__);
SSL_free(ssl); SSL_free(ssl);
if (close_openssl_socket(s, NULL) < 0) if (close_openssl_socket(s, NULL) < 0)
goto done; goto done;
@ -1092,8 +1098,18 @@ restconf_accept_client(int fd,
*/ */
if (restconf_auth_type_get(h) == CLIXON_AUTH_CLIENT_CERTIFICATE && if (restconf_auth_type_get(h) == CLIXON_AUTH_CLIENT_CERTIFICATE &&
SSL_get_peer_certificate(ssl) == NULL) { /* Get certificates (if available) */ 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; 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; goto ok;
} }
/* Get the actual peer, XXX this maybe could be done in ca-auth client-cert code ? /* Get the actual peer, XXX this maybe could be done in ca-auth client-cert code ?

10
configure vendored
View file

@ -4992,7 +4992,6 @@ else
with_restconf=fcgi with_restconf=fcgi
fi fi
# Actions for each specific package # Actions for each specific package
if test "x${with_restconf}" == xfcgi; then if test "x${with_restconf}" == xfcgi; then
# Lives in libfcgi-dev # Lives in libfcgi-dev
@ -5187,7 +5186,12 @@ fi
for ac_header in evhtp/evhtp.h for ac_header in evhtp/evhtp.h
do : 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 : if test "x$ac_cv_header_evhtp_evhtp_h" = xyes; then :
cat >>confdefs.h <<_ACEOF cat >>confdefs.h <<_ACEOF
#define HAVE_EVHTP_EVHTP_H 1 #define HAVE_EVHTP_EVHTP_H 1
@ -5246,7 +5250,6 @@ else
as_fn_error $? "libevhtp missing" "$LINENO" 5 as_fn_error $? "libevhtp missing" "$LINENO" 5
fi fi
elif test "x${with_restconf}" == xno; then elif test "x${with_restconf}" == xno; then
# Cant get around "no" as an answer for --without-restconf that is reset here to undefined # Cant get around "no" as an answer for --without-restconf that is reset here to undefined
with_restconf= with_restconf=
@ -5254,6 +5257,7 @@ else
as_fn_error $? "No such restconf package: ${with_restconf}" "$LINENO" 5 as_fn_error $? "No such restconf package: ${with_restconf}" "$LINENO" 5
fi fi
if test "x${with_restconf}" != "x"; then if test "x${with_restconf}" != "x"; then
# This is so it appears in config.h # This is so it appears in config.h

View file

@ -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)]), AS_HELP_STRING([--with-restconf=fcgi],[FCGI interface for stand-alone web rev-proxy eg nginx (default)]),
, ,
[with_restconf=fcgi]) [with_restconf=fcgi])
# Actions for each specific package # Actions for each specific package
if test "x${with_restconf}" == xfcgi; then if test "x${with_restconf}" == xfcgi; then
# Lives in libfcgi-dev # 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(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(crypto, CRYPTO_new_ex_data, , AC_MSG_ERROR([libcrypto missing]))
AC_CHECK_LIB(event, event_init,, AC_MSG_ERROR([libevent 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]) AC_CHECK_LIB(evhtp, evhtp_new,, AC_MSG_ERROR([libevhtp missing]),[-lpthread -levent -levent_openssl -lssl -lcrypto])
elif test "x${with_restconf}" == xno; then elif test "x${with_restconf}" == xno; then
# Cant get around "no" as an answer for --without-restconf that is reset here to undefined # Cant get around "no" as an answer for --without-restconf that is reset here to undefined
with_restconf= with_restconf=
@ -224,6 +229,7 @@ else
AC_MSG_ERROR([No such restconf package: ${with_restconf}]) AC_MSG_ERROR([No such restconf package: ${with_restconf}])
fi fi
if test "x${with_restconf}" != "x"; then if test "x${with_restconf}" != "x"; then
# This is so it appears in config.h # This is so it appears in config.h
AC_DEFINE_UNQUOTED(WITH_RESTCONF, ${with_restconf}, [Restconf package]) AC_DEFINE_UNQUOTED(WITH_RESTCONF, ${with_restconf}, [Restconf package])

View file

@ -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 # Create a directory to hold source-code, dependencies etc
RUN mkdir /clixon RUN mkdir /clixon
# libevht # evhtp
# dependencies # dependencies
RUN apk add --update libevent cmake libevent-dev RUN apk add --update libevent libevent-dev
# clone libevhtp # clone libevhtp
WORKDIR /clixon WORKDIR /clixon
RUN git clone https://github.com/clicon/clixon-libevhtp.git RUN git clone https://github.com/clicon/clixon-libevhtp.git
WORKDIR /clixon/libevhtp WORKDIR /clixon/clixon-libevhtp
RUN ./configure RUN ./configure
RUN make RUN make

View file

@ -254,7 +254,7 @@ example_basic_auth(clicon_handle h,
user=NULL; /* to avoid free below */ user=NULL; /* to avoid free below */
retval = 1; retval = 1;
done: /* error */ 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) if (user)
free(user); free(user);
if (cb) if (cb)
@ -324,7 +324,7 @@ example_no_auth(clicon_handle h,
user=NULL; /* to avoid free below */ user=NULL; /* to avoid free below */
retval = 1; retval = 1;
done: /* error */ 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) if (user)
free(user); free(user);
if (cb) if (cb)

View file

@ -105,10 +105,9 @@ EOF
new "wait backend" new "wait backend"
wait_backend wait_backend
else
new "Restart backend as eg follows: -Ff $cfg -s $db"
sleep 2
fi fi
new "wait backend"
wait_backend
if [ $RC -ne 0 ]; then # Bring your own restconf if [ $RC -ne 0 ]; then # Bring your own restconf
new "kill old restconf daemon" new "kill old restconf daemon"
@ -116,10 +115,9 @@ EOF
new "start restconf daemon" new "start restconf daemon"
start_restconf -f $cfg start_restconf -f $cfg
fi
new "wait restconf" new "wait restconf"
wait_restconf wait_restconf
fi
# Use POST (instead of startup) # Use POST (instead of startup)
# Note this only works because CLICON_NACM_DISABLED_ON_EMPTY is true # Note this only works because CLICON_NACM_DISABLED_ON_EMPTY is true
@ -177,9 +175,12 @@ EOF
status="HTTP/1.1 200 OK" status="HTTP/1.1 200 OK"
;; ;;
esac esac
new "get 99" new "get 99"
expectpart "$(curl -u guest:bar $CURLOPTS -X GET $RCPROTO://localhost/restconf/data/nacm-example:x)" 0 "$status" "$ret" 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 if [ $RC -ne 0 ]; then # Bring your own restconf
new "Kill restconf daemon" new "Kill restconf daemon"
stop_restconf stop_restconf

View file

@ -184,10 +184,10 @@ nacm
# delete | p/d | xp/dx | p/d # delete | p/d | xp/dx | p/d
# replace all, then must include NACM rules as well # 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>" MSG="<data>$RULES</data>"
new "update root list permit" 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' 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" 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"}}} ' 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"}}} '

View file

@ -97,7 +97,6 @@ system=$($sshcmd uname) # we use the release "hack" instead
# Some release have packages, some need to be built from source # Some release have packages, some need to be built from source
buildfcgi=false buildfcgi=false
buildevhtp=false
case $release in case $release in
openbsd) openbsd)
# packages for building # packages for building
@ -130,7 +129,7 @@ case $release in
$sshcmd sudo pkg install -y fcgi-devkit nginx $sshcmd sudo pkg install -y fcgi-devkit nginx
;; ;;
evhtp) evhtp)
$sshcmd sudo pkg install -y libevent libevhtp $sshcmd sudo pkg install -y libevent
;; ;;
esac esac
;; ;;
@ -157,7 +156,6 @@ case $release in
;; ;;
evhtp) evhtp)
$sshcmd sudo yum install -y libevent openssl $sshcmd sudo yum install -y libevent openssl
buildevhtp=true
$sshcmd sudo yum install -y libevent-devel openssl-devel $sshcmd sudo yum install -y libevent-devel openssl-devel
;; ;;
esac esac
@ -203,7 +201,6 @@ case $release in
;; ;;
evhtp) evhtp)
# $sshcmd sudo apt install -y libevent-2.1 # $sshcmd sudo apt install -y libevent-2.1
buildevhtp=true
$sshcmd sudo apt install -y libevent-dev libssl-dev $sshcmd sudo apt install -y libevent-dev libssl-dev
;; ;;
esac esac
@ -257,15 +254,13 @@ case ${with_restconf} in
. ./nginx.sh $dir $idfile $port $wwwuser . ./nginx.sh $dir $idfile $port $wwwuser
;; ;;
evhtp) evhtp)
if $buildevhtp; then
$sshcmd << 'EOF' $sshcmd << 'EOF'
test -d libevhtp || git clone https://github.com/clicon/libevhtp.git test -d clixon-libevhtp || git clone https://github.com/clicon/clixon-libevhtp.git
cd libevhtp; cd clixon-libevhtp;
./configure --libdir=/usr/lib # otherwise in /usr/local/lib where RH dont look ./configure --libdir=/usr/lib # otherwise in /usr/local/lib where RH dont look
make make
sudo make install sudo make install
EOF EOF
fi
;; ;;
esac esac