181f494838
Submitted by: Steve Wills <steve@stevenwills.com>
633 lines
12 KiB
Text
633 lines
12 KiB
Text
Obtained from: ftp://ftp.linux.org.uk/pub/linux/rmk/ijb20.rmk.diff
|
|
|
|
--- bind.c.orig Fri Nov 30 11:25:23 2001
|
|
+++ bind.c Fri Nov 30 11:33:46 2001
|
|
@@ -45,6 +45,242 @@
|
|
long remote_ip_long;
|
|
char *remote_ip_str;
|
|
|
|
+#ifdef HAVE_IPV6
|
|
+#ifdef HAVE_POLL
|
|
+/*
|
|
+ * Do we have the superiour poll() interface?
|
|
+ */
|
|
+#include <sys/poll.h>
|
|
+
|
|
+static struct pollfd *b_pfd;
|
|
+static int nr_fds;
|
|
+#else
|
|
+/*
|
|
+ * Argh, we've only got the select() interface.
|
|
+ */
|
|
+#include <sys/select.h>
|
|
+
|
|
+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
|
|
@@ -100,7 +336,6 @@
|
|
return fd;
|
|
}
|
|
|
|
-
|
|
/*
|
|
* ACCEPT-CONNECTION
|
|
* the argument, fd, is the value returned from bind_port
|
|
@@ -128,3 +363,5 @@
|
|
|
|
return afd;
|
|
}
|
|
+#endif
|
|
+
|
|
--- conn.c.orig Fri Nov 30 11:25:23 2001
|
|
+++ conn.c Fri Nov 30 11:30:30 2001
|
|
@@ -41,6 +41,10 @@
|
|
#include "gnuregex.h"
|
|
#endif
|
|
|
|
+#ifdef HAVE_POLL
|
|
+#include <sys/poll.h>
|
|
+#endif
|
|
+
|
|
#include "jcc.h"
|
|
|
|
int
|
|
@@ -82,14 +86,127 @@
|
|
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;
|
|
- fd_set wfds;
|
|
- struct timeval tv[1];
|
|
int flags;
|
|
struct access_control_addr src[1], dst[1];
|
|
|
|
@@ -122,23 +239,19 @@
|
|
}
|
|
|
|
#ifdef TCP_NODELAY
|
|
-{ /* turn off TCP coalescence */
|
|
- int mi = 1;
|
|
- setsockopt (fd, IPPROTO_TCP, TCP_NODELAY, (char * ) &mi, sizeof (int));
|
|
-}
|
|
+ { /* turn off TCP coalescence */
|
|
+ int mi = 1;
|
|
+ setsockopt (fd, IPPROTO_TCP, TCP_NODELAY, (char * ) &mi, sizeof (int));
|
|
+ }
|
|
#endif
|
|
-
|
|
-#ifndef _WIN32
|
|
-#ifndef __BEOS__
|
|
+#if !defined(_WIN32) && !defined(__BEOS__)
|
|
if ((flags = fcntl(fd, F_GETFL, 0)) != -1) {
|
|
flags |= O_NDELAY;
|
|
fcntl(fd, F_SETFL, flags);
|
|
}
|
|
#endif
|
|
-#endif
|
|
|
|
while (connect(fd, (struct sockaddr *) & inaddr, sizeof inaddr) == -1) {
|
|
-
|
|
#ifdef _WIN32
|
|
if (errno == WSAEINPROGRESS)
|
|
#else
|
|
@@ -154,25 +267,59 @@
|
|
}
|
|
}
|
|
|
|
-#ifndef _WIN32
|
|
-#ifndef __BEOS__
|
|
+#if !defined(_WIN32) && !defined(__BEOS__)
|
|
if (flags != -1) {
|
|
flags &= ~O_NDELAY;
|
|
fcntl(fd, F_SETFL, flags);
|
|
}
|
|
#endif
|
|
-#endif
|
|
|
|
- /* wait for connection to complete */
|
|
- FD_ZERO(&wfds);
|
|
- FD_SET(fd, &wfds);
|
|
+ {
|
|
+#ifdef HAVE_POLL
|
|
+ struct pollfd pfd;
|
|
+
|
|
+ pfd.fd = fd;
|
|
+ pfd.events = POLLOUT | POLLERR | POLLHUP;
|
|
+
|
|
+ if (poll(&pfd, 1, 30000) <= 0) {
|
|
+ close(fd);
|
|
+ return -1;
|
|
+ }
|
|
|
|
- tv->tv_sec = 30;
|
|
- tv->tv_usec = 0;
|
|
+ if (pfd.revents & (POLLERR|POLLHUP)) {
|
|
+ close(fd);
|
|
+ return -1;
|
|
+ }
|
|
+#else
|
|
+ fd_set rfds, wfds;
|
|
+ struct timeval tv[1];
|
|
|
|
- if (select(fd + 1, NULL, &wfds, NULL, tv) <= 0) {
|
|
- (void) close(fd);
|
|
- return(-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
|
|
--- jcc.c.orig Fri Nov 30 11:25:24 2001
|
|
+++ jcc.c Fri Nov 30 11:30:30 2001
|
|
@@ -32,9 +32,13 @@
|
|
#include <OS.h> /* declarations for threads and stuff. */
|
|
#endif
|
|
|
|
+#ifdef HAVE_POLL
|
|
+#include <sys/poll.h>
|
|
+#else
|
|
#ifndef FD_ZERO
|
|
#include <select.h>
|
|
#endif
|
|
+#endif
|
|
|
|
#endif
|
|
|
|
@@ -640,7 +644,26 @@
|
|
|
|
server_body = 0;
|
|
|
|
+#ifdef HAVE_POLL
|
|
+ fds[0].fd = csp->cfd;
|
|
+ fds[0].events = POLLIN|POLLHUP;
|
|
+ fds[1].fd = csp->sfd;
|
|
+ fds[1].events = POLLIN|POLLHUP;
|
|
+#endif
|
|
+
|
|
for(;;) {
|
|
+#ifdef HAVE_POLL
|
|
+ n = poll(fds, 2, -1);
|
|
+
|
|
+ if (n < 0) {
|
|
+ fprintf(logfp, "%s: poll() failed!: ", prog);
|
|
+ fperror(logfp, "");
|
|
+ return;
|
|
+ }
|
|
+
|
|
+#define IS_CLIENT() (fds[0].revents & POLLIN)
|
|
+#define IS_SERVER() (fds[1].revents & POLLIN)
|
|
+#else
|
|
FD_ZERO(&rfds);
|
|
|
|
FD_SET(csp->cfd, &rfds);
|
|
@@ -653,12 +676,14 @@
|
|
fperror(logfp, "");
|
|
return;
|
|
}
|
|
-
|
|
+#define IS_CLIENT() FD_ISSET(csp->cfd, &rfds)
|
|
+#define IS_SERVER() FD_ISSET(csp->sfd, &rfds)
|
|
+#endif
|
|
/* this is the body of the browser's request
|
|
* just read it and write it.
|
|
*/
|
|
|
|
- if(FD_ISSET(csp->cfd, &rfds)) {
|
|
+ if(IS_CLIENT()) {
|
|
|
|
n = read_socket(csp->cfd, buf, sizeof(buf));
|
|
|
|
@@ -679,7 +704,7 @@
|
|
* otherwise it's the body
|
|
*/
|
|
|
|
- if(FD_ISSET(csp->sfd, &rfds)) {
|
|
+ if(IS_SERVER()) {
|
|
|
|
n = read_socket(csp->sfd, buf, sizeof(buf));
|
|
|
|
--- jcc.h.orig Fri Nov 30 11:25:24 2001
|
|
+++ jcc.h Fri Nov 30 11:37:12 2001
|
|
@@ -339,6 +339,7 @@
|
|
extern void client_cookie_adder(struct client_state *csp);
|
|
extern void client_xtra_adder(struct client_state *csp);
|
|
extern void client_x_forwarded_adder(struct client_state *csp);
|
|
+extern void server_conn_close_adder(struct client_state *csp);
|
|
|
|
/* interceptors from filters.c
|
|
*/
|
|
--- parsers.c.orig Fri Nov 30 11:25:24 2001
|
|
+++ parsers.c Fri Nov 30 11:30:30 2001
|
|
@@ -32,6 +32,7 @@
|
|
{ "cookie:", 7, client_send_cookie },
|
|
{ "x-forwarded-for:", 16, client_x_forwarded },
|
|
{ "proxy-connection:", 17, crumble },
|
|
+ { "keep-alive:", 11, crumble },
|
|
/* { "if-modified-since:", 18, crumble }, */
|
|
{ NULL, 0, NULL }
|
|
};
|
|
@@ -57,6 +58,7 @@
|
|
};
|
|
|
|
void (*add_server_headers[])() = {
|
|
+ server_conn_close_adder, /* for http/1.1 */
|
|
NULL
|
|
};
|
|
|
|
@@ -608,6 +610,12 @@
|
|
if(csp->accept_server_cookie == 0) return(crumble(v, s, csp));
|
|
|
|
return(strdup(s));
|
|
+}
|
|
+
|
|
+void server_conn_close_adder(struct client_state *csp)
|
|
+{
|
|
+ char *p = strsav(NULL, "Connection: close");
|
|
+ enlist(csp->headers, p);
|
|
}
|
|
|
|
/* case insensitive string comparison */
|
|
--- socks4.c.orig Fri Nov 30 11:25:25 2001
|
|
+++ socks4.c Fri Nov 30 11:30:31 2001
|
|
@@ -11,6 +11,7 @@
|
|
|
|
|
|
#include <stdio.h>
|
|
+#include <string.h>
|
|
#include <sys/types.h>
|
|
#include <errno.h>
|
|
|
|
@@ -112,6 +113,8 @@
|
|
strcpy(((char *)cbuf) + csiz, http->host);
|
|
csiz = n;
|
|
break;
|
|
+ default:
|
|
+ return -1; /* oops */
|
|
}
|
|
|
|
c->vn = 4;
|