/* Hostaliases for SunOS 5.6, 5.7, 5.8 and 5.9 by Johan Rudholm, 2003-04 == To compile: % cc -O -D_REENTRANT -Kpic -G -z text -ldl -lsocket -lnsl -o libhost.so \ libhost.c % gcc -O -D_REENTRANT -fpic -shared -z text -ldl -lsocket -lnsl -o libhost.so \ libhost.c == To use: % env LD_PRELOAD=/path/to/libhost.so command or you can setenv LD_PRELOAD but this will make setuid and setgid programs complain about libhost.so not being in a secure directory (see ld.so.1(1)). == Some information: I've located four functions that seem to be most oftenly used to look up names, these are: gethostbyname gethostbyname_r getipnodebyname getaddrinfo The two last functions doesn't seem to exist on 5.6 and 5.7 but this library still implements them, however since they will never be called this won't be a problem.. I had to implement my own lookup function for hostaliases since res_hostalias(3RESOLV) is horribly slow (reads one byte at a time) and only seems to exist on 5.8 and 5.9. Thanks to Andy Polyakov for help with the asm() and more :-) */ #define getaddrinfo mask_getaddrinfo_declaration #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #undef getaddrinfo /* * Get the real symbols from their libs */ struct hostent *(*__gethostbyname) (const char *name); struct hostent *(*__gethostbyname_r) (const char *, struct hostent *, char *, int, int *); static int (*__getaddrinfo) (const char *, const char *, const void *, void **); static struct hostent *(*__getipnodebyname) (const char *, int, int, int *); static const char *hostalias(const char *name, char *buf, int bufsize); static char *gethostbyname_name = NULL; #if defined(__SUNPRO_C) # pragma init(setmeup) /* SPARCCompiler specific #pragma */ #elif defined(__GNUC__) # if defined(__i386__) && (defined(sun) || defined(__sun)) /* Solaris x86 assembler doesn't accept quotes around .init:-( */ asm (".section .init call setmeup"); # elif defined(__i386__) || defined(__sparc__) asm (".section \".init\" call setmeup nop"); # elif defined(__alpha__) && defined(__linux) asm (".section \".init\" jsr setmeup"); # endif #endif static void setmeup (void) { void *handle, *handle2; struct utsname uts; if (uname (&uts) < 0) { fprintf (stderr, "uname failed\n"); exit (1); } handle2 = dlopen ("libnsl.so.1", RTLD_LAZY); if (handle2 == NULL) { fprintf (stderr, "Cannot dlopen libnsl.so.1\n"); exit (1); } __gethostbyname = (struct hostent * (*) (const char *)) dlsym (handle2, "gethostbyname"); if (__gethostbyname == NULL) { fprintf (stderr, "Cannot dlsym gethostbyname\n"); exit (1); } __gethostbyname_r = (struct hostent * (*) (const char *, struct hostent *, char *, int, int *)) dlsym (handle2, "gethostbyname_r"); if (__gethostbyname_r == NULL) { fprintf (stderr, "Cannot dlsym gethostbyname_r\n"); exit (1); } if (!strcmp (uts.sysname, "SunOS") && strcmp (uts.release, "5.8") >= 0) { handle = dlopen ("libsocket.so.1", RTLD_LAZY); if (handle == NULL) { fprintf (stderr, "Cannot dlopen libsocket.so.1\n"); exit (1); } __getaddrinfo = (int (*)(const char *, const char *, const void *, void **)) dlsym (handle, "getaddrinfo"); if (__getaddrinfo == NULL) { fprintf (stderr, "Cannot dlsym getaddrinfo\n"); exit (1); } __getipnodebyname = (struct hostent * (*) (const char *, int, int, int *)) dlsym (handle2, "getipnodebyname"); if (__getipnodebyname == NULL) { fprintf (stderr, "Cannot dlsym getipnodebyname\n"); exit (1); } } } /* * gethostbyname * * It's possible that gethostbyname calls gethostbyname_r to do it's * deeds but we probably can't rely on this everywhere. */ struct hostent *gethostbyname(const char *name) { const char *newname; char tmp[1024]; struct hostent *ret; if ((newname = hostalias (name, tmp, 1024))) ret = (*__gethostbyname) ((gethostbyname_name = (char *)newname)); else ret = (*__gethostbyname) ((gethostbyname_name = (char *)name)); gethostbyname_name = NULL; return (ret); } /* * gethostbyname_r */ struct hostent *gethostbyname_r(const char *name, struct hostent *result, char *buffer, int buflen, int *h_errnop) { const char *newname; char tmp[1024]; if ((gethostbyname_name != name) && (newname = hostalias (name, tmp, 1024))) return ((*__gethostbyname_r) (newname, result, buffer, buflen, h_errnop)); else return ((*__gethostbyname_r) (name, result, buffer, buflen, h_errnop)); } /* * getaddrinfo */ int getaddrinfo(const char *nodename, const char *servname, const void *hints, void **res) { const char *newname; char tmp[1024]; if ((newname = hostalias (nodename, tmp, 1024))) return ((*__getaddrinfo) (newname, servname, hints, res)); else return ((*__getaddrinfo) (nodename, servname, hints, res)); } /* * getipnodebyname */ struct hostent *getipnodebyname(const char *name, int af, int flags, int *error_num) { const char *newname; char tmp[1024]; if ((newname = hostalias (name, tmp, 1024))) return ((*__getipnodebyname) (newname, af, flags, error_num)); else return ((*__getipnodebyname) (name, af, flags, error_num)); } /* * hostalias, inspired by FreeBSD: /usr/src/lib/libc/net/res_query.c */ static const char *hostalias(const char *name, char *buf, int bufsize) { char *file; const char *cp; FILE *fp; /* * We won't look up names with dots in them */ for (cp = name; *cp; cp++) if (*cp == '.') return (NULL); file = getenv ("HOSTALIASES"); if (file == NULL || (fp = fopen (file, "r")) == NULL) return (NULL); while (fgets (buf, bufsize, fp)) { if (buf[strlen(buf)-1] == '\n') buf[strlen(buf)-1] = '\0'; if (!strncmp (buf, name, strlen (name)) && isspace ((int)buf[strlen (name)])) { cp = buf+strlen(name); while (*cp && isspace ((int)*cp)) cp++; if (*cp) { fclose (fp); return (cp); } else continue; } } fclose (fp); return (NULL); }