Primera Version
This commit is contained in:
commit
4ee8015953
|
@ -0,0 +1,174 @@
|
||||||
|
# Byte-compiled / optimized / DLL files
|
||||||
|
__pycache__/
|
||||||
|
*.py[cod]
|
||||||
|
*$py.class
|
||||||
|
|
||||||
|
# C extensions
|
||||||
|
*.so
|
||||||
|
|
||||||
|
# Distribution / packaging
|
||||||
|
.Python
|
||||||
|
build/
|
||||||
|
develop-eggs/
|
||||||
|
dist/
|
||||||
|
downloads/
|
||||||
|
eggs/
|
||||||
|
.eggs/
|
||||||
|
lib/
|
||||||
|
lib64/
|
||||||
|
parts/
|
||||||
|
sdist/
|
||||||
|
var/
|
||||||
|
wheels/
|
||||||
|
share/python-wheels/
|
||||||
|
*.egg-info/
|
||||||
|
.installed.cfg
|
||||||
|
*.egg
|
||||||
|
MANIFEST
|
||||||
|
|
||||||
|
# PyInstaller
|
||||||
|
# Usually these files are written by a python script from a template
|
||||||
|
# before PyInstaller builds the exe, so as to inject date/other infos into it.
|
||||||
|
*.manifest
|
||||||
|
*.spec
|
||||||
|
|
||||||
|
# Installer logs
|
||||||
|
pip-log.txt
|
||||||
|
pip-delete-this-directory.txt
|
||||||
|
|
||||||
|
# Unit test / coverage reports
|
||||||
|
htmlcov/
|
||||||
|
.tox/
|
||||||
|
.nox/
|
||||||
|
.coverage
|
||||||
|
.coverage.*
|
||||||
|
.cache
|
||||||
|
nosetests.xml
|
||||||
|
coverage.xml
|
||||||
|
*.cover
|
||||||
|
*.py,cover
|
||||||
|
.hypothesis/
|
||||||
|
.pytest_cache/
|
||||||
|
cover/
|
||||||
|
|
||||||
|
# Translations
|
||||||
|
*.mo
|
||||||
|
*.pot
|
||||||
|
|
||||||
|
# Django stuff:
|
||||||
|
*.log
|
||||||
|
local_settings.py
|
||||||
|
db.sqlite3
|
||||||
|
db.sqlite3-journal
|
||||||
|
|
||||||
|
# Flask stuff:
|
||||||
|
instance/
|
||||||
|
.webassets-cache
|
||||||
|
|
||||||
|
# Scrapy stuff:
|
||||||
|
.scrapy
|
||||||
|
|
||||||
|
# Sphinx documentation
|
||||||
|
docs/_build/
|
||||||
|
|
||||||
|
# PyBuilder
|
||||||
|
.pybuilder/
|
||||||
|
target/
|
||||||
|
|
||||||
|
# Jupyter Notebook
|
||||||
|
.ipynb_checkpoints
|
||||||
|
|
||||||
|
# IPython
|
||||||
|
profile_default/
|
||||||
|
ipython_config.py
|
||||||
|
|
||||||
|
# pyenv
|
||||||
|
# For a library or package, you might want to ignore these files since the code is
|
||||||
|
# intended to run in multiple environments; otherwise, check them in:
|
||||||
|
# .python-version
|
||||||
|
|
||||||
|
# pipenv
|
||||||
|
# According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control.
|
||||||
|
# However, in case of collaboration, if having platform-specific dependencies or dependencies
|
||||||
|
# having no cross-platform support, pipenv may install dependencies that don't work, or not
|
||||||
|
# install all needed dependencies.
|
||||||
|
#Pipfile.lock
|
||||||
|
|
||||||
|
# UV
|
||||||
|
# Similar to Pipfile.lock, it is generally recommended to include uv.lock in version control.
|
||||||
|
# This is especially recommended for binary packages to ensure reproducibility, and is more
|
||||||
|
# commonly ignored for libraries.
|
||||||
|
#uv.lock
|
||||||
|
|
||||||
|
# poetry
|
||||||
|
# Similar to Pipfile.lock, it is generally recommended to include poetry.lock in version control.
|
||||||
|
# This is especially recommended for binary packages to ensure reproducibility, and is more
|
||||||
|
# commonly ignored for libraries.
|
||||||
|
# https://python-poetry.org/docs/basic-usage/#commit-your-poetrylock-file-to-version-control
|
||||||
|
#poetry.lock
|
||||||
|
|
||||||
|
# pdm
|
||||||
|
# Similar to Pipfile.lock, it is generally recommended to include pdm.lock in version control.
|
||||||
|
#pdm.lock
|
||||||
|
# pdm stores project-wide configurations in .pdm.toml, but it is recommended to not include it
|
||||||
|
# in version control.
|
||||||
|
# https://pdm.fming.dev/latest/usage/project/#working-with-version-control
|
||||||
|
.pdm.toml
|
||||||
|
.pdm-python
|
||||||
|
.pdm-build/
|
||||||
|
|
||||||
|
# PEP 582; used by e.g. github.com/David-OConnor/pyflow and github.com/pdm-project/pdm
|
||||||
|
__pypackages__/
|
||||||
|
|
||||||
|
# Celery stuff
|
||||||
|
celerybeat-schedule
|
||||||
|
celerybeat.pid
|
||||||
|
|
||||||
|
# SageMath parsed files
|
||||||
|
*.sage.py
|
||||||
|
|
||||||
|
# Environments
|
||||||
|
.env
|
||||||
|
.venv
|
||||||
|
env/
|
||||||
|
venv/
|
||||||
|
ENV/
|
||||||
|
env.bak/
|
||||||
|
venv.bak/
|
||||||
|
|
||||||
|
# Spyder project settings
|
||||||
|
.spyderproject
|
||||||
|
.spyproject
|
||||||
|
|
||||||
|
# Rope project settings
|
||||||
|
.ropeproject
|
||||||
|
|
||||||
|
# mkdocs documentation
|
||||||
|
/site
|
||||||
|
|
||||||
|
# mypy
|
||||||
|
.mypy_cache/
|
||||||
|
.dmypy.json
|
||||||
|
dmypy.json
|
||||||
|
|
||||||
|
# Pyre type checker
|
||||||
|
.pyre/
|
||||||
|
|
||||||
|
# pytype static type analyzer
|
||||||
|
.pytype/
|
||||||
|
|
||||||
|
# Cython debug symbols
|
||||||
|
cython_debug/
|
||||||
|
|
||||||
|
# PyCharm
|
||||||
|
# JetBrains specific template is maintained in a separate JetBrains.gitignore that can
|
||||||
|
# be found at https://github.com/github/gitignore/blob/main/Global/JetBrains.gitignore
|
||||||
|
# and can be added to the global gitignore or merged into this file. For a more nuclear
|
||||||
|
# option (not recommended) you can uncomment the following to ignore the entire idea folder.
|
||||||
|
#.idea/
|
||||||
|
|
||||||
|
# Ruff stuff:
|
||||||
|
.ruff_cache/
|
||||||
|
|
||||||
|
# PyPI configuration file
|
||||||
|
.pypirc
|
|
@ -0,0 +1,22 @@
|
||||||
|
import json
|
||||||
|
|
||||||
|
IP_HISTORY_FILE = "tu_ruta_a_ip_history.json" # Asegúrate de definir la ruta correcta
|
||||||
|
|
||||||
|
def remove_duplicates_preserve_order(history):
|
||||||
|
"""Elimina duplicados de la lista manteniendo el orden."""
|
||||||
|
seen = set()
|
||||||
|
new_history = []
|
||||||
|
for item in history:
|
||||||
|
if item not in seen:
|
||||||
|
seen.add(item)
|
||||||
|
new_history.append(item)
|
||||||
|
return new_history
|
||||||
|
|
||||||
|
if os.path.exists(IP_HISTORY_FILE):
|
||||||
|
with open(IP_HISTORY_FILE, "r") as file:
|
||||||
|
ip_history = json.load(file)
|
||||||
|
ip_history = remove_duplicates_preserve_order(ip_history)
|
||||||
|
|
||||||
|
# Guardar la lista actualizada en el archivo JSON
|
||||||
|
with open(IP_HISTORY_FILE, "w") as file:
|
||||||
|
json.dump(ip_history, file)
|
|
@ -0,0 +1,106 @@
|
||||||
|
import sys
|
||||||
|
import subprocess
|
||||||
|
import ctypes
|
||||||
|
import time
|
||||||
|
import logging
|
||||||
|
import os
|
||||||
|
from datetime import datetime
|
||||||
|
|
||||||
|
def setup_logging():
|
||||||
|
"""Configura el logging para el script"""
|
||||||
|
log_dir = os.path.join(os.path.dirname(__file__), 'logs')
|
||||||
|
if not os.path.exists(log_dir):
|
||||||
|
os.makedirs(log_dir)
|
||||||
|
|
||||||
|
log_file = os.path.join(log_dir, 'ip_changer_admin.log')
|
||||||
|
|
||||||
|
logging.basicConfig(
|
||||||
|
level=logging.DEBUG,
|
||||||
|
format='%(asctime)s - %(levelname)s - %(message)s',
|
||||||
|
handlers=[
|
||||||
|
logging.FileHandler(log_file),
|
||||||
|
logging.StreamHandler(sys.stdout)
|
||||||
|
]
|
||||||
|
)
|
||||||
|
return logging.getLogger(__name__)
|
||||||
|
|
||||||
|
def is_admin():
|
||||||
|
"""Verifica si el script se está ejecutando con privilegios de administrador"""
|
||||||
|
try:
|
||||||
|
return ctypes.windll.shell32.IsUserAnAdmin()
|
||||||
|
except:
|
||||||
|
return False
|
||||||
|
|
||||||
|
def run_command(logger, cmd: str) -> bool:
|
||||||
|
"""Ejecuta un comando y retorna True si fue exitoso"""
|
||||||
|
logger.info(f"Executing command: {cmd}")
|
||||||
|
try:
|
||||||
|
result = subprocess.run(
|
||||||
|
cmd,
|
||||||
|
shell=True,
|
||||||
|
capture_output=True,
|
||||||
|
text=True
|
||||||
|
)
|
||||||
|
|
||||||
|
if result.stdout:
|
||||||
|
logger.info(f"Command output: {result.stdout}")
|
||||||
|
if result.stderr:
|
||||||
|
logger.error(f"Command error: {result.stderr}")
|
||||||
|
|
||||||
|
return result.returncode == 0
|
||||||
|
|
||||||
|
except Exception as e:
|
||||||
|
logger.error(f"Error executing command: {str(e)}")
|
||||||
|
return False
|
||||||
|
|
||||||
|
def main():
|
||||||
|
logger = setup_logging()
|
||||||
|
|
||||||
|
# Log startup information
|
||||||
|
logger.info("=" * 50)
|
||||||
|
logger.info(f"Script started at {datetime.now()}")
|
||||||
|
logger.info(f"Arguments received: {sys.argv}")
|
||||||
|
logger.info(f"Running with admin privileges: {is_admin()}")
|
||||||
|
|
||||||
|
if not is_admin():
|
||||||
|
logger.error("This script requires administrator privileges")
|
||||||
|
return 1
|
||||||
|
|
||||||
|
if len(sys.argv) < 3:
|
||||||
|
logger.error("Insufficient arguments")
|
||||||
|
logger.info("Usage: ip_changer_admin.py <interface> <ip|dhcp>")
|
||||||
|
logger.info("Example for static IP: ip_changer_admin.py Ethernet 192.168.1.100")
|
||||||
|
logger.info("Example for DHCP: ip_changer_admin.py Ethernet dhcp")
|
||||||
|
return 1
|
||||||
|
|
||||||
|
interface = sys.argv[1]
|
||||||
|
ip_mode = sys.argv[2]
|
||||||
|
|
||||||
|
logger.info(f"Processing request for interface: {interface}")
|
||||||
|
logger.info(f"IP mode: {ip_mode}")
|
||||||
|
|
||||||
|
if ip_mode.lower() == "dhcp":
|
||||||
|
cmd = f'netsh interface ip set address "{interface}" dhcp'
|
||||||
|
else:
|
||||||
|
# Asumimos que es una IP estática
|
||||||
|
ip = ip_mode
|
||||||
|
gateway = '.'.join(ip.split('.')[:3] + ['1'])
|
||||||
|
cmd = f'netsh interface ip set address "{interface}" static {ip} 255.255.255.0 {gateway}'
|
||||||
|
|
||||||
|
success = run_command(logger, cmd)
|
||||||
|
|
||||||
|
if success:
|
||||||
|
logger.info("Command executed successfully")
|
||||||
|
return 0
|
||||||
|
else:
|
||||||
|
logger.error("Command failed")
|
||||||
|
return 1
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
try:
|
||||||
|
exit_code = main()
|
||||||
|
sys.exit(exit_code)
|
||||||
|
except Exception as e:
|
||||||
|
logger = setup_logging()
|
||||||
|
logger.exception("Unhandled exception occurred")
|
||||||
|
sys.exit(1)
|
|
@ -0,0 +1 @@
|
||||||
|
{"last_interface": "Ethernet", "last_ip_prefix": "10.1.33"}
|
|
@ -0,0 +1 @@
|
||||||
|
["10.1.22", "169.254.38", "10.1.20", "10.146.76", "192.168.0", "10.101.8", "10.1.33", "10.1.92", "192.168.121", "192.168.1", "169.254.3", "10.202.4", "192.168.2", "10.1.30", "192.168.88"]
|
|
@ -0,0 +1,192 @@
|
||||||
|
import ctypes
|
||||||
|
import subprocess
|
||||||
|
import sys
|
||||||
|
import re
|
||||||
|
import os
|
||||||
|
import json
|
||||||
|
import time
|
||||||
|
from win10toast import ToastNotifier
|
||||||
|
|
||||||
|
# Definir una constante para la ruta del directorio
|
||||||
|
DIR = "D:\\Proyectos\\Scripts\\IPChanger"
|
||||||
|
IP_HISTORY_FILE = os.path.join(DIR, "ip_history.json")
|
||||||
|
|
||||||
|
|
||||||
|
def is_admin():
|
||||||
|
"""Verifica si el script se está ejecutando con privilegios de administrador."""
|
||||||
|
try:
|
||||||
|
return ctypes.windll.shell32.IsUserAnAdmin()
|
||||||
|
except:
|
||||||
|
return False
|
||||||
|
|
||||||
|
|
||||||
|
def run_as_admin(argv=None, debug=False):
|
||||||
|
"""Ejecuta el script como administrador."""
|
||||||
|
shell32 = ctypes.windll.shell32
|
||||||
|
if argv is None and shell32.IsUserAnAdmin():
|
||||||
|
# Ya estamos ejecutando como administrador, no es necesario hacer nada
|
||||||
|
return True
|
||||||
|
if argv is None:
|
||||||
|
argv = sys.argv
|
||||||
|
if hasattr(sys, "_MEIPASS"):
|
||||||
|
# Soporte para PyInstaller
|
||||||
|
arguments = map(str, argv[1:])
|
||||||
|
else:
|
||||||
|
arguments = map(str, argv)
|
||||||
|
argument_line = " ".join(arguments)
|
||||||
|
executable = str(sys.executable)
|
||||||
|
if debug:
|
||||||
|
print(f"Command line: {executable} {argument_line}")
|
||||||
|
ret = shell32.ShellExecuteW(None, "runas", executable, argument_line, None, 1)
|
||||||
|
if int(ret) <= 32:
|
||||||
|
return False
|
||||||
|
return None
|
||||||
|
|
||||||
|
|
||||||
|
def set_static_ip(ip_address, gateway):
|
||||||
|
"""Establece una dirección IP estática para el adaptador Ethernet."""
|
||||||
|
try:
|
||||||
|
subprocess.run(
|
||||||
|
f'netsh interface ip set address "Ethernet" static {ip_address} 255.255.255.0 {gateway}',
|
||||||
|
shell=True,
|
||||||
|
)
|
||||||
|
return f"Dirección IP establecida en {ip_address}"
|
||||||
|
except Exception as e:
|
||||||
|
return f"Error al establecer la dirección IP: {e}"
|
||||||
|
|
||||||
|
|
||||||
|
def set_dhcp():
|
||||||
|
"""Configura el adaptador Ethernet para obtener la dirección IP automáticamente a través de DHCP."""
|
||||||
|
try:
|
||||||
|
subprocess.run('netsh interface ip set address "Ethernet" dhcp', shell=True)
|
||||||
|
return "Adaptador Ethernet configurado para DHCP"
|
||||||
|
except Exception as e:
|
||||||
|
return f"Error al configurar DHCP: {e}"
|
||||||
|
|
||||||
|
|
||||||
|
def save_current_ip():
|
||||||
|
"""Guarda la dirección IP actual del adaptador Ethernet en un archivo."""
|
||||||
|
try:
|
||||||
|
ip_config_output = subprocess.check_output("ipconfig", shell=True).decode(
|
||||||
|
"cp850"
|
||||||
|
)
|
||||||
|
current_ip = re.search(
|
||||||
|
"Adaptador de Ethernet Ethernet:[\s\S]*?Dirección IPv4. . . . . . . . . . . . . . : (\d+\.\d+\.\d+\.\d+)",
|
||||||
|
ip_config_output,
|
||||||
|
)
|
||||||
|
if current_ip:
|
||||||
|
update_ip_history(current_ip.group(1))
|
||||||
|
return f"Dirección IP actual guardada: {current_ip.group(1)}"
|
||||||
|
else:
|
||||||
|
return "No se encontró la dirección IP actual."
|
||||||
|
except Exception as e:
|
||||||
|
return f"Error al guardar la dirección IP actual: {e}"
|
||||||
|
|
||||||
|
|
||||||
|
def update_ip_history(current_ip):
|
||||||
|
"""Actualiza el historial de las últimas 10 IPs usadas, excluyendo 'auto'."""
|
||||||
|
if current_ip.lower() == "auto":
|
||||||
|
return
|
||||||
|
|
||||||
|
if os.path.exists(IP_HISTORY_FILE):
|
||||||
|
with open(IP_HISTORY_FILE, "r") as file:
|
||||||
|
ip_history = json.load(file)
|
||||||
|
else:
|
||||||
|
ip_history = []
|
||||||
|
|
||||||
|
ip_history.insert(0, current_ip)
|
||||||
|
ip_history = ip_history[:10]
|
||||||
|
|
||||||
|
with open("ip_history.json", "w") as file:
|
||||||
|
json.dump(ip_history, file)
|
||||||
|
|
||||||
|
|
||||||
|
def restore_last_ip():
|
||||||
|
"""Restaura la última dirección IP guardada para el adaptador Ethernet."""
|
||||||
|
if os.path.exists(IP_HISTORY_FILE):
|
||||||
|
with open(IP_HISTORY_FILE, "r") as file:
|
||||||
|
ip_history = json.load(file)
|
||||||
|
if ip_history:
|
||||||
|
last_ip = ip_history[0] # Obtener la última IP del historial
|
||||||
|
gateway = last_ip.rsplit(".", 1)[0] + ".1"
|
||||||
|
return set_static_ip(last_ip, gateway)
|
||||||
|
else:
|
||||||
|
return "No hay direcciones IP guardadas en el historial."
|
||||||
|
else:
|
||||||
|
return "No se encontró el archivo de historial de IPs."
|
||||||
|
|
||||||
|
|
||||||
|
def get_input_parameter():
|
||||||
|
"""Solicita al usuario un parámetro por línea de comandos."""
|
||||||
|
return input(
|
||||||
|
"Ingrese la dirección IP, 'auto' para DHCP, o 'last' para la última IP: "
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
def display_ip_history(ip_history):
|
||||||
|
"""Muestra el historial de las últimas 10 IPs y permite al usuario seleccionar una."""
|
||||||
|
if ip_history:
|
||||||
|
for i, ip in enumerate(ip_history):
|
||||||
|
print(f"{i}: {ip}")
|
||||||
|
choice = input(
|
||||||
|
"Seleccione una IP del historial (0-9), o presione Enter para continuar: "
|
||||||
|
)
|
||||||
|
if choice.isdigit() and 0 <= int(choice) < len(ip_history):
|
||||||
|
return ip_history[int(choice)]
|
||||||
|
return None
|
||||||
|
|
||||||
|
|
||||||
|
def main():
|
||||||
|
if not is_admin():
|
||||||
|
# Si no se está ejecutando como administrador, solicitar elevación
|
||||||
|
result = run_as_admin()
|
||||||
|
if result is True:
|
||||||
|
print("Ejecutando como administrador.")
|
||||||
|
elif result is False:
|
||||||
|
print("No se pudo obtener privilegios de administrador.")
|
||||||
|
return
|
||||||
|
else:
|
||||||
|
# El script se reinició con privilegios de administrador
|
||||||
|
return
|
||||||
|
|
||||||
|
if os.path.exists(IP_HISTORY_FILE):
|
||||||
|
with open(IP_HISTORY_FILE, "r") as file:
|
||||||
|
ip_history = json.load(file)
|
||||||
|
|
||||||
|
argument = sys.argv[1] if len(sys.argv) > 1 else None
|
||||||
|
|
||||||
|
if not argument:
|
||||||
|
chosen_ip = display_ip_history()
|
||||||
|
if chosen_ip:
|
||||||
|
argument = chosen_ip
|
||||||
|
else:
|
||||||
|
argument = get_input_parameter()
|
||||||
|
|
||||||
|
# Guardar la dirección IP actual solo si no es 'auto'
|
||||||
|
if argument.lower() != "auto":
|
||||||
|
message = save_current_ip()
|
||||||
|
|
||||||
|
if argument == "auto":
|
||||||
|
message = set_dhcp()
|
||||||
|
elif argument == "last":
|
||||||
|
message = restore_last_ip()
|
||||||
|
else:
|
||||||
|
ip_parts = argument.split(".")
|
||||||
|
if len(ip_parts) == 3:
|
||||||
|
argument += ".249"
|
||||||
|
gateway = ".".join(ip_parts[:3]) + ".1"
|
||||||
|
message = set_static_ip(argument, gateway)
|
||||||
|
update_ip_history(argument) # Actualizar el historial solo con IPs estáticas
|
||||||
|
|
||||||
|
# Aquí asumimos que 'message' contiene el mensaje que quieres mostrar
|
||||||
|
try:
|
||||||
|
toaster = ToastNotifier()
|
||||||
|
toaster.show_toast("Cambio de IP", message, duration=10)
|
||||||
|
except Exception as e:
|
||||||
|
print(
|
||||||
|
f"Se produjo un error al mostrar la notificación, pero la operación se completó con éxito: {e}"
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
main()
|
|
@ -0,0 +1,203 @@
|
||||||
|
import ctypes
|
||||||
|
import subprocess
|
||||||
|
import sys
|
||||||
|
import re
|
||||||
|
import os
|
||||||
|
import json
|
||||||
|
import time
|
||||||
|
from win10toast import ToastNotifier
|
||||||
|
import threading
|
||||||
|
|
||||||
|
# Definir una constante para la ruta del directorio
|
||||||
|
DIR = "D:\\Proyectos\\Scripts\\IPChanger"
|
||||||
|
IP_HISTORY_FILE = os.path.join(DIR, "ip_history.json")
|
||||||
|
|
||||||
|
|
||||||
|
def is_admin():
|
||||||
|
"""Verifica si el script se está ejecutando con privilegios de administrador."""
|
||||||
|
try:
|
||||||
|
return ctypes.windll.shell32.IsUserAnAdmin()
|
||||||
|
except:
|
||||||
|
return False
|
||||||
|
|
||||||
|
|
||||||
|
def run_as_admin(argv=None, debug=False):
|
||||||
|
"""Ejecuta el script como administrador."""
|
||||||
|
shell32 = ctypes.windll.shell32
|
||||||
|
if argv is None and shell32.IsUserAnAdmin():
|
||||||
|
# Ya estamos ejecutando como administrador, no es necesario hacer nada
|
||||||
|
return True
|
||||||
|
if argv is None:
|
||||||
|
argv = sys.argv
|
||||||
|
if hasattr(sys, "_MEIPASS"):
|
||||||
|
# Soporte para PyInstaller
|
||||||
|
arguments = map(str, argv[1:])
|
||||||
|
else:
|
||||||
|
arguments = map(str, argv)
|
||||||
|
argument_line = " ".join(arguments)
|
||||||
|
executable = str(sys.executable)
|
||||||
|
if debug:
|
||||||
|
print(f"Command line: {executable} {argument_line}")
|
||||||
|
ret = shell32.ShellExecuteW(None, "runas", executable, argument_line, None, 1)
|
||||||
|
if int(ret) <= 32:
|
||||||
|
return False
|
||||||
|
return None
|
||||||
|
|
||||||
|
|
||||||
|
def set_static_ip(ip_address, gateway):
|
||||||
|
"""Establece una dirección IP estática para el adaptador Ethernet."""
|
||||||
|
try:
|
||||||
|
subprocess.run(
|
||||||
|
f'netsh interface ip set address "Ethernet" static {ip_address} 255.255.255.0 {gateway}',
|
||||||
|
shell=True,
|
||||||
|
)
|
||||||
|
return f"Dirección IP establecida en {ip_address}"
|
||||||
|
except Exception as e:
|
||||||
|
return f"Error al establecer la dirección IP: {e}"
|
||||||
|
|
||||||
|
|
||||||
|
def set_dhcp():
|
||||||
|
"""Configura el adaptador Ethernet para obtener la dirección IP automáticamente a través de DHCP."""
|
||||||
|
try:
|
||||||
|
subprocess.run('netsh interface ip set address "Ethernet" dhcp', shell=True)
|
||||||
|
return "Adaptador Ethernet configurado para DHCP"
|
||||||
|
except Exception as e:
|
||||||
|
return f"Error al configurar DHCP: {e}"
|
||||||
|
|
||||||
|
|
||||||
|
def save_current_ip(ip_history):
|
||||||
|
"""Guarda la dirección IP actual del adaptador Ethernet en un archivo y detecta si es de DHCP."""
|
||||||
|
try:
|
||||||
|
ip_config_output = subprocess.check_output("ipconfig /all", shell=True).decode(
|
||||||
|
"cp850"
|
||||||
|
)
|
||||||
|
|
||||||
|
# Buscar la sección del adaptador de Ethernet y DHCP
|
||||||
|
ethernet_config = re.search(
|
||||||
|
"Adaptador de Ethernet Ethernet:[\s\S]*?(DHCP habilitado[\s\S]*?)\r\n\r\n",
|
||||||
|
ip_config_output,
|
||||||
|
)
|
||||||
|
current_ip = re.search(
|
||||||
|
"Dirección IPv4. . . . . . . . . . . . . . : (\d+\.\d+\.\d+\.\d+)",
|
||||||
|
ethernet_config.group(1) if ethernet_config else "",
|
||||||
|
)
|
||||||
|
dhcp_enabled = re.search(
|
||||||
|
"DHCP habilitado . . . . . . . . . . . . . : sí",
|
||||||
|
ethernet_config.group(1) if ethernet_config else "",
|
||||||
|
)
|
||||||
|
|
||||||
|
if current_ip and not dhcp_enabled:
|
||||||
|
ip_history.insert(0, current_ip.group(1))
|
||||||
|
ip_history = ip_history[:10]
|
||||||
|
return f"Dirección IP actual guardada: {current_ip.group(1)}"
|
||||||
|
elif dhcp_enabled:
|
||||||
|
return "La dirección IP actual es obtenida por DHCP."
|
||||||
|
else:
|
||||||
|
return "No se encontró la dirección IP actual."
|
||||||
|
except Exception as e:
|
||||||
|
return f"Error al obtener la configuración IP: {e}"
|
||||||
|
|
||||||
|
|
||||||
|
def restore_last_ip(ip_history):
|
||||||
|
"""Restaura la última dirección IP guardada para el adaptador Ethernet."""
|
||||||
|
if ip_history:
|
||||||
|
last_ip = ip_history[0] # Obtener la última IP del historial
|
||||||
|
gateway = last_ip.rsplit(".", 1)[0] + ".1"
|
||||||
|
return set_static_ip(last_ip, gateway)
|
||||||
|
else:
|
||||||
|
return "No hay direcciones IP guardadas en el historial."
|
||||||
|
|
||||||
|
|
||||||
|
def get_input_parameter():
|
||||||
|
"""Solicita al usuario un parámetro por línea de comandos."""
|
||||||
|
return input(
|
||||||
|
"Ingrese la dirección IP, 0-9 para los ultimas IP, 'a' o 'auto' para DHCP, o 'l' o 'last' para la última IP: "
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
def display_ip_history(ip_history):
|
||||||
|
"""Muestra el historial de las últimas 10 IPs en orden inverso (de la más antigua a la más reciente) y permite al usuario seleccionar una."""
|
||||||
|
if ip_history:
|
||||||
|
for i, ip in enumerate(reversed(ip_history)):
|
||||||
|
print(f"{len(ip_history) - 1 - i}: {ip}")
|
||||||
|
return None
|
||||||
|
|
||||||
|
|
||||||
|
def remove_duplicates_preserve_order(ip_history):
|
||||||
|
"""Elimina duplicados de la lista manteniendo el orden."""
|
||||||
|
seen = set()
|
||||||
|
new_history = []
|
||||||
|
for item in ip_history:
|
||||||
|
if item not in seen:
|
||||||
|
seen.add(item)
|
||||||
|
new_history.append(item)
|
||||||
|
return new_history
|
||||||
|
|
||||||
|
|
||||||
|
def show_notification(message, duration):
|
||||||
|
toaster = ToastNotifier()
|
||||||
|
toaster.show_toast("Cambio de IP", message, duration=duration)
|
||||||
|
|
||||||
|
|
||||||
|
def main():
|
||||||
|
if not is_admin():
|
||||||
|
# Si no se está ejecutando como administrador, solicitar elevación
|
||||||
|
result = run_as_admin()
|
||||||
|
if result is True:
|
||||||
|
print("Ejecutando como administrador.")
|
||||||
|
elif result is False:
|
||||||
|
print("No se pudo obtener privilegios de administrador.")
|
||||||
|
return
|
||||||
|
else:
|
||||||
|
# El script se reinició con privilegios de administrador
|
||||||
|
return
|
||||||
|
|
||||||
|
if os.path.exists(IP_HISTORY_FILE):
|
||||||
|
with open(IP_HISTORY_FILE, "r") as file:
|
||||||
|
ip_history = json.load(file)
|
||||||
|
ip_history = remove_duplicates_preserve_order(ip_history)
|
||||||
|
else:
|
||||||
|
ip_history = []
|
||||||
|
|
||||||
|
argument = sys.argv[1] if len(sys.argv) > 1 else None
|
||||||
|
|
||||||
|
if not argument:
|
||||||
|
chosen_ip = display_ip_history(ip_history)
|
||||||
|
argument = get_input_parameter()
|
||||||
|
|
||||||
|
if len(argument) == 0:
|
||||||
|
return
|
||||||
|
|
||||||
|
if ip_history:
|
||||||
|
if len(argument) == 1:
|
||||||
|
if argument.isdigit() and 0 <= int(argument) < len(ip_history):
|
||||||
|
argument = ip_history[int(argument)]
|
||||||
|
|
||||||
|
# Guardar la dirección IP actual solo si no es 'auto'
|
||||||
|
message = save_current_ip(ip_history)
|
||||||
|
print(message)
|
||||||
|
|
||||||
|
if argument == "auto" or argument == "a":
|
||||||
|
message = set_dhcp()
|
||||||
|
elif argument == "last" or argument == "l":
|
||||||
|
if ip_history:
|
||||||
|
message = restore_last_ip(ip_history)
|
||||||
|
print(message)
|
||||||
|
|
||||||
|
else:
|
||||||
|
ip_parts = argument.split(".")
|
||||||
|
if len(ip_parts) == 3:
|
||||||
|
argument += ".249"
|
||||||
|
gateway = ".".join(ip_parts[:3]) + ".1"
|
||||||
|
message = set_static_ip(argument, gateway)
|
||||||
|
print(message)
|
||||||
|
|
||||||
|
with open(IP_HISTORY_FILE, "w") as file:
|
||||||
|
json.dump(ip_history, file)
|
||||||
|
|
||||||
|
notification_thread = threading.Thread(target=show_notification, args=(message, 3))
|
||||||
|
notification_thread.start()
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
main()
|
|
@ -0,0 +1 @@
|
||||||
|
python ipchange.py
|
|
@ -0,0 +1 @@
|
||||||
|
10.1.30.249
|
|
@ -0,0 +1,551 @@
|
||||||
|
import tkinter as tk
|
||||||
|
from tkinter import ttk, messagebox
|
||||||
|
import json
|
||||||
|
import os
|
||||||
|
import subprocess
|
||||||
|
import re
|
||||||
|
import ctypes
|
||||||
|
import sys
|
||||||
|
import ipaddress
|
||||||
|
from typing import List, Optional
|
||||||
|
from dataclasses import dataclass
|
||||||
|
import threading
|
||||||
|
import time
|
||||||
|
|
||||||
|
try:
|
||||||
|
import wmi
|
||||||
|
WMI_AVAILABLE = True
|
||||||
|
except ImportError:
|
||||||
|
WMI_AVAILABLE = False
|
||||||
|
print("WMI module not found. Using alternative method for network interface detection.")
|
||||||
|
|
||||||
|
@dataclass
|
||||||
|
class NetworkInterface:
|
||||||
|
name: str
|
||||||
|
description: str
|
||||||
|
ip_address: str = ""
|
||||||
|
subnet_mask: str = ""
|
||||||
|
gateway: str = ""
|
||||||
|
dhcp_enabled: bool = True
|
||||||
|
active: bool = True
|
||||||
|
adapter_id: str = ""
|
||||||
|
|
||||||
|
class IPChangeConfig:
|
||||||
|
def __init__(self):
|
||||||
|
self.config_file = "ip_config.json"
|
||||||
|
self.history_file = "ip_history.json"
|
||||||
|
self.load_config()
|
||||||
|
|
||||||
|
def load_config(self):
|
||||||
|
try:
|
||||||
|
if os.path.exists(self.config_file):
|
||||||
|
with open(self.config_file, 'r') as f:
|
||||||
|
config = json.load(f)
|
||||||
|
self.last_interface = config.get('last_interface', '')
|
||||||
|
self.last_ip_prefix = config.get('last_ip_prefix', '')
|
||||||
|
else:
|
||||||
|
self.last_interface = ''
|
||||||
|
self.last_ip_prefix = ''
|
||||||
|
except Exception as e:
|
||||||
|
print(f"Error loading config: {e}")
|
||||||
|
self.last_interface = ''
|
||||||
|
self.last_ip_prefix = ''
|
||||||
|
|
||||||
|
def save_config(self):
|
||||||
|
try:
|
||||||
|
config = {
|
||||||
|
'last_interface': self.last_interface,
|
||||||
|
'last_ip_prefix': self.last_ip_prefix
|
||||||
|
}
|
||||||
|
with open(self.config_file, 'w') as f:
|
||||||
|
json.dump(config, f)
|
||||||
|
except Exception as e:
|
||||||
|
print(f"Error saving config: {e}")
|
||||||
|
|
||||||
|
class IPChangerApp:
|
||||||
|
def __init__(self, master):
|
||||||
|
self.master = master
|
||||||
|
self.master.title("Network Interface IP Configuration")
|
||||||
|
self.master.geometry("900x700")
|
||||||
|
|
||||||
|
# Inicializar configuración antes que nada
|
||||||
|
self.config = IPChangeConfig()
|
||||||
|
|
||||||
|
# Inicializar estructuras de datos
|
||||||
|
self.interfaces: List[NetworkInterface] = []
|
||||||
|
self.ip_history: List[str] = []
|
||||||
|
|
||||||
|
# Inicializar WMI si está disponible
|
||||||
|
if WMI_AVAILABLE:
|
||||||
|
self.wmi_client = wmi.WMI()
|
||||||
|
|
||||||
|
# Cargar datos guardados antes de crear widgets
|
||||||
|
self.load_ip_history()
|
||||||
|
|
||||||
|
# Crear la interfaz
|
||||||
|
self.create_widgets()
|
||||||
|
|
||||||
|
# Actualizar la lista de IPs en el combo
|
||||||
|
self.update_history_display()
|
||||||
|
|
||||||
|
# Refrescar interfaces
|
||||||
|
self.refresh_interfaces()
|
||||||
|
|
||||||
|
# Configurar pesos de la cuadrícula
|
||||||
|
self.master.grid_columnconfigure(0, weight=1)
|
||||||
|
self.master.grid_rowconfigure(1, weight=1) # El log expandible
|
||||||
|
|
||||||
|
def get_ip_prefix(self, ip: str) -> str:
|
||||||
|
"""Extrae los primeros 3 octetos de una dirección IP"""
|
||||||
|
parts = ip.split('.')
|
||||||
|
if len(parts) >= 3:
|
||||||
|
return '.'.join(parts[:3])
|
||||||
|
return ip
|
||||||
|
|
||||||
|
def create_widgets(self):
|
||||||
|
# Panel superior para controles
|
||||||
|
self.control_frame = ttk.Frame(self.master, padding="10")
|
||||||
|
self.control_frame.grid(row=0, column=0, sticky='new')
|
||||||
|
|
||||||
|
# Sección de interfaces
|
||||||
|
self.interfaces_frame = ttk.LabelFrame(self.control_frame, text="Network Interfaces", padding="5")
|
||||||
|
self.interfaces_frame.grid(row=0, column=0, sticky='ew', pady=(0,10))
|
||||||
|
|
||||||
|
ttk.Label(self.interfaces_frame, text="Select Interface:").grid(row=0, column=0, sticky='w', padx=5)
|
||||||
|
self.if_var = tk.StringVar()
|
||||||
|
self.if_combo = ttk.Combobox(self.interfaces_frame, textvariable=self.if_var, state='readonly', width=50)
|
||||||
|
self.if_combo.grid(row=0, column=1, sticky='ew', padx=5)
|
||||||
|
self.if_combo.bind('<<ComboboxSelected>>', self.on_interface_selected)
|
||||||
|
|
||||||
|
# Info de configuración actual
|
||||||
|
self.current_frame = ttk.LabelFrame(self.control_frame, text="Current Configuration", padding="5")
|
||||||
|
self.current_frame.grid(row=1, column=0, sticky='ew', pady=(0,10))
|
||||||
|
|
||||||
|
self.current_ip_var = tk.StringVar()
|
||||||
|
self.current_mask_var = tk.StringVar()
|
||||||
|
self.current_gateway_var = tk.StringVar()
|
||||||
|
self.dhcp_status_var = tk.StringVar()
|
||||||
|
|
||||||
|
ttk.Label(self.current_frame, text="Current IP:").grid(row=0, column=0, sticky='w', padx=5)
|
||||||
|
ttk.Label(self.current_frame, textvariable=self.current_ip_var).grid(row=0, column=1, sticky='w')
|
||||||
|
ttk.Label(self.current_frame, text="Subnet Mask:").grid(row=1, column=0, sticky='w', padx=5)
|
||||||
|
ttk.Label(self.current_frame, textvariable=self.current_mask_var).grid(row=1, column=1, sticky='w')
|
||||||
|
ttk.Label(self.current_frame, text="Gateway:").grid(row=2, column=0, sticky='w', padx=5)
|
||||||
|
ttk.Label(self.current_frame, textvariable=self.current_gateway_var).grid(row=2, column=1, sticky='w')
|
||||||
|
ttk.Label(self.current_frame, text="DHCP Status:").grid(row=3, column=0, sticky='w', padx=5)
|
||||||
|
ttk.Label(self.current_frame, textvariable=self.dhcp_status_var).grid(row=3, column=1, sticky='w')
|
||||||
|
|
||||||
|
# Sección de configuración IP
|
||||||
|
self.ip_frame = ttk.LabelFrame(self.control_frame, text="IP Configuration", padding="5")
|
||||||
|
self.ip_frame.grid(row=2, column=0, sticky='ew', pady=(0,10))
|
||||||
|
|
||||||
|
ttk.Label(self.ip_frame, text="IP Prefix (first 3 octets):").grid(row=0, column=0, sticky='w', padx=5)
|
||||||
|
self.ip_prefix = tk.StringVar(value=self.config.last_ip_prefix)
|
||||||
|
self.ip_entry = ttk.Entry(self.ip_frame, textvariable=self.ip_prefix, width=30)
|
||||||
|
self.ip_entry.grid(row=0, column=1, sticky='w', padx=5)
|
||||||
|
|
||||||
|
ttk.Label(self.ip_frame, text="Last Octet:").grid(row=0, column=2, sticky='w', padx=5)
|
||||||
|
self.last_octet = tk.StringVar(value="249")
|
||||||
|
self.last_octet_entry = ttk.Entry(self.ip_frame, textvariable=self.last_octet, width=5)
|
||||||
|
self.last_octet_entry.grid(row=0, column=3, sticky='w', padx=5)
|
||||||
|
|
||||||
|
# Sección de historial
|
||||||
|
self.history_frame = ttk.LabelFrame(self.control_frame, text="IP History", padding="5")
|
||||||
|
self.history_frame.grid(row=3, column=0, sticky='ew', pady=(0,10))
|
||||||
|
|
||||||
|
ttk.Label(self.history_frame, text="Previous IPs:").grid(row=0, column=0, sticky='w', padx=5)
|
||||||
|
self.history_var = tk.StringVar()
|
||||||
|
self.history_combo = ttk.Combobox(
|
||||||
|
self.history_frame,
|
||||||
|
textvariable=self.history_var,
|
||||||
|
state='readonly',
|
||||||
|
width=50
|
||||||
|
)
|
||||||
|
self.history_combo.grid(row=0, column=1, sticky='ew', padx=5)
|
||||||
|
self.history_combo.bind('<<ComboboxSelected>>', self.on_history_selected)
|
||||||
|
|
||||||
|
# Botones de acción
|
||||||
|
self.button_frame = ttk.Frame(self.control_frame)
|
||||||
|
self.button_frame.grid(row=4, column=0, sticky='ew', pady=(0,10))
|
||||||
|
|
||||||
|
ttk.Button(self.button_frame, text="Set Static IP", command=self.set_static_ip).grid(row=0, column=0, padx=5)
|
||||||
|
ttk.Button(self.button_frame, text="Enable DHCP", command=self.set_dhcp).grid(row=0, column=1, padx=5)
|
||||||
|
ttk.Button(self.button_frame, text="Refresh Interfaces", command=self.refresh_interfaces).grid(row=0, column=2, padx=5)
|
||||||
|
|
||||||
|
# Log en la parte inferior
|
||||||
|
self.log_frame = ttk.LabelFrame(self.master, text="Operation Log", padding="5")
|
||||||
|
self.log_frame.grid(row=1, column=0, sticky='nsew', padx=10, pady=(0,10))
|
||||||
|
|
||||||
|
self.log_text = tk.Text(self.log_frame, wrap="none", height=10)
|
||||||
|
self.log_scrollbar_y = ttk.Scrollbar(self.log_frame, orient="vertical", command=self.log_text.yview)
|
||||||
|
self.log_scrollbar_x = ttk.Scrollbar(self.log_frame, orient="horizontal", command=self.log_text.xview)
|
||||||
|
|
||||||
|
self.log_text.configure(
|
||||||
|
yscrollcommand=self.log_scrollbar_y.set,
|
||||||
|
xscrollcommand=self.log_scrollbar_x.set
|
||||||
|
)
|
||||||
|
|
||||||
|
self.log_text.grid(row=0, column=0, sticky='nsew')
|
||||||
|
self.log_scrollbar_y.grid(row=0, column=1, sticky='ns')
|
||||||
|
self.log_scrollbar_x.grid(row=1, column=0, sticky='ew')
|
||||||
|
|
||||||
|
ttk.Button(self.log_frame, text="Clear Log", command=self.clear_log).grid(row=2, column=0, columnspan=2, pady=5)
|
||||||
|
|
||||||
|
self.log_frame.grid_columnconfigure(0, weight=1)
|
||||||
|
self.log_frame.grid_rowconfigure(0, weight=1)
|
||||||
|
|
||||||
|
def clear_log(self):
|
||||||
|
self.log_text.delete('1.0', tk.END)
|
||||||
|
|
||||||
|
def log_message(self, message: str):
|
||||||
|
self.log_text.insert(tk.END, f"{message}\n")
|
||||||
|
self.log_text.see(tk.END)
|
||||||
|
self.log_text.update_idletasks()
|
||||||
|
|
||||||
|
def load_ip_history(self):
|
||||||
|
try:
|
||||||
|
if os.path.exists(self.config.history_file):
|
||||||
|
with open(self.config.history_file, 'r') as f:
|
||||||
|
self.ip_history = json.load(f)
|
||||||
|
else:
|
||||||
|
self.ip_history = []
|
||||||
|
except Exception as e:
|
||||||
|
self.log_message(f"Error loading IP history: {e}")
|
||||||
|
self.ip_history = []
|
||||||
|
|
||||||
|
def save_ip_history(self):
|
||||||
|
try:
|
||||||
|
with open(self.config.history_file, 'w') as f:
|
||||||
|
json.dump(self.ip_history, f)
|
||||||
|
except Exception as e:
|
||||||
|
self.log_message(f"Error saving IP history: {e}")
|
||||||
|
|
||||||
|
def add_to_history(self, ip_prefix: str):
|
||||||
|
if ip_prefix and ip_prefix not in self.ip_history:
|
||||||
|
self.ip_history.insert(0, ip_prefix)
|
||||||
|
self.ip_history = self.ip_history[:15] # Mantener solo las últimas 15 IPs
|
||||||
|
self.save_ip_history()
|
||||||
|
self.update_history_display()
|
||||||
|
|
||||||
|
def update_history_display(self):
|
||||||
|
self.history_combo['values'] = self.ip_history
|
||||||
|
if self.ip_history:
|
||||||
|
self.history_combo.set(self.ip_history[0])
|
||||||
|
|
||||||
|
def on_history_selected(self, event):
|
||||||
|
selected_ip = self.history_var.get()
|
||||||
|
if selected_ip:
|
||||||
|
# Ensure we only get the first three octets
|
||||||
|
ip_parts = selected_ip.split('.')
|
||||||
|
if len(ip_parts) >= 3:
|
||||||
|
ip_prefix = '.'.join(ip_parts[:3])
|
||||||
|
self.ip_prefix.set(ip_prefix)
|
||||||
|
self.config.last_ip_prefix = ip_prefix
|
||||||
|
self.config.save_config()
|
||||||
|
self.log_message(f"Selected IP prefix from history: {ip_prefix}")
|
||||||
|
|
||||||
|
def refresh_interfaces(self):
|
||||||
|
self.interfaces.clear()
|
||||||
|
try:
|
||||||
|
if WMI_AVAILABLE:
|
||||||
|
self._refresh_interfaces_wmi()
|
||||||
|
else:
|
||||||
|
self._refresh_interfaces_netsh()
|
||||||
|
|
||||||
|
# Actualizar combobox
|
||||||
|
self.if_combo['values'] = [inf.name for inf in self.interfaces if inf.active]
|
||||||
|
|
||||||
|
# Seleccionar última interfaz usada si está disponible
|
||||||
|
if self.config.last_interface in self.if_combo['values']:
|
||||||
|
self.if_combo.set(self.config.last_interface)
|
||||||
|
self.on_interface_selected()
|
||||||
|
|
||||||
|
self.log_message("Interfaces refreshed successfully")
|
||||||
|
|
||||||
|
except Exception as e:
|
||||||
|
self.log_message(f"Error refreshing interfaces: {str(e)}")
|
||||||
|
self.show_error(f"Error refreshing interfaces: {str(e)}")
|
||||||
|
|
||||||
|
def _refresh_interfaces_wmi(self):
|
||||||
|
try:
|
||||||
|
adapters = self.wmi_client.Win32_NetworkAdapter(PhysicalAdapter=True)
|
||||||
|
configs = self.wmi_client.Win32_NetworkAdapterConfiguration()
|
||||||
|
|
||||||
|
for adapter in adapters:
|
||||||
|
config = next((cfg for cfg in configs if cfg.InterfaceIndex == adapter.InterfaceIndex), None)
|
||||||
|
|
||||||
|
if config and config.IPEnabled:
|
||||||
|
interface = NetworkInterface(
|
||||||
|
name=adapter.NetConnectionID,
|
||||||
|
description=adapter.Description,
|
||||||
|
ip_address=config.IPAddress[0] if config.IPAddress else "",
|
||||||
|
subnet_mask=config.IPSubnet[0] if config.IPSubnet else "",
|
||||||
|
gateway=config.DefaultIPGateway[0] if config.DefaultIPGateway else "",
|
||||||
|
dhcp_enabled=config.DHCPEnabled,
|
||||||
|
active=adapter.NetEnabled,
|
||||||
|
adapter_id=adapter.GUID
|
||||||
|
)
|
||||||
|
self.interfaces.append(interface)
|
||||||
|
except Exception as e:
|
||||||
|
raise Exception(f"WMI refresh error: {str(e)}")
|
||||||
|
|
||||||
|
def _refresh_interfaces_netsh(self):
|
||||||
|
try:
|
||||||
|
output = subprocess.check_output("netsh interface ipv4 show config", shell=True, text=True)
|
||||||
|
configs = output.split("\n\n")
|
||||||
|
|
||||||
|
for config in configs:
|
||||||
|
if not config.strip():
|
||||||
|
continue
|
||||||
|
|
||||||
|
name_match = re.search(r"Configuración de\s+\"(.+?)\"", config)
|
||||||
|
if not name_match:
|
||||||
|
continue
|
||||||
|
|
||||||
|
name = name_match.group(1)
|
||||||
|
|
||||||
|
ip_match = re.search(r"Dirección IP:\s+(\d+\.\d+\.\d+\.\d+)", config)
|
||||||
|
mask_match = re.search(r"Máscara de subred:\s+(\d+\.\d+\.\d+\.\d+)", config)
|
||||||
|
gateway_match = re.search(r"Puerta de enlace predeterminada:\s+(\d+\.\d+\.\d+\.\d+)", config)
|
||||||
|
dhcp_match = re.search(r"DHCP habilitado:\s+(\w+)", config)
|
||||||
|
|
||||||
|
interface = NetworkInterface(
|
||||||
|
name=name,
|
||||||
|
description=name,
|
||||||
|
ip_address=ip_match.group(1) if ip_match else "",
|
||||||
|
subnet_mask=mask_match.group(1) if mask_match else "",
|
||||||
|
gateway=gateway_match.group(1) if gateway_match else "",
|
||||||
|
dhcp_enabled=dhcp_match.group(1).lower() == "sí" if dhcp_match else True,
|
||||||
|
active=True
|
||||||
|
)
|
||||||
|
self.interfaces.append(interface)
|
||||||
|
|
||||||
|
except subprocess.CalledProcessError as e:
|
||||||
|
raise Exception(f"Error executing netsh: {str(e)}")
|
||||||
|
except Exception as e:
|
||||||
|
raise Exception(f"Error parsing netsh output: {str(e)}")
|
||||||
|
|
||||||
|
def on_interface_selected(self, event=None):
|
||||||
|
selected = self.if_var.get()
|
||||||
|
interface = next((inf for inf in self.interfaces if inf.name == selected), None)
|
||||||
|
|
||||||
|
if interface:
|
||||||
|
self.current_ip_var.set(interface.ip_address)
|
||||||
|
self.current_mask_var.set(interface.subnet_mask)
|
||||||
|
self.current_gateway_var.set(interface.gateway)
|
||||||
|
self.dhcp_status_var.set("Enabled" if interface.dhcp_enabled else "Disabled")
|
||||||
|
|
||||||
|
# Actualizar IP prefix si hay una IP válida
|
||||||
|
if interface.ip_address:
|
||||||
|
prefix = '.'.join(interface.ip_address.split('.')[:3])
|
||||||
|
self.ip_prefix.set(prefix)
|
||||||
|
|
||||||
|
# Guardar interfaz seleccionada
|
||||||
|
self.config.last_interface = selected
|
||||||
|
self.config.save_config()
|
||||||
|
|
||||||
|
self.log_message(f"Selected interface: {selected}")
|
||||||
|
|
||||||
|
def validate_ip_input(self) -> tuple[bool, str]:
|
||||||
|
try:
|
||||||
|
prefix = self.ip_prefix.get().strip()
|
||||||
|
last_octet = self.last_octet.get().strip()
|
||||||
|
|
||||||
|
# Validar formato del prefijo
|
||||||
|
if not re.match(r'^\d{1,3}\.\d{1,3}\.\d{1,3}', prefix):
|
||||||
|
return False, "IP prefix must be in format: xxx.xxx.xxx"
|
||||||
|
|
||||||
|
# Validar último octeto
|
||||||
|
if not last_octet.isdigit() or not 0 <= int(last_octet) <= 255:
|
||||||
|
return False, "Last octet must be between 0 and 255"
|
||||||
|
|
||||||
|
# Construir y validar IP completa
|
||||||
|
ip = f"{prefix}.{last_octet}"
|
||||||
|
ipaddress.IPv4Address(ip)
|
||||||
|
|
||||||
|
return True, ip
|
||||||
|
|
||||||
|
except ValueError as e:
|
||||||
|
return False, f"Invalid IP address: {str(e)}"
|
||||||
|
|
||||||
|
def execute_admin_script(self, interface: str, mode: str, debug: bool = True) -> bool:
|
||||||
|
"""
|
||||||
|
Ejecuta el script administrativo con los argumentos proporcionados
|
||||||
|
mode puede ser una IP o 'dhcp'
|
||||||
|
"""
|
||||||
|
# Obtener rutas absolutas
|
||||||
|
current_dir = os.path.dirname(os.path.abspath(__file__))
|
||||||
|
script_path = os.path.join(current_dir, "ip-changer-admin.py")
|
||||||
|
python_exe = sys.executable
|
||||||
|
|
||||||
|
# Verificar que el script existe
|
||||||
|
if not os.path.exists(script_path):
|
||||||
|
error_msg = f"Admin script not found at: {script_path}"
|
||||||
|
self.log_message(error_msg)
|
||||||
|
return False
|
||||||
|
|
||||||
|
# Construir la línea de argumentos
|
||||||
|
args = f'"{script_path}" "{interface}" "{mode}"'
|
||||||
|
|
||||||
|
if debug:
|
||||||
|
self.log_message("Debug Information:")
|
||||||
|
self.log_message(f"Current Directory: {current_dir}")
|
||||||
|
self.log_message(f"Script Path: {script_path}")
|
||||||
|
self.log_message(f"Python Executable: {python_exe}")
|
||||||
|
self.log_message(f"Full Command: {python_exe} {args}")
|
||||||
|
|
||||||
|
try:
|
||||||
|
self.log_message(f"Attempting to execute admin script with elevated privileges")
|
||||||
|
|
||||||
|
ret = ctypes.windll.shell32.ShellExecuteW(
|
||||||
|
None, # hwnd
|
||||||
|
"runas", # operation
|
||||||
|
python_exe, # file
|
||||||
|
args, # parameters
|
||||||
|
current_dir, # directory
|
||||||
|
1 # show command
|
||||||
|
)
|
||||||
|
|
||||||
|
result_code = int(ret)
|
||||||
|
if result_code > 32:
|
||||||
|
self.log_message(f"ShellExecuteW successful (return code: {result_code})")
|
||||||
|
return True
|
||||||
|
else:
|
||||||
|
error_codes = {
|
||||||
|
0: "The operating system is out of memory or resources",
|
||||||
|
2: "The specified file was not found",
|
||||||
|
3: "The specified path was not found",
|
||||||
|
5: "Access denied",
|
||||||
|
8: "Insufficient memory to complete the operation",
|
||||||
|
11: "Bad format",
|
||||||
|
26: "A sharing violation occurred",
|
||||||
|
27: "The file name association is incomplete or invalid",
|
||||||
|
28: "The DDE operation timed out",
|
||||||
|
29: "The DDE operation failed",
|
||||||
|
30: "The DDE operation is busy",
|
||||||
|
31: "The file name association is unavailable",
|
||||||
|
32: "No application is associated with the file"
|
||||||
|
}
|
||||||
|
|
||||||
|
self.log_message(f"Failed to execute admin script. Error code {result_code}: {error_msg}")
|
||||||
|
return False
|
||||||
|
|
||||||
|
except Exception as e:
|
||||||
|
self.log_message(f"Exception while executing admin script: {str(e)}")
|
||||||
|
return False
|
||||||
|
|
||||||
|
def set_static_ip(self):
|
||||||
|
interface = self.if_var.get()
|
||||||
|
if not interface:
|
||||||
|
self.show_error("Please select a network interface")
|
||||||
|
return
|
||||||
|
|
||||||
|
# Validar IP
|
||||||
|
is_valid, result = self.validate_ip_input()
|
||||||
|
if not is_valid:
|
||||||
|
self.show_error(result)
|
||||||
|
return
|
||||||
|
|
||||||
|
ip = result
|
||||||
|
|
||||||
|
# Guardar IP actual en el historial
|
||||||
|
self.add_to_history(self.ip_prefix.get())
|
||||||
|
|
||||||
|
# Ejecutar script con privilegios
|
||||||
|
if self.execute_admin_script(interface, ip, debug=True):
|
||||||
|
time.sleep(2) # Esperar a que se apliquen los cambios
|
||||||
|
self.refresh_interfaces()
|
||||||
|
self.log_message(f"Successfully set static IP {ip} on {interface}")
|
||||||
|
else:
|
||||||
|
self.show_error("Failed to set static IP. Check the log for details.")
|
||||||
|
|
||||||
|
def set_dhcp(self):
|
||||||
|
interface = self.if_var.get()
|
||||||
|
if not interface:
|
||||||
|
self.show_error("Please select a network interface")
|
||||||
|
return
|
||||||
|
|
||||||
|
# Ejecutar script con privilegios
|
||||||
|
if self.execute_admin_script(interface, "dhcp", debug=True):
|
||||||
|
time.sleep(2) # Esperar a que se apliquen los cambios
|
||||||
|
self.refresh_interfaces()
|
||||||
|
self.log_message(f"Successfully enabled DHCP on {interface}")
|
||||||
|
else:
|
||||||
|
self.show_error("Failed to enable DHCP. Check the log for details.")
|
||||||
|
|
||||||
|
def run_command(self, cmd: str) -> bool:
|
||||||
|
self.log_message(f"Executing command: {cmd}")
|
||||||
|
try:
|
||||||
|
process = subprocess.Popen(
|
||||||
|
cmd,
|
||||||
|
shell=True,
|
||||||
|
stdout=subprocess.PIPE,
|
||||||
|
stderr=subprocess.PIPE,
|
||||||
|
universal_newlines=True
|
||||||
|
)
|
||||||
|
|
||||||
|
while True:
|
||||||
|
output = process.stdout.readline()
|
||||||
|
if output == '' and process.poll() is not None:
|
||||||
|
break
|
||||||
|
if output:
|
||||||
|
self.log_message(output.strip())
|
||||||
|
|
||||||
|
retcode = process.poll()
|
||||||
|
|
||||||
|
error_output = process.stderr.read()
|
||||||
|
if error_output:
|
||||||
|
self.log_message(f"Error output:\n{error_output}")
|
||||||
|
|
||||||
|
if retcode == 0:
|
||||||
|
self.log_message("Command executed successfully")
|
||||||
|
return True
|
||||||
|
else:
|
||||||
|
self.log_message(f"Command failed with return code: {retcode}")
|
||||||
|
return False
|
||||||
|
|
||||||
|
except Exception as e:
|
||||||
|
self.log_message(f"Error executing command: {str(e)}")
|
||||||
|
return False
|
||||||
|
|
||||||
|
def is_admin(self):
|
||||||
|
try:
|
||||||
|
return ctypes.windll.shell32.IsUserAnAdmin()
|
||||||
|
except Exception as e:
|
||||||
|
self.log_message(f"Error checking admin privileges: {str(e)}")
|
||||||
|
return False
|
||||||
|
|
||||||
|
def elevate_privileges(self):
|
||||||
|
if sys.platform == 'win32':
|
||||||
|
self.show_info("The application needs administrator privileges to change network settings. "
|
||||||
|
"Please confirm the UAC prompt.")
|
||||||
|
script_path = os.path.abspath(sys.argv[0])
|
||||||
|
try:
|
||||||
|
ctypes.windll.shell32.ShellExecuteW(
|
||||||
|
None,
|
||||||
|
"runas",
|
||||||
|
sys.executable,
|
||||||
|
f'"{script_path}"',
|
||||||
|
None,
|
||||||
|
1
|
||||||
|
)
|
||||||
|
self.master.quit()
|
||||||
|
except Exception as e:
|
||||||
|
self.log_message(f"Error elevating privileges: {str(e)}")
|
||||||
|
self.show_error("Failed to elevate privileges")
|
||||||
|
|
||||||
|
def show_error(self, message: str):
|
||||||
|
self.log_message(f"ERROR: {message}")
|
||||||
|
messagebox.showerror("Error", message)
|
||||||
|
|
||||||
|
def show_info(self, message: str):
|
||||||
|
self.log_message(f"INFO: {message}")
|
||||||
|
messagebox.showinfo("Information", message)
|
||||||
|
|
||||||
|
def main():
|
||||||
|
root = tk.Tk()
|
||||||
|
app = IPChangerApp(root)
|
||||||
|
root.mainloop()
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
main()
|
|
@ -0,0 +1,55 @@
|
||||||
|
import ctypes
|
||||||
|
import sys
|
||||||
|
import os
|
||||||
|
import subprocess
|
||||||
|
import re
|
||||||
|
|
||||||
|
def is_admin():
|
||||||
|
"""Verifica si el script se está ejecutando con privilegios de administrador."""
|
||||||
|
try:
|
||||||
|
return ctypes.windll.shell32.IsUserAnAdmin()
|
||||||
|
except:
|
||||||
|
return False
|
||||||
|
|
||||||
|
def run_as_admin(argv=None, debug=False):
|
||||||
|
"""Ejecuta el script como administrador."""
|
||||||
|
shell32 = ctypes.windll.shell32
|
||||||
|
if argv is None and shell32.IsUserAnAdmin():
|
||||||
|
# Ya estamos ejecutando como administrador, no es necesario hacer nada
|
||||||
|
return True
|
||||||
|
if argv is None:
|
||||||
|
argv = sys.argv
|
||||||
|
if hasattr(sys, '_MEIPASS'):
|
||||||
|
# Soporte para PyInstaller
|
||||||
|
arguments = map(str, argv[1:])
|
||||||
|
else:
|
||||||
|
arguments = map(str, argv)
|
||||||
|
argument_line = u' '.join(arguments)
|
||||||
|
executable = str(sys.executable)
|
||||||
|
if debug:
|
||||||
|
print(f'Command line: {executable} {argument_line}')
|
||||||
|
ret = shell32.ShellExecuteW(None, "runas", executable, argument_line, None, 1)
|
||||||
|
if int(ret) <= 32:
|
||||||
|
return False
|
||||||
|
return None
|
||||||
|
|
||||||
|
def main():
|
||||||
|
if not is_admin():
|
||||||
|
# Si no se está ejecutando como administrador, solicitar elevación
|
||||||
|
result = run_as_admin()
|
||||||
|
if result is True:
|
||||||
|
print("Ejecutando como administrador.")
|
||||||
|
elif result is False:
|
||||||
|
print("No se pudo obtener privilegios de administrador.")
|
||||||
|
return
|
||||||
|
else:
|
||||||
|
# El script se reinició con privilegios de administrador
|
||||||
|
return
|
||||||
|
|
||||||
|
# Aquí va el resto del código de tu script...
|
||||||
|
# Por ejemplo:
|
||||||
|
# save_current_ip()
|
||||||
|
# ...
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
main()
|
Loading…
Reference in New Issue