CLI client supports setting up DHCP server or client on an interface

This commit is contained in:
mame82 2018-05-11 23:25:06 +00:00
parent 604e7d7073
commit c3771a5069
4 changed files with 181 additions and 3 deletions

View File

@ -7,6 +7,9 @@ import (
"errors"
"fmt"
"google.golang.org/grpc/status"
"../service"
"strings"
"strconv"
)
//Empty settings used to store cobra flags
@ -16,6 +19,9 @@ var (
tmpStrAddress4 string = ""
tmpStrNetmask4 string = ""
tmpDisabled bool = false
tmpDHCPSrvOptions []string = []string{}
tmpDHCPSrvRanges []string = []string{}
)
/*
@ -78,7 +84,7 @@ func cobraNetSetManual(cmd *cobra.Command, args []string) {
return
}
fmt.Printf("Deployin ethernet inteface settings:\n\t%v\n", settings)
fmt.Printf("Deploying ethernet inteface settings:\n\t%v\n", settings)
err = ClientDeployEthernetInterfaceSettings(StrRemoteHost, StrRemotePort, settings)
if err != nil {
@ -88,11 +94,37 @@ func cobraNetSetManual(cmd *cobra.Command, args []string) {
}
func cobraNetSetDHCPClient(cmd *cobra.Command, args []string) {
settings, err := createDHCPClientSettings(tmpStrInterface, tmpDisabled)
if err != nil {
fmt.Printf("Error: %v\n", err)
return
}
fmt.Printf("Deploying ethernet inteface settings:\n\t%v\n", settings)
err = ClientDeployEthernetInterfaceSettings(StrRemoteHost, StrRemotePort, settings)
if err != nil {
fmt.Println(status.Convert(err).Message())
}
return
}
func cobraNetSetDHCPServer(cmd *cobra.Command, args []string) {
settings, err := createDHCPServerSettings(tmpStrInterface, tmpStrAddress4, tmpStrNetmask4, tmpDisabled, tmpDHCPSrvRanges, tmpDHCPSrvOptions)
if err != nil {
fmt.Printf("Error: %v\n", err)
return
}
fmt.Printf("Deploying ethernet inteface settings:\n\t%v\n", settings)
err = ClientDeployEthernetInterfaceSettings(StrRemoteHost, StrRemotePort, settings)
if err != nil {
fmt.Println(status.Convert(err).Message())
}
return
}
func createManualSettings(iface string, ip4 string, mask4 string, disabled bool) (settings *pb.EthernetInterfaceSettings, err error) {
@ -113,6 +145,112 @@ func createManualSettings(iface string, ip4 string, mask4 string, disabled bool)
return
}
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))
}
optNum, err := strconv.Atoi(splOpt[0])
if err != nil || optNum < 0 {
return nil,errors.New(fmt.Sprintf("Invalid DHCP option Number: %s\nOption format is \"<DHCPOptionNumber>:[DHCPOptionValue]\"", splOpt[0]))
}
uOptNum := uint32(optNum)
if len(splOpt) == 1 {
options[uOptNum] = ""
// fmt.Printf("Setting DHCP server option %d to empty value (disabeling option %d)\n", uOptNum, uOptNum)
} else {
//Replace '|' with ',' (a comma couldn't be used as it'd be interpreted as slice delimiter)
strOptNew := strings.Replace(splOpt[1], "|", ",",-1)
options[uOptNum] = strOptNew
// fmt.Printf("Setting DHCP server option %d to '%s'\n", uOptNum, splOpt[1])
}
}
return options,nil
}
func parseDhcpServerRanges(strRanges []string) (ranges []*pb.DHCPServerRange, err error) {
ranges = []*pb.DHCPServerRange{}
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))
}
if net.ParseIP(splRange[0]) == nil {
return nil, errors.New(fmt.Sprintf("%s in range '%s' is no valid IP address", splRange[0], strRange))
}
if net.ParseIP(splRange[1]) == nil {
return nil, errors.New(fmt.Sprintf("%s in range '%s' is no valid IP address", splRange[1], strRange))
}
pRange := &pb.DHCPServerRange{
RangeLower: splRange[0],
RangeUpper: splRange[1],
}
if len(splRange) > 2 {
//ToDo: Regex check lease time to be valid [0-9]+[mh]
pRange.LeaseTime = splRange[2]
}
ranges = append(ranges, pRange)
}
return ranges,nil
}
func createDHCPServerSettings(iface string, ip4 string, mask4 string, disabled bool, strRanges []string, strOptions []string) (settings *pb.EthernetInterfaceSettings, err error) {
if len(iface) == 0 { return nil,errors.New("Please provide a network interface name") }
err = checkIPv4(ip4)
if err != nil { return nil,errors.New("Please provide a valid IPv4 address for the interface") }
err = checkIPv4(mask4)
if err != nil { return nil,errors.New("Please provide a valid IPv4 netmask for the interface") }
options, err := parseDhcpServerOptions(strOptions)
if err != nil {
return nil, err
}
ranges, err := parseDhcpServerRanges(strRanges)
if err != nil {
return nil, err
}
settings = &pb.EthernetInterfaceSettings {
Mode: pb.EthernetInterfaceSettings_DHCP_SERVER,
Name: iface,
IpAddress4: ip4,
Netmask4: mask4,
Enabled: !disabled,
DhcpServerSettings: &pb.DHCPServerSettings{
ListenInterface:iface,
LeaseFile: service.NameLeaseFileDHCPSrv(iface),
CallbackScript: "",
ListenPort: 0, //Disable DNS
DoNotBindInterface: false, //only listen on given interface
NotAuthoritative: false, // be authoritative
Ranges: ranges,
Options: options,
},
}
return
}
func createDHCPClientSettings(iface string, disabled bool) (settings *pb.EthernetInterfaceSettings, err error) {
if len(iface) == 0 { return nil,errors.New("Please provide a network interface name") }
settings = &pb.EthernetInterfaceSettings {
Mode: pb.EthernetInterfaceSettings_DHCP_CLIENT,
Name: iface,
Enabled: !disabled,
DhcpServerSettings: nil,
}
return
}
func checkIPv4(ip4 string) error {
ip := net.ParseIP(ip4)
if ip == nil {
@ -139,4 +277,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)")
}

View File

@ -128,6 +128,7 @@ func ClientSetLED(host string, port string, ls pb.LEDSettings) (err error) {
}
func ClientDeployEthernetInterfaceSettings(host string, port string, settings *pb.EthernetInterfaceSettings) (err error) {
//ToDo: set longer context deadline
conn, client, ctx, cancel, err := ClientConnectServer(host, port)
defer conn.Close()
defer cancel()

23
examples.sh Normal file
View File

@ -0,0 +1,23 @@
# Update USB gadget configuration (enable RNDIS, disable CDC ECM, enable HID Keyboard)
P4wnP1_cli USB set -r1 -e0 -k1
# Set new network configuration for "usbeth" (the interface is present when USB RNDIS, CDC ECM or both are enabled)
# - "server" means a DHCP server is started for the interface "usbeth"
# - set the address of the interface to 172.16.0.1 (-a flag)
# - set the netmask of the interface to 255.255.255.252 (-m flag)
# - add a range 127.16.0.2 to 172.16.0.2 to the DHCP server with leastime 3 minutes (-r flag, could be used multiple times to add more ranges)
# - add option 3 (ROUTER) to the DHCP server, but don't provide a value to disable sending a gateway entry (-o flag)
# - add option 6 (NAMESERVER) to the DHCP server, but don't provide a value to disable sending a DNS entry (-o flag, again)
# - add option 252 (WPAD) to DHCP server with value 'http://172.16.0.1/wpad.dat' (-o flag, again)
P4wnP1_cli NET set server -i usbeth -a 172.16.0.1 -m 255.255.255.252 -r "172.16.0.2|172.16.0.2|3m" -o "3:" -o "6:" -o "252:http://172.16.0.1/wpad.dat"
# Note: valid DHCP options are defined in RFC 2132 and additional RFCs (f.e. draft-ietf-wrec-wpad-01 defines WPAD)
# Note 2: some option values are lists with comma, f.e option 121 (static route) "121:10.0.0.0/8,10.0.0.1,11.0.0.0,10.0.0.1"
# as the comma "," is already used as delimiter for multiple options, it has to be replaced by a pipe operator "|"
# and the option has to be provided like this:
# -o "121:10.0.0.0/8|10.0.0.1|11.0.0.0/8|10.0.0.1"
# Start a DHCP Client for interface wlan0
P4wnP1_cli NET set client -i wlan0

View File

@ -29,7 +29,11 @@ func pidFileDHCPClient(nameIface string) string {
}
func leaseFileDHCPSrv(s *pb.DHCPServerSettings) (lf string) {
return fmt.Sprintf("/tmp/dnsmasq_%s.leases", s.ListenInterface) //default lease file
return NameLeaseFileDHCPSrv(s.ListenInterface) //default lease file
}
func NameLeaseFileDHCPSrv(nameIface string) (lf string) {
return fmt.Sprintf("/tmp/dnsmasq_%s.leases", nameIface)
}
@ -214,6 +218,7 @@ func DHCPCreateConfigFile(s *pb.DHCPServerSettings, filename string) (err error)
file_content, err := DHCPCreateConfigFileString(s)
if err != nil {return}
err = ioutil.WriteFile(filename, []byte(file_content), os.ModePerm)
//ToDo: test config with `dnsmasq -C configfile --test`
return
}
@ -232,7 +237,15 @@ func DHCPCreateConfigFileString(s *pb.DHCPServerSettings) (config string, err er
//Iterate over Ranges
for _, pRange := range s.Ranges {
config += fmt.Sprintf("dhcp-range=%s,%s,%s\n", pRange.RangeLower, pRange.RangeUpper, pRange.LeaseTime)
//ToDo: regex check for leaseTime
//ToDo: check rangeLower + rangeUpper to be valid IP addresses
if len(pRange.LeaseTime) > 0 {
config += fmt.Sprintf("dhcp-range=%s,%s,%s\n", pRange.RangeLower, pRange.RangeUpper, pRange.LeaseTime)
} else {
//default to 5 minute lease
config += fmt.Sprintf("dhcp-range=%s,%s,5m\n", pRange.RangeLower, pRange.RangeUpper)
}
}
//Iterate over options
@ -254,6 +267,7 @@ func DHCPCreateConfigFileString(s *pb.DHCPServerSettings) (config string, err er
config += fmt.Sprintf("log-dhcp\n") //extensive logging by default
if (!s.NotAuthoritative) { config += fmt.Sprintf("dhcp-authoritative\n") }
return
}