l2tp

package
v0.1.4 Latest Latest
Warning

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

Go to latest
Published: Oct 13, 2023 License: MIT Imports: 16 Imported by: 0

Documentation

Overview

Package l2tp is a library for Layer 2 Tunneling Protocol applications running on Linux systems.

L2TP is specified by RFC2661 (L2TPv2) and RFC3931 (L2TPv3).

L2TPv2 applies only to PPP tunneling, and is widely used in home broadband installations to convey consumer PPPoE frames to the ISP network. It is also used in conjunction with IPSec in VPN implementations.

L2TPv3 extends the protocol in a backward-compatible manner, and allows for the tunneling of various additional Layer 2 frames including Ethernet and VLAN.

On Linux systems, the kernel natively supports the L2TPv2 and L2TPv3 data plane. Tunneled frames are handled entirely by the kernel for maximum efficiency. The more complex control plane for instantiating and managing tunnel and session instances is implemented in user space.

Currently package l2tp implements:

  • support for controlling the Linux L2TP data plane for L2TPv2 and L2TPv3 tunnels and sessions,
  • the L2TPv2 control plane for client/LAC mode.

In the future we plan to add support for the L2TPv3 control plane, and server/LNS mode.

Usage

import (
	"github.com/katalix/go-l2tp/l2tp"
	"github.com/katalix/go-l2tp/config"
)

# Note we're ignoring errors for brevity.

# Read configuration using the config package.
# This is optional: you can build your own configuration
# structures if you prefer.
config, _ := config.LoadFile("./my-l2tp-config.toml")

# Creation of L2TP instances requires an L2TP context.
# We're disabling logging and using the default Linux data plane.
l2tpctx, _ := l2tp.NewContext(l2tp.LinuxNetlinkDataPlane, nil)

# Create tunnel and session instances based on the config
for _, tcfg := range config.Tunnels {
	tunl, _ := l2tpctx.NewStaticTunnel(tcfg.Name, tcfg.Config)
	for _, scfg := range tcfg.Sessions {
		_, _, := tunl.NewSession(scfg.Name, scfg.Config)
	}
}

Tunnel types

Package l2tp has a concept of "tunnel types" which are used to describe how much of the L2TP control protocol the tunnel instance runs.

The most basic type is the static tunnel (sometimes described as an "unmanaged" tunnel). The static tunnel runs no control protocol at all, and just instantiates the L2TP data plane in the Linux kernel. Consequently all configuration parameters relating to the tunnel and the sessions within that tunnel must be agreed ahead of time by the peers terminating the tunnel.

A slight variation on the theme of the static tunnel is the quiescent tunnel. The quiescent tunnel extends the static tunnel slightly by running just enough of the L2TP control protocol to allow keep-alive (HELLO) messages to be sent and acknowledged using the L2TP reliable transport algorithm. This slight extension allows for detection of tunnel failure in an otherwise static setup.

The final tunnel type is the dynamic tunnel. This runs the full L2TP control protocol.

Configuration

Each tunnel and session instance can be configured using the TunnelConfig and SessionConfig types respectively.

These types can be generated as required for your use-case. This partner package config in this repository implements a TOML parser for expressing L2TP configuration using a configuration file.

Logging

Package l2tp uses structured logging. The logger of choice is the go-kit logger: https://godoc.org/github.com/go-kit/kit/log, and uses go-kit levels in order to separate verbose debugging logs from normal informational output: https://godoc.org/github.com/go-kit/kit/log/level.

Logging emitted at level.Info should be enabled for normal useful runtime information about the lifetime of tunnels and sessions.

Logging emitted at level.Debug should be enabled for more verbose output allowing development debugging of the code or troubleshooting misbehaving L2TP instances.

To disable all logging from package l2tp, pass in a nil logger.

Index

Constants

