def send(self, data): """Send encoded data to server.""" try: flog.info(f"Sending data of length: {len(data)}") self.client.send(data) except (BlockingIOError, ConnectionResetError, socket.timeout) as e: flog.debug(e)
def start_tcp_tls_server(self): """Start tcp tls echo server as background process.""" script_path = os.path.join(self.server_tools, "host/tcp_tls_server.py") log_file = os.path.join(self.server_root, "logs/tcp_tls_server.log") cmd = "python3 -u {} > {} 2>&1 &".format(script_path, log_file) flog.debug("Starting tcp tls echo server with: {}".format(cmd)) return os.system(cmd) == 0
def run_cmd(self): """Run iperf command.""" iperf_cmd = "iperf3 -s -p {port} --logfile {log_file} -D" for port in self.ports: cmd = iperf_cmd.format(port=port, log_file=self.log_file) flog.debug(cmd) assert os.system(cmd) == 0, "Failed to start iperf"
def tcp_handle(client_sock, killable=False): """Echo data over TCP socket.""" flog.info("Launch TCP Handler.") while True: try: data = client_sock.recv(max_buffer) try: data_str = data.decode("utf-8") except Exception: pass if killable and data_str and "kill" in data_str: flog.debug("Killing Socket...") pid = os.getpid() os.kill(pid, signal.SIGKILL) if data: flog.debug("Received TCP data: %s" % data) client_sock.send(data) else: client_sock.close() break except Exception as ex: flog.warning("TCP Handler Exception: {}".format(ex)) client_sock.close() break flog.info("End TCP Handler")
def get_dev(): """Get interface device.""" cmd = "ip route | grep default | awk '{print $5}'" flog.debug(cmd) rsp = subprocess.check_output(cmd, shell=True).decode("utf-8").strip() flog.debug("dev: {}".format(rsp)) return rsp
def add_ip_tables(self, host=None): """Add ip table rules. Accepts incoming traffic on ports. Redirects traffic on simulation ports to default ports. Configuration specified in server config. """ flog.info("Accepting and redirecting ports (host=%s)" % host) if host: hostname = os.environ.get("FILTER_HOST", "filter") filter_host = socket.gethostbyname(hostname) assert host, "Unable to get host from hostname %s" % hostname flog.debug("Redirect connections to host %s to %s" % (filter_host, host)) self.run( "-t nat -A POSTROUTING -o eth0 -j SNAT --to-source %s" % filter_host, tool=Command.Iptables, ) for protocol, protocol_set in self.server_config["ports"].items(): for default_port, port_set in protocol_set.items(): if default_port != "null": port_set.append(default_port) if not self.accept_ports(protocol=protocol, ports=port_set): return False if host: default_port = host if default_port != "null" and not self.redirect_ports( protocol=protocol, src_list=port_set, dst=default_port): return False self.show_ip_tables() return True
def start_dynamic_http_server(self): """Start dynamic http server as background process.""" script_path = os.path.join(self.server_tools, "host/dynamic_http.py") log_file = os.path.join(self.server_root, "logs/dynamic_http.log") cmd = "python3 -u {} > {} 2>&1 &".format(script_path, log_file) flog.debug("Starting dynamic http server with: {}".format(cmd)) return os.system(cmd) == 0
def open_pcap_process(self): """Open pcap process.""" cmd = "/usr/sbin/tcpdump {scheme} -i {dev} port {port} -w {log}".format( scheme=self.scheme, dev=self.dev, port=self.port, log=self.tmp_log) if self.headers_only: cmd += " -s 96" flog.debug("pcap process command: {}".format(cmd)) self.pcap_process = subprocess.Popen(cmd.split())
def configure_pcap(self): """Configure pcap settings.""" flog.debug("configuring pcap_manager cron settings.") self.cron_config["pcap"] = { "script": os.path.join(self.server_tools, "host/pcap_manager.py"), "log_file": os.path.join(self.server_root, "logs/pcap_manager.log"), } return True
def run(self, command, tool=Command.Tc, output=False): """Run traffic control command.""" cmd = "{} ".format(tool.value) if tool else "" cmd += command flog.debug(cmd) if output: return subprocess.check_output(cmd, shell=True).decode("utf-8").strip() return os.system(cmd) == 0
def configure_iperf(self): """Configure iperf settings.""" flog.debug("configuring iperf cron settings.") self.cron_config["iperf"] = { "script": os.path.join(self.server_tools, "host/iperf3_manager.py"), "log_file": os.path.join(self.server_root, "logs/iperf_manager.log"), } return True
def check_message(self, message): "Check if message has command encoded." try: data_str = message.decode("utf-8") flog.debug(data_str) if "close" in data_str: flog.info("Received close command") return "close" except Exception: pass return ""
def create_listener_process(self): """Create pcap process and pcap listener.""" self.open_pcap_process() cmd = "tail -c +1 -f {}".format(self.tmp_log) flog.debug("listener command: {}".format(cmd)) delete_pcap_processes(cmd) while not os.path.exists(self.tmp_log): continue self.listener_process = subprocess.Popen(cmd.split(), stdout=subprocess.PIPE, stderr=subprocess.PIPE)
def run(self): """Run UDP server.""" # bind udp socket flog.debug("starting udp server on {}".format(self.port)) self.udp_server.bind((self.local_ip, self.port)) while True: # listen for udp data, addr = self.udp_server.recvfrom(self.port) flog.debug("Received UDP: {}".format(data)) if data: request = data.decode("utf-8") data = self.get_file(path=request) self.send_file(data, addr)
def udp_handle(self): """Echo data over UDP socket.""" flog.info("Launch UDP Handler.") while True: data, addr = self.udp_server.recvfrom(max_buffer) if data: if data == b"0 byte test": flog.debug("Received 0 byte test") self.udp_server.sendto(b"", addr) else: flog.debug("Received UDP data: %s" % data) self.udp_server.sendto(data, addr) if not data: self.udp_server.close()
def run_tcp_tls_server(): """Run TCP TLS server.""" flog.info("Starting TCP TLS echo server") config = ServerConfig() tcp_TLS_server = TcpTLSServer(config) tcp_TLS_server_mutual = TcpTLSServer(config, mutual=True) flog.debug("Launch mutual authentication server thread.") mutual_thread = threading.Thread(target=tcp_TLS_server_mutual.run, args=()) mutual_thread.start() flog.debug("Launch server authentication server thread.") server_thread = threading.Thread(target=tcp_TLS_server.run, args=()) server_thread.start() mutual_thread.join() server_thread.join()
def delete_pcap_processes(cmd): """Delete Previous PCAP processes.""" flog.debug("Deleting Previous PCAP processses.") command = 'ps -ef | grep "{}"'.format(cmd) ps_output = os.popen(command).read() print(ps_output) if ps_output.count(cmd) > 2: tail_pid = int(ps_output.split()[1]) parent_pid = int(ps_output.split()[2]) flog.debug("Previous Tail ID: {}".format(tail_pid)) flog.debug("Previous Parent ID: {}".format(parent_pid)) if tail_pid is not None: flog.debug("Killing Tail PID: {}".format(tail_pid)) flog.debug("Killing Parent PID: {}".format(parent_pid)) os.kill(tail_pid, signal.SIGTERM) os.kill(parent_pid, signal.SIGTERM)
def run(self): """Run TCP/UDP client.""" flog.info(f"Connecting to {self.mode} server at {self.address}:{self.port}") flog.debug(f"Echo: {self.echo}") if not self.echo: flog.debug(f"Message Size: {len(self.message)}") if self.mode == "TCP": self.run_tcp() elif self.mode == "UDP": self.run_udp() else: flog.error( f"Cannot run client in mode: {self.mode}\nplease use either TCP or UDP" ) return flog.info(f"End {self.mode} Client")
def run(self): """Run Echo servers.""" flog.debug("Starting echo server on {}".format(self.port)) flog.debug("Starting tcp kill server on {}".format(self.kill_port)) self.tcp_server.bind((self.local_ip, self.port)) self.tcp_kill_server.bind((self.local_ip, self.kill_port)) self.tcp_local_poll_server.bind((self.local_ip, self.polling_port)) self.udp_server.bind((self.local_ip, self.port)) self.tcp_server.listen(5) self.tcp_kill_server.listen(5) self.tcp_local_poll_server.listen(5) l_onoff = 1 l_linger = 0 self.tcp_kill_server.setsockopt( socket.SOL_SOCKET, socket.SO_LINGER, struct.pack("ii", l_onoff, l_linger) ) # listen for UDP _thread.start_new_thread(self.udp_handle, ()) # listen for TCP while True: sockets, _, _ = select.select( (self.tcp_server, self.tcp_kill_server, self.tcp_local_poll_server), (), (), 1, ) for sock in sockets: client_sock, _ = sock.accept() client_sock.settimeout(self.timeout) if sock == self.tcp_server: _thread.start_new_thread(tcp_handle, (client_sock, False)) elif sock == self.tcp_kill_server: x = multiprocessing.Process( target=tcp_handle, args=(client_sock, True) ) x.start() else: _thread.start_new_thread(tcp_poll_handle, (client_sock,)) else: time.sleep(1) with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as poll_socket: poll_socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEPORT, 1) poll_socket.connect_ex((self.local_ip, self.polling_port))
def tcp_tls_handle(conn_stream, client_sock): """Echo data over TLS connection.""" flog.info("TCP TLS Handle Launched.") while True: try: data = conn_stream.read() if data: flog.debug("Received TCP TLS: {}".format(data)) conn_stream.send(data) if not data: conn_stream.close() client_sock.close() break except Exception as ex: flog.warning("TCP TLS Handler Exception: {}".format(ex)) conn_stream.close() client_sock.close() break flog.info("End TCP TLS Handler.")
def receive(self): """Receive encoded data from server.""" data = b"" wait_time = 1 got_data = False for _ in range(0, self.timeout, wait_time): sockets, _, _ = select.select((self.client,), (), (), wait_time) for sock in sockets: data += sock.recv(MAX_BUFFER) got_data = data != b"" flog.debug(f"Data part received length: {len(data)}") break else: if got_data: flog.debug("Data parts complete") break if not got_data: return None flog.info(f"Received message of length: {len(data)} bytes") return data
def run(self): """Run TCP TLS server.""" TLS_context = ssl.SSLContext(ssl.PROTOCOL_TLSv1_2) flog.debug("Loading cert and keyfile") TLS_context.load_cert_chain(certfile=self.fullchain, keyfile=self.privkey) if self.is_mutual is True: flog.debug("Setting server to mutual authentication.") # CA root used for verifying Client certificates TLS_context.load_verify_locations(cafile=self.CAroot) TLS_context.verify_mode = ssl.CERT_REQUIRED self.tcp_server.bind((self.local_ip, self.port)) self.tcp_server.listen(5) flog.debug("Starting TCP TLS server on {}".format(self.port)) while True: # listen for tcp then wrap with TLS client_sock, addr = self.tcp_server.accept() client_sock.settimeout(self.timeout) flog.info("TCP Socket Connected.") try: conn_stream = TLS_context.wrap_socket(client_sock, server_side=True) TLS_thread = threading.Thread(target=tcp_tls_handle, args=(conn_stream, client_sock)) TLS_thread.start() except Exception as ex: flog.info("Could not wrap socket. Closing TCP Socket.") flog.info(ex) client_sock.close()
def configure_cron(self): """Configure cron settings.""" flog.debug("configuring cron") env_vars = "PYTHONPATH={} FLAKE_SERVER={} FLAKE_TOOLS={} SHELL=/bin/bash".format( os.environ.get("PYTHONPATH"), os.environ.get("FLAKE_SERVER"), os.environ.get("FLAKE_TOOLS"), ) for cron_script, info in self.cron_config.items(): script = "python3 -u {} > {} 2>&1".format(info["script"], info["log_file"]) cmd = "{vars} {script}".format(vars=env_vars, script=script) # Restart script every 3 hours. cron_cmd = '(crontab -l ; echo "{cron_time} {cmd}") | crontab -'.format( cron_time="0 */3 * * *", cmd=cmd) try: # Initial start flog.debug(cmd) assert os.system(cmd) == 0, "Failed to start {}".format( cron_script) # Configure cron flog.debug(cron_cmd) assert os.system(cron_cmd) == 0, "Failed to configure cron" except AssertionError as e: flog.error(e) return False try: assert os.system( "/etc/init.d/cron restart") == 0, "Failed to start cron" except AssertionError as e: flog.error(e) return False return True
def start_cap(): parser = argparse.ArgumentParser(description="Pcap listener.") parser.add_argument("--dev", type=str, help="Network device", required=True) parser.add_argument("--scheme", type=str, help="Scheme", choices=["tcp", "udp"], required=True) parser.add_argument("--port", type=str, help="Port", required=True) parser.add_argument("--log_dir", type=str, help="Log directory", required=True) parser.add_argument("--tmp_log", type=str, help="Temporary log file for listener", required=True) parser.add_argument("--timeout", type=int, help="Timeout", default=10) parser.add_argument("--rotation_len", type=int, help="Number of logs to rotate", default=10) parser.add_argument( "--headers_only", type=str, help="Only capture packet header", choices=["True", "False"], default="False", ) args = parser.parse_args() args.headers_only = eval(args.headers_only) flog.debug(args) pcap_listener = PcapListener(**vars(args)) pcap_listener.run() flog.error("RUN ENDED")
def _get_dev(self): """Get interface device.""" cmd = "ip route | grep default | awk '{print $5}'" rsp = self.run(cmd, tool=None, output=True) flog.debug("dev: {}".format(rsp)) return rsp
def run_cmd(self, cmd): """Run pcap command.""" flog.debug(cmd) assert os.system(cmd) == 0, "Failed to start pcap"
def rotate_logs(self): """Remove old logs from directory.""" log_list = self.get_logs() for log in log_list[self.rotation_len:]: flog.debug("Removing old log: {}".format(log)) os.remove(log)