diff options
-rw-r--r-- | src/listener.c | 97 | ||||
-rw-r--r-- | src/listener.h | 2 | ||||
-rw-r--r-- | src/string_list.c | 5 | ||||
-rw-r--r-- | src/tcp.c | 32 | ||||
-rw-r--r-- | src/tcp.h | 4 | ||||
-rw-r--r-- | src/tcpproxy.c | 19 |
6 files changed, 141 insertions, 18 deletions
diff --git a/src/listener.c b/src/listener.c index 4025b26..07428bc 100644 --- a/src/listener.c +++ b/src/listener.c @@ -25,13 +25,20 @@ * along with tcpproxy. If not, see <http://www.gnu.org/licenses/>. */ -#include <unistd.h> +#include <errno.h> #include <stdlib.h> -#include <stdio.h> +#include <unistd.h> #include <string.h> +#include <stdio.h> +#include <netdb.h> +#include <sys/types.h> +#include <sys/socket.h> +#include <arpa/inet.h> +#include <netinet/in.h> #include "listener.h" #include "tcp.h" +#include "log.h" void listener_delete_element(void* e) { @@ -54,27 +61,85 @@ void listener_clear(listeners_t* list) slist_clear(list); } -int listener_add(listeners_t* list, char* laddr, char* lport, char* raddr, char* rport) +int listener_add(listeners_t* list, const char* laddr, const char* lport, const char* raddr, const char* rport) { if(!list) return -1; - - listener_t* element = malloc(sizeof(listener_t)); - if(!element) - return -2; - -// TODO: open listen socket and resolv local and remote address - static int fds = 6; +// TODO: what if more than one address is returned here? + struct addrinfo* re = tcp_resolve_endpoint(raddr, rport, ANY); + if(!re) + return -1; + + struct addrinfo* le = tcp_resolve_endpoint(laddr, lport, ANY); + if(!le) { + freeaddrinfo(re); + return -1; + } + + struct addrinfo* l = le; + int ret = 0; + while(l) { + listener_t* element = malloc(sizeof(listener_t)); + if(!element) { + ret = -2; + break; + } + memset(&(element->remote_end_), 0, sizeof(element->remote_end_)); + memcpy(&(element->remote_end_), re->ai_addr, re->ai_addrlen); + + memset(&(element->local_end_), 0, sizeof(element->local_end_)); + memcpy(&(element->local_end_), l->ai_addr, l->ai_addrlen); + + element->fd_ = socket(l->ai_family, SOCK_STREAM, 0); + if(element->fd_ < 0) { + log_printf(ERROR, "Error on opening tcp socket: %s", strerror(errno)); + free(element); + ret = -1; + break; + } + + if(l->ai_family == AF_INET6) { + int on = 1; + if(setsockopt(element->fd_, IPPROTO_IPV6, IPV6_V6ONLY, &on, sizeof(on))) + log_printf(WARNING, "failed to set IPV6_V6ONLY socket option: %s", strerror(errno)); + } + + ret = bind(element->fd_, l->ai_addr, l->ai_addrlen); + if(ret) { + log_printf(ERROR, "Error on bind(): %s", strerror(errno)); + close(element->fd_); + free(element); + break; + } - element->fd_ = fds++; - memset(&(element->local_end_), 0, sizeof(element->local_end_)); - memset(&(element->remote_end_), 0, sizeof(element->remote_end_)); + ret = listen(element->fd_, 0); + if(ret) { + log_printf(ERROR, "Error on listen(): %s", strerror(errno)); + close(element->fd_); + free(element); + break; + } + + char* ls = tcp_endpoint_to_string(element->local_end_); + char* rs = tcp_endpoint_to_string(element->remote_end_); + log_printf(NOTICE, "listening on: %s (remote: %s)", ls ? ls:"(null)", rs ? rs:"(null)"); + if(ls) free(ls); + if(rs) free(rs); + + if(slist_add(list, element) == NULL) { + close(element->fd_); + free(element); + ret = -2; + break; + } - if(slist_add(list, element) == NULL) - return -2; + l = l->ai_next; + } + freeaddrinfo(re); + freeaddrinfo(le); - return 0; + return ret; } void listener_remove(listeners_t* list, int fd) diff --git a/src/listener.h b/src/listener.h index c545bdc..2bd5dc8 100644 --- a/src/listener.h +++ b/src/listener.h @@ -43,7 +43,7 @@ typedef slist_t listeners_t; int listener_init(listeners_t* list); void listener_clear(listeners_t* list); -int listener_add(listeners_t* list, char* laddr, char* lport, char* raddr, char* rport); +int listener_add(listeners_t* list, const char* laddr, const char* lport, const char* raddr, const char* rport); void listener_remove(listeners_t* list, int fd); listener_t* listener_find(listeners_t* list, int fd); void listener_print(listeners_t* list); diff --git a/src/string_list.c b/src/string_list.c index 192ff19..e197749 100644 --- a/src/string_list.c +++ b/src/string_list.c @@ -47,8 +47,11 @@ int string_list_add(string_list_t* list, const char* string) if(!list) return -1; - if(slist_add(list, strdup(string)) == NULL) + char* tmp = strdup(string); + if(slist_add(list, tmp) == NULL) { + free(tmp); return -2; + } return 0; } @@ -29,10 +29,14 @@ #include <stdio.h> #include <stdlib.h> #include <arpa/inet.h> +#include <sys/types.h> +#include <sys/socket.h> +#include <netdb.h> #include "datatypes.h" #include "tcp.h" +#include "log.h" char* tcp_endpoint_to_string(tcp_endpoint_t e) { @@ -68,3 +72,31 @@ char* tcp_endpoint_to_string(tcp_endpoint_t e) free(addrstr); return ret; } + +struct addrinfo* tcp_resolve_endpoint(const char* addr, const char* port, resolv_type_t rt) +{ + struct addrinfo hints, *res; + + res = NULL; + memset (&hints, 0, sizeof (hints)); + hints.ai_socktype = SOCK_STREAM; + hints.ai_flags = AI_PASSIVE | AI_ADDRCONFIG; + + switch(rt) { + 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(addr, port, &hints, &res); + if (errcode != 0) { + log_printf(ERROR, "Error resolving local address (%s:%s): %s", (addr) ? addr : "*", port, gai_strerror(errcode)); + return NULL; + } + if(!res) { + log_printf(ERROR, "getaddrinfo returned no address for %s:%s", addr, port); + return NULL; + } + + return res; +} @@ -31,8 +31,12 @@ #include <sys/types.h> #include <sys/socket.h> +enum resolv_type_enum { ANY, IPV4_ONLY, IPV6_ONLY }; +typedef enum resolv_type_enum resolv_type_t; + typedef struct sockaddr_storage tcp_endpoint_t; char* tcp_endpoint_to_string(tcp_endpoint_t e); +struct addrinfo* tcp_resolve_endpoint(const char* addr, const char* port, resolv_type_t rt); #endif diff --git a/src/tcpproxy.c b/src/tcpproxy.c index 45402c7..d55277e 100644 --- a/src/tcpproxy.c +++ b/src/tcpproxy.c @@ -123,9 +123,25 @@ int main(int argc, char* argv[]) log_printf(NOTICE, "just started..."); options_parse_post(&opt); + listeners_t listeners; + ret = listener_init(&listeners); + if(ret) { + options_clear(&opt); + log_close(); + exit(-1); + } + ret = listener_add(&listeners, opt.local_addr_, opt.local_port_, opt.remote_addr_, opt.remote_port_); + if(ret) { + listener_clear(&listeners); + options_clear(&opt); + log_close(); + exit(-1); + } + priv_info_t priv; if(opt.username_) if(priv_init(&priv, opt.username_, opt.groupname_)) { + listener_clear(&listeners); options_clear(&opt); log_close(); exit(-1); @@ -141,12 +157,14 @@ int main(int argc, char* argv[]) if(opt.chroot_dir_) if(do_chroot(opt.chroot_dir_)) { + listener_clear(&listeners); options_clear(&opt); log_close(); exit(-1); } if(opt.username_) if(priv_drop(&priv)) { + listener_clear(&listeners); options_clear(&opt); log_close(); exit(-1); @@ -166,6 +184,7 @@ int main(int argc, char* argv[]) ret = main_loop(&opt); + listener_clear(&listeners); options_clear(&opt); if(!ret) |