pan

package
v0.5.0 Latest Latest
Warning

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

Go to latest
Published: Jan 5, 2022 License: Apache-2.0 Imports: 35 Imported by: 15

Documentation

Overview

Package pan provides a policy-based, path aware network library for building applications supporting SCION natively.

The main entry points for applications are:

  • DialUDP / ListenUDP
  • DialQUIC / ListenQUIC

Both forms of the Dial call allow to specify a Policy and a Selector.

Policy

A path policy defines the allowed paths and/or a preference order of the paths. Policies are generally stateless and, in particular, they don't look for any short term information like measured latency or path "liveness". Connections allow to change the path policy at any time.

Selector

A path selector is a stateful controller associated with a connection/socket. It receives the paths filtered by the Policy as an input. For each packet sent, the selector chooses the path. The default selector keeps using the first chosen path unless SCMP path down notifications are encountered, in which case it will always switch to the next alive path. Custom selectors implement e.g. active path probing, coupling of multiple connections to either use the same path or to use maximally disjoint paths, direct performance feedback from the application, etc.

Dialed vs Listening

pan differentiates between dialed and listening sockets. Dialed sockets (for "clients") define the path policy and a selector. The client side of a connection is in control of the path used. The listening side (for "servers") only replies on the paths last used by each client, by means of a customizable reply path selector. The listening side does not implement any policy, nor does it do anything to keep the paths fresh. The default reply path selector records a fixed number of paths used by a client. It normally uses the path last used by the client for replies, but does use other recorded paths to try routing around temporarily broken paths.

Dispatcher and SCION daemon connections

During the hidden initialisation of this package, the dispatcher and sciond connections are opened. The sciond connection determines the local IA. The dispatcher and sciond sockets are assumed to be at default locations, but this can be overridden using environment variables:

SCION_DISPATCHER_SOCKET: /run/shm/dispatcher/default.sock
SCION_DAEMON_ADDRESS: 127.0.0.1:30255

This is convenient for the normal use case of running the endhost stack for a single SCION AS. When running multiple local ASes, e.g. during development, the address of the sciond corresponding to the desired AS needs to be specified in the SCION_DAEMON_ADDRESS environment variable.

Wildcard IP Addresses

The SCION end host stack does not currently support binding to wildcard addresses. This will hopefully be added eventually, but in the meantime this package resolves wildcard addresses to a default local IP address when creating a socket. Binding to one specific local IP address, means that the application will not be reachable at any of the other IP addresses of the host. Traffic sent will always appear to originate from this specific IP address, even if that's not the correct route to a destination in the local AS.

Notes

  • pan only performs path lookups for destinations requested by the application. Path lookup for an unverified peer could easily be abused for various attacks.
  • Recording the reply path for each peer can be vulnerable to source address spoofing. This can potentially be abused to hijack connections. The plan is to require source authentication.
  • In order to allow more explicit control over paths for the listening side, plan is to add an explicit "Dial" function to the ListenerConn. There are a few different options for this, and none is particularly great (either awkward API or performance overhead), so deferred until requirements become clearer.
  • To allow isolation of different application "contexts" that need to avoid leaking path usage information, the plan is to encapsulating the global state of this package in a single object that can be overridden in the context.Context passed to Dial/Listen.

Index

Constants

This section is empty.

Variables

View Source
var (
	AvailablePreferencePolicies = []string{"latency", "bandwidth", "hops", "mtu"}
)
View Source
var ErrNoPath = errors.New("no path")

Functions

func ListenQUIC

func ListenQUIC(ctx context.Context, local netaddr.IPPort, selector ReplySelector,
	tlsConf *tls.Config, quicConfig *quic.Config) (quic.Listener, error)

ListenQUIC listens for QUIC connections on a SCION/UDP port.

See note on wildcard addresses in the package documentation.

func MangleSCIONAddr

func MangleSCIONAddr(address string) string

MangleSCIONAddr mangles a SCION address string (if it is one) so it can be safely used in the host part of a URL.

func ParseOptionalIPPort

func ParseOptionalIPPort(s string) (netaddr.IPPort, error)

