diff --git a/daemon/core/gui/appconfig.py b/daemon/core/gui/appconfig.py index 36a5d1b7..c19fb029 100644 --- a/daemon/core/gui/appconfig.py +++ b/daemon/core/gui/appconfig.py @@ -41,6 +41,7 @@ DEFAULT_IP4S = ["10.0.0.0", "192.168.0.0", "172.16.0.0"] DEFAULT_IP4 = DEFAULT_IP4S[0] DEFAULT_IP6S = ["2001::", "2002::", "a::"] DEFAULT_IP6 = DEFAULT_IP6S[0] +DEFAULT_MAC = "00:00:00:aa:00:00" class IndentDumper(yaml.Dumper): @@ -113,6 +114,7 @@ def check_directory(): "ip4s": DEFAULT_IP4S, "ip6s": DEFAULT_IP6S, }, + "mac": DEFAULT_MAC, } save(config) diff --git a/daemon/core/gui/coreclient.py b/daemon/core/gui/coreclient.py index 5cc822de..d93cdf51 100644 --- a/daemon/core/gui/coreclient.py +++ b/daemon/core/gui/coreclient.py @@ -483,7 +483,17 @@ class CoreClient: self.app.after(0, show_grpc_error, e, self.app, self.app) def start_session(self) -> core_pb2.StartSessionResponse: + self.interfaces_manager.reset_mac() nodes = [x.core_node for x in self.canvas_nodes.values()] + links = [] + for edge in self.links.values(): + link = edge.link + logging.info("link: %s", link) + if link.HasField("interface_one") and not link.interface_one.mac: + link.interface_one.mac = self.interfaces_manager.next_mac() + if link.HasField("interface_two") and not link.interface_two.mac: + link.interface_two.mac = self.interfaces_manager.next_mac() + links.append(link) links = [x.link for x in self.links.values()] wlan_configs = self.get_wlan_configs_proto() mobility_configs = self.get_mobility_configs_proto() @@ -849,7 +859,6 @@ class CoreClient: ip6=ip6, ip6mask=ip6_mask, ) - canvas_node.interfaces.append(interface) logging.debug( "create node(%s) interface(%s) IPv4(%s) IPv6(%s)", node.name, @@ -875,13 +884,11 @@ class CoreClient: src_interface = None if NodeUtils.is_container_node(src_node.type): src_interface = self.create_interface(canvas_src_node) - edge.src_interface = src_interface self.interface_to_edge[(src_node.id, src_interface.id)] = edge.token dst_interface = None if NodeUtils.is_container_node(dst_node.type): dst_interface = self.create_interface(canvas_dst_node) - edge.dst_interface = dst_interface self.interface_to_edge[(dst_node.id, dst_interface.id)] = edge.token link = core_pb2.Link( @@ -891,6 +898,12 @@ class CoreClient: interface_one=src_interface, interface_two=dst_interface, ) + if src_interface: + edge.src_interface = link.interface_one + canvas_src_node.interfaces.append(link.interface_one) + if dst_interface: + edge.dst_interface = link.interface_two + canvas_dst_node.interfaces.append(link.interface_two) edge.set_link(link) self.links[edge.token] = edge logging.info("Add link between %s and %s", src_node.name, dst_node.name) diff --git a/daemon/core/gui/dialogs/macdialog.py b/daemon/core/gui/dialogs/macdialog.py index a880e204..6b6faf95 100644 --- a/daemon/core/gui/dialogs/macdialog.py +++ b/daemon/core/gui/dialogs/macdialog.py @@ -1,6 +1,10 @@ -from tkinter import ttk +import tkinter as tk +from tkinter import messagebox, ttk from typing import TYPE_CHECKING +import netaddr + +from core.gui import appconfig from core.gui.dialogs.dialog import Dialog from core.gui.themes import PADX, PADY @@ -11,6 +15,8 @@ if TYPE_CHECKING: class MacConfigDialog(Dialog): def __init__(self, master: "Application", app: "Application") -> None: super().__init__(master, app, "MAC Configuration", modal=True) + mac = self.app.guiconfig.get("mac", appconfig.DEFAULT_MAC) + self.mac_var = tk.StringVar(value=mac) self.draw() def draw(self) -> None: @@ -32,7 +38,7 @@ class MacConfigDialog(Dialog): frame.grid(stick="ew", pady=PADY) label = ttk.Label(frame, text="Starting MAC") label.grid(row=0, column=0, sticky="ew", padx=PADX) - entry = ttk.Entry(frame) + entry = ttk.Entry(frame, textvariable=self.mac_var) entry.grid(row=0, column=1, sticky="ew") # draw buttons @@ -46,4 +52,10 @@ class MacConfigDialog(Dialog): button.grid(row=0, column=1, sticky="ew") def click_save(self) -> None: - pass + mac = self.mac_var.get() + if not netaddr.valid_mac(mac): + messagebox.showerror("MAC Error", f"{mac} is an invalid mac") + else: + self.app.core.interfaces_manager.mac = netaddr.EUI(mac) + self.app.guiconfig["mac"] = mac + self.app.save_config() diff --git a/daemon/core/gui/dialogs/nodeconfig.py b/daemon/core/gui/dialogs/nodeconfig.py index ce8ea802..9d10a083 100644 --- a/daemon/core/gui/dialogs/nodeconfig.py +++ b/daemon/core/gui/dialogs/nodeconfig.py @@ -70,16 +70,12 @@ def check_ip4(parent, name: str, value: str) -> bool: return True -def mac_auto(is_auto: tk.BooleanVar, entry: ttk.Entry): - logging.info("mac auto clicked") +def mac_auto(is_auto: tk.BooleanVar, entry: ttk.Entry, mac: tk.StringVar) -> None: if is_auto.get(): - logging.info("disabling mac") - entry.delete(0, tk.END) - entry.insert(tk.END, "") + mac.set("") entry.config(state=tk.DISABLED) else: - entry.delete(0, tk.END) - entry.insert(tk.END, "00:00:00:00:00:00") + mac.set("00:00:00:00:00:00") entry.config(state=tk.NORMAL) @@ -252,7 +248,7 @@ class NodeConfigDialog(Dialog): mac = tk.StringVar(value=interface.mac) entry = ttk.Entry(tab, textvariable=mac, state=state) entry.grid(row=row, column=2, sticky="ew") - func = partial(mac_auto, is_auto, entry) + func = partial(mac_auto, is_auto, entry, mac) checkbutton.config(command=func) row += 1 @@ -283,7 +279,7 @@ class NodeConfigDialog(Dialog): frame.columnconfigure(0, weight=1) frame.columnconfigure(1, weight=1) - button = ttk.Button(frame, text="Apply", command=self.config_apply) + button = ttk.Button(frame, text="Apply", command=self.click_apply) button.grid(row=0, column=0, padx=PADX, sticky="ew") button = ttk.Button(frame, text="Cancel", command=self.destroy) @@ -302,7 +298,7 @@ class NodeConfigDialog(Dialog): self.image_button.config(image=self.image) self.image_file = file_path - def config_apply(self): + def click_apply(self): error = False # update core node @@ -328,7 +324,6 @@ class NodeConfigDialog(Dialog): ip4_net = data.ip4.get() if not check_ip4(self, interface.name, ip4_net): error = True - data.ip4.set(f"{interface.ip4}/{interface.ip4mask}") break if ip4_net: ip4, ip4mask = ip4_net.split("/") @@ -342,7 +337,6 @@ class NodeConfigDialog(Dialog): ip6_net = data.ip6.get() if not check_ip6(self, interface.name, ip6_net): error = True - data.ip6.set(f"{interface.ip6}/{interface.ip6mask}") break if ip6_net: ip6, ip6mask = ip6_net.split("/") @@ -353,13 +347,13 @@ class NodeConfigDialog(Dialog): interface.ip6mask = ip6mask mac = data.mac.get() - if mac and not netaddr.valid_mac(mac): + auto_mac = data.is_auto.get() + if not auto_mac and not netaddr.valid_mac(mac): title = f"MAC Error for {interface.name}" messagebox.showerror(title, "Invalid MAC Address") error = True - data.mac.set(interface.mac) break - else: + elif not auto_mac: mac = netaddr.EUI(mac) mac.dialect = netaddr.mac_unix_expanded interface.mac = str(mac) diff --git a/daemon/core/gui/interface.py b/daemon/core/gui/interface.py index b5c24fc4..359dba8e 100644 --- a/daemon/core/gui/interface.py +++ b/daemon/core/gui/interface.py @@ -2,8 +2,10 @@ import logging import random from typing import TYPE_CHECKING, Set, Union -from netaddr import IPNetwork +import netaddr +from netaddr import EUI, IPNetwork +from core.gui import appconfig from core.gui.nodeutils import NodeUtils if TYPE_CHECKING: @@ -35,12 +37,15 @@ class InterfaceManager: def __init__(self, app: "Application") -> None: self.app = app ip_config = self.app.guiconfig.get("ips", {}) - ip4 = ip_config.get("ip4", "10.0.0.0") - ip6 = ip_config.get("ip6", "2001::") + ip4 = ip_config.get("ip4", appconfig.DEFAULT_IP4) + ip6 = ip_config.get("ip6", appconfig.DEFAULT_IP6) self.ip4_mask = 24 self.ip6_mask = 64 self.ip4_subnets = IPNetwork(f"{ip4}/{self.ip4_mask}") self.ip6_subnets = IPNetwork(f"{ip6}/{self.ip6_mask}") + mac = self.app.guiconfig.get("mac", appconfig.DEFAULT_MAC) + self.mac = EUI(mac) + self.current_mac = None self.current_subnets = None def update_ips(self, ip4: str, ip6: str) -> None: @@ -48,6 +53,17 @@ class InterfaceManager: self.ip4_subnets = IPNetwork(f"{ip4}/{self.ip4_mask}") self.ip6_subnets = IPNetwork(f"{ip6}/{self.ip6_mask}") + def reset_mac(self) -> None: + self.current_mac = self.mac + self.current_mac.dialect = netaddr.mac_unix_expanded + + def next_mac(self) -> str: + mac = str(self.current_mac) + value = self.current_mac.value + 1 + self.current_mac = EUI(value) + self.current_mac.dialect = netaddr.mac_unix_expanded + return mac + def next_subnets(self) -> Subnets: # define currently used subnets used_subnets = set()