mirror of
https://github.com/netbirdio/gvisor.git
synced 2026-05-22 17:12:49 -07:00
Add nat table support for iptables.
- Fix review comments.
This commit is contained in:
@@ -292,9 +292,9 @@ func marshalRedirectTarget() []byte {
|
||||
},
|
||||
}
|
||||
copy(target.Target.Name[:], redirectTargetName)
|
||||
|
||||
|
||||
ret := make([]byte, 0, linux.SizeOfXTRedirectTarget)
|
||||
return binary.Marshal(ret, usermem.ByteOrder, target)
|
||||
return binary.Marshal(ret, usermem.ByteOrder, target)
|
||||
}
|
||||
|
||||
func marshalJumpTarget(jt JumpTarget) []byte {
|
||||
@@ -670,15 +670,21 @@ func parseTarget(filter iptables.IPHeaderFilter, optVal []byte) (iptables.Target
|
||||
|
||||
// TODO(gvisor.dev/issue/170): Check if the flags are valid.
|
||||
// Also check if we need to map ports or IP.
|
||||
// For now, redirect target only supports dest port change.
|
||||
// For now, redirect target only supports destination port change.
|
||||
// Port range and IP range are not supported yet.
|
||||
if nfRange.RangeIPV4.Flags&linux.NF_NAT_RANGE_PROTO_SPECIFIED == 0 {
|
||||
return nil, fmt.Errorf("netfilter.SetEntries: invalid argument.")
|
||||
}
|
||||
target.Flags = nfRange.RangeIPV4.Flags
|
||||
target.RangeProtoSpecified = true
|
||||
|
||||
target.MinIP = tcpip.Address(nfRange.RangeIPV4.MinIP[:])
|
||||
target.MaxIP = tcpip.Address(nfRange.RangeIPV4.MaxIP[:])
|
||||
|
||||
// TODO(gvisor.dev/issue/170): Port range is not supported yet.
|
||||
if nfRange.RangeIPV4.MinPort != nfRange.RangeIPV4.MaxPort {
|
||||
return nil, fmt.Errorf("netfilter.SetEntries: invalid argument.")
|
||||
}
|
||||
|
||||
// Convert port from big endian to little endian.
|
||||
port := make([]byte, 2)
|
||||
binary.BigEndian.PutUint16(port, nfRange.RangeIPV4.MinPort)
|
||||
|
||||
@@ -69,8 +69,11 @@ func (ReturnTarget) Action(tcpip.PacketBuffer) (RuleVerdict, int) {
|
||||
// Min and Max values for IP and Ports in the struct indicate the range of
|
||||
// values which can be used to redirect.
|
||||
type RedirectTarget struct {
|
||||
// Flags to check if the redirect is for address or ports.
|
||||
Flags uint32
|
||||
// TODO(gvisor.dev/issue/170): Other flags need to be aded after
|
||||
// we support them.
|
||||
// RangeProtoSpecified flag indicates single port is specified to
|
||||
// redirect.
|
||||
RangeProtoSpecified bool
|
||||
|
||||
// Min address used to redirect.
|
||||
MinIP tcpip.Address
|
||||
@@ -86,30 +89,56 @@ type RedirectTarget struct {
|
||||
}
|
||||
|
||||
// Action implements Target.Action.
|
||||
// TODO(gvisor.dev/issue/170): Parse headers without copying. The current
|
||||
// implementation only works for PREROUTING and calls pkt.Clone(), neither
|
||||
// of which should be the case.
|
||||
func (rt RedirectTarget) Action(pkt tcpip.PacketBuffer) (RuleVerdict, int) {
|
||||
headerView := pkt.Data.First()
|
||||
newPkt := pkt.Clone()
|
||||
|
||||
// Network header should be set.
|
||||
// Set network header.
|
||||
headerView := newPkt.Data.First()
|
||||
netHeader := header.IPv4(headerView)
|
||||
if netHeader == nil {
|
||||
return RuleDrop, 0
|
||||
}
|
||||
newPkt.NetworkHeader = headerView[:netHeader.HeaderLength()]
|
||||
|
||||
hlen := int(netHeader.HeaderLength())
|
||||
tlen := int(netHeader.TotalLength())
|
||||
newPkt.Data.TrimFront(hlen)
|
||||
newPkt.Data.CapLength(tlen - hlen)
|
||||
|
||||
// TODO(gvisor.dev/issue/170): Change destination address to
|
||||
// loopback or interface address on which the packet was
|
||||
// received.
|
||||
|
||||
// TODO(gvisor.dev/issue/170): Check Flags in RedirectTarget if
|
||||
// we need to change dest address (for OUTPUT chain) or ports.
|
||||
hlen := int(netHeader.HeaderLength())
|
||||
|
||||
switch protocol := netHeader.TransportProtocol(); protocol {
|
||||
case header.UDPProtocolNumber:
|
||||
udp := header.UDP(headerView[hlen:])
|
||||
udp.SetDestinationPort(rt.MinPort)
|
||||
var udpHeader header.UDP
|
||||
if newPkt.TransportHeader != nil {
|
||||
udpHeader = header.UDP(newPkt.TransportHeader)
|
||||
} else {
|
||||
if len(pkt.Data.First()) < header.UDPMinimumSize {
|
||||
return RuleDrop, 0
|
||||
}
|
||||
udpHeader = header.UDP(newPkt.Data.First())
|
||||
}
|
||||
udpHeader.SetDestinationPort(rt.MinPort)
|
||||
case header.TCPProtocolNumber:
|
||||
var tcpHeader header.TCP
|
||||
if newPkt.TransportHeader != nil {
|
||||
tcpHeader = header.TCP(newPkt.TransportHeader)
|
||||
} else {
|
||||
if len(pkt.Data.First()) < header.TCPMinimumSize {
|
||||
return RuleDrop, 0
|
||||
}
|
||||
tcpHeader = header.TCP(newPkt.TransportHeader)
|
||||
}
|
||||
// TODO(gvisor.dev/issue/170): Need to recompute checksum
|
||||
// and implement nat connection tracking to support TCP.
|
||||
tcp := header.TCP(headerView[hlen:])
|
||||
tcp.SetDestinationPort(rt.MinPort)
|
||||
tcpHeader.SetDestinationPort(rt.MinPort)
|
||||
default:
|
||||
return RuleDrop, 0
|
||||
}
|
||||
|
||||
return RuleAccept, 0
|
||||
}
|
||||
|
||||
@@ -163,6 +163,6 @@ type Matcher interface {
|
||||
type Target interface {
|
||||
// Action takes an action on the packet and returns a verdict on how
|
||||
// traversal should (or should not) continue. If the return value is
|
||||
// Jump, it also returns the name of the chain to jump to.
|
||||
// Jump, it also returns the index of the rule to jump to.
|
||||
Action(packet tcpip.PacketBuffer) (RuleVerdict, int)
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user