mirror of
https://github.com/netbirdio/gvisor.git
synced 2026-05-22 17:12:49 -07:00
Add basic iptables structures to netstack.
Change-Id: Ib589906175a59dae315405a28f2d7f525ff8877f
This commit is contained in:
@@ -0,0 +1,20 @@
|
||||
package(licenses = ["notice"])
|
||||
|
||||
load("//tools/go_stateify:defs.bzl", "go_library", "go_test")
|
||||
|
||||
go_library(
|
||||
name = "iptables",
|
||||
srcs = [
|
||||
"iptables.go",
|
||||
"targets.go",
|
||||
"types.go",
|
||||
],
|
||||
importpath = "gvisor.googlesource.com/gvisor/pkg/tcpip/iptables",
|
||||
visibility = ["//visibility:public"],
|
||||
deps = [
|
||||
"//pkg/state",
|
||||
"//pkg/tcpip",
|
||||
"//pkg/tcpip/buffer",
|
||||
"//pkg/tcpip/header",
|
||||
],
|
||||
)
|
||||
@@ -0,0 +1,97 @@
|
||||
// Copyright 2019 The gVisor authors.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
// Package iptables supports packet filtering and manipulation via the iptables
|
||||
// tool.
|
||||
package iptables
|
||||
|
||||
const (
|
||||
tablenameNat = "nat"
|
||||
tablenameMangle = "mangle"
|
||||
)
|
||||
|
||||
// Chain names as defined by net/ipv4/netfilter/ip_tables.c.
|
||||
const (
|
||||
chainNamePrerouting = "PREROUTING"
|
||||
chainNameInput = "INPUT"
|
||||
chainNameForward = "FORWARD"
|
||||
chainNameOutput = "OUTPUT"
|
||||
chainNamePostrouting = "POSTROUTING"
|
||||
)
|
||||
|
||||
// DefaultTables returns a default set of tables. Each chain is set to accept
|
||||
// all packets.
|
||||
func DefaultTables() *IPTables {
|
||||
tables := IPTables{
|
||||
Tables: map[string]*Table{
|
||||
tablenameNat: &Table{
|
||||
BuiltinChains: map[Hook]*Chain{
|
||||
Prerouting: unconditionalAcceptChain(chainNamePrerouting),
|
||||
Input: unconditionalAcceptChain(chainNameInput),
|
||||
Output: unconditionalAcceptChain(chainNameOutput),
|
||||
Postrouting: unconditionalAcceptChain(chainNamePostrouting),
|
||||
},
|
||||
DefaultTargets: map[Hook]Target{
|
||||
Prerouting: UnconditionalAcceptTarget{},
|
||||
Input: UnconditionalAcceptTarget{},
|
||||
Output: UnconditionalAcceptTarget{},
|
||||
Postrouting: UnconditionalAcceptTarget{},
|
||||
},
|
||||
UserChains: map[string]*Chain{},
|
||||
},
|
||||
tablenameMangle: &Table{
|
||||
BuiltinChains: map[Hook]*Chain{
|
||||
Prerouting: unconditionalAcceptChain(chainNamePrerouting),
|
||||
Output: unconditionalAcceptChain(chainNameOutput),
|
||||
},
|
||||
DefaultTargets: map[Hook]Target{
|
||||
Prerouting: UnconditionalAcceptTarget{},
|
||||
Output: UnconditionalAcceptTarget{},
|
||||
},
|
||||
UserChains: map[string]*Chain{},
|
||||
},
|
||||
},
|
||||
Priorities: map[Hook][]string{
|
||||
Prerouting: []string{tablenameMangle, tablenameNat},
|
||||
Output: []string{tablenameMangle, tablenameNat},
|
||||
},
|
||||
}
|
||||
|
||||
// Initialize each table's Chains field.
|
||||
tables.Tables[tablenameNat].Chains = map[string]*Chain{
|
||||
chainNamePrerouting: tables.Tables[tablenameNat].BuiltinChains[Prerouting],
|
||||
chainNameInput: tables.Tables[tablenameNat].BuiltinChains[Input],
|
||||
chainNameOutput: tables.Tables[tablenameNat].BuiltinChains[Output],
|
||||
chainNamePostrouting: tables.Tables[tablenameNat].BuiltinChains[Postrouting],
|
||||
}
|
||||
tables.Tables[tablenameMangle].Chains = map[string]*Chain{
|
||||
chainNamePrerouting: tables.Tables[tablenameMangle].BuiltinChains[Prerouting],
|
||||
chainNameInput: tables.Tables[tablenameMangle].BuiltinChains[Input],
|
||||
chainNameOutput: tables.Tables[tablenameMangle].BuiltinChains[Output],
|
||||
chainNamePostrouting: tables.Tables[tablenameMangle].BuiltinChains[Postrouting],
|
||||
}
|
||||
|
||||
return &tables
|
||||
}
|
||||
|
||||
func unconditionalAcceptChain(name string) *Chain {
|
||||
return &Chain{
|
||||
Name: name,
|
||||
Rules: []*Rule{
|
||||
&Rule{
|
||||
Target: UnconditionalAcceptTarget{},
|
||||
},
|
||||
},
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,35 @@
|
||||
// Copyright 2019 The gVisor Authors.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package iptables
|
||||
|
||||
import "gvisor.googlesource.com/gvisor/pkg/tcpip/buffer"
|
||||
|
||||
// This file contains various Targets.
|
||||
|
||||
// UnconditionalAcceptTarget accepts all packets.
|
||||
type UnconditionalAcceptTarget struct{}
|
||||
|
||||
// Action implements Target.Action.
|
||||
func (_ UnconditionalAcceptTarget) Action(packet buffer.VectorisedView) (Verdict, string) {
|
||||
return Accept, ""
|
||||
}
|
||||
|
||||
// UnconditionalDropTarget denies all packets.
|
||||
type UnconditionalDropTarget struct{}
|
||||
|
||||
// Action implements Target.Action.
|
||||
func (_ UnconditionalDropTarget) Action(packet buffer.VectorisedView) (Verdict, string) {
|
||||
return Drop, ""
|
||||
}
|
||||
@@ -0,0 +1,190 @@
|
||||
// Copyright 2019 The gVisor authors.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package iptables
|
||||
|
||||
import (
|
||||
"sync"
|
||||
|
||||
"gvisor.googlesource.com/gvisor/pkg/tcpip"
|
||||
"gvisor.googlesource.com/gvisor/pkg/tcpip/buffer"
|
||||
)
|
||||
|
||||
// Hook specifies one of the hooks built into the network stack.
|
||||
//
|
||||
// Userspace app Userspace app
|
||||
// ^ |
|
||||
// | v
|
||||
// [Input] [Output]
|
||||
// ^ |
|
||||
// | v
|
||||
// | routing
|
||||
// | |
|
||||
// | v
|
||||
// ----->[Prerouting]----->routing----->[Forward]---------[Postrouting]----->
|
||||
type Hook uint
|
||||
|
||||
// These values correspond to values in include/uapi/linux/netfilter.h.
|
||||
const (
|
||||
// Prerouting happens before a packet is routed to applications or to
|
||||
// be forwarded.
|
||||
Prerouting Hook = iota
|
||||
|
||||
// Input happens before a packet reaches an application.
|
||||
Input
|
||||
|
||||
// Forward happens once it's decided that a packet should be forwarded
|
||||
// to another host.
|
||||
Forward
|
||||
|
||||
// Output happens after a packet is written by an application to be
|
||||
// sent out.
|
||||
Output
|
||||
|
||||
// Postrouting happens just before a packet goes out on the wire.
|
||||
Postrouting
|
||||
|
||||
// The total number of hooks.
|
||||
NumHooks
|
||||
)
|
||||
|
||||
// Verdict is returned by a rule's target to indicate how traversal of rules
|
||||
// should (or should not) continue.
|
||||
type Verdict int
|
||||
|
||||
const (
|
||||
// Accept indicates the packet should continue traversing netstack as
|
||||
// normal.
|
||||
Accept Verdict = iota
|
||||
|
||||
// Drop inicates the packet should be dropped, stopping traversing
|
||||
// netstack.
|
||||
Drop
|
||||
|
||||
// Stolen indicates the packet was co-opted by the target and should
|
||||
// stop traversing netstack.
|
||||
Stolen
|
||||
|
||||
// Queue indicates the packet should be queued for userspace processing.
|
||||
Queue
|
||||
|
||||
// Repeat indicates the packet should re-traverse the chains for the
|
||||
// current hook.
|
||||
Repeat
|
||||
|
||||
// None indicates no verdict was reached.
|
||||
None
|
||||
|
||||
// Jump indicates a jump to another chain.
|
||||
Jump
|
||||
|
||||
// Continue indicates that traversal should continue at the next rule.
|
||||
Continue
|
||||
|
||||
// Return indicates that traversal should return to the calling chain.
|
||||
Return
|
||||
)
|
||||
|
||||
// IPTables holds all the tables for a netstack.
|
||||
type IPTables struct {
|
||||
// mu protects the entire struct.
|
||||
mu sync.RWMutex
|
||||
|
||||
// Tables maps table names to tables. User tables have arbitrary names.
|
||||
Tables map[string]*Table
|
||||
|
||||
// Priorities maps each hook to a list of table names. The order of the
|
||||
// list is the order in which each table should be visited for that
|
||||
// hook.
|
||||
Priorities map[Hook][]string
|
||||
}
|
||||
|
||||
// Table defines a set of chains and hooks into the network stack. The
|
||||
// currently supported tables are:
|
||||
// * nat
|
||||
// * mangle
|
||||
type Table struct {
|
||||
// BuiltinChains holds the un-deletable chains built into netstack. If
|
||||
// a hook isn't present in the map, this table doesn't utilize that
|
||||
// hook.
|
||||
BuiltinChains map[Hook]*Chain
|
||||
|
||||
// DefaultTargets holds a target for each hook that will be executed if
|
||||
// chain traversal doesn't yield a verdict.
|
||||
DefaultTargets map[Hook]Target
|
||||
|
||||
// UserChains holds user-defined chains for the keyed by name. Users
|
||||
// can give their chains arbitrary names.
|
||||
UserChains map[string]*Chain
|
||||
|
||||
// Chains maps names to chains for both builtin and user-defined chains.
|
||||
// Its entries point to Chains already either in BuiltinChains and
|
||||
// UserChains, and its purpose is to make looking up tables by name
|
||||
// fast.
|
||||
Chains map[string]*Chain
|
||||
}
|
||||
|
||||
// ValidHooks returns a bitmap of the builtin hooks for the given table.
|
||||
//
|
||||
// Precondition: IPTables.mu must be locked for reading.
|
||||
func (table *Table) ValidHooks() (uint32, *tcpip.Error) {
|
||||
hooks := uint32(0)
|
||||
for hook, _ := range table.BuiltinChains {
|
||||
hooks |= 1 << hook
|
||||
}
|
||||
return hooks, nil
|
||||
}
|
||||
|
||||
// Chain defines a list of rules for packet processing. When a packet traverses
|
||||
// a chain, it is checked against each rule until either a rule returns a
|
||||
// verdict or the chain ends.
|
||||
//
|
||||
// By convention, builtin chains end with a rule that matches everything and
|
||||
// returns either Accept or Drop. User-defined chains end with Return. These
|
||||
// aren't strictly necessary here, but the iptables tool writes tables this way.
|
||||
type Chain struct {
|
||||
// Name is the chain name.
|
||||
Name string
|
||||
|
||||
// Rules is the list of rules to traverse.
|
||||
Rules []*Rule
|
||||
}
|
||||
|
||||
// Rule is a packet processing rule. It consists of two pieces. First it
|
||||
// contains zero or more matchers, each of which is a specification of which
|
||||
// packets this rule applies to. If there are no matchers in the rule, it
|
||||
// applies to any packet.
|
||||
type Rule struct {
|
||||
// Matchers is the list of matchers for this rule.
|
||||
Matchers []Matcher
|
||||
|
||||
// Target is the action to invoke if all the matchers match the packet.
|
||||
Target Target
|
||||
}
|
||||
|
||||
// Matcher is the interface for matching packets.
|
||||
type Matcher interface {
|
||||
// Match returns whether the packet matches and whether the packet
|
||||
// should be "hotdropped", i.e. dropped immediately. This is usually
|
||||
// used for suspicious packets.
|
||||
Match(hook Hook, packet buffer.VectorisedView, interfaceName string) (matches bool, hotdrop bool)
|
||||
}
|
||||
|
||||
// Target is the interface for taking an action for a packet.
|
||||
type Target interface {
|
||||
// Action takes an action on the packet and returns a verdict on how
|
||||
// traversal should (or should not) continue. If the return value is
|
||||
// Jump, it also returns the name of the chain to jump to.
|
||||
Action(packet buffer.VectorisedView) (Verdict, string)
|
||||
}
|
||||
Reference in New Issue
Block a user