We still use the packet.* alloc-free types in the data path, but the compilation from netaddr to packet happens within the filter package. Signed-off-by: David Anderson <danderson@tailscale.com>main
parent
7988f75b87
commit
b3634f020d
@ -0,0 +1,151 @@ |
||||
// Copyright (c) 2020 Tailscale Inc & AUTHORS All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package filter |
||||
|
||||
import ( |
||||
"fmt" |
||||
"math/bits" |
||||
"strings" |
||||
|
||||
"inet.af/netaddr" |
||||
"tailscale.com/net/packet" |
||||
) |
||||
|
||||
type net4 struct { |
||||
ip packet.IP4 |
||||
mask packet.IP4 |
||||
} |
||||
|
||||
func net4FromIPPrefix(pfx netaddr.IPPrefix) net4 { |
||||
if !pfx.IP.Is4() { |
||||
panic("net4FromIPPrefix given non-ipv4 prefix") |
||||
} |
||||
return net4{ |
||||
ip: packet.IP4FromNetaddr(pfx.IP), |
||||
mask: netmask4(pfx.Bits), |
||||
} |
||||
} |
||||
|
||||
func nets4FromIPPrefixes(pfxs []netaddr.IPPrefix) (ret []net4) { |
||||
for _, pfx := range pfxs { |
||||
if pfx.IP.Is4() { |
||||
ret = append(ret, net4FromIPPrefix(pfx)) |
||||
} |
||||
} |
||||
return ret |
||||
} |
||||
|
||||
func (n net4) Contains(ip packet.IP4) bool { |
||||
return (n.ip & n.mask) == (ip & n.mask) |
||||
} |
||||
|
||||
func (n net4) Bits() int { |
||||
return 32 - bits.TrailingZeros32(uint32(n.mask)) |
||||
} |
||||
|
||||
func (n net4) String() string { |
||||
b := n.Bits() |
||||
if b == 32 { |
||||
return n.ip.String() |
||||
} else if b == 0 { |
||||
return "*" |
||||
} else { |
||||
return fmt.Sprintf("%s/%d", n.ip, b) |
||||
} |
||||
} |
||||
|
||||
type npr4 struct { |
||||
net net4 |
||||
ports PortRange |
||||
} |
||||
|
||||
func (npr npr4) String() string { |
||||
return fmt.Sprintf("%s:%s", npr.net, npr.ports) |
||||
} |
||||
|
||||
type match4 struct { |
||||
dsts []npr4 |
||||
srcs []net4 |
||||
} |
||||
|
||||
type matches4 []match4 |
||||
|
||||
func (ms matches4) String() string { |
||||
var b strings.Builder |
||||
for _, m := range ms { |
||||
fmt.Fprintf(&b, "%s => %s\n", m.srcs, m.dsts) |
||||
} |
||||
return b.String() |
||||
} |
||||
|
||||
func newMatches4(ms Matches) (ret matches4) { |
||||
for _, m := range ms { |
||||
var m4 match4 |
||||
for _, src := range m.Srcs { |
||||
if src.IP.Is4() { |
||||
m4.srcs = append(m4.srcs, net4FromIPPrefix(src)) |
||||
} |
||||
} |
||||
for _, dst := range m.Dsts { |
||||
if dst.Net.IP.Is4() { |
||||
m4.dsts = append(m4.dsts, npr4{net4FromIPPrefix(dst.Net), dst.Ports}) |
||||
} |
||||
} |
||||
if len(m4.srcs) > 0 && len(m4.dsts) > 0 { |
||||
ret = append(ret, m4) |
||||
} |
||||
} |
||||
return ret |
||||
} |
||||
|
||||
// match returns whether q's source IP and destination IP:port match
|
||||
// any of ms.
|
||||
func (ms matches4) match(q *packet.ParsedPacket) bool { |
||||
for _, m := range ms { |
||||
if !ip4InList(q.SrcIP, m.srcs) { |
||||
continue |
||||
} |
||||
for _, dst := range m.dsts { |
||||
if !dst.net.Contains(q.DstIP) { |
||||
continue |
||||
} |
||||
if !dst.ports.contains(q.DstPort) { |
||||
continue |
||||
} |
||||
return true |
||||
} |
||||
} |
||||
return false |
||||
} |
||||
|
||||
// matchIPsOnly returns whether q's source and destination IP match
|
||||
// any of ms.
|
||||
func (ms matches4) matchIPsOnly(q *packet.ParsedPacket) bool { |
||||
for _, m := range ms { |
||||
if !ip4InList(q.SrcIP, m.srcs) { |
||||
continue |
||||
} |
||||
for _, dst := range m.dsts { |
||||
if dst.net.Contains(q.DstIP) { |
||||
return true |
||||
} |
||||
} |
||||
} |
||||
return false |
||||
} |
||||
|
||||
func netmask4(bits uint8) packet.IP4 { |
||||
b := ^uint32((1 << (32 - bits)) - 1) |
||||
return packet.IP4(b) |
||||
} |
||||
|
||||
func ip4InList(ip packet.IP4, netlist []net4) bool { |
||||
for _, net := range netlist { |
||||
if net.Contains(ip) { |
||||
return true |
||||
} |
||||
} |
||||
return false |
||||
} |
||||
Loading…
Reference in new issue