/* * 2004, Ben Winslow * * libc wrapper to support ACE-encoded DNS names (per IDNA, RFC 3492) * * gcc -shared -o idnawrap.so idnawrap.c -ldl \ * `pkg-config --cflags --libs-only-l libidn` */ #include #include #include #include #include #include #include #define LIBC "libc.so.6" #define NAME "idnawrap" #define NAMEPREFIX NAME ": " struct hostent; struct addrinfo; typedef struct hostent *(ghbn_t)(const char *); typedef int (gai_t)(const char *, const char *, const struct addrinfo *, struct addrinfo **); void *libc; ghbn_t *real_gethostbyname; gai_t *real_getaddrinfo; static void moof_init(void) __attribute__((constructor)); static void moof_fini(void) __attribute__((destructor)); static void moof_init(void) { char *err; setlocale(LC_ALL, ""); if ((libc = dlopen(LIBC, RTLD_NOW)) == NULL) { fprintf(stderr, NAMEPREFIX "fatal: error opening %s: %s\n", LIBC, dlerror()); abort(); } dlerror(); /* clear any previous errors */ if ((real_gethostbyname = (ghbn_t *)dlsym(libc, "gethostbyname")) == NULL) { err = dlerror(); fprintf(stderr, NAMEPREFIX "fatal: error resolving %s: %s\n", "gethostbyname", err != NULL ? err : "NULL symbol"); abort(); } if ((real_getaddrinfo = (gai_t *)dlsym(libc, "getaddrinfo")) == NULL) { err = dlerror(); fprintf(stderr, NAMEPREFIX "fatal: error resolving %s: %s\n", "getaddrinfo", err != NULL ? err : "NULL symbol"); abort(); } } static void moof_fini(void) { if (libc != NULL) dlclose(libc); } struct hostent *gethostbyname(const char *addr) { struct hostent *he = NULL; char *encoded; int same = 0; assert(addr != NULL); if (idna_to_ascii_lz(addr, &encoded, 0) == IDNA_SUCCESS) { he = real_gethostbyname(encoded); same = !strcmp(encoded, addr); free(encoded); if (he != NULL || same) return he; } return real_gethostbyname(addr); } int getaddrinfo(const char *addr, const char *svc, const struct addrinfo *hints, struct addrinfo **res) { int ret, same = 0; char *encoded; if (addr != NULL && idna_to_ascii_lz(addr, &encoded, 0) == IDNA_SUCCESS) { ret = real_getaddrinfo(encoded, svc, hints, res); same = !strcmp(encoded, addr); free(encoded); if (ret == 0 || same) return ret; } return real_getaddrinfo(addr, svc, hints, res); }