From ef6f698d866855c031bd6e7eee64efb8f06d43b3 Mon Sep 17 00:00:00 2001
From: Yves Rutschle <git1@rutschle.net>
Date: Thu, 3 Apr 2025 21:30:34 +0200
Subject: [PATCH] document proxyprotocol

---
 ChangeLog       | 2 ++
 README.md       | 6 ++++++
 common.c        | 5 +++--
 doc/INSTALL.md  | 5 +++--
 doc/config.md   | 3 +++
 example.cfg     | 8 ++++++--
 proxyprotocol.c | 2 +-
 test.cfg        | 2 +-
 version.h       | 2 +-
 9 files changed, 26 insertions(+), 9 deletions(-)

diff --git a/ChangeLog b/ChangeLog
index 83da99a..f096723 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -5,6 +5,8 @@ vNEXT:
 	(listening or connecting) will be performed on Unix
 	socket instead of Internet sockets.
 
+	Support proxyprotocol on the backend server side.
+
 v2.1.3:
 	Fix Landlock access to /etc/hosts.deny and
 	/etc/hosts.allow.
diff --git a/README.md b/README.md
index 2365545..63274fd 100644
--- a/README.md
+++ b/README.md
@@ -42,6 +42,12 @@ Transparent proxying
 Transparent proxying allows the target server to see the
 original client IP address, i.e. `sslh` becomes invisible.
 
+The same result can be achieved more easily by using
+`proxyprotocol` if the backend server supports it. This is a
+simple setting to add to the `sslh` protocol configuration,
+usually with an equivalently simple setting to add in
+the backend server configuration, so try that first.
+
 This means services behind `sslh` (Apache, `sshd` and so on)
 will see the external IP and ports as if the external world
 connected directly to them. This simplifies IP-based access
diff --git a/common.c b/common.c
index f22f732..4545560 100644
--- a/common.c
+++ b/common.c
@@ -413,8 +413,9 @@ static int connect_inet(struct connection *cnx, int fd_from, connect_blocking bl
                            cnx->proto->port);
     }
     for (a = cnx->proto->saddr; a; a = a->ai_next) {
-        /* When transparent, make sure both connections use the same address family */
-        if (transparent && a->ai_family != from.ai_addr->sa_family)
+        /* When transparent or using proxyprotocol, make sure both 
+         * connections use the same address family (e.g. IP4 on both sides) */
+        if ((transparent || cnx->proto->proxyprotocol_is_present) && (a->ai_family != from.ai_addr->sa_family))
             continue;
         print_message(msg_connections_try, "trying to connect to %s family %d len %d\n",
                     sprintaddr(buf, sizeof(buf), a),
diff --git a/doc/INSTALL.md b/doc/INSTALL.md
index 983da2a..f761371 100644
--- a/doc/INSTALL.md
+++ b/doc/INSTALL.md
@@ -46,11 +46,12 @@ Dependencies
 * [libproxyprotocol](https://github.com/kosmas-valianos/libproxyprotocol.git)
   to support HAProxy's [ProxyProtocol](https://www.haproxy.org/download/2.3/doc/proxy-protocol.txt).
   As this is not part of the distribution packages, set
-  C_INCLUDE_PATH and LD_LIBRARY_PATH to the appropriate
+  C_INCLUDE_PATH, LD_LIBRARY_PATH, and LIBRARY_PATH to the appropriate
   values:
   ```
     export C_INCLUDE_PATH=/home/user/src/libproxyprotocol/src 
-    export LD_LIBRARY_PATH=/home/user/src/libproxyprotocol/src
+    export LD_LIBRARY_PATH=/home/user/src/libproxyprotocol/libs
+    export LIBRARY_PATH=/home/user/src/libproxyprotocol/libs
   ```
 
 For OpenSUSE, these are contained in packages libconfig9 and
diff --git a/doc/config.md b/doc/config.md
index e712190..baa277d 100644
--- a/doc/config.md
+++ b/doc/config.md
@@ -102,6 +102,9 @@ Transparent proxy support
 Transparent proxying is described in its own
 [document](tproxy.md).
 
+It might be easier to configure `sslh` to use Proxyprotocol
+if the backend server supports it.
+
 Systemd Socket Activation
 -------------------------
 If compiled with `USESYSTEMD` then it is possible to activate 
diff --git a/example.cfg b/example.cfg
index 77868af..74a8e10 100644
--- a/example.cfg
+++ b/example.cfg
@@ -78,8 +78,12 @@ listen:
 #         transparently (server sees the remote client IP
 #         address). Same as the global option, but per-protocol
 #   is_unix: [true|false] connect to a UNIX socket. The host
-#   field becomes the pathname to the socket, and the port
-#   field is unused (but necessary).
+#         field becomes the pathname to the socket, and the port
+#         field is unused (but necessary).
+#   proxyprotocol: <1|2>; When connecting to the backend
+#         server, a proxyprotocol header of the specified
+#         version will be added, containing the client's
+#         connection information.
 #
 #  Probe-specific options:
 # (sslh will try each probe in order they are declared, and
diff --git a/proxyprotocol.c b/proxyprotocol.c
index b5033ca..aab218c 100644
--- a/proxyprotocol.c
+++ b/proxyprotocol.c
@@ -44,7 +44,7 @@ static int family_to_pp(int af_family)
     }
 }
 
-typedef char libpp_addr[108];
+typedef char libpp_addr[108]; /* This is hardcoded in libproxyprotocol/proxy_protocol.h */
 
 /* Fills *addr, *host and *serv with the connection information corresponding
  * to fd. *host is the IP address as string and *serv is the service (port)
diff --git a/test.cfg b/test.cfg
index 4c4342c..9aa7877 100644
--- a/test.cfg
+++ b/test.cfg
@@ -45,7 +45,7 @@ protocols:
 (
      { name: "ssh";  host: "localhost"; port: "9000"; fork: true; transparent: true; resolve_on_forward: true; },
      { name: "socks5";  host: "localhost"; port: "9001";  },
-     { name: "http";  host: "localhost"; port: "80"; proxyprotocol: 1;  },
+     { name: "http";  host: "localhost"; port: "80"; proxyprotocol: 2;  },
      { name: "tinc";  host: "localhost"; port: "9003"; },
      { name: "openvpn";  host: "localhost"; port: "9004"; },
      { name: "xmpp";  host: "localhost"; port: "9009"; },
diff --git a/version.h b/version.h
index 11c3bc4..39a8717 100644
--- a/version.h
+++ b/version.h
@@ -1,5 +1,5 @@
 #ifndef VERSION_H 
 #define VERSION_H 
 
-#define VERSION "v2.1.4-39-g2f111b6-dirty"
+#define VERSION "v2.1.4-40-g416a82f-dirty"
 #endif