commit 77f2353054ee6bd5c7781df2e91246e51cbea323 Author: Fabian Stamm Date: Wed Apr 7 21:11:48 2021 +0200 First Commit diff --git a/gen.go b/gen.go new file mode 100644 index 0000000..d11e54f --- /dev/null +++ b/gen.go @@ -0,0 +1,292 @@ +package main + +import ( + "bufio" + "bytes" + "encoding/json" + "fmt" + "image/png" + "io/ioutil" + "log" + "os" + "os/exec" + "strconv" + "strings" + + "github.com/boombuler/barcode" + "github.com/boombuler/barcode/qr" + "github.com/urfave/cli/v2" +) + +func generateKeys() (string, string) { + cmd := exec.Command("wg", "genkey") + var out1 bytes.Buffer + cmd.Stdout = &out1 + cmd.Run() + + private := strings.ReplaceAll(out1.String(), "\n", "") + + cmd2 := exec.Command("wg", "pubkey") + cmd2.Stdin = strings.NewReader(private) + + var out2 bytes.Buffer + cmd2.Stdout = &out2 + + cmd2.Run() + public := strings.ReplaceAll(out2.String(), "\n", "") + + return private, public +} + +func generateConfigs(storage *Storage) { + os.MkdirAll("out/server", 0755) + os.MkdirAll("out/clients", 0755) + + serverConfig := "" + serverConfig += "[Interface]\n" + serverConfig += fmt.Sprintf("ListenPort = %d\n", storage.Port) + serverConfig += fmt.Sprintf("Address = %s1/32,%s1/128\n", storage.Subnet, storage.Subnet6) + serverConfig += fmt.Sprintf("PrivateKey = %s\n", storage.Server.Private) + + if len(storage.Server.IPTablesUp) > 0 { + serverConfig += fmt.Sprintf("PostUp = %s\n", strings.Join(storage.Server.IPTablesUp, "; ")) + } + + if len(storage.Server.IPTablesDown) > 0 { + serverConfig += fmt.Sprintf("PostDown = %s\n", strings.Join(storage.Server.IPTablesDown, "; ")) + } + + serverConfig += "# ---------------------------\n\n" + + for name, peer := range storage.Clients { + serverConfig += fmt.Sprintf("[Peer] # %s\n", name) + serverConfig += fmt.Sprintf("PublicKey = %s\n", peer.Public) + serverConfig += fmt.Sprintf("AllowedIPs = %s%d/32,%s%d/128\n", storage.Subnet, peer.IP, storage.Subnet6, peer.IP) + + // serverConfig += fmt.Sprintf("Endpoint = %s:%d\n", storage.Server.EndPoint, storage.Port) + serverConfig += "\n" + } + + os.WriteFile("out/server/server.conf", []byte(serverConfig), 0644) + + for name, peer := range storage.Clients { + peerConfig := "[Interface]\n" + peerConfig += fmt.Sprintf("Address = %s%d/32,%s%d/128\n", storage.Subnet, peer.IP, storage.Subnet6, peer.IP) + peerConfig += fmt.Sprintf("PrivateKey = %s\n", peer.Private) + peerConfig += fmt.Sprintf("DNS = 1.1.1.1\n") + peerConfig += "\n" + peerConfig += fmt.Sprintf("[Peer] # Server\n") + peerConfig += fmt.Sprintf("PublicKey = %s\n", storage.Server.Public) + if !peer.OnlySubnet { + peerConfig += fmt.Sprintf("AllowedIPs = 0.0.0.0/0, ::0/0\n") + } else { + peerConfig += fmt.Sprintf("AllowedIPs = %s0/24, %s0/68\n", storage.Subnet, storage.Subnet6) + } + peerConfig += fmt.Sprintf("Endpoint = %s:%d\n", storage.Server.EndPoint, storage.Port) + + os.WriteFile(fmt.Sprintf("out/clients/%s.conf", name), []byte(peerConfig), 0644) + qrCode, _ := qr.Encode(peerConfig, qr.L, qr.Auto) + qrCode, _ = barcode.Scale(qrCode, 512, 512) + + file, err := os.Create(fmt.Sprintf("out/clients/%s.png", name)) + if err != nil { + log.Fatal(err) + } + + defer file.Close() + + png.Encode(file, qrCode) + + file.Sync() + } +} + +func initConfig(storage *Storage) { + var text string + + scanner := bufio.NewScanner(os.Stdin) + fmt.Printf("Enter IPv4 subnet (%s): ", storage.Subnet) + scanner.Scan() + text = scanner.Text() + if len(text) > 0 { + storage.Subnet = text + } + + fmt.Printf("Enter IPv6 subnet (%s): ", storage.Subnet6) + scanner.Scan() + text = scanner.Text() + if len(text) > 0 { + storage.Subnet6 = text + } + + fmt.Printf("Enter Server Endpoint (%s): ", storage.Server.EndPoint) + scanner.Scan() + text = scanner.Text() + if len(text) > 0 { + storage.Server.EndPoint = text + } + + fmt.Printf("Enter Port (%d): ", storage.Port) + scanner.Scan() + text = scanner.Text() + if len(text) > 0 { + u, err := strconv.ParseUint(text, 10, 32) + if err != nil { + log.Fatal(err) + } + storage.Port = uint32(u) + } +} + +func main() { + if !fileExists("config.json") { + err := ioutil.WriteFile("config.json", []byte("{}"), os.FileMode(0750)) + if err != nil { + fmt.Print(err) + os.Exit(1) + } + } + + data, err := ioutil.ReadFile("config.json") + if err != nil { + log.Fatal(err) + } + + storage := new(Storage) + + err = json.Unmarshal(data, &storage) + + if err != nil { + log.Fatal(err) + } + + if storage.Server.Private == "" || storage.Server.Public == "" { + pr, pu := generateKeys() + storage.Server.Private = pr + storage.Server.Public = pu + } + + for storage.Subnet == "" || storage.Subnet6 == "" || storage.Server.EndPoint == "" { + initConfig(storage) + } + + if storage.Clients == nil { + storage.Clients = map[string]Client{} + } + + if storage.Server.IPTablesUp == nil { + storage.Server.IPTablesUp = []string{} + } + + if storage.Server.IPTablesDown == nil { + storage.Server.IPTablesDown = []string{} + } + + // fmt.Printf("%+v\n", storage) + + app := &cli.App{ + Name: "wgconf", + Usage: "make an explosive entrance", + Version: "0.0.1", + Commands: []*cli.Command{ + { + Name: "generate", + Aliases: []string{"g"}, + Usage: "Generate the wireguard configs", + Action: func(c *cli.Context) error { + generateConfigs(storage) + return nil + }, + }, { + Name: "add", + Aliases: []string{"a"}, + Usage: "Add device", + Flags: []cli.Flag{ + &cli.BoolFlag{ + Name: "onlysubnet", + Aliases: []string{"s"}, + Usage: "Only VPN subnet, not whole traffic", + Value: false, + }, + }, + Action: func(c *cli.Context) error { + name := c.Args().First() + if len(name) <= 0 { + log.Fatalln("Name not set!") + } + + freeIP := 1 + + for _, peer := range storage.Clients { + if peer.IP >= freeIP { + freeIP = peer.IP + 1 + } + } + + private, public := generateKeys() + + storage.Clients[name] = Client{ + OnlySubnet: c.Bool("onlysubnet"), + Private: private, + Public: public, + IP: freeIP, + } + + return nil + }, + }, + }, + Action: func(c *cli.Context) error { + fmt.Println("boom! I say!") + return nil + }, + } + + err = app.Run(os.Args) + + if err != nil { + log.Fatal(err) + } + + data, err = json.MarshalIndent(storage, "", " ") + + if err != nil { + log.Fatal(err) + } + + err = os.WriteFile("config.json", data, 0644) + if err != nil { + log.Fatal(err) + } +} + +func fileExists(filename string) bool { + info, err := os.Stat(filename) + if os.IsNotExist(err) { + return false + } + return !info.IsDir() +} + +type Client struct { + IP int `json:"ip"` + Private string `json:"private"` + Public string `json:"public"` + OnlySubnet bool `json:"onlysubnet"` +} + +type Server struct { + EndPoint string `json:"endpoint"` + Private string `json:"private"` + Public string `json:"public"` + IPTablesUp []string `json:"iptables-up"` + IPTablesDown []string `json:"iptables-down"` +} + +type Storage struct { + Subnet string `json:"subnet"` + Port uint32 `json:"port"` + Server Server `json:"server"` + Clients map[string]Client `json:"clients"` + Subnet6 string `json:"subnet6"` +} diff --git a/go.mod b/go.mod new file mode 100644 index 0000000..6752d5c --- /dev/null +++ b/go.mod @@ -0,0 +1,9 @@ +module wg_generate + +go 1.16 + +require ( + github.com/boombuler/barcode v1.0.1 // indirect + github.com/urfave/cli v1.22.5 + github.com/urfave/cli/v2 v2.3.0 // indirect +) diff --git a/go.sum b/go.sum new file mode 100644 index 0000000..855856f --- /dev/null +++ b/go.sum @@ -0,0 +1,18 @@ +github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= +github.com/boombuler/barcode v1.0.1 h1:NDBbPmhS+EqABEs5Kg3n/5ZNjy73Pz7SIV+KCeqyXcs= +github.com/boombuler/barcode v1.0.1/go.mod h1:paBWMcWSl3LHKBqUq+rly7CNSldXjb2rDl3JlRe0mD8= +github.com/cpuguy83/go-md2man/v2 v2.0.0-20190314233015-f79a8a8ca69d h1:U+s90UTSYgptZMwQh2aRr3LuazLJIa+Pg3Kc1ylSYVY= +github.com/cpuguy83/go-md2man/v2 v2.0.0-20190314233015-f79a8a8ca69d/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU= +github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= +github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/russross/blackfriday/v2 v2.0.1 h1:lPqVAte+HuHNfhJ/0LC98ESWRz8afy9tM/0RK8m9o+Q= +github.com/russross/blackfriday/v2 v2.0.1/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= +github.com/shurcooL/sanitized_anchor_name v1.0.0 h1:PdmoCO6wvbs+7yrJyMORt4/BmY5IYyJwS/kOiWx8mHo= +github.com/shurcooL/sanitized_anchor_name v1.0.0/go.mod h1:1NzhyTcUVG4SuEtjjoZeVRXNmyL/1OwPU0+IJeTBvfc= +github.com/urfave/cli v1.22.5 h1:lNq9sAHXK2qfdI8W+GRItjCEkI+2oR4d+MEHy1CKXoU= +github.com/urfave/cli v1.22.5/go.mod h1:Gos4lmkARVdJ6EkW0WaNv/tZAAMe9V7XWyB60NtXRu0= +github.com/urfave/cli/v2 v2.3.0 h1:qph92Y649prgesehzOrQjdWyxFOp/QVM+6imKHad91M= +github.com/urfave/cli/v2 v2.3.0/go.mod h1:LJmUH05zAU44vOAcrfzZQKsZbVcdbOG8rtL3/XcUArI= +gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.2.3/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=