X-Git-Url: https://git.syn-net.org/?p=debian%2Fuanytun.git;a=blobdiff_plain;f=src%2Fudp.c;h=3e1def603275bef88216c498ce1006cdf04fcabc;hp=7f539a86fccd0f920ff99afe454addb497cc28f9;hb=aa74a4fd24d8e8537f76531e6257fa90145355d3;hpb=e3f8e33112e2191999c6d6f6b6a767c72db800a0 diff --git a/src/udp.c b/src/udp.c index 7f539a8..3e1def6 100644 --- a/src/udp.c +++ b/src/udp.c @@ -15,7 +15,7 @@ * tunneling and relaying of packets of any protocol. * * - * Copyright (C) 2007-2008 Christian Pointner + * Copyright (C) 2007-2010 Christian Pointner * * This file is part of uAnytun. * @@ -49,14 +49,14 @@ #include #include -int udp_init(udp_socket_t* sock, const char* local_addr, const char* port, resolv_addr_type_t resolv_type) +int udp_init(udp_t* sock, const char* local_addr, const char* port, resolv_addr_type_t resolv_type) { if(!sock || !port) return -1; - - sock->fd_ = 0; - memset(&(sock->local_end_), 0, sizeof(sock->local_end_)); - memset(&(sock->remote_end_), 0, sizeof(sock->local_end_)); + + sock->socks_ = NULL; + sock->active_sock_ = NULL; + memset(&(sock->remote_end_), 0, sizeof(sock->remote_end_)); sock->remote_end_set_ = 0; struct addrinfo hints, *res; @@ -64,12 +64,12 @@ int udp_init(udp_socket_t* sock, const char* local_addr, const char* port, resol res = NULL; memset (&hints, 0, sizeof (hints)); hints.ai_socktype = SOCK_DGRAM; - hints.ai_flags |= AI_PASSIVE; + hints.ai_flags = AI_PASSIVE | AI_ADDRCONFIG; switch(resolv_type) { - case IPV4_ONLY: hints.ai_family = PF_INET; break; - case IPV6_ONLY: hints.ai_family = PF_INET6; break; - default: hints.ai_family = PF_UNSPEC; break; + case IPV4_ONLY: hints.ai_family = AF_INET; break; + case IPV6_ONLY: hints.ai_family = AF_INET6; break; + default: hints.ai_family = AF_UNSPEC; break; } int errcode = getaddrinfo(local_addr, port, &hints, &res); @@ -78,46 +78,86 @@ int udp_init(udp_socket_t* sock, const char* local_addr, const char* port, resol udp_close(sock); return -1; } - if(!res) { udp_close(sock); log_printf(ERROR, "getaddrinfo returned no address for %s:%s", local_addr, port); return -1; } - memcpy(&(sock->local_end_), res->ai_addr, res->ai_addrlen); + struct addrinfo* r = res; + udp_socket_t* prev_sock = NULL; + while(r) { + udp_socket_t* new_sock = malloc(sizeof(udp_socket_t)); + if(!new_sock) { + log_printf(ERROR, "memory error at udp_init"); + freeaddrinfo(res); + udp_close(sock); + return -2; + } + memset(&(new_sock->local_end_), 0, sizeof(new_sock->local_end_)); + new_sock->next_ = NULL; + + if(!sock->socks_) { + sock->socks_ = new_sock; + prev_sock = new_sock; + } + else { + prev_sock->next_ = new_sock; + prev_sock = new_sock; + } + + memcpy(&(new_sock->local_end_), r->ai_addr, r->ai_addrlen); + new_sock->fd_ = socket(r->ai_family, SOCK_DGRAM, 0); + if(new_sock->fd_ < 0) { + log_printf(ERROR, "Error on opening udp socket: %s", strerror(errno)); + freeaddrinfo(res); + udp_close(sock); + return -1; + } + + if(r->ai_family == AF_INET6) { + int on = 1; + if(setsockopt(new_sock->fd_, IPPROTO_IPV6, IPV6_V6ONLY, &on, sizeof(on))) + log_printf(ERROR, "Error on setting IPV6_V6ONLY socket option: %s", strerror(errno)); + } + + errcode = bind(new_sock->fd_, r->ai_addr, r->ai_addrlen); + if(errcode) { + log_printf(ERROR, "Error on binding udp socket: %s", strerror(errno)); + freeaddrinfo(res); + udp_close(sock); + return -1; + } + + char* local_string = udp_endpoint_to_string(new_sock->local_end_); + if(local_string) { + log_printf(NOTICE, "listening on: %s", local_string); + free(local_string); + } - sock->fd_ = socket(res->ai_family, SOCK_DGRAM, 0); - if(sock->fd_ < 0) { - log_printf(ERROR, "Error on opening udp socket: %s", strerror(errno)); - freeaddrinfo(res); - udp_close(sock); - return -1; + r = r->ai_next; } - errcode = bind(sock->fd_, res->ai_addr, res->ai_addrlen); - if(errcode) { - log_printf(ERROR, "Error on binding udp socket: %s", strerror(errno)); - freeaddrinfo(res); - udp_close(sock); - return -1; - } - -/* this doesn't work on linux ?? */ -/* #ifdef NO_V4MAPPED */ -/* if(res->ai_family == AF_INET6) { */ -/* log_printf(NOTICE, "disabling V4-Mapped addresses"); */ -/* int on = 1; */ -/* if(setsockopt(sock->fd_, IPPROTO_IPV6, IPV6_V6ONLY, &on, sizeof(on))) */ -/* log_printf(ERROR, "Error on setting IPV6_V6ONLY socket option: %s", strerror(errno)); */ -/* } */ -/* #endif */ freeaddrinfo(res); return 0; } -int udp_set_remote(udp_socket_t* sock, const char* remote_addr, const char* port, resolv_addr_type_t resolv_type) +int udp_init_fd_set(udp_t* sock, fd_set* set) +{ + int max_fd = 0; + + udp_socket_t* s = sock->socks_; + while(s) { + FD_SET(s->fd_, set); + max_fd = s->fd_ > max_fd ? s->fd_ : max_fd; + s = s->next_; + } + + return max_fd; +} + +int udp_set_remote(udp_t* sock, const char* remote_addr, const char* port, resolv_addr_type_t resolv_type) { if(!sock || !remote_addr || !port) return -1; @@ -145,18 +185,53 @@ int udp_set_remote(udp_socket_t* sock, const char* remote_addr, const char* port } memcpy(&(sock->remote_end_), res->ai_addr, res->ai_addrlen); sock->remote_end_set_ = 1; + + if(!sock->active_sock_) { + udp_socket_t* s = sock->socks_; + while(s) { + if((((struct sockaddr *)&s->local_end_)->sa_family) == res->ai_family) { + sock->active_sock_ = s; + break; + } + s = s->next_; + } + } + freeaddrinfo(res); return 0; } -void udp_close(udp_socket_t* sock) +void udp_set_active_sock(udp_t* sock, int fd) +{ + if(!sock || (sock->active_sock_ && sock->active_sock_->fd_ == fd)) + return; + + udp_socket_t* s = sock->socks_; + while(s) { + if(s->fd_ == fd) { + sock->active_sock_ = s; + return; + } + s = s->next_; + } +} + +void udp_close(udp_t* sock) { if(!sock) return; - if(sock->fd_ > 0) - close(sock->fd_); + while(sock->socks_) { + if(sock->socks_->fd_ > 0) + close(sock->socks_->fd_); + + udp_socket_t*s = sock->socks_; + sock->socks_ = sock->socks_->next_; + + free(s); + } + sock->socks_ = NULL; } char* udp_endpoint_to_string(udp_endpoint_t e) @@ -194,15 +269,7 @@ char* udp_endpoint_to_string(udp_endpoint_t e) return ret; } -char* udp_get_local_end_string(udp_socket_t* sock) -{ - if(!sock) - return NULL; - - return udp_endpoint_to_string(sock->local_end_); -} - -char* udp_get_remote_end_string(udp_socket_t* sock) +char* udp_get_remote_end_string(udp_t* sock) { if(!sock || !sock->remote_end_set_) return NULL; @@ -210,27 +277,26 @@ char* udp_get_remote_end_string(udp_socket_t* sock) return udp_endpoint_to_string(sock->remote_end_); } -int udp_read(udp_socket_t* sock, u_int8_t* buf, u_int32_t len, udp_endpoint_t* remote_end) +int udp_read(udp_t* sock, int fd, u_int8_t* buf, u_int32_t len, udp_endpoint_t* remote_end) { if(!sock || !remote_end) return -1; socklen_t socklen = sizeof(*remote_end); - return recvfrom(sock->fd_, buf, len, 0, (struct sockaddr *)remote_end, &socklen); + return recvfrom(fd, buf, len, 0, (struct sockaddr *)remote_end, &socklen); } -int udp_write(udp_socket_t* sock, u_int8_t* buf, u_int32_t len) +int udp_write(udp_t* sock, u_int8_t* buf, u_int32_t len) { - if(!sock || !sock->remote_end_set_) - return -1; + if(!sock || !sock->remote_end_set_ || !sock->active_sock_) + return 0; socklen_t socklen = sizeof(sock->remote_end_); -#ifdef NO_V4MAPPED - if((((struct sockaddr *)&sock->local_end_)->sa_family) == AF_INET) + if((((struct sockaddr *)&sock->active_sock_->local_end_)->sa_family) == AF_INET) socklen = sizeof(struct sockaddr_in); - else if ((((struct sockaddr *)&sock->local_end_)->sa_family) == AF_INET6) + else if ((((struct sockaddr *)&sock->active_sock_->local_end_)->sa_family) == AF_INET6) socklen = sizeof(struct sockaddr_in6); -#endif - return sendto(sock->fd_, buf, len, 0, (struct sockaddr *)&(sock->remote_end_), socklen);; + + return sendto(sock->active_sock_->fd_, buf, len, 0, (struct sockaddr *)&(sock->remote_end_), socklen); }