safing-portmaster/network/packet/packet.go
2018-08-13 14:14:27 +02:00

316 lines
6.4 KiB
Go

// Copyright Safing ICS Technologies GmbH. Use of this source code is governed by the AGPL license that can be found in the LICENSE file.
package packet
import (
"fmt"
"net"
)
type (
IPVersion uint8
IPProtocol uint8
Verdict uint8
Endpoint bool
)
const (
IPv4 = IPVersion(4)
IPv6 = IPVersion(6)
InBound = true
OutBound = false
Local = true
Remote = false
// convenience
IGMP = IPProtocol(2)
RAW = IPProtocol(255)
TCP = IPProtocol(6)
UDP = IPProtocol(17)
ICMP = IPProtocol(1)
ICMPv6 = IPProtocol(58)
)
const (
DROP Verdict = iota
BLOCK
ACCEPT
STOLEN
QUEUE
REPEAT
STOP
)
// Returns the byte size of the ip, IPv4 = 4 bytes, IPv6 = 16
func (v IPVersion) ByteSize() int {
switch v {
case IPv4:
return 4
case IPv6:
return 16
}
return 0
}
func (v IPVersion) String() string {
switch v {
case IPv4:
return "IPv4"
case IPv6:
return "IPv6"
}
return fmt.Sprintf("<unknown ip version, %d>", uint8(v))
}
func (p IPProtocol) String() string {
switch p {
case RAW:
return "RAW"
case TCP:
return "TCP"
case UDP:
return "UDP"
case ICMP:
return "ICMP"
case ICMPv6:
return "ICMPv6"
case IGMP:
return "IGMP"
}
return fmt.Sprintf("<unknown protocol, %d>", uint8(p))
}
func (v Verdict) String() string {
switch v {
case DROP:
return "DROP"
case ACCEPT:
return "ACCEPT"
}
return fmt.Sprintf("<unsupported verdict, %d>", uint8(v))
}
type IPHeader struct {
Version IPVersion
Tos, TTL uint8
Protocol IPProtocol
Src, Dst net.IP
}
type TCPUDPHeader struct {
SrcPort, DstPort uint16
Checksum uint16 //not implemented
}
type PacketBase struct {
connectionID string
Direction bool
InTunnel bool
Payload []byte
*IPHeader
*TCPUDPHeader
}
func (pkt *PacketBase) GetIPHeader() *IPHeader {
return pkt.IPHeader
}
func (pkt *PacketBase) GetTCPUDPHeader() *TCPUDPHeader {
return pkt.TCPUDPHeader
}
func (pkt *PacketBase) GetPayload() []byte {
return pkt.Payload
}
func (pkt *PacketBase) SetInbound() {
pkt.Direction = true
}
func (pkt *PacketBase) SetOutbound() {
pkt.Direction = false
}
func (pkt *PacketBase) IsInbound() bool {
return pkt.Direction
}
func (pkt *PacketBase) IsOutbound() bool {
return !pkt.Direction
}
func (pkt *PacketBase) IPVersion() IPVersion {
return pkt.Version
}
func (pkt *PacketBase) GetConnectionID() string {
if pkt.connectionID == "" {
pkt.createConnectionID()
}
return pkt.connectionID
}
func (pkt *PacketBase) createConnectionID() {
if pkt.IPHeader.Protocol == TCP || pkt.IPHeader.Protocol == UDP {
if pkt.Direction {
pkt.connectionID = fmt.Sprintf("%d-%s-%d-%s-%d", pkt.Protocol, pkt.Dst, pkt.DstPort, pkt.Src, pkt.SrcPort)
} else {
pkt.connectionID = fmt.Sprintf("%d-%s-%d-%s-%d", pkt.Protocol, pkt.Src, pkt.SrcPort, pkt.Dst, pkt.DstPort)
}
} else {
if pkt.Direction {
pkt.connectionID = fmt.Sprintf("%d-%s-%s", pkt.Protocol, pkt.Dst, pkt.Src)
} else {
pkt.connectionID = fmt.Sprintf("%d-%s-%s", pkt.Protocol, pkt.Src, pkt.Dst)
}
}
}
// Matches checks if a the packet matches a given endpoint (remote or local) in protocol, network and port.
//
// IN OUT
// Local Dst Src
// Remote Src Dst
//
func (pkt *PacketBase) MatchesAddress(endpoint bool, protocol IPProtocol, network *net.IPNet, port uint16) bool {
if pkt.Protocol != protocol {
return false
}
if pkt.Direction != endpoint {
if !network.Contains(pkt.Src) {
return false
}
if port != 0 && pkt.TCPUDPHeader != nil {
if pkt.SrcPort != port {
return false
}
}
} else {
if !network.Contains(pkt.Dst) {
return false
}
if port != 0 && pkt.TCPUDPHeader != nil {
if pkt.DstPort != port {
return false
}
}
}
return true
}
func (pkt *PacketBase) MatchesIP(endpoint bool, network *net.IPNet) bool {
if pkt.Direction != endpoint {
if network.Contains(pkt.Src) {
return true
}
} else {
if network.Contains(pkt.Dst) {
return true
}
}
return false
}
// func (pkt *PacketBase) Accept() error {
// return nil
// }
//
// func (pkt *PacketBase) Drop() error {
// return nil
// }
//
// func (pkt *PacketBase) Block() error {
// return nil
// }
//
// func (pkt *PacketBase) Verdict(verdict Verdict) error {
// return nil
// }
// FORMATTING
func (pkt *PacketBase) String() string {
return pkt.FmtPacket()
}
// FmtPacket returns the most important information about the packet as a string
func (pkt *PacketBase) FmtPacket() string {
if pkt.IPHeader.Protocol == TCP || pkt.IPHeader.Protocol == UDP {
if pkt.Direction {
return fmt.Sprintf("IN %s %s:%d <-> %s:%d", pkt.Protocol, pkt.Dst, pkt.DstPort, pkt.Src, pkt.SrcPort)
}
return fmt.Sprintf("OUT %s %s:%d <-> %s:%d", pkt.Protocol, pkt.Src, pkt.SrcPort, pkt.Dst, pkt.DstPort)
}
if pkt.Direction {
return fmt.Sprintf("IN %s %s <-> %s", pkt.Protocol, pkt.Dst, pkt.Src)
}
return fmt.Sprintf("OUT %s %s <-> %s", pkt.Protocol, pkt.Src, pkt.Dst)
}
// FmtProtocol returns the protocol as a string
func (pkt *PacketBase) FmtProtocol() string {
return pkt.IPHeader.Protocol.String()
}
// FmtRemoteIP returns the remote IP address as a string
func (pkt *PacketBase) FmtRemoteIP() string {
if pkt.Direction {
return pkt.IPHeader.Src.String()
}
return pkt.IPHeader.Dst.String()
}
// FmtRemotePort returns the remote port as a string
func (pkt *PacketBase) FmtRemotePort() string {
if pkt.TCPUDPHeader != nil {
if pkt.Direction {
return fmt.Sprintf("%d", pkt.TCPUDPHeader.SrcPort)
}
return fmt.Sprintf("%d", pkt.TCPUDPHeader.DstPort)
}
return "-"
}
// FmtRemoteAddress returns the full remote address (protocol, IP, port) as a string
func (pkt *PacketBase) FmtRemoteAddress() string {
return fmt.Sprintf("%s:%s:%s", pkt.IPHeader.Protocol.String(), pkt.FmtRemoteIP(), pkt.FmtRemotePort())
}
// Packet is an interface to a network packet to provide object behaviour the same across all systems
type Packet interface {
// VERDICTS
Accept() error
Block() error
Drop() error
PermanentAccept() error
PermanentBlock() error
PermanentDrop() error
RerouteToNameserver() error
RerouteToTunnel() error
// INFO
GetIPHeader() *IPHeader
GetTCPUDPHeader() *TCPUDPHeader
GetPayload() []byte
IsInbound() bool
IsOutbound() bool
SetInbound()
SetOutbound()
GetConnectionID() string
IPVersion() IPVersion
// MATCHING
MatchesAddress(bool, IPProtocol, *net.IPNet, uint16) bool
MatchesIP(bool, *net.IPNet) bool
// FORMATTING
String() string
FmtPacket() string
FmtProtocol() string
FmtRemoteIP() string
FmtRemotePort() string
FmtRemoteAddress() string
}