diff --git a/.gitignore b/.gitignore index 347dcd1..bb6c9eb 100644 --- a/.gitignore +++ b/.gitignore @@ -36,9 +36,6 @@ venv*/* # Pycharm stuff .idea/* -# VSCode -.vscode/* - # Translations *.mo @@ -46,5 +43,10 @@ venv*/* .mr.developer.cfg .project .pydevproject + +# Editor Configuration Files +.vscode + # python core dump python*.core + diff --git a/LICENSE b/LICENSE index c936cde..184fdaf 100644 --- a/LICENSE +++ b/LICENSE @@ -1,4 +1,4 @@ -Copyright (c) 2014, GhostBSD +Copyright (c) 2012-2023, GhostBSD All rights reserved. Redistribution and use in source and binary forms, with or without modification, diff --git a/NetworkMgr/__init__.py b/NetworkMgr/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/NetworkMgr/configuration.py b/NetworkMgr/configuration.py new file mode 100755 index 0000000..b535fae --- /dev/null +++ b/NetworkMgr/configuration.py @@ -0,0 +1,515 @@ +#!/usr/bin/env python + +import gi +import os +import re +gi.require_version('Gtk', '3.0') +from gi.repository import Gtk, GLib +from NetworkMgr.net_api import ( + defaultcard, + nics_list, + restart_card_network, + restart_rounting_and_dhcp, + start_static_network, + wait_inet +) +from NetworkMgr.query import get_interface_settings +from subprocess import run + +rcconf = open('/etc/rc.conf', 'r').read() +if os.path.exists('/etc/rc.conf.local'): + rcconflocal = open('/etc/rc.conf.local', 'r').read() +else: + rcconflocal = "None" + + +class netCardConfigWindow(Gtk.Window): + + def edit_ipv4_setting(self, widget): + if widget.get_active(): + self.method = widget.get_label() + if self.method == "DHCP": + self.ipInputAddressEntry.set_sensitive(False) + self.ipInputMaskEntry.set_sensitive(False) + self.ipInputGatewayEntry.set_sensitive(False) + self.prymary_dnsEntry.set_sensitive(False) + self.secondary_dnsEntry.set_sensitive(False) + else: + self.ipInputAddressEntry.set_sensitive(True) + self.ipInputMaskEntry.set_sensitive(True) + self.ipInputGatewayEntry.set_sensitive(True) + self.prymary_dnsEntry.set_sensitive(True) + self.secondary_dnsEntry.set_sensitive(True) + if self.method == self.currentSettings["Assignment Method"]: + self.saveButton.set_sensitive(False) + else: + self.saveButton.set_sensitive(True) + + def edit_ipv6_setting(self, widget, value): + if value == "SLAAC": + self.ipInputAddressEntry6.set_sensitive(False) + self.ipInputMaskEntry6.set_sensitive(False) + self.ipInputGatewayEntry6.set_sensitive(False) + self.prymary_dnsEntry6.set_sensitive(False) + self.searchEntry6.set_sensitive(False) + self.saveButton.set_sensitive(False) + else: + self.ipInputAddressEntry6.set_sensitive(True) + self.ipInputMaskEntry6.set_sensitive(True) + self.ipInputGatewayEntry6.set_sensitive(True) + self.prymary_dnsEntry6.set_sensitive(True) + self.searchEntry6.set_sensitive(True) + self.saveButton.set_sensitive(True) + + def entry_trigger_save_button(self, widget, event): + self.saveButton.set_sensitive(True) + + def __init__(self, selected_nic=None): + # Build Default Window + Gtk.Window.__init__(self, title="Network Configuration") + self.set_default_size(475, 400) + self.NICS = nics_list() + DEFAULT_NIC = selected_nic if selected_nic else defaultcard() + # Build Tab 1 Content + # Interface Drop Down Combo Box + cell = Gtk.CellRendererText() + + interfaceComboBox = Gtk.ComboBox() + interfaceComboBox.pack_start(cell, expand=True) + interfaceComboBox.add_attribute(cell, 'text', 0) + + # Add interfaces to a ListStore + store = Gtk.ListStore(str) + + for nic in self.NICS: + store.append([nic]) + + interfaceComboBox.set_model(store) + interfaceComboBox.set_margin_top(15) + interfaceComboBox.set_margin_end(30) + if DEFAULT_NIC: + active_index = self.NICS.index(f"{DEFAULT_NIC}") + interfaceComboBox.set_active(active_index) + self.currentSettings = get_interface_settings(DEFAULT_NIC) + self.method = self.currentSettings["Assignment Method"] + interfaceComboBox.connect("changed", self.cbox_config_refresh, self.NICS) + + # Build Label to sit in front of the ComboBox + labelOne = Gtk.Label(label="Interface:") + labelOne.set_margin_top(15) + labelOne.set_margin_start(30) + + # Add both objects to a single box, which will then be added to the grid + interfaceBox = Gtk.Box(orientation=0, spacing=100) + interfaceBox.pack_start(labelOne, False, False, 0) + interfaceBox.pack_end(interfaceComboBox, True, True, 0) + + # Add radio button to toggle DHCP or not + self.version = self.currentSettings["Assignment Method"] + self.rb_dhcp4 = Gtk.RadioButton.new_with_label(None, "DHCP") + self.rb_dhcp4.set_margin_top(15) + self.rb_manual4 = Gtk.RadioButton.new_with_label_from_widget( + self.rb_dhcp4, "Manual") + self.rb_manual4.set_margin_top(15) + if self.currentSettings["Assignment Method"] == "DHCP": + self.rb_dhcp4.set_active(True) + else: + self.rb_manual4.set_active(True) + self.rb_manual4.join_group(self.rb_dhcp4) + + radioButtonLabel = Gtk.Label(label="IPv4 Method:") + radioButtonLabel.set_margin_top(15) + radioButtonLabel.set_margin_start(30) + + radioBox = Gtk.Box(orientation=0, spacing=50) + radioBox.set_homogeneous(False) + radioBox.pack_start(radioButtonLabel, False, False, 0) + radioBox.pack_start(self.rb_dhcp4, True, False, 0) + radioBox.pack_end(self.rb_manual4, True, True, 0) + + # Add Manual Address Field + ipInputAddressLabel = Gtk.Label(label="Address") + ipInputAddressLabel.set_margin_top(15) + + ipInputMaskLabel = Gtk.Label(label="Subnet Mask") + ipInputMaskLabel.set_margin_top(15) + + ipInputGatewayLabel = Gtk.Label(label="Gateway") + ipInputGatewayLabel.set_margin_top(15) + + self.ipInputAddressEntry = Gtk.Entry() + self.ipInputAddressEntry.set_margin_start(15) + self.ipInputAddressEntry.set_text(self.currentSettings["Interface IP"]) + self.ipInputAddressEntry.connect("key-release-event", self.entry_trigger_save_button) + + self.ipInputMaskEntry = Gtk.Entry() + self.ipInputMaskEntry.set_text(self.currentSettings["Interface Subnet Mask"]) + self.ipInputMaskEntry.connect("key-release-event", self.entry_trigger_save_button) + + self.ipInputGatewayEntry = Gtk.Entry() + self.ipInputGatewayEntry.set_margin_end(15) + self.ipInputGatewayEntry.set_text(self.currentSettings["Default Gateway"]) + self.ipInputGatewayEntry.connect("key-release-event", self.entry_trigger_save_button) + + ipInputBox = Gtk.Box(orientation=0, spacing=0) + ipInputBox.set_homogeneous(True) + ipInputBox.pack_start(ipInputAddressLabel, False, False, 0) + ipInputBox.pack_start(ipInputMaskLabel, False, False, 0) + ipInputBox.pack_start(ipInputGatewayLabel, False, False, 0) + + ipEntryBox = Gtk.Box(orientation=0, spacing=30) + ipEntryBox.pack_start(self.ipInputAddressEntry, False, False, 0) + ipEntryBox.pack_start(self.ipInputMaskEntry, False, False, 0) + ipEntryBox.pack_start(self.ipInputGatewayEntry, False, False, 0) + + # Add DNS Server Settings + prymary_dns_Label = Gtk.Label(label="Primary DNS Servers: ") + prymary_dns_Label.set_margin_top(15) + prymary_dns_Label.set_margin_end(58) + prymary_dns_Label.set_margin_start(30) + + secondary_dns_Label = Gtk.Label(label="Secondary DNS Servers: ") + secondary_dns_Label.set_margin_top(15) + secondary_dns_Label.set_margin_end(58) + secondary_dns_Label.set_margin_start(30) + + self.prymary_dnsEntry = Gtk.Entry() + self.prymary_dnsEntry.set_margin_end(30) + self.prymary_dnsEntry.set_text(self.currentSettings["DNS Server 1"]) + self.prymary_dnsEntry.connect("key-release-event", self.entry_trigger_save_button) + + self.secondary_dnsEntry = Gtk.Entry() + self.secondary_dnsEntry.set_margin_end(30) + self.secondary_dnsEntry.set_text(self.currentSettings["DNS Server 2"]) + self.secondary_dnsEntry.connect("key-release-event", self.entry_trigger_save_button) + + dnsEntryBox1 = Gtk.Box(orientation=0, spacing=0) + dnsEntryBox1.pack_start(prymary_dns_Label, False, False, 0) + + dnsEntryBox1.pack_end(self.prymary_dnsEntry, True, True, 0) + + dnsEntryBox2 = Gtk.Box(orientation=0, spacing=0) + dnsEntryBox2.pack_start(secondary_dns_Label, False, False, 0) + + dnsEntryBox2.pack_end(self.secondary_dnsEntry, True, True, 0) + + # Add Search Domain Settings + searchLabel = Gtk.Label(label="Search domains: ") + searchLabel.set_margin_top(15) + searchLabel.set_margin_end(30) + searchLabel.set_margin_start(30) + + self.searchEntry = Gtk.Entry() + self.searchEntry.set_margin_top(21) + self.searchEntry.set_margin_end(30) + self.searchEntry.set_margin_bottom(30) + self.searchEntry.set_text(self.currentSettings["Search Domain"]) + self.searchEntry.connect("key-release-event", self.entry_trigger_save_button) + + searchBox = Gtk.Box(orientation=0, spacing=0) + searchBox.pack_start(searchLabel, False, False, 0) + searchBox.pack_end(self.searchEntry, True, True, 0) + + self.rb_dhcp4.connect("toggled", self.edit_ipv4_setting) + self.rb_manual4.connect("toggled", self.edit_ipv4_setting) + + if self.currentSettings["Assignment Method"] == "DHCP": + self.ipInputAddressEntry.set_sensitive(False) + self.ipInputMaskEntry.set_sensitive(False) + self.ipInputGatewayEntry.set_sensitive(False) + self.prymary_dnsEntry.set_sensitive(False) + self.secondary_dnsEntry.set_sensitive(False) + self.searchEntry.set_sensitive(False) + + gridOne = Gtk.Grid() + gridOne.set_column_homogeneous(True) + gridOne.set_row_homogeneous(False) + gridOne.set_column_spacing(5) + gridOne.set_row_spacing(10) + gridOne.attach(interfaceBox, 0, 0, 4, 1) + gridOne.attach(radioBox, 0, 1, 4, 1) + gridOne.attach(ipInputBox, 0, 2, 4, 1) + gridOne.attach(ipEntryBox, 0, 3, 4, 1) + gridOne.attach(dnsEntryBox1, 0, 4, 4, 1) + gridOne.attach(dnsEntryBox2, 0, 5, 4, 1) + gridOne.attach(searchBox, 0, 6, 4, 1) + + # Build Tab 2 Content + + # Interface Drop Down Combo Box + cell6 = Gtk.CellRendererText() + + interfaceComboBox6 = Gtk.ComboBox() + interfaceComboBox6.pack_start(cell6, expand=True) + interfaceComboBox6.add_attribute(cell6, 'text', 0) + + # Add interfaces to a ListStore + store6 = Gtk.ListStore(str) + for validinterface6 in self.NICS: + store6.append([validinterface6]) + + interfaceComboBox6.set_model(store) + interfaceComboBox6.set_margin_top(15) + interfaceComboBox6.set_margin_end(30) + + if DEFAULT_NIC: + activeComboBoxObjectIndex6 = self.NICS.index(f"{DEFAULT_NIC}") + interfaceComboBox6.set_active(activeComboBoxObjectIndex6) + interfaceComboBox6.connect("changed", self.cbox_config_refresh) + + # Build Label to sit in front of the ComboBox + labelOne6 = Gtk.Label(label="Interface:") + labelOne6.set_margin_top(15) + labelOne6.set_margin_start(30) + + # Add both objects to a single box, which will then be added to the grid + interfaceBox6 = Gtk.Box(orientation=0, spacing=100) + interfaceBox6.pack_start(labelOne6, False, False, 0) + interfaceBox6.pack_end(interfaceComboBox6, True, True, 0) + + # Add radio button to toggle DHCP or not + rb_slaac6 = Gtk.RadioButton.new_with_label(None, "SLAAC") + rb_slaac6.set_margin_top(15) + rb_slaac6.connect("toggled", self.edit_ipv6_setting, "SLAAC") + rb_manual6 = Gtk.RadioButton.new_with_label_from_widget( + rb_slaac6, "Manual") + rb_manual6.set_margin_top(15) + rb_manual6.join_group(rb_slaac6) + rb_manual6.connect("toggled", self.edit_ipv6_setting, "Manual") + + radioButtonLabel6 = Gtk.Label(label="IPv4 Method:") + radioButtonLabel6.set_margin_top(15) + radioButtonLabel6.set_margin_start(30) + + radioBox6 = Gtk.Box(orientation=0, spacing=50) + radioBox6.set_homogeneous(False) + radioBox6.pack_start(radioButtonLabel6, False, False, 0) + radioBox6.pack_start(rb_slaac6, True, False, 0) + radioBox6.pack_end(rb_manual6, True, True, 0) + + # Add Manual Address Field + ipInputAddressLabel6 = Gtk.Label(label="Address") + ipInputAddressLabel6.set_margin_top(15) + + ipInputMaskLabel6 = Gtk.Label(label="Subnet Mask") + ipInputMaskLabel6.set_margin_top(15) + + ipInputGatewayLabel6 = Gtk.Label(label="Gateway") + ipInputGatewayLabel6.set_margin_top(15) + + self.ipInputAddressEntry6 = Gtk.Entry() + self.ipInputAddressEntry6.set_margin_start(15) + self.ipInputAddressEntry6.connect("key-release-event", self.entry_trigger_save_button) + self.ipInputMaskEntry6 = Gtk.Entry() + self.ipInputAddressEntry6.connect("key-release-event", self.entry_trigger_save_button) + self.ipInputGatewayEntry6 = Gtk.Entry() + self.ipInputGatewayEntry6.set_margin_end(15) + self.ipInputGatewayEntry6.connect("key-release-event", self.entry_trigger_save_button) + + ipInputBox6 = Gtk.Box(orientation=0, spacing=0) + ipInputBox6.set_homogeneous(True) + ipInputBox6.pack_start(ipInputAddressLabel6, False, False, 0) + ipInputBox6.pack_start(ipInputMaskLabel6, False, False, 0) + ipInputBox6.pack_start(ipInputGatewayLabel6, False, False, 0) + + ipEntryBox6 = Gtk.Box(orientation=0, spacing=30) + ipEntryBox6.pack_start(self.ipInputAddressEntry6, False, False, 0) + ipEntryBox6.pack_start(self.ipInputMaskEntry6, False, False, 0) + ipEntryBox6.pack_start(self.ipInputGatewayEntry6, False, False, 0) + + # Add DNS Server Settings + prymary_dns_Label6 = Gtk.Label(label="Primary DNS Servers: ") + prymary_dns_Label6.set_margin_top(15) + prymary_dns_Label6.set_margin_end(58) + prymary_dns_Label6.set_margin_start(30) + + secondary_dns_Label6 = Gtk.Label(label="Secondary DNS Servers: ") + secondary_dns_Label6.set_margin_top(15) + secondary_dns_Label6.set_margin_end(58) + secondary_dns_Label6.set_margin_start(30) + + self.prymary_dnsEntry6 = Gtk.Entry() + self.prymary_dnsEntry6.set_margin_end(30) + self.prymary_dnsEntry6.connect("key-release-event", self.entry_trigger_save_button) + + dnsEntryBox6 = Gtk.Box(orientation=0, spacing=0) + dnsEntryBox6.pack_start(prymary_dns_Label6, False, False, 0) + dnsEntryBox6.pack_end(self.prymary_dnsEntry6, True, True, 0) + + # Add Search Domain Settings + + searchLabel6 = Gtk.Label(label="Search domains: ") + searchLabel6.set_margin_top(15) + searchLabel6.set_margin_end(30) + searchLabel6.set_margin_start(30) + + self.searchEntry6 = Gtk.Entry() + self.searchEntry6.set_margin_top(21) + self.searchEntry6.set_margin_end(30) + self.searchEntry6.set_margin_bottom(30) + self.searchEntry6.connect("key-release-event", self.entry_trigger_save_button) + + searchBox6 = Gtk.Box(orientation=0, spacing=0) + searchBox6.pack_start(searchLabel6, False, False, 0) + searchBox6.pack_end(self.searchEntry6, True, True, 0) + + self.ipInputAddressEntry6.set_sensitive(False) + self.ipInputMaskEntry6.set_sensitive(False) + self.ipInputGatewayEntry6.set_sensitive(False) + self.prymary_dnsEntry6.set_sensitive(False) + self.searchEntry6.set_sensitive(False) + + gridOne6 = Gtk.Grid() + gridOne6.set_column_homogeneous(True) + gridOne6.set_row_homogeneous(False) + gridOne6.set_column_spacing(5) + gridOne6.set_row_spacing(10) + gridOne6.attach(interfaceBox6, 0, 0, 4, 1) + gridOne6.attach(radioBox6, 0, 1, 4, 1) + gridOne6.attach(ipInputBox6, 0, 2, 4, 1) + gridOne6.attach(ipEntryBox6, 0, 3, 4, 1) + gridOne6.attach(dnsEntryBox6, 0, 4, 4, 1) + gridOne6.attach(searchBox6, 0, 5, 4, 1) + gridOne6.set_sensitive(False) + + # Build Notebook + + nb = Gtk.Notebook() + nb.set_margin_start(10) + nb.set_margin_end(10) + nb.set_margin_top(10) + nb.set_margin_bottom(10) + nb.set_tab_pos(2) + # nb.set_sensitive(False) + # Build Save & Cancel Buttons + + self.saveButton = Gtk.Button(label="Save") + self.saveButton.set_margin_bottom(10) + self.saveButton.set_margin_start(10) + self.saveButton.connect("clicked", self.commit_pending_changes) + self.saveButton.set_sensitive(False) + cancelButton = Gtk.Button(label="Cancel") + cancelButton.set_margin_bottom(10) + cancelButton.connect("clicked", self.discard_pending_changes) + buttonsWindow = Gtk.Box(orientation=0, spacing=10) + buttonsWindow.pack_start(self.saveButton, False, False, 0) + buttonsWindow.pack_start(cancelButton, False, False, 0) + + # Apply Tab 1 content and formatting to the notebook + nb.append_page(gridOne) + nb.set_tab_label_text(gridOne, "IPv4 Settings") + + # Apply Tab 2 content and formatting to the notebook + nb.append_page(gridOne6) + nb.set_tab_label_text(gridOne6, "IPv6 Settings WIP") + # Put all the widgets together into one window + mainBox = Gtk.Box(orientation=1, spacing=0) + mainBox.pack_start(nb, True, True, 0) + mainBox.pack_end(buttonsWindow, False, False, 0) + self.add(mainBox) + + # Used with the combo box to refresh the UI of tab 1 with active settings + # for the newly selected active interface. + def cbox_config_refresh(self, widget, nics): + # actions here need to refresh the values on the first two tabs. + self.currentSettings = get_interface_settings(nics[widget.get_active()]) + self.update_interface_settings() + + def update_interface_settings(self): + self.ipInputAddressEntry.set_text(self.currentSettings["Interface IP"]) + self.ipInputMaskEntry.set_text(self.currentSettings["Interface Subnet Mask"]) + self.ipInputGatewayEntry.set_text(self.currentSettings["Default Gateway"]) + self.prymary_dnsEntry.set_text(self.currentSettings["DNS Server 1"]) + self.secondary_dnsEntry.set_text(self.currentSettings["DNS Server 2"]) + self.searchEntry.set_text(self.currentSettings["Search Domain"]) + if self.currentSettings["Assignment Method"] == "DHCP": + self.rb_dhcp4.set_active(True) + else: + self.rb_manual4.set_active(True) + + def commit_pending_changes(self, widget): + self.hide_window() + GLib.idle_add(self.update_system) + + def update_system(self): + nic = self.currentSettings["Active Interface"] + inet = self.ipInputAddressEntry.get_text() + netmask = self.ipInputMaskEntry.get_text() + defaultrouter = self.ipInputGatewayEntry.get_text() + if self.method == 'Manual': + if 'wlan' in nic: + ifconfig_nic = f'ifconfig_{nic}="WPA inet {inet} netmask {netmask}"\n' + else: + ifconfig_nic = f'ifconfig_{nic}="inet {inet} netmask {netmask}"\n' + self.update_rc_conf(ifconfig_nic) + defaultrouter_line = f'defaultrouter="{defaultrouter}"\n' + self.update_rc_conf(defaultrouter_line) + start_static_network(nic, inet, netmask) + resolv_conf = open('/etc/resolv.conf', 'w') + resolv_conf.writelines('# Generated by NetworkMgr\n') + search = self.searchEntry.get_text() + if search: + search_line = f'search {search}\n' + resolv_conf.writelines(search_line) + dns1 = self.prymary_dnsEntry.get_text() + nameserver1_line = f'nameserver {dns1}\n' + resolv_conf.writelines(nameserver1_line) + dns2 = self.secondary_dnsEntry.get_text() + if dns2: + nameserver2_line = f'nameserver {dns2}\n' + resolv_conf.writelines(nameserver2_line) + resolv_conf.close() + else: + if 'wlan' in nic: + ifconfig_nic = f'ifconfig_{nic}="WPA DHCP"\n' + else: + ifconfig_nic = f'ifconfig_{nic}="DHCP"\n' + self.update_rc_conf(ifconfig_nic) + + rc_conf = open('/etc/rc.conf', 'r').read() + for nic_search in self.NICS: + if re.search(f'^ifconfig_{nic_search}=".*inet', rc_conf, re.MULTILINE): + break + else: + defaultrouter_line = f'defaultrouter="{defaultrouter}"\n' + self.remove_rc_conf_line(defaultrouter_line) + restart_card_network(nic) + wait_inet(nic) + restart_rounting_and_dhcp(nic) + + self.destroy() + + def hide_window(self): + self.hide() + return False + + def discard_pending_changes(self, widget): + self.destroy() + + def update_rc_conf(self, line): + run(f'sysrc {line}', shell=True) + + def remove_rc_conf_line(self, line): + with open('/etc/rc.conf', "r+") as rc_conf: + lines = rc_conf.readlines() + rc_conf.seek(0) + idx = lines.index(line) + lines.pop(idx) + rc_conf.truncate() + rc_conf.writelines(lines) + + +def network_card_configuration(default_int): + win = netCardConfigWindow(default_int) + win.connect("destroy", Gtk.main_quit) + win.show_all() + win.set_keep_above(True) + Gtk.main() + + +def network_card_configuration_window(): + win = netCardConfigWindow() + win.connect("destroy", Gtk.main_quit) + win.show_all() + win.set_keep_above(True) + Gtk.main() diff --git a/src/net_api.py b/NetworkMgr/net_api.py similarity index 69% rename from src/net_api.py rename to NetworkMgr/net_api.py index 563dc92..df107f1 100755 --- a/src/net_api.py +++ b/NetworkMgr/net_api.py @@ -1,52 +1,8 @@ -#!/usr/bin/env python3 -""" -Copyright (c) 2014-2019, GhostBSD. All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions -are met: - -1. Redistribution's of source code must retain the above copyright - notice, this list of conditions and the following disclaimer. - -2. Redistribution's in binary form must reproduce the above - copyright notice,this list of conditions and the following - disclaimer in the documentation and/or other materials provided - with the distribution. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS -FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE -COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, -INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES(INCLUDING, -BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER -CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT -LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN -ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE -POSSIBILITY OF SUCH DAMAGE. -""" - -from subprocess import Popen, PIPE, run -from sys import path -import os +#!/usr/bin/env python + +from subprocess import Popen, PIPE, run, check_output import re from time import sleep -path.append("/usr/local/share/networkmgr") - - -cmd = "kenv | grep rc_system" -rc_system = Popen(cmd, shell=True, stdout=PIPE, universal_newlines=True) - -if 'openrc' in rc_system.stdout.read(): - openrc = True - rc = 'rc-' - network = 'network' -else: - openrc = False - rc = '' - network = 'netif' def card_online(netcard): @@ -96,7 +52,7 @@ def nics_list(): notnics_regex = r"(enc|lo|fwe|fwip|tap|plip|pfsync|pflog|ipfw|tun|sl|" \ r"faith|ppp|bridge|wg)[0-9]+(\s*)|vm-[a-z]+(\s*)" nics = Popen( - 'ifconfig -l ether', + 'ifconfig -l', shell=True, stdout=PIPE, universal_newlines=True @@ -117,16 +73,7 @@ def barpercent(sn): def network_service_state(): - if openrc: - status = Popen( - f'{rc}service {network} status', - shell=True, - stdout=PIPE, - universal_newlines=True - ) - return 'status: started' in status.stdout.read() - else: - return False + return False def networkdictionary(): @@ -232,61 +179,67 @@ def switch_default(nic): ).stdout.read() if 'status: active' in nic_info or 'status: associated' in nic_info: if 'inet ' in nic_info or 'inet6' in nic_info: - if openrc: - os.system(f'service dhcpcd.{card} restart') - else: - os.system(f'service dhclient restart {card}') + run(f'service dhclient restart {card}', shell=True) break return def stopallnetwork(): - os.system(f'{rc}service {network} stop') + run('service netif stop', shell=True) def startallnetwork(): - os.system(f'{rc}service {network} start') + run('service netif start', shell=True) def stopnetworkcard(netcard): - if openrc: - os.system(f'ifconfig {netcard} down') - else: - os.system(f'service netif stop {netcard}') - switch_default(netcard) + run(f'service netif stop {netcard}', shell=True) + switch_default(netcard) + + +def restart_card_network(netcard): + run(f'service netif restart {netcard}', shell=True) + + +def restart_rounting_and_dhcp(netcard): + run('service routing restart', shell=True) + sleep(1) + run(f'service dhclient restart {netcard}', shell=True) + + +def start_static_network(netcard, inet, netmask): + run(f'ifconfig {netcard} inet {inet} netmask {netmask}', shell=True) + sleep(1) + run('service routing restart', shell=True) def startnetworkcard(netcard): - if openrc: - os.system(f'ifconfig {netcard} up') - os.system(f'{rc}service dhcpcd.{netcard} restart') - else: - os.system(f'service netif start {netcard}') - sleep(1) - os.system('service routing restart') - os.system(f'service dhclient start {netcard}') + run(f'service netif start {netcard}', shell=True) + sleep(1) + run('service routing restart', shell=True) + run(f'service dhclient start {netcard}', shell=True) def wifiDisconnection(wificard): - os.system(f'ifconfig {wificard} down') - os.system(f"ifconfig {wificard} ssid 'none'") - os.system(f'ifconfig {wificard} up') + run(f'ifconfig {wificard} down', shell=True) + run(f"ifconfig {wificard} ssid 'none'", shell=True) + run(f'ifconfig {wificard} up', shell=True) def disableWifi(wificard): - os.system(f'ifconfig {wificard} down') + run(f'ifconfig {wificard} down', shell=True) def enableWifi(wificard): - os.system(f'ifconfig {wificard} up') - os.system(f'ifconfig {wificard} up scan') + run(f'ifconfig {wificard} up', shell=True) + run(f'ifconfig {wificard} up scan', shell=True) def connectToSsid(name, wificard): - os.system('killall wpa_supplicant') + run('killall wpa_supplicant', shell=True) # service sleep(0.5) - os.system(f"ifconfig {wificard} ssid '{name}'") + run(f"ifconfig {wificard} ssid '{name}'", shell=True) sleep(0.5) wpa_supplicant = run( f'wpa_supplicant -B -i {wificard} -c /etc/wpa_supplicant.conf', @@ -320,7 +273,7 @@ def delete_ssid_wpa_supplicant_config(ssid): wpa_supplicant_conf.close() -def wlan_status(card): +def nic_status(card): out = Popen( f'ifconfig {card} | grep status:', shell=True, stdout=PIPE, @@ -330,8 +283,20 @@ def wlan_status(card): def start_dhcp(wificard): - if openrc: - os.system(f'dhcpcd -x {wificard}') - os.system(f'dhcpcd {wificard}') - else: - os.system(f'dhclient {wificard}') + run(f'dhclient {wificard}', shell=True) + + +def wait_inet(card): + IPREGEX = r'[0-9]+\.[0-9]+\.[0-9]+\.[0-9]+' + status = 'associated' if 'wlan' in card else 'active' + while nic_status(card) != status: + sleep(0.1) + print(nic_status(card)) + while True: + ifcmd = f"ifconfig -f inet:dotted {card}" + ifoutput = check_output(ifcmd.split(" "), universal_newlines=True) + print(ifoutput) + re_ip = re.search(fr'inet {IPREGEX}', ifoutput) + if re_ip and '0.0.0.0' not in re_ip.group(): + print(re_ip) + break diff --git a/NetworkMgr/query.py b/NetworkMgr/query.py new file mode 100644 index 0000000..07b9bc7 --- /dev/null +++ b/NetworkMgr/query.py @@ -0,0 +1,88 @@ +#!/usr/bin/env python + +from subprocess import check_output +import re +import os + + +def get_interface_settings(active_nic): + interface_settings = {} + rc_conf = open("/etc/rc.conf", "r").read() + DHCPSearch = re.findall(fr'^ifconfig_{active_nic}=".*DHCP', rc_conf, re.MULTILINE) + print(f"DHCPSearch is {DHCPSearch} and the length is {len(DHCPSearch)}") + if len(DHCPSearch) < 1: + DHCPStatusOutput = "Manual" + else: + DHCPStatusOutput = "DHCP" + + IPREGEX = r'[0-9]+\.[0-9]+\.[0-9]+\.[0-9]+' + + ifcmd = f"ifconfig -f inet:dotted {active_nic}" + ifoutput = check_output(ifcmd.split(" "), universal_newlines=True) + re_ip = re.search(fr'inet {IPREGEX}', ifoutput) + if re_ip: + if_ip = re_ip.group().replace("inet ", "").strip() + re_netmask = re.search(fr'netmask {IPREGEX}', ifoutput) + if_netmask = re_netmask.group().replace("netmask ", "").strip() + re_broadcast = re.search(fr'broadcast {IPREGEX}', ifoutput) + if_broadcast = re_broadcast.group().replace("broadcast ", "").strip() + else: + if_ip = "" + if_netmask = "" + if_broadcast = "" + if (DHCPStatusOutput == "DHCP"): + dhclient_leases = f"/var/db/dhclient.leases.{active_nic}" + + if os.path.exists(dhclient_leases) is False: + print("DHCP is enabled, but we're unable to read the lease " + f"file a /var/db/dhclient.leases.{active_nic}") + gateway = "" + else: + dh_lease = open(dhclient_leases, "r").read() + re_gateway = re.search(fr"option routers {IPREGEX}", dh_lease) + gateway = re_gateway.group().replace("option routers ", "") + else: + rc_conf = open('/etc/rc.conf', 'r').read() + re_gateway = re.search(fr'^defaultrouter="{IPREGEX}"', rc_conf, re.MULTILINE) + if re_gateway: + gateway = re_gateway.group().replace('"', "") + gateway = gateway.replace('defaultrouter=', "") + else: + gateway = "" + + if os.path.exists('/etc/resolv.conf'): + resolv_conf = open('/etc/resolv.conf').read() + nameservers = re.findall(fr'^nameserver {IPREGEX}', str(resolv_conf), re.MULTILINE) + print(nameservers) + + re_domain_search = re.findall('search [a-zA-Z.]*', str(resolv_conf)) + if len(re_domain_search) < 1: + re_domain_search = re.findall('domain (.*)', resolv_conf) + domain_search = str(re_domain_search).replace("domain ", "") + domain_search = domain_search.replace("'", "") + domain_search = domain_search.replace("[", "") + domain_search = domain_search.replace("]", "") + domain_search = domain_search.replace('search', '').strip() + else: + domain_search = '' + nameservers = [] + + interface_settings["Active Interface"] = active_nic + interface_settings["Assignment Method"] = DHCPStatusOutput + interface_settings["Interface IP"] = if_ip + interface_settings["Interface Subnet Mask"] = if_netmask + interface_settings["Broadcast Address"] = if_broadcast + interface_settings["Default Gateway"] = gateway + interface_settings["Search Domain"] = domain_search + + for num in range(len(nameservers)): + interface_settings[ + f"DNS Server {num + 1}" + ] = str(nameservers[(num)]).replace("nameserver", "").strip() + # if DNS Server 1 and 2 are missing create them with empty string + if "DNS Server 1" not in interface_settings: + interface_settings["DNS Server 1"] = "" + if "DNS Server 2" not in interface_settings: + interface_settings["DNS Server 2"] = "" + + return interface_settings diff --git a/src/trayicon.py b/NetworkMgr/trayicon.py similarity index 92% rename from src/trayicon.py rename to NetworkMgr/trayicon.py index 39b3781..9bb636a 100755 --- a/src/trayicon.py +++ b/NetworkMgr/trayicon.py @@ -1,21 +1,14 @@ -#!/usr/bin/env python3 +#!/usr/bin/env python import gi gi.require_version('Gtk', '3.0') -from gi.repository import Gtk, GObject, GLib import gettext -from time import sleep import threading import _thread -from sys import path import locale - -gettext.bindtextdomain('networkmgr', '/usr/local/share/locale') -gettext.textdomain('networkmgr') -_ = gettext.gettext - -path.append("/usr/local/share/networkmgr") -from net_api import ( +from time import sleep +from gi.repository import Gtk, GObject, GLib +from NetworkMgr.net_api import ( stopnetworkcard, startnetworkcard, wifiDisconnection, @@ -26,10 +19,15 @@ enableWifi, connectionStatus, networkdictionary, - openrc, delete_ssid_wpa_supplicant_config, - wlan_status + nic_status ) +from NetworkMgr.configuration import network_card_configuration + + +gettext.bindtextdomain('networkmgr', '/usr/local/share/locale') +gettext.textdomain('networkmgr') +_ = gettext.gettext encoding = locale.getpreferredencoding() threadBreak = False @@ -78,10 +76,13 @@ def nm_menu(self): wired_item = Gtk.MenuItem(_("Wired %s Connected") % cardnum) wired_item.set_sensitive(False) self.menu.append(wired_item) - disconnect_item = Gtk.ImageMenuItem(_("Disable")) + disconnect_item = Gtk.ImageMenuItem(_(f"Disable {netcard}")) disconnect_item.connect("activate", self.disconnectcard, netcard) self.menu.append(disconnect_item) + configure_item = Gtk.ImageMenuItem(f"Configure {netcard}") + configure_item.connect("activate", self.configuration_window_open, netcard) + self.menu.append(configure_item) elif connection_state == "Disconnected": notonline = Gtk.MenuItem(_("Wired %s Disconnected") % cardnum) notonline.set_sensitive(False) @@ -131,21 +132,21 @@ def nm_menu(self): diswifi = Gtk.MenuItem(_("Disable Wifi %s") % wifinum) diswifi.connect("activate", self.disable_Wifi, netcard) self.menu.append(diswifi) + configure_item = Gtk.ImageMenuItem(f"Configure {netcard}") + configure_item.connect("activate", self.configuration_window_open, netcard) + self.menu.append(configure_item) self.menu.append(Gtk.SeparatorMenuItem()) wifinum += 1 - - if openrc: - if not self.cardinfo['service']: - label = _("Enable Networking") - action = self.openNetwork - else: - label = _("Disable Networking") - action = self.closeNetwork - item = Gtk.MenuItem(label) - item.connect("activate", action) - self.menu.append(item) + if self.cardinfo['service'] is False: + open_item = Gtk.MenuItem(_("Enable Networking")) + open_item.connect("activate", self.openNetwork) + self.menu.append(open_item) else: - print('service netif status not supported') + close_item = Gtk.MenuItem(_("Disable Networking")) + close_item.connect("activate", self.closeNetwork) + self.menu.append(close_item) + # else: + # print('service netif status not supported') close_manager = Gtk.MenuItem(_("Close Network Manager")) close_manager.connect("activate", self.stop_manager) self.menu.append(close_manager) @@ -185,6 +186,9 @@ def wifiListMenu(self, wificard, cssid, passes, cards): wiconncmenu.append(menu_item) self.menu.append(avconnmenu) + def configuration_window_open(self, widget, interface): + network_card_configuration(interface) + def menu_click_open(self, widget, ssid, wificard): if f'"{ssid}"' in open("/etc/wpa_supplicant.conf").read(): connectToSsid(ssid, wificard) @@ -332,8 +336,8 @@ def try_to_connect_to_ssid(self, ssid, ssid_info, card): delete_ssid_wpa_supplicant_config(ssid) GLib.idle_add(self.restart_authentication, ssid_info, card) else: - for _ in range(60): - if wlan_status(card) == 'associated': + for _ in list(range(60)): + if nic_status(card) == 'associated': self.updateinfo() break sleep(1) diff --git a/networkmgr b/networkmgr index a5a95e9..b804412 100755 --- a/networkmgr +++ b/networkmgr @@ -1,13 +1,8 @@ -#!/usr/bin/env python3 +#!/usr/bin/env python -from os.path import dirname -from sys import path import signal -path.append("/usr/local/share/networkmgr") -path.append(dirname(__file__) + "/src") -from trayicon import trayIcon +from NetworkMgr.trayicon import trayIcon signal.signal(signal.SIGINT, signal.SIG_DFL) -i = trayIcon() -i.tray() +trayIcon().tray() diff --git a/networkmgr_configuration b/networkmgr_configuration new file mode 100755 index 0000000..9b57566 --- /dev/null +++ b/networkmgr_configuration @@ -0,0 +1,8 @@ +#!/usr/bin/env python + +import signal +from NetworkMgr import configuration + +signal.signal(signal.SIGINT, signal.SIG_DFL) + +configuration.network_card_configuration_window() diff --git a/setup.py b/setup.py index 59095d8..a362367 100755 --- a/setup.py +++ b/setup.py @@ -1,4 +1,4 @@ -#!/usr/bin/env python3 +#!/usr/bin/env python # -*- coding: utf-8 -*- import os @@ -7,7 +7,7 @@ from setuptools import setup from subprocess import run -__VERSION__ = '6.2' +__VERSION__ = '6.3' PROGRAM_VERSION = __VERSION__ prefix = '/usr/local' if system() == 'FreeBSD' else sys.prefix @@ -15,6 +15,7 @@ # compiling translations os.system("sh compile_translations.sh") + def datafilelist(installbase, sourcebase): datafileList = [] for root, subFolders, files in os.walk(sourcebase): @@ -25,16 +26,14 @@ def datafilelist(installbase, sourcebase): return datafileList -share_networkmgr = [ +networkmgr_share = [ 'src/auto-switch.py', - 'src/net_api.py', - 'src/setup-nic.py', - 'src/trayicon.py' + 'src/setup-nic.py' ] data_files = [ (f'{prefix}/etc/xdg/autostart', ['src/networkmgr.desktop']), - (f'{prefix}/share/networkmgr', share_networkmgr), + (f'{prefix}/share/networkmgr', networkmgr_share), (f'{prefix}/share/locale/zh_CN/LC_MESSAGES', ['src/locale/zh_CN/networkmgr.mo']), (f'{prefix}/share/locale/ru/LC_MESSAGES', ['src/locale/ru/networkmgr.mo']), (f'{prefix}/etc/sudoers.d', ['src/sudoers.d/networkmgr']) @@ -48,16 +47,17 @@ def datafilelist(installbase, sourcebase): data_files.extend(datafilelist(f'{prefix}/share/icons/hicolor', 'src/icons')) setup( - name="networkmgr", + name="NetworkMgr", version=PROGRAM_VERSION, - description="Networkmgr is a tool to manage FreeBSD/GHostBSD network", + description="NetworkMgr is a tool to manage FreeBSD/GhostBSD network", license='BSD', author='Eric Turgeon', url='https://github/GhostBSD/networkmgr/', package_dir={'': '.'}, data_files=data_files, install_requires=['setuptools'], - scripts=['networkmgr', 'src/netcardmgr'] + packages=['NetworkMgr'], + scripts=['networkmgr', 'networkmgr_configuration'] ) run('gtk-update-icon-cache -f /usr/local/share/icons/hicolor', shell=True) diff --git a/src/netcardmgr b/src/netcardmgr deleted file mode 100755 index 71cd7db..0000000 --- a/src/netcardmgr +++ /dev/null @@ -1,119 +0,0 @@ -#!/usr/bin/env python3 - -from subprocess import Popen, PIPE -import os -import re -from time import sleep - -ncard = 'ifconfig -l' -nics = Popen(ncard, shell=True, stdout=PIPE, close_fds=True, - universal_newlines=True) -netcard = nics.stdout.readlines()[0].rstrip() -wifis = 'sysctl -in net.wlan.devices' -wifinics = Popen(wifis, shell=True, stdout=PIPE, close_fds=True, - universal_newlines=True) -wifiscard = wifinics.stdout.readlines()[0].rstrip() -rcconf = open('/etc/rc.conf', 'r').read() -if os.path.exists('/etc/rc.conf.local'): - rcconflocal = open('/etc/rc.conf.local', 'r').read() -else: - rcconflocal = "None" - -notnics = [ - "enc", - "lo", - "fwe", - "fwip", - "tap", - "plip", - "pfsync", - "pflog", - "ipfw", - "tun", - "sl", - "faith", - "ppp", - "bridge", - "ixautomation", - "vm-ixautomation", - "wg" -] - -cmd = "kenv | grep rc_system" -rc_system = Popen(cmd, shell=True, stdout=PIPE, universal_newlines=True) -if 'openrc' in rc_system.stdout.read(): - openrc = True - rc = 'rc-' - network = 'network' -else: - openrc = False - rc = '' - network = 'netif' - -restart_network = f'{rc}service {network} restart' - - -class autoConfigure(): - - def __init__(self): - for line in netcard.split(): - card = line.rstrip() - # VLAN tags in ifconfig are delimited by period - # but in rc.conf delimiter is underscore - card = card.replace(".", "_") - nc = re.sub(r'\d+', '', line.rstrip()) - if nc not in notnics: - if f'ifconfig_{card}=' in (rcconf or rcconflocal): - print("Your wired network card is already configured.") - else: - rc = open('/etc/rc.conf', 'a') - rc.writelines(f'ifconfig_{card}="DHCP"\n') - rc.close() - sleep(1) - os.system(restart_network) - sleep(1) - if os.path.exists("/sbin/openrc") is True: - cmd = f"rc-service dhcpcd.{card} restart" - os.system(cmd) - print("Your wired network card is configured.") - - for card in wifiscard.split(): - for wlanNum in range(0, 9): - if f'wlan{wlanNum}' not in (rcconf + rcconflocal): - break - if f'wlans_{card}=' in (rcconf + rcconflocal): - print("Your wifi network card is already configured.") - if not os.path.exists('/etc/wpa_supplicant.conf'): - open('/etc/wpa_supplicant.conf', 'a').close() - os.system('chown root:wheel /etc/wpa_supplicant.conf') - os.system('chmod 765 /etc/wpa_supplicant.conf') - else: - os.system('chown root:wheel /etc/wpa_supplicant.conf') - os.system('chmod 765 /etc/wpa_supplicant.conf') - else: - rc = open('/etc/rc.conf', 'a') - rc.writelines(f'wlans_{card}="wlan{wlanNum}"\n') - rc.writelines(f'ifconfig_wlan{wlanNum}="WPA DHCP"\n') - rc.close() - if not os.path.exists('/etc/wpa_supplicant.conf'): - open('/etc/wpa_supplicant.conf', 'a').close() - os.system('chown root:wheel /etc/wpa_supplicant.conf') - os.system('chmod 765 /etc/wpa_supplicant.conf') - sleep(1) - os.system(restart_network) - sleep(1) - nicslist = 'ifconfig -l' - ifconfig = Popen(nicslist, shell=True, stdout=PIPE, - close_fds=True, universal_newlines=True) - cardlist = ifconfig.stdout.read() - if f'wlan{wlanNum}' not in cardlist: - sleep(1) - os.system(restart_network) - sleep(1) - os.system(f'ifconfig wlan{wlanNum} up scan') - os.system(f'ifconfig wlan{wlanNum} up scan') - sleep(1) - wlanNum += 1 - - -autoConfigure()