]> git.ipfire.org Git - thirdparty/squid.git/blob - src/proxyp/Elements.cc
Source Format Enforcement (#532)
[thirdparty/squid.git] / src / proxyp / Elements.cc
1 /*
2 * Copyright (C) 1996-2020 The Squid Software Foundation and contributors
3 *
4 * Squid software is distributed under GPLv2+ license and includes
5 * contributions from numerous individuals and organizations.
6 * Please see the COPYING and CONTRIBUTORS files for details.
7 */
8
9 #include "squid.h"
10 #include "parser/Tokenizer.h"
11 #include "proxyp/Elements.h"
12 #include "sbuf/Stream.h"
13
14 #include <algorithm>
15 #include <limits>
16 #include <vector>
17
18 namespace ProxyProtocol {
19 namespace Two {
20
21 /// a mapping between pseudo header names and ids
22 typedef std::vector< std::pair<SBuf, FieldType> > FieldMap;
23 static const FieldMap PseudoHeaderFields = {
24 { SBuf(":version"), htPseudoVersion },
25 { SBuf(":command"), htPseudoCommand },
26 { SBuf(":src_addr"), htPseudoSrcAddr },
27 { SBuf(":dst_addr"), htPseudoDstAddr },
28 { SBuf(":src_port"), htPseudoSrcPort },
29 { SBuf(":dst_port"), htPseudoDstPort }
30 };
31
32 } // namespace Two
33
34 static Two::FieldType NameToFieldType(const SBuf &);
35 static Two::FieldType IntegerToFieldType(const SBuf &);
36
37 } // namespace ProxyProtocol
38
39 const SBuf &
40 ProxyProtocol::PseudoFieldTypeToFieldName(const Two::FieldType fieldType)
41 {
42 const auto it = std::find_if(Two::PseudoHeaderFields.begin(), Two::PseudoHeaderFields.end(),
43 [fieldType](const Two::FieldMap::value_type &item) {
44 return item.second == fieldType;
45 });
46
47 assert(it != Two::PseudoHeaderFields.end());
48 return it->first;
49 }
50
51 /// FieldNameToFieldType() helper that handles pseudo headers
52 ProxyProtocol::Two::FieldType
53 ProxyProtocol::NameToFieldType(const SBuf &name)
54 {
55 const auto it = std::find_if(Two::PseudoHeaderFields.begin(), Two::PseudoHeaderFields.end(),
56 [&name](const Two::FieldMap::value_type &item) {
57 return item.first == name;
58 });
59
60 if (it != Two::PseudoHeaderFields.end())
61 return it->second;
62
63 static const SBuf pseudoMark(":");
64 if (name.startsWith(pseudoMark))
65 throw TexcHere(ToSBuf("Unsupported PROXY protocol pseudo header: ", name));
66
67 throw TexcHere(ToSBuf("Invalid PROXY protocol pseudo header or TLV type name. ",
68 "Expected a pseudo header like :src_addr but got '", name, "'"));
69 }
70
71 /// FieldNameToFieldType() helper that handles integer TLV types
72 ProxyProtocol::Two::FieldType
73 ProxyProtocol::IntegerToFieldType(const SBuf &rawInteger)
74 {
75 int64_t tlvType = 0;
76
77 Parser::Tokenizer ptok(rawInteger);
78 if (ptok.skip('0')) {
79 if (!ptok.atEnd())
80 throw TexcHere(ToSBuf("Invalid PROXY protocol TLV type value. ",
81 "Expected a decimal integer without leading zeros but got '",
82 rawInteger, "'")); // e.g., 077, 0xFF, or 0b101
83 // tlvType stays zero
84 } else {
85 Must(ptok.int64(tlvType, 10, false)); // the first character is a DIGIT
86 if (!ptok.atEnd())
87 throw TexcHere(ToSBuf("Invalid PROXY protocol TLV type value. ",
88 "Trailing garbage after ", tlvType, " in '",
89 rawInteger, "'")); // e.g., 1.0 or 5e0
90 }
91
92 const auto limit = std::numeric_limits<uint8_t>::max();
93 if (tlvType > limit)
94 throw TexcHere(ToSBuf("Invalid PROXY protocol TLV type value. ",
95 "Expected an integer less than ", limit,
96 " but got '", tlvType, "'"));
97
98 return Two::FieldType(tlvType);
99 }
100
101 ProxyProtocol::Two::FieldType
102 ProxyProtocol::FieldNameToFieldType(const SBuf &tlvTypeRaw)
103 {
104 // we could branch on ":" instead of DIGIT but then field names that lack a
105 // leading ":" (like "version") would get a less accurate error message
106 return Parser::Tokenizer(tlvTypeRaw).skipOne(CharacterSet::DIGIT) ?
107 IntegerToFieldType(tlvTypeRaw):
108 NameToFieldType(tlvTypeRaw);
109 }
110