View Source
const (
	// ProtocolVersion3Fallback is used for RFC3931 fallback mode
	ProtocolVersion3Fallback = 1
	// ProtocolVersion2 is used for RFC2661
	ProtocolVersion2 = nll2tp.ProtocolVersion2
	// ProtocolVersion3 is used for RFC3931
	ProtocolVersion3 = nll2tp.ProtocolVersion3
)
View Source
const (
	// EncapTypeUDP is used for RFC2661 and RFC3931 tunnels using UDP encapsulation
	EncapTypeUDP = nll2tp.EncaptypeUdp
	// EncapTypeIP is used for RFC3931 tunnels using IP encapsulation
	EncapTypeIP = nll2tp.EncaptypeIp
)
View Source
const (
	// FramingCapSync indicates synchronous framing is supported
	FramingCapSync = 0x1
	// FramingCapAsync indicates asynchronous framing is supported
	FramingCapAsync = 0x2
)
View Source
const (
	// PseudowireTypePPP specifies a PPP pseudowire
	PseudowireTypePPP = nll2tp.PwtypePpp
	// PseudowireTypeEth specifies an Ethernet pseudowire
	PseudowireTypeEth = nll2tp.PwtypeEth
	// PseudowireTypePPPAC specifies an Access Concentrator PPP pseudowire
	PseudowireTypePPPAC = nll2tp.PwtypePppAc
)
View Source
const (
	// DebugFlagsControl enables logging of userspace/kernelspace API interactions
	DebugFlagsControl = nll2tp.MsgControl
	// DebugFlagsSeq enables logging of data sequence numbers if enabled for a given session
	DebugFlagsSeq = nll2tp.MsgSeq
	// DebugFlagsData enables logging of session data messages
	DebugFlagsData = nll2tp.MsgData
)
View Source
const (
	// L2SpecTypeNone defines no sublayer is to be used
	L2SpecTypeNone = nll2tp.L2spectypeNone
	// L2SpecTypeDefault defines use of the default sublayer
	L2SpecTypeDefault = nll2tp.L2spectypeDefault
)
View Source
const (
	// TunnelTypeDynamic runs the L2TPv2 (RFC2661) or L2TPv3 (RFC3931) control
	// protocol to instantiate the tunnel instance.
	TunnelTypeDynamic = iota
	// TunnelTypeAcquiescent runs a minimal tunnel control protocol transport
	// which will ACK control messages and optionally send periodic HELLO messages.
	TunnelTypeAcquiescent
	// TunnelTypeStatic runs no control protocol, and instantiates the data plane
	// only.
	TunnelTypeStatic
)

Variables

This section is empty.

Functions

This section is empty.

Types

type Context

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

Context is a container for a collection of L2TP tunnels and their sessions.

func NewContext

func NewContext(dataPlane DataPlane, logger log.Logger) (*Context, error)

NewContext creates a new L2TP context, which can then be used to instantiate tunnel and session instances.

The dataplane interface may be specified as LinuxNetlinkDataPlane, in which case an internal implementation of the Linux Kernel L2TP data plane is used. In this case, context creation will fail if it is not possible to connect to the kernel L2TP subsystem: the kernel must be running the L2TP modules, and the process must have appropriate permissions to access them.

If the dataplane is specified as nil, a special "null" data plane implementation is used. This is useful for experimenting with the control protocol without requiring root permissions.

Logging is generated using go-kit levels: informational logging uses the Info level, while verbose debugging logging uses the Debug level. Error conditions may be logged using the Error level depending on the tunnel type.

If a nil logger is passed, all logging is disabled.

func (*Context) Close

func (ctx *Context) Close()

Close tears down the context, including all the L2TP tunnels and sessions running inside it.

func (*Context) NewDynamicTunnel

func (ctx *Context) NewDynamicTunnel(name string, cfg *TunnelConfig) (tunl Tunnel, err error)

NewDynamicTunnel creates a new dynamic L2TP.

A dynamic L2TP tunnel runs a full RFC2661 (L2TPv2) or RFC3931 (L2TPv3) tunnel instance using the control protocol for tunnel instantiation and management.

The name provided must be unique in the Context.

func (*Context) NewQuiescentTunnel

func (ctx *Context) NewQuiescentTunnel(name string, cfg *TunnelConfig) (tunl Tunnel, err error)

NewQuiescentTunnel creates a new "quiescent" L2TP tunnel.

A quiescent tunnel creates a user space socket for the L2TP control plane, but does not run the control protocol beyond acknowledging messages and optionally sending HELLO messages.

The data plane is established on creation of the tunnel instance.

The name provided must be unique in the Context.

The tunnel configuration must include local and peer addresses and local and peer tunnel IDs.

func (*Context) NewStaticTunnel

func (ctx *Context) NewStaticTunnel(name string, cfg *TunnelConfig) (tunl Tunnel, err error)

NewStaticTunnel creates a new static (unmanaged) L2TP tunnel.

A static tunnel does not run any control protocol and instead merely instantiates the data plane in the kernel. This is equivalent to the Linux 'ip l2tp' command(s).

