1

I've written a small dynamic library that interposes calls to getaddrinfo and connect. I insert this library using DYLD_INSERT_LIBRARIES on Firefox and Safari to hijack requests for www.apple.com and send them to www.microsoft.com. The code works on Firefox, but while Safari calls into my interposed functions, it ignores the redirection.

I'm wondering if anyone has insight into why Safari ignores the redirection and whether there's a way, perhaps via addrinfo flags, to get Safari to behave as Firefox does. My code listing follows.

// -*- mode: c++ -*-

#include <sys/socket.h>
#include <sys/types.h>
#include <sys/uio.h>
#include <netdb.h>
#include <arpa/inet.h>
#include <unistd.h>
#include <dlfcn.h>
#include <dns_sd.h>
#include <cstdio>
#include <cstdlib>
#include <cstdarg>
#include <cstring>
#include <string>

typedef int (*connect_type) (int, struct sockaddr const*, socklen_t);
typedef int (*getaddrinfo_type)(
        const char*, const char*, struct addrinfo const*, addrinfo**);

connect_type     real_connect     = 0;
getaddrinfo_type real_getaddrinfo = 0;

int
do_getaddrinfo_impl(const char* nodename, const char* servname,
                    struct addrinfo const* hints, struct addrinfo** ppai) 
{
    int result = real_getaddrinfo (nodename, servname, hints, ppai);
    if(result != 0) {
        fprintf(stderr, "! real_getaddrinfo error on %s: %s\n", nodename, gai_strerror(result));
    }

    return result;
}

int
do_getaddrinfo(const char* nodename, const char* servname,
               struct addrinfo const* hints, struct addrinfo** ppai) 
{
    if (0 == nodename) {
        return do_getaddrinfo_impl(nodename, servname, hints, ppai);
    }

    if (hints->ai_family == AF_INET6) {
        printf ("# do_getaddrinfo : IPv6 resolution\n");
        return do_getaddrinfo_impl(nodename, servname, hints, ppai);
    }

    if (   hints->ai_flags & AI_PASSIVE 
        || hints->ai_flags & AI_CANONNAME 
        || hints->ai_flags & AI_NUMERICHOST 
        || hints->ai_flags & AI_NUMERICSERV) {
        printf ("# do_getaddrinfo : unsupported resolution flags\n");
        return do_getaddrinfo_impl (nodename, servname, hints, ppai);
    }

    if ((hints->ai_flags & AI_V4MAPPED) && !(hints->ai_flags & AI_ALL)) {
        printf ("# do_getaddrinfo : unsupported IPv6-mapping\n");
        return do_getaddrinfo_impl (nodename, servname, hints, ppai);
    }

    // redirect requests for www.apple.com to microsoft at 65.55.57.80 (0x41373950)
    if(0 == strcmp(nodename, "www.apple.com")) {
        addrinfo* pai = (addrinfo*)calloc (1, sizeof (addrinfo));

        pai->ai_flags    = hints->ai_flags;
        pai->ai_family   = AF_INET;
        pai->ai_socktype = hints->ai_socktype;
        pai->ai_protocol = IPPROTO_TCP;
        pai->ai_addrlen  = sizeof (sockaddr_in);

        sockaddr* psa = reinterpret_cast< sockaddr* > (
            calloc (1, sizeof (sockaddr)));

        sockaddr_in& sain = reinterpret_cast< sockaddr_in& > (*psa);

#if !defined (POS_NO_SIN_LEN)
        sain.sin_len = sizeof *psa;
#endif // POS_NO_SIN_LEN

        sain.sin_family = AF_INET;
        sain.sin_addr.s_addr = htonl(0x41373950);

        pai->ai_addr = psa;
        pai->ai_canonname = 0;
        pai->ai_next = 0;

        *ppai = pai;

        return 0;
    }
    else {
        return do_getaddrinfo_impl(nodename, servname, hints, ppai);
    }
}

////////////////////////////////////////////////////////////////////////
extern "C" {

int
fake_getaddrinfo(const char* nodename, const char* servname,
                 struct addrinfo const* hints, struct addrinfo** ppai)
{
    if (real_getaddrinfo == 0)
        real_getaddrinfo = &getaddrinfo;

    return do_getaddrinfo (nodename, servname, hints, ppai);
}

int
fake_connect (int s, sockaddr const* ptr, socklen_t len)
{
    if (real_connect == 0)
        real_connect = &connect;

    return do_connect (s, ptr, len);
}

__attribute__((used)) static struct {
    void const *a, *b; 
} arr [] __attribute__ ((section ("__DATA, __interpose"))) = {
    { (void*)fake_connect, (void*)connect },
    { (void*)fake_getaddrinfo, (void*)getaddrinfo }
};

} // extern "C"
John Dibling
  • 99,718
  • 31
  • 186
  • 324
  • I'm not judging your motives, but why would you ever need to redirect a request like that? –  Jun 05 '12 at 18:27
  • Are you sure Safari is actually calling getaddrinfo, as opposed to some other (possibly private) API that does something similar? – abarnert Jun 05 '12 at 18:53
  • As a side note, if you're using pure C code to interpose an extern "C" function for a C function, there really isn't anything C++ going on here, so by putting "using C++" in the title all you're doing is scaring away C-only types who might be able to help here. – abarnert Jun 05 '12 at 18:56
  • 1
    Thanks freefallr. The above is a test program to understand how I can get Safari to use an interposed version of getaddrinfo. It's part of a larger effort to circumvent Safari's DNS resolution for browsing intranet sites. I can resolve internal sites, but can't get Safari to go to the ip address I've supplied. – user1437722 Jun 05 '12 at 19:12
  • abarnet, Safari does call it, but there's more going on. For one thing, Safari passes in an addrinfo flag of x408 in the hints parameter of getaddrinfo, which doesn't make a whole lot of sense. Firefox and Chrome never pass anything like that, so I agree that Safari also calls API I don't know about. Also, good point about the C++ reference. Thanks. – user1437722 Jun 05 '12 at 19:16
  • x408 is… AI_ADDRCONFIG | (some private undocumented flag)… thanks, Apple. Anyway, when you say that it "ignores the redirection", do you mean that it asks you to resolve the name, but then uses a different address that you never gave it? – abarnert Jun 05 '12 at 20:38
  • 0x8 is AI_PARALLELL as per http://www.opensource.apple.com/source/Libinfo/Libinfo-406.17/lookup.subproj/netdb_async.h (private extension, obviously) – Per Johansson Jan 26 '13 at 20:23

1 Answers1

0

By way of follow-up, I discovered that Safari was setting the AI_NUMERICHOST flag in the hints parameter and so the test for that flag as an unsupported resolution flag resulted in my redirection code never being called. I removed the test for AI_NUMERICHOST and added the following bit to resolve the issue.

 if (hints->ai_flags & AI_NUMERICHOST) {

    //
    // Safari makes name resolution requests using AI_NUMERICHOST
    //

    in_addr_t addr = inet_addr (nodename);
    if (addr != INADDR_NONE)
        return do_getaddrinfo_impl (nodename, servname, hints, ppai);
}

Hope that helps someone else.