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 <[email protected]>
  • Loading branch information
aszlig committed Aug 6, 2023
1 parent 3790608 commit 3581ecb
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 @@ -114,11 +114,23 @@ bool SockAddr::set_host(const SockAddr &other)
return false;
}

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->is_inet4()) {
this->cast4()->sin_addr.s_addr =
htonl(static_cast<uint32_t>(peercred.pid));
htonl(static_cast<uint32_t>(PEERCRED_PID));
return true;
}

Expand All @@ -128,12 +140,15 @@ bool SockAddr::set_host(const ucred &peercred)
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;
}

Expand Down
8 changes: 8 additions & 0 deletions src/sockaddr.hh
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,10 @@
#include <sys/socket.h>
#include <sys/un.h>

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

struct sockaddr_in6;
struct sockaddr_in;

Expand All @@ -27,7 +31,11 @@ struct SockAddr

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 @@ -15,6 +15,10 @@
#include <stdint.h>
#include <unistd.h>

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

std::optional<Socket::Ptr> Socket::find(int fd)
{
using itype = decltype(Socket::registry)::const_iterator;
Expand Down Expand Up @@ -272,10 +276,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 @@ -460,11 +473,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 3581ecb

Please sign in to comment.