netguard

package
v0.3.0 Latest Latest
Warning

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

Go to latest
Published: Nov 11, 2026 License: AGPL-3.0 Imports: 9 Imported by: 0

Documentation

Overview

Package netguard keeps HTTP requests to addresses chosen by users (webhook URLs, ntfy servers) away from the server's own machine and network. Any member can add a destination, so without it a URL such as http://169.254.169.254/ would let them read cloud credentials through Exhale (server-side request forgery).

The rules: http and https only; loopback, link-local and cloud-metadata addresses are never reachable; private networks only when the owner allows them. The check runs when a connection is opened, on the address actually dialed, so a DNS name that changes its answer or a redirect cannot get around it.

Index

Constants

This section is empty.

Variables

View Source
var ErrBlocked = errors.New("destination not allowed")

ErrBlocked marks a destination refused by the rules (as opposed to one that could not be reached).

Functions

func Cause

func Cause(err error) error

Cause strips the URL from an HTTP client error, leaving what went wrong. Webhook URLs carry secrets and must not reach logs or the outbox.

func Host

func Host(raw string) string

Host returns the host of a URL for logs and errors ("" if it has none).

Types

type Guard

type Guard struct {
	// AllowPrivate reports whether private-network addresses (10/8,
	// 192.168/16, fc00::/7…) may be reached right now. Nil means no.
	AllowPrivate func(ctx context.Context) bool
	// Resolver defaults to net.DefaultResolver.
	Resolver Resolver
	// Dial opens the connection to an address that already passed the
	// rules. It defaults to a net.Dialer; tests replace it.
	Dial func(ctx context.Context, network, addr string) (net.Conn, error)
}

Guard applies the rules. The zero value refuses private networks and uses the system resolver.

func (*Guard) CheckURL

func (g *Guard) CheckURL(ctx context.Context, raw string) (*url.URL, error)

CheckURL validates an address a user typed: a well-formed http or https URL whose host passes the rules today. It returns the parsed URL.

func (*Guard) Client

func (g *Guard) Client(timeout time.Duration) *http.Client

Client returns an HTTP client for user-chosen addresses. It does not follow redirects: the response of the address the user gave is the answer.

func (*Guard) DialContext

func (g *Guard) DialContext(ctx context.Context, network, addr string) (net.Conn, error)

DialContext resolves the host itself, checks every address and connects to the checked address (never back to the name).

func (*Guard) Transport

func (g *Guard) Transport() *http.Transport

Transport returns an HTTP transport whose every connection goes through the guard. It ignores proxy settings: a proxy would connect on our behalf to an address we could not check.

type Kind

type Kind int

Kind says how an address is treated.

const (
	Public Kind = iota
	Private
	Never
)

func Classify

func Classify(a netip.Addr) (Kind, string)

Classify returns how the rules treat an address and, when it is not public, what it is ("a private network", "this machine"…).

type Resolver

type Resolver interface {
	LookupIPAddr(ctx context.Context, host string) ([]net.IPAddr, error)
}

Resolver looks up the addresses of a host name. *net.Resolver implements it; tests inject their own.

Jump to

Keyboard shortcuts

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