From 714fa685ee2f704a9d1945a7b0b1fa73bfe6ff55 Mon Sep 17 00:00:00 2001 From: Linus Nordberg Date: Thu, 3 Mar 2011 11:50:35 +0100 Subject: Correct an error string. --- lib/packet.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'lib/packet.c') diff --git a/lib/packet.c b/lib/packet.c index 9527012..ea1a07f 100644 --- a/lib/packet.c +++ b/lib/packet.c @@ -452,7 +452,7 @@ _set_timeout (struct rs_connection *conn) conn->tev = evtimer_new (conn->evb, _conn_timeout_cb, conn); if (!conn->tev) return rs_err_conn_push_fl (conn, RSE_EVENT, __FILE__, __LINE__, - "event_new"); + "evtimer_new"); tv.tv_sec = conn->realm->timeout; tv.tv_usec = 0; evtimer_add (conn->tev, &tv); -- cgit v1.1 From b01fafad7778040ec98619653328deecc1ef1ab1 Mon Sep 17 00:00:00 2001 From: Linus Nordberg Date: Thu, 3 Mar 2011 14:02:40 +0100 Subject: Correct an error code. --- lib/packet.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'lib/packet.c') diff --git a/lib/packet.c b/lib/packet.c index ea1a07f..2ef7e45 100644 --- a/lib/packet.c +++ b/lib/packet.c @@ -46,9 +46,11 @@ _do_send (struct rs_packet *pkt) assert (pkt->rpkt); assert (!pkt->original); + /* Add Message-Authenticator, RFC 2869. */ + /* FIXME: Make Message-Authenticator optional? */ vp = paircreate (PW_MESSAGE_AUTHENTICATOR, PW_TYPE_OCTETS); if (!vp) - return rs_err_conn_push_fl (pkt->conn, RSE_NOMEM, __FILE__, __LINE__, + return rs_err_conn_push_fl (pkt->conn, RSE_FR, __FILE__, __LINE__, "paircreate: %s", fr_strerror ()); pairadd (&pkt->rpkt->vps, vp); -- cgit v1.1 From 41a69151d5a375f524e2227f87979ff758bf2a62 Mon Sep 17 00:00:00 2001 From: Linus Nordberg Date: Thu, 3 Mar 2011 16:05:48 +0100 Subject: _init_evb: Don't crash on socket errors. --- lib/packet.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) (limited to 'lib/packet.c') diff --git a/lib/packet.c b/lib/packet.c index 2ef7e45..d025027 100644 --- a/lib/packet.c +++ b/lib/packet.c @@ -404,13 +404,15 @@ _init_socket (struct rs_connection *conn, struct rs_peer *p) p->addr->ai_protocol); if (conn->fd < 0) return rs_err_conn_push_fl (conn, RSE_SOCKERR, __FILE__, __LINE__, - strerror (errno)); + "socket: %d (%s)", + errno, strerror (errno)); if (evutil_make_socket_nonblocking (conn->fd) < 0) { evutil_closesocket (conn->fd); conn->fd = -1; return rs_err_conn_push_fl (conn, RSE_SOCKERR, __FILE__, __LINE__, - strerror (errno)); + "evutil_make_socket_nonblocking: %d (%s)", + errno, strerror (errno)); } return RSE_OK; } -- cgit v1.1 From fda0bfd44f940688f85fe3a99a0c8cd91611452f Mon Sep 17 00:00:00 2001 From: Linus Nordberg Date: Sun, 6 Mar 2011 14:44:27 +0100 Subject: Cosmetic changes. --- lib/packet.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) (limited to 'lib/packet.c') diff --git a/lib/packet.c b/lib/packet.c index d025027..9874dee 100644 --- a/lib/packet.c +++ b/lib/packet.c @@ -330,9 +330,9 @@ _read_packet (struct rs_packet *pkt) Inform upper layer about successful reception of valid RADIUS message by invoking conn->callbacks.recevied_cb(), if !NULL. */ static void -_read_cb (struct bufferevent *bev, void *ctx) +_read_cb (struct bufferevent *bev, void *user_data) { - struct rs_packet *pkt = (struct rs_packet *) ctx; + struct rs_packet *pkt = (struct rs_packet *) user_data; assert (pkt); assert (pkt->conn); @@ -765,21 +765,21 @@ rs_conn_receive_packet (struct rs_connection *conn, } void -rs_packet_add_attr(struct rs_packet *pkt, struct rs_attr *attr) +rs_packet_add_attr (struct rs_packet *pkt, struct rs_attr *attr) { pairadd (&pkt->rpkt->vps, attr->vp); attr->pkt = pkt; } struct radius_packet * -rs_packet_frpkt(struct rs_packet *pkt) +rs_packet_frpkt (struct rs_packet *pkt) { assert (pkt); return pkt->rpkt; } void -rs_packet_destroy(struct rs_packet *pkt) +rs_packet_destroy (struct rs_packet *pkt) { if (pkt) { -- cgit v1.1 From 7636505962a348d9564e53922834dc6df1274653 Mon Sep 17 00:00:00 2001 From: Linus Nordberg Date: Sun, 6 Mar 2011 14:46:57 +0100 Subject: UDP w/o bufferevents, part 1. Sending, no retransmitting and no receiving. --- lib/packet.c | 277 ++++++++++++++++++++++++++++++++++++++++++++--------------- 1 file changed, 208 insertions(+), 69 deletions(-) (limited to 'lib/packet.c') diff --git a/lib/packet.c b/lib/packet.c index 9874dee..afe2725 100644 --- a/lib/packet.c +++ b/lib/packet.c @@ -8,17 +8,19 @@ #include #include #include +#include #include #include #include #include #include #include -#include "tls.h" +#include "compat.h" #include "debug.h" #if defined (RS_ENABLE_TLS) #include #include +#include "tls.h" #endif #if defined (DEBUG) #include @@ -27,6 +29,18 @@ #endif static int +_close_conn (struct rs_connection **connp) +{ + int r; + assert (connp); + assert (*connp); + r = rs_conn_destroy (*connp); + if (!r) + *connp = NULL; + return r; +} + +static int _loopbreak (struct rs_connection *conn) { int err = event_base_loopbreak (conn->evb); @@ -37,11 +51,12 @@ _loopbreak (struct rs_connection *conn) return err; } +/* Badly named helper function for preparing a RADIUS message and + queue it. FIXME: Rename. */ static int _do_send (struct rs_packet *pkt) { - int err; - VALUE_PAIR *vp; + VALUE_PAIR *vp = NULL; assert (pkt->rpkt); assert (!pkt->original); @@ -73,23 +88,39 @@ _do_send (struct rs_packet *pkt) } #endif - err = bufferevent_write (pkt->conn->bev, pkt->rpkt->data, - pkt->rpkt->data_len); - if (err < 0) - return rs_err_conn_push_fl (pkt->conn, RSE_EVENT, __FILE__, __LINE__, - "bufferevent_write: %s", - evutil_gai_strerror (err)); + if (pkt->conn->bev) + { + int err = bufferevent_write (pkt->conn->bev, pkt->rpkt->data, + pkt->rpkt->data_len); + if (err < 0) + return rs_err_conn_push_fl (pkt->conn, RSE_EVENT, __FILE__, __LINE__, + "bufferevent_write: %s", + evutil_gai_strerror (err)); + } + else + { + struct rs_packet **pp = &pkt->conn->out_queue; + + while (*pp && (*pp)->next) + *pp = (*pp)->next; + *pp = pkt; + } + return RSE_OK; } static void -_on_connect (struct rs_connection *conn) +_on_connect (struct rs_connection *conn, struct rs_packet *pkt) { + assert (!conn->is_connecting); conn->is_connected = 1; rs_debug (("%s: %p connected\n", __func__, conn->active_peer)); - evtimer_del (conn->tev); + if (conn->tev) + evtimer_del (conn->tev); if (conn->callbacks.connected_cb) conn->callbacks.connected_cb (conn->user_data); + if (pkt) + _do_send (pkt); } static void @@ -103,9 +134,9 @@ _on_disconnect (struct rs_connection *conn) } static void -_event_cb (struct bufferevent *bev, short events, void *ctx) +_event_cb (struct bufferevent *bev, short events, void *user_data) { - struct rs_packet *pkt = (struct rs_packet *)ctx; + struct rs_packet *pkt = (struct rs_packet *) user_data; struct rs_connection *conn = NULL; struct rs_peer *p = NULL; int sockerr = 0; @@ -122,9 +153,7 @@ _event_cb (struct bufferevent *bev, short events, void *ctx) conn->is_connecting = 0; if (events & BEV_EVENT_CONNECTED) { - _on_connect (conn); - if (_do_send (pkt)) - rs_debug (("%s: error sending\n", __func__)); + _on_connect (conn, pkt); } else if (events & BEV_EVENT_EOF) { @@ -145,15 +174,11 @@ _event_cb (struct bufferevent *bev, short events, void *ctx) } else { + rs_debug (("%s: %d: %d (%s)\n", __func__, conn->fd, sockerr, + evutil_socket_error_to_string (sockerr))); rs_err_conn_push_fl (pkt->conn, RSE_SOCKERR, __FILE__, __LINE__, - "%d: socket error %d (%s)", - conn->fd, - sockerr, + "%d: %d (%s)", conn->fd, sockerr, evutil_socket_error_to_string (sockerr)); - rs_debug (("%s: socket error on fd %d: %s (%d)\n", __func__, - conn->fd, - evutil_socket_error_to_string (sockerr), - sockerr)); } #if defined (RS_ENABLE_TLS) if (conn->tls_ssl) /* FIXME: correct check? */ @@ -204,7 +229,7 @@ _read_header (struct rs_packet *pkt) pkt->rpkt->data_len = (pkt->hdr[2] << 8) + pkt->hdr[3]; if (pkt->rpkt->data_len < 20 || pkt->rpkt->data_len > 4096) { - bufferevent_free (pkt->conn->bev); /* Close connection. */ + _close_conn (&pkt->conn); return rs_err_conn_push (pkt->conn, RSE_INVALID_PKT, "invalid packet length: %d", pkt->rpkt->data_len); @@ -212,7 +237,7 @@ _read_header (struct rs_packet *pkt) pkt->rpkt->data = rs_malloc (pkt->conn->ctx, pkt->rpkt->data_len); if (!pkt->rpkt->data) { - bufferevent_free (pkt->conn->bev); /* Close connection. */ + _close_conn (&pkt->conn); return rs_err_conn_push_fl (pkt->conn, RSE_NOMEM, __FILE__, __LINE__, NULL); } @@ -228,7 +253,7 @@ _read_header (struct rs_packet *pkt) } else /* Error: libevent gave us less than the low watermark. */ { - bufferevent_free (pkt->conn->bev); /* Close connection. */ + _close_conn (&pkt->conn); return rs_err_conn_push_fl (pkt->conn, RSE_INTERNAL, __FILE__, __LINE__, "got %d octets reading header", n); } @@ -264,7 +289,7 @@ _read_packet (struct rs_packet *pkt) - attribute sizes adding up correctly */ if (!rad_packet_ok (pkt->rpkt, 0) != 0) { - bufferevent_free (pkt->conn->bev); /* Close connection. */ + _close_conn (&pkt->conn); return rs_err_conn_push_fl (pkt->conn, RSE_FR, __FILE__, __LINE__, "invalid packet: %s", fr_strerror ()); } @@ -280,7 +305,7 @@ _read_packet (struct rs_packet *pkt) if (rad_verify (pkt->rpkt, pkt->original->rpkt, pkt->conn->active_peer->secret)) { - bufferevent_free (pkt->conn->bev); /* Close connection. */ + _close_conn (&pkt->conn); return rs_err_conn_push_fl (pkt->conn, RSE_FR, __FILE__, __LINE__, "rad_verify: %s", fr_strerror ()); } @@ -289,7 +314,7 @@ _read_packet (struct rs_packet *pkt) if (rad_decode (pkt->rpkt, pkt->original->rpkt, pkt->conn->active_peer->secret)) { - bufferevent_free (pkt->conn->bev); /* Close connection. */ + _close_conn (&pkt->conn); return rs_err_conn_push_fl (pkt->conn, RSE_FR, __FILE__, __LINE__, "rad_decode: %s", fr_strerror ()); } @@ -376,7 +401,7 @@ _evlog_cb (int severity, const char *msg) } static int -_init_evb (struct rs_connection *conn) +_init_eventbase (struct rs_connection *conn) { if (conn->evb) return RSE_OK; @@ -465,27 +490,21 @@ _set_timeout (struct rs_connection *conn) } static int -_init_bev (struct rs_connection *conn, struct rs_peer *peer) +_init_bufferevent (struct rs_connection *conn, struct rs_peer *peer) { if (conn->bev) return RSE_OK; - switch (conn->realm->type) + if (conn->realm->type == RS_CONN_TYPE_TCP) { - case RS_CONN_TYPE_UDP: - /* Fall through. */ - /* NOTE: We know this is wrong for several reasons, most notably - because libevent doesn't work as expected with UDP. The - timeout handling is wrong too. */ - case RS_CONN_TYPE_TCP: conn->bev = bufferevent_socket_new (conn->evb, conn->fd, 0); if (!conn->bev) return rs_err_conn_push_fl (conn, RSE_EVENT, __FILE__, __LINE__, "bufferevent_socket_new"); - break; - + } #if defined (RS_ENABLE_TLS) - case RS_CONN_TYPE_TLS: + else if (conn->realm->type == RS_CONN_TYPE_TLS) + { if (rs_tls_init (conn)) return -1; /* Would be convenient to pass BEV_OPT_CLOSE_ON_FREE but things @@ -497,13 +516,10 @@ _init_bev (struct rs_connection *conn, struct rs_peer *peer) if (!conn->bev) return rs_err_conn_push_fl (conn, RSE_EVENT, __FILE__, __LINE__, "bufferevent_openssl_socket_new"); - break; - - case RS_CONN_TYPE_DTLS: - return rs_err_conn_push_fl (conn, RSE_NOSYS, __FILE__, __LINE__, NULL); + } #endif /* RS_ENABLE_TLS */ - - default: + else + { return rs_err_conn_push_fl (conn, RSE_INTERNAL, __FILE__, __LINE__, "%s: unknown connection type: %d", __func__, conn->realm->type); @@ -512,11 +528,81 @@ _init_bev (struct rs_connection *conn, struct rs_peer *peer) return RSE_OK; } +/* Callback for conn->wev and conn->rev. FIXME: Rename. */ +static void +_evcb (evutil_socket_t fd, short what, void *user_data) +{ + //rs_debug (("%s: fd=%d what=0x%x\n", __func__, fd, what)); + if (what & EV_TIMEOUT) + { + struct rs_connection *conn = (struct rs_connection *) user_data; + assert (conn); + conn->is_connecting = 0; + rs_debug (("%s: UDP timeout NYI", __func__)); + } + else if (what & EV_READ) + { + struct rs_connection *conn = (struct rs_connection *) user_data; + assert (conn); + /* read a single UDP packet and stick it in a new struct + rs_packet */ + + rs_debug (("%s: UDP read NYI", __func__)); + } + else if (what & EV_WRITE) + { + struct rs_packet *pkt = (struct rs_packet *) user_data; + assert (pkt); + /* Socket ready for writing, possibly as a result of a + successful connect. */ + if (!pkt->conn->is_connected) + _on_connect (pkt->conn, pkt); + if (pkt->conn->out_queue) + { + /* Send one packet, the first. */ + ssize_t r = 0; + struct rs_packet *p = pkt->conn->out_queue; + + assert (p->rpkt); + assert (p->rpkt->data); + r = compat_send (fd, p->rpkt->data, p->rpkt->data_len, 0); + if (r == -1) + { + int sockerr = evutil_socket_geterror (p->conn->fd); + if (sockerr != EAGAIN) + rs_err_conn_push_fl (p->conn, RSE_SOCKERR, __FILE__, __LINE__, + "%d: send: %d (%s)", fd, sockerr, + evutil_socket_error_to_string (sockerr)); + return; /* Don't unlink packet. */ + } + pkt->conn->out_queue = p->next; + } + } +} + +static int +_init_udp (struct rs_connection *conn, struct rs_packet *pkt) +{ + assert (!conn->bev); + + conn->rev = event_new (conn->evb, conn->fd, EV_READ|EV_PERSIST, _evcb, conn); + conn->wev = event_new (conn->evb, conn->fd, EV_WRITE|EV_PERSIST, _evcb, pkt); + if (!conn->rev || !conn->wev) + { + if (conn->rev) + event_free (conn->rev); + /* ENOMEM _or_ EINVAL but EINVAL only if we use EV_SIGNAL, at + least for now (libevent-2.0.5). */ + return rs_err_conn_push_fl (conn, RSE_NOMEM, __FILE__, __LINE__, NULL); + } + return RSE_OK; +} + static void _do_connect (struct rs_connection *conn) { struct rs_peer *p; - int err; + int err, sockerr; assert (conn); assert (conn->active_peer); @@ -534,21 +620,37 @@ _do_connect (struct rs_connection *conn) } #endif - _set_timeout (conn); - err = bufferevent_socket_connect (p->conn->bev, p->addr->ai_addr, - p->addr->ai_addrlen); - if (err < 0) - rs_err_conn_push_fl (p->conn, RSE_EVENT, __FILE__, __LINE__, - "bufferevent_socket_connect: %s", - evutil_gai_strerror (err)); - else - p->conn->is_connecting = 1; + if (p->conn->bev) /* TCP */ + { + _set_timeout (conn); + err = bufferevent_socket_connect (p->conn->bev, p->addr->ai_addr, + p->addr->ai_addrlen); + if (err < 0) + rs_err_conn_push_fl (p->conn, RSE_EVENT, __FILE__, __LINE__, + "bufferevent_socket_connect: %s", + evutil_gai_strerror (err)); + else + p->conn->is_connecting = 1; + } + else /* UDP */ + { + err = connect (p->conn->fd, p->addr->ai_addr, p->addr->ai_addrlen); + if (err < 0) + { + sockerr = evutil_socket_geterror (p->conn->fd); + rs_debug (("%s: %d: connect: %d (%s)\n", __func__, p->conn->fd, + sockerr, evutil_socket_error_to_string (sockerr))); + rs_err_conn_push_fl (p->conn, RSE_SOCKERR, __FILE__, __LINE__, + "%d: connect: %d (%s)", p->conn->fd, sockerr, + evutil_socket_error_to_string (sockerr)); + } + } } static int -_conn_open(struct rs_connection *conn, struct rs_packet *pkt) +_conn_open (struct rs_connection *conn, struct rs_packet *pkt) { - if (_init_evb (conn)) + if (_init_eventbase (conn)) return -1; if (!conn->active_peer) @@ -559,8 +661,17 @@ _conn_open(struct rs_connection *conn, struct rs_packet *pkt) if (_init_socket (conn, conn->active_peer)) return -1; - if (_init_bev (conn, conn->active_peer)) - return -1; + if (conn->realm->type == RS_CONN_TYPE_TCP + || conn->realm->type == RS_CONN_TYPE_TLS) + { + if (_init_bufferevent (conn, conn->active_peer)) + return -1; + } + else + { + if (_init_udp (conn, pkt)) + return -1; + } if (!conn->is_connected) if (!conn->is_connecting) @@ -640,7 +751,10 @@ _wcb (void *user_data) struct rs_packet *pkt = (struct rs_packet *) user_data; assert (pkt); pkt->written_flag = 1; - bufferevent_disable (pkt->conn->bev, EV_WRITE|EV_READ); + if (pkt->conn->bev) + bufferevent_disable (pkt->conn->bev, EV_WRITE|EV_READ); + else + event_del (pkt->conn->wev); } int @@ -660,13 +774,24 @@ rs_packet_send (struct rs_packet *pkt, void *user_data) return -1; assert (conn->evb); - assert (conn->bev); assert (conn->active_peer); assert (conn->fd >= 0); conn->user_data = user_data; - bufferevent_setcb (conn->bev, NULL, _write_cb, _event_cb, pkt); - bufferevent_enable (conn->bev, EV_WRITE); + + if (conn->bev) /* TCP */ + { + bufferevent_setcb (conn->bev, NULL, _write_cb, _event_cb, pkt); + bufferevent_enable (conn->bev, EV_WRITE); + } + else /* UDP */ + { + err = event_add (conn->wev, NULL); + if (err < 0) + return rs_err_conn_push_fl (pkt->conn, RSE_EVENT, __FILE__, __LINE__, + "event_add: %s", + evutil_gai_strerror (err)); + } /* Do dispatch, unless the user wants to do it herself. */ if (!conn->user_dispatch_flag) @@ -696,7 +821,10 @@ _rcb (struct rs_packet *packet, void *user_data) struct rs_packet *pkt = (struct rs_packet *) user_data; assert (pkt); pkt->valid_flag = 1; - bufferevent_disable (pkt->conn->bev, EV_WRITE|EV_READ); + if (pkt->conn->bev) + bufferevent_disable (pkt->conn->bev, EV_WRITE|EV_READ); + else + event_del (pkt->conn->rev); } /* Special function used in libradsec blocking dispatching mode, @@ -737,11 +865,22 @@ rs_conn_receive_packet (struct rs_connection *conn, assert (conn->active_peer); assert (conn->fd >= 0); - bufferevent_setwatermark (conn->bev, EV_READ, RS_HEADER_LEN, 0); - bufferevent_setcb (conn->bev, _read_cb, NULL, _event_cb, pkt); - bufferevent_enable (conn->bev, EV_READ); conn->callbacks.received_cb = _rcb; conn->user_data = pkt; + if (conn->bev) + { + bufferevent_setwatermark (conn->bev, EV_READ, RS_HEADER_LEN, 0); + bufferevent_setcb (conn->bev, _read_cb, NULL, _event_cb, pkt); + bufferevent_enable (conn->bev, EV_READ); + } + else + { + err = event_add (conn->rev, NULL); + if (err < 0) + return rs_err_conn_push_fl (pkt->conn, RSE_EVENT, __FILE__, __LINE__, + "event_add: %s", + evutil_gai_strerror (err)); + } /* Dispatch. */ rs_debug (("%s: entering event loop\n", __func__)); -- cgit v1.1 From 5c60297a1eaab7b10d6f584ba329493a41b812d0 Mon Sep 17 00:00:00 2001 From: Linus Nordberg Date: Sun, 6 Mar 2011 15:53:58 +0100 Subject: Restructure code, moving most code out of packet.c Also, move copyright notice out of COPYING and into every file. --- lib/packet.c | 782 +---------------------------------------------------------- 1 file changed, 7 insertions(+), 775 deletions(-) (limited to 'lib/packet.c') diff --git a/lib/packet.c b/lib/packet.c index afe2725..6ba9fd3 100644 --- a/lib/packet.c +++ b/lib/packet.c @@ -1,60 +1,27 @@ -/* See the file COPYING for licensing information. */ +/* Copyright 2010, 2011 NORDUnet A/S. All rights reserved. + See the file COPYING for licensing information. */ #if defined HAVE_CONFIG_H #include #endif -#include -#include -#include -#include -#include #include -#include -#include #include #include #include -#include "compat.h" #include "debug.h" -#if defined (RS_ENABLE_TLS) -#include -#include -#include "tls.h" -#endif +#include "packet.h" + #if defined (DEBUG) #include #include #include #endif -static int -_close_conn (struct rs_connection **connp) -{ - int r; - assert (connp); - assert (*connp); - r = rs_conn_destroy (*connp); - if (!r) - *connp = NULL; - return r; -} - -static int -_loopbreak (struct rs_connection *conn) -{ - int err = event_base_loopbreak (conn->evb); - if (err < 0) - rs_err_conn_push_fl (conn, RSE_EVENT, __FILE__, __LINE__, - "event_base_loopbreak: %s", - evutil_gai_strerror (err)); - return err; -} - /* Badly named helper function for preparing a RADIUS message and queue it. FIXME: Rename. */ -static int -_do_send (struct rs_packet *pkt) +int +packet_do_send (struct rs_packet *pkt) { VALUE_PAIR *vp = NULL; @@ -109,583 +76,6 @@ _do_send (struct rs_packet *pkt) return RSE_OK; } -static void -_on_connect (struct rs_connection *conn, struct rs_packet *pkt) -{ - assert (!conn->is_connecting); - conn->is_connected = 1; - rs_debug (("%s: %p connected\n", __func__, conn->active_peer)); - if (conn->tev) - evtimer_del (conn->tev); - if (conn->callbacks.connected_cb) - conn->callbacks.connected_cb (conn->user_data); - if (pkt) - _do_send (pkt); -} - -static void -_on_disconnect (struct rs_connection *conn) -{ - conn->is_connecting = 0; - conn->is_connected = 0; - rs_debug (("%s: %p disconnected\n", __func__, conn->active_peer)); - if (conn->callbacks.disconnected_cb) - conn->callbacks.disconnected_cb (conn->user_data); -} - -static void -_event_cb (struct bufferevent *bev, short events, void *user_data) -{ - struct rs_packet *pkt = (struct rs_packet *) user_data; - struct rs_connection *conn = NULL; - struct rs_peer *p = NULL; - int sockerr = 0; -#if defined (RS_ENABLE_TLS) - unsigned long tlserr = 0; -#endif - - assert (pkt); - assert (pkt->conn); - assert (pkt->conn->active_peer); - conn = pkt->conn; - p = conn->active_peer; - - conn->is_connecting = 0; - if (events & BEV_EVENT_CONNECTED) - { - _on_connect (conn, pkt); - } - else if (events & BEV_EVENT_EOF) - { - _on_disconnect (conn); - } - else if (events & BEV_EVENT_TIMEOUT) - { - rs_debug (("%s: %p times out on %s\n", __func__, p, - (events & BEV_EVENT_READING) ? "read" : "write")); - rs_err_conn_push_fl (pkt->conn, RSE_TIMEOUT_IO, __FILE__, __LINE__, NULL); - } - else if (events & BEV_EVENT_ERROR) - { - sockerr = evutil_socket_geterror (conn->active_peer->fd); - if (sockerr == 0) /* FIXME: True that errno == 0 means closed? */ - { - _on_disconnect (conn); - } - else - { - rs_debug (("%s: %d: %d (%s)\n", __func__, conn->fd, sockerr, - evutil_socket_error_to_string (sockerr))); - rs_err_conn_push_fl (pkt->conn, RSE_SOCKERR, __FILE__, __LINE__, - "%d: %d (%s)", conn->fd, sockerr, - evutil_socket_error_to_string (sockerr)); - } -#if defined (RS_ENABLE_TLS) - if (conn->tls_ssl) /* FIXME: correct check? */ - { - for (tlserr = bufferevent_get_openssl_error (conn->bev); - tlserr; - tlserr = bufferevent_get_openssl_error (conn->bev)) - { - rs_debug (("%s: openssl error: %s\n", __func__, - ERR_error_string (tlserr, NULL))); - rs_err_conn_push_fl (pkt->conn, RSE_SSLERR, __FILE__, __LINE__, - ERR_error_string (tlserr, NULL)); - } - } -#endif /* RS_ENABLE_TLS */ - _loopbreak (conn); - } - -#if defined (DEBUG) - if (events & BEV_EVENT_ERROR && events != BEV_EVENT_ERROR) - rs_debug (("%s: BEV_EVENT_ERROR and more: 0x%x\n", __func__, events)); -#endif -} - -static void -_write_cb (struct bufferevent *bev, void *ctx) -{ - struct rs_packet *pkt = (struct rs_packet *) ctx; - - assert (pkt); - assert (pkt->conn); - - if (pkt->conn->callbacks.sent_cb) - pkt->conn->callbacks.sent_cb (pkt->conn->user_data); -} - -/* Read one RADIUS packet header. Return !0 on error. A return value - of 0 means that we need more data. */ -static int -_read_header (struct rs_packet *pkt) -{ - size_t n = 0; - - n = bufferevent_read (pkt->conn->bev, pkt->hdr, RS_HEADER_LEN); - if (n == RS_HEADER_LEN) - { - pkt->hdr_read_flag = 1; - pkt->rpkt->data_len = (pkt->hdr[2] << 8) + pkt->hdr[3]; - if (pkt->rpkt->data_len < 20 || pkt->rpkt->data_len > 4096) - { - _close_conn (&pkt->conn); - return rs_err_conn_push (pkt->conn, RSE_INVALID_PKT, - "invalid packet length: %d", - pkt->rpkt->data_len); - } - pkt->rpkt->data = rs_malloc (pkt->conn->ctx, pkt->rpkt->data_len); - if (!pkt->rpkt->data) - { - _close_conn (&pkt->conn); - return rs_err_conn_push_fl (pkt->conn, RSE_NOMEM, __FILE__, __LINE__, - NULL); - } - memcpy (pkt->rpkt->data, pkt->hdr, RS_HEADER_LEN); - bufferevent_setwatermark (pkt->conn->bev, EV_READ, - pkt->rpkt->data_len - RS_HEADER_LEN, 0); - rs_debug (("%s: packet header read, total pkt len=%d\n", - __func__, pkt->rpkt->data_len)); - } - else if (n < 0) - { - rs_debug (("%s: buffer frozen while reading header\n", __func__)); - } - else /* Error: libevent gave us less than the low watermark. */ - { - _close_conn (&pkt->conn); - return rs_err_conn_push_fl (pkt->conn, RSE_INTERNAL, __FILE__, __LINE__, - "got %d octets reading header", n); - } - - return 0; -} - -static int -_read_packet (struct rs_packet *pkt) -{ - size_t n = 0; - - rs_debug (("%s: trying to read %d octets of packet data\n", __func__, - pkt->rpkt->data_len - RS_HEADER_LEN)); - - n = bufferevent_read (pkt->conn->bev, - pkt->rpkt->data + RS_HEADER_LEN, - pkt->rpkt->data_len - RS_HEADER_LEN); - - rs_debug (("%s: read %ld octets of packet data\n", __func__, n)); - - if (n == pkt->rpkt->data_len - RS_HEADER_LEN) - { - bufferevent_disable (pkt->conn->bev, EV_READ); - rs_debug (("%s: complete packet read\n", __func__)); - pkt->hdr_read_flag = 0; - memset (pkt->hdr, 0, sizeof(*pkt->hdr)); - - /* Checks done by rad_packet_ok: - - lenghts (FIXME: checks really ok for tcp?) - - invalid code field - - attribute lengths >= 2 - - attribute sizes adding up correctly */ - if (!rad_packet_ok (pkt->rpkt, 0) != 0) - { - _close_conn (&pkt->conn); - return rs_err_conn_push_fl (pkt->conn, RSE_FR, __FILE__, __LINE__, - "invalid packet: %s", fr_strerror ()); - } - - /* TODO: Verify that reception of an unsolicited response packet - results in connection being closed. */ - - /* If we have a request to match this response against, verify - and decode the response. */ - if (pkt->original) - { - /* Verify header and message authenticator. */ - if (rad_verify (pkt->rpkt, pkt->original->rpkt, - pkt->conn->active_peer->secret)) - { - _close_conn (&pkt->conn); - return rs_err_conn_push_fl (pkt->conn, RSE_FR, __FILE__, __LINE__, - "rad_verify: %s", fr_strerror ()); - } - - /* Decode and decrypt. */ - if (rad_decode (pkt->rpkt, pkt->original->rpkt, - pkt->conn->active_peer->secret)) - { - _close_conn (&pkt->conn); - return rs_err_conn_push_fl (pkt->conn, RSE_FR, __FILE__, __LINE__, - "rad_decode: %s", fr_strerror ()); - } - } - -#if defined (DEBUG) - /* Find out what happens if there's data left in the buffer. */ - { - size_t rest = 0; - rest = evbuffer_get_length (bufferevent_get_input (pkt->conn->bev)); - if (rest) - rs_debug (("%s: returning with %d octets left in buffer\n", __func__, - rest)); - } -#endif - - /* Hand over message to user, changes ownership of pkt. Don't - touch it afterwards -- it might have been freed. */ - if (pkt->conn->callbacks.received_cb) - pkt->conn->callbacks.received_cb (pkt, pkt->conn->user_data); - } - else if (n < 0) /* Buffer frozen. */ - rs_debug (("%s: buffer frozen when reading packet\n", __func__)); - else /* Short packet. */ - rs_debug (("%s: waiting for another %d octets\n", __func__, - pkt->rpkt->data_len - RS_HEADER_LEN - n)); - - return 0; -} - -/* Read callback for TCP. - - Read exactly one RADIUS message from BEV and store it in struct - rs_packet passed in CTX (hereby called 'pkt'). - - Verify the received packet against pkt->original, if !NULL. - - Inform upper layer about successful reception of valid RADIUS - message by invoking conn->callbacks.recevied_cb(), if !NULL. */ -static void -_read_cb (struct bufferevent *bev, void *user_data) -{ - struct rs_packet *pkt = (struct rs_packet *) user_data; - - assert (pkt); - assert (pkt->conn); - assert (pkt->rpkt); - - pkt->rpkt->sockfd = pkt->conn->fd; - pkt->rpkt->vps = NULL; - - if (!pkt->hdr_read_flag) - if (_read_header (pkt)) - return; - _read_packet (pkt); -} - -static void -_evlog_cb (int severity, const char *msg) -{ - const char *sevstr; - switch (severity) - { - case _EVENT_LOG_DEBUG: -#if !defined (DEBUG_LEVENT) - return; -#endif - sevstr = "debug"; - break; - case _EVENT_LOG_MSG: - sevstr = "msg"; - break; - case _EVENT_LOG_WARN: - sevstr = "warn"; - break; - case _EVENT_LOG_ERR: - sevstr = "err"; - break; - default: - sevstr = "???"; - break; - } - fprintf (stderr, "libevent: [%s] %s\n", sevstr, msg); /* FIXME: stderr? */ -} - -static int -_init_eventbase (struct rs_connection *conn) -{ - if (conn->evb) - return RSE_OK; - -#if defined (DEBUG) - event_enable_debug_mode (); -#endif - event_set_log_callback (_evlog_cb); - conn->evb = event_base_new (); - if (!conn->evb) - return rs_err_conn_push_fl (conn, RSE_EVENT, __FILE__, __LINE__, - "event_base_new"); - - return RSE_OK; -} - -static int -_init_socket (struct rs_connection *conn, struct rs_peer *p) -{ - if (conn->fd != -1) - return RSE_OK; - - assert (p->addr); - conn->fd = socket (p->addr->ai_family, p->addr->ai_socktype, - p->addr->ai_protocol); - if (conn->fd < 0) - return rs_err_conn_push_fl (conn, RSE_SOCKERR, __FILE__, __LINE__, - "socket: %d (%s)", - errno, strerror (errno)); - if (evutil_make_socket_nonblocking (conn->fd) < 0) - { - evutil_closesocket (conn->fd); - conn->fd = -1; - return rs_err_conn_push_fl (conn, RSE_SOCKERR, __FILE__, __LINE__, - "evutil_make_socket_nonblocking: %d (%s)", - errno, strerror (errno)); - } - return RSE_OK; -} - -static struct rs_peer * -_pick_peer (struct rs_connection *conn) -{ - assert (conn); - - if (conn->active_peer) - conn->active_peer = conn->active_peer->next; /* Next. */ - if (!conn->active_peer) - conn->active_peer = conn->peers; /* From the top. */ - - return conn->active_peer; -} - -static void -_conn_timeout_cb (int fd, short event, void *data) -{ - struct rs_connection *conn; - - assert (data); - conn = (struct rs_connection *) data; - - if (event & EV_TIMEOUT) - { - rs_debug (("%s: connection timeout on %p (fd %d) connecting to %p\n", - __func__, conn, conn->fd, conn->active_peer)); - conn->is_connecting = 0; - rs_err_conn_push_fl (conn, RSE_TIMEOUT_IO, __FILE__, __LINE__, NULL); - _loopbreak (conn); - } -} -static int -_set_timeout (struct rs_connection *conn) -{ - struct timeval tv; - - if (!conn->tev) - conn->tev = evtimer_new (conn->evb, _conn_timeout_cb, conn); - if (!conn->tev) - return rs_err_conn_push_fl (conn, RSE_EVENT, __FILE__, __LINE__, - "evtimer_new"); - tv.tv_sec = conn->realm->timeout; - tv.tv_usec = 0; - evtimer_add (conn->tev, &tv); - - return RSE_OK; -} - -static int -_init_bufferevent (struct rs_connection *conn, struct rs_peer *peer) -{ - if (conn->bev) - return RSE_OK; - - if (conn->realm->type == RS_CONN_TYPE_TCP) - { - conn->bev = bufferevent_socket_new (conn->evb, conn->fd, 0); - if (!conn->bev) - return rs_err_conn_push_fl (conn, RSE_EVENT, __FILE__, __LINE__, - "bufferevent_socket_new"); - } -#if defined (RS_ENABLE_TLS) - else if (conn->realm->type == RS_CONN_TYPE_TLS) - { - if (rs_tls_init (conn)) - return -1; - /* Would be convenient to pass BEV_OPT_CLOSE_ON_FREE but things - seem to break when be_openssl_ctrl() (in libevent) calls - SSL_set_bio() after BIO_new_socket() with flag=1. */ - conn->bev = - bufferevent_openssl_socket_new (conn->evb, conn->fd, conn->tls_ssl, - BUFFEREVENT_SSL_CONNECTING, 0); - if (!conn->bev) - return rs_err_conn_push_fl (conn, RSE_EVENT, __FILE__, __LINE__, - "bufferevent_openssl_socket_new"); - } -#endif /* RS_ENABLE_TLS */ - else - { - return rs_err_conn_push_fl (conn, RSE_INTERNAL, __FILE__, __LINE__, - "%s: unknown connection type: %d", __func__, - conn->realm->type); - } - - return RSE_OK; -} - -/* Callback for conn->wev and conn->rev. FIXME: Rename. */ -static void -_evcb (evutil_socket_t fd, short what, void *user_data) -{ - //rs_debug (("%s: fd=%d what=0x%x\n", __func__, fd, what)); - if (what & EV_TIMEOUT) - { - struct rs_connection *conn = (struct rs_connection *) user_data; - assert (conn); - conn->is_connecting = 0; - rs_debug (("%s: UDP timeout NYI", __func__)); - } - else if (what & EV_READ) - { - struct rs_connection *conn = (struct rs_connection *) user_data; - assert (conn); - /* read a single UDP packet and stick it in a new struct - rs_packet */ - - rs_debug (("%s: UDP read NYI", __func__)); - } - else if (what & EV_WRITE) - { - struct rs_packet *pkt = (struct rs_packet *) user_data; - assert (pkt); - /* Socket ready for writing, possibly as a result of a - successful connect. */ - if (!pkt->conn->is_connected) - _on_connect (pkt->conn, pkt); - if (pkt->conn->out_queue) - { - /* Send one packet, the first. */ - ssize_t r = 0; - struct rs_packet *p = pkt->conn->out_queue; - - assert (p->rpkt); - assert (p->rpkt->data); - r = compat_send (fd, p->rpkt->data, p->rpkt->data_len, 0); - if (r == -1) - { - int sockerr = evutil_socket_geterror (p->conn->fd); - if (sockerr != EAGAIN) - rs_err_conn_push_fl (p->conn, RSE_SOCKERR, __FILE__, __LINE__, - "%d: send: %d (%s)", fd, sockerr, - evutil_socket_error_to_string (sockerr)); - return; /* Don't unlink packet. */ - } - pkt->conn->out_queue = p->next; - } - } -} - -static int -_init_udp (struct rs_connection *conn, struct rs_packet *pkt) -{ - assert (!conn->bev); - - conn->rev = event_new (conn->evb, conn->fd, EV_READ|EV_PERSIST, _evcb, conn); - conn->wev = event_new (conn->evb, conn->fd, EV_WRITE|EV_PERSIST, _evcb, pkt); - if (!conn->rev || !conn->wev) - { - if (conn->rev) - event_free (conn->rev); - /* ENOMEM _or_ EINVAL but EINVAL only if we use EV_SIGNAL, at - least for now (libevent-2.0.5). */ - return rs_err_conn_push_fl (conn, RSE_NOMEM, __FILE__, __LINE__, NULL); - } - return RSE_OK; -} - -static void -_do_connect (struct rs_connection *conn) -{ - struct rs_peer *p; - int err, sockerr; - - assert (conn); - assert (conn->active_peer); - p = conn->active_peer; - -#if defined (DEBUG) - { - char host[80], serv[80]; - - getnameinfo (p->addr->ai_addr, - p->addr->ai_addrlen, - host, sizeof(host), serv, sizeof(serv), - 0 /* NI_NUMERICHOST|NI_NUMERICSERV*/); - rs_debug (("%s: connecting to %s:%s\n", __func__, host, serv)); - } -#endif - - if (p->conn->bev) /* TCP */ - { - _set_timeout (conn); - err = bufferevent_socket_connect (p->conn->bev, p->addr->ai_addr, - p->addr->ai_addrlen); - if (err < 0) - rs_err_conn_push_fl (p->conn, RSE_EVENT, __FILE__, __LINE__, - "bufferevent_socket_connect: %s", - evutil_gai_strerror (err)); - else - p->conn->is_connecting = 1; - } - else /* UDP */ - { - err = connect (p->conn->fd, p->addr->ai_addr, p->addr->ai_addrlen); - if (err < 0) - { - sockerr = evutil_socket_geterror (p->conn->fd); - rs_debug (("%s: %d: connect: %d (%s)\n", __func__, p->conn->fd, - sockerr, evutil_socket_error_to_string (sockerr))); - rs_err_conn_push_fl (p->conn, RSE_SOCKERR, __FILE__, __LINE__, - "%d: connect: %d (%s)", p->conn->fd, sockerr, - evutil_socket_error_to_string (sockerr)); - } - } -} - -static int -_conn_open (struct rs_connection *conn, struct rs_packet *pkt) -{ - if (_init_eventbase (conn)) - return -1; - - if (!conn->active_peer) - _pick_peer (conn); - if (!conn->active_peer) - return rs_err_conn_push_fl (conn, RSE_NOPEER, __FILE__, __LINE__, NULL); - - if (_init_socket (conn, conn->active_peer)) - return -1; - - if (conn->realm->type == RS_CONN_TYPE_TCP - || conn->realm->type == RS_CONN_TYPE_TLS) - { - if (_init_bufferevent (conn, conn->active_peer)) - return -1; - } - else - { - if (_init_udp (conn, pkt)) - return -1; - } - - if (!conn->is_connected) - if (!conn->is_connecting) - _do_connect (conn); - - return RSE_OK; -} - -static int -_conn_is_open_p (struct rs_connection *conn) -{ - return conn->active_peer && conn->is_connected; -} - /* Public functions. */ int rs_packet_create (struct rs_connection *conn, struct rs_packet **pkt_out) @@ -744,165 +134,6 @@ rs_packet_create_authn_request (struct rs_connection *conn, return RSE_OK; } -/* User callback used when we're dispatching for user. */ -static void -_wcb (void *user_data) -{ - struct rs_packet *pkt = (struct rs_packet *) user_data; - assert (pkt); - pkt->written_flag = 1; - if (pkt->conn->bev) - bufferevent_disable (pkt->conn->bev, EV_WRITE|EV_READ); - else - event_del (pkt->conn->wev); -} - -int -rs_packet_send (struct rs_packet *pkt, void *user_data) -{ - struct rs_connection *conn = NULL; - int err = 0; - - assert (pkt); - assert (pkt->conn); - conn = pkt->conn; - - if (_conn_is_open_p (conn)) - _do_send (pkt); - else - if (_conn_open (conn, pkt)) - return -1; - - assert (conn->evb); - assert (conn->active_peer); - assert (conn->fd >= 0); - - conn->user_data = user_data; - - if (conn->bev) /* TCP */ - { - bufferevent_setcb (conn->bev, NULL, _write_cb, _event_cb, pkt); - bufferevent_enable (conn->bev, EV_WRITE); - } - else /* UDP */ - { - err = event_add (conn->wev, NULL); - if (err < 0) - return rs_err_conn_push_fl (pkt->conn, RSE_EVENT, __FILE__, __LINE__, - "event_add: %s", - evutil_gai_strerror (err)); - } - - /* Do dispatch, unless the user wants to do it herself. */ - if (!conn->user_dispatch_flag) - { - conn->callbacks.sent_cb = _wcb; - conn->user_data = pkt; - rs_debug (("%s: entering event loop\n", __func__)); - err = event_base_dispatch (conn->evb); - if (err < 0) - return rs_err_conn_push_fl (pkt->conn, RSE_EVENT, __FILE__, __LINE__, - "event_base_dispatch: %s", - evutil_gai_strerror (err)); - rs_debug (("%s: event loop done\n", __func__)); - conn->callbacks.sent_cb = NULL; - conn->user_data = NULL; - - if (!pkt->written_flag) - return -1; - } - - return RSE_OK; -} - -static void -_rcb (struct rs_packet *packet, void *user_data) -{ - struct rs_packet *pkt = (struct rs_packet *) user_data; - assert (pkt); - pkt->valid_flag = 1; - if (pkt->conn->bev) - bufferevent_disable (pkt->conn->bev, EV_WRITE|EV_READ); - else - event_del (pkt->conn->rev); -} - -/* Special function used in libradsec blocking dispatching mode, - i.e. with socket set to block on read/write and with no libradsec - callbacks registered. - - For any other use of libradsec, a the received_cb callback should - be registered in the callbacks member of struct rs_connection. - - On successful reception, verification and decoding of a RADIUS - message, PKT_OUT will upon return point at a pointer to a struct - rs_packet containing the message. - - If anything goes wrong or if the read times out (TODO: explain), - PKT_OUT will point at the NULL pointer and one or more errors are - pushed on the connection (available through rs_err_conn_pop()). */ - -int -rs_conn_receive_packet (struct rs_connection *conn, - struct rs_packet *request, - struct rs_packet **pkt_out) -{ - int err = 0; - struct rs_packet *pkt = NULL; - - assert (conn); - assert (conn->realm); - assert (!conn->user_dispatch_flag); /* Dispatching mode only. */ - - if (rs_packet_create (conn, pkt_out)) - return -1; - pkt = *pkt_out; - pkt->conn = conn; - pkt->original = request; - - assert (conn->evb); - assert (conn->bev); - assert (conn->active_peer); - assert (conn->fd >= 0); - - conn->callbacks.received_cb = _rcb; - conn->user_data = pkt; - if (conn->bev) - { - bufferevent_setwatermark (conn->bev, EV_READ, RS_HEADER_LEN, 0); - bufferevent_setcb (conn->bev, _read_cb, NULL, _event_cb, pkt); - bufferevent_enable (conn->bev, EV_READ); - } - else - { - err = event_add (conn->rev, NULL); - if (err < 0) - return rs_err_conn_push_fl (pkt->conn, RSE_EVENT, __FILE__, __LINE__, - "event_add: %s", - evutil_gai_strerror (err)); - } - - /* Dispatch. */ - rs_debug (("%s: entering event loop\n", __func__)); - err = event_base_dispatch (conn->evb); - conn->callbacks.received_cb = NULL; - if (err < 0) - return rs_err_conn_push_fl (pkt->conn, RSE_EVENT, __FILE__, __LINE__, - "event_base_dispatch: %s", - evutil_gai_strerror (err)); - rs_debug (("%s: event loop done\n", __func__)); - - if (!pkt->valid_flag) - return -1; - -#if defined (DEBUG) - rs_dump_packet (pkt); -#endif - - pkt->original = NULL; /* FIXME: Why? */ - return RSE_OK; -} - void rs_packet_add_attr (struct rs_packet *pkt, struct rs_attr *attr) { @@ -927,3 +158,4 @@ rs_packet_destroy (struct rs_packet *pkt) rs_free (pkt->conn->ctx, pkt); } } + -- cgit v1.1 From cbcaa6a7c8f8a6704f6b4a68f260020957214a07 Mon Sep 17 00:00:00 2001 From: Linus Nordberg Date: Mon, 7 Mar 2011 15:23:40 +0100 Subject: Move verification of response packets up to a level where it makes sense. Replace the user_dispatch_flag on connections with conn_user_dispatch_p(). Remove the 'original' member from packet and instead have an upper layer verify. Rename packet valid_flag --> received_flag to reflect that we don't verify. Move _close_conn() --> conn_close(). Move packet flags into a single unsigned int, for portability. (_read_packet): Don't verify packet. (rs_conn_receive_packet): Don't touch PKT_OUT if there isn't a packet. (rs_conn_receive_packet): Verify packet using packet_verify_response(). --- lib/packet.c | 39 ++++++++++++++++++++++++++++++++++++--- 1 file changed, 36 insertions(+), 3 deletions(-) (limited to 'lib/packet.c') diff --git a/lib/packet.c b/lib/packet.c index 6ba9fd3..799234f 100644 --- a/lib/packet.c +++ b/lib/packet.c @@ -9,6 +9,7 @@ #include #include #include +#include "conn.h" #include "debug.h" #include "packet.h" @@ -18,15 +19,47 @@ #include #endif -/* Badly named helper function for preparing a RADIUS message and - queue it. FIXME: Rename. */ +int +packet_verify_response (struct rs_connection *conn, + struct rs_packet *response, + struct rs_packet *request) +{ + assert (conn); + assert (conn->active_peer); + assert (conn->active_peer->secret); + assert (response); + assert (response->rpkt); + assert (request); + assert (request->rpkt); + + /* Verify header and message authenticator. */ + if (rad_verify (response->rpkt, request->rpkt, conn->active_peer->secret)) + { + conn_close (&conn); + return rs_err_conn_push_fl (conn, RSE_FR, __FILE__, __LINE__, + "rad_verify: %s", fr_strerror ()); + } + + /* Decode and decrypt. */ + if (rad_decode (response->rpkt, request->rpkt, conn->active_peer->secret)) + { + conn_close (&conn); + return rs_err_conn_push_fl (conn, RSE_FR, __FILE__, __LINE__, + "rad_decode: %s", fr_strerror ()); + } + + return RSE_OK; +} + + +/* Badly named function for preparing a RADIUS message and queue it. + FIXME: Rename. */ int packet_do_send (struct rs_packet *pkt) { VALUE_PAIR *vp = NULL; assert (pkt->rpkt); - assert (!pkt->original); /* Add Message-Authenticator, RFC 2869. */ /* FIXME: Make Message-Authenticator optional? */ -- cgit v1.1 From ce4d6dfe1728e5633a8f49fc4b16c36df0d23521 Mon Sep 17 00:00:00 2001 From: Linus Nordberg Date: Wed, 9 Mar 2011 10:18:06 +0100 Subject: Add retransmission timer support (UDP). --- lib/packet.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) (limited to 'lib/packet.c') diff --git a/lib/packet.c b/lib/packet.c index 799234f..2611b46 100644 --- a/lib/packet.c +++ b/lib/packet.c @@ -88,7 +88,7 @@ packet_do_send (struct rs_packet *pkt) } #endif - if (pkt->conn->bev) + if (pkt->conn->bev) /* TCP. */ { int err = bufferevent_write (pkt->conn->bev, pkt->rpkt->data, pkt->rpkt->data_len); @@ -97,13 +97,15 @@ packet_do_send (struct rs_packet *pkt) "bufferevent_write: %s", evutil_gai_strerror (err)); } - else + else /* UDP. */ { struct rs_packet **pp = &pkt->conn->out_queue; while (*pp && (*pp)->next) *pp = (*pp)->next; *pp = pkt; + + conn_activate_timeout (pkt->conn); /* Retransmission timer. */ } return RSE_OK; -- cgit v1.1 From e92bfb068a357645de21a920362fe82ab6ec669f Mon Sep 17 00:00:00 2001 From: Linus Nordberg Date: Wed, 9 Mar 2011 19:49:54 +0100 Subject: Formatting changes. --- lib/packet.c | 1 + 1 file changed, 1 insertion(+) (limited to 'lib/packet.c') diff --git a/lib/packet.c b/lib/packet.c index 2611b46..e79268b 100644 --- a/lib/packet.c +++ b/lib/packet.c @@ -88,6 +88,7 @@ packet_do_send (struct rs_packet *pkt) } #endif + /* Put message in output buffer. */ if (pkt->conn->bev) /* TCP. */ { int err = bufferevent_write (pkt->conn->bev, pkt->rpkt->data, -- cgit v1.1 From 11cf984f611e835c394deede450af9fd69434e30 Mon Sep 17 00:00:00 2001 From: Linus Nordberg Date: Wed, 9 Mar 2011 19:51:59 +0100 Subject: Don't add Message-Authenticator more than once. Retransmiting the packet showed that we added another Message-Authenticator attribute every time we sent it. --- lib/packet.c | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) (limited to 'lib/packet.c') diff --git a/lib/packet.c b/lib/packet.c index e79268b..7b5ae2d 100644 --- a/lib/packet.c +++ b/lib/packet.c @@ -59,19 +59,25 @@ packet_do_send (struct rs_packet *pkt) { VALUE_PAIR *vp = NULL; + assert (pkt); + assert (pkt->conn); + assert (pkt->conn->active_peer); + assert (pkt->conn->active_peer->secret); assert (pkt->rpkt); - /* Add Message-Authenticator, RFC 2869. */ + /* Add a Message-Authenticator, RFC 2869, if not already present. */ /* FIXME: Make Message-Authenticator optional? */ vp = paircreate (PW_MESSAGE_AUTHENTICATOR, PW_TYPE_OCTETS); if (!vp) return rs_err_conn_push_fl (pkt->conn, RSE_FR, __FILE__, __LINE__, "paircreate: %s", fr_strerror ()); - pairadd (&pkt->rpkt->vps, vp); + pairreplace (&pkt->rpkt->vps, vp); + /* Encode message. */ if (rad_encode (pkt->rpkt, NULL, pkt->conn->active_peer->secret)) return rs_err_conn_push_fl (pkt->conn, RSE_FR, __FILE__, __LINE__, "rad_encode: %s", fr_strerror ()); + /* Sign message. */ if (rad_sign (pkt->rpkt, NULL, pkt->conn->active_peer->secret)) return rs_err_conn_push_fl (pkt->conn, RSE_FR, __FILE__, __LINE__, "rad_sign: %s", fr_strerror ()); -- cgit v1.1 From 0a7d803b9aa40512cf0f0c574d397ccba3ff1d13 Mon Sep 17 00:00:00 2001 From: Linus Nordberg Date: Wed, 9 Mar 2011 23:09:26 +0100 Subject: Get UDP working. For UDP, activate retransmit timer before receiving rather than sending makes the event loop break nicely after sending a message (which is important for blocking mode). Not quite sure that this is really accurate wrt to retransmission timing though but it should do for now. For UDP, set the user_data member for the read callback in rs_conn_receive_packet -- the one from udp_init() doesn't do much good now. For UDP, implement receiving message. Add compat_recv(). --- lib/packet.c | 2 -- 1 file changed, 2 deletions(-) (limited to 'lib/packet.c') diff --git a/lib/packet.c b/lib/packet.c index 7b5ae2d..48fb55e 100644 --- a/lib/packet.c +++ b/lib/packet.c @@ -111,8 +111,6 @@ packet_do_send (struct rs_packet *pkt) while (*pp && (*pp)->next) *pp = (*pp)->next; *pp = pkt; - - conn_activate_timeout (pkt->conn); /* Retransmission timer. */ } return RSE_OK; -- cgit v1.1