proxyprotocol

package module
v0.0.0-...-4622579 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Jul 18, 2023 License: Apache-2.0 Imports: 11 Imported by: 1

README

proxyprotocol

GoDoc Build Status

This package provides PROXY protocol support for versions 1 and 2.

https://www.haproxy.org/download/1.8/doc/proxy-protocol.txt

Features:

  • Auto detect both V1 and V2
  • Client & Server usage support
  • Listener with optional subnet filtering (for TCP/UDP listeners)

Installation

Installable via go get

go get -u github.com/mastercactapus/proxyprotocol

Usage

// Create any net.Listener
l, err := net.Listen("tcp", ":0")
l, err := net.Listen("udp", ":0")
l, err := net.Listen("unix", "/tmp/example")
l, err := net.Listen("unixgram", "/tmp/example")

// Wrap it to have RemoteAddr() and LocalAddr() resolved for all new connections
l = proxyprotocol.NewListener(l, 0)

c, err : = l.Accept()

c.RemoteAddr() // = The PROXY header source address
c.LocalAddr()  // = The PROXY header destination address

Documentation

Overview

Package proxyprotocol implements version 1 and 2 of the PROXY protocol.

https://www.haproxy.org/download/1.8/doc/proxy-protocol.txt

Index

Examples

Constants

This section is empty.

Variables

This section is empty.

Functions

This section is empty.

Types

type Cmd

type Cmd byte

Cmd indicates the PROXY command being used.

const (
	// CmdLocal indicates the connection was established on purpose by the proxy without being relayed.
	CmdLocal Cmd = 0x00

	// CmdProxy the connection was established on behalf of another node, and reflects the original connection endpoints.
	CmdProxy Cmd = 0x01
)

type Conn

type Conn struct {
	net.Conn
	// contains filtered or unexported fields
}

Conn wraps a net.Conn using the PROXY protocol to determin LocalAddr() and RemoteAddr().

func NewConn

func NewConn(c net.Conn, deadline time.Time) *Conn

NewConn will wrap an existing net.Conn using `deadline` to receive the header.

func (*Conn) LocalAddr

func (c *Conn) LocalAddr() net.Addr

LocalAddr returns the local network address provided by the PROXY header.

func (*Conn) ProxyHeader

func (c *Conn) ProxyHeader() (Header, error)

ProxyHeader will return the PROXY header received on the current connection.

func (*Conn) Read

func (c *Conn) Read(p []byte) (int, error)

Read reads data from the connection, after parsing the PROXY header.

func (*Conn) RemoteAddr

func (c *Conn) RemoteAddr() net.Addr

RemoteAddr returns the remote network address provided by the PROXY header.

func (*Conn) SetDeadline

func (c *Conn) SetDeadline(t time.Time) error

SetDeadline calls SetDeadline on the underlying net.Conn.

func (*Conn) SetReadDeadline

func (c *Conn) SetReadDeadline(t time.Time) error

SetReadDeadline calls SetReadDeadline on the underlying net.Conn.

type Header interface {
	Version() int
	SrcAddr() net.Addr
	DestAddr() net.Addr

	WriteTo(io.Writer) (int64, error)
}

Header provides information decoded from a PROXY header.

func Parse

func Parse(r *bufio.Reader) (Header, error)

Parse will parse detect and return a V1 or V2 header, otherwise InvalidHeaderErr is returned.

type HeaderV1

type HeaderV1 struct {
	SrcPort  int
	SrcIP    net.IP
	DestPort int
	DestIP   net.IP
}

HeaderV1 contains information relayed by the PROXY protocol version 1 (human-readable) header.

Example (Proxy)
l, err := net.Listen("tcp", ":8080")
if err != nil {
	log.Println("ERROR: listen:", err)
	return
}
defer l.Close()

var hdr HeaderV1
c, err := l.Accept()
if err != nil {
	log.Println("ERROR: accept:", err)
	return
}
defer c.Close()

// Populate hdr from the new incomming connection.
hdr.FromConn(c, false)

// Example target
//
// This server will be sent a PROXY header.
dst, err := net.Dial("tcp", "192.168.0.2:12345")
if err != nil {
	log.Println("ERROR: connect:", err)
	return
}
defer dst.Close()

// This will write the PROXY header to the backend server.
_, err = hdr.WriteTo(dst)
if err != nil {
	log.Println("ERROR: write header:", err)
	return
}
Output:

func (HeaderV1) DestAddr

func (h HeaderV1) DestAddr() net.Addr

DestAddr returns the TCP destination address.

func (*HeaderV1) FromConn

func (h *HeaderV1) FromConn(c net.Conn, outgoing bool)

FromConn will populate header data from the given net.Conn.

The RemoteAddr of the Conn will be considered the Source address/port and the LocalAddr of the Conn will be considered the Destination address/port for the purposes of the PROXY header if outgoing is false, if outgoing is true, the inverse is true.

func (HeaderV1) SrcAddr

func (h HeaderV1) SrcAddr() net.Addr

