Files
openlan/pkg/libol/protocol.go
2022-07-29 23:38:54 +08:00

533 lines
10 KiB
Go
Executable File

package libol
import (
"encoding/binary"
"fmt"
)
var (
EthZero = []byte{0x00, 0x00, 0x00, 0x00, 0x00, 0x00}
EthAll = []byte{0xff, 0xff, 0xff, 0xff, 0xff, 0xff}
)
const (
EthArp = 0x0806
EthIp4 = 0x0800
EthIp6 = 0x86DD
EthVlan = 0x8100
)
type Ether struct {
Dst []byte
Src []byte
Type uint16
Len int
}
const (
EtherLen = 14
VlanLen = 4
TcpLen = 20
Ipv4Len = 20
UdpLen = 8
)
func NewEther(t uint16) (e *Ether) {
e = &Ether{
Type: t,
Src: make([]byte, 6),
Dst: make([]byte, 6),
Len: EtherLen,
}
return
}
func NewEtherArp() (e *Ether) {
return NewEther(EthArp)
}
func NewEtherIP4() (e *Ether) {
return NewEther(EthIp4)
}
func NewEtherFromFrame(frame []byte) (e *Ether, err error) {
e = NewEther(0)
err = e.Decode(frame)
return
}
func (e *Ether) Decode(frame []byte) error {
if len(frame) < 14 {
return NewErr("Ether.Decode too small header: %d", len(frame))
}
copy(e.Dst[:6], frame[:6])
copy(e.Src[:6], frame[6:12])
e.Type = binary.BigEndian.Uint16(frame[12:14])
e.Len = 14
return nil
}
func (e *Ether) Encode() []byte {
buffer := make([]byte, 14)
copy(buffer[:6], e.Dst[:6])
copy(buffer[6:12], e.Src[:6])
binary.BigEndian.PutUint16(buffer[12:14], e.Type)
return buffer[:14]
}
func (e *Ether) IsVlan() bool {
return e.Type == EthVlan
}
func (e *Ether) IsArp() bool {
return e.Type == EthArp
}
func (e *Ether) IsIP4() bool {
return e.Type == EthIp4
}
type Vlan struct {
Tci uint16
Vid uint16
Pro uint16
Len int
}
func NewVlan(tci uint16, vid uint16) (n *Vlan) {
n = &Vlan{
Tci: tci,
Vid: vid,
Len: VlanLen,
}
return
}
func NewVlanFromFrame(frame []byte) (n *Vlan, err error) {
n = &Vlan{
Len: VlanLen,
}
err = n.Decode(frame)
return
}
func (n *Vlan) Decode(frame []byte) error {
if len(frame) < VlanLen {
return NewErr("Vlan.Decode: too small header")
}
v := binary.BigEndian.Uint16(frame[0:2])
n.Tci = uint16(v >> 12)
n.Vid = uint16(0x0fff & v)
n.Pro = binary.BigEndian.Uint16(frame[2:4])
return nil
}
func (n *Vlan) Encode() []byte {
buffer := make([]byte, 16)
v := (n.Tci << 12) | n.Vid
binary.BigEndian.PutUint16(buffer[0:2], v)
binary.BigEndian.PutUint16(buffer[2:4], n.Pro)
return buffer[:4]
}
const (
ArpRequest = 1
ArpReply = 2
)
const (
ArpHrdNetrom = 0
ArpHrdEther = 1
)
type Arp struct {
HrdCode uint16 // format hardware address
ProCode uint16 // format protocol address
HrdLen uint8 // length of hardware address
ProLen uint8 // length of protocol address
OpCode uint16 // ARP Op(command)
SHwAddr []byte // sender hardware address.
SIpAddr []byte // sender IP address.
THwAddr []byte // target hardware address.
TIpAddr []byte // target IP address.
Len int
}
func NewArp() (a *Arp) {
a = &Arp{
HrdCode: ArpHrdEther,
ProCode: EthIp4,
HrdLen: 6,
ProLen: 4,
OpCode: ArpRequest,
Len: 0,
SHwAddr: make([]byte, 6),
SIpAddr: make([]byte, 4),
THwAddr: make([]byte, 6),
TIpAddr: make([]byte, 4),
}
return
}
func NewArpFromFrame(frame []byte) (a *Arp, err error) {
a = NewArp()
err = a.Decode(frame)
return
}
func (a *Arp) Decode(frame []byte) error {
var err error
if len(frame) < 8 {
return NewErr("Arp.Decode: too small header: %d", len(frame))
}
a.HrdCode = binary.BigEndian.Uint16(frame[0:2])
a.ProCode = binary.BigEndian.Uint16(frame[2:4])
a.HrdLen = uint8(frame[4])
a.ProLen = uint8(frame[5])
if a.HrdLen != 6 || a.ProLen != 4 {
return NewErr("Arp.Decode: AddrLen: %d,%d", a.HrdLen, a.ProLen)
}
a.OpCode = binary.BigEndian.Uint16(frame[6:8])
p := uint8(8)
if len(frame) < int(p+2*(a.HrdLen+a.ProLen)) {
return NewErr("Arp.Decode: too small frame: %d", len(frame))
}
copy(a.SHwAddr[:6], frame[p:p+6])
p += a.HrdLen
copy(a.SIpAddr[:4], frame[p:p+4])
p += a.ProLen
copy(a.THwAddr[:6], frame[p:p+6])
p += a.HrdLen
copy(a.TIpAddr[:4], frame[p:p+4])
p += a.ProLen
a.Len = int(p)
return err
}
func (a *Arp) Encode() []byte {
buffer := make([]byte, 1024)
binary.BigEndian.PutUint16(buffer[0:2], a.HrdCode)
binary.BigEndian.PutUint16(buffer[2:4], a.ProCode)
buffer[4] = byte(a.HrdLen)
buffer[5] = byte(a.ProLen)
binary.BigEndian.PutUint16(buffer[6:8], a.OpCode)
p := uint8(8)
copy(buffer[p:p+a.HrdLen], a.SHwAddr[0:a.HrdLen])
p += a.HrdLen
copy(buffer[p:p+a.ProLen], a.SIpAddr[0:a.ProLen])
p += a.ProLen
copy(buffer[p:p+a.HrdLen], a.THwAddr[0:a.HrdLen])
p += a.HrdLen
copy(buffer[p:p+a.ProLen], a.TIpAddr[0:a.ProLen])
p += a.ProLen
a.Len = int(p)
return buffer[:p]
}
func (a *Arp) IsIP4() bool {
return a.ProCode == EthIp4
}
func (a *Arp) IsReply() bool {
return a.OpCode == ArpReply
}
func (a *Arp) IsRequest() bool {
return a.OpCode == ArpRequest
}
const (
Ipv4Ver = 0x04
Ipv6Ver = 0x06
)
const (
IpIcmp = 0x01
IpIgmp = 0x02
IpIpIp = 0x04
IpTcp = 0x06
IpUdp = 0x11
IpEsp = 0x32
IpAh = 0x33
IpOspf = 0x59
IpPim = 0x67
IpVrrp = 0x70
IpIsis = 0x7c
)
func IpProto2Str(proto uint8) string {
switch proto {
case IpIcmp:
return "icmp"
case IpIgmp:
return "igmp"
case IpIpIp:
return "ipip"
case IpEsp:
return "esp"
case IpAh:
return "ah"
case IpOspf:
return "ospf"
case IpIsis:
return "isis"
case IpUdp:
return "udp"
case IpTcp:
return "tcp"
case IpPim:
return "pim"
case IpVrrp:
return "vrrp"
default:
return fmt.Sprintf("%02x", proto)
}
}
type Ipv4 struct {
Version uint8 //4bite v4: 0100, v6: 0110
HeaderLen uint8 //4bit 15*4
ToS uint8 //Type of Service
TotalLen uint16
Identifier uint16
Flag uint16 //3bit Z|DF|MF
Offset uint16 //13bit Fragment offset
ToL uint8 //Time of Live
Protocol uint8
HeaderChecksum uint16 //Header Checksum
Source []byte
Destination []byte
Options uint32 //Reserved
Len int
}
func NewIpv4() (i *Ipv4) {
i = &Ipv4{
Version: 0x04,
HeaderLen: 0x05,
ToS: 0,
TotalLen: 0,
Identifier: 0,
Flag: 0,
Offset: 0,
ToL: 0xff,
Protocol: 0,
HeaderChecksum: 0,
Options: 0,
Len: Ipv4Len,
Source: make([]byte, 4),
Destination: make([]byte, 4),
}
return
}
func NewIpv4FromFrame(frame []byte) (i *Ipv4, err error) {
i = NewIpv4()
err = i.Decode(frame)
return
}
func (i *Ipv4) Decode(frame []byte) error {
if len(frame) < Ipv4Len {
return NewErr("Ipv4.Decode: too small header: %d", len(frame))
}
h := uint8(frame[0])
i.Version = h >> 4
i.HeaderLen = h & 0x0f
i.ToS = uint8(frame[1])
i.TotalLen = binary.BigEndian.Uint16(frame[2:4])
i.Identifier = binary.BigEndian.Uint16(frame[4:6])
f := binary.BigEndian.Uint16(frame[6:8])
i.Offset = f & 0x1fFf
i.Flag = f >> 13
i.ToL = uint8(frame[8])
i.Protocol = uint8(frame[9])
i.HeaderChecksum = binary.BigEndian.Uint16(frame[10:12])
if !i.IsIP4() {
return NewErr("Ipv4.Decode: not right ipv4 version: 0x%x", i.Version)
}
copy(i.Source[:4], frame[12:16])
copy(i.Destination[:4], frame[16:20])
return nil
}
func (i *Ipv4) Encode() []byte {
buffer := make([]byte, 32)
h := uint8((i.Version << 4) | i.HeaderLen)
buffer[0] = h
buffer[1] = i.ToS
binary.BigEndian.PutUint16(buffer[2:4], i.TotalLen)
binary.BigEndian.PutUint16(buffer[4:6], i.Identifier)
f := uint16((i.Flag << 13) | i.Offset)
binary.BigEndian.PutUint16(buffer[6:8], f)
buffer[8] = i.ToL
buffer[9] = i.Protocol
binary.BigEndian.PutUint16(buffer[10:12], i.HeaderChecksum)
copy(buffer[12:16], i.Source[:4])
copy(buffer[16:20], i.Destination[:4])
return buffer[:i.Len]
}
func (i *Ipv4) IsIP4() bool {
return i.Version == Ipv4Ver
}
const (
TcpUrg = 0x20
TcpAck = 0x10
TcpPsh = 0x08
TcpRst = 0x04
TcpSyn = 0x02
TcpFin = 0x01
)
type Tcp struct {
Source uint16
Destination uint16
Sequence uint32
Acknowledgment uint32
DataOffset uint8
ControlBits uint8
Window uint16
Checksum uint16
UrgentPointer uint16
Options []byte
Padding []byte
Len int
}
func NewTcp() (t *Tcp) {
t = &Tcp{
Source: 0,
Destination: 0,
Sequence: 0,
Acknowledgment: 0,
DataOffset: 0,
ControlBits: 0,
Window: 0,
Checksum: 0,
UrgentPointer: 0,
Len: TcpLen,
}
return
}
func NewTcpFromFrame(frame []byte) (t *Tcp, err error) {
t = NewTcp()
err = t.Decode(frame)
return
}
func (t *Tcp) Decode(frame []byte) error {
if len(frame) < TcpLen {
return NewErr("Tcp.Decode: too small header: %d", len(frame))
}
t.Source = binary.BigEndian.Uint16(frame[0:2])
t.Destination = binary.BigEndian.Uint16(frame[2:4])
t.Sequence = binary.BigEndian.Uint32(frame[4:8])
t.Acknowledgment = binary.BigEndian.Uint32(frame[8:12])
t.DataOffset = uint8(frame[12])
t.ControlBits = uint8(frame[13])
t.Window = binary.BigEndian.Uint16(frame[14:16])
t.Checksum = binary.BigEndian.Uint16(frame[16:18])
t.UrgentPointer = binary.BigEndian.Uint16(frame[18:20])
return nil
}
func (t *Tcp) Encode() []byte {
buffer := make([]byte, 32)
binary.BigEndian.PutUint16(buffer[0:2], t.Source)
binary.BigEndian.PutUint16(buffer[2:4], t.Destination)
binary.BigEndian.PutUint32(buffer[4:8], t.Sequence)
binary.BigEndian.PutUint32(buffer[8:12], t.Acknowledgment)
buffer[12] = t.DataOffset
buffer[13] = t.ControlBits
binary.BigEndian.PutUint16(buffer[14:16], t.Window)
binary.BigEndian.PutUint16(buffer[16:18], t.Checksum)
binary.BigEndian.PutUint16(buffer[18:20], t.UrgentPointer)
return buffer[:t.Len]
}
func (t *Tcp) HasFlag(flag uint8) bool {
return t.ControlBits&flag == flag
}
type Udp struct {
Source uint16
Destination uint16
Length uint16
Checksum uint16
Len int
}
func NewUdp() (u *Udp) {
u = &Udp{
Source: 0,
Destination: 0,
Length: 0,
Checksum: 0,
Len: UdpLen,
}
return
}
func NewUdpFromFrame(frame []byte) (u *Udp, err error) {
u = NewUdp()
err = u.Decode(frame)
return
}
func (u *Udp) Decode(frame []byte) error {
if len(frame) < UdpLen {
return NewErr("Udp.Decode: too small header: %d", len(frame))
}
u.Source = binary.BigEndian.Uint16(frame[0:2])
u.Destination = binary.BigEndian.Uint16(frame[2:4])
u.Length = binary.BigEndian.Uint16(frame[4:6])
u.Checksum = binary.BigEndian.Uint16(frame[6:8])
return nil
}
func (u *Udp) Encode() []byte {
buffer := make([]byte, 32)
binary.BigEndian.PutUint16(buffer[0:2], u.Source)
binary.BigEndian.PutUint16(buffer[2:4], u.Destination)
binary.BigEndian.PutUint16(buffer[4:6], u.Length)
binary.BigEndian.PutUint16(buffer[6:8], u.Checksum)
return buffer[:u.Len]
}