From cb86d3ea02af1eefd2ed75e19479c1bffb903869 Mon Sep 17 00:00:00 2001 From: Kevin Krakauer Date: Fri, 10 Nov 2023 21:24:27 -0800 Subject: [PATCH] netstack: support snat target rev 1 for both IPv4 and IPv6 We had IPv6 support, and since they two are almost identical, they can share code. The only difference is the length of the address. PiperOrigin-RevId: 581447406 --- pkg/sentry/socket/netfilter/snat.go | 29 +++++++++++++++++--------- pkg/sentry/socket/netfilter/targets.go | 5 ++++- 2 files changed, 23 insertions(+), 11 deletions(-) diff --git a/pkg/sentry/socket/netfilter/snat.go b/pkg/sentry/socket/netfilter/snat.go index 213670403..ea0eac7b5 100644 --- a/pkg/sentry/socket/netfilter/snat.go +++ b/pkg/sentry/socket/netfilter/snat.go @@ -15,6 +15,8 @@ package netfilter import ( + "fmt" + "gvisor.dev/gvisor/pkg/abi/linux" "gvisor.dev/gvisor/pkg/marshal" "gvisor.dev/gvisor/pkg/syserr" @@ -117,11 +119,11 @@ func (*snatTargetMakerV4) unmarshal(buf []byte, filter stack.IPHeaderFilter) (ta return &target, nil } -type snatTargetMakerV6 struct { +type snatTargetMakerR1 struct { NetworkProtocol tcpip.NetworkProtocolNumber } -func (st *snatTargetMakerV6) id() targetID { +func (st *snatTargetMakerR1) id() targetID { return targetID{ name: SNATTargetName, networkProtocol: st.NetworkProtocol, @@ -129,7 +131,7 @@ func (st *snatTargetMakerV6) id() targetID { } } -func (*snatTargetMakerV6) marshal(target target) []byte { +func (*snatTargetMakerR1) marshal(target target) []byte { st := target.(*snatTarget) nt := linux.XTNATTargetV1{ Target: linux.XTEntryTarget{ @@ -148,14 +150,14 @@ func (*snatTargetMakerV6) marshal(target target) []byte { return marshal.Marshal(&nt) } -func (*snatTargetMakerV6) unmarshal(buf []byte, filter stack.IPHeaderFilter) (target, *syserr.Error) { +func (st *snatTargetMakerR1) unmarshal(buf []byte, filter stack.IPHeaderFilter) (target, *syserr.Error) { if size := linux.SizeOfXTNATTargetV1; len(buf) < size { - nflog("snatTargetMakerV6: buf has insufficient size (%d) for SNAT V6 target (%d)", len(buf), size) + nflog("snatTargetMakerR1: buf has insufficient size (%d) for SNAT target (%d)", len(buf), size) return nil, syserr.ErrInvalidArgument } if p := filter.Protocol; p != header.TCPProtocolNumber && p != header.UDPProtocolNumber { - nflog("snatTargetMakerV6: bad proto %d", p) + nflog("snatTargetMakerR1: bad proto %d", p) return nil, syserr.ErrInvalidArgument } @@ -164,27 +166,34 @@ func (*snatTargetMakerV6) unmarshal(buf []byte, filter stack.IPHeaderFilter) (ta // TODO(gvisor.dev/issue/5697): Support port or address ranges. if natRange.MinAddr != natRange.MaxAddr { - nflog("snatTargetMakerV6: MinAddr and MaxAddr are different") + nflog("snatTargetMakerR1: MinAddr and MaxAddr are different") return nil, syserr.ErrInvalidArgument } if natRange.MinProto != natRange.MaxProto { - nflog("snatTargetMakerV6: MinProto and MaxProto are different") + nflog("snatTargetMakerR1: MinProto and MaxProto are different") return nil, syserr.ErrInvalidArgument } // TODO(gvisor.dev/issue/5698): Support other NF_NAT_RANGE flags. if natRange.Flags != linux.NF_NAT_RANGE_MAP_IPS|linux.NF_NAT_RANGE_PROTO_SPECIFIED { - nflog("snatTargetMakerV6: invalid range flags %d", natRange.Flags) + nflog("snatTargetMakerR1: invalid range flags %d", natRange.Flags) return nil, syserr.ErrInvalidArgument } target := snatTarget{ SNATTarget: stack.SNATTarget{ NetworkProtocol: filter.NetworkProtocol(), - Addr: tcpip.AddrFrom16(natRange.MinAddr), Port: ntohs(natRange.MinProto), }, } + switch st.NetworkProtocol { + case header.IPv4ProtocolNumber: + target.SNATTarget.Addr = tcpip.AddrFrom4Slice(natRange.MinAddr[:4]) + case header.IPv6ProtocolNumber: + target.SNATTarget.Addr = tcpip.AddrFrom16(natRange.MinAddr) + default: + panic(fmt.Sprintf("invalid protocol number: %d", st.NetworkProtocol)) + } return &target, nil } diff --git a/pkg/sentry/socket/netfilter/targets.go b/pkg/sentry/socket/netfilter/targets.go index 2ed17346b..e62844f1c 100644 --- a/pkg/sentry/socket/netfilter/targets.go +++ b/pkg/sentry/socket/netfilter/targets.go @@ -64,7 +64,10 @@ func init() { registerTargetMaker(&snatTargetMakerV4{ NetworkProtocol: header.IPv4ProtocolNumber, }) - registerTargetMaker(&snatTargetMakerV6{ + registerTargetMaker(&snatTargetMakerR1{ + NetworkProtocol: header.IPv4ProtocolNumber, + }) + registerTargetMaker(&snatTargetMakerR1{ NetworkProtocol: header.IPv6ProtocolNumber, }) }