mirror of
https://git.baguette.netlib.re/Baguette/networkctl
synced 2025-05-12 16:33:15 +00:00
396 lines
10 KiB
Crystal
396 lines
10 KiB
Crystal
|
|
# TODO: OpenBSD: no '-w' parameter for sysctl
|
|
# 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)
|
|
property search : Array(String)
|
|
|
|
def initialize()
|
|
@addresses = Array(String).new
|
|
@search = Array(String).new
|
|
end
|
|
|
|
def to_s(io : IO)
|
|
addresses.each do |ip|
|
|
io << "nameserver #{ip}"
|
|
end
|
|
|
|
io << "search #{search.join(" ")}" unless search.empty?
|
|
end
|
|
|
|
def execute
|
|
if Context.simulation
|
|
puts "simulation, writing in #{Context.root}/etc/resolv.conf:"
|
|
@addresses.each do |address|
|
|
puts "\tnameserver #{address}"
|
|
end
|
|
|
|
puts "\tsearch #{@search.join(" ")}" unless search.empty?
|
|
else
|
|
Dir.mkdir_p("#{Context.root}/etc/")
|
|
|
|
File.open("#{Context.root}/etc/resolv.conf", "w+") do |file|
|
|
@addresses.each do |address|
|
|
file.puts "nameserver #{address}"
|
|
end
|
|
|
|
file.puts "search #{@search.join(" ")}" unless search.empty?
|
|
end
|
|
end
|
|
end
|
|
end
|
|
|
|
class IWCommand
|
|
# get the available SSID
|
|
def self.scan(ifname : String) : Array(String)
|
|
ssids = Array(String).new
|
|
|
|
Do.run("iw", [ ifname, "scan" ]) do |p|
|
|
p.output.each_line do |line|
|
|
ssid = /SSID: (?<ssid>[a-zA-Z0-9_-]+)/.match(line).try &.["ssid"]
|
|
|
|
unless ssid.nil?
|
|
ssids << ssid
|
|
end
|
|
end
|
|
end
|
|
|
|
if ssids.empty?
|
|
raise "(iw) cannot get ssid list from #{ifname}"
|
|
end
|
|
|
|
ssids
|
|
end
|
|
end
|
|
|
|
class WPASupplicant
|
|
# store the AP passphrase in the wpa_supplicant way
|
|
def self.passphrase(ssid : String, passphrase : String)
|
|
dirpath = "#{Context.root}/#{Context.keydir}"
|
|
|
|
Dir.mkdir_p(dirpath) unless Dir.exists?(dirpath)
|
|
|
|
# verify if the passphrase already is stored for wpa_supplicant
|
|
return if File.exists?("#{dirpath}/#{ssid}.conf")
|
|
|
|
File.open("#{dirpath}/#{ssid}.conf", "w+") do |file|
|
|
Do.run("wpa_passphrase", [ ssid, "#{passphrase}" ]) do |p|
|
|
p.output.each_line do |line|
|
|
file.puts line
|
|
end
|
|
end
|
|
end
|
|
end
|
|
|
|
def self.connection(ifname : String, ssid : String)
|
|
dirpath = "#{Context.root}/#{Context.keydir}"
|
|
unless Do.run("wpa_supplicant",
|
|
[ "-B", "-c", "#{dirpath}/#{ssid}.conf", "-i", ifname ]).success?
|
|
raise "(wpa_supplicant) cannot connect to the wireless AP #{ssid} via the interface #{ifname}"
|
|
end
|
|
end
|
|
|
|
def self.disconnection(ifname : String, ssid : String)
|
|
# TODO: this kills every running wpa_supplicant application
|
|
# not only the instance for ifname
|
|
dirpath = "#{Context.root}/#{Context.keydir}"
|
|
unless Do.run("pkill", [ "wpa_supplicant" ]).success?
|
|
raise "(wpa_supplicant) cannot stop the wpa_supplicant daemon"
|
|
end
|
|
end
|
|
end
|
|
|
|
class UDHCPCCommand
|
|
def self.run(ifname : String)
|
|
unless Do.run("udhcpc", [ ifname ]).success?
|
|
raise "(udhcpc) dhcp failed on #{ifname}"
|
|
end
|
|
end
|
|
|
|
def self.dhcp6(ifname : String)
|
|
# we suppose udhcpc6 installed along with udhcpc
|
|
unless Do.run("udhcpc6", [ ifname ]).success?
|
|
raise "(udhcpc6) dhcp failed on #{ifname}"
|
|
end
|
|
end
|
|
end
|
|
|
|
class DHClientCommand
|
|
def self.run(ifname : String)
|
|
unless Do.run("dhclient", [ ifname ]).success?
|
|
raise "(dhclient) dhcp failed on #{ifname}"
|
|
end
|
|
end
|
|
|
|
def self.dhcp6(ifname : String)
|
|
unless Do.run("dhclient", [ "-6", ifname ]).success?
|
|
raise "(dhclient) dhcp6 failed on #{ifname}"
|
|
end
|
|
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?
|
|
end
|
|
|
|
def self.up_or_down(name : String, updown : String)
|
|
unless Do.run("ifconfig", [ name, updown ]).success?
|
|
raise "(ifconfig) Cannot set #{updown} link name #{name}"
|
|
end
|
|
end
|
|
def self.up(name : String)
|
|
self.up_or_down name, "up"
|
|
end
|
|
def self.down(name : String)
|
|
self.up_or_down name, "down"
|
|
end
|
|
|
|
def self.set_ip(name : String, ip : IPAddress)
|
|
unless Do.run("ifconfig", [ name, ip.to_string ]).success?
|
|
raise "(ifconfig) Cannot set ip address #{ip.to_string} for #{name}"
|
|
end
|
|
end
|
|
|
|
# currently, aliasses with ifconfig: ifconfig add ip/mask
|
|
# same command as the ip setup
|
|
def self.set_alias(name : String, ip : IPAddress)
|
|
unless Do.run("ifconfig", [ name, "add", ip.to_s ]).success?
|
|
raise "(ifconfig) Cannot set ip address alias #{ip.to_s} for #{name}"
|
|
end
|
|
end
|
|
|
|
def self.mtu(name : String, mtu : Int32?)
|
|
unless Do.run("ifconfig", [ name, "mtu", mtu.to_s ]).success?
|
|
raise "(ifconfig) Cannot set mtu #{mtu} for #{name}"
|
|
end
|
|
end
|
|
|
|
def self.description(name : String, description : String)
|
|
unless Do.run("ifconfig", [ name, "description", "\"#{description}\"" ]).success?
|
|
raise "(ifconfig) Cannot set description #{description} for #{name}"
|
|
end
|
|
end
|
|
|
|
def self.flush(name : String)
|
|
unless Do.run("ifconfig", [ name, "0.0.0.0" ]).success?
|
|
raise "(ifconfig) Cannot flush #{name} ip addresses"
|
|
end
|
|
end
|
|
|
|
def self.down(name : String)
|
|
unless Do.run("ifconfig", [ name, "down" ]).success?
|
|
raise "(ifconfig) Cannot set down #{name}"
|
|
end
|
|
end
|
|
|
|
# ifconfig also performs wireless configuration on some OSs
|
|
def self.scan(name : String)
|
|
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 (?<ssid>[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
|
|
|
|
class IPCommand
|
|
def self.interface_exists(name : String)
|
|
Do.run("ip", [ "link", "show", "dev", name ]).success?
|
|
end
|
|
|
|
def self.up_or_down(name : String, updown : String)
|
|
unless Do.run("ip", [ "link", "set", updown, "dev", name ]).success?
|
|
raise "(ip) Cannot set #{updown} link name #{name}"
|
|
end
|
|
end
|
|
def self.up(name : String)
|
|
self.up_or_down name, "up"
|
|
end
|
|
def self.down(name : String)
|
|
self.up_or_down name, "down"
|
|
end
|
|
|
|
def self.set_ip(name : String, ip : IPAddress)
|
|
unless Do.run("ip", [ "address", "add", ip.to_string, "dev", name ]).success?
|
|
raise "(ip) Cannot add ip address #{ip.to_string} to #{name}"
|
|
end
|
|
end
|
|
|
|
def self.set_alias(name : String, ip : IPAddress)
|
|
unless Do.run("ip", [ "address", "add", ip.to_string, "dev", name ]).success?
|
|
raise "(ip) Cannot add ip address alias #{ip.to_string} to #{name}"
|
|
end
|
|
end
|
|
|
|
def self.mtu(name : String, mtu : Int32?)
|
|
unless Do.run("ip", [ "link", "set", "mtu", mtu.to_s, "dev", name ]).success?
|
|
raise "(ip) Cannot set mtu #{mtu} to #{name}"
|
|
end
|
|
end
|
|
|
|
def self.flush(name : String)
|
|
unless Do.run("ip", [ "address", "flush", "dev", name ]).success?
|
|
raise "(ip) Cannot flush #{name} ip addresses"
|
|
end
|
|
end
|
|
|
|
def self.down(name : String)
|
|
unless Do.run("ip", [ "link", "set", "down", "dev", name ]).success?
|
|
raise "(ip) Cannot set down #{name}"
|
|
end
|
|
end
|
|
|
|
def self.description(name : String, description : String)
|
|
puts "TODO: (ip) setup description '#{description}' to interface #{name}"
|
|
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
|
|
|
|
def self.interface_exists(name : String)
|
|
@@cmd_network_configuration.interface_exists(name)
|
|
end
|
|
|
|
def self.up(ifname : String)
|
|
@@cmd_network_configuration.up(ifname)
|
|
end
|
|
|
|
def self.down(ifname : String)
|
|
@@cmd_network_configuration.up(ifname)
|
|
end
|
|
|
|
def self.set_ip(name : String, ip : IPAddress)
|
|
@@cmd_network_configuration.set_ip name, ip
|
|
end
|
|
|
|
def self.dhcp(name : String)
|
|
cmd = @@cmd_dhcp_client
|
|
case cmd
|
|
when NotSetup.class
|
|
raise "no dhcp client: cannot perform dhcp on #{name}"
|
|
else
|
|
cmd.run name
|
|
end
|
|
end
|
|
|
|
def self.set_alias(name : String, ip : IPAddress)
|
|
@@cmd_network_configuration.set_alias name, ip
|
|
end
|
|
|
|
def self.mtu(name : String, mtu : Int32?)
|
|
@@cmd_network_configuration.mtu name, mtu
|
|
end
|
|
|
|
def self.description(name : String, description : String)
|
|
@@cmd_network_configuration.description name, description
|
|
end
|
|
|
|
def self.flush(name : String)
|
|
@@cmd_network_configuration.flush name
|
|
end
|
|
|
|
def self.down(name : String)
|
|
@@cmd_network_configuration.down name
|
|
end
|
|
|
|
def self.scan(ifname : String)
|
|
cmd = @@cmd_wireless_configuration
|
|
case cmd
|
|
when NotSetup.class
|
|
raise "no wireless configuration program: cannot list ssid"
|
|
else
|
|
cmd.scan ifname
|
|
end
|
|
end
|
|
|
|
def self.autoconfiguration(ifname : String)
|
|
cmd = @@cmd_sysctl
|
|
|
|
case cmd
|
|
when NotSetup.class
|
|
raise "cannot autoconfigure IPv6"
|
|
else
|
|
cmd.autoconfiguration ifname
|
|
end
|
|
end
|
|
|
|
def self.dhcp6(ifname : String)
|
|
cmd = @@cmd_dhcp_client
|
|
case cmd
|
|
when NotSetup.class
|
|
raise "no dhcpv6 program"
|
|
else
|
|
cmd.dhcp6 ifname
|
|
end
|
|
end
|
|
|
|
def self.store_access_point_keys(ssid : String, security : WirelessAPSetup::WPA)
|
|
# TODO: only one way to do it
|
|
NetworkCommands::WPASupplicant.passphrase ssid, security.key
|
|
end
|
|
|
|
def self.wireless_access_point_connection(ifname : String, ssid : String)
|
|
NetworkCommands::WPASupplicant.connection ifname, ssid
|
|
end
|
|
|
|
def self.wireless_access_point_disconnection(ifname : String, ssid : String)
|
|
NetworkCommands::WPASupplicant.disconnection ifname, ssid
|
|
end
|
|
end
|