|  | 
|  | 1 | +// Copyright 2020 The gVisor Authors. | 
|  | 2 | +// | 
|  | 3 | +// Licensed under the Apache License, Version 2.0 (the "License"); | 
|  | 4 | +// you may not use this file except in compliance with the License. | 
|  | 5 | +// You may obtain a copy of the License at | 
|  | 6 | +// | 
|  | 7 | +//     http://www.apache.org/licenses/LICENSE-2.0 | 
|  | 8 | +// | 
|  | 9 | +// Unless required by applicable law or agreed to in writing, software | 
|  | 10 | +// distributed under the License is distributed on an "AS IS" BASIS, | 
|  | 11 | +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | 
|  | 12 | +// See the License for the specific language governing permissions and | 
|  | 13 | +// limitations under the License. | 
|  | 14 | + | 
|  | 15 | +package netfilter | 
|  | 16 | + | 
|  | 17 | +import ( | 
|  | 18 | +	"fmt" | 
|  | 19 | + | 
|  | 20 | +	"gvisor.dev/gvisor/pkg/abi/linux" | 
|  | 21 | +	"gvisor.dev/gvisor/pkg/binary" | 
|  | 22 | +	"gvisor.dev/gvisor/pkg/tcpip/iptables" | 
|  | 23 | +	"gvisor.dev/gvisor/pkg/usermem" | 
|  | 24 | +) | 
|  | 25 | + | 
|  | 26 | +// TODO(gvisor.dev/issue/170): The following per-matcher params should be | 
|  | 27 | +// supported: | 
|  | 28 | +// - Table name | 
|  | 29 | +// - Match size | 
|  | 30 | +// - User size | 
|  | 31 | +// - Hooks | 
|  | 32 | +// - Proto | 
|  | 33 | +// - Family | 
|  | 34 | + | 
|  | 35 | +// matchMaker knows how to (un)marshal the matcher named name(). | 
|  | 36 | +type matchMaker interface { | 
|  | 37 | +	// name is the matcher name as stored in the xt_entry_match struct. | 
|  | 38 | +	name() string | 
|  | 39 | + | 
|  | 40 | +	// marshal converts from an iptables.Matcher to an ABI struct. | 
|  | 41 | +	marshal(matcher iptables.Matcher) []byte | 
|  | 42 | + | 
|  | 43 | +	// unmarshal converts from the ABI matcher struct to an | 
|  | 44 | +	// iptables.Matcher. | 
|  | 45 | +	unmarshal(buf []byte, filter iptables.IPHeaderFilter) (iptables.Matcher, error) | 
|  | 46 | +} | 
|  | 47 | + | 
|  | 48 | +// matchMakers maps the name of supported matchers to the matchMaker that | 
|  | 49 | +// marshals and unmarshals it. It is immutable after package initialization. | 
|  | 50 | +var matchMakers = map[string]matchMaker{} | 
|  | 51 | + | 
|  | 52 | +// registermatchMaker should be called by match extensions to register them | 
|  | 53 | +// with the netfilter package. | 
|  | 54 | +func registerMatchMaker(mm matchMaker) { | 
|  | 55 | +	if _, ok := matchMakers[mm.name()]; ok { | 
|  | 56 | +		panic(fmt.Sprintf("Multiple matches registered with name %q.", mm.name())) | 
|  | 57 | +	} | 
|  | 58 | +	matchMakers[mm.name()] = mm | 
|  | 59 | +} | 
|  | 60 | + | 
|  | 61 | +func marshalMatcher(matcher iptables.Matcher) []byte { | 
|  | 62 | +	matchMaker, ok := matchMakers[matcher.Name()] | 
|  | 63 | +	if !ok { | 
|  | 64 | +		panic(fmt.Sprintf("Unknown matcher of type %T.", matcher)) | 
|  | 65 | +	} | 
|  | 66 | +	return matchMaker.marshal(matcher) | 
|  | 67 | +} | 
|  | 68 | + | 
|  | 69 | +// marshalEntryMatch creates a marshalled XTEntryMatch with the given name and | 
|  | 70 | +// data appended at the end. | 
|  | 71 | +func marshalEntryMatch(name string, data []byte) []byte { | 
|  | 72 | +	nflog("marshaling matcher %q", name) | 
|  | 73 | + | 
|  | 74 | +	// We have to pad this struct size to a multiple of 8 bytes. | 
|  | 75 | +	size := alignUp(linux.SizeOfXTEntryMatch+len(data), 8) | 
|  | 76 | +	matcher := linux.KernelXTEntryMatch{ | 
|  | 77 | +		XTEntryMatch: linux.XTEntryMatch{ | 
|  | 78 | +			MatchSize: uint16(size), | 
|  | 79 | +		}, | 
|  | 80 | +		Data: data, | 
|  | 81 | +	} | 
|  | 82 | +	copy(matcher.Name[:], name) | 
|  | 83 | + | 
|  | 84 | +	buf := make([]byte, 0, size) | 
|  | 85 | +	buf = binary.Marshal(buf, usermem.ByteOrder, matcher) | 
|  | 86 | +	return append(buf, make([]byte, size-len(buf))...) | 
|  | 87 | +} | 
|  | 88 | + | 
|  | 89 | +func unmarshalMatcher(match linux.XTEntryMatch, filter iptables.IPHeaderFilter, buf []byte) (iptables.Matcher, error) { | 
|  | 90 | +	matchMaker, ok := matchMakers[match.Name.String()] | 
|  | 91 | +	if !ok { | 
|  | 92 | +		return nil, fmt.Errorf("unsupported matcher with name %q", match.Name.String()) | 
|  | 93 | +	} | 
|  | 94 | +	return matchMaker.unmarshal(buf, filter) | 
|  | 95 | +} | 
|  | 96 | + | 
|  | 97 | +// alignUp rounds a length up to an alignment. align must be a power of 2. | 
|  | 98 | +func alignUp(length int, align uint) int { | 
|  | 99 | +	return (length + int(align) - 1) & ^(int(align) - 1) | 
|  | 100 | +} | 
0 commit comments