GithubHelp home page GithubHelp logo

graygnuorg / pound Goto Github PK

View Code? Open in Web Editor NEW
39.0 6.0 12.0 1.76 MB

Light-weight reverse proxy, load balancer and HTTPS front-end for Web servers.

License: GNU General Public License v3.0

Makefile 1.03% C 85.54% Shell 0.07% M4 5.19% Perl 8.03% BitBake 0.14%

pound's Introduction

Pound

Pound is a reverse proxy, load balancer and HTTPS front-end for Web servers. It 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 GNU General Public License, Version 3, or (at your option) any later version.

The original version of pound was written by Robert Segall at Apsis GmbH. In 2018, Sergey Poznyakoff added support for OpenSSL 1.x to the then current version of the program (2.8). This version of pound, hosted on github was further modified by Rick O'Sullivan and Frank Schmirler, who added WebSocket support.

On April 2020, Apsis started development of pound 3.0 - essentially an attempt to rewrite pound from scratch, introducing dependencies on some third-party software.

On 2022-09-19, Robert announced that he stops further development and maintenance of pound. Following that, Sergey decided to continue development of the program starting from his fork.

What Pound Is

  1. a reverse-proxy: it passes requests from client browsers to one or more backend servers.
  2. a load balancer: it distributes requests from client browsers among several backend servers, while keeping session information.
  3. an SSL wrapper: it decrypts HTTPS requests from client browsers and passes them as plain HTTP to the backend servers.
  4. an HTTP/HTTPS sanitizer: it verifies requests for correctness and accepts only well-formed ones.
  5. a fail-over server: should a backend 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 files 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: it serves no content itself, it only passes requests and responses back and forth between clients and actual web servers (backends).
  2. Pound is not a Web accelerator: no caching is done -- every request is passed to a backend server "as is".

Notice On Project Versioning

I took over pound development at its 2.x branch. The branch 3.x, which emerged for a short time before the original project was abandoned, I consider to be a failed experiment. To ensure consistent versioning and avoid confusion, my versioning of pound starts with 4.0.

Documentation

Documentation in texinfo and manpage formats is available in the distribution. A copy of the documentation is available online.

Build requirements

To build, pound needs OpenSSL version 1.1.x or 3.0.x.

As of current release, pound still supports OpenSSL 1.0, but this support will soon be discontinued.

If you compile it on a Debian-based system, you need to install the libssl-dev package prior to building pound.

Compilation

If you cloned pound from the repository, you will need the following tools in order to build it:

First, run

 ./bootstrap

