summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorChristian Pointner <equinox@spreadspace.org>2010-11-27 03:31:35 +0000
committerChristian Pointner <equinox@spreadspace.org>2010-11-27 03:31:35 +0000
commit4793dc0638330ef5296c126d136489228d9521b0 (patch)
tree25623cd2a2388ec9ad16ac04107f0aaef91daac9
parentadded tcp listener list (diff)
listening on tcp sockets works now
git-svn-id: https://svn.spreadspace.org/tcpproxy/trunk@8 e61f0598-a718-4e21-a8f0-0aadfa62ad6b
-rw-r--r--src/listener.c97
-rw-r--r--src/listener.h2
-rw-r--r--src/string_list.c5
-rw-r--r--src/tcp.c32
-rw-r--r--src/tcp.h4
-rw-r--r--src/tcpproxy.c19
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;
}
diff --git a/src/tcp.c b/src/tcp.c
index 42db969..0211526 100644
--- a/src/tcp.c
+++ b/src/tcp.c
@@ -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;
+}
diff --git a/src/tcp.h b/src/tcp.h
index a2c50d6..f56ff46 100644
--- a/src/tcp.h
+++ b/src/tcp.h
@@ -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)