multi threading http server in python

Viewed 277

I am trying to build a HTTP server in python, that sniffs packets and sends them to an other interface. the server can get routing paths through a POST http request. So that I need that the server will parallely sniff pakets and listen to http requests. this is my code:

from scapy.all import *
from scapy.layers.inet import IP, UDP
from http.server import BaseHTTPRequestHandler, HTTPServer
import json
from socketserver import ThreadingMixIn
import threading

ROUTING_LIST = []
INTERFACE_TO_SNIFF = 'vEthernet'
PORT = 80


class Route:
    def __init__(self):
        self.first_IP_src = ""
        self.first_port_src = ""
        self.first_IP_dst = ""
        self.first_port_dst = ""
        self.first_iface = ""
        self.second_IP_src = ""
        self.second_port_src = ""
        self.second_IP_dst = ""
        self.second_port_dst = ""
        self.second_iface = ""

class Server(BaseHTTPRequestHandler):
    # POST echoes the message adding a JSON field
    def do_POST(self):
        # read the message and convert it into a python dictionary
        length = int(self.headers['Content-length'])
        message = self.rfile.read(length)
        routing_dict = json.loads(message, strict=False)

        if add_routing_http(routing_dict) is True:
            print("New Routing received:")
            print("{" + "\n".join("{!r}: {!r},".format(k, v) for k, v in routing_dict.items()) + "}")

            self.send_response(200)
            self.send_header('Content-type', 'text/html')
            self.end_headers()
            self.wfile.write(
                ("POST routing request received! now we have " + str(len(ROUTING_LIST)) + " routes").encode("utf8"))


def run_server():
    global PORT
    server_address = ('', PORT)
    httpd = HTTPServer(server_address, Server)

    print('Starting httpd on port %d...' % PORT)
    httpd.serve_forever()



def add_routing_local(first_IP_src, first_port_src, first_IP_dst, first_port_dst, first_iface,
                      second_IP_src, second_port_src, second_IP_dst, second_port_dst, second_iface):
    global ROUTING_LIST

    temp = Route()
    temp.first_IP_src = first_IP_src
    temp.first_port_src = first_port_src
    temp.first_IP_dst = first_IP_dst
    temp.first_port_dst = first_port_dst
    temp.first_iface = first_iface
    temp.second_IP_src = second_IP_src
    temp.second_port_src = second_port_src
    temp.second_IP_dst = second_IP_dst
    temp.second_port_dst = second_port_dst
    temp.second_iface = second_iface

    ROUTING_LIST.append(temp)


def add_routing_http(routing_dict):
    global ROUTING_LIST

    temp = Route()
    temp.first_IP_src = routing_dict.get('firstIpSrc')
    temp.first_port_src = routing_dict.get('firstPortSrc')
    temp.first_IP_dst = routing_dict.get('firstIpDst')
    temp.first_port_dst = routing_dict.get('firstPortDst')
    temp.first_iface = routing_dict.get('firstIface')
    temp.second_IP_src = routing_dict.get('secondIpSrc')
    temp.second_port_src = routing_dict.get('secondPortSrc')
    temp.second_IP_dst = routing_dict.get('secondIpDst')
    temp.second_port_dst = routing_dict.get('secondPortDst')
    temp.second_iface = routing_dict.get('secondIface')

    ROUTING_LIST.append(temp)

    return True


def packets_filter(packet):
    return IP in packet and UDP in packet and Raw in packet


def match_packet(packet, routing):
    match = True
    if routing.first_IP_src != '' and packet[IP].src != routing.first_IP_src:
        return False
    if routing.first_IP_dst != '' and packet[IP].dst != routing.first_IP_dst:
        return False
    if routing.first_port_src != '' and packet[UDP].sport != routing.first_port_src:
        return False
    if routing.first_port_dst != '' and packet[UDP].dport != routing.first_port_dst:
        return False
    if routing.first_iface != '' and packet.sniffed_on is not None and routing.first_iface != packet.sniffed_on:
        return False

    return True


def handle_packet(packet):
    global ROUTING_LIST

    for routing in ROUTING_LIST:
        if match_packet(packet, routing) is True:
            new_packet = packet.copy()
            new_packet[IP].src = routing.second_IP_src
            new_packet[IP].dst = routing.second_IP_dst
            new_packet[UDP].sport = routing.second_port_src
            new_packet[UDP].dport = routing.second_port_dst

            new_packet.show()
            sendp(new_packet)  # sendp(new_packet, iface=routing.second_iface)iface='eth0'
            return


def main():
    daemon = threading.Thread(name='daemon_server', target=run_server, args=())
    daemon.setDaemon(True)  # Set as a daemon so it will be killed once the main thread is dead.
    daemon.start()

    print("start sniffing")
    sniff(lfilter=packets_filter, prn=handle_packet)  # sniff(lfilter=packets_filter, prn=handle_packet, iface=INTERFACE_TO_SNIFF)


if __name__ == "__main__":
    main()

In short - I wantthe main function to run in parallel both of functions: run_server, sniff. if I try to run inly one of them - both work great. In this code only the run_server works but not the sniffing. What is wrong? thank you

1 Answers

You have created Thread only for the run_server method. In order to run the sniff function on multithreaded, you will have to create a thread for the sniff function too.

You can learn about basic multithreading from this document: https://www.geeksforgeeks.org/multithreading-python-set-1/

Related