Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Don't use transparent proxying for clients on the listener itself #374

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
25 changes: 25 additions & 0 deletions src/address.c
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@
#include <arpa/inet.h> /* inet_pton */
#include <sys/un.h>
#include <assert.h>
#include <string.h>
#include "address.h"


Expand Down Expand Up @@ -259,6 +260,30 @@ address_compare(const struct Address *addr_1, const struct Address *addr_2) {
return result;
}

int
address_addr_eq(const struct Address *addr, const struct sockaddr *sa) {
if (addr->type != SOCKADDR)
return 0;

if (address_sa(addr)->sa_family != sa->sa_family)
return 0;

switch (address_sa(addr)->sa_family) {
case AF_INET:
return !memcmp(&((struct sockaddr_in *)addr->data)->sin_addr,
&((struct sockaddr_in *)sa)->sin_addr,
sizeof(((struct sockaddr_in *)sa)->sin_addr));

case AF_INET6:
return !memcmp(&((struct sockaddr_in6 *)addr->data)->sin6_addr,
&((struct sockaddr_in6 *)sa)->sin6_addr,
sizeof(((struct sockaddr_in6 *)sa)->sin6_addr));

default:
return 0;
}
}

int
address_is_hostname(const struct Address *addr) {
return addr != NULL && addr->type == HOSTNAME;
Expand Down
1 change: 1 addition & 0 deletions src/address.h
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@ struct Address *new_address_sa(const struct sockaddr *, socklen_t);
struct Address *copy_address(const struct Address *);
size_t address_len(const struct Address *);
int address_compare(const struct Address *, const struct Address *);
int address_addr_eq(const struct Address *, const struct sockaddr *);
int address_is_hostname(const struct Address *);
int address_is_sockaddr(const struct Address *);
int address_is_wildcard(const struct Address *);
Expand Down
46 changes: 34 additions & 12 deletions src/connection.c
Original file line number Diff line number Diff line change
Expand Up @@ -630,23 +630,45 @@ initiate_server_connect(struct Connection *con, struct ev_loop *loop) {

if (con->listener->transparent_proxy &&
con->client.addr.ss_family == con->server.addr.ss_family) {
int result;

if (address_addr_eq(con->listener->address,
(struct sockaddr *)&con->client.addr)) {
/* Client is the same host as the listener, bind to a new port. */
struct sockaddr_storage self = con->client.addr;

switch (con->client.addr.ss_family) {
case AF_INET:
((struct sockaddr_in *)&self)->sin_port = 0;
break;

case AF_INET6:
((struct sockaddr_in6 *)&self)->sin6_port = 0;
break;
}

result = bind(sockfd, (struct sockaddr *)&self,
con->client.addr_len);
} else {
#ifdef IP_TRANSPARENT
int on = 1;
int result = setsockopt(sockfd, SOL_IP, IP_TRANSPARENT, &on, sizeof(on));
int on = 1;
result = setsockopt(sockfd, SOL_IP, IP_TRANSPARENT, &on, sizeof(on));
#else
int result = -EPERM;
/* XXX error: not implemented would be better, but this shouldn't be
* reached since it is prohibited in the configuration parser. */
result = -EPERM;
/* XXX error: not implemented would be better, but this shouldn't be
* reached since it is prohibited in the configuration parser. */
#endif
if (result < 0) {
err("setsockopt IP_TRANSPARENT failed: %s", strerror(errno));
close(sockfd);
abort_connection(con);
return;
if (result < 0) {
err("setsockopt IP_TRANSPARENT failed: %s", strerror(errno));
close(sockfd);
abort_connection(con);
return;
}

result = bind(sockfd, (struct sockaddr *)&con->client.addr,
con->client.addr_len);
}

result = bind(sockfd, (struct sockaddr *)&con->client.addr,
con->client.addr_len);
if (result < 0) {
err("bind failed: %s", strerror(errno));
close(sockfd);
Expand Down