SrcAddr returns the TCP source address.

func (HeaderV1) Version

func (HeaderV1) Version() int

Version always returns 1.

func (HeaderV1) WriteTo

func (h HeaderV1) WriteTo(w io.Writer) (int64, error)

WriteTo will write the V1 header to w. The proto/fam will be set to UNKNOWN if source and dest IPs are of mismatched types, or any port is out of bounds.

type HeaderV2

type HeaderV2 struct {
	Command Cmd
	Src     net.Addr
	Dest    net.Addr
}

HeaderV2 contains information relayed by the PROXY protocol version 2 (binary) header.

Example (Proxy)
l, err := net.Listen("tcp", ":8080")
if err != nil {
	log.Println("ERROR: listen:", err)
	return
}
defer l.Close()

var hdr HeaderV2
c, err := l.Accept()
if err != nil {
	log.Println("ERROR: accept:", err)
	return
}
defer c.Close()

// Populate hdr from the new incomming connection.
hdr.FromConn(c, false)

// Example target
//
// This server will be sent a PROXY header.
dst, err := net.Dial("tcp", "192.168.0.2:12345")
if err != nil {
	log.Println("ERROR: connect:", err)
	return
}
defer dst.Close()

// This will write the PROXY header to the backend server.
_, err = hdr.WriteTo(dst)
if err != nil {
	log.Println("ERROR: write header:", err)
	return
}
Output:

func (HeaderV2) DestAddr

func (h HeaderV2) DestAddr() net.Addr

DestAddr returns the destination address as TCP, UDP, Unix, or nil depending on Protocol and Family.

func (*HeaderV2) FromConn

func (h *HeaderV2) FromConn(c net.Conn, outgoing bool)

FromConn will populate header data from the given net.Conn.

The RemoteAddr of the Conn will be considered the Source address/port and the LocalAddr of the Conn will be considered the Destination address/port for the purposes of the PROXY header if outgoing is false, if outgoing is true, the inverse is true.

func (HeaderV2) SrcAddr

func (h HeaderV2) SrcAddr() net.Addr

SrcAddr returns the source address as TCP, UDP, Unix, or nil depending on Protocol and Family.

func (HeaderV2) Version

func (HeaderV2) Version() int

Version always returns 2.

func (HeaderV2) WriteTo

func (h HeaderV2) WriteTo(w io.Writer) (int64, error)

WriteTo will write the V2 header to w. Command must be CommandProxy to send any address data.

type InvalidHeaderErr

type InvalidHeaderErr struct {
	Read []byte
	// contains filtered or unexported fields
}

InvalidHeaderErr contains the parsing error as well as all data read from the reader.

type Listener

type Listener struct {
	net.Listener
	// contains filtered or unexported fields
}

Listener wraps a net.Listener automatically wrapping new connections with PROXY protocol support.

func NewListener

func NewListener(nl net.Listener, t time.Duration) *Listener

NewListener will wrap nl, automatically handling PROXY headers for all connections. To expect PROXY headers only from certain addresses/subnets, use SetFilter.

By default, all connections must provide a PROXY header within the specified timeout.

Example
nl, err := net.Listen("tcp", ":80")
if err != nil {
	log.Println("ERROR: listen:", err)
	return
}
defer nl.Close()

// Wrap listener with 3 second timeout for PROXY header
l := NewListener(nl, 3*time.Second)

for {
	c, err := l.Accept()
	if err != nil {
		log.Println("ERROR: accept:", err)
		return
	}

	// RemoteAddr will be the source address of the PROXY header
	log.Println("New connection from:", c.RemoteAddr().String())
}
Output:

func (*Listener) Accept

func (l *Listener) Accept() (net.Conn, error)

Accept waits for and returns the next connection to the listener, wrapping it with NewConn if the RemoteAddr matches any registered rules.

func (*Listener) Filter

func (l *Listener) Filter() []Rule

Filter returns the current set of filter rules.

Filter is safe to call from multiple goroutines while the listener is in use.

func (*Listener) SetDefaultTimeout

func (l *Listener) SetDefaultTimeout(t time.Duration)

SetDefaultTimeout sets the default timeout, used when the subnet filter is nil.

SetDefaultTimeout is safe to call from multiple goroutines while the listener is in use.

func (*Listener) SetFilter

func (l *Listener) SetFilter(filter []Rule)

SetFilter allows limiting PROXY header requirements to matching Subnets with an optional timeout. If filter is nil, all connections will be required to provide a PROXY header (the default).

Connections not matching any rule will be returned directly without reading a PROXY header.

Duplicate subnet rules will automatically be removed and the lowest non-zero timeout will be used.

SetFilter is safe to call from multiple goroutines while the listener is in use.

type Rule

type Rule struct {
	// Subnet is used to match incomming IP addresses against this rule.
	Subnet *net.IPNet

	// Timeout indicates the max amount of time to receive the PROXY header before
	// terminating the connection.
	Timeout time.Duration
}

Rule contains configuration for a single subnet.

Directories

Path Synopsis
cmd

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL