From 174a9f39da1f09c6ffd9c6f0b3a6a42da5ec4163 Mon Sep 17 00:00:00 2001 From: Christian Pointner Date: Sun, 28 Nov 2010 22:55:24 +0000 Subject: source address to connect from can now be specified git-svn-id: https://svn.spreadspace.org/tcpproxy/trunk@13 e61f0598-a718-4e21-a8f0-0aadfa62ad6b --- src/clients.c | 18 +++++++++++++++++- src/clients.h | 2 +- src/listener.c | 24 +++++++++++++++++++++--- src/listener.h | 3 ++- src/options.c | 6 ++++++ src/options.h | 1 + src/tcp.c | 6 ++++-- src/tcpproxy.c | 2 +- 8 files changed, 53 insertions(+), 9 deletions(-) (limited to 'src') diff --git a/src/clients.c b/src/clients.c index 9e5c9fc..6db10fc 100644 --- a/src/clients.c +++ b/src/clients.c @@ -63,7 +63,7 @@ void clients_clear(clients_t* list) slist_clear(list); } -int clients_add(clients_t* list, int fd, const tcp_endpoint_t* remote_end) +int clients_add(clients_t* list, int fd, const tcp_endpoint_t* remote_end, const tcp_endpoint_t* source_end) { if(!list) @@ -87,6 +87,22 @@ int clients_add(clients_t* list, int fd, const tcp_endpoint_t* remote_end) return -1; } + if(source_end->ss_family != AF_UNSPEC) { + socklen_t socklen = sizeof(*source_end); + if(source_end->ss_family == AF_INET) + socklen = sizeof(struct sockaddr_in); + else if (source_end->ss_family == AF_INET6) + socklen = sizeof(struct sockaddr_in6); + + if(bind(element->fd_[1], (struct sockaddr *)source_end, socklen)==-1) { + log_printf(INFO, "Error on bind(): %s, not adding client %d", strerror(errno), element->fd_[0]); + close(element->fd_[0]); + close(element->fd_[1]); + free(element); + return -1; + } + } + socklen_t socklen = sizeof(*remote_end); if(remote_end->ss_family == AF_INET) socklen = sizeof(struct sockaddr_in); diff --git a/src/clients.h b/src/clients.h index 7052161..8a78aa2 100644 --- a/src/clients.h +++ b/src/clients.h @@ -47,7 +47,7 @@ typedef slist_t clients_t; int clients_init(clients_t* list); void clients_clear(clients_t* list); -int clients_add(clients_t* list, int fd, const tcp_endpoint_t* remote_end); +int clients_add(clients_t* list, int fd, const tcp_endpoint_t* remote_end, const tcp_endpoint_t* source_end); void clients_remove(clients_t* list, int fd); client_t* clients_find(clients_t* list, int fd); void clients_print(clients_t* list); diff --git a/src/listener.c b/src/listener.c index e649bf8..5e34c3d 100644 --- a/src/listener.c +++ b/src/listener.c @@ -66,7 +66,7 @@ void listener_clear(listeners_t* list) slist_clear(list); } -int listener_add(listeners_t* list, const char* laddr, const char* lport, const char* raddr, const char* rport) +int listener_add(listeners_t* list, const char* laddr, const char* lport, const char* raddr, const char* rport, const char* saddr) { if(!list) return -1; @@ -76,9 +76,20 @@ int listener_add(listeners_t* list, const char* laddr, const char* lport, const if(!re) return -1; + struct addrinfo* se = NULL; + if(saddr) { + se = tcp_resolve_endpoint(saddr, NULL, ANY); + if(!se) { + freeaddrinfo(re); + return -1; + } + } + struct addrinfo* le = tcp_resolve_endpoint(laddr, lport, ANY); if(!le) { freeaddrinfo(re); + if(se) + freeaddrinfo(se); return -1; } @@ -93,6 +104,10 @@ int listener_add(listeners_t* list, const char* laddr, const char* lport, const memset(&(element->remote_end_), 0, sizeof(element->remote_end_)); memcpy(&(element->remote_end_), re->ai_addr, re->ai_addrlen); + memset(&(element->source_end_), 0, sizeof(element->source_end_)); + if(se) memcpy(&(element->source_end_), se->ai_addr, se->ai_addrlen); + else element->source_end_.ss_family = AF_UNSPEC; + memset(&(element->local_end_), 0, sizeof(element->local_end_)); memcpy(&(element->local_end_), l->ai_addr, l->ai_addrlen); @@ -135,9 +150,11 @@ int listener_add(listeners_t* list, const char* laddr, const char* lport, const 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)"); + char* ss = tcp_endpoint_to_string(element->source_end_); + log_printf(NOTICE, "listening on: %s (remote: %s%s%s)", ls ? ls:"(null)", rs ? rs:"(null)", ss ? " with source " : "", ss ? ss : ""); if(ls) free(ls); if(rs) free(rs); + if(ss) free(ss); if(slist_add(list, element) == NULL) { close(element->fd_); @@ -149,6 +166,7 @@ int listener_add(listeners_t* list, const char* laddr, const char* lport, const l = l->ai_next; } freeaddrinfo(re); + if(se) freeaddrinfo(se); freeaddrinfo(le); return ret; @@ -231,7 +249,7 @@ int listener_handle_accept(listeners_t* list, clients_t* clients, fd_set* set) if(rs) free(rs); FD_CLR(l->fd_, set); - clients_add(clients, new_client, &(l->remote_end_)); + clients_add(clients, new_client, &(l->remote_end_), &(l->source_end_)); } tmp = tmp->next_; } diff --git a/src/listener.h b/src/listener.h index 8e87e96..11d5d24 100644 --- a/src/listener.h +++ b/src/listener.h @@ -38,6 +38,7 @@ typedef struct { int fd_; tcp_endpoint_t local_end_; tcp_endpoint_t remote_end_; + tcp_endpoint_t source_end_; } listener_t; void listener_delete_element(void* e); @@ -46,7 +47,7 @@ typedef slist_t listeners_t; int listener_init(listeners_t* list); void listener_clear(listeners_t* list); -int listener_add(listeners_t* list, const char* laddr, const char* lport, const char* raddr, const char* rport); +int listener_add(listeners_t* list, const char* laddr, const char* lport, const char* raddr, const char* rport, const char* saddr); 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/options.c b/src/options.c index 27c97d0..39e53ee 100644 --- a/src/options.c +++ b/src/options.c @@ -182,6 +182,7 @@ int options_parse(options_t* opt, int argc, char* argv[]) PARSE_STRING_PARAM("-p","--local-port", opt->local_port_) PARSE_STRING_PARAM("-r","--remote-addr", opt->remote_addr_) PARSE_STRING_PARAM("-o","--remote-port", opt->remote_port_) + PARSE_STRING_PARAM("-s","--source-addr", opt->source_addr_) PARSE_STRING_PARAM("-c","--config", opt->config_file_) else return i; @@ -222,6 +223,7 @@ void options_default(options_t* opt) opt->local_port_ = NULL; opt->remote_addr_ = NULL; opt->remote_port_ = NULL; + opt->source_addr_ = NULL; opt->config_file_ = strdup(CONFFILE); string_list_init(&opt->log_targets_); opt->debug_ = 0; @@ -251,6 +253,8 @@ void options_clear(options_t* opt) free(opt->remote_addr_); if(opt->remote_port_) free(opt->remote_port_); + if(opt->source_addr_) + free(opt->source_addr_); if(opt->config_file_) free(opt->config_file_); } @@ -272,6 +276,7 @@ void options_print_usage() printf(" [-p|--local-port] local port to listen on\n"); printf(" [-r|--remote-addr] remote address to connect to\n"); printf(" [-o|--remote-port] remote port to connect to\n"); + printf(" [-r|--source-addr] source address to connect from\n"); printf(" [-c|--config] configuration file\n"); } @@ -298,6 +303,7 @@ void options_print(options_t* opt) printf("local_port: '%s'\n", opt->local_port_); printf("remote_addr: '%s'\n", opt->remote_addr_); printf("remote_port: '%s'\n", opt->remote_port_); + printf("source_addr: '%s'\n", opt->source_addr_); printf("config_file: '%s'\n", opt->config_file_); printf("debug: %s\n", !opt->debug_ ? "false" : "true"); } diff --git a/src/options.h b/src/options.h index 197d337..aa0f751 100644 --- a/src/options.h +++ b/src/options.h @@ -43,6 +43,7 @@ struct options_struct { char* local_port_; char* remote_addr_; char* remote_port_; + char* source_addr_; char* config_file_; int debug_; }; diff --git a/src/tcp.c b/src/tcp.c index 0211526..cbc9134 100644 --- a/src/tcp.c +++ b/src/tcp.c @@ -60,6 +60,8 @@ char* tcp_endpoint_to_string(tcp_endpoint_t e) addrstr_len = INET6_ADDRSTRLEN + 1; addrport_sep = '.'; break; + case AF_UNSPEC: + return NULL; default: asprintf(&ret, "unknown address type"); return ret; @@ -90,11 +92,11 @@ struct addrinfo* tcp_resolve_endpoint(const char* addr, const char* port, resolv 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)); + log_printf(ERROR, "Error resolving local address (%s:%s): %s", (addr) ? addr : "*", (port) ? port : "0", gai_strerror(errcode)); return NULL; } if(!res) { - log_printf(ERROR, "getaddrinfo returned no address for %s:%s", addr, port); + log_printf(ERROR, "getaddrinfo returned no address for %s:%s", (addr) ? addr : "*", (port) ? port : "0"); return NULL; } diff --git a/src/tcpproxy.c b/src/tcpproxy.c index 6a55ea1..2abf6e6 100644 --- a/src/tcpproxy.c +++ b/src/tcpproxy.c @@ -145,7 +145,7 @@ int main(int argc, char* argv[]) log_close(); exit(-1); } - ret = listener_add(&listeners, opt.local_addr_, opt.local_port_, opt.remote_addr_, opt.remote_port_); + ret = listener_add(&listeners, opt.local_addr_, opt.local_port_, opt.remote_addr_, opt.remote_port_, opt.source_addr_); if(ret) { listener_clear(&listeners); options_clear(&opt); -- cgit v1.2.3