/* -- NB -- This code has been modified from the original * Internet Junkbuster Proxy (TM) - see attached 'README' file for details */ char *bind_rcs = "$Id: bind.c,v 2.9 1998/10/22 15:30:16 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 #include #ifdef _WIN32 #include #include "win32.h" #else #include #include #include #include #include #ifndef __BEOS__ #include #include #include #endif #endif #ifdef REGEX #include #endif #include "jcc.h" /* For atoip() */ long remote_ip_long; char *remote_ip_str; #ifdef HAVE_IPV6 #ifdef HAVE_POLL /* * Do we have the superiour poll() interface? */ #include static struct pollfd *b_pfd; static int nr_fds; #else /* * Argh, we've only got the select() interface. */ #include static fd_set sfd; static int max_fd; #endif static int add_fd(fd) int fd; { #ifdef HAVE_POLL struct pollfd *n; int nr = nr_fds + 1; n = realloc(b_pfd, nr * sizeof(*n)); if (!n) return -3; n[nr_fds].fd = fd; n[nr_fds].events = POLLIN; b_pfd = n; nr_fds = nr; return 0; #else if (fd >= max_fd) max_fd = fd + 1; FD_SET(fd, &sfd); return 0; #endif } /* * Bind one port of an address family, specified by `ai' */ static int bind_one(ai) struct addrinfo *ai; { int fd, one = 1; fd = socket(ai->ai_family, ai->ai_socktype, ai->ai_protocol); if (fd == -1) { /* * Is it an unsupported family or protocol? * Move along please. */ if (errno == EINVAL || errno == EPROTONOSUPPORT) return -1; /* * Ok, something else went wrong - fatal error. */ return -3; } setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, (char *)&one, sizeof(one)); /* * Now bind the socket. This may fail on Linux. */ if (bind(fd, ai->ai_addr, ai->ai_addrlen) < 0) { close(fd); if (errno == EADDRINUSE) return -2; else return -1; } /* * and ensure that it is listening. */ while (listen(fd, 5) == -1) { if (errno != EINTR) { close(fd); return -1; } } return add_fd(fd); } /* * BIND-PORT (portnum) * if success, return file descriptor * if failure, returns -2 if address is in use, otherwise -1 */ int bind_port (hostnam, portnum) char *hostnam; int portnum; { struct addrinfo *ai, *aip, aihint; int rc, nr = 0; char serv[NI_MAXSERV]; if (snprintf(serv, NI_MAXSERV, "%d", portnum) >= NI_MAXSERV) return -1; memset(&aihint, 0, sizeof(aihint)); aihint.ai_flags = AI_PASSIVE; aihint.ai_family = PF_UNSPEC; aihint.ai_socktype = SOCK_STREAM; rc = getaddrinfo(hostnam, serv, &aihint, &ai); if (rc) return -1; /* * Go through each entry creating a socket and trying * to bind it. Note that on Linux, if we bind to an * IPv6 address, we can't bind to it's corresponding * IPv4 address, so we bind IPv6 first, then IPv4. * * We classify success as being able to establish at * least one listening socket. */ for (aip = ai; aip; aip = aip->ai_next) { if (aip->ai_family == PF_INET6) { rc = bind_one(aip); if (rc == 0) nr++; } } for (aip = ai; aip; aip = aip->ai_next) { if (aip->ai_family == PF_INET) { rc = bind_one(aip); if (rc == 0) nr++; } } freeaddrinfo(ai); if (nr != 0) rc = 0; return rc; } /* * ACCEPT-CONNECTION * the argument, fd, is the value returned from bind_port * * when a connection is accepted, it returns the file descriptor * for the connected port */ int accept_connection (_fd) int _fd; { struct sockaddr_storage sa; int afd, alen = sizeof(sa); char host[NI_MAXHOST]; int rc, fd; #ifdef HAVE_POLL int i; do { rc = poll(b_pfd, nr_fds, -1); } while (rc == 0 || (rc == -1 && errno == EINTR)); /* * I wish we could spawn the handler here. Alas, without * rewriting more of ijb... */ for (i = 0; i < nr_fds; i++) if (b_pfd[i].revents) break; /* * hmm, if we ran out of fds to check, someone lied to us. */ if (i >= nr_fds) return -1; fd = b_pfd[i].fd; #else fd_set rfds; rfds = sfd; do { rc = select(max_fd, &rfds, NULL, NULL, NULL); } while (rc == 0 || (rc == -1 && errno == EINTR)); /* * Find the first fd. Same comment as above. */ for (fd = 0; fd < max_fd; fd++) if (FD_ISSET(fd, &rfds)) break; /* * If we found no fds, someone lied to us. */ if (fd >= max_fd) return -1; #endif afd = accept(fd, (struct sockaddr *)&sa, &alen); if (afd < 0) return -1; if (getnameinfo((struct sockaddr *)&sa, alen, host, NI_MAXHOST, NULL, 0, NI_NUMERICHOST)) strcpy(host, "unknown"); remote_ip_str = strdup(host); remote_ip_long = 0; return afd; } #else /* * -------------------------------- IPv4 ---------------------------- */ extern int atoip(); /* * BIND-PORT (portnum) * if success, return file descriptor * if failure, returns -2 if address is in use, otherwise -1 */ int bind_port (hostnam, portnum) char *hostnam; int portnum; { struct sockaddr_in inaddr; int fd; int one = 1; memset ((char * ) &inaddr, '\0', sizeof inaddr); inaddr.sin_family = AF_INET; inaddr.sin_addr.s_addr = atoip(hostnam); if(sizeof(inaddr.sin_port) == sizeof(short)) { inaddr.sin_port = htons(portnum); } else { inaddr.sin_port = htonl(portnum); } fd = socket(AF_INET, SOCK_STREAM, 0); if (fd < 0) { return(-1); } setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, (char *)&one, sizeof(one)); if (bind (fd, (struct sockaddr *)&inaddr, sizeof(inaddr)) < 0) { close (fd); #ifdef _WIN32 if (errno == WSAEADDRINUSE) #else if (errno == EADDRINUSE) #endif { return(-2); } else { return(-1); } } while (listen(fd, 5) == -1) { if (errno != EINTR) { return(-1); } } return fd; } /* * ACCEPT-CONNECTION * the argument, fd, is the value returned from bind_port * * when a connection is accepted, it returns the file descriptor * for the connected port */ int accept_connection (int fd) { struct sockaddr raddr; struct sockaddr_in *rap = (struct sockaddr_in *) &raddr; int afd, raddrlen; raddrlen = sizeof raddr; do { afd = accept (fd, &raddr, &raddrlen); } while (afd < 1 && errno == EINTR); if (afd < 0) { return(-1); } remote_ip_str = strdup(inet_ntoa(rap->sin_addr)); remote_ip_long = ntohl(rap->sin_addr.s_addr); return afd; } #endif