Looking for a way to send tcp reset for selective url using flask API Looking for a way to send tcp reset for selective url using flask API flask flask

Looking for a way to send tcp reset for selective url using flask API


Have a look at the Python Sicket documentation, https://docs.python.org/3/howto/sockets.html

I think you can send a TCP reset just like this, based on the answer here: Sending a reset in TCP/IP Socket connection

def client(host, port):    s = socket.socket(socket.AF_INET, socket.SOCK_STREAM, 0)    s.connect((host, port))    l_onoff = 1                                                                                                                                                               l_linger = 0                                                                                                                                                              s.setsockopt(socket.SOL_SOCKET, socket.SO_LINGER,                                                                                                                                      struct.pack('ii', l_onoff, l_linger))    # send data here    s.close()


Getting the flask's connection socket object from flask app itself is not possible as of now.

From what I've found on other questions on SO about flask's sockets, it seems we can set file descriptor of the socket for werkzeug.serving.BaseWSGIServer.

Another problem is sending a socket reset in a pythonic way.

So, I was able to combine the answers of the linked questions into something like this, I went with the default werkzeug's wsgi server (the one used when app.run is called).

import loggingimport osimport socketimport socketserverimport structfrom flask import Flask, abort, request, sessionfrom werkzeug.serving import BaseWSGIServerlogging.basicConfig(level=logging.DEBUG)logger = logging.getLogger(__name__)app = Flask(__name__)sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)sock.set_inheritable(True)sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)sock.setsockopt(socket.SOL_SOCKET, socket.SO_LINGER, struct.pack('ii', 1, 0))@app.route('/hello')def hello():    return "Hello"@app.route('/bye')def bye():    return ""if __name__ == "__main__":    try:        bind_to = ('127.0.0.1', 5000)        sock.bind(bind_to)        sock.listen()        sock_fd = sock.fileno()        logging.info("Sock FD is {}".format(sock_fd))        # calls Socket.dup on the sock_fd        # and passes the context into init of inherited        # HTTPServer, rendering the server and sock         # unpatchable afterwards        base_wsgi = BaseWSGIServer(            *bind_to, app, fd=sock_fd)        base_wsgi.serve_forever()    finally:        if not sock._closed:            msg = "Socket not closed, closing."            sock.close()        else:            msg = "Socket already closed."        logger.info(msg)

It might (or might not) be easier and completely possible to control the socket & connection with different wsgi backends like Gevent, Twisted web, ...

The result

Checking from wireshark, it now additionally sends RSTs after each request. So after the connection is naturally closed - FIN.

One issue is that the RST can't be controlled - this basically extends the socket with the SO_LINGER options causing RSTs to be always sent when connections are closed. To allow selective RST sending, one would have to propagate the underlying connection (created from the sock) into the endpoint, then set the sockoptions on that connection and close it - which might also cause the underlying webserver to fail.