commit c17283f4350c1868cacb273c2118f82f5f63b4e5
parent 9cd7d67d498bd3e2093eb453e1c58f307ad42136
Author: finwo <finwo@pm.me>
Date: Sat, 3 Jan 2026 19:36:24 +0100
2.32
Diffstat:
5 files changed, 219 insertions(+), 28 deletions(-)
diff --git a/ChangeLog b/ChangeLog
@@ -1,3 +1,6 @@
+2.32 [KK 2008-11-05]
+- Bugfix in "stored-ip" dispatching algorithm.
+
2.31 [KK 2008-10-30]
- Changes related to XML-style configuration file support. A
new-style xrctl is in provided and during "make install" put in
@@ -37,6 +40,13 @@
- Implemented generation of a new configuration using "xrctl
generateconfig".
+2.30 [KK 2008-10-25]
+- Reversioned to 2.30 in prepration for STABLE release.
+- Bugfix in Netbuffer::netwrite() (debug output of written data)
+- SIGPIPE gets ignored, see sys/main.cc
+- Fixed re-entrancy issues for gethostbyname() that applies to some
+ unices. See Backend::connect() (xr/backend/connect.cc).
+
2.22 [KK 2008-10-16]
- Implemented up/down state in back ends. Fixed up the docs.
- Rewrote msg() and debugmsg() handling: these are now macros that
diff --git a/Makefile b/Makefile
@@ -1,7 +1,7 @@
# Top-level Makefile for XR
# -------------------------
-VER = 2.31
+VER = 2.32
BINDIR = /usr/sbin
TAR = /tmp/crossroads-$(VER).tar.gz
AUTHOR = Karel Kubat <karel@kubat.nl>
diff --git a/test/udpfwd.c b/test/udpfwd.c
@@ -0,0 +1,184 @@
+
+#include <ctype.h>
+#include <errno.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdarg.h>
+#include <string.h>
+#include <unistd.h>
+
+#include <arpa/inet.h>
+#include <netinet/in.h>
+#include <sys/select.h>
+#include <sys/socket.h>
+#include <sys/types.h>
+
+#define MIN_RANGE 1
+#define MAX_RANGE 65000
+
+void die (char const *fmt, ...) {
+ va_list args;
+
+ va_start(args, fmt);
+ vfprintf(stderr, fmt, args);
+ fputc('\n', stderr);
+ exit(1);
+}
+
+struct sockaddr_in si_backend;
+fd_set listen_set;
+
+typedef struct {
+ struct sockaddr_in si;
+ int sock;
+} Conn;
+
+typedef struct {
+ int cl_port, sr_port;
+ struct in_addr cl_addr, sr_addr;
+} Db;
+
+Db *db;
+int ndb;
+Db *db_find (struct sockaddr_in s) {
+ int i;
+ for (i = 0; i < ndb; i++)
+ if (db[i].cl_port == s.sin_port &&
+ (*(long*)(&db[i].cl_addr) == (*(long*)(&s.sin_addr))))
+ return db + i;
+ return 0;
+}
+
+void db_add(int clport, struct in_addr claddr,
+ int srport, struct in_addr sraddr) {
+ if (! (db = realloc(db, (ndb + 1) * sizeof(Db))) )
+ die ("memory fault while reallocating db to %d entries\n",
+ ndb + 1);
+ db[ndb].cl_port = clport;
+ db[ndb].cl_addr = claddr;
+ db[ndb].sr_port = srport;
+ db[ndb].sr_addr = sraddr;
+}
+
+void dumpbuf (int len, char const *buf) {
+ char disp[4];
+ int i;
+
+ printf ("Data, %d bytes: ", len);
+ for (i = 0; i < len; i++) {
+ if (isprint(buf[i])) {
+ putchar(buf[i]);
+ putchar (' ');
+ } else {
+ sprintf(disp, "%3.3o", buf[i] & 0xff);
+ printf(" \\%s", disp);
+ }
+ }
+ putchar('\n');
+}
+
+Conn make_server_conn (int port) {
+ Conn ret;
+ int p;
+
+ printf ("Attempting to create connector for port %d\n", port);
+ if ( (ret.sock = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP)) < 1 )
+ die ("cannot create socket: %s", strerror(errno));
+ memset((char *) &(ret.si), 0, sizeof(ret.si));
+ ret.si.sin_family = AF_INET;
+ ret.si.sin_addr.s_addr = htonl(INADDR_ANY);
+
+ for (p = port; p <= MAX_RANGE; p++) {
+ ret.si.sin_port = htons(p);
+ if (bind(ret.sock, (struct sockaddr *) &ret.si, sizeof(ret.si)) != 1) {
+ printf("Socket bound to port %d\n", p);
+ FD_SET(ret.sock, &listen_set);
+ return ret;
+ }
+ }
+ die ("Failed to bind socket to any port\n");
+ /* To satisfy */
+ return ret;
+}
+
+void handle_socket(int sock, char *buf, int buflen) {
+ struct sockaddr_in si_other;
+ Conn c;
+ int nreceived;
+ unsigned slen = sizeof(si_other);
+ Db *db;
+
+ nreceived = recvfrom(sock, buf, buflen, 0,
+ (struct sockaddr *)&si_other, &slen);
+
+ if (nreceived < 1)
+ die ("receive from client failed: %s", strerror(errno));
+ printf("Received packet from %s:%d on socket %d\n",
+ inet_ntoa(si_other.sin_addr), ntohs(si_other.sin_port), sock);
+ dumpbuf(nreceived, buf);
+
+ if (! (db = db_find (si_other)) ) {
+ printf ("New client connection, forwarding to back end\n");
+ c = make_server_conn(20000);
+ if (sendto(c.sock, buf, nreceived, 0,
+ (struct sockaddr *)&si_backend, slen) == -1)
+ die ("failed to send to back end: %s", strerror(errno));
+ db_add(c.si.sin_port, c.si.sin_addr,
+ si_other.sin_port, si_other.sin_addr);
+ } else {
+ print ("Return connection from back end, sending to client\n");
+
+
+}
+
+int main (int argc, char **argv) {
+ int buflen, port, backend_port;
+ char *buf;
+
+ /* Get arguments */
+ if (argc < 5)
+ die ("Usage: udpfwd buflen port backendip backendport");
+ if (! (buflen = atoi(argv[1])) )
+ die("bad buffer length '%s'", argv[1]);
+ if (! (buf = malloc(buflen)) )
+ die("memory fault, cannot allocate buffer of %d bytes", buflen);
+ if (! (port = atoi(argv[2])) )
+ die("bad server port '%s'", argv[2]);
+ if (! (backend_port = atoi(argv[4])) )
+ die ("bad back end port '%s'", argv[4]);
+
+ /* Set up the back end. */
+ memset(&si_backend, 0, sizeof(si_backend));
+ si_backend.sin_family = AF_INET;
+ si_backend.sin_port = htons(backend_port);
+ if (inet_aton(argv[3], &si_backend.sin_addr) == 0)
+ die ("bad back end IP '%s': %s", argv[3], strerror(errno));
+
+ /* Set up server */
+ FD_ZERO(&listen_set);
+ make_server_conn (port);
+
+ while (1) {
+ fd_set read_set;
+ int nready, i;
+
+ FD_COPY(&listen_set, &read_set);
+ printf("Monitoring server sockets:");
+ for (i = 0; i < FD_SETSIZE; i++)
+ if (FD_ISSET(i, &read_set))
+ printf (" %d", i);
+ putchar ('\n');
+
+ nready = select(FD_SETSIZE, &read_set, 0, 0, 0);
+ if (nready < 1)
+ die("select error: %s", strerror(errno));
+ for (i = 0; i < FD_SETSIZE; i++)
+ if (FD_ISSET(i, &read_set)) {
+ printf ("Activity on socket %d\n", i);
+ handle_socket(i, buf, buflen);
+ }
+ }
+
+ /* All done */
+ return 0;
+}
diff --git a/xr/DispatchAlgorithms/storedip/target.cc b/xr/DispatchAlgorithms/storedip/target.cc
@@ -14,17 +14,16 @@ struct ClientDataCmp {
}
};
-static map<struct in_addr, ClientData, ClientDataCmp> store;
+typedef map<struct in_addr, ClientData, ClientDataCmp> StoreMap;
+static StoreMap store;
unsigned StoredIp::target(struct in_addr clientip,
BackendVector const &targetlist) {
unsigned target;
time_t now = time(0);
- // Is the client already known in the map, and not timed out?
- map<struct in_addr, ClientData, ClientDataCmp>::iterator hit =
- store.find(clientip);
if (store.count(clientip) > 0) {
+ // Client already known, maybe timed out.
time_t diff = now - store[clientip].lastaccess;
msg ("Client IP " + static_cast<string>(inet_ntoa(clientip)) +
@@ -71,17 +70,15 @@ unsigned StoredIp::target(struct in_addr clientip,
ClientData entry = {target, now};
store[clientip] = entry;
- // Weed out store
- map<struct in_addr, ClientData, ClientDataCmp>::iterator
- iter = store.begin();
- while (iter != store.end()) {
- debugmsg ("Stored-IP: " +
- (string)inet_ntoa((*iter).first) + " visited on " +
+ // Weed out store.
+ for (StoreMap::iterator iter = store.begin(); iter != store.end();
+ iter++) {
+ debugmsg (Mstr(inet_ntoa(iter->first)) + Mstr(" visited on ") +
timestamp((*iter).second.lastaccess) + "\n");
- if (now - ((*iter).second.lastaccess) > config.ipstoretimeout())
+ if (now - ((*iter).second.lastaccess) > config.ipstoretimeout()) {
+ debugmsg (" Erasing stale entry, stale\n");
store.erase(iter);
- else
- iter++;
+ }
}
// Return target to caller
diff --git a/xr/etc/status.xslt b/xr/etc/status.xslt
@@ -162,7 +162,7 @@
</tr>
<tr>
<td>Timeouts</td>
- <td>Client</td>
+ <td>Client read/write</td>
<td>
<xsl:choose>
<xsl:when test="clienttimeout = 0">
@@ -181,7 +181,7 @@
</tr>
<tr>
<td></td>
- <td>Backend</td>
+ <td>Backend read/write/connect</td>
<td>
<xsl:choose>
<xsl:when test="backendtimeout = 0">
@@ -200,7 +200,7 @@
</tr>
<tr>
<td></td>
- <td>DNS</td>
+ <td>DNS cache validity</td>
<td>
<xsl:choose>
<xsl:when test="dnscachetimeout = 0">
@@ -280,9 +280,9 @@
</tr>
<tr>
<td></td>
- <td colspan="2">Traffic log directory</td>
- <td>
- <input type="text" size="8" name="logtrafficdir" id="logtrafficdir"
+ <td>Traffic log directory</td>
+ <td colspan="2" align="right">
+ <input type="text" size="30" name="logtrafficdir" id="logtrafficdir"
value="{debugging/logtrafficdir}"
onchange="goto('/server/logtrafficdir/', 'logtrafficdir');"/>
</td>
@@ -318,7 +318,7 @@
<tr>
<td></td>
- <td>Time interval</td>
+ <td>Sample duration</td>
<td>sec</td>
<td>
<input type="text" size="8" name="timeinterval" class="input"
@@ -335,7 +335,7 @@
unlimited
</xsl:when>
<xsl:otherwise>
- sessions per time interval (0 for unlimited)
+ sessions per sample (0 for unlimited)
</xsl:otherwise>
</xsl:choose>
</td>
@@ -354,7 +354,7 @@
unlimited
</xsl:when>
<xsl:otherwise>
- sessions per time interval (0 for unlimited)
+ sessions per sample (0 for unlimited)
</xsl:otherwise>
</xsl:choose>
</td>
@@ -434,7 +434,7 @@
</tr>
<tr>
<td><b>State</b></td>
- <td>health</td>
+ <td>Health</td>
<td colspan="2">
<xsl:value-of select="live"/>,
<xsl:value-of select="available"/>
@@ -442,12 +442,12 @@
</tr>
<tr>
<td></td>
- <td>connections</td>
+ <td>Connections</td>
<td colspan="2"><xsl:value-of select="connections"/></td>
</tr>
<tr>
<td></td>
- <td>served</td>
+ <td>Served</td>
<td colspan="2">
<xsl:value-of select="bytesserved"/> bytes,
<xsl:value-of select="clientsserved"/> clients
@@ -455,7 +455,7 @@
</tr>
<tr>
<td><b>Options</b></td>
- <td colspan="2">weight</td>
+ <td colspan="2">Weight</td>
<td>
<input type="text" size="8" name="setbackendweight{nr}"
id="setbackendweight{nr}" value="{weight}"
@@ -464,7 +464,7 @@
</tr>
<tr>
<td></td>
- <td>max. connections</td>
+ <td>Max. connections</td>
<td>
<xsl:choose>
<xsl:when test="maxconnections = 0">