/* * Copyright (c) 2001 Nicholas W. Sayer. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * */ #include #include #include #include #include #include #include #include #include #if (defined(__unix__) || defined(unix)) && !defined(USG) #include #endif #define NUMSOCK (1024) /* Maximum number of supported sockets */ enum status { NEED_INIT, INACTIVE, ACTIVE }; static enum status active = NEED_INIT; static int sock_type[NUMSOCK]; static int (*R_socket)(); static int (*R_connect)(); static int (*R_close)(); static int (*R_getaddrinfo)(); static struct hostent *(*R_gethostbyname)(); static void initlib() { void *handle; int i; active = INACTIVE; for(i = 0; i < NUMSOCK; i++) sock_type[i] = -1; #ifdef BSD handle = dlopen("/usr/lib/libc.so", RTLD_LAZY); #elif defined(LINUX) handle = dlopen("/lib/libc.so", RTLD_LAZY); #else #error "Unknown operating system" #endif if (handle == NULL) return; #define SET_UP(x,y) if ((x = dlsym(handle, y)) == NULL) return SET_UP(R_socket, "socket"); SET_UP(R_connect, "connect"); SET_UP(R_close, "close"); /* If we got here, everything worked. We are ready to go */ active = ACTIVE; } /* * Socket needs to do nothing more than make a note of the 2nd argument * if the socket is AF_INET */ int socket(int family, int type, int proto) { int sock; if (active == NEED_INIT) initlib(); if (active == ACTIVE && family == PF_INET && getenv("NATPT_PREFIX") != NULL) { family = PF_INET6; sock = R_socket(family, type, proto); if (sock < 0) return sock; if (sock > NUMSOCK) { R_close(sock); errno = EAGAIN; return -1; } sock_type[sock] = type; return sock; } else return R_socket(family, type, proto); } /* * If the socket had its 2nd argument noted before, then we need * to look up any previously cached information we got from * gethostbyname and make connections to the real addresses * instead. If we connect successfully, we dup2() over the old * (user-supplied) socket. */ int connect(int s, const struct sockaddr *name, socklen_t namelen) { int i; char *prefix; struct sockaddr_in6 new_addr; if (active == NEED_INIT) initlib(); if (active == INACTIVE) return R_connect(s, name, namelen); if (s < 0 || s >= NUMSOCK) /* ignore rather than core */ return R_connect(s, name, namelen); if (sock_type[s] < 0) /* if, for instance, it is AF_UNIX */ return R_connect(s, name, namelen); if ((prefix = getenv("NATPT_PREFIX")) == NULL) return R_connect(s, name, namelen); bzero(&new_addr, sizeof(struct sockaddr_in6)); new_addr.sin6_len = sizeof(struct sockaddr_in6); new_addr.sin6_family = PF_INET6; if (inet_pton(AF_INET6, prefix, &(new_addr.sin6_addr.s6_addr)) != 1) return R_connect(s, name, namelen); for(i = 0; i < sizeof(in_addr_t); i++) new_addr.sin6_addr.s6_addr[i + 12] = ((unsigned char *)&((struct sockaddr_in *)name)->sin_addr.s_addr)[i]; new_addr.sin6_port = ((struct sockaddr_in *)name)->sin_port; return R_connect(s, &new_addr, sizeof(new_addr)); } int close(int s) { int out; if (active == NEED_INIT) initlib(); if (s >= 0 && s < NUMSOCK) sock_type[s] = -1; return R_close(s); }