mirror of
https://github.com/safing/portmaster
synced 2025-04-21 03:19: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>
210 lines
5.3 KiB
Go
210 lines
5.3 KiB
Go
package terminal
|
|
|
|
import (
|
|
"context"
|
|
|
|
"github.com/safing/jess"
|
|
"github.com/safing/portmaster/spn/cabin"
|
|
"github.com/safing/portmaster/spn/hub"
|
|
"github.com/safing/structures/container"
|
|
"github.com/safing/structures/dsd"
|
|
"github.com/safing/structures/varint"
|
|
)
|
|
|
|
/*
|
|
|
|
Terminal Init Message Format:
|
|
|
|
- Version [varint]
|
|
- Data Block [bytes; not blocked]
|
|
- TerminalOpts as DSD
|
|
|
|
*/
|
|
|
|
const (
|
|
minSupportedTerminalVersion = 1
|
|
maxSupportedTerminalVersion = 1
|
|
)
|
|
|
|
// TerminalOpts holds configuration for the terminal.
|
|
type TerminalOpts struct { //nolint:golint,maligned // TODO: Rename.
|
|
Version uint8 `json:"-"`
|
|
Encrypt bool `json:"e,omitempty"`
|
|
Padding uint16 `json:"p,omitempty"`
|
|
|
|
FlowControl FlowControlType `json:"fc,omitempty"`
|
|
FlowControlSize uint32 `json:"qs,omitempty"` // Previously was "QueueSize".
|
|
|
|
UsePriorityDataMsgs bool `json:"pr,omitempty"`
|
|
}
|
|
|
|
// ParseTerminalOpts parses terminal options from the container and checks if
|
|
// they are valid.
|
|
func ParseTerminalOpts(c *container.Container) (*TerminalOpts, *Error) {
|
|
// Parse and check version.
|
|
version, err := c.GetNextN8()
|
|
if err != nil {
|
|
return nil, ErrMalformedData.With("failed to parse version: %w", err)
|
|
}
|
|
if version < minSupportedTerminalVersion || version > maxSupportedTerminalVersion {
|
|
return nil, ErrUnsupportedVersion.With("requested terminal version %d", version)
|
|
}
|
|
|
|
// Parse init message.
|
|
initMsg := &TerminalOpts{}
|
|
_, err = dsd.Load(c.CompileData(), initMsg)
|
|
if err != nil {
|
|
return nil, ErrMalformedData.With("failed to parse init message: %w", err)
|
|
}
|
|
initMsg.Version = version
|
|
|
|
// Check if options are valid.
|
|
tErr := initMsg.Check(false)
|
|
if tErr != nil {
|
|
return nil, tErr
|
|
}
|
|
|
|
return initMsg, nil
|
|
}
|
|
|
|
// Pack serialized the terminal options and checks if they are valid.
|
|
func (opts *TerminalOpts) Pack() (*container.Container, *Error) {
|
|
// Check if options are valid.
|
|
tErr := opts.Check(true)
|
|
if tErr != nil {
|
|
return nil, tErr
|
|
}
|
|
|
|
// Pack init message.
|
|
optsData, err := dsd.Dump(opts, dsd.CBOR)
|
|
if err != nil {
|
|
return nil, ErrInternalError.With("failed to pack init message: %w", err)
|
|
}
|
|
|
|
// Compile init message.
|
|
return container.New(
|
|
varint.Pack8(opts.Version),
|
|
optsData,
|
|
), nil
|
|
}
|
|
|
|
// Check checks if terminal options are valid.
|
|
func (opts *TerminalOpts) Check(useDefaultsForRequired bool) *Error {
|
|
// Version is required - use default when permitted.
|
|
if opts.Version == 0 && useDefaultsForRequired {
|
|
opts.Version = 1
|
|
}
|
|
if opts.Version < minSupportedTerminalVersion || opts.Version > maxSupportedTerminalVersion {
|
|
return ErrInvalidOptions.With("unsupported terminal version %d", opts.Version)
|
|
}
|
|
|
|
// FlowControl is optional.
|
|
switch opts.FlowControl {
|
|
case FlowControlDefault:
|
|
// Set to default flow control.
|
|
opts.FlowControl = defaultFlowControl
|
|
case FlowControlNone, FlowControlDFQ:
|
|
// Ok.
|
|
default:
|
|
return ErrInvalidOptions.With("unknown flow control type: %d", opts.FlowControl)
|
|
}
|
|
|
|
// FlowControlSize is required as it needs to be same on both sides.
|
|
// Use default when permitted.
|
|
if opts.FlowControlSize == 0 && useDefaultsForRequired {
|
|
opts.FlowControlSize = opts.FlowControl.DefaultSize()
|
|
}
|
|
if opts.FlowControlSize <= 0 || opts.FlowControlSize > MaxQueueSize {
|
|
return ErrInvalidOptions.With("invalid flow control size of %d", opts.FlowControlSize)
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
// NewLocalBaseTerminal creates a new local terminal base for use with inheriting terminals.
|
|
func NewLocalBaseTerminal(
|
|
ctx context.Context,
|
|
id uint32,
|
|
parentID string,
|
|
remoteHub *hub.Hub,
|
|
initMsg *TerminalOpts,
|
|
upstream Upstream,
|
|
) (
|
|
t *TerminalBase,
|
|
initData *container.Container,
|
|
err *Error,
|
|
) {
|
|
// Pack, check and add defaults to init message.
|
|
initData, err = initMsg.Pack()
|
|
if err != nil {
|
|
return nil, nil, err
|
|
}
|
|
|
|
// Create baseline.
|
|
t, err = createTerminalBase(ctx, id, parentID, false, initMsg, upstream)
|
|
if err != nil {
|
|
return nil, nil, err
|
|
}
|
|
|
|
// Setup encryption if enabled.
|
|
if remoteHub != nil {
|
|
initMsg.Encrypt = true
|
|
|
|
// Select signet (public key) of remote Hub to use.
|
|
s := remoteHub.SelectSignet()
|
|
if s == nil {
|
|
return nil, nil, ErrHubNotReady.With("failed to select signet of remote hub")
|
|
}
|
|
|
|
// Create new session.
|
|
env := jess.NewUnconfiguredEnvelope()
|
|
env.SuiteID = jess.SuiteWireV1
|
|
env.Recipients = []*jess.Signet{s}
|
|
jession, err := env.WireCorrespondence(nil)
|
|
if err != nil {
|
|
return nil, nil, ErrIntegrity.With("failed to initialize encryption: %w", err)
|
|
}
|
|
t.jession = jession
|
|
|
|
// Encryption is ready for sending.
|
|
close(t.encryptionReady)
|
|
}
|
|
|
|
return t, initData, nil
|
|
}
|
|
|
|
// NewRemoteBaseTerminal creates a new remote terminal base for use with inheriting terminals.
|
|
func NewRemoteBaseTerminal(
|
|
ctx context.Context,
|
|
id uint32,
|
|
parentID string,
|
|
identity *cabin.Identity,
|
|
initData *container.Container,
|
|
upstream Upstream,
|
|
) (
|
|
t *TerminalBase,
|
|
initMsg *TerminalOpts,
|
|
err *Error,
|
|
) {
|
|
// Parse init message.
|
|
initMsg, err = ParseTerminalOpts(initData)
|
|
if err != nil {
|
|
return nil, nil, err
|
|
}
|
|
|
|
// Create baseline.
|
|
t, err = createTerminalBase(ctx, id, parentID, true, initMsg, upstream)
|
|
if err != nil {
|
|
return nil, nil, err
|
|
}
|
|
|
|
// Setup encryption if enabled.
|
|
if initMsg.Encrypt {
|
|
if identity == nil {
|
|
return nil, nil, ErrInternalError.With("missing identity for setting up incoming encryption")
|
|
}
|
|
t.identity = identity
|
|
}
|
|
|
|
return t, initMsg, nil
|
|
}
|