summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--plugins/imtcp/imtcp.c9
-rw-r--r--runtime/nsd_gtls.c127
-rw-r--r--runtime/nsd_gtls.h9
-rw-r--r--runtime/nsd_ptcp.c3
-rw-r--r--tcpsrv.c28
5 files changed, 157 insertions, 19 deletions
diff --git a/plugins/imtcp/imtcp.c b/plugins/imtcp/imtcp.c
index bb5f4fe5..a9924365 100644
--- a/plugins/imtcp/imtcp.c
+++ b/plugins/imtcp/imtcp.c
@@ -44,6 +44,7 @@
#include "module-template.h"
#include "net.h"
#include "netstrm.h"
+#include "errmsg.h"
#include "tcpsrv.h"
MODULE_TYPE_INPUT
@@ -54,6 +55,7 @@ DEFobjCurrIf(tcpsrv)
DEFobjCurrIf(tcps_sess)
DEFobjCurrIf(net)
DEFobjCurrIf(netstrm)
+DEFobjCurrIf(errmsg)
/* Module static data */
static tcpsrv_t *pOurTcpsrv = NULL; /* our TCP server(listener) TODO: change for multiple instances */
@@ -134,6 +136,11 @@ static rsRetVal addTCPListener(void __attribute__((unused)) *pVal, uchar *pNewVa
}
finalize_it:
+ if(iRet != RS_RET_OK) {
+ errmsg.LogError(NO_ERRCODE, "error %d trying to add listener", iRet);
+ if(pOurTcpsrv != NULL)
+ tcpsrv.Destruct(&pOurTcpsrv);
+ }
RETiRet;
}
@@ -179,6 +186,7 @@ CODESTARTmodExit
objRelease(netstrm, LM_NETSTRMS_FILENAME);
objRelease(tcps_sess, LM_TCPSRV_FILENAME);
objRelease(tcpsrv, LM_TCPSRV_FILENAME);
+ objRelease(errmsg, CORE_COMPONENT);
ENDmodExit
@@ -207,6 +215,7 @@ CODEmodInit_QueryRegCFSLineHdlr
CHKiRet(objUse(netstrm, LM_NETSTRMS_FILENAME));
CHKiRet(objUse(tcps_sess, LM_TCPSRV_FILENAME));
CHKiRet(objUse(tcpsrv, LM_TCPSRV_FILENAME));
+ CHKiRet(objUse(errmsg, CORE_COMPONENT));
/* register config file handlers */
CHKiRet(omsdRegCFSLineHdlr((uchar *)"inputtcpserverrun", 0, eCmdHdlrGetWord,
diff --git a/runtime/nsd_gtls.c b/runtime/nsd_gtls.c
index a06d7cca..51d32b6c 100644
--- a/runtime/nsd_gtls.c
+++ b/runtime/nsd_gtls.c
@@ -35,6 +35,13 @@
#include "nsd_ptcp.h"
#include "nsd_gtls.h"
+/* things to move to some better place/functionality - TODO */
+#define DH_BITS 1024
+#define CAFILE "ca.pem" // TODO: allow to specify
+#define KEYFILE "key.pem"
+#define CERTFILE "cert.pem"
+#define CRLFILE "crl.pem"
+
MODULE_TYPE_LIB
/* static data */
@@ -43,19 +50,36 @@ DEFobjCurrIf(errmsg)
DEFobjCurrIf(glbl)
DEFobjCurrIf(nsd_ptcp)
+static int bGlblSrvrInitDone = 0; /**< 0 - server global init not yet done, 1 - already done */
/* a macro to check GnuTLS calls against unexpected errors */
#define CHKgnutls(x) \
if((gnuRet = (x)) != 0) { \
- dbgprintf("unexpected GnuTLS error %d in %s:%d\n", gnuRet, __FILE__, __LINE__); \
- gnutls_perror(gnuRet); /* TODO: can we do better? */ \
+ uchar *pErr = gtlsStrerror(gnuRet); \
+ dbgprintf("unexpected GnuTLS error %d in %s:%d: %s\n", gnuRet, __FILE__, __LINE__, pErr); \
+ free(pErr); \
ABORT_FINALIZE(RS_RET_GNUTLS_ERR); \
}
-#define CAFILE "ca.pem" // TODO: allow to specify
/* ------------------------------ GnuTLS specifics ------------------------------ */
static gnutls_certificate_credentials xcred;
+static gnutls_dh_params dh_params;
+
+/* a thread-safe variant of gnutls_strerror - TODO: implement it!
+ * The caller must free the returned string.
+ * rgerhards, 2008-04-30
+ */
+uchar *gtlsStrerror(int error)
+{
+ uchar *pErr;
+
+ // TODO: guard by mutex!
+ pErr = (uchar*) strdup(gnutls_strerror(error));
+
+ return pErr;
+}
+
/* globally initialize GnuTLS */
static rsRetVal
@@ -76,6 +100,71 @@ finalize_it:
RETiRet;
}
+static rsRetVal
+gtlsInitSession(nsd_gtls_t *pThis)
+{
+ DEFiRet;
+ int gnuRet;
+ gnutls_session session;
+
+ gnutls_init(&session, GNUTLS_SERVER);
+ pThis->bHaveSess = 1;
+ pThis->bIsInitiator = 0;
+
+ /* avoid calling all the priority functions, since the defaults are adequate. */
+ CHKgnutls(gnutls_set_default_priority(session));
+ CHKgnutls(gnutls_credentials_set(session, GNUTLS_CRD_CERTIFICATE, xcred));
+
+ /* request client certificate if any. */
+ gnutls_certificate_server_set_request( session, GNUTLS_CERT_REQUEST);
+ gnutls_dh_set_prime_bits(session, DH_BITS);
+
+ pThis->sess = session;
+
+finalize_it:
+ RETiRet;
+}
+
+
+
+static rsRetVal
+generate_dh_params(void)
+{
+ int gnuRet;
+ DEFiRet;
+ /* Generate Diffie Hellman parameters - for use with DHE
+ * kx algorithms. These should be discarded and regenerated
+ * once a day, once a week or once a month. Depending on the
+ * security requirements.
+ */
+ CHKgnutls(gnutls_dh_params_init( &dh_params));
+ CHKgnutls(gnutls_dh_params_generate2( dh_params, DH_BITS));
+finalize_it:
+ RETiRet;
+}
+
+
+/* set up all global things that are needed for server operations
+ * rgerhards, 2008-04-30
+ */
+static rsRetVal
+gtlsGlblInitLstn(void)
+{
+ int gnuRet;
+ DEFiRet;
+
+ if(bGlblSrvrInitDone == 0) {
+ //CHKgnutls(gnutls_certificate_set_x509_crl_file(xcred, CRLFILE, GNUTLS_X509_FMT_PEM));
+ CHKgnutls(gnutls_certificate_set_x509_key_file(xcred, CERTFILE, KEYFILE, GNUTLS_X509_FMT_PEM));
+ CHKiRet(generate_dh_params());
+ gnutls_certificate_set_dh_params(xcred, dh_params); /* this is void */
+ bGlblSrvrInitDone = 1; /* we are all set now */
+ }
+
+finalize_it:
+ RETiRet;
+}
+
/* globally de-initialize GnuTLS */
static rsRetVal
@@ -100,9 +189,11 @@ gtlsEndSess(nsd_gtls_t *pThis)
DEFiRet;
if(pThis->bHaveSess) {
- gnuRet = gnutls_bye(pThis->sess, GNUTLS_SHUT_RDWR);
- while(gnuRet == GNUTLS_E_INTERRUPTED || gnuRet == GNUTLS_E_AGAIN) {
+ if(pThis->bIsInitiator) {
gnuRet = gnutls_bye(pThis->sess, GNUTLS_SHUT_RDWR);
+ while(gnuRet == GNUTLS_E_INTERRUPTED || gnuRet == GNUTLS_E_AGAIN) {
+ gnuRet = gnutls_bye(pThis->sess, GNUTLS_SHUT_RDWR);
+ }
}
gnutls_deinit(pThis->sess);
}
@@ -116,6 +207,7 @@ gtlsEndSess(nsd_gtls_t *pThis)
/* Standard-Constructor */
BEGINobjConstruct(nsd_gtls) /* be sure to specify the object type also in END macro! */
iRet = nsd_ptcp.Construct(&pThis->pTcp);
+ pThis->iMode = 1; // TODO: remove!
ENDobjConstruct(nsd_gtls)
@@ -204,7 +296,9 @@ LstnInit(netstrms_t *pNS, void *pUsr, rsRetVal(*fAddLstn)(void*,netstrm_t*),
uchar *pLstnPort, uchar *pLstnIP, int iSessMax)
{
DEFiRet;
+ CHKiRet(gtlsGlblInitLstn());
iRet = nsd_ptcp.LstnInit(pNS, pUsr, fAddLstn, pLstnPort, pLstnIP, iSessMax);
+finalize_it:
RETiRet;
}
@@ -247,6 +341,7 @@ static rsRetVal
AcceptConnReq(nsd_t *pNsd, nsd_t **ppNew)
{
DEFiRet;
+ int gnuRet;
nsd_gtls_t *pNew = NULL;
nsd_gtls_t *pThis = (nsd_gtls_t*) pNsd;
@@ -256,6 +351,23 @@ AcceptConnReq(nsd_t *pNsd, nsd_t **ppNew)
CHKiRet(nsd_ptcp.Destruct(&pNew->pTcp));
CHKiRet(nsd_ptcp.AcceptConnReq(pThis->pTcp, &pNew->pTcp));
+ if(pThis->iMode == 0) {
+ /* we are in non-TLS mode, so we are done */
+ *ppNew = (nsd_t*) pNew;
+ FINALIZE;
+ }
+
+ /* if we reach this point, we are in TLS mode */
+ CHKiRet(gtlsInitSession(pNew));
+ gnutls_transport_set_ptr(pNew->sess, (gnutls_transport_ptr)((nsd_ptcp_t*) (pNew->pTcp))->sock);
+
+ /* we now do the handshake. This is a bit complicated, because we are
+ * on non-blocking sockets. Usually, the handshake will not complete
+ * immediately, so that we need to retry it some time later.
+ */
+ CHKgnutls(gnutls_handshake(pNew->sess));
+ pThis->iMode = 1; /* this session is now in TLS mode! */
+
*ppNew = (nsd_t*) pNew;
finalize_it:
@@ -280,6 +392,8 @@ static rsRetVal
Rcv(nsd_t *pNsd, uchar *pBuf, ssize_t *pLenBuf)
{
DEFiRet;
+ int gnuRet;
+ ssize_t lenRcvd;
nsd_gtls_t *pThis = (nsd_gtls_t*) pNsd;
ISOBJ_TYPE_assert(pThis, nsd_gtls);
@@ -289,6 +403,8 @@ Rcv(nsd_t *pNsd, uchar *pBuf, ssize_t *pLenBuf)
}
/* in TLS mode now */
+ lenRcvd = gnutls_record_recv(pThis->sess, pBuf, *pLenBuf);
+ *pLenBuf = lenRcvd;
finalize_it:
RETiRet;
@@ -358,6 +474,7 @@ Connect(nsd_t *pNsd, int family, uchar *port, uchar *host)
/* we reach this point if in TLS mode */
CHKgnutls(gnutls_init(&pThis->sess, GNUTLS_CLIENT));
pThis->bHaveSess = 1;
+ pThis->bIsInitiator = 1;
/* Use default priorities */
CHKgnutls(gnutls_set_default_priority(pThis->sess));
diff --git a/runtime/nsd_gtls.h b/runtime/nsd_gtls.h
index c193f57c..492a2da1 100644
--- a/runtime/nsd_gtls.h
+++ b/runtime/nsd_gtls.h
@@ -26,6 +26,10 @@
#include "nsd.h"
+typedef enum {
+ gtlsRtry_None = 0 /**< no call needs to be retried */
+} gtlsRtryCall_t; /**< IDs of calls that needs to be retried */
+
typedef nsd_if_t nsd_gtls_if_t; /* we just *implement* this interface */
/* the nsd_gtls object */
@@ -33,8 +37,11 @@ struct nsd_gtls_s {
BEGINobjInstance; /* Data to implement generic object - MUST be the first data element! */
nsd_t *pTcp; /**< our aggregated nsd_ptcp data */
int iMode; /* 0 - plain tcp, 1 - TLS */
+ gtlsRtryCall_t rtryCall;/**< what must we retry? */
+ int bIsInitiator; /**< 0 if socket is the server end (listener), 1 if it is the initiator */
gnutls_session sess;
- int bHaveSess;
+ int bHaveSess; /* as we don't know exactly which gnutls_session values are invalid, we use this one
+ to flag whether or not we are in a session (same as -1 for a socket meaning no sess) */
};
/* interface is defined in nsd.h, we just implement it! */
diff --git a/runtime/nsd_ptcp.c b/runtime/nsd_ptcp.c
index e26347c3..c4fb1cf1 100644
--- a/runtime/nsd_ptcp.c
+++ b/runtime/nsd_ptcp.c
@@ -273,6 +273,8 @@ AcceptConnReq(nsd_t *pNsd, nsd_t **ppNew)
CHKiRet(FillRemHost(pNew, (struct sockaddr*) &addr));
+#warning "socket set to blocking for tls testing - re-enable non-blocking mode!"
+#if 0
/* set the new socket to non-blocking IO -TODO:do we really need to do this here? Do we always want it? */
if((sockflags = fcntl(iNewSock, F_GETFL)) != -1) {
sockflags |= O_NONBLOCK;
@@ -285,6 +287,7 @@ AcceptConnReq(nsd_t *pNsd, nsd_t **ppNew)
dbgprintf("error %d setting fcntl(O_NONBLOCK) on tcp socket %d", errno, iNewSock);
ABORT_FINALIZE(RS_RET_IO_ERROR);
}
+#endif
pNew->sock = iNewSock;
*ppNew = (nsd_t*) pNew;
diff --git a/tcpsrv.c b/tcpsrv.c
index 621f9d54..56d7464b 100644
--- a/tcpsrv.c
+++ b/tcpsrv.c
@@ -181,12 +181,15 @@ TCPSessGetNxtSess(tcpsrv_t *pThis, int iCurr)
{
register int i;
+ BEGINfunc
ISOBJ_TYPE_assert(pThis, tcpsrv);
+ assert(pThis->pSessions != NULL);
for(i = iCurr + 1 ; i < pThis->iSessMax ; ++i) {
if(pThis->pSessions[i] != NULL)
break;
}
+ ENDfunc
return((i < pThis->iSessMax) ? i : -1);
}
@@ -202,20 +205,20 @@ static void deinit_tcp_listener(tcpsrv_t *pThis)
int i;
ISOBJ_TYPE_assert(pThis, tcpsrv);
- assert(pThis->pSessions != NULL);
- /* close all TCP connections! */
- i = TCPSessGetNxtSess(pThis, -1);
- while(i != -1) {
- tcps_sess.Destruct(&pThis->pSessions[i]);
- /* now get next... */
- i = TCPSessGetNxtSess(pThis, i);
+ if(pThis->pSessions != NULL) {
+ /* close all TCP connections! */
+ i = TCPSessGetNxtSess(pThis, -1);
+ while(i != -1) {
+ tcps_sess.Destruct(&pThis->pSessions[i]);
+ /* now get next... */
+ i = TCPSessGetNxtSess(pThis, i);
+ }
+
+ /* we are done with the session table - so get rid of it... */
+ free(pThis->pSessions);
+ pThis->pSessions = NULL; /* just to make sure... */
}
-
- /* we are done with the session table - so get rid of it...
- */
- free(pThis->pSessions);
- pThis->pSessions = NULL; /* just to make sure... */
if(pThis->TCPLstnPort != NULL)
free(pThis->TCPLstnPort);
@@ -413,7 +416,6 @@ Run(tcpsrv_t *pThis)
/* Add the TCP listen sockets to the list of read descriptors. */
for(i = 0 ; i < pThis->iLstnMax ; ++i) {
-RUNLOG_VAR("%d", i);
CHKiRet(nssel.Add(pSel, pThis->ppLstn[i], NSDSEL_RD));
}