crossroads

Git mirror of https://crossroads.e-tunity.com/
git clone git://git.finwo.net/app/crossroads
Log | Files | Refs | LICENSE

commit c17283f4350c1868cacb273c2118f82f5f63b4e5
parent 9cd7d67d498bd3e2093eb453e1c58f307ad42136
Author: finwo <finwo@pm.me>
Date:   Sat,  3 Jan 2026 19:36:24 +0100

2.32

Diffstat:
MChangeLog | 10++++++++++
MMakefile | 2+-
Atest/udpfwd.c | 184+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Mxr/DispatchAlgorithms/storedip/target.cc | 23++++++++++-------------
Mxr/etc/status.xslt | 28++++++++++++++--------------
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">