ParseOptionalIPPort parses a string to netaddr.IPPort This accepts either of the following formats

  • <ip>:<port>
  • :<port>
  • (empty)

in contrast to netaddr.ParseOptionalIPPort which disallows omitting the IP.

This is provided by this package as typical usage of the Dial/Listen will allow to provide the local address as a string, where the omitting the IP is a convenient shortcut, valid for both IPv4 and IPv6.

func SplitHostPort

func SplitHostPort(hostport string) (host, port string, err error)

SplitHostPort splits a host:port string into host and port variables. This is analogous to net.SplitHostPort, which however refuses to handle SCION addresses. The address can be of the form of a SCION address (i.e. of the form "ISD-AS,[IP]:port") or in the form of "hostname:port".

func UnmangleSCIONAddr

func UnmangleSCIONAddr(address string) string

UnmangleSCIONAddr returns a SCION address that can be parsed with with snet.ParseUDPAddr. If the input is not a SCION address (e.g. a hostname), the address is returned unchanged. This parses the address, so that it can safely join host and port, with the brackets in the right place. Yes, this means this will be parsed twice.

Assumes that address always has a port (this is enforced by the http3 roundtripper code)

Types

type ACL

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

ACL is a policy filtering paths matching an ACL pattern. The ACL pattern is an ordered list of allow/deny actions over hop predicates. See https://scion.docs.anapaya.net/en/latest/PathPolicy.html#acl.

func NewACL

func NewACL(list []string) (ACL, error)

NewACL creates a new ACL from a string list

func (ACL) Filter

func (l ACL) Filter(paths []*Path) []*Path

Filter evaluates the interface ACL and returns the set of paths that match the list

type CommandlinePrompter

type CommandlinePrompter struct{}

CommandlinePrompter is a Prompter for InteractiveSelection, prompting the user for textual path selection input on stdin/out.

func (CommandlinePrompter) Prompt

func (p CommandlinePrompter) Prompt(paths []*Path, remote IA) []*Path

type Conn

type Conn interface {
	net.Conn
	// SetPolicy allows to set the path policy for paths used by Write, at any
	// time.
	SetPolicy(policy Policy)
	// WriteVia writes a message to the remote address via the given path.
	// This bypasses the path policy and selector used for Write.
	WriteVia(path *Path, b []byte) (int, error)
	// ReadVia reads a message and returns the (return-)path via which the
	// message was received.
	ReadVia(b []byte) (int, *Path, error)
}

Conn represents a _dialed_ connection.

func DialUDP

func DialUDP(ctx context.Context, local netaddr.IPPort, remote UDPAddr,
	policy Policy, selector Selector) (Conn, error)

DialUDP opens a SCION/UDP socket, connected to the remote address. If the local address, or either its IP or port, are left unspecified, they will be automatically chosen.

DialUDP looks up SCION paths to the destination AS. The policy defines the allowed paths and their preference order. The selector dynamically selects a path among this set for each Write operation. If the policy is nil, all paths are allowed. If the selector is nil, a DefaultSelector is used.

type DefaultReplySelector

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

func NewDefaultReplySelector

func NewDefaultReplySelector() *DefaultReplySelector

func (*DefaultReplySelector) Close

func (s *DefaultReplySelector) Close() error

func (*DefaultReplySelector) Initialize

func (s *DefaultReplySelector) Initialize(local UDPAddr)

func (*DefaultReplySelector) Path

func (s *DefaultReplySelector) Path(remote UDPAddr) *Path

func (*DefaultReplySelector) PathDown

func (*DefaultReplySelector) Record

func (s *DefaultReplySelector) Record(remote UDPAddr, path *Path)

type DefaultSelector

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

DefaultSelector is a Selector for a single dialed socket. This will keep using the current path, starting with the first path chosen by the policy, as long possible. Faults are detected passively via SCMP down notifications; whenever such a down notification affects the current path, the DefaultSelector will switch to the first path (in the order defined by the policy) that is not affected by down notifications.

func NewDefaultSelector

func NewDefaultSelector() *DefaultSelector

func (*DefaultSelector) Close

func (s *DefaultSelector) Close() error

func (*DefaultSelector) Initialize

