ip6tables: move ipv4-specific logic into its own file

A later change will introduce the equivalent IPv6 logic.

#3549

PiperOrigin-RevId: 327499064
This commit is contained in:
Kevin Krakauer
2020-08-19 13:47:47 -07:00
committed by gVisor bot
parent 5cf330106a
commit 182f66ee5e
6 changed files with 297 additions and 237 deletions
+1
View File
@@ -6,6 +6,7 @@ go_library(
name = "netfilter",
srcs = [
"extensions.go",
"ipv4.go",
"netfilter.go",
"owner_matcher.go",
"targets.go",
+235
View File
@@ -0,0 +1,235 @@
// Copyright 2020 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 netfilter
import (
"bytes"
"fmt"
"gvisor.dev/gvisor/pkg/abi/linux"
"gvisor.dev/gvisor/pkg/binary"
"gvisor.dev/gvisor/pkg/syserr"
"gvisor.dev/gvisor/pkg/tcpip"
"gvisor.dev/gvisor/pkg/tcpip/header"
"gvisor.dev/gvisor/pkg/tcpip/stack"
"gvisor.dev/gvisor/pkg/usermem"
)
// emptyIPv4Filter is for comparison with a rule's filters to determine whether
// it is also empty. It is immutable.
var emptyIPv4Filter = stack.IPHeaderFilter{
Dst: "\x00\x00\x00\x00",
DstMask: "\x00\x00\x00\x00",
Src: "\x00\x00\x00\x00",
SrcMask: "\x00\x00\x00\x00",
}
func getEntries4(table stack.Table, info *linux.IPTGetinfo) linux.KernelIPTGetEntries {
var entries linux.KernelIPTGetEntries
copy(entries.Name[:], info.Name[:])
for ruleIdx, rule := range table.Rules {
nflog("convert to binary: current offset: %d", entries.Size)
setHooksAndUnderflow(info, table, entries.Size, ruleIdx)
// Each rule corresponds to an entry.
entry := linux.KernelIPTEntry{
Entry: linux.IPTEntry{
IP: linux.IPTIP{
Protocol: uint16(rule.Filter.Protocol),
},
NextOffset: linux.SizeOfIPTEntry,
TargetOffset: linux.SizeOfIPTEntry,
},
}
copy(entry.Entry.IP.Dst[:], rule.Filter.Dst)
copy(entry.Entry.IP.DstMask[:], rule.Filter.DstMask)
copy(entry.Entry.IP.Src[:], rule.Filter.Src)
copy(entry.Entry.IP.SrcMask[:], rule.Filter.SrcMask)
copy(entry.Entry.IP.OutputInterface[:], rule.Filter.OutputInterface)
copy(entry.Entry.IP.OutputInterfaceMask[:], rule.Filter.OutputInterfaceMask)
if rule.Filter.DstInvert {
entry.Entry.IP.InverseFlags |= linux.IPT_INV_DSTIP
}
if rule.Filter.SrcInvert {
entry.Entry.IP.InverseFlags |= linux.IPT_INV_SRCIP
}
if rule.Filter.OutputInterfaceInvert {
entry.Entry.IP.InverseFlags |= linux.IPT_INV_VIA_OUT
}
for _, matcher := range rule.Matchers {
// Serialize the matcher and add it to the
// entry.
serialized := marshalMatcher(matcher)
nflog("convert to binary: matcher serialized as: %v", serialized)
if len(serialized)%8 != 0 {
panic(fmt.Sprintf("matcher %T is not 64-bit aligned", matcher))
}
entry.Elems = append(entry.Elems, serialized...)
entry.Entry.NextOffset += uint16(len(serialized))
entry.Entry.TargetOffset += uint16(len(serialized))
}
// Serialize and append the target.
serialized := marshalTarget(rule.Target)
if len(serialized)%8 != 0 {
panic(fmt.Sprintf("target %T is not 64-bit aligned", rule.Target))
}
entry.Elems = append(entry.Elems, serialized...)
entry.Entry.NextOffset += uint16(len(serialized))
nflog("convert to binary: adding entry: %+v", entry)
entries.Size += uint32(entry.Entry.NextOffset)
entries.Entrytable = append(entries.Entrytable, entry)
info.NumEntries++
}
info.Size = entries.Size
nflog("convert to binary: finished with an marshalled size of %d", info.Size)
return entries
}
func modifyEntries4(stk *stack.Stack, optVal []byte, replace *linux.IPTReplace, table *stack.Table) (map[uint32]int, *syserr.Error) {
nflog("set entries: setting entries in table %q", replace.Name.String())
// Convert input into a list of rules and their offsets.
var offset uint32
// offsets maps rule byte offsets to their position in table.Rules.
offsets := map[uint32]int{}
for entryIdx := uint32(0); entryIdx < replace.NumEntries; entryIdx++ {
nflog("set entries: processing entry at offset %d", offset)
// Get the struct ipt_entry.
if len(optVal) < linux.SizeOfIPTEntry {
nflog("optVal has insufficient size for entry %d", len(optVal))
return nil, syserr.ErrInvalidArgument
}
var entry linux.IPTEntry
buf := optVal[:linux.SizeOfIPTEntry]
binary.Unmarshal(buf, usermem.ByteOrder, &entry)
initialOptValLen := len(optVal)
optVal = optVal[linux.SizeOfIPTEntry:]
if entry.TargetOffset < linux.SizeOfIPTEntry {
nflog("entry has too-small target offset %d", entry.TargetOffset)
return nil, syserr.ErrInvalidArgument
}
// TODO(gvisor.dev/issue/170): We should support more IPTIP
// filtering fields.
filter, err := filterFromIPTIP(entry.IP)
if err != nil {
nflog("bad iptip: %v", err)
return nil, syserr.ErrInvalidArgument
}
// TODO(gvisor.dev/issue/170): Matchers and targets can specify
// that they only work for certain protocols, hooks, tables.
// Get matchers.
matchersSize := entry.TargetOffset - linux.SizeOfIPTEntry
if len(optVal) < int(matchersSize) {
nflog("entry doesn't have enough room for its matchers (only %d bytes remain)", len(optVal))
return nil, syserr.ErrInvalidArgument
}
matchers, err := parseMatchers(filter, optVal[:matchersSize])
if err != nil {
nflog("failed to parse matchers: %v", err)
return nil, syserr.ErrInvalidArgument
}
optVal = optVal[matchersSize:]
// Get the target of the rule.
targetSize := entry.NextOffset - entry.TargetOffset
if len(optVal) < int(targetSize) {
nflog("entry doesn't have enough room for its target (only %d bytes remain)", len(optVal))
return nil, syserr.ErrInvalidArgument
}
target, err := parseTarget(filter, optVal[:targetSize])
if err != nil {
nflog("failed to parse target: %v", err)
return nil, syserr.ErrInvalidArgument
}
optVal = optVal[targetSize:]
table.Rules = append(table.Rules, stack.Rule{
Filter: filter,
Target: target,
Matchers: matchers,
})
offsets[offset] = int(entryIdx)
offset += uint32(entry.NextOffset)
if initialOptValLen-len(optVal) != int(entry.NextOffset) {
nflog("entry NextOffset is %d, but entry took up %d bytes", entry.NextOffset, initialOptValLen-len(optVal))
return nil, syserr.ErrInvalidArgument
}
}
return offsets, nil
}
func filterFromIPTIP(iptip linux.IPTIP) (stack.IPHeaderFilter, error) {
if containsUnsupportedFields4(iptip) {
return stack.IPHeaderFilter{}, fmt.Errorf("unsupported fields in struct iptip: %+v", iptip)
}
if len(iptip.Dst) != header.IPv4AddressSize || len(iptip.DstMask) != header.IPv4AddressSize {
return stack.IPHeaderFilter{}, fmt.Errorf("incorrect length of destination (%d) and/or destination mask (%d) fields", len(iptip.Dst), len(iptip.DstMask))
}
if len(iptip.Src) != header.IPv4AddressSize || len(iptip.SrcMask) != header.IPv4AddressSize {
return stack.IPHeaderFilter{}, fmt.Errorf("incorrect length of source (%d) and/or source mask (%d) fields", len(iptip.Src), len(iptip.SrcMask))
}
n := bytes.IndexByte([]byte(iptip.OutputInterface[:]), 0)
if n == -1 {
n = len(iptip.OutputInterface)
}
ifname := string(iptip.OutputInterface[:n])
n = bytes.IndexByte([]byte(iptip.OutputInterfaceMask[:]), 0)
if n == -1 {
n = len(iptip.OutputInterfaceMask)
}
ifnameMask := string(iptip.OutputInterfaceMask[:n])
return stack.IPHeaderFilter{
Protocol: tcpip.TransportProtocolNumber(iptip.Protocol),
Dst: tcpip.Address(iptip.Dst[:]),
DstMask: tcpip.Address(iptip.DstMask[:]),
DstInvert: iptip.InverseFlags&linux.IPT_INV_DSTIP != 0,
Src: tcpip.Address(iptip.Src[:]),
SrcMask: tcpip.Address(iptip.SrcMask[:]),
SrcInvert: iptip.InverseFlags&linux.IPT_INV_SRCIP != 0,
OutputInterface: ifname,
OutputInterfaceMask: ifnameMask,
OutputInterfaceInvert: iptip.InverseFlags&linux.IPT_INV_VIA_OUT != 0,
}, nil
}
func containsUnsupportedFields4(iptip linux.IPTIP) bool {
// The following features are supported:
// - Protocol
// - Dst and DstMask
// - Src and SrcMask
// - The inverse destination IP check flag
// - OutputInterface, OutputInterfaceMask and its inverse.
var emptyInterface = [linux.IFNAMSIZ]byte{}
// Disable any supported inverse flags.
inverseMask := uint8(linux.IPT_INV_DSTIP) | uint8(linux.IPT_INV_SRCIP) | uint8(linux.IPT_INV_VIA_OUT)
return iptip.InputInterface != emptyInterface ||
iptip.InputInterfaceMask != emptyInterface ||
iptip.Flags != 0 ||
iptip.InverseFlags&^inverseMask != 0
}
+37 -233
View File
@@ -17,7 +17,6 @@
package netfilter
import (
"bytes"
"errors"
"fmt"
@@ -26,8 +25,6 @@ import (
"gvisor.dev/gvisor/pkg/log"
"gvisor.dev/gvisor/pkg/sentry/kernel"
"gvisor.dev/gvisor/pkg/syserr"
"gvisor.dev/gvisor/pkg/tcpip"
"gvisor.dev/gvisor/pkg/tcpip/header"
"gvisor.dev/gvisor/pkg/tcpip/stack"
"gvisor.dev/gvisor/pkg/usermem"
)
@@ -37,15 +34,6 @@ import (
// developing iptables, but can pollute sentry logs otherwise.
const enableLogging = false
// emptyFilter is for comparison with a rule's filters to determine whether it
// is also empty. It is immutable.
var emptyFilter = stack.IPHeaderFilter{
Dst: "\x00\x00\x00\x00",
DstMask: "\x00\x00\x00\x00",
Src: "\x00\x00\x00\x00",
SrcMask: "\x00\x00\x00\x00",
}
// nflog logs messages related to the writing and reading of iptables.
func nflog(format string, args ...interface{}) {
if enableLogging && log.IsLogging(log.Debug) {
@@ -71,9 +59,9 @@ func GetInfo(t *kernel.Task, stack *stack.Stack, outPtr usermem.Addr) (linux.IPT
return info, nil
}
// GetEntries returns netstack's iptables rules encoded for the iptables tool.
func GetEntries(t *kernel.Task, stack *stack.Stack, outPtr usermem.Addr, outLen int) (linux.KernelIPTGetEntries, *syserr.Error) {
// Read in the struct and table name.
// GetEntries4 returns netstack's iptables rules encoded for the iptables tool.
func GetEntries4(t *kernel.Task, stack *stack.Stack, outPtr usermem.Addr, outLen int) (linux.KernelIPTGetEntries, *syserr.Error) {
// Read in the ABI struct.
var userEntries linux.IPTGetEntries
if _, err := userEntries.CopyIn(t, outPtr); err != nil {
nflog("couldn't copy in entries %q", userEntries.Name)
@@ -99,108 +87,48 @@ func GetEntries(t *kernel.Task, stack *stack.Stack, outPtr usermem.Addr, outLen
// format expected by the iptables tool. Linux stores each table as a binary
// blob that can only be traversed by parsing a bit, reading some offsets,
// jumping to those offsets, parsing again, etc.
func convertNetstackToBinary(stack *stack.Stack, tablename linux.TableName) (linux.KernelIPTGetEntries, linux.IPTGetinfo, error) {
table, ok := stack.IPTables().GetTable(tablename.String())
if !ok {
return linux.KernelIPTGetEntries{}, linux.IPTGetinfo{}, fmt.Errorf("couldn't find table %q", tablename)
}
var entries linux.KernelIPTGetEntries
var info linux.IPTGetinfo
info.ValidHooks = table.ValidHooks()
func convertNetstackToBinary(stk *stack.Stack, tablename linux.TableName) (linux.KernelIPTGetEntries, linux.IPTGetinfo, error) {
// The table name has to fit in the struct.
if linux.XT_TABLE_MAXNAMELEN < len(tablename) {
return linux.KernelIPTGetEntries{}, linux.IPTGetinfo{}, fmt.Errorf("table name %q too long", tablename)
}
copy(info.Name[:], tablename[:])
copy(entries.Name[:], tablename[:])
for ruleIdx, rule := range table.Rules {
nflog("convert to binary: current offset: %d", entries.Size)
// Is this a chain entry point?
for hook, hookRuleIdx := range table.BuiltinChains {
if hookRuleIdx == ruleIdx {
nflog("convert to binary: found hook %d at offset %d", hook, entries.Size)
info.HookEntry[hook] = entries.Size
}
}
// Is this a chain underflow point?
for underflow, underflowRuleIdx := range table.Underflows {
if underflowRuleIdx == ruleIdx {
nflog("convert to binary: found underflow %d at offset %d", underflow, entries.Size)
info.Underflow[underflow] = entries.Size
}
}
// Each rule corresponds to an entry.
entry := linux.KernelIPTEntry{
Entry: linux.IPTEntry{
IP: linux.IPTIP{
Protocol: uint16(rule.Filter.Protocol),
},
NextOffset: linux.SizeOfIPTEntry,
TargetOffset: linux.SizeOfIPTEntry,
},
}
copy(entry.Entry.IP.Dst[:], rule.Filter.Dst)
copy(entry.Entry.IP.DstMask[:], rule.Filter.DstMask)
copy(entry.Entry.IP.Src[:], rule.Filter.Src)
copy(entry.Entry.IP.SrcMask[:], rule.Filter.SrcMask)
copy(entry.Entry.IP.OutputInterface[:], rule.Filter.OutputInterface)
copy(entry.Entry.IP.OutputInterfaceMask[:], rule.Filter.OutputInterfaceMask)
if rule.Filter.DstInvert {
entry.Entry.IP.InverseFlags |= linux.IPT_INV_DSTIP
}
if rule.Filter.SrcInvert {
entry.Entry.IP.InverseFlags |= linux.IPT_INV_SRCIP
}
if rule.Filter.OutputInterfaceInvert {
entry.Entry.IP.InverseFlags |= linux.IPT_INV_VIA_OUT
}
for _, matcher := range rule.Matchers {
// Serialize the matcher and add it to the
// entry.
serialized := marshalMatcher(matcher)
nflog("convert to binary: matcher serialized as: %v", serialized)
if len(serialized)%8 != 0 {
panic(fmt.Sprintf("matcher %T is not 64-bit aligned", matcher))
}
entry.Elems = append(entry.Elems, serialized...)
entry.Entry.NextOffset += uint16(len(serialized))
entry.Entry.TargetOffset += uint16(len(serialized))
}
// Serialize and append the target.
serialized := marshalTarget(rule.Target)
if len(serialized)%8 != 0 {
panic(fmt.Sprintf("target %T is not 64-bit aligned", rule.Target))
}
entry.Elems = append(entry.Elems, serialized...)
entry.Entry.NextOffset += uint16(len(serialized))
nflog("convert to binary: adding entry: %+v", entry)
entries.Size += uint32(entry.Entry.NextOffset)
entries.Entrytable = append(entries.Entrytable, entry)
info.NumEntries++
table, ok := stk.IPTables().GetTable(tablename.String())
if !ok {
return linux.KernelIPTGetEntries{}, linux.IPTGetinfo{}, fmt.Errorf("couldn't find table %q", tablename)
}
nflog("convert to binary: finished with an marshalled size of %d", info.Size)
info.Size = entries.Size
// Setup the info struct.
var info linux.IPTGetinfo
info.ValidHooks = table.ValidHooks()
copy(info.Name[:], tablename[:])
entries := getEntries4(table, &info)
return entries, info, nil
}
// setHooksAndUnderflow checks whether the rule at ruleIdx is a hook entrypoint
// or underflow, in which case it fills in info.HookEntry and info.Underflows.
func setHooksAndUnderflow(info *linux.IPTGetinfo, table stack.Table, offset uint32, ruleIdx int) {
// Is this a chain entry point?
for hook, hookRuleIdx := range table.BuiltinChains {
if hookRuleIdx == ruleIdx {
nflog("convert to binary: found hook %d at offset %d", hook, offset)
info.HookEntry[hook] = offset
}
}
// Is this a chain underflow point?
for underflow, underflowRuleIdx := range table.Underflows {
if underflowRuleIdx == ruleIdx {
nflog("convert to binary: found underflow %d at offset %d", underflow, offset)
info.Underflow[underflow] = offset
}
}
}
// SetEntries sets iptables rules for a single table. See
// net/ipv4/netfilter/ip_tables.c:translate_table for reference.
func SetEntries(stk *stack.Stack, optVal []byte) *syserr.Error {
// Get the basic rules data (struct ipt_replace).
if len(optVal) < linux.SizeOfIPTReplace {
nflog("optVal has insufficient size for replace %d", len(optVal))
return syserr.ErrInvalidArgument
}
var replace linux.IPTReplace
replaceBuf := optVal[:linux.SizeOfIPTReplace]
optVal = optVal[linux.SizeOfIPTReplace:]
@@ -218,79 +146,9 @@ func SetEntries(stk *stack.Stack, optVal []byte) *syserr.Error {
return syserr.ErrInvalidArgument
}
nflog("set entries: setting entries in table %q", replace.Name.String())
// Convert input into a list of rules and their offsets.
var offset uint32
// offsets maps rule byte offsets to their position in table.Rules.
offsets := map[uint32]int{}
for entryIdx := uint32(0); entryIdx < replace.NumEntries; entryIdx++ {
nflog("set entries: processing entry at offset %d", offset)
// Get the struct ipt_entry.
if len(optVal) < linux.SizeOfIPTEntry {
nflog("optVal has insufficient size for entry %d", len(optVal))
return syserr.ErrInvalidArgument
}
var entry linux.IPTEntry
buf := optVal[:linux.SizeOfIPTEntry]
binary.Unmarshal(buf, usermem.ByteOrder, &entry)
initialOptValLen := len(optVal)
optVal = optVal[linux.SizeOfIPTEntry:]
if entry.TargetOffset < linux.SizeOfIPTEntry {
nflog("entry has too-small target offset %d", entry.TargetOffset)
return syserr.ErrInvalidArgument
}
// TODO(gvisor.dev/issue/170): We should support more IPTIP
// filtering fields.
filter, err := filterFromIPTIP(entry.IP)
if err != nil {
nflog("bad iptip: %v", err)
return syserr.ErrInvalidArgument
}
// TODO(gvisor.dev/issue/170): Matchers and targets can specify
// that they only work for certain protocols, hooks, tables.
// Get matchers.
matchersSize := entry.TargetOffset - linux.SizeOfIPTEntry
if len(optVal) < int(matchersSize) {
nflog("entry doesn't have enough room for its matchers (only %d bytes remain)", len(optVal))
return syserr.ErrInvalidArgument
}
matchers, err := parseMatchers(filter, optVal[:matchersSize])
if err != nil {
nflog("failed to parse matchers: %v", err)
return syserr.ErrInvalidArgument
}
optVal = optVal[matchersSize:]
// Get the target of the rule.
targetSize := entry.NextOffset - entry.TargetOffset
if len(optVal) < int(targetSize) {
nflog("entry doesn't have enough room for its target (only %d bytes remain)", len(optVal))
return syserr.ErrInvalidArgument
}
target, err := parseTarget(filter, optVal[:targetSize])
if err != nil {
nflog("failed to parse target: %v", err)
return syserr.ErrInvalidArgument
}
optVal = optVal[targetSize:]
table.Rules = append(table.Rules, stack.Rule{
Filter: filter,
Target: target,
Matchers: matchers,
})
offsets[offset] = int(entryIdx)
offset += uint32(entry.NextOffset)
if initialOptValLen-len(optVal) != int(entry.NextOffset) {
nflog("entry NextOffset is %d, but entry took up %d bytes", entry.NextOffset, initialOptValLen-len(optVal))
return syserr.ErrInvalidArgument
}
offsets, err := modifyEntries4(stk, optVal, &replace, &table)
if err != nil {
return err
}
// Go through the list of supported hooks for this table and, for each
@@ -323,7 +181,7 @@ func SetEntries(stk *stack.Stack, optVal []byte) *syserr.Error {
}
}
// Add the user chains.
// Check the user chains.
for ruleIdx, rule := range table.Rules {
if _, ok := rule.Target.(stack.UserChainTarget); !ok {
continue
@@ -404,7 +262,6 @@ func parseMatchers(filter stack.IPHeaderFilter, optVal []byte) ([]stack.Matcher,
// Check some invariants.
if match.MatchSize < linux.SizeOfXTEntryMatch {
return nil, fmt.Errorf("match size is too small, must be at least %d", linux.SizeOfXTEntryMatch)
}
if len(optVal) < int(match.MatchSize) {
@@ -429,64 +286,11 @@ func parseMatchers(filter stack.IPHeaderFilter, optVal []byte) ([]stack.Matcher,
return matchers, nil
}
func filterFromIPTIP(iptip linux.IPTIP) (stack.IPHeaderFilter, error) {
if containsUnsupportedFields(iptip) {
return stack.IPHeaderFilter{}, fmt.Errorf("unsupported fields in struct iptip: %+v", iptip)
}
if len(iptip.Dst) != header.IPv4AddressSize || len(iptip.DstMask) != header.IPv4AddressSize {
return stack.IPHeaderFilter{}, fmt.Errorf("incorrect length of destination (%d) and/or destination mask (%d) fields", len(iptip.Dst), len(iptip.DstMask))
}
if len(iptip.Src) != header.IPv4AddressSize || len(iptip.SrcMask) != header.IPv4AddressSize {
return stack.IPHeaderFilter{}, fmt.Errorf("incorrect length of source (%d) and/or source mask (%d) fields", len(iptip.Src), len(iptip.SrcMask))
}
n := bytes.IndexByte([]byte(iptip.OutputInterface[:]), 0)
if n == -1 {
n = len(iptip.OutputInterface)
}
ifname := string(iptip.OutputInterface[:n])
n = bytes.IndexByte([]byte(iptip.OutputInterfaceMask[:]), 0)
if n == -1 {
n = len(iptip.OutputInterfaceMask)
}
ifnameMask := string(iptip.OutputInterfaceMask[:n])
return stack.IPHeaderFilter{
Protocol: tcpip.TransportProtocolNumber(iptip.Protocol),
Dst: tcpip.Address(iptip.Dst[:]),
DstMask: tcpip.Address(iptip.DstMask[:]),
DstInvert: iptip.InverseFlags&linux.IPT_INV_DSTIP != 0,
Src: tcpip.Address(iptip.Src[:]),
SrcMask: tcpip.Address(iptip.SrcMask[:]),
SrcInvert: iptip.InverseFlags&linux.IPT_INV_SRCIP != 0,
OutputInterface: ifname,
OutputInterfaceMask: ifnameMask,
OutputInterfaceInvert: iptip.InverseFlags&linux.IPT_INV_VIA_OUT != 0,
}, nil
}
func containsUnsupportedFields(iptip linux.IPTIP) bool {
// The following features are supported:
// - Protocol
// - Dst and DstMask
// - Src and SrcMask
// - The inverse destination IP check flag
// - OutputInterface, OutputInterfaceMask and its inverse.
var emptyInterface = [linux.IFNAMSIZ]byte{}
// Disable any supported inverse flags.
inverseMask := uint8(linux.IPT_INV_DSTIP) | uint8(linux.IPT_INV_SRCIP) | uint8(linux.IPT_INV_VIA_OUT)
return iptip.InputInterface != emptyInterface ||
iptip.InputInterfaceMask != emptyInterface ||
iptip.Flags != 0 ||
iptip.InverseFlags&^inverseMask != 0
}
func validUnderflow(rule stack.Rule) bool {
if len(rule.Matchers) != 0 {
return false
}
if rule.Filter != emptyFilter {
if rule.Filter != emptyIPv4Filter {
return false
}
switch rule.Target.(type) {
+11 -2
View File
@@ -949,6 +949,9 @@ func (s *SocketOperations) GetSockOpt(t *kernel.Task, level, name int, outPtr us
if outLen < linux.SizeOfIPTGetinfo {
return nil, syserr.ErrInvalidArgument
}
if s.family != linux.AF_INET {
return nil, syserr.ErrInvalidArgument
}
stack := inet.StackFromContext(t)
if stack == nil {
@@ -964,12 +967,15 @@ func (s *SocketOperations) GetSockOpt(t *kernel.Task, level, name int, outPtr us
if outLen < linux.SizeOfIPTGetEntries {
return nil, syserr.ErrInvalidArgument
}
if s.family != linux.AF_INET {
return nil, syserr.ErrInvalidArgument
}
stack := inet.StackFromContext(t)
if stack == nil {
return nil, syserr.ErrNoDevice
}
entries, err := netfilter.GetEntries(t, stack.(*Stack).Stack, outPtr, outLen)
entries, err := netfilter.GetEntries4(t, stack.(*Stack).Stack, outPtr, outLen)
if err != nil {
return nil, err
}
@@ -1650,12 +1656,15 @@ func (s *SocketOperations) SetSockOpt(t *kernel.Task, level int, name int, optVa
return nil
}
if s.skType == linux.SOCK_RAW && level == linux.IPPROTO_IP {
if s.skType == linux.SOCK_RAW && level == linux.SOL_IP {
switch name {
case linux.IPT_SO_SET_REPLACE:
if len(optVal) < linux.SizeOfIPTReplace {
return syserr.ErrInvalidArgument
}
if s.family != linux.AF_INET {
return syserr.ErrInvalidArgument
}
stack := inet.StackFromContext(t)
if stack == nil {
+11 -2
View File
@@ -239,6 +239,9 @@ func (s *SocketVFS2) GetSockOpt(t *kernel.Task, level, name int, outPtr usermem.
if outLen < linux.SizeOfIPTGetinfo {
return nil, syserr.ErrInvalidArgument
}
if s.family != linux.AF_INET {
return nil, syserr.ErrInvalidArgument
}
stack := inet.StackFromContext(t)
if stack == nil {
@@ -254,12 +257,15 @@ func (s *SocketVFS2) GetSockOpt(t *kernel.Task, level, name int, outPtr usermem.
if outLen < linux.SizeOfIPTGetEntries {
return nil, syserr.ErrInvalidArgument
}
if s.family != linux.AF_INET {
return nil, syserr.ErrInvalidArgument
}
stack := inet.StackFromContext(t)
if stack == nil {
return nil, syserr.ErrNoDevice
}
entries, err := netfilter.GetEntries(t, stack.(*Stack).Stack, outPtr, outLen)
entries, err := netfilter.GetEntries4(t, stack.(*Stack).Stack, outPtr, outLen)
if err != nil {
return nil, err
}
@@ -298,12 +304,15 @@ func (s *SocketVFS2) SetSockOpt(t *kernel.Task, level int, name int, optVal []by
return nil
}
if s.skType == linux.SOCK_RAW && level == linux.IPPROTO_IP {
if s.skType == linux.SOCK_RAW && level == linux.SOL_IP {
switch name {
case linux.IPT_SO_SET_REPLACE:
if len(optVal) < linux.SizeOfIPTReplace {
return syserr.ErrInvalidArgument
}
if s.family != linux.AF_INET {
return syserr.ErrInvalidArgument
}
stack := inet.StackFromContext(t)
if stack == nil {
+2
View File
@@ -632,6 +632,8 @@ var sockOptNames = map[uint64]abi.ValueSet{
linux.IPV6_UNICAST_IF: "IPV6_UNICAST_IF",
linux.MCAST_MSFILTER: "MCAST_MSFILTER",
linux.IPV6_ADDRFORM: "IPV6_ADDRFORM",
linux.IP6T_SO_GET_INFO: "IP6T_SO_GET_INFO",
linux.IP6T_SO_GET_ENTRIES: "IP6T_SO_GET_ENTRIES",
},
linux.SOL_NETLINK: {
linux.NETLINK_BROADCAST_ERROR: "NETLINK_BROADCAST_ERROR",