A very simple DN-rewriting LDAP reverse proxy (useful for multiple LLDAP instances)
Find a file
Repository files (latest commit first)
Filename Latest commit message Latest commit date
2026-09-18 20:46:03 +02:00
src minor: Change timeout to 5s 2026-09-18 20:46:03 +02:00
.gitignore feat: Initial implementation (bind/search/whoami) 2026-08-20 21:45:33 +02:00
Cargo.lock meta: Rename ldap-rp (that one's available) 2026-08-21 12:12:50 +02:00
Cargo.toml refactor: EVERYTHING 2026-08-31 20:59:02 +02:00
config.toml refactor: EVERYTHING 2026-08-31 20:59:02 +02:00
LICENSE.md feat: Initial implementation (bind/search/whoami) 2026-08-20 21:45:33 +02:00
README.md feat: Search by mail attribute (stalwart compatibility) 2026-08-28 12:03:23 +02:00

ldap-rp

Proxy LDAP requests to different LDAP servers based on base DN. Based on code from kanidm/ldap-proxy under the MPL license.

Features

  • No TLS setup ; use only in trusted networks
  • LDAP bind requests
  • LDAP search requests
    • extract requested backend from mail attribute filter
    • bind to requested backend with mapping user and password fields
    • not (yet?) planned: extract requested backend from more filters
    • rewrite the search dn with backend to dn (eg. ou=people,dc=a,dc=localhost -> ou=people,dc=example,dc=com)
    •  rewrite returned entries with backend dn (eg. uid=a,ou=people,dc=example,dc=com -> uid=a,ou=people,dc=a,dc=localhost)
    • rewrite search dn and result entries for authenticated searches on a backend
  • Configurable listening port
  • Default fallback to /etc/ldap-rp/config.toml
  • Unix Domain Socket support (incoming requests)
  • Unix Domain Socket garbage collection (incoming requests)
  • Unix Domain Socket support (outgoing requests)
  • not planned: TLS termination (incoming requests)
  • not planned: TLS backend connections (outgoing requests)
  • not planned: TLS SNI passthrough

Running

Create a configuration file config.toml with the following:

# Where to listen to incoming connections ([::1]:389 by default, requires privileges)
#  - ip/port: `127.0.0.1:3389` (ipv4 only on localhost) `[::1]:3389` (ipv4/ipv6 on localhost),
#             `0.0.0.0:3389` (ipv4 only on all interfaces, `[::]:3389` (ipv4/ipv6 on any interface)
#  - socket: `./ldap.sock` for a socket in the current working directory
#            `/var/run/ldap.sock` for a socket with an absolute path
listen = "[::]:3389"
[[mapping]]
from = "a.localhost"
to = "example.com"
# The LDAP address of the backend server:
# - start with `./` or `/` for a socket URI
# - start with anything else for a TCP connection
# backend = "/run/lldap/example.com.sock"
backend = "127.0.0.1:4389"
# Credentials for performing search query to the backend
# set `lldap_strict_readonly` perms on the account in lldap.
user = "stalwart"
password = "adminadmin"
[[mapping]]
from = "b.localhost"
to = "example.com"
backend = "127.0.0.1:5389"
user = "stalwart"
password = "adminadmin"

By default, ldap-rp will look for a config file in /etc/ldap-rp/config.toml but you can change that with the --config CLI flag.

You can now run:

ldap-rp --config config.toml

Testing your setup

Once you have a LDAP server running, you can test your settings with the ldapwhoami command from the openldap package:

# Test when listening on port 3389
ldapwhoami -H ldap://localhost:3389 -D "cn=b,ou=people,dc=a,dc=localhost" -W
# Test when listening on socket /run/ldap-rp/ldap-rp.sock, where `/` is escaped
# with `%2F` and the protocol is changed to `ldapi`
ldapwhoami -H ldapi://%2Frun%2Fldap-rp%2Fldap-rp.sock -D "cn=b,ou=people,dc=a,dc=localhost" -W

You can also perform a search by email without binding with specific credentials, the base dn provided will have its hostname set to the backend mapping's from value:

ldapsearch -x -b "ou=people" -H "ldap://localhost:3389" -s sub "(mail=a@a.localhost)" uid mail

This is strictly equivalent to using -b "ou=people,dc=a,dc=localhost" because the search dn is always overwritten.