mirror of https://github.com/tailscale/tailscale/
wgengine/filter: use netaddr types in public API.
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>pull/910/head
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