BREAKING: Interface name is now specified by configuration file
continuous-integration/drone/push Build is passing Details

The syntax for the hypd server command has changed.  Now instead of specifying an interface name as an argument to the server command, you instead specify a configuration file path.

Example:
./hypd server hypdconfig.json
This commit is contained in:
Steven Polley 2024-04-17 19:41:24 -06:00
parent e95b4972da
commit 1ffadf5c86
5 changed files with 38 additions and 23 deletions

1
.gitignore vendored
View File

@ -2,3 +2,4 @@ hyp.secret
*.exe
hypd/hypd
hyp/hyp
hypdconfig.json

View File

@ -16,7 +16,9 @@ var defaultconfigCmd = &cobra.Command{
Use: "defaultconfig",
Short: "Prints the default configuration to stdout",
Long: `The default configuration is used if one is not set. The default configuration
can be used as a reference to build your own. `,
can be used as a reference to build your own.
hypd generate defaultconfig | tee hypdconfig.json`,
Run: func(cmd *cobra.Command, args []string) {
config := configuration.DefaultConfig()
b, err := json.MarshalIndent(config, "", " ")

View File

@ -5,6 +5,7 @@ package cmd
import (
"fmt"
"os/user"
"deadbeef.codes/steven/hyp/hypd/configuration"
"deadbeef.codes/steven/hyp/hypd/server"
@ -13,34 +14,43 @@ import (
// serverCmd represents the server command
var serverCmd = &cobra.Command{
Use: "server <NIC>",
Use: "server <configFilePath>",
Args: cobra.ExactArgs(1),
Short: "Runs hyp in server mode",
Long: `Runs the hyp server and begins capture on the NIC specified
Long: `Runs the hyp server and begins watching for authentic knock sequences.
Before running this command, you must first have a configuration file. You can
generate a configuration file with: hypd generate defaultconfig > hypdconfig.json
You should then edit the config file to meet your needs.
In addition to a config file you will need to generate pre-shared keys:
mkdir -p ./secrets
hypd generate secret > secrets/mykey.secret
Example Usage:
# Linux - capture enp0s0
hyp server enp0s0
# Linux - capture eth0
hyp server eth0
# Windows - get-netadapter | where {$_.Name -eq Ethernet} | Select-Object -Property DeviceName
hyp.exe server "\\Device\\NPF_{A6F067DE-C2DC-4B4E-9C74-BE649C4C0F03}"
# Use config file in local directory
hypd server hypdconfig.json
# Use config file in /etc/hyp/
hypd server /etc/hyp/hypdconfig.json
`,
Run: func(cmd *cobra.Command, args []string) {
configFile, err := cmd.Flags().GetString("configfile")
currentUser, err := user.Current()
if err != nil {
panic(fmt.Errorf("failed to get configfile flag: %w", err))
panic(fmt.Errorf("could not determine current user: %w", err))
}
hypdConfiguration, err := configuration.LoadConfiguration(configFile)
if currentUser.Username != "root" {
fmt.Println("WARNING: It's recommended you run this as root, but will proceed anyways...")
}
hypdConfiguration, err := configuration.LoadConfiguration(args[0])
if err != nil {
panic(fmt.Errorf("failed to start packet server: %w", err))
}
err = server.PacketServer(args[0], hypdConfiguration)
err = server.PacketServer(hypdConfiguration)
if err != nil {
panic(fmt.Errorf("failed to start packet server: %w", err))
}
@ -50,6 +60,4 @@ Example Usage:
func init() {
rootCmd.AddCommand(serverCmd)
serverCmd.PersistentFlags().String("configfile", "", "Path to the file containing the hypd configuration.")
}

View File

@ -7,6 +7,7 @@ import (
)
type HypdConfiguration struct {
NetworkInterface string `json:"networkInterface"`
PreSharedKeyDirectory string `json:"preSharedKeyDirectory"` // hypd will load all *.secret files from this directory
SuccessAction string `json:"successAction"` // The action to take
TimeoutSeconds int `json:"timeoutSeconds"` // If > 0, once a knock sequence has been successful this value will count down and when it reaches 0, it will perform the TimeoutAction on the client.
@ -19,6 +20,7 @@ type HypdConfiguration struct {
func LoadConfiguration(configFilePath string) (*HypdConfiguration, error) {
if configFilePath == "" {
commonLocations := []string{"hypdconfig.json",
"~/.hypdconfig.json",
"~/.config/hyp/hypdConfig.json",
"/etc/hyp/hypdConfig.json",
"/usr/local/etc/hyp/hypdConfig.json",
@ -33,6 +35,7 @@ func LoadConfiguration(configFilePath string) (*HypdConfiguration, error) {
}
// if it's still not found after checking common locations, load default config
if configFilePath == "" {
fmt.Println("no configuration file found. You can generate one with ./hypd generate defaultconfig | tee hypdconfig.json")
return DefaultConfig(), nil
}
@ -45,17 +48,18 @@ func LoadConfiguration(configFilePath string) (*HypdConfiguration, error) {
return nil, fmt.Errorf("failed to read config file '%s': %w", configFilePath, err)
}
var hypdConfiguration *HypdConfiguration
hypdConfiguration := &HypdConfiguration{}
err = json.Unmarshal(b, hypdConfiguration)
if err != nil {
return nil, fmt.Errorf("failed to unmarshal config file json to HypdConfiguration (is the config file malformed?): %w", err)
}
return nil, nil
return hypdConfiguration, nil
}
func DefaultConfig() *HypdConfiguration {
return &HypdConfiguration{
NetworkInterface: "enp0s3",
PreSharedKeyDirectory: "./secrets/",
SuccessAction: "iptables -A INPUT -p tcp -s %s --dport 22 -j ACCEPT",
TimeoutSeconds: 1440,

View File

@ -49,11 +49,11 @@ var (
// PacketServer is the main function when operating in server mode
// it sets up the pcap on the capture device and starts a goroutine
// to rotate the knock sequence
func PacketServer(captureDevice string, config *configuration.HypdConfiguration) error {
func PacketServer(config *configuration.HypdConfiguration) error {
iface, err := net.InterfaceByName(captureDevice)
iface, err := net.InterfaceByName(config.NetworkInterface)
if err != nil {
log.Fatalf("lookup network iface %q: %v", captureDevice, err)
log.Fatalf("lookup network iface %q: %v", config.NetworkInterface, err)
}
secretBytes, err := os.ReadFile("hyp.secret")