From 4402f3381b369ae47963ef8936c8f9672697d8db Mon Sep 17 00:00:00 2001 From: Dimitri Staessens Date: Sat, 2 Jan 2021 14:20:25 +0100 Subject: ipcpd: Single UDP port for the ipcpd-udp The UDP layer will now use a single (configurable) UDP port, default 3435. This makes it easer to allocate flows as a client from behind a NAT firewall without having to configure port forwarding rules. So basically, from now on Ouroboros traffic is transported over a bidirectional : UDP tunnel. The reason for not using/allowing different client/server ports is that it would require reading from different sockets using select() or something similar, but since we need the EID anyway (mgmt packets arrive on the same server UDP port), there's not a lot of benefit in doing it. Now the operation is similar to the ipcpd-eth, with the port somewhat functioning as a "layer name", where in UDP, the Ethertype functions as a "layer name". Signed-off-by: Dimitri Staessens Signed-off-by: Sander Vrijders --- include/ouroboros/ipcp.h | 3 +- src/ipcpd/ipcp.c | 3 +- src/ipcpd/udp/main.c | 226 ++++++++++++------------------------- src/lib/ipcp_config.proto | 7 +- src/lib/irm.c | 6 +- src/tools/irm/irm_ipcp_bootstrap.c | 20 ++-- 6 files changed, 85 insertions(+), 180 deletions(-) diff --git a/include/ouroboros/ipcp.h b/include/ouroboros/ipcp.h index 29ca42fc..53b166da 100644 --- a/include/ouroboros/ipcp.h +++ b/include/ouroboros/ipcp.h @@ -91,8 +91,7 @@ struct ipcp_config { /* UDP */ uint32_t ip_addr; uint32_t dns_addr; - uint16_t clt_port; - uint16_t srv_port; + uint16_t port; /* Ethernet */ char * dev; diff --git a/src/ipcpd/ipcp.c b/src/ipcpd/ipcp.c index 7be946dc..838ecda0 100644 --- a/src/ipcpd/ipcp.c +++ b/src/ipcpd/ipcp.c @@ -252,8 +252,7 @@ static void * mainloop(void * o) case IPCP_UDP: conf.ip_addr = conf_msg->ip_addr; conf.dns_addr = conf_msg->dns_addr; - conf.clt_port = conf_msg->clt_port; - conf.srv_port = conf_msg->srv_port; + conf.port = conf_msg->port; conf.layer_info.dir_hash_algo = HASH_MD5; layer_info.dir_hash_algo = HASH_MD5; break; diff --git a/src/ipcpd/udp/main.c b/src/ipcpd/udp/main.c index dba831ff..4314b330 100644 --- a/src/ipcpd/udp/main.c +++ b/src/ipcpd/udp/main.c @@ -67,10 +67,8 @@ #define DNS_TTL 86400 #define FD_UPDATE_TIMEOUT 100 /* microseconds */ -#define SERV_PORT udp_data.s_saddr.sin_port; -#define SERV_SADDR ((struct sockaddr *) &udp_data.s_saddr) -#define CLNT_SADDR ((struct sockaddr *) &udp_data.c_saddr) -#define SERV_SADDR_SIZE (sizeof(udp_data.s_saddr)) +#define SADDR ((struct sockaddr *) &udp_data.s_saddr) +#define SADDR_SIZE (sizeof(udp_data.s_saddr)) #define LOCAL_IP (udp_data.s_saddr.sin_addr.s_addr) #define MGMT_EID 0 @@ -106,20 +104,17 @@ struct mgmt_frame { /* UDP flow */ struct uf { - int d_eid; - /* IP details are stored through connect(). */ - int skfd; + int d_eid; + struct sockaddr_in r_saddr; }; struct { struct shim_data * shim_data; uint32_t dns_addr; - /* server socket */ + struct sockaddr_in s_saddr; int s_fd; - /* client port */ - int clt_port; fset_t * np1_flows; struct uf fd_to_uf[SYS_MAX_FLOWS]; @@ -148,10 +143,8 @@ static int udp_data_init(void) if (pthread_mutex_init(&udp_data.mgmt_lock, NULL)) goto fail_mgmt_lock; - for (i = 0; i < SYS_MAX_FLOWS; ++i) { - udp_data.fd_to_uf[i].skfd = -1; + for (i = 0; i < SYS_MAX_FLOWS; ++i) udp_data.fd_to_uf[i].d_eid = -1; - } udp_data.np1_flows = fset_create(); if (udp_data.np1_flows == NULL) @@ -187,12 +180,12 @@ static void udp_data_fini(void) pthread_mutex_destroy(&udp_data.mgmt_lock); } -static int ipcp_udp_port_alloc(int skfd, - uint32_t s_eid, - const uint8_t * dst, - qosspec_t qs, - const void * data, - size_t dlen) +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) { uint8_t * buf; struct mgmt_msg * msg; @@ -222,7 +215,9 @@ static int ipcp_udp_port_alloc(int skfd, memcpy(msg + 1, dst, ipcp_dir_hash_len()); memcpy(buf + len, data, dlen); - if (write(skfd, msg, len + dlen) < 0) { + if (sendto(udp_data.s_fd, msg, len + dlen, + MSG_CONFIRM, + (const struct sockaddr *) r_saddr, sizeof(*r_saddr)) < 0) { free(buf); return -1; } @@ -232,14 +227,14 @@ static int ipcp_udp_port_alloc(int skfd, return 0; } -static int ipcp_udp_port_alloc_resp(int skfd, - uint32_t s_eid, - uint32_t d_eid, - int8_t response, - const void * data, - size_t len) +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) { - struct mgmt_msg * msg; + struct mgmt_msg * msg; msg = malloc(sizeof(*msg) + len); if (msg == NULL) @@ -253,7 +248,9 @@ static int ipcp_udp_port_alloc_resp(int skfd, memcpy(msg + 1, data, len); - if (write(skfd, msg, sizeof(*msg) + len) < 0) { + if (sendto(udp_data.s_fd, msg, sizeof(*msg) + len, + MSG_CONFIRM, + (const struct sockaddr *) r_saddr, sizeof(*r_saddr)) < 0 ) { free(msg); return -1; } @@ -270,26 +267,9 @@ static int ipcp_udp_port_req(struct sockaddr_in * c_saddr, const void * data, size_t len) { - struct timespec ts = {0, FD_UPDATE_TIMEOUT * 1000}; - struct timespec abstime; - int skfd; - int fd; - - skfd = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP); - if (skfd < 0) { - log_err("Could not create UDP socket."); - return -1; - } - - /* Remote listens on server port. Mod of c_saddr allowed. */ - c_saddr->sin_port = udp_data.s_saddr.sin_port; - - /* Connect stores the remote address in the file descriptor. */ - if (connect(skfd, (struct sockaddr *) c_saddr, sizeof(*c_saddr)) < 0) { - log_err("Could not connect to remote UDP client."); - close(skfd); - return -1; - } + struct timespec ts = {0, FD_UPDATE_TIMEOUT * 1000}; + struct timespec abstime; + int fd; clock_gettime(PTHREAD_COND_CLOCK, &abstime); @@ -304,7 +284,6 @@ static int ipcp_udp_port_req(struct sockaddr_in * c_saddr, if (ipcp_get_state() != IPCP_OPERATIONAL) { log_dbg("Won't allocate over non-operational IPCP."); pthread_mutex_unlock(&ipcpi.alloc_lock); - close(skfd); return -1; } @@ -313,14 +292,13 @@ static int ipcp_udp_port_req(struct sockaddr_in * c_saddr, if (fd < 0) { pthread_mutex_unlock(&ipcpi.alloc_lock); log_err("Could not get new flow from IRMd."); - close(skfd); return -1; } pthread_rwlock_wrlock(&udp_data.flows_lock); - udp_data.fd_to_uf[fd].skfd = skfd; - udp_data.fd_to_uf[fd].d_eid = d_eid; + udp_data.fd_to_uf[fd].r_saddr = *c_saddr; + udp_data.fd_to_uf[fd].d_eid = d_eid; pthread_rwlock_unlock(&udp_data.flows_lock); @@ -335,44 +313,27 @@ static int ipcp_udp_port_req(struct sockaddr_in * c_saddr, return 0; } -static int ipcp_udp_port_alloc_reply(uint32_t s_eid, - uint32_t d_eid, - int8_t response, - const void * data, - size_t len) +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) { - struct sockaddr_in t_saddr; - socklen_t t_saddr_len; - int ret = 0; - int skfd = -1; - - t_saddr_len = sizeof(t_saddr); - pthread_rwlock_wrlock(&udp_data.flows_lock); - skfd = udp_data.fd_to_uf[s_eid].skfd; - if (skfd < 0) { + if (memcmp(&udp_data.fd_to_uf[s_eid].r_saddr, saddr, sizeof(*saddr))) { pthread_rwlock_unlock(&udp_data.flows_lock); - log_err("Got reply for unknown UDP eid: %u.", s_eid); + log_warn("Flow allocation reply for %u from wrong source.", + s_eid); return -1; } - udp_data.fd_to_uf[s_eid].d_eid = d_eid; + if (response == 0) + udp_data.fd_to_uf[s_eid].d_eid = d_eid; pthread_rwlock_unlock(&udp_data.flows_lock); - if (getpeername(skfd, (struct sockaddr *) &t_saddr, &t_saddr_len) < 0) { - log_dbg("Flow with fd %d has no peer.", s_eid); - close(skfd); - return -1; - } - - if (connect(skfd, (struct sockaddr *) &t_saddr, sizeof(t_saddr)) < 0) { - log_dbg("Could not connect flow to remote."); - close(skfd); - return -1; - } - if (ipcp_flow_alloc_reply(s_eid, response, data, len) < 0) { log_dbg("Failed to reply to flow allocation."); return -1; @@ -381,7 +342,7 @@ static int ipcp_udp_port_alloc_reply(uint32_t s_eid, log_dbg("Flow allocation completed on eids (%d, %d).", s_eid, d_eid); - return ret; + return 0; } static int ipcp_udp_mgmt_frame(const uint8_t * buf, @@ -416,7 +377,8 @@ static int ipcp_udp_mgmt_frame(const uint8_t * buf, case FLOW_REPLY: assert(len >= sizeof(*msg)); - return ipcp_udp_port_alloc_reply(ntoh32(msg->s_eid), + return ipcp_udp_port_alloc_reply(&c_saddr, + ntoh32(msg->s_eid), ntoh32(msg->d_eid), msg->response, buf + sizeof(*msg), @@ -543,8 +505,9 @@ static void * ipcp_udp_packet_writer(void * o) pthread_cleanup_push(cleanup_writer, fq); while (true) { - int fd; - int eid; + struct sockaddr_in saddr; + int eid; + int fd; fevent(udp_data.np1_flows, fq, NULL); while ((fd = fqueue_next(fq)) >= 0) { struct shm_du_buff * sdb; @@ -576,7 +539,7 @@ static void * ipcp_udp_packet_writer(void * o) pthread_rwlock_rdlock(&udp_data.flows_lock); eid = hton32(udp_data.fd_to_uf[fd].d_eid); - fd = udp_data.fd_to_uf[fd].skfd; + saddr = udp_data.fd_to_uf[fd].r_saddr; pthread_rwlock_unlock(&udp_data.flows_lock); @@ -585,7 +548,10 @@ static void * ipcp_udp_packet_writer(void * o) pthread_cleanup_push((void (*)(void *)) ipcp_sdb_release, (void *) sdb); - if (write(fd, buf, len + OUR_HEADER_LEN) < 0) + if (sendto(udp_data.s_fd, buf, len + OUR_HEADER_LEN, + MSG_CONFIRM, + (const struct sockaddr *) &saddr, + sizeof(saddr)) < 0) log_err("Failed to send packet."); pthread_cleanup_pop(true); @@ -633,22 +599,17 @@ static int ipcp_udp_bootstrap(const struct ipcp_config * conf) goto fail_socket; } - if (setsockopt(udp_data.s_fd, SOL_SOCKET, SO_REUSEADDR, - &i, sizeof(i)) < 0) - log_warn("Failed to set SO_REUSEADDR."); - 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->srv_port); + udp_data.s_saddr.sin_port = htons(conf->port); - if (bind(udp_data.s_fd, SERV_SADDR, SERV_SADDR_SIZE) < 0) { + if (bind(udp_data.s_fd, SADDR, SADDR_SIZE) < 0) { log_err("Couldn't bind to %s.", ipstr); goto fail_bind; } udp_data.dns_addr = conf->dns_addr; - udp_data.clt_port = htons(conf->clt_port); ipcp_set_state(IPCP_OPERATIONAL); @@ -674,12 +635,11 @@ static int ipcp_udp_bootstrap(const struct ipcp_config * conf) } } - sprintf(portstr, "%d", conf->clt_port); + sprintf(portstr, "%d", conf->port); log_dbg("Bootstrapped IPCP over UDP with pid %d.", getpid()); log_dbg("Bound to IP address %s.", ipstr); - log_dbg("Client port is %s.", conf->clt_port == 0 ? "random" : portstr); - log_dbg("Server port is %u.", conf->srv_port); + log_dbg("Using port %u.", conf->port); log_dbg("DNS server address is %s.", dnsstr); return 0; @@ -997,13 +957,8 @@ static int ipcp_udp_flow_alloc(int fd, size_t len) { struct sockaddr_in r_saddr; /* Server address */ - struct sockaddr_in c_saddr; /* Client address */ - socklen_t c_saddr_len; - int skfd; uint32_t ip_addr = 0; - char ip_str[INET_ADDRSTRLEN]; - - c_saddr_len = sizeof(c_saddr); + char ipstr[INET_ADDRSTRLEN]; log_dbg("Allocating flow to " HASH_FMT ".", HASH_VAL(dst)); @@ -1011,70 +966,36 @@ static int ipcp_udp_flow_alloc(int fd, assert(dst); - skfd = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP); - if (skfd < 0) { - log_err("Could not create socket."); - return -1; - } - - /* This socket is for the flow. */ - memset((char *) &c_saddr, 0, sizeof(c_saddr)); - c_saddr.sin_family = AF_INET; - c_saddr.sin_addr.s_addr = LOCAL_IP; - c_saddr.sin_port = udp_data.clt_port; - - if (bind(skfd, (struct sockaddr *) &c_saddr, sizeof(c_saddr)) < 0) { - log_dbg("Could not bind socket to client address."); - close(skfd); - return -1; - } - - if (getsockname(skfd, (struct sockaddr *) &c_saddr, &c_saddr_len) < 0) { - log_err("Could not get address from fd."); - close(skfd); - return -1; - } - if (!shim_data_dir_has(udp_data.shim_data, dst)) { log_dbg("Could not resolve destination."); - close(skfd); return -1; } ip_addr = (uint32_t) shim_data_dir_get_addr(udp_data.shim_data, dst); - inet_ntop(AF_INET, &ip_addr, ip_str, INET_ADDRSTRLEN); - log_dbg("Destination UDP ipcp resolved at %s.", ip_str); + inet_ntop(AF_INET, &ip_addr, ipstr, INET_ADDRSTRLEN); + log_dbg("Destination UDP ipcp resolved at %s.", ipstr); - /* Connect to server and store the remote IP address in the skfd. */ 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; - if (connect(skfd, (struct sockaddr *) &r_saddr, sizeof(r_saddr)) < 0) { - log_dbg("Could not connect socket to remote."); - close(skfd); - return -1; - } - - if (ipcp_udp_port_alloc(skfd, fd, dst, qs, data, len) < 0) { + if (ipcp_udp_port_alloc(&r_saddr, fd, dst, qs, data, len) < 0) { log_err("Could not allocate port."); - close(skfd); return -1; } pthread_rwlock_wrlock(&udp_data.flows_lock); - udp_data.fd_to_uf[fd].d_eid = -1; - udp_data.fd_to_uf[fd].skfd = skfd; + udp_data.fd_to_uf[fd].d_eid = -1; + udp_data.fd_to_uf[fd].r_saddr = r_saddr; pthread_rwlock_unlock(&udp_data.flows_lock); fset_add(udp_data.np1_flows, fd); - log_dbg("Flow pending on fd %d, UDP src port %d, dst port %d.", - fd, ntohs(c_saddr.sin_port), ntohs(r_saddr.sin_port)); + log_dbg("Flow to %s pending on fd %d.", ipstr, fd); return 0; } @@ -1084,10 +1005,10 @@ static int ipcp_udp_flow_alloc_resp(int fd, const void * data, size_t len) { - struct timespec ts = {0, FD_UPDATE_TIMEOUT * 1000}; - struct timespec abstime; - int skfd; - int d_eid; + struct timespec ts = {0, FD_UPDATE_TIMEOUT * 1000}; + struct timespec abstime; + struct sockaddr_in saddr; + int d_eid; if (resp) return 0; @@ -1115,12 +1036,13 @@ static int ipcp_udp_flow_alloc_resp(int fd, pthread_rwlock_rdlock(&udp_data.flows_lock); - skfd = udp_data.fd_to_uf[fd].skfd; + saddr = udp_data.fd_to_uf[fd].r_saddr; d_eid = udp_data.fd_to_uf[fd].d_eid; pthread_rwlock_unlock(&udp_data.flows_lock); - if (ipcp_udp_port_alloc_resp(skfd, d_eid, fd, resp, data, len) < 0) { + if (ipcp_udp_port_alloc_resp(&saddr, d_eid, fd, resp, data, len) < 0) { + fset_del(udp_data.np1_flows, fd); log_err("Failed to respond to flow request."); return -1; } @@ -1135,23 +1057,17 @@ static int ipcp_udp_flow_alloc_resp(int fd, static int ipcp_udp_flow_dealloc(int fd) { - int skfd = -1; - ipcp_flow_fini(fd); fset_del(udp_data.np1_flows, fd); pthread_rwlock_wrlock(&udp_data.flows_lock); - skfd = udp_data.fd_to_uf[fd].skfd; - udp_data.fd_to_uf[fd].d_eid = -1; - udp_data.fd_to_uf[fd].skfd = -1; + memset(&udp_data.fd_to_uf[fd].r_saddr, 0, SADDR_SIZE); pthread_rwlock_unlock(&udp_data.flows_lock); - close(skfd); - flow_dealloc(fd); log_dbg("Flow with fd %d deallocated.", fd); diff --git a/src/lib/ipcp_config.proto b/src/lib/ipcp_config.proto index 9cbf1e49..185d9af7 100644 --- a/src/lib/ipcp_config.proto +++ b/src/lib/ipcp_config.proto @@ -40,12 +40,11 @@ message ipcp_config_msg { // Config for UDP optional uint32 ip_addr = 9; optional uint32 dns_addr = 10; - optional uint32 clt_port = 11; - optional uint32 srv_port = 12; + optional uint32 port = 11; // Config for the Ethernet - optional string dev = 13; + optional string dev = 12; // Config for DIX Ethernet - optional uint32 ethertype = 14; + optional uint32 ethertype = 13; } enum enroll_code { diff --git a/src/lib/irm.c b/src/lib/irm.c index 19bee4d2..b86b02c9 100644 --- a/src/lib/irm.c +++ b/src/lib/irm.c @@ -140,10 +140,8 @@ int irm_bootstrap_ipcp(pid_t pid, config.ip_addr = conf->ip_addr; config.has_dns_addr = true; config.dns_addr = conf->dns_addr; - config.has_srv_port = true; - config.srv_port = conf->srv_port; - config.has_clt_port = true; - config.clt_port = conf->clt_port; + config.has_port = true; + config.port = conf->port; break; case IPCP_LOCAL: case IPCP_BROADCAST: diff --git a/src/tools/irm/irm_ipcp_bootstrap.c b/src/tools/irm/irm_ipcp_bootstrap.c index cd6c3c8a..95330e99 100644 --- a/src/tools/irm/irm_ipcp_bootstrap.c +++ b/src/tools/irm/irm_ipcp_bootstrap.c @@ -73,8 +73,7 @@ #define DEFAULT_CONG_AVOID CA_MB_ECN #define DEFAULT_HASH_ALGO DIR_HASH_SHA3_256 #define DEFAULT_ETHERTYPE 0xA000 -#define DEFAULT_CLIENT_PORT 0x0000 /* random port */ -#define DEFAULT_SERVER_PORT 0x0D6B /* 3435 */ +#define DEFAULT_UDP_PORT 0x0D6B /* 3435 */ #define FLAT_RANDOM_ADDR_AUTH "flat" #define LINK_STATE_ROUTING "link_state" @@ -109,8 +108,7 @@ static void usage(void) SHA3_384 " " SHA3_512 "}\n\n" "if TYPE == " UDP "\n" " ip \n" - " [cport (default: random)]\n" - " [sport (default: %d)]\n" + " [port (default: %d)]\n" " [dns " " (default: none)]\n\n" "if TYPE == " ETH_LLC "\n" @@ -136,7 +134,7 @@ static void usage(void) " [autobind]\n\n", DEFAULT_ADDR_SIZE, DEFAULT_EID_SIZE, DEFAULT_TTL, FLAT_RANDOM_ADDR_AUTH, LINK_STATE_ROUTING, MB_ECN_CA, - SHA3_256, DEFAULT_SERVER_PORT, SHA3_256, 0xA000, SHA3_256, + SHA3_256, DEFAULT_UDP_PORT, SHA3_256, 0xA000, SHA3_256, SHA3_256, SHA3_256); } @@ -165,8 +163,7 @@ int do_bootstrap_ipcp(int argc, int i = 0; bool autobind = false; int cargs; - int cport = DEFAULT_CLIENT_PORT; - int sport = DEFAULT_SERVER_PORT; + int port = DEFAULT_UDP_PORT; while (argc > 0) { cargs = 2; @@ -213,10 +210,8 @@ int do_bootstrap_ipcp(int argc, eid_size = atoi(*(argv + 1)); } else if (matches(*argv, "ttl") == 0) { max_ttl = atoi(*(argv + 1)); - } else if (matches(*argv, "cport") == 0) { - cport = atoi(*(argv + 1)); - } else if (matches(*argv, "sport") == 0) { - sport = atoi(*(argv + 1)); + } else if (matches(*argv, "port") == 0) { + port = atoi(*(argv + 1)); } else if (matches(*argv, "autobind") == 0) { autobind = true; cargs = 1; @@ -336,8 +331,7 @@ int do_bootstrap_ipcp(int argc, goto fail_usage; conf.ip_addr = ip_addr; conf.dns_addr = dns_addr; - conf.clt_port = cport; - conf.srv_port = sport; + conf.port = port; break; case IPCP_ETH_LLC: if (dev == NULL) -- cgit v1.2.3