commit bee61e021322c813cba3c0d3a9f3c2572011abd8
parent c17283f4350c1868cacb273c2118f82f5f63b4e5
Author: finwo <finwo@pm.me>
Date: Sat, 3 Jan 2026 19:36:26 +0100
2.33
Diffstat:
9 files changed, 342 insertions(+), 200 deletions(-)
diff --git a/ChangeLog b/ChangeLog
@@ -1,3 +1,10 @@
+2.33 [KK 2008-11-07]
+- Solaris portability for gcc 3.4 issues in Tcpdispatcher::execute()
+- Removed warnings about non-found libraries (on systems that don't
+ need them)
+- Support for DESTDIR setting in top Makefile (for debian packaging)
+- Man pages added as doc/xr.1, doc/xrctl.1 and doc/xrctl.xml.5.
+
2.32 [KK 2008-11-05]
- Bugfix in "stored-ip" dispatching algorithm.
diff --git a/Makefile b/Makefile
@@ -1,8 +1,10 @@
# Top-level Makefile for XR
# -------------------------
-VER = 2.32
-BINDIR = /usr/sbin
+VER = 2.33
+PREFIX = $(DESTDIR)/usr
+BINDIR = $(PREFIX)/sbin
+MANDIR = $(PREFIX)/share/man
TAR = /tmp/crossroads-$(VER).tar.gz
AUTHOR = Karel Kubat <karel@kubat.nl>
MAINTAINER = Karel Kubat <karel@kubat.nl>
@@ -32,7 +34,7 @@ local:
localprof:
PROF=-pg PROFILER=-DPROFILER make local
-install: local $(BINDIR)/xrctl
+install: local $(BINDIR)/xrctl install-manpages
mkdir -p $(BINDIR)
BASE=$(BASE) AUTHOR='$(AUTHOR)' MAINTAINER='$(MAINTAINER)' \
DISTSITE='$(DISTSITE)' \
@@ -41,7 +43,7 @@ install: local $(BINDIR)/xrctl
@echo ' The balancer program xr is now installed to $(BINDIR).'
@echo ' The control script xrctl is installed there too. In order to'
@echo ' use it, you will have to create /etc/xrctl.xml (if you have'
- @echo ' not done so yet). See test/sampleconf.xml for an example.'
+ @echo ' not done so yet). See "man xrctl.xml" for an example.'
@echo
@echo ' Have fun with Crossroads $(VER),'
@echo ' -- $(MAINTAINER)'
@@ -49,6 +51,17 @@ install: local $(BINDIR)/xrctl
$(BINDIR)/xrctl: xrctl/xrctl
cp xrctl/xrctl $(BINDIR)/xrctl
chmod +x $(BINDIR)/xrctl
+install-manpages: $(MANDIR)/man1/xr.1 $(MANDIR)/man1/xrctl.1 \
+ $(MANDIR)/man5/xrctl.xml.5
+$(MANDIR)/man1/xr.1: doc/xr.1
+ mkdir -p $(MANDIR)/man1
+ cp $< $@
+$(MANDIR)/man1/xrctl.1: doc/xrctl.1
+ mkdir -p $(MANDIR)/man1
+ cp $< $@
+$(MANDIR)/man5/xrctl.xml.5: doc/xrctl.xml.5
+ mkdir -p $(MANDIR)/man5
+ cp $< $@
uninstall:
rm -f $(BINDIR)/xr $(BINDIR)/xrctl
diff --git a/doc/xr.1 b/doc/xr.1
@@ -0,0 +1,56 @@
+.TH "XR" "1" "Nov 6, 2008" "Man Pages"
+
+.SH "NAME"
+xr \- Crossroads Load Balancer & Fail Over Utility
+
+.SH "SYNOPSIS"
+\fBxr [--verbose] [--web-interface XRSERVER:PORT] --server
+tcp:XRSERVER:PORT --backend BACKEND:PORT [--backend BACKEND:PORT] ...\fR
+
+.SH "DESCRIPTION"
+This manual page briefly documents XR, the Crossroads Load Balancer &
+Fail Over Utility.
+
+XR is an open source load balancer and fail over utility for TCP based
+services. It is a dae mon running in user space, and features
+extensive configurability, polling of back ends using wake up calls,
+status reporting, many algorithms to select the 'right' back end for a
+reques t (and user-defined algorithms for very special cases), and
+much more.
+
+XR is service-independent: it is usable for any TCP service, such as
+HTTP(S), SSH, SMTP, dat abase connections. In the case of HTTP
+balancing, XR handles multiple host balancing, and can provide session
+stickiness for back end processes that need sessions, but aren't
+session-awa re of other back ends.
+
+XR furthermore features a management web interface and can be run as a
+stand-alone daemon, or via inetd.
+
+Execute 'xr -h' to get a complete list of available command-line parameters.
+
+.SH "EXAMPLE"
+xr --verbose --server tcp:0:80 --backend 10.1.1.1:80 --backend
+10.1.1.2:80 --backend 10.1.1. 3:80 --web-interface 0:8001
+
+This instructs XR to listen to port 80 and to dispatch traffic to the
+servers 10.1.1.1, 10.1.1.2 and 10.1.1.2, port 80. A web interface for
+the balancer is started on port 8001.
+
+Direct your browser to the server running XR. You will see the pages
+served by one of the three back ends. The console where XR is
+started, will show what's going on (due to the presence of
+--verbose).
+
+Direct your browser to the server running XR, but port 8001. You will
+see the web interface, which shows the status, and where you can
+alter some settings.
+
+.SH "SEE ALSO"
+xrctl(1)
+
+.SH "AUTHOR"
+XR was written by Karel Kubat <karel@kubat.nl>. Web page:
+http://crossroads.e-tunity.com
+.P
+This man page was written by Frederik Dannemare <frederik@dannemare.net>.
diff --git a/doc/xrctl.1 b/doc/xrctl.1
@@ -0,0 +1,37 @@
+.TH "XRCTL" "1" "Nov 7, 2008" "Man Pages"
+
+.SH "NAME"
+xrctl \- Crossroads control-script
+
+.SH "SYNOPSIS"
+\fBxrctl [OPTION]...\fR
+
+.SH "DESCRIPTION"
+This manual page briefly documents xrctl, the Crossroads
+control-script. Instead of starting XR by hand, consider using xrctl.
+
+Edit /etc/xrctl.xml, which is the configuration file, and configure
+your service(s), all their options, and back ends. Then type xrctl
+start to start all your services, or xrctl stop to stop them.
+
+.SH "OPTIONS"
+.nf
+list [SERVICE] - show configuration of a service, or of all
+start [SERVICE] - start a service, or all configured services
+stop [SERVICE] - stop a service, or all configured services
+force [SERVICE] - start a service (or all) if not running
+restart [SERVICE] - stop and start a service, or all
+status [SERVICE] - show running status of a service, or of all
+rotate [SERVICE] - rotate logs of a service or of all
+generateconfig [SERVICE] - queries running XR's for the configuration
+ and shows it in the format of /etc/xrctl.xml
+.fi
+
+.SH "SEE ALSO"
+xr(1), xrctl.xml(5)
+
+.SH "AUTHOR"
+xrctl was written by Karel Kubat <karel@kubat.nl>. Web page:
+http://crossroads.e-tunity.com
+.P
+This man page was written by Frederik Dannemare <frederik@dannemare.net>.
diff --git a/doc/xrctl.xml.5 b/doc/xrctl.xml.5
@@ -0,0 +1,213 @@
+.TH "XRCTL.XML" "5" "Nov 8, 2008" "Man Pages"
+
+.SH "NAME"
+xrctl.xml \- Crossroads control-script configuration file
+
+.SH "SYNOPSIS"
+The file /etc/xrctl.xml is xrctl's configuration. It defines how xrctl
+will start the balancer xr. If you wish to use xrctl to control the
+balancer, then you must configure all services, options and back ends
+in xrctl.xml.
+
+.SH "EXAMPLE"
+
+The following is a configuration example. See the file xr.pdf which is
+distributed with the sources for a full description.
+
+.nf
+<?xml version="1.0" encoding="UTF-8">
+
+<configuration>
+
+ <!-- General system configuration section -->
+
+ <system>
+ <!-- Where do PID files get stored? -->
+ <piddir>/var/run</piddir>
+ <!-- "ps" command that shows the PID and command. On Solaris, use
+ /usr/bin/ps -ef "pid comm" -->
+ <pscmd>/bin/ps ax -o pid,command</pscmd>
+ <!-- Use "logger" to add output to syslog or not? Logger will be
+ used if the binary can be found, and if uselogger is true. -->
+ <uselogger>true</uselogger>
+ <!-- If logger is not used: where do logs get written? -->
+ <logdir>/var/log</logdir>
+ <!-- If logger is not used: how big may the logs become?
+ Manipulated during "xrctl rotate". -->
+ <maxlogsize>100000</maxlogsize>
+ <!-- If logger is not used: how many history logs to keep? -->
+ <loghistory>10</loghistory>
+ <!-- Path where the "xr" binary is searched, and zippers as "gzip"
+ and "bzip2" -->
+ <path>/bin:/sbin:/usr/bin:/usr/sbin:/usr/local/bin:/usr/local/sbin:/opt/local/bin:/opt/local/sbin</path>
+ </system>
+
+ <!-- Service descriptions: This section defines all balancing
+ services that you want to start. Each service will lead to one
+ invocation of "xr". -->
+
+ <!-- Very simple TCP service that dispatches SSH connections on
+ port 20.000 to three back ends. Most options are left to
+ their defaults. -->
+ <service>
+ <!-- Service name, must be unique -->
+ <name>ssh</name>
+ <server>
+ <!-- Type (tcp/http, here: tcp), and IP-address/port to bind
+ to. Use "0" for IP-address to bind to all interfaces. The
+ web interface will listen to localhost, port 20.001. -->
+ <type>tcp</type>
+ <address>0:20000</address>
+ <webinterface>0:20001</webinterface>
+ <!-- Clients may be idle for 30 minutes, then they are logged
+ out. -->
+ <clienttimeout>1800</clienttimeout>
+ </server>
+
+ <!-- Back ends for the service. -->
+ <backend>
+ <!-- IP:port to dispatch to. -->
+ <address>server1:22</address>
+ </backend>
+ <backend>
+ <address>server2:22</address>
+ </backend>
+ <backend>
+ <address>server2:22</address>
+ </backend>
+ </service>
+
+ <!-- Here is an HTTP service for web balancing. It shows more
+ advanced features. -->
+ <service>
+ <name>webone</name>
+
+ <!-- Balancer server description -->
+ <server>
+ <!-- Server binding. XR will listen to any IP interface, on port
+ 20.010. It'll be an HTTP balancer. The web interface will
+ be on port 20.011. -->
+ <address>0:20010</address>
+ <type>http</type>
+ <webinterface>127.0.0.1:20011</webinterface>
+
+ <!-- A non-default dispatch mode, here: by client IP.-->
+ <dispatchmode>lax-hashed-ip</dispatchmode>
+
+ <!-- Checks. Dead back ends are checked each 3 seconds. There is
+ no checking of dead and live back ends (checkupinterval 0). -->
+ <checks>
+ <wakeupinterval>3</wakeupinterval>
+ <checkupinterval>0</checkupinterval>
+ </checks>
+
+ <debugging>
+ <!-- Let's go with full messaging: verbose, debug, and logging
+ of transmitted messages. -->
+ <verbose>yes</verbose>
+ <debug>yes</debug>
+ <logtrafficdir>/tmp</logtrafficdir>
+ </debugging>
+
+ <!-- If the balancer runs out of sockets because too many
+ closing connections are in TIME_WAIT state, use: -->
+ <closesocketsfast>yes</closesocketsfast>
+
+ <!-- Access restrictions: we allow from two IP ranges, and deny
+ from one IP address. The overall results:will be:
+ - Access will be allowed from 10.*.*.*
+ - And allowed from 192.168.1.*, but not from 192.168.1.100 -->
+ <acl>
+ <allowfrom>10.255.255.255</allowfrom>
+ <allowfrom>192.168.1.255</allowfrom>
+ <denyfrom>192.168.1.100</denyfrom>
+ </acl>
+
+ <dosprotection>
+ <!-- Here is some basic DOS protection. Connections from IP's
+ are counted over timeinterval seconds (here: 2 sec). When a
+ client exceeds the hard limit hardmaxconnrate (here: 200),
+ then it is denied access. When it exceeds the soft limit
+ softmaxconnrate (here: 150), then each connection is
+ delayed for defertime microsecs (here: 1.000.000, one
+ sec).
+ Finally, the entire balancer will be allowed to serve up
+ to 400 simultaneous connections.
+ -->
+ <timeinterval>2</timeinterval>
+ <hardmaxconnrate>200</hardmaxconnrate>
+ <softmaxconnrate>150</softmaxconnrate>
+ <defertime>1000000</defertime>
+ <maxconnections>400</maxconnections>
+
+ <!-- Let's add some more protection. When a user exceeds their
+ hard maxconn rate, "/path/to/program" will be invoked
+ with the IP as argument. That program may eg. call
+ iptables to block the client. There is also a tag
+ softmaxconnexcess (not shown here). -->
+ <hardmaxconnexcess>/path/to/program</hardmaxconnexcess>
+
+ </dosprotection>
+
+ <http>
+ <!-- Since this is an HTTP balancer, let's add some goodies:
+ no header for the XR version,
+ a header X-Forwarded-For: client-ip
+ no sticky http sessions
+ two serverheaders to insert -->
+ <addxrversion>off</addxrversion>
+ <addxforwardedfor>on</addxforwardedfor>
+ <stickyhttp>off</stickyhttp>
+ <serverheaders>
+ <header>MyFirstHeader: Whatever</header>
+ <header>MySecondHeader: WhateverElse</header>
+ </serverheaders>
+ </http>
+ </server>
+
+ <!-- Back end definitions -->
+ <backend>
+ <!-- Backend lives on server1:80 and is very big (weight 2).
+ XR will forward up to 300 connections to it. The back end
+ checking is left to the default, which is: connect to the
+ IP and port of the back end. Requests for host
+ www.mysite.org will be serviced here. -->
+ <address>server1:80</address>
+ <weight>2</weight>
+ <maxconnections>300</maxconnections>
+ <hostmatch>www.mysite.org</hostmatch>
+ </backend>
+ <backend>
+ <!-- Backend lives on server2:80, has the default weight 1.
+ XR will forward up to 100 connections to it. The back end
+ checking is done by connecting to an alternative port 81.
+ This back end will be eligible for requests for the site
+ www.myothersite.org. -->
+ <address>server2:80</address>
+ <maxconnections>100</maxconnections>
+ <backendcheck>connect::81</backendcheck>
+ <hostmatch>www.myothersite.org</hostmatch>
+ </backend>
+ <backend>
+ <!-- Backend lives on server3:80, has the standard weight and no
+ limitations for the max nr. of connections. Back end
+ checking is done by retrieving /healthcheck.cgi from the
+ server. The back end is eligible for www.myothersite.org. -->
+ <address>server3:80</address>
+ <backendcheck>get:server3:80/healthcheck.cgi</backendcheck>
+ <hostmatch>www.myothersite.org</hostmatch>
+ </backend>
+ </service>
+
+</configuration>
+.fi
+
+.SH "SEE ALSO"
+xr(1), xrctl(1)
+
+.SH "AUTHOR"
+xrctl and the corresponding configuration file format were written by
+Karel Kubat <karel@kubat.nl>. Web page: http://crossroads.e-tunity.com
+
+.p
+This man page was written by Karel Kubat <karel@kubat.nl>.
diff --git a/test/udpfwd.c b/test/udpfwd.c
@@ -1,184 +0,0 @@
-
-#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/Makefile b/xr/Makefile
@@ -5,17 +5,17 @@ BUILDDIR = build
BIN = $(BUILDDIR)/xr
LIB = $(BUILDDIR)/libxr.a
TMPXR = /tmp/xr-$(shell whoami)
-CONF_CC = $(shell etc/c-conf -vc $(BUILDDIR)/config.cache c++-compiler)
-CONF_OPTFLAGS = $(shell etc/c-conf -vc $(BUILDDIR)/config.cache optflags)
-CONF_LIB = $(shell etc/c-conf -vc $(BUILDDIR)/config.cache \
+CONF_CC = $(shell etc/c-conf -c $(BUILDDIR)/config.cache c++-compiler)
+CONF_OPTFLAGS = $(shell etc/c-conf -c $(BUILDDIR)/config.cache optflags)
+CONF_LIB = $(shell etc/c-conf -c $(BUILDDIR)/config.cache \
lib ucb nsl pthread socket m alf)
-CONF_GETOPT = $(shell etc/c-conf -vc $(BUILDDIR)/config.cache \
+CONF_GETOPT = $(shell etc/c-conf -c $(BUILDDIR)/config.cache \
ifheader getopt.h HAVE_GETOPT_H)
-CONF_GETOPT_LONG = $(shell etc/c-conf -vc $(BUILDDIR)/config.cache \
+CONF_GETOPT_LONG = $(shell etc/c-conf -c $(BUILDDIR)/config.cache \
libfunction getopt_long HAVE_GETOPT_LONG)
-CONF_INET_ATON = $(shell etc/c-conf -vc $(BUILDDIR)/config.cache \
+CONF_INET_ATON = $(shell etc/c-conf -c $(BUILDDIR)/config.cache \
libfunction inet_aton HAVE_INET_ATON)
-CONF_STRNSTR = $(shell etc/c-conf -vc $(BUILDDIR)/config.cache \
+CONF_STRNSTR = $(shell etc/c-conf -c $(BUILDDIR)/config.cache \
libfunction strnstr HAVE_STRNSTR)
foo:
diff --git a/xr/etc/c-conf b/xr/etc/c-conf
@@ -362,8 +362,8 @@ ENDHELP
output ("-l$lib");
}
}
- warning ("Library '$lib' not found\n")
- unless ($found);
+ #warning ("Library '$lib' not found\n")
+ # unless ($found);
}
}
diff --git a/xr/tcpdispatcher/execute.cc b/xr/tcpdispatcher/execute.cc
@@ -1,6 +1,7 @@
#include "tcpdispatcher"
-static map <unsigned long, queue <time_t> > accesslog;
+typedef map < unsigned long, std::queue<time_t> > AccessMap;
+static AccessMap accesslog;
static time_t accesslog_lastclean = 0;
// Execute an external program upon excess of hard/soft rates
@@ -53,8 +54,7 @@ void TcpDispatcher::execute() {
accesslog_lastclean = now;
Mutex::unlock(&accesslog_lastclean);
- for (map<unsigned long, queue <time_t> >::iterator i =
- accesslog.begin();
+ for (AccessMap::iterator i = accesslog.begin();
i != accesslog.end();
i++ ) {
if (accesslog[i->first].back() < min_ts) {