mirror of
https://github.com/Control-D-Inc/ctrld.git
synced 2026-02-03 22:18:39 +00:00
all: add pin protected deactivation
This commit is contained in:
committed by
Cuong Manh Le
parent
0826671809
commit
d822bf4257
@@ -364,6 +364,9 @@ func initCLI() {
|
||||
return
|
||||
}
|
||||
initLogging()
|
||||
if err := checkDeactivationPin(s); errors.Is(err, errInvalidDeactivationPin) {
|
||||
os.Exit(deactivationPinInvalidExitCode)
|
||||
}
|
||||
if doTasks([]task{{s.Stop, true}}) {
|
||||
p.router.Cleanup()
|
||||
p.resetDNS()
|
||||
@@ -372,6 +375,8 @@ func initCLI() {
|
||||
},
|
||||
}
|
||||
stopCmd.Flags().StringVarP(&iface, "iface", "", "", `Reset DNS setting for iface, "auto" means the default interface gateway`)
|
||||
stopCmd.Flags().Int64VarP(&deactivationPin, "pin", "", defaultDeactivationPin, `Pin code for stopping ctrld`)
|
||||
_ = stopCmd.Flags().MarkHidden("pin")
|
||||
|
||||
restartCmd := &cobra.Command{
|
||||
PreRun: func(cmd *cobra.Command, args []string) {
|
||||
@@ -518,10 +523,15 @@ NOTE: Uninstalling will set DNS to values provided by DHCP.`,
|
||||
if iface == "" {
|
||||
iface = "auto"
|
||||
}
|
||||
if err := checkDeactivationPin(s); errors.Is(err, errInvalidDeactivationPin) {
|
||||
os.Exit(deactivationPinInvalidExitCode)
|
||||
}
|
||||
uninstall(p, s)
|
||||
},
|
||||
}
|
||||
uninstallCmd.Flags().StringVarP(&iface, "iface", "", "", `Reset DNS setting for iface, use "auto" for the default gateway interface`)
|
||||
uninstallCmd.Flags().Int64VarP(&deactivationPin, "pin", "", defaultDeactivationPin, `Pin code for uninstalling ctrld`)
|
||||
_ = uninstallCmd.Flags().MarkHidden("pin")
|
||||
|
||||
listIfacesCmd := &cobra.Command{
|
||||
Use: "list",
|
||||
@@ -1171,6 +1181,18 @@ func processNoConfigFlags(noConfigStart bool) {
|
||||
v.Set("upstream", upstream)
|
||||
}
|
||||
|
||||
// defaultDeactivationPin is the default value for cdDeactivationPin.
|
||||
// If cdDeactivationPin equals to this default, it means the pin code is not set from Control D API.
|
||||
const defaultDeactivationPin = -1
|
||||
|
||||
// cdDeactivationPin is used in cd mode to decide whether stop and uninstall commands can be run.
|
||||
var cdDeactivationPin int64 = defaultDeactivationPin
|
||||
|
||||
// deactivationPinNotSet reports whether cdDeactivationPin was not set by processCDFlags.
|
||||
func deactivationPinNotSet() bool {
|
||||
return cdDeactivationPin == defaultDeactivationPin
|
||||
}
|
||||
|
||||
func processCDFlags(cfg *ctrld.Config) error {
|
||||
logger := mainLog.Load().With().Str("mode", "cd").Logger()
|
||||
logger.Info().Msgf("fetching Controld D configuration from API: %s", cdUID)
|
||||
@@ -1195,6 +1217,11 @@ func processCDFlags(cfg *ctrld.Config) error {
|
||||
return err
|
||||
}
|
||||
|
||||
if resolverConfig.DeactivationPin != nil {
|
||||
logger.Debug().Msg("saving deactivation pin")
|
||||
cdDeactivationPin = *resolverConfig.DeactivationPin
|
||||
}
|
||||
|
||||
logger.Info().Msg("generating ctrld config from Control-D configuration")
|
||||
|
||||
*cfg = ctrld.Config{}
|
||||
@@ -2049,3 +2076,29 @@ func noticeWritingControlDConfig() error {
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// deactivationPinInvalidExitCode indicates exit code due to invalid pin code.
|
||||
const deactivationPinInvalidExitCode = 126
|
||||
|
||||
// errInvalidDeactivationPin indicates that the deactivation pin is invalid.
|
||||
var errInvalidDeactivationPin = errors.New("deactivation pin is invalid")
|
||||
|
||||
// checkDeactivationPin validates if the deactivation pin matches one in ControlD config.
|
||||
func checkDeactivationPin(s service.Service) error {
|
||||
dir, err := socketDir()
|
||||
if err != nil {
|
||||
mainLog.Load().Err(err).Msg("could not check deactivation pin")
|
||||
return err
|
||||
}
|
||||
cc := newSocketControlClient(s, dir)
|
||||
if cc == nil {
|
||||
return nil // ctrld is not running.
|
||||
}
|
||||
data, _ := json.Marshal(&deactivationRequest{Pin: deactivationPin})
|
||||
resp, _ := cc.post(deactivationPath, bytes.NewReader(data))
|
||||
if resp != nil && resp.StatusCode == http.StatusOK {
|
||||
return nil // valid pin
|
||||
}
|
||||
mainLog.Load().Error().Msg("deactivation pin is invalid")
|
||||
return errInvalidDeactivationPin
|
||||
}
|
||||
|
||||
@@ -27,3 +27,8 @@ func newControlClient(addr string) *controlClient {
|
||||
func (c *controlClient) post(path string, data io.Reader) (*http.Response, error) {
|
||||
return c.c.Post("http://unix"+path, contentTypeJson, data)
|
||||
}
|
||||
|
||||
// deactivationRequest represents request for validating deactivation pin.
|
||||
type deactivationRequest struct {
|
||||
Pin int64 `json:"pin"`
|
||||
}
|
||||
|
||||
@@ -16,10 +16,11 @@ import (
|
||||
)
|
||||
|
||||
const (
|
||||
contentTypeJson = "application/json"
|
||||
listClientsPath = "/clients"
|
||||
startedPath = "/started"
|
||||
reloadPath = "/reload"
|
||||
contentTypeJson = "application/json"
|
||||
listClientsPath = "/clients"
|
||||
startedPath = "/started"
|
||||
reloadPath = "/reload"
|
||||
deactivationPath = "/deactivation"
|
||||
)
|
||||
|
||||
type controlServer struct {
|
||||
@@ -146,6 +147,25 @@ func (p *prog) registerControlServerHandler() {
|
||||
// Otherwise, reload is done.
|
||||
w.WriteHeader(http.StatusOK)
|
||||
}))
|
||||
p.cs.register(deactivationPath, http.HandlerFunc(func(w http.ResponseWriter, request *http.Request) {
|
||||
// Non-cd mode or pin code not set, always allowing deactivation.
|
||||
if cdUID == "" || deactivationPinNotSet() {
|
||||
w.WriteHeader(http.StatusOK)
|
||||
return
|
||||
}
|
||||
|
||||
var req deactivationRequest
|
||||
if err := json.NewDecoder(request.Body).Decode(&req); err != nil {
|
||||
w.WriteHeader(http.StatusPreconditionFailed)
|
||||
mainLog.Load().Err(err).Msg("invalid deactivation request")
|
||||
return
|
||||
}
|
||||
code := http.StatusBadRequest
|
||||
if req.Pin == cdDeactivationPin {
|
||||
code = http.StatusOK
|
||||
}
|
||||
w.WriteHeader(code)
|
||||
}))
|
||||
}
|
||||
|
||||
func jsonResponse(next http.Handler) http.Handler {
|
||||
|
||||
@@ -34,6 +34,7 @@ var (
|
||||
ifaceStartStop string
|
||||
nextdns string
|
||||
cdUpstreamProto string
|
||||
deactivationPin int64
|
||||
|
||||
mainLog atomic.Pointer[zerolog.Logger]
|
||||
consoleWriter zerolog.ConsoleWriter
|
||||
|
||||
@@ -35,8 +35,9 @@ type ResolverConfig struct {
|
||||
Ctrld struct {
|
||||
CustomConfig string `json:"custom_config"`
|
||||
} `json:"ctrld"`
|
||||
Exclude []string `json:"exclude"`
|
||||
UID string `json:"uid"`
|
||||
Exclude []string `json:"exclude"`
|
||||
UID string `json:"uid"`
|
||||
DeactivationPin *int64 `json:"deactivation_pin,omitempty"`
|
||||
}
|
||||
|
||||
type utilityResponse struct {
|
||||
|
||||
Reference in New Issue
Block a user