Static L2TPv2 tunnels are not practically useful, so NewStaticTunnel only supports creation of L2TPv3 unmanaged tunnel instances.

The name provided must be unique in the Context.

The tunnel configuration must include local and peer addresses and local and peer tunnel IDs.

func (*Context) RegisterEventHandler

func (ctx *Context) RegisterEventHandler(handler EventHandler)

RegisterEventHandler adds an event handler to the L2TP context.

On return, the event handler may be called at any time.

The event handler may be called from multiple go routines managed by the L2TP context.

func (*Context) UnregisterEventHandler

func (ctx *Context) UnregisterEventHandler(handler EventHandler)

UnregisterEventHandler removes an event handler from the L2TP context.

It must not be called from the context of an event handler callback.

On return the event handler will not be called on further L2TP events.

type ControlConnID

type ControlConnID uint32

ControlConnID is a generic identifier used for RFC2661 tunnel and session IDs as well as RFC3931 control connection IDs.

type DataPlane

type DataPlane interface {
	// NewTunnel creates a new tunnel data plane instance.
	//
	// The localAddress and peerAddress arguments are unix Sockaddr
	// representations of the tunnel local and peer address.
	//
	// fd is the tunnel socket fd, which may be invalid (<0) for tunnel
	// types which don't manage the tunnel socket in userspace.
	//
	// On successful return the dataplane should be fully ready for use.
	NewTunnel(
		tcfg *TunnelConfig,
		localAddress, peerAddress unix.Sockaddr,
		fd int) (TunnelDataPlane, error)

	// NewSession creates a new session data plane instance.
	//
	// tunnelID and peerTunnelID are the L2TP IDs for the parent tunnel
	// of this session (local and peer respectively).
	//
	// On successful return the dataplane should be fully ready for use.
	NewSession(tunnelID, peerTunnelID ControlConnID, scfg *SessionConfig) (SessionDataPlane, error)

	// Close is called to release any resources held by the dataplane instance.
	// It is called when the l2tp Context using the dataplane shuts down.
	Close()
}

DataPlane is an interface for creating tunnel and session data plane instances.

var LinuxNetlinkDataPlane DataPlane = &nullDataPlane{}

LinuxNetlinkDataPlane is a special sentinel value used to indicate that the L2TP context should use the internal Linux kernel data plane implementation.

type DebugFlags

type DebugFlags uint32

DebugFlags is used for kernel-space tunnel and session logging control. Logging is emitted using the kernel's printk facility, and may be viewed using dmesg, syslog, or the systemd journal depending on distro configuration. Multiple flags may be combined to enable different log messages.

type EncapType

type EncapType int

EncapType is the lower-level encapsulation to use for a tunnel

func (EncapType) String

func (e EncapType) String() string

type EventHandler

type EventHandler interface {
	// HandleEvent is called when an event occurs.
	//
	// HandleEvent will be called from the goroutine of the tunnel or
	// session generating the event.
	//
	// The event passed is a pointer to a type specific to the event
	// which has occurred.  Use type assertions to determine which event
	// is being passed.
	HandleEvent(event interface{})
}

EventHandler is an interface for receiving L2TP-specific events.

type FramingCapability

type FramingCapability uint32

FramingCapability describes the type of framing which a peer supports. It should be specified as a bitwise OR of FramingCap* values.

type L2SpecType

type L2SpecType int32

L2SpecType defines the Layer 2 specific sublayer for data packets as per RFC3931 section 3.2.2.

type ProtocolVersion

type ProtocolVersion int

ProtocolVersion is the version of the L2TP protocol to use

type PseudowireType

type PseudowireType int

PseudowireType is the session type for a given session. RFC2661 is PPP-only; whereas RFC3931 supports multiple types.

type Session

type Session interface {
	// Close closes the session, releasing allocated resources.
	Close()
}

Session is an interface representing an L2TP session.

type SessionConfig

