vnet

package
v1.3.0 Latest Latest
Warning

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

Go to latest
Published: Jul 15, 2020 License: MIT Imports: 12 Imported by: 0

README

vnet

A virtual network layer for pion.

Overview

Goals
  • To make NAT traversal tests easy.
  • To emulate packet impairment at application level for testing.
  • To monitor packets at specified arbitrary interfaces.
Features
  • Configurable virtual LAN and WAN
  • Virtually hosted ICE servers
Virtual network components
Top View
                           ......................................
                           :         Virtual Network (vnet)     :
                           :                                    :
   +-------+ *         1 +----+         +--------+              :
   | :App  |------------>|:Net|--o<-----|:Router |              :
   +-------+             +----+         |        |              :
   +-----------+ *     1 +----+         |        |              :
   |:STUNServer|-------->|:Net|--o<-----|        |              :
   +-----------+         +----+         |        |              :
   +-----------+ *     1 +----+         |        |              :
   |:TURNServer|-------->|:Net|--o<-----|        |              :
   +-----------+         +----+ [1]     |        |              :
                           :          1 |        | 1  <<has>>   :
                           :      +---<>|        |<>----+ [2]   :
                           :      |     +--------+      |       :
                         To form  |      *|             v 0..1  :
                   a subnet tree  |       o [3]      +-----+    :
                           :      |       ^          |:NAT |    :
                           :      |       |          +-----+    :
                           :      +-------+                     :
                           ......................................
    Note:
        o: NIC (Netork Interface Controller)
      [1]: Net implments NIC interface.
      [2]: Root router has no NAT. All child routers have a NAT always.
      [3]: Router implements NIC interface for accesses from the
           parent router.
Net

Net provides 3 interfaces:

  • Configuration API (direct)
  • Network API via Net (equivalent to net.Xxx())
  • Router access via NIC interface
                   (Pion module/app, ICE servers, etc.)
                             +-----------+
                             |   :App    |
                             +-----------+
                                 * | 
                                   | <<uses>>
                                 1 v
   +---------+ 1           * +-----------+ 1    * +-----------+ 1    * +------+
 ..| :Router |----+------>o--|   :Net    |<>------|:Interface |<>------|:Addr |
   +---------+    |      NIC +-----------+        +-----------+        +------+
                  | <<interface>>               (vnet.Interface)      (net.Addr)
                  |
                  |        * +-----------+ 1    * +-----------+ 1    * +------+
                  +------>o--|  :Router  |<>------|:Interface |<>------|:Addr |
                         NIC +-----------+        +-----------+        +------+
                    <<interface>>               (vnet.Interface)      (net.Addr)

The instance of Net will be the one passed around the project. Net class has public methods for configuration and for application use.

Implementation

Design Policy
  • Each pion package should have config object which has Net (of type vnet.Net) property. (just like how we distribute LoggerFactory throughout the pion project.
  • DNS => a simple dictionary (global)?
  • Each Net has routing capability (a goroutine)
  • Use interface provided net package as much as possible
  • Routers are connected in a tree structure (no loop is allowed)
    • To simplify routing
    • Easy to control / monitor (stats, etc)
  • Root router has no NAT (== Internet / WAN)
  • Non-root router has a NAT always
  • When a Net is instantiated, it will automatically add lo0 and eth0 interface, and lo0 will have one IP address, 127.0.0.1. (this is not used in pion/ice, however)
  • When a Net is added to a router, the router automatically assign an IP address for eth0 interface.
    • For simplicity
  • User data won't fragment, but optionally drop chunk larger than MTU
  • IPv6 is not supported
Basic steps for setting up virtual network
  1. Create a root router (WAN)
  2. Create child routers and add to its parent (forms a tree, don't create a loop!)
  3. Add instances of Net to each routers
  4. Call Stop(), or Stop(), on the top router, which propages all other routers
Example: WAN with one endpoint (vnet)
import (
	"net"

	"github.com/mudutv/transport/vnet"
	"github.com/mudutv/logging"
)

// Create WAN (a root router).
wan, err := vnet.NewRouter(&RouterConfig{
    CIDR:          "0.0.0.0/0",
    LoggerFactory: logging.NewDefaultLoggerFactory(),
})

// Create a network.
// You can specify a static IP for the instance of Net to use. If not specified,
// router will assign an IP address that is contained in the router's CIDR.
nw := vnet.NewNet(&vnet.NetConfig{
    StaticIP: "27.1.2.3",
})

// Add the network to the router.
// The router will assign an IP address to `nw`.
if err = wan.AddNet(nw); err != nil {
    // handle error
}

// Start router.
// This will start internal goroutine to route packets.
// If you set child routers (using AddRouter), the call on the root router
// will start the rest of routers for you.
if err = wan.Start(); err != nil {
    // handle error
}

//
// Your application runs here using `nw`.
//

// Stop the router.
// This will stop all internal goroutines in the router tree.
// (No need to call Stop() on child routers)
if err = wan.Stop(); err != nil {
    // handle error
}
Example of how to pass around the instance of vnet.Net

The instance of vnet.Net wraps a subset of net package to enable operations on the virtual network. Your project must be able to pass the instance to all your routines that do network operation with net package. A typical way is to use a config param to create your instances with the virtual network instance (nw in the above example) like this:

type AgentConfig struct {
    :
    Net:  *vnet.Net,
}

type Agent struct {
     :
    net:  *vnet.Net,
}

func NetAgent(config *AgentConfig) *Agent {
    if config.Net == nil {
        config.Net = vnet.NewNet(nil) // defaults to native operation
    }
    
    return &Agent {
         :
        net: config.Net,
    }
}
// a.net is the instance of vnet.Net class
func (a *Agent) listenUDP(...) error {
    conn, err := a.net.ListenPacket("udp", ...)
    if err != nil {
        return nil, err
    }
      :
}
Compatibility and Support Status
net
(built-in)
vnet Note
net.Interfaces() a.net.Interfaces()
net.InterfaceByName() a.net.InterfaceByName()
net.ResolveUDPAddr() a.net.ResolveUDPAddr()
net.ListenPacket() a.net.ListenPacket()
net.ListenUDP() a.net.ListenUDP() (ListenPacket() is recommended)
net.Listen() a.net.Listen() (TODO)
net.ListenTCP() (not supported) (Listen() would be recommended)
net.Dial() a.net.Dial()
net.DialUDP() a.net.DialUDP()
net.DialTCP() (not supported)
net.Interface vnet.Interface
net.PacketConn (use it as-is)
net.UDPConn vnet.UDPConn Use vnet.UDPPacketConn in your code
net.TCPConn vnet.TCPConn (TODO)
net.Dialer vnet.Dialer Use a.net.CreateDialer() to create it.
The use of vnet.Dialer is currently experimental.

a.net is an instance of Net class, and types are defined under the package name vnet

Most of other interface types in net package can be used as is.

Please post a github issue when other types/methods need to be added to vnet/vnet.Net.

TODO / Next Step

  • Implement TCP (TCPConn, Listen)
  • Support of IPv6
  • Write a bunch of examples for building virtual networks.
  • Add network impairment features (on Router)
    • Introduce lantecy / jitter
    • Packet filtering handler (allow selectively drop packets, etc.)
  • Add statistics data retrieval
    • Total number of packets forward by each router
    • Total number of packet loss
    • Total number of connection failure (TCP)

References

Code experiments

Documentation

Overview

Package vnet provides a virtual network layer for pion

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

This section is empty.

Types

type Chunk

type Chunk interface {
	SourceAddr() net.Addr
	DestinationAddr() net.Addr
	UserData() []byte
	Tag() string
	Clone() Chunk
	Network() string // returns "udp" or "tcp"
	String() string
	// contains filtered or unexported methods
}

Chunk represents a packet passed around in the vnet

type ChunkFilter

type ChunkFilter func(c Chunk) bool

ChunkFilter is a handler users can add to filter chunks. If the filter returns false, the packet will be dropped.

type Dialer

type Dialer interface {
	Dial(network, address string) (net.Conn, error)
}

Dialer is identical to net.Dialer excepts that its methods (Dial, DialContext) are overridden to use virtual network. Use vnet.CreateDialer() to create an instance of this Dialer.

type EndpointDependencyType

type EndpointDependencyType uint8

EndpointDependencyType defines a type of behavioral dependendency on the remote endpoint's IP address or port number. This is used for the two kinds of behaviors:

  • Port mapping behavior
  • Filtering behavior

See: https://tools.ietf.org/html/rfc4787

const (
	// EndpointIndependent means the behavior is independent of the endpoint's address or port
	EndpointIndependent EndpointDependencyType = iota
	// EndpointAddrDependent means the behavior is dependent on the endpoint's address
	EndpointAddrDependent
	// EndpointAddrPortDependent means the behavior is dependent on the endpoint's address and port
	EndpointAddrPortDependent
)

type Interface

type Interface struct {
	InterfaceBase
	// contains filtered or unexported fields
}

Interface ...

func NewInterface

func NewInterface(ifc net.Interface) *Interface

NewInterface ...

func (*Interface) AddAddr

func (ifc *Interface) AddAddr(addr net.Addr)

AddAddr ...

func (*Interface) Addrs

func (ifc *Interface) Addrs() ([]net.Addr, error)

Addrs ...

type InterfaceBase

type InterfaceBase net.Interface

InterfaceBase ...

type NATMode

type NATMode uint8

NATMode defines basic behavior of the NAT

const (
	// NATModeNormal means the NAT behaves as a standard NAPT (RFC 2663).
	NATModeNormal NATMode = iota
	// NATModeNAT1To1 exhibits 1:1 DNAT where the external IP address is statically mapped to
	// a specific local IP address with port number is preserved always between them.
	// When this mode is selected, MappingBehavior, FilteringBehavior, PortPreservation and
	// MappingLifeTime of NATType are ignored.
	NATModeNAT1To1
)

type NATType

type NATType struct {
	Mode              NATMode
	MappingBehavior   EndpointDependencyType
	FilteringBehavior EndpointDependencyType
	Hairpining        bool // Not implemented yet
	PortPreservation  bool // Not implemented yet
	MappingLifeTime   time.Duration
}

NATType has a set of parameters that define the behavior of NAT.

type NIC

type NIC interface {
	// contains filtered or unexported methods
}

NIC is a nework inerface controller that interfaces Router

type Net

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

Net represents a local network stack euivalent to a set of layers from NIC up to the transport (UDP / TCP) layer.

func NewNet

func NewNet(config *NetConfig) *Net

NewNet creates an instance of Net. If config is nil, the virtual network is disabled. (uses corresponding net.Xxxx() operations. By design, it always have lo0 and eth0 interfaces. The lo0 has the address 127.0.0.1 assigned by default. IP address for eth0 will be assigned when this Net is added to a router.

func (*Net) CreateDialer

func (n *Net) CreateDialer(dialer *net.Dialer) Dialer

CreateDialer creates an instance of vnet.Dialer

func (*Net) Dial

func (n *Net) Dial(network, address string) (net.Conn, error)

Dial connects to the address on the named network.

func (*Net) DialUDP

func (n *Net) DialUDP(network string, laddr, raddr *net.UDPAddr) (UDPPacketConn, error)

DialUDP acts like Dial for UDP networks.

func (*Net) InterfaceByName

func (n *Net) InterfaceByName(name string) (*Interface, error)

InterfaceByName returns the interface specified by name.

func (*Net) Interfaces

func (n *Net) Interfaces() ([]*Interface, error)

Interfaces returns a list of the system's network interfaces.

func (*Net) IsVirtual

func (n *Net) IsVirtual() bool

IsVirtual tests if the virtual network is enabled.

func (*Net) ListenPacket

func (n *Net) ListenPacket(network string, address string) (net.PacketConn, error)

ListenPacket announces on the local network address.

func (*Net) ListenUDP

func (n *Net) ListenUDP(network string, locAddr *net.UDPAddr) (UDPPacketConn, error)

ListenUDP acts like ListenPacket for UDP networks.

func (*Net) ResolveUDPAddr

func (n *Net) ResolveUDPAddr(network, address string) (*net.UDPAddr, error)

ResolveUDPAddr returns an address of UDP end point.

type NetConfig

type NetConfig struct {
	// StaticIPs is an array of static IP addresses to be assigned for this Net.
	// If no static IP address is given, the router will automatically assign
	// an IP address.
	StaticIPs []string

	// StaticIP is deprecated. Use StaticIPs.
	StaticIP string
}

NetConfig is a bag of configuration parameters passed to NewNet().

type Router

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

Router ...

func NewRouter

func NewRouter(config *RouterConfig) (*Router, error)

NewRouter ...

func (*Router) AddChunkFilter

func (r *Router) AddChunkFilter(filter ChunkFilter)

AddChunkFilter adds a filter for chunks traversing this router. You may add more than one filter. The filters are called in the order of this method call. If a chunk is dropped by a filter, subsequent filter will not receive the chunk.

func (*Router) AddHost

func (r *Router) AddHost(hostName string, ipAddr string) error

AddHost adds a mapping of hostname and an IP address to the local resolver.

func (*Router) AddNet

func (r *Router) AddNet(nic NIC) error

AddNet ...

func (*Router) AddRouter

func (r *Router) AddRouter(router *Router) error

AddRouter adds a chile Router.

func (*Router) Start

func (r *Router) Start() error

Start ...

func (*Router) Stop

func (r *Router) Stop() error

Stop ...

type RouterConfig

type RouterConfig struct {
	// Name of router. If not specified, a unique name will be assigned.
	Name string
	// CIDR notation, like "192.0.2.0/24"
	CIDR string
	// StaticIPs is an array of static IP addresses to be assigned for this router.
	// If no static IP address is given, the router will automatically assign
	// an IP address.
	// This will be ignored if this router is the root.
	StaticIPs []string
	// StaticIP is deprecated. Use StaticIPs.
	StaticIP string
	// Internal queue size
	QueueSize int
	// Effective only when this router has a parent router
	NATType *NATType
	// Minimum Delay
	MinDelay time.Duration
	// Max Jitter
	MaxJitter time.Duration
	// Logger factory
	LoggerFactory logging.LoggerFactory
}

RouterConfig ...

type UDPConn

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

UDPConn is the implementation of the Conn and PacketConn interfaces for UDP network connections. comatible with net.PacketConn and net.Conn

func (*UDPConn) Close

func (c *UDPConn) Close() error

Close closes the connection. Any blocked ReadFrom or WriteTo operations will be unblocked and return errors.

func (*UDPConn) LocalAddr

func (c *UDPConn) LocalAddr() net.Addr

LocalAddr returns the local network address.

func (*UDPConn) Read

func (c *UDPConn) Read(b []byte) (int, error)

Read reads data from the connection. Read can be made to time out and return an Error with Timeout() == true after a fixed time limit; see SetDeadline and SetReadDeadline.

func (*UDPConn) ReadFrom

func (c *UDPConn) ReadFrom(p []byte) (n int, addr net.Addr, err error)

ReadFrom reads a packet from the connection, copying the payload into p. It returns the number of bytes copied into p and the return address that was on the packet. It returns the number of bytes read (0 <= n <= len(p)) and any error encountered. Callers should always process the n > 0 bytes returned before considering the error err. ReadFrom can be made to time out and return an Error with Timeout() == true after a fixed time limit; see SetDeadline and SetReadDeadline.

func (*UDPConn) RemoteAddr

func (c *UDPConn) RemoteAddr() net.Addr

RemoteAddr returns the remote network address.

func (*UDPConn) SetDeadline

func (c *UDPConn) SetDeadline(t time.Time) error

SetDeadline sets the read and write deadlines associated with the connection. It is equivalent to calling both SetReadDeadline and SetWriteDeadline.

A deadline is an absolute time after which I/O operations fail with a timeout (see type Error) instead of blocking. The deadline applies to all future and pending I/O, not just the immediately following call to ReadFrom or WriteTo. After a deadline has been exceeded, the connection can be refreshed by setting a deadline in the future.

An idle timeout can be implemented by repeatedly extending the deadline after successful ReadFrom or WriteTo calls.

A zero value for t means I/O operations will not time out.

func (*UDPConn) SetReadDeadline

func (c *UDPConn) SetReadDeadline(t time.Time) error

SetReadDeadline sets the deadline for future ReadFrom calls and any currently-blocked ReadFrom call. A zero value for t means ReadFrom will not time out.

func (*UDPConn) SetWriteDeadline

func (c *UDPConn) SetWriteDeadline(t time.Time) error

SetWriteDeadline sets the deadline for future WriteTo calls and any currently-blocked WriteTo call. Even if write times out, it may return n > 0, indicating that some of the data was successfully written. A zero value for t means WriteTo will not time out.

func (*UDPConn) Write

func (c *UDPConn) Write(b []byte) (int, error)

Write writes data to the connection. Write can be made to time out and return an Error with Timeout() == true after a fixed time limit; see SetDeadline and SetWriteDeadline.

func (*UDPConn) WriteTo

func (c *UDPConn) WriteTo(p []byte, addr net.Addr) (n int, err error)

WriteTo writes a packet with payload p to addr. WriteTo can be made to time out and return an Error with Timeout() == true after a fixed time limit; see SetDeadline and SetWriteDeadline. On packet-oriented connections, write timeouts are rare.

type UDPPacketConn

type UDPPacketConn interface {
	net.PacketConn
	Read(b []byte) (int, error)
	RemoteAddr() net.Addr
	Write(b []byte) (int, error)
}

UDPPacketConn is packet-oriented connection for UDP.

Jump to

Keyboard shortcuts

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