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 ¶
- Variables
- func ListenQUIC(ctx context.Context, local netaddr.IPPort, selector ReplySelector, ...) (quic.Listener, error)
- func MangleSCIONAddr(address string) string
- func ParseOptionalIPPort(s string) (netaddr.IPPort, error)
- func SplitHostPort(hostport string) (host, port string, err error)
- func UnmangleSCIONAddr(address string) string
- type ACL
- type CommandlinePrompter
- type Conn
- type DefaultReplySelector
- type DefaultSelector
- type DestinationStats
- type ForwardingPath
- type GeoCoordinates
- type HighestBandwidth
- type HighestMTU
- type HostNotFoundError
- type IA
- type IPPortValue
- type IfID
- type InteractiveSelection
- type InteractiveSelectionType
- type LeastHops
- type LinkType
- type ListenConn
- type LowestLatency
- type Path
- type PathFingerprint
- type PathInterface
- type PathInterfaceStats
- type PathMetadata
- type PathStats
- type PingingSelector
- func (s *PingingSelector) Close() error
- func (s *PingingSelector) Initialize(local, remote UDPAddr, paths []*Path)
- func (s *PingingSelector) Path() *Path
- func (s *PingingSelector) PathDown(pf PathFingerprint, pi PathInterface)
- func (s *PingingSelector) Refresh(paths []*Path)
- func (s *PingingSelector) SetActive(numActive int)
- type Pinned
- type Policy
- type PolicyChain
- type PolicyFunc
- type Preferred
- type Prompter
- type QUICEarlySession
- type QUICSession
- type ReplySelector
- type SCMPError
- type Selector
- type Sequence
- type StatsLatencySample
- type StatsLatencySamples
- type UDPAddr
Constants ¶
This section is empty.
Variables ¶
var (
AvailablePreferencePolicies = []string{"latency", "bandwidth", "hops", "mtu"}
)
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 ¶
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 ¶
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 ¶
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 ¶
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.
type CommandlinePrompter ¶
type CommandlinePrompter struct{}
CommandlinePrompter is a Prompter for InteractiveSelection, prompting the user for textual path selection input on stdin/out.
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 (s *DefaultReplySelector) PathDown(PathFingerprint, PathInterface)
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 ¶
FIXME: leaking addr.I, addr.A
func MustParseIA ¶
MustParseIA calls ParseIA and panics on error. This is intended for testing.
func (IA) IsWildcard ¶
IsWildcard reports whether ia has a wildcard part (isd or as, or both).
type IPPortValue ¶
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 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 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?
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 PathInterfaceStats ¶
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 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.
type Policy ¶
Policy is a stateless filter / sorter for paths.
func PolicyFromCommandline ¶
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 ¶
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.
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 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 ¶
NewSequence creates a new sequence from a string
type StatsLatencySamples ¶
type StatsLatencySamples []StatsLatencySample
type UDPAddr ¶
UDPAddr is an address for a SCION/UDP end point.
func MustParseUDPAddr ¶
MustParseUDPAddr calls ParseUDPAddr and panics on error. This is intended for testing.
func ParseUDPAddr ¶
ParseUDPAddr converts an address string to a SCION address.
func ResolveUDPAddr ¶
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 ¶
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.