]> git.ipfire.org Git - thirdparty/squid.git/blame - src/proxyp/Elements.cc
Log PROXY protocol v2 TLVs; fix PROXY protocol parsing bugs (#342)
[thirdparty/squid.git] / src / proxyp / Elements.cc
CommitLineData
36c774f7
EB
1/*
2 * Copyright (C) 1996-2018 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 <limits>
15
16const ProxyProtocol::FieldMap ProxyProtocol::PseudoHeaderFields = {
17 { SBuf(":version"), ProxyProtocol::Two::htPseudoVersion },
18 { SBuf(":command"), ProxyProtocol::Two::htPseudoCommand },
19 { SBuf(":src_addr"), ProxyProtocol::Two::htPseudoSrcAddr },
20 { SBuf(":dst_addr"), ProxyProtocol::Two::htPseudoDstAddr },
21 { SBuf(":src_port"), ProxyProtocol::Two::htPseudoSrcPort },
22 { SBuf(":dst_port"), ProxyProtocol::Two::htPseudoDstPort }
23};
24
25namespace ProxyProtocol {
26static Two::FieldType NameToFieldType(const SBuf &);
27static Two::FieldType IntegerToFieldType(const SBuf &);
28} // namespace ProxyProtocol
29
30/// FieldNameToFieldType() helper that handles pseudo headers
31ProxyProtocol::Two::FieldType
32ProxyProtocol::NameToFieldType(const SBuf &name)
33{
34 const auto it = PseudoHeaderFields.find(name);
35 if (it != PseudoHeaderFields.end())
36 return it->second;
37
38 static const SBuf pseudoMark(":");
39 if (name.startsWith(pseudoMark))
40 throw TexcHere(ToSBuf("Unsupported PROXY protocol pseudo header: ", name));
41
42 throw TexcHere(ToSBuf("Invalid PROXY protocol pseudo header or TLV type name. ",
43 "Expected a pseudo header like :src_addr but got '", name, "'"));
44}
45
46/// FieldNameToFieldType() helper that handles integer TLV types
47ProxyProtocol::Two::FieldType
48ProxyProtocol::IntegerToFieldType(const SBuf &rawInteger)
49{
50 int64_t tlvType = 0;
51
52 Parser::Tokenizer ptok(rawInteger);
53 if (ptok.skip('0')) {
54 if (!ptok.atEnd())
55 throw TexcHere(ToSBuf("Invalid PROXY protocol TLV type value. ",
56 "Expected a decimal integer without leading zeros but got '",
57 rawInteger, "'")); // e.g., 077, 0xFF, or 0b101
58 // tlvType stays zero
59 } else {
60 Must(ptok.int64(tlvType, 10, false)); // the first character is a DIGIT
61 if (!ptok.atEnd())
62 throw TexcHere(ToSBuf("Invalid PROXY protocol TLV type value. ",
63 "Trailing garbage after ", tlvType, " in '",
64 rawInteger, "'")); // e.g., 1.0 or 5e0
65 }
66
67 const auto limit = std::numeric_limits<uint8_t>::max();
68 if (tlvType > limit)
69 throw TexcHere(ToSBuf("Invalid PROXY protocol TLV type value. ",
70 "Expected an integer less than ", limit,
71 " but got '", tlvType, "'"));
72
73 return Two::FieldType(tlvType);
74}
75
76ProxyProtocol::Two::FieldType
77ProxyProtocol::FieldNameToFieldType(const SBuf &tlvTypeRaw)
78{
79 // we could branch on ":" instead of DIGIT but then field names that lack a
80 // leading ":" (like "version") would get a less accurate error message
81 return Parser::Tokenizer(tlvTypeRaw).skipOne(CharacterSet::DIGIT) ?
82 IntegerToFieldType(tlvTypeRaw):
83 NameToFieldType(tlvTypeRaw);
84}
85