mirror of
https://github.com/safing/portmaster
synced 2025-04-25 13:29:10 +00:00
* Move portbase into monorepo * Add new simple module mgr * [WIP] Switch to new simple module mgr * Add StateMgr and more worker variants * [WIP] Switch more modules * [WIP] Switch more modules * [WIP] swtich more modules * [WIP] switch all SPN modules * [WIP] switch all service modules * [WIP] Convert all workers to the new module system * [WIP] add new task system to module manager * [WIP] Add second take for scheduling workers * [WIP] Add FIXME for bugs in new scheduler * [WIP] Add minor improvements to scheduler * [WIP] Add new worker scheduler * [WIP] Fix more bug related to new module system * [WIP] Fix start handing of the new module system * [WIP] Improve startup process * [WIP] Fix minor issues * [WIP] Fix missing subsystem in settings * [WIP] Initialize managers in constructor * [WIP] Move module event initialization to constrictors * [WIP] Fix setting for enabling and disabling the SPN module * [WIP] Move API registeration into module construction * [WIP] Update states mgr for all modules * [WIP] Add CmdLine operation support * Add state helper methods to module group and instance * Add notification and module status handling to status package * Fix starting issues * Remove pilot widget and update security lock to new status data * Remove debug logs * Improve http server shutdown * Add workaround for cleanly shutting down firewall+netquery * Improve logging * Add syncing states with notifications for new module system * Improve starting, stopping, shutdown; resolve FIXMEs/TODOs * [WIP] Fix most unit tests * Review new module system and fix minor issues * Push shutdown and restart events again via API * Set sleep mode via interface * Update example/template module * [WIP] Fix spn/cabin unit test * Remove deprecated UI elements * Make log output more similar for the logging transition phase * Switch spn hub and observer cmds to new module system * Fix log sources * Make worker mgr less error prone * Fix tests and minor issues * Fix observation hub * Improve shutdown and restart handling * Split up big connection.go source file * Move varint and dsd packages to structures repo * Improve expansion test * Fix linter warnings * Fix interception module on windows * Fix linter errors --------- Co-authored-by: Vladimir Stoilov <vladimir@safing.io>
220 lines
6 KiB
Go
220 lines
6 KiB
Go
package ships
|
|
|
|
import (
|
|
"errors"
|
|
"fmt"
|
|
"net"
|
|
|
|
"github.com/tevino/abool"
|
|
|
|
"github.com/safing/portmaster/base/log"
|
|
"github.com/safing/portmaster/spn/hub"
|
|
)
|
|
|
|
const (
|
|
defaultLoadSize = 4096
|
|
)
|
|
|
|
// ErrSunk is returned when a ship sunk, ie. the connection was lost.
|
|
var ErrSunk = errors.New("ship sunk")
|
|
|
|
// Ship represents a network layer connection.
|
|
type Ship interface {
|
|
// String returns a human readable informational summary about the ship.
|
|
String() string
|
|
|
|
// Transport returns the transport used for this ship.
|
|
Transport() *hub.Transport
|
|
|
|
// IsMine returns whether the ship was launched from here.
|
|
IsMine() bool
|
|
|
|
// IsSecure returns whether the ship provides transport security.
|
|
IsSecure() bool
|
|
|
|
// Public returns whether the ship is marked as public.
|
|
Public() bool
|
|
|
|
// MarkPublic marks the ship as public.
|
|
MarkPublic()
|
|
|
|
// LoadSize returns the recommended data size that should be handed to Load().
|
|
// This value will be most likely somehow related to the connection's MTU.
|
|
// Alternatively, using a multiple of LoadSize is also recommended.
|
|
LoadSize() int
|
|
|
|
// Load loads data into the ship - ie. sends the data via the connection.
|
|
// Returns ErrSunk if the ship has already sunk earlier.
|
|
Load(data []byte) error
|
|
|
|
// UnloadTo unloads data from the ship - ie. receives data from the
|
|
// connection - puts it into the buf. It returns the amount of data
|
|
// written and an optional error.
|
|
// Returns ErrSunk if the ship has already sunk earlier.
|
|
UnloadTo(buf []byte) (n int, err error)
|
|
|
|
// LocalAddr returns the underlying local net.Addr of the connection.
|
|
LocalAddr() net.Addr
|
|
|
|
// RemoteAddr returns the underlying remote net.Addr of the connection.
|
|
RemoteAddr() net.Addr
|
|
|
|
// Sink closes the underlying connection and cleans up any related resources.
|
|
Sink()
|
|
|
|
// MaskAddress masks the address, if enabled.
|
|
MaskAddress(addr net.Addr) string
|
|
// MaskIP masks an IP, if enabled.
|
|
MaskIP(ip net.IP) string
|
|
// Mask masks a value.
|
|
Mask(value []byte) string
|
|
}
|
|
|
|
// ShipBase implements common functions to comply with the Ship interface.
|
|
type ShipBase struct {
|
|
// conn is the actual underlying connection.
|
|
conn net.Conn
|
|
// transport holds the transport definition of the ship.
|
|
transport *hub.Transport
|
|
|
|
// mine specifies whether the ship was launched from here.
|
|
mine bool
|
|
// secure specifies whether the ship provides transport security.
|
|
secure bool
|
|
// public specifies whether the ship is public.
|
|
public *abool.AtomicBool
|
|
// bufSize specifies the size of the receive buffer.
|
|
bufSize int
|
|
// loadSize specifies the recommended data size that should be handed to Load().
|
|
loadSize int
|
|
|
|
// initial holds initial data from setting up the ship.
|
|
initial []byte
|
|
// sinking specifies if the connection is being closed.
|
|
sinking *abool.AtomicBool
|
|
}
|
|
|
|
func (ship *ShipBase) initBase() {
|
|
// init
|
|
ship.sinking = abool.New()
|
|
ship.public = abool.New()
|
|
|
|
// set default
|
|
if ship.loadSize == 0 {
|
|
ship.loadSize = defaultLoadSize
|
|
}
|
|
if ship.bufSize == 0 {
|
|
ship.bufSize = ship.loadSize
|
|
}
|
|
}
|
|
|
|
// String returns a human readable informational summary about the ship.
|
|
func (ship *ShipBase) String() string {
|
|
if ship.mine {
|
|
return fmt.Sprintf("<Ship to %s using %s>", ship.MaskAddress(ship.RemoteAddr()), ship.transport)
|
|
}
|
|
return fmt.Sprintf("<Ship from %s using %s>", ship.MaskAddress(ship.RemoteAddr()), ship.transport)
|
|
}
|
|
|
|
// Transport returns the transport used for this ship.
|
|
func (ship *ShipBase) Transport() *hub.Transport {
|
|
return ship.transport
|
|
}
|
|
|
|
// IsMine returns whether the ship was launched from here.
|
|
func (ship *ShipBase) IsMine() bool {
|
|
return ship.mine
|
|
}
|
|
|
|
// IsSecure returns whether the ship provides transport security.
|
|
func (ship *ShipBase) IsSecure() bool {
|
|
return ship.secure
|
|
}
|
|
|
|
// Public returns whether the ship is marked as public.
|
|
func (ship *ShipBase) Public() bool {
|
|
return ship.public.IsSet()
|
|
}
|
|
|
|
// MarkPublic marks the ship as public.
|
|
func (ship *ShipBase) MarkPublic() {
|
|
ship.public.Set()
|
|
}
|
|
|
|
// LoadSize returns the recommended data size that should be handed to Load().
|
|
// This value will be most likely somehow related to the connection's MTU.
|
|
// Alternatively, using a multiple of LoadSize is also recommended.
|
|
func (ship *ShipBase) LoadSize() int {
|
|
return ship.loadSize
|
|
}
|
|
|
|
// Load loads data into the ship - ie. sends the data via the connection.
|
|
// Returns ErrSunk if the ship has already sunk earlier.
|
|
func (ship *ShipBase) Load(data []byte) error {
|
|
// Empty load is used as a signal to cease operaetion.
|
|
if len(data) == 0 {
|
|
if ship.sinking.SetToIf(false, true) {
|
|
_ = ship.conn.Close()
|
|
}
|
|
return nil
|
|
}
|
|
|
|
// Send all given data.
|
|
n, err := ship.conn.Write(data)
|
|
switch {
|
|
case err != nil:
|
|
return err
|
|
case n == 0:
|
|
return errors.New("loaded 0 bytes")
|
|
case n < len(data):
|
|
// If not all data was sent, try again.
|
|
log.Debugf("spn/ships: %s only loaded %d/%d bytes", ship, n, len(data))
|
|
data = data[n:]
|
|
return ship.Load(data)
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
// UnloadTo unloads data from the ship - ie. receives data from the
|
|
// connection - puts it into the buf. It returns the amount of data
|
|
// written and an optional error.
|
|
// Returns ErrSunk if the ship has already sunk earlier.
|
|
func (ship *ShipBase) UnloadTo(buf []byte) (n int, err error) {
|
|
// Process initial data, if there is any.
|
|
if ship.initial != nil {
|
|
// Copy as much data as possible.
|
|
copy(buf, ship.initial)
|
|
|
|
// If buf was too small, skip the copied section.
|
|
if len(buf) < len(ship.initial) {
|
|
ship.initial = ship.initial[len(buf):]
|
|
return len(buf), nil
|
|
}
|
|
|
|
// If everything was copied, unset the initial data.
|
|
n := len(ship.initial)
|
|
ship.initial = nil
|
|
return n, nil
|
|
}
|
|
|
|
// Receive data.
|
|
return ship.conn.Read(buf)
|
|
}
|
|
|
|
// LocalAddr returns the underlying local net.Addr of the connection.
|
|
func (ship *ShipBase) LocalAddr() net.Addr {
|
|
return ship.conn.LocalAddr()
|
|
}
|
|
|
|
// RemoteAddr returns the underlying remote net.Addr of the connection.
|
|
func (ship *ShipBase) RemoteAddr() net.Addr {
|
|
return ship.conn.RemoteAddr()
|
|
}
|
|
|
|
// Sink closes the underlying connection and cleans up any related resources.
|
|
func (ship *ShipBase) Sink() {
|
|
if ship.sinking.SetToIf(false, true) {
|
|
_ = ship.conn.Close()
|
|
}
|
|
}
|