Skip to content

Commit

Permalink
Accept hostname in 'relay'
Browse files Browse the repository at this point in the history
  • Loading branch information
semigodking committed Sep 20, 2023
1 parent 7fe2741 commit 99b1122
Show file tree
Hide file tree
Showing 6 changed files with 103 additions and 14 deletions.
13 changes: 7 additions & 6 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,14 +11,15 @@ redsocks.
1. Redirect TCP connections which are blocked via proxy automatically without
need of blacklist.
2. Redirect UDP based DNS requests via TCP connection.
3. Integrated [shadowsocks](http://shadowsocks.org/) proxy support(IPv4 Only).
3. Integrated [shadowsocks](http://shadowsocks.org/) proxy support.
4. Redirect TCP connections without proxy.
5. Redirect TCP connections via specified network interface.
6. UDP transparent proxy via shadowsocks proxy.
7. Support Ful-cone NAT Traversal when working with shadowsocks or socks5 proxy.
8. Integrated HTTPS proxy support(HTTP CONNECT over SSL).
9. Support TCP Fast Open on local server side and shadowsocks client side
10. Support port reuse ([SO_REUSEPORT](https://lwn.net/Articles/542629/))
9. Support TCP Fast Open on local server side and shadowsocks client side.
10. Support port reuse ([SO_REUSEPORT](https://lwn.net/Articles/542629/)).
11. Support IPv6.

[Chinese Reference](https://github.com/semigodking/redsocks/wiki)

Expand Down Expand Up @@ -133,7 +134,7 @@ by field 'login'.
timeout = 13;
autoproxy = 1;
login = "aes-128-cfb"; // field 'login' is reused as encryption
// method of shadowsocks
// method of shadowsocks
password = "your password"; // Your shadowsocks password
}

Expand Down Expand Up @@ -217,8 +218,8 @@ with the following config section.
// Transform UDP DNS requests into TCP DNS requests.
// You can also redirect connections to external TCP DNS server to
// REDSOCKS transparent proxy via iptables.
bind = "192.168.1.1:1053"; // Local server to act as DNS server
tcpdns1 = "8.8.4.4:53"; // DNS server that supports TCP DNS requests
bind = "192.168.1.1:1053"; // Local server to act as DNS server
tcpdns1 = "8.8.4.4:53"; // DNS server that supports TCP DNS requests
tcpdns2 = 8.8.8.8; // DNS server that supports TCP DNS requests
timeout = 4; // Timeout value for TCP DNS requests
}
Expand Down
25 changes: 23 additions & 2 deletions redsocks.c
Original file line number Diff line number Diff line change
Expand Up @@ -205,8 +205,29 @@ static int redsocks_onexit(parser_section *section)
if (!err && instance->config.relay) {
struct sockaddr * addr = (struct sockaddr *)&instance->config.relayaddr;
int addr_size = sizeof(instance->config.relayaddr);
if (evutil_parse_sockaddr_port(instance->config.relay, addr, &addr_size))
err = "invalid relay address";
if (evutil_parse_sockaddr_port(instance->config.relay, addr, &addr_size)) {
char * pos = strchr(instance->config.relay, ':');
char * host = NULL;
if (pos != NULL)
host = strndup(instance->config.relay, pos - instance->config.relay);
else
host = instance->config.relay;
int result = resolve_hostname(host, AF_INET, addr);
if (result != 0) {
result = resolve_hostname(host, AF_INET6, addr);
}
if (result != 0) {
err = "invalid relay address";
}
if (!err && pos != NULL) {
if (addr->sa_family == AF_INET)
((struct sockaddr_in*)addr)->sin_port = htons(atoi(pos+1));
else
((struct sockaddr_in6*)addr)->sin6_port = htons(atoi(pos+1));
}
if (host != instance->config.relay)
free(host);
}
}

if (!err && instance->config.type) {
Expand Down
9 changes: 5 additions & 4 deletions redsocks.conf.example
Original file line number Diff line number Diff line change
Expand Up @@ -71,15 +71,16 @@ redsocks {
// min_accept_backoff = 100;
// max_accept_backoff = 60000;

// `relay` is IP address and port of proxy-server. Domain name is not
// supported yet.
// `relay` is IP address and port of proxy-server.
// Can be:
// [IPv6Address]:port
// [IPv6Address]
// IPv6Address
// IPv4Address:port
// IPv4Address
// domain.name:port
// If no port is given, 0 is used. Usually, a valid port is required.
// Random valid resolved IP address will be used.
relay = "127.0.0.1:1080";

// known types: socks4, socks5, http-connect, http-relay
Expand Down Expand Up @@ -111,7 +112,7 @@ redsocks {
timeout = 10;

// login = "foobar";// field 'login' is reused as encryption
// method of shadowsocks
// method of shadowsocks
// password = "baz";
}

Expand All @@ -124,7 +125,7 @@ redudp {
// `relay' is ip and port of socks5 proxy server.
relay = "10.0.0.1:1080";
login = username;// field 'login' is reused as encryption
// method of shadowsocks
// method of shadowsocks
password = pazzw0rd;

// know types: socks5, shadowsocks
Expand Down
25 changes: 23 additions & 2 deletions redudp.c
Original file line number Diff line number Diff line change
Expand Up @@ -516,8 +516,29 @@ static int redudp_onexit(parser_section *section)
if (!err && instance->config.relay) {
struct sockaddr * addr = (struct sockaddr *)&instance->config.relayaddr;
int addr_size = sizeof(instance->config.relayaddr);
if (evutil_parse_sockaddr_port(instance->config.relay, addr, &addr_size))
err = "invalid relay address";
if (evutil_parse_sockaddr_port(instance->config.relay, addr, &addr_size)) {
char * pos = strchr(instance->config.relay, ':');
char * host = NULL;
if (pos != NULL)
host = strndup(instance->config.relay, pos - instance->config.relay);
else
host = instance->config.relay;
int result = resolve_hostname(host, AF_INET, addr);
if (result != 0) {
result = resolve_hostname(host, AF_INET6, addr);
}
if (result != 0) {
err = "invalid relay address";
}
if (!err && pos != NULL) {
if (addr->sa_family == AF_INET)
((struct sockaddr_in*)addr)->sin_port = htons(atoi(pos+1));
else
((struct sockaddr_in6*)addr)->sin6_port = htons(atoi(pos+1));
}
if (host != instance->config.relay)
free(host);
}
}
else if (!instance->config.relay)
err = "missing relay address";
Expand Down
44 changes: 44 additions & 0 deletions utils.c
Original file line number Diff line number Diff line change
Expand Up @@ -573,5 +573,49 @@ void replace_eventcb(struct bufferevent * buffev, bufferevent_event_cb eventcb)
#endif
}

int resolve_hostname(const char *hostname, int sa_family, struct sockaddr *addr) {
char addr_str[RED_INET_ADDRSTRLEN];
struct addrinfo *ainfo, hints;
memset(&hints, 0, sizeof(hints));
hints.ai_family = sa_family; /* IPv4-only */
hints.ai_socktype = SOCK_STREAM; /* I want to have one address once and ONLY once, that's why I specify socktype and protocol */
hints.ai_protocol = IPPROTO_TCP;
hints.ai_flags = AI_ADDRCONFIG; /* I don't need IPv4 addrs without IPv4 connectivity */
int addr_err = getaddrinfo(hostname, NULL, &hints, &ainfo);
if (addr_err == 0) {
int count, taken;
struct addrinfo *iter;
struct sockaddr *resolved_addr;
for (iter = ainfo, count = 0; iter; iter = iter->ai_next, ++count)
;
taken = red_randui32() % count;
for (iter = ainfo; taken > 0; iter = iter->ai_next, --taken)
;
resolved_addr = iter->ai_addr;
assert(resolved_addr->sa_family == iter->ai_family && iter->ai_family == sa_family);
if (count != 1)
log_error(LOG_WARNING, "%s resolves to %d addresses, using %s",
hostname,
count,
red_inet_ntop((const struct sockaddr_storage*)resolved_addr, addr_str, sizeof(addr_str)));
if (resolved_addr->sa_family == AF_INET) {
memcpy(&(((struct sockaddr_in*)addr)->sin_addr),
&(((struct sockaddr_in*)resolved_addr)->sin_addr),
sizeof(struct in_addr));
}
else if (resolved_addr->sa_family == AF_INET6) {
memcpy(&(((struct sockaddr_in6*)addr)->sin6_addr),
&(((struct sockaddr_in6*)resolved_addr)->sin6_addr),
sizeof(struct in6_addr));
}
freeaddrinfo(ainfo);
addr->sa_family = sa_family;
return 0;
}
else {
log_errno(LOG_ERR, "Unable to resolve hostname: %s", hostname);
return -1;
}
}

/* vim:set tabstop=4 softtabstop=4 shiftwidth=4: */
1 change: 1 addition & 0 deletions utils.h
Original file line number Diff line number Diff line change
Expand Up @@ -118,6 +118,7 @@ void replace_eventcb(struct bufferevent * buffev, bufferevent_event_cb eventcb);
# define RED_INET_ADDRSTRLEN (1 + INET6_ADDRSTRLEN + 1 + 1 + 5 + 1) // [ + addr + ] + : + port + \0
#endif
char *red_inet_ntop(const struct sockaddr_storage * sa, char* buffer, size_t buffer_size);
int resolve_hostname(const char *hostname, int sa_family, struct sockaddr *addr);

/* vim:set tabstop=4 softtabstop=4 shiftwidth=4: */
/* vim:set foldmethod=marker foldlevel=32 foldmarker={,}: */
Expand Down

0 comments on commit 99b1122

Please sign in to comment.