]>
Commit | Line | Data |
---|---|---|
36c774f7 | 1 | /* |
77b1029d | 2 | * Copyright (C) 1996-2020 The Squid Software Foundation and contributors |
36c774f7 EB |
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 | ||
e015580e | 14 | #include <algorithm> |
36c774f7 | 15 | #include <limits> |
e015580e | 16 | #include <vector> |
36c774f7 | 17 | |
e015580e EB |
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 } | |
36c774f7 EB |
30 | }; |
31 | ||
e015580e EB |
32 | } // namespace Two |
33 | ||
36c774f7 EB |
34 | static Two::FieldType NameToFieldType(const SBuf &); |
35 | static Two::FieldType IntegerToFieldType(const SBuf &); | |
e015580e | 36 | |
36c774f7 EB |
37 | } // namespace ProxyProtocol |
38 | ||
e015580e EB |
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 | ||
36c774f7 EB |
51 | /// FieldNameToFieldType() helper that handles pseudo headers |
52 | ProxyProtocol::Two::FieldType | |
53 | ProxyProtocol::NameToFieldType(const SBuf &name) | |
54 | { | |
e015580e EB |
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()) | |
36c774f7 EB |
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 |