Documentation ¶
Overview ¶
Package natlab lets us simulate different types of networks all in-memory without running VMs or requiring root, etc. Despite the name, it does more than just NATs. But NATs are the most interesting.
Index ¶
Constants ¶
const DefaultMappingTimeout = 30 * time.Second
DefaultMappingTimeout is the default timeout for a NAT mapping.
const DefaultSessionTimeout = 30 * time.Second
DefaultSessionTimeout is the default timeout for a firewall session.
Variables ¶
This section is empty.
Functions ¶
This section is empty.
Types ¶
type Firewall ¶
type Firewall struct { // SessionTimeout is the lifetime of idle sessions in the firewall // state. Packets transiting from the TrustedInterface reset the // session lifetime to SessionTimeout. If zero, // DefaultSessionTimeout is used. SessionTimeout time.Duration // Type specifies how precisely return traffic must match // previously seen outbound traffic to be allowed. Defaults to // AddressAndPortDependentFirewall. Type FirewallType // TrustedInterface is an optional interface that is considered // trusted in addition to PacketConns local to the Machine. All // other interfaces can only respond to traffic from // TrustedInterface or the local host. TrustedInterface *Interface // TimeNow is a function returning the current time. If nil, // time.Now is used. TimeNow func() time.Time // contains filtered or unexported fields }
Firewall is a simple stateful firewall that allows all outbound traffic and filters inbound traffic based on recently seen outbound traffic. Its HandlePacket method should be attached to a Machine to give it a stateful firewall.
func (*Firewall) HandleForward ¶
type FirewallType ¶
type FirewallType int
FirewallType is the type of filtering a stateful firewall does. Values express different modes defined by RFC 4787.
const ( // AddressAndPortDependentFirewall specifies a destination // address-and-port dependent firewall. Outbound traffic to an // ip:port authorizes traffic from that ip:port exactly, and // nothing else. AddressAndPortDependentFirewall FirewallType = iota // AddressDependentFirewall specifies a destination address // dependent firewall. Once outbound traffic has been seen to an // IP address, that IP address can talk back from any port. AddressDependentFirewall // EndpointIndependentFirewall specifies a destination endpoint // independent firewall. Once outbound traffic has been seen from // a source, anyone can talk back to that source. EndpointIndependentFirewall )
type Interface ¶
type Interface struct {
// contains filtered or unexported fields
}
type Machine ¶
type Machine struct { // Name is a pretty name for debugging and packet tracing. It need // not be globally unique. Name string // PacketHandler, if not nil, is a PacketHandler implementation // that inspects all packets arriving, departing, or transiting // the Machine. See the definition of the PacketHandler interface // for semantics. // // If PacketHandler is nil, the machine allows all inbound // traffic, all outbound traffic, and drops forwarded packets. PacketHandler PacketHandler // contains filtered or unexported fields }
A Machine is a representation of an operating system's network stack. It has a network routing table and can have multiple attached networks. The zero value is valid, but lacks any networking capability until Attach is called.
func (*Machine) AddNetwork ¶
func (*Machine) Attach ¶
Attach adds an interface to a machine.
The first interface added to a Machine becomes that machine's default route.
func (*Machine) ListenPacket ¶
type NATType ¶
type NATType int
NATType is the mapping behavior of a NAT device. Values express different modes defined by RFC 4787.
const ( // EndpointIndependentNAT specifies a destination endpoint // independent NAT. All traffic from a source ip:port gets mapped // to a single WAN ip:port. EndpointIndependentNAT NATType = iota // AddressDependentNAT specifies a destination address dependent // NAT. Every distinct destination IP gets its own WAN ip:port // allocation. AddressDependentNAT // AddressAndPortDependentNAT specifies a destination // address-and-port dependent NAT. Every distinct destination // ip:port gets its own WAN ip:port allocation. AddressAndPortDependentNAT )
type Network ¶
type Network struct { Name string Prefix4 netip.Prefix Prefix6 netip.Prefix // contains filtered or unexported fields }
func NewInternet ¶
func NewInternet() *Network
NewInternet returns a network that simulates the internet.
func (*Network) SetDefaultGateway ¶
type Packet ¶
type Packet struct {
Src, Dst netip.AddrPort
Payload []byte
// contains filtered or unexported fields
}
Packet represents a UDP packet flowing through the virtual network.
func (*Packet) Equivalent ¶
Equivalent returns true if Src, Dst and Payload are the same in p and p2.
type PacketHandler ¶
type PacketHandler interface { // HandleIn processes a packet arriving on iif, whose destination // is an IP address owned by the attached Machine. If p is // returned unmodified, the Machine will go on to deliver the // Packet to the appropriate listening PacketConn, if one exists. HandleIn(p *Packet, iif *Interface) *Packet // HandleOut processes a packet about to depart on oif from a // local PacketConn. If p is returned unmodified, the Machine will // transmit the Packet on oif. HandleOut(p *Packet, oif *Interface) *Packet // HandleForward is called when the Machine wants to forward a // packet from iif to oif. If p is returned unmodified, the // Machine will transmit the packet on oif. HandleForward(p *Packet, iif, oif *Interface) *Packet }
A PacketHandler can look at packets arriving at, departing, and transiting a Machine, and filter or mutate them.
Each method is invoked with a Packet that natlab would like to keep processing. Handlers can return that same Packet to allow processing to continue; nil to drop the Packet; or a different Packet that should be processed instead of the original.
Packets passed to handlers share no state with anything else, and are therefore safe to mutate. It's safe to return the original packet mutated in-place, or a brand new packet initialized from scratch.
Packets mutated by a PacketHandler are processed anew by the associated Machine, as if the packet had always been the mutated one. For example, if HandleForward is invoked with a Packet, and the handler changes the destination IP address to one of the Machine's own IPs, the Machine restarts delivery, but this time going to a local PacketConn (which in turn will invoke HandleIn, since the packet is now destined for local delivery).
type PacketVerdict ¶
type PacketVerdict int
A PacketVerdict is a decision of what to do with a packet.
const ( // Continue means the packet should be processed by the "local // sockets" logic of the Machine. Continue PacketVerdict = iota // Drop means the packet should not be handled further. Drop )
func (PacketVerdict) String ¶
func (v PacketVerdict) String() string
type SNAT44 ¶
type SNAT44 struct { // Machine is the machine to which this NAT is attached. Altered // packets are injected back into this Machine for processing. Machine *Machine // ExternalInterface is the "WAN" interface of Machine. Packets // from other sources get NATed onto this interface. ExternalInterface *Interface // Type specifies the mapping allocation behavior for this NAT. Type NATType // MappingTimeout is the lifetime of individual NAT sessions. Once // a session expires, the mapped port effectively "closes" to new // traffic. If MappingTimeout is 0, DefaultMappingTimeout is used. MappingTimeout time.Duration // Firewall is an optional packet handler that will be invoked as // a firewall during NAT translation. The firewall always sees // packets in their "LAN form", i.e. before translation in the // outbound direction and after translation in the inbound // direction. Firewall PacketHandler // TimeNow is a function that returns the current time. If // nil, time.Now is used. TimeNow func() time.Time // contains filtered or unexported fields }
SNAT44 implements an IPv4-to-IPv4 source NAT (SNAT) translator, with optional builtin firewall.