blob: 942e5af9051a728d0c6e05367a2c89d5b16c7acd [file] [log] [blame]
// Copyright 2021 The Fuchsia Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
//go:build !build_with_native_toolchain
package filter
import (
"fmt"
"fidl/fuchsia/hardware/network"
"gvisor.dev/gvisor/pkg/tcpip/header"
"gvisor.dev/gvisor/pkg/tcpip/stack"
)
var _ stack.Matcher = (*filterDisabledNICMatcher)(nil)
// filterDisabledNICMatcher is a stack.Matcher that keeps track of which
// NICs have filtering disabled.
//
// All NICs are considered to have filtering disabled until explicitly
// enabled.
type filterDisabledNICMatcher struct {
enabledNics *enabledNicsCache
}
// Name implements stack.Matcher.
func (*filterDisabledNICMatcher) Name() string {
return "filterDisabledNICMatcher"
}
// Match implements stack.Matcher.
func (d *filterDisabledNICMatcher) Match(hook stack.Hook, _ *stack.PacketBuffer, inNicName, outNicName string) (matches bool, hotdrop bool) {
if inNicName != "" && d.enabledNics.nicDisabled(inNicName) {
return true, false
}
if outNicName != "" && d.enabledNics.nicDisabled(outNicName) {
return true, false
}
return false, false
}
var _ stack.Matcher = (*deviceClassNICMatcher)(nil)
type NICMatcherDirection uint32
const (
_ NICMatcherDirection = iota
NICMatcherDirectionInput
NICMatcherDirectionOutput
)
// deviceClassNICMatcher is a stack.Matcher that matches on the device class
// of an incoming or outgoing interface.
type deviceClassNICMatcher struct {
// enabledNics keeps track of the enabled NIC cache that provides the
// matcher with the NIC's device class when available.
enabledNics *enabledNicsCache
// match is the device class the matcher matches on.
match network.DeviceClass
// direction controls if the input or output interface should be matched on.
direction NICMatcherDirection
}
// Name implements stack.Matcher.
func (*deviceClassNICMatcher) Name() string {
return "deviceClassNICMatcher"
}
// Match implements stack.Matcher.
func (d *deviceClassNICMatcher) Match(_ stack.Hook, _ *stack.PacketBuffer, inNicName, outNicName string) (matches bool, hotdrop bool) {
var nicName string
switch d := d.direction; d {
case NICMatcherDirectionInput:
nicName = inNicName
case NICMatcherDirectionOutput:
nicName = outNicName
default:
panic(fmt.Sprintf("invalid nic matcher direction %d", d))
}
if nicName != "" {
deviceClass := d.enabledNics.nicDeviceClass(nicName)
return (deviceClass != nil && *deviceClass == d.match), false
}
return false, false
}
// portMatcher matches port to some range.
type portMatcher struct {
start uint16
end uint16
}
func (m *portMatcher) match(port uint16) bool {
return port >= m.start && port <= m.end
}
func NewTCPSourcePortMatcher(start, end uint16) *TCPSourcePortMatcher {
return &TCPSourcePortMatcher{portMatcher: portMatcher{start, end}}
}
var _ stack.Matcher = (*TCPSourcePortMatcher)(nil)
// TCPSourcePortMatcher matches TCP packets and ports.
type TCPSourcePortMatcher struct {
portMatcher
}
// Name implements stack.Matcher.
func (*TCPSourcePortMatcher) Name() string {
return "TCPSourcePortMatcher"
}
// Match implements stack.Matcher.
func (m *TCPSourcePortMatcher) Match(_ stack.Hook, pkt *stack.PacketBuffer, _, _ string) (matches bool, hotdrop bool) {
tcp := header.TCP(pkt.TransportHeader().Slice())
if len(tcp) < header.TCPMinimumSize {
// Drop immediately as the packet is invalid.
return false, true
}
return m.portMatcher.match(tcp.SourcePort()), false
}
func NewTCPDestinationPortMatcher(start, end uint16) *TCPDestinationPortMatcher {
return &TCPDestinationPortMatcher{portMatcher: portMatcher{start, end}}
}
var _ stack.Matcher = (*TCPDestinationPortMatcher)(nil)
// TCPDestinationPortMatcher matches TCP packets and ports.
type TCPDestinationPortMatcher struct {
portMatcher
}
// Name implements stack.Matcher.
func (*TCPDestinationPortMatcher) Name() string {
return "TCPDestinationPortMatcher"
}
// Match implements stack.Matcher.
func (m *TCPDestinationPortMatcher) Match(_ stack.Hook, pkt *stack.PacketBuffer, _, _ string) (matches bool, hotdrop bool) {
tcp := header.TCP(pkt.TransportHeader().Slice())
if len(tcp) < header.TCPMinimumSize {
// Drop immediately as the packet is invalid.
return false, true
}
return m.portMatcher.match(tcp.DestinationPort()), false
}
func NewUDPSourcePortMatcher(start, end uint16) *UDPSourcePortMatcher {
return &UDPSourcePortMatcher{portMatcher: portMatcher{start, end}}
}
var _ stack.Matcher = (*UDPSourcePortMatcher)(nil)
// UDPSourcePortMatcher matches UDP packets and ports.
type UDPSourcePortMatcher struct {
portMatcher
}
// Name implements stack.Matcher.
func (*UDPSourcePortMatcher) Name() string {
return "UDPSourcePortMatcher"
}
// Match implements stack.Matcher.
func (m *UDPSourcePortMatcher) Match(_ stack.Hook, pkt *stack.PacketBuffer, _, _ string) (matches bool, hotdrop bool) {
udp := header.UDP(pkt.TransportHeader().Slice())
if len(udp) < header.UDPMinimumSize {
// Drop immediately as the packet is invalid.
return false, true
}
return m.portMatcher.match(udp.SourcePort()), false
}
func NewUDPDestinationPortMatcher(start, end uint16) *UDPDestinationPortMatcher {
return &UDPDestinationPortMatcher{portMatcher: portMatcher{start, end}}
}
var _ stack.Matcher = (*UDPDestinationPortMatcher)(nil)
// UDPDestinationPortMatcher matches UDP packets and ports.
type UDPDestinationPortMatcher struct {
portMatcher
}
// Name implements stack.Matcher.
func (*UDPDestinationPortMatcher) Name() string {
return "UDPDestinationPortMatcher"
}
// Match implements stack.Matcher.
func (m *UDPDestinationPortMatcher) Match(_ stack.Hook, pkt *stack.PacketBuffer, _, _ string) (matches bool, hotdrop bool) {
udp := header.UDP(pkt.TransportHeader().Slice())
if len(udp) < header.UDPMinimumSize {
// Drop immediately as the packet is invalid.
return false, true
}
return m.portMatcher.match(udp.DestinationPort()), false
}