/* -- NB -- This code has been modified from the original * Internet Junkbuster Proxy (TM) - see attached 'README' file for details */ char *conn_rcs = "$Id: conn.c,v 2.16 1998/10/27 02:14:07 ACJC Exp $"; /* Written and copyright 1997 Anonymous Coders and Junkbusters Corporation. * Distributed under the GNU General Public License; see the README file. * This code comes with NO WARRANTY. http://www.junkbusters.com/ht/en/gpl.html */ #include #include #include #include #include #include #ifdef _WIN32 #include "win32.h" #include #include #else #include #include #include #include #include #include #ifndef __BEOS__ #include #include #endif #endif #ifdef REGEX #include "gnu_regex.h" #endif #ifdef HAVE_POLL #include #endif #include "jcc.h" int direct_connect(struct gateway *gw, struct http_request *http, struct client_state *csp) { if(gw->forward_host) { return(connect_to(gw->forward_host, gw->forward_port, csp)); } else { return(connect_to(http->host, http->port, csp)); } } int atoip(char *host) { struct sockaddr_in inaddr; struct hostent *hostp; if ((host == NULL) || (*host == '\0')) return(INADDR_ANY); memset ((char * ) &inaddr, 0, sizeof inaddr); if ((inaddr.sin_addr.s_addr = inet_addr(host)) == -1) { if ((hostp = gethostbyname(host)) == NULL) { errno = EINVAL; return(-1); } if (hostp->h_addrtype != AF_INET) { #ifdef _WIN32 errno = WSAEPROTOTYPE; #else errno = EPROTOTYPE; #endif return(-1); } memcpy((char * ) &inaddr.sin_addr, (char * ) hostp->h_addr, sizeof(inaddr.sin_addr)); } return(inaddr.sin_addr.s_addr); } #ifdef HAVE_IPV6 int connect_to(char *host, int portnum, struct client_state *csp) { struct addrinfo *ai, *aip, aihint; int fd = -1, rc; char serv[NI_MAXSERV]; if (snprintf(serv, NI_MAXSERV, "%d", portnum) >= NI_MAXSERV) { errno = EOVERFLOW; return -1; } memset(&aihint, 0, sizeof(aihint)); aihint.ai_family = PF_UNSPEC; aihint.ai_socktype = SOCK_STREAM; rc = getaddrinfo(host, serv, &aihint, &ai); if (rc) return -1; /* * Go through each entry trying to connect to the host. */ for (aip = ai; aip; aip = aip->ai_next) { int flags; fd = socket(aip->ai_family, aip->ai_socktype, aip->ai_protocol); if (fd == -1) continue; #ifdef TCP_NODELAY /* turn off TCP coalescence */ { int mi = 1; setsockopt(fd, IPPROTO_TCP, TCP_NODELAY, (char *)&mi, sizeof(mi)); } #endif #if !defined(_WIN32) && !defined(__BEOS__) flags = fcntl(fd, F_GETFL, 0); if (flags != -1) fcntl(fd, F_SETFL, flags | O_NDELAY); #endif do { rc = connect(fd, aip->ai_addr, aip->ai_addrlen); } while (rc == -1 && errno == EINTR); if (rc == -1 && errno != EINPROGRESS) { close(fd); fd = -1; continue; } /* * Ok, the connection is in progress. */ #if !defined(_WIN32) && !defined(__BEOS__) if (flags != -1) fcntl(fd, F_SETFL, flags); #endif { #ifdef HAVE_POLL struct pollfd pfd; pfd.fd = fd; pfd.events = POLLOUT | POLLERR | POLLHUP; if (poll(&pfd, 1, 30000) <= 0) { close(fd); fd = -1; continue; } if (pfd.revents & (POLLERR|POLLHUP)) { close(fd); fd = -1; continue; } #else fd_set rfds, wfds; struct timeval tv[1]; FD_ZERO(&rfds); FD_ZERO(&wfds); FD_SET(fd, &rfds); FD_SET(fd, &wfds); tv->tv_sec = 30; tv->tv_usec = 0; if (select(fd + 1, &rfds, &wfds, NULL, tv) <= 0) { (void) close(fd); fd = -1; continue; } if (FD_ISSET(fd, &rfds) && FD_ISSET(fd, &wfds)) { int r = 0, l = sizeof(r); if (getsockopt(fd, SOL_SOCKET, SO_ERROR, &r, &l) || r) { (void) close(fd); fd = -1; continue; } } #endif } break; } freeaddrinfo(ai); return fd; } #else int connect_to(char *host, int portnum, struct client_state *csp) { struct sockaddr_in inaddr; int fd, addr; int flags; struct access_control_addr src[1], dst[1]; memset ((char * ) &inaddr, 0, sizeof inaddr); if((addr = atoip(host)) == -1) return(-1); src->addr = csp->ip_addr_long; src->port = 0; dst->addr = ntohl(addr); dst->port = portnum; if(block_acl(src, dst, csp)) { errno = EPERM; return(-1); } inaddr.sin_addr.s_addr = addr; inaddr.sin_family = AF_INET; if (sizeof(inaddr.sin_port) == sizeof(short)) { inaddr.sin_port = htons(portnum); } else { inaddr.sin_port = htonl(portnum); } if((fd = socket(inaddr.sin_family, SOCK_STREAM, 0)) < 0) { return(-1); } #ifdef TCP_NODELAY { /* turn off TCP coalescence */ int mi = 1; setsockopt (fd, IPPROTO_TCP, TCP_NODELAY, (char * ) &mi, sizeof (int)); } #endif #if !defined(_WIN32) && !defined(__BEOS__) if ((flags = fcntl(fd, F_GETFL, 0)) != -1) { flags |= O_NDELAY; fcntl(fd, F_SETFL, flags); } #endif while (connect(fd, (struct sockaddr *) & inaddr, sizeof inaddr) == -1) { #ifdef _WIN32 if (errno == WSAEINPROGRESS) #else if (errno == EINPROGRESS) #endif { break; } if (errno != EINTR) { (void) close (fd); return(-1); } } #if !defined(_WIN32) && !defined(__BEOS__) if (flags != -1) { flags &= ~O_NDELAY; fcntl(fd, F_SETFL, flags); } #endif { #ifdef HAVE_POLL struct pollfd pfd; pfd.fd = fd; pfd.events = POLLOUT | POLLERR | POLLHUP; if (poll(&pfd, 1, 30000) <= 0) { close(fd); return -1; } if (pfd.revents & (POLLERR|POLLHUP)) { close(fd); return -1; } #else fd_set rfds, wfds; struct timeval tv[1]; /* wait for connection to complete */ FD_ZERO(&rfds); FD_ZERO(&wfds); FD_SET(fd, &rfds); FD_SET(fd, &wfds); tv->tv_sec = 30; tv->tv_usec = 0; if (select(fd + 1, &rfds, &wfds, NULL, tv) <= 0) { (void) close(fd); return(-1); } if (FD_ISSET(fd, &rfds) && FD_ISSET(fd, &wfds)) { int r = 0, l = sizeof(r); if (getsockopt(fd, SOL_SOCKET, SO_ERROR, &r, &l) || r) { (void) close(fd); fd = -1; } } #endif } return(fd); } #endif