2

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
  • 1
    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. Commented Dec 22, 2021 at 7:46

1 Answer 1

1

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/

Sign up to request clarification or add additional context in comments.

2 Comments

I can't run the sniff from he main thread - without creating a new thread for it?
You have to create a Thread for Each function, followed by the start and join methods. And then it will be a multithreaded application. In Your case, the same way you have created a daemon thread, similarly you have to replicate the same for sniff function.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.