Crates.io | haprox-rs |
lib.rs | haprox-rs |
version | 0.2.3 |
created_at | 2025-05-04 20:54:37.919775+00 |
updated_at | 2025-09-24 23:03:26.921042+00 |
description | A HaProxy protocol parser. |
homepage | |
repository | https://codeberg.org/4neko/haprox-rs |
max_upload_size | |
id | 1659924 |
size | 171,507 |
A HaProxy proxy protocol parser.
V2 of the protocol revision 3.1 2020/03/05.
V1 is not supported.
The pull requests are now supported because the repository was moved to Codeberg. The alternative way is to send patches over the email to patch[at]4neko.org.
In case if you would like to contribute the code, please use pull request. Your pull request should include:
Description of changes and why it is needed.
Test the pull request.
In case of you prefer email and patch files please consider the following:
For each feature or fix, please send patches separatly.
Please write what your patch is implementing or fixing.
I can read the code and I am able to understand it, so don't write a poem or essay in the description to the patches.
Please test your patch.
Can I use the MPL-2.0 licensed code (crate) in larger project licensed with more permissive license like BSD or MIT.
I want to distribute (outside my organization) executable programs or libraries that I have compiled from someone else's unchanged MPL-licensed source code, either standalone or part of a larger work. What do I have to do?
You must inform the recipients where they can get the source for the MPLed code in the executable program or library you are distributing (i.e., you must comply with Section 3.2). You may distribute any executables you create under a license of your choosing, as long as that license does not interfere with the recipients' rights to the source under the terms of the MPL.
Yes, MPL- and Apache-licensed code can be used with an MIT codebase (so in that sense, they are "compatible"). However, the MPL- / Apache-licensed code remains under its original license. (So although compatible, you cannot relicense someone else's MPL or Apache code into the MIT license.) This means that your final codebase will contain a mix of MPL, Apache, and MIT licensed code. As an example, MPL has weak copyleft, so if you modified an MPL file, that file (including your changes) must remain under the MPL license.
You should use this license if you are located in the EU which gives you more advantages over GPL because in case of any disputes, the license allows you to defend your rights in a European Union country, in this case it will be Spain. It has also been translated into all languages of the EU member states.
Matrix of EUPL compatible open source licences
EUPL-1.2
is incompatiable with GPL
according to GNU ORG
This is a free software license. By itself, it has a copyleft comparable to the GPL's, and incompatible with it.
v0.2.2
Sources are available under: MPL-2.0 OR EUPL-1.2
The project has moved to Codeberg.
use std::{fmt, io::Cursor};
use byteorder::{BigEndian, WriteBytesExt};
use haprox_rs::{common::map_io_err, protocol::PP2TlvDump, protocol_composer::{HdrV2OpProxy, ProxyHdrV2}, HaProxRes, PP2TlvClient, ProxyTransportFam, ProxyV2Addr};
#[derive(Clone, Debug)]
pub enum ProxyV2Dummy2
{
SomeTlvName(u32, u32),
}
impl fmt::Display for ProxyV2Dummy2
{
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result
{
write!(f, "DUMMY external reader")
}
}
impl PP2TlvDump for ProxyV2Dummy2
{
fn get_type(&self) -> u8
{
let Self::SomeTlvName(..) = self else { panic!("wrong") };
return 0xE0;
}
fn dump(&self, cur: &mut Cursor<Vec<u8>>) -> HaProxRes<()>
{
match self
{
Self::SomeTlvName(arg0, arg1) =>
{
cur.write_u32::<BigEndian>(*arg0).map_err(map_io_err)?;
cur.write_u32::<BigEndian>(*arg1).map_err(map_io_err)?;
}
}
return Ok(());
}
}
fn main()
{
let addr = ProxyV2Addr::try_from(("127.0.0.1:39754", "127.0.0.67:11883")).unwrap();
let mut comp =
ProxyHdrV2::<HdrV2OpProxy>::new(ProxyTransportFam::STREAM, addr).unwrap();
let plts = comp.set_plts();
let mut ssl = plts.add_ssl(PP2TlvClient::PP2_CLIENT_SSL, 0).unwrap();
ssl.add_ssl_sub_version("TLSv1.2").unwrap();
let mut plts = ssl.done().unwrap();
let cust_plt = ProxyV2Dummy2::SomeTlvName(0x01020304, 0x05060708);
plts.add_tlv(cust_plt, Some(&[0xE0..=0xE0])).unwrap();
drop(plts);
let pkt: Vec<u8> = comp.try_into().unwrap();
let ctrl =
b"\x0d\x0a\x0d\x0a\x00\x0d\x0a\x51\x55\x49\x54\x0a\x21\x11\x00\x29\
\x7f\x00\x00\x01\x7f\x00\x00\x43\x9b\x4a\x2e\x6b\x20\x00\x0f\x01\
\x00\x00\x00\x00\x21\x00\x07\x54\x4c\x53\x76\x31\x2e\x32\xE0\x00\
\x08\x01\x02\x03\x04\x05\x06\x07\x08";
assert_eq!(pkt.as_slice(), ctrl.as_slice());
}
use std::{fmt, io::Cursor};
use byteorder::{BigEndian, ReadBytesExt};
use haprox_rs::{common, protocol::{PP2TlvDump, PP2TlvRestore}, ProxyV2Parser, return_error, HaProxRes, HdrV2Command, PP2TlvClient, PP2Tlvs, ProtocolVersion, ProxyTransportFam, ProxyV2Addr, ProxyV2AddrType, PP2_TYPE_MIN_CUSTOM};
#[derive(Clone, Debug)]
pub enum ProxyV2Dummy2
{
SomeTlvName(u32, u32),
OtherTlv,
}
impl fmt::Display for ProxyV2Dummy2
{
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result
{
write!(f, "DUMMY external reader")
}
}
impl PP2TlvRestore for ProxyV2Dummy2
{
fn restore(tlv_type: u8, cur: &mut Cursor<&[u8]>) -> HaProxRes<Self> where Self: Sized
{
match tlv_type
{
0xE0 =>
{
let arg0 = cur.read_u32::<BigEndian>().map_err(common::map_io_err)?;
let arg1 = cur.read_u32::<BigEndian>().map_err(common::map_io_err)?;
return Ok(Self::SomeTlvName(arg0, arg1));
},
_ =>
return_error!(ProtocolUnknownData, "unknown tlv_type: {}", tlv_type)
}
}
fn is_in_range(tlv_type: u8, _tlv_parent_type: Option<u8>) -> bool
{
return tlv_type == PP2_TYPE_MIN_CUSTOM;
}
fn contains_subtype(&self) -> bool
{
return false;
}
}
impl PP2TlvDump for ProxyV2Dummy2
{
fn get_type(&self) -> u8
{
let Self::SomeTlvName(..) = self else { panic!("wrong") };
return 0xE0;
}
fn dump(&self, _cur: &mut Cursor<Vec<u8>>) -> HaProxRes<()>
{
todo!()
}
}
fn main() -> HaProxRes<()>
{
let pkt_ssl =
b"\x0d\x0a\x0d\x0a\x00\x0d\x0a\x51\x55\x49\x54\x0a\x21\x11\x00\x29\
\x7f\x00\x00\x01\x7f\x00\x00\x43\x9b\x4a\x2e\x6b\x20\x00\x0f\x01\
\x00\x00\x00\x00\x21\x00\x07\x54\x4c\x53\x76\x31\x2e\x32\xE0\x00\
\x08\x01\x02\x03\x04\x05\x06\x07\x08";
let dec = ProxyV2Parser::<ProxyV2Dummy2>::try_from_slice_custom(pkt_ssl.as_slice()).unwrap();
assert_eq!(dec.get_transport().is_ok(), true);
assert_eq!(dec.get_transport().unwrap(), ProxyTransportFam::STREAM);
assert_eq!(dec.get_proto_version(), ProtocolVersion::V2);
assert_eq!(dec.get_proto_command(), HdrV2Command::PROXY);
assert_eq!(dec.get_address_family().is_ok(), true);
assert_eq!(dec.get_address_family().unwrap(), ProxyV2AddrType::AfInet);
let addr = dec.get_address().unwrap();
assert_eq!(addr.is_some(), true);
let addr = addr.unwrap();
let maddr = ProxyV2Addr::try_from(("127.0.0.1:39754", "127.0.0.67:11883")).unwrap();
assert_eq!(addr, maddr);
let tlv_iter = dec.get_tlvs_iter();
assert_eq!(tlv_iter.is_some(), true);
let mut tlv_iter = tlv_iter.unwrap();
let type_ssl = tlv_iter.next().unwrap().take_internal().unwrap();
assert_eq!(type_ssl.get_type(), PP2Tlvs::TYPE_SSL);
let PP2Tlvs::TypeSsl { client, verify } = type_ssl else {panic!("wrong")};
assert_eq!(client, PP2TlvClient::PP2_CLIENT_SSL);
assert_eq!(verify, 0);
// --
let type_ssl_version = tlv_iter.next().unwrap().take_internal().unwrap();
assert_eq!(type_ssl_version.get_type(), PP2Tlvs::TYPE_SUBTYPE_SSL_VERSION);
let PP2Tlvs::TypeSubtypeSslVersion(ssl_version) = type_ssl_version else { panic!("wrong") };
assert_eq!(ssl_version, "TLSv1.2");
// ---
let ext_type_e0 = tlv_iter.next().unwrap().take_external().unwrap();
assert_eq!(ext_type_e0.get_type(), 0xE0);
let ProxyV2Dummy2::SomeTlvName(arg0, arg1) = ext_type_e0 else {panic!("wrong")};
assert_eq!(arg0, 0x01020304);
assert_eq!(arg1, 0x05060708);
return Ok(());
}