def nfq_hook_cb(qh, nfmsg, nfad, data): """ int nfq_callback(struct nfq_q_handle *qh, struct nfgenmsg *nfmsg, struct nfq_data *nfad, void *data); """ packet_id = NFQ.cb_get_packet_id(nfad) ip_bytes = NFQ.cb_get_payload(nfad) this_id = data this = ctypes.cast(this_id, ctypes.py_object).value assert isinstance(this, NFQHook) this.send_ip_packet_to_inspector(packet_id, ip_bytes) return 1
def cb(qh, nfmsg, nfad, data): """ int nfq_callback(struct nfq_q_handle *qh, struct nfgenmsg *nfmsg, struct nfq_data *nfad, void *data); """ payload = NFQ.cb_get_payload(nfad) packet_id = NFQ.cb_get_packet_id(nfad) ip = IP(payload) LOG.info("ID %d: %s", packet_id, ip.summary()) sleep(SLEEP_SECS) NFQ.cb_set_verdict(qh, packet_id, NFQ.NF_ACCEPT) return 1
def __init__(self, nfq_number, zmq_addr): LOG.info('NFQ Number: %s', nfq_number) assert isinstance(nfq_number, int) self.self_id = id(self) self.nfq = NFQ(nfq_number, nfq_hook_cb_c, ctypes.c_void_p(self.self_id)) self.zmq_client = NFQHookZMQC(zmq_addr, self.nfq)
class NFQHook(object): NFQ_SOCKET_BUFFER_SIZE = 1024 * 4 def __init__(self, nfq_number, zmq_addr): LOG.info('NFQ Number: %s', nfq_number) assert isinstance(nfq_number, int) self.self_id = id(self) self.nfq = NFQ(nfq_number, nfq_hook_cb_c, ctypes.c_void_p(self.self_id)) self.zmq_client = NFQHookZMQC(zmq_addr, self.nfq) def start(self): zmq_worker_handle = self.zmq_client.start() nfq_worker_handle = eventlet.spawn(self._nfq_worker) nfq_worker_handle.wait() zmq_worker_handle.wait() raise RuntimeError('should not reach here') def _nfq_worker(self): s = socket.fromfd(self.nfq.fd, socket.AF_UNIX, socket.SOCK_STREAM) try: while True: LOG.debug('NFQ Recv') nfad = s.recv(self.NFQ_SOCKET_BUFFER_SIZE) self.nfq.handle_packet(nfad) LOG.error('NFQ Worker loop leave!') finally: LOG.error('NFQ Worker closing socket!') s.close() self.nfq.close() sys.exit(1) def send_ip_packet_to_inspector(self, packet_id, ip_bytes): LOG.debug('Sending packet %d to inspector', packet_id) # from hexdump import hexdump # for l in hexdump(ip_bytes, result='generator'): # LOG.debug(l) # TODO: eliminate dummy eth header dummy_eth = '\xff\xff\xff\xff\xff\xff' + '\x00\x00\x00\x00\x00\x00' + '\x08\x00' + ip_bytes self.zmq_client.send(packet_id, dummy_eth)
def on_drop(self, packet_id, eth_bytes, metadata=None): NFQ.cb_set_verdict(self.nfq.qh, packet_id, NFQ.NF_DROP)
def on_accept(self, packet_id, eth_bytes, metadata=None): NFQ.cb_set_verdict(self.nfq.qh, packet_id, NFQ.NF_ACCEPT)
def cb(qh, nfmsg, nfad, data): """ int nfq_callback(struct nfq_q_handle *qh, struct nfgenmsg *nfmsg, struct nfq_data *nfad, void *data); """ payload = NFQ.cb_get_payload(nfad) packet_id = NFQ.cb_get_packet_id(nfad) ip = IP(payload) LOG.info("ID %d: %s", packet_id, ip.summary()) sleep(SLEEP_SECS) NFQ.cb_set_verdict(qh, packet_id, NFQ.NF_ACCEPT) return 1 cb_c = NFQ.CALLBACK_CFUNCTYPE(cb) # https://github.com/JohannesBuchner/PyMultiNest/issues/5 if __name__ == '__main__': LOG.info("Please run `iptables -A OUTPUT -p tcp -m owner --uid-owner $(id -u nfqhooked) -j NFQUEUE --queue-num 42` before running this hook.") LOG.info("and then run `sudo -u nfqhooked SOME_COMMAND`") nfq = NFQ(NFQ_NUMBER, cb_c) s = socket.fromfd(nfq.fd, socket.AF_UNIX, socket.SOCK_STREAM) while True: d = s.recv(SOCK_BUF_SIZE) assert d nfq.handle_packet(d) s.close() nfq.close()