Documentation ¶
Index ¶
Examples ¶
Constants ¶
This section is empty.
Variables ¶
var ( // ErrDenied is an error returned by a dial function when the address is // denied by security rules. ErrDenied = errors.New("address not allowed") )
Functions ¶
Types ¶
type DialFunc ¶
DialFunc is a type of function used to establish network connections.
The function matches the signatures of standard functions like net.(*Dialer).DialContext or http.(*Transport).DialContext.
type Resolver ¶
type Resolver interface {
LookupNetIP(ctx context.Context, network, host string) ([]netip.Addr, error)
}
Resolver is an interface used to abstract the name resolver used by security rules to convert logical hostnames to IP addresses.
type Rules ¶
Rules is a set of rules used to determine whether a network address can be accessed.
By default, the rules denies all addresses. Rules can be added to open networks, and further block subsets of the open address space.
func ContextRules ¶
ContextRules returns the network access control rules embedded in ctx.
If the context did not contain any rules, nil is returned.
func (*Rules) AppendTo ¶
AppendTo appends a string representation of the security rules to the given byte slice and returns the resulting slice.
func (*Rules) DialFunc ¶
DialFunc returns a dial function using the given resolver and dialer to establish connections to addresses that are allowed by the security rules.
The resolver is used to convert logical hostnames to IP addresses before applying the security rules.
If the resolver is nil, net.DefaultResolver is used.
If the dialer is nil, a new dialer is created with the default options.
type Transport ¶
type Transport struct { // A function used to create http transports for each network access control // configuration. // // The function must create a new http.Transport instance, and return it. // A panic is triggered if the function returns nil, or if it returns the // same http.Transport more than once. // // The returned http.Transport cannot have DialTLS or DialTLSContext set, // or a panic is triggered. This is due to network access controls having to // be applied before the TLS handshake on the IP addresses resolved from the // hostname in the request, but DialTLS and DialTSLContext need to receive // the hostname to validate the server certificate, which couples the // function to name resolution. // // A simple implementation of this function is to close the default http // transport: // // New: func() *http.Transport { // return http.DefaultTransport.(*http.Transport).Clone() // } // // The function might be invoked concurrently from multiple goroutines. New func() *http.Transport // The resolver used to convert logical hostnames to IP addresses before // checking network access controls. // // If nil, the default resolver is used. Resolver Resolver // Maximum number of idle transports to retain. If the limit is reached, // the least recently used transport is evicted, and CloseIdleConnections // called. // // Default to 256. MaxIdleTransports int // contains filtered or unexported fields }
Transport is a type similar to http.Transport, but which applies rules for network access control embedded in the context of requests it serves.
Requests that don't include network access control rules are always denied.
Requests that are denied fail with the error ErrDenied.
The implementation of this http transport uses http.Transport instances rather than http.RoundTripper. This design decision helps to limit the potential edge cases that may arise if applications are allowed to inject arbitrary http.RoundTripper instances into the transport. Since the purpose of this transport is to apply security controls, we want to optimize for safety, at the expense of composability in this case. Applications that need a more flexible integration can use the Rules type directly, by wrapping the dialers to implement network access controls.
Example ¶
package main import ( "context" "errors" "fmt" "log" "net/http" "net/netip" "github.com/stealthrocket/netjail" ) func main() { // This rule set only allows connecting to a private IPv4 network. ctx := netjail.ContextWithRules(context.Background(), &netjail.Rules{ Allow: []netip.Prefix{ netip.MustParsePrefix("10.0.0.0/8"), }, }, ) client := &http.Client{ Transport: &netjail.Transport{ New: func() *http.Transport { return http.DefaultTransport.(*http.Transport).Clone() }, }, } r, err := http.NewRequestWithContext(ctx, "GET", "http://localhost/", nil) if err != nil { log.Fatal(err) } if r, err := client.Do(r); err != nil { if !errors.Is(err, netjail.ErrDenied) { log.Fatal(err) } else { fmt.Println("Access Denied") } } else { r.Body.Close() fmt.Println("Access Granted") } }
Output: Access Denied
func (*Transport) CloseIdleConnections ¶
func (t *Transport) CloseIdleConnections()