Skip to content
This repository was archived by the owner on Mar 2, 2021. It is now read-only.
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
27 changes: 26 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,8 @@ To replace the `/boot/occidentalis.txt` (as we want this feature for more boards
* ☑ Set WiFi SSID/PSK
* ☐ Set timezone
* ☐ Set locale
* ☐ Set static IP (see hypriot/device-init#6)
* ☑ Set static IP
* ☑ Configure network interfaces
* ☑ Pull some docker images
* ☐ Install a list of DEB packages
* ☑ Run a custom script from /boot
Expand All @@ -25,8 +26,32 @@ The `device-init` tool reads the file `/boot/device-init.yaml` to initialize sev
hostname: "black-pearl"
```

### Network Settings

```yaml
network:
interfaces:
eth0:
# sets a static IP
address: 192.168.13.37
netmask: 255.255.255.0
gateway: 192.168.13.1
dnsnameservers:
- 8.8.8.8
- 8.8.4.4
dnssearch:
example.com
eth1:
# uses dhcp
wlan0:
ssid: "MyNetwork"
password: "secret_password"
```

### Wifi Settings

This option only allows creating wlan intefaces and setting SSID/PSK. For advanced configuration see [network configuration](#network-settings).

```yaml
wifi:
interfaces:
Expand Down
199 changes: 199 additions & 0 deletions cmd/network.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,199 @@
package cmd

import (
"fmt"
"text/template"
"bytes"
"strings"
"os"
"path"
"io/ioutil"
"regexp"
"os/exec"

"github.com/spf13/cobra"
)

type Interface struct {
Name string
Address string
Netmask string
Gateway string
DNSNameservers []string
DNSSearch string
SSID string
Password string
}

type NetworkConfig struct {
Interfaces map[string]Interface
}

var networkCmd = &cobra.Command{
Use: "network",
Short: "set network settings",
Long: `Set network settings.
Network configuration only possible via config file.`,
Run: func(cmd *cobra.Command, args []string) {
if config.IsSet("network") {
setNetwork()
} else {
cmd.Help()
}
},
}

func setNetwork() {
if config.IsSet("network") {
var networkConfig NetworkConfig
err := config.UnmarshalKey("network", &networkConfig)
if err != nil {
fmt.Println("Could not unmarshal Network configuration")
}
configureNetwork(networkConfig)
}
}

func configureNetwork(networkConfig NetworkConfig) {
for interfaceName, interfaceConfig := range networkConfig.Interfaces {
interfaceConfig.Name = interfaceName

if interfaceConfig.Password != "" && interfaceConfig.SSID != ""{
interfaceConfig.Password = createEncryptedPsk([]byte(interfaceConfig.Password), []byte(interfaceConfig.SSID))
}

interfaceString := generateInterfaceConfig(interfaceConfig)
applyInterfaceConfig(interfaceName, interfaceString)
}
}

func generateInterfaceConfig(interfaceConfig Interface) string {
var interfaceString string

const interfaceTemlate = `# interface configuration generated by device-init
allow-hotplug {{.Name}}
auto {{.Name}}
iface {{.Name}} inet {{if .Address}}static{{else}}dhcp{{end}}
{{if .Address}}address {{.Address}}{{end}}
{{if .Netmask}}netmask {{.Netmask}}{{end}}
{{if .Gateway}}gateway {{.Gateway}}{{end}}
{{if .DNSNameservers}}dns-nameservers {{range $key, $value := .DNSNameservers}}{{$value}} {{end}}{{end}}
{{if .DNSSearch}}dns-search {{.DNSSearch}}{{end}}
{{if .SSID}}wpa-ssid {{.SSID}}{{end}}
{{if .Password}}wpa-psk {{.Password}}{{end}}
{{if .Address}}pre-up ip addr flush dev {{.Name}}{{end}}
`
t := template.Must(template.New("config").Parse(interfaceTemlate))
var buffer bytes.Buffer
err := t.Execute(&buffer, interfaceConfig)
if err != nil {
fmt.Println("Error writing configuration:", err)
}

interfaceString = buffer.String()
interfaceString = strings.Replace(interfaceString, " \n", "", -1)

return interfaceString
}

func applyInterfaceConfig(interfaceName string, interfaceConfig string) {
err := os.MkdirAll(networkInterfacesPath, 0755)
if err != nil {
fmt.Println("Could not create path: ", networkInterfacesPath)
}

configFilePath := path.Join(networkInterfacesPath, interfaceName)
if _, err := os.Stat(configFilePath); err == nil {
filepath, filename := path.Dir(configFilePath), path.Base(configFilePath)
backupFile := "." + filename + ".backup"
backupPath := path.Join(filepath, backupFile)
err = os.Rename(configFilePath, backupPath)
if err != nil {
fmt.Println("Could not backup file ", backupPath, ": ", err)
}
}

f, err := os.Create(configFilePath)
defer f.Close()
if err != nil {
fmt.Println("Could not create file: "+configFilePath+": ", err)
}

err = ioutil.WriteFile(configFilePath, []byte(interfaceConfig), 0644)
if err != nil {
panic(err)
}

// restart an existing interface
if interfaceExists(interfaceName) {
output, err := exec.Command("/sbin/ifdown", interfaceName).CombinedOutput()
if err != nil {
message := fmt.Sprintf("Could not bring the interface down %s: %s ", interfaceName, err)
fmt.Println(message)
}
fmt.Println(string(output)[:])
}

if interfaceExistsAndIsDown(interfaceName) {
output, err := exec.Command("/sbin/ifup", interfaceName).CombinedOutput()
if err != nil {
message := fmt.Sprintf("Could not bring up interface %s: %s", interfaceName, err)
fmt.Println(message)
}
fmt.Println(string(output)[:])
}

// try to bring the interface up once more but bring it down before
if interfaceExistsAndIsDown(interfaceName) {
output, err := exec.Command("/sbin/ifdown", interfaceName).CombinedOutput()
if err != nil {
message := fmt.Sprintf("Could not bring the interface down %s: %s ", interfaceName, err)
fmt.Println(message)
}
fmt.Println(string(output)[:])
output, err = exec.Command("/sbin/ifup", interfaceName).CombinedOutput()
if err != nil {
message := fmt.Sprintf("Could still not bring up interface %s: %s", interfaceName, err)
fmt.Println(message)
}
}
}


func init() {
RootCmd.AddCommand(networkCmd)
}


func interfaceExistsAndIsDown(interfaceName string) bool {
stats := getInterfaceStats()
for _, line := range stats {
interfaceExists, _ := regexp.MatchString(interfaceName, line)
interfaceIsDown, _ := regexp.MatchString("state DOWN", line)
if interfaceExists && interfaceIsDown {
return true
}
}
return false
}


func interfaceExists(interfaceName string) bool {
stats := getInterfaceStats()
for _, line := range stats {
interfaceExists, _ := regexp.MatchString(interfaceName, line)
if interfaceExists {
return true
}
}
return false
}


func getInterfaceStats() []string {
output, err := exec.Command("ip", "link").Output()
if err != nil {
fmt.Println("Could not run 'ip link'", err)
}
return strings.Split(string(output), "\n")
}
2 changes: 1 addition & 1 deletion cmd/root.go
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,7 @@ func setAllCommands() {
if err := config.ReadInConfig(); err == nil {
setHostname()
setWifi()
setNetwork()
dockerPreloadImages()
manageClusterLab()
runCommands()
Expand All @@ -83,5 +84,4 @@ func initConfig() {
fmt.Println("Using config file:", config.ConfigFileUsed())
}
}

}
100 changes: 6 additions & 94 deletions cmd/wifi_set.go
Original file line number Diff line number Diff line change
Expand Up @@ -23,15 +23,9 @@ package cmd
import (
"crypto/sha1"
"encoding/hex"
"fmt"

"github.com/spf13/cobra"
"golang.org/x/crypto/pbkdf2"
"os"
"os/exec"
"path"
"regexp"
"strings"
"text/template"
)

// setCmd represents the set command
Expand All @@ -45,18 +39,8 @@ var setWifiCmd = &cobra.Command{
}

func setWifi() {
var err error

readWifiConfig()

const interfaceTemlate = `allow-hotplug {{.Name}}

auto {{.Name}}
iface {{.Name}} inet dhcp
wpa-ssid {{.Ssid}}
wpa-psk {{.Psk}}
`

// if we have command line parameters only add those to our wifi configuration
if cmdInterfaceName != "" && cmdSsid != " " && cmdPassword != "" {
for key := range myWifiConfig.Interfaces {
Expand All @@ -67,69 +51,13 @@ iface {{.Name}} inet dhcp
}

for interfaceName, interfaceCredentials := range myWifiConfig.Interfaces {

type templateVariables struct {
Name, Ssid, Psk string
}

variables := templateVariables{
variables := Interface{
Name: interfaceName,
Ssid: interfaceCredentials.Ssid,
Psk: createEncryptedPsk([]byte(interfaceCredentials.Password), []byte(interfaceCredentials.Ssid)),
}

err = os.MkdirAll(networkInterfacesPath, 0755)
if err != nil {
fmt.Println("Could not create path: ", networkInterfacesPath)
}

configFilePath := path.Join(networkInterfacesPath, interfaceName)
if _, err := os.Stat(configFilePath); err == nil {
filepath, filename := path.Dir(configFilePath), path.Base(configFilePath)
backupFile := "." + filename + ".backup"
backupPath := path.Join(filepath, backupFile)
err = os.Rename(configFilePath, backupPath)
if err != nil {
fmt.Println("Could not backup file ", backupPath, ": ", err)
}
}

f, err := os.Create(configFilePath)
defer f.Close()
if err != nil {
fmt.Println("Could not create file: "+configFilePath+": ", err)
}

t := template.Must(template.New("config").Parse(interfaceTemlate))

err = t.Execute(f, variables)
if err != nil {
fmt.Println("Error writing configuration:", err)
}

if interfaceExistsAndIsDown(interfaceName) {
output, err := exec.Command("/sbin/ifup", interfaceName).CombinedOutput()
if err != nil {
message := fmt.Sprintf("Could not bring up interface %s: %s", interfaceName, err)
fmt.Println(message)
}
fmt.Println(string(output)[:])
}

// try to bring the interface up once more but bring it down before
if interfaceExistsAndIsDown(interfaceName) {
output, err := exec.Command("/sbin/ifdown", interfaceName).CombinedOutput()
if err != nil {
message := fmt.Sprintf("Could not bring the interface down %s: %s ", interfaceName, err)
fmt.Println(message)
}
fmt.Println(string(output)[:])
output, err = exec.Command("/sbin/ifup", interfaceName).CombinedOutput()
if err != nil {
message := fmt.Sprintf("Could still not bring up interface %s: %s", interfaceName, err)
fmt.Println(message)
}
SSID: interfaceCredentials.Ssid,
Password: createEncryptedPsk([]byte(interfaceCredentials.Password), []byte(interfaceCredentials.Ssid)),
}
interfaceString := generateInterfaceConfig(variables)
applyInterfaceConfig(interfaceName, interfaceString)
}
}

Expand All @@ -152,19 +80,3 @@ func createEncryptedPsk(password, salt []byte) string {
result := pbkdf2.Key(password, salt, 4096, 32, sha1.New)
return hex.EncodeToString(result)
}

func interfaceExistsAndIsDown(interfaceName string) bool {
output, err := exec.Command("ip", "link").Output()
if err != nil {
fmt.Println("Could not run 'ip link'", err)
}
lines := strings.Split(string(output), "\n")
for _, line := range lines {
interfaceExists, _ := regexp.MatchString(interfaceName, line)
interfaceIsDown, _ := regexp.MatchString("state DOWN", line)
if interfaceExists && interfaceIsDown {
return true
}
}
return false
}
Loading