mirror of
https://github.com/tailscale/tailscale.git
synced 2025-02-20 11:58:39 +00:00
net/packet: implement methods for rewriting v6 addresses
Implements the ability for the address-rewriting code to support rewriting IPv6 addresses. Specifically, UpdateSrcAddr & UpdateDstAddr. Signed-off-by: Tom DNetto <tom@tailscale.com> Updates https://github.com/tailscale/corp/issues/11202
This commit is contained in:
parent
c26d91d6bd
commit
656a77ab4e
@ -17,6 +17,7 @@ tailscale.com/cmd/derper dependencies: (generated by github.com/tailscale/depawa
|
|||||||
github.com/fxamacker/cbor/v2 from tailscale.com/tka
|
github.com/fxamacker/cbor/v2 from tailscale.com/tka
|
||||||
github.com/golang/groupcache/lru from tailscale.com/net/dnscache
|
github.com/golang/groupcache/lru from tailscale.com/net/dnscache
|
||||||
github.com/golang/protobuf/proto from github.com/matttproud/golang_protobuf_extensions/pbutil
|
github.com/golang/protobuf/proto from github.com/matttproud/golang_protobuf_extensions/pbutil
|
||||||
|
github.com/google/btree from gvisor.dev/gvisor/pkg/tcpip/header
|
||||||
L github.com/google/nftables from tailscale.com/util/linuxfw
|
L github.com/google/nftables from tailscale.com/util/linuxfw
|
||||||
L 💣 github.com/google/nftables/alignedbuff from github.com/google/nftables/xt
|
L 💣 github.com/google/nftables/alignedbuff from github.com/google/nftables/xt
|
||||||
L 💣 github.com/google/nftables/binaryutil from github.com/google/nftables+
|
L 💣 github.com/google/nftables/binaryutil from github.com/google/nftables+
|
||||||
@ -78,6 +79,22 @@ tailscale.com/cmd/derper dependencies: (generated by github.com/tailscale/depawa
|
|||||||
google.golang.org/protobuf/runtime/protoimpl from github.com/golang/protobuf/proto+
|
google.golang.org/protobuf/runtime/protoimpl from github.com/golang/protobuf/proto+
|
||||||
google.golang.org/protobuf/types/descriptorpb from google.golang.org/protobuf/reflect/protodesc
|
google.golang.org/protobuf/types/descriptorpb from google.golang.org/protobuf/reflect/protodesc
|
||||||
google.golang.org/protobuf/types/known/timestamppb from github.com/prometheus/client_golang/prometheus+
|
google.golang.org/protobuf/types/known/timestamppb from github.com/prometheus/client_golang/prometheus+
|
||||||
|
gvisor.dev/gvisor/pkg/atomicbitops from gvisor.dev/gvisor/pkg/buffer+
|
||||||
|
gvisor.dev/gvisor/pkg/bits from gvisor.dev/gvisor/pkg/buffer
|
||||||
|
💣 gvisor.dev/gvisor/pkg/buffer from gvisor.dev/gvisor/pkg/tcpip+
|
||||||
|
gvisor.dev/gvisor/pkg/context from gvisor.dev/gvisor/pkg/refs
|
||||||
|
💣 gvisor.dev/gvisor/pkg/gohacks from gvisor.dev/gvisor/pkg/state/wire+
|
||||||
|
gvisor.dev/gvisor/pkg/linewriter from gvisor.dev/gvisor/pkg/log
|
||||||
|
gvisor.dev/gvisor/pkg/log from gvisor.dev/gvisor/pkg/context+
|
||||||
|
gvisor.dev/gvisor/pkg/refs from gvisor.dev/gvisor/pkg/buffer
|
||||||
|
💣 gvisor.dev/gvisor/pkg/state from gvisor.dev/gvisor/pkg/atomicbitops+
|
||||||
|
gvisor.dev/gvisor/pkg/state/wire from gvisor.dev/gvisor/pkg/state
|
||||||
|
💣 gvisor.dev/gvisor/pkg/sync from gvisor.dev/gvisor/pkg/atomicbitops+
|
||||||
|
gvisor.dev/gvisor/pkg/tcpip from gvisor.dev/gvisor/pkg/tcpip/header+
|
||||||
|
gvisor.dev/gvisor/pkg/tcpip/checksum from gvisor.dev/gvisor/pkg/buffer+
|
||||||
|
gvisor.dev/gvisor/pkg/tcpip/header from tailscale.com/net/packet
|
||||||
|
gvisor.dev/gvisor/pkg/tcpip/seqnum from gvisor.dev/gvisor/pkg/tcpip/header
|
||||||
|
gvisor.dev/gvisor/pkg/waiter from gvisor.dev/gvisor/pkg/context+
|
||||||
nhooyr.io/websocket from tailscale.com/cmd/derper+
|
nhooyr.io/websocket from tailscale.com/cmd/derper+
|
||||||
nhooyr.io/websocket/internal/errd from nhooyr.io/websocket
|
nhooyr.io/websocket/internal/errd from nhooyr.io/websocket
|
||||||
nhooyr.io/websocket/internal/xsync from nhooyr.io/websocket
|
nhooyr.io/websocket/internal/xsync from nhooyr.io/websocket
|
||||||
|
@ -17,6 +17,7 @@ tailscale.com/cmd/tailscale dependencies: (generated by github.com/tailscale/dep
|
|||||||
github.com/fxamacker/cbor/v2 from tailscale.com/tka
|
github.com/fxamacker/cbor/v2 from tailscale.com/tka
|
||||||
L 💣 github.com/godbus/dbus/v5 from github.com/coreos/go-systemd/v22/dbus
|
L 💣 github.com/godbus/dbus/v5 from github.com/coreos/go-systemd/v22/dbus
|
||||||
github.com/golang/groupcache/lru from tailscale.com/net/dnscache
|
github.com/golang/groupcache/lru from tailscale.com/net/dnscache
|
||||||
|
github.com/google/btree from gvisor.dev/gvisor/pkg/tcpip/header
|
||||||
L github.com/google/nftables from tailscale.com/util/linuxfw
|
L github.com/google/nftables from tailscale.com/util/linuxfw
|
||||||
L 💣 github.com/google/nftables/alignedbuff from github.com/google/nftables/xt
|
L 💣 github.com/google/nftables/alignedbuff from github.com/google/nftables/xt
|
||||||
L 💣 github.com/google/nftables/binaryutil from github.com/google/nftables+
|
L 💣 github.com/google/nftables/binaryutil from github.com/google/nftables+
|
||||||
@ -64,6 +65,22 @@ tailscale.com/cmd/tailscale dependencies: (generated by github.com/tailscale/dep
|
|||||||
go4.org/netipx from tailscale.com/wgengine/filter+
|
go4.org/netipx from tailscale.com/wgengine/filter+
|
||||||
W 💣 golang.zx2c4.com/wireguard/windows/tunnel/winipcfg from tailscale.com/net/interfaces+
|
W 💣 golang.zx2c4.com/wireguard/windows/tunnel/winipcfg from tailscale.com/net/interfaces+
|
||||||
gopkg.in/yaml.v2 from sigs.k8s.io/yaml
|
gopkg.in/yaml.v2 from sigs.k8s.io/yaml
|
||||||
|
gvisor.dev/gvisor/pkg/atomicbitops from gvisor.dev/gvisor/pkg/buffer+
|
||||||
|
gvisor.dev/gvisor/pkg/bits from gvisor.dev/gvisor/pkg/buffer
|
||||||
|
💣 gvisor.dev/gvisor/pkg/buffer from gvisor.dev/gvisor/pkg/tcpip+
|
||||||
|
gvisor.dev/gvisor/pkg/context from gvisor.dev/gvisor/pkg/refs
|
||||||
|
💣 gvisor.dev/gvisor/pkg/gohacks from gvisor.dev/gvisor/pkg/state/wire+
|
||||||
|
gvisor.dev/gvisor/pkg/linewriter from gvisor.dev/gvisor/pkg/log
|
||||||
|
gvisor.dev/gvisor/pkg/log from gvisor.dev/gvisor/pkg/context+
|
||||||
|
gvisor.dev/gvisor/pkg/refs from gvisor.dev/gvisor/pkg/buffer
|
||||||
|
💣 gvisor.dev/gvisor/pkg/state from gvisor.dev/gvisor/pkg/atomicbitops+
|
||||||
|
gvisor.dev/gvisor/pkg/state/wire from gvisor.dev/gvisor/pkg/state
|
||||||
|
💣 gvisor.dev/gvisor/pkg/sync from gvisor.dev/gvisor/pkg/atomicbitops+
|
||||||
|
gvisor.dev/gvisor/pkg/tcpip from gvisor.dev/gvisor/pkg/tcpip/header+
|
||||||
|
gvisor.dev/gvisor/pkg/tcpip/checksum from gvisor.dev/gvisor/pkg/buffer+
|
||||||
|
gvisor.dev/gvisor/pkg/tcpip/header from tailscale.com/net/packet
|
||||||
|
gvisor.dev/gvisor/pkg/tcpip/seqnum from gvisor.dev/gvisor/pkg/tcpip/header
|
||||||
|
gvisor.dev/gvisor/pkg/waiter from gvisor.dev/gvisor/pkg/context+
|
||||||
k8s.io/client-go/util/homedir from tailscale.com/cmd/tailscale/cli
|
k8s.io/client-go/util/homedir from tailscale.com/cmd/tailscale/cli
|
||||||
nhooyr.io/websocket from tailscale.com/derp/derphttp+
|
nhooyr.io/websocket from tailscale.com/derp/derphttp+
|
||||||
nhooyr.io/websocket/internal/errd from nhooyr.io/websocket
|
nhooyr.io/websocket/internal/errd from nhooyr.io/websocket
|
||||||
|
@ -238,13 +238,13 @@ tailscale.com/cmd/tailscaled dependencies: (generated by github.com/tailscale/de
|
|||||||
tailscale.com/health/healthmsg from tailscale.com/ipn/ipnlocal
|
tailscale.com/health/healthmsg from tailscale.com/ipn/ipnlocal
|
||||||
tailscale.com/hostinfo from tailscale.com/control/controlclient+
|
tailscale.com/hostinfo from tailscale.com/control/controlclient+
|
||||||
tailscale.com/ipn from tailscale.com/ipn/ipnlocal+
|
tailscale.com/ipn from tailscale.com/ipn/ipnlocal+
|
||||||
💣 tailscale.com/ipn/ipnauth from tailscale.com/ipn/ipnserver+
|
💣 tailscale.com/ipn/ipnauth from tailscale.com/ipn/ipnlocal+
|
||||||
tailscale.com/ipn/ipnlocal from tailscale.com/ssh/tailssh+
|
tailscale.com/ipn/ipnlocal from tailscale.com/ssh/tailssh+
|
||||||
tailscale.com/ipn/ipnserver from tailscale.com/cmd/tailscaled
|
tailscale.com/ipn/ipnserver from tailscale.com/cmd/tailscaled
|
||||||
tailscale.com/ipn/ipnstate from tailscale.com/control/controlclient+
|
tailscale.com/ipn/ipnstate from tailscale.com/control/controlclient+
|
||||||
tailscale.com/ipn/localapi from tailscale.com/ipn/ipnserver
|
tailscale.com/ipn/localapi from tailscale.com/ipn/ipnserver
|
||||||
tailscale.com/ipn/policy from tailscale.com/ipn/ipnlocal
|
tailscale.com/ipn/policy from tailscale.com/ipn/ipnlocal
|
||||||
tailscale.com/ipn/store from tailscale.com/cmd/tailscaled+
|
tailscale.com/ipn/store from tailscale.com/ipn/ipnlocal+
|
||||||
L tailscale.com/ipn/store/awsstore from tailscale.com/ipn/store
|
L tailscale.com/ipn/store/awsstore from tailscale.com/ipn/store
|
||||||
L tailscale.com/ipn/store/kubestore from tailscale.com/ipn/store
|
L tailscale.com/ipn/store/kubestore from tailscale.com/ipn/store
|
||||||
tailscale.com/ipn/store/mem from tailscale.com/ipn/store+
|
tailscale.com/ipn/store/mem from tailscale.com/ipn/store+
|
||||||
@ -347,7 +347,7 @@ tailscale.com/cmd/tailscaled dependencies: (generated by github.com/tailscale/de
|
|||||||
tailscale.com/util/osshare from tailscale.com/ipn/ipnlocal+
|
tailscale.com/util/osshare from tailscale.com/ipn/ipnlocal+
|
||||||
W tailscale.com/util/pidowner from tailscale.com/ipn/ipnauth
|
W tailscale.com/util/pidowner from tailscale.com/ipn/ipnauth
|
||||||
tailscale.com/util/racebuild from tailscale.com/logpolicy
|
tailscale.com/util/racebuild from tailscale.com/logpolicy
|
||||||
tailscale.com/util/rands from tailscale.com/ipn/localapi+
|
tailscale.com/util/rands from tailscale.com/ipn/ipnlocal+
|
||||||
tailscale.com/util/ringbuffer from tailscale.com/wgengine/magicsock
|
tailscale.com/util/ringbuffer from tailscale.com/wgengine/magicsock
|
||||||
tailscale.com/util/set from tailscale.com/health+
|
tailscale.com/util/set from tailscale.com/health+
|
||||||
tailscale.com/util/singleflight from tailscale.com/control/controlclient+
|
tailscale.com/util/singleflight from tailscale.com/control/controlclient+
|
||||||
@ -508,7 +508,7 @@ tailscale.com/cmd/tailscaled dependencies: (generated by github.com/tailscale/de
|
|||||||
regexp from github.com/coreos/go-iptables/iptables+
|
regexp from github.com/coreos/go-iptables/iptables+
|
||||||
regexp/syntax from regexp
|
regexp/syntax from regexp
|
||||||
runtime/debug from github.com/klauspost/compress/zstd+
|
runtime/debug from github.com/klauspost/compress/zstd+
|
||||||
runtime/pprof from net/http/pprof+
|
runtime/pprof from tailscale.com/ipn/ipnlocal+
|
||||||
runtime/trace from net/http/pprof
|
runtime/trace from net/http/pprof
|
||||||
slices from tailscale.com/wgengine/magicsock+
|
slices from tailscale.com/wgengine/magicsock+
|
||||||
sort from compress/flate+
|
sort from compress/flate+
|
||||||
|
@ -10,6 +10,8 @@ import (
|
|||||||
"net/netip"
|
"net/netip"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
|
"gvisor.dev/gvisor/pkg/tcpip"
|
||||||
|
"gvisor.dev/gvisor/pkg/tcpip/header"
|
||||||
"tailscale.com/net/netaddr"
|
"tailscale.com/net/netaddr"
|
||||||
"tailscale.com/types/ipproto"
|
"tailscale.com/types/ipproto"
|
||||||
)
|
)
|
||||||
@ -453,11 +455,14 @@ func (q *Parsed) IsEchoResponse() bool {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// UpdateSrcAddr updates the source address in the packet buffer (e.g. during
|
// UpdateSrcAddr updates the source address in the packet buffer (e.g. during
|
||||||
// SNAT). It also updates the checksum. Currently (2022-12-10) only TCP/UDP/ICMP
|
// SNAT). It also updates the checksum. Currently (2023-09-22) only TCP/UDP/ICMP
|
||||||
// over IPv4 is supported. It panics if called with IPv6 addr.
|
// is supported. It panics if provided with an address in a different
|
||||||
|
// family to the parsed packet.
|
||||||
func (q *Parsed) UpdateSrcAddr(src netip.Addr) {
|
func (q *Parsed) UpdateSrcAddr(src netip.Addr) {
|
||||||
if q.IPVersion != 4 || src.Is6() {
|
if src.Is6() && q.IPVersion != 6 {
|
||||||
panic("UpdateSrcAddr: only IPv4 is supported")
|
panic("UpdateSrcAddr: cannot write IPv6 address to v4 packet")
|
||||||
|
} else if src.Is4() && q.IPVersion != 4 {
|
||||||
|
panic("UpdateSrcAddr: cannot write IPv4 address to v6 packet")
|
||||||
}
|
}
|
||||||
q.CaptureMeta.DidSNAT = true
|
q.CaptureMeta.DidSNAT = true
|
||||||
q.CaptureMeta.OriginalSrc = q.Src
|
q.CaptureMeta.OriginalSrc = q.Src
|
||||||
@ -466,19 +471,27 @@ func (q *Parsed) UpdateSrcAddr(src netip.Addr) {
|
|||||||
q.Src = netip.AddrPortFrom(src, q.Src.Port())
|
q.Src = netip.AddrPortFrom(src, q.Src.Port())
|
||||||
|
|
||||||
b := q.Buffer()
|
b := q.Buffer()
|
||||||
v4 := src.As4()
|
if src.Is6() {
|
||||||
copy(b[12:16], v4[:])
|
v6 := src.As16()
|
||||||
updateV4PacketChecksums(q, old, src)
|
copy(b[8:24], v6[:])
|
||||||
|
updateV6PacketChecksums(q, old, src)
|
||||||
|
} else {
|
||||||
|
v4 := src.As4()
|
||||||
|
copy(b[12:16], v4[:])
|
||||||
|
updateV4PacketChecksums(q, old, src)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// UpdateDstAddr updates the source address in the packet buffer (e.g. during
|
// UpdateDstAddr updates the destination address in the packet buffer (e.g. during
|
||||||
// DNAT). It also updates the checksum. Currently (2022-12-10) only TCP/UDP/ICMP
|
// DNAT). It also updates the checksum. Currently (2022-12-10) only TCP/UDP/ICMP
|
||||||
// over IPv4 is supported. It panics if called with IPv6 addr.
|
// is supported. It panics if provided with an address in a different
|
||||||
|
// family to the parsed packet.
|
||||||
func (q *Parsed) UpdateDstAddr(dst netip.Addr) {
|
func (q *Parsed) UpdateDstAddr(dst netip.Addr) {
|
||||||
if q.IPVersion != 4 || dst.Is6() {
|
if dst.Is6() && q.IPVersion != 6 {
|
||||||
panic("UpdateDstAddr: only IPv4 is supported")
|
panic("UpdateDstAddr: cannot write IPv6 address to v4 packet")
|
||||||
|
} else if dst.Is4() && q.IPVersion != 4 {
|
||||||
|
panic("UpdateDstAddr: cannot write IPv4 address to v6 packet")
|
||||||
}
|
}
|
||||||
|
|
||||||
q.CaptureMeta.DidDNAT = true
|
q.CaptureMeta.DidDNAT = true
|
||||||
q.CaptureMeta.OriginalDst = q.Dst
|
q.CaptureMeta.OriginalDst = q.Dst
|
||||||
|
|
||||||
@ -486,9 +499,15 @@ func (q *Parsed) UpdateDstAddr(dst netip.Addr) {
|
|||||||
q.Dst = netip.AddrPortFrom(dst, q.Dst.Port())
|
q.Dst = netip.AddrPortFrom(dst, q.Dst.Port())
|
||||||
|
|
||||||
b := q.Buffer()
|
b := q.Buffer()
|
||||||
v4 := dst.As4()
|
if dst.Is6() {
|
||||||
copy(b[16:20], v4[:])
|
v6 := dst.As16()
|
||||||
updateV4PacketChecksums(q, old, dst)
|
copy(b[24:36], v6[:])
|
||||||
|
updateV6PacketChecksums(q, old, dst)
|
||||||
|
} else {
|
||||||
|
v4 := dst.As4()
|
||||||
|
copy(b[16:20], v4[:])
|
||||||
|
updateV4PacketChecksums(q, old, dst)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// EchoIDSeq extracts the identifier/sequence bytes from an ICMP Echo response,
|
// EchoIDSeq extracts the identifier/sequence bytes from an ICMP Echo response,
|
||||||
@ -572,13 +591,13 @@ func updateV4PacketChecksums(p *Parsed, old, new netip.Addr) {
|
|||||||
tr := p.Transport()
|
tr := p.Transport()
|
||||||
switch p.IPProto {
|
switch p.IPProto {
|
||||||
case ipproto.UDP, ipproto.DCCP:
|
case ipproto.UDP, ipproto.DCCP:
|
||||||
if len(tr) < 8 {
|
if len(tr) < header.UDPMinimumSize {
|
||||||
// Not enough space for a UDP header.
|
// Not enough space for a UDP header.
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
updateV4Checksum(tr[6:8], o4[:], n4[:])
|
updateV4Checksum(tr[6:8], o4[:], n4[:])
|
||||||
case ipproto.TCP:
|
case ipproto.TCP:
|
||||||
if len(tr) < 18 {
|
if len(tr) < header.TCPMinimumSize {
|
||||||
// Not enough space for a TCP header.
|
// Not enough space for a TCP header.
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@ -596,6 +615,39 @@ func updateV4PacketChecksums(p *Parsed, old, new netip.Addr) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// updateV6PacketChecksums updates the checksums in the packet buffer.
|
||||||
|
// p is modified in place.
|
||||||
|
// If p.IPProto is unknown, no checksums are updated.
|
||||||
|
func updateV6PacketChecksums(p *Parsed, old, new netip.Addr) {
|
||||||
|
if len(p.Buffer()) < 40 {
|
||||||
|
// Not enough space for an IPv6 header.
|
||||||
|
return
|
||||||
|
}
|
||||||
|
o6, n6 := tcpip.AddrFrom16Slice(old.AsSlice()), tcpip.AddrFrom16Slice(new.AsSlice())
|
||||||
|
|
||||||
|
// Now update the transport layer checksums, where applicable.
|
||||||
|
tr := p.Transport()
|
||||||
|
switch p.IPProto {
|
||||||
|
case ipproto.ICMPv6:
|
||||||
|
if len(tr) < header.ICMPv6MinimumSize {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
header.ICMPv6(tr).UpdateChecksumPseudoHeaderAddress(o6, n6)
|
||||||
|
case ipproto.UDP, ipproto.DCCP:
|
||||||
|
if len(tr) < header.UDPMinimumSize {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
header.UDP(tr).UpdateChecksumPseudoHeaderAddress(o6, n6, true)
|
||||||
|
case ipproto.TCP:
|
||||||
|
if len(tr) < header.TCPMinimumSize {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
header.TCP(tr).UpdateChecksumPseudoHeaderAddress(o6, n6, true)
|
||||||
|
case ipproto.SCTP:
|
||||||
|
// No transport layer update required.
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// updateV4Checksum calculates and updates the checksum in the packet buffer for
|
// updateV4Checksum calculates and updates the checksum in the packet buffer for
|
||||||
// a change between old and new. The oldSum must point to the 16-bit checksum
|
// a change between old and new. The oldSum must point to the 16-bit checksum
|
||||||
// field in the packet buffer that holds the old checksum value, it will be
|
// field in the packet buffer that holds the old checksum value, it will be
|
||||||
|
@ -13,6 +13,9 @@ import (
|
|||||||
"testing"
|
"testing"
|
||||||
"unicode"
|
"unicode"
|
||||||
|
|
||||||
|
"gvisor.dev/gvisor/pkg/tcpip"
|
||||||
|
"gvisor.dev/gvisor/pkg/tcpip/checksum"
|
||||||
|
"gvisor.dev/gvisor/pkg/tcpip/header"
|
||||||
"tailscale.com/tstest"
|
"tailscale.com/tstest"
|
||||||
"tailscale.com/types/ipproto"
|
"tailscale.com/types/ipproto"
|
||||||
"tailscale.com/util/must"
|
"tailscale.com/util/must"
|
||||||
@ -45,7 +48,7 @@ func fullHeaderChecksumV4(b []byte) uint16 {
|
|||||||
return ^uint16(s)
|
return ^uint16(s)
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestHeaderChecksums(t *testing.T) {
|
func TestHeaderChecksumsV4(t *testing.T) {
|
||||||
// This is not a good enough test, because it doesn't
|
// This is not a good enough test, because it doesn't
|
||||||
// check the various packet types or the many edge cases
|
// check the various packet types or the many edge cases
|
||||||
// of the checksum algorithm. But it's a start.
|
// of the checksum algorithm. But it's a start.
|
||||||
@ -109,6 +112,108 @@ func TestHeaderChecksums(t *testing.T) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestNatChecksumsV6UDP(t *testing.T) {
|
||||||
|
a1, a2 := netip.MustParseAddr("a::1"), netip.MustParseAddr("b::1")
|
||||||
|
|
||||||
|
// Make a fake UDP packet with 32 bytes of zeros as the datagram payload.
|
||||||
|
b := header.IPv6(make([]byte, header.IPv6MinimumSize+header.UDPMinimumSize+32))
|
||||||
|
b.Encode(&header.IPv6Fields{
|
||||||
|
PayloadLength: header.UDPMinimumSize + 32,
|
||||||
|
TransportProtocol: header.UDPProtocolNumber,
|
||||||
|
HopLimit: 16,
|
||||||
|
SrcAddr: tcpip.AddrFrom16Slice(a1.AsSlice()),
|
||||||
|
DstAddr: tcpip.AddrFrom16Slice(a2.AsSlice()),
|
||||||
|
})
|
||||||
|
udp := header.UDP(b[header.IPv6MinimumSize:])
|
||||||
|
udp.Encode(&header.UDPFields{
|
||||||
|
SrcPort: 42,
|
||||||
|
DstPort: 43,
|
||||||
|
Length: header.UDPMinimumSize + 32,
|
||||||
|
})
|
||||||
|
xsum := header.PseudoHeaderChecksum(
|
||||||
|
header.UDPProtocolNumber,
|
||||||
|
tcpip.AddrFrom16Slice(a1.AsSlice()),
|
||||||
|
tcpip.AddrFrom16Slice(a2.AsSlice()),
|
||||||
|
uint16(header.UDPMinimumSize+32),
|
||||||
|
)
|
||||||
|
xsum = checksum.Checksum(b.Payload()[header.UDPMinimumSize:], xsum)
|
||||||
|
udp.SetChecksum(^udp.CalculateChecksum(xsum))
|
||||||
|
if !udp.IsChecksumValid(tcpip.AddrFrom16Slice(a1.AsSlice()), tcpip.AddrFrom16Slice(a2.AsSlice()), checksum.Checksum(b.Payload()[header.UDPMinimumSize:], 0)) {
|
||||||
|
t.Fatal("test broken; initial packet has incorrect checksum")
|
||||||
|
}
|
||||||
|
|
||||||
|
// Parse the packet.
|
||||||
|
var p Parsed
|
||||||
|
p.Decode(b)
|
||||||
|
t.Log(p.String())
|
||||||
|
|
||||||
|
// Update the source address of the packet to be the same as the dest.
|
||||||
|
p.UpdateSrcAddr(a2)
|
||||||
|
if !udp.IsChecksumValid(tcpip.AddrFrom16Slice(a2.AsSlice()), tcpip.AddrFrom16Slice(a2.AsSlice()), checksum.Checksum(b.Payload()[header.UDPMinimumSize:], 0)) {
|
||||||
|
t.Fatal("incorrect checksum after updating source address")
|
||||||
|
}
|
||||||
|
|
||||||
|
// Update the dest address of the packet to be the original source address.
|
||||||
|
p.UpdateDstAddr(a1)
|
||||||
|
if !udp.IsChecksumValid(tcpip.AddrFrom16Slice(a2.AsSlice()), tcpip.AddrFrom16Slice(a1.AsSlice()), checksum.Checksum(b.Payload()[header.UDPMinimumSize:], 0)) {
|
||||||
|
t.Fatal("incorrect checksum after updating destination address")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestNatChecksumsV6TCP(t *testing.T) {
|
||||||
|
a1, a2 := netip.MustParseAddr("a::1"), netip.MustParseAddr("b::1")
|
||||||
|
|
||||||
|
// Make a fake TCP packet with no payload.
|
||||||
|
b := header.IPv6(make([]byte, header.IPv6MinimumSize+header.TCPMinimumSize))
|
||||||
|
b.Encode(&header.IPv6Fields{
|
||||||
|
PayloadLength: header.TCPMinimumSize,
|
||||||
|
TransportProtocol: header.TCPProtocolNumber,
|
||||||
|
HopLimit: 16,
|
||||||
|
SrcAddr: tcpip.AddrFrom16Slice(a1.AsSlice()),
|
||||||
|
DstAddr: tcpip.AddrFrom16Slice(a2.AsSlice()),
|
||||||
|
})
|
||||||
|
tcp := header.TCP(b[header.IPv6MinimumSize:])
|
||||||
|
tcp.Encode(&header.TCPFields{
|
||||||
|
SrcPort: 42,
|
||||||
|
DstPort: 43,
|
||||||
|
SeqNum: 1,
|
||||||
|
AckNum: 2,
|
||||||
|
DataOffset: header.TCPMinimumSize,
|
||||||
|
Flags: 3,
|
||||||
|
WindowSize: 4,
|
||||||
|
Checksum: 0,
|
||||||
|
UrgentPointer: 5,
|
||||||
|
})
|
||||||
|
xsum := header.PseudoHeaderChecksum(
|
||||||
|
header.TCPProtocolNumber,
|
||||||
|
tcpip.AddrFrom16Slice(a1.AsSlice()),
|
||||||
|
tcpip.AddrFrom16Slice(a2.AsSlice()),
|
||||||
|
uint16(header.TCPMinimumSize),
|
||||||
|
)
|
||||||
|
tcp.SetChecksum(^tcp.CalculateChecksum(xsum))
|
||||||
|
|
||||||
|
if !tcp.IsChecksumValid(tcpip.AddrFrom16Slice(a1.AsSlice()), tcpip.AddrFrom16Slice(a2.AsSlice()), 0, 0) {
|
||||||
|
t.Fatal("test broken; initial packet has incorrect checksum")
|
||||||
|
}
|
||||||
|
|
||||||
|
// Parse the packet.
|
||||||
|
var p Parsed
|
||||||
|
p.Decode(b)
|
||||||
|
t.Log(p.String())
|
||||||
|
|
||||||
|
// Update the source address of the packet to be the same as the dest.
|
||||||
|
p.UpdateSrcAddr(a2)
|
||||||
|
if !tcp.IsChecksumValid(tcpip.AddrFrom16Slice(a2.AsSlice()), tcpip.AddrFrom16Slice(a2.AsSlice()), 0, 0) {
|
||||||
|
t.Fatal("incorrect checksum after updating source address")
|
||||||
|
}
|
||||||
|
|
||||||
|
// Update the dest address of the packet to be the original source address.
|
||||||
|
p.UpdateDstAddr(a1)
|
||||||
|
if !tcp.IsChecksumValid(tcpip.AddrFrom16Slice(a2.AsSlice()), tcpip.AddrFrom16Slice(a1.AsSlice()), 0, 0) {
|
||||||
|
t.Fatal("incorrect checksum after updating destination address")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func mustIPPort(s string) netip.AddrPort {
|
func mustIPPort(s string) netip.AddrPort {
|
||||||
ipp, err := netip.ParseAddrPort(s)
|
ipp, err := netip.ParseAddrPort(s)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
Loading…
x
Reference in New Issue
Block a user