func (s *DefaultSelector) Initialize(local, remote UDPAddr, paths []*Path)

func (*DefaultSelector) Path

func (s *DefaultSelector) Path() *Path

func (*DefaultSelector) PathDown

func (s *DefaultSelector) PathDown(pf PathFingerprint, pi PathInterface)

func (*DefaultSelector) Refresh

func (s *DefaultSelector) Refresh(paths []*Path)

type DestinationStats

type DestinationStats struct {
	Latency map[PathFingerprint]StatsLatencySamples
}

type ForwardingPath

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

ForwardingPath represents a data plane forwarding path.

func (ForwardingPath) Copy

func (p ForwardingPath) Copy() ForwardingPath

func (ForwardingPath) IsEmpty

func (p ForwardingPath) IsEmpty() bool

func (ForwardingPath) Reversed

func (p ForwardingPath) Reversed() (ForwardingPath, error)

func (ForwardingPath) String

func (p ForwardingPath) String() string

type GeoCoordinates

type GeoCoordinates = snet.GeoCoordinates

type HighestBandwidth

type HighestBandwidth struct{}

func (HighestBandwidth) Filter

func (p HighestBandwidth) Filter(paths []*Path) []*Path

type HighestMTU

type HighestMTU struct{}

func (HighestMTU) Filter

func (p HighestMTU) Filter(paths []*Path) []*Path

type HostNotFoundError

type HostNotFoundError struct {
	Host string
}

HostNotFoundError is returned by ResolveUDPAddr when the name was not found, but otherwise no error occurred.

func (HostNotFoundError) Error

func (e HostNotFoundError) Error() string

type IA

type IA addr.IA

FIXME: leaking addr.I, addr.A

func MustParseIA

func MustParseIA(s string) IA

MustParseIA calls ParseIA and panics on error. This is intended for testing.

func ParseIA

func ParseIA(s string) (IA, error)

ParseIA parses an IA from a string of the format 'ia-as'.

func (IA) IsWildcard

func (ia IA) IsWildcard() bool

IsWildcard reports whether ia has a wildcard part (isd or as, or both).

func (IA) IsZero

func (ia IA) IsZero() bool

IsZero reports whether ia is the zero value of the IA type.

func (IA) String

func (ia IA) String() string

type IPPortValue

type IPPortValue netaddr.IPPort

IPPortValue implements the flag.Value for a inet.af/netaddr.IPPort, using the ParseIPPort function. NOTE: once go-1.18 becomes available, we'll switch this package over to net/netip.

func (*IPPortValue) Get

func (v *IPPortValue) Get() netaddr.IPPort

func (*IPPortValue) Set

func (v *IPPortValue) Set(s string) error

func (*IPPortValue) String

func (v *IPPortValue) String() string

type IfID

type IfID uint64

type InteractiveSelection

type InteractiveSelection struct {
	Prompter Prompter
	// contains filtered or unexported fields
}

InteractiveSelection is a path policy that prompts for paths once per destination IA

func (*InteractiveSelection) Filter

func (p *InteractiveSelection) Filter(paths []*Path) []*Path

type InteractiveSelectionType

type InteractiveSelectionType int

type LeastHops

type LeastHops struct{}

func (LeastHops) Filter

func (p LeastHops) Filter(paths []*Path) []*Path

type LinkType

type LinkType = snet.LinkType

type ListenConn

type ListenConn interface {
	net.PacketConn
	// ReadFromVia reads a message and returns the (return-)path via which the
	// message was received.
	ReadFromVia(b []byte) (int, UDPAddr, *Path, error)
	// WriteToVia writes a message to the remote address via the given path.
	// This bypasses selector used for WriteTo.
	WriteToVia(b []byte, dst UDPAddr, path *Path) (int, error)
}

func ListenUDP

func ListenUDP(ctx context.Context, local netaddr.IPPort,
	selector ReplySelector) (ListenConn, error)

type LowestLatency

type LowestLatency struct{}

TODO: (optionally) fill missing latency info with geo coordinates

func (LowestLatency) Filter

func (p LowestLatency) Filter(paths []*Path) []*Path

