def find_unused_port(start_port, end_port, host="127.0.0.1", socket_type="TCP", ignore_ports=[]): """ Finds an unused port in a range. :param start_port: first port in the range :param end_port: last port in the range :param host: host/address for bind() :param socket_type: TCP (default) or UDP :param ignore_ports: list of port to ignore within the range """ if end_port < start_port: raise HTTPConflict( text="Invalid port range {}-{}".format(start_port, end_port)) if socket_type == "UDP": socket_type = socket.SOCK_DGRAM else: socket_type = socket.SOCK_STREAM last_exception = None for port in range(start_port, end_port + 1): if port in ignore_ports: continue try: if ":" in host: # IPv6 address support with socket.socket(socket.AF_INET6, socket_type) as s: s.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) s.bind( (host, port )) # the port is available if bind is a success else: with socket.socket(socket.AF_INET, socket_type) as s: s.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) s.bind( (host, port )) # the port is available if bind is a success return port except OSError as e: last_exception = e if port + 1 == end_port: break else: continue raise HTTPConflict( text= "Could not find a free port between {} and {} on host {}, last exception: {}" .format(start_port, end_port, host, last_exception))
def statistics(request, response): try: memory_total = psutil.virtual_memory().total memory_free = psutil.virtual_memory().available memory_used = memory_total - memory_free # actual memory usage in a cross platform fashion swap_total = psutil.swap_memory().total swap_free = psutil.swap_memory().free swap_used = psutil.swap_memory().used cpu_percent = int(CpuPercent.get()) load_average_percent = [ int(x / psutil.cpu_count() * 100) for x in psutil.getloadavg() ] memory_percent = int(psutil.virtual_memory().percent) swap_percent = int(psutil.swap_memory().percent) disk_usage_percent = int(psutil.disk_usage('/').percent) except psutil.Error as e: raise HTTPConflict(text="Psutil error detected: {}".format(e)) response.json({ "memory_total": memory_total, "memory_free": memory_free, "memory_used": memory_used, "swap_total": swap_total, "swap_free": swap_free, "swap_used": swap_used, "cpu_usage_percent": cpu_percent, "memory_usage_percent": memory_percent, "swap_usage_percent": swap_percent, "disk_usage_percent": disk_usage_percent, "load_average_percent": load_average_percent })
async def users_post(request: Request) -> Response: session_maker = request.app['db_session_manager'] session: Session = session_maker() try: data = await request.json() if data: user = session.query(Users).filter_by(login=data['login']).first() if user: return HTTPConflict() user = UsersSchema().load(data, session=session) session.add(user) session.commit() return HTTPCreated(headers={ 'Location': f"/users/{user.login}", 'Content-Type': 'application/json' }, body=json.dumps({'id': user.id})) else: return HTTPBadRequest() except Exception: session.rollback() raise finally: session.close()
def reserve_udp_port(self, port, project): """ Reserve a specific UDP port number :param port: UDP port number :param project: Project instance """ if port in self._used_udp_ports: raise HTTPConflict( text="UDP port {} already in use on host {}".format( port, self._console_host)) if port < self._udp_port_range[0] or port > self._udp_port_range[1]: raise HTTPConflict( text="UDP port {} is outside the range {}-{}".format( port, self._udp_port_range[0], self._udp_port_range[1])) self._used_udp_ports.add(port) project.record_udp_port(port) log.debug("UDP port {} has been reserved".format(port))
def create_nio(request, response): docker_manager = Docker.instance() container = docker_manager.get_node(request.match_info["node_id"], project_id=request.match_info["project_id"]) nio_type = request.json["type"] if nio_type != "nio_udp": raise HTTPConflict(text="NIO of type {} is not supported".format(nio_type)) nio = docker_manager.create_nio(request.json) yield from container.adapter_add_nio_binding(int(request.match_info["adapter_number"]), nio) response.set_status(201) response.json(nio)
async def start(request, response): vmware_manager = VMware.instance() vm = vmware_manager.get_node(request.match_info["node_id"], project_id=request.match_info["project_id"]) if vm.check_hw_virtualization(): pm = ProjectManager.instance() if pm.check_hardware_virtualization(vm) is False: raise HTTPConflict(text="Cannot start VM because hardware virtualization (VT-x/AMD-V) is already used by another software like VirtualBox or KVM (on Linux)") await vm.start() response.set_status(204)
def start(request, response): vbox_manager = VirtualBox.instance() vm = vbox_manager.get_vm(request.match_info["vm_id"], project_id=request.match_info["project_id"]) if (yield from vm.check_hw_virtualization()): pm = ProjectManager.instance() if pm.check_hardware_virtualization(vm) is False: raise HTTPConflict(text="Cannot start VM because hardware virtualization (VT-x/AMD-V) is already used by another software like VMware or KVM (on Linux)") yield from vm.start() response.set_status(204)
def create_nio(request, response): vmware_manager = VMware.instance() vm = vmware_manager.get_vm(request.match_info["vm_id"], project_id=request.match_info["project_id"]) nio_type = request.json["type"] if nio_type != "nio_udp": raise HTTPConflict(text="NIO of type {} is not supported".format(nio_type)) nio = vmware_manager.create_nio(None, request.json) yield from vm.adapter_add_nio_binding(int(request.match_info["adapter_number"]), nio) response.set_status(201) response.json(nio)
def create_nio(request, response): iou_manager = IOU.instance() vm = iou_manager.get_vm(request.match_info["vm_id"], project_id=request.match_info["project_id"]) nio_type = request.json["type"] if nio_type not in ("nio_udp", "nio_tap", "nio_generic_ethernet"): raise HTTPConflict(text="NIO of type {} is not supported".format(nio_type)) nio = iou_manager.create_nio(vm.iouyap_path, request.json) vm.adapter_add_nio_binding(int(request.match_info["adapter_number"]), int(request.match_info["port_number"]), nio) response.set_status(201) response.json(nio)
def start(request, response): qemu_manager = Qemu.instance() vm = qemu_manager.get_vm(request.match_info["vm_id"], project_id=request.match_info["project_id"]) if sys.platform.startswith("linux") and qemu_manager.config.get_section_config("Qemu").getboolean("enable_kvm", True) \ and "-no-kvm" not in vm.options: pm = ProjectManager.instance() if pm.check_hardware_virtualization(vm) is False: raise HTTPConflict(text="Cannot start VM with KVM enabled because hardware virtualization (VT-x/AMD-V) is already used by another software like VMware or VirtualBox") yield from vm.start() response.json(vm)
async def create_nio(request, response): vmware_manager = VMware.instance() vm = vmware_manager.get_node(request.match_info["node_id"], project_id=request.match_info["project_id"]) nio_type = request.json["type"] if nio_type not in ("nio_udp", "nio_vmnet", "nio_nat", "nio_tap"): raise HTTPConflict(text="NIO of type {} is not supported".format(nio_type)) nio = vmware_manager.create_nio(request.json) await vm.adapter_add_nio_binding(int(request.match_info["adapter_number"]), nio) response.set_status(201) response.json(nio)
def create_nio(request, response): qemu_manager = Qemu.instance() vm = qemu_manager.get_vm(request.match_info["vm_id"], project_id=request.match_info["project_id"]) nio_type = request.json["type"] if nio_type not in ("nio_udp", "nio_tap", "nio_nat"): raise HTTPConflict(text="NIO of type {} is not supported".format(nio_type)) nio = qemu_manager.create_nio(vm.qemu_path, request.json) yield from vm.adapter_add_nio_binding(int(request.match_info["adapter_number"]), nio) response.set_status(201) response.json(nio)
def create_nio(request, response): vpcs_manager = VPCS.instance() vm = vpcs_manager.get_node(request.match_info["node_id"], project_id=request.match_info["project_id"]) nio_type = request.json["type"] if nio_type not in ("nio_udp", "nio_tap"): raise HTTPConflict(text="NIO of type {} is not supported".format(nio_type)) nio = vpcs_manager.create_nio(request.json) yield from vm.port_add_nio_binding(int(request.match_info["port_number"]), nio) response.set_status(201) response.json(nio)
def write_settings(request, response): controller = Controller.instance() if controller.settings is None: # Server is not loaded ignore settings update to prevent buggy client sync issue return controller.settings = request.json try: controller.save() except (OSError, PermissionError) as e: raise HTTPConflict( text="Can't save the settings {}".format(str(e))) response.json(controller.settings) response.set_status(201)
def start_capture(request, response): iou_manager = IOU.instance() vm = iou_manager.get_vm(request.match_info["vm_id"], project_id=request.match_info["project_id"]) adapter_number = int(request.match_info["adapter_number"]) port_number = int(request.match_info["port_number"]) pcap_file_path = os.path.join(vm.project.capture_working_directory(), request.json["capture_file_name"]) if not vm.is_running(): raise HTTPConflict(text="Cannot capture traffic on a non started VM") yield from vm.start_capture(adapter_number, port_number, pcap_file_path, request.json["data_link_type"]) response.json({"pcap_file_path": str(pcap_file_path)})
def stop_capture(request, response): iou_manager = IOU.instance() vm = iou_manager.get_vm(request.match_info["vm_id"], project_id=request.match_info["project_id"]) if not vm.is_running(): raise HTTPConflict(text="Cannot capture traffic on a non started VM") adapter_number = int(request.match_info["adapter_number"]) port_number = int(request.match_info["port_number"]) yield from vm.stop_capture(adapter_number, port_number) response.set_status(204)
def find_unused_port(start_port, end_port, host="127.0.0.1", socket_type="TCP", ignore_ports=None): """ Finds an unused port in a range. :param start_port: first port in the range :param end_port: last port in the range :param host: host/address for bind() :param socket_type: TCP (default) or UDP :param ignore_ports: list of port to ignore within the range """ if end_port < start_port: raise HTTPConflict( text="Invalid port range {}-{}".format(start_port, end_port)) last_exception = None for port in range(start_port, end_port + 1): if ignore_ports and (port in ignore_ports or port in BANNED_PORTS): continue try: PortManager._check_port(host, port, socket_type) if host != "0.0.0.0": PortManager._check_port("0.0.0.0", port, socket_type) return port except OSError as e: last_exception = e if port + 1 == end_port: break else: continue raise HTTPConflict( text= "Could not find a free port between {} and {} on host {}, last exception: {}" .format(start_port, end_port, host, last_exception))
def reserve_tcp_port(self, port, project): """ Reserve a specific TCP port number :param port: TCP port number :param project: Project instance """ if port in self._used_tcp_ports: raise HTTPConflict(text="TCP port {} already in use on host".format(port, self._console_host)) self._used_tcp_ports.add(port) project.record_tcp_port(port) log.debug("TCP port {} has been reserved".format(port)) return port
def update_nio(request, response): builtin_manager = Builtin.instance() node = builtin_manager.get_node( request.match_info["node_id"], project_id=request.match_info["project_id"]) adapter_number = int(request.match_info["adapter_number"]) try: nio = node.nios[adapter_number] except KeyError: raise HTTPConflict( text="NIO `{}` doesn't exist".format(adapter_number)) if "filters" in request.json and nio: nio.filters = request.json["filters"] yield from node.update_nio(int(request.match_info["port_number"]), nio) response.set_status(201) response.json(request.json)
async def put(self, request: Request) -> Response: """ --- summary: Create a new user description: security: - Bearer Authentication: [users_manage] - X-API-Key Authentication: [users_manage] - Session Authentication: [users_manage] tags: - users requestBody: description: JSON containing the changes to the user and/or their username to find them required: true content: application/json: schema: type: object properties: username: type: string description: username of the user you want to modify required: true password: type: string description: unhashed password that will be hashed before being added to the user cards: oneOf: - type: array description: list of all cards that will be assigned to the user items: type: string format: mifare uid pattern: '^([0-9a-fA-F]{8}|([0-9a-fA-F]{14}|[0-9a-fA-F]{20})$' - type: string description: a single card that will be assigned to the user format: mifare uid pattern: '^([0-9a-fA-F]{8}|([0-9a-fA-F]{14}|[0-9a-fA-F]{20})$' permissions: oneOf: - type: array description: list of all permissions that the user will have items: type: string enum: - admin - enter - logs - users_read - users_manage - cards - type: string description: a single permission you want to give the user enum: - admin - enter - logs - users_read - users_manage - cards example: username: example password: hunter2 cards: - ABABABAB - 12345678 permissions: enter responses: "200": description: A JSON document indicating success along with some information about the user content: application/json: schema: $ref: '#/components/schemas/User' "401": description: A JSON document indicating error in request (user not authenticated) content: application/json: schema: $ref: '#/components/schemas/Error' "403": description: A JSON document indicating error in request (user doesn't have permission to preform this action) content: application/json: schema: $ref: '#/components/schemas/Error' "409": description: A JSON document indicating error in request (user already exists) content: application/json: schema: $ref: '#/components/schemas/Error' """ data = await request.json() permissions = data.get("permissions", []) if not isinstance(permissions, list): permissions = [permissions] await check_api_permissions(request, ["users_manage", *permissions]) username = data.get("username", False) if not username: raise HTTPBadRequest( reason="no username provided", body=json.dumps( {"Ok": False, "Error": "no username provided", "status_code": 401} ), content_type="application/json", ) user = await user_exists(request.app, username) if user: raise HTTPConflict( reason="User with this username already exists", body=json.dumps( { "Ok": False, "Error": "User with this username already exists", "status_code": 404, } ), content_type="application/json", ) cards = data.get("cards", []) if not isinstance(cards, list): cards = [cards] uid = register_user( request.app, username, data.get("password", None), permissions, cards ) user = find_user_by_uid(request.app, uid, ["username", "cards", "permissions"]) return respond_with_json( {"Ok": True, "Error": None, "status_code": 200, "user": user} )
def check_version(request, response): if request.json["version"] != __version__: raise HTTPConflict( text="Client version {} differs with server version {}".format( request.json["version"], __version__)) response.json({"version": __version__})
async def put(self, request: Request) -> Response: """ --- summary: Create multiple new users description: security: - Bearer Authentication: [users_manage] - X-API-Key Authentication: [users_manage] - Session Authentication: [users_manage] tags: - users requestBody: description: JSON containing a list of new user objects required: true content: application/json: schema: type: object properties: users: type: array items: type: object properties: username: type: string description: username of the user you want to modify required: true password: type: string description: unhashed password that will be hashed before being added to the user cards: description: a single card or list of cards that will be assigned to the user oneOf: - type: array description: list of all cards that will be assigned to the user items: type: string format: mifare uid pattern: '^([0-9a-fA-F]{8}|([0-9a-fA-F]{14}|[0-9a-fA-F]{20})$' - type: string description: a single card that will be assigned to the user format: mifare uid pattern: '^([0-9a-fA-F]{8}|([0-9a-fA-F]{14}|[0-9a-fA-F]{20})$' permissions: description: a single permission or list of permissions that the user will have (you need to have a permission to assign it to others) oneOf: - type: array description: list of all permissions that the user will have items: type: string enum: - admin - enter - logs - users_read - users_manage - cards - type: string description: a single permission you want to give the user enum: - admin - enter - logs - users_read - users_manage - cards example: users: - username: example password: hunter2 cards: - ABABABAB - 12345678 permissions: enter - username: example2 password: hunter4 cards: FFFFFFFF permissions: - enter - cards - users_read responses: "200": description: A JSON document indicating success along with some information about the user content: application/json: schema: $ref: '#/components/schemas/User' "401": description: A JSON document indicating error in request (user not authenticated) content: application/json: schema: $ref: '#/components/schemas/Error' "403": description: A JSON document indicating error in request (user doesn't have permission to preform this action) content: application/json: schema: $ref: '#/components/schemas/Error' "409": description: A JSON document indicating error in request (user already exists) content: application/json: schema: $ref: '#/components/schemas/Error' """ data = await request.json() if isinstance(data.get("users", None), list): users = data["users"] elif isinstance(data.get("users", ""), str): users = [data.get("users", "")] else: raise HTTPBadRequest( reason="no users provided", body=json.dumps({ "Ok": False, "Error": "no users provided", "status_code": 401 }), content_type="application/json", ) permissions = set() for user in users: user_permissions = user.get("permissions", []) if not isinstance(user_permissions, list): user_permission = [user_permissions] permissions.update(set(user_permissions)) await check_api_permissions(request, ["users_manage", *permissions]) result_users = [] for user_data in users: username = user_data.get("username", False) if not username: raise HTTPBadRequest( reason="no username provided for at least one user", body=json.dumps({ "Ok": False, "Error": "no username provided for at least one user", "status_code": 401, }), content_type="application/json", ) user = await user_exists(request.app, username) if user: raise HTTPConflict( reason= f"User with this username ({username}) already exists", body=json.dumps({ "Ok": False, "Error": f"User with this username ({username}) already exists", "status_code": 409, }), content_type="application/json", ) cards = user_data.get("cards", []) if not isinstance(cards, list): user_data["cards"] = [cards] await register_users(request.app, users) users = [{ "username": user.get("username"), "cards": user.get("cards", []), "permissions": user.get("permissions", []), } for user in users] return respond_with_json({ "Ok": True, "Error": None, "status_code": 200, "users": users })