atom-device/Packet.go

112 lines
2.7 KiB
Go

package Atom_Device
import (
"encoding/binary"
"git.sydch.com/Go-Module/atom-device/utils"
"golang.org/x/net/ipv4"
"golang.org/x/net/ipv6"
"golang.zx2c4.com/wireguard/device"
"io"
"net"
)
const (
InterfaceMTU = 3500
maxContentSize = InterfaceMTU * 2
outboundChCap = 50
tunPacketOffset = 14
ipv4offsetChecksum = 10
)
type Packet struct {
Buffer [maxContentSize]byte
Packet []byte
Src net.IP
Dst net.IP
IsIPv6 bool
}
func (data *Packet) clear() {
data.Packet = nil
data.Src = nil
data.Dst = nil
data.IsIPv6 = false
}
func (data *Packet) ReadFrom(stream io.Reader) (int64, error) {
var totalRead = tunPacketOffset
for {
n, err := stream.Read(data.Buffer[totalRead:])
totalRead += n
if err == io.EOF {
data.Packet = data.Buffer[tunPacketOffset:totalRead]
return int64(totalRead - tunPacketOffset), nil
} else if err != nil {
return int64(totalRead - tunPacketOffset), err
}
}
}
func (data *Packet) Parse() bool {
packet := data.Packet
switch version := packet[0] >> 4; version {
case ipv4.Version:
if len(packet) < ipv4.HeaderLen {
return false
}
data.Src = packet[device.IPv4offsetSrc : device.IPv4offsetSrc+net.IPv4len]
data.Dst = packet[device.IPv4offsetDst : device.IPv4offsetDst+net.IPv4len]
data.IsIPv6 = false
case ipv6.Version:
if len(packet) < ipv6.HeaderLen {
return false
}
data.Src = packet[device.IPv6offsetSrc : device.IPv6offsetSrc+net.IPv6len]
data.Dst = packet[device.IPv6offsetDst : device.IPv6offsetDst+net.IPv6len]
data.IsIPv6 = true
default:
return false
}
return true
}
func (data *Packet) ParseBuffer() {
var tmp [InterfaceMTU * 2]byte
for i := 0; i < len(data.Packet) && i+14 < len(tmp); i++ {
tmp[i+14] = data.Packet[i]
}
data.Buffer = tmp
}
func (data *Packet) RecalculateChecksum() {
const (
IPProtocolTCP = 6
IPProtocolUDP = 17
)
if data.IsIPv6 {
// TODO
} else {
ipHeaderLen := int(data.Packet[0]&0x0f) << 2
copy(data.Packet[ipv4offsetChecksum:], []byte{0, 0})
ipChecksum := utils.ChecksumIPv4Header(data.Packet[:ipHeaderLen])
binary.BigEndian.PutUint16(data.Packet[ipv4offsetChecksum:], ipChecksum)
switch protocol := data.Packet[9]; protocol {
case IPProtocolTCP:
tcpOffsetChecksum := ipHeaderLen + 16
copy(data.Packet[tcpOffsetChecksum:], []byte{0, 0})
checksum := utils.ChecksumIPv4TCPUDP(data.Packet[ipHeaderLen:], uint32(protocol), data.Src, data.Dst)
binary.BigEndian.PutUint16(data.Packet[tcpOffsetChecksum:], checksum)
case IPProtocolUDP:
udpOffsetChecksum := ipHeaderLen + 6
copy(data.Packet[udpOffsetChecksum:], []byte{0, 0})
checksum := utils.ChecksumIPv4TCPUDP(data.Packet[ipHeaderLen:], uint32(protocol), data.Src, data.Dst)
binary.BigEndian.PutUint16(data.Packet[udpOffsetChecksum:], checksum)
}
}
}