safing-portmaster/firewall/interception/windowskext/handler.go
2020-10-15 12:18:57 +02:00

135 lines
2.9 KiB
Go

// +build windows
package windowskext
import (
"encoding/binary"
"errors"
"net"
"github.com/tevino/abool"
"github.com/safing/portbase/log"
"github.com/safing/portmaster/network/packet"
)
// VerdictRequest is the request structure from the Kext.
type VerdictRequest struct {
id uint32 // ID from RegisterPacket
_ uint64 // Process ID - does not yet work
direction uint8
ipV6 uint8 // True: IPv6, False: IPv4
protocol uint8 // Protocol
_ uint8
localIP [4]uint32 // Source Address
remoteIP [4]uint32 // Destination Address
localPort uint16 // Source Port
remotePort uint16 // Destination port
_ uint32 // compartmentID
_ uint32 // interfaceIndex
_ uint32 // subInterfaceIndex
packetSize uint32
}
// Handler transforms received packets to the Packet interface.
func Handler(packets chan packet.Packet) {
if !ready.IsSet() {
return
}
defer close(packets)
for {
if !ready.IsSet() {
return
}
packetInfo, err := RecvVerdictRequest()
if err != nil {
// Check if we are done with processing.
if errors.Is(err, ErrKextNotReady) {
return
}
log.Warningf("failed to get packet from windows kext: %s", err)
continue
}
if packetInfo == nil {
continue
}
// log.Tracef("packet: %+v", packetInfo)
// New Packet
new := &Packet{
verdictRequest: packetInfo,
verdictSet: abool.NewBool(false),
}
info := new.Info()
info.Inbound = packetInfo.direction > 0
info.InTunnel = false
info.Protocol = packet.IPProtocol(packetInfo.protocol)
// IP version
if packetInfo.ipV6 == 1 {
info.Version = packet.IPv6
} else {
info.Version = packet.IPv4
}
// IPs
if info.Version == packet.IPv4 {
// IPv4
if info.Inbound {
// Inbound
info.Src = convertIPv4(packetInfo.remoteIP)
info.Dst = convertIPv4(packetInfo.localIP)
} else {
// Outbound
info.Src = convertIPv4(packetInfo.localIP)
info.Dst = convertIPv4(packetInfo.remoteIP)
}
} else {
// IPv6
if info.Inbound {
// Inbound
info.Src = convertIPv6(packetInfo.remoteIP)
info.Dst = convertIPv6(packetInfo.localIP)
} else {
// Outbound
info.Src = convertIPv6(packetInfo.localIP)
info.Dst = convertIPv6(packetInfo.remoteIP)
}
}
// Ports
if info.Inbound {
// Inbound
info.SrcPort = packetInfo.remotePort
info.DstPort = packetInfo.localPort
} else {
// Outbound
info.SrcPort = packetInfo.localPort
info.DstPort = packetInfo.remotePort
}
packets <- new
}
}
// convertIPv4 as needed for data from the kernel
func convertIPv4(input [4]uint32) net.IP {
addressBuf := make([]byte, 4)
binary.BigEndian.PutUint32(addressBuf, input[0])
return net.IP(addressBuf)
}
func convertIPv6(input [4]uint32) net.IP {
addressBuf := make([]byte, 16)
for i := 0; i < 4; i++ {
binary.BigEndian.PutUint32(addressBuf[i*4:i*4+4], input[i])
}
return net.IP(addressBuf)
}