// SPDX-License-Identifier: BSD-3-Clause OR Apache-2.0 #include "routing/compat/config_parser.h" #include "routing/compat/node.h" #include "routing/compat/router.h" #include "platform/hal_io.h" #include "ud3tn/eid.h" #include #include #include #include static const char EID_START_DELIMITER = '('; static const char EID_END_DELIMITER = ')'; static const char CLA_ADDR_START_DELIMITER = '('; static const char CLA_ADDR_END_DELIMITER = ')'; static const char NODE_CONF_RELIABILITY_SEPARATOR = ','; static const char NODE_CONF_CLA_ADDR_SEPARATOR = ':'; static const char CLA_ADDR_NODES_SEPARATOR = ':'; static const char LIST_START_DELIMITER = '['; static const char LIST_END_DELIMITER = ']'; static const char LIST_ELEMENT_SEPARATOR = ','; static const char OBJECT_START_DELIMITER = '{'; static const char OBJECT_END_DELIMITER = '}'; static const char OBJECT_ELEMENT_SEPARATOR = ','; static const char NODES_CONTACTS_SEPARATOR = ':'; static const uint8_t COMMAND_END_MARKER = ';'; static const uint8_t DEFAULT_EID_BUFFER_SIZE = 16; static const uint8_t DEFAULT_CLA_ADDR_BUFFER_SIZE = 21; static const uint8_t DEFAULT_INT_BUFFER_SIZE = 16; static void begin_read_data_eid( struct config_parser *parser, struct endpoint_list **target) { struct endpoint_list *new_entry = malloc(sizeof(struct endpoint_list)); if (!new_entry) return; char *new_eid = malloc(DEFAULT_EID_BUFFER_SIZE * sizeof(char)); if (!new_eid) { free(new_entry); return; } new_eid[0] = '\0'; new_entry->eid = new_eid; new_entry->next = NULL; if (parser->current_eid == NULL) *target = new_entry; else parser->current_eid->next = new_entry; parser->current_eid = new_entry; parser->current_index = 0; } static void begin_read_node_conf_eid(struct config_parser *parser) { parser->router_command->data->eid = malloc(DEFAULT_EID_BUFFER_SIZE * sizeof(char)); parser->router_command->data->eid[0] = '\0'; parser->current_index = 0; } static bool read_eid( struct config_parser *parser, char **eid_ptr, const char byte) { /* Check for valid chars (URIs) */ if ( /* !"#$%&'()*+,-./0123456789:<=>?@ / A-Z / [\]^_ */ (byte >= 0x21 && byte <= 0x5F) || /* a-z / ~ */ (byte >= 0x61 && byte <= 0x7A) || byte == 0x7E ) { (*eid_ptr)[parser->current_index++] = byte; if (parser->current_index >= DEFAULT_EID_BUFFER_SIZE) (*eid_ptr) = realloc(*eid_ptr, (parser->current_index + 1) * sizeof(char)); (*eid_ptr)[parser->current_index] = '\0'; return true; } else { return false; } } static void end_read_eid(const struct config_parser *parser, char **eid_ptr) { (*eid_ptr)[parser->current_index] = '\0'; struct eid read_eid_struct = eid_from_string(*eid_ptr); // Our current router implementation searches for the EID returned by // get_node_id(destination). This might differ, e.g., by a slash added // at the end of a `dtn` scheme EID. Thus, we want to ensure that this // value is added to the routing table if we can determine it. struct eid node_id = eid_get_admin_endpoint(read_eid_struct); char *const node_id_str = eid_to_string(node_id); eid_free(read_eid_struct); eid_free(node_id); if (node_id_str) { free(*eid_ptr); *eid_ptr = node_id_str; } } static void begin_read_cla_addr(struct config_parser *parser) { parser->router_command->data->cla_addr = malloc(DEFAULT_CLA_ADDR_BUFFER_SIZE * sizeof(char)); parser->router_command->data->cla_addr[0] = '\0'; parser->current_index = 0; } static void end_read_cla_addr( const struct config_parser *parser, char **cla_addr_ptr) { (*cla_addr_ptr)[parser->current_index] = '\0'; } static bool read_cla_addr( struct config_parser *parser, char **cla_addr_ptr, const char byte) { if ( (byte >= '0' && byte <= '9') || (byte >= 'A' && byte <= 'Z') || (byte >= 'a' && byte <= 'z') || (byte == ':') || (byte == '.') || (byte == '[') || (byte == ']') || (byte == '#') || (byte == '/') || (byte == '-') ) { (*cla_addr_ptr)[parser->current_index++] = byte; if (parser->current_index >= DEFAULT_CLA_ADDR_BUFFER_SIZE) (*cla_addr_ptr) = realloc(*cla_addr_ptr, (parser->current_index + 1) * sizeof(char)); return true; } else { return false; } } static void begin_read_contact(struct config_parser *parser) { struct contact_list *new_entry = malloc(sizeof(struct contact_list)); if (!new_entry) return; new_entry->next = NULL; new_entry->data = contact_create(parser->router_command->data); if (parser->current_contact == NULL) parser->router_command->data->contacts = new_entry; else parser->current_contact->next = new_entry; parser->current_contact = new_entry; /* Reset for contact eids, misc eid reading has finished here */ parser->current_eid = NULL; } static void begin_read_integer(struct config_parser *parser) { parser->current_int_data = malloc(DEFAULT_INT_BUFFER_SIZE * sizeof(char)); parser->current_index = 0; } static bool read_integer(struct config_parser *parser, const char byte) { if (byte >= 0x30 && byte <= 0x39) { /* 0..9 */ parser->current_int_data[parser->current_index++] = byte; if (parser->current_index >= DEFAULT_INT_BUFFER_SIZE) parser->current_int_data = realloc( parser->current_int_data, (parser->current_index + 1) * sizeof(char)); return true; } else { return false; } } static void end_read_uint64(struct config_parser *parser, uint64_t *out) { parser->current_int_data[parser->current_index] = '\0'; /* No further checks because read_integer already checks for digits */ *out = strtoull(parser->current_int_data, NULL, 10); free(parser->current_int_data); parser->current_int_data = NULL; } static void end_read_uint32(struct config_parser *parser, uint32_t *out) { parser->current_int_data[parser->current_index] = '\0'; /* No further checks because read_integer already checks for digits */ *out = strtoul(parser->current_int_data, NULL, 10); free(parser->current_int_data); parser->current_int_data = NULL; } static void end_read_uint16(struct config_parser *parser, uint16_t *out) { parser->current_int_data[parser->current_index] = '\0'; /* No further checks because read_integer already checks for digits */ /* XXX: Overflow might be possible here */ *out = (uint16_t)atoi(parser->current_int_data); free(parser->current_int_data); parser->current_int_data = NULL; } static void read_command(struct config_parser *parser, const uint8_t byte) { uint16_t tmp; struct node *cur_gs = parser->router_command->data; switch (parser->stage) { default: parser->basedata->status = PARSER_STATUS_ERROR; break; case RP_EXPECT_NODE_CONF_START_DELIMITER: if (byte == EID_START_DELIMITER) { begin_read_node_conf_eid(parser); parser->stage = RP_EXPECT_NODE_CONF_EID; } else { parser->basedata->status = PARSER_STATUS_ERROR; } break; case RP_EXPECT_NODE_CONF_EID: if (byte == EID_END_DELIMITER) { end_read_eid(parser, &(cur_gs->eid)); parser->stage = RP_EXPECT_NODE_CONF_RELIABILITY_SEPARATOR; } else if (!read_eid(parser, &(cur_gs->eid), byte)) { parser->basedata->status = PARSER_STATUS_ERROR; } break; case RP_EXPECT_NODE_CONF_RELIABILITY_SEPARATOR: if (byte == NODE_CONF_RELIABILITY_SEPARATOR) { begin_read_integer(parser); parser->stage = RP_EXPECT_NODE_CONF_RELIABILITY; } else if (byte == NODE_CONF_CLA_ADDR_SEPARATOR) { parser->stage = RP_EXPECT_CLA_ADDR_START_DELIMITER; } else if (byte == COMMAND_END_MARKER) { parser->basedata->status = PARSER_STATUS_DONE; } else { parser->basedata->status = PARSER_STATUS_ERROR; } break; case RP_EXPECT_NODE_CONF_RELIABILITY: if (byte == NODE_CONF_CLA_ADDR_SEPARATOR || byte == COMMAND_END_MARKER ) { end_read_uint16(parser, &tmp); if (tmp < 100 || tmp > 1000) { parser->basedata->status = PARSER_STATUS_ERROR; break; } // NOTE: Reliability is not used anymore. parser->stage = RP_EXPECT_CLA_ADDR_START_DELIMITER; if (byte == COMMAND_END_MARKER) parser->basedata->status = PARSER_STATUS_DONE; } else if (!read_integer(parser, byte)) { parser->basedata->status = PARSER_STATUS_ERROR; } break; case RP_EXPECT_CLA_ADDR_START_DELIMITER: if (byte == CLA_ADDR_START_DELIMITER) { begin_read_cla_addr(parser); parser->stage = RP_EXPECT_CLA_ADDR; } else if (byte == CLA_ADDR_NODES_SEPARATOR) { parser->stage = RP_EXPECT_NODE_LIST_START_DELIMITER; } else if (byte == COMMAND_END_MARKER) { parser->basedata->status = PARSER_STATUS_DONE; } else { parser->basedata->status = PARSER_STATUS_ERROR; } break; case RP_EXPECT_CLA_ADDR: if (byte == CLA_ADDR_END_DELIMITER) { end_read_cla_addr(parser, &(cur_gs->cla_addr)); parser->stage = RP_EXPECT_CLA_ADDR_NODES_SEPARATOR; } else if (!read_cla_addr(parser, &(cur_gs->cla_addr), byte)) { parser->basedata->status = PARSER_STATUS_ERROR; } break; case RP_EXPECT_CLA_ADDR_NODES_SEPARATOR: if (byte == CLA_ADDR_NODES_SEPARATOR) parser->stage = RP_EXPECT_NODE_LIST_START_DELIMITER; else if (byte == COMMAND_END_MARKER) parser->basedata->status = PARSER_STATUS_DONE; else parser->basedata->status = PARSER_STATUS_ERROR; break; case RP_EXPECT_NODE_LIST_START_DELIMITER: if (byte == LIST_START_DELIMITER) parser->stage = RP_EXPECT_NODE_START_DELIMITER; else if (byte == NODES_CONTACTS_SEPARATOR) parser->stage = RP_EXPECT_CONTACT_LIST_START_DELIMITER; else if (byte == COMMAND_END_MARKER) parser->basedata->status = PARSER_STATUS_DONE; else parser->basedata->status = PARSER_STATUS_ERROR; break; case RP_EXPECT_NODE_START_DELIMITER: if (byte == EID_START_DELIMITER) { begin_read_data_eid(parser, &(cur_gs->endpoints)); parser->stage = RP_EXPECT_NODE_EID; } else if (byte == LIST_END_DELIMITER) { parser->stage = RP_EXPECT_NODES_CONTACTS_SEPARATOR; } else { parser->basedata->status = PARSER_STATUS_ERROR; } break; case RP_EXPECT_NODE_EID: if (byte == EID_END_DELIMITER) { end_read_eid(parser, &(parser->current_eid->eid)); parser->stage = RP_EXPECT_NODE_SEPARATOR; } else if (!read_eid(parser, &(parser->current_eid->eid), byte) ) { parser->basedata->status = PARSER_STATUS_ERROR; } break; case RP_EXPECT_NODE_SEPARATOR: if (byte == LIST_ELEMENT_SEPARATOR) parser->stage = RP_EXPECT_NODE_START_DELIMITER; else if (byte == LIST_END_DELIMITER) parser->stage = RP_EXPECT_NODES_CONTACTS_SEPARATOR; else parser->basedata->status = PARSER_STATUS_ERROR; break; case RP_EXPECT_NODES_CONTACTS_SEPARATOR: if (byte == NODES_CONTACTS_SEPARATOR) parser->stage = RP_EXPECT_CONTACT_LIST_START_DELIMITER; else if (byte == COMMAND_END_MARKER) parser->basedata->status = PARSER_STATUS_DONE; else parser->basedata->status = PARSER_STATUS_ERROR; break; case RP_EXPECT_CONTACT_LIST_START_DELIMITER: if (byte == LIST_START_DELIMITER) parser->stage = RP_EXPECT_CONTACT_START_DELIMITER; else if (byte == COMMAND_END_MARKER) parser->basedata->status = PARSER_STATUS_DONE; else parser->basedata->status = PARSER_STATUS_ERROR; break; case RP_EXPECT_CONTACT_START_DELIMITER: if (byte == OBJECT_START_DELIMITER) { begin_read_contact(parser); begin_read_integer(parser); parser->stage = RP_EXPECT_CONTACT_START_TIME; } else if (byte == LIST_END_DELIMITER) { parser->stage = RP_EXPECT_COMMAND_END_MARKER; } else { parser->basedata->status = PARSER_STATUS_ERROR; } break; case RP_EXPECT_CONTACT_START_TIME: if (byte == OBJECT_ELEMENT_SEPARATOR) { end_read_uint64(parser, &(parser->current_contact->data->from_ms)); if (parser->current_contact->data->from_ms >= UINT64_MAX / 1000) { parser->basedata->status = PARSER_STATUS_ERROR; break; } parser->current_contact->data->from_ms *= 1000; begin_read_integer(parser); parser->stage = RP_EXPECT_CONTACT_END_TIME; } else if (!read_integer(parser, byte)) { parser->basedata->status = PARSER_STATUS_ERROR; } break; case RP_EXPECT_CONTACT_END_TIME: if (byte == OBJECT_ELEMENT_SEPARATOR) { end_read_uint64(parser, &(parser->current_contact->data->to_ms)); if (parser->current_contact->data->to_ms >= UINT64_MAX / 1000) { parser->basedata->status = PARSER_STATUS_ERROR; break; } parser->current_contact->data->to_ms *= 1000; begin_read_integer(parser); parser->stage = RP_EXPECT_CONTACT_BITRATE; } else if (!read_integer(parser, byte)) { parser->basedata->status = PARSER_STATUS_ERROR; } break; case RP_EXPECT_CONTACT_BITRATE: if (byte == OBJECT_ELEMENT_SEPARATOR) { end_read_uint32(parser, &(parser->current_contact->data ->bitrate_bytes_per_s)); parser->stage = RP_EXPECT_CONTACT_NODE_LIST_START_DELIMITER; } else if (byte == OBJECT_END_DELIMITER) { end_read_uint32(parser, &(parser->current_contact->data ->bitrate_bytes_per_s)); parser->stage = RP_EXPECT_CONTACT_SEPARATOR; } else if (!read_integer(parser, byte)) { parser->basedata->status = PARSER_STATUS_ERROR; } break; case RP_EXPECT_CONTACT_NODE_LIST_START_DELIMITER: if (byte == LIST_START_DELIMITER) parser->stage = RP_EXPECT_CONTACT_NODE_START_DELIMITER; else parser->basedata->status = PARSER_STATUS_ERROR; break; case RP_EXPECT_CONTACT_NODE_START_DELIMITER: if (byte == EID_START_DELIMITER) { begin_read_data_eid(parser, &(parser->current_contact ->data->contact_endpoints)); parser->stage = RP_EXPECT_CONTACT_NODE_EID; } else if (byte == LIST_END_DELIMITER) { parser->stage = RP_EXPECT_CONTACT_END_DELIMITER; } else { parser->basedata->status = PARSER_STATUS_ERROR; } break; case RP_EXPECT_CONTACT_NODE_EID: if (byte == EID_END_DELIMITER) { end_read_eid(parser, &(parser->current_eid->eid)); parser->stage = RP_EXPECT_CONTACT_NODE_SEPARATOR; } else if (!read_eid(parser, &(parser->current_eid->eid), byte) ) { parser->basedata->status = PARSER_STATUS_ERROR; } break; case RP_EXPECT_CONTACT_NODE_SEPARATOR: if (byte == LIST_ELEMENT_SEPARATOR) parser->stage = RP_EXPECT_CONTACT_NODE_START_DELIMITER; else if (byte == LIST_END_DELIMITER) parser->stage = RP_EXPECT_CONTACT_END_DELIMITER; else parser->basedata->status = PARSER_STATUS_ERROR; break; case RP_EXPECT_CONTACT_END_DELIMITER: if (byte == OBJECT_END_DELIMITER) parser->stage = RP_EXPECT_CONTACT_SEPARATOR; else parser->basedata->status = PARSER_STATUS_ERROR; break; case RP_EXPECT_CONTACT_SEPARATOR: if (byte == LIST_ELEMENT_SEPARATOR) parser->stage = RP_EXPECT_CONTACT_START_DELIMITER; else if (byte == LIST_END_DELIMITER) parser->stage = RP_EXPECT_COMMAND_END_MARKER; else parser->basedata->status = PARSER_STATUS_ERROR; break; case RP_EXPECT_COMMAND_END_MARKER: if (byte == COMMAND_END_MARKER) parser->basedata->status = PARSER_STATUS_DONE; else parser->basedata->status = PARSER_STATUS_ERROR; break; } } static void config_parser_read_byte(struct config_parser *parser, uint8_t byte) { if (parser->basedata->status != PARSER_STATUS_GOOD) return; if (parser->stage == RP_EXPECT_COMMAND_TYPE) { parser->stage = RP_EXPECT_NODE_CONF_START_DELIMITER; if (byte >= (uint8_t)ROUTER_COMMAND_ADD && byte <= (uint8_t)ROUTER_COMMAND_QUERY) parser->router_command->type = (enum router_command_type)byte; else parser->basedata->status = PARSER_STATUS_ERROR; } else { read_command(parser, *(char *)(&byte)); } } size_t config_parser_read(struct config_parser *parser, const uint8_t *buffer, size_t length) { size_t i = 0; while (i < length) { if (parser->basedata->status != PARSER_STATUS_GOOD && parser->basedata->status != PARSER_STATUS_DONE) { LOGF_WARN( "ConfigAgentParser: parser status was not good at %d ('%c') -> reset parser", i, buffer[i] ); config_parser_reset(parser); return length; } config_parser_read_byte(parser, buffer[i]); i++; if (parser->basedata->status == PARSER_STATUS_DONE) break; } return i; } enum ud3tn_result config_parser_reset(struct config_parser *parser) { if (parser->basedata->status == PARSER_STATUS_GOOD && parser->stage == RP_EXPECT_COMMAND_TYPE) return UD3TN_OK; else if (parser->basedata->status == PARSER_STATUS_ERROR) (void)parser; parser->basedata->status = PARSER_STATUS_GOOD; parser->basedata->flags = PARSER_FLAG_NONE; parser->stage = RP_EXPECT_COMMAND_TYPE; parser->current_eid = NULL; parser->current_contact = NULL; if (parser->router_command != NULL) { if (parser->router_command->data != NULL) free_node(parser->router_command->data); free(parser->router_command); parser->router_command = NULL; } if (parser->current_int_data != NULL) { free(parser->current_int_data); parser->current_int_data = NULL; } parser->router_command = malloc(sizeof(struct router_command)); if (parser->router_command == NULL) return UD3TN_FAIL; parser->router_command->type = ROUTER_COMMAND_UNDEFINED; parser->router_command->data = node_create(NULL); if (parser->router_command->data == NULL) return UD3TN_FAIL; return UD3TN_OK; } struct parser *config_parser_init(struct config_parser *parser) { parser->basedata = malloc(sizeof(struct parser)); if (parser->basedata == NULL) return NULL; parser->basedata->status = PARSER_STATUS_ERROR; parser->router_command = NULL; if (config_parser_reset(parser) != UD3TN_OK) return NULL; return parser->basedata; }