Skip to content

Commit bcc0b39

Browse files
parth-opensrcgvisor-bot
authored andcommitted
IPTables: Added support for Reject with TCP Reset.
iptables_test: Fixed some of the broken ipv6 tests. PiperOrigin-RevId: 940087094
1 parent b80f6c3 commit bcc0b39

15 files changed

Lines changed: 1101 additions & 28 deletions

File tree

pkg/abi/linux/netfilter.go

Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -859,3 +859,53 @@ type XTMarkMtinfo1 struct {
859859

860860
// SizeOfXTMarkMtinfo1 is the size of XTMarkMtinfo1.
861861
const SizeOfXTMarkMtinfo1 = 12
862+
863+
// Ref: include/uapi/linux/netfilter_ipv4/ipt_REJECT.h:enum ipt_reject_with
864+
const (
865+
IPT_ICMP_NET_UNREACHABLE = iota
866+
IPT_ICMP_HOST_UNREACHABLE
867+
IPT_ICMP_PROT_UNREACHABLE
868+
IPT_ICMP_PORT_UNREACHABLE
869+
IPT_ICMP_ECHOREPLY
870+
IPT_ICMP_NET_PROHIBITED
871+
IPT_ICMP_HOST_PROHIBITED
872+
IPT_TCP_RESET
873+
IPT_ICMP_ADMIN_PROHIBITED
874+
)
875+
876+
// Ref: include/uapi/linux/netfilter_ipv6/ip6t_REJECT.h:enum ip6t_reject_with
877+
const (
878+
IP6T_ICMP6_NO_ROUTE = iota
879+
IP6T_ICMP6_ADM_PROHIBITED
880+
IP6T_ICMP6_NOT_NEIGHBOUR
881+
IP6T_ICMP6_ADDR_UNREACH
882+
IP6T_ICMP6_PORT_UNREACH
883+
IP6T_ICMP6_ECHOREPLY
884+
IP6T_TCP_RESET
885+
IP6T_ICMP6_POLICY_FAIL
886+
IP6T_ICMP6_REJECT_ROUTE
887+
)
888+
889+
// IPTRejectInfo is the argument for the IPT_REJECT target. It corresponds to
890+
// struct ipt_reject_info in include/uapi/linux/netfilter_ipv4/ipt_REJECT.h.
891+
//
892+
// +marshal
893+
type IPTRejectInfo struct {
894+
_ structs.HostLayout
895+
With uint32
896+
}
897+
898+
// SizeOfIPTRejectInfo is the size of an IPTRejectInfo.
899+
const SizeOfIPTRejectInfo = 4
900+
901+
// IP6TRejectInfo is the argument for the IP6T_REJECT target. It corresponds to
902+
// struct ip6t_reject_info in include/uapi/linux/netfilter_ipv6/ip6t_REJECT.h.
903+
//
904+
// +marshal
905+
type IP6TRejectInfo struct {
906+
_ structs.HostLayout
907+
With uint32
908+
}
909+
910+
// SizeOfIP6TRejectInfo is the size of an IP6TRejectInfo.
911+
const SizeOfIP6TRejectInfo = 4

pkg/sentry/socket/netfilter/ipv4.go

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -186,6 +186,20 @@ func modifyEntries4(mapper IDMapper, stk *stack.Stack, optVal []byte, replace *l
186186
nflog("failed to parse target: %v", err)
187187
return nil, err
188188
}
189+
// Set the handler for REJECT targets.
190+
if rejectTarget, ok := target.(*rejectIPv4Target); ok {
191+
if replace.Name.String() != filterTable {
192+
nflog("REJECT target is only supported in the filter table")
193+
return nil, syserr.ErrInvalidArgument
194+
}
195+
netProto := stk.NetworkProtocolInstance(header.IPv4ProtocolNumber)
196+
handler, ok := netProto.(stack.RejectIPv4WithHandler)
197+
if !ok {
198+
nflog("modifyEntries4: expected %T to implement stack.RejectIPv4WithHandler", netProto)
199+
return nil, syserr.ErrInvalidArgument
200+
}
201+
rejectTarget.Handler = handler
202+
}
189203
rule.Target = target
190204
}
191205
optVal = optVal[targetSize:]