type SessionConfig struct {
	// SessionID specifies the local session ID of the session.
	// Session IDs must be unique to the tunnel for L2TPv2, or unique to
	// the peer for L2TPv3.
	// The session ID must be specified for sessions in static or
	// quiescent tunnels.
	SessionID ControlConnID

	// PeerSessionID specifies the peer's session ID for the session.
	// The peer session ID must be specified for sessions in static or
	// quiescent tunnels.
	PeerSessionID ControlConnID

	// Pseudowire specifies the type of layer 2 frames carried by the session.
	// L2TPv2 tunnels support PPP pseudowires only.
	Pseudowire PseudowireType

	// SeqNum, if set, enables the transmission of sequence numbers with
	// L2TP data messages.  Use of sequence numbers enables the data plane
	// to reorder data packets to ensure they are delivered in sequence.
	// By default sequence numbers are not used.
	SeqNum bool

	// ReorderTimeout, if set, specifies the length of time to queue out
	// of sequence data packets before discarding them.
	// This parameter is not currently implemented and should not be used.
	ReorderTimeout time.Duration

	// Cookie, if set, specifies the local L2TPv3 cookie for the session.
	// Cookies are a data verification mechanism intended to allow misdirected
	// data packets to be detected and rejected.
	// Transmitted data packets will include the local cookie in their header.
	// Cookies may be either 4 or 8 bytes long, and contain aribrary data.
	// By default no local cookie is set.
	Cookie []byte

	// PeerCookie, if set, specifies the L2TPv3 cookie the peer will send in
	// the header of its data messages.
	// Messages received without the peer's cookie (or with the wrong cookie)
	// will be rejected.
	// By default no peer cookie is set.
	PeerCookie []byte

	// InterfaceName, if set, specifies the network interface name to be
	// used for the session instance.
	// Setting the interface name can be useful when you need to be certain
	// of the interface name a given session will use.
	// By default the Linux kernel autogenerates an interface name specific to
	// the pseudowire type, e.g. "l2tpeth0", "ppp0".
	InterfaceName string

	// L2SpecType specifies the L2TPv3 Layer 2 specific sublayer field to
	// be used in data packet headers as per RFC3931 section 3.2.2.
	// By default no Layer 2 specific sublayer is used.
	L2SpecType L2SpecType

	// PPPoESessionId specifies the assigned PPPoE ID of the session.
	// This parameter applies to PseudowireTypePPPAC only.
	PPPoESessionId uint16

	// PPPoEPeerMac specifies the MAC address of the PPPoE peer.
	// This parameter applies to PseudowireTypePPPAC only.
	PPPoEPeerMac [6]byte
}

SessionConfig encapsulates session configuration for a pseudowire connection within a tunnel between two L2TP hosts.

type SessionDataPlane

type SessionDataPlane interface {
	// GetStatistics obtains session statistics.
	GetStatistics() (*SessionDataPlaneStatistics, error)

	// GetInterfaceName obtains the interface name for the session,
	// which may have been generated by the dataplane.
	GetInterfaceName() (string, error)

	// Down performs the necessary actions to tear down the data plane.
	// On successful return the dataplane should be fully destroyed.
	Down() error
}

SessionDataPlane is an interface representing a session data plane.

type SessionDataPlaneStatistics

type SessionDataPlaneStatistics struct {
	TxPackets, TxBytes, TxErrors, RxPackets, RxBytes, RxErrors uint64
}

SessionDataPlaneStatistics holds dataplane statistics for receipt and transmission.

type SessionDownEvent

type SessionDownEvent struct {
	TunnelName    string
	Tunnel        Tunnel
	TunnelConfig  *TunnelConfig
	SessionName   string
	Session       Session
	SessionConfig *SessionConfig
	InterfaceName string
	Result        string
}

SessionDownEvent is passed to registered EventHandler instances when a session comes up. In the case of static or quiescent sessions, this occurs immediately on instantiation of the session. For dynamic sessions, this occurs on the completion of the L2TP control protocol message exchange with the peer.

type SessionUpEvent

type SessionUpEvent struct {
	TunnelName    string
	Tunnel        Tunnel
	TunnelConfig  *TunnelConfig
	SessionName   string
	Session       Session
	SessionConfig *SessionConfig
	InterfaceName string
}

SessionUpEvent is passed to registered EventHandler instances when a session comes up. In the case of static or quiescent sessions, this occurs immediately on instantiation of the session. For dynamic sessions, this occurs on the completion of the L2TP control protocol message exchange with the peer.

type Tunnel

type Tunnel interface {
	// NewSession adds a session to a tunnel instance.
	//
	// The name provided must be unique in the parent tunnel.
	NewSession(name string, cfg *SessionConfig) (Session, error)

	// Close closes the tunnel, releasing allocated resources.
	//
	// Any sessions instantiated inside the tunnel are removed.
	Close()
}

Tunnel is an interface representing an L2TP tunnel.

type TunnelConfig

