mirror of
https://github.com/RoganDawes/P4wnP1_aloa.git
synced 2025-03-17 21:31:56 +01:00
Fix cli DHCP options, started WiFi config for CLI, wrapped wpa_supplicant into service
This commit is contained in:
parent
19d352fb37
commit
848fd50815
@ -33,7 +33,6 @@ func init(){
|
||||
}
|
||||
*/
|
||||
|
||||
// usbCmd represents the usb command
|
||||
var netCmd = &cobra.Command{
|
||||
Use: "NET",
|
||||
Short: "Configure Network settings of ethernet interfaces (including USB ethernet if enabled)",
|
||||
@ -147,10 +146,13 @@ func createManualSettings(iface string, ip4 string, mask4 string, disabled bool)
|
||||
|
||||
func parseDhcpServerOptions(strOptions []string) (options map[uint32]string, err error) {
|
||||
options = map[uint32]string{}
|
||||
|
||||
for _, strOpt := range strOptions {
|
||||
splOpt := strings.SplitN(strOpt,":", 2)
|
||||
if len(splOpt) == 0 {
|
||||
return nil,errors.New(fmt.Sprintf("Invalid DHCP option: %s\nOption format is \"<DHCPOptionNumber>:[DHCPOptionValue]\"", strOpt))
|
||||
//return nil,errors.New(fmt.Sprintf("Invalid DHCP option: %s\nOption format is \"<DHCPOptionNumber>:[DHCPOptionValue]\"", strOpt))
|
||||
//ignore empty options
|
||||
continue
|
||||
}
|
||||
optNum, err := strconv.Atoi(splOpt[0])
|
||||
if err != nil || optNum < 0 {
|
||||
@ -174,10 +176,14 @@ func parseDhcpServerOptions(strOptions []string) (options map[uint32]string, err
|
||||
|
||||
func parseDhcpServerRanges(strRanges []string) (ranges []*pb.DHCPServerRange, err error) {
|
||||
ranges = []*pb.DHCPServerRange{}
|
||||
if len(strRanges) == 0 {
|
||||
return nil,errors.New(fmt.Sprintf("Missing DHCP range: At least one range should be provided to allow assigning IP addresses to clients\n"))
|
||||
}
|
||||
|
||||
for _,strRange := range strRanges {
|
||||
splRange := strings.Split(strRange, "|")
|
||||
if len(splRange) != 3 && len(splRange) != 2 {
|
||||
return nil,errors.New(fmt.Sprintf("Invalid DHCP range: %s\nOption format is \"<first IPv4>|<last IPv4>[|leaseTime]\"", strRange))
|
||||
return nil,errors.New(fmt.Sprintf("Invalid DHCP range: %s\nformat is \"<first IPv4>|<last IPv4>[|leaseTime]\"", strRange))
|
||||
}
|
||||
|
||||
if net.ParseIP(splRange[0]) == nil {
|
||||
@ -277,6 +283,6 @@ func init() {
|
||||
netSetManualCmd.Flags().StringVarP(&tmpStrNetmask4, "netmask","m", "", "The IPv4 netmask to use for the interface")
|
||||
netSetDHCPServerCmd.Flags().StringVarP(&tmpStrAddress4, "address","a", "", "The IPv4 address to use for the interface")
|
||||
netSetDHCPServerCmd.Flags().StringVarP(&tmpStrNetmask4, "netmask","m", "", "The IPv4 netmask to use for the interface")
|
||||
netSetDHCPServerCmd.Flags().StringSliceVarP(&tmpDHCPSrvRanges, "range", "r",[]string{""}, "A DHCP Server range in form \"<lowest IPv4>|<highest IPv4>[|lease time]\" (the flag could be used multiple times)")
|
||||
netSetDHCPServerCmd.Flags().StringSliceVarP(&tmpDHCPSrvOptions, "option", "o",[]string{""}, "A DHCP Server option in form \"<option number>:<value1|value2>\" (Option values have to be separated by '|' not by ','. The flag could be used multiple times)")
|
||||
netSetDHCPServerCmd.Flags().StringSliceVarP(&tmpDHCPSrvRanges, "range", "r",[]string{}, "A DHCP Server range in form \"<lowest IPv4>|<highest IPv4>[|lease time]\" (the flag could be used multiple times)")
|
||||
netSetDHCPServerCmd.Flags().StringSliceVarP(&tmpDHCPSrvOptions, "option", "o",[]string{}, "A DHCP Server option in form \"<option number>:<value1|value2>\" (Option values have to be separated by '|' not by ','. The flag could be used multiple times)")
|
||||
}
|
||||
|
160
cli_client/cmd_wifi.go
Normal file
160
cli_client/cmd_wifi.go
Normal file
@ -0,0 +1,160 @@
|
||||
package cli_client
|
||||
|
||||
import (
|
||||
"github.com/spf13/cobra"
|
||||
pb "../proto"
|
||||
"fmt"
|
||||
"google.golang.org/grpc/status"
|
||||
"os"
|
||||
"errors"
|
||||
"strings"
|
||||
)
|
||||
|
||||
//Empty settings used to store cobra flags
|
||||
var (
|
||||
|
||||
tmpWifiStrReg string = ""
|
||||
tmpWifiStrChannel uint8 = 0
|
||||
tmpWifiHideSSID bool = false
|
||||
tmpWifiDisabled bool = false
|
||||
tmpWifiDisableNexmon bool = false
|
||||
tmpWifiSSID string = ""
|
||||
tmpWifiPSK string = ""
|
||||
|
||||
)
|
||||
|
||||
/*
|
||||
func init(){
|
||||
//Configure spew for struct deep printing (disable using printer interface for gRPC structs)
|
||||
spew.Config.Indent="\t"
|
||||
spew.Config.DisableMethods = true
|
||||
spew.Config.DisablePointerAddresses = true
|
||||
}
|
||||
*/
|
||||
|
||||
var wifiCmd = &cobra.Command{
|
||||
Use: "WIFI",
|
||||
Short: "Configure WiFi (spawn Access Point or join WiFi networks)",
|
||||
}
|
||||
|
||||
var wifiSetCmd = &cobra.Command{
|
||||
Use: "set",
|
||||
Short: "set WiFi settings",
|
||||
Long: ``,
|
||||
}
|
||||
|
||||
var wifiSetAPCmd = &cobra.Command{
|
||||
Use: "ap",
|
||||
Short: "Configure WiFi interface as access point",
|
||||
Long: ``,
|
||||
Run: cobraWifiSetAP,
|
||||
}
|
||||
|
||||
|
||||
var wifiSetStaCmd = &cobra.Command{
|
||||
Use: "sta",
|
||||
Short: "Configure WiFi interface to join a network as station",
|
||||
Long: ``,
|
||||
Run: cobraWifiSetSta,
|
||||
}
|
||||
|
||||
var wifiGetCmd = &cobra.Command{
|
||||
Use: "get",
|
||||
Short: "get WiFi settings",
|
||||
Long: ``,
|
||||
Run: cobraWifiGet,
|
||||
}
|
||||
|
||||
func cobraWifiGet(cmd *cobra.Command, args []string) {
|
||||
return
|
||||
}
|
||||
|
||||
func cobraWifiSetAP(cmd *cobra.Command, args []string) {
|
||||
settings, err := createWifiAPSettings(tmpWifiStrChannel, tmpWifiStrReg, tmpWifiSSID, tmpWifiPSK, tmpWifiHideSSID, tmpWifiDisableNexmon, tmpWifiDisabled)
|
||||
if err != nil {
|
||||
fmt.Printf("Error: %v\n", err)
|
||||
|
||||
os.Exit(-1) //exit with error
|
||||
return
|
||||
}
|
||||
|
||||
|
||||
fmt.Printf("Deploying WiFi inteface settings:\n\t%v\n", settings)
|
||||
|
||||
err = ClientDeployWifiSettings(StrRemoteHost, StrRemotePort, settings)
|
||||
if err != nil {
|
||||
fmt.Println(status.Convert(err).Message())
|
||||
os.Exit(-1) //exit with error
|
||||
}
|
||||
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
func cobraWifiSetSta(cmd *cobra.Command, args []string) {
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
func createWifiAPSettings(channel uint8, reg string, strSSID string, strPSK string, hideSsid bool, nexmon bool, disabled bool) (settings *pb.WiFiSettings, err error) {
|
||||
|
||||
|
||||
if channel < 1 || channel > 14 {
|
||||
return nil,errors.New(fmt.Sprintf("Only 2.4GHz channels between 1 and 14 are supported, but '%d' was given\n", channel))
|
||||
}
|
||||
|
||||
|
||||
if len(reg) != 2 {
|
||||
return nil,errors.New(fmt.Sprintf("Regulatory domain has to consist of two uppercase letters (ISO/IEC 3166-1 alpha2), but '%s' was given\n", reg))
|
||||
}
|
||||
reg = strings.ToUpper(reg)
|
||||
|
||||
|
||||
if len(strSSID) < 1 || len(strSSID) > 32 {
|
||||
return nil,errors.New(fmt.Sprintf("SSID has to consist of 1 to 32 ASCII letters (even if hidden), but '%s' was given\n", strSSID))
|
||||
}
|
||||
|
||||
if len(strPSK) > 0 && len(strPSK) < 8 {
|
||||
return nil,errors.New(fmt.Sprintf("A non-empty PSK implies WPA2 and has to have a minimum of 8 characters, but given PSK has '%d' charactres\n", len(strPSK)))
|
||||
}
|
||||
|
||||
settings = &pb.WiFiSettings{
|
||||
Mode: pb.WiFiSettings_AP,
|
||||
AuthMode: pb.WiFiSettings_OPEN,
|
||||
Disabled: disabled,
|
||||
Reg: reg,
|
||||
ApChannel: uint32(channel),
|
||||
ApHideSsid: hideSsid,
|
||||
BssCfgAP: &pb.BSSCfg{
|
||||
SSID: strSSID,
|
||||
PSK: strPSK,
|
||||
},
|
||||
DisableNexmon: !nexmon,
|
||||
BssCfgClient: nil, //not needed
|
||||
}
|
||||
|
||||
if len(strPSK) > 0 {
|
||||
settings.AuthMode = pb.WiFiSettings_WPA2_PSK //if PSK is given use WPA2
|
||||
}
|
||||
|
||||
|
||||
return settings, err
|
||||
}
|
||||
|
||||
|
||||
func init() {
|
||||
rootCmd.AddCommand(wifiCmd)
|
||||
wifiCmd.AddCommand(wifiGetCmd)
|
||||
wifiCmd.AddCommand(wifiSetCmd)
|
||||
wifiSetCmd.AddCommand(wifiSetAPCmd)
|
||||
wifiSetCmd.AddCommand(wifiSetStaCmd)
|
||||
|
||||
wifiSetCmd.PersistentFlags().StringVarP(&tmpWifiStrReg, "reg","r", "US", "Sets the regulatory domain according to ISO/IEC 3166-1 alpha2")
|
||||
wifiSetCmd.PersistentFlags().BoolVarP(&tmpWifiDisabled, "disable","d", false, "The flag disables the WiFi interface (omitting the flag enables the interface")
|
||||
wifiSetCmd.PersistentFlags().BoolVarP(&tmpWifiDisableNexmon, "nonexmon","n", false, "Don't use the modified nexmon firmware")
|
||||
wifiSetCmd.PersistentFlags().StringVarP(&tmpWifiSSID, "ssid","s", "", "The SSID to use for an Access Point or to join as station")
|
||||
wifiSetCmd.PersistentFlags().StringVarP(&tmpWifiPSK, "psk","k", "", "The Pre-Shared-Key to use for the Access Point (if empty, an OPEN AP is created) or for the network")
|
||||
|
||||
wifiSetAPCmd.Flags().Uint8VarP(&tmpWifiStrChannel, "channel","c", 1, "The WiFi channel to use for the Access Point")
|
||||
wifiSetAPCmd.Flags().BoolVarP(&tmpWifiHideSSID, "hide","x", false, "Hide the SSID of the Access Point")
|
||||
}
|
@ -139,6 +139,28 @@ func ClientDeployEthernetInterfaceSettings(host string, port string, settings *p
|
||||
|
||||
}
|
||||
|
||||
func ClientDeployWifiSettings(host string, port string, settings *pb.WiFiSettings) (err error) {
|
||||
// Set up a connection to the server.
|
||||
address := host + ":" + port
|
||||
//log.Printf("Connecting %s ...", address)
|
||||
connection, err := grpc.Dial(address, grpc.WithInsecure())
|
||||
if err != nil {
|
||||
log.Fatalf("Could not connect to P4wnP1 RPC server: %v", err)
|
||||
}
|
||||
defer connection.Close()
|
||||
|
||||
rpcClient := pb.NewP4WNP1Client(connection)
|
||||
|
||||
// Contact the server
|
||||
ctx, cancel := context.WithTimeout(context.Background(), time.Second * 30)
|
||||
defer cancel()
|
||||
|
||||
_,err = rpcClient.DeployWifiSettings(ctx, settings)
|
||||
|
||||
|
||||
return err
|
||||
}
|
||||
|
||||
/*
|
||||
func ClientDisconnectServer(cancel context.CancelFunc, connection *grpc.ClientConn) error {
|
||||
defer connection.Close()
|
||||
|
@ -29,3 +29,4 @@ sudo pip install pydispatcher
|
||||
|
||||
|
||||
sudo update-rc.d dhcpcd disable
|
||||
sudo update-rc.d dnsmasq disable
|
||||
|
4
notes.txt
Normal file
4
notes.txt
Normal file
@ -0,0 +1,4 @@
|
||||
- global dnsmasq service needs to be stopped, in order to avoid overwriting resolv.conf with configuration of local loopback interface (nameserver 127.0.0.1)
|
||||
- global dhcpcd service needs to be stopped
|
||||
- gloabel hostapd service needs to be stopped
|
||||
- global wpa_supplicant service needs to be stopped
|
113
service/wifi.go
113
service/wifi.go
@ -14,6 +14,8 @@ import (
|
||||
"strconv"
|
||||
"syscall"
|
||||
"time"
|
||||
"bufio"
|
||||
"io"
|
||||
)
|
||||
|
||||
const (
|
||||
@ -32,6 +34,10 @@ const (
|
||||
WiFiAuthMode_UNSUPPORTED
|
||||
)
|
||||
|
||||
const (
|
||||
WPA_SUPPLICANT_CONNECT_TIMEOUT = time.Second * 10
|
||||
)
|
||||
|
||||
type BSS struct {
|
||||
SSID string
|
||||
BSSID net.HardwareAddr
|
||||
@ -127,7 +133,7 @@ func DeployWifiSettings(ws *pb.WiFiSettings) (err error) {
|
||||
err = WifiCreateWpaSupplicantConfigFile(ws.BssCfgClient.SSID, ws.BssCfgClient.PSK, confFileWpaSupplicant(wifi_if_name))
|
||||
if err != nil { return err }
|
||||
//ToDo: proper error handling, in case connection not possible
|
||||
err = wifiStartWpaSupplicant(wifi_if_name)
|
||||
err = wifiStartWpaSupplicant2(wifi_if_name, WPA_SUPPLICANT_CONNECT_TIMEOUT)
|
||||
if err != nil { return err }
|
||||
}
|
||||
|
||||
@ -203,6 +209,8 @@ func wifiCreateWpaSupplicantConfString(ssid string, psk string) (config string,
|
||||
return "",errors.New(fmt.Sprintf("Error craeting wpa_supplicant.conf for SSID '%s' with PSK '%s': %s", ssid, psk, string(cres)))
|
||||
}
|
||||
config = string(cres)
|
||||
config = "ctrl_interface=/run/wpa_supplicant\n" + config
|
||||
|
||||
|
||||
return
|
||||
}
|
||||
@ -307,7 +315,9 @@ func wifiStartHostapd(nameIface string) (err error) {
|
||||
//We use the run command and allow hostapd to daemonize
|
||||
proc := exec.Command("/usr/sbin/hostapd", "-B", "-P", pidFileHostapd(nameIface), "-f", logFileHostapd(nameIface), confpath)
|
||||
err = proc.Run()
|
||||
if err != nil { return err}
|
||||
if err != nil {
|
||||
return errors.New(fmt.Sprintf("Error starting hostapd '%v'", err))
|
||||
}
|
||||
|
||||
|
||||
log.Printf("... hostapd for interface '%s' started\n", nameIface)
|
||||
@ -358,11 +368,11 @@ func wifiStartWpaSupplicant(nameIface string) (err error) {
|
||||
|
||||
confpath := confFileWpaSupplicant(nameIface)
|
||||
|
||||
//stop hostapd if already running
|
||||
//stop wpa_supplicant if already running
|
||||
wifiStopWpaSupplicant(nameIface)
|
||||
|
||||
|
||||
//We use the run command and allow hostapd to daemonize
|
||||
//We use the run command and allow wpa_supplicant to daemonize
|
||||
//wpa_supplicant -P /tmp/wpa_supplicant.pid -i wlan0 -c /tmp/wpa_supplicant.conf -B
|
||||
proc := exec.Command("/sbin/wpa_supplicant", "-B", "-P", pidFileWpaSupplicant(nameIface), "-f", logFileWpaSupplicant(nameIface), "-c", confpath, "-i", nameIface)
|
||||
err = proc.Run()
|
||||
@ -373,6 +383,101 @@ func wifiStartWpaSupplicant(nameIface string) (err error) {
|
||||
return nil
|
||||
}
|
||||
|
||||
func wifiWpaSupplicantOutParser(chanResult chan string, reader *bufio.Reader) {
|
||||
log.Println("... Start monitoring wpa_supplicant output")
|
||||
|
||||
for {
|
||||
line, _, err := reader.ReadLine()
|
||||
if err != nil {
|
||||
//in case wpa_supplicant is killed, we should land here, which ends the goroutine
|
||||
if err != io.EOF {
|
||||
log.Printf("Can't read wpa_supplicant output: %s\n", err)
|
||||
}
|
||||
|
||||
break
|
||||
}
|
||||
strLine := string(line)
|
||||
|
||||
//fmt.Printf("Read:\n%s\n", strLine)
|
||||
|
||||
switch {
|
||||
case strings.Contains(strLine, "WRONG_KEY"):
|
||||
log.Printf("Seems the provided PSK doesn't match\n")
|
||||
chanResult <- "WRONG_KEY"
|
||||
break
|
||||
case strings.Contains(strLine, "CTRL-EVENT-CONNECTED"):
|
||||
log.Printf("Connected to target network\n")
|
||||
chanResult <- "CONNECTED"
|
||||
break // stop loop
|
||||
}
|
||||
}
|
||||
log.Println("... stopped monitoring wpa_supplicant output")
|
||||
}
|
||||
|
||||
func wifiStartWpaSupplicant2(nameIface string, timeout time.Duration) (err error) {
|
||||
log.Printf("Starting wpa_supplicant for interface '%s'...\n", nameIface)
|
||||
|
||||
//check if interface is valid
|
||||
if_exists,_ := CheckInterfaceExistence(nameIface)
|
||||
if !if_exists {
|
||||
return errors.New(fmt.Sprintf("The given interface '%s' doesn't exist", nameIface))
|
||||
}
|
||||
|
||||
if !wifiWpaSupplicantAvailable() {
|
||||
return errors.New("wpa_supplicant seems to be missing, please install it")
|
||||
}
|
||||
|
||||
confpath := confFileWpaSupplicant(nameIface)
|
||||
|
||||
//stop wpa_supplicant if already running
|
||||
wifiStopWpaSupplicant(nameIface)
|
||||
|
||||
|
||||
//we monitor output of wpa_supplicant till we are connected, fail due to wrong PSK or timeout is reached
|
||||
proc := exec.Command("/sbin/wpa_supplicant", "-P", pidFileWpaSupplicant(nameIface), "-c", confpath, "-i", nameIface)
|
||||
|
||||
wpa_stdout, err := proc.StdoutPipe()
|
||||
if err != nil { return err}
|
||||
|
||||
err = proc.Start()
|
||||
if err != nil { return err}
|
||||
|
||||
//result channel
|
||||
wpa_res := make(chan string, 1)
|
||||
//start output parser
|
||||
wpa_stdout_reader := bufio.NewReader(wpa_stdout)
|
||||
|
||||
go wifiWpaSupplicantOutParser(wpa_res, wpa_stdout_reader)
|
||||
|
||||
//analyse output
|
||||
select {
|
||||
case res := <-wpa_res:
|
||||
if strings.Contains(res, "CONNECTED") {
|
||||
//We could return success and keep wpa_supplicant running
|
||||
log.Println("... connected to given WiFi network, wpa_supplicant running")
|
||||
return nil
|
||||
}
|
||||
if strings.Contains(res, "WRONG_KEY") {
|
||||
//we stop wpa_supplicant and return err
|
||||
log.Println("... seems the wrong PSK wwas provided for the given WiFi network, stopping wpa_supplicant ...")
|
||||
//wifiStopWpaSupplicant(nameIface)
|
||||
log.Println("... killing wpa_supplicant")
|
||||
proc.Process.Kill()
|
||||
return errors.New("Wrong PSK")
|
||||
}
|
||||
case <- time.After(timeout):
|
||||
//we stop wpa_supplicant and return err
|
||||
log.Println("... wpa_supplicant reached timeout without beeing able to connect to given network")
|
||||
log.Println("... killing wpa_supplicant")
|
||||
//wifiStopWpaSupplicant(nameIface)
|
||||
proc.Process.Kill()
|
||||
return errors.New("TIMEOUT REACHED")
|
||||
}
|
||||
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
|
||||
func wifiStopWpaSupplicant(nameIface string) (err error) {
|
||||
log.Printf("... stop running wpa_supplicant processes for interface '%s'\n", nameIface)
|
||||
|
Loading…
x
Reference in New Issue
Block a user