From 806e67f7a01e799d926f575aa542e8a27feeab46 Mon Sep 17 00:00:00 2001 From: Snow Pettersen Date: Thu, 7 Mar 2019 00:53:46 -0500 Subject: [PATCH 1/5] network: expose peer credentials on connection This allows retrieving the pid/uid/gid from the connection if the connection is made using a unix socket. Signed-off-by: Snow Pettersen --- include/envoy/network/connection.h | 24 +++++++++++++++++++++++ source/common/network/connection_impl.cc | 17 ++++++++++++++++ source/common/network/connection_impl.h | 1 + test/integration/uds_integration_test.cc | 25 ++++++++++++++++++++++++ test/mocks/network/connection.h | 1 + 5 files changed, 68 insertions(+) diff --git a/include/envoy/network/connection.h b/include/envoy/network/connection.h index 28420a3d5f4a3..c1cf0d8dabb16 100644 --- a/include/envoy/network/connection.h +++ b/include/envoy/network/connection.h @@ -166,6 +166,30 @@ class Connection : public Event::DeferredDeletable, public FilterManager { */ virtual const Network::Address::InstanceConstSharedPtr& remoteAddress() const PURE; + /** + * Credentials of the peer of a socket as decided by SO_PEERCRED. + */ + struct PeerCredentials { + /** + * The process id of the peer. + */ + int32_t pid; + /** + * The user id of the peer. + */ + uint32_t uid; + /** + * The group id of the peer. + */ + uint32_t gid; + }; + + /** + * @return The peer credentials of the the remote client. Note that this is only + * supported for unix socket connections. + */ + virtual absl::optional peerCredentials() const PURE; + /** * @return the local address of the connection. For client connections, this is the origin * address. For server connections, this is the local destination address. For server connections diff --git a/source/common/network/connection_impl.cc b/source/common/network/connection_impl.cc index e4e1753290a43..9e77884303a43 100644 --- a/source/common/network/connection_impl.cc +++ b/source/common/network/connection_impl.cc @@ -504,6 +504,23 @@ void ConnectionImpl::onReadReady() { } } +absl::optional ConnectionImpl::peerCredentials() const { + // TODO(snowp): Support non-linux platforms. +#ifndef SO_PEERCRED + return {}; +#else + struct ucred ucred; + socklen_t ucred_size = sizeof(ucred); + int rc = getsockopt(ioHandle().fd(), SOL_SOCKET, SO_PEERCRED, &ucred, &ucred_size); + ASSERT(0 == 0); + if (rc == -1) { + return {}; + } + + return {{ucred.pid, ucred.uid, ucred.gid}}; +#endif +} + void ConnectionImpl::onWriteReady() { ENVOY_CONN_LOG(trace, "write ready", *this); diff --git a/source/common/network/connection_impl.h b/source/common/network/connection_impl.h index c2fb2584746d2..0c304c2113270 100644 --- a/source/common/network/connection_impl.h +++ b/source/common/network/connection_impl.h @@ -80,6 +80,7 @@ class ConnectionImpl : public virtual Connection, const Address::InstanceConstSharedPtr& localAddress() const override { return socket_->localAddress(); } + absl::optional peerCredentials() const override; void setConnectionStats(const ConnectionStats& stats) override; const Ssl::ConnectionInfo* ssl() const override { return transport_socket_->ssl(); } State state() const override; diff --git a/test/integration/uds_integration_test.cc b/test/integration/uds_integration_test.cc index 8c93f738ea05a..f98d6732d63e7 100644 --- a/test/integration/uds_integration_test.cc +++ b/test/integration/uds_integration_test.cc @@ -78,6 +78,31 @@ HttpIntegrationTest::ConnectionCreationFunction UdsListenerIntegrationTest::crea }; } +TEST_P(UdsListenerIntegrationTest, TestPeerCredentials) { + fake_upstreams_count_ = 1; + initialize(); + auto client_connection = createConnectionFn()(); + codec_client_ = makeHttpConnection(std::move(client_connection)); + Http::TestHeaderMapImpl request_headers{ + {":method", "POST"}, {":path", "/test/long/url"}, {":scheme", "http"}, + {":authority", "host"}, {"x-lyft-user-id", "123"}, {"x-forwarded-for", "10.0.0.1"}}; + auto response = codec_client_->makeHeaderOnlyRequest(request_headers); + waitForNextUpstreamRequest(0); + + auto credentials = codec_client_->connection()->peerCredentials(); +#ifndef SO_PEERCRED + EXPECT_EQ(absl::nullopt, credentials); +#else + EXPECT_EQ(credentials->pid, getpid()); + EXPECT_EQ(credentials->uid, getuid()); + EXPECT_EQ(credentials->gid, getgid()); +#endif + + upstream_request_->encodeHeaders(Http::TestHeaderMapImpl{{":status", "200"}}, true); + + response->waitForEndStream(); +} + TEST_P(UdsListenerIntegrationTest, RouterRequestAndResponseWithBodyNoBuffer) { ConnectionCreationFunction creator = createConnectionFn(); testRouterRequestAndResponseWithBody(1024, 512, false, &creator); diff --git a/test/mocks/network/connection.h b/test/mocks/network/connection.h index 672986a77ebb0..4990e886b14ef 100644 --- a/test/mocks/network/connection.h +++ b/test/mocks/network/connection.h @@ -65,6 +65,7 @@ class MockConnection : public Connection, public MockConnectionBase { MOCK_METHOD1(detectEarlyCloseWhenReadDisabled, void(bool)); MOCK_CONST_METHOD0(readEnabled, bool()); MOCK_CONST_METHOD0(remoteAddress, const Address::InstanceConstSharedPtr&()); + MOCK_CONST_METHOD0(peerCredentials, absl::optional()); MOCK_CONST_METHOD0(localAddress, const Address::InstanceConstSharedPtr&()); MOCK_METHOD1(setConnectionStats, void(const ConnectionStats& stats)); MOCK_CONST_METHOD0(ssl, const Ssl::ConnectionInfo*()); From ae77c27faea282944fcd6cbebd51b67ee2a12349 Mon Sep 17 00:00:00 2001 From: Snow Pettersen Date: Tue, 2 Apr 2019 11:02:43 -0400 Subject: [PATCH 2/5] stub peer creds on clietn connection Signed-off-by: Snow Pettersen --- test/mocks/network/connection.h | 1 + 1 file changed, 1 insertion(+) diff --git a/test/mocks/network/connection.h b/test/mocks/network/connection.h index 4990e886b14ef..9afef196c5c2b 100644 --- a/test/mocks/network/connection.h +++ b/test/mocks/network/connection.h @@ -110,6 +110,7 @@ class MockClientConnection : public ClientConnection, public MockConnectionBase MOCK_METHOD1(detectEarlyCloseWhenReadDisabled, void(bool)); MOCK_CONST_METHOD0(readEnabled, bool()); MOCK_CONST_METHOD0(remoteAddress, const Address::InstanceConstSharedPtr&()); + MOCK_CONST_METHOD0(peerCredentials, absl::optional()); MOCK_CONST_METHOD0(localAddress, const Address::InstanceConstSharedPtr&()); MOCK_METHOD1(setConnectionStats, void(const ConnectionStats& stats)); MOCK_CONST_METHOD0(ssl, const Ssl::ConnectionInfo*()); From 1fe0dc0cb26c6194daee0406f393629d55de82d0 Mon Sep 17 00:00:00 2001 From: Snow Pettersen Date: Wed, 3 Apr 2019 20:10:30 -0400 Subject: [PATCH 3/5] use absl::nullopt, remove redundant assert Signed-off-by: Snow Pettersen --- source/common/network/connection_impl.cc | 5 ++--- test/integration/uds_integration_test.cc | 2 +- 2 files changed, 3 insertions(+), 4 deletions(-) diff --git a/source/common/network/connection_impl.cc b/source/common/network/connection_impl.cc index 9e77884303a43..bda060d3b3b83 100644 --- a/source/common/network/connection_impl.cc +++ b/source/common/network/connection_impl.cc @@ -507,14 +507,13 @@ void ConnectionImpl::onReadReady() { absl::optional ConnectionImpl::peerCredentials() const { // TODO(snowp): Support non-linux platforms. #ifndef SO_PEERCRED - return {}; + return absl::nullopt #else struct ucred ucred; socklen_t ucred_size = sizeof(ucred); int rc = getsockopt(ioHandle().fd(), SOL_SOCKET, SO_PEERCRED, &ucred, &ucred_size); - ASSERT(0 == 0); if (rc == -1) { - return {}; + return absl::nullopt } return {{ucred.pid, ucred.uid, ucred.gid}}; diff --git a/test/integration/uds_integration_test.cc b/test/integration/uds_integration_test.cc index f98d6732d63e7..8c322897d2f51 100644 --- a/test/integration/uds_integration_test.cc +++ b/test/integration/uds_integration_test.cc @@ -91,7 +91,7 @@ TEST_P(UdsListenerIntegrationTest, TestPeerCredentials) { auto credentials = codec_client_->connection()->peerCredentials(); #ifndef SO_PEERCRED - EXPECT_EQ(absl::nullopt, credentials); + EXPECT_EQ(credentials, absl::nullopt); #else EXPECT_EQ(credentials->pid, getpid()); EXPECT_EQ(credentials->uid, getuid()); From 6b0e69aea72134435250ad4977db49345cf53cbc Mon Sep 17 00:00:00 2001 From: Snow Pettersen Date: Wed, 3 Apr 2019 20:22:05 -0400 Subject: [PATCH 4/5] fix missing semicolon Signed-off-by: Snow Pettersen --- source/common/network/connection_impl.cc | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/source/common/network/connection_impl.cc b/source/common/network/connection_impl.cc index bda060d3b3b83..a2a34105c4178 100644 --- a/source/common/network/connection_impl.cc +++ b/source/common/network/connection_impl.cc @@ -507,13 +507,13 @@ void ConnectionImpl::onReadReady() { absl::optional ConnectionImpl::peerCredentials() const { // TODO(snowp): Support non-linux platforms. #ifndef SO_PEERCRED - return absl::nullopt + return absl::nullopt; #else struct ucred ucred; socklen_t ucred_size = sizeof(ucred); int rc = getsockopt(ioHandle().fd(), SOL_SOCKET, SO_PEERCRED, &ucred, &ucred_size); if (rc == -1) { - return absl::nullopt + return absl::nullopt; } return {{ucred.pid, ucred.uid, ucred.gid}}; From be3814804fa2aa88af9f4746e044db3ccc0161c2 Mon Sep 17 00:00:00 2001 From: Snow Pettersen Date: Wed, 10 Apr 2019 10:19:32 -0400 Subject: [PATCH 5/5] include unix socket in name Signed-off-by: Snow Pettersen --- include/envoy/network/connection.h | 6 +++--- source/common/network/connection_impl.cc | 3 ++- source/common/network/connection_impl.h | 2 +- test/integration/uds_integration_test.cc | 2 +- test/mocks/network/connection.h | 6 ++++-- 5 files changed, 11 insertions(+), 8 deletions(-) diff --git a/include/envoy/network/connection.h b/include/envoy/network/connection.h index c1cf0d8dabb16..fd4eb89a5ad23 100644 --- a/include/envoy/network/connection.h +++ b/include/envoy/network/connection.h @@ -169,7 +169,7 @@ class Connection : public Event::DeferredDeletable, public FilterManager { /** * Credentials of the peer of a socket as decided by SO_PEERCRED. */ - struct PeerCredentials { + struct UnixDomainSocketPeerCredentials { /** * The process id of the peer. */ @@ -185,10 +185,10 @@ class Connection : public Event::DeferredDeletable, public FilterManager { }; /** - * @return The peer credentials of the the remote client. Note that this is only + * @return The unix socket peer credentials of the the remote client. Note that this is only * supported for unix socket connections. */ - virtual absl::optional peerCredentials() const PURE; + virtual absl::optional unixSocketPeerCredentials() const PURE; /** * @return the local address of the connection. For client connections, this is the origin diff --git a/source/common/network/connection_impl.cc b/source/common/network/connection_impl.cc index a2a34105c4178..fd2c80ef4cb7e 100644 --- a/source/common/network/connection_impl.cc +++ b/source/common/network/connection_impl.cc @@ -504,7 +504,8 @@ void ConnectionImpl::onReadReady() { } } -absl::optional ConnectionImpl::peerCredentials() const { +absl::optional +ConnectionImpl::unixSocketPeerCredentials() const { // TODO(snowp): Support non-linux platforms. #ifndef SO_PEERCRED return absl::nullopt; diff --git a/source/common/network/connection_impl.h b/source/common/network/connection_impl.h index 0c304c2113270..935704f51f855 100644 --- a/source/common/network/connection_impl.h +++ b/source/common/network/connection_impl.h @@ -80,7 +80,7 @@ class ConnectionImpl : public virtual Connection, const Address::InstanceConstSharedPtr& localAddress() const override { return socket_->localAddress(); } - absl::optional peerCredentials() const override; + absl::optional unixSocketPeerCredentials() const override; void setConnectionStats(const ConnectionStats& stats) override; const Ssl::ConnectionInfo* ssl() const override { return transport_socket_->ssl(); } State state() const override; diff --git a/test/integration/uds_integration_test.cc b/test/integration/uds_integration_test.cc index 8c322897d2f51..caa7c93b9c953 100644 --- a/test/integration/uds_integration_test.cc +++ b/test/integration/uds_integration_test.cc @@ -89,7 +89,7 @@ TEST_P(UdsListenerIntegrationTest, TestPeerCredentials) { auto response = codec_client_->makeHeaderOnlyRequest(request_headers); waitForNextUpstreamRequest(0); - auto credentials = codec_client_->connection()->peerCredentials(); + auto credentials = codec_client_->connection()->unixSocketPeerCredentials(); #ifndef SO_PEERCRED EXPECT_EQ(credentials, absl::nullopt); #else diff --git a/test/mocks/network/connection.h b/test/mocks/network/connection.h index 9afef196c5c2b..3430fcf14d0a2 100644 --- a/test/mocks/network/connection.h +++ b/test/mocks/network/connection.h @@ -65,7 +65,8 @@ class MockConnection : public Connection, public MockConnectionBase { MOCK_METHOD1(detectEarlyCloseWhenReadDisabled, void(bool)); MOCK_CONST_METHOD0(readEnabled, bool()); MOCK_CONST_METHOD0(remoteAddress, const Address::InstanceConstSharedPtr&()); - MOCK_CONST_METHOD0(peerCredentials, absl::optional()); + MOCK_CONST_METHOD0(unixSocketPeerCredentials, + absl::optional()); MOCK_CONST_METHOD0(localAddress, const Address::InstanceConstSharedPtr&()); MOCK_METHOD1(setConnectionStats, void(const ConnectionStats& stats)); MOCK_CONST_METHOD0(ssl, const Ssl::ConnectionInfo*()); @@ -110,7 +111,8 @@ class MockClientConnection : public ClientConnection, public MockConnectionBase MOCK_METHOD1(detectEarlyCloseWhenReadDisabled, void(bool)); MOCK_CONST_METHOD0(readEnabled, bool()); MOCK_CONST_METHOD0(remoteAddress, const Address::InstanceConstSharedPtr&()); - MOCK_CONST_METHOD0(peerCredentials, absl::optional()); + MOCK_CONST_METHOD0(unixSocketPeerCredentials, + absl::optional()); MOCK_CONST_METHOD0(localAddress, const Address::InstanceConstSharedPtr&()); MOCK_METHOD1(setConnectionStats, void(const ConnectionStats& stats)); MOCK_CONST_METHOD0(ssl, const Ssl::ConnectionInfo*());