From c7290452ad33774b98f0325dc0fc99ad91a903aa Mon Sep 17 00:00:00 2001
From: Philippe PITTOLI
Date: Fri, 4 Oct 2019 19:08:37 +0200
Subject: [PATCH] wireless stuff
---
src/main.cr | 115 ++++++++++++++++++++++++++++++++++++++++++++++++----
1 file changed, 106 insertions(+), 9 deletions(-)
diff --git a/src/main.cr b/src/main.cr
index 0d5160d..9aa5ca0 100644
--- a/src/main.cr
+++ b/src/main.cr
@@ -7,6 +7,7 @@ simulation = false
file = nil
prefered_network_configuration_program = nil
+prefered_wireless_configuration_program = nil
prefered_dhcp_client = nil
OptionParser.parse! do |parser|
@@ -14,6 +15,10 @@ OptionParser.parse! do |parser|
simulation = true
end
+ parser.on "-w wireless-configuration-program", "--wireless wireless-configuration-program", "iw" do |prog|
+ prefered_wireless_configuration_program = prog
+ end
+
parser.on "-n network-configuration-program", "--net-conf network-configuration-program", "ifconfig | ip" do |prog|
prefered_network_configuration_program = prog
end
@@ -60,8 +65,17 @@ end
class NetworkCommands
class_property cmd_network_configuration : IfconfigCommand.class | IPCommand.class = IfconfigCommand
+ class_property cmd_wireless_configuration : IWCommand.class | NotSetup.class = NotSetup
class_property cmd_dhcp_client : UDHCPCCommand.class | NotSetup.class = NotSetup
+ class IWCommand
+ def self.get_ssid(ifname : String, ssid)
+ unless Do.run(cmd, [ name ]).success?
+ raise "(#{cmd}) dhcp failed on #{ifname}"
+ end
+ end
+ end
+
class UDHCPCCommand
def self.run(ifname : String)
# TODO: verify which dhcp client is installed on the system
@@ -164,6 +178,43 @@ class NetworkCommands
def self.set_alias(name : String, ip : IPAddress)
@@cmd_network_configuration.set_alias name, ip
end
+
+ def self.wireless_list_ssid(ifname : String)
+ cmd = @@cmd_wireless_configuration
+ case cmd
+ when NotSetup
+ puts "no wireless configuration program: cannot list ssid"
+ when IWCommand
+ cmd.list_ssid ifname
+ end
+ end
+
+ def self.wireless_connect_wpa_psk(ifname : String, ssid : String, passwd : String)
+ cmd = @@cmd_wireless_configuration
+ case cmd
+ when NotSetup
+ puts "no wireless configuration program: cannot connect to ssid #{ssid}"
+ when IWCommand
+ cmd.list_ssid ifname
+ end
+ end
+end
+
+
+class WirelessAPSetup
+ property ssid : String
+
+ # we currently only support WPA2-PSK wireless security mechanism
+ property security : WPA
+
+ class WPA
+ property key : String
+ def initialize(@key)
+ end
+ end
+
+ def initialize(@ssid, @security)
+ end
end
@@ -180,12 +231,18 @@ class InterfaceConfiguration
property name : String
property up : Bool
+ property description : String?
+ property wireless : Bool
property main_ip_v4 : IPAddress | DHCP | NotSetup
property main_ip_v6 : IPAddress | DHCP | NotSetup
property aliasses_v4 : Array(IPAddress)
property aliasses_v6 : Array(IPAddress)
+ property wireless_networks : Hash(String, WirelessAPSetup)
- def initialize (@name, @up, @main_ip_v4, @main_ip_v6, aliasses)
+ def initialize (@name, @up,
+ @description,
+ @main_ip_v4, @main_ip_v6, aliasses,
+ @wireless, @wireless_networks)
@aliasses_v4 = Array(IPAddress).new
@aliasses_v6 = Array(IPAddress).new
@@ -211,16 +268,19 @@ class InterfaceConfiguration
end
str << "\t#{@up? "up" : "down"}\n"
- str << "\tinet #{@main_ip_v4}\n"
+ description = @description
+ str << "\t#description #{description.not_nil!}\n" unless description.nil?
+ # ipv4
+ str << "\tinet #{@main_ip_v4}\n"
unless @aliasses_v4.empty?
@aliasses_v4.each do |a|
str << "\talias #{a}\n"
end
end
+ # ipv6
str << "\tinet6 #{@main_ip_v6}\n"
-
unless @aliasses_v6.empty?
@aliasses_v6.each do |a|
str << "\talias6 #{a}\n"
@@ -294,20 +354,31 @@ class NetworkConfigurationParser
content = File.read(file_name)
content = content.rchop
ifname = /.([a-zA-Z0-9]+)$/.match(file_name).try &.[1]
- self.parse(ifname.not_nil!, content)
+ if ifname.nil?
+ raise "The interface name is not known from the filename: '#{file_name}'"
+ end
+
+ wireless = false
+ wireless = true unless /^wl[0-9]+$/.match(ifname)
+ self.parse(ifname.not_nil!, content, wireless)
end
- def self.parse (ifname : String, data : String) : InterfaceConfiguration
+ def self.parse (ifname : String, data : String, wireless = false) : InterfaceConfiguration
up = false
+ description = nil
main_ip_v4 = NotSetup.new
main_ip_v6 = NotSetup.new
aliasses = [] of IPAddress
+ wireless_networks = {} of String => WirelessAPSetup
+
data.split("\n").each do |line|
case line
when /^up/
up = true
+ when /^description/
+ description = /^description (.+)/.match(line).try &.[1]
when /^inet6? alias .*/
ipstr = /^inet6? alias ([a-f0-9:.\/]+)/.match(line).try &.[1]
if ipstr.nil?
@@ -333,17 +404,32 @@ class NetworkConfigurationParser
else
main_ip_v6 = IPAddress.parse ipstr
end
+ when /^join [^ ]+ wpakey .*/
+ # WPA2-PSK, other security mechanisms are not supported, yet
+
+ when /^network [^ ]+ inet .*/
+ puts "TODO: network SSID inet IP/prefix"
+
+ when /^network [^ ]+ dhcp/
+ puts "TODO: network SSID dhcp"
+
+ when /^#.*$/
+ # simple comment
+ when /^[ \t]*$/
+ # empty line
else
raise "Cannot parse: #{line}"
end
end
- InterfaceConfiguration.new(ifname, up, main_ip_v4, main_ip_v6, aliasses)
+ InterfaceConfiguration.new(ifname, up,
+ description,
+ main_ip_v4, main_ip_v6,
+ aliasses,
+ wireless, wireless_networks)
end
end
-Do.simulation = simulation
-
def which(cmd : String)
if Process.run("which", [ cmd ]).success?
puts "#{cmd} installed"
@@ -355,6 +441,8 @@ def which(cmd : String)
end
+Do.simulation = simulation
+
#
# discover available configuration commands
#
@@ -371,6 +459,10 @@ possible_dhcp_clients = {
"udhcpc" => NetworkCommands::UDHCPCCommand
}
+# iw = linux
+possible_wireless_configuration_cmds = {
+ "iw" => NetworkCommands::IWCommand
+}
key = prefered_network_configuration_program
key = possible_network_configuration_cmds.keys.find { |key| which(key) } if key.nil?
@@ -382,10 +474,15 @@ key = possible_dhcp_clients.keys.find { |key| which(key) } if key.nil?
# should not crash if there is no
NetworkCommands.cmd_dhcp_client = possible_dhcp_clients[key] unless key.nil?
+key = prefered_wireless_configuration_program
+key = possible_wireless_configuration_cmds.keys.find { |key| which(key) } if key.nil?
+# should crash if there is no wireless command installed
+NetworkCommands.cmd_wireless_configuration = possible_wireless_configuration_cmds[key.not_nil!]
+
if file.nil?
raise "Cannot choose files yet"
else
# TODO: why having to force "not_nil!" ? Seems like a compiler bug
- NetworkConfigurationParser.parse_file(file.not_nil!).execute
+NetworkConfigurationParser.parse_file(file.not_nil!).execute
end