paivana

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

paivana-httpd.h (12113B)


      1 /*
      2      This file is part of GNUnet.
      3      Copyright (C) 2026 Taler Systems SA
      4 
      5      Paivana is free software; you can redistribute it and/or
      6      modify it under the terms of the GNU Affero General Public License
      7      as published by the Free Software Foundation; either version
      8      3, or (at your option) any later version.
      9 
     10      Paivana is distributed in the hope that it will be useful,
     11      but WITHOUT ANY WARRANTY; without even the implied warranty
     12      of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See
     13      the GNU Affero General Public License for more details.
     14 
     15      You should have received a copy of the GNU Affero General Public
     16      License along with Paivana; see the file COPYING.  If not,
     17      write to the Free Software Foundation, Inc., 51 Franklin
     18      Street, Fifth Floor, Boston, MA 02110-1301, USA.
     19 */
     20 
     21 /**
     22  * @author Christian Grothoff
     23  * @file paivana-httpd.h
     24  * @brief globals for the HTTPD reverse proxy
     25  */
     26 #ifndef PAIVANA_HTTPD_H
     27 #define PAIVANA_HTTPD_H
     28 
     29 #include <regex.h>
     30 #include <stdbool.h>
     31 
     32 /**
     33  * The de-facto forwarding headers.  libmicrohttpd only defines the
     34  * standardized #MHD_HTTP_HEADER_FORWARDED (RFC 7239), but these are
     35  * what nginx, Apache and everything else in front of us actually
     36  * emit.  They are consumed on the way in (client address, base URL)
     37  * and produced on the way out (proxying), in different files, so
     38  * they are spelled out once here.
     39  */
     40 #define PH_HEADER_X_FORWARDED_FOR "X-Forwarded-For"
     41 #define PH_HEADER_X_FORWARDED_PROTO "X-Forwarded-Proto"
     42 #define PH_HEADER_X_FORWARDED_HOST "X-Forwarded-Host"
     43 #define PH_HEADER_X_FORWARDED_PORT "X-Forwarded-Port"
     44 
     45 /**
     46  * Longest URL we are willing to run a regular expression over.
     47  *
     48  * Both the WHITELIST expression and the ones from the merchant's
     49  * templates are matched against client-controlled URLs on the
     50  * pre-payment path, and neither is validated beyond regcomp(3)
     51  * succeeding.  A careless expression can exhibit catastrophic
     52  * backtracking, whose cost then grows super-linearly in the length of
     53  * the subject; capping the subject length bounds that cost.  16 kb is
     54  * far above any legitimate URL and at (or above) the request line
     55  * limit of the usual front-end servers.
     56  */
     57 #define PH_MAX_URL_LENGTH (16 * 1024)
     58 
     59 #define PAIVANA_LOG_INFO(...)                                  \
     60         GNUNET_log (GNUNET_ERROR_TYPE_INFO, __VA_ARGS__)
     61 #define PAIVANA_LOG_DEBUG(...)                                  \
     62         GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, __VA_ARGS__)
     63 #define PAIVANA_LOG_WARNING(...)                                  \
     64         GNUNET_log (GNUNET_ERROR_TYPE_WARNING, __VA_ARGS__)
     65 #define PAIVANA_LOG_ERROR(...)                                  \
     66         GNUNET_log (GNUNET_ERROR_TYPE_ERROR, __VA_ARGS__)
     67 
     68 /**
     69  * Destination to which HTTP server we forward requests to.
     70  * Of the format "http://servername:PORT"
     71  */
     72 extern char *PH_target_server_base_url;
     73 
     74 /**
     75  * Replace the connection to target server.
     76  * File path to the unix socket
     77  */
     78 extern char *PH_target_server_unixpath;
     79 
     80 /**
     81  * Public merchant backend base URL advertised to browsers and wallets.
     82  */
     83 extern char *PH_merchant_base_url;
     84 
     85 /**
     86  * Merchant backend base URL used for Paivana's private API requests.
     87  * Defaults to a copy of #PH_merchant_base_url.
     88  */
     89 extern char *PH_merchant_internal_url;
     90 
     91 /**
     92  * Optional Unix socket used to reach the merchant backend.  Kept so the
     93  * forced-fresh transport diagnostic follows the same route as the regular
     94  * merchant client.
     95  */
     96 extern char *PH_merchant_unixpath;
     97 
     98 /**
     99  * Base URL of this site as seen by the client. If not set,
    100  * we will try to determine it from "X-Forwarded-Host" and
    101  * "Host" and "X-Forwarded-Port" headers.
    102  */
    103 extern char *PH_base_url;
    104 
    105 /**
    106  * Curl context for talking to the merchant backend.  Carries the
    107  * `Authorization: Bearer $MERCHANT_ACCESS_TOKEN` header on every
    108  * request, so it must never be used for anything but the backend.
    109  * NULL in `-n` (no payment) mode, where there is no backend.
    110  */
    111 extern struct GNUNET_CURL_Context *PH_merchant_ctx;
    112 
    113 /**
    114  * Curl context for forwarding client requests to the origin server.
    115  * Deliberately separate from #PH_merchant_ctx: headers appended to a
    116  * context apply to every request made through it, and our credentials
    117  * for the merchant backend have no business being sent to the site we
    118  * proxy for.
    119  */
    120 extern struct GNUNET_CURL_Context *PH_proxy_ctx;
    121 
    122 /**
    123  * Pre-compiled regular expression for sites that are whitelisted
    124  * and never paywalled.
    125  */
    126 extern regex_t PH_whitelist_ex;
    127 
    128 /**
    129  * True if whitelist_ex was set.
    130  */
    131 extern bool PH_have_whitelist_ex;
    132 
    133 /**
    134  * Set to true if the cookie applies globally to all sites
    135  * and not per-page.
    136  */
    137 extern int PH_global_cookie;
    138 
    139 /**
    140  * Disable paywall check.
    141  */
    142 extern int PH_no_check;
    143 
    144 /**
    145  * If set, we are behind a reverse proxy: the socket peer is a proxy we
    146  * trust, and the forwarding headers ("Forwarded" and the "X-Forwarded-*"
    147  * family) are read to recover what the client actually did.  Unset, no
    148  * forwarding header is consulted at all and the peer *is* the client.
    149  * Only enable it when the server in front writes those headers itself,
    150  * either setting them or appending to them.  Appending is enough --
    151  * what it appends is the address it accepted the request from, so the
    152  * element we read is still one it vouches for.  What is not safe is a
    153  * front server that passes the client's own headers through unchanged,
    154  * which leaves the client writing the element we believe.
    155  *
    156  * This flag alone extends trust exactly one hop, to the peer, so with
    157  * no #PH_trusted_proxies4 / #PH_trusted_proxies6 the client is the
    158  * RIGHTMOST element of the chain -- the only one the peer vouches for.
    159  * Naming further networks there extends the walk leftwards, one hop per
    160  * trusted node; see PAIVANA_HTTPD_resolve_forwarding().
    161  *
    162  * It also decides whether `BASE_URL` is optional: the flag is the
    163  * assertion that the proxy enforced a correct "Host", which is what
    164  * makes reconstructing our own URL from the request safe.
    165  */
    166 extern int PH_respect_forwarded_headers;
    167 
    168 /**
    169  * Networks whose members are reverse proxies we trust to report the
    170  * client address truthfully, from the `TRUSTED_PROXIES` configuration
    171  * option.  NULL if unconfigured.  These are the hops BEYOND the socket
    172  * peer: #PH_respect_forwarded_headers already trusts the peer, and each
    173  * network named here lets the walk step one element further left, past
    174  * a node it matches.  The first node not covered is the client.
    175  */
    176 extern struct GNUNET_STRINGS_IPv4NetworkPolicy *PH_trusted_proxies4;
    177 
    178 /**
    179  * IPv6 counterpart of #PH_trusted_proxies4, from `TRUSTED_PROXIES6`.
    180  */
    181 extern struct GNUNET_STRINGS_IPv6NetworkPolicy *PH_trusted_proxies6;
    182 
    183 /**
    184  * True if either #PH_trusted_proxies4 or #PH_trusted_proxies6 was
    185  * configured.  Distinguishes "no hop beyond the peer is trusted" from
    186  * "these networks are, in addition to the peer".
    187  */
    188 extern bool PH_have_trusted_proxies;
    189 
    190 /**
    191  * Value to return from main()
    192  */
    193 extern int PH_global_ret;
    194 
    195 /**
    196  * Our configuration.
    197  */
    198 extern const struct GNUNET_CONFIGURATION_Handle *PH_cfg;
    199 
    200 /**
    201  * Total number of concurrent client connections we accept, from the
    202  * `CONNECTION_LIMIT` configuration option.  Divided evenly over the
    203  * listen sockets that come up, because MHD's own limit is per daemon
    204  * and TALER_MHD_listen_bind() starts one daemon per address.
    205  *
    206  * MHD's default (about 1018 per daemon) is wrong here in both
    207  * directions: it is not process-wide, and it does not know that we
    208  * spend file descriptors on outbound libcurl handles from the same
    209  * table -- exhausting them makes *paying* clients' requests fail.
    210  */
    211 extern unsigned int PH_connection_limit;
    212 
    213 /**
    214  * Number of the total connection slots reserved for requests to redeem a
    215  * payment, from `PAYMENT_CONNECTION_LIMIT`; 32 by default.  Keeping this
    216  * separate prevents a burst of ordinary proxy traffic from consuming every
    217  * request slot needed to confirm already-paid orders.
    218  */
    219 extern unsigned int PH_payment_connection_limit;
    220 
    221 /**
    222  * Number of concurrent connections we accept from any single client
    223  * address, from `PER_IP_CONNECTION_LIMIT`; 0 disables the check, which
    224  * is MHD's default.
    225  *
    226  * Must be 0 wherever the peer address is not the client's: under
    227  * `SERVE = unix` or `systemd` every client shares one peer, and behind
    228  * a reverse proxy or a NAT many clients do.  See the README.
    229  */
    230 extern unsigned int PH_per_ip_connection_limit;
    231 
    232 /**
    233  * Maximum aggregate bytes the ordinary-request streaming rings may account
    234  * for, from `RELAY_MEMORY_LIMIT`; 256 MiB by default.  Startup validates the
    235  * product of the two per-request ring limits and the ordinary request slots.
    236  */
    237 extern unsigned long long PH_relay_memory_limit;
    238 
    239 /**
    240  * Time accepted requests may finish after shutdown begins, from
    241  * `SHUTDOWN_GRACE_PERIOD`; 60 seconds by default.  Zero requests immediate
    242  * shutdown, while the packaged service allows another 15 seconds for cleanup.
    243  */
    244 extern struct GNUNET_TIME_Relative PH_shutdown_grace_period;
    245 
    246 /**
    247  * How many bytes of a request body we hold in memory at once while
    248  * relaying it upstream, from `REQUEST_BUFFER_MAX` or the `-u` /
    249  * `--max-upload` command-line option; 256 KiB by default.
    250  *
    251  * A throughput knob, not a limit: the body is streamed, so this bounds
    252  * only how far the client may run ahead of the origin before we stop
    253  * reading from it.  What an upload is *allowed* to be is
    254  * #PH_max_request_size.  Larger means fewer suspend/resume round trips
    255  * on a fast link and more memory per request in flight; the worst case
    256  * is the product with #PH_connection_limit.
    257  *
    258  * Bounds the *proxied* path only.  Bodies sent to our own endpoints
    259  * never reach this buffer: `POST /.well-known/paivana` is read by
    260  * TALER_MHD_parse_post_json(), whose limit is
    261  * #TALER_MHD_REQUEST_BUFFER_MAX.
    262  */
    263 extern unsigned long long PH_request_buffer_max;
    264 
    265 /**
    266  * How many bytes of a response body we hold in memory at once while
    267  * relaying it to the client, from `RESPONSE_BUFFER_MAX`; 256 KiB by
    268  * default.  The mirror of #PH_request_buffer_max, and equally not a
    269  * limit — there is deliberately no ceiling on the size of a response.
    270  */
    271 extern unsigned long long PH_response_buffer_max;
    272 
    273 /**
    274  * Largest request body we accept, from `MAX_REQUEST_SIZE`; 1 MiB by
    275  * default.  Anything above it is answered 413, on the declared
    276  * `Content-Length` where there is one and otherwise once the body
    277  * actually exceeds it.
    278  *
    279  * Distinct from #PH_request_buffer_max, which used to do both jobs
    280  * because a body that could not be buffered could not be forwarded.
    281  * Streaming separates them: this one is policy, that one is memory.
    282  * For the sake of configurations written when they were one number,
    283  * an explicitly configured `REQUEST_BUFFER_MAX` with no
    284  * `MAX_REQUEST_SIZE` beside it still sets both.
    285  */
    286 extern unsigned long long PH_max_request_size;
    287 
    288 /**
    289  * How long the origin has to produce its response *headers* before we
    290  * give up on it and answer 504, from `UPSTREAM_TIMEOUT`; 60 s by
    291  * default.
    292  *
    293  * Deliberately not a bound on the whole request: a response is
    294  * relayed as it arrives, so a large one legitimately runs for as long
    295  * as it runs.  This clock is cancelled the moment the final header
    296  * section ends, and it is the only one of the three that can still
    297  * produce a status code — after that the status is already on the
    298  * wire.  A stalling origin is caught afterwards by
    299  * #PH_upstream_stall_timeout instead.
    300  */
    301 extern struct GNUNET_TIME_Relative PH_upstream_timeout;
    302 
    303 /**
    304  * How long the origin may make no progress at all — no byte moved in
    305  * either direction — before we give up on the request, from
    306  * `UPSTREAM_STALL_TIMEOUT`; 60 s by default.
    307  *
    308  * Not a bound on how long a request may take: a 500 MiB download is
    309  * expected to run for as long as it runs.  The clock is suspended
    310  * whenever *we* are the reason nothing is moving, i.e. while we hold
    311  * libcurl's receive side paused because the client has not drained
    312  * what we already have.
    313  */
    314 extern struct GNUNET_TIME_Relative PH_upstream_stall_timeout;
    315 
    316 
    317 #endif