blob: 5df0e009851e6e7a2c4096df063b087139ef2aa0 [file] [log] [blame]
// Copyright 2018 The Fuchsia 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 (
"github.com/google/netstack/tcpip"
"github.com/google/netstack/tcpip/buffer"
"github.com/google/netstack/tcpip/header"
"github.com/google/netstack/tcpip/transport/tcp"
"github.com/google/netstack/tcpip/transport/udp"
)
type icmpV4Params struct {
srcAddr tcpip.Address
dstAddr tcpip.Address
icmpV4Type header.ICMPv4Type
code byte
}
func icmpV4Packet(payload []byte, p *icmpV4Params) (buffer.Prependable, buffer.VectorisedView) {
hdr := buffer.NewPrependable(header.IPv4MinimumSize + header.ICMPv4MinimumSize)
// Create the ICMP header.
i := header.ICMPv4(hdr.Prepend(header.ICMPv4MinimumSize))
i.SetType(p.icmpV4Type)
i.SetCode(p.code)
// Calculate the ICMP checksum and set it.
i.SetChecksum(^header.Checksum(i, header.Checksum(payload, 0)))
// Create the IPv4 header.
ip := header.IPv4(hdr.Prepend(header.IPv4MinimumSize))
ip.Encode(&header.IPv4Fields{
IHL: header.IPv4MinimumSize,
TotalLength: uint16(header.IPv4MinimumSize + header.ICMPv4MinimumSize + len(payload)),
TTL: 65,
Protocol: uint8(header.ICMPv4ProtocolNumber),
SrcAddr: p.srcAddr,
DstAddr: p.dstAddr,
})
ip.SetChecksum(^ip.CalculateChecksum())
return hdr, buffer.View(payload).ToVectorisedView()
}
type udpParams struct {
srcAddr tcpip.Address
srcPort uint16
dstAddr tcpip.Address
dstPort uint16
noUDPChecksum bool
}
func udpV4Packet(payload []byte, p *udpParams) (buffer.Prependable, buffer.VectorisedView) {
hdr := buffer.NewPrependable(header.IPv4MinimumSize + header.UDPMinimumSize)
// Create the UDP header.
u := header.UDP(hdr.Prepend(header.UDPMinimumSize))
u.Encode(&header.UDPFields{
SrcPort: p.srcPort,
DstPort: p.dstPort,
Length: uint16(header.UDPMinimumSize + len(payload)),
})
if p.noUDPChecksum {
u.SetChecksum(0)
} else {
// Calculate the UDP pseudo-header checksum.
xsum := header.Checksum([]byte(p.srcAddr), 0)
xsum = header.Checksum([]byte(p.dstAddr), xsum)
xsum = header.Checksum([]byte{0, uint8(udp.ProtocolNumber)}, xsum)
// Calculate the UDP checksum and set it.
length := uint16(header.UDPMinimumSize + len(payload))
xsum = header.Checksum(payload, xsum)
u.SetChecksum(^u.CalculateChecksum(xsum, length))
}
// Create the IPv4 header.
ip := header.IPv4(hdr.Prepend(header.IPv4MinimumSize))
ip.Encode(&header.IPv4Fields{
IHL: header.IPv4MinimumSize,
TotalLength: uint16(header.IPv4MinimumSize + header.UDPMinimumSize + len(payload)),
TTL: 65,
Protocol: uint8(udp.ProtocolNumber),
SrcAddr: p.srcAddr,
DstAddr: p.dstAddr,
})
ip.SetChecksum(^ip.CalculateChecksum())
return hdr, buffer.View(payload).ToVectorisedView()
}
func udpV6Packet(payload []byte, p *udpParams) (buffer.Prependable, buffer.VectorisedView) {
hdr := buffer.NewPrependable(header.IPv6MinimumSize + header.UDPMinimumSize)
// Create the UDP header.
u := header.UDP(hdr.Prepend(header.UDPMinimumSize))
u.Encode(&header.UDPFields{
SrcPort: p.srcPort,
DstPort: p.dstPort,
Length: uint16(header.UDPMinimumSize + len(payload)),
})
if p.noUDPChecksum {
u.SetChecksum(0)
} else {
// Calculate the UDP pseudo-header checksum.
xsum := header.Checksum([]byte(p.srcAddr), 0)
xsum = header.Checksum([]byte(p.dstAddr), xsum)
xsum = header.Checksum([]byte{0, uint8(udp.ProtocolNumber)}, xsum)
// Calculate the UDP checksum and set it.
length := uint16(header.UDPMinimumSize + len(payload))
xsum = header.Checksum(payload, xsum)
u.SetChecksum(^u.CalculateChecksum(xsum, length))
}
// Create the IPv6 header.
ip := header.IPv6(hdr.Prepend(header.IPv6MinimumSize))
ip.Encode(&header.IPv6Fields{
PayloadLength: uint16(header.UDPMinimumSize + len(payload)),
NextHeader: uint8(header.UDPProtocolNumber),
HopLimit: 1,
SrcAddr: p.srcAddr,
DstAddr: p.dstAddr,
})
return hdr, buffer.View(payload).ToVectorisedView()
}
type tcpParams struct {
srcAddr tcpip.Address
srcPort uint16
dstAddr tcpip.Address
dstPort uint16
seqNum uint32
ackNum uint32
flags int
tcpOpts []byte
rcvWnd uint16
}
func tcpV4Packet(payload []byte, p *tcpParams) (buffer.Prependable, buffer.VectorisedView) {
hdr := buffer.NewPrependable(header.IPv4MinimumSize + header.TCPMinimumSize + len(p.tcpOpts))
tcpHdr := hdr.Prepend(header.TCPMinimumSize + len(p.tcpOpts))
copy(tcpHdr[header.TCPMinimumSize:], p.tcpOpts)
// Create the TCP header.
t := header.TCP(tcpHdr)
t.Encode(&header.TCPFields{
SrcPort: p.srcPort,
DstPort: p.dstPort,
SeqNum: uint32(p.seqNum),
AckNum: uint32(p.ackNum),
DataOffset: uint8(header.TCPMinimumSize + len(p.tcpOpts)),
Flags: uint8(p.flags),
WindowSize: uint16(p.rcvWnd),
})
// Calculate the TCP pseudo-header checksum.
xsum := header.Checksum([]byte(p.srcAddr), 0)
xsum = header.Checksum([]byte(p.dstAddr), xsum)
xsum = header.Checksum([]byte{0, uint8(tcp.ProtocolNumber)}, xsum)
// Calculate the TCP checksum and set it.
length := uint16(header.TCPMinimumSize + len(p.tcpOpts) + len(payload))
xsum = header.Checksum(payload, xsum)
t.SetChecksum(^t.CalculateChecksum(xsum, length))
// Create the IPv4 header.
ip := header.IPv4(hdr.Prepend(header.IPv4MinimumSize))
ip.Encode(&header.IPv4Fields{
IHL: header.IPv4MinimumSize,
TotalLength: uint16(header.IPv4MinimumSize + header.TCPMinimumSize + len(payload)),
TTL: 65,
Protocol: uint8(tcp.ProtocolNumber),
SrcAddr: p.srcAddr,
DstAddr: p.dstAddr,
})
ip.SetChecksum(^ip.CalculateChecksum())
return hdr, buffer.View(payload).ToVectorisedView()
}
func tcpV6Packet(payload []byte, p *tcpParams) (buffer.Prependable, buffer.VectorisedView) {
hdr := buffer.NewPrependable(header.IPv6MinimumSize + header.TCPMinimumSize + len(p.tcpOpts))
tcpHdr := hdr.Prepend(header.TCPMinimumSize + len(p.tcpOpts))
copy(tcpHdr[header.TCPMinimumSize:], p.tcpOpts)
// Create the TCP header.
t := header.TCP(tcpHdr)
t.Encode(&header.TCPFields{
SrcPort: p.srcPort,
DstPort: p.dstPort,
DataOffset: uint8(header.TCPMinimumSize + len(p.tcpOpts)),
Flags: uint8(p.flags),
})
// Calculate the TCP pseudo-header checksum.
xsum := header.Checksum([]byte(p.srcAddr), 0)
xsum = header.Checksum([]byte(p.dstAddr), xsum)
xsum = header.Checksum([]byte{0, uint8(tcp.ProtocolNumber)}, xsum)
// Calculate the TCP checksum and set it.
length := uint16(header.TCPMinimumSize + len(p.tcpOpts) + len(payload))
xsum = header.Checksum(payload, xsum)
t.SetChecksum(^t.CalculateChecksum(xsum, length))
// Create the IPv6 header.
ip := header.IPv6(hdr.Prepend(header.IPv6MinimumSize))
ip.Encode(&header.IPv6Fields{
PayloadLength: uint16(header.TCPMinimumSize + len(payload)),
NextHeader: uint8(header.TCPProtocolNumber),
HopLimit: 1,
SrcAddr: p.srcAddr,
DstAddr: p.dstAddr,
})
return hdr, buffer.View(payload).ToVectorisedView()
}