paivana

HTTP paywall reverse proxy
Log | Files | Refs | README | LICENSE

commit 54306aeb704d7078f93f4987511dc6f5f64399ed
parent 7c29dd278d79fe3b3819ab0fe0172624cb675cf1
Author: Christian Grothoff <christian@grothoff.org>
Date:   Mon, 20 Apr 2026 15:21:07 +0200

WiP

Diffstat:
Msrc/backend/Makefile.am | 1+
Msrc/backend/paivana-httpd.c | 141+++++++++++++++++++++++++++++++++++++++++++------------------------------------
Asrc/backend/paivana-httpd_helper.c | 120+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/backend/paivana-httpd_helper.h | 62++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/backend/paivana-httpd_templates.c | 55+++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/backend/paivana-httpd_templates.h | 63+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
6 files changed, 377 insertions(+), 65 deletions(-)

diff --git a/src/backend/Makefile.am b/src/backend/Makefile.am @@ -15,6 +15,7 @@ paivana_httpd_SOURCES = \ paivana-httpd_helper.c paivana-httpd_helper.h \ paivana-httpd_reverse.c paivana-httpd_reverse.h \ paivana-httpd_pay.c paivana-httpd_pay.h \ + paivana-httpd_templates.c paivana-httpd_templates.h \ paivana_pd.c paivana_pd.h paivana_httpd_LDADD = \ $(LIBGCRYPT_LIBS) \ diff --git a/src/backend/paivana-httpd.c b/src/backend/paivana-httpd.c @@ -36,6 +36,7 @@ #include "paivana-httpd_helper.h" #include "paivana-httpd_pay.h" #include "paivana-httpd_reverse.h" +#include "paivana-httpd_templates.h" #include "paivana_pd.h" @@ -308,6 +309,78 @@ mhd_log_callback (void *cls, } +/** + * Callback invoked on every listen socket to start the + * respective MHD HTTP daemon. + * + * @param cls unused + * @param lsock the listen socket + */ +static void +start_daemon (void *cls, + int lsock) +{ + struct MHD_Daemon *mhd; + + (void) cls; + GNUNET_assert (-1 != lsock); + mhd = MHD_start_daemon ( + MHD_USE_DEBUG + | MHD_ALLOW_SUSPEND_RESUME + | MHD_USE_DUAL_STACK, + 0, + NULL, NULL, + &create_response, NULL, + MHD_OPTION_LISTEN_SOCKET, + lsock, + MHD_OPTION_CONNECTION_TIMEOUT, (unsigned int) 16, + MHD_OPTION_NOTIFY_COMPLETED, &mhd_completed_cb, NULL, + MHD_OPTION_URI_LOG_CALLBACK, &mhd_log_callback, NULL, + MHD_OPTION_END); + + if (NULL == mhd) + { + GNUNET_break (0); + GNUNET_SCHEDULER_shutdown (); + return; + } + have_daemons = true; + TALER_MHD_daemon_start (mhd); +} + + +static void +serve_requests (void *cls) +{ + enum GNUNET_GenericReturnValue ret; + + ret = TALER_MHD_listen_bind (cfg, + "paivana", + &start_daemon, + NULL); + switch (ret) + { + case GNUNET_SYSERR: + global_ret = EXIT_NOTCONFIGURED; + GNUNET_SCHEDULER_shutdown (); + return; + case GNUNET_NO: + if (! have_daemons) + { + global_ret = EXIT_NOTCONFIGURED; + GNUNET_SCHEDULER_shutdown (); + return; + } + GNUNET_log (GNUNET_ERROR_TYPE_WARNING, + "Could not open all configured listen sockets\n"); + break; + case GNUNET_OK: + break; + } + +} + + /* *************** General / main code *************** */ @@ -326,6 +399,7 @@ do_shutdown (void *cls) PAIVANA_HTTPD_payment_shutdown (); PAIVANA_HTTPD_reverse_shutdown (); TALER_MHD_daemons_destroy (); + PAIVANA_HTTPD_unload_templates (); GNUNET_free (PH_target_server_base_url); GNUNET_free (PH_merchant_base_url); GNUNET_free (PH_base_url); @@ -394,46 +468,6 @@ load_paywall (void) /** - * Callback invoked on every listen socket to start the - * respective MHD HTTP daemon. - * - * @param cls unused - * @param lsock the listen socket - */ -static void -start_daemon (void *cls, - int lsock) -{ - struct MHD_Daemon *mhd; - - (void) cls; - GNUNET_assert (-1 != lsock); - mhd = MHD_start_daemon ( - MHD_USE_DEBUG - | MHD_ALLOW_SUSPEND_RESUME - | MHD_USE_DUAL_STACK, - 0, - NULL, NULL, - &create_response, NULL, - MHD_OPTION_LISTEN_SOCKET, - lsock, - MHD_OPTION_CONNECTION_TIMEOUT, (unsigned int) 16, - MHD_OPTION_NOTIFY_COMPLETED, &mhd_completed_cb, NULL, - MHD_OPTION_URI_LOG_CALLBACK, &mhd_log_callback, NULL, - MHD_OPTION_END); - - if (NULL == mhd) - { - GNUNET_break (0); - GNUNET_SCHEDULER_shutdown (); - return; - } - have_daemons = true; - TALER_MHD_daemon_start (mhd); -} - - -/** * Main function that will be run. Main tasks are (1) init. the * curl infrastructure (curl_global_init() / curl_multi_init()), * then fetch the HTTP port where its Web service should listen at, @@ -450,7 +484,6 @@ run (void *cls, const char *cfgfile, const struct GNUNET_CONFIGURATION_Handle *c) { - enum GNUNET_GenericReturnValue ret; char *secret; (void) cls; @@ -594,30 +627,8 @@ run (void *cls, GNUNET_free (auth_header); } ctx_rc = GNUNET_CURL_gnunet_rc_create (PH_ctx); - - ret = TALER_MHD_listen_bind (c, - "paivana", - &start_daemon, - NULL); - switch (ret) - { - case GNUNET_SYSERR: - global_ret = EXIT_NOTCONFIGURED; - GNUNET_SCHEDULER_shutdown (); - return; - case GNUNET_NO: - if (! have_daemons) - { - global_ret = EXIT_NOTCONFIGURED; - GNUNET_SCHEDULER_shutdown (); - return; - } - GNUNET_log (GNUNET_ERROR_TYPE_WARNING, - "Could not open all configured listen sockets\n"); - break; - case GNUNET_OK: - break; - } + PAIVANA_HTTPD_load_templates (&serve_requests, + NULL); } diff --git a/src/backend/paivana-httpd_helper.c b/src/backend/paivana-httpd_helper.c @@ -0,0 +1,120 @@ +/* + This file is part of GNUnet. + Copyright (C) 2026 Taler Systems SA + + Paivana is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public License + as published by the Free Software Foundation; either version + 3, or (at your option) any later version. + + Paivana is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty + of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See + the GNU General Public License for more details. + + You should have received a copy of the GNU General Public + License along with Paivana; see the file COPYING. If not, + write to the Free Software Foundation, Inc., 51 Franklin + Street, Fifth Floor, Boston, MA 02110-1301, USA. +*/ + +/** + * @author Christian Grothoff + * @file paivana-httpd_helper.c + * @brief helper functions + */ +#include "paivana-httpd.h" +#include "paivana-httpd_helper.h" +#include <taler/taler_mhd_lib.h> + +bool +PAIVANA_HTTPD_get_client_address (struct MHD_Connection *connection, + void **ca, + size_t *ca_len) +{ + const union MHD_ConnectionInfo *ci; + const struct sockaddr *sa; + socklen_t sa_len; + + // FIXME: also support getting client address from HTTP + // headers instead (in case of reverse proxy). + ci = MHD_get_connection_info (connection, + MHD_CONNECTION_INFO_CLIENT_ADDRESS); + GNUNET_assert (NULL != ci); + sa = ci->client_addr; + switch (sa->sa_family) + { + case AF_INET: + sa_len = sizeof (struct sockaddr_in); + break; + case AF_INET6: + sa_len = sizeof (struct sockaddr_in6); + break; + default: + GNUNET_break (0); + *ca = NULL; + *ca_len = 0; + return false; + } + ca = GNUNET_memdup (sa, + sa_len); + *ca_len = sa_len; + return true; +} + + +bool +PAIVANA_HTTPD_get_base_url (struct MHD_Connection *connection, + struct GNUNET_Buffer *buf) +{ + const char *host; + const char *forwarded_host; + const char *forwarded_port; + + GNUNET_buffer_clear (buf); + if (NULL != PH_base_url) + { + GNUNET_buffer_write_str (buf, + PH_base_url); + return true; + } + if (GNUNET_YES == + TALER_mhd_is_https (connection)) + GNUNET_buffer_write_str (buf, + "https://"); + else + GNUNET_buffer_write_str (buf, + "http://"); + host = MHD_lookup_connection_value (connection, + MHD_HEADER_KIND, + MHD_HTTP_HEADER_HOST); + forwarded_host = MHD_lookup_connection_value (connection, + MHD_HEADER_KIND, + "X-Forwarded-Host"); + if (NULL != forwarded_host) + { + GNUNET_buffer_write_str (buf, + forwarded_host); + } + else + { + if (NULL == host) + { + GNUNET_break (0); + return false; + } + GNUNET_buffer_write_str (buf, + host); + } + forwarded_port = MHD_lookup_connection_value (connection, + MHD_HEADER_KIND, + "X-Forwarded-Port"); + if (NULL != forwarded_port) + { + GNUNET_buffer_write_str (buf, + ":"); + GNUNET_buffer_write_str (buf, + forwarded_port); + } + return true; +} diff --git a/src/backend/paivana-httpd_helper.h b/src/backend/paivana-httpd_helper.h @@ -0,0 +1,62 @@ +/* + This file is part of GNUnet. + Copyright (C) 2026 Taler Systems SA + + Paivana is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public License + as published by the Free Software Foundation; either version + 3, or (at your option) any later version. + + Paivana is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty + of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See + the GNU General Public License for more details. + + You should have received a copy of the GNU General Public + License along with Paivana; see the file COPYING. If not, + write to the Free Software Foundation, Inc., 51 Franklin + Street, Fifth Floor, Boston, MA 02110-1301, USA. +*/ + +/** + * @author Christian Grothoff + * @file paivana-httpd_helper.h + * @brief helper functions + */ +#ifndef PAIVANA_HTTPD_HELPER_H +#define PAIVANA_HTTPD_HELPER_H + +#include <stdbool.h> +#include <microhttpd.h> +#include <gnunet/gnunet_util_lib.h> + + +/** + * Obtain the client address of @a connection + * + * @param connection HTTP client connection + * @param[out] ca where to write the client address + * @param[out] ca_len number of bytes in @a ca + * @return true on success + */ +bool +PAIVANA_HTTPD_get_client_address (struct MHD_Connection *connection, + void **ca, + size_t *ca_len); + +/** + * Determine the Base URL that the client made the HTTP request to. + * The URL returned will be without the trailing '/'. + * + * @param connection client connection used + * @param[out] buf where to write the base URL; buffer will be cleared + * and must be reaped by caller. + * @return false on error (no suitable HTTP headers found and nothing + * configured) + */ +bool +PAIVANA_HTTPD_get_base_url (struct MHD_Connection *connection, + struct GNUNET_Buffer *buf); + + +#endif diff --git a/src/backend/paivana-httpd_templates.c b/src/backend/paivana-httpd_templates.c @@ -0,0 +1,55 @@ +/* + This file is part of GNUnet. + Copyright (C) 2026 Taler Systems SA + + Paivana is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public License + as published by the Free Software Foundation; either version + 3, or (at your option) any later version. + + Paivana is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty + of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See + the GNU General Public License for more details. + + You should have received a copy of the GNU General Public + License along with Paivana; see the file COPYING. If not, + write to the Free Software Foundation, Inc., 51 Franklin + Street, Fifth Floor, Boston, MA 02110-1301, USA. +*/ + +/** + * @author Christian Grothoff + * @file paivana-httpd_templates.c + * @brief template functions + */ +#include "paivana-httpd.h" +#include "paivana-httpd_templates.h" +#include <taler/taler_mhd_lib.h> + + +void +PAIVANA_HTTPD_load_templates (GNUNET_SCHEDULER_TaskCallback cb, + void *cb_cls) +{ + // FIXME: not implemented! + GNUNET_SCHEDULER_add_now (cb, + cb_cls); +} + + +struct MHD_Response * +PAIVANA_HTTPD_search_templates (const char *website) +{ + // FIXME: not implemented + return NULL; +} + + +/** + * Unload all of the template state. + */ +void +PAIVANA_HTTPD_unload_templates () +{ +} diff --git a/src/backend/paivana-httpd_templates.h b/src/backend/paivana-httpd_templates.h @@ -0,0 +1,63 @@ +/* + This file is part of GNUnet. + Copyright (C) 2026 Taler Systems SA + + Paivana is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public License + as published by the Free Software Foundation; either version + 3, or (at your option) any later version. + + Paivana is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty + of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See + the GNU General Public License for more details. + + You should have received a copy of the GNU General Public + License along with Paivana; see the file COPYING. If not, + write to the Free Software Foundation, Inc., 51 Franklin + Street, Fifth Floor, Boston, MA 02110-1301, USA. +*/ + +/** + * @author Christian Grothoff + * @file paivana-httpd_templates.h + * @brief functions to work with merchant backend templates + */ +#ifndef PAIVANA_HTTPD_TEMPLATES_H +#define PAIVANA_HTTPD_TEMPLATES_H + +#include <microhttpd.h> +#include <gnunet/gnunet_util_lib.h> + + +/** + * Load the templates from the merchant backend. + * Calls @a cb upon completion if successful, otherwise + * may initiate shutdown. + * + * @param cb continuation to call when done + * @param cb_cls closure for @a cb + */ +void +PAIVANA_HTTPD_load_templates (GNUNET_SCHEDULER_TaskCallback cb, + void *cb_cls); + + +/** + * Return the paywall page for the given @a website. + * + * @param website site to look for paywall templates for + * @return NULL if the @a url is not protected by the paywall, + * otherwise paywall response to return (do NOT free!) + */ +struct MHD_Response * +PAIVANA_HTTPD_search_templates (const char *website); + + +/** + * Unload all of the template state. + */ +void +PAIVANA_HTTPD_unload_templates (void); + +#endif