GCC Code Coverage Report


Directory: ./
File: fpphttp_clientip.h
Date: 2026-10-29 08:11:58
Exec Total Coverage
Lines: 5 11 45.5%
Functions: 1 1 100.0%
Branches: 6 20 30.0%

Line Branch Exec Source
1 #pragma once
2 /*
3 * This file is part of the Falcon Player (FPP) and is Copyright (C)
4 * 2013-2022 by the Falcon Player Developers.
5 *
6 * The Falcon Player (FPP) is free software, and is covered under
7 * multiple Open Source licenses. Please see the included 'LICENSES'
8 * file for descriptions of what files are covered by each license.
9 *
10 * This source file is covered under the LGPL v2.1 as described in the
11 * included LICENSE.LGPL file.
12 */
13
14 // FPP-internal, deliberately NOT part of the plugin API.
15 //
16 // This lives outside fpphttp.h because it is the only helper of its kind that
17 // needs HttpRequest's *members* (getHeader/getPeerAddr) rather than just the
18 // HttpRequestPtr alias. Plugins vendor fpphttp.h (along with Plugin.h,
19 // fpphttp_types.h and fpp-json-fwd.h) and compile it against their own stand-in
20 // for drogon; a non-template inline function is emitted in every translation
21 // unit that includes its header, so putting this in fpphttp.h would force every
22 // such stub to grow both methods. Nothing outside FPP's own sources includes
23 // this file, so the requirement stays where it belongs.
24
25 #include "fpphttp.h"
26
27 #include <string>
28
29 // Best-effort real client IP for a request that may have come through FPP's
30 // local Apache reverse proxy (see etc/apache2.site - it proxies /api/* and
31 // friends to this process on 127.0.0.1:FPP_HTTP_PORT and, by Apache's
32 // mod_proxy default (ProxyAddHeaders On), appends X-Forwarded-For; the same
33 // default applies to the cross-host /proxy/<ip>/api/... rules used to reach
34 // another FPP's API through this one's Apache, so a multi-hop chain of FPP
35 // devices relaying a request ends up as multiple comma-separated entries).
36 // Logging the raw TCP peer for those requests always shows Apache's own
37 // loopback connection, indistinguishable from a local script/plugin calling
38 // this process directly.
39 //
40 // This is intentionally simple and NOT a trust/security check: if
41 // X-Forwarded-For is present at all, use its LEFTMOST entry (the original
42 // client, as far back through any proxy chain as the header reaches);
43 // otherwise fall back to the raw TCP peer. The header is trivially spoofable
44 // by anything that talks to this port directly - Apache only ever appends to
45 // whatever value it received, never validates or replaces what's already
46 // there - so treat this as best-effort attribution for logs, never as an
47 // access-control decision.
48 683292 inline std::string getEffectiveClientIP(const HttpRequestPtr& req) {
49
3/6
✓ Branch 0 taken 683292 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 683292 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 683292 times.
✗ Branch 5 not taken.
1366584 std::string xff = req->getHeader("x-forwarded-for");
50
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 683292 times.
683292 if (!xff.empty()) {
51 ✗ std::string first = xff.substr(0, xff.find(','));
52 ✗ size_t b = first.find_first_not_of(" \t");
53 ✗ size_t e = first.find_last_not_of(" \t");
54 ✗ if (b != std::string::npos) {
55 ✗ return first.substr(b, e - b + 1);
56 }
57 ✗ }
58
2/4
✓ Branch 0 taken 683292 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 683292 times.
✗ Branch 3 not taken.
683292 return req->getPeerAddr().toIp();
59 683292 }
60