This will prepare the necessary infrastructure files (Makefile.in's etc.)

If you are building pound from a tarball, the above step is not needed, since all the necessary files are already included in it.

To prepare pound for compilation, run ./configure. Its command line options will decide where on the filesystem the binary will be installed, where it will look for its configuration file, etc. When run without options, the binary will be installed at /usr/local/sbin and it will look for its configuration in file /usr/local/etc/pound.cfg.

If you run it as:

 ./configure --prefix=/usr --sysconfdir=/etc

then the binary will be installed at /usr/sbin/pound and it will read its configuration from /etc/pound.cfg.

For a detailed discussion of --prefix, --sysconfdir, and other generic configure options, refer to Autoconf documentation.

Apart from the generic ones, there are also several pound-specific configuration options:

  • --enable-pcreposix or --disable-pcreposix

    Enable or disable the use of the libpcreposix2 or libpcreposix library. This is a library that makes it possible to use both POSIX extended and Perl-compatible regular expressions in pound configuration file.

    By default, its presence is determined automatically; libpcreposix2 is preferred over libpcreposix. To force compiling with the older libpcreposix, use --enable-pcreposix=pcre1.

  • --enable-pthread-cancel-probe or --disable-pthread-cancel-probe

    Pound calls the pthread_cancel function as part of its shutdown sequence. In GNU libc, this function tries to load shared library libgcc_s.so.1. It will fail to do so, if the program is running in chroot (the RootJail statement is given), unless the library has previously been copied to the chroot directory. To avoid this, pound will do a temptative call to pthread_cancel early, before chrooting, so that the necessary library will be loaded and remain available after chroot. To determine whether to do this pthread_cancel probe hack, configure checks if the program is going to be linked with GNU libc.

    These two options allow you to forcefully enable or disable this probe. For instance, you may wish to enable it, if another libc implementation exhibits a similar behavior.

  • --with-maxbuf=n

    Sets the value of MAXBUF parameter - the size of a generic buffer used internally by pound for various needs. The default is 4096. You will probably not want to change it.

  • --with-owner=user

    Name of the system user who will own the pound executable file. When not supplied, the first name from the following list that exists in the /etc/passwd file will be used: proxy, www, daemon, bin, sys, root.

  • --with-group=group

    Name of the system group who will own the pound executable. When not supplied, the first name from the following list that exists in the /etc/passwd file will be used: proxy, www, daemon, bin, sys, root.

  • --with-dh=n

    Default DH parameter length. Allowed values for n are 2048 (the default) and 1024.

    This option has no effect when compiling with OpenSSL 1.1 or later.

  • --with-ssl=directory

    Directory under which OpenSSL is installed. You will seldom need this option. Most of the time configure is able to detect that location automatically.

  • --with-t_rsa=n

    Sets default time interval for regeneration of RSA ephemeral keys.

    This option has no effect when compiling with OpenSSL 1.1 or later.

When configuration is finished, run

 make

When building from a git clone, the first run of this command can take considerable time, if you are compiling with OpenSSL 1.0. That's because it involves generating DH parameters.

Testing

Testing a reverse proxy in general, and pound in particular, is not a trivial task. Testsuite in pound was implemented quite recently and is still somewhat experimental. Notwithstanding that, it has already helped to discover several important bugs that lurked in the code.

To test pound you will need Perl version 5.26.3 or later, and the IO::FDPass module. To install the latter on a reasonably recent debian-based system, run

 apt-get install libio-fdpass-perl

On other systems you may need to install it directly from cpan by running

 cpan -i IO::FDPass

Testing HTTPS requires additionally Perl modules IO::Socket::SSL and Net::SSLeay. If these are not installed, HTTPS tests will be skipped. To install these on a debian-based system, run:

 apt-get install libio-socket-ssl-perl libnet-ssleay-perl

To run tests, type

 make check

from the top-level source directory. On success, you will see something like that (ellipsis indicating output omitted for brevity):

## -------------------------- ##
## pound 4.8 test suite.      ##
## -------------------------- ##
  1: Configuration file syntax                       ok
  2: Basic request processing                        ok
  3: xHTTP                                           ok
  4: CheckURL                                        ok
  5: Custom Error Response                           ok
  6: MaxRequest                                      ok
  7: RewriteLocation                                 ok

Listener request modification

  8: Basic set directives                            ok

  ...

## ------------- ##
## Test results. ##
## ------------- ##

All 46 tests were successful.

If a test results in something other than ok, it leaves detailed diagnostics in directory tests/testsuite.dir/NN, where NN is the ordinal number of the test. If you encounter such failed tests, please tar the contents of tests/testsuite.dir and send the resulting tarball over to [email protected] for investigation. See also section Bug Reporting below.

Installation

If both building and testing succeeded, it's time to install pound. To do so, run the following command as root:

 make install

Configuration

Pound looks for its configuration file in a location defined at compile time, normally /etc/pound.cfg, or /usr/local/etc/pound.cfg. The configuration file syntax is discussed in detail in the manual. Here we will describe some example configurations.

Any pound configuration must contain at least two parts: a ListenHTTP (or ListenHTTPS) section, that declares a frontend, i.e. the end of the proxy that is responsible for connection with the outside world, and Service section with one or more Backend sections within, which declares where the incoming requests should go. The Service section can be global or it can be located within the ListenHTTP block. Global Service sections can be shared between two or more ListenHTTP sections. Multiple Service sections can be supplied, in which case the Service to use when handling a particular HTTP request will be selected using the supplied criteria, such as source IP address, URL, request header or the like.

Simplest configuration

The following configuration instructs pound to listen for incoming HTTP requests on 192.0.2.1:80 and pass them to single backend on 10.10.0.1:8080.

ListenHTTP
	Address 192.0.2.1
	Port 80
	Service
		Backend
			Address 10.10.0.1
			Port 8080
		End
	End
End

Notice, that the two statements Address, and Port are in general mandatory both in ListenHTTP and in Backend. There are two exceptions, however: if Address is a file name of a UNIX socket file, or if an already opened socket is passed to pound via the SocketFrom statement. These two cases are discussed below.

Argument to the Address statement can be an IPv4 or IPv6 address, a hostname, that will be resolved at program startup, or a full pathname of a UNIX socket file.

HTTPS frontend

This example shows how to configure HTTPS frontend and redirect all plain HTTP requests to it. It assumes the domain name of the site is www.example.org and its IP address is 192.0.2.1.

# Declare HTTP frontend
ListenHTTP
	Address 192.0.2.1
	Port 80
	Service
		# Redirect all requests to HTTPS.  The redirection
		# target has no path component, which means that the
		# path (and query parameters, if any) from the request
		# will be preserved.
		Redirect 301 https://www.example.org
	End
End

# Declare HTTPS frontend.
ListenHTTPS
	Address 192.0.2.1
	Port 443
	# Certificate file must contain the certificate, optional
	# certificate chain and the signature, in that order.
	Cert "/etc/ssl/priv/example.pem"
	# List of certificate authority certificates.
	CAlist /etc/ssl/acme/lets-encrypt-root.pem"
	# Disable obsolete protocols (SSLv2, SSLv3 and TLSv1).
	Disable TLSv1
	Service
		Backend
			Address 10.10.0.1
			Port 8080
		End
	End
End

Virtual Hosts

To implement virtual hosts, one needs to instruct pound to route requests to different services depending on the values of their Host: headers. To do so, use the Host statement in the Service section.

The argument to Host specifies the host name. When an incoming request arrives, it is compared with this value. The Service section will be used only if the value of the Host: header from the request matched the argument to the Host statement. By default, exact case-insensitive comparison is used.

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 192.0.2.1. The configuration file would look like this:

ListenHTTP
	Address 192.0.2.1
	Port    80

	Service
		Host "www.server0.com"
		Backend
			Address 192.168.0.10
			Port    80
		End
	End

	Service
		Host "www.server1.com"
		Backend
			Address 192.168.0.11
			Port    80
		End
	End
End

The same can be done using ListenHTTPS.

If you want to use the same service for both the hostname and the hostname prefixed with www., you can either use the Match statement, or a regular expression.

A Match statement groups several conditions using boolean shortcut evaluation. In the following example, boolean or is used to group two Host statements:

	Service
		Match OR
			Host "server0.com"
			Host "www.server0.com"
		End
		Backend
			Address 192.168.0.10
			Port    80
		End
	End

When this service is considered, the value of the Host: header from the incoming request is matched against each host listed in the Match OR statement. If any value compares equal, the match succeeds and the service is selected for processing the request.

By default, the Host directive uses exact case-insensitive string match. This can be altered by supplying one or more options to it. In the example below, we use regular expression matching to achieve the same result as in the configuration above:

	Service
		Host -re "^(www\\.)?server0\\.com$"
		Backend
			Address 192.168.0.10
			Port    80
		End
	End

Notice double-slashes: a slash is an escape character and must be escaped if intended to be used literally.

Sessions

Pound is able to keep track of sessions between a client browser and a backend server. Unfortunately, HTTP is defined as a stateless protocol, which complicates matters: many schemes have been invented to allow keeping track of sessions, and none of them works perfectly. What's 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 backend 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.

Session tracking is declared using the Session block in Service section. Only one Session can be used per Service. The type of session tracking is declared with the Type statement.

  • Type IP: Session tracking by address

    In this scheme pound directs all requests from the same client IP address to the same backend 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.

  • Type Basic: by Basic Authentication

    In this scheme pound directs all requests from the same user (as identified in the Basic Authentication header) to the same backend 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.

    This type is a special case of the Type Header, described below.

    WARNING: given the constraints of the HTTP protocol it may very well be that the authenticated request will go to a different backend server than the one originally requesting it. Make sure all your servers support the same authentication scheme!

  • Type URL: 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.

  • Type Cookie: 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.

  • Type Parm: 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 - sessions will be tracked by the value of the parameter.

  • Type Header: 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 backend time after time. Some reverse proxies use a mechanism called cookie injection in order to achieve this: a cookie is added to backend responses and tracked by the reverse proxy.

Pound was designed to be as transparent as possible, therefore this mechanism is not supported. If you really need this sort of persistent mapping use the client address session mechanism (Type IP), which achieves the same result without changing the contents in any way.

Logging

If pound operates in daemon mode (the default), all diagnostics goes to the syslog facility daemon. Pound switches to syslog right before it disconnects from the controlling terminal. Until then, it sends its messages to the standard error.

By default only error and informative messages are logged. The amount of information logged is controlled by the LogLevel configuration statement. Possible settings are:

  • 0 No logging.

  • 1 Regular logging: only error conditions and important informative messages are logged.

  • 2 Extended logging: show chosen backend servers as well.

  • 3 Log requests using Apache-style Combined Log format.

  • 4 Same as 3, but without the virtual host information.

  • 5 Same as 4 but with information about the Service and Backend used.

The LogLevel statement can be global (effective for all listeners), as well as per-listener.

Socket Passing

Pound can obtain socket to listen on from another program via a UNIX socket. This mode of operation is requested by the following statement in ListenHTTP section:

  SocketFrom "/path/to/socket"

When this statement is present, neither Address nor Port may be used in this listener. Pound will connect to the named socket and obtain the socket descriptor from it. Then it will start listening for incoming requests on that socket.

This can be used both in ListenHTTP and ListenHTTPS sections.

Currently it is used in pound testsuite.

Request Modification

Normally, pound passes all incoming requests to backends verbatim. Several request modification directives are provided, that allow you to add or remove headers from the request. The following two groups of headers are added by default. Each of them can be turned off using the HeaderOption directive.

  1. The forwarded headers:
  • X-Forwarded-For: header passes the actual IP address of the client machine that sent the request.

  • X-Forwarded-Proto: header contains the original protocol (http or https).

  • X-Forwarded-Port: header contains the port on the server that the client connected to.

  1. Second group contains ssl headers that are added only if the client connected using HTTPS. The X-SSL-Cipher header is always present if this header group is enabled. The rest of headers below is added only if the client certificate was supplied:
  • X-SSL-Cipher: SSL version followed by a slash and active cipher algorithm.
  • X-SSL-Certificate: the full client certificate (multi-line).
  • X-SSL-Issuer: information about the certificate issuer (CA).
  • X-SSL-Subject: information about the certificate owner.
  • X-SSL-notAfter: end od validity date for the certificate.
  • X-SSL-notBefore: start of validity date for the certificate.
  • X-SSL-serial: certificate serial number (in decimal).

The HeaderOption directive can be used (either globally or in listener block) to disable any or both of these groups, e.g.:

HeaderOption no-ssl forwarded

Any number of headers can be added or removed using the HeaderAdd and HeaderRemove directives in the listener section. The order in which these directives are applied is:

  1. Headers controlled by the HeaderOption directive are added.
  2. Headers requested by HeaderRemove directives are removed.
  3. Headers from HeaderAdd directives are added.

ACME

Pound offers built-in support for ACME (a.k.a. LetsEncrypt) HTTP-01 challenge type. Thus, it can be used with any certificate controller to obtain SSL certificates on the fly.

Assuming your certificate controller is configured to store challenges in directory /var/lib/pound/acme, all you need to do is add the ACME statement to the ListenHTTP block, for example:

ListenHTTP
	ACME "/var/lib/pound/acme"
	.
	.
	.
End

Now, each request whose URL ends in /.well-known/acme-challenge/NAME will be served by directly by pound: it will send the content of the file /var/lib/pound/acme/NAME as a reply.

Using RootJail

The RootJail configuration directive instructs pound to chroot to the given directory at startup. Normally, its use should be quite straightforward:

RootJail "/var/pound"

Pound tries to open all files and devices it needs before chrooting. There might be cases, however, when it is not enough and you would need to copy certain system files to the chroot directory.

Bug-reporting

If you think you found a bug in pound or in its documentation, please send a mail to Sergey Poznyakoff [email protected] (or [email protected]), or use the github issue tracker.

When reporting failed tests, please make an archive of the tests/testsuite.dir subdirectory and attach it to your report.

pound's People

Contributors

graygnuorg avatar patrodyne avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar

pound's Issues

Pound forwards messages containing unrecognized transfer codings

Pound forwards unrecognized transfer codings. This is something that the standard recommends against. From RFC 9112, section 6.1:

A server that receives a request message with a transfer coding it does not understand SHOULD respond with 501 (Not Implemented).

While Pound's current behavior is not in violation of the RFCs, it's not particularly wise because some origin servers have strange interpretations of transfer codings. For example, there exist servers that interpret all unrecognized transfer codings as equivalent to chunked. This obviously pairs very poorly with Pound's policy of "forward all unknown transfer codings."

Nearly all other reverse proxies (including Akamai CDN, Apache httpd, Apache Traffic Server, Caddy, H2O, HAProxy, nghttpx, Nginx, Squid, Varnish, AWS CloudFront, Cloudflare CDN, Fastly, Google Cloud classic application load balancer, Google Cloud global application load balancer, and OpenBSD relayd) reject requests containing unrecognized transfer codings.

Pound forwards requests with invalid whitespace around chunk sizes

RFC 9112 defines a chunked message body with the following ABNF rules:

  chunked-body   = *chunk
                   last-chunk
                   trailer-section
                   CRLF

  chunk          = chunk-size [ chunk-ext ] CRLF
                   chunk-data CRLF
  chunk-size     = 1*HEXDIG
  last-chunk     = 1*("0") [ chunk-ext ] CRLF

  chunk-data     = 1*OCTET ; a sequence of chunk-size octets

Note that no whitespace is permitted preceding a chunk-size.
Pound accepts and forwards whitespace before chunk-sizes.

For example, when I send the following invalid request to my Pound reverse proxy:

POST / HTTP/1.1\r\n
Host: whatever\r\n
Transfer-Encoding: chunked\r\n
\r\n
\t0\r\n
\r\n'

here's what it forwards to its backend:

POST / HTTP/1.1\r\n
Host: whatever\r\n
Transfer-Encoding: chunked\r\n
X-Forwarded-For: 172.18.0.1\r\n
X-Forwarded-Proto: http\r\n
X-Forwarded-Port: 80\r\n
\r\n
\t0\r\n
\r\n

Note that the \t before the 0 chunk size is preserved through the proxy.

Unable to use the same backend for different virtual hosts

Hi, I have an Apache backend which serves multiples sites on the same IP on port 80 but on different virtual hosts via the ServerName directive:

    http://app1.domain.local
    http://app2.domain.local

and so on.
I'm unable to make this configuration work with pound.
I defined the following backends:

  BackEnd "App1"
          Address app1.domain.local
          Port 80
  End
  BackEnd "App2"
          Address app2.domain.local
          Port 80
  End

This is not working because pound talks with the backend using its IP.

Is there any way to handle this kind of configuration?

Kind regards,
A.

"error copy client cont" error

Using pound 4.9.90 and upgraded to 4.11.90.

We started seeing more and more of the following errors for a specific backend:

e500 for [ext ip address] error copy client cont to [backend address]/POST /EWS/mrsproxy.svc HTTP/1.1: Connection timed out (10.038 sec)

Can you help us understand what does the error mean and where the time out is set?

This is the configuration stanza in use:

    Service
            HeadRequire "Host: .*redacted*"
            URL ".*/(autodiscover|ecp|ews|EWS|mapi|Microsoft-ActiveSync|oab|owa|rpc).*"
            IgnoreCase 1
            BackEnd
                    HTTPS
                    Address redacted
                    Port 443
                    TimeOut 180
            End
    End

Regards,
AB

Small logging patch

Hi Sergey,

Thanks a lot for continuing the pound project, nice to see the story is going on!

May I propose a small patch which slightly changes the logging?

The first changes affect the http_log_1() and http_log_2() where they write the response_code to the log instead of what?
In my logs I never see anything printed after the - so it ends up with simply two spaces. I thought it's better to have the HTTP status code there instead of nothing but I don't know what should be printed there instead.

From
Apr 3 15:12:47 ns1 pound[15656]: 18.143.5.18 GET /mail/ HTTP/1.1 - (abc.invoca.ch/- -> 18.161.91.34:8080) 0.018 sec
To
Apr 3 15:12:47 ns1 pound[15656]: 18.143.5.18 GET /mail/ HTTP/1.1 - 302 (abc.invoca.ch/- -> 18.161.91.34:8080) 0.018 sec

The second change is to bring the terminating thread message in line with other messages about threads:

From
Apr 3 15:12:48 ns1 pound[15656]: (7f404797e700) e503 no service "GET /favicon.ico HTTP/1.1" from 18.143.5.18 abc.invoca.ch
Apr 3 15:12:48 ns1 pound[15656]: thread 7f404797e700 terminating on idle timeout

To
Apr 3 15:12:48 ns1 pound[15656]: (7f404797e700) e503 no service "GET /favicon.ico HTTP/1.1" from 18.143.5.18 abc.invoca.ch
Apr 3 15:12:48 ns1 pound[15656]: (7f404797e700) terminating thread on idle timeout

Thanks,
Simon

pound-4.7-logmsg.patch.txt

HeadRemove Bad Response & Include no longer supported in ListenHTTPS section

Hi

FreeBSD ports recently upgraded from pound 2.8 to 4.5 - and I ran across two issues with this.

  1. The directive 'HeadRemove "X-Forwarded-Proto"' now results in a 'Bad Request' response when trying to access any websites.

  2. 'Include' is no longer supported within ListenHTTPS.

For the latter, I was able to fix this with the following patch:

*** src/config.c.old    Sun Feb 12 19:56:35 2023
--- src/config.c        Sat Mar 18 20:02:12 2023
***************
*** 3387,3392 ****
--- 3387,3393 ----
  }

  static PARSER_TABLE https_parsetab[] = {
+   { "Include", parse_include },
    { "End", parse_end },
    { "Address", assign_address, NULL, offsetof (LISTENER, addr) },
    { "Port", assign_port, NULL, offsetof (LISTENER, addr) },

But a more generic case may be considered - to apply this to other sections within the configuration - but this was the only area I needed it fixed.

I did not do any further investigation on the HeadRemove issue.

Segmentation fault with pound 4.11 on OpenSUSE

I compiled pound 4.11 on some OpenSUSE servers, and installed it.

When running pound and pointing it to the configuration file, it results in: Segmentation fault (core dumped).

This happens already when verifying the configuration file with "-c", example

 /usr/local/sbin/pound -c -f /path/to/my/poundconfiguration.cfg
Segmentation fault (core dumped)

Valgrind gives some details:

==11314== Memcheck, a memory error detector
==11314== Copyright (C) 2002-2017, and GNU GPL'd, by Julian Seward et al.
==11314== Using Valgrind-3.18.1 and LibVEX; rerun with -h for copyright info
==11314== Command: /usr/sbin/pound.new -c -f /etc/pound.cfg
==11314==
==11314== Invalid read of size 4
==11314==    at 0x40E7B0: parse_config_file (config.c:5134)
==11314==    by 0x40ECD5: config_parse (config.c:5354)
==11314==    by 0x405813: main (pound.c:1000)
==11314==  Address 0x10 is not stack'd, malloc'd or (recently) free'd
==11314==
==11314==
==11314== Process terminating with default action of signal 11 (SIGSEGV)
==11314==  Access not within mapped region at address 0x10
==11314==    at 0x40E7B0: parse_config_file (config.c:5134)
==11314==    by 0x40ECD5: config_parse (config.c:5354)
==11314==    by 0x405813: main (pound.c:1000)
...
==11314== ERROR SUMMARY: 1 errors from 1 contexts (suppressed: 0 from 0)
Segmentation fault (core dumped)

My crystal ball told me that pound expects a configuration file, even if empty, at /usr/local/etc/pound.cfg
Based on that I found a workaround:

sudo mkdir /usr/local/etc
sudo touch /usr/local/etc/pound.cfg

and no more Segmentation fault.

I assume that at installation the file pound.cfg was not created because there was no directory yet at /usr/local/etc.

I suggest to either remove the requirement of having something at /usr/local/etc/pound.cfg or to make sure it is created at make install.

openssl 0A000438 error and Caddy servers

I'm getting error for some Caddy server backends:

pound: BIO_do_handshake with xx.xx.xx.xx:443 failed: error:0A000438:SSL routines::tlsv1 alert internal error

backend configuration (inside https listener) is minimal:

       BackEnd              
           HTTPS            
           Address some.caddy.server
           Port 443         
       End                  

Playing with Disable TLSx or Ciphers options (like any other options) changed nothing.
Tested with openssl 3.0.9 and 3.1.3 – same results.

Here's Qualys report on one of "problematic" sites.
Also, this discussion on stackoverflow may be relevant to the issue

Pound forwards requests containing both `Transfer-Encoding` and `Content-Length` headers

When Pound receives a request containing both an unrecognized Transfer-Encoding value and a Content-Length value, both are forwarded to the backend. This violates RFC 9112, section 6.2:

A sender MUST NOT send a Content-Length header field in any message that contains a Transfer-Encoding header field.

To see this for yourself, start up Pound and send it the following request:

POST / HTTP/1.1\r\n
Host: a\r\n
Content-Length: 5\r\n
Transfer-Encoding: invalid!!\r\n
\r\n
0\r\n\r\n

You should see the following forwarded to the backend:

POST / HTTP/1.1\r\n
Host: a\r\n
Content-Length: 5\r\n
Transfer-Encoding: invalid!!\r\n
X-Forwarded-For: 172.19.0.1\r\n
X-Forwarded-Proto: http\r\n
X-Forwarded-Port: 80\r\n
\r\n
0\r\n\r\n

Note that both headers remain.

`ACME "directory"` not working when in `RootJail`

@graygnuorg thank you for keeping this project alive.

I've recently migrated under FreeBSD the from the old aspis version to your new 4.6 release (downloaded and compiled myself).

Wile trying out the ACME functionality, I found that I always get 404 error for the challenge. Doing manual steps to investigate, and found that pound always returns 404 despite a file being placed in the correct directory. Config is like:

User		"nobody"
Group		"nobody"
RootJail	"/var/jail/pound/"
PIDFile		"/var/run/pound.pid"

ListenHTTP
	Address 127.0.0.1
	Port    9080  #access is done through port forwards from WAN to here
	LogLevel 5
	xHTTP 3
	Err404 "/var/jail/pound/err404.txt"
	Err413 "/var/jail/pound/err413.txt"
	Err414 "/var/jail/pound/err414.txt"
	Err500 "/var/jail/pound/err500.txt"
	Err501 "/var/jail/pound/err501.txt"
	Err503 "/var/jail/pound/err503.txt"

	Service
		HeadRequire "Host: someotherhost.example.com"
		Backend
			Address 192.168.1.22
			Port    80
			TimeOut 900
		End
	End

	ACME "/var/jail/pound/acme"

	...

Placed a file under /var/jail/pound/acme (with echo test > /var/jail/pound/acme/aaa.txt) and trying to access through a browser via http://example.com/.well-known/acme-challenge/aaa.txt results in Error404. Also tried to place the file at /var/jail/pound/acme/.well-known/acme-challenge/aaa.txt but still 404.

In the log only:

Mar 28 10:15:34 | pound | 68281 | example.com 192.168.0.1 - - [28/Mar/2023:10:15:34 +0200]  "GET /.well-known/acme-challenge/aaa.txt HTTP/1.1" 404 - "" "Mozilla/5.0  (Windows NT 10.0; Win64; x64; rv:109.0) Gecko/20100101 Firefox/111.0"  ((acme) -> acme:/var/jail/pound/acme/$1) 0.000 sec

Of course if I omit or modify .well-known/acme-challenge from the URL I get Error503 so it looks like the ACME listener properly detects it, but doesn't serve the file.

Commenting out the RootJail configuration seems to fix it. But I don't see why, as the ACME directory is within the jail, and Err files are served well from there.

Pound forwards requests with multiple `Transfer-Encoding: chunked` headers

When I send the following request to Pound:

GET / HTTP/1.1\r\n
Host: a\r\n
Transfer-Encoding: chunked\r\n
Transfer-Encoding: chunked\r\n
\r\n
0\r\n
\r\n

It forwards the following to my backend:

GET / HTTP/1.1\r\n
Host: a\r\n
Transfer-Encoding: chunked\r\n
Transfer-Encoding: chunked\r\n
X-Forwarded-For: 172.19.0.1\r\n
X-Forwarded-Proto: http\r\n
X-Forwarded-Port: 80\r\n
\r\n
0\r\n
\r\n

Note that the two Transfer-Encoding headers are preserved. This is problematic for the many servers that misinterpret such requests, and can lead to request smuggling.

There are three potential fixes for this problem:

  1. Reject messages with multiple Transfer-Encoding: chunked headers. This is what Apache, Caddy, Envoy, HAProxy, nghttpx, Nginx, LiteSpeed, Squid, Traefik, Akamai, AWS, Azure, CloudFlare, Fastly, and Google Cloud do.
  2. Normalize the request to have only one Transfer-Encoding: chunked header. This is what Apache Traffic Server does.
  3. Buffer the request and use Content-Length instead. This is what H2O and Varnish do.

Backed does not come back from dead status

One of our backend (Tomcat on Windows) does not come back from the "dead" status when, for some reasons, it becomes unreachable for some time.
We do not have set the "Alive" parameter.
The only way to get it back working is to restart pound.
Is there anything we can check?

Unable to delete pid file when not running as root

Hi,

I see the following issue when running pound as user pound:

Apr 3 17:14:16 ns1 pound[4066]: got signal 15
Apr 3 17:14:16 ns1 pound[4069]: shutting down...
Apr 3 17:14:16 ns1 pound[4069]: can't remove file /var/run/pound/ctl_socket: Permission denied
Apr 3 17:14:16 ns1 pound[4069]: can't remove file /var/run/pound.pid: Permission denied
Apr 3 17:14:16 ns1 pound[4066]: got signal 17

I understand that this is because the files are owned by root and in fact it doesn't happen when pound is running as root.

Is this the expected behavior and the error messages should just be ignored?

Thanks,
Simon

Different behaviour in URL parsing between versions of libpcre?

Hi, we are experiencing an odd behaviour between Pound 2.8 and Pound 4 for one backend used to wrap in HTTPS an HTTP internal server.
The URL is written as: URL ".*/AlboOnline.*"

With Pound 2.8, if we go to https://our.site/AlboOnline (no slash at the end), the internal backend server generates a "302 Redirect" to **https://**our.site/AlboOnline/ then a "302 Redirect" to https://our.site/AlboOnline/ricercaAlbo (no slash at the end) which is the desired page.

With Pound 4, if we go to https://our.site/AlboOnline (no slash at the end), the internal backend server generates a "302 Redirect" to **http://**our.site/AlboOnline which does not work.
Instead, if we go to https://our.site/AlboOnline/ (with slash at the end), the internal backend server generates a "302 Redirect" to
**http://**our.site/AlboOnline/ricercaAlbo which, of course, does not work.

Could this behaviour related to the different versions of libpcre?

GCC flag -fcommon required with GCC v. 10.2.0

Hello, I'm currently building pound to run on Photon OS (VMware Linux container).
Photon OS ships with GCC 10.2.0: the assembly steps (ld) with the following error:

gcc -pthread -g -O2   -o poundctl poundctl.o ./libpound.a -lpthread -lssl -lcrypto -lresolv -ldl -lrt
/usr/bin/ld: ./libpound.a(json.o):/root/pound-4.4/src/pound.h:792: multiple definition of `progname'; poundctl.o:/root/pound-4.4/src/pound.h:792: first defined here
/usr/bin/ld: ./libpound.a(mem.o):/root/pound-4.4/src/pound.h:792: multiple definition of `progname'; poundctl.o:/root/pound-4.4/src/pound.h:792: first defined here
/usr/bin/ld: ./libpound.a(progname.o):/root/pound-4.4/src/./pound.h:792: multiple definition of `progname'; poundctl.o:/root/pound-4.4/src/pound.h:792: first defined here
/usr/bin/ld: ./libpound.a(tmpl.o):/root/pound-4.4/src/pound.h:792: multiple definition of `progname'; poundctl.o:/root/pound-4.4/src/pound.h:792: first defined here

Setting CFLAGS=-fcommon before running configure solves the problem.
The flags is reported on multiple source to be a change in the default behaviour of GCC v. 10 and above.

[FR] response headers modification

pound has a good and sufficient mechanism to manipulate request headers. Though, sometimes may be needed to change response headers too (it may be needed especially when there is no way to modify backend server behaviour or when in need of removing «improper» headers, if any.

It would be nice to have a possibility to use appropriate directives inside Backend section (e.g. SetResponseHeader "name: value" and DeleteResponseHeader [options] "pattern") – with the same logic as for request headers (include Rewrite conditionals)

GPF after a short time

Hi, we are running pound 4.6.90 on Oracle Linux 9 compiled with tcmalloc, openSSL 3.01 and MAXBUF=8192.
After a short time we get a lot of general protection fault errors:

Mar 30 17:09:56 pound-98 pound[26221]: (7f9c30143640) Can't read BIO_f_base64
Mar 30 17:09:56 pound-98 kernel: traps: pound[26228] general protection fault ip:7f9c3086532e sp:7f9c3013fb88 error:0 in libtcmalloc.so.4.5.9[7f9c3083e000+28000]

Any ideas on what to check?

Pound forwards chunk sizes prefixed with `0x`, `-`, and `+`

Because Pound parses chunk sizes using strtoll(, , 16), chunk sizes that begin with 0x are erroneously accepted and forwarded. - and + prefixes are also accepted for the same reason, though - is only accepted when the chunk size is 0. This is not permitted in the HTTP RFCs, and can lead to problems for downstream servers because some servers interpret chunk sizes that begin with 0x as equivalent to 0. This can be used for request smuggling against such servers.

Create release of prerelease versions?

Hi Sergey,

Would it be possible that you create a release of prerelease versions like 4.8.91? Since I'm maintaining RPM packages also for older distributions, it would make it easier for me to create such prereleases and test them. Problem is, the whole GNU auto* stuff is not new enough on such systems.

Thanks,
Simon

Bug in chunked message body decoding causes malformed requests to be forwarded

When Pound receives a request with the Transfer-Encoding: chunked header and a malformed message body, Pound forwards that request without its message body.

To see this for yourself, send Pound the following request:

POST /  HTTP/1.1\r\n
Transfer-Encoding: chunked\r\n
\r\n
1\r0\n

It should forward something like this:

POST /  HTTP/1.1\r\n
Transfer-Encoding: chunked\r\n
X-Forwarded-For: <some ip address>\r\n
X-Forwarded-Proto: http\r\n
X-Forwarded-Port: <some port>\r\n
\r\n

This forwarded message is incomplete, and will almost certainly cause the backend to time out while it waits for the message body to arrive.

Multiple "Can't read BIO_f_base64" in log

We've started migrating our old pound-2.8 server to pound-4.8.90
Everything seems working fine but we have multiple "Can't read BIO_f_base64" warning in the log.
Is this harmless? Is there something we should check?
We compiled pound-4 with a buffer size of 8192 because some backend applications needed it.

OpenSSL 3 misses dhparam -C option to print C code

OpenSSL 3 misses dhparam -C option to print C code.

Resulting error:
make -C pound CC="ccache arm-linux-uclibc-gcc" make[1]: Entering directory '/media/egc/linuxdata/ddwrt/src/router/pound' openssl dhparam -5 -C -noout 512 > dh512.h

Code is in Makefile.am

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.