diff options
Diffstat (limited to 'src/ipcpd/shim-udp')
-rw-r--r-- | src/ipcpd/shim-udp/main.c | 163 |
1 files changed, 100 insertions, 63 deletions
diff --git a/src/ipcpd/shim-udp/main.c b/src/ipcpd/shim-udp/main.c index 62e1b2d0..e06787ce 100644 --- a/src/ipcpd/shim-udp/main.c +++ b/src/ipcpd/shim-udp/main.c @@ -20,9 +20,9 @@ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ +#define OUROBOROS_PREFIX "ipcpd/shim-udp" + #include <ouroboros/config.h> -#include "ipcp.h" -#include "shim_udp_config.h" #include <ouroboros/list.h> #include <ouroboros/utils.h> #include <ouroboros/dev.h> @@ -30,11 +30,12 @@ #include <ouroboros/fqueue.h> #include <ouroboros/fcntl.h> #include <ouroboros/errno.h> - -#define OUROBOROS_PREFIX "ipcpd/shim-udp" - #include <ouroboros/logs.h> +#include "shim_udp_messages.pb-c.h" +#include "ipcp.h" +#include "shim_udp_config.h" + #include <string.h> #include <sys/socket.h> #include <sys/select.h> @@ -47,8 +48,6 @@ #include <sys/wait.h> #include <fcntl.h> -#include "shim_udp_messages.pb-c.h" - typedef ShimUdpMsg shim_udp_msg_t; #define THIS_TYPE IPCP_SHIM_UDP @@ -79,6 +78,7 @@ struct { int s_fd; flow_set_t * np1_flows; + fqueue_t * fq; fd_set flow_fd_s; /* bidir mappings of (n - 1) file descriptor to (n) flow descriptor */ int uf_to_fd[FD_SETSIZE]; @@ -112,6 +112,12 @@ static int udp_data_init(void) if (udp_data.np1_flows == NULL) return -ENOMEM; + udp_data.fq = fqueue_create(); + if (udp_data.fq == NULL) { + flow_set_destroy(udp_data.np1_flows); + return -ENOMEM; + } + pthread_rwlock_init(&udp_data.flows_lock, NULL); pthread_cond_init(&udp_data.fd_set_cond, NULL); pthread_mutex_init(&udp_data.fd_set_lock, NULL); @@ -122,6 +128,7 @@ static int udp_data_init(void) static void udp_data_fini(void) { flow_set_destroy(udp_data.np1_flows); + fqueue_destroy(udp_data.fq); pthread_rwlock_destroy(&udp_data.flows_lock); pthread_mutex_destroy(&udp_data.fd_set_lock); @@ -523,23 +530,16 @@ static void * ipcp_udp_sdu_loop(void * o) int fd; struct timespec timeout = {0, FD_UPDATE_TIMEOUT * 1000}; struct shm_du_buff * sdb; - fqueue_t * fq = fqueue_create(); - if (fq == NULL) - return (void *) 1; (void) o; while (true) { - int ret = flow_event_wait(udp_data.np1_flows, fq, &timeout); - if (ret == -ETIMEDOUT) + if (flow_event_wait(udp_data.np1_flows, + udp_data.fq, + &timeout) == -ETIMEDOUT) continue; - if (ret < 0) { - LOG_ERR("Event wait returned error code %d.", -ret); - continue; - } - - while ((fd = fqueue_next(fq)) >= 0) { + while ((fd = fqueue_next(udp_data.fq)) >= 0) { if (ipcp_flow_read(fd, &sdb)) { LOG_ERR("Bad read from fd %d.", fd); continue; @@ -594,13 +594,11 @@ static int ipcp_udp_bootstrap(struct dif_config * conf) int enable = 1; int fd = -1; - if (conf == NULL) - return -1; /* -EINVAL */ + assert(conf); + assert(conf->type == THIS_TYPE); - if (conf->type != THIS_TYPE) { - LOG_ERR("Config doesn't match IPCP type."); - return -1; - } + /* this IPCP doesn't need to maintain its dif_name */ + free(conf->dif_name); if (inet_ntop(AF_INET, &conf->ip_addr, @@ -833,7 +831,7 @@ static int ipcp_udp_name_reg(char * name) pthread_rwlock_rdlock(&ipcpi.state_lock); - if (ipcp_data_add_reg_entry(ipcpi.data, name)) { + if (ipcp_data_reg_add_entry(ipcpi.data, name)) { pthread_rwlock_unlock(&ipcpi.state_lock); LOG_ERR("Failed to add %s to local registry.", name); return -1; @@ -864,7 +862,7 @@ static int ipcp_udp_name_reg(char * name) if (ddns_send(cmd)) { pthread_rwlock_rdlock(&ipcpi.state_lock); - ipcp_data_del_reg_entry(ipcpi.data, name); + ipcp_data_reg_del_entry(ipcpi.data, name); pthread_rwlock_unlock(&ipcpi.state_lock); return -1; } @@ -885,7 +883,6 @@ static int ipcp_udp_name_unreg(char * name) char cmd[100]; uint32_t dns_addr; #endif - if (strlen(name) > 24) { LOG_ERR("DNS names cannot be longer than 24 chars."); return -1; @@ -914,7 +911,74 @@ static int ipcp_udp_name_unreg(char * name) pthread_rwlock_rdlock(&ipcpi.state_lock); - ipcp_data_del_reg_entry(ipcpi.data, name); + ipcp_data_reg_del_entry(ipcpi.data, name); + + pthread_rwlock_unlock(&ipcpi.state_lock); + + return 0; +} + +static int ipcp_udp_name_query(char * name) +{ + uint32_t ip_addr = 0; + struct hostent * h; +#ifdef CONFIG_OUROBOROS_ENABLE_DNS + uint32_t dns_addr = 0; +#endif + + assert(name); + + if (strlen(name) > 24) { + LOG_ERR("DNS names cannot be longer than 24 chars."); + return -1; + } + + pthread_rwlock_rdlock(&ipcpi.state_lock); + + if (ipcp_get_state() != IPCP_ENROLLED) { + pthread_rwlock_unlock(&ipcpi.state_lock); + LOG_DBG("Won't query a name on a non-enrolled IPCP."); + return -1; /* -ENOTENROLLED */ + } + +#ifdef CONFIG_OUROBOROS_ENABLE_DNS + dns_addr = udp_data.dns_addr; + + if (dns_addr != 0) { + pthread_rwlock_unlock(&ipcpi.state_lock); + + ip_addr = ddns_resolve(name, dns_addr); + if (ip_addr == 0) { + LOG_DBG("Could not resolve %s.", name); + return -1; + } + + pthread_rwlock_rdlock(&ipcpi.state_lock); + + if (ipcp_get_state() != IPCP_ENROLLED) { + pthread_rwlock_unlock(&ipcpi.state_lock); + LOG_DBG("Won't add name to the directory."); + return -1; /* -ENOTENROLLED */ + } + } else { +#endif + h = gethostbyname(name); + if (h == NULL) { + pthread_rwlock_unlock(&ipcpi.state_lock); + LOG_DBG("Could not resolve %s.", name); + return -1; + } + + ip_addr = *((uint32_t *) (h->h_addr_list[0])); +#ifdef CONFIG_OUROBOROS_ENABLE_DNS + } +#endif + + if (ipcp_data_dir_add_entry(ipcpi.data, name, ip_addr)) { + pthread_rwlock_unlock(&ipcpi.state_lock); + LOG_ERR("Failed to add directory entry."); + return -1; + } pthread_rwlock_unlock(&ipcpi.state_lock); @@ -930,15 +994,13 @@ static int ipcp_udp_flow_alloc(int fd, struct sockaddr_in f_saddr; /* flow */ socklen_t f_saddr_len = sizeof(f_saddr); int skfd; - struct hostent * h; uint32_t ip_addr = 0; -#ifdef CONFIG_OUROBOROS_ENABLE_DNS - uint32_t dns_addr = 0; -#endif + LOG_DBG("Allocating flow to %s.", dst_name); if (dst_name == NULL || src_ae_name == NULL) return -1; + if (strlen(dst_name) > 255 || strlen(src_ae_name) > 255) { LOG_ERR("Name too long for this shim."); @@ -976,39 +1038,13 @@ static int ipcp_udp_flow_alloc(int fd, return -1; /* -ENOTENROLLED */ } -#ifdef CONFIG_OUROBOROS_ENABLE_DNS - dns_addr = udp_data.dns_addr; - - if (dns_addr != 0) { + if (!ipcp_data_dir_has(ipcpi.data, dst_name)) { pthread_rwlock_unlock(&ipcpi.state_lock); - - ip_addr = ddns_resolve(dst_name, dns_addr); - if (ip_addr == 0) { - LOG_DBG("Could not resolve %s.", dst_name); - close(fd); - return -1; - } - - pthread_rwlock_rdlock(&ipcpi.state_lock); - if (ipcp_get_state() != IPCP_ENROLLED) { - pthread_rwlock_unlock(&ipcpi.state_lock); - LOG_DBG("Won't allocate flow with non-enrolled IPCP."); - close(skfd); - return -1; /* -ENOTENROLLED */ - } - } else { -#endif - h = gethostbyname(dst_name); - if (h == NULL) { - LOG_DBG("Could not resolve %s.", dst_name); - close(skfd); - return -1; - } - - ip_addr = *((uint32_t *) (h->h_addr_list[0])); -#ifdef CONFIG_OUROBOROS_ENABLE_DNS + LOG_DBG("Could not resolve destination."); + close(skfd); + return -1; } -#endif + ip_addr = (uint32_t) ipcp_data_dir_get_addr(ipcpi.data, dst_name); /* connect to server (store the remote IP address in the fd) */ memset((char *) &r_saddr, 0, sizeof(r_saddr)); @@ -1171,6 +1207,7 @@ static struct ipcp_ops udp_ops = { .ipcp_enroll = NULL, /* shim */ .ipcp_name_reg = ipcp_udp_name_reg, .ipcp_name_unreg = ipcp_udp_name_unreg, + .ipcp_name_query = ipcp_udp_name_query, .ipcp_flow_alloc = ipcp_udp_flow_alloc, .ipcp_flow_alloc_resp = ipcp_udp_flow_alloc_resp, .ipcp_flow_dealloc = ipcp_udp_flow_dealloc |