diff --git a/src/or/rendservice.c b/src/or/rendservice.c
index 2e0f83c6f3..fac782bd9f 100644
--- a/src/or/rendservice.c
+++ b/src/or/rendservice.c
@@ -308,10 +308,26 @@ rend_add_service(rend_service_t *service)
}
}
+/** Return a new rend_service_port_config_t with its path set to
+ * socket_path or empty if socket_path is NULL */
+static rend_service_port_config_t *
+rend_service_port_config_new(const char *socket_path)
+{
+ if (!socket_path)
+ return tor_malloc_zero(sizeof(rend_service_port_config_t));
+
+ const size_t pathlen = strlen(socket_path) + 1;
+ rend_service_port_config_t *conf =
+ tor_malloc_zero(sizeof(rend_service_port_config_t) + pathlen);
+ memcpy(conf->unix_addr, socket_path, pathlen);
+ conf->is_unix_addr = 1;
+ return conf;
+}
+
/** Parses a real-port to virtual-port mapping and returns a new
* rend_service_port_config_t.
*
- * The format is: VirtualPort (IP|RealPort|IP:RealPort)?
+ * The format is: VirtualPort (IP|RealPort|IP:RealPort|'socket':path)?
*
* IP defaults to 127.0.0.1; RealPort defaults to VirtualPort.
*/
@@ -325,6 +341,9 @@ parse_port_config(const char *string)
tor_addr_t addr;
const char *addrport;
rend_service_port_config_t *result = NULL;
+ const char *socket_prefix = "socket:";
+ unsigned int is_unix_addr = 0;
+ char *socket_path = NULL;
sl = smartlist_new();
smartlist_split_string(sl, string, " ",
@@ -347,7 +366,26 @@ parse_port_config(const char *string)
tor_addr_from_ipv4h(&addr, 0x7F000001u); /* 127.0.0.1 */
} else {
addrport = smartlist_get(sl,1);
- if (strchr(addrport, ':') || strchr(addrport, '.')) {
+ /* If it starts with socket:, try to parse it as a socket path */
+ if (!strcmpstart(addrport, socket_prefix)) {
+ if (strlen(addrport + strlen(socket_prefix)) > 0) {
+#ifdef HAVE_SYS_UN_H
+ is_unix_addr = 1;
+ socket_path = tor_strdup(addrport + strlen(socket_prefix));
+#else
+ log_warn(LD_CONFIG,
+ "Hidden service port configuration %s is for an AF_UNIX "
+ "socket, but we have no support available on this platform",
+ escaped(addrport));
+ goto err;
+#endif /* defined(HAVE_SYS_UN_H) */
+ } else {
+ log_warn(LD_CONFIG,
+ "Empty socket path in hidden service port configuration.");
+ goto err;
+ }
+ } else if (strchr(addrport, ':') || strchr(addrport, '.')) {
+ /* else try it as an IP:port pair if it has a : or . in it */
if (tor_addr_port_lookup(addrport, &addr, &p)<0) {
log_warn(LD_CONFIG,"Unparseable address in hidden service port "
"configuration.");
@@ -366,15 +404,21 @@ parse_port_config(const char *string)
}
}
- result = tor_malloc(sizeof(rend_service_port_config_t));
+ /* Allow room for unix_addr */
+ result = rend_service_port_config_new(socket_path);
result->virtual_port = virtport;
- /* TODO actually support AF_UNIX here */
- result->is_unix_addr = 0;
- result->real_port = realport;
- tor_addr_copy(&result->real_addr, &addr);
+ result->is_unix_addr = is_unix_addr;
+ if (!is_unix_addr) {
+ result->real_port = realport;
+ tor_addr_copy(&result->real_addr, &addr);
+ result->unix_addr[0] = '\0';
+ }
+
err:
SMARTLIST_FOREACH(sl, char *, c, tor_free(c));
smartlist_free(sl);
+ if (socket_path) tor_free(socket_path);
+
return result;
}