]> git.ipfire.org Git - thirdparty/FORT-validator.git/commitdiff
Support RTRv1, validate version on PDU exchanges
authorpcarana <pc.moreno2099@gmail.com>
Sat, 20 Jul 2019 00:45:34 +0000 (19:45 -0500)
committerpcarana <pc.moreno2099@gmail.com>
Sat, 20 Jul 2019 00:45:34 +0000 (19:45 -0500)
src/clients.c
src/clients.h
src/notify.c
src/rtr/err_pdu.c
src/rtr/err_pdu.h
src/rtr/pdu.c
src/rtr/pdu.h
src/rtr/pdu_handler.c
src/rtr/pdu_sender.c
src/rtr/pdu_sender.h
src/rtr/rtr.c

index 4bc3d0c3ee393cc02a40f1c8fd6ef5d68f9e9aef..d0975935b9100d18783f8d38d939aba3a84b4f92 100644 (file)
@@ -44,6 +44,7 @@ create_client(int fd, struct sockaddr_storage addr, pthread_t tid)
 
        client->meat.fd = fd;
        client->meat.serial_number_set = false;
+       client->meat.rtr_version_set = false;
        client->meat.addr = addr;
        client->meat.tid = tid;
 
@@ -88,7 +89,7 @@ clients_get_addr(int fd, struct sockaddr_storage *addr)
        int result;
 
        result = -ENOENT;
-       rwlock_write_lock(&lock);
+       rwlock_read_lock(&lock);
 
        HASH_FIND_INT(db.clients, &fd, client);
        if (client != NULL) {
@@ -144,6 +145,54 @@ unlock:
        return retval;
 }
 
