netguard

package
v0.3.0 Latest Latest
Warning

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

Go to latest
Published: Oct 17, 2026 License: Apache-2.0 Imports: 12 Imported by: 0

Documentation

Overview

Package netguard builds HTTP clients and validates URLs for user-configured outbound requests such as webhooks, refusing loopback, private, link-local, and other internal addresses to prevent server-side request forgery. The check runs at dial time, so redirects and DNS rebinding are covered.

Index

Examples

Constants

View Source
const AllowPrivateEnv = "APP_NOTIFY_ALLOW_PRIVATE_NETWORKS"

AllowPrivateEnv names the env var that, when true, lets outbound notification requests reach internal addresses (for example a self-hosted chat server on a private IP).

Variables

View Source
var ErrBlockedAddress = errors.New("netguard: destination address is internal and not allowed")

ErrBlockedAddress is returned when a dial targets an internal address while AllowPrivateEnv is not enabled.

View Source
var ErrInvalidURL = errors.New("netguard: not an absolute http or https URL")

ErrInvalidURL is returned by ValidateURL for a URL that is not an absolute http(s) URL with a host.

Functions

func AllowPrivate

func AllowPrivate() bool

AllowPrivate reports whether AllowPrivateEnv is set to a true value.

func IsBlocked

func IsBlocked(addr netip.Addr) bool

IsBlocked reports whether addr is an address an outbound notification must not reach unless AllowPrivateEnv is enabled.

Example
package main

import (
	"fmt"
	"net/netip"

	"github.com/GLINCKER/levelrail/kit/netguard"
)

func main() {
	for _, s := range []string{"127.0.0.1", "10.0.0.5", "169.254.169.254", "93.184.216.34"} {
		fmt.Println(s, netguard.IsBlocked(netip.MustParseAddr(s)))
	}
}
Output:
127.0.0.1 true
10.0.0.5 true
169.254.169.254 true
93.184.216.34 false

func NewClient

func NewClient() *http.Client

NewClient returns an HTTP client whose every connection, including redirects, is refused when it targets an internal address. It ignores HTTP(S)_PROXY, since a proxy would dial the destination on our behalf and bypass the check.

func NewClientAllowing

func NewClientAllowing(allowEnvs ...string) *http.Client

NewClientAllowing is NewClient with its own opt-in env vars, so one feature can allow private addresses without relaxing the others. The first name is the one shown in the refusal message.

func ValidateURL

func ValidateURL(ctx context.Context, raw string) error

ValidateURL rejects, at configuration time, a URL every later send would refuse: a non-http(s) URL, a loopback or private IP literal, localhost, or a hostname whose every resolved address is internal. A hostname that does not resolve here is accepted, since resolution can differ at send time.

Example
package main

import (
	"context"
	"errors"
	"fmt"

	"github.com/GLINCKER/levelrail/kit/netguard"
)

func main() {
	err := netguard.ValidateURL(context.Background(), "http://127.0.0.1:8080/hook")
	fmt.Println(errors.Is(err, netguard.ErrBlockedAddress))

	err = netguard.ValidateURL(context.Background(), "ftp://example.com/hook")
	fmt.Println(errors.Is(err, netguard.ErrInvalidURL))
}
Output:
true
true

Types

This section is empty.

Jump to

Keyboard shortcuts

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