diff --git a/.gitignore b/.gitignore index 7b480b5..585b705 100644 --- a/.gitignore +++ b/.gitignore @@ -2,6 +2,7 @@ Makefile Makefile.in install-sh *.orig +*.pid *.rej core config.h @@ -15,7 +16,7 @@ stamp-h1 dh.h dh2048.h dh512.h -pound +/pound poundctl configure config.guess diff --git a/README b/README deleted file mode 100644 index 1c4ddc6..0000000 --- a/README +++ /dev/null @@ -1,938 +0,0 @@ -POUND - REVERSE-PROXY AND LOAD-BALANCER - - The Pound program is a reverse proxy, load balancer and - HTTPS front-end for Web server(s). Pound was developed - to enable distributing the load among several Web-servers - and to allow for a convenient SSL wrapper for those Web - servers that do not offer it natively. Pound is distributed - under the GPL - no warranty, it's free to use, copy and - give away. - -ABOUT THIS VERSION (with OpenSSL v1.1.0 and WebSocket support) - - This is a fork of Pound 2.8a modified to compile and link - with OpenSSL version 1.1.0 and later. Backward compatibility - with earlier versions of OpenSSL is retained. The orginal code - has been obtained from http://www.apsis.ch/pound/Pound-2.8a.tgz. - Later on, the changes from the stable 2.8 release were applied. - - This modified version was tested under production load with - OpenSSL 1.1.0g and 1.0.1e. - - This version was further modified by Rick O'Sullivan by - incorporating WebSocket support, provided by Frank Schmirler - (see - ) - -WHAT POUND IS: - - 1. a reverse-proxy: it passes requests from client - browsers to one or more back-end servers. - - 2. a load balancer: it will distribute the requests from - the client browsers among several back-end servers, - while keeping session information. - - 3. an SSL wrapper: Pound will decrypt HTTPS requests - from client browsers and pass them as plain HTTP - to the back-end servers. - - 4. an HTTP/HTTPS sanitizer: Pound will verify requests - for correctness and accept only well-formed ones. - - 5. a fail over-server: should a back-end server fail, - Pound will take note of the fact and stop passing - requests to it until it recovers. - - 6. a request redirector: requests may be distributed - among servers according to the requested URL. - - Pound is a very small program, easily audited for security - problems. It can run as setuid/setgid and/or in a chroot - jail. Pound does not access the hard-disk at all (except - for reading certificate file(s) on start, if required) - and should thus pose no security threat to any machine. - - -WHAT POUND IS NOT: - - 1. Pound is not a Web server: by itself, Pound serves no - content - it contacts the back-end server(s) for that - purpose. - - 2. Pound is not a Web accelerator: no caching is done - - every request is passed "as is" to a back-end server. - - -STATUS - - As of release 1.0 Pound is declared to be production-quality code. - - Quite a few people have reported using Pound successfully in production - environments. The largest volume reported to date is a site with an - average of about 30M requests per day, peaking at over 600 requests/sec. - - Pound was successfully used in production with a variety of Web servers, - including Apache, IIS, Zope, WebLogic, Jakarta/Tomcat, iPlanet, etc. In - general Pound passes requests and responses back and forth unchanged, - so we have no reason to think that any web server would be incompatible. - - Client browsers that were tested: - - - IE 5.0/5.5 (Windows) HTTP/HTTPS - - - Netscape 4.7 (Windows/Linux) HTTP/HTTPS - - - Mozilla (Windows/Linux) HTTP/HTTPS - - - Konqueror (Linux) HTTP/HTTPS - - - Galleon (Linux) HTTP/HTTPS - - - Opera (Linux/Windows) HTTP/HTTPS - - - Lynx (Linux) HTTP - - Given that Pound is in production and no problems were reported, we have - no reason to believe that other browsers would present a problem. A few - issues were observed with problematic SSL implementations, most notably - with Opera 6, but these should be OK in the present version. - -BOOTSTRAPPING - - If you obtained the sources from the repository, you will need the - following tools in order to build from them: - - - Autoconf v.2.63 or later (http://www.gnu.org/software/automake) - - Automake v.1.11 or later (http://www.gnu.org/software/autoconf) - - Change to the project directory and run - - ./bootstrap - - This will create the configure script and populate the directory with - auxiliary files needed for configuration. Once done, proceed to - ./configure and make as discussed in the following section. - -INSTALLATION - - Probably the easiest way to install Pound is to use a pre-compiled package - if you can find one. While Apsis offers no such packages, they are available - for quite a few systems (Suse, Debian and derivatives such as Ubuntu), as - well as some private packages: - - - RPMs for RedHat are available at http://www.invoca.ch/pub/packages/pound/ - - - A nice FreeBSD live-CD distribution is available at http://www.targeted.org as - http://www.targeted.org/files/fbsd62_pound23.iso.gz, including a Pound binary. - - Failing that you should install from sources: - - 1. Pound was tested on Linux, Solaris and OpenBSD, but - it should work unchanged on just about any modern - Unix-like system. You will require at least OpenSSL and - libpthread. The PCRE package is strongly recommended. - - Warning: as Pound is a multi-threaded program it requires - a version of OpenSSL with thread support. This is normally - the case on Linux and Solaris (for example) but not on *BSD. - If your system has the wrong library please download, compile - and install OpenSSL (from http://www.openssl.org). - - If the PCRE package is available Pound will link against it. - This will provide a significant performance boost. - - 2. Download the current version of Pound-current file and unpack - it. The archive is signed. - My signature is available at http://www.apsis.ch/pound/roseg.asc. - Alternately see below for stable versions. - - Unpack. Do the usual thing: - - ./configure - - 3. The following options are available for the configure script: - - --with-ssl=ssl_dir -- OpenSSL home directory (default: system defined). - - --disable-super -- disable supervisor process (default: enabled) - - --with-t_rsa=nnn -- timeout of the RSA ephemeral keys regeneration - (default: 1800 seconds). - - --with-owner=owner -- name of installed binaries owner (default is - system-dependent). - - --with-group=group -- name of installed binaries group (default is - system-dependent). - - 4. Check that the resulting Makefile is correct and possibly - adjust flags as needed on your system. Compile: - - make - - 5. If it works, you may want to do some testing before installing. - - 6. Install the executable somewhere (it's likely that - /usr/local/sbin would make a good choice), as well - as the manual page (pound.8 -> /usr/local/man/man8). - The supplied Makefile will do it for you. - - 7. Make sure Pound gets started on boot. Read the man - page for available options and examples. - - -COPYRIGHT - - Pound is copyrighted by Apsis GmbH and is distributed under - the terms of the GNU Public License with the additional - exemption that compiling, linking, and/or using OpenSSL is - allowed. Basically, this means that you can use it free of - charge, copy it, distribute it (provided the copyright is - maintained and the full package is distributed), modify it, - or line a bird-cage with it. - - We would be happy to hear from you if you use it and - suggestions and improvements are gladly accepted. - - -CONTACT - - Robert Segall, roseg@apsis.ch - - Apsis GmbH, http://www.apsis.ch - - P O Box - - CH-8707 Uetikon am See - - Switzerland - - +41-44-920 4904 - - -MAILING LIST - - Pound has its own mailing list now: please send a message with - the subject "subscribe" to pound@apsis.ch in order to - subscribe. You will receive confirmation and instructions in - the reply. - - All messages are available and indexed (searcheable) in the - archive http://www.apsis.ch/pound/pound_list. - - The mailing list is the primary support forum for Pound - please - post there any questions you may have. The developpers' address is - given here for information purposes only. - - - -ZOPE - - A special note for Zope users: the original intent on - developing Pound was to allow distributing the load - among several Zope servers running on top of ZEO. This - it does. - - A special problem arises when you try using Pound as an - SSL wrapper: Zope assumes that the requests are made via - HTTP and insists on prepending 'http://' to the (correct) - address in the replies, including in the tag and - the absolute URLs it generates (for images for example). - This is clearly an undesirable behavior. - - For older Zope versions (prior to 2.7): a modified z2.py (as - well as a patch) is included in the distribution. The main - difference is that this z2.py allows starting an additional - HTTP server via the -y flag that sets the environment - HTTPS variable - thus correcting the problem. That means - that in order to use Pound as an SSL wrapper you need to: - - - start Zope (modify the 'start' file) as: - - python -X -w 8080 -y 8443 ... - - For Zope 2.7 or later the same effect can be achieved via suitable - modifications to zope.conf. - - - -VIRTUAL HOSTS (IN GENERAL) - - Some people asked about the possibility of redirecting requests to back-ends - as per some virtual hosts definition. While I believe this is not Pound's - job, it can be done. As of version 0.10, Pound supports filtering requests - based not only on the request URL, but also on the presence or absence of - certain headers. - - Let's assume that you have internal server 192.168.0.10 that is supposed to - serve the needs of virtual host www.server0.com and 192.168.0.11 that serves - www.server1.com. You want Pound to listen on address 1.2.3.4 and separate - the requests to each host. The config file would look something like this: - - ListenHTTP - Address 1.2.3.4 - Port 80 - - Service - HeadRequire "Host: .*www.server0.com.*" - - BackEnd - Address 192.168.0.10 - Port 80 - End - End - - Service - HeadRequire "Host: .*www.server1.com.*" - - BackEnd - Address 192.168.0.11 - Port 80 - End - End - End - - (add whatever else is necessary) or, if you want even safer filtering: - - ListenHTTP - Address 1.2.3.4 - Port 80 - - Service - HeadRequire "Host: .*www.server0.com.*" - HeadDeny "Host: .*www.server1.com.*" - - BackEnd - Address 192.168.0.10 - Port 80 - End - End - - Service - HeadRequire "Host: .*www.server1.com.*" - HeadDeny "Host: .*www.server0.com.*" - - BackEnd - Address 192.168.0.11 - Port 80 - End - End - End - - This is NOT recommended (I personally believe that virtual hosts should be - implemented in the back-end servers - putting this in a proxy - is a major security kludge) but it works. - - - -VIRTUAL HOSTS AND HTTPS - - Quite often we get inquiries about Pound's ability to do virtual hosting - with HTTPS. In order to lay this matter to rest, let me say: - - HTTPS does not allow virtual hosting! - - This is not a limitation of Pound, but of HTTPS - no Web server or proxy - are able to do it due to the nature of the beast. - - In order to see why this is the case we need to look at the way HTTPS works. - Basically there are three stages in any HTTPS connection: - - 1. Connection negotiation - the client (your browser) and the server (Web - server or proxy) negotiate the basic parameters: ciphers to use, session - key, etc. - - 2. Connection authentication: at the very least the server presents the - client with a certificate that says "I am server www.encrypted.com - and - certificate.authority.org will verify that". The client may also present - a certificate of its own at this stage. - - 3. Request/response cycle: normal HTTP is sent (through the encrypted - channel) back and forth. - - The vital point to notice here is that connection authentication takes place - BEFORE any request was issued. - - On the other hand, the way virtual hosting works is for the client to - specify in the request to which server it would like to talk. This is - accomplished via a Host header: - - GET /index.html HTTP/1.1 - Host: http://www.virthost.com - - Combining the two we get to an impasse: on connection setup the server will - reply with the certificate for "www.realhost.com", but the request is really - for "www.virthost.com" - and most browsers will scream blue murder (as well - they should) if the two do not match. - - There is a new twist on this however: some of the newer browsers will accept - so-called "wild-card certificates". This is a specially crafted certificate - that is not issued to a host, but rather to a domain. The result is that - on setting-up a new SSL connection, the server replies not with "I am - www.encrypted.com", but with "I am *.encrypted.com". If the browser is - capable of processing this type of certificate then the connection is - set up and normal HTTPS (with www.encrypted.com or special.encrypted.com or - even some.other.server.encrypted.com or whatever other name matches) proceeds - as usual. Pound supports these certificates and you can use virtual hosts in - the normal way. - - Update June 2010: starting with the 2.6 series, Pound has SNI support, if your - OpenSSL version supports it. Basically you supply Pound with several certificates, - one for each virtual host (wild card certificates - as described above - are - allowed). On connecting the client signals to which server it wants to talk, - and Pound searches among its certificates which would fit. Not all versions - of OpenSSL and not all clients support this mode, but if available it allows - for virtual hosts over HTTPS. - - An additional option is to use a semi-official TLS extension, the so called - alternate subject name. If your version of OpenSSL supports it you may specify - in one certificate several alternate server names. This requires support for a - special TLS feature, and nor all clients accept it. - - - -VIRTUAL HOSTS IN ZOPE - - For reasons I can't quite grasp, it seems that a lot of Zope - users are convinced that virtual hosts are only possible through - the Apache/VHM combination and that it requires some kind of - magic incantation at midnight in order to work (I won't even - start on the virgin sacrifices). - - The simple fact is that VHM and the Apache VirtualHost directives - (as well as various tricks through mod_rewrite and mod_proxy) are - (almost) mutually exclusive: they perform exactly the same - functions and, leaving aside the logging issues, are used - independently of each other. Let me repeat that: you may use the - VHM without Apache - just click on the VHM mappings tab and add - whatever virtual host you wish. From this moment on any request - to that host will be mapped back and forth by Zope to the required - URL. This works weather you access Zope directly or via any number - of proxies on the way, Pound included. - - To test: add a new host name to your /etc/hosts file, making it an - alias for localhost - something like:: - - 127.0.0.1 localhost www.testhost.mine - - Add a mapping in VHM from www.testhost.mine to some Zope folder - (Examples is already there). Point your browser to http://localhost - and you get the normal Zope start page; point it to - http://www.testhost.mine and you'll see the Examples starting page. - All requests are mapped correctly, and the URLs in the pages (such - as base or absoluteURL) are translated correctly in the response. - - -SESSIONS - - Pound has the ability to keep track of sessions between a client - browser and a back-end server. Unfortunately, HTTP is defined as - a stateless protocol, which complicates matters: many schemes have - been invented to allow keeping track of sessions, none of which works - perfectly. Even worse, sessions are critical in order to allow - web-based applications to function correctly - it is vital that once - a session is established all subsequent requests from the same browser - be directed to the same back-end server. - - Six possible ways of detecting a session have been implemented in - Pound (hopefully the most useful ones): by client address, by Basic - authentication (user id/password), by URL parameter, by cookie, by - HTTP parameter and by header value. - - - by client address: in this scheme Pound directs all requests from - the same client IP address to the same back-end server. Put the - lines - - Session - Type IP - TTL 300 - End - - in the configuration file to achieve this effect. The value indicates - what period of inactivity is allowed before the session is discarded. - - - by Basic Authentication: in this scheme Pound directs all requests from - the same user (as identified in the Basic Authentication header) to the - same back-end server. Put the lines - - Session - Type Basic - TTL 300 - End - - in configuration file to achieve this effect. The value indicates what - period of inactivity is allowed before the session is discarded. - - WARNING: given the constraints of the HTTP protocol it may very well be - that the authenticated request will go to a different back-end server than - the one originally requesting it. Make sure all your servers support - the same authentication scheme! - - - by URL parameter: quite often session information is passed through URL - parameters (the browser is pointed to something like http://xxx?id=123). - Put the lines - - Session - Type URL - ID "id" - TTL 300 - End - - to support this scheme and the sessions will be tracked based on the value - of the "id" parameter. - - - by cookie value: applications that use this method pass a certain cookie - back and forth. Add the lines - - Session - Type Cookie - ID "sess" - TTL 300 - End - - to your configuration file - the sessions will be tracked by the value of - the "sess" cookie. - - - by HTTP parameter value: applications that use this method pass an HTTP - parameter (http://x.y/z;parameter) back and forth. Add the lines - - Session - Type PARM - TTL 300 - End - - to your configuration file - the sessions will be tracked by the value of - the parameter. - - - by header value: applications that use this method pass a certain header - back and forth. Add the lines - - Session - Type Header - ID "X-sess" - TTL 300 - End - - to your configuration file - the sessions will be tracked by the value of - the "X-sess" header. - - Please note the following restrictions on session tracking: - - - session tracking is always associated with a certain Service. Thus each - group may have other methods and parameters. - - - there is no default session: if you have not defined any sessions no - session tracking will be done. - - - only one session definition is allowed per Service. If your application - has alternative methods for sessions you will have to define a separate - Service for each method. - - A note on cookie injection: some applications have no session-tracking mechanism at - all but would still like to have the client always directed to the same back-end - time after time. Some reverse proxies use a mechanism called "cookie injection" in - order to achieve this: a cookie is added to the back-end responses and tracked by the - reverse proxy. - - Pound was designed to be as transparent as possible, and this mechanism is not - supported. If you really need this sort of persistent mapping use the client address - session mechanism (Session Type IP), which achieves the same result without - changing the contents in any way. - - -REQUEST LOGGING - - As a general rule, Pound passes all headers as they arrive from the client - browser to the back-end server(s). There are two exceptions to this rule: - Pound may add information about the SSL client certificate (as described - below), and it will add an X-Forwarded-For header. The general format is: - - X-Forwarded-for: client-IP-address - - The back-end server(s) may use this extra information in order to create - their log-files with the real client address (otherwise all requests will - appear to originate from Pound itself, which is rather useless). - - In addition, Pound logs requests and replies to the system log. This is - controlled by the LogLevel configuration variable (0 - no logging, - 1 - normal log, 2 - full log, 3 - Apache combined log format, 4 - Apache - combined log format without virtual host). - - By default the messages go to the LOG_DAEMON facility, but you can change - this in the configuration file. If you don't want to, you can just do a: - - fgrep pound /var/log/messages - - to get all the messages generated by Pound. - - -HTTPS CERTIFICATES - - If a client browser connects via HTTPS and if it presents a - certificate and if HTTPSHeaders is set, Pound will obtain the - certificate data and add the following HTTP headers to the - request it makes to the server: - - - X-SSL-Subject: information about the certificate owner - - - X-SSL-Issuer: information about the certificate issuer (CA) - - - X-SSL-notBefore: begin validity date for the certificate - - - X-SSL-notAfter: end validity date for the certificate - - - X-SSL-serial: certificate serial number (in decimal) - - - X-SSL-cipher: the cipher currently in use - - - X-SSL-certificate: the full client certificate (multi-line) - - It is the application's responsibility to actually use these - headers - Pound just passes this information without checking - it in any way (except for signature and encryption correctness). - - Please note that this mechanism allows forgeries: a client may - (maliciously) send these headers to Pound in order to masquerade - as an SSL client with a specific certificate. If this is a problem - for your application make sure to deny these requests. Add: - - HeadDeny "X-SSL-Subject:.*" - HeadDeny "X-SSL-Issuer:.*" - HeadDeny "X-SSL-notBefore:.*" - HeadDeny "X-SSL-notAfter:.*" - HeadDeny "X-SSL-serial:.*" - HeadDeny "X-SSL-cipher:.*" - - within the Service(s). - - -THREADS AND LIMITS - - A few people ran into problems when installing Pound because of the - various threading models and how they interact with system-imposed - limits. Please keep in mind the following requirements: - - - on most System V derived Unices (of which Linux up to 2.4 is one), - a thread is a process. This means that when doing a 'ps' you will see - as many processes with the name 'pound' as there are active threads. - Each such process uses only two file descriptors, but the system needs - to support the required number of processes, both in total and per - user (possibly also per process group). In bash, this is 'ulimit -u', - in csh this is 'limit maxproc'. - - - on BSD style systems all threads run in the same process space. Do - a ps and you see a single 'pound' process. The process needs two - file descriptors per active request (bash: 'ulimit -n', csh - 'limit maxfiles'/'limit openfiles'). - - - on most systems the thread library comes with a built-in limit on the - maximal number of concurrent threads allowed - on older systems it usually - is 1024, on newer systems quite a bit higher. In very - rare cases (very high load and long response times) you may run into - this limitation - the symptom is log messages saying "can't create - thread". Your only solution is to recompile the system threads library - (and possibly the kernel itself) with a higher limit. - - Please note that your kernel needs to be configured to support the - required resources - the above are just the shell commands. - -SIMILAR SYSTEMS - - Quite a few people asked "What is wrong with Apache/Squid/ - stunnel/your_favorite? Do we really need another proxy - system?". The simple answer is that there is nothing wrong - - they are all excellent systems that do their jobs very well. - The reasoning behind Pound is however slightly different: - - - In my experience, a load-balancer may easily become a - bottle-neck in itself. If you have a heavily loaded site, - there are few things more depressing than seeing your - "load-balancer" slow down the entire network. This means that - the load-balancer should be kept as light-weight as possible. - - - Security: auditing a large system for security issues is a - major undertaking for anybody (ask Bill Gates about it). This - implies that in order to avoid introducing new vulnerabilities - into a system (after all, your installation is only as secure - as its weakest component) the proxy/load-balancer should be - kept as small as possible. - - - Protection: I assume Pound will be the only component exposed - to the Internet - your back-end servers will run in a protected - network behind it. This means that Pound should filter requests - and make sure only valid, correctly formed ones are passed to the - back-end servers, thus protecting them from malicious clients. - - Taking these criteria into consideration, it is easy to see why - the other systems mentioned above do not fit: - - - Apache (with mod_proxy and mod_backhand): great system, but very - large. Imposes a significant load on the system, complex set-up - procedure (and it is so easy to get it wrong: check how many Apache - servers allow proxying from and to external hosts). While Apache - has proven remarkably exploit free, I wouldn't wish to go into a - security audit for the tens of thousands of lines of code involved, - not to mention all the additional modules. - - - Squid: great caching proxy, but even should load-balancing - features become available in the future, do you really need - caching on the load-balancer? After all, Pound can easily run on a - disk-less system, whereas with Squid you'd better prepare a high - throughput RAID. Squid is still perfectly usable as a caching - proxy between Pound and the actual Web server, should it lack - its own cache (which Zope happily has). - - - stunnel: probably comes closest to my understanding of software - design (does one job only and does it very well). However, it - lacks the load balancing and HTTP filtering features that I - considered necessary. Using stunnel in front of Pound (for HTTPS) - would have made sense, except that integrating HTTPS into Pound - proved to be so simple that it was not worth the trouble. - - - your favourite system: let me know how it looks in light of the - above criteria - I am always interested in new ideas. - - -DEDICATED SERVERS - - Some people asked about the possibility of dedicating specific - back-end servers to some clients - in other words, if a request - originates from a certain IP address or group of addresses then - it should be sent to a specific group of back-end servers. - - Given the ease with which IP addresses can be forged I am personally - doubtful of the utility of such a feature. Even should you think it - desirable, it is probably best implemented via the packet filter, - rather than a proxy server. Assuming that requests from x.com are - to go to s1.local, requests from y.com to s2.local and everything - else to s3.local and s4.local, here is how to do it: - - - make sure your firewall blocks requests to port 8080, 8081 and 8082 - - - configure Pound as follows: - - ListenHTTP - Address 127.0.0.1 - Port 8080 - - Service - BackEnd - Address s1.local - Port 80 - End - End - End - - ListenHTTP - Address 127.0.0.1 - Port 8081 - - Service - BackEnd - Address s2.local - Port 80 - End - End - End - - ListenHTTP - Address 127.0.0.1 - Port 8082 - - Service - BackEnd - Address s3.local - Port 80 - End - BackEnd - Address s4.local - Port 80 - End - End - End - - - have your packet filter redirect requests to the right local ports - based on the origin address. In OpenBSD pf syntax this would be - something like: - - rdr on rl0 from x.com to myhost.com port 80 -> localhost port 8080 - rdr on rl0 from y.com to myhost.com port 80 -> localhost port 8081 - rdr on rl0 from any to myhost.com port 80 -> localhost port 8082 - - or in Linux iptables:: - - iptables -t nat -A PREROUTING -p tcp -s x.com --dport 80 -i eth0 \ - -j DNAT --to 127.0.0.1:8080 - iptables -t nat -A PREROUTING -p tcp -s y.com --dport 80 -i eth0 \ - -j DNAT --to 127.0.0.1:8081 - iptables -t nat -A PREROUTING -p tcp --dport 80 -i eth0 -j DNAT \ - --to 127.0.0.1:8082 - - This would give you the desired effect and probably better - performance than a purely proxy-based solution (though the - performance improvement is debatable, at least on Linux). - - -WebDAV - - As of version 1.0 Pound supports the full WebDAV command-set. In - fact, it has been tested and is known to (almost) work with the - Microsoft Outlook Web Gateway, which is quite remarkable given that - Microsoft's own proxy does not. - - Regrettably, Microsoft adherence to standards leaves something to be - desired: they decided to add some characters to their URLs - thus - breaking a whole set of RFC's. - - Rather then change Pound to accept these characters (which could create - some serious issues with security on other systems) we have made this - behaviour dependent on a configuration switch: xHTTP (see the man page - for details). - - If you also use the SSL wrapper feature in front of a Microsoft server - you should probably also add 'AddHeader "Front-End-Https: on"'. - - These changes are also required to access a Subversion server via - Pound. - - -OTHER ISSUES - - The following problems were reported by various people who use pound: - - - delays in loading pages when the client browser is IE 5.5 (possibly - limited to W2K/XP). It seems that IE opens exactly 4 connections (sockets) - to the server and keeps them open until some time-out or until the server - closes the connection. This works fine, unless you redirect IE to another - server - given that all 4 sockets are used IE waits for a while before - the redirect is actually performed. - - Solution: use the directive "Client 1" to ensure that Pound closes - sockets very early, thus freeing the necessary resources. Experiment with - the time-out - as it may cause problems with slow connections. - - - Pound fails to start; HTTPS is enabled and the message "can't read - private key from file xxx" appears in the log. - - Solution: make sure that the certificate file includes: - - - (optional) a chain of certificates from a known certificate authority to - your server certificate - - - the server certificate - - - the private key; the key may NOT be password-protected - - The file should be in PEM format. The OpenSSL command to generate a - self-signed certificate in the correct format would be something like:: - - openssl req -x509 -newkey rsa:1024 -keyout test.pem -out test.pem \ - -days 365 -nodes - - Note the '-nodes' flag - it's important! - - - Pound fails to operate correctly with SSL when RootJail is specified. - Solution: OpenSSL requires access to /dev/urandom, so make sure such a - device is accessible from the root jail directory. Thus if your root - jail is something like /var/pound: - - mkdir /var/pound/dev - mknod /var/pound/dev/urandom c 1 9 - - or whatever major/minor number are appropriate for your system. - - - In chroot mode logging may stop functioning. - Solution: make sure /dev and the root jail are on the same filesystem - and create a hard link in the root jail to /dev/log: - - mkdir /chroot/jail/dev - ln /dev/log /chroot/jail/dev/log - - Alternately you can have syslog (or syslog-ng) listen on another - socket - see the man page for details. - - - In chroot mode name resolution (and especially redirects) may stop - functioning. Solution: make sure your resolver works correctly in the - jail. You probably need copies of /etc/resolv.conf and (at least part) - of /etc/hosts. Depending on your system additional files may be required - check your resolver man page for details. Should name resolution fail the - translation of host names to IP addresses would fail, thereby defeating - the mechanism Pound uses to identify when should a Redirect be rewritten. - - - IE 5.x fails to work (correctly or at all) with Pound in HTTPS mode. - Solution: define the supported OpenSSL ciphers for IE compatibility (this - is really a work-around for a known IE bug): - - Ciphers "ALL:!ADH:!EXPORT56:RC4+RSA:+HIGH:+MEDIUM:+LOW:+SSLv2:+EXP:+eNULL" - - (Thanks to Andi Roedl for the tip). - - - Linux-specific: some people use various redundant Pound solutions for - Linux which require Pound instances on separate machines to bind to the - same address. The default configuration of Linux does not allow a - program to bind() to non-local addresses, which may cause a problem. - Solution: add - - echo 1 > /proc/sys/net/ipv4/ip_nonlocal_bind - - in your start-up script, or just set - - net.ipv4.ip_nonlocal_bind = 1 - - in /etc/sysctl.conf (if you have one). - - (Thanks to RUne Saetre for the suggestion). - - -ACKNOWLEDGMENTS - - Albert (of Alacra) for investigating and writing the TCP_NODELAY code. - - Luuk de Boer did some serious testing and debugging of the WebDAV - code for Microsoft servers. - - Alession Cervellin packages and makes available Solaris packages for - various Pound versions. - - David Couture found some nasty, lurking bugs, as well as contributing - some serious testing on big hardware. - - Frank Denis contributed a few excellent code patches and some good ideas. - - Dmitriy Dvoinikov makes available a live-CD FreeBSD distribution that - includes a Pound binary. - - Abner G. Jacobsen did a lot of testing in a production environment - and contributed some very nice ideas. - - Akira Higuchi found a significant security issue in Pound and contributed - the code to fix it. - - Ken Lalonde contributed very useful remarks and suggestions, as well as - correcting a few code errors. - - Phil Lodwick contributed essential parts of the high-availability code and - came up with some good ideas. In addition, did some serious testing under - heavy loads. - - Simon Matter packages and makes available RPMs for various Pound versions. - - Jan-Piet Mens raised some interesting security points about the HTTPS - implementation and brought the original idea for SSL header filtering. - - Andreas Roedl for testing and some ideas about logging in root jails. - - Gurkan Sengun tested Pound on Solaris, contributed the Solaris cc flags - and makes a Solaris pre-compiled version available on his Web-site - (www.linuks.mine.nu) - - Shinji Tanaka contributed a patch for controlling logging to disk files. - This is available at http://www.hatena-inc.co.jp/~stanaka/pound/ - - Jim Washington contributed the code for WebDAV and tested it. - - Maxime Yve discovered a nasty bug in the session tracking code and - contributed the patch to fix it. - - All the others who tested Pound and told me about their results. diff --git a/README-QUICK.md b/README-QUICK.md new file mode 100644 index 0000000..0389466 --- /dev/null +++ b/README-QUICK.md @@ -0,0 +1,80 @@ +# Pound Quick Build + +Pound is a C language program. To build Pound from source code, install the prerequisite tools and libraries on your system then build using the hints shown below. + +## Prerequisites (Debian) + + sudo apt install build-essential + sudo apt install libssl-dev + sudo apt install libpcre3-dev + sudo apt install linux-headers-$(uname -r) + sudo apt install autoconf + +See also . + +### Build + + 1) ./bootstrap + 2) ./configure --with-maxbuf=8192 + 3) make all + 3.1) makes poundctl + 3.2) makes pound + 3.3) ldd pound + 4) sudo make install-strip + 4.1) installs /usr/local/bin/poundctl + 4.2) installs /usr/local/sbin/pound + 4.3) installs /usr/local/share/man/man8/poundctl.8 + 4.4) installs /usr/local/share/man/man8/pound.8 + 5) Manually review 'etc' samples and install, as needed. + 5.1) installed-list.sh - lists installed files. + 5.2) installed-test.sh - runs pound for testing. + +### Standard make targets + +- **all**: Compile the entire program. (default target) + +- **install**: Compile the program and copy the executables, libraries, and so on to the file names where they should reside for actual use. + +- **install-strip**: Like install, but strip the executable files while installing them. + +- **uninstall**: Delete all the installed files—the copies that the ‘install’ and ‘install-*’ targets create. + +- **clean**: Delete all files in the current directory that are normally created by building the program. + +- **distclean**: Delete all files in the current directory (or created by this makefile) that are created by configuring or building the program. + +- **dist**: Create a distribution tar file for this program. + +- **check**: Perform self-tests (if any). + +- **installcheck**: Perform installation tests (if any). + +- **installdirs**: It’s useful to add a target named ‘installdirs’ to create the directories where files are installed, and their parent directories. + +### Installation Paths + + /etc/pound/ + /etc/rsyslog.d/30-pound.conf + /usr/local/share/man/man8/pound.8 + /usr/local/share/man/man8/poundctl.8 + /usr/local/bin/poundctl + /usr/local/sbin/pound + /var/chroot/pound/ + /var/log/pound/ + /var/run/pound.pid + /var/run/pound/poundctl.socket + +### Daemon Paths + + SystemD: /etc/systemd/system/pound.service + SystemV: /etc/default/pound + SystemV: /etc/init.d/pound + SystemV: /etc/rc?.d/*pound + +### Git Status / Clean + + git status -u + git remote show origin + git ls-files . --ignored --exclude-standard --others + git clean -xn + git clean -xfd diff --git a/README.md b/README.md new file mode 100644 index 0000000..ac011f9 --- /dev/null +++ b/README.md @@ -0,0 +1,986 @@ +# POUND + +The Pound program is a reverse proxy, load balancer and HTTPS +front-end for Web server(s). + +## REVERSE-PROXY AND LOAD-BALANCER + +Pound was developed to enable distributing the load among several +Web-servers and to allow for a convenient SSL wrapper for those Web +servers that do not offer it natively. Pound is distributed +under the GPL - no warranty, it's free to use, copy and +give away. + +### ABOUT THIS VERSION (with OpenSSL v1.1.0 and WebSocket support) + +This is a fork of Pound 2.8a modified to compile and link +with OpenSSL version 1.1.0 and later. Backward compatibility +with earlier versions of OpenSSL is retained. The orginal code +has been obtained from . +Later on, the changes from the stable 2.8 release were applied. + +This modified version was tested under production load with +OpenSSL 1.1.0g and 1.0.1e. + +### ABOUT THIS VERSION (with OpenSSL v1.1.0 and WebSocket and Patches) + +This is a fork of Sergey Poznyakoff's fork (2) of Pound from +Apsis (1) patched with WebSocket support and other patches +provided by Frank Schmirler (3,4,8). + +1. +2. +3. [WebSocket support for pound](https://admin.hostpoint.ch/pipermail/pound_apsis.ch/2018-August/000037.html) +4. [Wrong use of Fallback SCSV / TLS1.3 interoperability](https://admin.hostpoint.ch/pipermail/pound_apsis.ch/2018-December/000030.html) +5. Added `etc` folder with SysV and SystemD boot scripts. +6. Added XSSLHeaders directive to control sending X-SSL headers to the back-end. +7. Added [README-QUICK.md](https://github.com/patrodyne/pound/blob/master/README-QUICK.md) +8. [Added Strict-Transport-Security response header at service level](https://admin.hostpoint.ch/pipermail/pound_apsis.ch/2019-December/008038.html) + +### WHAT POUND IS: + +1. **a reverse-proxy:** it passes requests from client + browsers to one or more back-end servers. + +2. **a load balancer:** it will distribute the requests from + the client browsers among several back-end servers, + while keeping session information. + +3. **an SSL wrapper:** Pound will decrypt HTTPS requests + from client browsers and pass them as plain HTTP + to the back-end servers. + +4. **an HTTP/HTTPS sanitizer:** Pound will verify requests + for correctness and accept only well-formed ones. + +5. **a fail over-server:** should a back-end server fail, + Pound will take note of the fact and stop passing + requests to it until it recovers. + +6. **a request redirector:** requests may be distributed + among servers according to the requested URL. + +Pound is a very small program, easily audited for security +problems. It can run as `setuid/setgid` and/or in a `chroot` +jail. Pound does not access the hard-disk at all (except +for reading certificate file(s) on start, if required) +and should thus pose no security threat to any machine. + + +### WHAT POUND IS NOT: + +1. **Pound is not a Web server:** by itself, Pound serves no + content - it contacts the back-end server(s) for that + purpose. + +2. **Pound is not a Web accelerator:** no caching is done - + every request is passed "as is" to a back-end server. + + +### STATUS + +As of release 1.0 Pound is declared to be production-quality code. + +Quite a few people have reported using Pound successfully in production +environments. The largest volume reported to date is a site with an +average of about 30M requests per day, peaking at over 600 requests/sec. + +Pound was successfully used in production with a variety of Web servers, +including Apache, IIS, Zope, WebLogic, Jakarta/Tomcat, iPlanet, etc. In +general Pound passes requests and responses back and forth unchanged, +so we have no reason to think that any web server would be incompatible. + +Client browsers that were tested: + +- IE 5.0/5.5 (Windows) HTTP/HTTPS + +- Netscape 4.7 (Windows/Linux) HTTP/HTTPS + +- Mozilla (Windows/Linux) HTTP/HTTPS + +- Konqueror (Linux) HTTP/HTTPS + +- Galleon (Linux) HTTP/HTTPS + +- Opera (Linux/Windows) HTTP/HTTPS + +- Lynx (Linux) HTTP + +Given that Pound is in production and no problems were reported, we have +no reason to believe that other browsers would present a problem. A few +issues were observed with problematic SSL implementations, most notably +with Opera 6, but these should be OK in the present version. + +### BOOTSTRAPPING + +If you obtained the sources from the repository, you will need the +following tools in order to build from them: + + - Autoconf v.2.63 or later () + - Automake v.1.11 or later () + +Change to the project directory and run + + ./bootstrap + +This will create the configure script and populate the directory with +auxiliary files needed for configuration. Once done, proceed to + + ./configure + +and make as discussed in the following section. + +### INSTALLATION + +Probably the easiest way to install Pound is to use a pre-compiled package +if you can find one. While Apsis offers no such packages, they are available +for quite a few systems (Suse, Debian and derivatives such as Ubuntu), as +well as some private packages: + +- RPMs for RedHat are available at + +- A nice FreeBSD live-CD distribution is available at as +, including a Pound binary. + +Failing that you should install from sources: + +1. Pound was tested on Linux, Solaris and OpenBSD, but + it should work unchanged on just about any modern + Unix-like system. You will require at least OpenSSL and + libpthread. The PCRE package is strongly recommended. + + Warning: as Pound is a multi-threaded program it requires + a version of OpenSSL with thread support. This is normally + the case on Linux and Solaris (for example) but not on *BSD. + If your system has the wrong library please download, compile + and install OpenSSL (from ). + + If the PCRE package is available Pound will link against it. + This will provide a significant performance boost. + +2. Download the current version of Pound-current file and unpack + it. The archive is signed. + My signature is available at . + Alternately see below for stable versions. + + Unpack. Do the usual thing: + + ./configure + +3. The following options are available for the configure script: + + `--with-ssl=ssl_dir` -- OpenSSL home directory (default: system defined). + + `--disable-super` -- disable supervisor process (default: enabled) + + `--with-t_rsa=nnn` -- timeout of the RSA ephemeral keys regeneration + (default: 1800 seconds). + + `--with-owner=owner` -- name of installed binaries owner (default is + system-dependent). + + `--with-group=group` -- name of installed binaries group (default is + system-dependent). + +4. Check that the resulting Makefile is correct and possibly + adjust flags as needed on your system. Compile: + + make + +5. If it works, you may want to do some testing before installing. + +6. Install the executable somewhere (it's likely that + `/usr/local/sbin` would make a good choice), as well + as the manual page (`pound.8` -> `/usr/local/man/man8`). + The supplied Makefile will do it for you. + +7. Make sure Pound gets started on boot. Read the man + page for available options and examples. + + +### COPYRIGHT + +Pound is copyrighted by Apsis GmbH and is distributed under +the terms of the GNU Public License with the additional +exemption that compiling, linking, and/or using OpenSSL is +allowed. Basically, this means that you can use it free of +charge, copy it, distribute it (provided the copyright is +maintained and the full package is distributed), modify it, +or line a bird-cage with it. + +We would be happy to hear from you if you use it and +suggestions and improvements are gladly accepted. + + +### CONTACT + + Robert Segall, roseg@apsis.ch + + Apsis GmbH, http://www.apsis.ch + + P O Box + + CH-8707 Uetikon am See + + Switzerland + + +41-44-920 4904 + + +### MAILING LIST + +Pound has its own mailing list now: please send a message with +the subject "subscribe" to pound@apsis.ch in order to +subscribe. You will receive confirmation and instructions in +the reply. + +All messages are available and indexed (searcheable) in the +archive +and at . + +The mailing list is the primary support forum for Pound - please +post there any questions you may have. The developpers' address is +given here for information purposes only. + + + +### ZOPE + +A special note for Zope users: the original intent on +developing Pound was to allow distributing the load +among several Zope servers running on top of ZEO. This +it does. + +A special problem arises when you try using Pound as an +SSL wrapper: Zope assumes that the requests are made via +HTTP and insists on prepending `http://` to the (correct) +address in the replies, including in the `` tag and +the absolute URLs it generates (for images for example). +This is clearly an undesirable behavior. + +For older Zope versions (prior to 2.7): a modified z2.py (as +well as a patch) is included in the distribution. The main +difference is that this z2.py allows starting an additional +HTTP server via the -y flag that sets the environment +HTTPS variable - thus correcting the problem. That means +that in order to use Pound as an SSL wrapper you need to: + +- start Zope (modify the 'start' file) as: + + python -X -w 8080 -y 8443 ... + +For Zope 2.7 or later the same effect can be achieved via suitable +modifications to zope.conf. + + + +### VIRTUAL HOSTS (IN GENERAL) + +Some people asked about the possibility of redirecting requests to back-ends +as per some virtual hosts definition. While I believe this is not Pound's +job, it can be done. As of version 0.10, Pound supports filtering requests +based not only on the request URL, but also on the presence or absence of +certain headers. + +Let's assume that you have internal server `192.168.0.10` that is supposed to +serve the needs of virtual host `www.server0.com` and `192.168.0.11` that serves +`www.server1.com`. You want Pound to listen on address `1.2.3.4` and separate +the requests to each host. The config file would look something like this: + + ListenHTTP + Address 1.2.3.4 + Port 80 + + Service + HeadRequire "Host: .*www.server0.com.*" + + BackEnd + Address 192.168.0.10 + Port 80 + End + End + + Service + HeadRequire "Host: .*www.server1.com.*" + + BackEnd + Address 192.168.0.11 + Port 80 + End + End + End + +(add whatever else is necessary) or, if you want even safer filtering: + + ListenHTTP + Address 1.2.3.4 + Port 80 + + Service + HeadRequire "Host: .*www.server0.com.*" + HeadDeny "Host: .*www.server1.com.*" + + BackEnd + Address 192.168.0.10 + Port 80 + End + End + + Service + HeadRequire "Host: .*www.server1.com.*" + HeadDeny "Host: .*www.server0.com.*" + + BackEnd + Address 192.168.0.11 + Port 80 + End + End + End + +This is NOT recommended (I personally believe that virtual hosts should be +implemented in the back-end servers - putting this in a proxy +is a major security kludge) but it works. + + + +### VIRTUAL HOSTS AND HTTPS + +Quite often we get inquiries about Pound's ability to do virtual hosting +with HTTPS. In order to lay this matter to rest, let me say: + + HTTPS does not allow virtual hosting! + +This is not a limitation of Pound, but of HTTPS - no Web server or proxy +are able to do it due to the nature of the beast. + +In order to see why this is the case we need to look at the way HTTPS works. +Basically there are three stages in any HTTPS connection: + +1. **Connection negotiation:** - the client (your browser) and the server (Web + server or proxy) negotiate the basic parameters: ciphers to use, session + key, etc. + +2. **Connection authentication:** at the very least the server presents the + client with a certificate that says "I am server `www.encrypted.com` - and + `certificate.authority.org` will verify that". The client may also present + a certificate of its own at this stage. + +3. **Request/response cycle:** normal HTTP is sent (through the encrypted + channel) back and forth. + +The vital point to notice here is that connection authentication takes place +BEFORE any request was issued. + +On the other hand, the way virtual hosting works is for the client to +specify in the request to which server it would like to talk. This is +accomplished via a Host header: + + GET /index.html HTTP/1.1 + Host: http://www.virthost.com + +Combining the two we get to an impasse: on connection setup the server will +reply with the certificate for `www.realhost.com`, but the request is really +for `www.virthost.com` - and most browsers will scream blue murder (as well +they should) if the two do not match. + +There is a new twist on this however: some of the newer browsers will accept +so-called "wild-card certificates". This is a specially crafted certificate +that is not issued to a host, but rather to a domain. The result is that +on setting-up a new SSL connection, the server replies not with "I am +`www.encrypted.com`", but with "I am `*.encrypted.com`". If the browser is +capable of processing this type of certificate then the connection is +set up and normal HTTPS (with `www.encrypted.com` or `special.encrypted.com` or +even `some.other.server.encrypted.com` or whatever other name matches) proceeds +as usual. Pound supports these certificates and you can use virtual hosts in +the normal way. + +Update June 2010: starting with the 2.6 series, Pound has SNI support, if your +OpenSSL version supports it. Basically you supply Pound with several certificates, +one for each virtual host (wild card certificates - as described above - are +allowed). On connecting the client signals to which server it wants to talk, +and Pound searches among its certificates which would fit. Not all versions +of OpenSSL and not all clients support this mode, but if available it allows +for virtual hosts over HTTPS. + +An additional option is to use a semi-official TLS extension, the so called +alternate subject name. If your version of OpenSSL supports it you may specify +in one certificate several alternate server names. This requires support for a +special TLS feature, and nor all clients accept it. + + + +### VIRTUAL HOSTS IN ZOPE + +For reasons I can't quite grasp, it seems that a lot of Zope +users are convinced that virtual hosts are only possible through +the Apache/VHM combination and that it requires some kind of +magic incantation at midnight in order to work (I won't even +start on the virgin sacrifices). + +The simple fact is that VHM and the Apache VirtualHost directives +(as well as various tricks through mod_rewrite and mod_proxy) are +(almost) mutually exclusive: they perform exactly the same +functions and, leaving aside the logging issues, are used +independently of each other. Let me repeat that: you may use the +VHM without Apache - just click on the VHM mappings tab and add +whatever virtual host you wish. From this moment on any request +to that host will be mapped back and forth by Zope to the required +URL. This works weather you access Zope directly or via any number +of proxies on the way, Pound included. + +To test: add a new host name to your `/etc/hosts` file, making it an +alias for localhost - something like:: + + 127.0.0.1 localhost www.testhost.mine + +Add a mapping in VHM from www.testhost.mine to some Zope folder +(Examples is already there). Point your browser to +and you get the normal Zope start page; point it to +`http://www.testhost.mine` and you'll see the Examples starting page. +All requests are mapped correctly, and the URLs in the pages (such +as base or absoluteURL) are translated correctly in the response. + + +### SESSIONS + +Pound has the ability to keep track of sessions between a client +browser and a back-end server. Unfortunately, HTTP is defined as +a stateless protocol, which complicates matters: many schemes have +been invented to allow keeping track of sessions, none of which works +perfectly. Even worse, sessions are critical in order to allow +web-based applications to function correctly - it is vital that once +a session is established all subsequent requests from the same browser +be directed to the same back-end server. + +Six possible ways of detecting a session have been implemented in +Pound (hopefully the most useful ones): by client address, by Basic +authentication (user id/password), by URL parameter, by cookie, by +HTTP parameter and by header value. + +- **by client address:** in this scheme Pound directs all requests from + the same client IP address to the same back-end server. Put the + lines + + Session + Type IP + TTL 300 + End + + in the configuration file to achieve this effect. The value indicates + what period of inactivity is allowed before the session is discarded. + +- **by Basic Authentication:** in this scheme Pound directs all requests from + the same user (as identified in the Basic Authentication header) to the + same back-end server. Put the lines + + Session + Type Basic + TTL 300 + End + + in configuration file to achieve this effect. The value indicates what + period of inactivity is allowed before the session is discarded. + + WARNING: given the constraints of the HTTP protocol it may very well be + that the authenticated request will go to a different back-end server than + the one originally requesting it. Make sure all your servers support + the same authentication scheme! + +- **by URL parameter:** quite often session information is passed through URL + parameters (the browser is pointed to something like `http://xxx?id=123`). + Put the lines + + Session + Type URL + ID "id" + TTL 300 + End + + to support this scheme and the sessions will be tracked based on the value + of the "id" parameter. + +- **by cookie value:** applications that use this method pass a certain cookie + back and forth. Add the lines + + Session + Type Cookie + ID "sess" + TTL 300 + End + + to your configuration file - the sessions will be tracked by the value of + the "sess" cookie. + +- **by HTTP parameter value:** applications that use this method pass an HTTP + parameter (`http://x.y/z;parameter`) back and forth. Add the lines + + Session + Type PARM + TTL 300 + End + + to your configuration file - the sessions will be tracked by the value of + the parameter. + +- **by header value:** applications that use this method pass a certain header + back and forth. Add the lines + + Session + Type Header + ID "X-sess" + TTL 300 + End + + to your configuration file - the sessions will be tracked by the value of + the "X-sess" header. + +Please note the following restrictions on session tracking: + +- session tracking is always associated with a certain Service. Thus each + group may have other methods and parameters. + +- there is no default session: if you have not defined any sessions no + session tracking will be done. + +- only one session definition is allowed per Service. If your application + has alternative methods for sessions you will have to define a separate + Service for each method. + +A note on cookie injection: some applications have no session-tracking mechanism at +all but would still like to have the client always directed to the same back-end +time after time. Some reverse proxies use a mechanism called "cookie injection" in +order to achieve this: a cookie is added to the back-end responses and tracked by the +reverse proxy. + +Pound was designed to be as transparent as possible, and this mechanism is not +supported. If you really need this sort of persistent mapping use the client address +session mechanism (Session Type IP), which achieves the same result without +changing the contents in any way. + + +### REQUEST LOGGING + +As a general rule, Pound passes all headers as they arrive from the client +browser to the back-end server(s). There are two exceptions to this rule: +Pound may add information about the SSL client certificate (as described +below), and it will add an X-Forwarded-For header. The general format is: + + X-Forwarded-For: client-IP-address + +The back-end server(s) may use this extra information in order to create +their log-files with the real client address (otherwise all requests will +appear to originate from Pound itself, which is rather useless). + +In addition, Pound logs requests and replies to the system log. This is +controlled by the LogFacility configuration variable: + +- daemon = output to the LOG_DAEMON facility. +- local0 = output to file configured by rsyslog. +- \- = direct messages to stdout or stderr (use for journalctl). +- \+ = same as '-' but prepend priority \ on log messages. +- \* = same as '+' but flush the stdout buffer after each log message. + +The log message format is controlled by the LogLevel configuration variable: + +- 0 = no logging, +- 1 = normal log, +- 2 = full log, +- 3 = Apache combined log format, +- 4 = Apache combined log format without virtual host. + +By default the messages go to the LOG_DAEMON facility, but you can change +this in the configuration file. + +In your distribution, systemd's journal may be configured to forward the +standard output and standard error of all systemd services to /var/log/syslog. +To suppress logs to syslog, set `ForwardToSyslog=no` in /etc/systemd/journald.conf +then reload: + + sudo systemd daemon-reload + +To use journalctl: + + journalctl --unit pound.service --since yesterday + +If you don't want to use journalctl only, you can just do a: + + fgrep pound /var/log/messages + +to get all the messages generated by Pound. + + +### HTTPS CLIENT CERTIFICATES + +If a client browser connects via HTTPS and if it presents a +certificate and if XSSLHeaders is set, Pound will obtain the +certificate data and add the following HTTP headers to the +request it makes to the server: + +If `XSSLHeaders >= 1` include: + +- **X-SSL-cipher:** the cipher currently in use + +If `XSSLHeaders >= 2` include: + +- **X-SSL-Subject:** information about the certificate owner + +- **X-SSL-Issuer:** information about the certificate issuer (CA) + +- **X-SSL-notBefore:** begin validity date for the certificate + +- **X-SSL-notAfter:** end validity date for the certificate + +- **X-SSL-serial:** certificate serial number (in decimal) + +If `XSSLHeaders = 3` include: + +- **X-SSL-certificate:** the full client certificate (single-line) + +It is the application's responsibility to actually use these +headers - Pound just passes this information without checking +it in any way (except for signature and encryption correctness). + +Please note that this mechanism allows forgeries: a client may +(maliciously) send these headers to Pound in order to masquerade +as an SSL client with a specific certificate. If this is a problem +for your application make sure to deny these requests. Add: + + HeadDeny "X-SSL-Subject:.*" + HeadDeny "X-SSL-Issuer:.*" + HeadDeny "X-SSL-notBefore:.*" + HeadDeny "X-SSL-notAfter:.*" + HeadDeny "X-SSL-serial:.*" + HeadDeny "X-SSL-cipher:.*" + +within the Service(s). + + +### THREADS AND LIMITS + +A few people ran into problems when installing Pound because of the +various threading models and how they interact with system-imposed +limits. Please keep in mind the following requirements: + +- on most System V derived Unices (of which Linux up to 2.4 is one), + a thread is a process. This means that when doing a `ps` you will see + as many processes with the name `pound` as there are active threads. + Each such process uses only two file descriptors, but the system needs + to support the required number of processes, both in total and per + user (possibly also per process group). In bash, this is `ulimit -u`, + in csh this is `limit maxproc`. + +- on BSD style systems all threads run in the same process space. Do + a `ps` and you see a single `pound` process. The process needs two + file descriptors per active request (bash: `ulimit -n`, csh + `limit maxfiles`/`limit openfiles`). + +- on most systems the thread library comes with a built-in limit on the + maximal number of concurrent threads allowed - on older systems it usually + is 1024, on newer systems quite a bit higher. In very + rare cases (very high load and long response times) you may run into + this limitation - the symptom is log messages saying "can't create + thread". Your only solution is to recompile the system threads library + (and possibly the kernel itself) with a higher limit. + +Please note that your kernel needs to be configured to support the +required resources - the above are just the shell commands. + +### SIMILAR SYSTEMS + +Quite a few people asked "What is wrong with Apache/Squid/ +stunnel/your_favorite? Do we really need another proxy +system?". The simple answer is that there is nothing wrong - +they are all excellent systems that do their jobs very well. +The reasoning behind Pound is however slightly different: + +- In my experience, a load-balancer may easily become a + bottle-neck in itself. If you have a heavily loaded site, + there are few things more depressing than seeing your + "load-balancer" slow down the entire network. This means that + the load-balancer should be kept as light-weight as possible. + +- Security: auditing a large system for security issues is a + major undertaking for anybody (ask Bill Gates about it). This + implies that in order to avoid introducing new vulnerabilities + into a system (after all, your installation is only as secure + as its weakest component) the proxy/load-balancer should be + kept as small as possible. + +- Protection: I assume Pound will be the only component exposed + to the Internet - your back-end servers will run in a protected + network behind it. This means that Pound should filter requests + and make sure only valid, correctly formed ones are passed to the + back-end servers, thus protecting them from malicious clients. + +Taking these criteria into consideration, it is easy to see why +the other systems mentioned above do not fit: + +- Apache (with mod_proxy and mod_backhand): great system, but very + large. Imposes a significant load on the system, complex set-up + procedure (and it is so easy to get it wrong: check how many Apache + servers allow proxying from and to external hosts). While Apache + has proven remarkably exploit free, I wouldn't wish to go into a + security audit for the tens of thousands of lines of code involved, + not to mention all the additional modules. + +- Squid: great caching proxy, but even should load-balancing + features become available in the future, do you really need + caching on the load-balancer? After all, Pound can easily run on a + disk-less system, whereas with Squid you'd better prepare a high + throughput RAID. Squid is still perfectly usable as a caching + proxy between Pound and the actual Web server, should it lack + its own cache (which Zope happily has). + +- stunnel: probably comes closest to my understanding of software + design (does one job only and does it very well). However, it + lacks the load balancing and HTTP filtering features that I + considered necessary. Using stunnel in front of Pound (for HTTPS) + would have made sense, except that integrating HTTPS into Pound + proved to be so simple that it was not worth the trouble. + +- your favourite system: let me know how it looks in light of the + above criteria - I am always interested in new ideas. + + +### DEDICATED SERVERS + +Some people asked about the possibility of dedicating specific +back-end servers to some clients - in other words, if a request +originates from a certain IP address or group of addresses then +it should be sent to a specific group of back-end servers. + +Given the ease with which IP addresses can be forged I am personally +doubtful of the utility of such a feature. Even should you think it +desirable, it is probably best implemented via the packet filter, +rather than a proxy server. Assuming that requests from `x.com` are +to go to `s1.local`, requests from `y.com` to `s2.local` and everything +else to `s3.local` and `s4.local`, here is how to do it: + +- make sure your firewall blocks requests to port 8080, 8081 and 8082 + +- configure Pound as follows: + + ListenHTTP + Address 127.0.0.1 + Port 8080 + + Service + BackEnd + Address s1.local + Port 80 + End + End + End + + ListenHTTP + Address 127.0.0.1 + Port 8081 + + Service + BackEnd + Address s2.local + Port 80 + End + End + End + + ListenHTTP + Address 127.0.0.1 + Port 8082 + + Service + BackEnd + Address s3.local + Port 80 + End + BackEnd + Address s4.local + Port 80 + End + End + End + +- have your packet filter redirect requests to the right local ports + based on the origin address. In OpenBSD pf syntax this would be + something like: + + rdr on rl0 from x.com to myhost.com port 80 -> localhost port 8080 + rdr on rl0 from y.com to myhost.com port 80 -> localhost port 8081 + rdr on rl0 from any to myhost.com port 80 -> localhost port 8082 + + or in Linux iptables:: + + iptables -t nat -A PREROUTING -p tcp -s x.com --dport 80 -i eth0 \ + -j DNAT --to 127.0.0.1:8080 + iptables -t nat -A PREROUTING -p tcp -s y.com --dport 80 -i eth0 \ + -j DNAT --to 127.0.0.1:8081 + iptables -t nat -A PREROUTING -p tcp --dport 80 -i eth0 -j DNAT \ + --to 127.0.0.1:8082 + +This would give you the desired effect and probably better +performance than a purely proxy-based solution (though the +performance improvement is debatable, at least on Linux). + + +### WebDAV + +As of version 1.0 Pound supports the full WebDAV command-set. In +fact, it has been tested and is known to (almost) work with the +Microsoft Outlook Web Gateway, which is quite remarkable given that +Microsoft's own proxy does not. + +Regrettably, Microsoft adherence to standards leaves something to be +desired: they decided to add some characters to their URLs - thus +breaking a whole set of RFC's. + +Rather then change Pound to accept these characters (which could create +some serious issues with security on other systems) we have made this +behaviour dependent on a configuration switch: xHTTP (see the man page +for details). + +If you also use the SSL wrapper feature in front of a Microsoft server +you should probably also add `AddHeader "Front-End-Https: on"`. + +These changes are also required to access a Subversion server via +Pound. + + +### OTHER ISSUES + +The following problems were reported by various people who use pound: + +- delays in loading pages when the client browser is IE 5.5 (possibly + limited to W2K/XP). It seems that IE opens exactly 4 connections (sockets) + to the server and keeps them open until some time-out or until the server + closes the connection. This works fine, unless you redirect IE to another + server - given that all 4 sockets are used IE waits for a while before + the redirect is actually performed. + + Solution: use the directive "Client 1" to ensure that Pound closes + sockets very early, thus freeing the necessary resources. Experiment with + the time-out - as it may cause problems with slow connections. + +- Pound fails to start; HTTPS is enabled and the message "can't read + private key from file xxx" appears in the log. + + Solution: make sure that the certificate file includes: + + - (optional) a chain of certificates from a known certificate authority to + your server certificate + + - the server certificate + + - the private key; the key may NOT be password-protected + + The file should be in PEM format. The OpenSSL command to generate a + self-signed certificate in the correct format would be something like:: + + openssl req -x509 -newkey rsa:1024 -keyout test.pem -out test.pem \ + -days 365 -nodes + + Note the '-nodes' flag - it's important! + +- Pound fails to operate correctly with SSL when RootJail is specified. + Solution: OpenSSL requires access to `/dev/urandom`, so make sure such a + device is accessible from the root jail directory. Thus if your root + jail is something like `/var/pound`: + + mkdir /var/pound/dev + mknod /var/pound/dev/urandom c 1 9 + + or whatever major/minor number are appropriate for your system. + +- In chroot mode logging may stop functioning. + Solution: make sure `/dev` and the root jail are on the same filesystem + and create a hard link in the root jail to `/dev/log`: + + mkdir /chroot/jail/dev + ln /dev/log /chroot/jail/dev/log + + Alternately you can have syslog (or syslog-ng) listen on another + socket - see the man page for details. + +- In chroot mode name resolution (and especially redirects) may stop + functioning. Solution: make sure your resolver works correctly in the + jail. You probably need copies of `/etc/resolv.conf` and (at least part) + of `/etc/hosts`. Depending on your system additional files may be required + check your resolver man page for details. Should name resolution fail the + translation of host names to IP addresses would fail, thereby defeating + the mechanism Pound uses to identify when should a Redirect be rewritten. + +- IE 5.x fails to work (correctly or at all) with Pound in HTTPS mode. + Solution: define the supported OpenSSL ciphers for IE compatibility (this + is really a work-around for a known IE bug): + + Ciphers "ALL:!ADH:!EXPORT56:RC4+RSA:+HIGH:+MEDIUM:+LOW:+SSLv2:+EXP:+eNULL" + + (Thanks to Andi Roedl for the tip). + +- Linux-specific: some people use various redundant Pound solutions for + Linux which require Pound instances on separate machines to bind to the + same address. The default configuration of Linux does not allow a + program to bind() to non-local addresses, which may cause a problem. + Solution: add + + echo 1 > /proc/sys/net/ipv4/ip_nonlocal_bind + + in your start-up script, or just set + + net.ipv4.ip_nonlocal_bind = 1 + + in `/etc/sysctl.conf` (if you have one). + + (Thanks to RUne Saetre for the suggestion). + + +### ACKNOWLEDGMENTS + +**Albert (of Alacra)** for investigating and writing the TCP_NODELAY code. + +**Luuk de Boer** did some serious testing and debugging of the WebDAV +code for Microsoft servers. + +**Alession Cervellin** packages and makes available Solaris packages for +various Pound versions. + +**David Couture** found some nasty, lurking bugs, as well as contributing +some serious testing on big hardware. + +**Frank Denis** contributed a few excellent code patches and some good ideas. + +**Dmitriy Dvoinikov** makes available a live-CD FreeBSD distribution that +includes a Pound binary. + +**Abner G. Jacobsen** did a lot of testing in a production environment +and contributed some very nice ideas. + +**Akira Higuchi** found a significant security issue in Pound and contributed +the code to fix it. + +**Ken Lalonde** contributed very useful remarks and suggestions, as well as +correcting a few code errors. + +**Phil Lodwick** contributed essential parts of the high-availability code and +came up with some good ideas. In addition, did some serious testing under +heavy loads. + +**Simon Matter** packages and makes available RPMs for various Pound versions. + +**Jan-Piet Mens** raised some interesting security points about the HTTPS +implementation and brought the original idea for SSL header filtering. + +**Andreas Roedl** for testing and some ideas about logging in root jails. + +**Gurkan Sengun** tested Pound on Solaris, contributed the Solaris cc flags +and makes a Solaris pre-compiled version available on his Web-site +(`www.linuks.mine.nu`) + +**Shinji Tanaka** contributed a patch for controlling logging to disk files. +This is available at `http://www.hatena-inc.co.jp/~stanaka/pound/` + +**Jim Washington** contributed the code for WebDAV and tested it. + +**Maxime Yve** discovered a nasty bug in the session tracking code and +contributed the patch to fix it. + +All the others who tested Pound and told me about their results. diff --git a/config.c b/config.c index 6d50777..deda081 100644 --- a/config.c +++ b/config.c @@ -74,10 +74,10 @@ static CODE facilitynames[] = { static regex_t Empty, Comment, User, Group, RootJail, Daemon, LogFacility, LogLevel, Alive, SSLEngine, Control; static regex_t ListenHTTP, ListenHTTPS, End, Address, Port, Cert, xHTTP, Client, CheckURL; static regex_t Err414, Err500, Err501, Err503, MaxRequest, HeadRemove, RewriteLocation, RewriteDestination; -static regex_t Service, ServiceName, URL, HeadRequire, HeadDeny, BackEnd, Emergency, Priority, HAport, HAportAddr; +static regex_t Service, ServiceName, URL, HeadRequire, HeadDeny, BackEnd, Emergency, Priority, HAport, HAportAddr, StrictTransportSecurity; static regex_t Redirect, RedirectN, TimeOut, WSTimeOut, Session, Type, TTL, ID; static regex_t ClientCert, AddHeader, DisableProto, SSLAllowClientRenegotiation, SSLHonorCipherOrder, Ciphers; -static regex_t CAlist, VerifyList, CRLlist, NoHTTPS11, Grace, Include, ConnTO, IgnoreCase, HTTPS; +static regex_t CAlist, VerifyList, CRLlist, XSSLHeaders, NoHTTPS11, Grace, Include, ConnTO, IgnoreCase, HTTPS; static regex_t Disabled, Threads, CNName, Anonymise, ECDHCurve; static regmatch_t matches[5]; @@ -355,9 +355,6 @@ parse_be(const int is_emergency) SSL_CTX_set_app_data(res->ctx, res); SSL_CTX_set_verify(res->ctx, SSL_VERIFY_NONE, NULL); SSL_CTX_set_mode(res->ctx, SSL_MODE_AUTO_RETRY); -#ifdef SSL_MODE_SEND_FALLBACK_SCSV - SSL_CTX_set_mode(res->ctx, SSL_MODE_SEND_FALLBACK_SCSV); -#endif SSL_CTX_set_options(res->ctx, SSL_OP_ALL); #ifdef SSL_OP_NO_COMPRESSION SSL_CTX_set_options(res->ctx, SSL_OP_NO_COMPRESSION); @@ -573,6 +570,7 @@ parse_service(const char *svc_name) conf_err("Service config: out of memory - aborted"); memset(res, 0, sizeof(SERVICE)); res->sess_type = SESS_NONE; + res->sts = -1; pthread_mutex_init(&res->mut, NULL); if(svc_name) strncpy(res->name, svc_name, KEY_SIZE); @@ -604,6 +602,8 @@ parse_service(const char *svc_name) lin[matches[1].rm_eo] = '\0'; if(regcomp(&m->pat, lin + matches[1].rm_so, REG_NEWLINE | REG_EXTENDED | (ign_case? REG_ICASE: 0))) conf_err("URL bad pattern - aborted"); + } else if(!regexec(&StrictTransportSecurity, lin, 4, matches, 0)) { + res->sts = atoi(lin + matches[1].rm_so); } else if(!regexec(&HeadRequire, lin, 4, matches, 0)) { if(res->req_head) { for(m = res->req_head; m->next; m = m->next) @@ -860,12 +860,16 @@ parse_HTTP(void) } else if(!regexec(&LogLevel, lin, 4, matches, 0)) { res->log_level = atoi(lin + matches[1].rm_so); } else if(!regexec(&Service, lin, 4, matches, 0)) { - if(res->services == NULL) + if(res->services == NULL) { res->services = parse_service(NULL); - else { + if(res->services->sts >= 0) + conf_err("StrictTransportSecurity not allowed in HTTP listener - aborted"); + } else { for(svc = res->services; svc->next; svc = svc->next) ; svc->next = parse_service(NULL); + if(svc->next->sts >= 0) + conf_err("StrictTransportSecurity not allowed in HTTP listener - aborted"); } } else if(!regexec(&ServiceName, lin, 4, matches, 0)) { lin[matches[1].rm_eo] = '\0'; @@ -1237,6 +1241,8 @@ parse_HTTPS(void) #else conf_err("your version of OpenSSL does not support CRL checking"); #endif + } else if(!regexec(&XSSLHeaders, lin, 4, matches, 0)) { + res->xSSLHeaders = atoi(lin + matches[1].rm_so); } else if(!regexec(&NoHTTPS11, lin, 4, matches, 0)) { res->noHTTPS11 = atoi(lin + matches[1].rm_so); } else if(!regexec(&Service, lin, 4, matches, 0)) { @@ -1334,6 +1340,10 @@ parse_file(void) lin[matches[1].rm_eo] = '\0'; if(lin[matches[1].rm_so] == '-') def_facility = -1; + else if(lin[matches[1].rm_so] == '+') + def_facility = -2; + else if(lin[matches[1].rm_so] == '*') + def_facility = -3; else for(i = 0; facilitynames[i].c_name; i++) if(!strcmp(facilitynames[i].c_name, lin + matches[1].rm_so)) { @@ -1446,8 +1456,8 @@ config_parse(const int argc, char **const argv) || regcomp(&RootJail, "^[ \t]*RootJail[ \t]+\"(.+)\"[ \t]*$", REG_ICASE | REG_NEWLINE | REG_EXTENDED) || regcomp(&Daemon, "^[ \t]*Daemon[ \t]+([01])[ \t]*$", REG_ICASE | REG_NEWLINE | REG_EXTENDED) || regcomp(&Threads, "^[ \t]*Threads[ \t]+([1-9][0-9]*)[ \t]*$", REG_ICASE | REG_NEWLINE | REG_EXTENDED) - || regcomp(&LogFacility, "^[ \t]*LogFacility[ \t]+([a-z0-9-]+)[ \t]*$", REG_ICASE | REG_NEWLINE | REG_EXTENDED) - || regcomp(&LogLevel, "^[ \t]*LogLevel[ \t]+([0-5])[ \t]*$", REG_ICASE | REG_NEWLINE | REG_EXTENDED) + || regcomp(&LogFacility, "^[ \t]*LogFacility[ \t]+([a-z0-9-+*]+)[ \t]*$", REG_ICASE | REG_NEWLINE | REG_EXTENDED) + || regcomp(&LogLevel, "^[ \t]*LogLevel[ \t]+([0-6])[ \t]*$", REG_ICASE | REG_NEWLINE | REG_EXTENDED) || regcomp(&Grace, "^[ \t]*Grace[ \t]+([0-9]+)[ \t]*$", REG_ICASE | REG_NEWLINE | REG_EXTENDED) || regcomp(&Alive, "^[ \t]*Alive[ \t]+([1-9][0-9]*)[ \t]*$", REG_ICASE | REG_NEWLINE | REG_EXTENDED) || regcomp(&SSLEngine, "^[ \t]*SSLEngine[ \t]+\"(.+)\"[ \t]*$", REG_ICASE | REG_NEWLINE | REG_EXTENDED) @@ -1472,6 +1482,7 @@ config_parse(const int argc, char **const argv) || regcomp(&Service, "^[ \t]*Service[ \t]*$", REG_ICASE | REG_NEWLINE | REG_EXTENDED) || regcomp(&ServiceName, "^[ \t]*Service[ \t]+\"(.+)\"[ \t]*$", REG_ICASE | REG_NEWLINE | REG_EXTENDED) || regcomp(&URL, "^[ \t]*URL[ \t]+\"(.+)\"[ \t]*$", REG_ICASE | REG_NEWLINE | REG_EXTENDED) + || regcomp(&StrictTransportSecurity, "^[ \t]*StrictTransportSecurity[ \t]+([0-9]+)[ \t]*$", REG_ICASE | REG_NEWLINE | REG_EXTENDED) || regcomp(&HeadRequire, "^[ \t]*HeadRequire[ \t]+\"(.+)\"[ \t]*$", REG_ICASE | REG_NEWLINE | REG_EXTENDED) || regcomp(&HeadDeny, "^[ \t]*HeadDeny[ \t]+\"(.+)\"[ \t]*$", REG_ICASE | REG_NEWLINE | REG_EXTENDED) || regcomp(&BackEnd, "^[ \t]*BackEnd[ \t]*$", REG_ICASE | REG_NEWLINE | REG_EXTENDED) @@ -1496,6 +1507,7 @@ config_parse(const int argc, char **const argv) || regcomp(&CAlist, "^[ \t]*CAlist[ \t]+\"(.+)\"[ \t]*$", REG_ICASE | REG_NEWLINE | REG_EXTENDED) || regcomp(&VerifyList, "^[ \t]*VerifyList[ \t]+\"(.+)\"[ \t]*$", REG_ICASE | REG_NEWLINE | REG_EXTENDED) || regcomp(&CRLlist, "^[ \t]*CRLlist[ \t]+\"(.+)\"[ \t]*$", REG_ICASE | REG_NEWLINE | REG_EXTENDED) + || regcomp(&XSSLHeaders, "^[ \t]*XSSLHeaders[ \t]+([0-3])[ \t]*$", REG_ICASE | REG_NEWLINE | REG_EXTENDED) || regcomp(&NoHTTPS11, "^[ \t]*NoHTTPS11[ \t]+([0-2])[ \t]*$", REG_ICASE | REG_NEWLINE | REG_EXTENDED) || regcomp(&Include, "^[ \t]*Include[ \t]+\"(.+)\"[ \t]*$", REG_ICASE | REG_NEWLINE | REG_EXTENDED) || regcomp(&ConnTO, "^[ \t]*ConnTO[ \t]+([1-9][0-9]*)[ \t]*$", REG_ICASE | REG_NEWLINE | REG_EXTENDED) @@ -1630,6 +1642,7 @@ config_parse(const int argc, char **const argv) regfree(&Service); regfree(&ServiceName); regfree(&URL); + regfree(&StrictTransportSecurity); regfree(&HeadRequire); regfree(&HeadDeny); regfree(&BackEnd); @@ -1654,6 +1667,7 @@ config_parse(const int argc, char **const argv) regfree(&CAlist); regfree(&VerifyList); regfree(&CRLlist); + regfree(&XSSLHeaders); regfree(&NoHTTPS11); regfree(&Include); regfree(&ConnTO); diff --git a/configure.ac b/configure.ac index 7ad9b3f..4966118 100644 --- a/configure.ac +++ b/configure.ac @@ -1,5 +1,5 @@ AC_PREREQ(2.63) -AC_INIT([pound],[2.8-gray],[gray+pound@gnu.org.ua], +AC_INIT([pound],[2.8-patrodyne-20200113],[rick.osullivan@patrodyne.org], [pound],[http://www.apsis.ch/pound]) AC_CONFIG_SRCDIR([pound.c]) AC_CONFIG_HEADERS([config.h]) diff --git a/etc/default/pound b/etc/default/pound new file mode 100644 index 0000000..48feba7 --- /dev/null +++ b/etc/default/pound @@ -0,0 +1,2 @@ +POUND_ARGS="-f /etc/pound/pound.cfg" +startup=1 diff --git a/etc/init.d/pound b/etc/init.d/pound new file mode 100644 index 0000000..70da924 --- /dev/null +++ b/etc/init.d/pound @@ -0,0 +1,90 @@ +#! /bin/sh +### BEGIN INIT INFO +# Provides: pound +# Required-Start: $remote_fs $syslog +# Required-Stop: $remote_fs $syslog +# Should-Start: $named +# Should-Stop: $named +# Default-Start: 2 3 4 5 +# Default-Stop: 0 1 6 +# Short-Description: reverse proxy and load balancer +# Description: reverse proxy, load balancer and +# HTTPS front-end for Web servers +### END INIT INFO +# +# pound - reverse proxy, load-balancer and https front-end for web-servers + +# Hint: SysV configuration for rcN.d symbolic links +# Debian.: sudo update-rc.d pound defaults +# RHEL...: sudo chkconfig pound on + +PATH=/sbin:/bin:/usr/sbin:/usr/bin:/usr/local/sbin:/usr/local/bin +DAEMON=/usr/local/sbin/pound +DESC="reverse proxy and load balancer" +NAME=pound + +# Exit if the daemon does not exist (anymore) +test -f $DAEMON || exit 0 + +. /lib/lsb/init-functions + +# Check if pound is configured or not +if [ -f "/etc/default/pound" ] +then + . /etc/default/pound + if [ "$startup" != "1" ] + then + log_warning_msg "$NAME will not start unconfigured." + log_warning_msg "Please configure; afterwards, set startup=1 in /etc/default/pound." + exit 0 + fi +else + log_failure_msg "/etc/default/pound not found" + exit 1 +fi + +# The real work of an init script +case "$1" in + start) + log_daemon_msg "Starting $DESC" "$NAME" + if [ ! -d "/var/run/pound" ] + then + mkdir -p /var/run/pound + fi + start_daemon $DAEMON $POUND_ARGS + log_end_msg $? + ;; + stop) + log_daemon_msg "Stopping $DESC" "$NAME" + killproc $DAEMON + log_end_msg $? + ;; + restart|force-reload) + log_daemon_msg "Validating Config" + if /usr/local/sbin/pound -c ; then + log_daemon_msg "Restarting $DESC" "$NAME" + killproc $DAEMON + start_daemon $DAEMON $POUND_ARGS + echo "." + else + log_daemon_msg "Failed to validate config file, refusing to restart" + fi + ;; + status) + pidofproc $DAEMON >/dev/null + status=$? + if [ $status -eq 0 ]; then + log_success_msg "$NAME is running" + else + log_success_msg "$NAME is not running" + fi + exit $status + ;; + *) + echo "Usage: $0 {start|stop|restart|force-reload|status}" + exit 1 + ;; +esac + +# Fallthrough if work done. +exit 0 diff --git a/etc/pound/error414.html b/etc/pound/error414.html new file mode 100644 index 0000000..54ca2b3 --- /dev/null +++ b/etc/pound/error414.html @@ -0,0 +1,25 @@ + + + + + + + + + + + SOMESITE: 414 - Bad Request + + + + + +
+

Bad Request Error 414

+

Request URI/URL is too long.

+ +
+ + diff --git a/etc/pound/error500.html b/etc/pound/error500.html new file mode 100644 index 0000000..dcee754 --- /dev/null +++ b/etc/pound/error500.html @@ -0,0 +1,26 @@ + + + + + + + + + + + SOMESITE: 500 - Webservice currently unavailable + + + + + +
+

Webservice currently unavailable Error 500

+

An unexpected condition was encountered.
+Our service team has been dispatched to bring it back online.

+ +
+ + diff --git a/etc/pound/error501.html b/etc/pound/error501.html new file mode 100644 index 0000000..29c10c8 --- /dev/null +++ b/etc/pound/error501.html @@ -0,0 +1,28 @@ + + + + + + + + + + + + SOMESITE: 501 - Not Implemented + + + + + +
+

Not Implemented Error 501

+

The Webserver cannot recognize the request method.

+ +
+ + diff --git a/etc/pound/error503.html b/etc/pound/error503.html new file mode 100644 index 0000000..a8d4874 --- /dev/null +++ b/etc/pound/error503.html @@ -0,0 +1,26 @@ + + + + + + + + + + + SOMESITE: 503 - Webservice currently unavailable + + + + + +
+

Webservice currently unavailable Error 503

+

We've got some trouble with our backend upstream cluster.
+Our service team has been dispatched to bring it back online.

+ +
+ + diff --git a/etc/pound/pound.cfg b/etc/pound/pound.cfg new file mode 100644 index 0000000..8eb7894 --- /dev/null +++ b/etc/pound/pound.cfg @@ -0,0 +1,98 @@ +## pound - HTTP/HTTPS reverse-proxy and load-balancer +# +# /etc/pound/pound.cfg +# +# Pound needs three objects to function: +# 1 Listener - Receives request from the client +# 2 Service - Load balance between back ends. +# 3 BackEnd - Provides response to the client +# Pound connects to the back-ends using HTTP. +# +## Global Options +# +# Specify user/group that pound will run as: +User "someuser" +Group "someuser" +# +# Specify apparent root directory' +RootJail "/var/chroot/pound" +# +## Logging: (goes to journalctl or syslog by default) +# +# Specify the log facility to use (default: daemon). +# SystemV: See facility names defined in syslog.h. +# SystemV: See /etc/rsyslog.d/30-pound.conf +# LogFacility local0 +# +# SystemD: See https://blog.selectel.com/managing-logging-systemd/ +# Use '-' to direct log messages to stdout and stderr for journalctl. +# Use '+' same as '-' but prepend priority '' to log messages. +# Use '*' same as '+' but flush stdout after each log message. +# Note: systemd will delete older logs as they approach a certain +# percentage of disk space used. +LogFacility * +# LogLevel: +# 0 No logging. +# 1 Default for regular logging. +# 2 Extended logging (show chosen backend server as well). +# 3 Apache-like format (Combined Log Format with Virtual Host). +# 4 Same as 3 but without the virtual host information. +# 5 Same as 4 but with information about the Service and BackEnd used. +# 6 Like 5 but in delimited format with thread id. +LogLevel 6 +# +## check backend every X secs: +Alive 30 +## poundctl control socket +Control "/var/run/pound/poundctl.socket" + +# Load Balance/Reverse Proxy WAN HTTP to LAN servers +ListenHTTP + Address localhost + Port 80 + + HeadRemove "X-Forwarded-Proto" + AddHeader "X-Forwarded-Proto: http" + + Err414 "/etc/pound/error414.html" + Err500 "/etc/pound/error500.html" + Err501 "/etc/pound/error501.html" + Err503 "/etc/pound/error503.html" +End + +# Load Balance/Reverse Proxy WAN HTTPS to LAN servers +#ListenHTTPS +# Address localhost +# Port 443 +# Cert "/etc/pound/cert/my-server-certificate.pem" +# +# SSLAllowClientRenegotiation 0 +# SSLHonorCipherOrder 1 +# Ciphers "ECDHE+AESGCM:ECDH+AESGCM:DH+AESGCM:ECDH+AES128:DH+AES:RSA+AESGCM:RSA+AES:!aNULL:!MD5:!DSS:!SSLv2" +# +# HeadRemove "X-Forwarded-Proto" +# AddHeader "X-Forwarded-Proto: https" +# +# XSSLHeaders 0 +# +# Err414 "/etc/pound/error414.html" +# Err500 "/etc/pound/error500.html" +# Err501 "/etc/pound/error501.html" +# Err503 "/etc/pound/error503.html" +#End + +# Test with simple echo server. +# server: ncat -l 8080 -k -c 'xargs -n1 echo' +# client: ncat localhost 8080 +Service + URL "(^\/favicon.ico$)|(^\/echo.*)" + BackEnd + Address localhost + Port 8080 + End + Session + Type Cookie + ID "JSESSIONID" + TTL 300 + End +End diff --git a/etc/rsyslog.d/30-pound.conf b/etc/rsyslog.d/30-pound.conf new file mode 100644 index 0000000..f1de89c --- /dev/null +++ b/etc/rsyslog.d/30-pound.conf @@ -0,0 +1,9 @@ +# Pound LogFacility=local0 + +# Filter messages from the local0 facility with any security level. +# Use a dash mark (-) as a prefix of the file path you specified to turn off syncing. +# In rsyslog v3, syncing has been turned off by default. +local0.* /var/log/pound/pound.log + +# Stop processing current message. +& stop diff --git a/etc/systemd/system/pound.service b/etc/systemd/system/pound.service new file mode 100644 index 0000000..7b65e4f --- /dev/null +++ b/etc/systemd/system/pound.service @@ -0,0 +1,28 @@ +# /etc/systemd/system/pound.service: systemd unit file +# +# Usage: +# sudo systemd-analyze verify pound.service +# sudo systemctl enable|disable pound +# sudo systemctl status|start|stop pound +# sudo systemctl daemon-reload + +[Unit] +Description=Pound Reverse Proxy And Load Balancer +After=network.target + +[Service] +Type=forking +RuntimeDirectory=pound +RuntimeDirectoryMode=755 +WorkingDirectory=/var/run/pound +PermissionsStartOnly=false +ExecStartPre=/bin/mkdir -m 777 -p /var/chroot/pound +ExecStartPre=/bin/mkdir -m 777 -p /var/log/pound +ExecStart=/usr/local/sbin/pound -f /etc/pound/pound.cfg +# ExecStop=/bin/kill -TERM $MAINPID +# PIDFile=/var/run/pound.pid +Restart=on-failure +RestartSec=10 + +[Install] +WantedBy=multi-user.target diff --git a/http.c b/http.c index 1fccacd..fd292c1 100644 --- a/http.c +++ b/http.c @@ -489,6 +489,25 @@ log_time(char *res) return; } +/* + * ISO 8601 log-file-style time format + */ +static void +log_time_iso(char *res) +{ + time_t now; + struct tm *t_now, t_res; + + now = time(NULL); +#ifdef HAVE_LOCALTIME_R + t_now = localtime_r(&now, &t_res); +#else + t_now = localtime(&now); +#endif + strftime(res, LOG_TIME_SIZE - 1, "%FT%T.000%z", t_now); + return; +} + static double cur_time(void) { @@ -704,7 +723,14 @@ do_http(thr_arg *arg) } memset(req_time, 0, LOG_TIME_SIZE); start_req = cur_time(); - log_time(req_time); + + /* Use Apache Common Log format for older log levels + * or ISO 8601 time format for new log levels. + */ + if ( lstn->log_level < 6 ) + log_time(req_time); + else + log_time_iso(req_time); /* check for correct request */ strncpy(request, headers[0], MAXBUF); @@ -1091,7 +1117,7 @@ do_http(thr_arg *arg) free_headers(headers); /* if SSL put additional headers for client certificate */ - if(cur_backend->be_type == 0 && ssl != NULL) { + if(cur_backend->be_type == 0 && ssl != NULL && lstn->xSSLHeaders > 0) { const SSL_CIPHER *cipher; if((cipher = SSL_get_current_cipher(ssl)) != NULL) { @@ -1108,7 +1134,7 @@ do_http(thr_arg *arg) } } - if(lstn->clnt_check > 0 && x509 != NULL && (bb = BIO_new(BIO_s_mem())) != NULL) { + if(lstn->clnt_check > 0 && x509 != NULL && (bb = BIO_new(BIO_s_mem())) != NULL && lstn->xSSLHeaders > 1) { X509_NAME_print_ex(bb, X509_get_subject_name(x509), 8, XN_FLAG_ONELINE & ~ASN1_STRFLGS_ESC_MSB); get_line(bb, buf, MAXBUF); if(BIO_printf(be, "X-SSL-Subject: %s\r\n", buf) <= 0) { @@ -1170,20 +1196,35 @@ do_http(thr_arg *arg) clean_all(); return; } - PEM_write_bio_X509(bb, x509); - get_line(bb, buf, MAXBUF); - if(BIO_printf(be, "X-SSL-certificate: %s", buf) <= 0) { - str_be(buf, MAXBUF - 1, cur_backend); - end_req = cur_time(); - logmsg(LOG_WARNING, "(%lx) e500 error write X-SSL-certificate to %s: %s (%.3f sec)", - pthread_self(), buf, strerror(errno), (end_req - start_req) / 1000000.0); - err_reply(cl, h500, lstn->err500); - BIO_free_all(bb); - clean_all(); - return; - } - while(get_line(bb, buf, MAXBUF) == 0) { - if(BIO_printf(be, "%s", buf) <= 0) { + if (lstn->xSSLHeaders > 2) + { + PEM_write_bio_X509(bb, x509); + get_line(bb, buf, MAXBUF); + strip_eol(buf); + if(BIO_printf(be, "X-SSL-certificate: %s", buf) <= 0) { + str_be(buf, MAXBUF - 1, cur_backend); + end_req = cur_time(); + logmsg(LOG_WARNING, "(%lx) e500 error write X-SSL-certificate to %s: %s (%.3f sec)", + pthread_self(), buf, strerror(errno), (end_req - start_req) / 1000000.0); + err_reply(cl, h500, lstn->err500); + BIO_free_all(bb); + clean_all(); + return; + } + while(get_line(bb, buf, MAXBUF) == 0) { + strip_eol(buf); + if(BIO_printf(be, "%s", buf) <= 0) { + str_be(buf, MAXBUF - 1, cur_backend); + end_req = cur_time(); + logmsg(LOG_WARNING, "(%lx) e500 error write X-SSL-certificate to %s: %s (%.3f sec)", + pthread_self(), buf, strerror(errno), (end_req - start_req) / 1000000.0); + err_reply(cl, h500, lstn->err500); + BIO_free_all(bb); + clean_all(); + return; + } + } + if(BIO_printf(be, "\r\n") <= 0) { str_be(buf, MAXBUF - 1, cur_backend); end_req = cur_time(); logmsg(LOG_WARNING, "(%lx) e500 error write X-SSL-certificate to %s: %s (%.3f sec)", @@ -1193,18 +1234,8 @@ do_http(thr_arg *arg) clean_all(); return; } - } - if(BIO_printf(be, "\r\n") <= 0) { - str_be(buf, MAXBUF - 1, cur_backend); - end_req = cur_time(); - logmsg(LOG_WARNING, "(%lx) e500 error write X-SSL-certificate to %s: %s (%.3f sec)", - pthread_self(), buf, strerror(errno), (end_req - start_req) / 1000000.0); - err_reply(cl, h500, lstn->err500); BIO_free_all(bb); - clean_all(); - return; } - BIO_free_all(bb); } } /* put additional client IP header */ @@ -1365,6 +1396,22 @@ do_http(thr_arg *arg) logmsg(LOG_INFO, "%s - %s [%s] \"%s\" %d 0 \"%s\" \"%s\"", caddr, u_name[0]? u_name: "-", req_time, request, cur_backend->be_type, referer, u_agent); break; + case 6: + logmsg(LOG_INFO, "%016lx|%s|%c%c%c|%0.3f|%s|%s|%s|%s|%s|%s|%s|%s|%s", + pthread_self(), // thread id + req_time, // request time ISO 8601 + response[9], response[10], response[11], // response code + (end_req - start_req) / 1000000.0, // duration seconds + s_res_bytes[0] == '-' ? "0" : s_res_bytes, // response bytes + v_host[0] ? v_host : "", // target host:port + svc->name[0] ? svc->name : "", // service name + caddr, // source client address + buf, // backend address:port + u_name[0] ? u_name : "", // user name + u_agent, // user agent + referer, // refering URI + request); // request URL + break; } if(!cl_11 || conn_closed || force_10) break; @@ -1411,6 +1458,22 @@ do_http(thr_arg *arg) s_res_bytes, referer, u_agent, svc->name[0]? svc->name: "-", buf, (end_req - start_req) / 1000000.0); break; + case 6: + logmsg(LOG_INFO, "%016lx|%s|%c%c%c|%0.3f|%s|%s|%s|%s|%s|%s|%s|%s|%s", + pthread_self(), // thread id + req_time, // request time ISO 8601 + response[9], response[10], response[11], // response code + (end_req - start_req) / 1000000.0, // duration seconds + s_res_bytes[0] == '-' ? "0" : s_res_bytes, // response bytes + v_host[0] ? v_host : "", // target host:port + svc->name[0] ? svc->name : "", // service name + caddr, // source client address + buf, // backend address:port + u_name[0] ? u_name : "", // user name + u_agent, // user agent + referer, // refering URI + request); // request URL + break; } /* no response expected - bail out */ break; @@ -1439,6 +1502,8 @@ do_http(thr_arg *arg) if(!strncasecmp("101", response + 9, 3)) is_ws |= WSS_RESP_101; + for(n = 0; n < MAXHEADERS; n++) + headers_ok[n] = 1; for(chunked = 0, cont = -1L, n = 1; n < MAXHEADERS && headers[n]; n++) { switch(check_header(headers[n], buf)) { case HEADER_CONNECTION: @@ -1496,6 +1561,11 @@ do_http(thr_arg *arg) } } break; + case HEADER_STRICT_TRANSPORT_SECURITY: + /* enforce pound's STS header */ + if(svc->sts >= 0) + headers_ok[n] = 0; + break; } } @@ -1505,6 +1575,8 @@ do_http(thr_arg *arg) /* send the response */ if(!skip) for(n = 0; n < MAXHEADERS && headers[n]; n++) { + if(!headers_ok[n]) + continue; if(BIO_printf(cl, "%s\r\n", headers[n]) <= 0) { if(errno) { addr2str(caddr, MAXBUF - 1, &from_host, 1); @@ -1516,6 +1588,8 @@ do_http(thr_arg *arg) } } free_headers(headers); + if(!skip && ssl && svc->sts >= 0) + BIO_printf(cl, "Strict-Transport-Security: max-age=%d\r\n", svc->sts); /* final CRLF */ if(!skip) @@ -1771,6 +1845,22 @@ do_http(thr_arg *arg) response[11], s_res_bytes, referer, u_agent, svc->name[0]? svc->name: "-", buf, (end_req - start_req) / 1000000.0); break; + case 6: + logmsg(LOG_INFO, "%016lx|%s|%c%c%c|%0.3f|%s|%s|%s|%s|%s|%s|%s|%s|%s", + pthread_self(), // thread id + req_time, // request time ISO 8601 + response[9], response[10], response[11], // response code + (end_req - start_req) / 1000000.0, // duration seconds + s_res_bytes[0] == '-' ? "0" : s_res_bytes, // response bytes + v_host[0] ? v_host : "", // target host:port + svc->name[0] ? svc->name : "", // service name + caddr, // source client address + buf, // backend address:port + u_name[0] ? u_name : "", // user name + u_agent, // user agent + referer, // refering URI + request); // request URL + break; } if(!be_11) { @@ -1807,7 +1897,7 @@ thr_http(void *dummy) for(;;) { while((arg = get_thr_arg()) == NULL) - logmsg(LOG_NOTICE, "NULL get_thr_arg"); + logmsg(LOG_NOTICE, "(%lx) get_thr_arg: http arg from request queue is NULL.", pthread_self()); do_http(arg); } } diff --git a/installed-list.sh b/installed-list.sh new file mode 100755 index 0000000..985ebf9 --- /dev/null +++ b/installed-list.sh @@ -0,0 +1,32 @@ +#!/bin/sh +# List installed Pound files. + +SYSTEMD="false" + +if [ "${SYSTEMD}" = "true" ]; then + # SystemD daemon + ls -l /etc/systemd/system/pound.service +else + # SystemV daemon + ls -l /etc/default/pound + ls -l /etc/init.d/pound + ls -l /etc/rc?.d/*pound +fi + +POUND_PATH="/usr/local" + +ls -l /etc/pound/*.cfg +ls -l /etc/pound/*.html +ls -l /etc/pound/ca/ +ls -l /etc/pound/cert/ +ls -l /etc/rsyslog.d/30-pound.conf +ls -l ${POUND_PATH}/share/doc/pound/* +ls -l ${POUND_PATH}/share/man/man8/pound.8* +ls -l ${POUND_PATH}/share/man/man8/poundctl.8* +ls -l ${POUND_PATH}/*bin/poundctl +ls -l ${POUND_PATH}/sbin/pound +ls -l /var/chroot/pound/ +ls -l /var/log/pound/ +ls -l /var/run/pound/poundctl.socket + +ls -l /var/lib/dpkg/info/pound* diff --git a/installed-test.sh b/installed-test.sh new file mode 100755 index 0000000..f66be8e --- /dev/null +++ b/installed-test.sh @@ -0,0 +1,4 @@ +#!/bin/sh +sudo /usr/local/sbin/pound -f /etc/pound/pound.cfg -p pound.pid +sudo /usr/local/bin/poundctl -c '/var/run/pound/poundctl.socket' +echo "To stop pound use: sudo kill $(sudo cat pound.pid)" diff --git a/pound.8 b/pound.8 index 784c0f3..5526920 100644 --- a/pound.8 +++ b/pound.8 @@ -236,10 +236,11 @@ to find the optimal value for your installation. Specify the log facility to use. .I value (default: daemon) must be one of the symbolic facility names defined in -\fIsyslog.h\fR. This facility shall be used for logging. Using a - for -the facility name causes +\fIsyslog.h\fR. This facility shall be used for logging. Using - or + +or * for the facility name causes .B Pound -to log to stdout/stderr. +to log to stdout/stderr. Use + to prepend the priority to each log +message. Further, use * to flush the stdout buffer after each log message. .TP \fBLogLevel\fR value Specify the logging level: 0 for no logging, 1 (default) for regular @@ -548,6 +549,12 @@ returned certificate. Set the CRL (Certificate Revocation List) file. The CRL_file is a file that contains the CRLs (in PEM format). .TP +\fBXSSLHeaders\fR 0|1|2|3 +Control sending X-SSL headers to the backend server. If this value is +0 disable the headers. If the value is 1 send some X-SLL headers. If the +value is 2 then send more X-SSL headers. If the value is 3 then send all +X-SSL headers. +.TP \fBNoHTTPS11\fR 0|1|2 Behave like an HTTP/1.0 server for HTTPS clients. If this value is 0 disable the check. If the value is 1 do not allow multiple @@ -694,6 +701,11 @@ the following .I End directives define a session-tracking mechanism for the current service. See below for details. +.TP +\fBStrictTransportSecurity\fR value +Add a header, on each response, to declare the HTTP Strict Transport Security (HSTS) policy. +The value, in seconds, specifies a period of time the user agent (i.e. browser) should +remember the policy. .SH "BackEnd" A back-end is a definition of a single back-end server .B Pound diff --git a/pound.c b/pound.c index 370189d..8a05148 100644 --- a/pound.c +++ b/pound.c @@ -314,7 +314,7 @@ main(const int argc, char **argv) /* read config */ config_parse(argc, argv); - if(log_facility != -1) + if(log_facility > -1) openlog("pound", LOG_CONS | LOG_NDELAY, LOG_DAEMON); if(ctrl_name != NULL) { struct sockaddr_un ctrl; @@ -391,7 +391,7 @@ main(const int argc, char **argv) /* daemonize - make ourselves a subprocess. */ switch (fork()) { case 0: - if(log_facility != -1) { + if(log_facility > -1) { close(0); close(1); close(2); diff --git a/pound.h b/pound.h index 1d01a17..77c012d 100644 --- a/pound.h +++ b/pound.h @@ -377,6 +377,7 @@ typedef struct _service { LHASH *sessions; /* currently active sessions */ #endif int disabled; /* true if the service is disabled */ + int sts; /* strict transport security */ struct _service *next; } SERVICE; @@ -398,6 +399,7 @@ typedef struct _listener { int sock; /* listening socket */ POUND_CTX *ctx; /* CTX for SSL connections */ int clnt_check; /* client verification mode */ + int xSSLHeaders; /* X-SSL headers mode */ int noHTTPS11; /* HTTP 1.1 mode for SSL */ char *add_head; /* extra SSL header */ regex_t verb; /* pattern to match the request verb against */ @@ -448,6 +450,7 @@ typedef enum { RENEG_INIT=0, RENEG_REJECT, RENEG_ALLOW, RENEG_ABORT } RENEG_STAT #define HEADER_URI 9 #define HEADER_DESTINATION 10 #define HEADER_EXPECT 11 +#define HEADER_STRICT_TRANSPORT_SECURITY 12 #define HEADER_UPGRADE 13 /* control request stuff */ @@ -633,3 +636,16 @@ extern void *thr_timer(void *); * listens to client requests and calls the appropriate functions */ extern void *thr_control(void *); + +/* + * systemd/sd-daemon.h + */ +#define SD_EMERG "<0>" /* system is unusable */ +#define SD_ALERT "<1>" /* action must be taken immediately */ +#define SD_CRIT "<2>" /* critical conditions */ +#define SD_ERR "<3>" /* error conditions */ +#define SD_WARNING "<4>" /* warning conditions */ +#define SD_NOTICE "<5>" /* normal but significant condition */ +#define SD_INFO "<6>" /* informational */ +#define SD_DEBUG "<7>" /* debug-level messages */ + diff --git a/svc.c b/svc.c index 5939ce8..1f30923 100644 --- a/svc.c +++ b/svc.c @@ -254,6 +254,15 @@ logmsg(const int priority, const char *fmt, ...) va_end(ap); if(log_facility == -1) { fprintf((priority == LOG_INFO || priority == LOG_DEBUG)? stdout: stderr, "%s\n", buf); + } else if (log_facility < -1) { + /* systemd: Prepend '

' to pass priority into units using SyslogLevelPrefix=true. */ + if ( priority == LOG_INFO || priority == LOG_DEBUG ) + fprintf(stdout, "%s%s\n", SD_INFO, buf); + else + fprintf(stderr, "%s%s\n", SD_ERR, buf); + /* Conditionally, flush stdout buffer. */ + if (log_facility < -2) + fflush(stdout); } else { if(print_log) printf("%s\n", buf); @@ -277,6 +286,15 @@ va_dcl va_end(ap); if(log_facility == -1) { fprintf((priority == LOG_INFO || priority == LOG_DEBUG)? stdout: stderr, "%s\n", buf); + } else if (log_facility < -1) { + /* systemd: Prepend '

' to pass priority into units using SyslogLevelPrefix=true. */ + if ( priority == LOG_INFO || priority == LOG_DEBUG ) + fprintf(stdout, "%s%s\n", SD_INFO, buf); + else + fprintf(stderr, "%s%s\n", SD_ERR, buf); + /* Conditionally, flush stdout buffer. */ + if (log_facility < -2) + fflush(stdout); } else { if(print_log) printf("%s\n", buf); @@ -418,6 +436,7 @@ check_header(const char *header, char *const content) { "User-agent", 10, HEADER_USER_AGENT }, { "Destination", 11, HEADER_DESTINATION }, { "Expect", 6, HEADER_EXPECT }, + { "Strict-Transport-Security", 25, HEADER_STRICT_TRANSPORT_SECURITY }, { "Upgrade", 7, HEADER_UPGRADE }, { "", 0, HEADER_OTHER }, };