Arrêter une fonction à partir d'une influence extérieure

L'auteur de ce sujet a trouvé une solution à son problème.
Auteur du sujet

Bonjour/bonsoire amis agrumes, je travaille sur un petit projet, où je veux faire afficher le résultat d'un sniffer en temps réel sur une page web. J'utilise le framework flask, avec l'extension flask-socketio qui permet l'utilisation des websockets.

Je mets d'abord le code partiel avant d'expliquer mon problème

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
def snif():
    connexion = socket.socket(socket.AF_PACKET, 
                socket.SOCK_RAW, socket.ntohs(3))

    while session['run']:
        raw_data, address = connexion.recvfrom(65535)
        dest_mac, src_mac, eth_proto, data = eth.ethernet_frame(raw_data)
        eth_message = ''
        eth_message += '\nEthernet Frame\n'
        eth_message += 'Destination: {}, Source: {}, Protocol: {}'.format(
                       dest_mac, src_mac, eth_proto)
        socketio.emit('ethernet', {'data': eth_message})

#Events handlers
@socketio.on('run')
def run(message):
    session['run'] = True
    snif()
    print('Message from client:', message['data'])

@socketio.on('stop')
def stop(message):
    session['run'] = False
    print('Message from Client:', message['data'])

Mon souci réside actuellement dans l'arrêt du sniffer. Je me suis dis qu'en jouant sur ma variable de session 'run', je pourrais stopper la boucle de la fonction snif, mais je me rends compte qu'une fois qu'elle est lancée, plus rien ne peut la changer.

J'ai pensé aux générateurs, mais c'est un peu le même problème. Si je mets le générateur dans une variable de session, et j'essaye d'appliquer la méthode stop() dans la fonction stop, rien ne se passe.

J'ai pensé aussi aux signaux, mais ça va arrêter toute mon application, ce qui n'est pas le but recherché.

Je suis à cours d'idée, quelqu'un aurait une proposition à me faire? Je remercie d'avance la personne qui le fera :)

+0 -0
Staff

Le truc c'est que l'objet session dans ton cas est régénéré à chaque appel.

J'ignore s'il y a un moyen flaskesque de faire ça, mais tu pourrais lancer le traitement dans un thread explicite, en référençant tes threads dans un dictionnaire global session_id -> thread.

Édité par nohar

I was a llama before it was cool

+0 -0
Staff

Le but de session est normalement de pouvoir passer des appels des données d'une requete à une autre d'un meme user. Selon la doc c'est un proxy et l'objet est partagé entre les thread donc peut-être que ça pourrait fonctionner. Par contre pour que ce soit le cas il faut absolument que secret_key soit définit dans la config, est-ce le cas ?

Sinon comme nohar, perso je ferai un thread (ou process) a part pour ça avec un canal pour demander l’arrêt.

+0 -0
Auteur du sujet

Bonjour à tous,

Déjà mille excuses à Kje et nohar qui ont pris la peine de m'aider et je n'ai pas répondu. J'ai eu quelques soucis ces derniers temps, donc j'ai mis ce petit projet en stand-by. Kje, effectivement j'ai créé une variable secret_key dans la config.

J'ai essayé avec les threads, mais ça n'a pas l'air de mieux marcher (à savoir mon programme n'arrive pas à s'arrêter quand j'appuie sur l'unique bouton stop de ma page web), je ne sais pas où je me loupe. J'ai mis le code entier pour que quelqu'un puisse peut-être trouvé la faille dans mon code.

  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
#!/usr/bin/env python

import socket
from threading import Thread

from flask import Flask, render_template, session
from flask_socketio import SocketIO

from display_facilities import *
from protocols import ethernet as eth
from protocols import ipv4, icmpv4, tcp, udp

# Choice of asynchronous mode
async_mode = 'threading'

#Application configuration
app = Flask(__name__)
app.config['SECRET_KEY'] = '&\x82\x81m\x0b\xfd\xc7\xeac\xfa4E\xf35\x8f\x13\x1c&\xfd\xa23\xad\xd3\xa0'
socketio = SocketIO(app, async_mode=async_mode)