type TunnelConfig struct {
	// The local address that the tunnel should bind its socket to.
	// This must be specified for static and quiescent tunnels.
	// For dynamic tunnels this can be left blank and the kernel
	// will autobind the socket when connecting to the peer.
	Local string

	// The address of the L2TP peer to connect to.
	Peer string

	// The encapsulation type to be used by the tunnel instance.
	// L2TPv2 tunnels support UDP encapsulation only.
	Encap EncapType

	// The version of the L2TP protocol to use for the tunnel.
	Version ProtocolVersion

	// The local tunnel ID for the tunnel instance.  Tunnel
	// IDs must be unique to the host, and must be non-zero.
	// The tunnel ID must be specified for static and quiescent tunnels.
	// For dynamic tunnels the tunnel ID can set to zero and
	// the L2TP context will autogenerate an ID.
	TunnelID ControlConnID

	// The peer's tunnel ID for the tunnel instance.
	// The peer's ID must be specified for static and quiescent tunnels.
	PeerTunnelID ControlConnID

	// The initial window size to use for the L2TP reliable transport
	// algorithm.  The window size dictates how many control messages the
	// tunnel may have "in flight" (i.e. pending an ACK from the peer)
	// at any one time.
	// Tuning the window size can allow high-volume L2TP servers
	// to improve performance.  Generally it won't be necessary to change
	// this from the default value of 4.
	WindowSize uint16

	// The amount of time to wait on receipt of a StopCCN message to allow
	// and retransmissions to be acknowledged.
	// The default is 31s per RFC2661 section 5.7.
	StopCCNTimeout time.Duration

	// The hello timeout, if set, enables transmission of L2TP keep-alive
	// (HELLO) messages.
	// A hello message is sent N milliseconds after the last control
	// message was sent or received.  It allows for early detection of
	// tunnel failure on quiet connections.
	// By default no keep-alive messages are sent.
	HelloTimeout time.Duration

	// The retry timeout specifies the starting retry timeout for the
	// reliable transport algorithm used for L2TP control messages.
	// The algorithm uses an exponential backoff when retrying messages.
	// By default a starting retry timeout of 1000ms is used.
	RetryTimeout time.Duration

	// MaxRetries sets how many times a given control message may be
	// retried before the transport considers the message transmission to
	// have failed.
	// It may be useful to tune this value on unreliable network connections
	// to avoid suprious tunnel failure, or conversely to allow for quicker
	// tunnel failure detection on reliable links.
	// The default is 3 retries.
	MaxRetries uint

	// HostName sets the host name the tunnel will advertise in the
	// Host Name AVP per RFC2661.
	// If unset the host's name will be queried and the returned value used.
	HostName string

	// FramingCaps sets the framing capabilities the tunnel will advertise
	// in the Framing Capabilities AVP per RFC2661.
	// The default is to advertise both sync and async framing.
	FramingCaps FramingCapability
}

TunnelConfig encapsulates tunnel configuration for a single connection between two L2TP hosts. Each tunnel may contain multiple sessions.

Not every configuration option applies to all tunnel types. Refer to the documentation for specific tunnel creation functions for more information.

type TunnelDataPlane

type TunnelDataPlane interface {
	// Down performs the necessary actions to tear down the data plane.
	// On successful return the dataplane should be fully destroyed.
	Down() error
}

TunnelDataPlane is an interface representing a tunnel data plane.

type TunnelDownEvent

type TunnelDownEvent struct {
	TunnelName                string
	Tunnel                    Tunnel
	Config                    *TunnelConfig
	LocalAddress, PeerAddress unix.Sockaddr
}

TunnelDownEvent is passed to registered EventHandler instances when a tunnel goes down. In the case of static or quiescent tunnels, this occurs immediately on closure of the tunnel. For dynamic tunnels, this occurs on completion of the L2TP control protocol message exchange with the peer.

type TunnelType

type TunnelType int

TunnelType define the runtime behaviour of a tunnel instance.

type TunnelUpEvent

type TunnelUpEvent struct {
	TunnelName                string
	Tunnel                    Tunnel
	Config                    *TunnelConfig
	LocalAddress, PeerAddress unix.Sockaddr
}

TunnelUpEvent is passed to registered EventHandler instances when a tunnel comes up. In the case of static or quiescent tunnels, this occurs immediately on instantiation of the tunnel. For dynamic tunnels, this occurs on completion of the L2TP control protocol message exchange with the peer.

Jump to

Keyboard shortcuts

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