type Path

type Path struct {
	Source         IA
	Destination    IA
	ForwardingPath ForwardingPath
	Metadata       *PathMetadata // optional
	Fingerprint    PathFingerprint
	Expiry         time.Time
}

TODO: revisit: pointer or value type? what goes where? should ForwardingPath be exported?

func (*Path) Copy

func (p *Path) Copy() *Path

func (*Path) String

func (p *Path) String() string

type PathFingerprint

type PathFingerprint string

PathFingerprint is an opaque identifier for a path. It identifies a path by the sequence of interface identifiers along the path.

type PathInterface

type PathInterface struct {
	IA   IA
	IfID IfID
}

type PathInterfaceStats

type PathInterfaceStats struct {
	// Was notified down at the recorded time (0 for never notified down)
	IsNotifiedDown time.Time
}

type PathMetadata

type PathMetadata struct {
	// Interfaces is a list of interfaces on the path.
	Interfaces []PathInterface

	// MTU is the maximum transmission unit for the path, in bytes.
	MTU uint16

	// Latency lists the latencies between any two consecutive interfaces.
	// Entry i describes the latency between interface i and i+1.
	// Consequently, there are N-1 entries for N interfaces.
	// A 0-value indicates that the AS did not announce a latency for this hop.
	Latency []time.Duration

	// Bandwidth lists the bandwidth between any two consecutive interfaces, in Kbit/s.
	// Entry i describes the bandwidth between interfaces i and i+1.
	// A 0-value indicates that the AS did not announce a bandwidth for this hop.
	Bandwidth []uint64

	// Geo lists the geographical position of the border routers along the path.
	// Entry i describes the position of the router for interface i.
	// A 0-value indicates that the AS did not announce a position for this router.
	Geo []GeoCoordinates

	// LinkType contains the announced link type of inter-domain links.
	// Entry i describes the link between interfaces 2*i and 2*i+1.
	LinkType []LinkType

	// InternalHops lists the number of AS internal hops for the ASes on path.
	// Entry i describes the hop between interfaces 2*i+1 and 2*i+2 in the same AS.
	// Consequently, there are no entries for the first and last ASes, as these
	// are not traversed completely by the path.
	InternalHops []uint32

	// Notes contains the notes added by ASes on the path, in the order of occurrence.
	// Entry i is the note of AS i on the path.
	Notes []string
}

PathMetadata contains supplementary information about a path.

The information about MTU, Latency, Bandwidth etc. are based solely on data contained in the AS entries in the path construction beacons. These entries are signed/verified based on the control plane PKI. However, the *correctness* of this meta data has *not* been checked.

NOTE: copied from snet.PathMetadata: does not contain Expiry and uses the local types (pan.PathInterface instead of snet.PathInterface, ...)

func (*PathMetadata) Copy

func (pm *PathMetadata) Copy() *PathMetadata

func (*PathMetadata) HigherBandwidth

func (pm *PathMetadata) HigherBandwidth(b *PathMetadata) (bool, bool)

HigherBandwidth compares the bandwidth of two paths. Returns

  • true, true if a has strictly higher bandwidth than b
  • false, true if a has equal or lower bandwidth than b
  • _, false if not enough information is available to compare a and b

func (*PathMetadata) LowerLatency

func (pm *PathMetadata) LowerLatency(b *PathMetadata) (bool, bool)

LowerLatency compares the latency of two paths. Returns

  • true, true if a has strictly lower latency than b
  • false, true if a has equal or higher latency than b
  • _, false if not enough information is available to compare a and b

type PathStats

type PathStats struct {
	// Was notified down at the recorded time (0 for never notified down)
	IsNotifiedDown time.Time
}

type PingingSelector

type PingingSelector struct {
	// Interval for pinging. Must be positive.
	Interval time.Duration
	// Timeout for the individual pings. Must be positive and less than Interval.
	Timeout time.Duration
	// contains filtered or unexported fields
}

func (*PingingSelector) Close

func (s *PingingSelector) Close() error

func (*PingingSelector) Initialize

func (s *PingingSelector) Initialize(local, remote UDPAddr, paths []*Path)

