from flask import Blueprint, render_template, redirect, url_for, request, flash, jsonify from flask_login import login_required from app.core.models import Subnet, Server from app.core.extensions import db from app.scripts.ip_scanner import scan import ipaddress from datetime import datetime bp = Blueprint('ipam', __name__, url_prefix='/ipam') @bp.route('/') @login_required def ipam_home(): """Main IPAM dashboard""" subnets = Subnet.query.all() # Calculate usage for each subnet for subnet in subnets: subnet.usage_percent = subnet.used_ips / 254 * 100 if subnet.cidr.endswith('/24') else 0 return render_template( 'ipam/index.html', title='IPAM Dashboard', subnets=subnets, now=datetime.now() ) @bp.route('/subnet/new', methods=['GET', 'POST']) @login_required def subnet_new(): """Create a new subnet""" if request.method == 'POST': cidr = request.form.get('cidr') location = request.form.get('location') auto_scan = 'auto_scan' in request.form # Basic validation if not cidr or not location: flash('Please fill in all required fields', 'danger') return render_template( 'ipam/subnet_form.html', title='New Subnet', now=datetime.now() ) # Check if valid CIDR try: ipaddress.ip_network(cidr) except ValueError: flash('Invalid CIDR notation', 'danger') return render_template( 'ipam/subnet_form.html', title='New Subnet', now=datetime.now() ) # Check if subnet already exists if Subnet.query.filter_by(cidr=cidr).first(): flash('Subnet already exists', 'danger') return render_template( 'ipam/subnet_form.html', title='New Subnet', now=datetime.now() ) subnet = Subnet( cidr=cidr, location=location, auto_scan=auto_scan ) db.session.add(subnet) db.session.commit() flash('Subnet created successfully', 'success') return redirect(url_for('ipam.subnet_view', subnet_id=subnet.id)) return render_template( 'ipam/subnet_form.html', title='New Subnet', now=datetime.now() ) @bp.route('/subnet/') @login_required def subnet_view(subnet_id): """View subnet details""" subnet = Subnet.query.get_or_404(subnet_id) servers = Server.query.filter_by(subnet_id=subnet_id).all() # Get network info network = ipaddress.ip_network(subnet.cidr) total_ips = network.num_addresses - 2 # Excluding network and broadcast addresses used_ips = len(servers) usage_percent = (used_ips / total_ips) * 100 if total_ips > 0 else 0 return render_template( 'ipam/subnet_view.html', title=f'Subnet - {subnet.cidr}', subnet=subnet, servers=servers, total_ips=total_ips, used_ips=used_ips, usage_percent=usage_percent, now=datetime.now() ) @bp.route('/subnet//scan') @login_required def subnet_scan(subnet_id): """Scan a subnet for active hosts""" subnet = Subnet.query.get_or_404(subnet_id) try: results = scan(subnet.cidr, save_results=True) flash(f'Scan completed for subnet {subnet.cidr}. Found {len(results)} active hosts.', 'success') except Exception as e: flash(f'Error scanning subnet: {e}', 'danger') return redirect(url_for('ipam.subnet_view', subnet_id=subnet_id)) @bp.route('/subnet//visualize') @login_required def subnet_visualize(subnet_id): """Visualize IP usage in a subnet""" subnet = Subnet.query.get_or_404(subnet_id) servers = Server.query.filter_by(subnet_id=subnet_id).all() # Create a dictionary of used IPs used_ips = {server.ip_address: server.hostname for server in servers} # Get network info network = ipaddress.ip_network(subnet.cidr) total_ips = network.num_addresses - 2 # Excluding network and broadcast addresses used_ip_count = len(servers) return render_template( 'ipam/subnet_visualization.html', title=f'Subnet Visualization - {subnet.cidr}', subnet=subnet, network=network, used_ips=used_ips, total_ips=total_ips, used_ip_count=used_ip_count, now=datetime.now() )