2 * Copyright (C) 1996-2020 The Squid Software Foundation and contributors
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.
10 #include "parser/Tokenizer.h"
11 #include "proxyp/Elements.h"
12 #include "sbuf/Stream.h"
18 namespace ProxyProtocol
{
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
}
34 static Two::FieldType
NameToFieldType(const SBuf
&);
35 static Two::FieldType
IntegerToFieldType(const SBuf
&);
37 } // namespace ProxyProtocol
40 ProxyProtocol::PseudoFieldTypeToFieldName(const Two::FieldType fieldType
)
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
;
47 assert(it
!= Two::PseudoHeaderFields
.end());
51 /// FieldNameToFieldType() helper that handles pseudo headers
52 ProxyProtocol::Two::FieldType
53 ProxyProtocol::NameToFieldType(const SBuf
&name
)
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
;
60 if (it
!= Two::PseudoHeaderFields
.end())
63 static const SBuf
pseudoMark(":");
64 if (name
.startsWith(pseudoMark
))
65 throw TexcHere(ToSBuf("Unsupported PROXY protocol pseudo header: ", name
));
67 throw TexcHere(ToSBuf("Invalid PROXY protocol pseudo header or TLV type name. ",
68 "Expected a pseudo header like :src_addr but got '", name
, "'"));
71 /// FieldNameToFieldType() helper that handles integer TLV types
72 ProxyProtocol::Two::FieldType
73 ProxyProtocol::IntegerToFieldType(const SBuf
&rawInteger
)
77 Parser::Tokenizer
ptok(rawInteger
);
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
85 Must(ptok
.int64(tlvType
, 10, false)); // the first character is a DIGIT
87 throw TexcHere(ToSBuf("Invalid PROXY protocol TLV type value. ",
88 "Trailing garbage after ", tlvType
, " in '",
89 rawInteger
, "'")); // e.g., 1.0 or 5e0
92 const auto limit
= std::numeric_limits
<uint8_t>::max();
94 throw TexcHere(ToSBuf("Invalid PROXY protocol TLV type value. ",
95 "Expected an integer less than ", limit
,
96 " but got '", tlvType
, "'"));
98 return Two::FieldType(tlvType
);
101 ProxyProtocol::Two::FieldType
102 ProxyProtocol::FieldNameToFieldType(const SBuf
&tlvTypeRaw
)
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
);