Bug 249275

Summary: New netgraph nodetype: ng_antispoof
Product: Base System Reporter: Markus Stoff <markus>
Component: kernAssignee: freebsd-net (Nobody) <net>
Status: Closed Overcome By Events    
Severity: Affects Only Me    
Priority: ---    
Version: 12.1-RELEASE   
Hardware: Any   
OS: Any   
Attachments:
Description Flags
New netgraph node type: ng_antispoof none

Description Markus Stoff 2020-09-12 09:38:32 UTC
Created attachment 217912 [details]
New netgraph node type: ng_antispoof

This introduces a new netgraph node type that prevents the upstream network from spoofing ethernet and IP addresses. It is called 'ng_antispoof' (name is open for debate, of course).

What it does:

It validates the upstream address each packet against a set of rules. If at least one rule matches, the packet is passed through, otherwise it is blocked.

Each rule consists of a ethernet address and a IP or IPv6 address (in a simplified point of view).


How it works:

Each node provides three hooks:

- 'filter':     Where to connect the upstream node to be protected (e.g. a jail, a VM, ...).
- 'downstream': Downstream node (e.g. a bridge device, the internet, ...).
- 'nomatch':    Useful for debugging with tcpdump. If connected, blocked traffic is forwarded on this hook instead of being discarded. This is output only, traffic arriving on this hook is immediately discarded.

          ___               +----------------+
     __.(     ).__          |                |
    ( downstream  )<------->|                |         
     .._ ( ) _ _..          |                |         I==========I
                            |  ng_antispoof  |<------->I  filter  I
                            |                |         I==========I
      nomatch <-------------|                |         
                            |                |
                            +----------------+


Use Case:

Prevent VNET jails from spoofing IP/MAC addresses while using pf(4) as the firewall on the host system.


Example:

Given a virtual network interface 'host_if' on the host system and 'jail_if' in a VNET enabled jail named 'malicious', restrict the jail to IP '192.168.1.42' on the MAC '1a:00:de:ad:be:ef':

  # Create ng_antispoof node and wire everything together
  ngctl mkpeer jail_if: antispoof ether filter
  ngctl name jail_if:ether as
  ngctl connect as: host_if: downstream ether

  # Add filter rule
  ngctl msg as: addinet '{ ether=1a:00:de:ad:be:ef ip_addr=192.168.1.42 }'


More Details:

Currently filter rules for IP and IPv6 address types can be created. The maximum number of rules is 65535 (UINT16_MAX).

  # For IPv4, subnets can be provided in CIDR or netmask notation
  ngctl msg as: addinet '{ ether=0a:00:de:ad:be:ef ip_addr=192.168.1.42 }'
  ngctl msg as: addinet '{ ether=0a:00:de:ad:be:ef ip_addr=192.168.1.0/24 }'
  ngctl msg as: addinet '{ ether=0a:00:de:ad:be:ef ip_addr=192.168.1.0 ip_mask=255.255.255.0 }'

  # For IPv6, subnets can be provided in CIDR notation
  ngctl msg as: addinet6 '{ ether=0a:00:de:ad:be:ef ip6_addr=::1 }'
  ngctl msg as: addinet6 '{ ether=0a:00:de:ad:be:ef ip6_addr=1:2::/32 }'


Open Questions:

- Is it correct to add the IPv6 parsing type should be added to ng_parse?
- Should the IPv4 and IPv6 prefix types for CIDR notation also go into ng_parse? 
- What is the idiomatic way to provide tests for kernel modules?
- Should VLAN tags be filtered as well (currently all VLAN tags are ignored)?
  - Filtering only the outermost tag would probably be the sensible approach here?
  - Should a single rule filter a single VID, a range of VIDs or a list of (ranges) of VIDs?
Comment 1 Markus Stoff 2020-09-13 09:40:39 UTC
Please let me also have your thoughts at review D26420.
Comment 2 Markus Stoff 2020-09-15 04:45:26 UTC
The proposed functionality is already provided by ng_bpf(4).