mirror of
https://github.com/safing/portmaster
synced 2025-09-01 10:09:11 +00:00
256 lines
6.6 KiB
Go
256 lines
6.6 KiB
Go
// +build windows
|
|
|
|
package iphelper
|
|
|
|
import (
|
|
"fmt"
|
|
"net"
|
|
"sync"
|
|
"time"
|
|
)
|
|
|
|
var (
|
|
tcp4Connections []*ConnectionEntry
|
|
tcp4Listeners []*ConnectionEntry
|
|
tcp6Connections []*ConnectionEntry
|
|
tcp6Listeners []*ConnectionEntry
|
|
|
|
udp4Connections []*ConnectionEntry
|
|
udp4Listeners []*ConnectionEntry
|
|
udp6Connections []*ConnectionEntry
|
|
udp6Listeners []*ConnectionEntry
|
|
|
|
ipHelper *IPHelper
|
|
lock sync.RWMutex
|
|
|
|
waitTime = 15 * time.Millisecond
|
|
)
|
|
|
|
func checkIPHelper() (err error) {
|
|
if ipHelper == nil {
|
|
ipHelper, err = New()
|
|
return err
|
|
}
|
|
return nil
|
|
}
|
|
|
|
// GetTCP4PacketInfo returns the pid of the given IPv4/TCP connection.
|
|
func GetTCP4PacketInfo(localIP net.IP, localPort uint16, remoteIP net.IP, remotePort uint16, pktDirection bool) (pid int, direction bool, err error) {
|
|
|
|
// search
|
|
pid, _ = search(tcp4Connections, tcp4Listeners, localIP, remoteIP, localPort, remotePort, pktDirection)
|
|
if pid >= 0 {
|
|
return pid, pktDirection, nil
|
|
}
|
|
|
|
for i := 0; i < 3; i++ {
|
|
// give kernel some time, then try again
|
|
// log.Tracef("process: giving kernel some time to think")
|
|
|
|
// if unable to find, refresh
|
|
lock.Lock()
|
|
err = checkIPHelper()
|
|
if err == nil {
|
|
tcp4Connections, tcp4Listeners, err = ipHelper.GetTables(TCP, IPv4)
|
|
}
|
|
lock.Unlock()
|
|
if err != nil {
|
|
return -1, pktDirection, err
|
|
}
|
|
|
|
// search
|
|
pid, _ = search(tcp4Connections, tcp4Listeners, localIP, remoteIP, localPort, remotePort, pktDirection)
|
|
if pid >= 0 {
|
|
return pid, pktDirection, nil
|
|
}
|
|
|
|
time.Sleep(waitTime)
|
|
}
|
|
|
|
return -1, pktDirection, nil
|
|
}
|
|
|
|
// GetTCP6PacketInfo returns the pid of the given IPv6/TCP connection.
|
|
func GetTCP6PacketInfo(localIP net.IP, localPort uint16, remoteIP net.IP, remotePort uint16, pktDirection bool) (pid int, direction bool, err error) {
|
|
|
|
// search
|
|
pid, _ = search(tcp6Connections, tcp6Listeners, localIP, remoteIP, localPort, remotePort, pktDirection)
|
|
if pid >= 0 {
|
|
return pid, pktDirection, nil
|
|
}
|
|
|
|
for i := 0; i < 3; i++ {
|
|
// give kernel some time, then try again
|
|
// log.Tracef("process: giving kernel some time to think")
|
|
|
|
// if unable to find, refresh
|
|
lock.Lock()
|
|
err = checkIPHelper()
|
|
if err == nil {
|
|
tcp6Connections, tcp6Listeners, err = ipHelper.GetTables(TCP, IPv6)
|
|
}
|
|
lock.Unlock()
|
|
if err != nil {
|
|
return -1, pktDirection, err
|
|
}
|
|
|
|
// search
|
|
pid, _ = search(tcp6Connections, tcp6Listeners, localIP, remoteIP, localPort, remotePort, pktDirection)
|
|
if pid >= 0 {
|
|
return pid, pktDirection, nil
|
|
}
|
|
|
|
time.Sleep(waitTime)
|
|
}
|
|
|
|
return -1, pktDirection, nil
|
|
}
|
|
|
|
// GetUDP4PacketInfo returns the pid of the given IPv4/UDP connection.
|
|
func GetUDP4PacketInfo(localIP net.IP, localPort uint16, remoteIP net.IP, remotePort uint16, pktDirection bool) (pid int, direction bool, err error) {
|
|
|
|
// search
|
|
pid, _ = search(udp4Connections, udp4Listeners, localIP, remoteIP, localPort, remotePort, pktDirection)
|
|
if pid >= 0 {
|
|
return pid, pktDirection, nil
|
|
}
|
|
|
|
for i := 0; i < 3; i++ {
|
|
// give kernel some time, then try again
|
|
// log.Tracef("process: giving kernel some time to think")
|
|
|
|
// if unable to find, refresh
|
|
lock.Lock()
|
|
err = checkIPHelper()
|
|
if err == nil {
|
|
udp4Connections, udp4Listeners, err = ipHelper.GetTables(UDP, IPv4)
|
|
}
|
|
lock.Unlock()
|
|
if err != nil {
|
|
return -1, pktDirection, err
|
|
}
|
|
|
|
// search
|
|
pid, _ = search(udp4Connections, udp4Listeners, localIP, remoteIP, localPort, remotePort, pktDirection)
|
|
if pid >= 0 {
|
|
return pid, pktDirection, nil
|
|
}
|
|
|
|
time.Sleep(waitTime)
|
|
}
|
|
|
|
return -1, pktDirection, nil
|
|
}
|
|
|
|
// GetUDP6PacketInfo returns the pid of the given IPv6/UDP connection.
|
|
func GetUDP6PacketInfo(localIP net.IP, localPort uint16, remoteIP net.IP, remotePort uint16, pktDirection bool) (pid int, direction bool, err error) {
|
|
|
|
// search
|
|
pid, _ = search(udp6Connections, udp6Listeners, localIP, remoteIP, localPort, remotePort, pktDirection)
|
|
if pid >= 0 {
|
|
return pid, pktDirection, nil
|
|
}
|
|
|
|
for i := 0; i < 3; i++ {
|
|
// give kernel some time, then try again
|
|
// log.Tracef("process: giving kernel some time to think")
|
|
|
|
// if unable to find, refresh
|
|
lock.Lock()
|
|
err = checkIPHelper()
|
|
if err == nil {
|
|
udp6Connections, udp6Listeners, err = ipHelper.GetTables(UDP, IPv6)
|
|
}
|
|
lock.Unlock()
|
|
if err != nil {
|
|
return -1, pktDirection, err
|
|
}
|
|
|
|
// search
|
|
pid, _ = search(udp6Connections, udp6Listeners, localIP, remoteIP, localPort, remotePort, pktDirection)
|
|
if pid >= 0 {
|
|
return pid, pktDirection, nil
|
|
}
|
|
|
|
time.Sleep(waitTime)
|
|
}
|
|
|
|
return -1, pktDirection, nil
|
|
}
|
|
|
|
func search(connections, listeners []*ConnectionEntry, localIP, remoteIP net.IP, localPort, remotePort uint16, pktDirection bool) (pid int, direction bool) {
|
|
lock.RLock()
|
|
defer lock.RUnlock()
|
|
|
|
if pktDirection {
|
|
// inbound
|
|
pid = searchListeners(listeners, localIP, localPort)
|
|
if pid >= 0 {
|
|
return pid, true
|
|
}
|
|
pid = searchConnections(connections, localIP, remoteIP, localPort, remotePort)
|
|
if pid >= 0 {
|
|
return pid, false
|
|
}
|
|
} else {
|
|
// outbound
|
|
pid = searchConnections(connections, localIP, remoteIP, localPort, remotePort)
|
|
if pid >= 0 {
|
|
return pid, false
|
|
}
|
|
pid = searchListeners(listeners, localIP, localPort)
|
|
if pid >= 0 {
|
|
return pid, true
|
|
}
|
|
}
|
|
|
|
return -1, pktDirection
|
|
}
|
|
|
|
func searchConnections(list []*ConnectionEntry, localIP, remoteIP net.IP, localPort, remotePort uint16) (pid int) {
|
|
|
|
for _, entry := range list {
|
|
if localPort == entry.localPort &&
|
|
remotePort == entry.remotePort &&
|
|
remoteIP.Equal(entry.remoteIP) &&
|
|
localIP.Equal(entry.localIP) {
|
|
return entry.pid
|
|
}
|
|
}
|
|
|
|
return -1
|
|
}
|
|
|
|
func searchListeners(list []*ConnectionEntry, localIP net.IP, localPort uint16) (pid int) {
|
|
|
|
for _, entry := range list {
|
|
if localPort == entry.localPort &&
|
|
(entry.localIP == nil || // nil IP means zero IP, see tables.go
|
|
localIP.Equal(entry.localIP)) {
|
|
return entry.pid
|
|
}
|
|
}
|
|
|
|
return -1
|
|
}
|
|
|
|
// GetActiveConnectionIDs returns all currently active connection IDs.
|
|
func GetActiveConnectionIDs() (connections []string) {
|
|
lock.Lock()
|
|
defer lock.Unlock()
|
|
|
|
for _, entry := range tcp4Connections {
|
|
connections = append(connections, fmt.Sprintf("%d-%s-%d-%s-%d", TCP, entry.localIP, entry.localPort, entry.remoteIP, entry.remotePort))
|
|
}
|
|
for _, entry := range tcp6Connections {
|
|
connections = append(connections, fmt.Sprintf("%d-%s-%d-%s-%d", TCP, entry.localIP, entry.localPort, entry.remoteIP, entry.remotePort))
|
|
}
|
|
for _, entry := range udp4Connections {
|
|
connections = append(connections, fmt.Sprintf("%d-%s-%d-%s-%d", UDP, entry.localIP, entry.localPort, entry.remoteIP, entry.remotePort))
|
|
}
|
|
for _, entry := range udp6Connections {
|
|
connections = append(connections, fmt.Sprintf("%d-%s-%d-%s-%d", UDP, entry.localIP, entry.localPort, entry.remoteIP, entry.remotePort))
|
|
}
|
|
|
|
return
|
|
}
|