Core packages: config validation, network renderers, root helper, auth, SQLite store, capture engine
Capture engine streams dumpcap pcapng into verbatim, hashed segments with per-segment tshark summaries; display filters, PDML dissection with verified byte ranges, export and import. Tests run in a Debian trixie container.
This commit is contained in:
@@ -0,0 +1,101 @@
|
||||
// Package helper defines the request protocol between the unprivileged core and
|
||||
// the root pilens-helper. Every operation is fixed and typed; there is no generic
|
||||
// command execution.
|
||||
package helper
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"net"
|
||||
"time"
|
||||
|
||||
"pilens.dev/pilens/internal/config"
|
||||
)
|
||||
|
||||
const DefaultSocket = "/run/pilens/helper.sock"
|
||||
|
||||
type Request struct {
|
||||
Op string `json:"op"`
|
||||
Network *config.Network `json:"network,omitempty"`
|
||||
}
|
||||
|
||||
type Response struct {
|
||||
OK bool `json:"ok"`
|
||||
Error string `json:"error,omitempty"`
|
||||
Data json.RawMessage `json:"data,omitempty"`
|
||||
}
|
||||
|
||||
// Operation names.
|
||||
const (
|
||||
OpApplyNetwork = "apply_network"
|
||||
OpStatus = "status"
|
||||
OpStations = "stations"
|
||||
OpLeases = "leases"
|
||||
)
|
||||
|
||||
type ApplyResult struct {
|
||||
Applied bool `json:"applied"`
|
||||
RolledBack bool `json:"rolled_back"`
|
||||
Steps []string `json:"steps"`
|
||||
Error string `json:"error,omitempty"`
|
||||
}
|
||||
|
||||
type Status struct {
|
||||
TableLoaded bool `json:"table_loaded"`
|
||||
APState string `json:"ap_state"` // NM GENERAL.STATE or "absent"
|
||||
DnsmasqActive bool `json:"dnsmasq_active"`
|
||||
IPForward bool `json:"ip_forward"`
|
||||
Regdomain string `json:"regdomain"`
|
||||
Configured bool `json:"configured"`
|
||||
LastError string `json:"last_error,omitempty"`
|
||||
}
|
||||
|
||||
type Station struct {
|
||||
MAC string `json:"mac"`
|
||||
SignalDBm *int `json:"signal_dbm,omitempty"`
|
||||
RxBytes uint64 `json:"rx_bytes"`
|
||||
TxBytes uint64 `json:"tx_bytes"`
|
||||
ConnectedS int64 `json:"connected_s"`
|
||||
InactiveMS int64 `json:"inactive_ms"`
|
||||
}
|
||||
|
||||
type Lease struct {
|
||||
Expiry int64 `json:"expiry"` // unix seconds; 0 = infinite
|
||||
MAC string `json:"mac"`
|
||||
IP string `json:"ip"`
|
||||
Hostname string `json:"hostname"`
|
||||
}
|
||||
|
||||
// Client talks to the helper socket.
|
||||
type Client struct{ Socket string }
|
||||
|
||||
func (c Client) Call(ctx context.Context, req Request, out any) error {
|
||||
d := net.Dialer{}
|
||||
conn, err := d.DialContext(ctx, "unix", c.Socket)
|
||||
if err != nil {
|
||||
return errors.New("network helper unavailable: " + err.Error())
|
||||
}
|
||||
defer conn.Close()
|
||||
dl, ok := ctx.Deadline()
|
||||
if !ok {
|
||||
dl = time.Now().Add(2 * time.Minute)
|
||||
}
|
||||
conn.SetDeadline(dl)
|
||||
if err := json.NewEncoder(conn).Encode(req); err != nil {
|
||||
return err
|
||||
}
|
||||
var resp Response
|
||||
if err := json.NewDecoder(conn).Decode(&resp); err != nil {
|
||||
return err
|
||||
}
|
||||
if out != nil && len(resp.Data) > 0 {
|
||||
if err := json.Unmarshal(resp.Data, out); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
if !resp.OK {
|
||||
return errors.New(resp.Error)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
Reference in New Issue
Block a user