├── .gitattributes ├── doc ├── NOTES.tls ├── NOTES.todo ├── NOTES.tests ├── NOTES.history ├── NOTES.selection ├── NOTES.dirlist-parsing ├── NOTES.forward-proxy ├── NOTES.proxy-datatransfer-policy ├── REFERENCES ├── NOTES.reverse-proxy ├── NOTES.load-balancing └── NOTES.protocol-translation ├── .gitignore ├── t ├── modules │ ├── mod_proxy.t │ └── mod_proxy │ │ ├── ban.t │ │ ├── sql.t │ │ ├── ssh.t │ │ ├── tls.t │ │ ├── redis.t │ │ ├── ssh │ │ └── redis.t │ │ ├── tls │ │ └── redis.t │ │ └── reverse │ │ └── ipv6.t ├── etc │ └── modules │ │ └── mod_tls │ │ └── psk.dat ├── api │ ├── ftp │ │ └── facts.c │ ├── tests.h │ ├── str.c │ ├── random.c │ └── tests.c └── Makefile.in ├── include └── proxy │ ├── ssh │ ├── poly1305.h │ ├── db.h │ ├── redis.h │ ├── misc.h │ ├── service.h │ ├── bcrypt.h │ ├── session.h │ ├── utf8.h │ ├── agent.h │ ├── crypto.h │ ├── auth.h │ ├── compress.h │ ├── kex.h │ ├── disconnect.h │ ├── umac.h │ ├── mac.h │ ├── cipher.h │ ├── keys.h │ ├── msg.h │ ├── interop.h │ └── ssh2.h │ ├── str.h │ ├── uri.h │ ├── tls │ ├── db.h │ └── redis.h │ ├── reverse │ ├── db.h │ └── redis.h │ ├── random.h │ ├── ftp │ ├── data.h │ ├── xfer.h │ ├── conn.h │ ├── sess.h │ ├── ctrl.h │ ├── facts.h │ ├── msg.h │ └── dirlist.h │ ├── inet.h │ ├── dns.h │ ├── forward.h │ ├── conn.h │ ├── netio.h │ ├── ssh.h │ ├── session.h │ ├── db.h │ ├── reverse.h │ └── tls.h ├── .codeql.yml ├── README.md ├── .clang-tidy ├── lib └── proxy │ ├── ssh │ ├── umac128.c │ ├── session.c │ ├── misc.c │ ├── service.c │ ├── poly1305.c │ └── disconnect.c │ ├── str.c │ ├── random.c │ ├── ftp │ ├── facts.c │ └── data.c │ └── inet.c ├── .github └── workflows │ ├── codeql.yml │ └── regressions.yml ├── tests.pl ├── Makefile.in └── mod_proxy.h.in /.gitattributes: -------------------------------------------------------------------------------- 1 | *.pl linguist-language=C 2 | *.pm linguist-language=C 3 | -------------------------------------------------------------------------------- /doc/NOTES.tls: -------------------------------------------------------------------------------- 1 | 2 | ProxyTLSOptions 3 | IgnoreFEAT 4 | UseCCC 5 | 6 | Passphrase provider support? 7 | -------------------------------------------------------------------------------- /doc/NOTES.todo: -------------------------------------------------------------------------------- 1 | 2 | default low (1 sec) ConnectTimeout; consider many slow backends 3 | MODE Z proxying (mod_deflate) 4 | 5 | setjmp/longjmp for -X command-line option 6 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | configure 2 | Makefile 3 | config.log 4 | config.status 5 | autom4te.cache 6 | mod_proxy.h 7 | tests.log 8 | t/api-tests 9 | t/api-tests.log 10 | .libs 11 | *.a 12 | *.sw? 13 | *.la 14 | *.lo 15 | *Tests*.log 16 | *.o 17 | *~ 18 | -------------------------------------------------------------------------------- /t/modules/mod_proxy.t: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env perl 2 | 3 | use lib qw(t/lib); 4 | use strict; 5 | 6 | use Test::Unit::HarnessUnit; 7 | 8 | $| = 1; 9 | 10 | my $r = Test::Unit::HarnessUnit->new(); 11 | $r->start("ProFTPD::Tests::Modules::mod_proxy"); 12 | -------------------------------------------------------------------------------- /t/modules/mod_proxy/ban.t: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env perl 2 | 3 | use lib qw(t/lib); 4 | use strict; 5 | 6 | use Test::Unit::HarnessUnit; 7 | 8 | $| = 1; 9 | 10 | my $r = Test::Unit::HarnessUnit->new(); 11 | $r->start("ProFTPD::Tests::Modules::mod_proxy::ban"); 12 | -------------------------------------------------------------------------------- /t/modules/mod_proxy/sql.t: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env perl 2 | 3 | use lib qw(t/lib); 4 | use strict; 5 | 6 | use Test::Unit::HarnessUnit; 7 | 8 | $| = 1; 9 | 10 | my $r = Test::Unit::HarnessUnit->new(); 11 | $r->start("ProFTPD::Tests::Modules::mod_proxy::sql"); 12 | -------------------------------------------------------------------------------- /t/modules/mod_proxy/ssh.t: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env perl 2 | 3 | use lib qw(t/lib); 4 | use strict; 5 | 6 | use Test::Unit::HarnessUnit; 7 | 8 | $| = 1; 9 | 10 | my $r = Test::Unit::HarnessUnit->new(); 11 | $r->start("ProFTPD::Tests::Modules::mod_proxy::ssh"); 12 | -------------------------------------------------------------------------------- /t/modules/mod_proxy/tls.t: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env perl 2 | 3 | use lib qw(t/lib); 4 | use strict; 5 | 6 | use Test::Unit::HarnessUnit; 7 | 8 | $| = 1; 9 | 10 | my $r = Test::Unit::HarnessUnit->new(); 11 | $r->start("ProFTPD::Tests::Modules::mod_proxy::tls"); 12 | -------------------------------------------------------------------------------- /t/modules/mod_proxy/redis.t: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env perl 2 | 3 | use lib qw(t/lib); 4 | use strict; 5 | 6 | use Test::Unit::HarnessUnit; 7 | 8 | $| = 1; 9 | 10 | my $r = Test::Unit::HarnessUnit->new(); 11 | $r->start("ProFTPD::Tests::Modules::mod_proxy::redis"); 12 | -------------------------------------------------------------------------------- /t/modules/mod_proxy/ssh/redis.t: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env perl 2 | 3 | use lib qw(t/lib); 4 | use strict; 5 | 6 | use Test::Unit::HarnessUnit; 7 | 8 | $| = 1; 9 | 10 | my $r = Test::Unit::HarnessUnit->new(); 11 | $r->start("ProFTPD::Tests::Modules::mod_proxy::ssh::redis"); 12 | -------------------------------------------------------------------------------- /t/modules/mod_proxy/tls/redis.t: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env perl 2 | 3 | use lib qw(t/lib); 4 | use strict; 5 | 6 | use Test::Unit::HarnessUnit; 7 | 8 | $| = 1; 9 | 10 | my $r = Test::Unit::HarnessUnit->new(); 11 | $r->start("ProFTPD::Tests::Modules::mod_proxy::tls::redis"); 12 | -------------------------------------------------------------------------------- /t/modules/mod_proxy/reverse/ipv6.t: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env perl 2 | 3 | use lib qw(t/lib); 4 | use strict; 5 | 6 | use Test::Unit::HarnessUnit; 7 | 8 | $| = 1; 9 | 10 | my $r = Test::Unit::HarnessUnit->new(); 11 | $r->start("ProFTPD::Tests::Modules::mod_proxy::reverse::ipv6"); 12 | -------------------------------------------------------------------------------- /t/etc/modules/mod_tls/psk.dat: -------------------------------------------------------------------------------- 1 | 25e262660dc554c2e77f33e3cdc9e7467070d4e6193a6a87f6ba6c08aeb76246278e8ca50d41254315cbc6f5a3afc87922620151a16fffde6b38dd3c8bf71e7ba87d95d880f2d6049d8b148a5883234189b7a5249d787e0b2fe4befe41bfce0b29634f6acde3db0e477d49efb766772a78de99e0ff316e6910b0c83c2875c77a551bf2e940807b5e705516509a00c9fc7d88956f89b6600efc4ca74bd12493a5 2 | -------------------------------------------------------------------------------- /doc/NOTES.tests: -------------------------------------------------------------------------------- 1 | 2 | Note that to run the API tests for mod_proxy, you must: 3 | 4 | $ ./configure --enable-tests ... 5 | 6 | Then: 7 | 8 | $ cd contrib/mod_proxy/t/ 9 | $ make api-tests 10 | 11 | Available external FTP sites for testing: 12 | 13 | ftp.microsoft.com 14 | ftp.cisco.com* 15 | ftp.kernel.org 16 | ftp.freebsd.org 17 | ftp.seagate.com* 18 | 19 | (*) denotes FTPS 20 | -------------------------------------------------------------------------------- /doc/NOTES.history: -------------------------------------------------------------------------------- 1 | 2 | Why does proftpd have the netio readers for buffering up reads? Seems 3 | overengineered/too complex. 4 | 5 | Answer: See issues like this: 6 | 7 | http://www.greatcircle.com/firewalls/mhonarc/firewalls.199710/msg00056.html 8 | 9 | Where does the formatting for using "USER name@host" for forward proxying 10 | coming from? Or using two USER/PASS commands for doing forward proxying 11 | with proxy auth? 12 | 13 | Answer: From TIS' FWTK: 14 | 15 | http://www.fwtk.org/fwtk/docs/user_guide.pdf 16 | http://www.fwtk.org/fwtk/docs/manpages.pdf 17 | 18 | See the cited example FTP sessions for both types of logins. 19 | -------------------------------------------------------------------------------- /doc/NOTES.selection: -------------------------------------------------------------------------------- 1 | 2 | Balancing vs Stickiness 3 | 4 | Balancing: 5 | random 6 | shuffle 7 | roundRobin 8 | leastConns 9 | 10 | Sticky: 11 | per USER 12 | per HOST 13 | 14 | Work on implementing just the balancing strategies, for now. 15 | 16 | Note: The state files used for the balancing strategies, especially once 17 | health checks are added, could be externally cached/managed, e.g. via 18 | memcache/redis, using JSON. 19 | 20 | Issues there: if each mod_proxy is doing its own health checks of the 21 | servers, it's possible for individual mod_proxy instances to disagree 22 | about the health of a given backend (think split-brain syndrome). 23 | 24 | When each mod_proxy instance is managing its own view, this is OK; 25 | when they all share that persisted view, it could be a problem. 26 | -------------------------------------------------------------------------------- /doc/NOTES.dirlist-parsing: -------------------------------------------------------------------------------- 1 | 2 | At some point, especially for protocol conversions, mod_proxy may need to 3 | parse the directory listing from the backend server to give to the frontend 4 | client. Thus we'll need some dirlist-parsing code. 5 | 6 | Here's a fun one, from the lftp changes: 7 | 8 | fixed MLSD parsing for semicolons in file names. 9 | 10 | See: 11 | 12 | http://lftp.yar.ru/news.html 13 | 14 | Maybe lftp has MLSD parsing code to reuse? 15 | 16 | It does indeed; see lftp-N.N.N/src/FtpListInfo.{h,cc}. Purportedly parses 17 | Unix, MLSD, OS/2, NT, AS400, and EPLF. Could write proxy module that does 18 | this. Note that FtpListInfo iterates through list of parsers to find the one 19 | which handles the current format; do same, but remember the parser which 20 | worked, per session/connection, so that such iteration isn't necessary 21 | per-dirlist. 22 | -------------------------------------------------------------------------------- /include/proxy/ssh/poly1305.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Public Domain poly1305 from Andrew Moon 3 | * poly1305-donna-unrolled.c from https://github.com/floodyberry/poly1305-donna 4 | */ 5 | 6 | #ifndef POLY1305_H 7 | #define POLY1305_H 8 | 9 | #include "mod_proxy.h" 10 | 11 | #if defined(HAVE_EVP_CHACHA20_OPENSSL) && \ 12 | !defined(HAVE_BROKEN_CHACHA20) 13 | #include 14 | 15 | #define POLY1305_KEYLEN 32 16 | #define POLY1305_TAGLEN 16 17 | 18 | void poly1305_auth(u_char out[POLY1305_TAGLEN], const u_char *m, size_t inlen, 19 | const u_char key[POLY1305_KEYLEN]) 20 | __attribute__((__bounded__(__minbytes__, 1, POLY1305_TAGLEN))) 21 | __attribute__((__bounded__(__buffer__, 2, 3))) 22 | __attribute__((__bounded__(__minbytes__, 4, POLY1305_KEYLEN))); 23 | 24 | #endif /* HAVE_EVP_CHACHA20_OPENSSL and !HAVE_BROKEN_CHACHA20 */ 25 | #endif /* POLY1305_H */ 26 | -------------------------------------------------------------------------------- /.codeql.yml: -------------------------------------------------------------------------------- 1 | --- 2 | query-filters: 3 | - exclude: 4 | # See: https://codeql.github.com/codeql-query-help/cpp/cpp-commented-out-code/ 5 | id: cpp/commented-out-code 6 | - exclude: 7 | # See: https://codeql.github.com/codeql-query-help/cpp/cpp-long-switch/ 8 | id: cpp/long-switch 9 | - exclude: 10 | # See: https://codeql.github.com/codeql-query-help/cpp/cpp-empty-if/ 11 | id: cpp/empty-if 12 | - exclude: 13 | # See: https://codeql.github.com/codeql-query-help/cpp/cpp-loop-variable-changed/ 14 | id: cpp/loop-variable-changed 15 | - exclude: 16 | # See: https://codeql.github.com/codeql-query-help/cpp/cpp-missing-check-scanf/ 17 | id: cpp/missing-check-scanf 18 | - exclude: 19 | # See: https://codeql.github.com/codeql-query-help/cpp/cpp-poorly-documented-function/ 20 | id: cpp/poorly-documented-function 21 | 22 | paths: 23 | - contrib/mod_proxy 24 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | proftpd-mod_proxy 2 | ================= 3 | 4 | Status 5 | ------ 6 | [![GitHub Actions CI Status](https://github.com/Castaglia/proftpd-mod_proxy/actions/workflows/ci.yml/badge.svg?branch=master)](https://github.com/Castaglia/proftpd-mod_proxy/actions/workflows/ci.yml) 7 | [![CodeQL Analysis](https://github.com/Castaglia/proftpd-mod_proxy/actions/workflows/codeql.yml/badge.svg)](https://github.com/Castaglia/proftpd-mod_proxy/actions/workflows/codeql.yml) 8 | [![License](https://img.shields.io/badge/license-GPL-brightgreen.svg)](https://img.shields.io/badge/license-GPL-brightgreen.svg) 9 | 10 | 11 | Synopsis 12 | -------- 13 | 14 | The `mod_proxy` module for ProFTPD proxies FTP/FTPS connections, supporting 15 | both forward and reverse proxy configurations. 16 | 17 | See the [mod_proxy.html](https://htmlpreview.github.io/?https://github.com/Castaglia/proftpd-mod_proxy/blob/master/mod_proxy.html) documentation for more details. 18 | -------------------------------------------------------------------------------- /include/proxy/str.h: -------------------------------------------------------------------------------- 1 | /* 2 | * ProFTPD - mod_proxy String API 3 | * Copyright (c) 2020 TJ Saunders 4 | * 5 | * This program is free software; you can redistribute it and/or modify 6 | * it under the terms of the GNU General Public License as published by 7 | * the Free Software Foundation; either version 2 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * This program is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU General Public License 16 | * along with this program; if not, write to the Free Software 17 | * Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA. 18 | * 19 | * As a special exemption, TJ Saunders and other respective copyright holders 20 | * give permission to link this program with OpenSSL, and distribute the 21 | * resulting executable, without including the source code for OpenSSL in the 22 | * source distribution. 23 | */ 24 | 25 | #ifndef MOD_PROXY_STR_H 26 | #define MOD_PROXY_STR_H 27 | 28 | #include "mod_proxy.h" 29 | 30 | char *proxy_strnstr(const char *s1, const char *s2, size_t len); 31 | 32 | #endif /* MOD_PROXY_STR_H */ 33 | -------------------------------------------------------------------------------- /include/proxy/uri.h: -------------------------------------------------------------------------------- 1 | /* 2 | * ProFTPD - mod_proxy URI API 3 | * Copyright (c) 2012-2016 TJ Saunders 4 | * 5 | * This program is free software; you can redistribute it and/or modify 6 | * it under the terms of the GNU General Public License as published by 7 | * the Free Software Foundation; either version 2 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * This program is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU General Public License 16 | * along with this program; if not, write to the Free Software 17 | * Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA. 18 | * 19 | * As a special exemption, TJ Saunders and other respective copyright holders 20 | * give permission to link this program with OpenSSL, and distribute the 21 | * resulting executable, without including the source code for OpenSSL in the 22 | * source distribution. 23 | */ 24 | 25 | #ifndef MOD_PROXY_URI_H 26 | #define MOD_PROXY_URI_H 27 | 28 | #include "mod_proxy.h" 29 | 30 | int proxy_uri_parse(pool *p, const char *uri, char **scheme, char **host, 31 | unsigned int *port, char **username, char **password); 32 | 33 | #endif /* MOD_PROXY_URI_H */ 34 | -------------------------------------------------------------------------------- /include/proxy/tls/db.h: -------------------------------------------------------------------------------- 1 | /* 2 | * ProFTPD - mod_proxy TLS Database API 3 | * Copyright (c) 2017 TJ Saunders 4 | * 5 | * This program is free software; you can redistribute it and/or modify 6 | * it under the terms of the GNU General Public License as published by 7 | * the Free Software Foundation; either version 2 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * This program is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU General Public License 16 | * along with this program; if not, write to the Free Software 17 | * Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA. 18 | * 19 | * As a special exemption, TJ Saunders and other respective copyright holders 20 | * give permission to link this program with OpenSSL, and distribute the 21 | * resulting executable, without including the source code for OpenSSL in the 22 | * source distribution. 23 | */ 24 | 25 | #ifndef MOD_PROXY_TLS_DB_H 26 | #define MOD_PROXY_TLS_DB_H 27 | 28 | #include "mod_proxy.h" 29 | #include "proxy/tls.h" 30 | 31 | int proxy_tls_db_as_datastore(struct proxy_tls_datastore *ds, void *ds_data, 32 | size_t ds_datasz); 33 | 34 | #endif /* MOD_PROXY_TLS_DB_H */ 35 | -------------------------------------------------------------------------------- /include/proxy/ssh/db.h: -------------------------------------------------------------------------------- 1 | /* 2 | * ProFTPD - mod_proxy SSH Database API 3 | * Copyright (c) 2021-2025 TJ Saunders 4 | * 5 | * This program is free software; you can redistribute it and/or modify 6 | * it under the terms of the GNU General Public License as published by 7 | * the Free Software Foundation; either version 2 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * This program is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU General Public License 16 | * along with this program; if not, write to the Free Software 17 | * Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA. 18 | * 19 | * As a special exemption, TJ Saunders and other respective copyright holders 20 | * give permission to link this program with OpenSSL, and distribute the 21 | * resulting executable, without including the source code for OpenSSL in the 22 | * source distribution. 23 | */ 24 | 25 | #ifndef MOD_PROXY_SSH_DB_H 26 | #define MOD_PROXY_SSH_DB_H 27 | 28 | #include "mod_proxy.h" 29 | #include "proxy/ssh.h" 30 | 31 | int proxy_ssh_db_as_datastore(struct proxy_ssh_datastore *ds, void *ds_data, 32 | size_t ds_datasz); 33 | 34 | #endif /* MOD_PROXY_SSH_DB_H */ 35 | -------------------------------------------------------------------------------- /include/proxy/ssh/redis.h: -------------------------------------------------------------------------------- 1 | /* 2 | * ProFTPD - mod_proxy SSH Redis API 3 | * Copyright (c) 2022 TJ Saunders 4 | * 5 | * This program is free software; you can redistribute it and/or modify 6 | * it under the terms of the GNU General Public License as published by 7 | * the Free Software Foundation; either version 2 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * This program is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU General Public License 16 | * along with this program; if not, write to the Free Software 17 | * Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA. 18 | * 19 | * As a special exemption, TJ Saunders and other respective copyright holders 20 | * give permission to link this program with OpenSSL, and distribute the 21 | * resulting executable, without including the source code for OpenSSL in the 22 | * source distribution. 23 | */ 24 | 25 | #ifndef MOD_PROXY_SSH_REDIS_H 26 | #define MOD_PROXY_SSH_REDIS_H 27 | 28 | #include "mod_proxy.h" 29 | #include "proxy/ssh.h" 30 | 31 | int proxy_ssh_redis_as_datastore(struct proxy_ssh_datastore *ds, void *ds_data, 32 | size_t ds_datasz); 33 | 34 | #endif /* MOD_PROXY_SSH_REDIS_H */ 35 | -------------------------------------------------------------------------------- /include/proxy/tls/redis.h: -------------------------------------------------------------------------------- 1 | /* 2 | * ProFTPD - mod_proxy TLS Redis API 3 | * Copyright (c) 2017 TJ Saunders 4 | * 5 | * This program is free software; you can redistribute it and/or modify 6 | * it under the terms of the GNU General Public License as published by 7 | * the Free Software Foundation; either version 2 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * This program is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU General Public License 16 | * along with this program; if not, write to the Free Software 17 | * Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA. 18 | * 19 | * As a special exemption, TJ Saunders and other respective copyright holders 20 | * give permission to link this program with OpenSSL, and distribute the 21 | * resulting executable, without including the source code for OpenSSL in the 22 | * source distribution. 23 | */ 24 | 25 | #ifndef MOD_PROXY_TLS_REDIS_H 26 | #define MOD_PROXY_TLS_REDIS_H 27 | 28 | #include "mod_proxy.h" 29 | #include "proxy/tls.h" 30 | 31 | int proxy_tls_redis_as_datastore(struct proxy_tls_datastore *ds, void *ds_data, 32 | size_t ds_datasz); 33 | 34 | #endif /* MOD_PROXY_TLS_REDIS_H */ 35 | -------------------------------------------------------------------------------- /include/proxy/reverse/db.h: -------------------------------------------------------------------------------- 1 | /* 2 | * ProFTPD - mod_proxy Reverse Database API 3 | * Copyright (c) 2017 TJ Saunders 4 | * 5 | * This program is free software; you can redistribute it and/or modify 6 | * it under the terms of the GNU General Public License as published by 7 | * the Free Software Foundation; either version 2 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * This program is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU General Public License 16 | * along with this program; if not, write to the Free Software 17 | * Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA. 18 | * 19 | * As a special exemption, TJ Saunders and other respective copyright holders 20 | * give permission to link this program with OpenSSL, and distribute the 21 | * resulting executable, without including the source code for OpenSSL in the 22 | * source distribution. 23 | */ 24 | 25 | #ifndef MOD_PROXY_REVERSE_DB_H 26 | #define MOD_PROXY_REVERSE_DB_H 27 | 28 | #include "mod_proxy.h" 29 | #include "proxy/reverse.h" 30 | 31 | int proxy_reverse_db_as_datastore(struct proxy_reverse_datastore *ds, 32 | void *ds_data, size_t ds_datasz); 33 | 34 | #endif /* MOD_PROXY_REVERSE_DB_H */ 35 | -------------------------------------------------------------------------------- /include/proxy/ssh/misc.h: -------------------------------------------------------------------------------- 1 | /* 2 | * ProFTPD - mod_proxy SSH miscellany API 3 | * Copyright (c) 2021-2025 TJ Saunders 4 | * 5 | * This program is free software; you can redistribute it and/or modify 6 | * it under the terms of the GNU General Public License as published by 7 | * the Free Software Foundation; either version 2 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * This program is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU General Public License 16 | * along with this program; if not, write to the Free Software 17 | * Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA. 18 | * 19 | * As a special exemption, TJ Saunders and other respective copyright holders 20 | * give permission to link this program with OpenSSL, and distribute the 21 | * resulting executable, without including the source code for OpenSSL in the 22 | * source distribution. 23 | */ 24 | 25 | #ifndef MOD_PROXY_SSH_MISC_H 26 | #define MOD_PROXY_SSH_MISC_H 27 | 28 | #include "mod_proxy.h" 29 | 30 | int proxy_ssh_misc_namelist_contains(pool *, const char *, const char *); 31 | const char *proxy_ssh_misc_namelist_shared(pool *, const char *, const char *); 32 | 33 | #endif /* MOD_PROXY_SSH_MISC_H */ 34 | -------------------------------------------------------------------------------- /include/proxy/random.h: -------------------------------------------------------------------------------- 1 | /* 2 | * ProFTPD - mod_proxy random number API 3 | * Copyright (c) 2013-2016 TJ Saunders 4 | * 5 | * This program is free software; you can redistribute it and/or modify 6 | * it under the terms of the GNU General Public License as published by 7 | * the Free Software Foundation; either version 2 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * This program is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU General Public License 16 | * along with this program; if not, write to the Free Software 17 | * Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA. 18 | * 19 | * As a special exemption, TJ Saunders and other respective copyright holders 20 | * give permission to link this program with OpenSSL, and distribute the 21 | * resulting executable, without including the source code for OpenSSL in the 22 | * source distribution. 23 | */ 24 | 25 | #ifndef MOD_PROXY_RANDOM_H 26 | #define MOD_PROXY_RANDOM_H 27 | 28 | #include "mod_proxy.h" 29 | 30 | int proxy_random_init(void); 31 | 32 | /* Return the next random number between the given min/max numbers, inclusive. 33 | */ 34 | long proxy_random_next(long min, long max); 35 | 36 | #endif /* MOD_PROXY_RANDOM_H */ 37 | -------------------------------------------------------------------------------- /include/proxy/ssh/service.h: -------------------------------------------------------------------------------- 1 | /* 2 | * ProFTPD - mod_proxy SSH service API 3 | * Copyright (c) 2021-2025 TJ Saunders 4 | * 5 | * This program is free software; you can redistribute it and/or modify 6 | * it under the terms of the GNU General Public License as published by 7 | * the Free Software Foundation; either version 2 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * This program is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU General Public License 16 | * along with this program; if not, write to the Free Software 17 | * Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA. 18 | * 19 | * As a special exemption, TJ Saunders and other respective copyright holders 20 | * give permission to link this program with OpenSSL, and distribute the 21 | * resulting executable, without including the source code for OpenSSL in the 22 | * source distribution. 23 | */ 24 | 25 | #ifndef MOD_PROXY_SSH_SERVICE_H 26 | #define MOD_PROXY_SSH_SERVICE_H 27 | 28 | #include "mod_proxy.h" 29 | #include "proxy/session.h" 30 | #include "proxy/ssh/packet.h" 31 | 32 | int proxy_ssh_service_handle(struct proxy_ssh_packet *, 33 | const struct proxy_session *); 34 | 35 | #endif /* MOD_PROXY_SSH_SERVICE_H */ 36 | -------------------------------------------------------------------------------- /include/proxy/ftp/data.h: -------------------------------------------------------------------------------- 1 | /* 2 | * ProFTPD - mod_proxy FTP data conn API 3 | * Copyright (c) 2012-2016 TJ Saunders 4 | * 5 | * This program is free software; you can redistribute it and/or modify 6 | * it under the terms of the GNU General Public License as published by 7 | * the Free Software Foundation; either version 2 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * This program is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU General Public License 16 | * along with this program; if not, write to the Free Software 17 | * Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA. 18 | * 19 | * As a special exemption, TJ Saunders and other respective copyright holders 20 | * give permission to link this program with OpenSSL, and distribute the 21 | * resulting executable, without including the source code for OpenSSL in the 22 | * source distribution. 23 | */ 24 | 25 | #ifndef MOD_PROXY_FTP_DATA_H 26 | #define MOD_PROXY_FTP_DATA_H 27 | 28 | #include "mod_proxy.h" 29 | 30 | pr_buffer_t *proxy_ftp_data_recv(pool *p, conn_t *conn, int frontend_data); 31 | int proxy_ftp_data_send(pool *p, conn_t *conn, pr_buffer_t *pbuf, 32 | int frontend_data); 33 | 34 | #endif /* MOD_PROXY_FTP_DATA_H */ 35 | -------------------------------------------------------------------------------- /include/proxy/reverse/redis.h: -------------------------------------------------------------------------------- 1 | /* 2 | * ProFTPD - mod_proxy Reverse Redis API 3 | * Copyright (c) 2017-2020 TJ Saunders 4 | * 5 | * This program is free software; you can redistribute it and/or modify 6 | * it under the terms of the GNU General Public License as published by 7 | * the Free Software Foundation; either version 2 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * This program is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU General Public License 16 | * along with this program; if not, write to the Free Software 17 | * Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA. 18 | * 19 | * As a special exemption, TJ Saunders and other respective copyright holders 20 | * give permission to link this program with OpenSSL, and distribute the 21 | * resulting executable, without including the source code for OpenSSL in the 22 | * source distribution. 23 | */ 24 | 25 | #ifndef MOD_PROXY_REVERSE_REDIS_H 26 | #define MOD_PROXY_REVERSE_REDIS_H 27 | 28 | #include "mod_proxy.h" 29 | #include "proxy/reverse.h" 30 | #include "proxy/reverse/redis.h" 31 | 32 | int proxy_reverse_redis_as_datastore(struct proxy_reverse_datastore *ds, 33 | void *ds_data, size_t ds_datasz); 34 | 35 | #endif /* MOD_PROXY_REVERSE_REDIS_H */ 36 | -------------------------------------------------------------------------------- /include/proxy/ssh/bcrypt.h: -------------------------------------------------------------------------------- 1 | /* 2 | * ProFTPD - mod_proxy SSH bcrypt PBKDF2 3 | * Copyright (c) 2021-2025 TJ Saunders 4 | * 5 | * This program is free software; you can redistribute it and/or modify 6 | * it under the terms of the GNU General Public License as published by 7 | * the Free Software Foundation; either version 2 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * This program is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU General Public License 16 | * along with this program; if not, write to the Free Software 17 | * Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA. 18 | * 19 | * As a special exemption, TJ Saunders and other respective copyright holders 20 | * give permission to link this program with OpenSSL, and distribute the 21 | * resulting executable, without including the source code for OpenSSL in the 22 | * source distribution. 23 | */ 24 | 25 | #ifndef MOD_PROXY_SSH_BCRYPT_H 26 | #define MOD_PROXY_SSH_BCRYPT_H 27 | 28 | #include "mod_proxy.h" 29 | 30 | #define PROXY_SSH_BCRYPT_DIGEST_LEN 32 31 | 32 | int proxy_ssh_bcrypt_pbkdf2(pool *p, const char *passphrase, 33 | size_t passphrase_len, unsigned char *salt, uint32_t salt_len, 34 | uint32_t rounds, unsigned char *key, uint32_t key_len); 35 | 36 | #endif /* MOD_PROXY_SSH_BCRYPT_H */ 37 | -------------------------------------------------------------------------------- /include/proxy/ftp/xfer.h: -------------------------------------------------------------------------------- 1 | /* 2 | * ProFTPD - mod_proxy FTP data transfer API 3 | * Copyright (c) 2013-2016 TJ Saunders 4 | * 5 | * This program is free software; you can redistribute it and/or modify 6 | * it under the terms of the GNU General Public License as published by 7 | * the Free Software Foundation; either version 2 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * This program is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU General Public License 16 | * along with this program; if not, write to the Free Software 17 | * Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA. 18 | * 19 | * As a special exemption, TJ Saunders and other respective copyright holders 20 | * give permission to link this program with OpenSSL, and distribute the 21 | * resulting executable, without including the source code for OpenSSL in the 22 | * source distribution. 23 | */ 24 | 25 | #ifndef MOD_PROXY_FTP_XFER_H 26 | #define MOD_PROXY_FTP_XFER_H 27 | 28 | #include "mod_proxy.h" 29 | #include "proxy/session.h" 30 | 31 | int proxy_ftp_xfer_prepare_active(int, cmd_rec *, const char *, 32 | struct proxy_session *, int); 33 | const pr_netaddr_t *proxy_ftp_xfer_prepare_passive(int, cmd_rec *, const char *, 34 | struct proxy_session *, int); 35 | 36 | #endif /* MOD_PROXY_FTP_XFER_H */ 37 | -------------------------------------------------------------------------------- /include/proxy/ssh/session.h: -------------------------------------------------------------------------------- 1 | /* 2 | * ProFTPD - mod_proxy SSH session API 3 | * Copyright (c) 2021-2025 TJ Saunders 4 | * 5 | * This program is free software; you can redistribute it and/or modify 6 | * it under the terms of the GNU General Public License as published by 7 | * the Free Software Foundation; either version 2 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * This program is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU General Public License 16 | * along with this program; if not, write to the Free Software 17 | * Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA. 18 | * 19 | * As a special exemption, TJ Saunders and other respective copyright holders 20 | * give permission to link this program with OpenSSL, and distribute the 21 | * resulting executable, without including the source code for OpenSSL in the 22 | * source distribution. 23 | */ 24 | 25 | #ifndef MOD_PROXY_SSH_SESSION_H 26 | #define MOD_PROXY_SSH_SESSION_H 27 | 28 | #include "mod_proxy.h" 29 | 30 | uint32_t proxy_ssh_session_get_id(const unsigned char **); 31 | 32 | /* Note that the provided pool must have the same lifetime as that of the 33 | * entire SSH session, e.g. proxy_pool or similar. 34 | */ 35 | int proxy_ssh_session_set_id(pool *p, const unsigned char *, uint32_t); 36 | 37 | #endif /* MOD_PROXY_SSH_SESSION_H */ 38 | -------------------------------------------------------------------------------- /include/proxy/ssh/utf8.h: -------------------------------------------------------------------------------- 1 | /* 2 | * ProFTPD - mod_proxy SSH UTF8 API 3 | * Copyright (c) 2021-2025 TJ Saunders 4 | * 5 | * This program is free software; you can redistribute it and/or modify 6 | * it under the terms of the GNU General Public License as published by 7 | * the Free Software Foundation; either version 2 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * This program is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU General Public License 16 | * along with this program; if not, write to the Free Software 17 | * Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA. 18 | * 19 | * As a special exemption, TJ Saunders and other respective copyright holders 20 | * give permission to link this program with OpenSSL, and distribute the 21 | * resulting executable, without including the source code for OpenSSL in the 22 | * source distribution. 23 | */ 24 | 25 | #ifndef MOD_PROXY_SSH_UTF8_H 26 | #define MOD_PROXY_SSH_UTF8_H 27 | 28 | char *proxy_ssh_utf8_decode_text(pool *p, const char *text); 29 | char *proxy_ssh_utf8_encode_text(pool *p, const char *text); 30 | 31 | /* Set the local charset to use explicitly, rather than relying on 32 | * nl_langinfo(3). 33 | */ 34 | int proxy_ssh_utf8_set_charset(const char *charset); 35 | 36 | int proxy_ssh_utf8_init(void); 37 | int proxy_ssh_utf8_free(void); 38 | 39 | #endif /* MOD_PROXY_SSH_UTF8_H */ 40 | -------------------------------------------------------------------------------- /include/proxy/ftp/conn.h: -------------------------------------------------------------------------------- 1 | /* 2 | * ProFTPD - mod_proxy FTP connection API 3 | * Copyright (c) 2013-2016 TJ Saunders 4 | * 5 | * This program is free software; you can redistribute it and/or modify 6 | * it under the terms of the GNU General Public License as published by 7 | * the Free Software Foundation; either version 2 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * This program is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU General Public License 16 | * along with this program; if not, write to the Free Software 17 | * Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA. 18 | * 19 | * As a special exemption, TJ Saunders and other respective copyright holders 20 | * give permission to link this program with OpenSSL, and distribute the 21 | * resulting executable, without including the source code for OpenSSL in the 22 | * source distribution. 23 | */ 24 | 25 | #ifndef MOD_PROXY_FTP_CONN_H 26 | #define MOD_PROXY_FTP_CONN_H 27 | 28 | #include "mod_proxy.h" 29 | 30 | conn_t *proxy_ftp_conn_accept(pool *p, conn_t *data_conn, conn_t *ctrl_conn, 31 | int frontend_data); 32 | conn_t *proxy_ftp_conn_connect(pool *p, const pr_netaddr_t *local_addr, 33 | const pr_netaddr_t *remote_addr, int frontend_data); 34 | conn_t *proxy_ftp_conn_listen(pool *p, const pr_netaddr_t *bind_addr, 35 | int frontend_data); 36 | 37 | #endif /* MOD_PROXY_FTP_CONN_H */ 38 | -------------------------------------------------------------------------------- /.clang-tidy: -------------------------------------------------------------------------------- 1 | Checks: ' 2 | *, 3 | -altera-*, 4 | -android-*, 5 | bugprone-*, 6 | -bugprone-branch-clone, 7 | -bugprone-easily-swappable-parameters, 8 | -bugprone-integer-division, 9 | -bugprone-macro-parentheses, 10 | -bugprone-narrowing-conversions, 11 | cert-*, 12 | -cert-err33-c, 13 | -cert-err34-c, 14 | -cert-msc30-c, 15 | -cert-msc50-cpp, 16 | clang-analyzer-*, 17 | -clang-analyzer-security.insecureAPI.DeprecatedOrUnsafeBufferHandling, 18 | -clang-analyzer-valist.Uninitialized, 19 | -concurrency-mt-unsafe, 20 | -cppcoreguidelines-avoid-magic-numbers, 21 | -cppcoreguidelines-avoid-non-const-global-variables, 22 | -cppcoreguidelines-init-variables, 23 | -cppcoreguidelines-narrowing-conversions, 24 | -google-readability-casting, 25 | -hicpp-signed-bitwise, 26 | llvm-*, 27 | -llvm-include-order, 28 | -llvmlibc-restrict-system-libc-headers, 29 | misc-*, 30 | -misc-redundant-expression, 31 | -misc-unused-parameters, 32 | modernize-*, 33 | -modernize-avoid-c-arrays, 34 | -modernize-deprecated-headers, 35 | -modernize-loop-convert, 36 | -modernize-use-auto, 37 | -modernize-use-nullptr, 38 | -modernize-use-trailing-return-type, 39 | -modernize-use-using, 40 | performance-*, 41 | portability-*, 42 | readability-*, 43 | -readability-function-cognitive-complexity, 44 | -readability-function-size, 45 | -readability-identifier-length, 46 | -readability-implicit-bool-conversion, 47 | -readability-inconsistent-declaration-parameter-name, 48 | -readability-isolate-declaration, 49 | -readability-magic-numbers, 50 | -readability-simplify-boolean-expr' 51 | -------------------------------------------------------------------------------- /lib/proxy/ssh/umac128.c: -------------------------------------------------------------------------------- 1 | /* 2 | * ProFTPD - mod_proxy SSH UMAC 3 | * Copyright (c) 2022 TJ Saunders 4 | * 5 | * This program is free software; you can redistribute it and/or modify 6 | * it under the terms of the GNU General Public License as published by 7 | * the Free Software Foundation; either version 2 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * This program is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU General Public License 16 | * along with this program; if not, write to the Free Software 17 | * Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA. 18 | * 19 | * As a special exemption, TJ Saunders and other respective copyright holders 20 | * give permission to link this program with OpenSSL, and distribute the 21 | * resulting executable, without including the source code for OpenSSL in the 22 | * source distribution. 23 | */ 24 | 25 | #include "mod_proxy.h" 26 | #include "proxy/ssh/umac.h" 27 | 28 | #define UMAC_OUTPUT_LEN 16 29 | 30 | #define proxy_ssh_umac_alloc proxy_ssh_umac128_alloc 31 | #define proxy_ssh_umac_init proxy_ssh_umac128_init 32 | #define proxy_ssh_umac_new proxy_ssh_umac128_new 33 | #define proxy_ssh_umac_update proxy_ssh_umac128_update 34 | #define proxy_ssh_umac_reset proxy_ssh_umac128_reset 35 | #define proxy_ssh_umac_final proxy_ssh_umac128_final 36 | #define proxy_ssh_umac_delete proxy_ssh_umac128_delete 37 | #define proxy_ssh_umac_ctx proxy_ssh_umac128_ctx 38 | 39 | #include "umac.c" 40 | -------------------------------------------------------------------------------- /include/proxy/ssh/agent.h: -------------------------------------------------------------------------------- 1 | /* 2 | * ProFTPD - mod_proxy SSH agent API 3 | * Copyright (c) 2021-2025 TJ Saunders 4 | * 5 | * This program is free software; you can redistribute it and/or modify 6 | * it under the terms of the GNU General Public License as published by 7 | * the Free Software Foundation; either version 2 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * This program is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU General Public License 16 | * along with this program; if not, write to the Free Software 17 | * Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA. 18 | * 19 | * As a special exemption, TJ Saunders and other respective copyright holders 20 | * give permission to link this program with OpenSSL, and distribute the 21 | * resulting executable, without including the source code for OpenSSL in the 22 | * source distribution. 23 | */ 24 | 25 | #ifndef MOD_PROXY_SSH_AGENT_H 26 | #define MOD_PROXY_SSH_AGENT_H 27 | 28 | #include "mod_proxy.h" 29 | 30 | struct agent_key { 31 | unsigned char *key_data; 32 | uint32_t key_datalen; 33 | const char *agent_path; 34 | }; 35 | 36 | int proxy_ssh_agent_get_keys(pool *p, const char *, array_header *); 37 | const unsigned char *proxy_ssh_agent_sign_data(pool *, const char *, 38 | const unsigned char *, uint32_t, const unsigned char *, uint32_t, uint32_t *, 39 | int); 40 | 41 | #define PROXY_SSH_AGENT_SIGN_FL_USE_RSA_SHA256 0x001 42 | #define PROXY_SSH_AGENT_SIGN_FL_USE_RSA_SHA512 0x002 43 | 44 | #endif /* MOD_PROXY_SSH_AGENT_H */ 45 | -------------------------------------------------------------------------------- /include/proxy/ssh/crypto.h: -------------------------------------------------------------------------------- 1 | /* 2 | * ProFTPD - mod_proxy SSH crypto API 3 | * Copyright (c) 2021-2025 TJ Saunders 4 | * 5 | * This program is free software; you can redistribute it and/or modify 6 | * it under the terms of the GNU General Public License as published by 7 | * the Free Software Foundation; either version 2 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * This program is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU General Public License 16 | * along with this program; if not, write to the Free Software 17 | * Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA. 18 | * 19 | * As a special exemption, TJ Saunders and other respective copyright holders 20 | * give permission to link this program with OpenSSL, and distribute the 21 | * resulting executable, without including the source code for OpenSSL in the 22 | * source distribution. 23 | */ 24 | 25 | #ifndef MOD_PROXY_SSH_CRYPTO_H 26 | #define MOD_PROXY_SSH_CRYPTO_H 27 | 28 | #include "mod_proxy.h" 29 | 30 | #include 31 | 32 | void proxy_ssh_crypto_free(int flags); 33 | const EVP_CIPHER *proxy_ssh_crypto_get_cipher(const char *algo, size_t *key_len, 34 | size_t *auth_len, size_t *discard_len); 35 | const EVP_MD *proxy_ssh_crypto_get_digest(const char *algo, uint32_t *mac_len); 36 | const char *proxy_ssh_crypto_get_kexinit_cipher_list(pool *p); 37 | const char *proxy_ssh_crypto_get_kexinit_digest_list(pool *p); 38 | 39 | const char *proxy_ssh_crypto_get_errors(void); 40 | size_t proxy_ssh_crypto_get_size(size_t, size_t); 41 | 42 | #endif /* MOD_PROXY_SSH_CRYPTO_H */ 43 | -------------------------------------------------------------------------------- /include/proxy/inet.h: -------------------------------------------------------------------------------- 1 | /* 2 | * ProFTPD - mod_proxy Inet API 3 | * Copyright (c) 2015-2016 TJ Saunders 4 | * 5 | * This program is free software; you can redistribute it and/or modify 6 | * it under the terms of the GNU General Public License as published by 7 | * the Free Software Foundation; either version 2 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * This program is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU General Public License 16 | * along with this program; if not, write to the Free Software 17 | * Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA. 18 | * 19 | * As a special exemption, TJ Saunders and other respective copyright holders 20 | * give permission to link this program with OpenSSL, and distribute the 21 | * resulting executable, without including the source code for OpenSSL in the 22 | * source distribution. 23 | */ 24 | 25 | #ifndef MOD_PROXY_INET_H 26 | #define MOD_PROXY_INET_H 27 | 28 | #include "mod_proxy.h" 29 | 30 | /* Proxied versions of the core Inet API functions; see include/inet.h. */ 31 | 32 | conn_t *proxy_inet_accept(pool *p, conn_t *data_conn, conn_t *ctrl_conn, 33 | int rfd, int wfd, int resolve); 34 | 35 | void proxy_inet_close(pool *p, conn_t *conn); 36 | 37 | int proxy_inet_connect(pool *p, conn_t *conn, const pr_netaddr_t *addr, 38 | int port); 39 | 40 | int proxy_inet_listen(pool *p, conn_t *conn, int backlog, int flags); 41 | 42 | conn_t *proxy_inet_openrw(pool *p, conn_t *conn, const pr_netaddr_t *addr, 43 | int strm_type, int fd, int rfd, int wfd, int resolve); 44 | 45 | #endif /* MOD_PROXY_INET_H */ 46 | -------------------------------------------------------------------------------- /include/proxy/ssh/auth.h: -------------------------------------------------------------------------------- 1 | /* 2 | * ProFTPD - mod_proxy SSH auth API 3 | * Copyright (c) 2021-2025 TJ Saunders 4 | * 5 | * This program is free software; you can redistribute it and/or modify 6 | * it under the terms of the GNU General Public License as published by 7 | * the Free Software Foundation; either version 2 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * This program is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU General Public License 16 | * along with this program; if not, write to the Free Software 17 | * Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA. 18 | * 19 | * As a special exemption, TJ Saunders and other respective copyright holders 20 | * give permission to link this program with OpenSSL, and distribute the 21 | * resulting executable, without including the source code for OpenSSL in the 22 | * source distribution. 23 | */ 24 | 25 | #ifndef MOD_PROXY_SSH_AUTH_H 26 | #define MOD_PROXY_SSH_AUTH_H 27 | 28 | #include "mod_proxy.h" 29 | #include "proxy/session.h" 30 | #include "proxy/ssh/packet.h" 31 | 32 | int proxy_ssh_auth_init(pool *p); 33 | int proxy_ssh_auth_sess_init(pool *p, const struct proxy_session *proxy_sess); 34 | 35 | /* Returns 1 for successfully completed authentication, 0 if the client 36 | * needs to make another authentication attempt, and -1 on error. 37 | */ 38 | int proxy_ssh_auth_handle(struct proxy_ssh_packet *pkt, 39 | const struct proxy_session *proxy_sess); 40 | 41 | int proxy_ssh_auth_set_frontend_success_handle(pool *p, int (*cb)(pool *p, 42 | const char *user)); 43 | 44 | #endif /* MOD_PROXY_SSH_AUTH_H */ 45 | -------------------------------------------------------------------------------- /include/proxy/ftp/sess.h: -------------------------------------------------------------------------------- 1 | /* 2 | * ProFTPD - mod_proxy FTP session API 3 | * Copyright (c) 2015-2021 TJ Saunders 4 | * 5 | * This program is free software; you can redistribute it and/or modify 6 | * it under the terms of the GNU General Public License as published by 7 | * the Free Software Foundation; either version 2 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * This program is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU General Public License 16 | * along with this program; if not, write to the Free Software 17 | * Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA. 18 | * 19 | * As a special exemption, TJ Saunders and other respective copyright holders 20 | * give permission to link this program with OpenSSL, and distribute the 21 | * resulting executable, without including the source code for OpenSSL in the 22 | * source distribution. 23 | */ 24 | 25 | #ifndef MOD_PROXY_FTP_SESS_H 26 | #define MOD_PROXY_FTP_SESS_H 27 | 28 | #include "mod_proxy.h" 29 | #include "proxy/session.h" 30 | 31 | /* ProxyTLSTransferProtectionPolicy values */ 32 | #define PROXY_FTP_SESS_TLS_XFER_PROTECTION_POLICY_REQUIRED 1 33 | #define PROXY_FTP_SESS_TLS_XFER_PROTECTION_POLICY_CLIENT 0 34 | #define PROXY_FTP_SESS_TLS_XFER_PROTECTION_POLICY_CLEAR -1 35 | 36 | int proxy_ftp_sess_get_feat(pool *, const struct proxy_session *proxy_sess); 37 | int proxy_ftp_sess_send_auth_tls(pool *p, 38 | const struct proxy_session *proxy_sess); 39 | int proxy_ftp_sess_send_host(pool *, const struct proxy_session *proxy_sess); 40 | int proxy_ftp_sess_send_pbsz_prot(pool *p, 41 | const struct proxy_session *proxy_sess); 42 | 43 | #endif /* MOD_PROXY_FTP_SESS_H */ 44 | -------------------------------------------------------------------------------- /include/proxy/ssh/compress.h: -------------------------------------------------------------------------------- 1 | /* 2 | * ProFTPD - mod_proxy SSH compression API 3 | * Copyright (c) 2021-2025 TJ Saunders 4 | * 5 | * This program is free software; you can redistribute it and/or modify 6 | * it under the terms of the GNU General Public License as published by 7 | * the Free Software Foundation; either version 2 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * This program is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU General Public License 16 | * along with this program; if not, write to the Free Software 17 | * Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA. 18 | * 19 | * As a special exemption, TJ Saunders and other respective copyright holders 20 | * give permission to link this program with OpenSSL, and distribute the 21 | * resulting executable, without including the source code for OpenSSL in the 22 | * source distribution. 23 | */ 24 | 25 | #ifndef MOD_PROXY_SSH_COMPRESS_H 26 | #define MOD_PROXY_SSH_COMPRESS_H 27 | 28 | #include "mod_proxy.h" 29 | #include "proxy/ssh/packet.h" 30 | 31 | #define PROXY_SSH_COMPRESS_FL_NEW_KEY 1 32 | #define PROXY_SSH_COMPRESS_FL_AUTHENTICATED 2 33 | 34 | int proxy_ssh_compress_init_read(int); 35 | const char *proxy_ssh_compress_get_read_algo(void); 36 | int proxy_ssh_compress_set_read_algo(pool *p, const char *algo); 37 | int proxy_ssh_compress_read_data(struct proxy_ssh_packet *); 38 | 39 | int proxy_ssh_compress_init_write(int); 40 | const char *proxy_ssh_compress_get_write_algo(void); 41 | int proxy_ssh_compress_set_write_algo(pool *p, const char *algo); 42 | int proxy_ssh_compress_write_data(struct proxy_ssh_packet *); 43 | 44 | #endif /* MOD_PROXY_SSH_COMPRESS_H */ 45 | -------------------------------------------------------------------------------- /include/proxy/ssh/kex.h: -------------------------------------------------------------------------------- 1 | /* 2 | * ProFTPD - mod_proxy SSH kex API 3 | * Copyright (c) 2021-2025 TJ Saunders 4 | * 5 | * This program is free software; you can redistribute it and/or modify 6 | * it under the terms of the GNU General Public License as published by 7 | * the Free Software Foundation; either version 2 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * This program is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU General Public License 16 | * along with this program; if not, write to the Free Software 17 | * Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA. 18 | * 19 | * As a special exemption, TJ Saunders and other respective copyright holders 20 | * give permission to link this program with OpenSSL, and distribute the 21 | * resulting executable, without including the source code for OpenSSL in the 22 | * source distribution. 23 | */ 24 | 25 | #ifndef MOD_PROXY_SSH_KEX_H 26 | #define MOD_PROXY_SSH_KEX_H 27 | 28 | #include "mod_proxy.h" 29 | #include "proxy/session.h" 30 | #include "proxy/ssh.h" 31 | 32 | int proxy_ssh_kex_handle(struct proxy_ssh_packet *pkt, 33 | const struct proxy_session *proxy_sess); 34 | int proxy_ssh_kex_init(pool *p, const char *client_version, 35 | const char *server_version); 36 | int proxy_ssh_kex_free(void); 37 | 38 | int proxy_ssh_kex_sess_init(pool *p, struct proxy_ssh_datastore *ds, 39 | int verify_hostkeys); 40 | int proxy_ssh_kex_sess_free(void); 41 | 42 | int proxy_ssh_kex_send_first_kexinit(pool *p, 43 | const struct proxy_session *proxy_sess); 44 | 45 | #define PROXY_SSH_KEX_DH_GROUP_MIN 1024 46 | #define PROXY_SSH_KEX_DH_GROUP_MAX 8192 47 | 48 | #endif /* MOD_PROXY_SSH_KEX_H */ 49 | -------------------------------------------------------------------------------- /include/proxy/ftp/ctrl.h: -------------------------------------------------------------------------------- 1 | /* 2 | * ProFTPD - mod_proxy FTP control conn API 3 | * Copyright (c) 2012-2023 TJ Saunders 4 | * 5 | * This program is free software; you can redistribute it and/or modify 6 | * it under the terms of the GNU General Public License as published by 7 | * the Free Software Foundation; either version 2 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * This program is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU General Public License 16 | * along with this program; if not, write to the Free Software 17 | * Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA. 18 | * 19 | * As a special exemption, TJ Saunders and other respective copyright holders 20 | * give permission to link this program with OpenSSL, and distribute the 21 | * resulting executable, without including the source code for OpenSSL in the 22 | * source distribution. 23 | */ 24 | 25 | #ifndef MOD_PROXY_FTP_CTRL_H 26 | #define MOD_PROXY_FTP_CTRL_H 27 | 28 | #include "mod_proxy.h" 29 | 30 | /* Note: this flag is only used for testing. */ 31 | #define PROXY_FTP_CTRL_FL_IGNORE_EOF 0x0001 32 | 33 | #define PROXY_FTP_CTRL_FL_IGNORE_BLANK_RESP 0x0002 34 | 35 | int proxy_ftp_ctrl_handle_async(pool *p, conn_t *backend_conn, 36 | conn_t *frontend_conn, int flags); 37 | 38 | pr_response_t *proxy_ftp_ctrl_recv_resp(pool *p, conn_t *ctrl_conn, 39 | unsigned int *resp_nlines, int flags); 40 | int proxy_ftp_ctrl_send_abort(pool *p, conn_t *ctrl_conn, cmd_rec *cmd); 41 | int proxy_ftp_ctrl_send_cmd(pool *p, conn_t *ctrl_conn, cmd_rec *cmd); 42 | int proxy_ftp_ctrl_send_resp(pool *p, conn_t *ctrl_conn, pr_response_t *resp, 43 | unsigned int resp_nlines); 44 | 45 | #endif /* MOD_PROXY_FTP_CTRL_H */ 46 | -------------------------------------------------------------------------------- /include/proxy/ftp/facts.h: -------------------------------------------------------------------------------- 1 | /* 2 | * ProFTPD - mod_proxy FTP Facts API 3 | * Copyright (c) 2020 TJ Saunders 4 | * 5 | * This program is free software; you can redistribute it and/or modify 6 | * it under the terms of the GNU General Public License as published by 7 | * the Free Software Foundation; either version 2 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * This program is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU General Public License 16 | * along with this program; if not, write to the Free Software 17 | * Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA. 18 | * 19 | * As a special exemption, TJ Saunders and other respective copyright holders 20 | * give permission to link this program with OpenSSL, and distribute the 21 | * resulting executable, without including the source code for OpenSSL in the 22 | * source distribution. 23 | */ 24 | 25 | #ifndef MOD_PROXY_FTP_FACTS_H 26 | #define MOD_PROXY_FTP_FACTS_H 27 | 28 | #include "mod_proxy.h" 29 | 30 | /* RFC 3659 Facts */ 31 | #define PROXY_FTP_FACTS_OPT_SHOW_MODIFY 0x00001 32 | #define PROXY_FTP_FACTS_OPT_SHOW_PERM 0x00002 33 | #define PROXY_FTP_FACTS_OPT_SHOW_SIZE 0x00004 34 | #define PROXY_FTP_FACTS_OPT_SHOW_TYPE 0x00008 35 | #define PROXY_FTP_FACTS_OPT_SHOW_UNIQUE 0x00010 36 | #define PROXY_FTP_FACTS_OPT_SHOW_UNIX_GROUP 0x00020 37 | #define PROXY_FTP_FACTS_OPT_SHOW_UNIX_MODE 0x00040 38 | #define PROXY_FTP_FACTS_OPT_SHOW_UNIX_OWNER 0x00080 39 | #define PROXY_FTP_FACTS_OPT_SHOW_UNIX_OWNER_NAME 0x00100 40 | #define PROXY_FTP_FACTS_OPT_SHOW_UNIX_GROUP_NAME 0x00200 41 | 42 | unsigned long proxy_ftp_facts_get_opts(void); 43 | void proxy_ftp_facts_parse_opts(char *facts); 44 | 45 | #endif /* MOD_PROXY_FTP_FACTS_H */ 46 | -------------------------------------------------------------------------------- /include/proxy/dns.h: -------------------------------------------------------------------------------- 1 | /* 2 | * ProFTPD - mod_proxy DNS API 3 | * Copyright (c) 2020 TJ Saunders 4 | * 5 | * This program is free software; you can redistribute it and/or modify 6 | * it under the terms of the GNU General Public License as published by 7 | * the Free Software Foundation; either version 2 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * This program is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU General Public License 16 | * along with this program; if not, write to the Free Software 17 | * Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA. 18 | * 19 | * As a special exemption, TJ Saunders and other respective copyright holders 20 | * give permission to link this program with OpenSSL, and distribute the 21 | * resulting executable, without including the source code for OpenSSL in the 22 | * source distribution. 23 | */ 24 | 25 | #ifndef MOD_PROXY_DNS_H 26 | #define MOD_PROXY_DNS_H 27 | 28 | #include "mod_proxy.h" 29 | 30 | typedef enum { 31 | PROXY_DNS_UNKNOWN, 32 | PROXY_DNS_A, 33 | PROXY_DNS_AAAA, 34 | PROXY_DNS_SRV, 35 | PROXY_DNS_TXT 36 | } proxy_dns_type_e; 37 | 38 | /* Resolves a given `name` to a list of textual response lines, based on the 39 | * given DNS record type. 40 | * 41 | * For A records, the responses will be IPv4 addresses. 42 | * For AAAA records, the responses will be IPv6 addresses. 43 | * For SRV records, the responses will be the returned address/ports, in 44 | * priority order. 45 | * For TXT records, the responses will be the returned textual lines. 46 | * 47 | * If a `ttl` pointer is provided, the shortest TTL on retrieved records 48 | * retrieved is returned. 49 | */ 50 | int proxy_dns_resolve(pool *p, const char *name, proxy_dns_type_e dns_type, 51 | array_header **resp, uint32_t *ttl); 52 | 53 | #endif /* MOD_PROXY_DNS_H */ 54 | -------------------------------------------------------------------------------- /lib/proxy/str.c: -------------------------------------------------------------------------------- 1 | /* 2 | * ProFTPD - mod_proxy String implementation 3 | * Copyright (c) 2020 TJ Saunders 4 | * 5 | * This program is free software; you can redistribute it and/or modify 6 | * it under the terms of the GNU General Public License as published by 7 | * the Free Software Foundation; either version 2 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * This program is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU General Public License 16 | * along with this program; if not, write to the Free Software 17 | * Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA. 18 | * 19 | * As a special exemption, TJ Saunders and other respective copyright holders 20 | * give permission to link this program with OpenSSL, and distribute the 21 | * resulting executable, without including the source code for OpenSSL in the 22 | * source distribution. 23 | */ 24 | 25 | #include "mod_proxy.h" 26 | #include "proxy/str.h" 27 | 28 | char *proxy_strnstr(const char *s1, const char *s2, size_t len) { 29 | #if defined(HAVE_STRNSTR) 30 | if (s1 == NULL || 31 | s2 == NULL || 32 | len == 0) { 33 | return NULL; 34 | } 35 | 36 | /* strnstr(3) does not check this, but it should. */ 37 | if (s2[0] == '\0') { 38 | return NULL; 39 | } 40 | 41 | return strnstr(s1, s2, len); 42 | 43 | #else 44 | register unsigned int i; 45 | size_t s2_len; 46 | 47 | if (s1 == NULL || 48 | s2 == NULL || 49 | len == 0) { 50 | return NULL; 51 | } 52 | 53 | s2_len = strlen(s2); 54 | if (s2_len == 0 || 55 | s2_len > len) { 56 | return NULL; 57 | } 58 | 59 | for (i = 0; i <= (unsigned int) (len - s2_len); i++) { 60 | if (s1[0] == s2[0] && 61 | strncmp(s1, s2, s2_len) == 0) { 62 | return (char *) s1; 63 | } 64 | 65 | s1++; 66 | } 67 | 68 | return NULL; 69 | #endif /* HAVE_STRNSTR */ 70 | } 71 | -------------------------------------------------------------------------------- /include/proxy/ftp/msg.h: -------------------------------------------------------------------------------- 1 | /* 2 | * ProFTPD - mod_proxy FTP message API 3 | * Copyright (c) 2013-2025 TJ Saunders 4 | * 5 | * This program is free software; you can redistribute it and/or modify 6 | * it under the terms of the GNU General Public License as published by 7 | * the Free Software Foundation; either version 2 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * This program is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU General Public License 16 | * along with this program; if not, write to the Free Software 17 | * Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA. 18 | * 19 | * As a special exemption, TJ Saunders and other respective copyright holders 20 | * give permission to link this program with OpenSSL, and distribute the 21 | * resulting executable, without including the source code for OpenSSL in the 22 | * source distribution. 23 | */ 24 | 25 | #ifndef MOD_PROXY_FTP_MSG_H 26 | #define MOD_PROXY_FTP_MSG_H 27 | 28 | #include "mod_proxy.h" 29 | 30 | /* Format a string containing the address for use in a PORT command or a 31 | * PASV response. 32 | */ 33 | const char *proxy_ftp_msg_fmt_addr(pool *, const pr_netaddr_t *, 34 | unsigned short, int); 35 | 36 | /* Format a string containing the address for use in an EPRT command or an 37 | * EPSV response. 38 | */ 39 | const char *proxy_ftp_msg_fmt_ext_addr(pool *, const pr_netaddr_t *, 40 | unsigned short, int, int); 41 | 42 | /* Parse the address/port out of a string, e.g. from a PORT command or from 43 | * a PASV response. 44 | */ 45 | const pr_netaddr_t *proxy_ftp_msg_parse_addr(pool *, const char *, int); 46 | 47 | /* Parse the address/port out of a string, e.g. from an EPRT command or from 48 | * an EPSV response. 49 | */ 50 | const pr_netaddr_t *proxy_ftp_msg_parse_ext_addr(pool *, const char *, 51 | const pr_netaddr_t *, int, const char *); 52 | 53 | #endif /* MOD_PROXY_FTP_MSG_H */ 54 | -------------------------------------------------------------------------------- /lib/proxy/random.c: -------------------------------------------------------------------------------- 1 | /* 2 | * ProFTPD - mod_proxy random number implementation 3 | * Copyright (c) 2013-2020 TJ Saunders 4 | * 5 | * This program is free software; you can redistribute it and/or modify 6 | * it under the terms of the GNU General Public License as published by 7 | * the Free Software Foundation; either version 2 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * This program is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU General Public License 16 | * along with this program; if not, write to the Free Software 17 | * Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA. 18 | * 19 | * As a special exemption, TJ Saunders and other respective copyright holders 20 | * give permission to link this program with OpenSSL, and distribute the 21 | * resulting executable, without including the source code for OpenSSL in the 22 | * source distribution. 23 | */ 24 | 25 | #include "mod_proxy.h" 26 | #include "proxy/random.h" 27 | 28 | static const char *trace_channel = "proxy.random"; 29 | 30 | /* If random(3) is supported on this platform, seed it. rand(3) is already 31 | * seeded by the core proftpd code. 32 | */ 33 | int proxy_random_init(void) { 34 | #ifdef HAVE_RANDOM 35 | struct timeval tv; 36 | 37 | gettimeofday(&tv, NULL); 38 | srandom(getpid() ^ tv.tv_usec); 39 | #endif /* HAVE_RANDOM */ 40 | 41 | return 0; 42 | } 43 | 44 | long proxy_random_next(long min, long max) { 45 | long r, scaled; 46 | 47 | #if defined(HAVE_RANDOM) 48 | r = random(); 49 | pr_trace_msg(trace_channel, 22, "obtained r = %ld from random(3)", r); 50 | #else 51 | r = (long) rand(); 52 | pr_trace_msg(trace_channel, 22, "obtained r = %ld from rand(3)", r); 53 | #endif /* HAVE_RANDOM */ 54 | 55 | scaled = r % (max - min + 1) + min; 56 | pr_trace_msg(trace_channel, 15, 57 | "yielding scaled r = %ld (r = %ld, max = %ld, min = %ld)", scaled, 58 | r, max, min); 59 | 60 | return scaled; 61 | } 62 | -------------------------------------------------------------------------------- /t/api/ftp/facts.c: -------------------------------------------------------------------------------- 1 | /* 2 | * ProFTPD - mod_proxy testsuite 3 | * Copyright (c) 2020 TJ Saunders 4 | * 5 | * This program is free software; you can redistribute it and/or modify 6 | * it under the terms of the GNU General Public License as published by 7 | * the Free Software Foundation; either version 2 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * This program is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU General Public License 16 | * along with this program; if not, write to the Free Software 17 | * Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA. 18 | * 19 | * As a special exemption, TJ Saunders and other respective copyright holders 20 | * give permission to link this program with OpenSSL, and distribute the 21 | * resulting executable, without including the source code for OpenSSL in the 22 | * source distribution. 23 | */ 24 | 25 | /* FTP Facts API tests. */ 26 | 27 | #include "../tests.h" 28 | 29 | static pool *p = NULL; 30 | 31 | static void set_up(void) { 32 | if (p == NULL) { 33 | p = permanent_pool = session.pool = make_sub_pool(NULL); 34 | } 35 | 36 | if (getenv("TEST_VERBOSE") != NULL) { 37 | pr_trace_set_levels("proxy.ftp.facts", 1, 20); 38 | } 39 | } 40 | 41 | static void tear_down(void) { 42 | if (getenv("TEST_VERBOSE") != NULL) { 43 | pr_trace_set_levels("proxy.ftp.facts", 0, 0); 44 | } 45 | 46 | if (p != NULL) { 47 | destroy_pool(p); 48 | p = permanent_pool = session.pool = NULL; 49 | } 50 | } 51 | 52 | START_TEST (get_facts_test) { 53 | } 54 | END_TEST 55 | 56 | START_TEST (parse_facts_test) { 57 | } 58 | END_TEST 59 | 60 | Suite *tests_get_ftp_facts_suite(void) { 61 | Suite *suite; 62 | TCase *testcase; 63 | 64 | suite = suite_create("ftp.facts"); 65 | testcase = tcase_create("base"); 66 | 67 | tcase_add_checked_fixture(testcase, set_up, tear_down); 68 | 69 | tcase_add_test(testcase, get_facts_test); 70 | tcase_add_test(testcase, parse_facts_test); 71 | 72 | suite_add_tcase(suite, testcase); 73 | return suite; 74 | } 75 | -------------------------------------------------------------------------------- /lib/proxy/ssh/session.c: -------------------------------------------------------------------------------- 1 | /* 2 | * ProFTPD - mod_proxy SSH session 3 | * Copyright (c) 2021-2025 TJ Saunders 4 | * 5 | * This program is free software; you can redistribute it and/or modify 6 | * it under the terms of the GNU General Public License as published by 7 | * the Free Software Foundation; either version 2 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * This program is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU General Public License 16 | * along with this program; if not, write to the Free Software 17 | * Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA. 18 | * 19 | * As a special exemption, TJ Saunders and other respective copyright holders 20 | * give permission to link this program with OpenSSL, and distribute the 21 | * resulting executable, without including the source code for OpenSSL in the 22 | * source distribution. 23 | */ 24 | 25 | #include "mod_proxy.h" 26 | #include "proxy/ssh/session.h" 27 | #include 28 | 29 | static unsigned char *session_id = NULL; 30 | static uint32_t session_idlen = 0; 31 | 32 | uint32_t proxy_ssh_session_get_id(const unsigned char **buf) { 33 | if (session_id != NULL) { 34 | *buf = session_id; 35 | return session_idlen; 36 | } 37 | 38 | return 0; 39 | } 40 | 41 | int proxy_ssh_session_set_id(pool *p, const unsigned char *hash, 42 | uint32_t hashlen) { 43 | /* The session ID is only set once, regardless of how many times 44 | * (re)keying occurs during the course of a session. 45 | */ 46 | 47 | if (session_id == NULL) { 48 | session_id = palloc(p, hashlen); 49 | memcpy(session_id, hash, hashlen); 50 | session_idlen = hashlen; 51 | 52 | #if OPENSSL_VERSION_NUMBER >= 0x000905000L 53 | /* Since the session ID contains unknown information from the client, 54 | * it can be used as a source of additional entropy. The amount 55 | * of entropy is a rough guess. 56 | */ 57 | RAND_add(hash, hashlen, hashlen * 0.5); 58 | #endif 59 | 60 | return 0; 61 | } 62 | 63 | errno = EEXIST; 64 | return -1; 65 | } 66 | -------------------------------------------------------------------------------- /include/proxy/ssh/disconnect.h: -------------------------------------------------------------------------------- 1 | /* 2 | * ProFTPD - mod_proxy SSH disconnect API 3 | * Copyright (c) 2021-2025 TJ Saunders 4 | * 5 | * This program is free software; you can redistribute it and/or modify 6 | * it under the terms of the GNU General Public License as published by 7 | * the Free Software Foundation; either version 2 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * This program is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU General Public License 16 | * along with this program; if not, write to the Free Software 17 | * Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA. 18 | * 19 | * As a special exemption, TJ Saunders and other respective copyright holders 20 | * give permission to link this program with OpenSSL, and distribute the 21 | * resulting executable, without including the source code for OpenSSL in the 22 | * source distribution. 23 | */ 24 | 25 | #ifndef MOD_PROXY_SSH_DISCONNECT_H 26 | #define MOD_PROXY_SSH_DISCONNECT_H 27 | 28 | #include "mod_proxy.h" 29 | 30 | void proxy_ssh_disconnect_conn(conn_t *, uint32_t, const char *, const char *, 31 | int, const char *); 32 | void proxy_ssh_disconnect_send(pool *, conn_t *, uint32_t, const char *, 33 | const char *, int, const char *); 34 | 35 | /* Given a disconnect reason code from a server, return a string explaining 36 | * that code. 37 | */ 38 | const char *proxy_ssh_disconnect_get_text(uint32_t); 39 | 40 | /* Deal with the fact that __FUNCTION__ is a gcc extension. Sun's compilers 41 | * (e.g. SunStudio) like __func__. 42 | */ 43 | 44 | #if defined(__FUNCTION__) 45 | #define PROXY_SSH_DISCONNECT_CONN(c, n, m) \ 46 | proxy_ssh_disconnect_conn((c), (n), (m), __FILE__, __LINE__, __FUNCTION__) 47 | 48 | #elif defined(__func__) 49 | #define PROXY_SSH_DISCONNECT_CONN(c, n, m) \ 50 | proxy_ssh_disconnect_conn((c), (n), (m), __FILE__, __LINE__, __func__) 51 | 52 | #else 53 | #define PROXY_SSH_DISCONNECT_CONN(c, n, m) \ 54 | proxy_ssh_disconnect_conn((c), (n), (m), __FILE__, __LINE__, "") 55 | 56 | #endif 57 | 58 | #endif /* MOD_PROXY_SSH_DISCONNECT_H */ 59 | -------------------------------------------------------------------------------- /include/proxy/ssh/umac.h: -------------------------------------------------------------------------------- 1 | /* ----------------------------------------------------------------------- 2 | * 3 | * umac.h -- C Implementation UMAC Message Authentication 4 | * 5 | * Version 0.93a of rfc4418.txt -- 2006 July 14 6 | * 7 | * For a full description of UMAC message authentication see the UMAC 8 | * world-wide-web page at http://www.cs.ucdavis.edu/~rogaway/umac 9 | * Please report bugs and suggestions to the UMAC webpage. 10 | * 11 | * Copyright (c) 1999-2004 Ted Krovetz 12 | * 13 | * Permission to use, copy, modify, and distribute this software and 14 | * its documentation for any purpose and with or without fee, is hereby 15 | * granted provided that the above copyright notice appears in all copies 16 | * and in supporting documentation, and that the name of the copyright 17 | * holder not be used in advertising or publicity pertaining to 18 | * distribution of the software without specific, written prior permission. 19 | * 20 | * Comments should be directed to Ted Krovetz (tdk@acm.org) 21 | * 22 | * ---------------------------------------------------------------------- */ 23 | 24 | #ifndef MOD_PROXY_SSH_UMAC_H 25 | #define MOD_PROXY_SSH_UMAC_H 26 | 27 | struct umac_ctx *proxy_ssh_umac_alloc(void); 28 | struct umac_ctx *proxy_ssh_umac_new(const unsigned char key[]); 29 | void proxy_ssh_umac_init(struct umac_ctx *ctx, const unsigned char key[]); 30 | int proxy_ssh_umac_reset(struct umac_ctx *ctx); 31 | int proxy_ssh_umac_update(struct umac_ctx *ctx, const unsigned char *input, 32 | long len); 33 | int proxy_ssh_umac_final(struct umac_ctx *ctx, unsigned char tag[], 34 | const unsigned char nonce[8]); 35 | int proxy_ssh_umac_delete(struct umac_ctx *ctx); 36 | 37 | struct umac_ctx *proxy_ssh_umac128_alloc(void); 38 | struct umac_ctx *proxy_ssh_umac128_new(const unsigned char key[]); 39 | void proxy_ssh_umac128_init(struct umac_ctx *ctx, const unsigned char key[]); 40 | int proxy_ssh_umac128_reset(struct umac_ctx *ctx); 41 | int proxy_ssh_umac128_update(struct umac_ctx *ctx, const unsigned char *input, 42 | long len); 43 | int proxy_ssh_umac128_final(struct umac_ctx *ctx, unsigned char tag[], 44 | const unsigned char nonce[8]); 45 | int proxy_ssh_umac128_delete(struct umac_ctx *ctx); 46 | 47 | #endif /* MOD_PROXY_SSH_UMAC_H */ 48 | -------------------------------------------------------------------------------- /include/proxy/ssh/mac.h: -------------------------------------------------------------------------------- 1 | /* 2 | * ProFTPD - mod_proxy SSH MAC API 3 | * Copyright (c) 2021-2025 TJ Saunders 4 | * 5 | * This program is free software; you can redistribute it and/or modify 6 | * it under the terms of the GNU General Public License as published by 7 | * the Free Software Foundation; either version 2 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * This program is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU General Public License 16 | * along with this program; if not, write to the Free Software 17 | * Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA. 18 | * 19 | * As a special exemption, TJ Saunders and other respective copyright holders 20 | * give permission to link this program with OpenSSL, and distribute the 21 | * resulting executable, without including the source code for OpenSSL in the 22 | * source distribution. 23 | */ 24 | 25 | #ifndef MOD_PROXY_SSH_MAC_H 26 | #define MOD_PROXY_SSH_MAC_H 27 | 28 | #include "mod_proxy.h" 29 | #include "proxy/ssh/packet.h" 30 | 31 | #include 32 | 33 | int proxy_ssh_mac_init(void); 34 | int proxy_ssh_mac_free(void); 35 | 36 | /* Returns the block size of the negotiated MAC algorithm, or 0 if no MAC 37 | * has been negotiated yet. 38 | */ 39 | size_t proxy_ssh_mac_get_block_size(void); 40 | void proxy_ssh_mac_set_block_size(size_t blocksz); 41 | 42 | const char *proxy_ssh_mac_get_read_algo(void); 43 | int proxy_ssh_mac_is_read_etm(void); 44 | int proxy_ssh_mac_set_read_algo(pool *p, const char *algo); 45 | int proxy_ssh_mac_set_read_key(pool *p, const EVP_MD *md, 46 | const unsigned char *k, uint32_t klen, const char *h, uint32_t hlen, 47 | int role); 48 | int proxy_ssh_mac_read_data(struct proxy_ssh_packet *pkt); 49 | 50 | const char *proxy_ssh_mac_get_write_algo(void); 51 | int proxy_ssh_mac_is_write_etm(void); 52 | int proxy_ssh_mac_set_write_algo(pool *p, const char *algo); 53 | int proxy_ssh_mac_set_write_key(pool *p, const EVP_MD *md, 54 | const unsigned char *k, uint32_t klen, const char *h, uint32_t hlen, 55 | int role); 56 | int proxy_ssh_mac_write_data(struct proxy_ssh_packet *pkt); 57 | 58 | #endif /* MOD_PROXY_SSH_MAC_H */ 59 | -------------------------------------------------------------------------------- /include/proxy/forward.h: -------------------------------------------------------------------------------- 1 | /* 2 | * ProFTPD - mod_proxy forward-proxy API 3 | * Copyright (c) 2012-2022 TJ Saunders 4 | * 5 | * This program is free software; you can redistribute it and/or modify 6 | * it under the terms of the GNU General Public License as published by 7 | * the Free Software Foundation; either version 2 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * This program is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU General Public License 16 | * along with this program; if not, write to the Free Software 17 | * Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA. 18 | * 19 | * As a special exemption, TJ Saunders and other respective copyright holders 20 | * give permission to link this program with OpenSSL, and distribute the 21 | * resulting executable, without including the source code for OpenSSL in the 22 | * source distribution. 23 | */ 24 | 25 | #ifndef MOD_PROXY_FORWARD_H 26 | #define MOD_PROXY_FORWARD_H 27 | 28 | #include "mod_proxy.h" 29 | #include "proxy/session.h" 30 | 31 | #define PROXY_FORWARD_ENABLED_NOTE "mod_proxy.forward-enabled" 32 | 33 | int proxy_forward_init(pool *p, const char *tables_dir); 34 | int proxy_forward_free(pool *p); 35 | 36 | int proxy_forward_sess_init(pool *p, const char *tables_dir, 37 | struct proxy_session *proxy_sess); 38 | int proxy_forward_sess_free(pool *p, struct proxy_session *proxy_sess); 39 | int proxy_forward_have_authenticated(cmd_rec *cmd); 40 | 41 | int proxy_forward_handle_user(cmd_rec *cmd, struct proxy_session *proxy_sess, 42 | int *successful, int *block_responses); 43 | int proxy_forward_handle_pass(cmd_rec *cmd, struct proxy_session *proxy_sess, 44 | int *successful, int *block_responses); 45 | 46 | /* Forward proxy method API */ 47 | 48 | #define PROXY_FORWARD_METHOD_USER_WITH_PROXY_AUTH 1 49 | #define PROXY_FORWARD_METHOD_USER_NO_PROXY_AUTH 2 50 | #define PROXY_FORWARD_METHOD_PROXY_USER_WITH_PROXY_AUTH 3 51 | #define PROXY_FORWARD_METHOD_USER_SNI_NO_PROXY_AUTH 4 52 | 53 | /* Return the method ID for the given string, or -1 if the given method 54 | * is not recognized/supported. 55 | */ 56 | int proxy_forward_get_method(const char *); 57 | 58 | /* Returns TRUE if the Forward API is using proxy auth, FALSE otherwise. */ 59 | int proxy_forward_use_proxy_auth(void); 60 | 61 | #endif /* MOD_PROXY_FORWARD_H */ 62 | -------------------------------------------------------------------------------- /include/proxy/conn.h: -------------------------------------------------------------------------------- 1 | /* 2 | * ProFTPD - mod_proxy conn API 3 | * Copyright (c) 2012-2020 TJ Saunders 4 | * 5 | * This program is free software; you can redistribute it and/or modify 6 | * it under the terms of the GNU General Public License as published by 7 | * the Free Software Foundation; either version 2 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * This program is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU General Public License 16 | * along with this program; if not, write to the Free Software 17 | * Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA. 18 | * 19 | * As a special exemption, TJ Saunders and other respective copyright holders 20 | * give permission to link this program with OpenSSL, and distribute the 21 | * resulting executable, without including the source code for OpenSSL in the 22 | * source distribution. 23 | */ 24 | 25 | #ifndef MOD_PROXY_CONN_H 26 | #define MOD_PROXY_CONN_H 27 | 28 | #include "mod_proxy.h" 29 | #include "proxy/session.h" 30 | 31 | struct proxy_conn; 32 | 33 | void proxy_conn_clear_username(const struct proxy_conn *pconn); 34 | void proxy_conn_clear_password(const struct proxy_conn *pconn); 35 | int proxy_conn_connect_timeout_cb(CALLBACK_FRAME); 36 | 37 | const struct proxy_conn *proxy_conn_create(pool *p, const char *uri, 38 | unsigned int flags); 39 | #define PROXY_CONN_CREATE_FL_USE_DNS_TTL 0x0001 40 | 41 | const pr_netaddr_t *proxy_conn_get_addr(const struct proxy_conn *, 42 | array_header **); 43 | int proxy_conn_get_dns_ttl(const struct proxy_conn *pconn); 44 | const char *proxy_conn_get_host(const struct proxy_conn *pconn); 45 | const char *proxy_conn_get_hostport(const struct proxy_conn *pconn); 46 | int proxy_conn_get_port(const struct proxy_conn *pconn); 47 | conn_t *proxy_conn_get_server_conn(pool *p, struct proxy_session *proxy_sess, 48 | const pr_netaddr_t *remote_addr); 49 | const char *proxy_conn_get_uri(const struct proxy_conn *pconn); 50 | const char *proxy_conn_get_username(const struct proxy_conn *pconn); 51 | const char *proxy_conn_get_password(const struct proxy_conn *pconn); 52 | int proxy_conn_get_tls(const struct proxy_conn *pconn); 53 | int proxy_conn_use_dns_srv(const struct proxy_conn *pconn); 54 | int proxy_conn_use_dns_txt(const struct proxy_conn *pconn); 55 | int proxy_conn_send_proxy_v1(pool *p, conn_t *conn); 56 | int proxy_conn_send_proxy_v2(pool *p, conn_t *conn); 57 | void proxy_conn_free(const struct proxy_conn *pconn); 58 | 59 | #endif /* MOD_PROXY_CONN_H */ 60 | -------------------------------------------------------------------------------- /include/proxy/netio.h: -------------------------------------------------------------------------------- 1 | /* 2 | * ProFTPD - mod_proxy NetIO API 3 | * Copyright (c) 2015-2016 TJ Saunders 4 | * 5 | * This program is free software; you can redistribute it and/or modify 6 | * it under the terms of the GNU General Public License as published by 7 | * the Free Software Foundation; either version 2 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * This program is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU General Public License 16 | * along with this program; if not, write to the Free Software 17 | * Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA. 18 | * 19 | * As a special exemption, TJ Saunders and other respective copyright holders 20 | * give permission to link this program with OpenSSL, and distribute the 21 | * resulting executable, without including the source code for OpenSSL in the 22 | * source distribution. 23 | */ 24 | 25 | #ifndef MOD_PROXY_NETIO_H 26 | #define MOD_PROXY_NETIO_H 27 | 28 | #include "mod_proxy.h" 29 | 30 | pr_netio_t *proxy_netio_unset(int strm_type, const char *fn); 31 | int proxy_netio_set(int strm_type, pr_netio_t *netio); 32 | 33 | /* Tells the Proxy NetIO API to use the given netio for the given stream 34 | * type, when proxy_netio_unset() and proxy_netio_set() are called on that 35 | * stream type. 36 | */ 37 | int proxy_netio_use(int strm_type, pr_netio_t *netio); 38 | 39 | /* Returns the netio that the Proxy NetIO API is using for a given stream 40 | * type, if any. 41 | */ 42 | int proxy_netio_using(int strm_type, pr_netio_t **netio); 43 | 44 | /* Proxied versions of the core NetIO API functions; see include/netio.h. */ 45 | 46 | pr_netio_stream_t *proxy_netio_open(pool *p, int strm_type, int fd, int mode); 47 | 48 | int proxy_netio_close(pr_netio_stream_t *nstrm); 49 | 50 | int proxy_netio_postopen(pr_netio_stream_t *nstrm); 51 | 52 | int proxy_netio_printf(pr_netio_stream_t *nstrm, const char *fmt, ...); 53 | 54 | int proxy_netio_poll(pr_netio_stream_t *nstrm); 55 | 56 | int proxy_netio_postopen(pr_netio_stream_t *nstrm); 57 | 58 | int proxy_netio_read(pr_netio_stream_t *nstrm, char *buf, size_t bufsz, 59 | int bufmin); 60 | 61 | void proxy_netio_reset_poll_interval(pr_netio_stream_t *nstrm); 62 | 63 | void proxy_netio_set_poll_interval(pr_netio_stream_t *nstrm, unsigned int secs); 64 | 65 | int proxy_netio_shutdown(pr_netio_stream_t *nstrm, int how); 66 | 67 | int proxy_netio_write(pr_netio_stream_t *nstrm, char *buf, size_t bufsz); 68 | 69 | #endif /* MOD_PROXY_NETIO_H */ 70 | -------------------------------------------------------------------------------- /include/proxy/ftp/dirlist.h: -------------------------------------------------------------------------------- 1 | /* 2 | * ProFTPD - mod_proxy FTP dirlist API 3 | * Copyright (c) 2020 TJ Saunders 4 | * 5 | * This program is free software; you can redistribute it and/or modify 6 | * it under the terms of the GNU General Public License as published by 7 | * the Free Software Foundation; either version 2 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * This program is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU General Public License 16 | * along with this program; if not, write to the Free Software 17 | * Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA. 18 | * 19 | * As a special exemption, TJ Saunders and other respective copyright holders 20 | * give permission to link this program with OpenSSL, and distribute the 21 | * resulting executable, without including the source code for OpenSSL in the 22 | * source distribution. 23 | */ 24 | 25 | #ifndef MOD_PROXY_FTP_DIRLIST_H 26 | #define MOD_PROXY_FTP_DIRLIST_H 27 | 28 | #include "mod_proxy.h" 29 | #include "proxy/session.h" 30 | 31 | int proxy_ftp_dirlist_init(pool *p, struct proxy_session *proxy_sess); 32 | int proxy_ftp_dirlist_finish(struct proxy_session *proxy_sess); 33 | 34 | struct proxy_dirlist_fileinfo { 35 | pool *pool; 36 | struct stat *st; 37 | unsigned char have_uid, have_gid; 38 | struct tm *tm; 39 | const char *user; 40 | const char *group; 41 | const char *type; 42 | const char *perm; 43 | const char *path; 44 | }; 45 | 46 | #define PROXY_FTP_DIRLIST_OPT_USE_SLINK 0x0001 47 | 48 | struct proxy_dirlist_fileinfo *proxy_ftp_dirlist_fileinfo_from_dos(pool *p, 49 | const char *text, size_t textlen, unsigned long opts); 50 | struct proxy_dirlist_fileinfo *proxy_ftp_dirlist_fileinfo_from_unix(pool *p, 51 | const char *text, size_t textlen, struct tm *tm, unsigned long opts); 52 | struct proxy_dirlist_fileinfo *proxy_ftp_dirlist_fileinfo_from_text(pool *p, 53 | const char *text, size_t textlen, struct tm *tm, void *user_data, 54 | unsigned long opts); 55 | 56 | const char *proxy_ftp_dirlist_fileinfo_to_facts(pool *p, 57 | const struct proxy_dirlist_fileinfo *pdf, size_t *textlen); 58 | 59 | /* Given a buffer of (possibly incomplete) dirlist data, return the text 60 | * to give to the client. Note that there may be enough data accumulated 61 | * yet to provide text to the client. 62 | */ 63 | int proxy_ftp_dirlist_to_text(pool *p, char *buf, size_t buflen, 64 | size_t max_textsz, char **text, size_t *textlen, void *user_data); 65 | 66 | #endif /* MOD_PROXY_FTP_DIRLIST_H */ 67 | -------------------------------------------------------------------------------- /lib/proxy/ssh/misc.c: -------------------------------------------------------------------------------- 1 | /* 2 | * ProFTPD - mod_proxy SSH miscellany 3 | * Copyright (c) 2021-2025 TJ Saunders 4 | * 5 | * This program is free software; you can redistribute it and/or modify 6 | * it under the terms of the GNU General Public License as published by 7 | * the Free Software Foundation; either version 2 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * This program is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU General Public License 16 | * along with this program; if not, write to the Free Software 17 | * Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA. 18 | * 19 | * As a special exemption, TJ Saunders and other respective copyright holders 20 | * give permission to link this program with OpenSSL, and distribute the 21 | * resulting executable, without including the source code for OpenSSL in the 22 | * source distribution. 23 | */ 24 | 25 | #include "mod_proxy.h" 26 | #include "proxy/ssh/misc.h" 27 | 28 | int proxy_ssh_misc_namelist_contains(pool *p, const char *namelist, 29 | const char *name) { 30 | register unsigned int i; 31 | int res = FALSE; 32 | pool *tmp_pool; 33 | array_header *list; 34 | const char **elts; 35 | 36 | tmp_pool = make_sub_pool(p); 37 | pr_pool_tag(tmp_pool, "Contains name pool"); 38 | 39 | list = pr_str_text_to_array(tmp_pool, namelist, ','); 40 | elts = (const char **) list->elts; 41 | 42 | for (i = 0; i < list->nelts; i++) { 43 | if (strcmp(elts[i], name) == 0) { 44 | res = TRUE; 45 | break; 46 | } 47 | } 48 | 49 | destroy_pool(tmp_pool); 50 | return res; 51 | } 52 | 53 | const char *proxy_ssh_misc_namelist_shared(pool *p, const char *c2s_names, 54 | const char *s2c_names) { 55 | register unsigned int i; 56 | const char *name = NULL, **client_names, **server_names; 57 | pool *tmp_pool; 58 | array_header *client_list, *server_list; 59 | 60 | tmp_pool = make_sub_pool(p); 61 | pr_pool_tag(tmp_pool, "Share name pool"); 62 | 63 | client_list = pr_str_text_to_array(tmp_pool, c2s_names, ','); 64 | client_names = (const char **) client_list->elts; 65 | 66 | server_list = pr_str_text_to_array(tmp_pool, s2c_names, ','); 67 | server_names = (const char **) server_list->elts; 68 | 69 | for (i = 0; i < client_list->nelts; i++) { 70 | register unsigned int j; 71 | 72 | if (name != NULL) { 73 | break; 74 | } 75 | 76 | for (j = 0; j < server_list->nelts; j++) { 77 | if (strcmp(client_names[i], server_names[j]) == 0) { 78 | name = client_names[i]; 79 | break; 80 | } 81 | } 82 | } 83 | 84 | name = pstrdup(p, name); 85 | destroy_pool(tmp_pool); 86 | 87 | return name; 88 | } 89 | -------------------------------------------------------------------------------- /include/proxy/ssh.h: -------------------------------------------------------------------------------- 1 | /* 2 | * ProFTPD - mod_proxy SSH API 3 | * Copyright (c) 2021-2023 TJ Saunders 4 | * 5 | * This program is free software; you can redistribute it and/or modify 6 | * it under the terms of the GNU General Public License as published by 7 | * the Free Software Foundation; either version 2 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * This program is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU General Public License 16 | * along with this program; if not, write to the Free Software 17 | * Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA. 18 | * 19 | * As a special exemption, TJ Saunders and other respective copyright holders 20 | * give permission to link this program with OpenSSL, and distribute the 21 | * resulting executable, without including the source code for OpenSSL in the 22 | * source distribution. 23 | */ 24 | 25 | #ifndef MOD_PROXY_SSH_H 26 | #define MOD_PROXY_SSH_H 27 | 28 | #include "mod_proxy.h" 29 | #include "proxy/session.h" 30 | 31 | /* ProxySFTPOptions values. NOTE: Make sure these do NOT collide with existing 32 | * PROXY_OPT_ values defined in mod_proxy.h. 33 | */ 34 | #define PROXY_OPT_SSH_PESSIMISTIC_KEXINIT 0x0100 35 | #define PROXY_OPT_SSH_OLD_PROTO_COMPAT 0x0200 36 | #define PROXY_OPT_SSH_ALLOW_WEAK_DH 0x0400 37 | #define PROXY_OPT_SSH_ALLOW_WEAK_SECURITY 0x0800 38 | #define PROXY_OPT_SSH_NO_EXT_INFO 0x1000 39 | #define PROXY_OPT_SSH_NO_HOSTKEY_ROTATION 0x2000 40 | #define PROXY_OPT_SSH_NO_STRICT_KEX 0x4000 41 | 42 | int proxy_ssh_init(pool *p, const char *tables_dir, int flags); 43 | int proxy_ssh_free(pool *p); 44 | 45 | int proxy_ssh_sess_init(pool *p, struct proxy_session *proxy_sess, int flags); 46 | int proxy_ssh_sess_free(pool *p); 47 | 48 | /* Defines the datastore interface. */ 49 | struct proxy_ssh_datastore { 50 | /* Keystore callbacks */ 51 | int (*hostkey_add)(pool *p, void *dsh, unsigned int vhost_id, 52 | const char *backend_uri, const char *algo, 53 | const unsigned char *hostkey_data, uint32_t hostkey_datalen); 54 | const unsigned char *(*hostkey_get)(pool *p, void *dsh, 55 | unsigned int vhost_id, const char *backend_uri, const char **algo, 56 | uint32_t *hostkey_datalen); 57 | int (*hostkey_update)(pool *p, void *dsh, unsigned int vhost_id, 58 | const char *backend_uri, const char *algo, 59 | const unsigned char *hostkey_data, uint32_t hostkey_datalen); 60 | 61 | int (*init)(pool *p, const char *path, int flags); 62 | void *(*open)(pool *p, const char *path, unsigned long opts); 63 | int (*close)(pool *p, void *dsh); 64 | 65 | /* Datastore handle returned by the open callback. */ 66 | void *dsh; 67 | }; 68 | 69 | #endif /* MOD_PROXY_SSH_H */ 70 | -------------------------------------------------------------------------------- /.github/workflows/codeql.yml: -------------------------------------------------------------------------------- 1 | name: CodeQL 2 | 3 | on: 4 | push: 5 | branches: 6 | - master 7 | paths-ignore: 8 | - '*.html' 9 | - '**/*.md' 10 | - '**/doc/*' 11 | - 't/etc/**' 12 | - 't/lib/**' 13 | - 't/modules/**' 14 | pull_request: 15 | branches: 16 | - master 17 | paths-ignore: 18 | - '**/*.md' 19 | - '**/doc/*' 20 | schedule: 21 | - cron: "37 17 * * 2" 22 | 23 | jobs: 24 | analyze: 25 | name: CodeQL Analysis 26 | runs-on: ubuntu-latest 27 | permissions: 28 | actions: read 29 | contents: read 30 | security-events: write 31 | 32 | strategy: 33 | fail-fast: true 34 | matrix: 35 | language: 36 | - cpp 37 | 38 | steps: 39 | - name: Checkout ProFTPD 40 | uses: actions/checkout@v4 41 | with: 42 | repository: proftpd/proftpd 43 | 44 | - name: Checkout mod_proxy 45 | uses: actions/checkout@v4 46 | with: 47 | path: contrib/mod_proxy 48 | 49 | - name: Install Packages 50 | run: | 51 | sudo apt-get update 52 | sudo apt-get install --yes libhiredis-dev libsqlite3-dev libssl-dev libsodium-dev zlib1g-dev 53 | 54 | - name: Configure 55 | run: | 56 | ./configure --enable-redis --with-modules=mod_sftp:mod_tls:mod_proxy 57 | 58 | - name: Initialize CodeQL 59 | uses: github/codeql-action/init@v3 60 | with: 61 | languages: ${{ matrix.language }} 62 | config-file: contrib/mod_proxy/.codeql.yml 63 | queries: +security-and-quality 64 | source-root: contrib/mod_proxy 65 | 66 | - name: Build 67 | run: | 68 | make 69 | 70 | - name: Perform CodeQL Analysis 71 | uses: github/codeql-action/analyze@v3 72 | with: 73 | category: "/language:${{ matrix.language }}" 74 | checkout_path: contrib/mod_proxy 75 | output: sarif-results 76 | upload: false 77 | 78 | - name: Filter CodeQL SARIF 79 | uses: advanced-security/filter-sarif@v1 80 | with: 81 | patterns: | 82 | -**/lib/proxy/dns.c:cpp/large-parameter 83 | -**/lib/proxy/ssh.c:cpp/stack-address-escape 84 | -**/lib/proxy/ssh/compress.c:cpp/stack-address-escape 85 | -**/lib/proxy/ssh/compress.c:cpp/uncontrolled-allocation-size 86 | -**/lib/proxy/ssh/packet.c:cpp/stack-address-escape 87 | -**/lib/proxy/ssh/packet.c:cpp/uncontrolled-allocation-size 88 | -**/lib/proxy/ssh/umac.c 89 | -**/lib/proxy/ssh/umac128.c 90 | input: "sarif-results/${{ matrix.language }}.sarif" 91 | output: "sarif-results/${{ matrix.language }}.sarif" 92 | 93 | - name: Upload CodeQL SARIF 94 | uses: github/codeql-action/upload-sarif@v3 95 | with: 96 | checkout_path: contrib/mod_proxy 97 | sarif_file: "sarif-results/${{ matrix.language }}.sarif" 98 | -------------------------------------------------------------------------------- /doc/NOTES.forward-proxy: -------------------------------------------------------------------------------- 1 | 2 | Supported forward proxy method: 3 | 4 | USER user@dest-server[:port] 5 | PASS pass 6 | 7 | Chilkatsoft.com ChilkatFtp2.ProxyMethod = 2 8 | 9 | Net::Config: 10 | ftp_firewall_type 1 11 | USER user@remote.host[:port] 12 | PASS pass 13 | 14 | Complications: 15 | 16 | '@' symbol in username? 17 | Avoidable if the USER argument is parsed from end-to-beginning 18 | 19 | What if no '@' symbol appears in USER argument? 20 | What if single '@' symbol appears in USER argument, as part of actual 21 | username? 22 | 23 | What if USER is not first command? I.e. what if we see FEAT, SYST, 24 | etc? 25 | 26 | What if USER specifies a host that returns 5xx in the banner? Should 27 | the client be allowed another USER? If so, does that count against 28 | MaxLoginAttempts? 29 | 30 | IPv6 dest server? 31 | Support "USER user@[::1]:port". Easy enough. 32 | 33 | FTPS? 34 | If USER command is received over SSL/TLS, then connection to dest 35 | server will use SSL/TLS. Configurable? 36 | 37 | Connect, then send FEAT. If "AUTH SSL" or "AUTH TLS" appears in 38 | FEAT, AND mod_proxy+mod_tls is available, then automatically try 39 | to do FTPS. No "implicit" FTPS support? 40 | 41 | Connection to dest server opened later 42 | 43 | Benefits: 44 | 45 | use mod_proxy in forward mode to add "IPv6" capability, i.e. talk to IPv6 46 | server, for IPv4-only client. 47 | 48 | use mod_proxy in forward mode to add SSL/TLS capability, i.e. to talk to 49 | FTPS server, for non-SSL/TLS clients? 50 | 51 | Supporting this means not connecting to the real server until pre-USER time; 52 | mod_proxy needs to be modified to deal with this case. It's work needed 53 | for USER-based backend selection in the reverse proxy case, anyway. 54 | 55 | Client configuration: 56 | 57 |
  • proxyuser,user@host 58 | FZ: 59 | https://www3.trustwave.com/support/kb/article.aspx?id=13497 60 | See WinSCP 61 | this is what lftp calls "user" for its ftp:proxy-auth-type setting. 62 |
  • 63 | 64 |
  • proxyuser@host,user 65 | Chrome: uses system proxy settings (on Mac, at least?) 66 | FF: 67 | http://www.wikihow.com/Enter-Proxy-Settings-in-Firefox 68 | FZ: 69 | https://www3.trustwave.com/support/kb/article.aspx?id=13497 70 | See WinSCP 71 | this is what lftp calls "proxy-user@host" for its ftp:proxy-auth-type setting. 72 | 73 | 74 | Future methods: 75 | 76 | Net::Config: 77 | ftp_firewall_type 2 78 | USER proxy-user 79 | PASS proxy-pass 80 | USER user@remote.host[:port] 81 | PASS pass 82 | 83 | ftp_firewall_type 6 84 | USER proxy-user@remote.host[:port] 85 | PASS proxy-pass 86 | USER user 87 | PASS pass 88 | 89 | See also this, which has *9* methods: 90 | http://www.mcknight.de/jftpgw/config.html#loginstyle 91 | 92 | 93 | Limiting the proxied hosts: 94 | ProxyBlock: 95 | http://httpd.apache.org/docs/2.4/mod/mod_proxy.html#proxyblock 96 | 97 | -------------------------------------------------------------------------------- /include/proxy/ssh/cipher.h: -------------------------------------------------------------------------------- 1 | /* 2 | * ProFTPD - mod_proxy SSH cipher API 3 | * Copyright (c) 2021-2025 TJ Saunders 4 | * 5 | * This program is free software; you can redistribute it and/or modify 6 | * it under the terms of the GNU General Public License as published by 7 | * the Free Software Foundation; either version 2 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * This program is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU General Public License 16 | * along with this program; if not, write to the Free Software 17 | * Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA. 18 | * 19 | * As a special exemption, TJ Saunders and other respective copyright holders 20 | * give permission to link this program with OpenSSL, and distribute the 21 | * resulting executable, without including the source code for OpenSSL in the 22 | * source distribution. 23 | */ 24 | 25 | #ifndef MOD_PROXY_SSH_CIPHER_H 26 | #define MOD_PROXY_SSH_CIPHER_H 27 | 28 | #include "mod_proxy.h" 29 | 30 | #include 31 | 32 | int proxy_ssh_cipher_init(void); 33 | int proxy_ssh_cipher_free(void); 34 | 35 | /* Returns the cipher block size, or 8, whichever is larger. This value is 36 | * used when reading in the first bytes of a packet in order to determine 37 | * the packet length. See RFC4253, Section 6, "Binary Packet Protocol". 38 | */ 39 | size_t proxy_ssh_cipher_get_read_block_size(void); 40 | size_t proxy_ssh_cipher_get_write_block_size(void); 41 | void proxy_ssh_cipher_set_read_block_size(size_t); 42 | void proxy_ssh_cipher_set_write_block_size(size_t); 43 | 44 | int proxy_ssh_cipher_is_read_chachapoly(void); 45 | 46 | /* Returns the cipher authenticated data size, or zero. */ 47 | size_t proxy_ssh_cipher_get_read_auth_size(void); 48 | size_t proxy_ssh_cipher_get_read_auth_size2(void); 49 | size_t proxy_ssh_cipher_get_write_auth_size(void); 50 | size_t proxy_ssh_cipher_get_write_auth_size2(void); 51 | 52 | const char *proxy_ssh_cipher_get_read_algo(void); 53 | int proxy_ssh_cipher_set_read_algo(pool *p, const char *algo); 54 | int proxy_ssh_cipher_set_read_key(pool *p, const EVP_MD *md, 55 | const unsigned char *k, uint32_t klen, const char *h, uint32_t hlen, 56 | int role); 57 | int proxy_ssh_cipher_read_data(struct proxy_ssh_packet *pkt, 58 | unsigned char *data, uint32_t data_len, unsigned char **buf, 59 | uint32_t *buflen); 60 | int proxy_ssh_cipher_read_packet_len(struct proxy_ssh_packet *pkt, 61 | unsigned char *data, uint32_t data_len, unsigned char **buf, 62 | uint32_t *buflen, uint32_t *packet_len); 63 | 64 | const char *proxy_ssh_cipher_get_write_algo(void); 65 | int proxy_ssh_cipher_set_write_algo(pool *p, const char *algo); 66 | int proxy_ssh_cipher_set_write_key(pool *p, const EVP_MD *md, 67 | const unsigned char *k, uint32_t klen, const char *h, uint32_t hlen, 68 | int role); 69 | int proxy_ssh_cipher_write_data(struct proxy_ssh_packet *pkt, 70 | unsigned char *buf, size_t *bufsz); 71 | 72 | #endif /* MOD_PROXY_SSH_CIPHER_H */ 73 | -------------------------------------------------------------------------------- /t/api/tests.h: -------------------------------------------------------------------------------- 1 | /* 2 | * ProFTPD - mod_proxy API testsuite 3 | * Copyright (c) 2012-2020 TJ Saunders 4 | * 5 | * This program is free software; you can redistribute it and/or modify 6 | * it under the terms of the GNU General Public License as published by 7 | * the Free Software Foundation; either version 2 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * This program is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU General Public License 16 | * along with this program; if not, write to the Free Software 17 | * Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA. 18 | * 19 | * As a special exemption, TJ Saunders and other respective copyright holders 20 | * give permission to link this program with OpenSSL, and distribute the 21 | * resulting executable, without including the source code for OpenSSL in the 22 | * source distribution. 23 | */ 24 | 25 | /* Testsuite management */ 26 | 27 | #ifndef MOD_PROXY_TESTS_H 28 | #define MOD_PROXY_TESTS_H 29 | 30 | #include "mod_proxy.h" 31 | 32 | #include "proxy/random.h" 33 | #include "proxy/db.h" 34 | #include "proxy/dns.h" 35 | #include "proxy/conn.h" 36 | #include "proxy/netio.h" 37 | #include "proxy/inet.h" 38 | #include "proxy/str.h" 39 | #include "proxy/uri.h" 40 | #include "proxy/tls.h" 41 | #include "proxy/tls/db.h" 42 | #include "proxy/tls/redis.h" 43 | #include "proxy/session.h" 44 | #include "proxy/reverse.h" 45 | #include "proxy/reverse/db.h" 46 | #include "proxy/reverse/redis.h" 47 | #include "proxy/forward.h" 48 | #include "proxy/ftp/msg.h" 49 | #include "proxy/ftp/conn.h" 50 | #include "proxy/ftp/ctrl.h" 51 | #include "proxy/ftp/data.h" 52 | #include "proxy/ftp/dirlist.h" 53 | #include "proxy/ftp/facts.h" 54 | #include "proxy/ftp/sess.h" 55 | #include "proxy/ftp/xfer.h" 56 | 57 | #ifdef HAVE_CHECK_H 58 | # include 59 | #else 60 | # error "Missing Check installation; necessary for ProFTPD testsuite" 61 | #endif 62 | 63 | int tests_rmpath(pool *p, const char *path); 64 | int tests_stubs_set_next_cmd(cmd_rec *cmd); 65 | 66 | Suite *tests_get_conn_suite(void); 67 | Suite *tests_get_db_suite(void); 68 | Suite *tests_get_dns_suite(void); 69 | Suite *tests_get_inet_suite(void); 70 | Suite *tests_get_netio_suite(void); 71 | Suite *tests_get_random_suite(void); 72 | Suite *tests_get_reverse_suite(void); 73 | Suite *tests_get_forward_suite(void); 74 | Suite *tests_get_str_suite(void); 75 | Suite *tests_get_tls_suite(void); 76 | Suite *tests_get_uri_suite(void); 77 | Suite *tests_get_session_suite(void); 78 | 79 | Suite *tests_get_ftp_msg_suite(void); 80 | Suite *tests_get_ftp_conn_suite(void); 81 | Suite *tests_get_ftp_ctrl_suite(void); 82 | Suite *tests_get_ftp_data_suite(void); 83 | Suite *tests_get_ftp_dirlist_suite(void); 84 | Suite *tests_get_ftp_facts_suite(void); 85 | Suite *tests_get_ftp_sess_suite(void); 86 | Suite *tests_get_ftp_xfer_suite(void); 87 | 88 | extern volatile unsigned int recvd_signal_flags; 89 | extern pid_t mpid; 90 | extern server_rec *main_server; 91 | 92 | #endif /* MOD_PROXY_TESTS_H */ 93 | -------------------------------------------------------------------------------- /include/proxy/ssh/keys.h: -------------------------------------------------------------------------------- 1 | /* 2 | * ProFTPD - mod_proxy SSH keys API 3 | * Copyright (c) 2021-2025 TJ Saunders 4 | * 5 | * This program is free software; you can redistribute it and/or modify 6 | * it under the terms of the GNU General Public License as published by 7 | * the Free Software Foundation; either version 2 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * This program is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU General Public License 16 | * along with this program; if not, write to the Free Software 17 | * Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA. 18 | * 19 | * As a special exemption, TJ Saunders and other respective copyright holders 20 | * give permission to link this program with OpenSSL, and distribute the 21 | * resulting executable, without including the source code for OpenSSL in the 22 | * source distribution. 23 | */ 24 | 25 | #ifndef MOD_PROXY_SSH_KEYS_H 26 | #define MOD_PROXY_SSH_KEYS_H 27 | 28 | #include "mod_proxy.h" 29 | 30 | #include 31 | 32 | enum proxy_ssh_key_type_e { 33 | PROXY_SSH_KEY_UNKNOWN = 0, 34 | PROXY_SSH_KEY_DSA, 35 | PROXY_SSH_KEY_RSA, 36 | PROXY_SSH_KEY_RSA_SHA256, 37 | PROXY_SSH_KEY_RSA_SHA512, 38 | PROXY_SSH_KEY_ECDSA_256, 39 | PROXY_SSH_KEY_ECDSA_384, 40 | PROXY_SSH_KEY_ECDSA_521, 41 | PROXY_SSH_KEY_ED25519, 42 | PROXY_SSH_KEY_ED448 43 | }; 44 | 45 | /* Returns a string of colon-separated lowercase hex characters, representing 46 | * the key "fingerprint" which has been run through the specified digest 47 | * algorithm. 48 | * 49 | * As per draft-ietf-secsh-fingerprint-00, only MD5 fingerprints are currently 50 | * supported. 51 | */ 52 | const char *proxy_ssh_keys_get_fingerprint(pool *, unsigned char *, uint32_t, 53 | int); 54 | #define PROXY_SSH_KEYS_FP_DIGEST_MD5 1 55 | #define PROXY_SSH_KEYS_FP_DIGEST_SHA1 2 56 | #define PROXY_SSH_KEYS_FP_DIGEST_SHA256 3 57 | 58 | enum proxy_ssh_key_type_e proxy_ssh_keys_get_key_type(const char *algo); 59 | const char *proxy_ssh_keys_get_key_type_desc(enum proxy_ssh_key_type_e); 60 | 61 | void proxy_ssh_keys_free(void); 62 | int proxy_ssh_keys_have_hostkey(enum proxy_ssh_key_type_e); 63 | int proxy_ssh_keys_get_hostkey(pool *p, const char *); 64 | const unsigned char *proxy_ssh_keys_get_hostkey_data(pool *, 65 | enum proxy_ssh_key_type_e, uint32_t *); 66 | void proxy_ssh_keys_get_passphrases(void); 67 | int proxy_ssh_keys_set_passphrase_provider(const char *); 68 | const unsigned char *proxy_ssh_keys_sign_data(pool *, enum proxy_ssh_key_type_e, 69 | const unsigned char *, size_t, size_t *); 70 | #if defined(PR_USE_OPENSSL_ECC) 71 | int proxy_ssh_keys_validate_ecdsa_params(const EC_GROUP *, const EC_POINT *); 72 | #endif /* PR_USE_OPENSSL_ECC */ 73 | int proxy_ssh_keys_verify_pubkey_type(pool *, unsigned char *, uint32_t, 74 | enum proxy_ssh_key_type_e); 75 | int proxy_ssh_keys_verify_signed_data(pool *p, const char *pubkey_algo, 76 | unsigned char *pubkey_data, uint32_t pubkey_datalen, 77 | unsigned char *signature, uint32_t signaturelen, 78 | unsigned char *sig_data, size_t sig_datalen); 79 | 80 | #endif /* MOD_PROXY_SSH_KEYS_H */ 81 | -------------------------------------------------------------------------------- /include/proxy/ssh/msg.h: -------------------------------------------------------------------------------- 1 | /* 2 | * ProFTPD - mod_proxy SSH message API 3 | * Copyright (c) 2021-2025 TJ Saunders 4 | * 5 | * This program is free software; you can redistribute it and/or modify 6 | * it under the terms of the GNU General Public License as published by 7 | * the Free Software Foundation; either version 2 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * This program is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU General Public License 16 | * along with this program; if not, write to the Free Software 17 | * Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA. 18 | * 19 | * As a special exemption, TJ Saunders and other respective copyright holders 20 | * give permission to link this program with OpenSSL, and distribute the 21 | * resulting executable, without including the source code for OpenSSL in the 22 | * source distribution. 23 | */ 24 | 25 | #ifndef MOD_PROXY_SSH_MSG_H 26 | #define MOD_PROXY_SSH_MSG_H 27 | 28 | #include "mod_proxy.h" 29 | #include 30 | 31 | #if defined(PR_USE_OPENSSL_ECC) 32 | # include 33 | # include 34 | #endif /* PR_USE_OPENSSL_ECC */ 35 | 36 | uint32_t proxy_ssh_msg_read_byte(pool *p, unsigned char **buf, 37 | uint32_t *buflen, unsigned char *msg); 38 | uint32_t proxy_ssh_msg_read_bool(pool *p, unsigned char **buf, 39 | uint32_t *buflen, int *msg); 40 | uint32_t proxy_ssh_msg_read_data(pool *p, unsigned char **buf, 41 | uint32_t *buflen, size_t msglen, unsigned char **msg); 42 | #if defined(PR_USE_OPENSSL_ECC) 43 | uint32_t proxy_ssh_msg_read_ecpoint(pool *p, unsigned char **buf, 44 | uint32_t *buflen, const EC_GROUP *ec_group, EC_POINT **msg); 45 | #endif /* PR_USE_OPENSSL_ECC */ 46 | uint32_t proxy_ssh_msg_read_int(pool *p, unsigned char **buf, uint32_t *buflen, 47 | uint32_t *msg); 48 | uint32_t proxy_ssh_msg_read_long(pool *p, unsigned char **buf, uint32_t *buflen, 49 | uint64_t *msg); 50 | uint32_t proxy_ssh_msg_read_mpint(pool *p, unsigned char **buf, 51 | uint32_t *buflen, const BIGNUM **msg); 52 | uint32_t proxy_ssh_msg_read_string(pool *p, unsigned char **buf, 53 | uint32_t *buflen, char **msg); 54 | 55 | uint32_t proxy_ssh_msg_write_byte(unsigned char **buf, uint32_t *buflen, 56 | unsigned char msg); 57 | uint32_t proxy_ssh_msg_write_bool(unsigned char **buf, uint32_t *buflen, 58 | unsigned char msg); 59 | uint32_t proxy_ssh_msg_write_data(unsigned char **buf, uint32_t *buflen, 60 | const unsigned char *msg, size_t msglen, int include_len); 61 | #if defined(PR_USE_OPENSSL_ECC) 62 | uint32_t proxy_ssh_msg_write_ecpoint(unsigned char **buf, uint32_t *buflen, 63 | const EC_GROUP *ec_group, const EC_POINT *ec_point); 64 | #endif /* PR_USE_OPENSSL_ECC */ 65 | uint32_t proxy_ssh_msg_write_int(unsigned char **buf, uint32_t *buflen, 66 | uint32_t msg); 67 | uint32_t proxy_ssh_msg_write_long(unsigned char **buf, uint32_t *buflen, 68 | uint64_t msg); 69 | uint32_t proxy_ssh_msg_write_mpint(unsigned char **buf, uint32_t *buflen, 70 | const BIGNUM *msg); 71 | uint32_t proxy_ssh_msg_write_string(unsigned char **buf, uint32_t *buflen, 72 | const char *msg); 73 | 74 | #endif /* MOD_PROXY_SSH_MSG_H */ 75 | -------------------------------------------------------------------------------- /include/proxy/session.h: -------------------------------------------------------------------------------- 1 | /* 2 | * ProFTPD - mod_proxy sessions 3 | * Copyright (c) 2012-2021 TJ Saunders 4 | * 5 | * This program is free software; you can redistribute it and/or modify 6 | * it under the terms of the GNU General Public License as published by 7 | * the Free Software Foundation; either version 2 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * This program is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU General Public License 16 | * along with this program; if not, write to the Free Software 17 | * Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA. 18 | * 19 | * As a special exemption, TJ Saunders and other respective copyright holders 20 | * give permission to link this program with OpenSSL, and distribute the 21 | * resulting executable, without including the source code for OpenSSL in the 22 | * source distribution. 23 | */ 24 | 25 | #ifndef MOD_PROXY_SESSION_H 26 | #define MOD_PROXY_SESSION_H 27 | 28 | #include "mod_proxy.h" 29 | 30 | struct proxy_conn; 31 | 32 | struct proxy_session { 33 | struct pool_rec *pool; 34 | 35 | int connect_timeout; 36 | int connect_timerno; 37 | int linger_timeout; 38 | 39 | /* Frontend connection */ 40 | conn_t *frontend_ctrl_conn; 41 | conn_t *frontend_data_conn; 42 | volatile int frontend_sess_flags; 43 | const pr_netaddr_t *frontend_data_addr; 44 | 45 | /* Backend connection */ 46 | conn_t *backend_ctrl_conn; 47 | conn_t *backend_data_conn; 48 | volatile int backend_sess_flags; 49 | const pr_netaddr_t *backend_data_addr; 50 | 51 | /* Address for connections to/from destination server. May be null. */ 52 | const pr_netaddr_t *src_addr; 53 | 54 | const struct proxy_conn *dst_pconn; 55 | 56 | /* Address of the destination server. May be null. */ 57 | const pr_netaddr_t *dst_addr; 58 | array_header *other_addrs; 59 | 60 | /* Which protocol are we proxying? */ 61 | int use_ftp, use_ssh; 62 | 63 | /* Features supported by backend server. */ 64 | pr_table_t *backend_features; 65 | 66 | /* Data transfer pool, for things like the frontend/backend address 67 | * objects. 68 | */ 69 | pool *dataxfer_pool; 70 | 71 | /* Data transfer policy: PASV, EPSV, PORT, EPRT, or client. */ 72 | int dataxfer_policy; 73 | 74 | /* Directory list policy: LIST, or client. */ 75 | int dirlist_policy; 76 | unsigned long dirlist_opts; 77 | void *dirlist_ctx; 78 | }; 79 | 80 | /* Zero indicates "do what the client does". */ 81 | 82 | #define PROXY_SESS_DATA_TRANSFER_POLICY_DEFAULT 0 83 | 84 | #define PROXY_SESS_DIRECTORY_LIST_POLICY_DEFAULT 0 85 | #define PROXY_SESS_DIRECTORY_LIST_POLICY_LIST 1 86 | 87 | /* Default MaxLoginAttempts */ 88 | #define PROXY_SESS_MAX_LOGIN_ATTEMPTS 3 89 | 90 | const struct proxy_session *proxy_session_alloc(pool *p); 91 | int proxy_session_free(pool *p, const struct proxy_session *proxy_sess); 92 | int proxy_session_reset_dataxfer(struct proxy_session *proxy_sess); 93 | 94 | int proxy_session_check_password(pool *p, const char *user, const char *passwd); 95 | int proxy_session_setup_env(pool *p, const char *user, int flags); 96 | #define PROXY_SESSION_FL_CHECK_LOGIN_ACL 0x00001 97 | 98 | #endif /* MOD_PROXY_SESSION_H */ 99 | -------------------------------------------------------------------------------- /t/api/str.c: -------------------------------------------------------------------------------- 1 | /* 2 | * ProFTPD - mod_proxy testsuite 3 | * Copyright (c) 2020-2022 TJ Saunders 4 | * 5 | * This program is free software; you can redistribute it and/or modify 6 | * it under the terms of the GNU General Public License as published by 7 | * the Free Software Foundation; either version 2 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * This program is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU General Public License 16 | * along with this program; if not, write to the Free Software 17 | * Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA. 18 | * 19 | * As a special exemption, TJ Saunders and other respective copyright holders 20 | * give permission to link this program with OpenSSL, and distribute the 21 | * resulting executable, without including the source code for OpenSSL in the 22 | * source distribution. 23 | */ 24 | 25 | /* String API tests */ 26 | 27 | #include "tests.h" 28 | 29 | static pool *p = NULL; 30 | 31 | static void set_up(void) { 32 | if (p == NULL) { 33 | p = permanent_pool = make_sub_pool(NULL); 34 | } 35 | } 36 | 37 | static void tear_down(void) { 38 | if (p != NULL) { 39 | destroy_pool(p); 40 | p = permanent_pool = NULL; 41 | } 42 | } 43 | 44 | START_TEST (strnstr_test) { 45 | const char *s1, *s2; 46 | size_t len; 47 | char *res; 48 | 49 | mark_point(); 50 | res = proxy_strnstr(NULL, NULL, 0); 51 | ck_assert_msg(res == NULL, "Failed to handle null s1"); 52 | 53 | mark_point(); 54 | s1 = "haystack"; 55 | res = proxy_strnstr(s1, NULL, 0); 56 | ck_assert_msg(res == NULL, "Failed to handle null s2"); 57 | 58 | mark_point(); 59 | s2 = "needle"; 60 | res = proxy_strnstr(s1, s2, 0); 61 | ck_assert_msg(res == NULL, "Failed to handle zero len"); 62 | 63 | mark_point(); 64 | len = 2; 65 | res = proxy_strnstr(s1, s2, len); 66 | ck_assert_msg(res == NULL, "Expected null, got %p for len %lu", res, 67 | (unsigned long) len); 68 | 69 | mark_point(); 70 | s1 = " "; 71 | res = proxy_strnstr(s1, s2, len); 72 | ck_assert_msg(res == NULL, "Expected null, got %p for s1 spaces", res); 73 | 74 | mark_point(); 75 | s1 = "haystack"; 76 | s2 = ""; 77 | res = proxy_strnstr(s1, s2, len); 78 | ck_assert_msg(res == NULL, "Expected null, got %p for s2 empty", res); 79 | 80 | mark_point(); 81 | s1 = "haystack"; 82 | s2 = "haystack"; 83 | len = 8; 84 | res = proxy_strnstr(s1, s2, len); 85 | ck_assert_msg(res != NULL, "Expected %p, got %p for s1 == s2", s1, res); 86 | 87 | mark_point(); 88 | s1 = "haystack"; 89 | s2 = "sta"; 90 | len = 7; 91 | res = proxy_strnstr(s1, s2, len); 92 | ck_assert_msg(res != NULL, "Expected %p, got %p", s1 + 3, res); 93 | } 94 | END_TEST 95 | 96 | Suite *tests_get_str_suite(void) { 97 | Suite *suite; 98 | TCase *testcase; 99 | 100 | suite = suite_create("str"); 101 | testcase = tcase_create("base"); 102 | 103 | tcase_add_checked_fixture(testcase, set_up, tear_down); 104 | 105 | tcase_add_test(testcase, strnstr_test); 106 | 107 | suite_add_tcase(suite, testcase); 108 | return suite; 109 | } 110 | -------------------------------------------------------------------------------- /include/proxy/db.h: -------------------------------------------------------------------------------- 1 | /* 2 | * ProFTPD - mod_proxy database API 3 | * Copyright (c) 2015-2021 TJ Saunders 4 | * 5 | * This program is free software; you can redistribute it and/or modify 6 | * it under the terms of the GNU General Public License as published by 7 | * the Free Software Foundation; either version 2 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * This program is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU General Public License 16 | * along with this program; if not, write to the Free Software 17 | * Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA. 18 | * 19 | * As a special exemption, TJ Saunders and other respective copyright holders 20 | * give permission to link this program with OpenSSL, and distribute the 21 | * resulting executable, without including the source code for OpenSSL in the 22 | * source distribution. 23 | */ 24 | 25 | #ifndef MOD_PROXY_DB_H 26 | #define MOD_PROXY_DB_H 27 | 28 | #include "mod_proxy.h" 29 | 30 | struct proxy_dbh; 31 | 32 | int proxy_db_init(pool *p); 33 | int proxy_db_free(void); 34 | 35 | /* Create/prepare the database (with the given schema name) at the given path */ 36 | struct proxy_dbh *proxy_db_open(pool *p, const char *table_path, 37 | const char *schema_name); 38 | 39 | /* Create/prepare the database (with the given schema name) at the given path. 40 | * If the database/schema already exists, check that its schema version is 41 | * greater than or equal to the given minimum version. If not, delete that 42 | * database and create a new one. 43 | */ 44 | struct proxy_dbh *proxy_db_open_with_version(pool *p, const char *table_path, 45 | const char *schema_name, unsigned int schema_version, int flags); 46 | #define PROXY_DB_OPEN_FL_SCHEMA_VERSION_CHECK 0x001 47 | #define PROXY_DB_OPEN_FL_ERROR_ON_SCHEMA_VERSION_SKEW 0x002 48 | #define PROXY_DB_OPEN_FL_INTEGRITY_CHECK 0x004 49 | #define PROXY_DB_OPEN_FL_VACUUM 0x008 50 | #define PROXY_DB_OPEN_FL_SKIP_VACUUM 0x010 51 | 52 | /* Close the database. */ 53 | int proxy_db_close(pool *p, struct proxy_dbh *dbh); 54 | 55 | int proxy_db_prepare_stmt(pool *p, struct proxy_dbh *dbh, const char *stmt); 56 | int proxy_db_finish_stmt(pool *p, struct proxy_dbh *dbh, const char *stmt); 57 | int proxy_db_bind_stmt(pool *p, struct proxy_dbh *dbh, const char *stmt, 58 | int idx, int type, void *data, int datalen); 59 | #define PROXY_DB_BIND_TYPE_INT 1 60 | #define PROXY_DB_BIND_TYPE_LONG 2 61 | #define PROXY_DB_BIND_TYPE_TEXT 3 62 | #define PROXY_DB_BIND_TYPE_BLOB 4 63 | #define PROXY_DB_BIND_TYPE_NULL 5 64 | 65 | /* Executes the given statement. Assumes that the caller is not using a SELECT, 66 | * and/or is uninterested in the statement results. 67 | */ 68 | int proxy_db_exec_stmt(pool *p, struct proxy_dbh *dbh, const char *stmt, 69 | const char **errstr); 70 | 71 | /* Executes the given statement as a previously prepared statement. */ 72 | array_header *proxy_db_exec_prepared_stmt(pool *p, struct proxy_dbh *dbh, 73 | const char *stmt, const char **errstr); 74 | 75 | /* Rebuild the named index. */ 76 | int proxy_db_reindex(pool *p, struct proxy_dbh *dbh, const char *index_name, 77 | const char **errstr); 78 | 79 | #endif /* MOD_PROXY_DB_H */ 80 | -------------------------------------------------------------------------------- /t/api/random.c: -------------------------------------------------------------------------------- 1 | /* 2 | * ProFTPD - mod_proxy testsuite 3 | * Copyright (c) 2013-2022 TJ Saunders 4 | * 5 | * This program is free software; you can redistribute it and/or modify 6 | * it under the terms of the GNU General Public License as published by 7 | * the Free Software Foundation; either version 2 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * This program is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU General Public License 16 | * along with this program; if not, write to the Free Software 17 | * Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA. 18 | * 19 | * As a special exemption, TJ Saunders and other respective copyright holders 20 | * give permission to link this program with OpenSSL, and distribute the 21 | * resulting executable, without including the source code for OpenSSL in the 22 | * source distribution. 23 | */ 24 | 25 | /* Random API tests. */ 26 | 27 | #include "tests.h" 28 | 29 | static pool *p = NULL; 30 | 31 | static void set_up(void) { 32 | if (p == NULL) { 33 | p = make_sub_pool(NULL); 34 | session.c = NULL; 35 | session.notes = NULL; 36 | } 37 | 38 | proxy_random_init(); 39 | } 40 | 41 | static void tear_down(void) { 42 | if (p) { 43 | destroy_pool(p); 44 | p = NULL; 45 | session.c = NULL; 46 | session.notes = NULL; 47 | } 48 | } 49 | 50 | START_TEST (random_next_range_10_test) { 51 | register unsigned int i; 52 | long min, max; 53 | 54 | min = -4; 55 | max = 5; 56 | 57 | for (i = 0; i < 10; i++) { 58 | long num; 59 | 60 | num = proxy_random_next(min, max); 61 | ck_assert_msg(num >= min, "random number %ld less than minimum %ld", num, 62 | min); 63 | ck_assert_msg(num <= max, "random number %ld greater than maximum %ld", num, 64 | max); 65 | } 66 | } 67 | END_TEST 68 | 69 | START_TEST (random_next_range_1000_test) { 70 | register int i; 71 | long min, max; 72 | int count = 10, seen[10]; 73 | 74 | min = 0; 75 | max = count-1; 76 | 77 | memset(seen, 0, sizeof(seen)); 78 | 79 | for (i = 0; i < 1000; i++) { 80 | long num; 81 | 82 | num = proxy_random_next(min, max); 83 | ck_assert_msg(num >= min, "random number %ld less than minimum %ld", num, 84 | min); 85 | ck_assert_msg(num <= max, "random number %ld greater than maximum %ld", num, 86 | max); 87 | 88 | seen[num] = 1; 89 | } 90 | 91 | /* In 1000 rounds, the chances of seeing all 10 possible numbers is pretty 92 | * good, right? 93 | */ 94 | for (i = 0; i < count; i++) { 95 | ck_assert_msg(seen[i] == 1, "Expected to have generated number %d", i); 96 | } 97 | } 98 | END_TEST 99 | 100 | Suite *tests_get_random_suite(void) { 101 | Suite *suite; 102 | TCase *testcase; 103 | 104 | suite = suite_create("random"); 105 | 106 | testcase = tcase_create("base"); 107 | 108 | tcase_add_checked_fixture(testcase, set_up, tear_down); 109 | 110 | tcase_add_test(testcase, random_next_range_10_test); 111 | tcase_add_test(testcase, random_next_range_1000_test); 112 | 113 | suite_add_tcase(suite, testcase); 114 | return suite; 115 | } 116 | -------------------------------------------------------------------------------- /t/Makefile.in: -------------------------------------------------------------------------------- 1 | CC=@CC@ 2 | @SET_MAKE@ 3 | 4 | top_builddir=../../.. 5 | top_srcdir=../../.. 6 | module_srcdir=.. 7 | srcdir=@srcdir@ 8 | VPATH=@srcdir@ 9 | 10 | include $(top_srcdir)/Make.rules 11 | 12 | # Necessary redefinitions 13 | INCLUDES=-I. -I.. -I$(module_srcdir)/include -I../../.. -I../../../include @INCLUDES@ 14 | TEST_CPPFLAGS=$(ADDL_CPPFLAGS) -DHAVE_CONFIG_H $(DEFAULT_PATHS) $(PLATFORM) $(INCLUDES) 15 | TEST_LDFLAGS=-L$(top_srcdir)/lib @LIBDIRS@ 16 | 17 | EXEEXT=@EXEEXT@ 18 | 19 | TEST_API_DEPS=\ 20 | $(top_srcdir)/lib/prbase.a \ 21 | $(top_srcdir)/src/pool.o \ 22 | $(top_srcdir)/src/privs.o \ 23 | $(top_srcdir)/src/str.o \ 24 | $(top_srcdir)/src/sets.o \ 25 | $(top_srcdir)/src/table.o \ 26 | $(top_srcdir)/src/netacl.o \ 27 | $(top_srcdir)/src/class.o \ 28 | $(top_srcdir)/src/event.o \ 29 | $(top_srcdir)/src/timers.o \ 30 | $(top_srcdir)/src/stash.o \ 31 | $(top_srcdir)/src/modules.o \ 32 | $(top_srcdir)/src/cmd.o \ 33 | $(top_srcdir)/src/configdb.o \ 34 | $(top_srcdir)/src/parser.o \ 35 | $(top_srcdir)/src/regexp.o \ 36 | $(top_srcdir)/src/fsio.o \ 37 | $(top_srcdir)/src/netio.o \ 38 | $(top_srcdir)/src/inet.o \ 39 | $(top_srcdir)/src/netaddr.o \ 40 | $(top_srcdir)/src/response.o \ 41 | $(top_srcdir)/src/auth.o \ 42 | $(top_srcdir)/src/env.o \ 43 | $(top_srcdir)/src/trace.o \ 44 | $(top_srcdir)/src/support.o \ 45 | $(top_srcdir)/src/json.o \ 46 | $(top_srcdir)/src/redis.o \ 47 | $(top_srcdir)/src/error.o \ 48 | $(module_srcdir)/lib/proxy/random.o \ 49 | $(module_srcdir)/lib/proxy/db.o \ 50 | $(module_srcdir)/lib/proxy/dns.o \ 51 | $(module_srcdir)/lib/proxy/uri.o \ 52 | $(module_srcdir)/lib/proxy/conn.o \ 53 | $(module_srcdir)/lib/proxy/netio.o \ 54 | $(module_srcdir)/lib/proxy/inet.o \ 55 | $(module_srcdir)/lib/proxy/str.o \ 56 | $(module_srcdir)/lib/proxy/tls.o \ 57 | $(module_srcdir)/lib/proxy/tls/db.o \ 58 | $(module_srcdir)/lib/proxy/tls/redis.o \ 59 | $(module_srcdir)/lib/proxy/session.o \ 60 | $(module_srcdir)/lib/proxy/reverse.o \ 61 | $(module_srcdir)/lib/proxy/reverse/db.o \ 62 | $(module_srcdir)/lib/proxy/reverse/redis.o \ 63 | $(module_srcdir)/lib/proxy/forward.o \ 64 | $(module_srcdir)/lib/proxy/ftp/conn.o \ 65 | $(module_srcdir)/lib/proxy/ftp/ctrl.o \ 66 | $(module_srcdir)/lib/proxy/ftp/data.o \ 67 | $(module_srcdir)/lib/proxy/ftp/dirlist.o \ 68 | $(module_srcdir)/lib/proxy/ftp/facts.o \ 69 | $(module_srcdir)/lib/proxy/ftp/msg.o \ 70 | $(module_srcdir)/lib/proxy/ftp/sess.o \ 71 | $(module_srcdir)/lib/proxy/ftp/xfer.o 72 | 73 | TEST_API_LIBS="-lcheck -lm @MODULE_LIBS@" 74 | 75 | TEST_API_OBJS=\ 76 | api/random.o \ 77 | api/db.o \ 78 | api/dns.o \ 79 | api/uri.o \ 80 | api/conn.o \ 81 | api/netio.o \ 82 | api/inet.o \ 83 | api/str.o \ 84 | api/tls.o \ 85 | api/reverse.o \ 86 | api/forward.o \ 87 | api/session.o \ 88 | api/ftp/msg.o \ 89 | api/ftp/conn.o \ 90 | api/ftp/ctrl.o \ 91 | api/ftp/data.o \ 92 | api/ftp/dirlist.o \ 93 | api/ftp/facts.o \ 94 | api/ftp/sess.o \ 95 | api/ftp/xfer.o \ 96 | api/stubs.o \ 97 | api/tests.o 98 | 99 | dummy: 100 | 101 | api/.c.o: 102 | $(CC) $(CPPFLAGS) $(TEST_CPPFLAGS) $(CFLAGS) -c $< 103 | 104 | api-tests$(EXEEXT): $(TEST_API_OBJS) $(TEST_API_DEPS) 105 | $(LIBTOOL) --mode=link --tag=CC $(CC) $(LDFLAGS) $(TEST_LDFLAGS) -o $@ $(TEST_API_DEPS) $(TEST_API_OBJS) $(TEST_API_LIBS) $(LIBS) 106 | ./$@ 107 | 108 | clean: 109 | $(LIBTOOL) --mode=clean $(RM) *.o api/*.o api/*/*.o api-tests$(EXEEXT) api-tests.log 110 | -------------------------------------------------------------------------------- /doc/NOTES.proxy-datatransfer-policy: -------------------------------------------------------------------------------- 1 | 2 | Client: 3 | 4 | C -> P: PORT 1,2,3,4,5,6 P -> S: PORT 9,8,7,6,5,4 5 | C <- P: 200 OK P <- S: 200 OK 6 | 7 | C -> P: PASV P -> S: PASV 8 | C <- P: 227 (1,2,3,4,5,6) P <- S: 227 (9,8,7,6,5,4) 9 | 10 | Order of operations: 11 | 12 | C -> P: PORT 13 | Parse addr/port 14 | Check RFC1918 addr 15 | Check AllowForeignAddress 16 | Check high-numbered port 17 | 18 | Open local listening conn 19 | Format local listening addr for PORT command 20 | Send new PORT command to S 21 | Receive 200 OK response from S 22 | 23 | Send 200 OK response to C 24 | Set frontend_sess_flags = SF_PORT 25 | Set backend_sess_flags = SF_PORT 26 | 27 | C -> P: PASV 28 | Send PASV command to S 29 | Receive 227 response from S 30 | Parse addr/port 31 | Check addr against remote addr 32 | Check high-numbered port 33 | 34 | Open local listening conn 35 | Format local listening addr for PASV response 36 | Send new PASV response to C 37 | 38 | Set frontend_sess_flags = SF_PASSIVE 39 | Set backend_sess_flags = SF_PASSIVE 40 | 41 | 42 | Active: 43 | 44 | C -> P: PORT 1,2,3,4,5,6 P -> S: PORT 9,8,7,6,5,4 45 | C <- P: 200 OK P <- S: 200 OK 46 | 47 | C -> P: PASV P -> S: PORT 9,8,7,6,5,4 48 | C <- P: 227 (1,2,3,4,5,6) P <- S: 200 OK 49 | 50 | Order of operations: 51 | 52 | C -> P: PORT 53 | Parse addr/port 54 | Check RFC1918 addr 55 | Check AllowForeignAddress 56 | Check high-numbered port 57 | 58 | Open local listening conn 59 | Format local listening addr for PORT command 60 | Send new PORT command to S 61 | Receive 200 OK response from S 62 | 63 | Send 200 OK response to C 64 | Set frontend_sess_flags = SF_PORT 65 | Set backend_sess_flags = SF_PORT 66 | 67 | C -> P: PASV 68 | Open local listening conn 69 | Format local listening addr for PORT command 70 | Send new PORT command to S 71 | Receive 200 OK response from S 72 | 73 | Open local listening conn 74 | Format local listening addr for PASV response 75 | Send new PASV response to C 76 | 77 | Set frontend_sess_flags = SF_PASSIVE 78 | Set backend_sess_flags = SF_PORT 79 | 80 | 81 | Passive: 82 | 83 | C -> P: PORT 1,2,3,4,5,6 P -> S: PASV 84 | C <- P: 200 OK P <- S: 227 (9,8,7,6,5,4) 85 | 86 | C -> P: PASV P -> S: PASV 87 | C <- P: 227 (1,2,3,4,5,6) P <- S: 227 (9,8,7,6,5,4) 88 | 89 | Order of operations: 90 | 91 | C -> P: PORT 92 | Parse addr/port 93 | Check RFC1918 addr 94 | Check AllowForeignAddress 95 | Check high-numbered port 96 | 97 | Send new PASV command to S 98 | Receive 227 responses from S 99 | Parse addr/port 100 | Check addr against remote addr 101 | Check high-numbered port 102 | 103 | Send 200 OK response to C 104 | Set frontend_sess_flags = SF_PORT 105 | Set backend_sess_flags = SF_PASSIVE 106 | 107 | C -> P: PASV 108 | Send PASV command to S 109 | Receive 227 response from S 110 | Parse addr/port 111 | Check addr against remote addr 112 | Check high-numbered port 113 | 114 | Open local listening conn 115 | Format local listening addr for PASV response 116 | Send new PASV response to C 117 | 118 | Set frontend_sess_flags = SF_PASSIVE 119 | Set backend_sess_flags = SF_PASSIVE 120 | 121 | -------------------------------------------------------------------------------- /doc/REFERENCES: -------------------------------------------------------------------------------- 1 | 2 | Stateful Inspection Advantage (Checkpoint): 3 | http://www.checkpoint.com/smb/help/z100g/7.5/7082.htm 4 | 5 | Linux Load Balancing with HAProxy + Heartbeat: 6 | https://wiki.gogrid.com/wiki/index.php/Customer:Linux_Load_Balancing_with_HAProxy+Heartbeat 7 | 8 | Load Balancing OpenSSH SFTP with HAProxy: 9 | http://jpmorris-iso.blogspot.com/2013/01/load-balancing-openssh-sftp-with-haproxy.html 10 | 11 | HAproxy PROXY protocol 12 | http://haproxy.1wt.eu/download/1.5/doc/proxy-protocol.txt 13 | 14 | FTP Load Balancing? 15 | http://www.formilux.org/archives/haproxy/0805/0976.html 16 | http://www.formilux.org/archives/haproxy/0805/0977.html 17 | 18 | Best way to use HAProxy for FTP? 19 | http://permalink.gmane.org/gmane.comp.web.haproxy/2486 20 | 21 | Load Balancing FTP: 22 | http://ben.timby.com/?page_id=210 23 | 24 | FTP Load-balanced through haproxy: 25 | http://www.taiter.com/techlog/2012/09/ftp-load-balanced-through-haproxy.html 26 | 27 | Network Load Balancing Services (MSFT): 28 | http://en.wikipedia.org/wiki/Network_Load_Balancing_Services 29 | 30 | Network Load Balancing: 31 | http://en.wikipedia.org/wiki/Network_Load_Balancing 32 | 33 | NcFTP.com "Why PASV Poses Problems for FTP Servers behind Load-Balancing Routers" 34 | http://www.ncftp.com/ncftpd/doc/misc/ftp_and_firewalls.html#PASVLBProblems 35 | 36 | ftpcluster: 37 | http://www.awk-scripting.de/cluster/ 38 | 39 | Brane Dump: Load Balancing FTP servers 40 | http://hezmatt.org/~mpalmer/blog/2008/10/22/load-balancing-ftp-servers.html 41 | 42 | Opensource load balancer projects: 43 | http://www.inlab.de/articles/free-and-open-source-load-balancing-software-and-projects.html 44 | http://sourceforge.net/projects/balance/ 45 | 46 | FTP ALG: 47 | http://www.amaranten.com/support/user%20guide/Application_Layer_Gateways/FTP_ALG.htm 48 | http://www.ietf.org/id/draft-tsou-behave-ftp46-00.txt 49 | 50 | Breaking through FTP ALGs: possible? 51 | http://seclists.org/bugtraq/2000/Feb/176 52 | http://seclists.org/vuln-dev/2000/Feb/82 53 | https://listserv.icsalabs.com/pipermail/firewall-wizards/2000-March/008251.html 54 | 55 | AWS ELB for FTP: 56 | https://forums.aws.amazon.com/thread.jspa?messageID=139143 57 | 58 | Trilent FTP Proxy: 59 | http://trilent-ftp-proxy.en.softonic.com/ 60 | 61 | ServerFault: 62 | Reverse Proxy FTP traffic: 63 | http://serverfault.com/questions/122636/reverse-proxy-ftp-traffic 64 | 65 | Search on an FTP server: 66 | http://serverfault.com/questions/28568/using-the-find-command-on-the-ftp-server?rq=1 67 | 68 | FTP Load balancer: 69 | http://serverfault.com/questions/139342/ftp-load-balancer?rq=1 70 | 71 | Possible to load balance FTP? 72 | http://serverfault.com/questions/113456/is-it-possible-to-load-balance-an-ftp-server 73 | 74 | frox as reverse proxy? 75 | http://serverfault.com/questions/390043/frox-as-reverse-proxy 76 | 77 | proxy and reverse proxy on same server 78 | http://serverfault.com/questions/65133/proxy-and-reverse-proxy-on-same-server?rq=1 79 | 80 | FTP/SFTP/FTPS proxying 81 | http://serverfault.com/questions/117899/ftp-sftp-ftps-proxying?rq=1 82 | 83 | X-Forwarded-For 84 | http://stackoverflow.com/questions/11891185/x-forward-for-over-ssl-using-load-balancers?rq=1 85 | 86 | Reverse proxy capabilities: 87 | http://www.rhinosoft.com/pressarchive/PressRelease2012-05-10.asp?prod=rs 88 | 89 | Diagrams: 90 | http://pic.dhe.ibm.com/infocenter/ssp/v3r4/index.jsp?topic=%2Fcom.ibm.help.sspftpreverseproxy.doc%2FSSP_FTS_FTPRProxCfg.html 91 | http://pic.dhe.ibm.com/infocenter/ssp/v3r4/index.jsp?topic=%2Fcom.ibm.help.sspoverview.doc%2FSSP_Diag_FinishedFTPRev.html 92 | http://pic.dhe.ibm.com/infocenter/ssp/v3r4/index.jsp?topic=%2Fcom.ibm.help.sspoverview.doc%2FSSP_Diag_FinishSFTPRev.html 93 | -------------------------------------------------------------------------------- /lib/proxy/ftp/facts.c: -------------------------------------------------------------------------------- 1 | /* 2 | * ProFTPD - mod_proxy FTP Facts routines 3 | * Copyright (c) 2020 TJ Saunders 4 | * 5 | * This program is free software; you can redistribute it and/or modify 6 | * it under the terms of the GNU General Public License as published by 7 | * the Free Software Foundation; either version 2 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * This program is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU General Public License 16 | * along with this program; if not, write to the Free Software 17 | * Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA. 18 | * 19 | * As a special exemption, TJ Saunders and other respective copyright holders 20 | * give permission to link this program with OpenSSL, and distribute the 21 | * resulting executable, without including the source code for OpenSSL in the 22 | * source distribution. 23 | */ 24 | 25 | #include "mod_proxy.h" 26 | 27 | #include "proxy/ftp/facts.h" 28 | 29 | /* Similar to those of mod_facts. */ 30 | 31 | /* NOTE: We only want to parse/handle any OPTS MLST commands from the frontend 32 | * client IFF the DirectoryListPolicy is "LIST". Otherwise, let the backend 33 | * handle them. But...what if the backend doesn't support OPTS MLST? Do 34 | * we watch for that error, and handle it ourselves (e.g. show our defaults)? 35 | */ 36 | 37 | static unsigned long facts_opts = PROXY_FTP_FACTS_OPT_SHOW_MODIFY| 38 | PROXY_FTP_FACTS_OPT_SHOW_PERM| 39 | PROXY_FTP_FACTS_OPT_SHOW_SIZE| 40 | PROXY_FTP_FACTS_OPT_SHOW_TYPE| 41 | PROXY_FTP_FACTS_OPT_SHOW_UNIQUE| 42 | PROXY_FTP_FACTS_OPT_SHOW_UNIX_GROUP| 43 | PROXY_FTP_FACTS_OPT_SHOW_UNIX_GROUP_NAME| 44 | PROXY_FTP_FACTS_OPT_SHOW_UNIX_MODE| 45 | PROXY_FTP_FACTS_OPT_SHOW_UNIX_OWNER| 46 | PROXY_FTP_FACTS_OPT_SHOW_UNIX_OWNER_NAME; 47 | 48 | static const char *trace_channel = "proxy.ftp.facts"; 49 | 50 | unsigned long proxy_ftp_facts_get_opts(void) { 51 | return facts_opts; 52 | } 53 | 54 | void proxy_ftp_facts_parse_opts(char *facts) { 55 | unsigned long opts = 0UL; 56 | char *ptr; 57 | 58 | if (facts == NULL) { 59 | return; 60 | } 61 | 62 | ptr = strchr(facts, ';'); 63 | while (ptr != NULL) { 64 | pr_signals_handle(); 65 | 66 | *ptr = '\0'; 67 | 68 | if (strcasecmp(facts, "modify") == 0) { 69 | opts |= PROXY_FTP_FACTS_OPT_SHOW_MODIFY; 70 | 71 | } else if (strcasecmp(facts, "perm") == 0) { 72 | opts |= PROXY_FTP_FACTS_OPT_SHOW_PERM; 73 | 74 | } else if (strcasecmp(facts, "size") == 0) { 75 | opts |= PROXY_FTP_FACTS_OPT_SHOW_SIZE; 76 | 77 | } else if (strcasecmp(facts, "type") == 0) { 78 | opts |= PROXY_FTP_FACTS_OPT_SHOW_TYPE; 79 | 80 | } else if (strcasecmp(facts, "unique") == 0) { 81 | opts |= PROXY_FTP_FACTS_OPT_SHOW_UNIQUE; 82 | 83 | } else if (strcasecmp(facts, "UNIX.group") == 0) { 84 | opts |= PROXY_FTP_FACTS_OPT_SHOW_UNIX_GROUP; 85 | 86 | } else if (strcasecmp(facts, "UNIX.groupname") == 0) { 87 | opts |= PROXY_FTP_FACTS_OPT_SHOW_UNIX_GROUP_NAME; 88 | 89 | } else if (strcasecmp(facts, "UNIX.mode") == 0) { 90 | opts |= PROXY_FTP_FACTS_OPT_SHOW_UNIX_MODE; 91 | 92 | } else if (strcasecmp(facts, "UNIX.owner") == 0) { 93 | opts |= PROXY_FTP_FACTS_OPT_SHOW_UNIX_OWNER; 94 | 95 | } else if (strcasecmp(facts, "UNIX.ownername") == 0) { 96 | opts |= PROXY_FTP_FACTS_OPT_SHOW_UNIX_OWNER_NAME; 97 | 98 | } else { 99 | pr_trace_msg(trace_channel, 7, 100 | "client requested unsupported fact '%s'", facts); 101 | } 102 | 103 | *ptr = ';'; 104 | facts = ptr + 1; 105 | ptr = strchr(facts, ';'); 106 | } 107 | 108 | facts_opts = opts; 109 | } 110 | -------------------------------------------------------------------------------- /include/proxy/ssh/interop.h: -------------------------------------------------------------------------------- 1 | /* 2 | * ProFTPD - mod_proxy SSH interop API 3 | * Copyright (c) 2021-2025 TJ Saunders 4 | * 5 | * This program is free software; you can redistribute it and/or modify 6 | * it under the terms of the GNU General Public License as published by 7 | * the Free Software Foundation; either version 2 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * This program is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU General Public License 16 | * along with this program; if not, write to the Free Software 17 | * Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA. 18 | * 19 | * As a special exemption, TJ Saunders and other respective copyright holders 20 | * give permission to link this program with OpenSSL, and distribute the 21 | * resulting executable, without including the source code for OpenSSL in the 22 | * source distribution. 23 | */ 24 | 25 | #ifndef MOD_PROXY_SSH_INTEROP_H 26 | #define MOD_PROXY_SSH_INTEROP_H 27 | 28 | #include "mod_proxy.h" 29 | #include "proxy/session.h" 30 | 31 | /* For servers which do not support IGNORE packets */ 32 | #define PROXY_SSH_FEAT_IGNORE_MSG 0x0001 33 | 34 | /* For servers which always truncate the HMAC len to 16 bits, regardless 35 | * of the actual HMAC len. 36 | */ 37 | #define PROXY_SSH_FEAT_MAC_LEN 0x0002 38 | 39 | /* For servers which do not include K when deriving cipher keys. */ 40 | #define PROXY_SSH_FEAT_CIPHER_USE_K 0x0004 41 | 42 | /* For servers which do not support rekeying */ 43 | #define PROXY_SSH_FEAT_REKEYING 0x0008 44 | 45 | /* For servers which do not support USERAUTH_BANNER packets */ 46 | #define PROXY_SSH_FEAT_USERAUTH_BANNER 0x0010 47 | 48 | /* For servers which do not send a string indicating the public key 49 | * algorithm in their publickey authentication requests. This also 50 | * includes servers which do not use the string "publickey", and the 51 | * string for the public key algorithm, in the public key signature 52 | * (as dictated by Section 7 of RFC4252). 53 | */ 54 | #define PROXY_SSH_FEAT_HAVE_PUBKEY_ALGO 0x0020 55 | 56 | /* For servers whose publickey signatures always use a service name of 57 | * "ssh-userauth", regardless of the actual service name included in the 58 | * USERAUTH_REQUEST packet. 59 | */ 60 | #define PROXY_SSH_FEAT_SERVICE_IN_PUBKEY_SIG 0x0040 61 | 62 | /* For servers whose DSA publickey signatures do not include the string 63 | * "ssh-dss". 64 | */ 65 | #define PROXY_SSH_FEAT_HAVE_PUBKEY_ALGO_IN_DSA_SIG 0x0080 66 | 67 | /* For servers whose hostbased signatures always use a service name of 68 | * "ssh-userauth", regardless of the actual service name included in the 69 | * USERAUTH_REQUEST packet. 70 | */ 71 | #define PROXY_SSH_FEAT_SERVICE_IN_HOST_SIG 0x0100 72 | 73 | /* For servers that want the client to pessimistically send its NEWKEYS message 74 | * after they send their NEWKEYS message. 75 | */ 76 | #define PROXY_SSH_FEAT_PESSIMISTIC_NEWKEYS 0x0200 77 | 78 | /* For servers which cannot/do not tolerate non-kex related packets after a 79 | * client has requested rekeying. 80 | */ 81 | #define PROXY_SSH_FEAT_NO_DATA_WHILE_REKEYING 0x0400 82 | 83 | /* For servers which do not support/implement RFC 4419 DH group exchange. */ 84 | #define PROXY_SSH_FEAT_DH_NEW_GEX 0x0800 85 | 86 | /* Compares the given server version string against a table of known server 87 | * versions and their interoperability/compatibility issues. 88 | */ 89 | int proxy_ssh_interop_handle_version(pool *, const struct proxy_session *, 90 | const char *); 91 | 92 | /* Returns TRUE if the server supports the requested feature, FALSE 93 | * otherwise. 94 | */ 95 | int proxy_ssh_interop_supports_feature(int); 96 | 97 | int proxy_ssh_interop_init(void); 98 | int proxy_ssh_interop_free(void); 99 | 100 | #endif /* MOD_PROXY_SSH_INTEROP_H */ 101 | -------------------------------------------------------------------------------- /tests.pl: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env perl 2 | 3 | use strict; 4 | 5 | use Cwd qw(abs_path); 6 | use File::Spec; 7 | use Getopt::Long; 8 | use Test::Harness qw(&runtests $verbose); 9 | 10 | my $opts = {}; 11 | GetOptions($opts, 'h|help', 'C|class=s@', 'K|keep-tmpfiles', 'F|file-pattern=s', 12 | 'V|verbose'); 13 | 14 | if ($opts->{h}) { 15 | usage(); 16 | } 17 | 18 | if ($opts->{K}) { 19 | $ENV{KEEP_TMPFILES} = 1; 20 | } 21 | 22 | $verbose = 1; 23 | 24 | if ($opts->{V}) { 25 | $ENV{TEST_VERBOSE} = 1; 26 | } 27 | 28 | # We use this, rather than use(), since use() is equivalent to a BEGIN 29 | # block, and we want the module to be loaded at run-time. 30 | 31 | if ($ENV{PROFTPD_TEST_DIR}) { 32 | push(@INC, "$ENV{PROFTPD_TEST_DIR}/t/lib"); 33 | } 34 | 35 | my $test_dir = (File::Spec->splitpath(abs_path(__FILE__)))[1]; 36 | push(@INC, "$test_dir/t/lib"); 37 | 38 | require ProFTPD::TestSuite::Utils; 39 | import ProFTPD::TestSuite::Utils qw(:testsuite); 40 | 41 | # This is to handle the case where this tests.pl script might be 42 | # being used to run test files other than those that ship with proftpd, 43 | # e.g. to run the tests that come with third-party modules. 44 | unless (defined($ENV{PROFTPD_TEST_BIN})) { 45 | $ENV{PROFTPD_TEST_BIN} = File::Spec->catfile($test_dir, '..', 'proftpd'); 46 | } 47 | 48 | $| = 1; 49 | 50 | my $test_files; 51 | 52 | if (scalar(@ARGV) > 0) { 53 | $test_files = [@ARGV]; 54 | 55 | } else { 56 | $test_files = [qw( 57 | t/modules/mod_proxy.t 58 | )]; 59 | 60 | # Now interrogate the build to see which module/feature-specific test files 61 | # should be added to the list. 62 | my $order = 0; 63 | 64 | my $FEATURE_TESTS = { 65 | 't/modules/mod_proxy/ban.t' => { 66 | order => ++$order, 67 | test_class => [qw(mod_ban mod_proxy)], 68 | }, 69 | 70 | 't/modules/mod_proxy/redis.t' => { 71 | order => ++$order, 72 | test_class => [qw(feature_redis mod_proxy)], 73 | }, 74 | 75 | 't/modules/mod_proxy/reverse/ipv6.t' => { 76 | order => ++$order, 77 | test_class => [qw(feature_ipv6 mod_proxy)], 78 | }, 79 | 80 | 't/modules/mod_proxy/sql.t' => { 81 | order => ++$order, 82 | test_class => [qw(mod_proxy mod_sql mod_sql_sqlite)], 83 | }, 84 | 85 | 't/modules/mod_proxy/ssh.t' => { 86 | order => ++$order, 87 | test_class => [qw(mod_proxy mod_sftp)], 88 | }, 89 | 90 | 't/modules/mod_proxy/tls.t' => { 91 | order => ++$order, 92 | test_class => [qw(mod_proxy mod_tls)], 93 | }, 94 | 95 | 't/modules/mod_proxy/tls/redis.t' => { 96 | order => ++$order, 97 | test_class => [qw(feature_redis mod_proxy mod_tls)], 98 | }, 99 | }; 100 | 101 | my @feature_tests = testsuite_get_runnable_tests($FEATURE_TESTS); 102 | my $feature_ntests = scalar(@feature_tests); 103 | if ($feature_ntests > 1 || 104 | ($feature_ntests == 1 && $feature_tests[0] ne 'testsuite_empty_test')) { 105 | push(@$test_files, @feature_tests); 106 | } 107 | } 108 | 109 | $ENV{PROFTPD_TEST} = 1; 110 | 111 | if (defined($opts->{C})) { 112 | $ENV{PROFTPD_TEST_ENABLE_CLASS} = join(':', @{ $opts->{C} }); 113 | 114 | } else { 115 | # Disable all 'flaky', 'inprogress' and 'slow' tests by default 116 | $ENV{PROFTPD_TEST_DISABLE_CLASS} = 'flaky:inprogress:slow'; 117 | } 118 | 119 | if (defined($opts->{F})) { 120 | # Using the provided string as a regex, and run only the tests whose 121 | # files match the pattern 122 | 123 | my $file_pattern = $opts->{F}; 124 | 125 | my $filtered_files = []; 126 | foreach my $test_file (@$test_files) { 127 | if ($test_file =~ /$file_pattern/) { 128 | push(@$filtered_files, $test_file); 129 | } 130 | } 131 | 132 | $test_files = $filtered_files; 133 | } 134 | 135 | runtests(@$test_files) if scalar(@$test_files) > 0; 136 | 137 | exit 0; 138 | 139 | sub usage { 140 | print STDOUT <backend_ctrl_conn, pkt); 40 | if (res < 0) { 41 | destroy_pool(pkt->pool); 42 | return -1; 43 | } 44 | 45 | destroy_pool(pkt->pool); 46 | proxy_ssh_packet_get_poll_attempts(&poll_attempts); 47 | proxy_ssh_packet_get_poll_timeout(&poll_timeout_secs, &poll_timeout_ms); 48 | 49 | proxy_ssh_packet_set_poll_attempts(3); 50 | proxy_ssh_packet_set_poll_timeout(0, 250); 51 | 52 | while (TRUE) { 53 | pr_signals_handle(); 54 | 55 | pkt = proxy_ssh_packet_create(proxy_pool); 56 | res = proxy_ssh_packet_read(proxy_sess->backend_ctrl_conn, pkt); 57 | if (res < 0) { 58 | xerrno = errno; 59 | 60 | destroy_pool(pkt->pool); 61 | proxy_ssh_packet_set_poll_attempts(poll_attempts); 62 | proxy_ssh_packet_set_poll_timeout(poll_timeout_secs, poll_timeout_ms); 63 | 64 | errno = xerrno; 65 | return -1; 66 | } 67 | 68 | msg_type = proxy_ssh_packet_peek_msg_type(pkt); 69 | 70 | pr_trace_msg(trace_channel, 3, "received %s (%d) packet (from mod_%s.c)", 71 | proxy_ssh_packet_get_msg_type_desc(msg_type), msg_type, 72 | pkt->m->name); 73 | 74 | /* Be sure to handle the messages that can come at any time as well. */ 75 | switch (msg_type) { 76 | case PROXY_SSH_MSG_SERVICE_ACCEPT: 77 | /* Expected */ 78 | break; 79 | 80 | case PROXY_SSH_MSG_DEBUG: 81 | case PROXY_SSH_MSG_DISCONNECT: 82 | case PROXY_SSH_MSG_EXT_INFO: 83 | case PROXY_SSH_MSG_IGNORE: 84 | case PROXY_SSH_MSG_UNIMPLEMENTED: 85 | proxy_ssh_packet_handle(pkt); 86 | continue; 87 | 88 | default: 89 | proxy_ssh_packet_set_poll_attempts(poll_attempts); 90 | proxy_ssh_packet_set_poll_timeout(poll_timeout_secs, poll_timeout_ms); 91 | destroy_pool(pkt->pool); 92 | 93 | /* Invalid protocol sequence */ 94 | (void) pr_log_writefile(proxy_logfd, MOD_PROXY_VERSION, 95 | "received unexpected %s packet during SSH service setup, failing", 96 | proxy_ssh_packet_get_msg_type_desc(msg_type)); 97 | errno = ENOSYS; 98 | return -1; 99 | } 100 | 101 | break; 102 | } 103 | 104 | proxy_ssh_packet_set_poll_attempts(poll_attempts); 105 | proxy_ssh_packet_set_poll_timeout(poll_timeout_secs, poll_timeout_ms); 106 | 107 | proxy_ssh_packet_log_cmd(pkt, FALSE); 108 | res = proxy_ssh_packet_proxied(proxy_sess, pkt, FALSE); 109 | xerrno = errno; 110 | 111 | destroy_pool(pkt->pool); 112 | errno = xerrno; 113 | return res; 114 | } 115 | -------------------------------------------------------------------------------- /.github/workflows/regressions.yml: -------------------------------------------------------------------------------- 1 | name: Regression Tests 2 | 3 | on: 4 | push: 5 | branches: 6 | - master 7 | paths-ignore: 8 | - '*.html' 9 | - '*.md' 10 | pull_request: 11 | branches: 12 | - master 13 | 14 | jobs: 15 | build: 16 | runs-on: ubuntu-latest 17 | 18 | env: 19 | # We need to avoid using NodeJS v20, because it doesn't work with 20 | # older glibc versions. See: 21 | # https://github.com/actions/checkout/issues/1809. 22 | ACTIONS_ALLOW_USE_UNSECURE_NODE_VERSION: true 23 | 24 | DEBIAN_FRONTEND: noninteractive 25 | REDIS_HOST: redis 26 | TZ: America/Los_Angeles 27 | 28 | services: 29 | redis: 30 | # Docker Hub image 31 | image: redis:6-alpine 32 | # Set health checks to wait until redis has started 33 | options: >- 34 | --health-cmd "redis-cli ping" 35 | --health-interval 10s 36 | --health-timeout 5s 37 | --health-retries 5 38 | 39 | strategy: 40 | matrix: 41 | compiler: 42 | - gcc 43 | container: 44 | - ubuntu:22.04 45 | 46 | container: ${{ matrix.container }} 47 | 48 | steps: 49 | - name: Checkout ProFTPD 50 | uses: actions/checkout@v3 51 | with: 52 | repository: proftpd/proftpd 53 | path: proftpd 54 | 55 | - name: Checkout mod_proxy_protocol source code 56 | uses: actions/checkout@v3 57 | with: 58 | repository: Castaglia/proftpd-mod_proxy_protocol 59 | path: mod_proxy_protocol 60 | 61 | - name: Checkout module source code 62 | uses: actions/checkout@v3 63 | with: 64 | path: proftpd/contrib/mod_proxy 65 | 66 | - name: Install Ubuntu packages 67 | run: | 68 | apt-get update -qq 69 | # for builds 70 | apt-get install -y gcc git make tzdata 71 | 72 | # for Redis support 73 | apt-get install -y libhiredis-dev 74 | # for OpenSSL support 75 | apt-get install -y libssl-dev 76 | # for SQLite support 77 | apt-get install -y libsqlite3-dev sqlite3 78 | # for Sodium support 79 | apt-get install -y --force-yes libsodium-dev 80 | 81 | # for integration/regression tests 82 | apt-get install -y \ 83 | libauthen-oath-perl \ 84 | libcompress-raw-zlib-perl \ 85 | libdata-dumper-simple-perl \ 86 | libdatetime-perl \ 87 | libfile-copy-recursive-perl \ 88 | libfile-path-tiny-perl \ 89 | libfile-spec-native-perl \ 90 | libmime-base32-perl \ 91 | libnet-address-ip-local-perl \ 92 | libnet-inet6glue-perl \ 93 | libnet-ssh2-perl \ 94 | libnet-ssleay-perl \ 95 | libnet-telnet-perl \ 96 | libposix-2008-perl \ 97 | libtest-unit-perl \ 98 | libtime-hr-perl \ 99 | libwww-perl 100 | PERL_MM_USE_DEFAULT=1 perl -MCPAN -e 'install Net::FTPSSL' 101 | 102 | # for debugging 103 | gcc --version 104 | openssl version -a 105 | 106 | - name: Prepare source code 107 | run: | 108 | cp mod_proxy_protocol/mod_proxy_protocol.c proftpd/contrib/mod_proxy_protocol.c 109 | 110 | - name: Install with static modules 111 | # NOTE: Docker does not have good IPv6 support, hence we disable it. 112 | run: | 113 | cd proftpd 114 | ./configure --enable-ctrls --disable-ipv6 --enable-redis --with-modules=mod_ban:mod_rewrite:mod_sftp:mod_auth_otp:mod_sql:mod_sql_sqlite:mod_tls:mod_tls_shmcache:mod_proxy:mod_unique_id:mod_proxy_protocol 115 | make 116 | ./proftpd -V 117 | make install 118 | 119 | - name: Run integration tests 120 | env: 121 | PROFTPD_TEST_BIN: /usr/local/sbin/proftpd 122 | PROFTPD_TEST_CI: github 123 | PROFTPD_TEST_DIR: ${{ github.workspace }}/proftpd/tests 124 | run: | 125 | cd proftpd/contrib/mod_proxy 126 | perl tests.pl 127 | -------------------------------------------------------------------------------- /doc/NOTES.load-balancing: -------------------------------------------------------------------------------- 1 | 2 | ProxyReverseConnectPolicy Random RoundRobin LeastConns PerUser PerHost 3 | 4 | on startup event, iterate through configured backend servers, mark which 5 | ones cannot be connected to as "dead". 6 | Means backend server list management, with attributes: 7 | server: 8 | connCount 9 | connectTime 10 | lastChecked 11 | 12 | Or, better: TWO lists: live list, dead list 13 | 14 | For tracking connectTime (time to connect, in millisecs): 15 | 16 | long timevaldiff(struct timeval *starttime, struct timeval *finishtime) { 17 | long msec; 18 | msec=(finishtime->tv_sec-starttime->tv_sec)*1000; 19 | msec+=(finishtime->tv_usec-starttime->tv_usec)/1000; 20 | return msec; 21 | } 22 | 23 | struct timeval start, finish; 24 | long msec; 25 | 26 | gettimeofday(&start, NULL); 27 | sleep(1); 28 | gettimeofday(&finish, NULL); 29 | msec = timevaldiff(&start, &finish); 30 | printf("Elapsed time for sleep(1) is: %d milliseconds.\n", msec); 31 | 32 | Some platforms have a timersub(3) macro for this, but it'll be more 33 | portable to do our own. 34 | 35 | Advanced balancing (selection at USER time): 36 | 37 | user-specific (lookup per user) 38 | Randomly select N backend servers for user if not already assigned? 39 | 40 | host-specific (lookup per HOST) 41 | Randomly select N backend servers for host if not already assigned? 42 | 43 | 44 | For stickiness, we have two cases: one where the backend(s) are administratively 45 | assigned, and one where they are randomly chosen/assigned. Assume the former 46 | is the more common case. 47 | 48 | Could do: 49 | ConnectPolicy PerUser/PerHost 50 | Servers ... 51 | 52 | with no specific assignments. In this case, the username/client IP 53 | is hashed into an index of one of the servers, and kept that way. Let's 54 | start with that as the first iteration. 55 | 56 | Next: 57 | ConnectPolicy PerUser/PerHost 58 | 59 | 60 | ReverseServers ... 61 | 62 | 63 | FAQ: Why no PerClass stickiness? 64 | A: It's the same as PerHost, with the added use of +ReverseServers 65 | 66 | FAQ: Why no per-SSL session/ticket/SNI stickiness? 67 | A: It's too late; TLS is hop-by-hop, and thus the SSL session on the frontend, 68 | with the client, has no relation to the SSL session on the backend. Thus 69 | any routing based on SSL session ID to a backend, based on the client's 70 | session ID, is too late -- and that client session is for the proxy anyway. 71 | 72 | We should to load balancing based on TLS protocol version, weak ciphers, etc, 73 | but that would be to a pool of backend servers, NOT "sticky". 74 | 75 | Complex/adaptive balancing: 76 | 77 | Client IP address/class (connect time selection) 78 | FTP USER (i.e. user affinity to specific server(s)) (USER time selection) 79 | lookup AND hashed (algo? Same algo used by Table API?) 80 | Backend response time (connect time selection) 81 | 82 | Balancing Versus Stickiness 83 | 84 | For reverse proxy configurations, there is a choice between "balancing" 85 | strategies and "sticky" strategies when it comes to selecting the backend 86 | server that will handle the incoming connection. 87 | 88 | Which should you use, and why? 89 | 90 | All of the "balancing" strategies are able to select the backend server *at 91 | connect time*. Most of the "sticky" strategies, on the other hand, require 92 | more knowledge about the user (e.g. USER name, HOST name, SSL session ID), 93 | thus backend server selection is delayed until that information is obtained. 94 | 95 | Balancing is best when all of your backend severs are identical with regard to 96 | the content they have, AND when it doesn't matter which server handles a 97 | particular client. Maybe all of your backend servers use a shared filesystem 98 | via NFS or similar, thus directory listings will be the same for a user no 99 | matter which backend server is used, and uploading files to one server means 100 | that those files can be downloaded/seen by the other servers. 101 | 102 | Stickiness is best when your backend servers are NOT identical, and some 103 | users/clients should only ever go to some particular set of backend servers. 104 | Thus the user/client needs to be "sticky" to a given backend server(s) -- 105 | that's when you need the sticky selection strategies. 106 | -------------------------------------------------------------------------------- /include/proxy/reverse.h: -------------------------------------------------------------------------------- 1 | /* 2 | * ProFTPD - mod_proxy reverse-proxy API 3 | * Copyright (c) 2012-2022 TJ Saunders 4 | * 5 | * This program is free software; you can redistribute it and/or modify 6 | * it under the terms of the GNU General Public License as published by 7 | * the Free Software Foundation; either version 2 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * This program is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU General Public License 16 | * along with this program; if not, write to the Free Software 17 | * Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA. 18 | * 19 | * As a special exemption, TJ Saunders and other respective copyright holders 20 | * give permission to link this program with OpenSSL, and distribute the 21 | * resulting executable, without including the source code for OpenSSL in the 22 | * source distribution. 23 | */ 24 | 25 | #ifndef MOD_PROXY_REVERSE_H 26 | #define MOD_PROXY_REVERSE_H 27 | 28 | #include "mod_proxy.h" 29 | #include "proxy/session.h" 30 | 31 | int proxy_reverse_init(pool *p, const char *tables_dir, int flags); 32 | int proxy_reverse_free(pool *p); 33 | 34 | int proxy_reverse_have_authenticated(cmd_rec *cmd); 35 | int proxy_reverse_sess_init(pool *p, const char *tables_dir, 36 | struct proxy_session *proxy_sess, int flags); 37 | int proxy_reverse_sess_free(pool *p, struct proxy_session *proxy_sess); 38 | int proxy_reverse_sess_exit(pool *p); 39 | 40 | int proxy_reverse_handle_user(cmd_rec *cmd, struct proxy_session *proxy_sess, 41 | int *successful, int *block_responses); 42 | int proxy_reverse_handle_pass(cmd_rec *cmd, struct proxy_session *proxy_sess, 43 | int *successful, int *block_responses); 44 | 45 | array_header *proxy_reverse_json_parse_uris(pool *p, const char *path, 46 | unsigned int flags); 47 | 48 | /* Connect policy API */ 49 | #define PROXY_REVERSE_CONNECT_POLICY_RANDOM 1 50 | #define PROXY_REVERSE_CONNECT_POLICY_ROUND_ROBIN 2 51 | #define PROXY_REVERSE_CONNECT_POLICY_LEAST_CONNS 3 52 | #define PROXY_REVERSE_CONNECT_POLICY_LEAST_RESPONSE_TIME 4 53 | #define PROXY_REVERSE_CONNECT_POLICY_SHUFFLE 5 54 | #define PROXY_REVERSE_CONNECT_POLICY_PER_USER 6 55 | #define PROXY_REVERSE_CONNECT_POLICY_PER_GROUP 7 56 | #define PROXY_REVERSE_CONNECT_POLICY_PER_HOST 8 57 | 58 | /* Returns the configured connect policy ID. */ 59 | int proxy_reverse_get_connect_policy(void); 60 | 61 | /* Return the policy ID for the given string, or -1 if the given policy 62 | * is not recognized/supported. 63 | */ 64 | int proxy_reverse_connect_get_policy_id(const char *policy); 65 | 66 | /* Returns TRUE if the given policy ID is a "sticky" policy, i.e. one of 67 | * PerUser, PerGroup, or PerHost. 68 | */ 69 | int proxy_reverse_policy_is_sticky(int policy_id); 70 | 71 | /* Returns a textual name for the given policy ID. */ 72 | const char *proxy_reverse_policy_name(int policy_id); 73 | 74 | /* Returns the per-user/group backends for the given name. */ 75 | array_header *proxy_reverse_pername_backends(pool *p, const char *name, 76 | int per_user); 77 | 78 | /* Look up, and connect to, the selected backend server. */ 79 | int proxy_reverse_connect(pool *p, struct proxy_session *proxy_sess, 80 | const void *connect_data); 81 | 82 | /* Returns TRUE if the Reverse API is using proxy auth, FALSE otherwise. */ 83 | int proxy_reverse_use_proxy_auth(void); 84 | 85 | /* Defines the datastore interface. */ 86 | struct proxy_reverse_datastore { 87 | /* Policy callbacks */ 88 | int (*policy_init)(pool *p, void *dsh, int policy_id, unsigned int vhost_id, 89 | array_header *backends, unsigned long opts); 90 | const struct proxy_conn *(*policy_next_backend)(pool *p, void *dsh, 91 | int policy_id, unsigned int vhost_id, array_header *default_backends, 92 | const void *policy_data, int *backend_id); 93 | int (*policy_used_backend)(pool *p, void *dsh, int policy_id, 94 | unsigned int vhost_id, int backend_id); 95 | int (*policy_update_backend)(pool *p, void *dsh, int policy_id, 96 | unsigned int vhost_id, int backend_id, int conn_incr, long connect_ms); 97 | 98 | void *(*init)(pool *p, const char *path, int flags); 99 | void *(*open)(pool *p, const char *path, array_header *backends); 100 | int (*close)(pool *p, void *dsh); 101 | 102 | /* Datastore handle returned by the open callback. */ 103 | void *dsh; 104 | 105 | int backend_id; 106 | }; 107 | 108 | #endif /* MOD_PROXY_REVERSE_H */ 109 | -------------------------------------------------------------------------------- /t/api/tests.c: -------------------------------------------------------------------------------- 1 | /* 2 | * ProFTPD - mod_proxy API testsuite 3 | * Copyright (c) 2012-2020 TJ Saunders 4 | * 5 | * This program is free software; you can redistribute it and/or modify 6 | * it under the terms of the GNU General Public License as published by 7 | * the Free Software Foundation; either version 2 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * This program is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU General Public License 16 | * along with this program; if not, write to the Free Software 17 | * Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA. 18 | * 19 | * As a special exemption, TJ Saunders and other respective copyright holders 20 | * give permission to link this program with OpenSSL, and distribute the 21 | * resulting executable, without including the source code for OpenSSL in the 22 | * source distribution. 23 | */ 24 | 25 | #include "tests.h" 26 | 27 | struct testsuite_info { 28 | const char *name; 29 | Suite *(*get_suite)(void); 30 | }; 31 | 32 | static struct testsuite_info suites[] = { 33 | { "db", tests_get_db_suite }, 34 | { "dns", tests_get_dns_suite }, 35 | { "conn", tests_get_conn_suite }, 36 | { "netio", tests_get_netio_suite }, 37 | { "inet", tests_get_inet_suite }, 38 | { "random", tests_get_random_suite }, 39 | { "reverse", tests_get_reverse_suite }, 40 | { "forward", tests_get_forward_suite }, 41 | { "str", tests_get_str_suite }, 42 | { "tls", tests_get_tls_suite }, 43 | { "uri", tests_get_uri_suite }, 44 | { "session", tests_get_session_suite }, 45 | { "ftp.msg", tests_get_ftp_msg_suite }, 46 | { "ftp.conn", tests_get_ftp_conn_suite }, 47 | { "ftp.ctrl", tests_get_ftp_ctrl_suite }, 48 | { "ftp.data", tests_get_ftp_data_suite }, 49 | { "ftp.dirlist", tests_get_ftp_dirlist_suite }, 50 | { "ftp.facts", tests_get_ftp_facts_suite }, 51 | { "ftp.sess", tests_get_ftp_sess_suite }, 52 | { "ftp.xfer", tests_get_ftp_xfer_suite }, 53 | 54 | { NULL, NULL } 55 | }; 56 | 57 | static Suite *tests_get_suite(const char *suite) { 58 | register unsigned int i; 59 | 60 | for (i = 0; suites[i].name != NULL; i++) { 61 | if (strcmp(suite, suites[i].name) == 0) { 62 | return (*suites[i].get_suite)(); 63 | } 64 | } 65 | 66 | errno = ENOENT; 67 | return NULL; 68 | } 69 | 70 | int main(int argc, char *argv[]) { 71 | const char *log_file = "api-tests.log"; 72 | int nfailed = 0; 73 | SRunner *runner = NULL; 74 | char *requested = NULL; 75 | 76 | runner = srunner_create(NULL); 77 | 78 | /* XXX This log name should be set outside this code, e.g. via environment 79 | * variable or command-line option. 80 | */ 81 | srunner_set_log(runner, log_file); 82 | 83 | requested = getenv("PROXY_TEST_SUITE"); 84 | if (requested) { 85 | Suite *suite; 86 | 87 | suite = tests_get_suite(requested); 88 | if (suite) { 89 | srunner_add_suite(runner, suite); 90 | 91 | } else { 92 | fprintf(stderr, 93 | "No such test suite ('%s') requested via PROXY_TEST_SUITE\n", 94 | requested); 95 | return EXIT_FAILURE; 96 | } 97 | 98 | } else { 99 | register unsigned int i; 100 | 101 | for (i = 0; suites[i].name; i++) { 102 | Suite *suite; 103 | 104 | suite = (suites[i].get_suite)(); 105 | if (suite) { 106 | srunner_add_suite(runner, suite); 107 | } 108 | } 109 | } 110 | 111 | /* Configure the Trace API to write to stderr. */ 112 | pr_trace_use_stderr(TRUE); 113 | 114 | requested = getenv("PROXY_TEST_NOFORK"); 115 | if (requested) { 116 | srunner_set_fork_status(runner, CK_NOFORK); 117 | } else { 118 | requested = getenv("CK_DEFAULT_TIMEOUT"); 119 | if (requested == NULL) { 120 | setenv("CK_DEFAULT_TIMEOUT", "60", 1); 121 | } 122 | } 123 | 124 | srunner_run_all(runner, CK_NORMAL); 125 | 126 | nfailed = srunner_ntests_failed(runner); 127 | 128 | if (runner) 129 | srunner_free(runner); 130 | 131 | if (nfailed != 0) { 132 | fprintf(stderr, "-------------------------------------------------\n"); 133 | fprintf(stderr, " FAILED %d %s\n\n", nfailed, 134 | nfailed != 1 ? "tests" : "test"); 135 | fprintf(stderr, " Please send email to:\n\n"); 136 | fprintf(stderr, " tj@castaglia.org\n\n"); 137 | fprintf(stderr, " containing the `%s' file (in the t/ directory)\n", log_file); 138 | fprintf(stderr, " and the output from running `proftpd -V'\n"); 139 | fprintf(stderr, "-------------------------------------------------\n"); 140 | 141 | return EXIT_FAILURE; 142 | } 143 | 144 | return EXIT_SUCCESS; 145 | } 146 | -------------------------------------------------------------------------------- /include/proxy/tls.h: -------------------------------------------------------------------------------- 1 | /* 2 | * ProFTPD - mod_proxy TLS API 3 | * Copyright (c) 2015-2025 TJ Saunders 4 | * 5 | * This program is free software; you can redistribute it and/or modify 6 | * it under the terms of the GNU General Public License as published by 7 | * the Free Software Foundation; either version 2 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * This program is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU General Public License 16 | * along with this program; if not, write to the Free Software 17 | * Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA. 18 | * 19 | * As a special exemption, TJ Saunders and other respective copyright holders 20 | * give permission to link this program with OpenSSL, and distribute the 21 | * resulting executable, without including the source code for OpenSSL in the 22 | * source distribution. 23 | */ 24 | 25 | #ifndef MOD_PROXY_TLS_H 26 | #define MOD_PROXY_TLS_H 27 | 28 | #include "mod_proxy.h" 29 | #include "proxy/session.h" 30 | 31 | #include 32 | #include 33 | #include 34 | #include 35 | #include 36 | #include 37 | #include 38 | #include 39 | #include 40 | #if OPENSSL_VERSION_NUMBER > 0x000907000L 41 | # if defined(PR_USE_OPENSSL_ENGINE) 42 | # include 43 | # endif /* PR_USE_OPENSSL_ENGINE */ 44 | # include 45 | #endif 46 | #ifdef PR_USE_OPENSSL_ECC 47 | # include 48 | # include 49 | #endif /* PR_USE_OPENSSL_ECC */ 50 | 51 | /* ProxyTLSEngine values */ 52 | #define PROXY_TLS_ENGINE_ON 1 53 | #define PROXY_TLS_ENGINE_OFF 2 54 | #define PROXY_TLS_ENGINE_AUTO 3 55 | #define PROXY_TLS_ENGINE_IMPLICIT 4 56 | #define PROXY_TLS_ENGINE_MATCH_CLIENT 5 57 | 58 | #define PROXY_TLS_IMPLICIT_FTPS_PORT 990 59 | 60 | /* ProxyTLSOptions values. NOTE: Make sure these do NOT collide with existing 61 | * PROXY_OPT_ values defined in mod_proxy.h. 62 | */ 63 | #define PROXY_TLS_OPT_ENABLE_DIAGS 0x0100 64 | #define PROXY_TLS_OPT_NO_SESSION_CACHE 0x0200 65 | #define PROXY_TLS_OPT_NO_SESSION_TICKETS 0x0400 66 | #define PROXY_TLS_OPT_ALLOW_WEAK_SECURITY 0x0800 67 | 68 | /* ProxyTLSProtocol handling */ 69 | #define PROXY_TLS_PROTO_SSL_V3 0x0001 70 | #define PROXY_TLS_PROTO_TLS_V1 0x0002 71 | #define PROXY_TLS_PROTO_TLS_V1_1 0x0004 72 | #define PROXY_TLS_PROTO_TLS_V1_2 0x0008 73 | #define PROXY_TLS_PROTO_TLS_V1_3 0x0010 74 | 75 | #if defined(PR_USE_OPENSSL) && \ 76 | OPENSSL_VERSION_NUMBER >= 0x10001000L 77 | # if defined(TLS1_3_VERSION) 78 | # define PROXY_TLS_PROTO_DEFAULT (PROXY_TLS_PROTO_TLS_V1|PROXY_TLS_PROTO_TLS_V1_1|PROXY_TLS_PROTO_TLS_V1_2|PROXY_TLS_PROTO_TLS_V1_3) 79 | # else 80 | # define PROXY_TLS_PROTO_DEFAULT (PROXY_TLS_PROTO_TLS_V1|PROXY_TLS_PROTO_TLS_V1_1|PROXY_TLS_PROTO_TLS_V1_2) 81 | # endif /* TLS1_3_VERSION */ 82 | #else 83 | # define PROXY_TLS_PROTO_DEFAULT (PROXY_TLS_PROTO_TLS_V1) 84 | #endif /* OpenSSL 1.0.1 or later */ 85 | 86 | /* This is used for e.g. "ProxyTLSProtocol ALL -SSLv3 ...". */ 87 | #define PROXY_TLS_PROTO_ALL (PROXY_TLS_PROTO_SSL_V3|PROXY_TLS_PROTO_TLS_V1|PROXY_TLS_PROTO_TLS_V1_1|PROXY_TLS_PROTO_TLS_V1_2|PROXY_TLS_PROTO_TLS_V1_3) 88 | 89 | const char *proxy_tls_get_errors(void); 90 | 91 | int proxy_tls_init(pool *p, const char *tables_dir, int flags); 92 | int proxy_tls_free(pool *p); 93 | 94 | int proxy_tls_sess_init(pool *p, struct proxy_session *proxy_sess, int flags); 95 | int proxy_tls_sess_free(pool *p); 96 | 97 | /* Set whether data transfers require TLS protection, based on e.g. clients' 98 | * PROT commands. 99 | */ 100 | int proxy_tls_set_data_prot(int); 101 | 102 | /* Programmatically set the ProxyTLSEngine value. */ 103 | int proxy_tls_set_tls(int); 104 | 105 | /* Returns the ProxyTLSEngine value; see above. */ 106 | int proxy_tls_using_tls(void); 107 | 108 | /* Implements the ProxyTLSEngine MatchClient functionality. */ 109 | int proxy_tls_match_client_tls(void); 110 | 111 | /* Defines the datastore interface. */ 112 | struct proxy_tls_datastore { 113 | int (*add_sess)(pool *p, void *dsh, const char *key, SSL_SESSION *sess); 114 | int (*remove_sess)(pool *p, void *dsh, const char *key); 115 | SSL_SESSION *(*get_sess)(pool *p, void *dsh, const char *key); 116 | int (*count_sess)(pool *p, void *dsh); 117 | int (*init)(pool *p, const char *path, int flags); 118 | void *(*open)(pool *p, const char *path, unsigned long opts); 119 | int (*close)(pool *p, void *dsh); 120 | 121 | /* Datastore handle returned by the open callback. */ 122 | void *dsh; 123 | }; 124 | 125 | #endif /* MOD_PROXY_TLS_H */ 126 | -------------------------------------------------------------------------------- /include/proxy/ssh/ssh2.h: -------------------------------------------------------------------------------- 1 | /* 2 | * ProFTPD - mod_proxy SSH2 constants 3 | * Copyright (c) 2021 TJ Saunders 4 | * 5 | * This program is free software; you can redistribute it and/or modify 6 | * it under the terms of the GNU General Public License as published by 7 | * the Free Software Foundation; either version 2 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * This program is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU General Public License 16 | * along with this program; if not, write to the Free Software 17 | * Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA. 18 | * 19 | * As a special exemption, TJ Saunders and other respective copyright holders 20 | * give permission to link this program with OpenSSL, and distribute the 21 | * resulting executable, without including the source code for OpenSSL in the 22 | * source distribution. 23 | */ 24 | 25 | #ifndef MOD_PROXY_SSH_SSH2_H 26 | #define MOD_PROXY_SSH_SSH2_H 27 | 28 | /* As per RFC 4253, Section 6.1, we MUST be able to handle a packet whose 29 | * length is 35000 bytes; we SHOULD be able to handle larger packets. We 30 | * impose a maximum size here to prevent overly-large packets from being 31 | * used by attackers. The maximum size is a bit arbitrary. 32 | */ 33 | #define PROXY_SSH_MAX_PACKET_LEN (1024 * 256) 34 | 35 | /* SSH2 message types */ 36 | 37 | #define PROXY_SSH_MSG_DISCONNECT 1 38 | #define PROXY_SSH_MSG_IGNORE 2 39 | #define PROXY_SSH_MSG_UNIMPLEMENTED 3 40 | #define PROXY_SSH_MSG_DEBUG 4 41 | #define PROXY_SSH_MSG_SERVICE_REQUEST 5 42 | #define PROXY_SSH_MSG_SERVICE_ACCEPT 6 43 | #define PROXY_SSH_MSG_EXT_INFO 7 44 | #define PROXY_SSH_MSG_KEXINIT 20 45 | #define PROXY_SSH_MSG_NEWKEYS 21 46 | 47 | /* Key exchange message types */ 48 | #define PROXY_SSH_MSG_KEX_DH_INIT 30 49 | #define PROXY_SSH_MSG_KEX_DH_REPLY 31 50 | #define PROXY_SSH_MSG_KEX_DH_GEX_REQUEST_OLD 30 51 | #define PROXY_SSH_MSG_KEX_DH_GEX_GROUP 31 52 | #define PROXY_SSH_MSG_KEX_DH_GEX_INIT 32 53 | #define PROXY_SSH_MSG_KEX_DH_GEX_REPLY 33 54 | #define PROXY_SSH_MSG_KEX_DH_GEX_REQUEST 34 55 | #define PROXY_SSH_MSG_KEXRSA_PUBKEY 30 56 | #define PROXY_SSH_MSG_KEXRSA_SECRET 31 57 | #define PROXY_SSH_MSG_KEXRSA_DONE 32 58 | #define PROXY_SSH_MSG_KEX_ECDH_INIT 30 59 | #define PROXY_SSH_MSG_KEX_ECDH_REPLY 31 60 | 61 | /* User authentication message types */ 62 | #define PROXY_SSH_MSG_USER_AUTH_REQUEST 50 63 | #define PROXY_SSH_MSG_USER_AUTH_FAILURE 51 64 | #define PROXY_SSH_MSG_USER_AUTH_SUCCESS 52 65 | #define PROXY_SSH_MSG_USER_AUTH_BANNER 53 66 | #define PROXY_SSH_MSG_USER_AUTH_PUBKEY 60 67 | #define PROXY_SSH_MSG_USER_AUTH_PK_OK 60 68 | #define PROXY_SSH_MSG_USER_AUTH_PASSWD 60 69 | #define PROXY_SSH_MSG_USER_AUTH_INFO_REQ 60 70 | #define PROXY_SSH_MSG_USER_AUTH_INFO_RESP 61 71 | 72 | /* Request types */ 73 | #define PROXY_SSH_MSG_GLOBAL_REQUEST 80 74 | #define PROXY_SSH_MSG_REQUEST_SUCCESS 81 75 | #define PROXY_SSH_MSG_REQUEST_FAILURE 82 76 | 77 | /* Channel message types */ 78 | #define PROXY_SSH_MSG_CHANNEL_OPEN 90 79 | #define PROXY_SSH_MSG_CHANNEL_OPEN_CONFIRMATION 91 80 | #define PROXY_SSH_MSG_CHANNEL_OPEN_FAILURE 92 81 | #define PROXY_SSH_MSG_CHANNEL_WINDOW_ADJUST 93 82 | #define PROXY_SSH_MSG_CHANNEL_DATA 94 83 | #define PROXY_SSH_MSG_CHANNEL_EXTENDED_DATA 95 84 | #define PROXY_SSH_MSG_CHANNEL_EOF 96 85 | #define PROXY_SSH_MSG_CHANNEL_CLOSE 97 86 | #define PROXY_SSH_MSG_CHANNEL_REQUEST 98 87 | #define PROXY_SSH_MSG_CHANNEL_SUCCESS 99 88 | #define PROXY_SSH_MSG_CHANNEL_FAILURE 100 89 | 90 | /* Channel extended data types */ 91 | #define PROXY_SSH_MSG_CHANNEL_EXTENDED_DATA_TYPE_STDERR 1 92 | 93 | /* SSH Disconnect reason codes */ 94 | #define PROXY_SSH_DISCONNECT_HOST_NOT_ALLOWED_TO_CONNECT 1 95 | #define PROXY_SSH_DISCONNECT_PROTOCOL_ERROR 2 96 | #define PROXY_SSH_DISCONNECT_KEY_EXCHANGE_FAILED 3 97 | #define PROXY_SSH_DISCONNECT_RESERVED 4 98 | #define PROXY_SSH_DISCONNECT_MAC_ERROR 5 99 | #define PROXY_SSH_DISCONNECT_COMPRESSION_ERROR 6 100 | #define PROXY_SSH_DISCONNECT_SERVICE_NOT_AVAILABLE 7 101 | #define PROXY_SSH_DISCONNECT_PROTOCOL_VERSION_NOT_SUPPORTED 8 102 | #define PROXY_SSH_DISCONNECT_HOST_KEY_NOT_VERIFIABLE 9 103 | #define PROXY_SSH_DISCONNECT_CONNECTION_LOST 10 104 | #define PROXY_SSH_DISCONNECT_BY_APPLICATION 11 105 | #define PROXY_SSH_DISCONNECT_TOO_MANY_CONNECTIONS 12 106 | #define PROXY_SSH_DISCONNECT_AUTH_CANCELLED_BY_USER 13 107 | #define PROXY_SSH_DISCONNECT_NO_MORE_AUTH_METHODS_AVAILABLE 14 108 | #define PROXY_SSH_DISCONNECT_ILLEGAL_USER_NAME 15 109 | 110 | #define PROXY_SSH_ID_PREFIX "SSH-2.0-" 111 | #define PROXY_SSH_ID_DEFAULT_STRING PROXY_SSH_ID_PREFIX MOD_PROXY_VERSION 112 | 113 | #endif /* MOD_PROXY_SSH_SSH2_H */ 114 | -------------------------------------------------------------------------------- /Makefile.in: -------------------------------------------------------------------------------- 1 | top_builddir=../.. 2 | top_srcdir=../.. 3 | srcdir=@srcdir@ 4 | 5 | include $(top_srcdir)/Make.rules 6 | 7 | .SUFFIXES: .la .lo 8 | 9 | SHARED_CFLAGS=-DPR_SHARED_MODULE 10 | SHARED_LDFLAGS=-avoid-version -export-dynamic -module 11 | VPATH=@srcdir@ 12 | 13 | MODULE_LIBS=@MODULE_LIBS@ 14 | MODULE_NAME=mod_proxy 15 | MODULE_OBJS=mod_proxy.o \ 16 | lib/proxy/random.o \ 17 | lib/proxy/db.o \ 18 | lib/proxy/dns.o \ 19 | lib/proxy/session.o \ 20 | lib/proxy/conn.o \ 21 | lib/proxy/netio.o \ 22 | lib/proxy/inet.o \ 23 | lib/proxy/str.o \ 24 | lib/proxy/ssh.o \ 25 | lib/proxy/ssh/db.o \ 26 | lib/proxy/ssh/redis.o \ 27 | lib/proxy/tls.o \ 28 | lib/proxy/tls/db.o \ 29 | lib/proxy/tls/redis.o \ 30 | lib/proxy/uri.o \ 31 | lib/proxy/forward.o \ 32 | lib/proxy/reverse.o \ 33 | lib/proxy/reverse/db.o \ 34 | lib/proxy/reverse/redis.o \ 35 | lib/proxy/ftp/conn.o \ 36 | lib/proxy/ftp/ctrl.o \ 37 | lib/proxy/ftp/data.o \ 38 | lib/proxy/ftp/dirlist.o \ 39 | lib/proxy/ftp/facts.o \ 40 | lib/proxy/ftp/msg.o \ 41 | lib/proxy/ftp/sess.o \ 42 | lib/proxy/ftp/xfer.o \ 43 | lib/proxy/ssh/agent.o \ 44 | lib/proxy/ssh/auth.o \ 45 | lib/proxy/ssh/bcrypt.o \ 46 | lib/proxy/ssh/cipher.o \ 47 | lib/proxy/ssh/compress.o \ 48 | lib/proxy/ssh/crypto.o \ 49 | lib/proxy/ssh/disconnect.o \ 50 | lib/proxy/ssh/interop.o \ 51 | lib/proxy/ssh/kex.o \ 52 | lib/proxy/ssh/keys.o \ 53 | lib/proxy/ssh/mac.o \ 54 | lib/proxy/ssh/misc.o \ 55 | lib/proxy/ssh/msg.o \ 56 | lib/proxy/ssh/packet.o \ 57 | lib/proxy/ssh/poly1305.o \ 58 | lib/proxy/ssh/service.o \ 59 | lib/proxy/ssh/session.o \ 60 | lib/proxy/ssh/umac.o \ 61 | lib/proxy/ssh/umac128.o \ 62 | lib/proxy/ssh/utf8.o 63 | 64 | SHARED_MODULE_OBJS=mod_proxy.lo \ 65 | lib/proxy/random.lo \ 66 | lib/proxy/db.lo \ 67 | lib/proxy/dns.lo \ 68 | lib/proxy/session.lo \ 69 | lib/proxy/conn.lo \ 70 | lib/proxy/netio.lo \ 71 | lib/proxy/inet.lo \ 72 | lib/proxy/str.lo \ 73 | lib/proxy/ssh.lo \ 74 | lib/proxy/ssh/db.lo \ 75 | lib/proxy/ssh/redis.lo \ 76 | lib/proxy/tls.lo \ 77 | lib/proxy/tls/db.lo \ 78 | lib/proxy/tls/redis.lo \ 79 | lib/proxy/uri.lo \ 80 | lib/proxy/forward.lo \ 81 | lib/proxy/reverse.lo \ 82 | lib/proxy/reverse/db.lo \ 83 | lib/proxy/reverse/redis.lo \ 84 | lib/proxy/ftp/conn.lo \ 85 | lib/proxy/ftp/ctrl.lo \ 86 | lib/proxy/ftp/data.lo \ 87 | lib/proxy/ftp/dirlist.lo \ 88 | lib/proxy/ftp/facts.lo \ 89 | lib/proxy/ftp/msg.lo \ 90 | lib/proxy/ftp/sess.lo \ 91 | lib/proxy/ftp/xfer.lo \ 92 | lib/proxy/ssh/agent.lo \ 93 | lib/proxy/ssh/auth.lo \ 94 | lib/proxy/ssh/bcrypt.lo \ 95 | lib/proxy/ssh/cipher.lo \ 96 | lib/proxy/ssh/compress.lo \ 97 | lib/proxy/ssh/crypto.lo \ 98 | lib/proxy/ssh/disconnect.lo \ 99 | lib/proxy/ssh/interop.lo \ 100 | lib/proxy/ssh/kex.lo \ 101 | lib/proxy/ssh/keys.lo \ 102 | lib/proxy/ssh/mac.lo \ 103 | lib/proxy/ssh/misc.lo \ 104 | lib/proxy/ssh/msg.lo \ 105 | lib/proxy/ssh/packet.lo \ 106 | lib/proxy/ssh/poly1305.lo \ 107 | lib/proxy/ssh/service.lo \ 108 | lib/proxy/ssh/session.lo \ 109 | lib/proxy/ssh/umac.lo \ 110 | lib/proxy/ssh/umac128.lo \ 111 | lib/proxy/ssh/utf8.lo 112 | 113 | # Necessary redefinitions 114 | INCLUDES=-I. -I./include -I../.. -I../../include @INCLUDES@ 115 | CPPFLAGS= $(ADDL_CPPFLAGS) -DHAVE_CONFIG_H $(DEFAULT_PATHS) $(PLATFORM) $(INCLUDES) 116 | LDFLAGS=-L../../lib @LIBDIRS@ 117 | 118 | .c.o: 119 | $(CC) $(CPPFLAGS) $(CFLAGS) -c $< -o $@ 120 | 121 | .c.lo: 122 | $(LIBTOOL) --mode=compile --tag=CC $(CC) $(CPPFLAGS) $(CFLAGS) $(SHARED_CFLAGS) -c $< -o $@ 123 | 124 | shared: $(SHARED_MODULE_OBJS) 125 | $(LIBTOOL) --mode=link --tag=CC $(CC) -o $(MODULE_NAME).la $(SHARED_MODULE_OBJS) -rpath $(LIBEXECDIR) $(LDFLAGS) $(SHARED_LDFLAGS) $(MODULE_LIBS) $(SHARED_MODULE_LIBS) `cat $(MODULE_NAME).c | grep '$$Libraries:' | sed -e 's/^.*\$$Libraries: \(.*\)\\$$/\1/'` 126 | 127 | static: $(MODULE_OBJS) 128 | test -z "$(MODULE_LIBS)" || echo "$(MODULE_LIBS)" >> $(MODULE_LIBS_FILE) 129 | $(AR) rc $(MODULE_NAME).a $(MODULE_OBJS) 130 | $(RANLIB) $(MODULE_NAME).a 131 | 132 | install: install-misc 133 | if [ -f $(MODULE_NAME).la ] ; then \ 134 | $(LIBTOOL) --mode=install --tag=CC $(INSTALL_BIN) $(MODULE_NAME).la $(DESTDIR)$(LIBEXECDIR) ; \ 135 | fi 136 | 137 | install-misc: 138 | $(INSTALL) -o $(INSTALL_USER) -g $(INSTALL_GROUP) -m 0644 cacerts.pem $(DESTDIR)$(sysconfdir)/cacerts.pem 139 | 140 | clean: 141 | $(LIBTOOL) --mode=clean $(RM) $(MODULE_NAME).a $(MODULE_NAME).la *.o *.lo .libs/*.o lib/proxy/*.o lib/proxy/*.lo lib/proxy/ftp/*.o lib/proxy/ftp/*.lo lib/proxy/reverse/*.o lib/proxy/reverse/*.lo lib/proxy/ssh/*.o lib/proxy/ssh/*.lo lib/proxy/tls/*.o lib/proxy/tls/*.lo 142 | cd t/ && $(MAKE) clean 143 | 144 | # Run the API tests 145 | check: 146 | test -z "$(ENABLE_TESTS)" || (cd t/ && $(MAKE) api-tests) 147 | 148 | distclean: clean 149 | $(RM) Makefile $(MODULE_NAME).h config.status config.cache config.log *.gcda *.gcno 150 | -$(RM) -r .libs/ .git/ CVS/ RCS/ 151 | -------------------------------------------------------------------------------- /doc/NOTES.protocol-translation: -------------------------------------------------------------------------------- 1 | 2 | FTP to SFTP (#1): 3 | 4 | https://www.bitvise.com/ftp-bridge 5 | https://enterprisedt.com/products/completeftp/doc/guide/html/gateway.html 6 | 7 | mindterm source (Java, FTPOverSFTP bridge code for mapping) 8 | 9 | For each FTP command, decompose it into SFTP request equivalents; note which 10 | FTP commands have no SFTP request equivalents. 11 | 12 | USER 13 | PASS 14 | USERAUTH 15 | ACCT 16 | n/a 17 | 18 | CWD 19 | XCWD 20 | CDUP 21 | XCUP 22 | n/a; will mod_proxy have to maintain some state about the FTP session 23 | for such directory traversal commands? Yuck. Maybe use with REALPATH? 24 | 25 | SMNT 26 | not implemented 27 | 28 | REIN 29 | not implemented 30 | 31 | QUIT 32 | CHANNEL_CLOSE 33 | 34 | PORT 35 | EPRT 36 | PASV 37 | EPSV 38 | this will be the most interesting; translating SFTP data transfers into 39 | frontend FTP transfers. 40 | 41 | TYPE 42 | n/a (binary only?) 43 | 44 | STRU 45 | n/a; always F 46 | 47 | MODE 48 | n/a; always S 49 | 50 | RANG 51 | REST 52 | RETR 53 | OPEN + READ + CLOSE 54 | 55 | RANG 56 | REST 57 | APPE 58 | STOR 59 | OPEN + WRITE + CLOSE 60 | 61 | STOU 62 | OPEN + WRITE + CLOSE; have mod_proxy generate the unique name for the 63 | backend SFTP file? Use O_CREAT|O_EXCL to force uniqueness, I guess... 64 | 65 | ALLO 66 | n/a 67 | 68 | RNFR 69 | RNTO 70 | RENAME 71 | 72 | ABOR 73 | n/a; maybe just stop the current data transfer, send CLOSE? 74 | 75 | DELE 76 | REMOVE 77 | 78 | MDTM 79 | STAT 80 | 81 | MKD 82 | XMKD 83 | MKDIR 84 | 85 | RMD 86 | XRMD 87 | RMDIR 88 | 89 | LIST 90 | MLSD 91 | MLST 92 | NLST 93 | OPENDIR + READDIR + CLOSE 94 | 95 | MFF 96 | FSETSTAT 97 | MFMT 98 | FSETSTAT 99 | 100 | PWD 101 | XPWD 102 | 103 | SITE 104 | n/a; support for specific SITE commands *may* be added later, e.g. 105 | SITE CHMOD = SETSTAT 106 | SITE CHGRP = SETSTAT 107 | SITE SYMLINK = SYMLINK (from mod_site_misc) 108 | SITE UTIME = SETSTAT (from mod_site_misc) 109 | 110 | SIZE 111 | STAT 112 | 113 | SYST 114 | n/a; always "215 UNIX Type: L8" 115 | 116 | STAT 117 | STAT 118 | 119 | HELP 120 | n/a? 121 | 122 | NOOP 123 | no backend equivalent; handle in proxy 124 | 125 | FEAT 126 | n/a (SFTP extensions?) 127 | 128 | OPTS 129 | LANG 130 | n/a 131 | 132 | HOST 133 | n/a 134 | 135 | CLNT 136 | n/a (would be part of SSH connect, but is too late in FTP protocol) 137 | 138 | AUTH 139 | PBSZ 140 | PROT 141 | n/a (provided by SSH by default!) 142 | 143 | For authentication, it will always be password authentication to the backend 144 | SSH server. (Or should this overridable, e.g. password authentication to 145 | the proxy, but hostbased authentication from the proxy to the backend server?) 146 | 147 | What does this look like, for an FTP forward proxy configuration to an SFTP 148 | backend? How would mod_proxy know that the destination server is an SFTP 149 | server? I suppose it could do a probe: make the initial TCP connection, 150 | see whether it gets the "220 Server Ready" FTP response, or the "ssh-..." 151 | SSH banner... 152 | 153 | Note: This would require that mod_proxy be built _without_ mod_sftp being 154 | present! This means that the logic regarding mod_sftp HOOKs would need 155 | to be revisited. 156 | 157 | Implementation: 158 | Implement a "protocol", which handles all of the above FTP commands. 159 | The default Protocol object will do what mod_proxy currently does for 160 | all of the commands; this will thus be a transparent change. These 161 | Protocol objects would then have to maintain/accumulate their own state, 162 | so as to implement/translate RNFR + RNTO = RENAME, *and* be responsible 163 | for translating the responses. Thus these would indeed be more than 164 | just codecs (or, for some value of "codec", very complicated codecs). 165 | 166 | Once that's done, we need to determine how to lookup a new Protocol object, 167 | and when do it, and when to register it. For cases where mod_proxy 168 | knows the backend URL at connect time, this is easier. What about for 169 | the auth-time (PerUser, PerGroup) URLs? 170 | 171 | FTP Implementation API: 172 | Suitable for plugging into mod_proxy's CMD C_ANY handler, *and* 173 | its POST_CMD C_PROT handler. Thus the API for the given impl 174 | input should be something like: 175 | 176 | MODRET (handle_cmd)(pool *p, cmd_rec *cmd, int cmd_phase); 177 | 178 | Consider, for example, a logging-only Implementation object, to 179 | demonstrate the concept? 180 | 181 | Note that this Impl API works for FTP, but NOT for SSH; SSH packets 182 | are not handled by the C_ANY handler. 183 | 184 | SFTP to FTP (#2): 185 | 186 | No forward proxying supported here, since SFTP doesn't have that notion; 187 | mod_proxy will know (via the ProxyReversServers URL schemes) which protocol 188 | to use for the backend server. 189 | 190 | SCP (#3?): 191 | subset of SFTP to FTP, with no directory listing support. 192 | -------------------------------------------------------------------------------- /lib/proxy/ssh/poly1305.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Public Domain poly1305 from Andrew Moon 3 | * poly1305-donna-unrolled.c from https://github.com/floodyberry/poly1305-donna 4 | */ 5 | 6 | #include "mod_proxy.h" 7 | #include "proxy/ssh/poly1305.h" 8 | 9 | #if defined(HAVE_EVP_CHACHA20_OPENSSL) && \ 10 | !defined(HAVE_BROKEN_CHACHA20) 11 | 12 | #define mul32x32_64(a,b) ((uint64_t)(a) * (b)) 13 | 14 | #define U8TO32_LE(p) \ 15 | (((uint32_t)((p)[0])) | \ 16 | ((uint32_t)((p)[1]) << 8) | \ 17 | ((uint32_t)((p)[2]) << 16) | \ 18 | ((uint32_t)((p)[3]) << 24)) 19 | 20 | #define U32TO8_LE(p, v) \ 21 | do { \ 22 | (p)[0] = (uint8_t)((v)); \ 23 | (p)[1] = (uint8_t)((v) >> 8); \ 24 | (p)[2] = (uint8_t)((v) >> 16); \ 25 | (p)[3] = (uint8_t)((v) >> 24); \ 26 | } while (0) 27 | 28 | void 29 | poly1305_auth(unsigned char out[POLY1305_TAGLEN], const unsigned char *m, size_t inlen, const unsigned char key[POLY1305_KEYLEN]) { 30 | uint32_t t0,t1,t2,t3; 31 | uint32_t h0,h1,h2,h3,h4; 32 | uint32_t r0,r1,r2,r3,r4; 33 | uint32_t s1,s2,s3,s4; 34 | uint32_t b, nb; 35 | size_t j; 36 | uint64_t t[5]; 37 | uint64_t f0,f1,f2,f3; 38 | uint32_t g0,g1,g2,g3,g4; 39 | uint64_t c; 40 | unsigned char mp[16]; 41 | 42 | /* clamp key */ 43 | t0 = U8TO32_LE(key+0); 44 | t1 = U8TO32_LE(key+4); 45 | t2 = U8TO32_LE(key+8); 46 | t3 = U8TO32_LE(key+12); 47 | 48 | /* precompute multipliers */ 49 | r0 = t0 & 0x3ffffff; t0 >>= 26; t0 |= t1 << 6; 50 | r1 = t0 & 0x3ffff03; t1 >>= 20; t1 |= t2 << 12; 51 | r2 = t1 & 0x3ffc0ff; t2 >>= 14; t2 |= t3 << 18; 52 | r3 = t2 & 0x3f03fff; t3 >>= 8; 53 | r4 = t3 & 0x00fffff; 54 | 55 | s1 = r1 * 5; 56 | s2 = r2 * 5; 57 | s3 = r3 * 5; 58 | s4 = r4 * 5; 59 | 60 | /* init state */ 61 | h0 = 0; 62 | h1 = 0; 63 | h2 = 0; 64 | h3 = 0; 65 | h4 = 0; 66 | 67 | /* full blocks */ 68 | if (inlen < 16) goto poly1305_donna_atmost15bytes; 69 | poly1305_donna_16bytes: 70 | m += 16; 71 | inlen -= 16; 72 | 73 | t0 = U8TO32_LE(m-16); 74 | t1 = U8TO32_LE(m-12); 75 | t2 = U8TO32_LE(m-8); 76 | t3 = U8TO32_LE(m-4); 77 | 78 | h0 += t0 & 0x3ffffff; 79 | h1 += ((((uint64_t)t1 << 32) | t0) >> 26) & 0x3ffffff; 80 | h2 += ((((uint64_t)t2 << 32) | t1) >> 20) & 0x3ffffff; 81 | h3 += ((((uint64_t)t3 << 32) | t2) >> 14) & 0x3ffffff; 82 | h4 += (t3 >> 8) | (1 << 24); 83 | 84 | 85 | poly1305_donna_mul: 86 | t[0] = mul32x32_64(h0,r0) + mul32x32_64(h1,s4) + mul32x32_64(h2,s3) + mul32x32_64(h3,s2) + mul32x32_64(h4,s1); 87 | t[1] = mul32x32_64(h0,r1) + mul32x32_64(h1,r0) + mul32x32_64(h2,s4) + mul32x32_64(h3,s3) + mul32x32_64(h4,s2); 88 | t[2] = mul32x32_64(h0,r2) + mul32x32_64(h1,r1) + mul32x32_64(h2,r0) + mul32x32_64(h3,s4) + mul32x32_64(h4,s3); 89 | t[3] = mul32x32_64(h0,r3) + mul32x32_64(h1,r2) + mul32x32_64(h2,r1) + mul32x32_64(h3,r0) + mul32x32_64(h4,s4); 90 | t[4] = mul32x32_64(h0,r4) + mul32x32_64(h1,r3) + mul32x32_64(h2,r2) + mul32x32_64(h3,r1) + mul32x32_64(h4,r0); 91 | 92 | h0 = (uint32_t)t[0] & 0x3ffffff; c = (t[0] >> 26); 93 | t[1] += c; h1 = (uint32_t)t[1] & 0x3ffffff; b = (uint32_t)(t[1] >> 26); 94 | t[2] += b; h2 = (uint32_t)t[2] & 0x3ffffff; b = (uint32_t)(t[2] >> 26); 95 | t[3] += b; h3 = (uint32_t)t[3] & 0x3ffffff; b = (uint32_t)(t[3] >> 26); 96 | t[4] += b; h4 = (uint32_t)t[4] & 0x3ffffff; b = (uint32_t)(t[4] >> 26); 97 | h0 += b * 5; 98 | 99 | if (inlen >= 16) goto poly1305_donna_16bytes; 100 | 101 | /* final bytes */ 102 | poly1305_donna_atmost15bytes: 103 | if (!inlen) goto poly1305_donna_finish; 104 | 105 | for (j = 0; j < inlen; j++) mp[j] = m[j]; 106 | mp[j++] = 1; 107 | for (; j < 16; j++) mp[j] = 0; 108 | inlen = 0; 109 | 110 | t0 = U8TO32_LE(mp+0); 111 | t1 = U8TO32_LE(mp+4); 112 | t2 = U8TO32_LE(mp+8); 113 | t3 = U8TO32_LE(mp+12); 114 | 115 | h0 += t0 & 0x3ffffff; 116 | h1 += ((((uint64_t)t1 << 32) | t0) >> 26) & 0x3ffffff; 117 | h2 += ((((uint64_t)t2 << 32) | t1) >> 20) & 0x3ffffff; 118 | h3 += ((((uint64_t)t3 << 32) | t2) >> 14) & 0x3ffffff; 119 | h4 += (t3 >> 8); 120 | 121 | goto poly1305_donna_mul; 122 | 123 | poly1305_donna_finish: 124 | b = h0 >> 26; h0 = h0 & 0x3ffffff; 125 | h1 += b; b = h1 >> 26; h1 = h1 & 0x3ffffff; 126 | h2 += b; b = h2 >> 26; h2 = h2 & 0x3ffffff; 127 | h3 += b; b = h3 >> 26; h3 = h3 & 0x3ffffff; 128 | h4 += b; b = h4 >> 26; h4 = h4 & 0x3ffffff; 129 | h0 += b * 5; b = h0 >> 26; h0 = h0 & 0x3ffffff; 130 | h1 += b; 131 | 132 | g0 = h0 + 5; b = g0 >> 26; g0 &= 0x3ffffff; 133 | g1 = h1 + b; b = g1 >> 26; g1 &= 0x3ffffff; 134 | g2 = h2 + b; b = g2 >> 26; g2 &= 0x3ffffff; 135 | g3 = h3 + b; b = g3 >> 26; g3 &= 0x3ffffff; 136 | g4 = h4 + b - (1 << 26); 137 | 138 | b = (g4 >> 31) - 1; 139 | nb = ~b; 140 | h0 = (h0 & nb) | (g0 & b); 141 | h1 = (h1 & nb) | (g1 & b); 142 | h2 = (h2 & nb) | (g2 & b); 143 | h3 = (h3 & nb) | (g3 & b); 144 | h4 = (h4 & nb) | (g4 & b); 145 | 146 | f0 = ((h0 ) | (h1 << 26)) + (uint64_t)U8TO32_LE(&key[16]); 147 | f1 = ((h1 >> 6) | (h2 << 20)) + (uint64_t)U8TO32_LE(&key[20]); 148 | f2 = ((h2 >> 12) | (h3 << 14)) + (uint64_t)U8TO32_LE(&key[24]); 149 | f3 = ((h3 >> 18) | (h4 << 8)) + (uint64_t)U8TO32_LE(&key[28]); 150 | 151 | U32TO8_LE(&out[ 0], f0); f1 += (f0 >> 32); 152 | U32TO8_LE(&out[ 4], f1); f2 += (f1 >> 32); 153 | U32TO8_LE(&out[ 8], f2); f3 += (f2 >> 32); 154 | U32TO8_LE(&out[12], f3); 155 | } 156 | #endif /* HAVE_EVP_CHACHA20_OPENSSL and !HAVE_BROKEN_CHACHA20 */ 157 | -------------------------------------------------------------------------------- /lib/proxy/ftp/data.c: -------------------------------------------------------------------------------- 1 | /* 2 | * ProFTPD - mod_proxy FTP data conn routines 3 | * Copyright (c) 2012-2020 TJ Saunders 4 | * 5 | * This program is free software; you can redistribute it and/or modify 6 | * it under the terms of the GNU General Public License as published by 7 | * the Free Software Foundation; either version 2 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * This program is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU General Public License 16 | * along with this program; if not, write to the Free Software 17 | * Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA. 18 | * 19 | * As a special exemption, TJ Saunders and other respective copyright holders 20 | * give permission to link this program with OpenSSL, and distribute the 21 | * resulting executable, without including the source code for OpenSSL in the 22 | * source distribution. 23 | */ 24 | 25 | #include "mod_proxy.h" 26 | 27 | #include "proxy/netio.h" 28 | #include "proxy/ftp/data.h" 29 | 30 | static const char *trace_channel = "proxy.ftp.data"; 31 | 32 | pr_buffer_t *proxy_ftp_data_recv(pool *p, conn_t *data_conn, 33 | int frontend_data) { 34 | int nread; 35 | pr_buffer_t *pbuf = NULL; 36 | 37 | if (p == NULL || 38 | data_conn == NULL || 39 | data_conn->instrm == NULL) { 40 | errno = EINVAL; 41 | return NULL; 42 | } 43 | 44 | if (data_conn->instrm->strm_buf != NULL) { 45 | pbuf = data_conn->instrm->strm_buf; 46 | 47 | } else { 48 | pbuf = pr_netio_buffer_alloc(data_conn->instrm); 49 | } 50 | 51 | pbuf->current = pbuf->buf; 52 | pbuf->remaining = pbuf->buflen; 53 | 54 | while (TRUE) { 55 | size_t avail_len; 56 | 57 | if (frontend_data) { 58 | nread = pr_netio_read(data_conn->instrm, pbuf->current, 59 | pbuf->remaining, 1); 60 | 61 | } else { 62 | nread = proxy_netio_read(data_conn->instrm, pbuf->current, 63 | pbuf->remaining, 1); 64 | } 65 | 66 | if (nread < 0) { 67 | return NULL; 68 | } 69 | 70 | if (nread == 0) { 71 | /* We might have had data left over in the buffer from a previous 72 | * iteration of the loop, thus we return it as is. 73 | */ 74 | return pbuf; 75 | } 76 | 77 | pr_timer_reset(PR_TIMER_NOXFER, ANY_MODULE); 78 | pr_timer_reset(PR_TIMER_STALLED, ANY_MODULE); 79 | pr_timer_reset(PR_TIMER_IDLE, ANY_MODULE); 80 | 81 | pr_trace_msg(trace_channel, 15, "received %d bytes of data", nread); 82 | 83 | pbuf->current += nread; 84 | pbuf->remaining -= nread; 85 | pr_event_generate("mod_proxy.data-read", pbuf); 86 | 87 | /* How much data is available in the buffer? It is possible that 88 | * event listeners consumed that data entirely. If there is no available 89 | * data left, we need to read more. 90 | */ 91 | avail_len = pbuf->current - pbuf->buf; 92 | if (avail_len > 0) { 93 | break; 94 | } 95 | } 96 | 97 | return pbuf; 98 | } 99 | 100 | int proxy_ftp_data_send(pool *p, conn_t *data_conn, pr_buffer_t *pbuf, 101 | int frontend_data) { 102 | int nwrote; 103 | char *buf; 104 | size_t buflen; 105 | 106 | if (p == NULL || 107 | data_conn == NULL || 108 | data_conn->outstrm == NULL || 109 | pbuf == NULL) { 110 | errno = EINVAL; 111 | return -1; 112 | } 113 | 114 | pr_event_generate("mod_proxy.data-write", pbuf); 115 | 116 | /* Currently, we make the conn_t nonblocking (via pr_inet_set_nonblocking), 117 | * BUT that does NOT set the nonblocking flag on the contained stream. 118 | * Thus this write is actually a BLOCKING write -- which means that we will 119 | * not need to worry about short writes here. 120 | * 121 | * In the future, we may want to make the streams nonblocking, but that 122 | * makes mod_proxy a little more sensitive to the slow producer/consumer 123 | * problem. 124 | */ 125 | 126 | buf = pbuf->buf; 127 | buflen = pbuf->current - pbuf->buf; 128 | 129 | pr_trace_msg(trace_channel, 25, "writing %lu bytes of data to %s", 130 | (unsigned long) buflen, 131 | frontend_data ? "frontend client" : "backend server"); 132 | 133 | if (frontend_data) { 134 | nwrote = pr_netio_write(data_conn->outstrm, buf, buflen); 135 | 136 | } else { 137 | nwrote = proxy_netio_write(data_conn->outstrm, buf, buflen); 138 | } 139 | 140 | while (nwrote < 0) { 141 | int xerrno = errno; 142 | 143 | if (xerrno == EAGAIN) { 144 | /* Since our socket is in non-blocking mode, write(2) can return 145 | * EAGAIN if there is not enough from for our data yet. Handle 146 | * this by delaying temporarily, then trying again. 147 | */ 148 | errno = EINTR; 149 | pr_signals_handle(); 150 | 151 | if (frontend_data) { 152 | nwrote = pr_netio_write(data_conn->outstrm, buf, buflen); 153 | 154 | } else { 155 | nwrote = proxy_netio_write(data_conn->outstrm, buf, buflen); 156 | } 157 | 158 | continue; 159 | } 160 | 161 | errno = xerrno; 162 | return -1; 163 | } 164 | 165 | pr_timer_reset(PR_TIMER_NOXFER, ANY_MODULE); 166 | pr_timer_reset(PR_TIMER_STALLED, ANY_MODULE); 167 | pr_timer_reset(PR_TIMER_IDLE, ANY_MODULE); 168 | 169 | return nwrote; 170 | } 171 | -------------------------------------------------------------------------------- /lib/proxy/ssh/disconnect.c: -------------------------------------------------------------------------------- 1 | /* 2 | * ProFTPD - mod_proxy SSH disconnects 3 | * Copyright (c) 2021-2025 TJ Saunders 4 | * 5 | * This program is free software; you can redistribute it and/or modify 6 | * it under the terms of the GNU General Public License as published by 7 | * the Free Software Foundation; either version 2 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * This program is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU General Public License 16 | * along with this program; if not, write to the Free Software 17 | * Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA. 18 | * 19 | * As a special exemption, TJ Saunders and other respective copyright holders 20 | * give permission to link this program with OpenSSL, and distribute the 21 | * resulting executable, without including the source code for OpenSSL in the 22 | * source distribution. 23 | */ 24 | 25 | #include "mod_proxy.h" 26 | #include "proxy/ssh/ssh2.h" 27 | #include "proxy/ssh/msg.h" 28 | #include "proxy/ssh/packet.h" 29 | #include "proxy/ssh/disconnect.h" 30 | 31 | struct disconnect_reason { 32 | uint32_t code; 33 | const char *explain; 34 | const char *lang; 35 | }; 36 | 37 | static struct disconnect_reason explanations[] = { 38 | { PROXY_SSH_DISCONNECT_HOST_NOT_ALLOWED_TO_CONNECT, "Host not allowed to connect", NULL }, 39 | { PROXY_SSH_DISCONNECT_PROTOCOL_ERROR, "Protocol error", NULL }, 40 | { PROXY_SSH_DISCONNECT_KEY_EXCHANGE_FAILED, "Key exchange failed", NULL }, 41 | { PROXY_SSH_DISCONNECT_MAC_ERROR, "MAC error", NULL }, 42 | { PROXY_SSH_DISCONNECT_COMPRESSION_ERROR, "Compression error", NULL }, 43 | { PROXY_SSH_DISCONNECT_SERVICE_NOT_AVAILABLE, "Requested service not available", NULL }, 44 | { PROXY_SSH_DISCONNECT_PROTOCOL_VERSION_NOT_SUPPORTED, "Protocol version not supported", NULL }, 45 | { PROXY_SSH_DISCONNECT_HOST_KEY_NOT_VERIFIABLE, "Host key not verifiable", NULL }, 46 | { PROXY_SSH_DISCONNECT_CONNECTION_LOST, "Connection lost", NULL }, 47 | { PROXY_SSH_DISCONNECT_BY_APPLICATION, "Application disconnected", NULL }, 48 | { PROXY_SSH_DISCONNECT_TOO_MANY_CONNECTIONS, "Too many connections", NULL }, 49 | { PROXY_SSH_DISCONNECT_AUTH_CANCELLED_BY_USER, "Authentication cancelled by user", NULL }, 50 | { PROXY_SSH_DISCONNECT_NO_MORE_AUTH_METHODS_AVAILABLE, "No other authentication mechanisms available", NULL }, 51 | { PROXY_SSH_DISCONNECT_ILLEGAL_USER_NAME, "Illegal user name", NULL }, 52 | { 0, NULL, NULL } 53 | }; 54 | 55 | static const char *trace_channel = "proxy.ssh.disconnect"; 56 | 57 | const char *proxy_ssh_disconnect_get_text(uint32_t reason_code) { 58 | register unsigned int i; 59 | 60 | for (i = 0; explanations[i].explain; i++) { 61 | if (explanations[i].code == reason_code) { 62 | return explanations[i].explain; 63 | } 64 | } 65 | 66 | errno = ENOENT; 67 | return NULL; 68 | } 69 | 70 | void proxy_ssh_disconnect_send(pool *p, conn_t *conn, uint32_t reason, 71 | const char *explain, const char *file, int lineno, const char *func) { 72 | struct proxy_ssh_packet *pkt; 73 | const char *lang = "en-US"; 74 | unsigned char *buf, *ptr; 75 | uint32_t buflen, bufsz, len = 0; 76 | 77 | /* Send the server a DISCONNECT mesg. */ 78 | pkt = proxy_ssh_packet_create(p); 79 | 80 | buflen = bufsz = 1024; 81 | ptr = buf = palloc(pkt->pool, bufsz); 82 | 83 | if (explain == NULL) { 84 | register unsigned int i; 85 | 86 | for (i = 0; explanations[i].explain; i++) { 87 | if (explanations[i].code == reason) { 88 | explain = explanations[i].explain; 89 | lang = explanations[i].lang; 90 | if (lang == NULL) { 91 | lang = "en-US"; 92 | } 93 | break; 94 | } 95 | } 96 | 97 | if (explain == NULL) { 98 | explain = "Unknown reason"; 99 | } 100 | 101 | } else { 102 | lang = "en-US"; 103 | } 104 | 105 | if (strlen(func) > 0) { 106 | pr_trace_msg(trace_channel, 9, "disconnecting (%s) [at %s:%d:%s()]", 107 | explain, file, lineno, func); 108 | 109 | } else { 110 | pr_trace_msg(trace_channel, 9, "disconnecting (%s) [at %s:%d]", explain, 111 | file, lineno); 112 | } 113 | 114 | len += proxy_ssh_msg_write_byte(&buf, &buflen, PROXY_SSH_MSG_DISCONNECT); 115 | len += proxy_ssh_msg_write_int(&buf, &buflen, reason); 116 | len += proxy_ssh_msg_write_string(&buf, &buflen, explain); 117 | len += proxy_ssh_msg_write_string(&buf, &buflen, lang); 118 | 119 | pkt->payload = ptr; 120 | pkt->payload_len = len; 121 | 122 | (void) pr_log_writefile(proxy_logfd, MOD_PROXY_VERSION, 123 | "disconnecting %s (%s)", pr_netaddr_get_ipstr(conn->remote_addr), explain); 124 | 125 | /* Explicitly set a short poll timeout of 2 secs. */ 126 | proxy_ssh_packet_set_poll_timeout(2, 0); 127 | 128 | if (proxy_ssh_packet_write(conn, pkt) < 0) { 129 | int xerrno = errno; 130 | 131 | pr_trace_msg(trace_channel, 12, 132 | "error writing DISCONNECT message: %s", strerror(xerrno)); 133 | } 134 | 135 | destroy_pool(pkt->pool); 136 | } 137 | 138 | void proxy_ssh_disconnect_conn(conn_t *conn, uint32_t reason, 139 | const char *explain, const char *file, int lineno, const char *func) { 140 | proxy_ssh_disconnect_send(proxy_pool, conn, reason, explain, file, lineno, 141 | func); 142 | 143 | #if defined(PR_DEVEL_COREDUMP) 144 | pr_session_end(PR_SESS_END_FL_NOEXIT); 145 | abort(); 146 | #else 147 | pr_session_disconnect(&proxy_module, PR_SESS_DISCONNECT_BY_APPLICATION, NULL); 148 | #endif /* PR_DEVEL_COREDUMP */ 149 | } 150 | -------------------------------------------------------------------------------- /lib/proxy/inet.c: -------------------------------------------------------------------------------- 1 | /* 2 | * ProFTPD - mod_proxy Inet implementation 3 | * Copyright (c) 2015-2021 TJ Saunders 4 | * 5 | * This program is free software; you can redistribute it and/or modify 6 | * it under the terms of the GNU General Public License as published by 7 | * the Free Software Foundation; either version 2 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * This program is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU General Public License 16 | * along with this program; if not, write to the Free Software 17 | * Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA. 18 | * 19 | * As a special exemption, TJ Saunders and other respective copyright holders 20 | * give permission to link this program with OpenSSL, and distribute the 21 | * resulting executable, without including the source code for OpenSSL in the 22 | * source distribution. 23 | */ 24 | 25 | #include "mod_proxy.h" 26 | 27 | #include "proxy/netio.h" 28 | #include "proxy/inet.h" 29 | 30 | conn_t *proxy_inet_accept(pool *p, conn_t *data_conn, conn_t *ctrl_conn, 31 | int rfd, int wfd, int resolve) { 32 | int xerrno; 33 | conn_t *conn; 34 | pr_netio_t *curr_netio; 35 | 36 | curr_netio = proxy_netio_unset(PR_NETIO_STRM_DATA, "inet_accept"); 37 | conn = pr_inet_accept(p, data_conn, ctrl_conn, rfd, wfd, 38 | (unsigned char) resolve); 39 | xerrno = errno; 40 | proxy_netio_set(PR_NETIO_STRM_DATA, curr_netio); 41 | 42 | errno = xerrno; 43 | return conn; 44 | } 45 | 46 | void proxy_inet_close(pool *p, conn_t *conn) { 47 | 48 | if (conn != NULL) { 49 | /* Note that we do our own close here, rather than relying on the 50 | * core Inet's close, as that one simply relies on the connection 51 | * cleanup callback -- and we want to use our own Proxy Netio API 52 | * functions for closing, too. 53 | */ 54 | 55 | /* Shutdowns first, then closes. */ 56 | if (conn->instrm != NULL) { 57 | proxy_netio_shutdown(conn->instrm, 0); 58 | } 59 | 60 | if (conn->outstrm != NULL) { 61 | proxy_netio_shutdown(conn->outstrm, 1); 62 | } 63 | 64 | if (conn->instrm != NULL) { 65 | proxy_netio_close(conn->instrm); 66 | conn->instrm = NULL; 67 | } 68 | 69 | if (conn->outstrm != NULL) { 70 | proxy_netio_close(conn->outstrm); 71 | conn->outstrm = NULL; 72 | } 73 | 74 | if (conn->listen_fd != -1) { 75 | (void) close(conn->listen_fd); 76 | conn->listen_fd = -1; 77 | } 78 | 79 | if (conn->rfd != -1) { 80 | (void) close(conn->rfd); 81 | conn->rfd = -1; 82 | } 83 | 84 | if (conn->wfd != -1) { 85 | (void) close(conn->wfd); 86 | conn->wfd = -1; 87 | } 88 | } 89 | } 90 | 91 | int proxy_inet_connect(pool *p, conn_t *conn, const pr_netaddr_t *addr, 92 | int port) { 93 | int instrm_type = -1, outstrm_type = -1, res, xerrno; 94 | pr_netio_t *in_netio = NULL, *out_netio = NULL; 95 | 96 | if (conn != NULL) { 97 | if (conn->instrm != NULL) { 98 | instrm_type = conn->instrm->strm_type; 99 | 100 | in_netio = proxy_netio_unset(instrm_type, "inet_connect"); 101 | } 102 | 103 | if (conn->outstrm != NULL) { 104 | outstrm_type = conn->outstrm->strm_type; 105 | 106 | if (outstrm_type != instrm_type) { 107 | out_netio = proxy_netio_unset(outstrm_type, "inet_connect"); 108 | } 109 | } 110 | } 111 | 112 | res = pr_inet_connect(p, conn, addr, port); 113 | xerrno = errno; 114 | 115 | if (in_netio != NULL) { 116 | proxy_netio_set(instrm_type, in_netio); 117 | } 118 | 119 | if (out_netio != NULL) { 120 | proxy_netio_set(outstrm_type, out_netio); 121 | } 122 | 123 | errno = xerrno; 124 | return res; 125 | } 126 | 127 | int proxy_inet_listen(pool *p, conn_t *conn, int backlog, int flags) { 128 | int instrm_type = -1, outstrm_type = -1, res, xerrno; 129 | pr_netio_t *in_netio = NULL, *out_netio = NULL; 130 | 131 | if (conn != NULL) { 132 | if (conn->instrm != NULL) { 133 | instrm_type = conn->instrm->strm_type; 134 | 135 | in_netio = proxy_netio_unset(instrm_type, "inet_listen"); 136 | } 137 | 138 | if (conn->outstrm != NULL) { 139 | outstrm_type = conn->outstrm->strm_type; 140 | 141 | if (outstrm_type != instrm_type) { 142 | out_netio = proxy_netio_unset(outstrm_type, "inet_listen"); 143 | } 144 | } 145 | } 146 | 147 | res = pr_inet_listen(p, conn, backlog, flags); 148 | xerrno = errno; 149 | 150 | if (in_netio != NULL) { 151 | proxy_netio_set(instrm_type, in_netio); 152 | } 153 | 154 | if (out_netio != NULL) { 155 | proxy_netio_set(outstrm_type, out_netio); 156 | } 157 | 158 | errno = xerrno; 159 | return res; 160 | } 161 | 162 | conn_t *proxy_inet_openrw(pool *p, conn_t *conn, const pr_netaddr_t *addr, 163 | int strm_type, int fd, int rfd, int wfd, int resolve) { 164 | int xerrno; 165 | conn_t *new_conn; 166 | pr_netio_t *curr_netio = NULL; 167 | 168 | curr_netio = proxy_netio_unset(strm_type, "inet_openrw"); 169 | new_conn = pr_inet_openrw(p, conn, addr, strm_type, fd, rfd, wfd, resolve); 170 | xerrno = errno; 171 | proxy_netio_set(strm_type, curr_netio); 172 | 173 | if (new_conn != NULL) { 174 | /* Note: pr_inet_openrw() calls pr_inet_copy_conn(), which registers 175 | * a cleanup on the create object. But we clean up our own data, 176 | * so that cleanup, when run, will attempt a double-free. Thus we 177 | * unregister that cleanup here. 178 | */ 179 | unregister_cleanup(new_conn->pool, new_conn, NULL); 180 | } 181 | 182 | errno = xerrno; 183 | return new_conn; 184 | } 185 | -------------------------------------------------------------------------------- /mod_proxy.h.in: -------------------------------------------------------------------------------- 1 | /* 2 | * ProFTPD - mod_proxy 3 | * Copyright (c) 2012-2025 TJ Saunders 4 | * 5 | * This program is free software; you can redistribute it and/or modify 6 | * it under the terms of the GNU General Public License as published by 7 | * the Free Software Foundation; either version 2 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * This program is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU General Public License 16 | * along with this program; if not, write to the Free Software 17 | * Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA. 18 | * 19 | * As a special exemption, TJ Saunders and other respective copyright holders 20 | * give permission to link this program with OpenSSL, and distribute the 21 | * resulting executable, without including the source code for OpenSSL in the 22 | * source distribution. 23 | */ 24 | 25 | #ifndef MOD_PROXY_H 26 | #define MOD_PROXY_H 27 | 28 | #include "conf.h" 29 | #include "privs.h" 30 | 31 | #include 32 | 33 | #if HAVE_SYS_MMAN_H 34 | # include 35 | #endif 36 | 37 | /* Define if you have the header. */ 38 | #undef HAVE_ZLIB_H 39 | 40 | #if defined(PR_USE_OPENSSL) 41 | #include 42 | #endif /* PR_USE_OPENSSL */ 43 | 44 | /* Define if you have the LibreSSL library. 45 | * 46 | * Note that in LibreSSL-3.5.0, the structs became opaque, as they are in 47 | * OpenSSL-1.1.0, and thus these version-dependent macros became more 48 | * complex. 49 | */ 50 | #if defined(LIBRESSL_VERSION_NUMBER) 51 | # define HAVE_LIBRESSL 1 52 | #endif 53 | 54 | /* Define if you have OpenSSL with crippled AES support. */ 55 | #undef HAVE_AES_CRIPPLED_OPENSSL 56 | 57 | /* Define if you have OpenSSL with EVP_aes_128_ctr support. */ 58 | #undef HAVE_EVP_AES_128_CTR_OPENSSL 59 | 60 | /* Define if you have OpenSSL with EVP_aes_192_ctr support. */ 61 | #undef HAVE_EVP_AES_192_CTR_OPENSSL 62 | 63 | /* Define if you have OpenSSL with EVP_aes_256_ctr support. */ 64 | #undef HAVE_EVP_AES_256_CTR_OPENSSL 65 | 66 | /* Define if you have OpenSSL with EVP_aes_256_gcm support. */ 67 | #undef HAVE_EVP_AES_256_GCM_OPENSSL 68 | 69 | /* Define if you have OpenSSL with EVP_chacha20 support. 70 | * 71 | * Note, however, that older LibreSSL versions have broken ChaCha20 support. 72 | */ 73 | #undef HAVE_EVP_CHACHA20_OPENSSL 74 | 75 | #if defined(HAVE_LIBRESSL) && \ 76 | LIBRESSL_VERSION_NUMBER < 0x3010000fL 77 | # define HAVE_BROKEN_CHACHA20 1 78 | #endif 79 | 80 | /* Define if you have OpenSSL with OSSL_PROVIDER_load support. */ 81 | #undef HAVE_OSSL_PROVIDER_LOAD_OPENSSL 82 | 83 | /* Define if you have OpenSSL with SHA256 support. */ 84 | #undef HAVE_SHA256_OPENSSL 85 | 86 | /* Define if you have OpenSSL with SHA512 support. */ 87 | #undef HAVE_SHA512_OPENSSL 88 | 89 | /* Define if you have OpenSSL with X448 support. */ 90 | #undef HAVE_X448_OPENSSL 91 | 92 | /* Define if you have the sqlite3.h header. */ 93 | #undef HAVE_SQLITE3_H 94 | #if !defined(HAVE_SQLITE3_H) 95 | # error "SQLite library/headers required" 96 | #endif 97 | 98 | /* Define if you have the random(3) function. */ 99 | #undef HAVE_RANDOM 100 | 101 | /* Define if you have the sqlite3_stmt_readonly() function. */ 102 | #undef HAVE_SQLITE3_STMT_READONLY 103 | 104 | /* Define if you have the sqlite3_trace() function. */ 105 | #undef HAVE_SQLITE3_TRACE 106 | 107 | /* Define if you have the sqlite3_trace_v2() function. */ 108 | #undef HAVE_SQLITE3_TRACE_V2 109 | 110 | /* Define if you have the srandom(3) function. */ 111 | #undef HAVE_SRANDOM 112 | 113 | /* Define if you have the strnstr(3) function. */ 114 | #undef HAVE_STRNSTR 115 | 116 | #define MOD_PROXY_VERSION "mod_proxy/0.9.6" 117 | 118 | /* Make sure the version of proftpd is as necessary. */ 119 | #if PROFTPD_VERSION_NUMBER < 0x0001030706 120 | # error "ProFTPD 1.3.7a or later required" 121 | #endif 122 | 123 | /* mod_proxy option flags */ 124 | #define PROXY_OPT_USE_PROXY_PROTOCOL_V1 0x0001 125 | #define PROXY_OPT_SHOW_FEATURES 0x0002 126 | #define PROXY_OPT_USE_REVERSE_PROXY_AUTH 0x0004 127 | #define PROXY_OPT_USE_DIRECT_DATA_TRANSFERS 0x0008 128 | #define PROXY_OPT_IGNORE_CONFIG_PERMS 0x0010 129 | #define PROXY_OPT_USE_PROXY_PROTOCOL_V2 0x0020 130 | #define PROXY_OPT_USE_PROXY_PROTOCOL_V2_TLVS 0x0040 131 | #define PROXY_OPT_ALLOW_FOREIGN_ADDRESS 0x0080 132 | #define PROXY_OPT_IGNORE_FOREIGN_ADDRESS 0x0100 133 | 134 | /* mod_proxy datastores */ 135 | #define PROXY_DATASTORE_SQLITE 1 136 | #define PROXY_DATASTORE_REDIS 2 137 | 138 | /* Miscellaneous */ 139 | extern int proxy_logfd; 140 | extern module proxy_module; 141 | extern pool *proxy_pool; 142 | extern unsigned long proxy_opts; 143 | extern unsigned int proxy_sess_state; 144 | extern int proxy_datastore; 145 | extern void *proxy_datastore_data; 146 | extern size_t proxy_datastore_datasz; 147 | 148 | /* mod_proxy session state flags */ 149 | #define PROXY_SESS_STATE_PROXY_AUTHENTICATED 0x0001 150 | #define PROXY_SESS_STATE_CONNECTED 0x0002 151 | #define PROXY_SESS_STATE_BACKEND_AUTHENTICATED 0x0004 152 | #define PROXY_SESS_STATE_BACKEND_HAS_CTRL_TLS 0x0008 153 | #define PROXY_SESS_STATE_BACKEND_HAS_DATA_TLS 0x0010 154 | 155 | #define PROXY_SESS_STATE_SSH_HAVE_KEX 0x0020 156 | #define PROXY_SESS_STATE_SSH_HAVE_SERVICE 0x0040 157 | #define PROXY_SESS_STATE_SSH_HAVE_AUTH 0x0080 158 | #define PROXY_SESS_STATE_SSH_REKEYING 0x0100 159 | #define PROXY_SESS_STATE_SSH_HAVE_EXT_INFO 0x0200 160 | 161 | #ifndef PROXY_DEFAULT_RETRY_COUNT 162 | # define PROXY_DEFAULT_RETRY_COUNT 5 163 | #endif 164 | 165 | /* mod_proxy SSH roles */ 166 | #define PROXY_SSH_ROLE_SERVER 1 167 | #define PROXY_SSH_ROLE_CLIENT 2 168 | 169 | #endif /* MOD_PROXY_H */ 170 | --------------------------------------------------------------------------------