diff options
author | Stef Walter <stef@thewalter.net> | 2010-10-28 15:17:05 +0000 |
---|---|---|
committer | Stef Walter <stef@thewalter.net> | 2011-01-23 15:47:45 -0600 |
commit | d806a9d9e19ae13ed8dbf4f26dce3c2afdde7c6a (patch) | |
tree | 0d89b936d1bb8c325efc6f5f731f14d18933f804 /common/spio.c | |
parent | e4c5c1f56e27da22aa0cd7960eee723750d6f3fe (diff) |
Initial implementation of true transparent proxying on linux.
Diffstat (limited to 'common/spio.c')
-rw-r--r-- | common/spio.c | 79 |
1 files changed, 51 insertions, 28 deletions
diff --git a/common/spio.c b/common/spio.c index 5d0733f..736ccc2 100644 --- a/common/spio.c +++ b/common/spio.c @@ -150,45 +150,68 @@ void spio_attach(spctx_t* ctx, spio_t* io, int fd, struct sockaddr_any* peer) io->_ln = 0; } -int spio_connect(spctx_t* ctx, spio_t* io, const struct sockaddr_any* sany, - const char* addrname) +int spio_connect(spctx_t* ctx, spio_t* io, const struct sockaddr_any* sdst, + const char* dstname, const struct sockaddr_any* ssrc, const char *srcname) { - int ret = 0; - int fd; - - ASSERT(ctx && io && sany && addrname); - ASSERT(io->fd == -1); - - if((fd = socket(SANY_TYPE(*sany), SOCK_STREAM, 0)) == -1) - RETURN(-1); - - if(setsockopt(fd, SOL_SOCKET, SO_RCVTIMEO, &(g_state.timeout), sizeof(g_state.timeout)) == -1 || - setsockopt(fd, SOL_SOCKET, SO_SNDTIMEO, &(g_state.timeout), sizeof(g_state.timeout)) == -1) - sp_messagex(ctx, LOG_DEBUG, "%s: couldn't set timeouts on connection", GET_IO_NAME(io)); + int ret = 0; + int fd; + + ASSERT(ctx && io && sdst && dstname); + ASSERT(io->fd == -1); + + if((fd = socket(SANY_TYPE(*sdst), SOCK_STREAM, 0)) == -1) + RETURN(-1); + + if(setsockopt(fd, SOL_SOCKET, SO_RCVTIMEO, &(g_state.timeout), sizeof(g_state.timeout)) == -1 || + setsockopt(fd, SOL_SOCKET, SO_SNDTIMEO, &(g_state.timeout), sizeof(g_state.timeout)) == -1) + sp_messagex(ctx, LOG_DEBUG, "%s: couldn't set timeouts on connection", GET_IO_NAME(io)); + + fcntl(fd, F_SETFD, fcntl(fd, F_GETFD, 0) | FD_CLOEXEC); + + if (ssrc != NULL) { +#ifdef LINUX_NETFILTER + int value = 1; + if(setsockopt(fd, SOL_IP, IP_TRANSPARENT, &value, sizeof(value)) < 0) { + sp_message(ctx, LOG_DEBUG, "%s: couldn't set transparent mode on connection", + GET_IO_NAME(io)); + ssrc = NULL; + } +#else + /* Can't set source address on other OS */ + ssrc = NULL; +#endif + } - fcntl(fd, F_SETFD, fcntl(fd, F_GETFD, 0) | FD_CLOEXEC); + if (ssrc != NULL) { + if(bind(fd, &SANY_ADDR(*ssrc), SANY_LEN(*ssrc)) < 0) + sp_message(ctx, LOG_WARNING, "%s: couldn't set source of transparent connection to: %s", + GET_IO_NAME(io), srcname); + else + sp_messagex(ctx, LOG_DEBUG, "%s: setup source of transparent connection: %s", + GET_IO_NAME(io), srcname); + } - if(connect(fd, &SANY_ADDR(*sany), SANY_LEN(*sany)) == -1) + if(connect(fd, &SANY_ADDR(*sdst), SANY_LEN(*sdst)) == -1) { close_raw(&fd); - RETURN(-1); + RETURN(-1); } - spio_attach(ctx, io, fd, NULL); + spio_attach(ctx, io, fd, NULL); cleanup: - if(ret < 0) - { - if(spio_valid(io)) - close_raw(&(io->fd)); + if(ret < 0) + { + if(spio_valid(io)) + close_raw(&(io->fd)); - sp_message(ctx, LOG_ERR, "%s: couldn't connect to: %s", GET_IO_NAME(io), addrname); - return -1; - } + sp_message(ctx, LOG_ERR, "%s: couldn't connect to: %s", GET_IO_NAME(io), dstname); + return -1; + } - ASSERT(io->fd != -1); - sp_messagex(ctx, LOG_DEBUG, "%s connected to: %s", GET_IO_NAME(io), io->peername); - return 0; + ASSERT(io->fd != -1); + sp_messagex(ctx, LOG_DEBUG, "%s connected to: %s", GET_IO_NAME(io), io->peername); + return 0; } void spio_disconnect(spctx_t* ctx, spio_t* io) |