ProtoCore v1.0.16
Deterministic, zero-heap network stack for embedded targets
Loading...
Searching...
No Matches
forwarded_trust.h
Go to the documentation of this file.
1// ProtoCore v1.0.16 - Copyright (C) 2026 Douglas Quigg (dstroy0) <dquigg123@gmail.com>
2// SPDX-License-Identifier: AGPL-3.0-or-later
3
4/**
5 * @file forwarded_trust.h
6 * @brief Trusted-reverse-proxy resolution of a forwarded client address (PROTOCORE_ENABLE_FORWARDED_TRUST).
7 *
8 * A `Forwarded` (RFC 7239) / `X-Forwarded-For` header is CLIENT-SPOOFABLE, so the client address it
9 * carries may only be believed when the connection's real TCP peer is a reverse proxy the operator
10 * trusts. This keeps a fixed BSS table of trusted-upstream CIDRs and resolves the effective client
11 * address for the abuse-prevention layer: when the TCP peer matches a trusted CIDR and the forwarded
12 * token is a valid, specified address, the forwarded client is used; otherwise the real TCP peer is
13 * used. Fail-safe by construction - an empty table trusts no header, and a malformed / obfuscated /
14 * unspecified token falls back to the TCP peer, so a direct (untrusted) client cannot spoof its way
15 * out of, or another peer into, the auth lockout. Pure (no sockets, no heap), host-tested.
16 *
17 * The table is a single owned instance reached only through this API (mirrors the source-IP allowlist
18 * and the auth-lockout table). Register upstreams with protocore_forwarded_trust_add_cidr("10.0.0.0/8").
19 */
20
21#ifndef PROTOCORE_FORWARDED_TRUST_H
22#define PROTOCORE_FORWARDED_TRUST_H
23
24#include "protocore_config.h" // the entry point: protocore_types.h for the widths
25
26#if PROTOCORE_ENABLE_FORWARDED_TRUST
27
29
30// PROTOCORE_FORWARDED_TRUST_BORROW - the bytes this module runs out of - is stated in protocore_config.h, which sums it
31// into its arena. A caller takes them once and passes the pointer to every call. How they are
32// carved is this module's and is never named here.
33
34/** @brief protocore_ip, as the caller already knows it. */
35struct protocore_ip;
36
37/** @brief What add takes. */
38typedef struct
39{
40 const struct protocore_ip *network;
41 uint8_t prefix_len;
42} ForwardedTrustAddArgs;
43
44/** @brief What add_cidr takes. */
45typedef struct
46{
47 const char *cidr;
48} ForwardedTrustAddCidrArgs;
49
50/** @brief What contains takes. */
51typedef struct
52{
53 const struct protocore_ip *peer;
54} ForwardedTrustContainsArgs;
55
56/** @brief What protocore_forwarded_effective_ip takes. */
57typedef struct
58{
59 const struct protocore_ip *peer;
60 const char *fwd_ip_str;
61 struct protocore_ip *out;
62} ForwardedTrustProtocoreForwardedEffectiveIpArgs;
63typedef struct
64{
65 ForwardedTrustAddArgs add_args;
66 ForwardedTrustAddCidrArgs add_cidr_args;
67 ForwardedTrustContainsArgs contains_args;
68 ForwardedTrustProtocoreForwardedEffectiveIpArgs protocore_forwarded_effective_ip_args;
69 proto_bool ok;
70} ForwardedTrustVars;
71
72/** @brief The operands and the outcome. */
73extern ForwardedTrustVars ForwardedTrustV;
74
75/** @brief The entries. */
76typedef struct
77{
78 void (*const reset)(uint8_t *work);
79 void (*const add)(uint8_t *work);
80 void (*const add_cidr)(uint8_t *work);
81 void (*const contains)(uint8_t *work);
82 void (*const protocore_forwarded_effective_ip)(uint8_t *work);
83} ForwardedTrustNs;
84
85// What the table binds, defined once in the .c and taking one parameter each: everything
86// else an entry needs is an operand in ForwardedTrustV or a region of the borrow at a fixed offset.
87void protocore_forwarded_trust_reset(uint8_t *work);
88void protocore_forwarded_trust_add(uint8_t *work);
89void protocore_forwarded_trust_add_cidr(uint8_t *work);
90void protocore_forwarded_trust_contains(uint8_t *work);
91void protocore_forwarded_trust_protocore_forwarded_effective_ip(uint8_t *work);
92
93// `static const`, initialised HERE rather than `extern` against a definition in the .c: a
94// const object whose initializer every translation unit can see is a COMPILE-TIME FACT, so
95// `ForwardedTrust.reset(work)` resolves to a named function and becomes a DIRECT call. An extern table
96// leaves the call indirect and the symbol live at every level, -O2 -flto included.
97static const ForwardedTrustNs ForwardedTrust __attribute__((unused)) = {
98 .reset = protocore_forwarded_trust_reset,
99 .add = protocore_forwarded_trust_add,
100 .add_cidr = protocore_forwarded_trust_add_cidr,
101 .contains = protocore_forwarded_trust_contains,
102 .protocore_forwarded_effective_ip = protocore_forwarded_trust_protocore_forwarded_effective_ip,
103};
104
105/**
106 * @brief The PROTOCORE_FORWARDED_TRUST_BORROW bytes this module's state lives in.
107 *
108 * Stated beside the namespace rather than on it: an entry takes a borrow, and this is where
109 * that borrow comes from. Taken once from the end of the pool, which no mark and no release
110 * walks, so the state lasts the life of the program.
111 *
112 * @return the span.
113 */
114uint8_t *protocore_forwarded_trust_span(void);
115
117
118#endif // PROTOCORE_ENABLE_FORWARDED_TRUST
119
120#endif // PROTOCORE_FORWARDED_TRUST_H
A v4 or v6 address in network (big-endian) byte order.
Definition ip.h:56
#define PROTOCORE_BEGIN_DECLS
Give a header's declarations C linkage, so their symbol names carry no parameter types.
Definition types.h:96
_Bool proto_bool
The truth value.
Definition types.h:64
#define PROTOCORE_END_DECLS
Definition types.h:97