mirror of
https://github.com/tailscale/tailscale.git
synced 2024-11-29 21:15:39 +00:00
2d604b3791
For the operations we perform on these types (mostly net6.Contains), this encoding is much faster. Part of #19. name old time/op new time/op delta Filter/icmp4-8 27.5ns ± 1% 28.0ns ± 2% +1.89% (p=0.016 n=5+5) Filter/tcp4_syn_in-8 38.8ns ± 2% 38.3ns ± 1% -1.24% (p=0.024 n=5+5) Filter/tcp4_syn_out-8 27.6ns ±12% 24.6ns ± 1% ~ (p=0.063 n=5+5) Filter/udp4_in-8 71.5ns ± 5% 65.9ns ± 1% -7.94% (p=0.008 n=5+5) Filter/udp4_out-8 132ns ±13% 119ns ± 1% -10.29% (p=0.008 n=5+5) Filter/icmp6-8 169ns ±10% 54ns ± 1% -68.35% (p=0.008 n=5+5) Filter/tcp6_syn_in-8 149ns ± 6% 43ns ± 1% -71.11% (p=0.008 n=5+5) Filter/tcp6_syn_out-8 37.7ns ± 4% 24.3ns ± 3% -35.51% (p=0.008 n=5+5) Filter/udp6_in-8 179ns ± 5% 103ns ± 1% -42.75% (p=0.008 n=5+5) Filter/udp6_out-8 156ns ± 3% 191ns ± 1% +22.54% (p=0.008 n=5+5) Signed-off-by: David Anderson <danderson@tailscale.com>
152 lines
2.7 KiB
Go
152 lines
2.7 KiB
Go
// 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 net6 struct {
|
|
ip packet.IP6
|
|
mask packet.IP6
|
|
}
|
|
|
|
func net6FromIPPrefix(pfx netaddr.IPPrefix) net6 {
|
|
if !pfx.IP.Is6() {
|
|
panic("net6FromIPPrefix given non-ipv6 prefix")
|
|
}
|
|
var mask packet.IP6
|
|
if pfx.Bits > 64 {
|
|
mask.Hi = ^uint64(0)
|
|
mask.Lo = (^uint64(0) << (128 - pfx.Bits))
|
|
} else {
|
|
mask.Hi = (^uint64(0) << (64 - pfx.Bits))
|
|
}
|
|
|
|
return net6{
|
|
ip: packet.IP6FromNetaddr(pfx.IP),
|
|
mask: mask,
|
|
}
|
|
}
|
|
|
|
func nets6FromIPPrefixes(pfxs []netaddr.IPPrefix) (ret []net6) {
|
|
for _, pfx := range pfxs {
|
|
if pfx.IP.Is6() {
|
|
ret = append(ret, net6FromIPPrefix(pfx))
|
|
}
|
|
}
|
|
return ret
|
|
}
|
|
|
|
func (n net6) Contains(ip packet.IP6) bool {
|
|
return ((n.ip.Hi&n.mask.Hi) == (ip.Hi&n.mask.Hi) &&
|
|
(n.ip.Lo&n.mask.Lo) == (ip.Lo&n.mask.Lo))
|
|
}
|
|
|
|
func (n net6) Bits() int {
|
|
return 128 - bits.TrailingZeros64(n.mask.Hi) - bits.TrailingZeros64(n.mask.Lo)
|
|
}
|
|
|
|
func (n net6) String() string {
|
|
switch n.Bits() {
|
|
case 128:
|
|
return n.ip.String()
|
|
case 0:
|
|
return "*"
|
|
default:
|
|
return fmt.Sprintf("%s/%d", n.ip, n.Bits())
|
|
}
|
|
}
|
|
|
|
type npr6 struct {
|
|
net net6
|
|
ports PortRange
|
|
}
|
|
|
|
func (npr npr6) String() string {
|
|
return fmt.Sprintf("%s:%s", npr.net, npr.ports)
|
|
}
|
|
|
|
type match6 struct {
|
|
srcs []net6
|
|
dsts []npr6
|
|
}
|
|
|
|
type matches6 []match6
|
|
|
|
func (ms matches6) String() string {
|
|
var b strings.Builder
|
|
for _, m := range ms {
|
|
fmt.Fprintf(&b, "%s => %s\n", m.srcs, m.dsts)
|
|
}
|
|
return b.String()
|
|
}
|
|
|
|
func newMatches6(ms []Match) (ret matches6) {
|
|
for _, m := range ms {
|
|
var m6 match6
|
|
for _, src := range m.Srcs {
|
|
if src.IP.Is6() {
|
|
m6.srcs = append(m6.srcs, net6FromIPPrefix(src))
|
|
}
|
|
}
|
|
for _, dst := range m.Dsts {
|
|
if dst.Net.IP.Is6() {
|
|
m6.dsts = append(m6.dsts, npr6{net6FromIPPrefix(dst.Net), dst.Ports})
|
|
}
|
|
}
|
|
if len(m6.srcs) > 0 && len(m6.dsts) > 0 {
|
|
ret = append(ret, m6)
|
|
}
|
|
}
|
|
return ret
|
|
}
|
|
|
|
func (ms matches6) match(q *packet.Parsed) bool {
|
|
for _, m := range ms {
|
|
if !ip6InList(q.SrcIP6, m.srcs) {
|
|
continue
|
|
}
|
|
for _, dst := range m.dsts {
|
|
if !dst.net.Contains(q.DstIP6) {
|
|
continue
|
|
}
|
|
if !dst.ports.contains(q.DstPort) {
|
|
continue
|
|
}
|
|
return true
|
|
}
|
|
}
|
|
return false
|
|
}
|
|
|
|
func (ms matches6) matchIPsOnly(q *packet.Parsed) bool {
|
|
for _, m := range ms {
|
|
if !ip6InList(q.SrcIP6, m.srcs) {
|
|
continue
|
|
}
|
|
for _, dst := range m.dsts {
|
|
if dst.net.Contains(q.DstIP6) {
|
|
return true
|
|
}
|
|
}
|
|
}
|
|
return false
|
|
}
|
|
|
|
func ip6InList(ip packet.IP6, netlist []net6) bool {
|
|
for _, net := range netlist {
|
|
if net.Contains(ip) {
|
|
return true
|
|
}
|
|
}
|
|
return false
|
|
}
|