+int
+clients_set_rtr_version(int fd, uint8_t rtr_version)
+{
+       struct hashable_client *client;
+       int result;
+
+       result = -ENOENT;
+       rwlock_write_lock(&lock);
+
+       HASH_FIND_INT(db.clients, &fd, client);
+       if (client == NULL)
+               goto unlock;
+
+       if (client->meat.rtr_version_set) {
+               result = -EINVAL; /* Can't be modified */
+               goto unlock;
+       }
+
+       client->meat.rtr_version = rtr_version;
+       client->meat.rtr_version_set = true;
+       result = 0;
+unlock:
+       rwlock_unlock(&lock);
+
+       return result;
+}
+
+int
+clients_get_rtr_version_set(int fd, bool *is_set, uint8_t *rtr_version)
+{
+       struct hashable_client *client;
+       int result;
+
+       result = -ENOENT;
+       rwlock_read_lock(&lock);
+
+       HASH_FIND_INT(db.clients, &fd, client);
+       if (client != NULL) {
+               (*is_set) = client->meat.rtr_version_set;
+               (*rtr_version) = client->meat.rtr_version;
+               result = 0;
+       }
+
+       rwlock_unlock(&lock);
+
+       return result;
+}
+
 void
 clients_forget(int fd)
 {
index dc8f9a7e25843f654cfd931fdb925bc44b1aeef5..1a883155df94534076746cb0c4f82888a1afe800 100644 (file)
@@ -18,6 +18,9 @@ struct client {
 
        serial_t serial_number;
        bool serial_number_set;
+
+       uint8_t rtr_version;
+       bool rtr_version_set;
 };
 
 int clients_db_init(void);
@@ -30,6 +33,9 @@ int clients_foreach(clients_foreach_cb, void *);
 int clients_get_min_serial(serial_t *);
 int clients_get_addr(int, struct sockaddr_storage *);
 
+int clients_set_rtr_version(int, uint8_t);
+int clients_get_rtr_version_set(int, bool *, uint8_t *);
+
 typedef int (*join_thread_cb)(pthread_t, void *);
 void clients_db_destroy(join_thread_cb, void *);
 
index 6e64adcbcc5882b4bb5a7c5c5bc4a820ecb18b76..7d54ade3c125bf58165ad99f6dbf24b768cd8e74 100644 (file)
@@ -14,7 +14,8 @@ send_notify(struct client const *client, void *arg)
        int error;
 
        /* Send Serial Notify PDU */
-       error = send_serial_notify_pdu(client->fd, *serial);
+       error = send_serial_notify_pdu(client->fd, client->rtr_version,
+           *serial);
 
        /* Error? Log it... */
        if (error)
index 2ade29eb2f858e982e24e5ac3d73c63441423c06..7df38d2218a2b812c8cdc0c6a3b853cc1db2a841 100644 (file)
@@ -18,8 +18,8 @@ typedef enum rtr_error_code {
 } rtr_error_code_t;
 
 static int
-err_pdu_send(int fd, rtr_error_code_t code, struct rtr_request const *request,
-    char const *message_const)
+err_pdu_send(int fd, uint8_t version, rtr_error_code_t code,
+    struct rtr_request const *request, char const *message_const)
 {
        char *message;
 
@@ -31,17 +31,18 @@ err_pdu_send(int fd, rtr_error_code_t code, struct rtr_request const *request,
 
        /* Need a clone to remove the const. */
        message = (message_const != NULL) ? strdup(message_const) : NULL;
-       send_error_report_pdu(fd, code, request, message);
+       send_error_report_pdu(fd, version, code, request, message);
        free(message);
 
        return -EINVAL;
 }
 
 int
-err_pdu_send_corrupt_data(int fd, struct rtr_request const *request,
-    char const *message)
+err_pdu_send_corrupt_data(int fd, uint8_t version,
+    struct rtr_request const *request, char const *message)
 {
-       return err_pdu_send(fd, ERR_PDU_CORRUPT_DATA, request, message);
+       return err_pdu_send(fd, version, ERR_PDU_CORRUPT_DATA, request,
+           message);
 }
 
 /*
@@ -50,15 +51,15 @@ err_pdu_send_corrupt_data(int fd, struct rtr_request const *request,
  * problem.
  */
 int
-err_pdu_send_internal_error(int fd)
+err_pdu_send_internal_error(int fd, uint8_t version)
 {
-       return err_pdu_send(fd, ERR_PDU_INTERNAL_ERROR, NULL, NULL);
+       return err_pdu_send(fd, version, ERR_PDU_INTERNAL_ERROR, NULL, NULL);
 }
 
 int
-err_pdu_send_no_data_available(int fd)
+err_pdu_send_no_data_available(int fd, uint8_t version)
 {
-       err_pdu_send(fd, ERR_PDU_NO_DATA_AVAILABLE, NULL, NULL);
+       err_pdu_send(fd, version, ERR_PDU_NO_DATA_AVAILABLE, NULL, NULL);
        /*
         * The connection should not be terminated because of this error.
         * So don't panic; client should retry later.
@@ -67,27 +68,29 @@ err_pdu_send_no_data_available(int fd)
 }
 
 int
-err_pdu_send_invalid_request(int fd, struct rtr_request const *request,
-    char const *message)
+err_pdu_send_invalid_request(int fd, uint8_t version,
+    struct rtr_request const *request, char const *message)
 {
-       return err_pdu_send(fd, ERR_PDU_INVALID_REQUEST, request, message);
+       return err_pdu_send(fd, version, ERR_PDU_INVALID_REQUEST, request,
+           message);
 }
 
 /* Caution: @header is supposed to be in serialized form. */
 int
-err_pdu_send_invalid_request_truncated(int fd, unsigned char *header,
-    char const *message)
+err_pdu_send_invalid_request_truncated(int fd, uint8_t version,
+    unsigned char *header, char const *message)
 {
        struct rtr_request request = {
                .bytes = header,
                .bytes_len = RTRPDU_HDR_LEN,
                .pdu = NULL,
        };
-       return err_pdu_send_invalid_request(fd, &request, message);
+       return err_pdu_send_invalid_request(fd, version, &request, message);
 }
 
 int
-err_pdu_send_unsupported_proto_version(int fd, unsigned char *header,
+err_pdu_send_unsupported_proto_version(int fd, uint8_t version,
+    unsigned char *header,
     char const *message)
 {
        struct rtr_request request = {
@@ -95,13 +98,28 @@ err_pdu_send_unsupported_proto_version(int fd, unsigned char *header,
                .bytes_len = RTRPDU_HDR_LEN,
                .pdu = NULL,
        };
-       return err_pdu_send(fd, ERR_PDU_UNSUP_PROTO_VERSION, &request, message);
+       return err_pdu_send(fd, version, ERR_PDU_UNSUP_PROTO_VERSION, &request,
+           message);
+}
+
+int
+err_pdu_send_unsupported_pdu_type(int fd, uint8_t version,
+    struct rtr_request const *request)
+{
+       return err_pdu_send(fd, version, ERR_PDU_UNSUP_PDU_TYPE, request, NULL);
 }
 
 int
-err_pdu_send_unsupported_pdu_type(int fd, struct rtr_request const *request)
+err_pdu_send_unexpected_proto_version(int fd, uint8_t version,
+    unsigned char *header, char const *message)
 {
-       return err_pdu_send(fd, ERR_PDU_UNSUP_PDU_TYPE, request, NULL);
+       struct rtr_request request = {
+               .bytes = header,
+               .bytes_len = RTRPDU_HDR_LEN,
+               .pdu = NULL,
+       };
+       return err_pdu_send(fd, version, ERR_PDU_UNEXPECTED_PROTO_VERSION, &request,
+           message);
 }
 
 char const *
index 1606b96d81b04070da2d9ff7f093a8e765c3ae66..5e8cda69f7c350968929c8e7721b3767795fe4e9 100644 (file)
  * Mainly, this is for the sake of making it easier to see whether the error is
  * supposed to contain a message and/or the original PDU or not.
  */
-int err_pdu_send_corrupt_data(int, struct rtr_request const *, char const *);
-int err_pdu_send_internal_error(int);
-int err_pdu_send_no_data_available(int);
-int err_pdu_send_invalid_request(int, struct rtr_request const *, char const *);
-int err_pdu_send_invalid_request_truncated(int, unsigned char *, char const *);
-int err_pdu_send_unsupported_proto_version(int, unsigned char *, char const *);
-int err_pdu_send_unsupported_pdu_type(int, struct rtr_request const *);
+int err_pdu_send_corrupt_data(int, uint8_t, struct rtr_request const *,
+    char const *);
+int err_pdu_send_internal_error(int, uint8_t);
+int err_pdu_send_no_data_available(int, uint8_t);
+int err_pdu_send_invalid_request(int, uint8_t, struct rtr_request const *,
+    char const *);
+int err_pdu_send_invalid_request_truncated(int, uint8_t, unsigned char *,
+    char const *);
+int err_pdu_send_unsupported_proto_version(int, uint8_t, unsigned char *,
+    char const *);
+int err_pdu_send_unsupported_pdu_type(int, uint8_t, struct rtr_request const *);
+int err_pdu_send_unexpected_proto_version(int, uint8_t, unsigned char *,
+    char const *);
 
 char const *err_pdu_to_string(uint16_t);
 
index ba031ad147e7073aeb374cf5cf587c518bc1ad79..4350d24e0005bc9207b556fd206e0791e614c414 100644 (file)
@@ -4,6 +4,7 @@
 #include <stdlib.h>
 #include <string.h>
 
+#include "clients.h"
 #include "common.h"
 #include "log.h"
 #include "rtr/err_pdu.h"
@@ -22,6 +23,57 @@ pdu_header_from_reader(struct pdu_reader *reader, struct pdu_header *header)
 #define RESPOND_ERROR(report_cb) \
        ((header.pdu_type != PDU_TYPE_ERROR_REPORT) ? (report_cb) : -EINVAL);
 
+static int
+validate_rtr_version(int fd, struct pdu_header *header,
+    unsigned char *hdr_bytes)
+{
+       uint8_t curr_version;
+       bool version_set;
+       int error;
+
+       error = clients_get_rtr_version_set(fd, &version_set, &curr_version);
+       if (error)
+               /* Unlikely, but close connection with min version */
+               return (header->pdu_type != PDU_TYPE_ERROR_REPORT) ?
+                   err_pdu_send_internal_error(fd, RTR_V0) : -EINVAL;
+
+       if (version_set) {
+               if (header->protocol_version == curr_version)
+                       return 0;
+
+               /* Don't send error on a rcvd error! */
+               if (header->pdu_type == PDU_TYPE_ERROR_REPORT)
+                       return -EINVAL;
+
+               switch(curr_version) {
+               case RTR_V1:
+                       /* Rcvd version is valid, but unexpected */
+                       if (header->protocol_version == RTR_V0)
+                               return err_pdu_send_unexpected_proto_version(
+                                   fd, curr_version, hdr_bytes,
+                                   "RTR version 0 was expected");
+                       /* Send common error */
+               case RTR_V0:
+                       return err_pdu_send_unsupported_proto_version(fd,
+                           curr_version, hdr_bytes,
+                           "RTR version received is unknown.");
+               default:
+                       pr_crit("Unknown RTR version %u", curr_version);
+                       break;
+               }
+       }
+
+       /* Unsigned and incremental values, so compare against major version */
+       if (header->protocol_version > RTR_V1)
+               /* ...and send error with min version */
+               return (header->pdu_type != PDU_TYPE_ERROR_REPORT) ?
+                   err_pdu_send_unsupported_proto_version(fd, RTR_V0,
+                   hdr_bytes, "RTR version received is unknown.")
+                   : -EINVAL;
+
+       return clients_set_rtr_version(fd, header->protocol_version);
+}
+
 int
 pdu_load(int fd, struct rtr_request *request,
     struct pdu_metadata const **metadata)
@@ -30,6 +82,7 @@ pdu_load(int fd, struct rtr_request *request,
        struct pdu_reader reader;
        struct pdu_header header;
        struct pdu_metadata const *meta;
+       uint8_t version;
        int error;
 
        /* Read the header into its buffer. */
@@ -42,21 +95,20 @@ pdu_load(int fd, struct rtr_request *request,
                /* No error response because the PDU might have been an error */
                return error;
 
+       error = validate_rtr_version(fd, &header, hdr_bytes);
+       if (error)
+               return error; /* Error response PDU already sent */
+
+       /* RTR version ok, keep it for later use */
+       version = header.protocol_version;
+
        /*
         * DO NOT USE THE err_pdu_* functions directly. Wrap them with
         * RESPOND_ERROR() INSTEAD.
         */
-
-       /*
-        * For now, only RTRv0 is supported
-        */
-       if (header.protocol_version != RTR_V0)
-               return RESPOND_ERROR(err_pdu_send_unsupported_proto_version(fd,
-                   hdr_bytes, "This server only supports RTRv0."));
-
        if (header.length < RTRPDU_HDR_LEN)
                return RESPOND_ERROR(err_pdu_send_invalid_request_truncated(fd,
-                   hdr_bytes, "Invalid header length. (< 8 bytes)"));
+                   version, hdr_bytes, "Invalid header length. (< 8 bytes)"));
 
        /*
         * Error messages can be quite large.
@@ -67,7 +119,7 @@ pdu_load(int fd, struct rtr_request *request,
         */
        if (header.length > 512)
                return RESPOND_ERROR(err_pdu_send_invalid_request_truncated(fd,
-                   hdr_bytes, "PDU is too large. (> 512 bytes)"));
+                   version, hdr_bytes, "PDU is too large. (> 512 bytes)"));
 
        /* Read the rest of the PDU into its buffer. */
        request->bytes_len = header.length;
@@ -89,7 +141,7 @@ pdu_load(int fd, struct rtr_request *request,
        meta = pdu_get_metadata(header.pdu_type);
        if (!meta) {
                error = RESPOND_ERROR(err_pdu_send_unsupported_pdu_type(fd,
-                   request));
+                   version, request));
                goto revert_bytes;
        }
 
@@ -101,13 +153,13 @@ pdu_load(int fd, struct rtr_request *request,
 
        error = meta->from_stream(&header, &reader, request->pdu);
        if (reader.size != 0) {
-               error = RESPOND_ERROR(err_pdu_send_invalid_request(fd,
+               error = RESPOND_ERROR(err_pdu_send_invalid_request(fd, version,
                    request,
                    "The PDU length sent doesn't match the real PDU length"));
                goto revert_pdu;
        }
        if (error) {
-               RESPOND_ERROR(err_pdu_send_internal_error(fd));
+               RESPOND_ERROR(err_pdu_send_internal_error(fd, version));
                goto revert_pdu;
        }
 
index 822ce977ba0046db9a8ff7f9aebb7f2dd6bc9077..b2ff63565700ac546fcb93b490ae99d1cce11567 100644 (file)
@@ -48,7 +48,8 @@ enum pdu_type {
 #define RTRPDU_CACHE_RESPONSE_LEN      8
 #define RTRPDU_IPV4_PREFIX_LEN         20
 #define RTRPDU_IPV6_PREFIX_LEN         32
-#define RTRPDU_END_OF_DATA_LEN         12
+#define RTRPDU_END_OF_DATA_V0_LEN      12
+#define RTRPDU_END_OF_DATA_V1_LEN      24
 #define RTRPDU_CACHE_RESET_LEN         8
 
 /* Ignores Error Report PDUs, which is fine. */
index 469e27951c5c5438a6af7228f6b172ece18266b7..5f10b2a3971e2de447f3756786a6d8240de41ab5 100644 (file)
 #include "pdu_sender.h"
 #include "rtr/db/vrps.h"
 
-#define warn_unexpected_pdu(fd, request, pdu_name)                     \
-       err_pdu_send_invalid_request(fd, request,                       \
-           "Clients are not supposed to send " pdu_name " PDUs.");
+#define WARN_UNEXPECTED_PDU(name, fd, request, pdu_name)               \
+       struct name##_pdu *pdu = request->pdu;                          \
+       return err_pdu_send_invalid_request(fd,                         \
+           pdu->header.protocol_version,                               \
+           request, "Clients are not supposed to send " pdu_name " PDUs.");
 
 int
 handle_serial_notify_pdu(int fd, struct rtr_request const *request)
 {
-       return warn_unexpected_pdu(fd, request, "Serial Notify");
+       WARN_UNEXPECTED_PDU(serial_notify, fd, request, "Serial Notify");
 }
 
 int
@@ -26,6 +28,7 @@ handle_serial_query_pdu(int fd, struct rtr_request const *request)
        struct serial_query_pdu *query = request->pdu;
        struct deltas_db deltas;
        serial_t final_serial;
+       uint8_t version;
        int error;
 
        /*
@@ -35,8 +38,10 @@ handle_serial_query_pdu(int fd, struct rtr_request const *request)
         * the mismatch MUST immediately terminate the session with an Error
         * Report PDU with code 0 ("Corrupt Data")"
         */
-       if (query->header.m.session_id != get_current_session_id(RTR_V0))
-               return err_pdu_send_corrupt_data(fd, request,
+       version = query->header.protocol_version;
+       if (query->header.m.session_id !=
+           get_current_session_id(version))
+               return err_pdu_send_corrupt_data(fd, version, request,
                    "Session ID doesn't match.");
 
        /*
@@ -55,11 +60,11 @@ handle_serial_query_pdu(int fd, struct rtr_request const *request)
        case 0:
                break;
        case -EAGAIN: /* Database still under construction */
-               error = err_pdu_send_no_data_available(fd);
+               error = err_pdu_send_no_data_available(fd, version);
                goto end;
        case -ESRCH: /* Invalid serial */
                /* https://tools.ietf.org/html/rfc6810#section-6.3 */
-               error = send_cache_reset_pdu(fd);
+               error = send_cache_reset_pdu(fd, version);
                goto end;
        case -ENOMEM: /* Memory allocation failure */
                goto end;
@@ -69,7 +74,7 @@ handle_serial_query_pdu(int fd, struct rtr_request const *request)
                 * RTR does not provide a code for that. Just fall through.
                 */
        default:
-               error = err_pdu_send_internal_error(fd);
+               error = err_pdu_send_internal_error(fd, version);
                goto end;
        }
 
@@ -80,13 +85,13 @@ handle_serial_query_pdu(int fd, struct rtr_request const *request)
         * programming errors. Best avoid error PDUs.
         */
 
-       error = send_cache_response_pdu(fd);
+       error = send_cache_response_pdu(fd, version);
        if (error)
                goto end;
-       error = send_delta_pdus(fd, &deltas);
+       error = send_delta_pdus(fd, version, &deltas);
        if (error)
                goto end;
-       error = send_end_of_data_pdu(fd, final_serial);
+       error = send_end_of_data_pdu(fd, version, final_serial);
 
 end:
        deltas_db_cleanup(&deltas, deltagroup_cleanup);
@@ -96,6 +101,7 @@ end:
 struct base_roa_args {
        bool started;
        int fd;
+       uint8_t version;
 };
 
 static int
@@ -105,33 +111,35 @@ send_base_roa(struct vrp const *vrp, void *arg)
        int error;
 
        if (!args->started) {
-               error = send_cache_response_pdu(args->fd);
+               error = send_cache_response_pdu(args->fd, args->version);
                if (error)
                        return error;
                args->started = true;
        }
 
-       return send_prefix_pdu(args->fd, vrp, FLAG_ANNOUNCEMENT);
+       return send_prefix_pdu(args->fd, args->version, vrp, FLAG_ANNOUNCEMENT);
 }
 
 int
 handle_reset_query_pdu(int fd, struct rtr_request const *request)
 {
+       struct reset_query_pdu *pdu = request->pdu;
        struct base_roa_args args;
        serial_t current_serial;
        int error;
 
        args.started = false;
        args.fd = fd;
+       args.version = pdu->header.protocol_version;
 
        error = get_last_serial_number(&current_serial);
        switch (error) {
        case 0:
                break;
        case -EAGAIN:
-               return err_pdu_send_no_data_available(fd);
+               return err_pdu_send_no_data_available(fd, args.version);
        default:
-               err_pdu_send_internal_error(fd);
+               err_pdu_send_internal_error(fd, args.version);
                return error;
        }
 
@@ -150,49 +158,49 @@ handle_reset_query_pdu(int fd, struct rtr_request const *request)
        case 0:
                break;
        case -EAGAIN:
-               return err_pdu_send_no_data_available(fd);
+               return err_pdu_send_no_data_available(fd, args.version);
        case EAGAIN:
-               err_pdu_send_internal_error(fd);
+               err_pdu_send_internal_error(fd, args.version);
                return error;
        }
 
-       return send_end_of_data_pdu(fd, current_serial);
+       return send_end_of_data_pdu(fd, args.version, current_serial);
 }
 
 int
 handle_cache_response_pdu(int fd, struct rtr_request const *request)
 {
-       return warn_unexpected_pdu(fd, request, "Cache Response");
+       WARN_UNEXPECTED_PDU(cache_response, fd, request, "Cache Response");
 }
 
 int
 handle_ipv4_prefix_pdu(int fd, struct rtr_request const *request)
 {
-       return warn_unexpected_pdu(fd, request, "IPv4 Prefix");
+       WARN_UNEXPECTED_PDU(ipv4_prefix, fd, request, "IPv4 Prefix");
 }
 
 int
 handle_ipv6_prefix_pdu(int fd, struct rtr_request const *request)
 {
-       return warn_unexpected_pdu(fd, request, "IPv6 Prefix");
+       WARN_UNEXPECTED_PDU(ipv6_prefix, fd, request, "IPv6 Prefix");
 }
 
 int
 handle_end_of_data_pdu(int fd, struct rtr_request const *request)
 {
-       return warn_unexpected_pdu(fd, request, "End of Data");
+       WARN_UNEXPECTED_PDU(end_of_data, fd, request, "End of Data");
 }
 
 int
 handle_cache_reset_pdu(int fd, struct rtr_request const *request)
 {
-       return warn_unexpected_pdu(fd, request, "Cache Reset");
+       WARN_UNEXPECTED_PDU(cache_reset, fd, request, "Cache Reset");
 }
 
 int
 handle_router_key_pdu(int fd, struct rtr_request const *request)
 {
-       return warn_unexpected_pdu(fd, request, "Router Key");
+       WARN_UNEXPECTED_PDU(router_key, fd, request, "Router Key");
 }
 
 int
index 547ef260bf348ccc78954fb7a2c91c59b699a08c..3d2ff749a399366b0d77f4256622f576f468ce24 100644 (file)
  * Set all the header values, EXCEPT length field.
  */
 static void
-set_header_values(struct pdu_header *header, uint8_t type, uint16_t reserved)
+set_header_values(struct pdu_header *header, uint8_t version, uint8_t type,
+    uint16_t reserved)
 {
-       /* FIXME Remove to support RTR_V1 */
-       header->protocol_version = RTR_V0;
+       header->protocol_version = version;
        header->pdu_type = type;
        header->m.reserved = reserved;
 }
@@ -37,14 +37,14 @@ send_response(int fd, unsigned char *data, size_t data_len)
 }
 
 int
-send_serial_notify_pdu(int fd, serial_t start_serial)
+send_serial_notify_pdu(int fd, uint8_t version, serial_t start_serial)
 {
        struct serial_notify_pdu pdu;
        unsigned char data[RTRPDU_SERIAL_NOTIFY_LEN];
        size_t len;
 
-       set_header_values(&pdu.header, PDU_TYPE_SERIAL_NOTIFY,
-           get_current_session_id(RTR_V0));
+       set_header_values(&pdu.header, version, PDU_TYPE_SERIAL_NOTIFY,
+           get_current_session_id(version));
 
        pdu.serial_number = start_serial;
        pdu.header.length = RTRPDU_SERIAL_NOTIFY_LEN;
@@ -57,14 +57,14 @@ send_serial_notify_pdu(int fd, serial_t start_serial)
 }
 
 int
-send_cache_reset_pdu(int fd)
+send_cache_reset_pdu(int fd, uint8_t version)
 {
        struct cache_reset_pdu pdu;
        unsigned char data[RTRPDU_CACHE_RESET_LEN];
        size_t len;
 
        /* This PDU has only the header */
-       set_header_values(&pdu.header, PDU_TYPE_CACHE_RESET, 0);
+       set_header_values(&pdu.header, version, PDU_TYPE_CACHE_RESET, 0);
        pdu.header.length = RTRPDU_CACHE_RESET_LEN;
 
        len = serialize_cache_reset_pdu(&pdu, data);
@@ -75,15 +75,15 @@ send_cache_reset_pdu(int fd)
 }
 
 int
-send_cache_response_pdu(int fd)
+send_cache_response_pdu(int fd, uint8_t version)
 {
        struct cache_response_pdu pdu;
        unsigned char data[RTRPDU_CACHE_RESPONSE_LEN];
        size_t len;
 
        /* This PDU has only the header */
-       set_header_values(&pdu.header, PDU_TYPE_CACHE_RESPONSE,
-           get_current_session_id(RTR_V0));
+       set_header_values(&pdu.header, version, PDU_TYPE_CACHE_RESPONSE,
+           get_current_session_id(version));
        pdu.header.length = RTRPDU_CACHE_RESPONSE_LEN;
 
        len = serialize_cache_response_pdu(&pdu, data);
@@ -94,13 +94,14 @@ send_cache_response_pdu(int fd)
 }
 
 static int
-send_ipv4_prefix_pdu(int fd, struct vrp const *vrp, uint8_t flags)
+send_ipv4_prefix_pdu(int fd, uint8_t version, struct vrp const *vrp,
+    uint8_t flags)
 {
        struct ipv4_prefix_pdu pdu;
        unsigned char data[RTRPDU_IPV4_PREFIX_LEN];
        size_t len;
 
-       set_header_values(&pdu.header, PDU_TYPE_IPV4_PREFIX, 0);
+       set_header_values(&pdu.header, version, PDU_TYPE_IPV4_PREFIX, 0);
        pdu.header.length = RTRPDU_IPV4_PREFIX_LEN;
 
        pdu.flags = flags;
@@ -118,13 +119,14 @@ send_ipv4_prefix_pdu(int fd, struct vrp const *vrp, uint8_t flags)
 }
 
 static int
-send_ipv6_prefix_pdu(int fd, struct vrp const *vrp, uint8_t flags)
+send_ipv6_prefix_pdu(int fd, uint8_t version, struct vrp const *vrp,
+    uint8_t flags)
 {
        struct ipv6_prefix_pdu pdu;
        unsigned char data[RTRPDU_IPV6_PREFIX_LEN];
        size_t len;
 
-       set_header_values(&pdu.header, PDU_TYPE_IPV6_PREFIX, 0);
+       set_header_values(&pdu.header, version, PDU_TYPE_IPV6_PREFIX, 0);
        pdu.header.length = RTRPDU_IPV6_PREFIX_LEN;
 
        pdu.flags = flags;
@@ -142,20 +144,21 @@ send_ipv6_prefix_pdu(int fd, struct vrp const *vrp, uint8_t flags)
 }
 
 int
-send_prefix_pdu(int fd, struct vrp const *vrp, uint8_t flags)
+send_prefix_pdu(int fd, uint8_t version, struct vrp const *vrp, uint8_t flags)
 {
        switch (vrp->addr_fam) {
        case AF_INET:
-               return send_ipv4_prefix_pdu(fd, vrp, flags);
+               return send_ipv4_prefix_pdu(fd, version, vrp, flags);
        case AF_INET6:
-               return send_ipv6_prefix_pdu(fd, vrp, flags);
+               return send_ipv6_prefix_pdu(fd, version, vrp, flags);
        }
 
        return -EINVAL;
 }
 
 int
-send_router_key_pdu(int fd, struct router_key const *router_key, uint8_t flags)
+send_router_key_pdu(int fd, uint8_t version,
+    struct router_key const *router_key, uint8_t flags)
 {
        struct router_key_pdu pdu;
        unsigned char *data;
@@ -163,12 +166,14 @@ send_router_key_pdu(int fd, struct router_key const *router_key, uint8_t flags)
        uint16_t reserved;
        int error;
 
-       /* TODO Sanity check: this can't be sent on RTRv0 */
+       /* Sanity check: this can't be sent on RTRv0 */
+       if (version == RTR_V0)
+               return 0;
 
        reserved = 0;
        /* Set the flags at the first 8 bits of reserved field */
        reserved += (flags << 8);
-       set_header_values(&pdu.header, PDU_TYPE_ROUTER_KEY, reserved);
+       set_header_values(&pdu.header, version, PDU_TYPE_ROUTER_KEY, reserved);
 
        pdu.ski = sk_info_get_ski(router_key->sk);
        pdu.ski_len = RK_SKI_LEN;
@@ -203,27 +208,37 @@ release_sk:
        return error;
 }
 
+struct simple_param {
+       int     fd;
+       uint8_t version;
+};
+
 static int
 vrp_simply_send(struct delta_vrp const *delta, void *arg)
 {
-       int *fd = arg;
+       struct simple_param *param = arg;
 
-       return send_prefix_pdu(*fd, &delta->vrp, delta->flags);
+       return send_prefix_pdu(param->fd, param->version, &delta->vrp,
+           delta->flags);
 }
 
 static int
 router_key_simply_send(struct delta_bgpsec const *delta, void *arg)
 {
-       int *fd = arg;
+       struct simple_param *param = arg;
 
-       return send_router_key_pdu(*fd, &delta->router_key,
-           delta->flags);
+       return send_router_key_pdu(param->fd, param->version,
+           &delta->router_key, delta->flags);
 }
 
 int
-send_delta_pdus(int fd, struct deltas_db *deltas)
+send_delta_pdus(int fd, uint8_t version, struct deltas_db *deltas)
 {
        struct delta_group *group;
+       struct simple_param param;
+
+       param.fd = fd;
+       param.version = version;
 
        /*
         * Short circuit: Entries that share serial are already guaranteed to
@@ -232,35 +247,38 @@ send_delta_pdus(int fd, struct deltas_db *deltas)
        if (deltas->len == 1) {
                group = &deltas->array[0];
                return deltas_foreach(group->serial, group->deltas,
-                   vrp_simply_send, router_key_simply_send, &fd);
+                   vrp_simply_send, router_key_simply_send, &param);
        }
 
        /* FIXME Apply to router keys as well */
-       return vrps_foreach_filtered_delta(deltas, vrp_simply_send, &fd);
+       return vrps_foreach_filtered_delta(deltas, vrp_simply_send, &param);
 }
 
+#define GET_END_OF_DATA_LENGTH(version)                                        \
+       ((version == RTR_V1) ?                                          \
+           RTRPDU_END_OF_DATA_V1_LEN : RTRPDU_END_OF_DATA_V0_LEN)
+
 int
-send_end_of_data_pdu(int fd, serial_t end_serial)
+send_end_of_data_pdu(int fd, uint8_t version, serial_t end_serial)
 {
        struct end_of_data_pdu pdu;
-       unsigned char data[RTRPDU_END_OF_DATA_LEN];
+       unsigned char data[GET_END_OF_DATA_LENGTH(version)];
        size_t len;
        int error;
 
-       set_header_values(&pdu.header, PDU_TYPE_END_OF_DATA,
-           get_current_session_id(RTR_V0));
-       pdu.header.length = RTRPDU_END_OF_DATA_LEN;
+       set_header_values(&pdu.header, version, PDU_TYPE_END_OF_DATA,
+           get_current_session_id(version));
+       pdu.header.length = GET_END_OF_DATA_LENGTH(version);
 
        pdu.serial_number = end_serial;
-       /* FIXME WRONG!! Check for the real version */
-       if (pdu.header.protocol_version == RTR_V1) {
+       if (version == RTR_V1) {
                pdu.refresh_interval = config_get_interval_refresh();
                pdu.retry_interval = config_get_interval_retry();
                pdu.expire_interval = config_get_interval_expire();
        }
 
        len = serialize_end_of_data_pdu(&pdu, data);
-       if (len != RTRPDU_END_OF_DATA_LEN)
+       if (len != GET_END_OF_DATA_LENGTH(version))
                pr_crit("Serialized End of Data is %zu bytes.", len);
 
        error = send_response(fd, data, len);
@@ -272,15 +290,15 @@ send_end_of_data_pdu(int fd, serial_t end_serial)
 }
 
 int
-send_error_report_pdu(int fd, uint16_t code, struct rtr_request const *request,
-    char *message)
+send_error_report_pdu(int fd, uint8_t version, uint16_t code,
+    struct rtr_request const *request, char *message)
 {
        struct error_report_pdu pdu;
        unsigned char *data;
        size_t len;
        int error;
 
-       set_header_values(&pdu.header, PDU_TYPE_ERROR_REPORT, code);
+       set_header_values(&pdu.header, version, PDU_TYPE_ERROR_REPORT, code);
 
        if (request != NULL) {
                pdu.error_pdu_length = (request->bytes_len > RTRPDU_MAX_LEN)
index 58b179cf3aef5e9d59ba98113fb419bd7597ca18..4f2cb33ef861a4407ada0bc147c39d2866cab78d 100644 (file)
@@ -5,16 +5,15 @@
 #include "object/router_key.h"
 #include "rtr/db/vrps.h"
 
-void init_sender_common(int, int, uint8_t);
-
-int send_serial_notify_pdu(int, serial_t);
-int send_cache_reset_pdu(int);
-int send_cache_response_pdu(int);
-int send_prefix_pdu(int, struct vrp const *, uint8_t);
-int send_router_key_pdu(int, struct router_key const *, uint8_t);
-int send_delta_pdus(int, struct deltas_db *);
-int send_end_of_data_pdu(int, serial_t);
-int send_error_report_pdu(int, uint16_t, struct rtr_request const *, char *);
+int send_serial_notify_pdu(int, uint8_t, serial_t);
+int send_cache_reset_pdu(int, uint8_t);
+int send_cache_response_pdu(int, uint8_t);
+int send_prefix_pdu(int, uint8_t, struct vrp const *, uint8_t);
+int send_router_key_pdu(int, uint8_t, struct router_key const *, uint8_t);
+int send_delta_pdus(int, uint8_t, struct deltas_db *);
+int send_end_of_data_pdu(int, uint8_t, serial_t);
+int send_error_report_pdu(int, uint8_t, uint16_t, struct rtr_request const *,
+    char *);
 
 
 #endif /* SRC_RTR_PDU_SENDER_H_ */
index cd0e1d332ab1bd335b9b00f8a243f75f004fcb60..8001e4323db5804798ff2a9b3c70615f7f71607d 100644 (file)
@@ -292,7 +292,8 @@ handle_client_connections(int server_fd)
                error = pthread_create(&param->tid, NULL,
                    client_thread_cb, param);
                if (error && error != EAGAIN)
-                       err_pdu_send_internal_error(client_fd);
+                       /* Error with min RTR version */
+                       err_pdu_send_internal_error(client_fd, RTR_V0);
                if (error) {
                        pr_errno(error, "Could not spawn the client's thread");
                        close(client_fd);