mirror of
https://github.com/luscis/openlan.git
synced 2025-10-05 16:47:11 +08:00
533 lines
10 KiB
Go
Executable File
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]
|
|
}
|