259 lines
No EOL
8.9 KiB
Python
259 lines
No EOL
8.9 KiB
Python
#!/usr/bin/env python3
|
|
|
|
import ssl
|
|
import sys
|
|
import json
|
|
import argparse
|
|
from datetime import datetime
|
|
|
|
try:
|
|
from librouteros import connect
|
|
from librouteros.query import Key
|
|
except ImportError:
|
|
print("Error: librouteros module not found")
|
|
print("Install with: pip install librouteros")
|
|
sys.exit(1)
|
|
|
|
def get_router_data(host, username='grahamro', password='cFKhz8q5gPLoucMbcT1Iy58r3IXgc3', port=8729):
|
|
"""
|
|
Connect to a MikroTik router and retrieve network configuration
|
|
|
|
Args:
|
|
host: IP address or hostname of the router
|
|
username: Router username (default: grahamro)
|
|
password: Router password
|
|
port: API-SSL port (default: 8729)
|
|
|
|
Returns:
|
|
Dictionary containing router configuration data
|
|
"""
|
|
|
|
print(f"=== Connecting to MikroTik Router ({host}) ===\n")
|
|
|
|
# SSL context for secure connection
|
|
ctx = ssl.create_default_context()
|
|
ctx.check_hostname = False
|
|
ctx.verify_mode = ssl.CERT_NONE
|
|
|
|
try:
|
|
# Connect to router
|
|
api = connect(
|
|
username=username,
|
|
password=password,
|
|
host=host,
|
|
port=port,
|
|
ssl_wrapper=ctx.wrap_socket
|
|
)
|
|
|
|
print("✓ Connected successfully\n")
|
|
|
|
# Get router identity
|
|
identity = None
|
|
try:
|
|
identity_data = api('/system/identity/print')
|
|
if identity_data:
|
|
identity = identity_data[0].get('name', 'Unknown')
|
|
print(f"Router Identity: {identity}\n")
|
|
except:
|
|
print("Could not retrieve router identity\n")
|
|
|
|
# Get IP addresses
|
|
print("=== IP Addresses ===")
|
|
ip_addresses = api('/ip/address/print')
|
|
|
|
subnets = []
|
|
for addr in ip_addresses:
|
|
if not addr.get('disabled', False):
|
|
address = addr['address']
|
|
interface = addr.get('interface', 'unknown')
|
|
network = addr.get('network', '')
|
|
comment = addr.get('comment', '')
|
|
dynamic = addr.get('dynamic', False)
|
|
|
|
print(f"Interface: {interface}")
|
|
print(f" Address: {address}")
|
|
print(f" Network: {network}")
|
|
if comment:
|
|
print(f" Comment: {comment}")
|
|
if dynamic:
|
|
print(f" Dynamic: Yes")
|
|
print()
|
|
|
|
subnets.append({
|
|
'address': address,
|
|
'network': network,
|
|
'interface': interface,
|
|
'comment': comment,
|
|
'dynamic': dynamic
|
|
})
|
|
|
|
# Get interfaces
|
|
print("\n=== Active Interfaces ===")
|
|
interfaces = api('/interface/print')
|
|
active_interfaces = []
|
|
|
|
for iface in interfaces:
|
|
if not iface.get('disabled', False) and iface.get('running', False):
|
|
name = iface['name']
|
|
itype = iface.get('type', 'unknown')
|
|
mac = iface.get('mac-address', 'N/A')
|
|
comment = iface.get('comment', '')
|
|
mtu = iface.get('mtu', 'default')
|
|
|
|
active_interfaces.append({
|
|
'name': name,
|
|
'type': itype,
|
|
'mac': mac,
|
|
'comment': comment,
|
|
'mtu': mtu
|
|
})
|
|
|
|
print(f"{name} ({itype})")
|
|
if comment:
|
|
print(f" Comment: {comment}")
|
|
if mac != 'N/A':
|
|
print(f" MAC: {mac}")
|
|
|
|
# Get VLANs
|
|
print("\n\n=== VLANs ===")
|
|
vlans = []
|
|
try:
|
|
vlan_interfaces = api('/interface/vlan/print')
|
|
for vlan in vlan_interfaces:
|
|
if not vlan.get('disabled', False):
|
|
name = vlan['name']
|
|
vlan_id = vlan.get('vlan-id', 'unknown')
|
|
interface = vlan.get('interface', 'unknown')
|
|
|
|
vlans.append({
|
|
'name': name,
|
|
'vlan_id': vlan_id,
|
|
'interface': interface
|
|
})
|
|
|
|
print(f"{name}: VLAN {vlan_id} on {interface}")
|
|
except:
|
|
print("No VLANs found or access denied")
|
|
|
|
# Get PPPoE servers
|
|
print("\n\n=== PPPoE Servers ===")
|
|
pppoe_servers = []
|
|
try:
|
|
servers = api('/interface/pppoe-server/server/print')
|
|
for server in servers:
|
|
if not server.get('disabled', False):
|
|
name = server.get('service-name', 'unnamed')
|
|
interface = server.get('interface', 'unknown')
|
|
|
|
pppoe_servers.append({
|
|
'service_name': name,
|
|
'interface': interface
|
|
})
|
|
|
|
print(f"Service: {name} on {interface}")
|
|
except:
|
|
print("No PPPoE servers found or access denied")
|
|
|
|
# Get static routes
|
|
print("\n\n=== Static Routes ===")
|
|
routes = []
|
|
try:
|
|
static_routes = api('/ip/route/print')
|
|
for route in static_routes:
|
|
if not route.get('dynamic', False) and not route.get('disabled', False):
|
|
dst = route.get('dst-address', '')
|
|
gateway = route.get('gateway', '')
|
|
distance = route.get('distance', '')
|
|
comment = route.get('comment', '')
|
|
|
|
if dst != '0.0.0.0/0': # Skip default route for brevity
|
|
routes.append({
|
|
'destination': dst,
|
|
'gateway': gateway,
|
|
'distance': distance,
|
|
'comment': comment
|
|
})
|
|
|
|
print(f"{dst} via {gateway}")
|
|
if comment:
|
|
print(f" Comment: {comment}")
|
|
except:
|
|
print("Could not retrieve routes")
|
|
|
|
# Close connection
|
|
api.close()
|
|
|
|
# Compile all data
|
|
router_data = {
|
|
'host': host,
|
|
'identity': identity,
|
|
'timestamp': datetime.now().isoformat(),
|
|
'subnets': subnets,
|
|
'interfaces': active_interfaces,
|
|
'vlans': vlans,
|
|
'pppoe_servers': pppoe_servers,
|
|
'routes': routes
|
|
}
|
|
|
|
print(f"\n\n=== Summary ===")
|
|
print(f"Router: {identity or host}")
|
|
print(f"Found {len(subnets)} IP addresses/subnets")
|
|
print(f"Found {len(active_interfaces)} active interfaces")
|
|
print(f"Found {len(vlans)} VLANs")
|
|
print(f"Found {len(pppoe_servers)} PPPoE servers")
|
|
print(f"Found {len(routes)} static routes")
|
|
|
|
return router_data
|
|
|
|
except Exception as e:
|
|
print(f"✗ Connection failed: {e}")
|
|
return None
|
|
|
|
|
|
def save_router_data(data, filename=None):
|
|
"""Save router data to a JSON file"""
|
|
if not filename:
|
|
# Generate filename based on router identity or IP
|
|
identity = data.get('identity') or data.get('host', 'router')
|
|
identity_clean = identity.replace(' ', '_').replace('/', '_').replace('.', '_')
|
|
filename = f"router_data_{identity_clean}_{datetime.now().strftime('%Y%m%d_%H%M%S')}.json"
|
|
|
|
with open(filename, 'w') as f:
|
|
json.dump(data, f, indent=2)
|
|
|
|
print(f"\nData saved to: {filename}")
|
|
return filename
|
|
|
|
|
|
def main():
|
|
parser = argparse.ArgumentParser(description='Retrieve configuration from a MikroTik router')
|
|
parser.add_argument('host', help='IP address or hostname of the router')
|
|
parser.add_argument('--username', '-u', default='grahamro', help='Router username (default: grahamro)')
|
|
parser.add_argument('--password', '-p', default='cFKhz8q5gPLoucMbcT1Iy58r3IXgc3', help='Router password')
|
|
parser.add_argument('--port', type=int, default=8729, help='API-SSL port (default: 8729)')
|
|
parser.add_argument('--output', '-o', help='Output filename (default: auto-generated)')
|
|
parser.add_argument('--json', action='store_true', help='Output raw JSON to stdout')
|
|
|
|
args = parser.parse_args()
|
|
|
|
# Get router data
|
|
data = get_router_data(args.host, args.username, args.password, args.port)
|
|
|
|
if data:
|
|
if args.json:
|
|
# Output JSON to stdout
|
|
print("\n=== JSON Output ===")
|
|
print(json.dumps(data, indent=2))
|
|
else:
|
|
# Save to file
|
|
save_router_data(data, args.output)
|
|
print("\n✓ Router data retrieved successfully")
|
|
else:
|
|
print("\n✗ Failed to retrieve router data")
|
|
return 1
|
|
|
|
return 0
|
|
|
|
|
|
if __name__ == "__main__":
|
|
sys.exit(main()) |