func (*PingingSelector) Path

func (s *PingingSelector) Path() *Path

func (*PingingSelector) PathDown

func (s *PingingSelector) PathDown(pf PathFingerprint, pi PathInterface)

func (*PingingSelector) Refresh

func (s *PingingSelector) Refresh(paths []*Path)

func (*PingingSelector) SetActive

func (s *PingingSelector) SetActive(numActive int)

SetActive enables active pinging on at most numActive paths.

type Pinned

type Pinned []PathFingerprint

Pinned is a policy that keeps only a preselected set of paths. This can be used to implement interactive hard path selection.

func (Pinned) Filter

func (p Pinned) Filter(paths []*Path) []*Path

type Policy

type Policy interface {
	// Filter and prioritize paths
	Filter(paths []*Path) []*Path
}

Policy is a stateless filter / sorter for paths.

func PolicyFromCommandline

func PolicyFromCommandline(sequence string, preference string, interactive bool) (Policy, error)

PolicyFromCommandline is a utilty function to create a path policy from command line options.

The intent of this function is to help providing a somewhat consistent CLI interface for applications using this library, without enforcing the use of a specific command line flag library.

The options should be presented to the user as:

  • a flag --interactive
  • an option --preference <preference>, sorting order for paths. Comma-separated list of available sorting options.
  • an option --sequence <sequence>, describing a hop-predicate sequence filter

type PolicyChain

type PolicyChain []Policy

PolicyChain applies multiple policies in order.

func (PolicyChain) Filter

func (p PolicyChain) Filter(paths []*Path) []*Path

type PolicyFunc

type PolicyFunc func(paths []*Path) []*Path

func (PolicyFunc) Filter

func (f PolicyFunc) Filter(paths []*Path) []*Path

type Preferred

type Preferred struct {
	Preferred Policy
}

Preferred is a policy adapter that keeps all paths but moves the paths selected by the child policy to the top. This can be used, for example, to implement interactive path preference with failover to other paths.

func (Preferred) Filter

func (p Preferred) Filter(paths []*Path) []*Path

type Prompter

type Prompter interface {
	Prompt(paths []*Path, remote IA) []*Path
}

Prompter is used by InteractiveSelection to prompt a user for path

type QUICEarlySession

type QUICEarlySession struct {
	quic.EarlySession
	Conn Conn
}

QUICEarlySession is a wrapper around quic.EarlySession, analogous to closerSession

func DialQUICEarly

func DialQUICEarly(ctx context.Context,
	local netaddr.IPPort, remote UDPAddr, policy Policy, selector Selector,
	host string, tlsConf *tls.Config, quicConf *quic.Config) (*QUICEarlySession, error)

DialQUICEarly establishes a new 0-RTT QUIC connection to a server. Analogous to DialQUIC.

func (*QUICEarlySession) CloseWithError

func (s *QUICEarlySession) CloseWithError(code quic.ApplicationErrorCode, desc string) error

type QUICSession

type QUICSession struct {
	quic.Session
	Conn Conn
}

QUICSession is a wrapper around quic.Session that always closes the underlying conn when closing the session.

func DialQUIC

func DialQUIC(ctx context.Context,
	local netaddr.IPPort, remote UDPAddr, policy Policy, selector Selector,
	host string, tlsConf *tls.Config, quicConf *quic.Config) (*QUICSession, error)

DialQUIC establishes a new QUIC connection to a server at the remote address.

The host parameter is used for SNI. The tls.Config must define an application protocol (using NextProtos).

func (*QUICSession) CloseWithError

func (s *QUICSession) CloseWithError(code quic.ApplicationErrorCode, desc string) error

type ReplySelector

type ReplySelector interface {
	// Path selects the path for the next packet to remote.
	// Invoked for each packet sent with WriteTo.
	Path(remote UDPAddr) *Path
	// Initialize the selector.
	// Invoked once during the creation of a ListenConn.
	Initialize(local UDPAddr)
	// Record a path used by the remote for a packet received.
	// Invoked whenever a packet is received.
	// The path is reversed, i.e. it's the path from here to remote.
	Record(remote UDPAddr, path *Path)
	// PathDown is called whenever an SCMP down notification is received on any
	// connection so that the selector can adapt its path choice. The down
	// notification may be for unrelated paths not used by this selector.
	PathDown(PathFingerprint, PathInterface)
	Close() error
}

