mirror of
https://github.com/GNS3/gns3-server.git
synced 2024-12-21 13:47:50 +00:00
New feature: packet capture for IOS routers.
This commit is contained in:
parent
14bb12d3fb
commit
606f773f3d
@ -56,6 +56,8 @@ from ..schemas.vm import VM_STOP_SCHEMA
|
|||||||
from ..schemas.vm import VM_SUSPEND_SCHEMA
|
from ..schemas.vm import VM_SUSPEND_SCHEMA
|
||||||
from ..schemas.vm import VM_RELOAD_SCHEMA
|
from ..schemas.vm import VM_RELOAD_SCHEMA
|
||||||
from ..schemas.vm import VM_UPDATE_SCHEMA
|
from ..schemas.vm import VM_UPDATE_SCHEMA
|
||||||
|
from ..schemas.vm import VM_START_CAPTURE_SCHEMA
|
||||||
|
from ..schemas.vm import VM_STOP_CAPTURE_SCHEMA
|
||||||
from ..schemas.vm import VM_SAVE_CONFIG_SCHEMA
|
from ..schemas.vm import VM_SAVE_CONFIG_SCHEMA
|
||||||
from ..schemas.vm import VM_IDLEPCS_SCHEMA
|
from ..schemas.vm import VM_IDLEPCS_SCHEMA
|
||||||
from ..schemas.vm import VM_ALLOCATE_UDP_PORT_SCHEMA
|
from ..schemas.vm import VM_ALLOCATE_UDP_PORT_SCHEMA
|
||||||
@ -484,6 +486,90 @@ class VM(object):
|
|||||||
|
|
||||||
self.send_response(response)
|
self.send_response(response)
|
||||||
|
|
||||||
|
@IModule.route("dynamips.vm.start_capture")
|
||||||
|
def vm_start_capture(self, request):
|
||||||
|
"""
|
||||||
|
Starts a packet capture.
|
||||||
|
|
||||||
|
Mandatory request parameters:
|
||||||
|
- id (vm identifier)
|
||||||
|
- port_id (port identifier)
|
||||||
|
- slot (slot number)
|
||||||
|
- port (port number)
|
||||||
|
- capture_file_name
|
||||||
|
|
||||||
|
Optional request parameters:
|
||||||
|
- data_link_type (PCAP DLT_* value)
|
||||||
|
|
||||||
|
Response parameters:
|
||||||
|
- port_id (port identifier)
|
||||||
|
- capture_file_path (path to the capture file)
|
||||||
|
|
||||||
|
:param request: JSON request
|
||||||
|
"""
|
||||||
|
|
||||||
|
# validate the request
|
||||||
|
if not self.validate_request(request, VM_START_CAPTURE_SCHEMA):
|
||||||
|
return
|
||||||
|
|
||||||
|
# get the router instance
|
||||||
|
router = self.get_device_instance(request["id"], self._routers)
|
||||||
|
if not router:
|
||||||
|
return
|
||||||
|
|
||||||
|
slot = request["slot"]
|
||||||
|
port = request["port"]
|
||||||
|
capture_file_name = request["capture_file_name"]
|
||||||
|
data_link_type = request.get("data_link_type")
|
||||||
|
|
||||||
|
try:
|
||||||
|
capture_file_path = os.path.join(router.hypervisor.working_dir, "captures", capture_file_name)
|
||||||
|
router.start_capture(slot, port, capture_file_path, data_link_type)
|
||||||
|
except DynamipsError as e:
|
||||||
|
self.send_custom_error(str(e))
|
||||||
|
return
|
||||||
|
|
||||||
|
response = {"port_id": request["port_id"],
|
||||||
|
"capture_file_path": capture_file_path}
|
||||||
|
self.send_response(response)
|
||||||
|
|
||||||
|
@IModule.route("dynamips.vm.stop_capture")
|
||||||
|
def vm_stop_capture(self, request):
|
||||||
|
"""
|
||||||
|
Stops a packet capture.
|
||||||
|
|
||||||
|
Mandatory request parameters:
|
||||||
|
- id (vm identifier)
|
||||||
|
- port_id (port identifier)
|
||||||
|
- slot (slot number)
|
||||||
|
- port (port number)
|
||||||
|
|
||||||
|
Response parameters:
|
||||||
|
- port_id (port identifier)
|
||||||
|
|
||||||
|
:param request: JSON request
|
||||||
|
"""
|
||||||
|
|
||||||
|
# validate the request
|
||||||
|
if not self.validate_request(request, VM_STOP_CAPTURE_SCHEMA):
|
||||||
|
return
|
||||||
|
|
||||||
|
# get the router instance
|
||||||
|
router = self.get_device_instance(request["id"], self._routers)
|
||||||
|
if not router:
|
||||||
|
return
|
||||||
|
|
||||||
|
slot = request["slot"]
|
||||||
|
port = request["port"]
|
||||||
|
try:
|
||||||
|
router.stop_capture(slot, port)
|
||||||
|
except DynamipsError as e:
|
||||||
|
self.send_custom_error(str(e))
|
||||||
|
return
|
||||||
|
|
||||||
|
response = {"port_id": request["port_id"]}
|
||||||
|
self.send_response(response)
|
||||||
|
|
||||||
@IModule.route("dynamips.vm.save_config")
|
@IModule.route("dynamips.vm.save_config")
|
||||||
def vm_save_config(self, request):
|
def vm_save_config(self, request):
|
||||||
"""
|
"""
|
||||||
|
@ -57,6 +57,8 @@ class NIO(object):
|
|||||||
Deletes this NIO.
|
Deletes this NIO.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
|
if self._input_filter or self._output_filter:
|
||||||
|
self.unbind_filter("both")
|
||||||
self._hypervisor.send("nio delete {}".format(self._name))
|
self._hypervisor.send("nio delete {}".format(self._name))
|
||||||
log.info("NIO {name} has been deleted".format(name=self._name))
|
log.info("NIO {name} has been deleted".format(name=self._name))
|
||||||
|
|
||||||
@ -134,7 +136,7 @@ class NIO(object):
|
|||||||
|
|
||||||
def setup_filter(self, direction, options):
|
def setup_filter(self, direction, options):
|
||||||
"""
|
"""
|
||||||
Setups a packet filter binded with this NIO.
|
Setups a packet filter bound with this NIO.
|
||||||
|
|
||||||
Filter "freq_drop" has 1 argument "<frequency>". It will drop
|
Filter "freq_drop" has 1 argument "<frequency>". It will drop
|
||||||
everything with a -1 frequency, drop every Nth packet with a
|
everything with a -1 frequency, drop every Nth packet with a
|
||||||
|
@ -1539,6 +1539,71 @@ class Router(object):
|
|||||||
slot_id=slot_id,
|
slot_id=slot_id,
|
||||||
port_id=port_id))
|
port_id=port_id))
|
||||||
|
|
||||||
|
def start_capture(self, slot_id, port_id, output_file, data_link_type="DLT_EN10MB"):
|
||||||
|
"""
|
||||||
|
Starts a packet capture.
|
||||||
|
|
||||||
|
:param slot_id: slot ID
|
||||||
|
:param port_id: port ID
|
||||||
|
:param output_file: PCAP destination file for the capture
|
||||||
|
:param data_link_type: PCAP data link type (DLT_*), default is DLT_EN10MB
|
||||||
|
"""
|
||||||
|
|
||||||
|
try:
|
||||||
|
adapter = self._slots[slot_id]
|
||||||
|
except IndexError:
|
||||||
|
raise DynamipsError("Slot {slot_id} doesn't exist on router {name}".format(name=self._name,
|
||||||
|
slot_id=slot_id))
|
||||||
|
if not adapter.port_exists(port_id):
|
||||||
|
raise DynamipsError("Port {port_id} doesn't exist in adapter {adapter}".format(adapter=adapter,
|
||||||
|
port_id=port_id))
|
||||||
|
|
||||||
|
data_link_type = data_link_type.lower()
|
||||||
|
if data_link_type.startswith("dlt_"):
|
||||||
|
data_link_type = data_link_type[4:]
|
||||||
|
|
||||||
|
nio = adapter.get_nio(port_id)
|
||||||
|
|
||||||
|
if nio.input_filter[0] is not None and nio.output_filter[0] is not None:
|
||||||
|
raise DynamipsError("Port {port_id} has already a filter applied on {adapter}".format(adapter=adapter,
|
||||||
|
port_id=port_id))
|
||||||
|
|
||||||
|
try:
|
||||||
|
os.makedirs(os.path.dirname(output_file))
|
||||||
|
except FileExistsError:
|
||||||
|
pass
|
||||||
|
except OSError as e:
|
||||||
|
raise DynamipsError("Could not create captures directory {}".format(e))
|
||||||
|
|
||||||
|
nio.bind_filter("both", "capture")
|
||||||
|
nio.setup_filter("both", "{} {}".format(data_link_type, output_file))
|
||||||
|
|
||||||
|
log.info("router {name} [id={id}]: capturing on port {slot_id}/{port_id}".format(name=self._name,
|
||||||
|
id=self._id,
|
||||||
|
nio_name=nio.name,
|
||||||
|
slot_id=slot_id,
|
||||||
|
port_id=port_id))
|
||||||
|
|
||||||
|
def stop_capture(self, slot_id, port_id):
|
||||||
|
"""
|
||||||
|
Stops a packet capture.
|
||||||
|
|
||||||
|
:param slot_id: slot ID
|
||||||
|
:param port_id: port ID
|
||||||
|
"""
|
||||||
|
|
||||||
|
try:
|
||||||
|
adapter = self._slots[slot_id]
|
||||||
|
except IndexError:
|
||||||
|
raise DynamipsError("Slot {slot_id} doesn't exist on router {name}".format(name=self._name,
|
||||||
|
slot_id=slot_id))
|
||||||
|
if not adapter.port_exists(port_id):
|
||||||
|
raise DynamipsError("Port {port_id} doesn't exist in adapter {adapter}".format(adapter=adapter,
|
||||||
|
port_id=port_id))
|
||||||
|
|
||||||
|
nio = adapter.get_nio(port_id)
|
||||||
|
nio.unbind_filter("both")
|
||||||
|
|
||||||
def _create_slots(self, numslots):
|
def _create_slots(self, numslots):
|
||||||
"""
|
"""
|
||||||
Creates the appropriate number of slots for this router.
|
Creates the appropriate number of slots for this router.
|
||||||
|
@ -372,6 +372,76 @@ VM_UPDATE_SCHEMA = {
|
|||||||
"required": ["id"]
|
"required": ["id"]
|
||||||
}
|
}
|
||||||
|
|
||||||
|
VM_START_CAPTURE_SCHEMA = {
|
||||||
|
"$schema": "http://json-schema.org/draft-04/schema#",
|
||||||
|
"description": "Request validation to start a packet capture on a VM instance port",
|
||||||
|
"type": "object",
|
||||||
|
"properties": {
|
||||||
|
"id": {
|
||||||
|
"description": "VM instance ID",
|
||||||
|
"type": "integer"
|
||||||
|
},
|
||||||
|
"port_id": {
|
||||||
|
"description": "Unique port identifier for the VM instance",
|
||||||
|
"type": "integer"
|
||||||
|
},
|
||||||
|
"slot": {
|
||||||
|
"description": "Slot number",
|
||||||
|
"type": "integer",
|
||||||
|
"minimum": 0,
|
||||||
|
"maximum": 6
|
||||||
|
},
|
||||||
|
"port": {
|
||||||
|
"description": "Port number",
|
||||||
|
"type": "integer",
|
||||||
|
"minimum": 0,
|
||||||
|
"maximum": 49 # maximum is 16 for regular port numbers, WICs port numbers start at 16, 32 or 48
|
||||||
|
},
|
||||||
|
"capture_file_name": {
|
||||||
|
"description": "Capture file name",
|
||||||
|
"type": "string",
|
||||||
|
"minLength": 1,
|
||||||
|
},
|
||||||
|
"data_link_type": {
|
||||||
|
"description": "PCAP data link type",
|
||||||
|
"type": "string",
|
||||||
|
"minLength": 1,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
"additionalProperties": False,
|
||||||
|
"required": ["id", "port_id", "slot", "port", "capture_file_name"]
|
||||||
|
}
|
||||||
|
|
||||||
|
VM_STOP_CAPTURE_SCHEMA = {
|
||||||
|
"$schema": "http://json-schema.org/draft-04/schema#",
|
||||||
|
"description": "Request validation to stop a packet capture on a VM instance port",
|
||||||
|
"type": "object",
|
||||||
|
"properties": {
|
||||||
|
"id": {
|
||||||
|
"description": "VM instance ID",
|
||||||
|
"type": "integer"
|
||||||
|
},
|
||||||
|
"port_id": {
|
||||||
|
"description": "Unique port identifier for the VM instance",
|
||||||
|
"type": "integer"
|
||||||
|
},
|
||||||
|
"slot": {
|
||||||
|
"description": "Slot number",
|
||||||
|
"type": "integer",
|
||||||
|
"minimum": 0,
|
||||||
|
"maximum": 6
|
||||||
|
},
|
||||||
|
"port": {
|
||||||
|
"description": "Port number",
|
||||||
|
"type": "integer",
|
||||||
|
"minimum": 0,
|
||||||
|
"maximum": 49 # maximum is 16 for regular port numbers, WICs port numbers start at 16, 32 or 48
|
||||||
|
},
|
||||||
|
},
|
||||||
|
"additionalProperties": False,
|
||||||
|
"required": ["id", "port_id", "slot", "port"]
|
||||||
|
}
|
||||||
|
|
||||||
VM_SAVE_CONFIG_SCHEMA = {
|
VM_SAVE_CONFIG_SCHEMA = {
|
||||||
"$schema": "http://json-schema.org/draft-04/schema#",
|
"$schema": "http://json-schema.org/draft-04/schema#",
|
||||||
"description": "Request validation to save the configs for VM instance",
|
"description": "Request validation to save the configs for VM instance",
|
||||||
|
@ -23,5 +23,5 @@
|
|||||||
# or negative for a release candidate or beta (after the base version
|
# or negative for a release candidate or beta (after the base version
|
||||||
# number has been incremented)
|
# number has been incremented)
|
||||||
|
|
||||||
__version__ = "1.0a7.dev2"
|
__version__ = "1.0a7.dev3"
|
||||||
__version_info__ = (1, 0, 0, -99)
|
__version_info__ = (1, 0, 0, -99)
|
||||||
|
Loading…
Reference in New Issue
Block a user