blob: 7d7fc34e46648f08bf5f373d93b4a0eb85f6f58c [file]
/** @file
PROXY Protocol
See: https://www.haproxy.org/download/1.8/doc/proxy-protocol.txt
@section license License
Licensed to the Apache Software Foundation (ASF) under one
or more contributor license agreements. See the NOTICE file
distributed with this work for additional information
regarding copyright ownership. The ASF licenses this file
to you under the Apache License, Version 2.0 (the
"License"); you may not use this file except in compliance
with the License. You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
#pragma once
#include <tscore/ink_inet.h>
#include <swoc/TextView.h>
#include <unordered_map>
#include <cstdlib>
#include <optional>
enum class ProxyProtocolVersion {
UNDEFINED,
V1,
V2,
};
enum class ProxyProtocolData {
UNDEFINED,
SRC,
DST,
};
constexpr uint8_t PP2_TYPE_ALPN = 0x01;
constexpr uint8_t PP2_TYPE_AUTHORITY = 0x02;
constexpr uint8_t PP2_TYPE_CRC32C = 0x03;
constexpr uint8_t PP2_TYPE_NOOP = 0x04;
constexpr uint8_t PP2_TYPE_UNIQUE_ID = 0x05;
constexpr uint8_t PP2_TYPE_SSL = 0x20;
constexpr uint8_t PP2_SUBTYPE_SSL_VERSION = 0x21;
constexpr uint8_t PP2_SUBTYPE_SSL_CN = 0x22;
constexpr uint8_t PP2_SUBTYPE_SSL_CIPHER = 0x23;
constexpr uint8_t PP2_SUBTYPE_SSL_SIG_ALG = 0x24;
constexpr uint8_t PP2_SUBTYPE_SSL_KEY_ALG = 0x25;
constexpr uint8_t PP2_SUBTYPE_SSL_GROUP = 0x26;
constexpr uint8_t PP2_TYPE_NETNS = 0x30;
class ProxyProtocol
{
public:
ProxyProtocol() {}
ProxyProtocol(ProxyProtocolVersion pp_ver, uint16_t family, IpEndpoint src, IpEndpoint dst)
: version(pp_ver), ip_family(family), src_addr(src), dst_addr(dst)
{
}
ProxyProtocol(const ProxyProtocol &other)
: version(other.version), ip_family(other.ip_family), src_addr(other.src_addr), dst_addr(other.dst_addr)
{
if (!other.additional_data.empty()) {
set_additional_data(other.additional_data);
}
}
ProxyProtocol(ProxyProtocol &&other)
: version(other.version), ip_family(other.ip_family), src_addr(other.src_addr), dst_addr(other.dst_addr)
{
if (!other.additional_data.empty()) {
set_additional_data(other.additional_data);
}
other.additional_data.clear();
other.tlv.clear();
}
~ProxyProtocol() = default;
/** Release owned heap and reset to the default-constructed state.
*
* Swap rather than clear() the containers: clear() retains capacity, which would be abandoned
* (leaked) when the slot is reused, since the NetVConnection allocators are Destruct_on_free=false
* and so never run ~ProxyProtocol.
*/
void
reset()
{
std::string{}.swap(additional_data);
std::unordered_map<uint8_t, std::string_view>{}.swap(tlv);
version = ProxyProtocolVersion::UNDEFINED;
ip_family = AF_UNSPEC;
type = 0;
src_addr = {};
dst_addr = {};
}
int set_additional_data(std::string_view data);
void set_ipv4_addrs(in_addr_t src_addr, uint16_t src_port, in_addr_t dst_addr, uint16_t dst_port);
void set_ipv6_addrs(const in6_addr &src_addr, uint16_t src_port, const in6_addr &dst_addr, uint16_t dst_port);
std::optional<std::string_view> get_tlv(const uint8_t tlvCode) const;
std::optional<std::string_view> get_tlv_ssl_version() const;
std::optional<std::string_view> get_tlv_ssl_cipher() const;
std::optional<std::string_view> get_tlv_ssl_group() const;
ProxyProtocolVersion version = ProxyProtocolVersion::UNDEFINED;
uint16_t ip_family = AF_UNSPEC;
int type = 0;
IpEndpoint src_addr = {};
IpEndpoint dst_addr = {};
std::unordered_map<uint8_t, std::string_view> tlv;
ProxyProtocol &
operator=(const ProxyProtocol &other)
{
if (&other == this) {
return *this;
}
version = other.version;
ip_family = other.ip_family;
src_addr = other.src_addr;
dst_addr = other.dst_addr;
if (!other.additional_data.empty()) {
set_additional_data(other.additional_data);
} else {
additional_data.clear();
tlv.clear();
}
return *this;
}
ProxyProtocol &
operator=(ProxyProtocol &&other)
{
version = other.version;
ip_family = other.ip_family;
src_addr = other.src_addr;
dst_addr = other.dst_addr;
additional_data.clear();
tlv.clear();
if (!other.additional_data.empty()) {
set_additional_data(other.additional_data);
}
other.additional_data.clear();
other.tlv.clear();
return *this;
}
private:
std::string additional_data;
std::optional<std::string_view> _get_tlv_ssl_subtype(uint8_t subtype) const;
};
const size_t PPv1_CONNECTION_HEADER_LEN_MAX = 108;
const size_t PPv2_CONNECTION_HEADER_LEN = 16;
extern bool proxy_protocol_detect(swoc::TextView tv);
extern size_t proxy_protocol_parse(ProxyProtocol *pp_info, swoc::TextView tv);
extern size_t proxy_protocol_build(uint8_t *buf, size_t max_buf_len, const ProxyProtocol &pp_info,
ProxyProtocolVersion force_version = ProxyProtocolVersion::UNDEFINED);
extern ProxyProtocolVersion proxy_protocol_version_cast(int i);