ReplySelector controls the reply path in a **listening** socket. Stateful.

type SCMPError

type SCMPError struct {

	// ErrorIA is the source IA of the SCMP error message
	ErrorIA IA
	// ErrorIP is the source IP of the SCMP error message
	ErrorIP netaddr.IP
	// contains filtered or unexported fields
}

func (SCMPError) Error

func (e SCMPError) Error() string

func (SCMPError) Temporary

func (e SCMPError) Temporary() bool

type Selector

type Selector interface {
	// Path selects the path for the next packet.
	// Invoked for each packet sent with Write.
	Path() *Path
	// Initialize the selector for a connection with the initial list of paths,
	// filtered/ordered by the Policy.
	// Invoked once during the creation of a Conn.
	Initialize(local, remote UDPAddr, paths []*Path)
	// Refresh updates the paths. This is called whenever the Policy is changed or
	// when paths were about to expire and are refreshed from the SCION daemon.
	// The set and order of paths may differ from previous invocations.
	Refresh([]*Path)
	// PathDown is called whenever an SCMP down notification is received on any
	// connection so that the selector can adapt its path choice. The down
	// notification may be for unrelated paths not used by this selector.
	PathDown(PathFingerprint, PathInterface)
	Close() error
}

Selector controls the path used by a single **dialed** socket. Stateful.

type Sequence

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

Sequence is a policy filtering paths matching a textual pattern. The sequence pattern is space separated sequence of hop predicates. See https://scion.docs.anapaya.net/en/latest/PathPolicy.html#sequence.

func NewSequence

func NewSequence(s string) (Sequence, error)

NewSequence creates a new sequence from a string

func (Sequence) Filter

func (s Sequence) Filter(paths []*Path) []*Path

Filter evaluates the interface sequence list and returns the set of paths that match the list

type StatsLatencySample

type StatsLatencySample struct {
	Time  time.Time
	Value time.Duration
}

type StatsLatencySamples

type StatsLatencySamples []StatsLatencySample

type UDPAddr

type UDPAddr struct {
	IA   IA
	IP   netaddr.IP
	Port uint16
}

UDPAddr is an address for a SCION/UDP end point.

func MustParseUDPAddr

func MustParseUDPAddr(s string) UDPAddr

MustParseUDPAddr calls ParseUDPAddr and panics on error. This is intended for testing.

func ParseUDPAddr

func ParseUDPAddr(s string) (UDPAddr, error)

ParseUDPAddr converts an address string to a SCION address.

func ResolveUDPAddr

func ResolveUDPAddr(address string) (UDPAddr, error)

ResolveUDPAddr parses the address and resolves the hostname. The address can be of the form of a SCION address (i.e. of the form "ISD-AS,[IP]:port") or in the form of "hostname:port". If the address is in the form of a hostname, the the following sources will be used to resolve a name, in the given order of precedence.

  • /etc/hosts
  • /etc/scion/hosts
  • RAINS, if a server is configured in /etc/scion/rains.cfg. Disabled if built with !norains.

Returns HostNotFoundError if none of the sources did resolve the hostname.

func (UDPAddr) IsValid

func (a UDPAddr) IsValid() bool

IsValue reports whether a is a valid address; IA is not a wildcard (and thus not zero) and IP is initialized (may be "0.0.0.0" or "::"). All ports are valid, including zero.

func (UDPAddr) IsZero

func (a UDPAddr) IsZero() bool

IsZero reports whether a is the zero value of the UDPAddr type.

func (UDPAddr) Network

func (a UDPAddr) Network() string

func (*UDPAddr) Set

func (a *UDPAddr) Set(s string) error

Set implements flag.Value

func (UDPAddr) String

func (a UDPAddr) String() string

func (UDPAddr) WithPort

func (a UDPAddr) WithPort(port uint16) UDPAddr

Directories

Path Synopsis
internal

Jump to

Keyboard shortcuts

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