diff --git a/src/autodetect_environment.cr b/src/autodetect_environment.cr index 014ca85..5a7a5ff 100644 --- a/src/autodetect_environment.cr +++ b/src/autodetect_environment.cr @@ -1,5 +1,15 @@ class Autodetect + def self.uname + os = nil : String? + Do.run("uname") do |p| + p.output.each_line do |line| + os = line + end + end + + os + end class_property print_autodetect : Bool = false def self.which(cmd : String) diff --git a/src/cli.cr b/src/cli.cr index a758cc3..cdc100c 100644 --- a/src/cli.cr +++ b/src/cli.cr @@ -105,22 +105,32 @@ possible_wireless_configuration_cmds = { "ifconfig" => NetworkCommands::IfconfigCommand } -key = Context.prefered_network_configuration_program -key = possible_network_configuration_cmds.keys.find { |key| Autodetect.which(key) } if key.nil? -# should crash if there is no network command installed -NetworkCommands.cmd_network_configuration = possible_network_configuration_cmds[key.not_nil!] +# first, check if we are on OpenBSD +Context.os = Autodetect.uname -key = Context.prefered_dhcp_client -key = possible_dhcp_clients.keys.find { |key| Autodetect.which(key) } if key.nil? -# should not crash if there is no -NetworkCommands.cmd_dhcp_client = possible_dhcp_clients[key] unless key.nil? - -key = Context.prefered_wireless_configuration_program -key = possible_wireless_configuration_cmds.keys.find { |key| Autodetect.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!] +case Context.os +when "Linux" + key = Context.prefered_network_configuration_program + key = possible_network_configuration_cmds.keys.find { |key| Autodetect.which(key) } if key.nil? + # should crash if there is no network command installed + NetworkCommands.cmd_network_configuration = possible_network_configuration_cmds[key.not_nil!] + key = Context.prefered_wireless_configuration_program + key = possible_wireless_configuration_cmds.keys.find { |key| Autodetect.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!] + key = Context.prefered_dhcp_client + key = possible_dhcp_clients.keys.find { |key| Autodetect.which(key) } if key.nil? + # should not crash if there is no dhcp client on the system + NetworkCommands.cmd_dhcp_client = possible_dhcp_clients[key] unless key.nil? + NetworkCommands.cmd_sysctl = NetworkCommands::SysctlCommand +when "OpenBSD" + NetworkCommands.cmd_network_configuration = NetworkCommands::OpenBSDIfconfigCommand + NetworkCommands.cmd_wireless_configuration = NetworkCommands::OpenBSDIfconfigCommand + NetworkCommands.cmd_dhcp_client = NetworkCommands::OpenBSDDHClientCommand + NetworkCommands.cmd_sysctl = NetworkCommands::OpenBSDSysctlCommand +end files = Array(String).new Dir.children("#{Context.root}/etc/").each do |f| diff --git a/src/context.cr b/src/context.cr index 503e420..d660cdb 100644 --- a/src/context.cr +++ b/src/context.cr @@ -2,6 +2,8 @@ class Context class_property root : String = "/" + class_property os : String? + class_property keydir : String = "/etc/network/keydir" class_property simulation = false diff --git a/src/do.cr b/src/do.cr index 6a2ed9c..f8db0a5 100644 --- a/src/do.cr +++ b/src/do.cr @@ -2,7 +2,7 @@ class Do < Process class_property simulation = false - def self.run(cmd : String, params : Array(String) = nil) + def self.run(cmd : String, params = [] of String) if @@simulation puts "simulation, do: #{cmd} #{params.join(" ")}" Process::Status.new 0 @@ -11,7 +11,7 @@ class Do < Process end end - def self.run(cmd : String, params : Array(String) = nil, &block : Process -> _) + def self.run(cmd : String, params = [] of String, &block : Process -> _) if @@simulation puts "simulation, do: #{cmd} #{params.join(" ")}" Process::Status.new 0 diff --git a/src/network_commands.cr b/src/network_commands.cr index 9c8cf3c..42c788d 100644 --- a/src/network_commands.cr +++ b/src/network_commands.cr @@ -1,12 +1,13 @@ # TODO: OpenBSD: no '-w' parameter for sysctl -# TODO: OpenBSD: ifconfig scan +# TODO: OpenBSD: test scanning for wireless AP with ifconfig # TODO: Linux: description with ip-* command family class NetworkCommands class_property cmd_network_configuration : IfconfigCommand.class | IPCommand.class = IfconfigCommand class_property cmd_wireless_configuration : IfconfigCommand.class | IWCommand.class | NotSetup.class = NotSetup class_property cmd_dhcp_client : UDHCPCCommand.class | DHClientCommand.class | NotSetup.class = NotSetup + class_property cmd_sysctl : SysctlCommand.class | OpenBSDSysctlCommand.class | NotSetup.class = NotSetup class DNS property addresses : Array(String) @@ -136,6 +137,12 @@ class NetworkCommands end end + class OpenBSDDHClientCommand < DHClientCommand + def self.dhcp6(ifname : String) + puts "TODO: dhcp6 on OpenBSD" + end + end + class IfconfigCommand def self.interface_exists(name : String) Do.run("ifconfig", [ name ]).success? @@ -193,7 +200,36 @@ class NetworkCommands # ifconfig also performs wireless configuration on some OSs def self.scan(name : String) - puts "TODO: (ifconfig) ifconfig ifname scan | grep SSID" + puts "TODO: (ifconfig) cannot get SSID with ifconfig on Linux" + end + end + + class OpenBSDIfconfigCommand < IfconfigCommand + # get the available SSID + def self.scan(ifname : String) : Array(String) + ssids = Array(String).new + + Do.run("ifconfig", [ ifname, "scan" ]) do |p| + p.output.each_line do |line| + ssid = /nwid (?[a-zA-Z0-9_-]+)/.match(line).try &.["ssid"] + + unless ssid.nil? + ssids << ssid + end + end + end + + if ssids.empty? + raise "(openbsd ifconfig) cannot get ssid list from #{ifname}" + end + + ssids + end + + def self.autoconfiguration(ifname : String) + unless Do.run("ifconfig", [ ifname, "inet6", "autoconf" ]).success? + raise "(openbsd ifconfig) Cannot set IPv6 autoconfiguration on #{ifname}" + end end end @@ -246,9 +282,24 @@ class NetworkCommands def self.description(name : String, description : String) puts "TODO: (ip) setup description '#{description}' to interface #{name}" - # unless Do.run("ip", [ "link", "set", "description", description, "dev", name ]).success? - # raise "(ip) Cannot set description #{description} to #{name}" - # end + end + end + + class SysctlCommand + def self.autoconfiguration(ifname : String) + unless Do.run("sysctl", [ "-w", "net.ipv6.conf.#{ifname}.autoconf=1" ]).success? + raise "(sysctl) cannot set 'net.ipv6.conf.#{ifname}.autoconf=1'" + end + + unless Do.run("sysctl", [ "-w", "net.ipv6.conf.#{ifname}.accept_ra=1" ]).success? + raise "(sysctl) cannot set 'net.ipv6.conf.#{ifname}.accept_ra=1'" + end + end + end + + class OpenBSDSysctlCommand + def self.autoconfiguration(ifname : String) + OpenBSDIfconfigCommand.autoconfiguration ifname end end @@ -309,13 +360,13 @@ class NetworkCommands end def self.autoconfiguration(ifname : String) - # TODO: no '-w' option on openbsd - unless Do.run("sysctl", [ "-w", "net.ipv6.conf.#{ifname}.autoconf=1" ]).success? - raise "(sysctl) cannot set 'net.ipv6.conf.#{ifname}.autoconf=1'" - end + cmd = @@cmd_sysctl - unless Do.run("sysctl", [ "-w", "net.ipv6.conf.#{ifname}.accept_ra=1" ]).success? - raise "(sysctl) cannot set 'net.ipv6.conf.#{ifname}.accept_ra=1'" + case cmd + when NotSetup.class + raise "cannot autoconfigure IPv6" + else + cmd.autoconfiguration ifname end end