mirror of
https://git.baguette.netlib.re/Baguette/networkctl
synced 2024-12-18 13:03:30 +00:00
dns, WIP autoconfiguration, context...
This commit is contained in:
parent
3b6073a949
commit
90e1aaa20d
171
src/main.cr
171
src/main.cr
@ -3,51 +3,57 @@ require "option_parser"
|
|||||||
require "ipaddress"
|
require "ipaddress"
|
||||||
require "./colors"
|
require "./colors"
|
||||||
|
|
||||||
simulation = false
|
class Context
|
||||||
file = nil
|
class_property root : String = "/"
|
||||||
|
|
||||||
|
class_property simulation = false
|
||||||
|
class_property verbosity = 1
|
||||||
|
|
||||||
prefered_network_configuration_program = nil
|
class_property prefered_network_configuration_program : String? = nil
|
||||||
prefered_wireless_configuration_program = nil
|
class_property prefered_wireless_configuration_program : String? = nil
|
||||||
prefered_dhcp_client = nil
|
class_property prefered_dhcp_client : String? = nil
|
||||||
|
|
||||||
root = "/"
|
class_property root = "/"
|
||||||
print_autodetect = false
|
class_property print_autodetect = false
|
||||||
|
|
||||||
command = "list"
|
class_property command = "list"
|
||||||
args = Array(String).new
|
class_property args = Array(String).new
|
||||||
|
end
|
||||||
|
|
||||||
|
file_option : String? = nil
|
||||||
|
|
||||||
OptionParser.parse! do |parser|
|
OptionParser.parse! do |parser|
|
||||||
parser.on "-s", "--simulation", "Export the network configuration." do
|
parser.on "-s", "--simulation", "Export the network configuration." do
|
||||||
simulation = true
|
Context.simulation = true
|
||||||
end
|
end
|
||||||
|
|
||||||
parser.on "-a", "--print-autodetect", "Print autodetection of the installed programs." do
|
parser.on "-a", "--print-autodetect", "Print autodetection of the installed programs." do
|
||||||
print_autodetect = true
|
Context.print_autodetect = true
|
||||||
end
|
end
|
||||||
|
|
||||||
parser.on "-w wireless-configuration-program", "--wireless wireless-configuration-program", "iw" do |prog|
|
parser.on "-w wireless-configuration-program", "--wireless wireless-configuration-program", "iw" do |prog|
|
||||||
prefered_wireless_configuration_program = prog
|
Context.prefered_wireless_configuration_program = prog
|
||||||
end
|
end
|
||||||
|
|
||||||
parser.on "-n network-configuration-program", "--net-conf network-configuration-program", "ifconfig | ip" do |prog|
|
parser.on "-n network-configuration-program", "--net-conf network-configuration-program", "ifconfig | ip" do |prog|
|
||||||
prefered_network_configuration_program = prog
|
Context.prefered_network_configuration_program = prog
|
||||||
end
|
end
|
||||||
|
|
||||||
parser.on "-d dhcp-client-program", "--dhcp-client dhcp-client-program", "udhcpc | dhclient" do |prog|
|
parser.on "-d dhcp-client-program", "--dhcp-client dhcp-client-program", "udhcpc | dhclient" do |prog|
|
||||||
prefered_dhcp_client = prog
|
Context.prefered_dhcp_client = prog
|
||||||
end
|
end
|
||||||
|
|
||||||
parser.on "-r root", "--root root", "Root where to search for <root>/etc/hostname.* files." do |optsn|
|
parser.on "-r root", "--root root", "Root where to search for <root>/etc/hostname.* files." do |optsn|
|
||||||
root = optsn
|
Context.root = optsn
|
||||||
end
|
end
|
||||||
|
|
||||||
parser.on "-f file", "--file file", "Parse a configuration file." do |optsn|
|
parser.on "-f file", "--file file", "Parse a configuration file." do |optsn|
|
||||||
file = optsn
|
file_option = optsn
|
||||||
end
|
end
|
||||||
|
|
||||||
# 0: nothing is printed, 1: only events, 2: events and messages
|
# 0: nothing is printed, 1: only events, 2: events and messages
|
||||||
parser.on "-v verbosity", "--verbosity verbosity", "Verbosity (0-2). Default: 1" do |optsn|
|
parser.on "-v verbosity", "--verbosity verbosity", "Verbosity (0-2). Default: 1" do |optsn|
|
||||||
verbosity = optsn.to_i
|
Context.verbosity = optsn.to_i
|
||||||
end
|
end
|
||||||
|
|
||||||
parser.missing_option do |opt|
|
parser.missing_option do |opt|
|
||||||
@ -62,16 +68,16 @@ OptionParser.parse! do |parser|
|
|||||||
end
|
end
|
||||||
|
|
||||||
parser.unknown_args do |arg|
|
parser.unknown_args do |arg|
|
||||||
command = arg.shift
|
Context.command = arg.shift
|
||||||
args = arg
|
Context.args = arg
|
||||||
|
|
||||||
case command
|
case Context.command
|
||||||
when /^(list)/
|
when /^(list)/
|
||||||
when /^(up)/
|
when /^(up)/
|
||||||
when /^(down)/
|
when /^(down)/
|
||||||
when /^(scan)/
|
when /^(scan)/
|
||||||
else
|
else
|
||||||
STDERR.puts "Command #{command} not understood"
|
STDERR.puts "Command #{Context.command} not understood"
|
||||||
exit 1
|
exit 1
|
||||||
end
|
end
|
||||||
|
|
||||||
@ -115,6 +121,12 @@ class NotSetup
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
class Autoconfiguration
|
||||||
|
def to_s(io : IO)
|
||||||
|
io << "autoconfiguration"
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
class DHCP
|
class DHCP
|
||||||
def to_s(io : IO)
|
def to_s(io : IO)
|
||||||
io << "dhcp"
|
io << "dhcp"
|
||||||
@ -127,6 +139,21 @@ class NetworkCommands
|
|||||||
class_property cmd_wireless_configuration : IfconfigCommand.class | IWCommand.class | NotSetup.class = NotSetup
|
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_dhcp_client : UDHCPCCommand.class | DHClientCommand.class | NotSetup.class = NotSetup
|
||||||
|
|
||||||
|
class DNS
|
||||||
|
def initialize(@addresses : Array(String), @search : Array(String))
|
||||||
|
end
|
||||||
|
|
||||||
|
def execute
|
||||||
|
File.open("#{Context.root}/etc/resolv.conf", "w") do |file|
|
||||||
|
@addresses.each do |address|
|
||||||
|
file.puts "nameserver #{address}\n"
|
||||||
|
end
|
||||||
|
|
||||||
|
file.puts "search #{@search.join(" ")}"
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
class IWCommand
|
class IWCommand
|
||||||
# get the available SSID
|
# get the available SSID
|
||||||
def self.scan(ifname : String) : Array(String)
|
def self.scan(ifname : String) : Array(String)
|
||||||
@ -338,6 +365,10 @@ class NetworkCommands
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def self.autoconfiguration(ifname : String)
|
||||||
|
puts "TODO: IPv6 autoconfiguration setup"
|
||||||
|
end
|
||||||
|
|
||||||
def self.wireless_connect_wpa_psk(ifname : String, ssid : String, passwd : String)
|
def self.wireless_connect_wpa_psk(ifname : String, ssid : String, passwd : String)
|
||||||
cmd = @@cmd_wireless_configuration
|
cmd = @@cmd_wireless_configuration
|
||||||
case cmd
|
case cmd
|
||||||
@ -358,7 +389,7 @@ class WirelessAPSetup
|
|||||||
property description : String?
|
property description : String?
|
||||||
property mtu : Int32?
|
property mtu : Int32?
|
||||||
property main_ip_v4 : IPAddress | DHCP | NotSetup
|
property main_ip_v4 : IPAddress | DHCP | NotSetup
|
||||||
property main_ip_v6 : IPAddress | DHCP | NotSetup
|
property main_ip_v6 : IPAddress | DHCP | Autoconfiguration | NotSetup
|
||||||
property aliasses_v4 : Array(IPAddress)
|
property aliasses_v4 : Array(IPAddress)
|
||||||
property aliasses_v6 : Array(IPAddress)
|
property aliasses_v6 : Array(IPAddress)
|
||||||
property dns : Array(IPAddress)
|
property dns : Array(IPAddress)
|
||||||
@ -397,29 +428,23 @@ class WirelessAPSetup
|
|||||||
# ipv4
|
# ipv4
|
||||||
unless main_ip_v4.is_a?(NotSetup)
|
unless main_ip_v4.is_a?(NotSetup)
|
||||||
str << "\t\tinet #{main_ip_v4}\n"
|
str << "\t\tinet #{main_ip_v4}\n"
|
||||||
end
|
|
||||||
|
|
||||||
aliasses_v4.each do |a|
|
aliasses_v4.each do |a|
|
||||||
str << "\t\talias #{a}\n"
|
str << "\t\talias #{a}\n"
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
# ipv6
|
# ipv6
|
||||||
unless main_ip_v6.is_a?(NotSetup)
|
unless main_ip_v6.is_a?(NotSetup)
|
||||||
str << "\t\tinet6 #{main_ip_v6}\n"
|
str << "\t\tinet6 #{main_ip_v6}\n"
|
||||||
end
|
|
||||||
|
|
||||||
unless @aliasses_v6.empty?
|
|
||||||
@aliasses_v6.each do |a|
|
@aliasses_v6.each do |a|
|
||||||
str << "\t\talias6 #{a}\n"
|
str << "\t\talias6 #{a}\n"
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
if dns.empty?
|
dns.each do |ip|
|
||||||
str << "\t\tno dns configured\n"
|
str << "\t\tdns: #{ip}\n"
|
||||||
else
|
|
||||||
dns.each do |ip|
|
|
||||||
str << "\t\tdns: #{ip}\n"
|
|
||||||
end
|
|
||||||
end
|
end
|
||||||
|
|
||||||
# to improve readability
|
# to improve readability
|
||||||
@ -441,7 +466,7 @@ class InterfaceConfiguration
|
|||||||
property mtu : Int32?
|
property mtu : Int32?
|
||||||
property wireless : Bool
|
property wireless : Bool
|
||||||
property main_ip_v4 : IPAddress | DHCP | NotSetup
|
property main_ip_v4 : IPAddress | DHCP | NotSetup
|
||||||
property main_ip_v6 : IPAddress | DHCP | NotSetup
|
property main_ip_v6 : IPAddress | Autoconfiguration | DHCP | NotSetup
|
||||||
property aliasses_v4 : Array(IPAddress)
|
property aliasses_v4 : Array(IPAddress)
|
||||||
property aliasses_v6 : Array(IPAddress)
|
property aliasses_v6 : Array(IPAddress)
|
||||||
property wireless_networks : Hash(String, WirelessAPSetup)
|
property wireless_networks : Hash(String, WirelessAPSetup)
|
||||||
@ -490,25 +515,33 @@ class InterfaceConfiguration
|
|||||||
# ipv4
|
# ipv4
|
||||||
unless main_ip_v4.is_a?(NotSetup)
|
unless main_ip_v4.is_a?(NotSetup)
|
||||||
str << "\tinet #{main_ip_v4}\n"
|
str << "\tinet #{main_ip_v4}\n"
|
||||||
end
|
|
||||||
|
|
||||||
unless aliasses_v4.empty?
|
|
||||||
aliasses_v4.each do |a|
|
aliasses_v4.each do |a|
|
||||||
str << "\talias #{a}\n"
|
str << "\talias #{a}\n"
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
# warning: alias but no main ip address
|
||||||
|
if main_ip_v4.is_a?(NotSetup) && ! aliasses_v4.empty?
|
||||||
|
str << "\t#{CRED}alias configured but no main ipv4 configuration.#{CRESET}\n"
|
||||||
|
str << "\t#{CRED}Should main ipv4 be obtained from DHCP? Static configuration?#{CRESET}\n"
|
||||||
|
end
|
||||||
|
|
||||||
# ipv6
|
# ipv6
|
||||||
unless main_ip_v6.is_a?(NotSetup)
|
unless main_ip_v6.is_a?(NotSetup)
|
||||||
str << "\tinet6 #{main_ip_v6}\n"
|
str << "\tinet6 #{main_ip_v6}\n"
|
||||||
end
|
|
||||||
|
|
||||||
unless aliasses_v6.empty?
|
|
||||||
aliasses_v6.each do |a|
|
aliasses_v6.each do |a|
|
||||||
str << "\talias6 #{a}\n"
|
str << "\talias6 #{a}\n"
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
# warning: alias but no main ip address
|
||||||
|
if main_ip_v6.is_a?(NotSetup) && ! aliasses_v6.empty?
|
||||||
|
str << "\t#{CRED}alias6 configured but no main ipv6 configuration.#{CRESET}\n"
|
||||||
|
str << "\t#{CRED}Should main ipv6 be obtained from autoconfiguration? DHCP? Static configuration?#{CRESET}\n"
|
||||||
|
end
|
||||||
|
|
||||||
unless dns.empty?
|
unless dns.empty?
|
||||||
dns.each do |ip|
|
dns.each do |ip|
|
||||||
str << "\tdns: #{ip}\n"
|
str << "\tdns: #{ip}\n"
|
||||||
@ -531,6 +564,17 @@ class InterfaceConfiguration
|
|||||||
raise "The interface #{@name} doesn't exists, yet."
|
raise "The interface #{@name} doesn't exists, yet."
|
||||||
end
|
end
|
||||||
|
|
||||||
|
# TODO: treat differently wireless and non-wireless interfaces
|
||||||
|
if @wireless
|
||||||
|
puts "interface #{name} is wireless"
|
||||||
|
puts "TODO:"
|
||||||
|
puts "1. scan for SSID"
|
||||||
|
puts "2. select configured SSID then try to connect"
|
||||||
|
puts "3. connectivity check with the gateway"
|
||||||
|
else
|
||||||
|
puts "interface #{name} is not wireless"
|
||||||
|
end
|
||||||
|
|
||||||
if up
|
if up
|
||||||
NetworkCommands.up name
|
NetworkCommands.up name
|
||||||
else
|
else
|
||||||
@ -569,19 +613,22 @@ class InterfaceConfiguration
|
|||||||
|
|
||||||
# ipv6 configuration
|
# ipv6 configuration
|
||||||
main_ip_v6.tap do |ip|
|
main_ip_v6.tap do |ip|
|
||||||
|
puts "CONFIGURATION IPV6"
|
||||||
|
|
||||||
case ip
|
case ip
|
||||||
when IPAddress
|
when IPAddress
|
||||||
NetworkCommands.set_ip name, ip
|
NetworkCommands.set_ip name, ip
|
||||||
# TODO
|
# TODO
|
||||||
#when Autoconfiguration
|
when Autoconfiguration
|
||||||
# NetworkCommands.autoconfiguration name
|
puts "CONFIGURATION IPV6 : autoconfiguration !!!"
|
||||||
|
NetworkCommands.autoconfiguration name
|
||||||
#when DHCP
|
#when DHCP
|
||||||
# NetworkCommands.dhcp6 name
|
# NetworkCommands.dhcp6 name
|
||||||
when NotSetup
|
when NotSetup
|
||||||
# do nothing
|
# do nothing
|
||||||
|
puts "CONFIGURATION IPV6 : not setup !!!"
|
||||||
else
|
else
|
||||||
raise "ipv4 configuration: neither static nor dynamic"
|
raise "ipv6 configuration: neither static nor dynamic"
|
||||||
end
|
end
|
||||||
|
|
||||||
# We wont setup aliasses unless there is an actual IP address
|
# We wont setup aliasses unless there is an actual IP address
|
||||||
@ -661,7 +708,7 @@ class NetworkConfigurationParser
|
|||||||
end
|
end
|
||||||
when /^inet6 autoconf/
|
when /^inet6 autoconf/
|
||||||
# IP address is autoconfigured
|
# IP address is autoconfigured
|
||||||
puts "TODO: IPv6 autoconfiguration"
|
main_ip_v6 = Autoconfiguration.new
|
||||||
|
|
||||||
when /^inet6? .*/
|
when /^inet6? .*/
|
||||||
ipstr = /^inet6? ([a-f0-9:.\/]+)/.match(line).try &.[1]
|
ipstr = /^inet6? ([a-f0-9:.\/]+)/.match(line).try &.[1]
|
||||||
@ -710,8 +757,9 @@ class NetworkConfigurationParser
|
|||||||
next
|
next
|
||||||
end
|
end
|
||||||
|
|
||||||
# TODO
|
|
||||||
access_point = wireless_networks[ssid].not_nil!
|
access_point = wireless_networks[ssid].not_nil!
|
||||||
|
access_point.main_ip_v6 = Autoconfiguration.new
|
||||||
|
puts "for SSID: #{ssid} ipv6 configuration = autoconf"
|
||||||
|
|
||||||
when /^network [^ \t]+ inet6? .*/
|
when /^network [^ \t]+ inet6? .*/
|
||||||
ssid = nil
|
ssid = nil
|
||||||
@ -841,8 +889,8 @@ class Autodetect
|
|||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
Do.simulation = simulation
|
Do.simulation = Context.simulation
|
||||||
Autodetect.print_autodetect = print_autodetect
|
Autodetect.print_autodetect = Context.print_autodetect
|
||||||
|
|
||||||
#
|
#
|
||||||
# discover available configuration commands
|
# discover available configuration commands
|
||||||
@ -867,17 +915,17 @@ possible_wireless_configuration_cmds = {
|
|||||||
"ifconfig" => NetworkCommands::IfconfigCommand
|
"ifconfig" => NetworkCommands::IfconfigCommand
|
||||||
}
|
}
|
||||||
|
|
||||||
key = prefered_network_configuration_program
|
key = Context.prefered_network_configuration_program
|
||||||
key = possible_network_configuration_cmds.keys.find { |key| Autodetect.which(key) } if key.nil?
|
key = possible_network_configuration_cmds.keys.find { |key| Autodetect.which(key) } if key.nil?
|
||||||
# should crash if there is no network command installed
|
# should crash if there is no network command installed
|
||||||
NetworkCommands.cmd_network_configuration = possible_network_configuration_cmds[key.not_nil!]
|
NetworkCommands.cmd_network_configuration = possible_network_configuration_cmds[key.not_nil!]
|
||||||
|
|
||||||
key = prefered_dhcp_client
|
key = Context.prefered_dhcp_client
|
||||||
key = possible_dhcp_clients.keys.find { |key| Autodetect.which(key) } if key.nil?
|
key = possible_dhcp_clients.keys.find { |key| Autodetect.which(key) } if key.nil?
|
||||||
# should not crash if there is no
|
# should not crash if there is no
|
||||||
NetworkCommands.cmd_dhcp_client = possible_dhcp_clients[key] unless key.nil?
|
NetworkCommands.cmd_dhcp_client = possible_dhcp_clients[key] unless key.nil?
|
||||||
|
|
||||||
key = prefered_wireless_configuration_program
|
key = Context.prefered_wireless_configuration_program
|
||||||
key = possible_wireless_configuration_cmds.keys.find { |key| Autodetect.which(key) } if key.nil?
|
key = possible_wireless_configuration_cmds.keys.find { |key| Autodetect.which(key) } if key.nil?
|
||||||
# should crash if there is no wireless command installed
|
# should crash if there is no wireless command installed
|
||||||
NetworkCommands.cmd_wireless_configuration = possible_wireless_configuration_cmds[key.not_nil!]
|
NetworkCommands.cmd_wireless_configuration = possible_wireless_configuration_cmds[key.not_nil!]
|
||||||
@ -885,7 +933,7 @@ NetworkCommands.cmd_wireless_configuration = possible_wireless_configuration_cmd
|
|||||||
|
|
||||||
|
|
||||||
files = Array(String).new
|
files = Array(String).new
|
||||||
Dir.children("#{root}/etc/").each do |f|
|
Dir.children("#{Context.root}/etc/").each do |f|
|
||||||
if /^hostname\./.match(f)
|
if /^hostname\./.match(f)
|
||||||
files << f
|
files << f
|
||||||
end
|
end
|
||||||
@ -893,46 +941,43 @@ end
|
|||||||
|
|
||||||
interface_files = Array(String).new
|
interface_files = Array(String).new
|
||||||
|
|
||||||
if ! file.nil?
|
if ! file_option.nil?
|
||||||
# file passed via the '-f' option
|
# file passed via the '-f' option
|
||||||
# TODO: why having to force "not_nil!" ? Seems like a compiler bug
|
# TODO: why having to force "not_nil!" ? Seems like a compiler bug
|
||||||
interface_files << file.not_nil!
|
interface_files << file_option.not_nil!
|
||||||
elsif args.empty?
|
elsif Context.args.empty?
|
||||||
# every configured interface
|
# every configured interface
|
||||||
files.each do |f|
|
files.each do |f|
|
||||||
interface_files << "#{root}/etc/#{f}"
|
interface_files << "#{Context.root}/etc/#{f}"
|
||||||
end
|
end
|
||||||
else
|
else
|
||||||
# only interfaces in arguments
|
# only interfaces in arguments
|
||||||
args.each do |interface|
|
Context.args.each do |interface|
|
||||||
interface_files << "#{root}/etc/hostname.#{interface}"
|
interface_files << "#{Context.root}/etc/hostname.#{interface}"
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
begin
|
begin
|
||||||
case command
|
case Context.command
|
||||||
when "list"
|
when "list"
|
||||||
interface_files.each do |f|
|
interface_files.each do |f|
|
||||||
puts NetworkConfigurationParser.parse_file(f.not_nil!)
|
puts NetworkConfigurationParser.parse_file(f)
|
||||||
end
|
end
|
||||||
when "up"
|
when "up"
|
||||||
# TODO: why having to force "not_nil!" ? Seems like a compiler bug
|
|
||||||
interface_files.each do |f|
|
interface_files.each do |f|
|
||||||
network_configuration = NetworkConfigurationParser.parse_file(f.not_nil!)
|
network_configuration = NetworkConfigurationParser.parse_file(f)
|
||||||
network_configuration.execute
|
network_configuration.execute
|
||||||
end
|
end
|
||||||
when "down"
|
when "down"
|
||||||
# TODO: why having to force "not_nil!" ? Seems like a compiler bug
|
|
||||||
interface_files.each do |f|
|
interface_files.each do |f|
|
||||||
network_configuration = NetworkConfigurationParser.parse_file(f.not_nil!)
|
network_configuration = NetworkConfigurationParser.parse_file(f)
|
||||||
network_configuration.down
|
network_configuration.down
|
||||||
end
|
end
|
||||||
when "scan"
|
when "scan"
|
||||||
# TODO: why having to force "not_nil!" ? Seems like a compiler bug
|
|
||||||
interface_files.each do |f|
|
interface_files.each do |f|
|
||||||
network_configuration = NetworkConfigurationParser.parse_file(f.not_nil!)
|
network_configuration = NetworkConfigurationParser.parse_file(f)
|
||||||
network_configuration.scan
|
network_configuration.scan
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
Loading…
Reference in New Issue
Block a user