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