mirror of
https://github.com/safing/portmaster
synced 2025-09-01 10:09:11 +00:00
146 lines
3 KiB
Go
146 lines
3 KiB
Go
package network
|
|
|
|
import (
|
|
"strconv"
|
|
"strings"
|
|
"sync"
|
|
|
|
"github.com/safing/portmaster/network/state"
|
|
|
|
"github.com/safing/portbase/database"
|
|
"github.com/safing/portbase/database/iterator"
|
|
"github.com/safing/portbase/database/query"
|
|
"github.com/safing/portbase/database/record"
|
|
"github.com/safing/portbase/database/storage"
|
|
"github.com/safing/portmaster/process"
|
|
)
|
|
|
|
var (
|
|
dnsConns = make(map[string]*Connection) // key: <PID>/Scope
|
|
dnsConnsLock sync.RWMutex
|
|
conns = make(map[string]*Connection) // key: Connection ID
|
|
connsLock sync.RWMutex
|
|
|
|
dbController *database.Controller
|
|
)
|
|
|
|
// StorageInterface provices a storage.Interface to the configuration manager.
|
|
type StorageInterface struct {
|
|
storage.InjectBase
|
|
}
|
|
|
|
// Get returns a database record.
|
|
func (s *StorageInterface) Get(key string) (record.Record, error) {
|
|
|
|
splitted := strings.Split(key, "/")
|
|
switch splitted[0] { //nolint:gocritic // TODO: implement full key space
|
|
case "tree":
|
|
switch len(splitted) {
|
|
case 2:
|
|
pid, err := strconv.Atoi(splitted[1])
|
|
if err == nil {
|
|
proc, ok := process.GetProcessFromStorage(pid)
|
|
if ok {
|
|
return proc, nil
|
|
}
|
|
}
|
|
case 3:
|
|
dnsConnsLock.RLock()
|
|
defer dnsConnsLock.RUnlock()
|
|
conn, ok := dnsConns[splitted[1]+"/"+splitted[2]]
|
|
if ok {
|
|
return conn, nil
|
|
}
|
|
case 4:
|
|
connsLock.RLock()
|
|
defer connsLock.RUnlock()
|
|
conn, ok := conns[splitted[3]]
|
|
if ok {
|
|
return conn, nil
|
|
}
|
|
}
|
|
case "system":
|
|
if len(splitted) >= 2 {
|
|
switch splitted[1] {
|
|
case "state":
|
|
return state.GetInfo(), nil
|
|
default:
|
|
}
|
|
}
|
|
}
|
|
|
|
return nil, storage.ErrNotFound
|
|
}
|
|
|
|
// Query returns a an iterator for the supplied query.
|
|
func (s *StorageInterface) Query(q *query.Query, local, internal bool) (*iterator.Iterator, error) {
|
|
it := iterator.New()
|
|
go s.processQuery(q, it)
|
|
// TODO: check local and internal
|
|
|
|
return it, nil
|
|
}
|
|
|
|
func (s *StorageInterface) processQuery(q *query.Query, it *iterator.Iterator) {
|
|
slashes := strings.Count(q.DatabaseKeyPrefix(), "/")
|
|
|
|
if slashes <= 1 {
|
|
// processes
|
|
for _, proc := range process.All() {
|
|
proc.Lock()
|
|
if q.Matches(proc) {
|
|
it.Next <- proc
|
|
}
|
|
proc.Unlock()
|
|
}
|
|
}
|
|
|
|
if slashes <= 2 {
|
|
// dns scopes only
|
|
dnsConnsLock.RLock()
|
|
for _, dnsConn := range dnsConns {
|
|
dnsConn.Lock()
|
|
if q.Matches(dnsConn) {
|
|
it.Next <- dnsConn
|
|
}
|
|
dnsConn.Unlock()
|
|
}
|
|
dnsConnsLock.RUnlock()
|
|
}
|
|
|
|
if slashes <= 3 {
|
|
// connections
|
|
connsLock.RLock()
|
|
for _, conn := range conns {
|
|
conn.Lock()
|
|
if q.Matches(conn) {
|
|
it.Next <- conn
|
|
}
|
|
conn.Unlock()
|
|
}
|
|
connsLock.RUnlock()
|
|
}
|
|
|
|
it.Finish(nil)
|
|
}
|
|
|
|
func registerAsDatabase() error {
|
|
_, err := database.Register(&database.Database{
|
|
Name: "network",
|
|
Description: "Network and Firewall Data",
|
|
StorageType: "injected",
|
|
PrimaryAPI: "",
|
|
})
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
controller, err := database.InjectDatabase("network", &StorageInterface{})
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
dbController = controller
|
|
process.SetDBController(dbController)
|
|
return nil
|
|
}
|