summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorNikos Mavrogiannopoulos <nmav@gnutls.org>2011-02-19 16:57:44 +0100
committerNikos Mavrogiannopoulos <nmav@gnutls.org>2011-02-19 19:08:35 +0100
commit089391da55d232908b9cdbba7f27b0ccfea26cca (patch)
treedbbdf207f712fb4c3b8975944ccea36c4f08bc35
parentb5c0c987913d93e0bb8414c4f48242ee8f350382 (diff)
downloadgnutls-089391da55d232908b9cdbba7f27b0ccfea26cca.tar.gz
Changes to allow DTLS server side to operate. Added a simple UDP server on gnutls-serv.
Server other cleanups.
-rw-r--r--lib/Makefile.am2
-rw-r--r--lib/ext_session_ticket.c4
-rw-r--r--lib/gnutls_buffers.c152
-rw-r--r--lib/gnutls_buffers.h3
-rw-r--r--lib/gnutls_constate.c17
-rw-r--r--lib/gnutls_dtls.c66
-rw-r--r--lib/gnutls_handshake.c68
-rw-r--r--lib/gnutls_int.h7
-rw-r--r--lib/gnutls_state.c5
-rw-r--r--lib/includes/gnutls/gnutls.h.in5
-rw-r--r--lib/libgnutls.map9
-rw-r--r--lib/system.c25
-rw-r--r--lib/system.h2
-rw-r--r--lib/system_override.c202
-rw-r--r--src/Makefile.am2
-rw-r--r--src/serv-gaa.c117
-rw-r--r--src/serv-gaa.h40
-rw-r--r--src/serv.c122
-rw-r--r--src/serv.gaa5
-rw-r--r--src/udp-serv.c174
-rw-r--r--src/udp-serv.h8
21 files changed, 726 insertions, 309 deletions
diff --git a/lib/Makefile.am b/lib/Makefile.am
index 6a2b1dce46..edf5209182 100644
--- a/lib/Makefile.am
+++ b/lib/Makefile.am
@@ -81,7 +81,7 @@ COBJECTS = gnutls_record.c gnutls_compress.c debug.c gnutls_cipher.c \
crypto.c random.c ext_signature.c cryptodev.c system.c \
crypto-api.c ext_safe_renegotiation.c gnutls_privkey.c \
pkcs11.c pkcs11_privkey.c gnutls_pubkey.c pkcs11_write.c locks.c \
- pkcs11_secret.c hash.c gnutls_dtls.c
+ pkcs11_secret.c hash.c gnutls_dtls.c system_override.c
if ENABLE_NETTLE
diff --git a/lib/ext_session_ticket.c b/lib/ext_session_ticket.c
index 9c44b90555..f51c127e7b 100644
--- a/lib/ext_session_ticket.c
+++ b/lib/ext_session_ticket.c
@@ -683,10 +683,8 @@ _gnutls_send_new_session_ticket (gnutls_session_t session, int again)
data_size = p - data;
}
- ret = _gnutls_send_handshake (session, data_size ? bufel : NULL,
+ return _gnutls_send_handshake (session, data_size ? bufel : NULL,
GNUTLS_HANDSHAKE_NEW_SESSION_TICKET);
-
- return ret;
}
int
diff --git a/lib/gnutls_buffers.c b/lib/gnutls_buffers.c
index a57784f633..41b024488f 100644
--- a/lib/gnutls_buffers.c
+++ b/lib/gnutls_buffers.c
@@ -68,58 +68,6 @@
*/
#define MAX_QUEUE 16
-/**
- * gnutls_transport_set_errno:
- * @session: is a #gnutls_session_t structure.
- * @err: error value to store in session-specific errno variable.
- *
- * Store @err in the session-specific errno variable. Useful values
- * for @err is EAGAIN and EINTR, other values are treated will be
- * treated as real errors in the push/pull function.
- *
- * This function is useful in replacement push/pull functions set by
- * gnutls_transport_set_push_function and
- * gnutls_transport_set_pullpush_function under Windows, where the
- * replacement push/pull may not have access to the same @errno
- * variable that is used by GnuTLS (e.g., the application is linked to
- * msvcr71.dll and gnutls is linked to msvcrt.dll).
- *
- * If you don't have the @session variable easily accessible from the
- * push/pull function, and don't worry about thread conflicts, you can
- * also use gnutls_transport_set_global_errno().
- **/
-void
-gnutls_transport_set_errno (gnutls_session_t session, int err)
-{
- session->internals.errnum = err;
-}
-
-/**
- * gnutls_transport_set_global_errno:
- * @err: error value to store in global errno variable.
- *
- * Store @err in the global errno variable. Useful values for @err is
- * EAGAIN and EINTR, other values are treated will be treated as real
- * errors in the push/pull function.
- *
- * This function is useful in replacement push/pull functions set by
- * gnutls_transport_set_push_function and
- * gnutls_transport_set_pullpush_function under Windows, where the
- * replacement push/pull may not have access to the same @errno
- * variable that is used by GnuTLS (e.g., the application is linked to
- * msvcr71.dll and gnutls is linked to msvcrt.dll).
- *
- * Whether this function is thread safe or not depends on whether the
- * global variable errno is thread safe, some system libraries make it
- * a thread-local variable. When feasible, using the guaranteed
- * thread-safe gnutls_transport_set_errno() may be better.
- **/
-void
-gnutls_transport_set_global_errno (int err)
-{
- errno = err;
-}
-
/* Buffers received packets of type APPLICATION DATA and
* HANDSHAKE DATA.
*/
@@ -451,16 +399,11 @@ _gnutls_writev_emu (gnutls_session_t session, const giovec_t * giovec,
{
int ret, j = 0;
gnutls_transport_ptr_t fd = session->internals.transport_send_ptr;
- void *iptr;
- size_t sizeOfPtr;
size_t total = 0;
for (j = 0; j < giovec_cnt; j++)
{
- sizeOfPtr = giovec[j].iov_len;
- iptr = giovec[j].iov_base;
-
- ret = session->internals.push_func (fd, iptr, sizeOfPtr);
+ ret = session->internals.push_func (fd, giovec[j].iov_base, giovec[j].iov_len);
if (ret == -1)
break;
@@ -673,7 +616,8 @@ _gnutls_io_read_buffered (gnutls_session_t session, size_t total,
* select think, that the socket is ready for reading.
* MSG_PEEK is only used with berkeley style sockets.
*/
- if (ret == readsize && recvlowat > 0 && !_gnutls_is_dtls(session))
+ if (ret == readsize && recvlowat > 0 && !_gnutls_is_dtls(session) &&
+ session->internals.pull_func == system_read)
{
ret2 = _gnutls_read (session, &bufel, recvlowat, system_read_peek);
@@ -844,13 +788,16 @@ _gnutls_io_write_flush (gnutls_session_t session)
* on timeout and a negative value on error.
*/
int
-_gnutls_io_check_recv (gnutls_session_t session, int ms)
+_gnutls_io_check_recv (gnutls_session_t session, void* data, size_t data_size, unsigned int ms)
{
gnutls_transport_ptr_t fd = session->internals.transport_send_ptr;
int ret;
-
- ret = system_recv_timeout(fd, ms);
+ if (session->internals.pull_timeout_func == system_recv_timeout &&
+ session->internals.pull_func != system_read)
+ return gnutls_assert_val(GNUTLS_E_PULL_ERROR);
+
+ ret = session->internals.pull_timeout_func(fd, data, data_size, ms);
if (ret == -1)
return gnutls_assert_val(GNUTLS_E_PULL_ERROR);
@@ -1111,84 +1058,3 @@ _gnutls_handshake_buffer_clear (gnutls_session_t session)
return 0;
}
-/**
- * gnutls_transport_set_pull_function:
- * @session: is a #gnutls_session_t structure.
- * @pull_func: a callback function similar to read()
- *
- * This is the function where you set a function for gnutls to receive
- * data. Normally, if you use berkeley style sockets, do not need to
- * use this function since the default (recv(2)) will probably be ok.
- *
- * PULL_FUNC is of the form,
- * ssize_t (*gnutls_pull_func)(gnutls_transport_ptr_t, void*, size_t);
- **/
-void
-gnutls_transport_set_pull_function (gnutls_session_t session,
- gnutls_pull_func pull_func)
-{
- session->internals.pull_func = pull_func;
-}
-
-/**
- * gnutls_transport_set_push_function:
- * @session: is a #gnutls_session_t structure.
- * @push_func: a callback function similar to write()
- *
- * This is the function where you set a push function for gnutls to
- * use in order to send data. If you are going to use berkeley style
- * sockets, you do not need to use this function since the default
- * (send(2)) will probably be ok. Otherwise you should specify this
- * function for gnutls to be able to send data.
- *
- * PUSH_FUNC is of the form,
- * ssize_t (*gnutls_push_func)(gnutls_transport_ptr_t, const void*, size_t);
- **/
-void
-gnutls_transport_set_push_function (gnutls_session_t session,
- gnutls_push_func push_func)
-{
- session->internals.push_func = push_func;
- session->internals.vec_push_func = NULL;
-}
-
-/**
- * gnutls_transport_set_push_function2:
- * @session: is a #gnutls_session_t structure.
- * @vec_func: a callback function similar to writev()
- *
- * This is the function where you set a push function for gnutls to
- * use in order to send data. If you are going to use berkeley style
- * sockets, you do not need to use this function since the default
- * (send(2)) will probably be ok. Otherwise you should specify this
- * function for gnutls to be able to send data.
- *
- * PUSH_FUNC is of the form,
- * ssize_t (*gnutls_push_func)(gnutls_transport_ptr_t, const void*, size_t);
- **/
-void
-gnutls_transport_set_push_function2 (gnutls_session_t session,
- gnutls_vec_push_func vec_func)
-{
- session->internals.push_func = NULL;
- session->internals.vec_push_func = vec_func;
-}
-
-/**
- * gnutls_transport_set_errno_function:
- * @session: is a #gnutls_session_t structure.
- * @errno_func: a callback function similar to write()
- *
- * This is the function where you set a function to retrieve errno
- * after a failed push or pull operation.
- *
- * errno_func is of the form,
- * int (*gnutls_errno_func)(gnutls_transport_ptr_t);
- * and should return the errno.
- **/
-void
-gnutls_transport_set_errno_function (gnutls_session_t session,
- gnutls_errno_func errno_func)
-{
- session->internals.errno_func = errno_func;
-}
diff --git a/lib/gnutls_buffers.h b/lib/gnutls_buffers.h
index 8028f734ef..37371ba6fb 100644
--- a/lib/gnutls_buffers.h
+++ b/lib/gnutls_buffers.h
@@ -60,7 +60,8 @@ int _gnutls_handshake_io_cache_int (gnutls_session_t,
gnutls_handshake_description_t,
mbuffer_st * bufel);
ssize_t _gnutls_io_write_flush (gnutls_session_t session);
-int _gnutls_io_check_recv (gnutls_session_t session, int ms);
+int
+_gnutls_io_check_recv (gnutls_session_t session, void* data, size_t data_size, unsigned int ms);
ssize_t _gnutls_handshake_io_write_flush (gnutls_session_t session);
#endif
diff --git a/lib/gnutls_constate.c b/lib/gnutls_constate.c
index aadb110d66..9e25d32fde 100644
--- a/lib/gnutls_constate.c
+++ b/lib/gnutls_constate.c
@@ -677,6 +677,7 @@ epoch_get_slot (gnutls_session_t session, uint16_t epoch)
if (epoch_index >= MAX_EPOCH_INDEX)
{
+ _gnutls_dtls_log("Epoch %d out of range (idx: %d, max: %d)\n", (int)epoch, (int)epoch_index, MAX_EPOCH_INDEX);
gnutls_assert ();
return NULL;
}
@@ -746,9 +747,19 @@ epoch_alive (gnutls_session_t session, record_parameters_st * params)
const security_parameters_st *sp = &session->security_parameters;
/* DTLS will, in addition, need to check the epoch timeout value. */
- return (params->epoch == sp->epoch_read
- || params->epoch == sp->epoch_write
- || params->epoch == sp->epoch_next);
+ if (params->usage_cnt > 0)
+ return 1;
+
+ if (params->epoch == sp->epoch_read)
+ return 1;
+
+ if (params->epoch == sp->epoch_write)
+ return 1;
+
+ if (params->epoch == sp->epoch_next)
+ return 1;
+
+ return 0;
}
void
diff --git a/lib/gnutls_dtls.c b/lib/gnutls_dtls.c
index 81d3e5f88f..fdb8479347 100644
--- a/lib/gnutls_dtls.c
+++ b/lib/gnutls_dtls.c
@@ -57,10 +57,7 @@ _gnutls_dtls_handshake_enqueue (gnutls_session_t session,
msg = gnutls_malloc (sizeof(dtls_hsk_retransmit_buffer));
if (msg == NULL)
- {
- gnutls_assert ();
- return GNUTLS_E_MEMORY_ERROR;
- }
+ return gnutls_assert_val(GNUTLS_E_MEMORY_ERROR);
msg->bufel = bufel;
@@ -70,9 +67,11 @@ _gnutls_dtls_handshake_enqueue (gnutls_session_t session,
msg->type = type;
msg->sequence = sequence;
- _gnutls_dtls_log ("DTLS[%p]: Enqueued Packet[%u] %s(%d) with length: %u\n",
+ params->usage_cnt++;
+
+ _gnutls_dtls_log ("DTLS[%p]: Enqueued Packet[%u] %s(%d) with length: %u on epoch %d\n",
session, (uint)sequence, _gnutls_handshake2str (type),
- type, msg->bufel->msg.size);
+ type, msg->bufel->msg.size, msg->epoch);
*(session->internals.dtls.retransmit_end) = msg;
session->internals.dtls.retransmit_end = &msg->next;
@@ -93,10 +92,11 @@ transmit_message (gnutls_session_t session,
if (msg->type == GNUTLS_HANDSHAKE_CHANGE_CIPHER_SPEC)
{
- return _gnutls_send_int (session, GNUTLS_CHANGE_CIPHER_SPEC, -1,
+ ret = _gnutls_send_int (session, GNUTLS_CHANGE_CIPHER_SPEC, -1,
msg->epoch,
_mbuffer_get_uhead_ptr(msg->bufel),
_mbuffer_get_uhead_size(msg->bufel), 0);
+ goto leave_epoch;
}
mtu_data = gnutls_malloc(mtu + DTLS_HANDSHAKE_HEADER_SIZE);
@@ -119,7 +119,7 @@ transmit_message (gnutls_session_t session,
_gnutls_write_uint16 (msg->sequence, &mtu_data[4]);
/* Chop up and send handshake message into mtu-size pieces. */
- for (offset=0; offset < data_size; offset += mtu)
+ for (offset=0; offset <= data_size; offset += mtu)
{
/* Calculate fragment length */
if(offset + mtu > data_size)
@@ -153,9 +153,29 @@ transmit_message (gnutls_session_t session,
}
gnutls_free (mtu_data);
+leave_epoch:
+
return ret;
}
+static int drop_usage_count(gnutls_session_t session)
+{
+ dtls_hsk_retransmit_buffer *msg;
+ record_parameters_st * params;
+ int ret;
+
+ for (msg = session->internals.dtls.retransmit; msg != NULL; msg = msg->next)
+ {
+ ret = _gnutls_epoch_get( session, msg->epoch, &params);
+ if (ret < 0)
+ return gnutls_assert_val(ret);
+ params->usage_cnt--;
+ if (params->usage_cnt < 0)
+ return gnutls_assert_val(GNUTLS_E_INTERNAL_ERROR);
+ }
+ return 0;
+}
+
/* This function transmits the flight that has been previously
* buffered.
*
@@ -170,26 +190,47 @@ int ret;
/* PREPARING -> SENDING state transition */
dtls_hsk_retransmit_buffer *msg;
unsigned int total_timeout = 0;
+ gnutls_handshake_description_t last_type = 0;
do
{
_gnutls_dtls_log ("DTLS[%p]: Start of flight transmission.\n", session);
for (msg = session->internals.dtls.retransmit; msg != NULL; msg = msg->next)
- transmit_message (session, msg);
+ {
+ transmit_message (session, msg);
+ last_type = msg->type;
+ }
ret = _gnutls_io_write_flush (session);
if (ret < 0)
return gnutls_assert_val(ret);
- ret = _gnutls_io_check_recv(session, session->internals.dtls.retrans_timeout);
- total_timeout += session->internals.dtls.retrans_timeout;
+ /* last message in handshake -> no ack */
+ if (session->security_parameters.entity == GNUTLS_SERVER &&
+ last_type == GNUTLS_HANDSHAKE_FINISHED)
+ {
+ opaque c;
+ ret = _gnutls_io_check_recv(session, &c, 1, session->internals.dtls.retrans_timeout);
+ if (ret == GNUTLS_E_TIMEDOUT)
+ ret = 0;
+ else if (ret >= 0)
+ {
+ if (c == GNUTLS_HANDSHAKE) /* retransmit */
+ ret = GNUTLS_E_TIMEDOUT;
+ }
+ total_timeout += session->internals.dtls.retrans_timeout;
+ }
+ else /* all other messages -> implicit ack (receive of next flight) */
+ {
+ ret = _gnutls_io_check_recv(session, NULL, 0, session->internals.dtls.retrans_timeout);
+ total_timeout += session->internals.dtls.retrans_timeout;
+ }
if (total_timeout >= session->internals.dtls.total_timeout) {
ret = gnutls_assert_val(GNUTLS_E_TIMEDOUT);
goto cleanup;
}
-
} while(ret == GNUTLS_E_TIMEDOUT);
if (ret < 0)
@@ -202,6 +243,7 @@ int ret;
ret = 0;
cleanup:
+ drop_usage_count(session);
_gnutls_dtls_clear_outgoing_buffer (session);
/* SENDING -> WAITING state transition */
diff --git a/lib/gnutls_handshake.c b/lib/gnutls_handshake.c
index 9889c3bd51..454232b26f 100644
--- a/lib/gnutls_handshake.c
+++ b/lib/gnutls_handshake.c
@@ -518,6 +518,16 @@ _gnutls_read_client_hello (gnutls_session_t session, opaque * data,
session->internals.resumed = RESUME_FALSE;
}
+ if (_gnutls_is_dtls(session))
+ {
+ int cookie_size;
+
+ DECR_LEN (len, 1);
+ cookie_size = data[pos++];
+ DECR_LEN (len, cookie_size);
+ pos+=cookie_size;
+ }
+
/* Remember ciphersuites for later
*/
DECR_LEN (len, 2);
@@ -943,31 +953,20 @@ _gnutls_server_select_suite (gnutls_session_t session, opaque * data,
gnutls_assert ();
return GNUTLS_E_UNEXPECTED_PACKET_LENGTH;
}
-#ifdef HANDSHAKE_DEBUG
- _gnutls_handshake_log ("HSK[%p]: Requested cipher suites: \n", session);
- for (j = 0; j < datalen; j += 2)
- {
- memcpy (&cs.suite, &data[j], 2);
- _gnutls_handshake_log ("\t%s\n", _gnutls_cipher_suite_get_name (&cs));
- }
- _gnutls_handshake_log ("HSK[%p]: Supported cipher suites: \n", session);
- for (j = 0; j < x; j++)
- _gnutls_handshake_log ("\t%s\n",
- _gnutls_cipher_suite_get_name (&ciphers[j]));
-#endif
- memset (session->security_parameters.current_cipher_suite.suite, '\0', 2);
+ memset (session->security_parameters.current_cipher_suite.suite, 0, 2);
retval = GNUTLS_E_UNKNOWN_CIPHER_SUITE;
+ _gnutls_handshake_log ("HSK[%p]: Requested cipher suites[size: %d]: \n", session, (int)datalen);
for (j = 0; j < datalen; j += 2)
{
+ memcpy (&cs.suite, &data[j], 2);
+ _gnutls_handshake_log ("\t0x%.2x, 0x%.2x %s\n", data[j], data[j+1], _gnutls_cipher_suite_get_name (&cs));
for (i = 0; i < x; i++)
{
if (memcmp (ciphers[i].suite, &data[j], 2) == 0)
{
- memcpy (&cs.suite, &data[j], 2);
-
_gnutls_handshake_log
("HSK[%p]: Selected cipher suite: %s\n", session,
_gnutls_cipher_suite_get_name (&cs));
@@ -1212,7 +1211,7 @@ _gnutls_send_handshake (gnutls_session_t session, mbuffer_st * bufel,
pos += 3;
}
- _gnutls_handshake_log ("HSK[%p]: %s was sent [%ld bytes]\n",
+ _gnutls_handshake_log ("HSK[%p]: %s was queued [%ld bytes]\n",
session, _gnutls_handshake2str (type),
(long) datasize);
@@ -1240,7 +1239,7 @@ _gnutls_send_handshake (gnutls_session_t session, mbuffer_st * bufel,
_gnutls_handshake_hash_add_sent (session, type, data, datasize)) < 0)
{
gnutls_assert ();
- _mbuffer_xfree(&bufel);
+ _mbuffer_xfree(&bufel);
return ret;
}
@@ -1418,6 +1417,9 @@ _gnutls_recv_handshake_header (gnutls_session_t session,
return length32;
else if (*recv_type != type)
{
+ _gnutls_handshake_log ("HSK[%p]: %s was received, expected %s\n",
+ session, _gnutls_handshake2str (*recv_type),
+ _gnutls_handshake2str (type));
gnutls_assert ();
return GNUTLS_E_UNEXPECTED_HANDSHAKE_PACKET;
}
@@ -1604,7 +1606,7 @@ _gnutls_recv_handshake (gnutls_session_t session, uint8_t ** data,
else
/* Signal our caller we have received a verification cookie
and ClientHello needs to be sent again. */
- ret = 1;
+ ret = 1;
goto cleanup; /* caller doesn't need dataptr */
@@ -2282,7 +2284,7 @@ _gnutls_send_client_hello (gnutls_session_t session, int again)
_gnutls_send_handshake (session, bufel, GNUTLS_HANDSHAKE_CLIENT_HELLO);
cleanup:
- gnutls_free (bufel);
+ _mbuffer_xfree(&bufel);
_gnutls_buffer_clear(&extdata);
return ret;
}
@@ -2870,20 +2872,20 @@ _gnutls_handshake_client (gnutls_session_t session)
case STATE11:
if (_gnutls_is_dtls (session))
- {
- ret =
- _gnutls_recv_handshake (session, NULL, NULL,
- GNUTLS_HANDSHAKE_HELLO_VERIFY_REQUEST,
- OPTIONAL_PACKET);
- STATE = STATE11;
- IMED_RET ("recv hello verify", ret, 1);
-
- if (ret == 1)
- {
- STATE = STATE0;
- return 1;
- }
- }
+ {
+ ret =
+ _gnutls_recv_handshake (session, NULL, NULL,
+ GNUTLS_HANDSHAKE_HELLO_VERIFY_REQUEST,
+ OPTIONAL_PACKET);
+ STATE = STATE11;
+ IMED_RET ("recv hello verify", ret, 1);
+
+ if (ret == 1)
+ {
+ STATE = STATE0;
+ return 1;
+ }
+ }
case STATE2:
/* receive the server hello */
ret =
diff --git a/lib/gnutls_int.h b/lib/gnutls_int.h
index 0923bbc0ba..d3da01d6ef 100644
--- a/lib/gnutls_int.h
+++ b/lib/gnutls_int.h
@@ -491,6 +491,12 @@ struct record_parameters_st
record_state_st read;
record_state_st write;
+
+ /* Whether this state is in use, i.e., if there is
+ a pending handshake message waiting to be encrypted
+ under this epoch's parameters.
+ */
+ int usage_cnt;
};
typedef struct
@@ -703,6 +709,7 @@ typedef struct
/* PUSH & PULL functions.
*/
+ gnutls_pull_timeout_func pull_timeout_func;
gnutls_pull_func pull_func;
gnutls_push_func push_func;
gnutls_vec_push_func vec_push_func;
diff --git a/lib/gnutls_state.c b/lib/gnutls_state.c
index 0ceaa2d74e..ab2350e2cd 100644
--- a/lib/gnutls_state.c
+++ b/lib/gnutls_state.c
@@ -372,6 +372,7 @@ gnutls_init (gnutls_session_t * session, gnutls_connection_end_t con_end)
#endif
gnutls_transport_set_pull_function (*session, system_read);
gnutls_transport_set_errno_function (*session, system_errno);
+ gnutls_transport_set_pull_timeout_function (*session, system_recv_timeout);
return 0;
}
@@ -407,8 +408,8 @@ gnutls_init_dtls (gnutls_session_t * session,
/* Initialize pointer used to enqueue messages for retransmit. */
(*session)->internals.dtls.retransmit_end = &(*session)->internals.dtls.retransmit;
- (*session)->internals.dtls.retrans_timeout = 100;
- (*session)->internals.dtls.total_timeout = 3000;
+ (*session)->internals.dtls.retrans_timeout = 1000;
+ (*session)->internals.dtls.total_timeout = 4000;
return 0;
}
diff --git a/lib/includes/gnutls/gnutls.h.in b/lib/includes/gnutls/gnutls.h.in
index 93b1cea44e..ebe09bd63f 100644
--- a/lib/includes/gnutls/gnutls.h.in
+++ b/lib/includes/gnutls/gnutls.h.in
@@ -1184,6 +1184,8 @@ extern "C"
typedef ssize_t (*gnutls_push_func) (gnutls_transport_ptr_t, const void *,
size_t);
+ typedef int (*gnutls_pull_timeout_func) (gnutls_transport_ptr_t, void*data, size_t size, unsigned int ms);
+
typedef ssize_t (*gnutls_vec_push_func) (gnutls_transport_ptr_t,
const giovec_t * iov, int iovcnt);
@@ -1210,6 +1212,9 @@ extern "C"
void gnutls_transport_set_pull_function (gnutls_session_t session,
gnutls_pull_func pull_func);
+ void gnutls_transport_set_pull_timeout_function (gnutls_session_t session,
+ gnutls_pull_timeout_func func);
+
void gnutls_transport_set_errno_function (gnutls_session_t session,
gnutls_errno_func errno_func);
diff --git a/lib/libgnutls.map b/lib/libgnutls.map
index fa16a998ef..5576c5a953 100644
--- a/lib/libgnutls.map
+++ b/lib/libgnutls.map
@@ -625,7 +625,6 @@ GNUTLS_2_12
gnutls_pkcs11_privkey_decrypt_data;
gnutls_pkcs11_obj_export;
gnutls_pkcs11_type_get_name;
-
gnutls_privkey_init;
gnutls_privkey_deinit;
gnutls_privkey_get_pk_algorithm;
@@ -667,7 +666,6 @@ GNUTLS_2_12
gnutls_global_set_mutex;
gnutls_transport_set_push_function2;
gnutls_transport_set_errno_function;
-
gnutls_sec_param_to_pk_bits;
gnutls_sec_param_get_name;
gnutls_pk_bits_to_sec_param;
@@ -687,6 +685,10 @@ GNUTLS_2_12
gnutls_openpgp_crt_verify_hash;
gnutls_pubkey_import_privkey;
gnutls_pubkey_verify_data;
+} GNUTLS_2_10;
+
+GNUTLS_3_0_0 {
+ global:
gnutls_x509_trust_list_verify_crt;
gnutls_x509_trust_list_add_crls;
gnutls_x509_trust_list_add_cas;
@@ -698,7 +700,8 @@ GNUTLS_2_12
gnutls_cipher_tag;
gnutls_cipher_add_auth;
gnutls_dtls_set_timeouts;
-} GNUTLS_2_10;
+ gnutls_transport_set_pull_timeout_function;
+} GNUTLS_2_12;
GNUTLS_PRIVATE {
global:
diff --git a/lib/system.c b/lib/system.c
index d89c283709..169dd1551c 100644
--- a/lib/system.c
+++ b/lib/system.c
@@ -105,12 +105,15 @@ system_read_peek (gnutls_transport_ptr ptr, void *data, size_t data_size)
return recv (GNUTLS_POINTER_TO_INT (ptr), data, data_size, MSG_PEEK);
}
-/* Wait for data to be received within a timeout period in milliseconds
+/* Wait for data to be received within a timeout period in milliseconds.
+ * If data_size > 0 it will return the specified amount of data in
+ * peek mode.
*/
-int system_recv_timeout(gnutls_transport_ptr ptr, size_t ms)
+int system_recv_timeout(gnutls_transport_ptr ptr, void* data, size_t data_size, unsigned int ms)
{
fd_set rfds;
struct timeval tv;
+int ret;
FD_ZERO(&rfds);
FD_SET(GNUTLS_POINTER_TO_INT(ptr), &rfds);
@@ -118,7 +121,23 @@ struct timeval tv;
tv.tv_sec = 0;
tv.tv_usec = ms * 1000;
- return select(GNUTLS_POINTER_TO_INT(ptr)+1, &rfds, NULL, NULL, &tv);
+ ret = select(GNUTLS_POINTER_TO_INT(ptr)+1, &rfds, NULL, NULL, &tv);
+
+ if (ret <= 0 || data_size == 0)
+ return ret;
+
+ /* only report ok if the next message is from the peer we expect
+ * from
+ */
+ ret = recv(GNUTLS_POINTER_TO_INT(ptr), data, data_size, MSG_PEEK);
+ if (ret > 0)
+ {
+ return ret;
+ }
+ else
+ {
+ return -1;
+ }
}
/* Thread stuff */
diff --git a/lib/system.h b/lib/system.h
index 6ec4e83204..207e6fa49d 100644
--- a/lib/system.h
+++ b/lib/system.h
@@ -8,7 +8,7 @@
#endif
int system_errno (gnutls_transport_ptr);
-int system_recv_timeout(gnutls_transport_ptr ptr, size_t ms);
+int system_recv_timeout(gnutls_transport_ptr ptr,void*data, size_t, unsigned int ms);
#ifdef _WIN32
ssize_t system_write (gnutls_transport_ptr ptr, const void *data,
diff --git a/lib/system_override.c b/lib/system_override.c
new file mode 100644
index 0000000000..852ec2bc16
--- /dev/null
+++ b/lib/system_override.c
@@ -0,0 +1,202 @@
+/*
+ * Copyright (C) 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008,
+ * 2009, 2010, 2011 Free Software Foundation, Inc.
+ *
+ * Author: Nikos Mavrogiannopoulos
+ *
+ * This file is part of GnuTLS.
+ *
+ * The GnuTLS is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
+ * USA
+ *
+ */
+
+/* This file contains function that will override the
+ * default berkeley sockets API per session.
+ */
+
+#include <gnutls_int.h>
+#include <gnutls_errors.h>
+#include <gnutls_num.h>
+#include <gnutls_record.h>
+#include <gnutls_buffers.h>
+#include <gnutls_mbuffers.h>
+#include <gnutls_state.h>
+#include <gnutls_dtls.h>
+#include <system.h>
+
+#include <errno.h>
+
+/**
+ * gnutls_transport_set_errno:
+ * @session: is a #gnutls_session_t structure.
+ * @err: error value to store in session-specific errno variable.
+ *
+ * Store @err in the session-specific errno variable. Useful values
+ * for @err is EAGAIN and EINTR, other values are treated will be
+ * treated as real errors in the push/pull function.
+ *
+ * This function is useful in replacement push/pull functions set by
+ * gnutls_transport_set_push_function and
+ * gnutls_transport_set_pullpush_function under Windows, where the
+ * replacement push/pull may not have access to the same @errno
+ * variable that is used by GnuTLS (e.g., the application is linked to
+ * msvcr71.dll and gnutls is linked to msvcrt.dll).
+ *
+ * If you don't have the @session variable easily accessible from the
+ * push/pull function, and don't worry about thread conflicts, you can
+ * also use gnutls_transport_set_global_errno().
+ **/
+void
+gnutls_transport_set_errno (gnutls_session_t session, int err)
+{
+ session->internals.errnum = err;
+}
+
+/**
+ * gnutls_transport_set_global_errno:
+ * @err: error value to store in global errno variable.
+ *
+ * Store @err in the global errno variable. Useful values for @err is
+ * EAGAIN and EINTR, other values are treated will be treated as real
+ * errors in the push/pull function.
+ *
+ * This function is useful in replacement push/pull functions set by
+ * gnutls_transport_set_push_function and
+ * gnutls_transport_set_pullpush_function under Windows, where the
+ * replacement push/pull may not have access to the same @errno
+ * variable that is used by GnuTLS (e.g., the application is linked to
+ * msvcr71.dll and gnutls is linked to msvcrt.dll).
+ *
+ * Whether this function is thread safe or not depends on whether the
+ * global variable errno is thread safe, some system libraries make it
+ * a thread-local variable. When feasible, using the guaranteed
+ * thread-safe gnutls_transport_set_errno() may be better.
+ **/
+void
+gnutls_transport_set_global_errno (int err)
+{
+ errno = err;
+}
+
+/**
+ * gnutls_transport_set_pull_function:
+ * @session: is a #gnutls_session_t structure.
+ * @pull_func: a callback function similar to read()
+ *
+ * This is the function where you set a function for gnutls to receive
+ * data. Normally, if you use berkeley style sockets, do not need to
+ * use this function since the default (recv(2)) will probably be ok.
+ *
+ * gnutls_pull_func is of the form,
+ * ssize_t (*gnutls_pull_func)(gnutls_transport_ptr_t, void*, size_t);
+ **/
+void
+gnutls_transport_set_pull_function (gnutls_session_t session,
+ gnutls_pull_func pull_func)
+{
+ session->internals.pull_func = pull_func;
+}
+
+/**
+ * gnutls_transport_set_pull_timeout_function:
+ * @session: is a #gnutls_session_t structure.
+ * @func: a callback function
+ *
+ * This is the function where you set a function for gnutls to know
+ * whether data are ready to be received within a time limit in
+ * milliseconds. The callback should return 0 on timeout, a positive
+ * number if data can be received, and -1 on error.
+ * If the #data_size is non-zero that function should copy that
+ * amount of data received in peek mode (i.e., if any other
+ * function is called to receive data, it should return them again).
+ *
+ * The callback function is used in DTLS only.
+ *
+ * gnutls_pull_timeout_func is of the form,
+ * ssize_t (*gnutls_pull_timeout_func)(gnutls_transport_ptr_t, void*data, size_t size, unsigned int ms);
+ *
+ **/
+void
+gnutls_transport_set_pull_timeout_function (gnutls_session_t session,
+ gnutls_pull_timeout_func func)
+{
+ session->internals.pull_timeout_func = func;
+}
+
+/**
+ * gnutls_transport_set_push_function:
+ * @session: is a #gnutls_session_t structure.
+ * @push_func: a callback function similar to write()
+ *
+ * This is the function where you set a push function for gnutls to
+ * use in order to send data. If you are going to use berkeley style
+ * sockets, you do not need to use this function since the default
+ * (send(2)) will probably be ok. Otherwise you should specify this
+ * function for gnutls to be able to send data.
+ *
+ * push_func is of the form,
+ * ssize_t (*gnutls_push_func)(gnutls_transport_ptr_t, const void*, size_t);
+ *
+ **/
+void
+gnutls_transport_set_push_function (gnutls_session_t session,
+ gnutls_push_func push_func)
+{
+ session->internals.push_func = push_func;
+ session->internals.vec_push_func = NULL;
+}
+
+/**
+ * gnutls_transport_set_push_function2:
+ * @session: is a #gnutls_session_t structure.
+ * @vec_func: a callback function similar to writev()
+ *
+ * This is the function where you set a push function for gnutls to
+ * use in order to send data. If you are going to use berkeley style
+ * sockets, you do not need to use this function since the default
+ * (send(2)) will probably be ok. Otherwise you should specify this
+ * function for gnutls to be able to send data.
+ *
+ * vec_func is of the form,
+ * ssize_t (*gnutls_vec_push_func) (gnutls_transport_ptr_t, const giovec_t * iov, int iovcnt);
+ *
+ **/
+void
+gnutls_transport_set_push_function2 (gnutls_session_t session,
+ gnutls_vec_push_func vec_func)
+{
+ session->internals.push_func = NULL;
+ session->internals.vec_push_func = vec_func;
+}
+
+/**
+ * gnutls_transport_set_errno_function:
+ * @session: is a #gnutls_session_t structure.
+ * @errno_func: a callback function similar to write()
+ *
+ * This is the function where you set a function to retrieve errno
+ * after a failed push or pull operation.
+ *
+ * errno_func is of the form,
+ * int (*gnutls_errno_func)(gnutls_transport_ptr_t);
+ * and should return the errno.
+ **/
+void
+gnutls_transport_set_errno_function (gnutls_session_t session,
+ gnutls_errno_func errno_func)
+{
+ session->internals.errno_func = errno_func;
+}
diff --git a/src/Makefile.am b/src/Makefile.am
index 509a446b0d..622ee8c2ed 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -40,7 +40,7 @@ endif
noinst_LTLIBRARIES =
-gnutls_serv_SOURCES = list.h serv.c common.h common.c certtool-common.h
+gnutls_serv_SOURCES = list.h serv.c udp-serv.c common.h common.c certtool-common.h
gnutls_serv_LDADD = ../lib/libgnutls.la ../libextra/libgnutls-extra.la
gnutls_serv_LDADD += libcmd-serv.la ../gl/libgnu.la
gnutls_serv_LDADD += $(LTLIBGCRYPT) $(LIBSOCKET) $(GETADDRINFO_LIB)
diff --git a/src/serv-gaa.c b/src/serv-gaa.c
index a3c050d50b..e1fd2ece15 100644
--- a/src/serv-gaa.c
+++ b/src/serv-gaa.c
@@ -133,6 +133,7 @@ void gaa_help(void)
__gaa_helpsingle(0, "noticket", "", "Does not issue session tickets.");
__gaa_helpsingle(0, "http", "", "Act as an HTTP Server.");
__gaa_helpsingle(0, "echo", "", "Act as an Echo Server.");
+ __gaa_helpsingle(0, "udp", "", "Enable UDP server instead of TCP.");
__gaa_helpsingle(0, "dhparams", "FILE ", "DH params file to use.");
__gaa_helpsingle(0, "x509fmtder", "", "Use DER format for certificates");
__gaa_helpsingle(0, "x509cafile", "FILE ", "Certificate file or PKCS #11 URL to use.");
@@ -169,44 +170,46 @@ typedef struct _gaainfo gaainfo;
struct _gaainfo
{
-#line 88 "serv.gaa"
+#line 91 "serv.gaa"
char *priorities;
-#line 85 "serv.gaa"
+#line 88 "serv.gaa"
char *srp_passwd_conf;
-#line 82 "serv.gaa"
+#line 85 "serv.gaa"
char *srp_passwd;
-#line 79 "serv.gaa"
+#line 82 "serv.gaa"
char *psk_hint;
-#line 76 "serv.gaa"
+#line 79 "serv.gaa"
char *psk_passwd;
-#line 73 "serv.gaa"
+#line 76 "serv.gaa"
int disable_client_cert;
-#line 70 "serv.gaa"
+#line 73 "serv.gaa"
int require_cert;
-#line 67 "serv.gaa"
+#line 70 "serv.gaa"
char *x509_dsacertfile;
-#line 64 "serv.gaa"
+#line 67 "serv.gaa"
char *x509_dsakeyfile;
-#line 61 "serv.gaa"
+#line 64 "serv.gaa"
char *x509_certfile;
-#line 58 "serv.gaa"
+#line 61 "serv.gaa"
char *x509_keyfile;
-#line 55 "serv.gaa"
+#line 58 "serv.gaa"
char *pgp_subkey;
-#line 52 "serv.gaa"
+#line 55 "serv.gaa"
char *pgp_certfile;
-#line 49 "serv.gaa"
+#line 52 "serv.gaa"
char *pgp_keyfile;
-#line 46 "serv.gaa"
+#line 49 "serv.gaa"
char *pgp_keyring;
-#line 43 "serv.gaa"
+#line 46 "serv.gaa"
char *x509_crlfile;
-#line 40 "serv.gaa"
+#line 43 "serv.gaa"
char *x509_cafile;
-#line 37 "serv.gaa"
+#line 40 "serv.gaa"
int fmtder;
-#line 34 "serv.gaa"
+#line 37 "serv.gaa"
char *dh_params_file;
+#line 34 "serv.gaa"
+ int udp;
#line 30 "serv.gaa"
int http;
#line 27 "serv.gaa"
@@ -275,7 +278,7 @@ static int gaa_error = 0;
#define GAA_MULTIPLE_OPTION 3
#define GAA_REST 0
-#define GAA_NB_OPTION 30
+#define GAA_NB_OPTION 31
#define GAAOPTID_version 1
#define GAAOPTID_help 2
#define GAAOPTID_list 3
@@ -298,14 +301,15 @@ static int gaa_error = 0;
#define GAAOPTID_x509cafile 20
#define GAAOPTID_x509fmtder 21
#define GAAOPTID_dhparams 22
-#define GAAOPTID_echo 23
-#define GAAOPTID_http 24
-#define GAAOPTID_noticket 25
-#define GAAOPTID_nodb 26
-#define GAAOPTID_quiet 27
-#define GAAOPTID_port 28
-#define GAAOPTID_generate 29
-#define GAAOPTID_debug 30
+#define GAAOPTID_udp 23
+#define GAAOPTID_echo 24
+#define GAAOPTID_http 25
+#define GAAOPTID_noticket 26
+#define GAAOPTID_nodb 27
+#define GAAOPTID_quiet 28
+#define GAAOPTID_port 29
+#define GAAOPTID_generate 30
+#define GAAOPTID_debug 31
#line 168 "gaa.skel"
@@ -655,6 +659,7 @@ static int gaa_get_option_num(char *str, int status)
GAA_CHECK1STR("a", GAAOPTID_disable_client_cert);
GAA_CHECK1STR("r", GAAOPTID_require_cert);
GAA_CHECK1STR("", GAAOPTID_x509fmtder);
+ GAA_CHECK1STR("", GAAOPTID_udp);
GAA_CHECK1STR("", GAAOPTID_echo);
GAA_CHECK1STR("", GAAOPTID_http);
GAA_CHECK1STR("", GAAOPTID_noticket);
@@ -687,6 +692,7 @@ static int gaa_get_option_num(char *str, int status)
GAA_CHECKSTR("x509cafile", GAAOPTID_x509cafile);
GAA_CHECKSTR("x509fmtder", GAAOPTID_x509fmtder);
GAA_CHECKSTR("dhparams", GAAOPTID_dhparams);
+ GAA_CHECKSTR("udp", GAAOPTID_udp);
GAA_CHECKSTR("echo", GAAOPTID_echo);
GAA_CHECKSTR("http", GAAOPTID_http);
GAA_CHECKSTR("noticket", GAAOPTID_noticket);
@@ -747,21 +753,21 @@ static int gaa_try(int gaa_num, int gaa_index, gaainfo *gaaval, char *opt_list)
{
case GAAOPTID_version:
OK = 0;
-#line 94 "serv.gaa"
+#line 97 "serv.gaa"
{ serv_version(); exit(0); ;};
return GAA_OK;
break;
case GAAOPTID_help:
OK = 0;
-#line 92 "serv.gaa"
+#line 95 "serv.gaa"
{ gaa_help(); exit(0); ;};
return GAA_OK;
break;
case GAAOPTID_list:
OK = 0;
-#line 91 "serv.gaa"
+#line 94 "serv.gaa"
{ print_list(0); exit(0); ;};
return GAA_OK;
@@ -771,7 +777,7 @@ static int gaa_try(int gaa_num, int gaa_index, gaainfo *gaaval, char *opt_list)
GAA_TESTMOREARGS;
GAA_FILL(GAATMP_priority.arg1, gaa_getstr, GAATMP_priority.size1);
gaa_index++;
-#line 89 "serv.gaa"
+#line 92 "serv.gaa"
{ gaaval->priorities = GAATMP_priority.arg1 ;};
return GAA_OK;
@@ -781,7 +787,7 @@ static int gaa_try(int gaa_num, int gaa_index, gaainfo *gaaval, char *opt_list)
GAA_TESTMOREARGS;
GAA_FILL(GAATMP_srppasswdconf.arg1, gaa_getstr, GAATMP_srppasswdconf.size1);
gaa_index++;
-#line 86 "serv.gaa"
+#line 89 "serv.gaa"
{ gaaval->srp_passwd_conf = GAATMP_srppasswdconf.arg1 ;};
return GAA_OK;
@@ -791,7 +797,7 @@ static int gaa_try(int gaa_num, int gaa_index, gaainfo *gaaval, char *opt_list)
GAA_TESTMOREARGS;
GAA_FILL(GAATMP_srppasswd.arg1, gaa_getstr, GAATMP_srppasswd.size1);
gaa_index++;
-#line 83 "serv.gaa"
+#line 86 "serv.gaa"
{ gaaval->srp_passwd = GAATMP_srppasswd.arg1 ;};
return GAA_OK;
@@ -801,7 +807,7 @@ static int gaa_try(int gaa_num, int gaa_index, gaainfo *gaaval, char *opt_list)
GAA_TESTMOREARGS;
GAA_FILL(GAATMP_pskhint.arg1, gaa_getstr, GAATMP_pskhint.size1);
gaa_index++;
-#line 80 "serv.gaa"
+#line 83 "serv.gaa"
{ gaaval->psk_hint = GAATMP_pskhint.arg1 ;};
return GAA_OK;
@@ -811,21 +817,21 @@ static int gaa_try(int gaa_num, int gaa_index, gaainfo *gaaval, char *opt_list)
GAA_TESTMOREARGS;
GAA_FILL(GAATMP_pskpasswd.arg1, gaa_getstr, GAATMP_pskpasswd.size1);
gaa_index++;
-#line 77 "serv.gaa"
+#line 80 "serv.gaa"
{ gaaval->psk_passwd = GAATMP_pskpasswd.arg1 ;};
return GAA_OK;
break;
case GAAOPTID_disable_client_cert:
OK = 0;
-#line 74 "serv.gaa"
+#line 77 "serv.gaa"
{ gaaval->disable_client_cert = 1 ;};
return GAA_OK;
break;
case GAAOPTID_require_cert:
OK = 0;
-#line 71 "serv.gaa"
+#line 74 "serv.gaa"
{ gaaval->require_cert = 1 ;};
return GAA_OK;
@@ -835,7 +841,7 @@ static int gaa_try(int gaa_num, int gaa_index, gaainfo *gaaval, char *opt_list)
GAA_TESTMOREARGS;
GAA_FILL(GAATMP_x509dsacertfile.arg1, gaa_getstr, GAATMP_x509dsacertfile.size1);
gaa_index++;
-#line 68 "serv.gaa"
+#line 71 "serv.gaa"
{ gaaval->x509_dsacertfile = GAATMP_x509dsacertfile.arg1 ;};
return GAA_OK;
@@ -845,7 +851,7 @@ static int gaa_try(int gaa_num, int gaa_index, gaainfo *gaaval, char *opt_list)
GAA_TESTMOREARGS;
GAA_FILL(GAATMP_x509dsakeyfile.arg1, gaa_getstr, GAATMP_x509dsakeyfile.size1);
gaa_index++;
-#line 65 "serv.gaa"
+#line 68 "serv.gaa"
{ gaaval->x509_dsakeyfile = GAATMP_x509dsakeyfile.arg1 ;};
return GAA_OK;
@@ -855,7 +861,7 @@ static int gaa_try(int gaa_num, int gaa_index, gaainfo *gaaval, char *opt_list)
GAA_TESTMOREARGS;
GAA_FILL(GAATMP_x509certfile.arg1, gaa_getstr, GAATMP_x509certfile.size1);
gaa_index++;
-#line 62 "serv.gaa"
+#line 65 "serv.gaa"
{ gaaval->x509_certfile = GAATMP_x509certfile.arg1 ;};
return GAA_OK;
@@ -865,7 +871,7 @@ static int gaa_try(int gaa_num, int gaa_index, gaainfo *gaaval, char *opt_list)
GAA_TESTMOREARGS;
GAA_FILL(GAATMP_x509keyfile.arg1, gaa_getstr, GAATMP_x509keyfile.size1);
gaa_index++;
-#line 59 "serv.gaa"
+#line 62 "serv.gaa"
{ gaaval->x509_keyfile = GAATMP_x509keyfile.arg1 ;};
return GAA_OK;
@@ -875,7 +881,7 @@ static int gaa_try(int gaa_num, int gaa_index, gaainfo *gaaval, char *opt_list)
GAA_TESTMOREARGS;
GAA_FILL(GAATMP_pgpsubkey.arg1, gaa_getstr, GAATMP_pgpsubkey.size1);
gaa_index++;
-#line 56 "serv.gaa"
+#line 59 "serv.gaa"
{ gaaval->pgp_subkey = GAATMP_pgpsubkey.arg1 ;};
return GAA_OK;
@@ -885,7 +891,7 @@ static int gaa_try(int gaa_num, int gaa_index, gaainfo *gaaval, char *opt_list)
GAA_TESTMOREARGS;
GAA_FILL(GAATMP_pgpcertfile.arg1, gaa_getstr, GAATMP_pgpcertfile.size1);
gaa_index++;
-#line 53 "serv.gaa"
+#line 56 "serv.gaa"
{ gaaval->pgp_certfile = GAATMP_pgpcertfile.arg1 ;};
return GAA_OK;
@@ -895,7 +901,7 @@ static int gaa_try(int gaa_num, int gaa_index, gaainfo *gaaval, char *opt_list)
GAA_TESTMOREARGS;
GAA_FILL(GAATMP_pgpkeyfile.arg1, gaa_getstr, GAATMP_pgpkeyfile.size1);
gaa_index++;
-#line 50 "serv.gaa"
+#line 53 "serv.gaa"
{ gaaval->pgp_keyfile = GAATMP_pgpkeyfile.arg1 ;};
return GAA_OK;
@@ -905,7 +911,7 @@ static int gaa_try(int gaa_num, int gaa_index, gaainfo *gaaval, char *opt_list)
GAA_TESTMOREARGS;
GAA_FILL(GAATMP_pgpkeyring.arg1, gaa_getstr, GAATMP_pgpkeyring.size1);
gaa_index++;
-#line 47 "serv.gaa"
+#line 50 "serv.gaa"
{ gaaval->pgp_keyring = GAATMP_pgpkeyring.arg1 ;};
return GAA_OK;
@@ -915,7 +921,7 @@ static int gaa_try(int gaa_num, int gaa_index, gaainfo *gaaval, char *opt_list)
GAA_TESTMOREARGS;
GAA_FILL(GAATMP_x509crlfile.arg1, gaa_getstr, GAATMP_x509crlfile.size1);
gaa_index++;
-#line 44 "serv.gaa"
+#line 47 "serv.gaa"
{ gaaval->x509_crlfile = GAATMP_x509crlfile.arg1 ;};
return GAA_OK;
@@ -925,14 +931,14 @@ static int gaa_try(int gaa_num, int gaa_index, gaainfo *gaaval, char *opt_list)
GAA_TESTMOREARGS;
GAA_FILL(GAATMP_x509cafile.arg1, gaa_getstr, GAATMP_x509cafile.size1);
gaa_index++;
-#line 41 "serv.gaa"
+#line 44 "serv.gaa"
{ gaaval->x509_cafile = GAATMP_x509cafile.arg1 ;};
return GAA_OK;
break;
case GAAOPTID_x509fmtder:
OK = 0;
-#line 38 "serv.gaa"
+#line 41 "serv.gaa"
{ gaaval->fmtder = 1 ;};
return GAA_OK;
@@ -942,11 +948,18 @@ static int gaa_try(int gaa_num, int gaa_index, gaainfo *gaaval, char *opt_list)
GAA_TESTMOREARGS;
GAA_FILL(GAATMP_dhparams.arg1, gaa_getstr, GAATMP_dhparams.size1);
gaa_index++;
-#line 35 "serv.gaa"
+#line 38 "serv.gaa"
{ gaaval->dh_params_file = GAATMP_dhparams.arg1 ;};
return GAA_OK;
break;
+ case GAAOPTID_udp:
+ OK = 0;
+#line 35 "serv.gaa"
+{ gaaval->udp = 1 ;};
+
+ return GAA_OK;
+ break;
case GAAOPTID_echo:
OK = 0;
#line 32 "serv.gaa"
@@ -1033,7 +1046,7 @@ int gaa(int argc, char **argv, gaainfo *gaaval)
if(inited == 0)
{
-#line 98 "serv.gaa"
+#line 101 "serv.gaa"
{ gaaval->generate=0; gaaval->port=5556; gaaval->http=0; gaaval->nodb = 0; gaaval->noticket = 0;
gaaval->x509_cafile = NULL; gaaval->pgp_keyfile=NULL; gaaval->pgp_certfile=NULL;
gaaval->x509_keyfile=NULL; gaaval->x509_certfile=NULL; gaaval->x509_crlfile = NULL;
@@ -1042,7 +1055,7 @@ int gaa(int argc, char **argv, gaainfo *gaaval)
gaaval->pgp_keyring=NULL; gaaval->fmtder = 0;
gaaval->disable_client_cert = 0; gaaval->priorities = NULL;
gaaval->dh_params_file=NULL; gaaval->debug=0; gaaval->require_cert = 0; gaaval->psk_passwd = 0;
- gaaval->pgp_subkey = NULL;;};
+ gaaval->pgp_subkey = NULL; gaaval->udp = 0; ;};
}
inited = 1;
diff --git a/src/serv-gaa.h b/src/serv-gaa.h
index 2a4a08ab43..0a1d560866 100644
--- a/src/serv-gaa.h
+++ b/src/serv-gaa.h
@@ -8,44 +8,46 @@ typedef struct _gaainfo gaainfo;
struct _gaainfo
{
-#line 88 "serv.gaa"
+#line 91 "serv.gaa"
char *priorities;
-#line 85 "serv.gaa"
+#line 88 "serv.gaa"
char *srp_passwd_conf;
-#line 82 "serv.gaa"
+#line 85 "serv.gaa"
char *srp_passwd;
-#line 79 "serv.gaa"
+#line 82 "serv.gaa"
char *psk_hint;
-#line 76 "serv.gaa"
+#line 79 "serv.gaa"
char *psk_passwd;
-#line 73 "serv.gaa"
+#line 76 "serv.gaa"
int disable_client_cert;
-#line 70 "serv.gaa"
+#line 73 "serv.gaa"
int require_cert;
-#line 67 "serv.gaa"
+#line 70 "serv.gaa"
char *x509_dsacertfile;
-#line 64 "serv.gaa"
+#line 67 "serv.gaa"
char *x509_dsakeyfile;
-#line 61 "serv.gaa"
+#line 64 "serv.gaa"
char *x509_certfile;
-#line 58 "serv.gaa"
+#line 61 "serv.gaa"
char *x509_keyfile;
-#line 55 "serv.gaa"
+#line 58 "serv.gaa"
char *pgp_subkey;
-#line 52 "serv.gaa"
+#line 55 "serv.gaa"
char *pgp_certfile;
-#line 49 "serv.gaa"
+#line 52 "serv.gaa"
char *pgp_keyfile;
-#line 46 "serv.gaa"
+#line 49 "serv.gaa"
char *pgp_keyring;
-#line 43 "serv.gaa"
+#line 46 "serv.gaa"
char *x509_crlfile;
-#line 40 "serv.gaa"
+#line 43 "serv.gaa"
char *x509_cafile;
-#line 37 "serv.gaa"
+#line 40 "serv.gaa"
int fmtder;
-#line 34 "serv.gaa"
+#line 37 "serv.gaa"
char *dh_params_file;
+#line 34 "serv.gaa"
+ int udp;
#line 30 "serv.gaa"
int http;
#line 27 "serv.gaa"
diff --git a/src/serv.c b/src/serv.c
index 068762438d..698ab5019d 100644
--- a/src/serv.c
+++ b/src/serv.c
@@ -49,6 +49,7 @@
#include "read-file.h"
#include "minmax.h"
#include "sockets.h"
+#include "udp-serv.h"
/* konqueror cannot handle sending the page in multiple
* pieces.
@@ -56,7 +57,6 @@
/* global stuff */
static int generate = 0;
static int http = 0;
-static int port = 0;
static int x509ctype;
static int debug;
@@ -81,6 +81,7 @@ char *dh_params_file;
char *x509_crlfile = NULL;
gnutls_datum_t session_ticket_key;
+static int tcp_server(const char* name, int port);
/* end of globals */
@@ -326,13 +327,15 @@ generate_rsa_params (void)
LIST_DECLARE_INIT (listener_list, listener_item, listener_free);
-static gnutls_session_t
-initialize_session (void)
+gnutls_session_t initialize_session (int dtls)
{
gnutls_session_t session;
const char *err;
- gnutls_init (&session, GNUTLS_SERVER);
+ if (dtls)
+ gnutls_init_dtls (&session, GNUTLS_SERVER, 0);
+ else
+ gnutls_init (&session, GNUTLS_SERVER);
/* allow the use of private ciphersuites.
*/
@@ -585,7 +588,7 @@ peer_print_info (gnutls_session_t session, int *ret_length,
return http_buffer;
}
-static const char *
+const char *
human_addr (const struct sockaddr *sa, socklen_t salen,
char *buf, size_t buflen)
{
@@ -633,8 +636,52 @@ human_addr (const struct sockaddr *sa, socklen_t salen,
return save_buf;
}
-static int
-listen_socket (const char *name, int listen_port)
+int wait_for_connection(void)
+{
+ listener_item *j;
+ fd_set rd, wr;
+ int n, sock = -1;
+
+ FD_ZERO (&rd);
+ FD_ZERO (&wr);
+ n = 0;
+
+ lloopstart (listener_list, j)
+ {
+ if (j->listen_socket)
+ {
+ FD_SET (j->fd, &rd);
+ n = MAX (n, j->fd);
+ }
+ }
+ lloopend (listener_list, j);
+
+ /* waiting part */
+ n = select (n + 1, &rd, &wr, NULL, NULL);
+ if (n == -1 && errno == EINTR)
+ return -1;
+ if (n < 0)
+ {
+ perror ("select()");
+ exit (1);
+ }
+
+ /* find which one is ready */
+ lloopstart (listener_list, j)
+ {
+ /* a new connection has arrived */
+ if (FD_ISSET (j->fd, &rd) && j->listen_socket)
+ {
+ sock = j->fd;
+ break;
+ }
+ }
+ lloopend (listener_list, j);
+ return sock;
+}
+
+int
+listen_socket (const char *name, int listen_port, int socktype)
{
struct addrinfo hints, *res, *ptr;
char portname[6];
@@ -644,7 +691,7 @@ listen_socket (const char *name, int listen_port)
snprintf (portname, sizeof (portname), "%d", listen_port);
memset (&hints, 0, sizeof (hints));
- hints.ai_socktype = SOCK_STREAM;
+ hints.ai_socktype = socktype;
hints.ai_flags = AI_PASSIVE;
if ((s = getaddrinfo (NULL, portname, &hints, &res)) != 0)
@@ -671,26 +718,32 @@ listen_socket (const char *name, int listen_port)
continue;
}
- yes = 1;
- if (setsockopt (s, SOL_SOCKET, SO_REUSEADDR,
- (const void *) &yes, sizeof (yes)) < 0)
+ if (socktype == SOCK_STREAM)
{
- perror ("setsockopt() failed");
- failed:
- close (s);
- continue;
+ yes = 1;
+ if (setsockopt (s, SOL_SOCKET, SO_REUSEADDR,
+ (const void *) &yes, sizeof (yes)) < 0)
+ {
+ perror ("setsockopt() failed");
+ close (s);
+ continue;
+ }
}
if (bind (s, ptr->ai_addr, ptr->ai_addrlen) < 0)
{
perror ("bind() failed");
- goto failed;
+ close (s);
+ continue;
}
- if (listen (s, 10) < 0)
+ if (socktype == SOCK_STREAM)
{
- perror ("listen() failed");
- goto failed;
+ if (listen (s, 10) < 0)
+ {
+ perror ("listen() failed");
+ exit(1);
+ }
}
/* new list entry for the connection */
@@ -706,10 +759,8 @@ listen_socket (const char *name, int listen_port)
fflush (stderr);
freeaddrinfo (res);
- if (!j)
- return -1;
- return 0;
+ return s;
}
/* strips \r\n from the end of the string
@@ -824,12 +875,8 @@ static void gaa_parser (int argc, char **argv);
int
main (int argc, char **argv)
{
- int ret, n;
- char topbuf[512];
+ int ret;
char name[256];
- int accept_fd;
- struct sockaddr_storage client_address;
- socklen_t calen;
set_program_name (argv[0]);
@@ -1049,7 +1096,22 @@ main (int argc, char **argv)
gnutls_session_ticket_key_generate (&session_ticket_key);
#endif
- if (listen_socket (name, port) < 0)
+ if (info.udp)
+ return udp_server(name, info.port);
+ else
+ return tcp_server(name, info.port);
+}
+
+static int tcp_server(const char* name, int port)
+{
+ int n, s;
+ char topbuf[512];
+ int accept_fd;
+ struct sockaddr_storage client_address;
+ socklen_t calen;
+
+ s = listen_socket (name, port, SOCK_STREAM);
+ if (s < 0)
exit (1);
for (;;)
@@ -1112,7 +1174,7 @@ main (int argc, char **argv)
{
gnutls_session_t tls_session;
- tls_session = initialize_session ();
+ tls_session = initialize_session (0);
calen = sizeof (client_address);
memset (&client_address, 0, calen);
@@ -1462,8 +1524,6 @@ gaa_parser (int argc, char **argv)
dh_params_file = info.dh_params_file;
- port = info.port;
-
x509_certfile = info.x509_certfile;
x509_keyfile = info.x509_keyfile;
x509_dsacertfile = info.x509_dsacertfile;
diff --git a/src/serv.gaa b/src/serv.gaa
index 0d886a54c0..93cc85d98e 100644
--- a/src/serv.gaa
+++ b/src/serv.gaa
@@ -31,6 +31,9 @@ option (noticket) { $noticket = 1 } "Does not issue session tickets."
option (http) { $http = 1 } "Act as an HTTP Server."
option (echo) { $http = 0 } "Act as an Echo Server."
+#int udp;
+option (udp) { $udp = 1 } "Enable UDP server instead of TCP."
+
#char *dh_params_file;
option (dhparams) STR "FILE" { $dh_params_file = $1 } "DH params file to use."
@@ -103,4 +106,4 @@ init { $generate=0; $port=5556; $http=0; $nodb = 0; $noticket = 0;
$pgp_keyring=NULL; $fmtder = 0;
$disable_client_cert = 0; $priorities = NULL;
$dh_params_file=NULL; $debug=0; $require_cert = 0; $psk_passwd = 0;
- $pgp_subkey = NULL;}
+ $pgp_subkey = NULL; $udp = 0; }
diff --git a/src/udp-serv.c b/src/udp-serv.c
new file mode 100644
index 0000000000..332917ea8b
--- /dev/null
+++ b/src/udp-serv.c
@@ -0,0 +1,174 @@
+#include <stdio.h>
+#include <sys/socket.h>
+#include <arpa/inet.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <errno.h>
+#include "udp-serv.h"
+#include "list.h"
+
+typedef struct {
+ gnutls_session_t session;
+ int fd;
+ struct sockaddr * cli_addr;
+ socklen_t cli_addr_size;
+} priv_data_st;
+
+static int pull_timeout_func(gnutls_transport_ptr ptr, void* data, size_t data_size, unsigned int ms);
+static ssize_t push_func (gnutls_transport_ptr_t p, const void * data, size_t size);
+static ssize_t pull_func(gnutls_transport_ptr_t p, void * data, size_t size);
+
+#define MAX_BUFFER 255 /* Longest string to echo */
+
+int udp_server(const char* name, int port)
+{
+ int sock, ret;
+ struct sockaddr_in cli_addr;
+ socklen_t cli_addr_size;
+ char buffer[MAX_BUFFER];
+ priv_data_st priv;
+ gnutls_session_t session;
+
+ ret = listen_socket (name, port, SOCK_DGRAM);
+ if (ret < 0)
+ exit (1);
+
+ for (;;)
+ {
+ printf("Waiting for connection...\n");
+ sock = wait_for_connection();
+ if (sock < 0)
+ continue;
+
+ cli_addr_size = sizeof(cli_addr);
+ ret = recvfrom(sock, buffer, 1, MSG_PEEK, (struct sockaddr*)&cli_addr, &cli_addr_size);
+ if (ret == 1)
+ printf ("Accepted connection from %s\n",
+ human_addr ((struct sockaddr *)
+ &cli_addr, sizeof(cli_addr), buffer,
+ sizeof (buffer)));
+ else
+ continue;
+
+ session = initialize_session(1);
+
+ priv.session = session;
+ priv.fd = sock;
+ priv.cli_addr = (struct sockaddr *)&cli_addr;
+ priv.cli_addr_size = sizeof(cli_addr);
+
+ gnutls_transport_set_ptr (session, &priv);
+ gnutls_transport_set_push_function (session, push_func);
+ gnutls_transport_set_pull_function (session, pull_func);
+ gnutls_transport_set_pull_timeout_function (session, pull_timeout_func);
+
+ ret = gnutls_handshake(session);
+ if (ret < 0)
+ {
+ fprintf(stderr, "Error in handshake(): %s\n", gnutls_strerror(ret));
+ continue;
+ }
+
+ for(;;)
+ {
+ ret = gnutls_record_recv(session, buffer, MAX_BUFFER);
+ if (ret < 0)
+ {
+ fprintf(stderr, "Error in recv(): %s\n", gnutls_strerror(ret));
+ break;
+ }
+ if (ret == 0)
+ {
+ printf("EOF\n\n");
+ break;
+ }
+ buffer[ret] = 0;
+ printf("received[%d]: %s\n", ret, buffer);
+
+ /* reply back */
+ ret = gnutls_record_send(session, buffer, ret);
+ if (ret < 0)
+ {
+ fprintf(stderr, "Error in send(): %s\n", gnutls_strerror(ret));
+ break;
+ }
+ }
+ }
+ gnutls_deinit(session);
+}
+
+/* Wait for data to be received within a timeout period in milliseconds
+ */
+static int pull_timeout_func(gnutls_transport_ptr ptr, void* data, size_t data_size, unsigned int ms)
+{
+fd_set rfds;
+struct timeval tv;
+priv_data_st *priv = ptr;
+struct sockaddr_in cli_addr;
+socklen_t cli_addr_size;
+int ret;
+char c;
+
+ FD_ZERO(&rfds);
+ FD_SET(priv->fd, &rfds);
+
+ tv.tv_sec = 0;
+ tv.tv_usec = ms * 1000;
+
+ ret = select(priv->fd+1, &rfds, NULL, NULL, &tv);
+
+ if (ret <= 0)
+ return ret;
+
+ if (data_size == 0)
+ {
+ data = &c;
+ data_size = 1;
+ }
+
+ /* only report ok if the next message is from the peer we expect
+ * from
+ */
+ cli_addr_size = sizeof(cli_addr);
+ ret = recvfrom(priv->fd, data, data_size, MSG_PEEK, (struct sockaddr*)&cli_addr, &cli_addr_size);
+ if (ret > 0)
+ {
+ if (cli_addr_size == priv->cli_addr_size && memcmp(&cli_addr, priv->cli_addr, sizeof(cli_addr))==0)
+ return 1;
+ }
+
+ return 0;
+}
+
+static ssize_t push_func (gnutls_transport_ptr_t p, const void * data, size_t size)
+{
+priv_data_st *priv = p;
+
+ return sendto(priv->fd, data, size, 0, priv->cli_addr, priv->cli_addr_size);
+}
+
+static ssize_t pull_func(gnutls_transport_ptr_t p, void * data, size_t size)
+{
+priv_data_st *priv = p;
+struct sockaddr_in cli_addr;
+socklen_t cli_addr_size;
+char buffer[64];
+int ret;
+
+ cli_addr_size = sizeof(cli_addr);
+ ret = recvfrom(priv->fd, data, size, 0, (struct sockaddr*)&cli_addr, &cli_addr_size);
+ if (ret == -1)
+ return ret;
+
+ if (cli_addr_size == priv->cli_addr_size && memcmp(&cli_addr, priv->cli_addr, sizeof(cli_addr))==0)
+ return ret;
+
+ printf ("Denied connection from %s\n",
+ human_addr ((struct sockaddr *)
+ &cli_addr, sizeof(cli_addr), buffer,
+ sizeof (buffer)));
+
+ gnutls_transport_set_errno(priv->session, EAGAIN);
+ return -1;
+}
diff --git a/src/udp-serv.h b/src/udp-serv.h
new file mode 100644
index 0000000000..7a481b93a9
--- /dev/null
+++ b/src/udp-serv.h
@@ -0,0 +1,8 @@
+#include <gnutls/dtls.h>
+
+int udp_server(const char* name, int port);
+gnutls_session_t initialize_session (int dtls);
+const char * human_addr (const struct sockaddr *sa, socklen_t salen,
+ char *buf, size_t buflen);
+int wait_for_connection(void);
+int listen_socket (const char *name, int listen_port, int socktype);