diff options
Diffstat (limited to 'src/ipcpd/udp')
-rw-r--r-- | src/ipcpd/udp/CMakeLists.txt | 34 | ||||
-rw-r--r-- | src/ipcpd/udp/udp.c (renamed from src/ipcpd/udp/main.c) | 681 | ||||
-rw-r--r-- | src/ipcpd/udp/udp4.c | 42 | ||||
-rw-r--r-- | src/ipcpd/udp/udp6.c | 42 |
4 files changed, 464 insertions, 335 deletions
diff --git a/src/ipcpd/udp/CMakeLists.txt b/src/ipcpd/udp/CMakeLists.txt index f1a29ef6..27e32094 100644 --- a/src/ipcpd/udp/CMakeLists.txt +++ b/src/ipcpd/udp/CMakeLists.txt @@ -12,16 +12,25 @@ include_directories(${CURRENT_BINARY_PARENT_DIR}) include_directories(${CMAKE_SOURCE_DIR}/include) include_directories(${CMAKE_BINARY_DIR}/include) -set(IPCP_UDP_TARGET ipcpd-udp CACHE INTERNAL "") +set(IPCP_UDP4_TARGET ipcpd-udp4 CACHE INTERNAL "") +set(IPCP_UDP6_TARGET ipcpd-udp6 CACHE INTERNAL "") -set(UDP_SOURCES +set(UDP4_SOURCES # Add source files here - ${CMAKE_CURRENT_SOURCE_DIR}/main.c - ) + udp4.c +) -add_executable(ipcpd-udp ${UDP_SOURCES} ${IPCP_SOURCES}) +set(UDP6_SOURCES + # Add source files here + udp6.c +) + +add_executable(ipcpd-udp4 ${UDP4_SOURCES} ${IPCP_SOURCES}) +target_link_libraries(ipcpd-udp4 LINK_PUBLIC ouroboros-dev) + +add_executable(ipcpd-udp6 ${UDP6_SOURCES} ${IPCP_SOURCES}) +target_link_libraries(ipcpd-udp6 LINK_PUBLIC ouroboros-dev) -target_link_libraries(ipcpd-udp LINK_PUBLIC ouroboros-dev) # Find the nsupdate executable find_program(NSUPDATE_EXECUTABLE @@ -55,13 +64,18 @@ else () endif () set(IPCP_UDP_RD_THR 3 CACHE STRING - "Number of reader threads in UDP IPCP") + "Number of reader threads in UDP IPCPs") set(IPCP_UDP_WR_THR 3 CACHE STRING - "Number of writer threads in UDP IPCP") + "Number of writer threads in UDP IPCPs") +set(IPCP_UDP_MPL 5000 CACHE STRING + "Default maximum packet lifetime for the UDP IPCPs, in ms") include(AddCompileFlags) if (CMAKE_BUILD_TYPE MATCHES "Debug*") - add_compile_flags(ipcpd-udp -DCONFIG_OUROBOROS_DEBUG) + add_compile_flags(ipcpd-udp4 -DCONFIG_OUROBOROS_DEBUG) + add_compile_flags(ipcpd-udp6 -DCONFIG_OUROBOROS_DEBUG) endif () -install(TARGETS ipcpd-udp RUNTIME DESTINATION ${CMAKE_INSTALL_SBINDIR}) +install(TARGETS ipcpd-udp4 RUNTIME DESTINATION ${CMAKE_INSTALL_SBINDIR}) +install(TARGETS ipcpd-udp6 RUNTIME DESTINATION ${CMAKE_INSTALL_SBINDIR}) + diff --git a/src/ipcpd/udp/main.c b/src/ipcpd/udp/udp.c index 6a3fb24a..be8069a4 100644 --- a/src/ipcpd/udp/main.c +++ b/src/ipcpd/udp/udp.c @@ -1,5 +1,5 @@ /* - * Ouroboros - Copyright (C) 2016 - 2021 + * Ouroboros - Copyright (C) 2016 - 2024 * * IPC process over UDP * @@ -20,22 +20,14 @@ * Foundation, Inc., http://www.fsf.org/about/contact/. */ -#if defined(__linux__) || defined(__CYGWIN__) -#define _DEFAULT_SOURCE -#else -#define _POSIX_C_SOURCE 200112L -#endif - #include "config.h" -#define OUROBOROS_PREFIX "ipcpd/udp" - #include <ouroboros/bitmap.h> +#include <ouroboros/endian.h> #include <ouroboros/hash.h> #include <ouroboros/list.h> #include <ouroboros/utils.h> #include <ouroboros/dev.h> -#include <ouroboros/ipcp-dev.h> #include <ouroboros/fqueue.h> #include <ouroboros/errno.h> #include <ouroboros/logs.h> @@ -58,14 +50,12 @@ #define FLOW_REQ 1 #define FLOW_REPLY 2 -#define THIS_TYPE IPCP_UDP -#define IPCP_UDP_MAX_PACKET_SIZE 8980 #define OUR_HEADER_LEN sizeof(uint32_t) /* adds eid */ -#define IPCP_UDP_BUF_SIZE 8980 -#define IPCP_UDP_MSG_SIZE 8980 +#define IPCP_UDP_BUF_SIZE IPCP_UDP_MAX_PACKET_SIZE +#define IPCP_UDP_MSG_SIZE IPCP_UDP_MAX_PACKET_SIZE + #define DNS_TTL 86400 -#define FD_UPDATE_TIMEOUT 100 /* microseconds */ #define SADDR ((struct sockaddr *) &udp_data.s_saddr) #define SADDR_SIZE (sizeof(udp_data.s_saddr)) @@ -81,45 +71,42 @@ #define SENDTO_FLAGS 0 #endif -struct ipcp ipcpi; - /* Keep order for alignment. */ struct mgmt_msg { uint32_t eid; uint32_t s_eid; uint32_t d_eid; - uint8_t code; - int8_t response; - /* QoS parameters from spec */ - uint8_t availability; - uint8_t in_order; + int32_t response; uint64_t bandwidth; uint32_t delay; uint32_t loss; uint32_t ber; uint32_t max_gap; - uint16_t cypher_s; + uint32_t timeout; + uint8_t code; + /* QoS parameters from spec */ + uint8_t availability; + uint8_t in_order; } __attribute__((packed)); struct mgmt_frame { - struct list_head next; - struct sockaddr_in r_saddr; - uint8_t buf[MGMT_FRAME_BUF_SIZE]; - size_t len; + struct list_head next; + struct __SOCKADDR r_saddr; + uint8_t buf[MGMT_FRAME_BUF_SIZE]; + size_t len; }; /* UDP flow */ struct uf { - int d_eid; - struct sockaddr_in r_saddr; + int d_eid; + struct __SOCKADDR r_saddr; }; struct { struct shim_data * shim_data; - uint32_t dns_addr; - - struct sockaddr_in s_saddr; + struct __ADDR dns_addr; + struct __SOCKADDR s_saddr; int s_fd; fset_t * np1_flows; @@ -136,14 +123,26 @@ struct { struct list_head mgmt_frames; } udp_data; +static const char * __inet_ntop(const struct __ADDR * addr, + char * buf) +{ + return inet_ntop(__AF, addr, buf, __ADDRSTRLEN); +} + static int udp_data_init(void) { - int i; + int i; + pthread_condattr_t cattr; if (pthread_rwlock_init(&udp_data.flows_lock, NULL)) goto fail_rwlock_init; - if (pthread_cond_init(&udp_data.mgmt_cond, NULL)) + if (pthread_condattr_init(&cattr)) + goto fail_condattr; +#ifndef __APPLE__ + pthread_condattr_setclock(&cattr, PTHREAD_COND_CLOCK); +#endif + if (pthread_cond_init(&udp_data.mgmt_cond, &cattr)) goto fail_mgmt_cond; if (pthread_mutex_init(&udp_data.mgmt_lock, NULL)) @@ -160,9 +159,12 @@ static int udp_data_init(void) if (udp_data.shim_data == NULL) goto fail_data; + pthread_condattr_destroy(&cattr); + list_head_init(&udp_data.mgmt_frames); return 0; + fail_data: fset_destroy(udp_data.np1_flows); fail_fset: @@ -170,6 +172,8 @@ static int udp_data_init(void) fail_mgmt_lock: pthread_cond_destroy(&udp_data.mgmt_cond); fail_mgmt_cond: + pthread_condattr_destroy(&cattr); + fail_condattr: pthread_rwlock_destroy(&udp_data.flows_lock); fail_rwlock_init: return -1; @@ -186,22 +190,21 @@ static void udp_data_fini(void) pthread_mutex_destroy(&udp_data.mgmt_lock); } -static int ipcp_udp_port_alloc(const struct sockaddr_in * r_saddr, - uint32_t s_eid, - const uint8_t * dst, - qosspec_t qs, - const void * data, - size_t dlen) +static int udp_ipcp_port_alloc(const struct __SOCKADDR * r_saddr, + uint32_t s_eid, + const uint8_t * dst, + qosspec_t qs, + const buffer_t * data) { uint8_t * buf; struct mgmt_msg * msg; size_t len; - assert(dlen > 0 ? data != NULL : data == NULL); + assert(data->len > 0 ? data->data != NULL : data->data == NULL); len = sizeof(*msg) + ipcp_dir_hash_len(); - buf = malloc(len + dlen); + buf = malloc(len + data->len); if (buf == NULL) return -1; @@ -216,14 +219,17 @@ static int ipcp_udp_port_alloc(const struct sockaddr_in * r_saddr, msg->ber = hton32(qs.ber); msg->in_order = qs.in_order; msg->max_gap = hton32(qs.max_gap); - msg->cypher_s = hton16(qs.cypher_s); + msg->timeout = hton32(qs.timeout); memcpy(msg + 1, dst, ipcp_dir_hash_len()); - memcpy(buf + len, data, dlen); + if (data->len > 0) + memcpy(buf + len, data->data, data->len); - if (sendto(udp_data.s_fd, msg, len + dlen, + if (sendto(udp_data.s_fd, msg, len + data->len, SENDTO_FLAGS, (const struct sockaddr *) r_saddr, sizeof(*r_saddr)) < 0) { + log_err("Failed to send flow allocation request: %s.", + strerror(errno)); free(buf); return -1; } @@ -233,16 +239,15 @@ static int ipcp_udp_port_alloc(const struct sockaddr_in * r_saddr, return 0; } -static int ipcp_udp_port_alloc_resp(const struct sockaddr_in * r_saddr, - uint32_t s_eid, - uint32_t d_eid, - int8_t response, - const void * data, - size_t len) +static int udp_ipcp_port_alloc_resp(const struct __SOCKADDR * r_saddr, + uint32_t s_eid, + uint32_t d_eid, + int32_t response, + const buffer_t * data) { struct mgmt_msg * msg; - msg = malloc(sizeof(*msg) + len); + msg = malloc(sizeof(*msg) + data->len); if (msg == NULL) return -1; @@ -250,11 +255,12 @@ static int ipcp_udp_port_alloc_resp(const struct sockaddr_in * r_saddr, msg->code = FLOW_REPLY; msg->s_eid = hton32(s_eid); msg->d_eid = hton32(d_eid); - msg->response = response; + msg->response = hton32(response); - memcpy(msg + 1, data, len); + if (data->len > 0) + memcpy(msg + 1, data->data, data->len); - if (sendto(udp_data.s_fd, msg, sizeof(*msg) + len, + if (sendto(udp_data.s_fd, msg, sizeof(*msg) + data->len, SENDTO_FLAGS, (const struct sockaddr *) r_saddr, sizeof(*r_saddr)) < 0 ) { free(msg); @@ -266,37 +272,16 @@ static int ipcp_udp_port_alloc_resp(const struct sockaddr_in * r_saddr, return 0; } -static int ipcp_udp_port_req(struct sockaddr_in * c_saddr, - int d_eid, - const uint8_t * dst, - qosspec_t qs, - const void * data, - size_t len) +static int udp_ipcp_port_req(struct __SOCKADDR * c_saddr, + int d_eid, + const uint8_t * dst, + qosspec_t qs, + const buffer_t * data) { - struct timespec ts = {0, FD_UPDATE_TIMEOUT * 1000}; - struct timespec abstime; - int fd; - - clock_gettime(PTHREAD_COND_CLOCK, &abstime); + int fd; - pthread_mutex_lock(&ipcpi.alloc_lock); - - while (ipcpi.alloc_id != -1 && ipcp_get_state() == IPCP_OPERATIONAL) { - ts_add(&abstime, &ts, &abstime); - pthread_cond_timedwait(&ipcpi.alloc_cond, &ipcpi.alloc_lock, - &abstime); - } - - if (ipcp_get_state() != IPCP_OPERATIONAL) { - log_dbg("Won't allocate over non-operational IPCP."); - pthread_mutex_unlock(&ipcpi.alloc_lock); - return -1; - } - - /* reply to IRM */ - fd = ipcp_flow_req_arr(dst, ipcp_dir_hash_len(), qs, data, len); + fd = ipcp_wait_flow_req_arr(dst, qs, IPCP_UDP_MPL, data); if (fd < 0) { - pthread_mutex_unlock(&ipcpi.alloc_lock); log_err("Could not get new flow from IRMd."); return -1; } @@ -308,30 +293,32 @@ static int ipcp_udp_port_req(struct sockaddr_in * c_saddr, pthread_rwlock_unlock(&udp_data.flows_lock); - ipcpi.alloc_id = fd; - pthread_cond_broadcast(&ipcpi.alloc_cond); - - pthread_mutex_unlock(&ipcpi.alloc_lock); - log_dbg("Pending allocation request, fd %d, remote eid %d.", fd, d_eid); return 0; } -static int ipcp_udp_port_alloc_reply(const struct sockaddr_in * saddr, - uint32_t s_eid, - uint32_t d_eid, - int8_t response, - const void * data, - size_t len) +static int udp_ipcp_port_alloc_reply(const struct __SOCKADDR * saddr, + uint32_t s_eid, + uint32_t d_eid, + int32_t response, + const buffer_t * data) { + time_t mpl = IPCP_UDP_MPL; + pthread_rwlock_wrlock(&udp_data.flows_lock); if (memcmp(&udp_data.fd_to_uf[s_eid].r_saddr, saddr, sizeof(*saddr))) { + char ipstr[__ADDRSTRLEN]; pthread_rwlock_unlock(&udp_data.flows_lock); - log_warn("Flow allocation reply for %u from wrong source.", - s_eid); + #ifdef BUILD_IPCP_UDP4 + __inet_ntop(&saddr->sin_addr, ipstr); + #else + __inet_ntop(&saddr->sin6_addr, ipstr); + #endif + log_err("Flow allocation reply for %u from wrong source %s.", + s_eid, ipstr); return -1; } @@ -340,8 +327,8 @@ static int ipcp_udp_port_alloc_reply(const struct sockaddr_in * saddr, pthread_rwlock_unlock(&udp_data.flows_lock); - if (ipcp_flow_alloc_reply(s_eid, response, data, len) < 0) { - log_dbg("Failed to reply to flow allocation."); + if (ipcp_flow_alloc_reply(s_eid, response, mpl, data) < 0) { + log_err("Failed to reply to flow allocation."); return -1; } @@ -351,13 +338,14 @@ static int ipcp_udp_port_alloc_reply(const struct sockaddr_in * saddr, return 0; } -static int ipcp_udp_mgmt_frame(const uint8_t * buf, - size_t len, - struct sockaddr_in c_saddr) +static int udp_ipcp_mgmt_frame(struct __SOCKADDR c_saddr, + const uint8_t * buf, + size_t len) { struct mgmt_msg * msg; size_t msg_len; qosspec_t qs; + buffer_t data; msg = (struct mgmt_msg *) buf; @@ -367,6 +355,10 @@ static int ipcp_udp_mgmt_frame(const uint8_t * buf, assert(len >= msg_len); + data.len = len - msg_len; + data.data = (uint8_t *) buf + msg_len; + + qs.delay = ntoh32(msg->delay); qs.bandwidth = ntoh64(msg->bandwidth); qs.availability = msg->availability; @@ -374,28 +366,29 @@ static int ipcp_udp_mgmt_frame(const uint8_t * buf, qs.ber = ntoh32(msg->ber); qs.in_order = msg->in_order; qs.max_gap = ntoh32(msg->max_gap); - qs.cypher_s = ntoh16(msg->cypher_s); + qs.timeout = ntoh32(msg->timeout); - return ipcp_udp_port_req(&c_saddr, ntoh32(msg->s_eid), + return udp_ipcp_port_req(&c_saddr, ntoh32(msg->s_eid), (uint8_t *) (msg + 1), qs, - buf + msg_len, - len - msg_len); + &data); case FLOW_REPLY: assert(len >= sizeof(*msg)); - return ipcp_udp_port_alloc_reply(&c_saddr, + data.len = len - sizeof(*msg); + data.data = (uint8_t *) buf + sizeof(*msg); + + return udp_ipcp_port_alloc_reply(&c_saddr, ntoh32(msg->s_eid), ntoh32(msg->d_eid), - msg->response, - buf + sizeof(*msg), - len - sizeof(*msg)); + ntoh32(msg->response), + &data); default: log_err("Unknown message received %d.", msg->code); return -1; } } -static void * ipcp_udp_mgmt_handler(void * o) +static void * udp_ipcp_mgmt_handler(void * o) { (void) o; @@ -417,7 +410,7 @@ static void * ipcp_udp_mgmt_handler(void * o) pthread_mutex_unlock(&udp_data.mgmt_lock); - ipcp_udp_mgmt_frame(frame->buf, frame->len, frame->r_saddr); + udp_ipcp_mgmt_frame(frame->r_saddr, frame->buf, frame->len); free(frame); } @@ -427,7 +420,7 @@ static void * ipcp_udp_mgmt_handler(void * o) return (void *) 0; } -static void * ipcp_udp_packet_reader(void * o) +static void * udp_ipcp_packet_reader(void * o) { uint8_t buf[IPCP_UDP_MAX_PACKET_SIZE]; uint8_t * data; @@ -437,13 +430,17 @@ static void * ipcp_udp_packet_reader(void * o) (void) o; + ipcp_lock_to_core(); + data = buf + sizeof(uint32_t); eid_p = (uint32_t *) buf; while (true) { - struct mgmt_frame * frame; - struct sockaddr_in r_saddr; - socklen_t len; + struct mgmt_frame * frame; + struct __SOCKADDR r_saddr; + socklen_t len; + struct shm_du_buff * sdb; + uint8_t * head; len = sizeof(r_saddr); @@ -484,10 +481,18 @@ static void * ipcp_udp_packet_reader(void * o) continue; } - flow_write(eid, data, n - sizeof(eid)); + n-= sizeof(eid); + + if (ipcp_sdb_reserve(&sdb, n)) + continue; + + head = shm_du_buff_head(sdb); + memcpy(head, data, n); + if (np1_flow_write(eid, sdb) < 0) + ipcp_sdb_release(sdb); } - return 0; + return (void *) 0; } static void cleanup_fqueue(void * fq) @@ -500,7 +505,7 @@ static void cleanup_sdb(void * sdb) ipcp_sdb_release((struct shm_du_buff *) sdb); } -static void * ipcp_udp_packet_writer(void * o) +static void * udp_ipcp_packet_writer(void * o) { fqueue_t * fq; @@ -515,9 +520,9 @@ static void * ipcp_udp_packet_writer(void * o) pthread_cleanup_push(cleanup_fqueue, fq); while (true) { - struct sockaddr_in saddr; - int eid; - int fd; + struct __SOCKADDR saddr; + int eid; + int fd; fevent(udp_data.np1_flows, fq, NULL); while ((fd = fqueue_next(fq)) >= 0) { struct shm_du_buff * sdb; @@ -527,12 +532,12 @@ static void * ipcp_udp_packet_writer(void * o) if (fqueue_type(fq) != FLOW_PKT) continue; - if (ipcp_flow_read(fd, &sdb)) { + if (np1_flow_read(fd, &sdb)) { log_dbg("Bad read from fd %d.", fd); continue; } - len = shm_du_buff_tail(sdb) - shm_du_buff_head(sdb); + len = shm_du_buff_len(sdb); if (len > IPCP_UDP_MAX_PACKET_SIZE) { log_dbg("Packet length exceeds MTU."); ipcp_sdb_release(sdb); @@ -572,103 +577,115 @@ static void * ipcp_udp_packet_writer(void * o) return (void *) 1; } -static int ipcp_udp_bootstrap(const struct ipcp_config * conf) +static bool is_addr_specified(const struct __ADDR * addr) +{ +#ifdef BUILD_IPCP_UDP4 + return addr->s_addr != 0; +#else + return !IN6_IS_ADDR_UNSPECIFIED(addr); +#endif +} + +static int udp_ipcp_bootstrap(struct ipcp_config * conf) { - char ipstr[INET_ADDRSTRLEN]; - char dnsstr[INET_ADDRSTRLEN]; - char portstr[128]; /* port is max 64535 = 5 chars */ + char ipstr[__ADDRSTRLEN]; + char dnsstr[__ADDRSTRLEN]; int i = 1; +#ifdef BUILD_IPCP_UDP4 + struct udp4_config * udp; + udp = &conf->udp4; +#else + struct udp6_config * udp; + udp = &conf->udp6; +#endif - assert(conf); + assert(conf != NULL); assert(conf->type == THIS_TYPE); + assert(conf->layer_info.dir_hash_algo == (enum pol_dir_hash) HASH_MD5); - ipcpi.dir_hash_algo = conf->layer_info.dir_hash_algo; - ipcpi.layer_name = strdup(conf->layer_info.layer_name); - if (ipcpi.layer_name == NULL) { - log_err("Failed to set layer name"); - return -ENOMEM; - } - - if (inet_ntop(AF_INET, &conf->ip_addr, ipstr, INET_ADDRSTRLEN) - == NULL) { - log_err("Failed to convert IP address"); + if (__inet_ntop(&udp->ip_addr, ipstr) == NULL) { + log_err("Failed to convert IP address."); return -1; } - if (conf->dns_addr != 0) { - if (inet_ntop(AF_INET, &conf->dns_addr, dnsstr, INET_ADDRSTRLEN) - == NULL) { - log_err("Failed to convert DNS address"); + if (is_addr_specified(&udp->dns_addr)) { + if (__inet_ntop(&udp->dns_addr, dnsstr) == NULL) { + log_err("Failed to convert DNS address."); return -1; } #ifndef HAVE_DDNS - log_warn("DNS disabled at compile time, address ignored"); + log_warn("DNS disabled at compile time, address ignored."); #endif } else { strcpy(dnsstr, "not set"); } /* UDP listen server */ - udp_data.s_fd = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP); + udp_data.s_fd = socket(__AF, SOCK_DGRAM, IPPROTO_UDP); if (udp_data.s_fd < 0) { log_err("Can't create socket: %s", strerror(errno)); goto fail_socket; } memset((char *) &udp_data.s_saddr, 0, sizeof(udp_data.s_saddr)); - udp_data.s_saddr.sin_family = AF_INET; - udp_data.s_saddr.sin_addr.s_addr = conf->ip_addr; - udp_data.s_saddr.sin_port = htons(conf->port); - +#ifdef BUILD_IPCP_UDP4 + udp_data.s_saddr.sin_family = AF_INET; + udp_data.s_saddr.sin_addr = udp->ip_addr; + udp_data.s_saddr.sin_port = htons(udp->port); +#else + udp_data.s_saddr.sin6_family = AF_INET6; + udp_data.s_saddr.sin6_addr = udp->ip_addr; + udp_data.s_saddr.sin6_port = htons(udp->port); +#endif if (bind(udp_data.s_fd, SADDR, SADDR_SIZE) < 0) { - log_err("Couldn't bind to %s.", ipstr); + log_err("Couldn't bind to %s:%d. %s.", + ipstr, udp->port, strerror(errno)); goto fail_bind; } - udp_data.dns_addr = conf->dns_addr; - - ipcp_set_state(IPCP_OPERATIONAL); + udp_data.dns_addr = udp->dns_addr; if (pthread_create(&udp_data.mgmt_handler, NULL, - ipcp_udp_mgmt_handler, NULL)) { - ipcp_set_state(IPCP_INIT); + udp_ipcp_mgmt_handler, NULL)) { + log_err("Failed to create management thread."); goto fail_bind; } for (i = 0; i < IPCP_UDP_RD_THR; ++i) { if (pthread_create(&udp_data.packet_reader[i], NULL, - ipcp_udp_packet_reader, NULL)) { - ipcp_set_state(IPCP_INIT); + udp_ipcp_packet_reader, NULL)) { + log_err("Failed to create reader thread."); goto fail_packet_reader; } } for (i = 0; i < IPCP_UDP_WR_THR; ++i) { if (pthread_create(&udp_data.packet_writer[i], NULL, - ipcp_udp_packet_writer, NULL)) { - ipcp_set_state(IPCP_INIT); + udp_ipcp_packet_writer, NULL)) { + log_err("Failed to create writer thread."); goto fail_packet_writer; } } - sprintf(portstr, "%d", conf->port); - - log_dbg("Bootstrapped IPCP over UDP with pid %d.", getpid()); + log_dbg("Bootstrapped " TYPE_STR " with pid %d.", getpid()); log_dbg("Bound to IP address %s.", ipstr); - log_dbg("Using port %u.", conf->port); - log_dbg("DNS server address is %s.", dnsstr); + log_dbg("Using port %u.", udp->port); + if (is_addr_specified(&udp_data.dns_addr)) + log_dbg("DNS server address is %s.", dnsstr); + else + log_dbg("DNS server not in use."); return 0; fail_packet_writer: - while (i > 0) { - pthread_cancel(udp_data.packet_writer[--i]); + while (i-- > 0) { + pthread_cancel(udp_data.packet_writer[i]); pthread_join(udp_data.packet_writer[i], NULL); } i = IPCP_UDP_RD_THR; fail_packet_reader: - while (i > 0) { - pthread_cancel(udp_data.packet_reader[--i]); + while (i-- > 0) { + pthread_cancel(udp_data.packet_reader[i]); pthread_join(udp_data.packet_reader[i], NULL); } pthread_cancel(udp_data.mgmt_handler); @@ -684,20 +701,22 @@ static int ipcp_udp_bootstrap(const struct ipcp_config * conf) /* NOTE: Disgusted with this crap */ static int ddns_send(char * cmd) { - pid_t pid = -1; + pid_t pid; int wstatus; int pipe_fd[2]; char * argv[] = {NSUPDATE_EXEC, 0}; char * envp[] = {0}; if (pipe(pipe_fd)) { - log_err("Failed to create pipe."); + log_err("Failed to create pipe: %s.", strerror(errno)); return -1; } pid = fork(); if (pid == -1) { - log_err("Failed to fork."); + log_err("Failed to fork: %s.", strerror(errno)); + close(pipe_fd[0]); + close(pipe_fd[1]); return -1; } @@ -705,12 +724,15 @@ static int ddns_send(char * cmd) close(pipe_fd[1]); dup2(pipe_fd[0], 0); execve(argv[0], &argv[0], envp); + log_err("Failed to execute: %s", strerror(errno)); + exit(1); } close(pipe_fd[0]); if (write(pipe_fd[1], cmd, strlen(cmd)) == -1) { - log_err("Failed to communicate with nsupdate."); + log_err("Failed to communicate with nsupdate: %s.", + strerror(errno)); close(pipe_fd[1]); return -1; } @@ -726,32 +748,34 @@ static int ddns_send(char * cmd) return 0; } -static uint32_t ddns_resolve(char * name, - uint32_t dns_addr) +static struct __ADDR ddns_resolve(char * name, + struct __ADDR dns_addr) { - pid_t pid = -1; - int wstatus; - int pipe_fd[2]; - char dnsstr[INET_ADDRSTRLEN]; - char buf[IPCP_UDP_BUF_SIZE]; - ssize_t count = 0; - char * substr = NULL; - char * substr2 = NULL; - char * addr_str = "Address:"; - uint32_t ip_addr = 0; - - if (inet_ntop(AF_INET, &dns_addr, dnsstr, INET_ADDRSTRLEN) == NULL) - return 0; + pid_t pid = -1; + int wstatus; + int pipe_fd[2]; + char dnsstr[__ADDRSTRLEN]; + char buf[IPCP_UDP_BUF_SIZE]; + ssize_t count = 0; + char * substr = NULL; + char * substr2 = NULL; + char * addr_str = "Address:"; + struct __ADDR ip_addr = __ADDR_ANY_INIT; + + if (__inet_ntop(&dns_addr, dnsstr) == NULL) + return ip_addr; if (pipe(pipe_fd)) { - log_err("Failed to create pipe."); - return 0; + log_err("Failed to create pipe: %s.", strerror(errno)); + return ip_addr; } pid = fork(); if (pid == -1) { - log_err("Failed to fork."); - return 0; + log_err("Failed to fork: %s.", strerror(errno)); + close(pipe_fd[0]); + close(pipe_fd[1]); + return ip_addr; } if (pid == 0) { @@ -761,22 +785,24 @@ static uint32_t ddns_resolve(char * name, close(pipe_fd[0]); dup2(pipe_fd[1], 1); execve(argv[0], &argv[0], envp); + log_err("Failed to execute: %s", strerror(errno)); + exit(1); } close(pipe_fd[1]); - count = read(pipe_fd[0], buf, IPCP_UDP_BUF_SIZE); + count = read(pipe_fd[0], buf, IPCP_UDP_BUF_SIZE - 1); if (count <= 0) { log_err("Failed to communicate with nslookup."); close(pipe_fd[0]); - return 0; + return ip_addr; } close(pipe_fd[0]); waitpid(pid, &wstatus, 0); if (WIFEXITED(wstatus) && WEXITSTATUS(wstatus) == 0 && - count != IPCP_UDP_BUF_SIZE) + count != IPCP_UDP_BUF_SIZE - 1) log_dbg("Succesfully communicated with nslookup."); else log_err("Failed to resolve DNS address."); @@ -790,40 +816,43 @@ static uint32_t ddns_resolve(char * name, if (substr2 == NULL || strstr(substr2, addr_str) == NULL) { log_err("Failed to resolve DNS address."); - return 0; + return ip_addr; } - if (inet_pton(AF_INET, substr2 + strlen(addr_str) + 1, &ip_addr) != 1) { + if (inet_pton(__AF, substr2 + strlen(addr_str) + 1, &ip_addr) != 1) { log_err("Failed to resolve DNS address."); - return 0; + assert(!is_addr_specified(&ip_addr)); + return ip_addr; } return ip_addr; } #endif -static int ipcp_udp_reg(const uint8_t * hash) +static int udp_ipcp_reg(const uint8_t * hash) { #ifdef HAVE_DDNS - char ipstr[INET_ADDRSTRLEN]; - char dnsstr[INET_ADDRSTRLEN]; - char cmd[1000]; - uint32_t dns_addr; - uint32_t ip_addr; + char ipstr[__ADDRSTRLEN]; + char dnsstr[__ADDRSTRLEN]; + char cmd[1000]; + struct __ADDR dns_addr; + struct __ADDR ip_addr; #endif char * hashstr; hashstr = malloc(ipcp_dir_hash_strlen() + 1); - if (hashstr == NULL) + if (hashstr == NULL) { + log_err("Failed to malloc hashstr."); return -1; + } assert(hash); ipcp_hash_str(hashstr, hash); if (shim_data_reg_add_entry(udp_data.shim_data, hash)) { - log_err("Failed to add " HASH_FMT " to local registry.", - HASH_VAL(hash)); + log_err("Failed to add " HASH_FMT32 " to local registry.", + HASH_VAL32(hash)); free(hashstr); return -1; } @@ -833,17 +862,20 @@ static int ipcp_udp_reg(const uint8_t * hash) dns_addr = udp_data.dns_addr; - if (dns_addr != 0) { - ip_addr = udp_data.s_saddr.sin_addr.s_addr; - - if (inet_ntop(AF_INET, &ip_addr, - ipstr, INET_ADDRSTRLEN) == NULL) { + if (is_addr_specified(&dns_addr)) { +#ifdef BUILD_IPCP_UDP4 + ip_addr = udp_data.s_saddr.sin_addr; +#else + ip_addr = udp_data.s_saddr.sin6_addr; +#endif + if (__inet_ntop(&ip_addr, ipstr) == NULL) { + log_err("Failed to convert IP address to string."); free(hashstr); return -1; } - if (inet_ntop(AF_INET, &dns_addr, - dnsstr, INET_ADDRSTRLEN) == NULL) { + if (__inet_ntop(&dns_addr, dnsstr) == NULL) { + log_err("Failed to convert DNS address to string."); free(hashstr); return -1; } @@ -852,34 +884,35 @@ static int ipcp_udp_reg(const uint8_t * hash) dnsstr, hashstr, DNS_TTL, ipstr); if (ddns_send(cmd)) { + log_err("Failed to send DDNS message."); shim_data_reg_del_entry(udp_data.shim_data, hash); free(hashstr); return -1; } } #endif - log_dbg("Registered " HASH_FMT ".", HASH_VAL(hash)); - free(hashstr); return 0; } -static int ipcp_udp_unreg(const uint8_t * hash) +static int udp_ipcp_unreg(const uint8_t * hash) { #ifdef HAVE_DDNS - char dnsstr[INET_ADDRSTRLEN]; + char dnsstr[__ADDRSTRLEN]; /* max DNS name length + max IP length + max command length */ - char cmd[100]; - uint32_t dns_addr; + char cmd[100]; + struct __ADDR dns_addr; #endif - char * hashstr; + char * hashstr; assert(hash); hashstr = malloc(ipcp_dir_hash_strlen() + 1); - if (hashstr == NULL) + if (hashstr == NULL) { + log_err("Failed to malloc hashstr."); return -1; + } ipcp_hash_str(hashstr, hash); @@ -888,9 +921,9 @@ static int ipcp_udp_unreg(const uint8_t * hash) dns_addr = udp_data.dns_addr; - if (dns_addr != 0) { - if (inet_ntop(AF_INET, &dns_addr, dnsstr, INET_ADDRSTRLEN) - == NULL) { + if (is_addr_specified(&dns_addr)) { + if (__inet_ntop(&dns_addr, dnsstr) == NULL) { + log_err("Failed to convert DNS address to string."); free(hashstr); return -1; } @@ -903,26 +936,28 @@ static int ipcp_udp_unreg(const uint8_t * hash) shim_data_reg_del_entry(udp_data.shim_data, hash); - log_dbg("Unregistered " HASH_FMT ".", HASH_VAL(hash)); - free(hashstr); return 0; } -static int ipcp_udp_query(const uint8_t * hash) +static int udp_ipcp_query(const uint8_t * hash) { - uint32_t ip_addr = 0; - char * hashstr; - struct hostent * h; + struct addr addr = {}; + char * hashstr; + struct addrinfo hints; + struct addrinfo * ai; #ifdef HAVE_DDNS - uint32_t dns_addr = 0; + struct __ADDR dns_addr = __ADDR_ANY_INIT; + struct __ADDR ip_addr = __ADDR_ANY_INIT; #endif assert(hash); hashstr = malloc(ipcp_dir_hash_strlen() + 1); - if (hashstr == NULL) + if (hashstr == NULL) { + log_err("Failed to malloc hashstr."); return -ENOMEM; + } ipcp_hash_str(hashstr, hash); @@ -934,28 +969,42 @@ static int ipcp_udp_query(const uint8_t * hash) #ifdef HAVE_DDNS dns_addr = udp_data.dns_addr; - if (dns_addr != 0) { + if (is_addr_specified(&dns_addr)) { ip_addr = ddns_resolve(hashstr, dns_addr); - if (ip_addr == 0) { - log_dbg("Could not resolve %s.", hashstr); + if (!is_addr_specified(&ip_addr)) { + log_err("Could not resolve %s.", hashstr); free(hashstr); return -1; } } else { #endif - h = gethostbyname(hashstr); - if (h == NULL) { - log_dbg("Could not resolve %s.", hashstr); + memset(&hints, 0, sizeof(hints)); + + hints.ai_family = __AF; + if (getaddrinfo(hashstr, NULL, &hints, &ai) != 0) { + log_err("Could not resolve %s: %s.", hashstr, + gai_strerror(errno)); + free(hashstr); + return -1; + } + + if (ai->ai_family != __AF) { + log_err("Wrong addres family for %s.", hashstr); + freeaddrinfo(ai); free(hashstr); return -1; } - ip_addr = *((uint32_t *) (h->h_addr_list[0])); + #ifdef BUILD_IPCP_UDP4 + addr.ip4 = ((struct sockaddr_in *) (ai->ai_addr))->sin_addr; + #else + addr.ip6 = ((struct sockaddr_in6 *) (ai->ai_addr))->sin6_addr; + #endif + freeaddrinfo(ai); #ifdef HAVE_DDNS } #endif - - if (shim_data_dir_add_entry(udp_data.shim_data, hash, ip_addr)) { + if (shim_data_dir_add_entry(udp_data.shim_data, hash, addr)) { log_err("Failed to add directory entry."); free(hashstr); return -1; @@ -966,38 +1015,51 @@ static int ipcp_udp_query(const uint8_t * hash) return 0; } -static int ipcp_udp_flow_alloc(int fd, - const uint8_t * dst, - qosspec_t qs, - const void * data, - size_t len) +static int udp_ipcp_flow_alloc(int fd, + const uint8_t * dst, + qosspec_t qs, + const buffer_t * data) { - struct sockaddr_in r_saddr; /* Server address */ - uint32_t ip_addr = 0; - char ipstr[INET_ADDRSTRLEN]; - - log_dbg("Allocating flow to " HASH_FMT ".", HASH_VAL(dst)); + struct __SOCKADDR r_saddr; /* Server address */ + struct __ADDR ip_addr; + struct addr addr; + char ipstr[__ADDRSTRLEN]; (void) qs; assert(dst); if (!shim_data_dir_has(udp_data.shim_data, dst)) { - log_dbg("Could not resolve destination."); + log_err("Could not resolve destination."); return -1; } - ip_addr = (uint32_t) shim_data_dir_get_addr(udp_data.shim_data, dst); + addr = shim_data_dir_get_addr(udp_data.shim_data, dst); +#ifdef BUILD_IPCP_UDP4 + ip_addr = addr.ip4; +#else + ip_addr = addr.ip6; +#endif + if (__inet_ntop(&ip_addr, ipstr) == NULL) { + log_err("Could not convert IP address."); + return -1; + } - inet_ntop(AF_INET, &ip_addr, ipstr, INET_ADDRSTRLEN); - log_dbg("Destination UDP ipcp resolved at %s.", ipstr); + log_dbg("Destination " HASH_FMT32 " resolved at IP %s.", + HASH_VAL32(dst), ipstr); memset((char *) &r_saddr, 0, sizeof(r_saddr)); - r_saddr.sin_family = AF_INET; - r_saddr.sin_addr.s_addr = ip_addr; - r_saddr.sin_port = udp_data.s_saddr.sin_port; +#ifdef BUILD_IPCP_UDP4 + r_saddr.sin_family = AF_INET; + r_saddr.sin_addr = addr.ip4; + r_saddr.sin_port = udp_data.s_saddr.sin_port; +#else + r_saddr.sin6_family = AF_INET6; + r_saddr.sin6_addr = addr.ip6; + r_saddr.sin6_port = udp_data.s_saddr.sin6_port; +#endif - if (ipcp_udp_port_alloc(&r_saddr, fd, dst, qs, data, len) < 0) { + if (udp_ipcp_port_alloc(&r_saddr, fd, dst, qs, data) < 0) { log_err("Could not allocate port."); return -1; } @@ -1011,45 +1073,21 @@ static int ipcp_udp_flow_alloc(int fd, fset_add(udp_data.np1_flows, fd); - log_dbg("Flow to %s pending on fd %d.", ipstr, fd); - return 0; } -static int ipcp_udp_flow_alloc_resp(int fd, - int resp, - const void * data, - size_t len) +static int udp_ipcp_flow_alloc_resp(int fd, + int resp, + const buffer_t * data) { - struct timespec ts = {0, FD_UPDATE_TIMEOUT * 1000}; - struct timespec abstime; - struct sockaddr_in saddr; - int d_eid; - - if (resp) - return 0; - - clock_gettime(PTHREAD_COND_CLOCK, &abstime); + struct __SOCKADDR saddr; + int d_eid; - pthread_mutex_lock(&ipcpi.alloc_lock); - - while (ipcpi.alloc_id != fd && ipcp_get_state() == IPCP_OPERATIONAL) { - ts_add(&abstime, &ts, &abstime); - pthread_cond_timedwait(&ipcpi.alloc_cond, - &ipcpi.alloc_lock, - &abstime); - } - - if (ipcp_get_state() != IPCP_OPERATIONAL) { - pthread_mutex_unlock(&ipcpi.alloc_lock); + if (ipcp_wait_flow_resp(fd) < 0) { + log_err("Failed to wait for flow response."); return -1; } - ipcpi.alloc_id = -1; - pthread_cond_broadcast(&ipcpi.alloc_cond); - - pthread_mutex_unlock(&ipcpi.alloc_lock); - pthread_rwlock_rdlock(&udp_data.flows_lock); saddr = udp_data.fd_to_uf[fd].r_saddr; @@ -1057,7 +1095,7 @@ static int ipcp_udp_flow_alloc_resp(int fd, pthread_rwlock_unlock(&udp_data.flows_lock); - if (ipcp_udp_port_alloc_resp(&saddr, d_eid, fd, resp, data, len) < 0) { + if (udp_ipcp_port_alloc_resp(&saddr, d_eid, fd, resp, data) < 0) { fset_del(udp_data.np1_flows, fd); log_err("Failed to respond to flow request."); return -1; @@ -1065,13 +1103,10 @@ static int ipcp_udp_flow_alloc_resp(int fd, fset_add(udp_data.np1_flows, fd); - log_dbg("Accepted flow, fd %d on eid %d.", - fd, d_eid); - return 0; } -static int ipcp_udp_flow_dealloc(int fd) +static int udp_ipcp_flow_dealloc(int fd) { ipcp_flow_fini(fd); @@ -1084,25 +1119,23 @@ static int ipcp_udp_flow_dealloc(int fd) pthread_rwlock_unlock(&udp_data.flows_lock); - flow_dealloc(fd); - - log_dbg("Flow with fd %d deallocated.", fd); + ipcp_flow_dealloc(fd); return 0; } static struct ipcp_ops udp_ops = { - .ipcp_bootstrap = ipcp_udp_bootstrap, + .ipcp_bootstrap = udp_ipcp_bootstrap, .ipcp_enroll = NULL, .ipcp_connect = NULL, .ipcp_disconnect = NULL, - .ipcp_reg = ipcp_udp_reg, - .ipcp_unreg = ipcp_udp_unreg, - .ipcp_query = ipcp_udp_query, - .ipcp_flow_alloc = ipcp_udp_flow_alloc, + .ipcp_reg = udp_ipcp_reg, + .ipcp_unreg = udp_ipcp_unreg, + .ipcp_query = udp_ipcp_query, + .ipcp_flow_alloc = udp_ipcp_flow_alloc, .ipcp_flow_join = NULL, - .ipcp_flow_alloc_resp = ipcp_udp_flow_alloc_resp, - .ipcp_flow_dealloc = ipcp_udp_flow_dealloc + .ipcp_flow_alloc_resp = udp_ipcp_flow_alloc_resp, + .ipcp_flow_dealloc = udp_ipcp_flow_dealloc }; int main(int argc, @@ -1110,53 +1143,51 @@ int main(int argc, { int i; - if (ipcp_init(argc, argv, &udp_ops, THIS_TYPE) < 0) - goto fail_init; if (udp_data_init() < 0) { log_err("Failed to init udp data."); goto fail_data_init; } - if (ipcp_boot() < 0) { - log_err("Failed to boot IPCP."); - goto fail_boot; + if (ipcp_init(argc, argv, &udp_ops, THIS_TYPE) < 0) { + log_err("Failed to initialize IPCP."); + goto fail_init; } - if (ipcp_create_r(0)) { - log_err("Failed to notify IRMd we are initialized."); - goto fail_create_r; + if (ipcp_start() < 0) { + log_err("Failed to start IPCP."); + goto fail_start; } - ipcp_shutdown(); + ipcp_sigwait(); if (ipcp_get_state() == IPCP_SHUTDOWN) { - for (i = 0; i < IPCP_UDP_RD_THR; ++i) - pthread_cancel(udp_data.packet_reader[i]); for (i = 0; i < IPCP_UDP_WR_THR; ++i) pthread_cancel(udp_data.packet_writer[i]); + for (i = 0; i < IPCP_UDP_RD_THR; ++i) + pthread_cancel(udp_data.packet_reader[i]); pthread_cancel(udp_data.mgmt_handler); - for (i = 0; i < IPCP_UDP_RD_THR; ++i) - pthread_join(udp_data.packet_reader[i], NULL); for (i = 0; i < IPCP_UDP_WR_THR; ++i) pthread_join(udp_data.packet_writer[i], NULL); + for (i = 0; i < IPCP_UDP_RD_THR; ++i) + pthread_join(udp_data.packet_reader[i], NULL); pthread_join(udp_data.mgmt_handler, NULL); + close(udp_data.s_fd); } - udp_data_fini(); + ipcp_stop(); ipcp_fini(); - exit(EXIT_SUCCESS); - fail_create_r: - ipcp_set_state(IPCP_NULL); - ipcp_shutdown(); - fail_boot: udp_data_fini(); - fail_data_init: + + exit(EXIT_SUCCESS); + + fail_start: ipcp_fini(); fail_init: - ipcp_create_r(-1); + udp_data_fini(); + fail_data_init: exit(EXIT_FAILURE); } diff --git a/src/ipcpd/udp/udp4.c b/src/ipcpd/udp/udp4.c new file mode 100644 index 00000000..07d5f818 --- /dev/null +++ b/src/ipcpd/udp/udp4.c @@ -0,0 +1,42 @@ +/* + * Ouroboros - Copyright (C) 2016 - 2024 + * + * IPC process over UDP/IPv4 + * + * Dimitri Staessens <dimitri@ouroboros.rocks> + * Sander Vrijders <sander@ouroboros.rocks> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., http://www.fsf.org/about/contact/. + */ + +#if defined(__linux__) || defined(__CYGWIN__) +#define _DEFAULT_SOURCE +#else +#define _POSIX_C_SOURCE 200112L +#endif + +#include <ouroboros/ipcp-dev.h> + +#define BUILD_IPCP_UDP4 +#define THIS_TYPE IPCP_UDP4 +#define TYPE_STR "IPCP over UDP/IPv4" +#define OUROBOROS_PREFIX "ipcpd/udp4" +#define IPCP_UDP_MAX_PACKET_SIZE 8980 +#define __AF AF_INET +#define __ADDRSTRLEN INET_ADDRSTRLEN +#define __SOCKADDR sockaddr_in +#define __ADDR in_addr +#define __ADDR_ANY_INIT { .s_addr = INADDR_ANY } + +#include "udp.c" diff --git a/src/ipcpd/udp/udp6.c b/src/ipcpd/udp/udp6.c new file mode 100644 index 00000000..b7924a3f --- /dev/null +++ b/src/ipcpd/udp/udp6.c @@ -0,0 +1,42 @@ +/* + * Ouroboros - Copyright (C) 2016 - 2024 + * + * IPC process over UDP/IPv6 + * + * Dimitri Staessens <dimitri@ouroboros.rocks> + * Sander Vrijders <sander@ouroboros.rocks> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., http://www.fsf.org/about/contact/. + */ + +#if defined(__linux__) || defined(__CYGWIN__) +#define _DEFAULT_SOURCE +#else +#define _POSIX_C_SOURCE 200112L +#endif + +#include <ouroboros/ipcp-dev.h> + +#define BUILD_IPCP_UDP6 +#define THIS_TYPE IPCP_UDP6 +#define TYPE_STR "IPCP over UDP/IPv6" +#define OUROBOROS_PREFIX "ipcpd/udp6" +#define IPCP_UDP_MAX_PACKET_SIZE 8952 +#define __AF AF_INET6 +#define __ADDRSTRLEN INET6_ADDRSTRLEN +#define __SOCKADDR sockaddr_in6 +#define __ADDR in6_addr +#define __ADDR_ANY_INIT IN6ADDR_ANY_INIT + +#include "udp.c" |