diff --git a/.gitignore b/.gitignore index 6fa524e..6622899 100644 --- a/.gitignore +++ b/.gitignore @@ -1,2 +1,25 @@ -**/*.pyc +# cached dev files +**/__pycache__/ +.mypy_cache/ +.ruff_cache/ **/*.swp + +# python build assets +.pybuild/ +build/ +*.egg-info/ + +# deb package build assests +debian/confconsole/ + +debian/.debhelper/ +debian/debhelper-build-stamp +debian/*.debhelper.log +debian/*.debhelper +debian/*.substvars +debian/files + +# other files/dirs +tmp +tags +*.tar.bz2 diff --git a/confconsole.py b/confconsole.py index a6353b2..02034d4 100755 --- a/confconsole.py +++ b/confconsole.py @@ -77,8 +77,8 @@ class Console: def __init__( self, title: str | None = None, - width: int = 60, - height: int = 20, + width: int = 65, + height: int = 25, ) -> None: self.width = width self.height = height @@ -275,8 +275,8 @@ def __init__( advanced_enabled: bool = True, ) -> None: title = "TurnKey GNU/Linux Configuration Console" - self.width = 60 - self.height = 20 + self.width = 65 + self.height = 25 self.console = Console(title, self.width, self.height) @@ -331,6 +331,9 @@ def _validip(ifname: str) -> bool: ip = ifutil.get_ipconf(ifname)[0] if ip and not ip.startswith("169"): return True + ip6 = ifutil.get_ipv6conf(ifname)[0] + if ip6: + return True return False defifname = conf.Conf().default_nic @@ -437,7 +440,11 @@ def _get_ifconftext(self, ifname: str) -> str: text = f"IP Address: {addr}\n" text += f"Netmask: {netmask}\n" text += f"Default Gateway: {gateway}\n" - text += f"Name Server(s): {' '.join(nameservers)}\n\n" + text += f"Name Server(s): {' '.join(nameservers)}\n" + ipv6_addr, ipv6_prefix = ifutil.get_ipv6conf(ifname) + if ipv6_addr: + text += f"IPv6 Address: {ipv6_addr}/{ipv6_prefix}\n" + text += "\n" ifmethod = ifutil.get_ifmethod(ifname) if ifmethod: @@ -500,21 +507,31 @@ def usage(self) -> str: ip_addr = self._get_public_ipaddr() if not ip_addr: ip_addr = ifutil.get_ipconf(ifname)[0] - + ipv6_addr, ipv6_prefix = ifutil.get_ipv6conf(ifname) hostname = netinfo.get_hostname().upper() try: with open(conf.path("services.txt")) as fob: t = fob.read().rstrip() - text = Template(t).substitute(appname=self.appname, - hostname=hostname, - ipaddr=ip_addr) + text = Template(t).safe_substitute( + appname=self.appname, + hostname=hostname, + ipaddr=ip_addr, + ) except conf.ConfconsoleConfError: t = "" - text = Template(t).substitute(ipaddr=ip_addr) + text = Template(t).safe_substitute(ipaddr=ip_addr) + + if ipv6_addr: + text += "\n" + text += f"\nIPv6 Web: https://[{ipv6_addr}]" + text += f"\nIPv6 SSH: root@{ipv6_addr}" + + gap = self.height - len(text.splitlines()) - 11 + gap = gap if gap >= 1 else 1 - text += f"\n\n{tklbam_status}\n\n" - text += "\n" * (self.height - len(text.splitlines()) - 7) + text += f"\n\n{tklbam_status}" + text += "\n" * gap text += " TurnKey Backups and Cloud Deployment\n" text += " https://hub.turnkeylinux.org" diff --git a/ifutil.py b/ifutil.py index 62356ae..9537897 100644 --- a/ifutil.py +++ b/ifutil.py @@ -413,8 +413,11 @@ def set_dhcp(ifname: str) -> str | None: raise e finally: output = ifup(ifname, True) - - net = InterfaceInfo(ifname) + for _retry in range(10): + net = InterfaceInfo(ifname) + if net.address: + break + sleep(1) if not net.address: raise IfError(f"Error obtaining IP address\n\n{output}") return None @@ -437,6 +440,25 @@ def get_ipconf( return (None, None, net.get_gateway(error), get_nameservers(ifname)) + +def get_ipv6conf(ifname: str) -> tuple[str | None, str | None]: + """Get IPv6 global address and prefix for an interface.""" + try: + out = subprocess.check_output( + ["ip", "-6", "addr", "show", ifname, "scope", "global"], + text=True, stderr=subprocess.DEVNULL + ) + for line in out.splitlines(): + line = line.strip() + if line.startswith("inet6"): + parts = line.split() + addr_prefix = parts[1] + addr, prefix = addr_prefix.split("/") + return (addr, prefix) + except Exception: + pass + return (None, None) + def get_ifmethod(ifname: str) -> str | None: interfaces = NetworkInterfaces() interfaces.read()