BREAKING: changes to CLI interface, moved to cobra CLI
To better support configuration and user friendliness, migrated to cobra based CLI. The source tree structure has also changed to single go module, the server has been renamed hypd and client has been named hyp. The original structure came into being organically, but now that the vision is more complete it's best to make these adjustments now.
This commit is contained in:
parent
cca8310dd1
commit
291cbaabd4
4
.gitignore
vendored
4
.gitignore
vendored
@ -1,4 +1,4 @@
|
||||
hyp.secret
|
||||
*.exe
|
||||
hypd
|
||||
hyp
|
||||
hypd/hypd
|
||||
hyp/hyp
|
@ -1,5 +0,0 @@
|
||||
module deadbeef.codes/steven/hyp
|
||||
|
||||
go 1.22.0
|
||||
|
||||
require deadbeef.codes/steven/hyp/otphyp v0.0.0-20240407135923-27c2f284299f
|
@ -1,4 +0,0 @@
|
||||
deadbeef.codes/steven/hyp/otphyp v0.0.0-20240407035202-7ccdf4d89fee h1:r9xdoIGPhc/tXzyOj+lCDb+ReYa/zkysqK3ZRCqpyIU=
|
||||
deadbeef.codes/steven/hyp/otphyp v0.0.0-20240407035202-7ccdf4d89fee/go.mod h1:NANpGD/K+nDkW+bkomchwaXMrsXWza58+8AR7Sau3fs=
|
||||
deadbeef.codes/steven/hyp/otphyp v0.0.0-20240407135923-27c2f284299f h1:M+QxtB9hQ/+9MmvPtqOvXSL+LGU/f54VlPZHsM4Knao=
|
||||
deadbeef.codes/steven/hyp/otphyp v0.0.0-20240407135923-27c2f284299f/go.mod h1:NANpGD/K+nDkW+bkomchwaXMrsXWza58+8AR7Sau3fs=
|
@ -1,60 +0,0 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"log"
|
||||
"net"
|
||||
"os"
|
||||
"time"
|
||||
|
||||
"deadbeef.codes/steven/hyp/otphyp"
|
||||
)
|
||||
|
||||
// MaxNetworkLatency specifies the number of milliseconds
|
||||
// A packet-switched network... more like "race condition factory"
|
||||
const MaxNetworkLatency = 500
|
||||
|
||||
func main() {
|
||||
|
||||
// validate number of input arguments
|
||||
if len(os.Args) < 2 {
|
||||
usage()
|
||||
os.Exit(1)
|
||||
}
|
||||
|
||||
// load secret and generate ports using secret and current time
|
||||
secretBytes, err := os.ReadFile("hyp.secret")
|
||||
if err != nil {
|
||||
log.Fatalf("failed to read file 'hyp.secret': %v", err)
|
||||
}
|
||||
sharedSecret := string(secretBytes)
|
||||
|
||||
ports, err := otphyp.GeneratePorts(sharedSecret, time.Now())
|
||||
if err != nil {
|
||||
log.Fatalf("failed to generate ports from shared secret: %v", err)
|
||||
}
|
||||
|
||||
// Transmit
|
||||
fmt.Println("Transmitting knock sequence:", ports)
|
||||
for _, port := range ports {
|
||||
conn, _ := net.Dial("udp", fmt.Sprintf("%s:%d", os.Args[1], port))
|
||||
conn.Write([]byte{0})
|
||||
conn.Close()
|
||||
time.Sleep(time.Millisecond * MaxNetworkLatency)
|
||||
}
|
||||
}
|
||||
|
||||
func usage() {
|
||||
fmt.Print(`hyp <server>
|
||||
|
||||
Example Usage:
|
||||
|
||||
# Transmit an authentic knock sequence to a server
|
||||
hyp 10.69.4.20
|
||||
|
||||
# You can use a DNS name too
|
||||
hyp hyp.stevenpolley.net
|
||||
|
||||
`)
|
||||
os.Exit(1)
|
||||
}
|
15
go.mod
Normal file
15
go.mod
Normal file
@ -0,0 +1,15 @@
|
||||
module deadbeef.codes/steven/hyp
|
||||
|
||||
go 1.22.0
|
||||
|
||||
require (
|
||||
github.com/google/gopacket v1.1.19
|
||||
github.com/spf13/cobra v1.8.0
|
||||
)
|
||||
|
||||
require (
|
||||
github.com/inconshreveable/mousetrap v1.1.0 // indirect
|
||||
github.com/spf13/pflag v1.0.5 // indirect
|
||||
golang.org/x/net v0.19.0 // indirect
|
||||
golang.org/x/sys v0.15.0 // indirect
|
||||
)
|
@ -1,21 +1,28 @@
|
||||
deadbeef.codes/steven/hyp/otphyp v0.0.0-20240407035202-7ccdf4d89fee h1:r9xdoIGPhc/tXzyOj+lCDb+ReYa/zkysqK3ZRCqpyIU=
|
||||
deadbeef.codes/steven/hyp/otphyp v0.0.0-20240407035202-7ccdf4d89fee/go.mod h1:NANpGD/K+nDkW+bkomchwaXMrsXWza58+8AR7Sau3fs=
|
||||
deadbeef.codes/steven/hyp/otphyp v0.0.0-20240407135923-27c2f284299f h1:M+QxtB9hQ/+9MmvPtqOvXSL+LGU/f54VlPZHsM4Knao=
|
||||
deadbeef.codes/steven/hyp/otphyp v0.0.0-20240407135923-27c2f284299f/go.mod h1:NANpGD/K+nDkW+bkomchwaXMrsXWza58+8AR7Sau3fs=
|
||||
github.com/cpuguy83/go-md2man/v2 v2.0.3/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o=
|
||||
github.com/google/gopacket v1.1.19 h1:ves8RnFZPGiFnTS0uPQStjwru6uO6h+nlr9j6fL7kF8=
|
||||
github.com/google/gopacket v1.1.19/go.mod h1:iJ8V8n6KS+z2U1A8pUwu8bW5SyEMkXJB8Yo/Vo+TKTo=
|
||||
github.com/inconshreveable/mousetrap v1.1.0 h1:wN+x4NVGpMsO7ErUn/mUI3vEoE6Jt13X2s0bqwp9tc8=
|
||||
github.com/inconshreveable/mousetrap v1.1.0/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw=
|
||||
github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
|
||||
github.com/spf13/cobra v1.8.0 h1:7aJaZx1B85qltLMc546zn58BxxfZdR/W22ej9CFoEf0=
|
||||
github.com/spf13/cobra v1.8.0/go.mod h1:WXLWApfZ71AjXPya3WOlMsY9yMs7YeiHhFVlvLyhcho=
|
||||
github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA=
|
||||
github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg=
|
||||
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
|
||||
golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
||||
golang.org/x/lint v0.0.0-20200302205851-738671d3881b/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY=
|
||||
golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg=
|
||||
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
||||
golang.org/x/net v0.0.0-20190620200207-3b0461eec859 h1:R/3boaszxrf1GEUWTVDzSKVwLmSJpwZ1yqXm8j0v2QI=
|
||||
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||
golang.org/x/net v0.19.0 h1:zTwKpTd2XuCqf8huc7Fo2iSy+4RHPd10s4KzeTnVr1c=
|
||||
golang.org/x/net v0.19.0/go.mod h1:CfAk/cbD4CthTvqiEl8NpboMuiuOYsAr/7NOjZJtv1U=
|
||||
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.19.0 h1:q5f1RH2jigJ1MoAWp2KTp3gm5zAGFUTarQZ5U386+4o=
|
||||
golang.org/x/sys v0.19.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
|
||||
golang.org/x/sys v0.15.0 h1:h48lPFYpsTvQJZF4EKyI4aLHaev3CxivZmv7yZig9pc=
|
||||
golang.org/x/sys v0.15.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
|
||||
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||
golang.org/x/tools v0.0.0-20200130002326-2f3ba24bd6e7/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
|
||||
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
@ -1,9 +1,9 @@
|
||||
# hyp-client
|
||||
|
||||
The client expects there to be a file named hyp.secret in the same directory. This file is generated by the hypd server using ./hypd generatesecret.
|
||||
The client expects there to be a file named hyp.secret in the same directory. This file is generated by the hypd server using ./hypd generate secret.
|
||||
|
||||
```bash
|
||||
# Example Usage
|
||||
# ./hyp-client <server>
|
||||
./hyp-client 192.168.50.5
|
||||
# ./hyp knock <server>
|
||||
./hyp knock 192.168.50.5
|
||||
```
|
59
hyp/cmd/knock.go
Normal file
59
hyp/cmd/knock.go
Normal file
@ -0,0 +1,59 @@
|
||||
/*
|
||||
Copyright © 2024 Steven Polley <himself@stevenpolley.net>
|
||||
*/
|
||||
package cmd
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"log"
|
||||
"net"
|
||||
"os"
|
||||
"time"
|
||||
|
||||
"deadbeef.codes/steven/hyp/otphyp"
|
||||
"github.com/spf13/cobra"
|
||||
)
|
||||
|
||||
// knockCmd represents the knock command
|
||||
var knockCmd = &cobra.Command{
|
||||
Use: "knock <hypServer>",
|
||||
Short: "Sends an authenticated knock sequence to the server specified",
|
||||
Long: `Runs the hyp client and performs an authentic knock sequence
|
||||
against the server provided.
|
||||
|
||||
Example usage:
|
||||
|
||||
hyp knock <hypServer>
|
||||
|
||||
hyp knock hyp.deadbeef.codes
|
||||
|
||||
hyp knock 10.69.4.20
|
||||
`,
|
||||
Args: cobra.ExactArgs(1),
|
||||
Run: func(cmd *cobra.Command, args []string) {
|
||||
// load secret and generate ports using secret and current time
|
||||
secretBytes, err := os.ReadFile("hyp.secret")
|
||||
if err != nil {
|
||||
log.Fatalf("failed to read file 'hyp.secret': %v", err)
|
||||
}
|
||||
sharedSecret := string(secretBytes)
|
||||
|
||||
ports, err := otphyp.GeneratePorts(sharedSecret, time.Now())
|
||||
if err != nil {
|
||||
log.Fatalf("failed to generate ports from shared secret: %v", err)
|
||||
}
|
||||
|
||||
// Transmit
|
||||
fmt.Println("Transmitting knock sequence:", ports)
|
||||
for _, port := range ports {
|
||||
conn, _ := net.Dial("udp", fmt.Sprintf("%s:%d", os.Args[1], port))
|
||||
conn.Write([]byte{0})
|
||||
conn.Close()
|
||||
time.Sleep(time.Millisecond * 200) // TBD: Make this configurable with flag (maxJitter)
|
||||
}
|
||||
},
|
||||
}
|
||||
|
||||
func init() {
|
||||
rootCmd.AddCommand(knockCmd)
|
||||
}
|
33
hyp/cmd/root.go
Normal file
33
hyp/cmd/root.go
Normal file
@ -0,0 +1,33 @@
|
||||
/*
|
||||
Copyright © 2024 Steven Polley <himself@stevenpolley.net>
|
||||
*/
|
||||
package cmd
|
||||
|
||||
import (
|
||||
"os"
|
||||
|
||||
"github.com/spf13/cobra"
|
||||
)
|
||||
|
||||
// rootCmd represents the base command when called without any subcommands
|
||||
var rootCmd = &cobra.Command{
|
||||
Use: "hyp",
|
||||
Short: "Hide Your Ports Client",
|
||||
Long: `Hide Your Ports (hyp) is a combination of Port Knocking and One Time Passwords:
|
||||
|
||||
hyp uses a pre-shared key distributed between the server and client, as well as the time
|
||||
to calculate a unique authentic knock sequence which is only valid for 90 seconds.`,
|
||||
}
|
||||
|
||||
// Execute adds all child commands to the root command and sets flags appropriately.
|
||||
// This is called by main.main(). It only needs to happen once to the rootCmd.
|
||||
func Execute() {
|
||||
err := rootCmd.Execute()
|
||||
if err != nil {
|
||||
os.Exit(1)
|
||||
}
|
||||
}
|
||||
|
||||
func init() {
|
||||
|
||||
}
|
10
hyp/main.go
Normal file
10
hyp/main.go
Normal file
@ -0,0 +1,10 @@
|
||||
/*
|
||||
Copyright © 2024 Steven Polley <himself@stevenpolley.net>
|
||||
*/
|
||||
package main
|
||||
|
||||
import "deadbeef.codes/steven/hyp/hyp/cmd"
|
||||
|
||||
func main() {
|
||||
cmd.Execute()
|
||||
}
|
12
hypd/README.md
Normal file
12
hypd/README.md
Normal file
@ -0,0 +1,12 @@
|
||||
# hyp server
|
||||
|
||||
hyp server is the port knocking daemon which listens for incoming authentic knock sequences.
|
||||
|
||||
### Usage
|
||||
|
||||
##### Starting the server
|
||||
|
||||
```bash
|
||||
# As root - or user that can capture packets and modify IPTables
|
||||
./hypd server eth0
|
||||
```
|
18
hypd/cmd/generate.go
Normal file
18
hypd/cmd/generate.go
Normal file
@ -0,0 +1,18 @@
|
||||
/*
|
||||
Copyright © 2024 Steven Polley <himself@stevenpolley.net>
|
||||
*/
|
||||
package cmd
|
||||
|
||||
import (
|
||||
"github.com/spf13/cobra"
|
||||
)
|
||||
|
||||
// generateCmd represents the generate command
|
||||
var generateCmd = &cobra.Command{
|
||||
Use: "generate",
|
||||
Short: "Generates configuration for Hide Your Ports",
|
||||
}
|
||||
|
||||
func init() {
|
||||
rootCmd.AddCommand(generateCmd)
|
||||
}
|
33
hypd/cmd/root.go
Normal file
33
hypd/cmd/root.go
Normal file
@ -0,0 +1,33 @@
|
||||
/*
|
||||
Copyright © 2024 Steven Polley <himself@stevenpolley.net>
|
||||
*/
|
||||
package cmd
|
||||
|
||||
import (
|
||||
"os"
|
||||
|
||||
"github.com/spf13/cobra"
|
||||
)
|
||||
|
||||
// rootCmd represents the base command when called without any subcommands
|
||||
var rootCmd = &cobra.Command{
|
||||
Use: "hypd",
|
||||
Short: "Hide Your Ports Daemon",
|
||||
Long: `Hide Your Ports (hyp) is a combination of Port Knocking and One Time Passwords:
|
||||
|
||||
hyp uses a pre-shared key distributed between the server and client, as well as the time
|
||||
to calculate a unique authentic knock sequence which is only valid for 90 seconds.`,
|
||||
}
|
||||
|
||||
// Execute adds all child commands to the root command and sets flags appropriately.
|
||||
// This is called by main.main(). It only needs to happen once to the rootCmd.
|
||||
func Execute() {
|
||||
err := rootCmd.Execute()
|
||||
if err != nil {
|
||||
os.Exit(1)
|
||||
}
|
||||
}
|
||||
|
||||
func init() {
|
||||
|
||||
}
|
44
hypd/cmd/secret.go
Normal file
44
hypd/cmd/secret.go
Normal file
@ -0,0 +1,44 @@
|
||||
/*
|
||||
Copyright © 2024 Steven Polley <himself@stevenpolley.net>
|
||||
*/
|
||||
package cmd
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"deadbeef.codes/steven/hyp/otphyp"
|
||||
"github.com/spf13/cobra"
|
||||
)
|
||||
|
||||
// secretCmd represents the secret command
|
||||
var secretCmd = &cobra.Command{
|
||||
Use: "secret",
|
||||
Short: "Generates a secret key for hyp",
|
||||
Long: `Generates a secret for hyp which should be distributed to both the
|
||||
server and to clients.
|
||||
|
||||
Example:
|
||||
|
||||
hypd generatesecret > hyp.secret`,
|
||||
Run: func(cmd *cobra.Command, args []string) {
|
||||
sharedSecret, err := otphyp.GenerateSecret()
|
||||
if err != nil {
|
||||
panic(fmt.Errorf("failed to generate shared secret: %w", err))
|
||||
}
|
||||
fmt.Println(sharedSecret)
|
||||
},
|
||||
}
|
||||
|
||||
func init() {
|
||||
generateCmd.AddCommand(secretCmd)
|
||||
|
||||
// Here you will define your flags and configuration settings.
|
||||
|
||||
// Cobra supports Persistent Flags which will work for this command
|
||||
// and all subcommands, e.g.:
|
||||
// secretCmd.PersistentFlags().String("foo", "", "A help for foo")
|
||||
|
||||
// Cobra supports local flags which will only run when this command
|
||||
// is called directly, e.g.:
|
||||
// secretCmd.Flags().BoolP("toggle", "t", false, "Help message for toggle")
|
||||
}
|
61
hypd/cmd/server.go
Normal file
61
hypd/cmd/server.go
Normal file
@ -0,0 +1,61 @@
|
||||
/*
|
||||
Copyright © 2024 Steven Polley <himself@stevenpolley.net>
|
||||
*/
|
||||
package cmd
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"deadbeef.codes/steven/hyp/hypd/server"
|
||||
"github.com/spf13/cobra"
|
||||
)
|
||||
|
||||
// serverCmd represents the server command
|
||||
var serverCmd = &cobra.Command{
|
||||
Use: "server <NIC>",
|
||||
Args: cobra.ExactArgs(1),
|
||||
Short: "Runs hyp in server mode",
|
||||
Long: `Runs the hyp server and begins capture on the NIC specified
|
||||
|
||||
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}"
|
||||
|
||||
`,
|
||||
Run: func(cmd *cobra.Command, args []string) {
|
||||
err := server.PacketServer(args[0])
|
||||
if err != nil {
|
||||
panic(fmt.Errorf("failed to start packet server: %w", err))
|
||||
}
|
||||
|
||||
},
|
||||
}
|
||||
|
||||
func init() {
|
||||
rootCmd.AddCommand(serverCmd)
|
||||
/*
|
||||
viper.SetConfigName("hypconfig")
|
||||
viper.SetConfigType("yaml")
|
||||
viper.AddConfigPath("/etc/hyp/")
|
||||
viper.AddConfigPath("$HOME/.hyp")
|
||||
viper.AddConfigPath(".")
|
||||
viper.SetDefault("RefreshInterval", 7200)
|
||||
|
||||
if err := viper.ReadInConfig(); err != nil {
|
||||
if _, ok := err.(viper.ConfigFileNotFoundError); ok {
|
||||
// Config file not found
|
||||
// TBD: Implement
|
||||
} else {
|
||||
// Config file was found, but another error was produced
|
||||
panic(fmt.Errorf("failed reading existing config file: %w", err))
|
||||
}
|
||||
}*/
|
||||
|
||||
}
|
10
hypd/main.go
Normal file
10
hypd/main.go
Normal file
@ -0,0 +1,10 @@
|
||||
/*
|
||||
Copyright © 2024 Steven Polley <himself@stevenpolley.net>
|
||||
*/
|
||||
package main
|
||||
|
||||
import "deadbeef.codes/steven/hyp/hypd/cmd"
|
||||
|
||||
func main() {
|
||||
cmd.Execute()
|
||||
}
|
@ -1,9 +1,15 @@
|
||||
package main
|
||||
/*
|
||||
Copyright © 2024 Steven Polley <himself@stevenpolley.net>
|
||||
*/
|
||||
|
||||
package server
|
||||
|
||||
import (
|
||||
"encoding/binary"
|
||||
"fmt"
|
||||
"log"
|
||||
"os"
|
||||
"os/exec"
|
||||
"time"
|
||||
|
||||
"deadbeef.codes/steven/hyp/otphyp"
|
||||
@ -13,8 +19,9 @@ import (
|
||||
|
||||
// Client is used to keep track of a client attempting to perform an authentic knock sequence
|
||||
type Client struct {
|
||||
Progress int // index of current progress in sequence. Value of 1 means first port has been matched
|
||||
Sequence [4]uint16 // stores the knock sequence the current client is attempting. It's set and tracked here to prevent race conditions during a knock sequence being received and key rotations
|
||||
Progress int // index of current progress in sequence. Value of 1 means first port has been matched
|
||||
Sequence [4]uint16 // stores the knock sequence the current client is attempting. It's set and tracked here to prevent race conditions during a knock sequence being received and key rotations
|
||||
LastUpdated time.Time // The last time the client sent a correct packet in the sequence
|
||||
}
|
||||
|
||||
// KnockSequence is used keep track of an ordered knock sequence and whether it's been marked for use (to prevent replay attacks)
|
||||
@ -32,14 +39,20 @@ 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) {
|
||||
clients = make(map[string]*Client, 0) // key is source IP address, value is the current progress through the sequence. i.e. value of 1 means that the first port in the sequence was successful
|
||||
knockSequences = []KnockSequence{} // Slice of accepted port sequences, there have to be several to account for clock skew between client and server
|
||||
func PacketServer(captureDevice string) error {
|
||||
secretBytes, err := os.ReadFile("hyp.secret")
|
||||
if err != nil {
|
||||
log.Fatalf("failed to read file 'hyp.secret': %v", err)
|
||||
}
|
||||
sharedSecret = string(secretBytes)
|
||||
|
||||
clients = make(map[string]*Client, 0)
|
||||
knockSequences = []KnockSequence{}
|
||||
|
||||
// Open pcap handle on device
|
||||
handle, err := pcap.OpenLive(captureDevice, 1600, true, pcap.BlockForever)
|
||||
if err != nil {
|
||||
log.Fatalf("failed to open adapter")
|
||||
return fmt.Errorf("failed to open pcap on capture device: %w", err)
|
||||
}
|
||||
packetSource := gopacket.NewPacketSource(handle, handle.LinkType())
|
||||
|
||||
@ -50,6 +63,7 @@ func packetServer(captureDevice string) {
|
||||
for packet := range packetSource.Packets() {
|
||||
handlePacket(packet) // Do something with a packet here.
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// packets that match the BPF filter get passed to handlePacket
|
||||
@ -139,3 +153,14 @@ func setPacketFilter(handle *pcap.Handle) error {
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// TBD: Implement - this is a temporary routine to demonstrate an application
|
||||
func handleSuccess(srcip string) {
|
||||
fmt.Println("Success for ", srcip)
|
||||
|
||||
cmd := exec.Command("iptables", "-A", "INPUT", "-p", "tcp", "-s", srcip, "--dport", "22", "-j", "ACCEPT")
|
||||
err := cmd.Run()
|
||||
if err != nil {
|
||||
log.Printf("failed to execute iptables command for '%s': %v", srcip, err)
|
||||
}
|
||||
}
|
@ -1,3 +0,0 @@
|
||||
module deadbeef.codes/steven/hyp/otphyp
|
||||
|
||||
go 1.22.0
|
@ -1,25 +0,0 @@
|
||||
# hypd
|
||||
|
||||
hypd is the hyp (Hide Your Ports) server.
|
||||
|
||||
### Requirements
|
||||
|
||||
On the server, libpcap-dev needs to be installed on linux or pcap from nmap.org on Windows.
|
||||
|
||||
### Usage
|
||||
|
||||
##### Generating a new shared key
|
||||
|
||||
```bash
|
||||
# As user that can write to current directory
|
||||
./hypd generatesecret
|
||||
```
|
||||
|
||||
Then copy the file to a client
|
||||
|
||||
##### Starting the server
|
||||
|
||||
```bash
|
||||
# As root - or user that can capture packets and modify IPTables
|
||||
./hypd server eth0
|
||||
```
|
@ -1,10 +0,0 @@
|
||||
module deadbeef.codes/steven/hypd
|
||||
|
||||
go 1.22.0
|
||||
|
||||
require (
|
||||
deadbeef.codes/steven/hyp/otphyp v0.0.0-20240407135923-27c2f284299f
|
||||
github.com/google/gopacket v1.1.19
|
||||
)
|
||||
|
||||
require golang.org/x/sys v0.19.0 // indirect
|
@ -1,81 +0,0 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"log"
|
||||
"os"
|
||||
"os/exec"
|
||||
|
||||
"deadbeef.codes/steven/hyp/otphyp"
|
||||
)
|
||||
|
||||
func main() {
|
||||
|
||||
if len(os.Args) < 2 {
|
||||
usage()
|
||||
}
|
||||
|
||||
switch os.Args[1] {
|
||||
case "generatesecret":
|
||||
sharedSecret, err := otphyp.GenerateSecret()
|
||||
if err != nil {
|
||||
log.Fatalf("failed to generate shared secret: %v", err)
|
||||
}
|
||||
f, err := os.Create("hyp.secret")
|
||||
if err != nil {
|
||||
log.Fatalf("failed to create file 'hyp.secret': %v", err)
|
||||
}
|
||||
_, err = f.WriteString(sharedSecret)
|
||||
if err != nil {
|
||||
log.Fatalf("failed to write to file 'hyp.secret': %v", err)
|
||||
}
|
||||
f.Close()
|
||||
fmt.Println("Created file hyp.secret")
|
||||
case "server":
|
||||
secretBytes, err := os.ReadFile("hyp.secret")
|
||||
if err != nil {
|
||||
log.Fatalf("failed to read file 'hyp.secret': %v", err)
|
||||
}
|
||||
sharedSecret = string(secretBytes)
|
||||
if len(os.Args) < 3 {
|
||||
usage()
|
||||
}
|
||||
packetServer(os.Args[2])
|
||||
default:
|
||||
usage()
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
func usage() {
|
||||
fmt.Print(`hypd <command>
|
||||
|
||||
Commands:
|
||||
generatesecret - creates a pre shared key file named hyp.secret which can be distributed to a trusted client
|
||||
server <device> - runs the hypd server watching for an authentic knock sequence
|
||||
|
||||
Example Usage:
|
||||
|
||||
# Generate a secret, to be shared with a trusted client
|
||||
hypd generatesecret
|
||||
|
||||
# Linux - ip link
|
||||
hypd server eth0
|
||||
|
||||
# Windows - get-netadapter | where {$_.Name -eq “Ethernet”} | Select-Object -Property DeviceName
|
||||
hypd server "\\Device\\NPF_{A066F7DE-CC2D-4E4B-97C4-BF0EC4C03649}"
|
||||
|
||||
`)
|
||||
os.Exit(1)
|
||||
}
|
||||
|
||||
// TBD: Implement - this is a temporary routine to demonstrate an application
|
||||
func handleSuccess(srcip string) {
|
||||
fmt.Println("Success for ", srcip)
|
||||
|
||||
cmd := exec.Command("iptables", "-A", "INPUT", "-p", "tcp", "-s", srcip, "--dport", "22", "-j", "ACCEPT")
|
||||
err := cmd.Run()
|
||||
if err != nil {
|
||||
log.Printf("failed to execute iptables command for '%s': %v", srcip, err)
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue
Block a user