1e1e5957e8
- Ips.vue: el-select 添加 width: 280px,修复网段下拉框过窄 - Ips.vue: query 参数 networkId → network_id(与 FastAPI snake_case 一致) - Scan.vue: el-select 用 network.id 代替整个 network 对象作为 value,修复切换网段不生效 - enhanced_scan_service.py: 替换失效的 scapy ARP 扫描为 arp-scan 命令;扫描结果自动创建缺失 IP 记录
180 lines
5.9 KiB
Python
180 lines
5.9 KiB
Python
from fastapi import APIRouter, Depends, HTTPException, Request
|
|
from sqlalchemy.orm import Session
|
|
from typing import Optional
|
|
|
|
from app.core.database import get_db
|
|
from app.core.security import get_current_user
|
|
from app.models.auth import User
|
|
from app.schemas.network import (
|
|
NetworkCreate, NetworkUpdate, Network, NetworkListResponse,
|
|
NetworkStats, IPAddressListResponse, IPAddressUpdate, IPAddress
|
|
)
|
|
from app.services.network_service import NetworkService
|
|
from app.services.audit_service import AuditService, AuditAction
|
|
|
|
router = APIRouter(
|
|
prefix="/networks",
|
|
tags=["网段管理"],
|
|
dependencies=[Depends(get_current_user)],
|
|
)
|
|
|
|
|
|
def _client_info(request: Request) -> tuple[str, str]:
|
|
return (
|
|
request.client.host if request.client else "",
|
|
(request.headers.get("user-agent") or "")[:500],
|
|
)
|
|
|
|
|
|
@router.get("", response_model=NetworkListResponse, summary="获取网段列表")
|
|
def get_networks(
|
|
skip: int = 0,
|
|
limit: int = 100,
|
|
group_name: Optional[str] = None,
|
|
db: Session = Depends(get_db)
|
|
):
|
|
"""获取所有网段列表"""
|
|
total, items = NetworkService.get_list(db, skip=skip, limit=limit, group_name=group_name)
|
|
return {"total": total, "items": items}
|
|
|
|
|
|
@router.get("/stats", response_model=list[NetworkStats], summary="获取所有网段统计")
|
|
def get_all_network_stats(db: Session = Depends(get_db)):
|
|
"""获取所有网段的统计信息"""
|
|
return NetworkService.get_all_stats(db)
|
|
|
|
|
|
@router.get("/{network_id}", response_model=Network, summary="获取网段详情")
|
|
def get_network(network_id: int, db: Session = Depends(get_db)):
|
|
"""根据ID获取网段详情"""
|
|
network = NetworkService.get_by_id(db, network_id)
|
|
if not network:
|
|
raise HTTPException(status_code=404, detail="网段不存在")
|
|
return network
|
|
|
|
|
|
@router.get("/{network_id}/stats", response_model=NetworkStats, summary="获取网段统计")
|
|
def get_network_stats(network_id: int, db: Session = Depends(get_db)):
|
|
"""获取指定网段的统计信息"""
|
|
stats = NetworkService.get_stats(db, network_id)
|
|
if not stats:
|
|
raise HTTPException(status_code=404, detail="网段不存在")
|
|
return stats
|
|
|
|
|
|
@router.get("/{network_id}/ips", response_model=IPAddressListResponse, summary="获取网段下的IP列表")
|
|
def get_network_ips(
|
|
network_id: int,
|
|
skip: int = 0,
|
|
limit: int = 200,
|
|
db: Session = Depends(get_db)
|
|
):
|
|
"""获取指定网段下的所有IP地址"""
|
|
from app.services.ip_service import IPService
|
|
total, items = IPService.get_list(db, network_id=network_id, skip=skip, limit=limit)
|
|
return {"total": total, "items": items}
|
|
|
|
|
|
@router.post("", response_model=Network, status_code=201, summary="创建网段")
|
|
def create_network(
|
|
network_in: NetworkCreate,
|
|
request: Request,
|
|
db: Session = Depends(get_db),
|
|
current_user: User = Depends(get_current_user),
|
|
):
|
|
"""创建新网段,支持CIDR格式"""
|
|
existing = NetworkService.get_by_cidr(db, network_in.cidr)
|
|
if existing:
|
|
raise HTTPException(status_code=400, detail="该网段已存在")
|
|
|
|
ip, ua = _client_info(request)
|
|
try:
|
|
network = NetworkService.create(db, network_in)
|
|
except ValueError as e:
|
|
raise HTTPException(status_code=400, detail=str(e))
|
|
|
|
AuditService.record(
|
|
db,
|
|
action=AuditAction.NETWORK_CREATE,
|
|
user=current_user,
|
|
resource_type="network",
|
|
resource_id=network.id,
|
|
resource_name=network.cidr,
|
|
method="POST",
|
|
path=str(request.url.path),
|
|
ip_address=ip,
|
|
user_agent=ua,
|
|
detail={"cidr": network.cidr, "name": network.name},
|
|
)
|
|
return network
|
|
|
|
|
|
@router.put("/{network_id}", response_model=Network, summary="更新网段")
|
|
def update_network(
|
|
network_id: int,
|
|
network_in: NetworkUpdate,
|
|
request: Request,
|
|
db: Session = Depends(get_db),
|
|
current_user: User = Depends(get_current_user),
|
|
):
|
|
"""更新网段信息"""
|
|
old = NetworkService.get_by_id(db, network_id)
|
|
if not old:
|
|
raise HTTPException(status_code=404, detail="网段不存在")
|
|
|
|
network = NetworkService.update(db, network_id, network_in)
|
|
if not network:
|
|
raise HTTPException(status_code=404, detail="网段不存在")
|
|
|
|
ip, ua = _client_info(request)
|
|
AuditService.record(
|
|
db,
|
|
action=AuditAction.NETWORK_UPDATE,
|
|
user=current_user,
|
|
resource_type="network",
|
|
resource_id=network.id,
|
|
resource_name=network.cidr,
|
|
method="PUT",
|
|
path=str(request.url.path),
|
|
ip_address=ip,
|
|
user_agent=ua,
|
|
detail={
|
|
"before": {"name": old.name, "gateway": old.gateway, "group_name": old.group_name, "vlan_id": old.vlan_id, "description": old.description},
|
|
"after": {"name": network.name, "gateway": network.gateway, "group_name": network.group_name, "vlan_id": network.vlan_id, "description": network.description},
|
|
},
|
|
)
|
|
return network
|
|
|
|
|
|
@router.delete("/{network_id}", summary="删除网段")
|
|
def delete_network(
|
|
network_id: int,
|
|
request: Request,
|
|
db: Session = Depends(get_db),
|
|
current_user: User = Depends(get_current_user),
|
|
):
|
|
"""删除网段及其下的所有IP记录"""
|
|
network = NetworkService.get_by_id(db, network_id)
|
|
if not network:
|
|
raise HTTPException(status_code=404, detail="网段不存在")
|
|
cidr_snapshot = network.cidr
|
|
|
|
success = NetworkService.delete(db, network_id)
|
|
if not success:
|
|
raise HTTPException(status_code=404, detail="网段不存在")
|
|
|
|
ip, ua = _client_info(request)
|
|
AuditService.record(
|
|
db,
|
|
action=AuditAction.NETWORK_DELETE,
|
|
user=current_user,
|
|
resource_type="network",
|
|
resource_id=network_id,
|
|
resource_name=cidr_snapshot,
|
|
method="DELETE",
|
|
path=str(request.url.path),
|
|
ip_address=ip,
|
|
user_agent=ua,
|
|
detail={"cidr": cidr_snapshot},
|
|
)
|
|
return {"message": "删除成功"} |