From c94c1f7fa5eb4a6f75563cb93fa7ce2763338945 Mon Sep 17 00:00:00 2001 From: Joseph Hickey Date: Thu, 31 Aug 2023 15:03:56 -0400 Subject: [PATCH 1/2] Fix #243, add ability to set CLA IP address in bpcat Adds command line options for local and remote CLA IP address and port numbers. --- app/bpcat.c | 228 +++++++++++++++++++++++++++++++++++++++------------- 1 file changed, 170 insertions(+), 58 deletions(-) diff --git a/app/bpcat.c b/app/bpcat.c index 52960fe9..59bedbac 100644 --- a/app/bpcat.c +++ b/app/bpcat.c @@ -34,6 +34,7 @@ #include #include #include +#include #include #include #include @@ -57,6 +58,11 @@ #define BPCAT_DATA_MESSAGE_MAX_SIZE (BPCAT_BUNDLE_BUFFER_SIZE - 520) #define BPCAT_RECV_WINDOW_SZ 32 +#define BPCAT_DEFAULT_LOCAL_NODENUM 100 +#define BPCAT_DEFAULT_REMOTE_NODENUM 101 +#define BPCAT_DEFAULT_SERVICENUM 1 +#define BPCAT_DEFAULT_UDP_PORT_BASE 36400 + /************************************************************************* * File Data *************************************************************************/ @@ -85,9 +91,15 @@ static bpcat_msg_recv_t recv_window[BPCAT_RECV_WINDOW_SZ]; static volatile sig_atomic_t app_running; -static const char ADDRESS_PREFIX[] = "ipn://"; -static char local_address_string[128] = "ipn://100.1"; -static char remote_address_string[128] = "ipn://101.1"; +static const char IPN_ADDRESS_PREFIX[] = "ipn://"; +static const char UDP_ADDRESS_PREFIX[] = "udp://"; + +#define ADDR_MAX_SIZE 128 + +static char local_dtnaddr_string[ADDR_MAX_SIZE]; +static char remote_dtnaddr_string[ADDR_MAX_SIZE]; +static char local_ipaddr_string[ADDR_MAX_SIZE]; +static char remote_ipaddr_string[ADDR_MAX_SIZE]; static long inter_bundle_delay = 20; @@ -126,6 +138,8 @@ static void display_banner(const char *prog_name) fprintf(stderr, " -r/--remote-addr=ipn://. remote address to use\n"); fprintf(stderr, " -i/--input-file= read input from given file instead of stdin\n"); fprintf(stderr, " -o/--output-file= write output to given file instead of stdout\n"); + fprintf(stderr, " --local-cla-uri=udp://: Bind local CLA to given IP:port \n"); + fprintf(stderr, " --remote-cla-uri=udp://: Send bundles to remote CLA at given IP:port\n"); fprintf(stderr, " -d/--delay= forced inter bundle send delay (20ms default)\n"); fprintf(stderr, "\n"); fprintf(stderr, " Creates a local BP agent with local IPN address as specified. All data\n"); @@ -138,39 +152,121 @@ static void display_banner(const char *prog_name) exit(-1); } -static void parse_address(const char *string_addr, bp_ipn_addr_t *parsed_addr) +static void parse_ipn_address(char *buffer, size_t buf_size, bp_ipn_addr_t *parsed_addr, uint32_t dfl_nodenum, + uint32_t dfl_svcnum) { - const char *start; - char *end; + char *start; + char *end; - if (strncmp(string_addr, ADDRESS_PREFIX, sizeof(ADDRESS_PREFIX) - 1) != 0) - { - fprintf(stderr, "IPN address string not well formed, must start with %s\n", ADDRESS_PREFIX); - abort(); - } + /* Start by setting defaults into the output struct */ + parsed_addr->node_number = dfl_nodenum; + parsed_addr->service_number = dfl_svcnum; - /* get node part */ - start = &string_addr[sizeof(ADDRESS_PREFIX) - 1]; - parsed_addr->node_number = strtoul(start, &end, 0); - if (end != NULL && *end == '.') + /* If the buffer is completely empty, then skip the rest - use all defaults */ + if (buffer != NULL && *buffer != 0) { - /* get service part */ - start = end + 1; - parsed_addr->service_number = strtoul(start, &end, 0); + if (strncmp(buffer, IPN_ADDRESS_PREFIX, sizeof(IPN_ADDRESS_PREFIX) - 1) != 0) + { + fprintf(stderr, "IPN address string not well formed, must start with %s\n", IPN_ADDRESS_PREFIX); + abort(); + } + + /* get node part */ + start = &buffer[sizeof(IPN_ADDRESS_PREFIX) - 1]; + + parsed_addr->node_number = strtoul(start, &end, 0); + if (end != NULL && *end == '.') + { + /* get service part */ + *end = 0; + start = end + 1; + + parsed_addr->service_number = strtoul(start, &end, 0); + } + else + { + parsed_addr->service_number = 0; + } + + if (end != NULL && *end != 0) + { + fprintf(stderr, "IPN address string not well formed, trailing data: %s\n", end); + abort(); + } } - else + + snprintf(buffer, buf_size, "%s%lu.%lu", IPN_ADDRESS_PREFIX, (unsigned long)parsed_addr->node_number, + (unsigned long)parsed_addr->service_number); +} + +static void parse_ip_address(char *buffer, size_t buf_size, struct sockaddr_in *parsed_addr, in_addr_t dfl_host, + in_port_t dfl_port) +{ + char *host_start; + char *port_start; + char *end; + long value; + + /* Start by setting defaults into the output struct */ + parsed_addr->sin_family = AF_INET; + parsed_addr->sin_port = htons(dfl_port); + parsed_addr->sin_addr.s_addr = htonl(dfl_host); + + /* If the buffer is completely empty, then skip the rest - use all defaults */ + if (buffer != NULL && *buffer != 0) { - parsed_addr->service_number = 0; + /* Otherwise this must be a UDP URI */ + if (strncmp(buffer, UDP_ADDRESS_PREFIX, sizeof(UDP_ADDRESS_PREFIX) - 1) != 0) + { + fprintf(stderr, "Error: Only UDP URIs are currently supported - must begin with %s\n", UDP_ADDRESS_PREFIX); + abort(); + } + + /* get node part */ + host_start = &buffer[sizeof(UDP_ADDRESS_PREFIX) - 1]; + port_start = strchr(host_start, ':'); + if (port_start != NULL) + { + *port_start = 0; + ++port_start; + + value = strtol(port_start, &end, 0); + if (value > 0 && value < 65536 && *end == 0) + { + /* overwrite default port with provided value */ + parsed_addr->sin_port = htons(value); + } + else + { + fprintf(stderr, "Error: Invalid UDP port number: %s\n", port_start); + abort(); + } + } + + /* For now, only dotted-decimal is accepted. In the future, this could do a DNS lookup. */ + if (!isdigit((unsigned char)*host_start)) + { + fprintf(stderr, "Error: IP address must be in dotted-decimal form: %s\n", host_start); + abort(); + } + + /* overwrite default host address with provided value */ + if (!inet_pton(parsed_addr->sin_family, host_start, &parsed_addr->sin_addr)) + { + fprintf(stderr, "Error: %s: %s\n", strerror(errno), host_start); + abort(); + } } - if (end != NULL && *end != 0) + strcpy(buffer, UDP_ADDRESS_PREFIX); + if (inet_ntop(parsed_addr->sin_family, &parsed_addr->sin_addr, &buffer[sizeof(UDP_ADDRESS_PREFIX) - 1], + buf_size - sizeof(UDP_ADDRESS_PREFIX)) == NULL) { - fprintf(stderr, "IPN address string not well formed, trailing data: %s\n", end); + fprintf(stderr, "Error: %s\n", strerror(errno)); abort(); } - fprintf(stderr, "Parsed address: %s%lu.%lu\n", ADDRESS_PREFIX, (unsigned long)parsed_addr->node_number, - (unsigned long)parsed_addr->service_number); + snprintf(&buffer[strlen(buffer)], buf_size - strlen(buffer), ":%u", (unsigned int)ntohs(parsed_addr->sin_port)); } void redirect_file(int fileno, const char *filename) @@ -210,7 +306,7 @@ static void parse_options(int argc, char *argv[]) /* * getopts parameter passing options string */ - static const char *opt_string = "l:r:i:o:d:?"; + static const char *opt_string = "l:r:i:o:12d:?"; /* * getopts_long long form argument table @@ -219,6 +315,8 @@ static void parse_options(int argc, char *argv[]) {"remote-addr", required_argument, NULL, 'r'}, {"input-file", required_argument, NULL, 'i'}, {"output-file", required_argument, NULL, 'o'}, + {"local-cla-uri", required_argument, NULL, 1000}, + {"remote-cla-uri", required_argument, NULL, 1001}, {"delay", required_argument, NULL, 'd'}, {"help", no_argument, NULL, '?'}, {NULL, no_argument, NULL, 0}}; @@ -231,15 +329,15 @@ static void parse_options(int argc, char *argv[]) env_str = getenv("BP_LOCAL_ADDRESS"); if (env_str != NULL) { - strncpy(local_address_string, env_str, sizeof(local_address_string) - 1); - local_address_string[sizeof(local_address_string) - 1] = 0; + strncpy(local_dtnaddr_string, env_str, sizeof(local_dtnaddr_string) - 1); + local_dtnaddr_string[sizeof(local_dtnaddr_string) - 1] = 0; } env_str = getenv("BP_REMOTE_ADDRESS"); if (env_str != NULL) { - strncpy(remote_address_string, env_str, sizeof(remote_address_string) - 1); - remote_address_string[sizeof(remote_address_string) - 1] = 0; + strncpy(remote_dtnaddr_string, env_str, sizeof(remote_dtnaddr_string) - 1); + remote_dtnaddr_string[sizeof(remote_dtnaddr_string) - 1] = 0; } do @@ -253,13 +351,13 @@ static void parse_options(int argc, char *argv[]) switch (opt) { case 'l': - strncpy(local_address_string, optarg, sizeof(local_address_string) - 1); - local_address_string[sizeof(local_address_string) - 1] = 0; + strncpy(local_dtnaddr_string, optarg, sizeof(local_dtnaddr_string) - 1); + local_dtnaddr_string[sizeof(local_dtnaddr_string) - 1] = 0; break; case 'r': - strncpy(remote_address_string, optarg, sizeof(remote_address_string) - 1); - remote_address_string[sizeof(remote_address_string) - 1] = 0; + strncpy(remote_dtnaddr_string, optarg, sizeof(remote_dtnaddr_string) - 1); + remote_dtnaddr_string[sizeof(remote_dtnaddr_string) - 1] = 0; break; case 'i': @@ -278,12 +376,21 @@ static void parse_options(int argc, char *argv[]) } break; + case 1000: + strncpy(local_ipaddr_string, optarg, sizeof(local_ipaddr_string) - 1); + local_ipaddr_string[sizeof(local_ipaddr_string) - 1] = 0; + break; + + case 1001: + strncpy(remote_ipaddr_string, optarg, sizeof(remote_ipaddr_string) - 1); + remote_ipaddr_string[sizeof(remote_ipaddr_string) - 1] = 0; + break; + default: display_banner(argv[0]); break; } - } - while (true); + } while (true); } #define join_thread(tsk) do_join_thread(#tsk, tsk##_task) @@ -451,10 +558,10 @@ static void *cla_out_entry(void *arg) return NULL; } -static int setup_cla(bplib_routetbl_t *rtbl, uint16_t local_port, uint16_t remote_port) +static int setup_cla(bplib_routetbl_t *rtbl, const struct sockaddr_in *local_cla_addr, + const struct sockaddr_in *remote_cla_addr) { static bplib_cla_intf_id_t cla_intf_id; /* static because its passed to pthread_create() */ - struct sockaddr_in addr; /* Create bplib CLA and default route */ cla_intf_id.rtbl = rtbl; @@ -485,20 +592,13 @@ static int setup_cla(bplib_routetbl_t *rtbl, uint16_t local_port, uint16_t remot return -1; } - memset(&addr, 0, sizeof(addr)); - addr.sin_family = AF_INET; - addr.sin_port = htons(local_port); - addr.sin_addr.s_addr = (in_addr_t)htonl(INADDR_LOOPBACK); - if (bind(cla_intf_id.sys_fd, (struct sockaddr *)&addr, sizeof(addr)) < 0) + if (bind(cla_intf_id.sys_fd, (const struct sockaddr *)local_cla_addr, sizeof(*local_cla_addr)) < 0) { perror("bind()"); return -1; } - addr.sin_family = AF_INET; - addr.sin_port = htons(remote_port); - addr.sin_addr.s_addr = (in_addr_t)htonl(INADDR_LOOPBACK); - if (connect(cla_intf_id.sys_fd, (struct sockaddr *)&addr, sizeof(addr)) < 0) + if (connect(cla_intf_id.sys_fd, (const struct sockaddr *)remote_cla_addr, sizeof(*remote_cla_addr)) < 0) { perror("connect()"); return -1; @@ -841,12 +941,14 @@ static int setup_connection(bplib_routetbl_t *rtbl, const bp_ipn_addr_t *local_a ******************************************************************************/ int main(int argc, char *argv[]) { - bplib_routetbl_t *rtbl; - bp_ipn_addr_t local_addr; - bp_ipn_addr_t remote_addr; - bp_ipn_addr_t storage_addr; - uint64_t stats_time; - uint64_t curr_time; + bplib_routetbl_t *rtbl; + bp_ipn_addr_t local_ipn_addr; + bp_ipn_addr_t remote_ipn_addr; + bp_ipn_addr_t storage_ipn_addr; + struct sockaddr_in local_cla_addr; + struct sockaddr_in remote_cla_addr; + uint64_t stats_time; + uint64_t curr_time; app_running = 1; signal(SIGINT, app_quick_exit); @@ -862,8 +964,18 @@ int main(int argc, char *argv[]) /* Process Command Line */ parse_options(argc, argv); - parse_address(local_address_string, &local_addr); - parse_address(remote_address_string, &remote_addr); + parse_ipn_address(local_dtnaddr_string, sizeof(local_dtnaddr_string), &local_ipn_addr, BPCAT_DEFAULT_LOCAL_NODENUM, + BPCAT_DEFAULT_SERVICENUM); + fprintf(stderr, "Local DTN address: %s\n", local_dtnaddr_string); + parse_ipn_address(remote_dtnaddr_string, sizeof(remote_dtnaddr_string), &remote_ipn_addr, + BPCAT_DEFAULT_LOCAL_NODENUM, BPCAT_DEFAULT_SERVICENUM); + fprintf(stderr, "Remote DTN address: %s\n", remote_dtnaddr_string); + parse_ip_address(local_ipaddr_string, sizeof(local_ipaddr_string), &local_cla_addr, INADDR_ANY, + local_ipn_addr.node_number + BPCAT_DEFAULT_UDP_PORT_BASE); + fprintf(stderr, "Local CLA URI: %s\n", local_ipaddr_string); + parse_ip_address(remote_ipaddr_string, sizeof(remote_ipaddr_string), &remote_cla_addr, INADDR_LOOPBACK, + remote_ipn_addr.node_number + BPCAT_DEFAULT_UDP_PORT_BASE); + fprintf(stderr, "Remote CLA URI: %s\n", remote_ipaddr_string); /* Test route table with 1MB of cache */ rtbl = bplib_route_alloc_table(10, 1 << 20); @@ -874,20 +986,20 @@ int main(int argc, char *argv[]) } /* this currently assumes service number 10 for storage, should be configurable */ - storage_addr = (bp_ipn_addr_t) {local_addr.node_number, 10}; - if (setup_storage(rtbl, &storage_addr) < 0) + storage_ipn_addr = (bp_ipn_addr_t) {local_ipn_addr.node_number, 10}; + if (setup_storage(rtbl, &storage_ipn_addr) < 0) { fprintf(stderr, "Failed setup_storage()... exiting\n"); return EXIT_FAILURE; } - if (setup_cla(rtbl, 36400 + local_addr.node_number, 36400 + remote_addr.node_number) < 0) + if (setup_cla(rtbl, &local_cla_addr, &remote_cla_addr) < 0) { fprintf(stderr, "Failed setup_cla()... exiting\n"); return EXIT_FAILURE; } - if (setup_connection(rtbl, &local_addr, &remote_addr) < 0) + if (setup_connection(rtbl, &local_ipn_addr, &remote_ipn_addr) < 0) { fprintf(stderr, "Failed setup_connection()... exiting\n"); return EXIT_FAILURE; From c7a6f95c52206ea2bfdf834cc9af141324f6d212 Mon Sep 17 00:00:00 2001 From: Joseph Hickey Date: Wed, 20 Sep 2023 11:16:25 -0400 Subject: [PATCH 2/2] Fix #247, use sendto rather than connect for remote IP Update bpcat to use "sendto" to transmit to the for the remote node, as opposed to connecting the socket. This permits return traffic to come from any IP+port, not isolated to the remote address that the socket was onnected to. --- app/bpcat.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/app/bpcat.c b/app/bpcat.c index 59bedbac..b3b852f4 100644 --- a/app/bpcat.c +++ b/app/bpcat.c @@ -72,6 +72,9 @@ typedef struct bplib_cla_intf_id bplib_routetbl_t *rtbl; bp_handle_t intf_id; int sys_fd; + + const struct sockaddr *remote_addr; + socklen_t remote_addr_len; } bplib_cla_intf_id_t; typedef struct bpcat_msg_content @@ -534,7 +537,7 @@ static void *cla_out_entry(void *arg) else { fprintf(stderr, "Call system send()... size=%zu\n", data_fill_sz); - status = send(cla->sys_fd, bundle_buffer, data_fill_sz, 0); + status = sendto(cla->sys_fd, bundle_buffer, data_fill_sz, 0, cla->remote_addr, cla->remote_addr_len); if (status == data_fill_sz) { data_fill_sz = 0; @@ -598,11 +601,8 @@ static int setup_cla(bplib_routetbl_t *rtbl, const struct sockaddr_in *local_cla return -1; } - if (connect(cla_intf_id.sys_fd, (const struct sockaddr *)remote_cla_addr, sizeof(*remote_cla_addr)) < 0) - { - perror("connect()"); - return -1; - } + cla_intf_id.remote_addr = (const struct sockaddr *)remote_cla_addr; + cla_intf_id.remote_addr_len = sizeof(*remote_cla_addr); /* Create CLA Threads, one for each direction */ /* This is currently necessary because they pend on different things */