Skip to content
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
6 changes: 6 additions & 0 deletions sniproxy.conf
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,12 @@ listen 80 {
# reduce the maximum number of simultaneous connections possible.
source 192.0.2.10

# Bind device for outgoing connections
#
# This is not available for all platforms.
# Root is required for SO_BINDTODEVICE
#device eth1

# Log the content of bad requests
#bad_requests log

Expand Down
8 changes: 8 additions & 0 deletions src/config.c
Original file line number Diff line number Diff line change
Expand Up @@ -132,6 +132,14 @@ struct Keyword listener_stanza_grammar[] = {
(int(*)(void *, char *))accept_listener_source_address,
NULL,
NULL},

#ifdef SO_BINDTODEVICE
{ "device",
NULL,
(int(*)(void *, char *))accept_listener_device_name,
NULL,
NULL},
#endif
{ "access_log",
(void *(*)())new_logger_builder,
(int(*)(void *, char *))accept_logger_filename,
Expand Down
47 changes: 47 additions & 0 deletions src/connection.c
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <net/if.h>
#include <netdb.h> /* getaddrinfo */
#include <unistd.h> /* close */
#include <fcntl.h>
Expand Down Expand Up @@ -221,6 +222,7 @@ server_socket_open(const struct Connection *con) {
static void
connection_cb(struct ev_loop *loop, struct ev_io *w, int revents) {
struct Connection *con = (struct Connection *)w->data;

int is_client = &con->client.watcher == w;
struct Buffer *input_buffer =
is_client ? con->client.buffer : con->server.buffer;
Expand Down Expand Up @@ -463,6 +465,8 @@ resolv_cb(struct Address *result, void *data) {
struct Connection *con = cb_data->connection;
struct ev_loop *loop = cb_data->loop;

debug("[DEBUG] %s(): Resolve '%s'", __FUNCTION__, address_hostname(cb_data->address));

if (con->state != RESOLVING) {
info("resolv_cb() called for connection not in RESOLVING state");
return;
Expand All @@ -484,6 +488,13 @@ resolv_cb(struct Address *result, void *data) {

con->state = RESOLVED;

char tmp1[INET6_ADDRSTRLEN + 8];
char tmp2[INET6_ADDRSTRLEN + 8];
debug("[DEBUG] %s(): Resolved. server='%s', client='%s'", __FUNCTION__,
display_sockaddr(&con->server.addr, tmp1, sizeof(tmp1)),
display_sockaddr(&con->client.addr, tmp2, sizeof(tmp2))
);

initiate_server_connect(con, loop);
}

Expand All @@ -499,6 +510,15 @@ free_resolv_cb_data(struct resolv_cb_data *cb_data) {

static void
initiate_server_connect(struct Connection *con, struct ev_loop *loop) {
char tmp1[INET6_ADDRSTRLEN + 8];
char tmp2[INET6_ADDRSTRLEN + 8];

debug("[DEBUG] %s(): Connecting to '%s', client='%s'",
__FUNCTION__,
display_sockaddr(&con->server.addr, tmp1, sizeof(tmp1)),
display_sockaddr(&con->client.addr, tmp2, sizeof(tmp2))
);

#ifdef HAVE_ACCEPT4
int sockfd = socket(con->server.addr.ss_family, SOCK_STREAM | SOCK_NONBLOCK, 0);
#else
Expand All @@ -513,6 +533,7 @@ initiate_server_connect(struct Connection *con, struct ev_loop *loop) {
return;
}


#ifndef HAVE_ACCEPT4
int flags = fcntl(sockfd, F_GETFL, 0);
fcntl(sockfd, F_SETFL, flags | O_NONBLOCK);
Expand Down Expand Up @@ -553,6 +574,11 @@ initiate_server_connect(struct Connection *con, struct ev_loop *loop) {
return;
}

debug("[DEBUG] %s(): Use source address '%s'",
__FUNCTION__,
inet_ntoa(((struct sockaddr_in *) address_sa(con->listener->source_address))->sin_addr));

int result = 0;
int tries = 5;
do {
result = bind(sockfd,
Expand All @@ -570,6 +596,27 @@ initiate_server_connect(struct Connection *con, struct ev_loop *loop) {
}
}

#ifdef SO_BINDTODEVICE
if (con->listener->device_name) {
debug("[DEBUG] %s(): Bind to interface '%s'", __FUNCTION__, con->listener->device_name);

struct ifreq ifr;

memcpy(&ifr.ifr_name, con->listener->device_name, sizeof(ifr.ifr_name));

if (setsockopt(sockfd, SOL_SOCKET, SO_BINDTODEVICE,
(void *)&ifr, sizeof(ifr)) < 0) {

err("bind failed: %s", strerror(errno));
close(sockfd);
abort_connection(con);
return;
}

}
#endif

debug("[DEBUG] %s(): Connect", __FUNCTION__);
int result = connect(sockfd,
(struct sockaddr *)&con->server.addr,
con->server.addr_len);
Expand Down
65 changes: 65 additions & 0 deletions src/listener.c
Original file line number Diff line number Diff line change
Expand Up @@ -166,6 +166,7 @@ listeners_reload(struct Listener_head *existing_listeners,
*/
static void
listener_update(struct Listener *existing_listener, struct Listener *new_listener, const struct Table_head *tables) {
debug("[DEBUG] %s(): ", __FUNCTION__);
assert(existing_listener != NULL);
assert(new_listener != NULL);
assert(address_compare(existing_listener->address, new_listener->address) == 0);
Expand All @@ -178,6 +179,12 @@ listener_update(struct Listener *existing_listener, struct Listener *new_listene
existing_listener->source_address = new_listener->source_address;
new_listener->source_address = NULL;

#ifdef SO_BINDTODEVICE
free(existing_listener->device_name);
existing_listener->device_name = new_listener->device_name;
new_listener->device_name = NULL;
#endif

existing_listener->protocol = new_listener->protocol;

free(existing_listener->table_name);
Expand Down Expand Up @@ -211,6 +218,9 @@ new_listener() {
return NULL;
}

#ifdef SO_BINDTODEVICE
listener->device_name = NULL;
#endif
listener->address = NULL;
listener->fallback_address = NULL;
listener->source_address = NULL;
Expand Down Expand Up @@ -329,6 +339,8 @@ accept_listener_ipv6_v6only(struct Listener *listener, char *ipv6_v6only) {

int
accept_listener_fallback_address(struct Listener *listener, char *fallback) {
debug("[DEBUG] %s(): load fallback address from config: '%s'", __FUNCTION__, fallback);

if (listener->fallback_address != NULL) {
err("Duplicate fallback address: %s", fallback);
return 0;
Expand Down Expand Up @@ -366,10 +378,21 @@ accept_listener_fallback_address(struct Listener *listener, char *fallback) {

int
accept_listener_source_address(struct Listener *listener, char *source) {
debug("[DEBUG] %s(): load source address from config: %s", __FUNCTION__, source);

if (listener->source_address != NULL || listener->transparent_proxy) {
err("Duplicate source address: %s", source);
return 0;
}
#ifdef SO_BINDTODEVICE
if (listener->device_name != NULL) {
err("Config Error: Cannot set source address '%s' with bind device '%s'",
listener->source_address,
listener->device_name
);
return 0;
}
#endif

if (strcasecmp("client", source) == 0) {
#ifdef IP_TRANSPARENT
Expand Down Expand Up @@ -399,8 +422,40 @@ accept_listener_source_address(struct Listener *listener, char *source) {
display_address(listener->address, address, sizeof(address)));
}

debug("[DEBUG] %s(): source address '%s' set.", __FUNCTION__, source);
return 1;
}


#ifdef SO_BINDTODEVICE
int
accept_listener_device_name(struct Listener *listener, char *device_name) {
debug("[DEBUG] %s(): load device name from config: %s", __FUNCTION__, device_name);

if (getuid() != 0) {
err("Binding device '%s' requires ROOT access.", device_name);
return 0;
}

if (listener->device_name != NULL) {
err("Duplicate device name: %s", device_name);
return 0;
}

if (listener->device_name != NULL) {
err("Config Error: Cannot set bind device '%s' with source address '%s'",
listener->device_name,
listener->source_address
);
return 0;
}

listener->device_name = strdup(device_name);

debug("[DEBUG] %s(): bind device '%s' set.", __FUNCTION__, listener->device_name);
return 1;
}
#endif

int
accept_listener_bad_request_action(struct Listener *listener, char *action) {
Expand Down Expand Up @@ -667,6 +722,11 @@ print_listener_config(FILE *file, const struct Listener *listener) {
display_address(listener->source_address,
address, sizeof(address)));

#ifdef SO_BINDTODEVICE
if (listener->device_name)
fprintf(file, "\tdevice %s\n", listener->device_name);
#endif

if (listener->reuseport)
fprintf(file, "\treuseport on\n");

Expand All @@ -692,6 +752,11 @@ free_listener(struct Listener *listener) {
free(listener->address);
free(listener->fallback_address);
free(listener->source_address);

#ifdef SO_BINDTODEVICE
listener->device_name = NULL;
#endif

free(listener->table_name);

table_ref_put(listener->table);
Expand Down
7 changes: 7 additions & 0 deletions src/listener.h
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,10 @@ struct Listener {
struct Logger *access_log;
int log_bad_requests, reuseport, transparent_proxy, ipv6_v6only;

#ifdef SO_BINDTODEVICE
char *device_name;
#endif

/* Runtime fields */
int reference_count;
struct ev_io watcher;
Expand All @@ -55,6 +59,9 @@ int accept_listener_arg(struct Listener *, char *);
int accept_listener_table_name(struct Listener *, char *);
int accept_listener_fallback_address(struct Listener *, char *);
int accept_listener_source_address(struct Listener *, char *);
#ifdef SO_BINDTODEVICE
int accept_listener_device_name(struct Listener *, char *);
#endif
int accept_listener_protocol(struct Listener *, char *);
int accept_listener_reuseport(struct Listener *, char *);
int accept_listener_ipv6_v6only(struct Listener *, char *);
Expand Down