From aa85ca2bf65672aa1de8449222cfbbe54aa52e9d Mon Sep 17 00:00:00 2001 From: pcarana Date: Wed, 20 Feb 2019 17:54:55 -0600 Subject: [PATCH] Fix a couple of bugs, implement Reset Query PDU handler. 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 | 11 ++- src/rtr/pdu_handler.c | 193 +++++++++++++++++++++++++++++++++++++++--- src/rtr/pdu_handler.h | 18 ++-- src/rtr/rtr.c | 8 +- 4 files changed, 206 insertions(+), 24 deletions(-) diff --git a/src/rtr/pdu.h b/src/rtr/pdu.h index 66a950ec..8d49d2b3 100644 --- a/src/rtr/pdu.h +++ b/src/rtr/pdu.h @@ -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 *); }; diff --git a/src/rtr/pdu_handler.c b/src/rtr/pdu_handler.c index 5d91f31c..50046b9a 100644 --- a/src/rtr/pdu_handler.c +++ b/src/rtr/pdu_handler.c @@ -2,9 +2,40 @@ #include #include +#include +#include +#include + +#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; diff --git a/src/rtr/pdu_handler.h b/src/rtr/pdu_handler.h index 481cb06c..f265e946 100644 --- a/src/rtr/pdu_handler.h +++ b/src/rtr/pdu_handler.h @@ -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_ */ diff --git a/src/rtr/rtr.c b/src/rtr/rtr.c index fcd0db2b..63b7a02d 100644 --- a/src/rtr/rtr.c +++ b/src/rtr/rtr.c @@ -5,6 +5,7 @@ #include #include #include +#include #include #include #include @@ -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"); -- 2.47.3