Skip to content

Commit

Permalink
darwin: Use LOCAL_PEERCRED instead of SO_PEERCRED
Browse files Browse the repository at this point in the history
While LOCAL_PEERCRED is somewhat similar to SO_PEERCRED, we
unfortunately don't have access to the PID of the remote peer.

This is something we actually need to properly distinguish the remote
peer by giving it an IP address with the PID encoded, otherwise we'd end
up with duplicate IPs.

On the other hand, using random IP addresses also is not a very good
solution here, since we actually *want* to have the same IP for the same
process.

Right now the UID and GID fields are not used at all on Darwin, but we
really need to figure out a way to properly assign fake IP addresses.

Signed-off-by: aszlig <aszlig@nix.build>
  • Loading branch information
aszlig committed Jul 8, 2021
1 parent aef1c6f commit 92cd86f
Show file tree
Hide file tree
Showing 3 changed files with 50 additions and 5 deletions.
25 changes: 20 additions & 5 deletions src/sockaddr.cc
Original file line number Diff line number Diff line change
Expand Up @@ -107,24 +107,39 @@ bool SockAddr::set_host(const SockAddr &other)
}
}

bool SockAddr::set_host(const ucred &peercred)
#if defined(SO_PEERCRED)
#define PEERCRED_TYPE ucred
#define PEERCRED_PID peercred.pid
#define PEERCRED_GID peercred.gid
#define PEERCRED_UID peercred.uid
#else
#define PEERCRED_TYPE xucred
#define PEERCRED_PID peercred.cr_pid
#define PEERCRED_GID peercred.cr_gid
#define PEERCRED_UID peercred.cr_uid
#endif

bool SockAddr::set_host(const PEERCRED_TYPE &peercred)
{
if (this->ss_family == AF_INET) {
this->cast4()->sin_addr.s_addr =
htonl(static_cast<uint32_t>(peercred.pid));
htonl(static_cast<uint32_t>(PEERCRED_PID));
return true;
} else if (this->ss_family == AF_INET6) {
sockaddr_in6 *addr = this->cast6();
addr->sin6_addr.s6_addr[0] = 0xfe;
addr->sin6_addr.s6_addr[1] = 0x80;
addr->sin6_addr.s6_addr[2] = 0x00;
addr->sin6_addr.s6_addr[3] = 0x00;
uint32_t part = htonl(static_cast<uint32_t>(peercred.uid));
uint32_t part = htonl(static_cast<uint32_t>(PEERCRED_UID));
memcpy(addr->sin6_addr.s6_addr + 4, &part, 4);
part = htonl(static_cast<uint32_t>(peercred.gid));
// XXX!
#if defined(SO_PEERCRED)
part = htonl(static_cast<uint32_t>(PEERCRED_GID));
memcpy(addr->sin6_addr.s6_addr + 8, &part, 4);
part = htonl(static_cast<uint32_t>(peercred.pid));
part = htonl(static_cast<uint32_t>(PEERCRED_PID));
memcpy(addr->sin6_addr.s6_addr + 12, &part, 4);
#endif
return true;
}
return false;
Expand Down
8 changes: 8 additions & 0 deletions src/sockaddr.hh
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,10 @@
#include <netinet/in.h>
#include <sys/un.h>

#if defined(__APPLE__)
#include <sys/ucred.h>
#endif

struct SockAddr : public sockaddr_storage
{
SockAddr();
Expand All @@ -20,7 +24,11 @@ struct SockAddr : public sockaddr_storage

std::optional<std::string> get_host(void) const;
bool set_host(const std::string&);
#if defined(SO_PEERCRED)
bool set_host(const ucred&);
#else
bool set_host(const xucred&);
#endif
bool set_host(const SockAddr&);

bool set_random_host(void);
Expand Down
22 changes: 22 additions & 0 deletions src/socket.cc
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,10 @@
#include <arpa/inet.h>
#include <sys/un.h>

#if defined(__APPLE__)
#include <sys/ucred.h>
#endif

#include "socket.hh"
#include "realcalls.hh"
#include "logging.hh"
Expand Down Expand Up @@ -265,10 +269,19 @@ bool Socket::create_binding(const SockAddr &addr)
if (!local.set_host(addr))
return false;
} else {
#if defined(SO_PEERCRED)
ucred local_cred;
local_cred.uid = getuid();
local_cred.gid = getgid();
local_cred.pid = getpid();
#else
xucred local_cred;
local_cred.cr_uid = getuid();
/* XXX!
local_cred.cr_gid = getgid();
local_cred.cr_pid = getpid();
*/
#endif

// Our local sockaddr, which we only need if we didn't have a
// bind() before our connect.
Expand Down Expand Up @@ -453,11 +466,20 @@ int Socket::accept(int sockfd, struct sockaddr *addr, socklen_t *addrlen)
} else {
// We use SO_PEERCRED to get uid, gid and pid in order to generate
// unique IP addresses.
#if defined(SO_PEERCRED)
ucred peercred;
socklen_t len = sizeof peercred;

if (getsockopt(sockfd, SOL_SOCKET, SO_PEERCRED, &peercred, &len) == -1)
return -1;
#else
xucred peercred;
socklen_t len = sizeof peercred;

if (getsockopt(sockfd, SOL_LOCAL, LOCAL_PEERCRED, &peercred,
&len) == -1)
return -1;
#endif

if (!peer.set_host(peercred)) {
errno = EINVAL;
Expand Down

0 comments on commit 92cd86f

Please sign in to comment.