mirror of
https://github.com/GNS3/gns3-server
synced 2024-11-24 09:18:08 +00:00
New feature: packet capture for IOU (not working, issue with iouyap).
This commit is contained in:
parent
33787d486a
commit
9bc0287540
@ -44,6 +44,8 @@ from .schemas import IOU_RELOAD_SCHEMA
|
|||||||
from .schemas import IOU_ALLOCATE_UDP_PORT_SCHEMA
|
from .schemas import IOU_ALLOCATE_UDP_PORT_SCHEMA
|
||||||
from .schemas import IOU_ADD_NIO_SCHEMA
|
from .schemas import IOU_ADD_NIO_SCHEMA
|
||||||
from .schemas import IOU_DELETE_NIO_SCHEMA
|
from .schemas import IOU_DELETE_NIO_SCHEMA
|
||||||
|
from .schemas import IOU_START_CAPTURE_SCHEMA
|
||||||
|
from .schemas import IOU_STOP_CAPTURE_SCHEMA
|
||||||
|
|
||||||
import logging
|
import logging
|
||||||
log = logging.getLogger(__name__)
|
log = logging.getLogger(__name__)
|
||||||
@ -669,6 +671,90 @@ class IOU(IModule):
|
|||||||
|
|
||||||
self.send_response(True)
|
self.send_response(True)
|
||||||
|
|
||||||
|
@IModule.route("iou.start_capture")
|
||||||
|
def start_capture(self, request):
|
||||||
|
"""
|
||||||
|
Starts a packet capture.
|
||||||
|
|
||||||
|
Mandatory request parameters:
|
||||||
|
- id (vm identifier)
|
||||||
|
- slot (slot number)
|
||||||
|
- port (port number)
|
||||||
|
- port_id (port identifier)
|
||||||
|
- 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, IOU_START_CAPTURE_SCHEMA):
|
||||||
|
return
|
||||||
|
|
||||||
|
# get the instance
|
||||||
|
iou_instance = self.get_iou_instance(request["id"])
|
||||||
|
if not iou_instance:
|
||||||
|
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(self._working_dir, "captures", capture_file_name)
|
||||||
|
iou_instance.start_capture(slot, port, capture_file_path, data_link_type)
|
||||||
|
except IOUError 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("iou.stop_capture")
|
||||||
|
def stop_capture(self, request):
|
||||||
|
"""
|
||||||
|
Stops a packet capture.
|
||||||
|
|
||||||
|
Mandatory request parameters:
|
||||||
|
- id (vm identifier)
|
||||||
|
- slot (slot number)
|
||||||
|
- port (port number)
|
||||||
|
- port_id (port identifier)
|
||||||
|
|
||||||
|
Response parameters:
|
||||||
|
- port_id (port identifier)
|
||||||
|
|
||||||
|
:param request: JSON request
|
||||||
|
"""
|
||||||
|
|
||||||
|
# validate the request
|
||||||
|
if not self.validate_request(request, IOU_STOP_CAPTURE_SCHEMA):
|
||||||
|
return
|
||||||
|
|
||||||
|
# get the instance
|
||||||
|
iou_instance = self.get_iou_instance(request["id"])
|
||||||
|
if not iou_instance:
|
||||||
|
return
|
||||||
|
|
||||||
|
slot = request["slot"]
|
||||||
|
port = request["port"]
|
||||||
|
try:
|
||||||
|
iou_instance.stop_capture(slot, port)
|
||||||
|
except IOUError as e:
|
||||||
|
self.send_custom_error(str(e))
|
||||||
|
return
|
||||||
|
|
||||||
|
response = {"port_id": request["port_id"]}
|
||||||
|
self.send_response(response)
|
||||||
|
|
||||||
@IModule.route("iou.echo")
|
@IModule.route("iou.echo")
|
||||||
def echo(self, request):
|
def echo(self, request):
|
||||||
"""
|
"""
|
||||||
|
@ -371,7 +371,7 @@ class IOUDevice(object):
|
|||||||
if self._id in self._instances:
|
if self._id in self._instances:
|
||||||
self._instances.remove(self._id)
|
self._instances.remove(self._id)
|
||||||
|
|
||||||
if self.console:
|
if self.console and self.console in self._allocated_console_ports:
|
||||||
self._allocated_console_ports.remove(self.console)
|
self._allocated_console_ports.remove(self.console)
|
||||||
|
|
||||||
log.info("IOU device {name} [id={id}] has been deleted".format(name=self._name,
|
log.info("IOU device {name} [id={id}] has been deleted".format(name=self._name,
|
||||||
@ -442,7 +442,24 @@ class IOUDevice(object):
|
|||||||
connection = {"eth_dev": "{ethernet_device}".format(ethernet_device=nio.ethernet_device)}
|
connection = {"eth_dev": "{ethernet_device}".format(ethernet_device=nio.ethernet_device)}
|
||||||
|
|
||||||
if connection:
|
if connection:
|
||||||
config["{iouyap_id}:{bay}/{unit}".format(iouyap_id=str(self._id + 512), bay=bay_id, unit=unit_id)] = connection
|
interface = "{iouyap_id}:{bay}/{unit}".format(iouyap_id=str(self._id + 512), bay=bay_id, unit=unit_id)
|
||||||
|
config[interface] = connection
|
||||||
|
|
||||||
|
if nio.capturing:
|
||||||
|
pcap_data_link_type = nio.pcap_data_link_type.upper()
|
||||||
|
if pcap_data_link_type == "DLT_PPP_SERIAL":
|
||||||
|
pcap_protocol = "ppp"
|
||||||
|
elif pcap_data_link_type == "DLT_C_HDLC":
|
||||||
|
pcap_protocol = "hdlc"
|
||||||
|
elif pcap_data_link_type == "DLT_FRELAY":
|
||||||
|
pcap_protocol = "fr"
|
||||||
|
else:
|
||||||
|
pcap_protocol = "ethernet"
|
||||||
|
capture_info = {"pcap_file": "{pcap_file}".format(pcap_file=nio.pcap_output_file),
|
||||||
|
"pcap_protocol": pcap_protocol,
|
||||||
|
"pcap_overwrite": "y"}
|
||||||
|
config[interface].update(capture_info)
|
||||||
|
|
||||||
unit_id += 1
|
unit_id += 1
|
||||||
bay_id += 1
|
bay_id += 1
|
||||||
|
|
||||||
@ -987,3 +1004,75 @@ class IOUDevice(object):
|
|||||||
adapters=len(self._serial_adapters)))
|
adapters=len(self._serial_adapters)))
|
||||||
|
|
||||||
self._slots = self._ethernet_adapters + self._serial_adapters
|
self._slots = self._ethernet_adapters + self._serial_adapters
|
||||||
|
|
||||||
|
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 port: allocated port
|
||||||
|
: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 IOUError("Slot {slot_id} doesn't exist on IOU {name}".format(name=self._name,
|
||||||
|
slot_id=slot_id))
|
||||||
|
|
||||||
|
if not adapter.port_exists(port_id):
|
||||||
|
raise IOUError("Port {port_id} doesn't exist in adapter {adapter}".format(adapter=adapter,
|
||||||
|
port_id=port_id))
|
||||||
|
|
||||||
|
nio = adapter.get_nio(port_id)
|
||||||
|
if nio.capturing:
|
||||||
|
raise IOUError("Packet capture is already activated on {slot_id}/{port_id}".format(slot_id=slot_id,
|
||||||
|
port_id=port_id))
|
||||||
|
|
||||||
|
try:
|
||||||
|
os.makedirs(os.path.dirname(output_file))
|
||||||
|
except FileExistsError:
|
||||||
|
pass
|
||||||
|
except OSError as e:
|
||||||
|
raise IOUError("Could not create captures directory {}".format(e))
|
||||||
|
|
||||||
|
nio.startPacketCapture(output_file, data_link_type)
|
||||||
|
|
||||||
|
log.info("IOU {name} [id={id}]: starting packet capture on {slot_id}/{port_id}".format(name=self._name,
|
||||||
|
id=self._id,
|
||||||
|
slot_id=slot_id,
|
||||||
|
port_id=port_id))
|
||||||
|
|
||||||
|
if self.is_iouyap_running():
|
||||||
|
self._update_iouyap_config()
|
||||||
|
os.kill(self._iouyap_process.pid, signal.SIGHUP)
|
||||||
|
|
||||||
|
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 IOUError("Slot {slot_id} doesn't exist on IOU {name}".format(name=self._name,
|
||||||
|
slot_id=slot_id))
|
||||||
|
|
||||||
|
if not adapter.port_exists(port_id):
|
||||||
|
raise IOUError("Port {port_id} doesn't exist in adapter {adapter}".format(adapter=adapter,
|
||||||
|
port_id=port_id))
|
||||||
|
|
||||||
|
nio = adapter.get_nio(port_id)
|
||||||
|
nio.stopPacketCapture()
|
||||||
|
log.info("IOU {name} [id={id}]: stopping packet capture on {slot_id}/{port_id}".format(name=self._name,
|
||||||
|
id=self._id,
|
||||||
|
slot_id=slot_id,
|
||||||
|
port_id=port_id))
|
||||||
|
if self.is_iouyap_running():
|
||||||
|
self._update_iouyap_config()
|
||||||
|
os.kill(self._iouyap_process.pid, signal.SIGHUP)
|
||||||
|
79
gns3server/modules/iou/nios/nio.py
Normal file
79
gns3server/modules/iou/nios/nio.py
Normal file
@ -0,0 +1,79 @@
|
|||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
#
|
||||||
|
# Copyright (C) 2013 GNS3 Technologies Inc.
|
||||||
|
#
|
||||||
|
# This program is free software: you can redistribute it and/or modify
|
||||||
|
# it under the terms of the GNU General Public License as published by
|
||||||
|
# the Free Software Foundation, either version 3 of the License, or
|
||||||
|
# (at your option) any later version.
|
||||||
|
#
|
||||||
|
# This program is distributed in the hope that it will be useful,
|
||||||
|
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
# GNU General Public License for more details.
|
||||||
|
#
|
||||||
|
# You should have received a copy of the GNU General Public License
|
||||||
|
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
"""
|
||||||
|
Base interface for NIOs.
|
||||||
|
"""
|
||||||
|
|
||||||
|
|
||||||
|
class NIO(object):
|
||||||
|
"""
|
||||||
|
IOU NIO.
|
||||||
|
"""
|
||||||
|
|
||||||
|
def __init__(self):
|
||||||
|
|
||||||
|
self._capturing = False
|
||||||
|
self._pcap_output_file = ""
|
||||||
|
self._pcap_data_link_type = ""
|
||||||
|
|
||||||
|
def startPacketCapture(self, pcap_output_file, pcap_data_link_type="DLT_EN10MB"):
|
||||||
|
"""
|
||||||
|
|
||||||
|
:param pcap_output_file: PCAP destination file for the capture
|
||||||
|
:param pcap_data_link_type: PCAP data link type (DLT_*), default is DLT_EN10MB
|
||||||
|
"""
|
||||||
|
|
||||||
|
self._capturing = True
|
||||||
|
self._pcap_output_file = pcap_output_file
|
||||||
|
self._pcap_data_link_type = pcap_data_link_type
|
||||||
|
|
||||||
|
def stopPacketCapture(self):
|
||||||
|
|
||||||
|
self._capturing = False
|
||||||
|
self._pcap_output_file = ""
|
||||||
|
self._pcap_data_link_type = ""
|
||||||
|
|
||||||
|
@property
|
||||||
|
def capturing(self):
|
||||||
|
"""
|
||||||
|
Returns either a capture is configured on this NIO.
|
||||||
|
|
||||||
|
:returns: boolean
|
||||||
|
"""
|
||||||
|
|
||||||
|
return self._capturing
|
||||||
|
|
||||||
|
@property
|
||||||
|
def pcap_output_file(self):
|
||||||
|
"""
|
||||||
|
Returns the path to the PCAP output file.
|
||||||
|
|
||||||
|
:returns: path to the PCAP output file
|
||||||
|
"""
|
||||||
|
|
||||||
|
return self._pcap_output_file
|
||||||
|
|
||||||
|
@property
|
||||||
|
def pcap_data_link_type(self):
|
||||||
|
"""
|
||||||
|
Returns the PCAP data link type
|
||||||
|
|
||||||
|
:returns: PCAP data link type (DLT_* value)
|
||||||
|
"""
|
||||||
|
|
||||||
|
return self._pcap_data_link_type
|
@ -19,8 +19,10 @@
|
|||||||
Interface for generic Ethernet NIOs (PCAP library).
|
Interface for generic Ethernet NIOs (PCAP library).
|
||||||
"""
|
"""
|
||||||
|
|
||||||
|
from .nio import NIO
|
||||||
|
|
||||||
class NIO_GenericEthernet(object):
|
|
||||||
|
class NIO_GenericEthernet(NIO):
|
||||||
"""
|
"""
|
||||||
NIO generic Ethernet NIO.
|
NIO generic Ethernet NIO.
|
||||||
|
|
||||||
@ -29,6 +31,7 @@ class NIO_GenericEthernet(object):
|
|||||||
|
|
||||||
def __init__(self, ethernet_device):
|
def __init__(self, ethernet_device):
|
||||||
|
|
||||||
|
NIO.__init__(self)
|
||||||
self._ethernet_device = ethernet_device
|
self._ethernet_device = ethernet_device
|
||||||
|
|
||||||
@property
|
@property
|
||||||
|
@ -19,8 +19,10 @@
|
|||||||
Interface for TAP NIOs (UNIX based OSes only).
|
Interface for TAP NIOs (UNIX based OSes only).
|
||||||
"""
|
"""
|
||||||
|
|
||||||
|
from .nio import NIO
|
||||||
|
|
||||||
class NIO_TAP(object):
|
|
||||||
|
class NIO_TAP(NIO):
|
||||||
"""
|
"""
|
||||||
IOU TAP NIO.
|
IOU TAP NIO.
|
||||||
|
|
||||||
@ -29,6 +31,7 @@ class NIO_TAP(object):
|
|||||||
|
|
||||||
def __init__(self, tap_device):
|
def __init__(self, tap_device):
|
||||||
|
|
||||||
|
NIO.__init__(self)
|
||||||
self._tap_device = tap_device
|
self._tap_device = tap_device
|
||||||
|
|
||||||
@property
|
@property
|
||||||
|
@ -19,8 +19,10 @@
|
|||||||
Interface for UDP NIOs.
|
Interface for UDP NIOs.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
|
from .nio import NIO
|
||||||
|
|
||||||
class NIO_UDP(object):
|
|
||||||
|
class NIO_UDP(NIO):
|
||||||
"""
|
"""
|
||||||
IOU UDP NIO.
|
IOU UDP NIO.
|
||||||
|
|
||||||
@ -33,6 +35,7 @@ class NIO_UDP(object):
|
|||||||
|
|
||||||
def __init__(self, lport, rhost, rport):
|
def __init__(self, lport, rhost, rport):
|
||||||
|
|
||||||
|
NIO.__init__(self)
|
||||||
self._lport = lport
|
self._lport = lport
|
||||||
self._rhost = rhost
|
self._rhost = rhost
|
||||||
self._rport = rport
|
self._rport = rport
|
||||||
|
@ -382,3 +382,73 @@ IOU_DELETE_NIO_SCHEMA = {
|
|||||||
"additionalProperties": False,
|
"additionalProperties": False,
|
||||||
"required": ["id", "slot", "port"]
|
"required": ["id", "slot", "port"]
|
||||||
}
|
}
|
||||||
|
|
||||||
|
IOU_START_CAPTURE_SCHEMA = {
|
||||||
|
"$schema": "http://json-schema.org/draft-04/schema#",
|
||||||
|
"description": "Request validation to start a packet capture on an IOU instance port",
|
||||||
|
"type": "object",
|
||||||
|
"properties": {
|
||||||
|
"id": {
|
||||||
|
"description": "IOU device instance ID",
|
||||||
|
"type": "integer"
|
||||||
|
},
|
||||||
|
"slot": {
|
||||||
|
"description": "Slot number",
|
||||||
|
"type": "integer",
|
||||||
|
"minimum": 0,
|
||||||
|
"maximum": 15
|
||||||
|
},
|
||||||
|
"port": {
|
||||||
|
"description": "Port number",
|
||||||
|
"type": "integer",
|
||||||
|
"minimum": 0,
|
||||||
|
"maximum": 3
|
||||||
|
},
|
||||||
|
"port_id": {
|
||||||
|
"description": "Unique port identifier for the IOU instance",
|
||||||
|
"type": "integer"
|
||||||
|
},
|
||||||
|
"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", "slot", "port", "port_id", "capture_file_name"]
|
||||||
|
}
|
||||||
|
|
||||||
|
IOU_STOP_CAPTURE_SCHEMA = {
|
||||||
|
"$schema": "http://json-schema.org/draft-04/schema#",
|
||||||
|
"description": "Request validation to stop a packet capture on an IOU instance port",
|
||||||
|
"type": "object",
|
||||||
|
"properties": {
|
||||||
|
"id": {
|
||||||
|
"description": "IOU device instance ID",
|
||||||
|
"type": "integer"
|
||||||
|
},
|
||||||
|
"slot": {
|
||||||
|
"description": "Slot number",
|
||||||
|
"type": "integer",
|
||||||
|
"minimum": 0,
|
||||||
|
"maximum": 15
|
||||||
|
},
|
||||||
|
"port": {
|
||||||
|
"description": "Port number",
|
||||||
|
"type": "integer",
|
||||||
|
"minimum": 0,
|
||||||
|
"maximum": 3
|
||||||
|
},
|
||||||
|
"port_id": {
|
||||||
|
"description": "Unique port identifier for the IOU instance",
|
||||||
|
"type": "integer"
|
||||||
|
},
|
||||||
|
},
|
||||||
|
"additionalProperties": False,
|
||||||
|
"required": ["id", "slot", "port", "port_id"]
|
||||||
|
}
|
||||||
|
@ -304,7 +304,7 @@ class VPCSDevice(object):
|
|||||||
if self._id in self._instances:
|
if self._id in self._instances:
|
||||||
self._instances.remove(self._id)
|
self._instances.remove(self._id)
|
||||||
|
|
||||||
if self.console:
|
if self.console and self.console in self._allocated_console_ports:
|
||||||
self._allocated_console_ports.remove(self.console)
|
self._allocated_console_ports.remove(self.console)
|
||||||
|
|
||||||
log.info("VPCS device {name} [id={id}] has been deleted".format(name=self._name,
|
log.info("VPCS device {name} [id={id}] has been deleted".format(name=self._name,
|
||||||
|
Loading…
Reference in New Issue
Block a user