Skip to main content

proxy_protocol_rs/
error.rs

1// Copyright (C) 2025-2026 Michael S. Klishin and Contributors
2//
3// Licensed under the Apache License, Version 2.0 (the "License");
4// you may not use this file except in compliance with the License.
5// You may obtain a copy of the License at
6//
7// http://www.apache.org/licenses/LICENSE-2.0
8//
9// Unless required by applicable law or agreed to in writing, software
10// distributed under the License is distributed on an "AS IS" BASIS,
11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12// See the License for the specific language governing permissions and
13// limitations under the License.
14
15use std::net::SocketAddr;
16
17#[derive(Debug, thiserror::Error)]
18#[non_exhaustive]
19pub enum ParseError {
20    #[error("data does not begin with a Proxy Protocol signature")]
21    NotProxyProtocol,
22
23    #[error("incomplete header, need more data")]
24    Incomplete,
25
26    #[error("malformed Proxy Protocol header: {0}")]
27    Invalid(InvalidReason),
28
29    #[error("CRC32c mismatch: expected {expected:#010x}, got {actual:#010x}")]
30    CrcMismatch { expected: u32, actual: u32 },
31}
32
33#[derive(Debug, thiserror::Error)]
34#[non_exhaustive]
35pub enum InvalidReason {
36    #[error("unsupported protocol version: {0:#x}")]
37    UnsupportedVersion(u8),
38
39    #[error("unknown command nibble: {0:#x}")]
40    UnknownCommand(u8),
41
42    #[error("unknown address family: {0:#x}")]
43    UnknownFamily(u8),
44
45    #[error("unknown transport protocol: {0:#x}")]
46    UnknownProtocol(u8),
47
48    #[error("v1 header exceeds 107-byte limit")]
49    V1TooLong,
50
51    #[error("v1 header not valid UTF-8")]
52    V1NotUtf8,
53
54    #[error("v1 invalid format: expected 6 space-separated fields")]
55    V1InvalidFormat,
56
57    #[error("v1 unknown transport: {0}")]
58    V1UnknownTransport(String),
59
60    #[error("invalid IP address: {0}")]
61    InvalidIp(String),
62
63    #[error("invalid port: {0}")]
64    InvalidPort(String),
65
66    #[error("PROXY command requires a concrete address family and protocol")]
67    UnspecWithProxy,
68
69    #[error("payload length {len} exceeds buffer ({buf_len} available)")]
70    PayloadOverflow { len: usize, buf_len: usize },
71
72    #[error("malformed TLV at offset {offset}")]
73    MalformedTlv { offset: usize },
74}
75
76#[derive(Debug, thiserror::Error)]
77#[non_exhaustive]
78pub enum AcceptError {
79    #[error("I/O error: {0}")]
80    Io(#[from] std::io::Error),
81
82    #[error("connection from {0} rejected by policy")]
83    Rejected(SocketAddr),
84
85    #[error("Proxy Protocol header timeout from {0}")]
86    HeaderTimeout(SocketAddr),
87
88    #[error("empty connection from {0}")]
89    EmptyConnection(SocketAddr),
90
91    #[error("Proxy Protocol parse error from {1}: {0}")]
92    Parse(ParseError, SocketAddr),
93
94    #[error("header validation failed from {1}: {0}")]
95    ValidationFailed(Box<dyn std::error::Error + Send + Sync>, SocketAddr),
96
97    #[error("unwanted Proxy Protocol version from {0}")]
98    VersionMismatch(SocketAddr),
99}
100
101#[derive(Debug, thiserror::Error)]
102#[non_exhaustive]
103pub enum TlvParseError {
104    #[error("malformed sub-TLV at offset {offset}")]
105    MalformedSubTlv { offset: usize },
106
107    #[error("invalid sub-TLV value: {reason}")]
108    InvalidValue { reason: String },
109}