From fb00a11bef28e4dc19f12653a431d545f1113533 Mon Sep 17 00:00:00 2001 From: Pascal Bouquet Date: Sat, 19 Apr 2025 16:39:54 +0200 Subject: [PATCH] Add --me flag to display local and public IPs with CGNAT detection This commit introduces the --me flag, which allows users to quickly display their current local IPv4 and public IPv4/IPv6 addresses. The public IPs are retrieved using ifconfig.me via curl, ensuring accurate detection even in CGNAT or split-DNS scenarios. Local IPv4 is determined via the system's active route through the configured resolver. The output also includes a CGNAT detection based on private IP ranges and the reserved 100.64.0.0/10 block, providing a helpful warning if detected. IPv6 privacy extensions are common, so local IPv6 detection has been removed to avoid redundant or unstable information. --- chkip.py | 59 ++++++++++++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 57 insertions(+), 2 deletions(-) diff --git a/chkip.py b/chkip.py index 4bcad8c..b0eb3b0 100644 --- a/chkip.py +++ b/chkip.py @@ -5,6 +5,7 @@ chkip.py – DNS- und Mailserver-Check-Tool Erstellt von Pascal Bouquet am 17.04.2025 +Aktualisiert am 19.04.2025 Dieses Programm ist freie Software: Sie können es unter den Bedingungen der GNU General Public License, wie von der Free Software Foundation veröffentlicht, @@ -20,6 +21,7 @@ Sie sollten eine Kopie der GNU General Public License zusammen mit diesem Programm erhalten haben. Falls nicht, siehe . """ + import sys import re import ipaddress @@ -28,6 +30,8 @@ import dns.reversename import requests import argparse import json +import socket +import subprocess # Resolver festlegen resolver = dns.resolver.Resolver() @@ -122,6 +126,43 @@ def resolve_tlsa(domain, mx_host): except: return "No TLSA record found" +def get_local_ipv4(): + try: + ip = next((ip for ip in resolver.nameservers if '.' in ip), '1.1.1.1') + s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) + s.connect((ip, 80)) + local_ip = s.getsockname()[0] + s.close() + return local_ip + except: + return "unavailable" + +def get_my_ip(): + def run_curl(protocol_flag): + try: + result = subprocess.run( + ["curl", "-s", protocol_flag, "ifconfig.me/ip"], + stdout=subprocess.PIPE, + stderr=subprocess.DEVNULL, + timeout=2, + text=True + ) + return result.stdout.strip() + except: + return "unavailable" + + local_v4 = get_local_ipv4() + public_v4 = run_curl("-4") + public_v6 = run_curl("-6") + return local_v4, public_v4, public_v6 + +def is_cgnat(ip): + try: + ip_obj = ipaddress.ip_address(ip) + return ip_obj.is_private or ip_obj in ipaddress.ip_network("100.64.0.0/10") + except: + return False + def print_json(output): print(json.dumps(output, indent=2)) @@ -165,15 +206,29 @@ def print_text(output, is_ip_mode=False): def main(): parser = argparse.ArgumentParser(description="chkip.py – DNS- und Mailserver-Check-Tool") - parser.add_argument("domain", help="Domain oder IP-Adresse") + parser.add_argument("domain", nargs="?", help="Domain oder IP-Adresse") parser.add_argument("-sS", "--spf", action="store_true", help="Prüft den SPF-Eintrag") parser.add_argument("-sD", "--dmarc", action="store_true", help="Prüft den DMARC-Eintrag") parser.add_argument("-sM", "--mta_sts", action="store_true", help="Prüft den MTA-STS-Eintrag") parser.add_argument("-sT", "--tlsa", action="store_true", help="Prüft den TLSA-Eintrag") parser.add_argument("-sDK", "--dkim", type=str, help="Prüft den DKIM-Eintrag für den angegebenen Selector") parser.add_argument("--json", action="store_true", help="Ausgabe als JSON") + parser.add_argument("--me", action="store_true", help="Zeigt lokale & öffentliche IPs und prüft auf CGNAT") args = parser.parse_args() + if args.me: + local_v4, public_v4, public_v6 = get_my_ip() + print(f"Your local IPv4: {local_v4}") + print(f"Your public IPv4: {public_v4}") + print(f"Your public IPv6: {public_v6}") + if is_cgnat(public_v4): + print("⚠️ Hinweis: Du befindest dich möglicherweise hinter CGNAT (Carrier-Grade NAT)") + return + + if not args.domain: + parser.print_help() + return + domain = args.domain is_ip = is_ip_address(domain) output = {} @@ -192,7 +247,7 @@ def main(): print_json(output) else: print_text(output, is_ip_mode=True) - return # ✅ wichtig! + return # Domain-Zweig output["A"] = resolve_a(domain) or "No A record"