Skip to content

Commit 695e854

Browse files
committed
rpc: More robust localhost-UNIX detection
evhttp has no direct support for UNIX sockets thus is not able to recognize UNIX peers. Add custom code in HTTPRequest::GetPeer and evunix to recognize these connections as coming from localhost. The previous solution did not work on some libevent versions.
1 parent f5acc05 commit 695e854

File tree

3 files changed

+46
-6
lines changed

3 files changed

+46
-6
lines changed

src/httpserver.cpp

Lines changed: 11 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -663,16 +663,21 @@ CService HTTPRequest::GetPeer()
663663
evhttp_connection* con = evhttp_request_get_connection(req);
664664
CService peer;
665665
if (con) {
666+
#ifdef HAVE_SOCKADDR_UN
667+
// evhttp has no way to query what bindsocket a connection
668+
// came in on, so we need this low-level code to be able to
669+
// correctly mark UNIX socket connections as coming from localhost.
670+
struct bufferevent *bev = evhttp_connection_get_bufferevent(con);
671+
if (bev && evunix_is_conn_from_unix(bev)) {
672+
// As we have no way to signify "UNIX localhost" here, just return
673+
// IPv6 localhost.
674+
return LookupNumeric("::1", 0);
675+
}
676+
#endif
666677
// evhttp retains ownership over returned address string
667678
const char* address = "";
668679
uint16_t port = 0;
669680
evhttp_connection_get_peer(con, (char**)&address, &port);
670-
if (!strcmp(address, "localhost")) {
671-
/* Special: will get here for UNIX sockets. As we have no way to indicate that,
672-
* just pass localhost IPv6.
673-
*/
674-
address = "::1";
675-
}
676681
peer = LookupNumeric(address, port);
677682
}
678683
return peer;

src/support/evunix.cpp

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -84,6 +84,18 @@ int evunix_connect_fd(const boost::filesystem::path &path)
8484
return fd;
8585
}
8686

87+
bool evunix_is_conn_from_unix_fd(int fd)
88+
{
89+
struct sockaddr_un peer_unix;
90+
socklen_t peer_unix_len = sizeof(peer_unix);
91+
if (getpeername(fd, (sockaddr*)&peer_unix, &peer_unix_len) == 0) {
92+
if (peer_unix.sun_family == AF_UNIX) {
93+
return true;
94+
}
95+
}
96+
return false;
97+
}
98+
8799
struct bufferevent *evunix_bind(struct event_base *base, const boost::filesystem::path &path)
88100
{
89101
struct bufferevent *rv;
@@ -105,3 +117,12 @@ struct bufferevent *evunix_connect(struct event_base *base, const boost::filesys
105117
}
106118
return rv;
107119
}
120+
121+
bool evunix_is_conn_from_unix(struct bufferevent *bev)
122+
{
123+
int fd;
124+
if ((fd = bufferevent_getfd(bev)) != -1) {
125+
return evunix_is_conn_from_unix_fd(fd);
126+
}
127+
return false;
128+
}

src/support/evunix.h

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,10 @@
1111
struct event_base;
1212
struct bufferevent;
1313

14+
// All these functions come in a plain (high-level) and _fd (low-level)
15+
// variant. The plain version takes/yields a libevent bufferevent*, the _fd
16+
// functions file descriptor.
17+
1418
/** Bind on a UNIX socket.
1519
* Returns a bufferevent that can be used to send or receive data on the socket, or NULL
1620
* on failure.
@@ -39,4 +43,14 @@ int evunix_connect_fd(const boost::filesystem::path &path);
3943
*/
4044
bool evunix_remove_socket(const boost::filesystem::path &path);
4145

46+
/** Return whether incoming connection fd came in on a UNIX socket.
47+
*/
48+
bool evunix_is_conn_from_unix_fd(int fd);
49+
50+
/** Return whether incoming connection bev came in on a UNIX socket.
51+
* This is a hack because evhttp won't let us know what bound socket a connection
52+
* came in on.
53+
*/
54+
bool evunix_is_conn_from_unix(struct bufferevent *bev);
55+
4256
#endif

0 commit comments

Comments
 (0)