]> git.ipfire.org Git - thirdparty/FORT-validator.git/commitdiff
Fix a couple of bugs, implement Reset Query PDU handler.
authorpcarana <pc.moreno2099@gmail.com>
Wed, 20 Feb 2019 23:54:55 +0000 (17:54 -0600)
committerpcarana <pc.moreno2099@gmail.com>
Wed, 20 Feb 2019 23:54:55 +0000 (17:54 -0600)
Bugs fixed: add stdio.h, send VERDICT_SUCCESS if client_fd >= 0, use correct
pointer when handling PDUs (all at rtr.c).
Handle Reset Query PDU sending Cache Response and End of Data PDUs.
Add RTR version constants (0 and 1) and some PDU types for responses.

src/rtr/pdu.h
src/rtr/pdu_handler.c
src/rtr/pdu_handler.h
src/rtr/rtr.c

index 66a950ecd4f47d3ecae8547576ef4773e3a3f57c..8d49d2b31ba29ad07355a465b382f85fe176e116 100644 (file)
@@ -6,6 +6,12 @@
 #include "../common.h"
 #include "primitive_reader.h"
 
+#define RTR_V0 0
+#define RTR_V1 1
+
+#define CACHE_RESPONSE_PDU_TYPE                3
+#define END_OF_DATA_PDU_TYPE           7
+
 struct pdu_header {
        u_int8_t        protocol_version;
        u_int8_t        pdu_type;
@@ -58,6 +64,9 @@ struct ipv6_prefix_pdu {
 struct end_of_data_pdu {
        struct  pdu_header header;
        u_int32_t       serial_number;
+       u_int32_t       refresh_interval;
+       u_int32_t       retry_interval;
+       u_int32_t       expire_interval;
 };
 
 struct cache_reset_pdu {
@@ -73,7 +82,7 @@ struct error_report_pdu {
 struct pdu_metadata {
        size_t  length;
        int     (*from_stream)(struct pdu_header *, int, void *);
-       int     (*handle)(void *);
+       int     (*handle)(int, void *);
        void    (*destructor)(void *);
 };
 
index 5d91f31c194d6a28382a36af9839c5116bf14f11..50046b9a549234dc4233eabb525a2cc9cb7366c7 100644 (file)
@@ -2,9 +2,40 @@
 
 #include <err.h>
 #include <errno.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#include "configuration.h"
+#include "pdu.h"
+#include "pdu_serializer.h"
+
+/* Header without length field is always 32 bits long */
+#define HEADER_LENGTH 4
+
+#define BUFFER_SIZE 32
+
+struct buffer {
+       size_t len;
+       size_t capacity;
+       char *data;
+};
 
 static int warn_unexpected_pdu(char *);
 
+static void
+init_buffer(struct buffer *buffer)
+{
+       buffer->capacity = BUFFER_SIZE;
+       buffer->data = malloc(BUFFER_SIZE);
+}
+
+static void
+free_buffer(struct buffer *buffer)
+{
+       free(buffer->data);
+}
+
 static int
 warn_unexpected_pdu(char *pdu_name)
 {
@@ -13,58 +44,196 @@ warn_unexpected_pdu(char *pdu_name)
        return -EINVAL;
 }
 
+/*
+ * Set all the header values, EXCEPT length field.
+ */
+static void
+set_header_values(struct pdu_header *header, u_int8_t version, u_int8_t type,
+    u_int16_t reserved)
+{
+       header->protocol_version = version;
+       header->pdu_type = type;
+       header->reserved = reserved;
+}
+
+static u_int32_t
+length_cache_response_pdu(struct cache_response_pdu *pdu)
+{
+       /* This PDU has no payload, consider 32 bits of the length field */
+       return HEADER_LENGTH + sizeof(u_int32_t);
+}
+
+static u_int32_t
+length_end_of_data_pdu(struct end_of_data_pdu *pdu)
+{
+       u_int32_t len;
+
+       /* Consider 32 bits of the length field */
+       len = HEADER_LENGTH + sizeof(u_int32_t);
+       len += sizeof(pdu->serial_number);
+       if (pdu->header.protocol_version == RTR_V1) {
+               len += sizeof(pdu->refresh_interval);
+               len += sizeof(pdu->retry_interval);
+               len += sizeof(pdu->expire_interval);
+       }
+
+       return len;
+}
+
+static int
+send_response(int fd, struct buffer *buffer)
+{
+       int error;
+
+       /*
+        * FIXME Check for buffer overflow
+        */
+
+       error = write(fd, buffer->data, buffer->len);
+       if (error < 0) {
+               err(error, "Error sending response");
+               /*
+                * TODO Send error PDU here depending on error type?
+                */
+               return error;
+       }
+
+       return 0;
+}
+
+static int
+send_cache_response_pdu(int fd, u_int8_t version, u_int16_t session_id)
+{
+       struct cache_response_pdu pdu;
+       struct buffer buffer;
+       int error;
+
+       init_buffer(&buffer);
+       set_header_values(&pdu.header, version,
+           CACHE_RESPONSE_PDU_TYPE, session_id);
+       pdu.header.length = length_cache_response_pdu(&pdu);
+
+       buffer.len = serialize_cache_response_pdu(&pdu, buffer.data);
+       error = send_response(fd, &buffer);
+       free_buffer(&buffer);
+       if (error)
+               return error;
+
+       return 0;
+}
+
+static int
+send_payload_pdus(int fd, u_int8_t version)
+{
+       // FIXME Complete me!!
+       return 0;
+}
+
+static int
+send_end_of_data_pdu(int fd, u_int8_t version, u_int16_t session_id)
+{
+       struct end_of_data_pdu pdu;
+       struct buffer buffer;
+       int error;
+
+       init_buffer(&buffer);
+       set_header_values(&pdu.header, version, END_OF_DATA_PDU_TYPE, session_id);
+       pdu.serial_number = 16;
+       if (version == RTR_V1) {
+               pdu.refresh_interval = config_get_refresh_interval();
+               pdu.retry_interval = config_get_retry_interval();
+               pdu.expire_interval = config_get_expire_interval();
+       }
+       pdu.header.length = length_end_of_data_pdu(&pdu);
+
+       buffer.len = serialize_end_of_data_pdu(&pdu, buffer.data);
+       error = send_response(fd, &buffer);
+       free_buffer(&buffer);
+       if (error)
+               return error;
+
+       return 0;
+}
+
 int
-handle_serial_notify_pdu(void *pdu)
+handle_serial_notify_pdu(int fd, void *pdu)
 {
        return warn_unexpected_pdu("Serial Notify");
 }
 
 int
-handle_serial_query_pdu(void *pdu)
+handle_serial_query_pdu(int fd, void *pdu)
 {
-       /* TODO */
        return -EUNIMPLEMENTED;
 }
 
 int
-handle_reset_query_pdu(void *pdu)
+handle_reset_query_pdu(int fd, void *pdu)
 {
-       /* TODO */
-       return -EUNIMPLEMENTED;
+       struct reset_query_pdu *received = pdu;
+       u_int16_t session_id;
+       u_int8_t version;
+       int error;
+
+       /*
+        * FIXME Complete behaviour:
+        * - Do I have data?
+        *   + NO: Send error
+        *         https://tools.ietf.org/html/rfc8210#section-8.4
+        *   + YES: Send data (cache response -> payloads -> end of data)
+        *          https://tools.ietf.org/html/rfc8210#section-8.1
+        */
+
+       /* FIXME Handle sessions and its ID */
+       session_id = 1;
+       version = received->header.protocol_version;
+
+       // Send Cache response PDU
+       error = send_cache_response_pdu(fd, version, session_id);
+       if (error)
+               return error;
+
+       // Send Payload PDUs
+       error = send_payload_pdus(fd, version);
+       if (error)
+               return error;
+
+       // Send End of data PDU
+       return send_end_of_data_pdu(fd, version, session_id);
 }
 
 int
-handle_cache_response_pdu(void *pdu)
+handle_cache_response_pdu(int fd, void *pdu)
 {
        return warn_unexpected_pdu("Cache Response");
 }
 
 int
-handle_ipv4_prefix_pdu(void *pdu)
+handle_ipv4_prefix_pdu(int fd, void *pdu)
 {
        return warn_unexpected_pdu("IPv4 Prefix");
 }
 
 int
-handle_ipv6_prefix_pdu(void *pdu)
+handle_ipv6_prefix_pdu(int fd, void *pdu)
 {
        return warn_unexpected_pdu("IPv6 Prefix");
 }
 
 int
-handle_end_of_data_pdu(void *pdu)
+handle_end_of_data_pdu(int fd, void *pdu)
 {
        return warn_unexpected_pdu("End of Data");
 }
 
 int
-handle_cache_reset_pdu(void *pdu)
+handle_cache_reset_pdu(int fd, void *pdu)
 {
        return warn_unexpected_pdu("Cache Reset");
 }
 
 int
-handle_error_report_pdu(void *pdu)
+handle_error_report_pdu(int fd, void *pdu)
 {
        /* TODO */
        return -EUNIMPLEMENTED;
index 481cb06cc9b940a8ab3c25e4f6e930502942089e..f265e9464d3c012fc2abbeaf2ce92c450d7df89a 100644 (file)
@@ -4,15 +4,15 @@
 #include "../common.h"
 
 __BEGIN_DECLS
-int handle_serial_notify_pdu(void *);
-int handle_serial_query_pdu(void *);
-int handle_reset_query_pdu(void *);
-int handle_cache_response_pdu(void *);
-int handle_ipv4_prefix_pdu(void *);
-int handle_ipv6_prefix_pdu(void *);
-int handle_end_of_data_pdu(void *);
-int handle_cache_reset_pdu(void *);
-int handle_error_report_pdu(void *);
+int handle_serial_notify_pdu(int, void *);
+int handle_serial_query_pdu(int, void *);
+int handle_reset_query_pdu(int, void *);
+int handle_cache_response_pdu(int, void *);
+int handle_ipv4_prefix_pdu(int, void *);
+int handle_ipv6_prefix_pdu(int, void *);
+int handle_end_of_data_pdu(int, void *);
+int handle_cache_reset_pdu(int, void *);
+int handle_error_report_pdu(int, void *);
 __END_DECLS
 
 #endif /* RTR_PDU_HANDLER_H_ */
index fcd0db2b3bec65067ef47484e283bc0dc9cae0c1..63b7a02de4dc850f0eff1970d45c5ecf5410b411 100644 (file)
@@ -5,6 +5,7 @@
 #include <netdb.h>
 #include <pthread.h>
 #include <stdbool.h>
+#include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
 #include <unistd.h>
@@ -72,7 +73,7 @@ enum verdict {
 static enum verdict
 handle_accept_result(int client_fd, int err)
 {
-       if (client_fd == 0)
+       if (client_fd >= 0)
                return VERDICT_SUCCESS;
 
        /*
@@ -120,7 +121,7 @@ client_thread_cb(void *param_void)
                if (err)
                        return NULL;
 
-               err = meta->handle(&pdu);
+               err = meta->handle(param.client_fd, pdu);
                meta->destructor(pdu);
                if (err)
                        return NULL;
@@ -171,6 +172,9 @@ handle_client_connections(int server_fd)
                }
                arg->client_fd = client_fd;
 
+               /*
+                * FIXME Handle session IDs, serial IDs, protocol version
+                */
                errno = pthread_create(&thread, NULL, client_thread_cb, arg);
                if (errno) {
                        warn("Could not spawn the client's thread");