Implement proxy protocol
All checks were successful
continuous-integration/drone/push Build is passing

This commit is contained in:
Juan José Gutiérrez de Quevedo Pérez 2025-12-16 13:41:24 +01:00
parent cb2752889f
commit 3e29737b44
7 changed files with 74 additions and 13 deletions

View file

@ -147,7 +147,10 @@ list<string> Configfile::parseAsList(string str)
string::size_type startpos=0,endpos=0,len;
string tmpstr;
if (str.length())
{
str=Configfile::parseAsString(str); //remove quotes around string
}
len=str.length();
while(startpos<len&&string::npos!=endpos)

View file

@ -221,14 +221,14 @@ bool,incoming_ssl,false
* file with our private key (PEM format).
* to generate, execute:
* # openssl genrsa 1024 > private.key
* # openssl genrsa 2048 > hermes.key
string,private_key_file,"/etc/hermes/hermes.key"
* file with our server certificate (PEM format).
* to generate, execute:
* # openssl req -new -x509 -nodes -sha1 -days 365 -key private.key > certificate.crt
* # openssl req -new -x509 -nodes -sha1 -days 365 -key hermes.key > certificate.crt
* and answer the questions
string,certificate_file,"/etc/hermes/hermes.cert"
string,certificate_file,"/etc/hermes/certificate.crt"
* optional file with Diffie-Hellman parameters for Perfect Forward Secrecy.
* to generate, execute:
@ -273,3 +273,9 @@ bool,query_spf,false
* You should enable this while debugging your hermes installation,
* as configuration errors won't be fatal.
bool,return_temp_error_on_reject,false
* whether to accept connections using the proxy protocol or not
* see https://www.haproxy.org/download/2.0/doc/proxy-protocol.txt
* only version 2.0 is supported at the moment
* only IPv4 is supported
bool,proxy_protocol,false

View file

@ -34,7 +34,7 @@ void Proxy::setOutside(Socket& p_outside)
* TODO: fill diagram and point to website with graphical version
*
*/
void Proxy::run(string &peer_address)
void Proxy::run(const string &real_peer_address)
{
#ifdef HAVE_SPF
Spf spf_checker;
@ -44,6 +44,32 @@ void Proxy::run(string &peer_address)
string to="";
string ehlostr="";
string resolvedname="";
string peer_address = "";
if (cfg.getProxyProtocol())
{
struct {
uint8_t sig[12]; /* hex 0D 0A 0D 0A 00 0D 0A 51 55 49 54 0A */
uint8_t ver_cmd; /* protocol version and command */
uint8_t fam; /* protocol family and address */
uint16_t len; /* number of following bytes part of the header */
} hdr_v2;
struct { /* for TCP/UDP over IPv4, len = 12 */
uint32_t src_addr;
uint32_t dst_addr;
uint16_t src_port;
uint16_t dst_port;
} ipv4_addr;
outside.readBytes(&hdr_v2, sizeof(hdr_v2));
outside.readBytes(&ipv4_addr, sizeof(ipv4_addr));
peer_address = Socket::intToIpv4Address(ipv4_addr.src_addr);
std::cout << "received proxied connection from " << peer_address << std::endl;
}
else
{
peer_address = real_peer_address;
}
unsigned char last_state=SMTP_STATE_WAIT_FOR_HELO;
long unimplemented_requests=0;

View file

@ -55,7 +55,7 @@ class Proxy
public:
//Proxy():outside(NULL),inside(NULL){};
void setOutside(Socket&);
void run(string&);
void run(const string&);
};
#endif //PROXY_H

View file

@ -21,6 +21,8 @@
#include <unistd.h>
#include <cstring>
#include <openssl/err.h>
int Socket::created_sockets=0;
#ifdef HAVE_SSL
@ -60,8 +62,12 @@ Socket::Socket():fd(-1)
if(!ssl_ctx_server)
throw Exception(_("Error creating SSL context"),__FILE__,__LINE__);
/* load certificate */
if(SSL_CTX_use_certificate_chain_file(ssl_ctx_server,cfg.getCertificateFile().c_str())==-1)
ERR_clear_error();
if(SSL_CTX_use_certificate_chain_file(ssl_ctx_server,cfg.getCertificateFile().c_str())!=1)
{
ERR_print_errors_fp(stderr);
throw Exception(_("Error loading certificate"),__FILE__,__LINE__);
}
/* load DH params */
BIO *bio;
@ -87,12 +93,21 @@ Socket::Socket():fd(-1)
}
}
ERR_clear_error();
/* load private key */
if(SSL_CTX_use_PrivateKey_file(ssl_ctx_server,cfg.getPrivateKeyFile().c_str(),SSL_FILETYPE_PEM)==-1)
int retval = SSL_CTX_use_PrivateKey_file(ssl_ctx_server,cfg.getPrivateKeyFile().c_str(),SSL_FILETYPE_PEM);
if(retval != 1)
{
ERR_print_errors_fp(stderr);
throw Exception(_("Error loading private key"),__FILE__,__LINE__);
}
/* check that private key and cert match */
if(!SSL_CTX_check_private_key(ssl_ctx_server))
retval = SSL_CTX_check_private_key(ssl_ctx_server);
if(retval != 1)
{
ERR_print_errors_fp(stderr);
throw Exception(_("Private key doesn't match certificate file"),__FILE__,__LINE__);
}
//client
ssl_ctx_client=NULL;
@ -590,6 +605,13 @@ string Socket::resolveInverselyToString(string ip)
}
#endif //HAVE_GETADDRINFO
string Socket::intToIpv4Address(uint32_t ip)
{
struct in_addr ip_addr;
ip_addr.s_addr = ip;
return inet_ntoa(ip_addr);
}
int Socket::getFD()
{
return fd;

View file

@ -84,6 +84,7 @@ class Socket
bool connect(string,unsigned int);
int getFD();
static struct sockaddr resolve(string);
static string intToIpv4Address(uint32_t);
static string resolveToString(string);
static string resolveInverselyToString(string);

View file

@ -84,12 +84,15 @@ string Utils::strtolower(string s)
*
*/
string Utils::trim(string s)
{
if(s.length())
{
while(isspace(s[0]))
s.erase(0,1);
while(isspace(s[s.length()-1]))
s.erase(s.length()-1,1);
}
return s;
}