pkg/sentry/socket/netfilter/ipv6.go

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -189,6 +189,20 @@ func modifyEntries6(mapper IDMapper, stk *stack.Stack, optVal []byte, replace *l
189189
nflog("failed to parse target: %v", err)
190190
return nil, err
191191
}
192+
// Set the handler for REJECT targets.
193+
if rejectTarget, ok := target.(*rejectIPv6Target); ok {
194+
if replace.Name.String() != filterTable {
195+
nflog("REJECT target is only supported in the filter table")
196+
return nil, syserr.ErrInvalidArgument
197+
}
198+
netProto := stk.NetworkProtocolInstance(header.IPv6ProtocolNumber)
199+
handler, ok := netProto.(stack.RejectIPv6WithHandler)
200+
if !ok {
201+
nflog("modifyEntries6: expected %T to implement stack.RejectIPv6WithHandler", netProto)
202+
return nil, syserr.ErrInvalidArgument
203+
}
204+
rejectTarget.Handler = handler
205+
}
192206
rule.Target = target
193207
}
194208
optVal = optVal[targetSize:]

pkg/sentry/socket/netfilter/targets.go

Lines changed: 217 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ import (
1919
"fmt"
2020

2121
"gvisor.dev/gvisor/pkg/abi/linux"
22+
"gvisor.dev/gvisor/pkg/bits"
2223
"gvisor.dev/gvisor/pkg/hostarch"
2324
"gvisor.dev/gvisor/pkg/marshal"
2425
"gvisor.dev/gvisor/pkg/syserr"
@@ -103,6 +104,15 @@ func init() {
103104
registerTargetMaker(&dnatTargetMakerR2{
104105
NetworkProtocol: header.IPv6ProtocolNumber,
105106
})
107+
108+
// REJECT targets.
109+
registerTargetMaker(&rejectTargetMaker{
110+
NetworkProtocol: header.IPv4ProtocolNumber,
111+
})
112+
registerTargetMaker(&rejectTargetMaker{
113+
NetworkProtocol: header.IPv6ProtocolNumber,
114+
})
115+
106116
}
107117

108118
// The stack package provides some basic, useful targets for us. The following
@@ -533,3 +543,210 @@ func htons(port uint16) uint16 {
533543
hostarch.ByteOrder.PutUint16(buf, port)
534544
return binary.BigEndian.Uint16(buf)
535545
}
546+
547+
// RejectTargetName is used to mark targets as reject targets.
548+
const RejectTargetName = "REJECT"
549+
550+
// +stateify savable
551+
type rejectIPv4Target struct {
552+
stack.RejectIPv4Target
553+
}
554+
555+
func (rt *rejectIPv4Target) id() targetID {
556+
return targetID{
557+
name: RejectTargetName,
558+
networkProtocol: header.IPv4ProtocolNumber,
559+
}
560+
}
561+
562+
// +stateify savable
563+
type rejectIPv6Target struct {
564+
stack.RejectIPv6Target
565+
}
566+
567+
func (rt *rejectIPv6Target) id() targetID {
568+
return targetID{
569+
name: RejectTargetName,
570+
networkProtocol: header.IPv6ProtocolNumber,
571+
}
572+
}
573+
574+
// +stateify savable
575+
type rejectTargetMaker struct {
576+
NetworkProtocol tcpip.NetworkProtocolNumber
577+
}
578+
579+
func (rm *rejectTargetMaker) id() targetID {
580+
return targetID{
581+
name: RejectTargetName,
582+
networkProtocol: rm.NetworkProtocol,
583+
}
584+
}
585+
586+
func (rm *rejectTargetMaker) marshalIPv4(tgt target) []byte {
587+
rt := tgt.(*rejectIPv4Target)
588+
size := bits.AlignUp(linux.SizeOfXTEntryTarget+linux.SizeOfIPTRejectInfo, 8)
589+
xt := linux.XTEntryTarget{
590+
TargetSize: uint16(size),
591+
}
592+
copy(xt.Name[:], RejectTargetName)
593+
594+
var with uint32
595+
switch rt.RejectWith {
596+
case stack.RejectIPv4WithICMPNetUnreachable:
597+
with = linux.IPT_ICMP_NET_UNREACHABLE
598+
case stack.RejectIPv4WithICMPHostUnreachable:
599+
with = linux.IPT_ICMP_HOST_UNREACHABLE
600+
case stack.RejectIPv4WithICMPPortUnreachable:
601+
with = linux.IPT_ICMP_PORT_UNREACHABLE
602+
case stack.RejectIPv4WithICMPNetProhibited:
603+
with = linux.IPT_ICMP_NET_PROHIBITED
604+
case stack.RejectIPv4WithICMPHostProhibited:
605+
with = linux.IPT_ICMP_HOST_PROHIBITED
606+
case stack.RejectIPv4WithICMPAdminProhibited:
607+
with = linux.IPT_ICMP_ADMIN_PROHIBITED
608+
case stack.RejectIPv4WithTCPReset:
609+
with = linux.IPT_TCP_RESET
610+
case stack.RejectIPv4WithICMPEchoReply:
611+
with = linux.IPT_ICMP_ECHOREPLY
612+
default:
613+
panic(fmt.Sprintf("unknown reject option %v", rt.RejectWith))
614+
}
615+
616+
info := linux.IPTRejectInfo{With: with}
617+
618+
buf := make([]byte, size)
619+
bufRemain := xt.MarshalUnsafe(buf)
620+
info.MarshalUnsafe(bufRemain)
621+
return buf
622+
}
623+
624+
func (rm *rejectTargetMaker) marshalIPv6(tgt target) []byte {
625+
rt := tgt.(*rejectIPv6Target)
626+
size := bits.AlignUp(linux.SizeOfXTEntryTarget+linux.SizeOfIP6TRejectInfo, 8)
627+
xt := linux.XTEntryTarget{
628+
TargetSize: uint16(size),
629+
}
630+
copy(xt.Name[:], RejectTargetName)
631+
632+
var with uint32
633+
switch rt.RejectWith {
634+
case stack.RejectIPv6WithICMPNoRoute:
635+
with = linux.IP6T_ICMP6_NO_ROUTE
636+
case stack.RejectIPv6WithICMPAddrUnreachable:
637+
with = linux.IP6T_ICMP6_ADDR_UNREACH
638+
case stack.RejectIPv6WithICMPPortUnreachable:
639+
with = linux.IP6T_ICMP6_PORT_UNREACH
640+
case stack.RejectIPv6WithICMPAdminProhibited:
641+
with = linux.IP6T_ICMP6_ADM_PROHIBITED
642+
case stack.RejectIPv6WithTCPReset:
643+
with = linux.IP6T_TCP_RESET
644+
case stack.RejectIPv6WithICMPNotNeighbour:
645+
with = linux.IP6T_ICMP6_NOT_NEIGHBOUR
646+
case stack.RejectIPv6WithICMPPolicyFail:
647+
with = linux.IP6T_ICMP6_POLICY_FAIL
648+
case stack.RejectIPv6WithICMPRejectRoute:
649+
with = linux.IP6T_ICMP6_REJECT_ROUTE
650+
default:
651+
panic(fmt.Sprintf("unknown reject option %v", rt.RejectWith))
652+
}
653+
654+
info := linux.IP6TRejectInfo{With: with}
655+
656+
buf := make([]byte, size)
657+
bufRemain := xt.MarshalUnsafe(buf)
658+
info.MarshalUnsafe(bufRemain)
659+
return buf
660+
}
661+
662+
func (rm *rejectTargetMaker) marshal(tgt target) []byte {
663+
netProto := rm.NetworkProtocol
664+
switch rm.NetworkProtocol {
665+
case header.IPv4ProtocolNumber:
666+
return rm.marshalIPv4(tgt)
667+
case header.IPv6ProtocolNumber:
668+
return rm.marshalIPv6(tgt)
669+
default:
670+
panic(fmt.Sprintf("unsupported network protocol %d", netProto))
671+
}
672+
}
673+
674+
func (rm *rejectTargetMaker) unmarshalIPv4(buf []byte, filter stack.IPHeaderFilter) (target, *syserr.Error) {
675+
if len(buf) < linux.SizeOfXTEntryTarget+linux.SizeOfIPTRejectInfo {
676+
nflog("rejectTargetMaker: buf has insufficient size %d", len(buf))
677+
return nil, syserr.ErrInvalidArgument
678+
}
679+
680+
var info linux.IPTRejectInfo
681+
info.UnmarshalUnsafe(buf[linux.SizeOfXTEntryTarget:])
682+
683+
var rejectWith stack.RejectIPv4WithICMPType
684+
switch info.With {
685+
case linux.IPT_ICMP_PORT_UNREACHABLE:
686+
rejectWith = stack.RejectIPv4WithICMPPortUnreachable
687+
case linux.IPT_TCP_RESET:
688+
if filter.Protocol != header.TCPProtocolNumber {
689+
nflog("rejectTargetMaker: TCP_RESET invalid for non-tcp")
690+
return nil, syserr.ErrInvalidArgument
691+
}
692+
rejectWith = stack.RejectIPv4WithTCPReset
693+
case linux.IPT_ICMP_HOST_UNREACHABLE, linux.IPT_ICMP_NET_UNREACHABLE,
694+
linux.IPT_ICMP_HOST_PROHIBITED, linux.IPT_ICMP_NET_PROHIBITED, linux.IPT_ICMP_ADMIN_PROHIBITED:
695+
696+
nflog("rejectTargetMaker: unsupported reject type %d", info.With)
697+
return nil, syserr.ErrNotSupported
698+
default:
699+
nflog("rejectTargetMaker: unknown reject type %d", info.With)
700+
return nil, syserr.ErrInvalidArgument
701+
}
702+
703+
return &rejectIPv4Target{stack.RejectIPv4Target{
704+
RejectWith: rejectWith,
705+
}}, nil
706+
}
707+
708+
func (rm *rejectTargetMaker) unmarshalIPv6(buf []byte, filter stack.IPHeaderFilter) (target, *syserr.Error) {
709+
if len(buf) < linux.SizeOfXTEntryTarget+linux.SizeOfIP6TRejectInfo {
710+
nflog("rejectTargetMaker: buf has insufficient size %d", len(buf))
711+
return nil, syserr.ErrInvalidArgument
712+
}
713+
714+
var info linux.IP6TRejectInfo
715+
info.UnmarshalUnsafe(buf[linux.SizeOfXTEntryTarget:])
716+
717+
var rejectWith stack.RejectIPv6WithICMPType
718+
switch info.With {
719+
case linux.IP6T_ICMP6_PORT_UNREACH:
720+
rejectWith = stack.RejectIPv6WithICMPPortUnreachable
721+
case linux.IP6T_TCP_RESET:
722+
if filter.Protocol != header.TCPProtocolNumber {
723+
nflog("rejectTargetMaker: TCP_RESET invalid for non-tcp")
724+
return nil, syserr.ErrInvalidArgument
725+
}
726+
rejectWith = stack.RejectIPv6WithTCPReset
727+
case linux.IP6T_ICMP6_NO_ROUTE, linux.IP6T_ICMP6_ADM_PROHIBITED, linux.IP6T_ICMP6_NOT_NEIGHBOUR,
728+
linux.IP6T_ICMP6_ADDR_UNREACH, linux.IP6T_ICMP6_POLICY_FAIL, linux.IP6T_ICMP6_REJECT_ROUTE:
729+
730+
nflog("rejectTargetMaker: unsupported reject type %d", info.With)
731+
return nil, syserr.ErrNotSupported
732+
default:
733+
nflog("rejectTargetMaker: unknown reject type %d", info.With)
734+
return nil, syserr.ErrInvalidArgument
735+
}
736+
737+
return &rejectIPv6Target{stack.RejectIPv6Target{
738+
RejectWith: rejectWith,
739+
}}, nil
740+
}
741+
742+
func (rm *rejectTargetMaker) unmarshal(buf []byte, filter stack.IPHeaderFilter) (target, *syserr.Error) {
743+
switch filter.NetworkProtocol() {
744+
case header.IPv4ProtocolNumber:
745+
return rm.unmarshalIPv4(buf, filter)
746+
case header.IPv6ProtocolNumber:
747+
return rm.unmarshalIPv6(buf, filter)
748+
default:
749+
nflog("rejectTargetMaker: unsupported network protocol %d", filter.NetworkProtocol())
750+
return nil, syserr.ErrInvalidArgument
751+
}
752+
}

pkg/tcpip/network/internal/ip/BUILD

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ go_library(
1111
"duplicate_address_detection.go",
1212
"errors.go",
1313
"generic_multicast_protocol.go",
14+
"reject_with_reset.go",
1415
"stats.go",
1516
],
1617
visibility = [
@@ -19,6 +20,7 @@ go_library(
1920
"//pkg/tcpip/network/ipv6:__pkg__",
2021
],
2122
deps = [
23+
"//pkg/buffer",
2224
"//pkg/sync",
2325
"//pkg/tcpip",
2426
"//pkg/tcpip/header",

0 commit comments

Comments
 (0)