class Process(Thread):
    # class which executes the main process

    def __init__(self):
        Thread.__init__(self)

    def run(self):
        """brief: analyse network packets and send packet informations to
        index.html via websockets or another technology"""

        connexion = socket.socket(socket.AF_PACKET, 
                    socket.SOCK_RAW, socket.ntohs(3))

        while True:
            raw_data, address = connexion.recvfrom(65535)
            dest_mac, src_mac, eth_proto, data = eth.ethernet_frame(raw_data)
            eth_message = '\nEthernet Frame\n'
            eth_message += TAB_1
            eth_message += 'Destination: {}, Source: {}, Protocol: {}'.format(
                           dest_mac, src_mac, eth_proto)
            socketio.emit('ethernet', {'data': eth_message})

            # 8 for IPv4
            if eth_proto == 8:
                version, header_length, ttl, proto, source,\
                target, data = ipv4.ipv4_packet(data)
                ipv4_message = TAB_1 + 'IPV4 Packet:\n'
                ipv4_message += TAB_2 + 'Version: {}\n'.format(version)
                ipv4_message += TAB_2 + 'Header Length: {}\n'.format(header_length)
                ipv4_message += TAB_2 + 'Time To Live: {}\n'.format(ttl)
                ipv4_message += TAB_2 + 'Protocol: {}\n'.format(proto)
                ipv4_message += TAB_2 + 'Source: {}\n'.format(source)
                ipv4_message += TAB_2 + 'Destination: {}\n'.format(target)
                socketio.emit('ipv4', {'data': ipv4_message})

                if proto == 1:  # ICMP packet
                    icmp_type, code, checksum, data = icmpv4.icmpv4_packet(data)
                    icmpv4_data = TAB_1 + 'ICMP Packet:\n'
                    icmpv4_data += TAB_2 + 'Type: {}\n'.format(icmp_type)
                    icmpv4_data += TAB_2 + 'Code: {}\n'.format(code)
                    icmpv4_data += TAB_2 + 'Checksum: {}\n'.format(checksum)
                    icmpv4_data += TAB_2 + 'Data:\n'
                    icmpv4_data += format_multi_line(DATA_TAB_3, data)
                    socketio.emit('icmpv4', {'data': icmpv4_data})

                elif proto == 6:  # TCP Segment
                    src_port, dest_port, seq, ack, offset, flag_urg, flag_ack,\
                    flag_psh, flag_rst, flag_syn, flag_fin,\
                    data = tcp.tcp_segment(data)
                    tcp_data = TAB_1 + 'TCP Segment\n'
                    tcp_data += TAB_2 + 'Source Port: {},\
                                Destination Port: {}\n'.format(src_port, dest_port)
                    tcp_data += TAB_2 + 'Sequence: {},\
                                Acknowledgement: {}\n'.format(seq, ack)
                    tcp_data += TAB_2 + 'Flags:\n'
                    tcp_data += TAB_3 + 'URG: {}, ACK: {}, PSH: {}, RST: {},\
                                SYN: {}, FIN: {}'.format(flag_urg, flag_ack,\
                                flag_psh, flag_rst, flag_syn, flag_fin)
                    tcp_data += TAB_2 + 'Data:\n'
                    tcp_data += format_multi_line(DATA_TAB_3, data)
                    socketio.emit('tcp', {'data': tcp_data})

                elif proto == 17:  # UDP Datagram
                    source_port, dst_port, size,\
                    checksum, data = udp.udp_datagram(data)
                    udp_data = TAB_1 + 'UDP Datagram\n'
                    udp_data += TAB_2 + 'Source Port: {}'.format(source_port)
                    udp_data += TAB_2 + 'Destination Port: {}'.format(dst_port)
                    udp_data += TAB_2 + 'Size: {}'.format(size)
                    udp_data += TAB_2 + 'cheksum: {}'.format(checksum)
                    udp_data += TAB_2 + 'Data:\n'
                    udp_data += format_multi_line(DATA_TAB_3, data)
                    socketio.emit('udp', {'data': udp_data})

                else:  # Other
                    other_data = TAB_1 + 'Data:\n'
                    other_data += format_multi_line(DATA_TAB_2, data)
                    socketio.emit('other', {'data': other_data})

            else:
                other_layer3 = 'Data:\n'
                other_layer3 += format_multi_line(DATA_TAB_1, data)
                socketio.emit('other_layer3', {'data': other_layer3})


#Route
@app.route('/')
def index():
    return render_template('index.html')

#Events handlers
@socketio.on('run')
def run(message):
    session['run'] = Process()
    session['run'].run()
    print('Message from client:', message['data'])

@socketio.on('stop')
def stop(message):
    session['run'].join()
    print('Message from Client:', message['data'])


if __name__ == '__main__':
    socketio.run(app, debug=True, host='0.0.0.0')
+0 -0
Vous devez être connecté pour pouvoir poster un message.
Connexion

Pas encore inscrit ?

Créez un compte en une minute pour profiter pleinement de toutes les fonctionnalités de Zeste de Savoir. Ici, tout est gratuit et sans publicité.
Créer un compte