proxyd

package module
v0.6.0 Latest Latest
Warning

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

Go to latest
Published: Apr 16, 2026 License: MPL-2.0 Imports: 12 Imported by: 0

README

A pocket-sized proxy orchestration service

You know how annoying it is to rustle with config files, if you ever tried to update multiple proxy configurations at once. Even though some proxy services offer some sort of an administrative API, a lot of the time those are incomplete, undocumented, buggy or all of the above.

I am not claiming that this thing is any better, but making my own thing sounded like a better idea, rather than to spending probably even more time trying to make someone else's crappy code work the way I want.

Another aspect is strictly political. I don't really trust a bunch of commie vibe-coders when it comes to anything remotely related to security. And guess what - proxies are kinda mission critical, unless you use them to browse some adult websites. With the latest tendencies in the world however, I guess even if that's your entire threat model, you'd still want to be sure it ain't tracking your activity and beaming it straight to the party/ofcom/big_brotha/etc.

Feature set

Anyway, as of now I don't got too much stuff going on here. For now it's just the basics.

Proxy protocols
Protocol Status Feature set Auth methods Note
SOCKS 4 ⚠️ Stub - Not supported Is present for compatibility reasons to gracefully reject requests
SOCKS 5 ⚠️ Partial support TCP CONNECT, IPv6 Usename/password BIND not supported; UDP not supported
HTTP ✅ Full support FORWARD, CONNECT (TUNNEL), IPv6 Basic auth Full http/1.1 proxy spec support (allegedly, I didn't even read it thrugh)
Management interfaces
Static config

If you don't feel like enjoying dynamic user configuration, you could specify everything in a config file. This would defeat the purpose of this project entirely but hey, you have the option to do that anyway.

A sample config would look something like this:

manager:
  type: static
  services:
    - bind_addr: 172.217.19.174:1080
      type: socks
      users:
        - username: maddsua
          password: mysupersecretpass
          max_conn: 256
          bandwidth_kbit: 100
          dns: 1.1.1.1
          outbound_addr: 172.217.19.174
RADIUS

RADIUS is used to authenticate connecting users and manage their sessions. You'd have to define the list of running proxy services in advance.

Example config:

manager:
  type: radius
  radius_auth_addr: 127.0.0.1:1812 # primary radius auth server addr
  radius_acct_addr: 127.0.0.1:1813 # optional accounting address. if left empty, the primary auth addr will be used for accounting as well
  dac_listen_addr: 127.0.0.1:3799 # this instance's DAC listen address
  radius_secret: testsecret # shared radius secret
  services: # list of services to spin-up
    - bind_addr: 127.0.0.1:1080
      type: socks
    - bind_addr: 127.0.0.1:8080
      type: http
      http_forward_enabled: true

Refer to the RADIUS section to learn more about autorizing users and the attributes used.

proxytables

proxytables is a REST-based API that allows to configure literally everything here without relying on third-party tools or protocols.

It is described here

Configuration

Default config location: /etc/proxyd/proxyd.yml.

Refer to the full configuration example for more.

Deployment target

It's best to deploy proxyd directly onto a VPS as it needs to see the original IP addresses of incoming connections.

It is not impossible to make it work with docker, but I didn't bother and so shouldn't you.

Documentation

Index

Constants

View Source
const BandwidthLimitMax = 1_250_000_000

Sets a maximal throttlable bandwidth limit at around 10 GBit/s; Values over this limit should be treated as no limit at all

View Source
const DefaultConnectionLimit = math.MaxUint8
View Source
const DefaultDnsTestResultTTL = time.Minute
View Source
const DefaultDnsTestTimeout = 5 * time.Second
View Source
const DefaultDnsTestWarnTimeout = 2 * time.Second
View Source
const DefaultDnsTimeout = 15 * time.Second
View Source
const MaxConnectionLimit = math.MaxUint16

Variables

View Source
var DefaultDnsProbeNames = []string{
	"one.one.one.one",
	"google.com",
	"ripe.net",
	"icann.org",
}
View Source
var ErrConnectionCtlClosed = errors.New("conn ctl closed")

Functions

func DestinationIPAllowed

func DestinationIPAllowed(ip net.IP) error

func NewAccountReader

func NewAccountReader(reader io.Reader, acc *atomic.Int64) io.Reader

func NewAccountWriter

func NewAccountWriter(writer io.Writer, acc *atomic.Int64) io.Writer

func NewBandwidthLimitReader

func NewBandwidthLimitReader(reader io.Reader, limiter *atomic.Int64) io.Reader

func NewBandwidthLimitWriter

func NewBandwidthLimitWriter(writer io.Writer, limiter *atomic.Int64) io.Writer

Types

type AccountReader

type AccountReader struct {
	Reader io.Reader
	Acc    *atomic.Int64
}

AccountReader is a wrapper on top of a normal reader that counts total data volume in realtime using an accumulator (atomic int)

func (*AccountReader) Read

func (reader *AccountReader) Read(buff []byte) (int, error)

type AccountWriter

type AccountWriter struct {
	Writer io.Writer
	Acc    *atomic.Int64
}

AccountWriter is a wrapper on top of a normal writer that counts total data volume in realtime using an accumulator (atomic int)

func (*AccountWriter) Write

func (wrt *AccountWriter) Write(data []byte) (int, error)

type BandwidthLimitReader

type BandwidthLimitReader struct {
	Reader  io.Reader
	Limiter *atomic.Int64
}

BandwidthLimitReader implements a simple reader wrapper that allows for the bandwidth to be externally controlled It is quite a lot more quirky when it comes to precision than the writer, therefore the latter should be preferred when possible

func (*BandwidthLimitReader) Read

func (reader *BandwidthLimitReader) Read(buff []byte) (int, error)

type BandwidthLimitWriter

type BandwidthLimitWriter struct {
	Writer  io.Writer
	Limiter *atomic.Int64
}

BandwidthLimitWriter implements a simple writer wrapper that allows for the bandwidth to be externally controlled

func (*BandwidthLimitWriter) Write

func (wrt *BandwidthLimitWriter) Write(data []byte) (int, error)

type ConnectionLimitError

type ConnectionLimitError struct {
	Message string
	Limit   int
}

func (*ConnectionLimitError) Error

func (err *ConnectionLimitError) Error() string

type DNSLookupError

type DNSLookupError struct {
	Query string
}

func (*DNSLookupError) Error

func (err *DNSLookupError) Error() string

type DNSTester

type DNSTester struct {
	ResultTTL time.Duration
	Dialer    net.Dialer
	Control   func(server string) error
	// contains filtered or unexported fields
}

func (*DNSTester) LookupTestRecords

func (state *DNSTester) LookupTestRecords(ctx context.Context, serverAddr string, names []string) error

func (*DNSTester) Test

func (dt *DNSTester) Test(ctx context.Context, addr string) error

type IpVersionError

type IpVersionError struct {
	RemoteNet, LocalNet string
}

func (*IpVersionError) Error

func (err *IpVersionError) Error() string

type NetworkPolicyError

type NetworkPolicyError struct {
	Message string
}

func (*NetworkPolicyError) Error

func (err *NetworkPolicyError) Error() string

type PeerAddr

type PeerAddr struct {
	IP net.IP
}

func (*PeerAddr) Network

func (addr *PeerAddr) Network() string

func (*PeerAddr) PublicIP

func (addr *PeerAddr) PublicIP() net.IP

func (*PeerAddr) String

func (addr *PeerAddr) String() string

func (*PeerAddr) TCPDialAddr

func (addr *PeerAddr) TCPDialAddr() net.Addr

func (*PeerAddr) UDPDialAddr

func (addr *PeerAddr) UDPDialAddr() net.Addr

type ProxyAttribute

type ProxyAttribute interface {
	EqualAttribute(attr ProxyAttribute) bool
	Destroy()
}

type ProxyAuthenticator

type ProxyAuthenticator interface {
	// Tries to authorize a user using their name and password.
	// MUST always return either a non-nil session or an error.
	// Use CredentialsError to indicate non-logic errors
	AuthenticateWithPassword(ctx context.Context, proxyHost net.Addr, clientIP net.IP, username, password string) (*ProxySession, error)
}

type ProxyConnCtl

type ProxyConnCtl struct {
	TrafficRx atomic.Int64
	TrafficTx atomic.Int64

	BandwidthRx atomic.Int64
	BandwidthTx atomic.Int64
	// contains filtered or unexported fields
}

func (*ProxyConnCtl) Close

func (ctl *ProxyConnCtl) Close() (err error)

func (*ProxyConnCtl) SetBandwidth

func (pool *ProxyConnCtl) SetBandwidth(rxBytes, txBytes int)

func (*ProxyConnCtl) WithConnection

func (ctl *ProxyConnCtl) WithConnection(conn net.Conn) (net.Conn, error)

type ProxyConnectionPool

type ProxyConnectionPool struct {
	TrafficRx atomic.Int64
	TrafficTx atomic.Int64
	// contains filtered or unexported fields
}

func (*ProxyConnectionPool) Add

func (pool *ProxyConnectionPool) Add() (*ProxyConnCtl, error)

func (*ProxyConnectionPool) Bandwidth

func (pool *ProxyConnectionPool) Bandwidth() (rxBytes, txBytes int)

func (*ProxyConnectionPool) CloseConnections

func (pool *ProxyConnectionPool) CloseConnections()

func (*ProxyConnectionPool) ConnectionLimit

func (pool *ProxyConnectionPool) ConnectionLimit() int

func (*ProxyConnectionPool) Rebalance

func (pool *ProxyConnectionPool) Rebalance()

func (*ProxyConnectionPool) SetBandwidth

func (pool *ProxyConnectionPool) SetBandwidth(rxBytes, txBytes int)

func (*ProxyConnectionPool) SetConnectionLimit

func (pool *ProxyConnectionPool) SetConnectionLimit(limit int) error

func (*ProxyConnectionPool) WithConnection

func (pool *ProxyConnectionPool) WithConnection(conn net.Conn) (net.Conn, error)

type ProxyCredentialsError

type ProxyCredentialsError struct {
	Username   string
	RetryAfter time.Time
}

func (*ProxyCredentialsError) Error

func (err *ProxyCredentialsError) Error() string

type ProxyDNSResolver

type ProxyDNSResolver struct {
	ServerAddr string
	Dialer     net.Dialer
}

func (*ProxyDNSResolver) LookupIpNetwork

func (dns *ProxyDNSResolver) LookupIpNetwork(ctx context.Context, ipnetwork, host string) (hostIP net.IP, err error)

func (*ProxyDNSResolver) ResolveDestination

func (dns *ProxyDNSResolver) ResolveDestination(ctx context.Context, ipnetwork, addr string) (string, error)

func (*ProxyDNSResolver) Resolver

func (dns *ProxyDNSResolver) Resolver() *net.Resolver

func (*ProxyDNSResolver) ServerName

func (dns *ProxyDNSResolver) ServerName() string

type ProxyDialer

type ProxyDialer struct {
	OutboundAddr *PeerAddr
}

ProxyDialer simplifies dialing proxy destinations

func (*ProxyDialer) DialContext

func (pd *ProxyDialer) DialContext(ctx context.Context, network, address string) (net.Conn, error)

type ProxyService

type ProxyService interface {
	ProxyService() string
	BindAddr() net.Addr
	Shutdown(ctx context.Context) error
}

type ProxySession

type ProxySession struct {
	PeerID      string
	PeerEnabled bool

	Dialer ProxyDialer
	DNS    ProxyDNSResolver

	Attributes ProxySessionAttributes
	Pool       ProxyConnectionPool
}

func (*ProxySession) DialDestinationContext

func (sess *ProxySession) DialDestinationContext(ctx context.Context, network, address string) (net.Conn, error)

Dials an address while checking that a peer is allowed to access the remote and wrapping resulting connection in a (proxyConnection)

func (*ProxySession) Reset

func (sess *ProxySession) Reset()

type ProxySessionAttributes

type ProxySessionAttributes struct {
	// contains filtered or unexported fields
}

Wraps the underlying sync map to prevent it from getting cleared without being properly closed

func (*ProxySessionAttributes) Reset

func (attrs *ProxySessionAttributes) Reset()

func (*ProxySessionAttributes) WithValue

func (attrs *ProxySessionAttributes) WithValue(key any, newAttr ProxyAttribute) (attr ProxyAttribute, replaced bool)

type ServiceManager

type ServiceManager interface {
	Exec() error
	Shutdown(ctx context.Context) error
}

Directories

Path Synopsis
rpc

Jump to

Keyboard shortcuts

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