proto header work
This commit is contained in:
		
							parent
							
								
									b250f70e33
								
							
						
					
					
						commit
						38f494df2c
					
				| @ -58,7 +58,6 @@ cdef enum: | ||||
| 
 | ||||
| cdef extern from "Python.h": | ||||
|     object PyBytes_FromStringAndSize(char *s, Py_ssize_t len) | ||||
|     object PyString_FromStringAndSize(char *s, Py_ssize_t len) | ||||
| 
 | ||||
| cdef extern from "sys/time.h": | ||||
|     ctypedef long time_t | ||||
| @ -113,39 +112,19 @@ cdef extern from "libnetfilter_queue/libnetfilter_queue.h": | ||||
| 
 | ||||
|     nfq_handle *nfq_open() | ||||
|     int nfq_close(nfq_handle *h) | ||||
| 
 | ||||
|     int nfq_bind_pf(nfq_handle *h, u_int16_t pf) | ||||
|     int nfq_unbind_pf(nfq_handle *h, u_int16_t pf) | ||||
|     ctypedef int *nfq_callback(nfq_q_handle *gh, nfgenmsg *nfmsg, | ||||
|                        nfq_data *nfad, void *data) | ||||
|     nfq_q_handle *nfq_create_queue(nfq_handle *h, | ||||
|                                     u_int16_t num, | ||||
|                                     nfq_callback *cb, | ||||
|                                     void *data) | ||||
|     ctypedef int *nfq_callback(nfq_q_handle *gh, nfgenmsg *nfmsg, nfq_data *nfad, void *data) | ||||
|     nfq_q_handle *nfq_create_queue(nfq_handle *h, u_int16_t num, nfq_callback *cb, void *data) | ||||
|     int nfq_destroy_queue(nfq_q_handle *qh) | ||||
| 
 | ||||
|     int nfq_handle_packet(nfq_handle *h, char *buf, int len) | ||||
|     int nfq_set_mode(nfq_q_handle *qh, u_int8_t mode, unsigned int len) | ||||
|     q_set_queue_maxlen(nfq_q_handle *qh, u_int32_t queuelen) | ||||
|     int nfq_set_verdict(nfq_q_handle *qh, u_int32_t id, u_int32_t verdict, u_int32_t data_len, unsigned char *buf) nogil | ||||
|     int nfq_set_verdict2(nfq_q_handle *qh, u_int32_t id, u_int32_t verdict, u_int32_t mark, | ||||
|         u_int32_t datalen, unsigned char *buf) nogil | ||||
| 
 | ||||
|     int nfq_set_mode(nfq_q_handle *qh, | ||||
|                        u_int8_t mode, unsigned int len) | ||||
| 
 | ||||
|     q_set_queue_maxlen(nfq_q_handle *qh, | ||||
|                      u_int32_t queuelen) | ||||
| 
 | ||||
|     int nfq_set_verdict(nfq_q_handle *qh, | ||||
|                           u_int32_t id, | ||||
|                           u_int32_t verdict, | ||||
|                           u_int32_t data_len, | ||||
|                           unsigned char *buf) nogil | ||||
| 
 | ||||
|     int nfq_set_verdict2(nfq_q_handle *qh, | ||||
|                             u_int32_t id, | ||||
|                             u_int32_t verdict, | ||||
|                             u_int32_t mark, | ||||
|                             u_int32_t datalen, | ||||
|                             unsigned char *buf) nogil | ||||
|     int nfq_set_queue_maxlen(nfq_q_handle *qh, u_int32_t queuelen) | ||||
| 
 | ||||
|     int nfq_fd(nfq_handle *h) | ||||
|     nfqnl_msg_packet_hdr *nfq_get_msg_packet_hdr(nfq_data *nfad) nogil | ||||
|     int nfq_get_payload(nfq_data *nfad, unsigned char **data) nogil | ||||
| @ -198,15 +177,13 @@ cdef class CPacket: | ||||
|     # Packet details: | ||||
|     cdef Py_ssize_t data_len | ||||
|     cdef readonly unsigned char *data | ||||
|     cdef readonly unsigned char *payload | ||||
|     cdef timeval timestamp | ||||
|     cdef u_int8_t hw_addr[6] | ||||
| 
 | ||||
|     cdef u_int32_t parse(self, nfq_q_handle *qh, nfq_data *nfa) nogil | ||||
|     cdef void _parse(self) nogil | ||||
|     cdef void verdict(self, u_int32_t verdict) | ||||
|     cdef double get_timestamp(self) | ||||
|     cdef u_int8_t get_inint(self, bint name=?) | ||||
|     cdef u_int8_t get_outint(self, bint name=?) | ||||
|     cpdef update_mark(self, u_int32_t mark) | ||||
|     cpdef accept(self) | ||||
|     cpdef drop(self) | ||||
|  | ||||
| @ -26,13 +26,13 @@ def set_user_callback(ref): | ||||
| 
 | ||||
|     user_callback = ref | ||||
| 
 | ||||
| cdef int nf_callback(nfq_q_handle *qh, nfgenmsg *nfmsg, nfq_data *nfa, void *data): | ||||
| cdef int nf_callback(nfq_q_handle *qh, nfgenmsg *nfmsg, nfq_data *nfa, void *data) with gil: | ||||
| 
 | ||||
|     cdef u_int32_t mark | ||||
| 
 | ||||
|     packet = CPacket() | ||||
|     with nogil: | ||||
|         mark = packet.parse(qh, nfa) | ||||
|     # with nogil: | ||||
|     mark = packet.parse(qh, nfa) | ||||
| 
 | ||||
|     user_callback(packet, mark) | ||||
| 
 | ||||
| @ -79,48 +79,58 @@ cdef class CPacket: | ||||
| 
 | ||||
|         self.ip_header = <iphdr*>self.data | ||||
| 
 | ||||
|         cdef u_int8_t hdr_shift = 4 | ||||
|         cdef u_int8_t hdr_multiplier = 4 | ||||
|         cdef u_int8_t hdr_xand = 15 | ||||
|         cdef u_int8_t iphdr_len | ||||
| 
 | ||||
|         iphdr_len = self.ip_header.ver_ihl & hdr_xand | ||||
|         iphdr_len = iphdr_len * hdr_multiplier | ||||
|         iphdr_len = (self.ip_header.ver_ihl & 15) * 4 | ||||
| 
 | ||||
|         # NOTE: tshoot print | ||||
|         printf('ip header length=%f\n', <double>iphdr_len) | ||||
| 
 | ||||
|         cdef u_int8_t tcphdr_len | ||||
|         cdef u_int8_t udphdr_len  = 8 | ||||
|         cdef u_int8_t icmphdr_len = 4 | ||||
|         cdef u_int8_t protohdr_len | ||||
| 
 | ||||
|         cdef void *data = &self.data[iphdr_len] | ||||
|         cdef ptrdiff_t hdrptr = <u_int32_t*>data - <u_int32_t*>self.data | ||||
|         # printf('data=%p, self.data=%p\n', <void*>&data, <void*>&self.data) | ||||
|         # cdef ptrdiff_t hdrptr = <u_int32_t*>data - <u_int32_t*>self.data | ||||
| 
 | ||||
|         if (self.ip_header.protocol == IPPROTO_TCP): | ||||
|             printf('TCP=%s\n', <char*>self.data_len) | ||||
| 
 | ||||
|             self.tcp_header = <tcphdr*>&hdrptr | ||||
|             self.tcp_header = <tcphdr*>&data | ||||
| 
 | ||||
|             tcphdr_len = self.tcp_header.th_off >> hdr_shift | ||||
|             tcphdr_len = tcphdr_len & hdr_xand | ||||
|             tcphdr_len = tcphdr_len * hdr_multiplier | ||||
|             tcphdr_len = (self.tcp_header.th_off >> 4) & 15 | ||||
|             protohdr_len = tcphdr_len * 4 | ||||
| 
 | ||||
|             # NOTE: tshoot print | ||||
|             printf('TCP HEADER LEN=%f\n', <double>tcphdr_len) | ||||
|             printf('TCP SPORT=%f\n', <double>self.tcp_header.th_sport) | ||||
| 
 | ||||
|             self.cmbhdr_len = iphdr_len + tcphdr_len | ||||
|             # self.cmbhdr_len = iphdr_len + tcphdr_len | ||||
| 
 | ||||
|         elif (self.ip_header.protocol == IPPROTO_UDP): | ||||
| 
 | ||||
|             self.udp_header = <udphdr*>&hdrptr | ||||
|             self.udp_header = <udphdr*>&data | ||||
| 
 | ||||
|             self.cmbhdr_len = iphdr_len + udphdr_len | ||||
|             protohdr_len = iphdr_len + 8 | ||||
| 
 | ||||
|             # self.cmbhdr_len = iphdr_len + 8 | ||||
| 
 | ||||
|         elif (self.ip_header.protocol == IPPROTO_ICMP): | ||||
| 
 | ||||
|             self.icmp_header = <icmphdr*>&hdrptr | ||||
|             self.icmp_header = <icmphdr*>&data | ||||
| 
 | ||||
|             self.cmbhdr_len = iphdr_len + icmphdr_len | ||||
|             protohdr_len = iphdr_len + 4 | ||||
| 
 | ||||
|             # self.cmbhdr_len = iphdr_len + 4 | ||||
| 
 | ||||
|         else: | ||||
|             printf('UNKNOWN PROTOCOL=%f\n', <double>self.ip_header.protocol) | ||||
| 
 | ||||
|         self.cmbhdr_len = protohdr_len + 20 | ||||
| 
 | ||||
|         self.payload = &self.data[iphdr_len+protohdr_len] | ||||
| 
 | ||||
|         printf('CMBHDR LEN=%f\n', <double>self.cmbhdr_len) | ||||
|         printf('DATA LEN=%f\n', <double>self.data_len) | ||||
| 
 | ||||
|     cdef void verdict(self, u_int32_t verdict): | ||||
|         '''Call appropriate set_verdict function on packet.''' | ||||
| @ -208,17 +218,18 @@ cdef class CPacket: | ||||
| 
 | ||||
|         self._hw = nfq_get_packet_hw(self._nfa) | ||||
|         if self._hw == NULL: | ||||
|             print(f'HW ERROR: {self._hw.hw_addr}') | ||||
|             # nfq_get_packet_hw doesn't work on OUTPUT and PREROUTING chains | ||||
|             # NOTE: making this a quick fail scenario since this would likely cause problems later in the packet | ||||
|             # parsing process and forcing error handling will ensure it is dealt with [properly]. | ||||
|             raise OSError('MAC address not available in OUTPUT and PREROUTING chains') | ||||
| 
 | ||||
|         cdef char* hw_addr = self._hw.hw_addr | ||||
|         cdef u_int8_t[8] hw_addr = self._hw.hw_addr | ||||
| 
 | ||||
|         # NOTE: this is 8 bytes in source and lib_netfilter_queue, but unsure why since mac addresses are only 6 | ||||
|         # bytes. the last two bytes may be padding, but either way removing here so it will not need to be done | ||||
|         # on the python side. | ||||
|         mac_addr = PyBytes_FromStringAndSize(hw_addr, 6) | ||||
|         mac_addr = PyBytes_FromStringAndSize(<char*>hw_addr, 6) | ||||
| 
 | ||||
|         hw_info = ( | ||||
|             in_interface, | ||||
| @ -234,6 +245,12 @@ cdef class CPacket: | ||||
| 
 | ||||
|         return self.data[:self.data_len] | ||||
| 
 | ||||
|     def get_ip_header_raw(self): | ||||
|         return self.data[:20] | ||||
| 
 | ||||
|     def get_proto_header_raw(self): | ||||
|         return self.data[20:self.cmbhdr_len] | ||||
| 
 | ||||
|     def get_ip_header(self): | ||||
|         '''Return layer3 of packet data as a tuple converted directly from C struct.''' | ||||
| 
 | ||||
| @ -298,11 +315,20 @@ cdef class CPacket: | ||||
|     def get_payload(self): | ||||
|         '''Return payload (>layer4) as Python bytes.''' | ||||
| 
 | ||||
|         cdef object payload | ||||
|         # cdef Py_ssize_t hdr_len = <Py_ssize_t>self.cmbhdr_len | ||||
| 
 | ||||
|         payload = self.data[<Py_ssize_t>self.cmbhdr_len:self.data_len] | ||||
|         cdef Py_ssize_t payload_len = self.data_len - self.cmbhdr_len | ||||
| 
 | ||||
|         return payload | ||||
| 
 | ||||
|         return self.payload[:payload_len] | ||||
| 
 | ||||
|         # if self.data_len - hdr_len > 0: | ||||
|         #     # print(f'DATA_LEN-1 = {self.data_len-1}') | ||||
|         #     # return self.data[hdr_len:self.data_len-1] | ||||
|         #     return self.payload | ||||
| 
 | ||||
|         # else: | ||||
|         #     return b'' | ||||
| 
 | ||||
| 
 | ||||
| cdef class NetfilterQueue: | ||||
| @ -371,9 +397,7 @@ cdef class NetfilterQueue: | ||||
|         cdef int fd = self.get_fd() | ||||
|         cdef char buf[4096] | ||||
|         cdef int rv | ||||
|         cdef int recv_flags | ||||
| 
 | ||||
|         recv_flags = 0 | ||||
|         cdef int recv_flags = 0 | ||||
| 
 | ||||
|         while True: | ||||
|             with nogil: | ||||
|  | ||||
							
								
								
									
										53
									
								
								nfq_test.py
									
									
									
									
									
								
							
							
						
						
									
										53
									
								
								nfq_test.py
									
									
									
									
									
								
							| @ -4,8 +4,11 @@ import threading | ||||
| 
 | ||||
| from time import perf_counter_ns | ||||
| from ipaddress import IPv4Address | ||||
| from struct import Struct | ||||
| 
 | ||||
| from new_packet import set_user_callback, NetfilterQueue | ||||
| from new_packet import set_user_callback, NetfilterQueue # pylint: disable=import-error | ||||
| 
 | ||||
| short_unpack = Struct('!H').unpack | ||||
| 
 | ||||
| TEST_FORWARD = 0 | ||||
| 
 | ||||
| @ -17,34 +20,44 @@ def print_and_accept(pkt, pkt_mark): | ||||
| #    print(pkt_mark) | ||||
| 
 | ||||
|     hw_info = pkt.get_hw() | ||||
|     print('[rcvd] hw info') | ||||
| 
 | ||||
| #    print(hw_info) | ||||
|     # print(hw_info) | ||||
| 
 | ||||
| #    print(hw_info[2].hex()) | ||||
| 
 | ||||
| #    print('-'*30) | ||||
|     # print('-'*30) | ||||
| 
 | ||||
| #    data = pkt.get_raw_packet() | ||||
|     data = pkt.get_raw_packet() | ||||
| 
 | ||||
|     print('[rcvd] RAW PACKET') | ||||
| 
 | ||||
| #    print(data[0], (data[0] & 15) * 4) | ||||
| 
 | ||||
| #    print('-'*30) | ||||
|     # print('-'*30) | ||||
| 
 | ||||
|     ip_header = pkt.get_ip_header() | ||||
|     if ip_header[6] == 6: | ||||
|         print('[rcvd] ip header') | ||||
| 
 | ||||
| #    print(ip_header) | ||||
| #    print(ip_header[6], IPv4Address(ip_header[8]), IPv4Address(ip_header[9])) | ||||
|         print(ip_header[6], IPv4Address(ip_header[8]), IPv4Address(ip_header[9])) | ||||
| 
 | ||||
| #    print('-'*30) | ||||
| 
 | ||||
|     proto_header = pkt.get_proto_header() | ||||
| 
 | ||||
| #    print(pkt.get_proto_header()) | ||||
|     if ip_header[6] == 6: | ||||
|         print('[rcvd] proto header') | ||||
|         print(f'th_off={proto_header[4]}', proto_header) | ||||
| 
 | ||||
| #    print('-'*30) | ||||
|     print('-'*30) | ||||
| 
 | ||||
|     payload = pkt.get_payload() | ||||
| #    print(pkt.get_payload()) | ||||
|     if ip_header[6] == 6: | ||||
| 
 | ||||
| 
 | ||||
|         payload = pkt.get_payload() | ||||
|         print(payload) | ||||
| 
 | ||||
| #    t, s, d = pkt.get_ip_header() | ||||
| 
 | ||||
| @ -102,7 +115,7 @@ def q_two(pkt): | ||||
|     print('-'*30) | ||||
| 
 | ||||
| def queue(callback, queue_num): | ||||
|     set_user_callback(print_and_accept) | ||||
|     set_user_callback(callback) | ||||
| 
 | ||||
|     nfqueue = NetfilterQueue() | ||||
|     nfqueue.bind(queue_num) | ||||
| @ -117,11 +130,27 @@ def queue(callback, queue_num): | ||||
|     finally: | ||||
|         nfqueue.unbind() | ||||
| 
 | ||||
| def tcp_test(packet, mark): | ||||
|     print('+'*30) | ||||
| 
 | ||||
|     start = perf_counter_ns() | ||||
|     ip_header = packet.get_ip_header() | ||||
|     if ip_header[6] == 6: | ||||
|         proto_header = packet.get_proto_header() | ||||
|         print(f'{IPv4Address(ip_header[8])}:{proto_header[0]} > {IPv4Address(ip_header[9])}:{proto_header[1]}') | ||||
|         print(packet.get_ip_header_raw()) | ||||
|         print(packet.get_proto_header_raw()) | ||||
|         print(packet.get_raw_packet()) | ||||
| 
 | ||||
|     print('='*30) | ||||
| 
 | ||||
| if __name__ == '__main__': | ||||
| 
 | ||||
|     CALLBACK = tcp_test | ||||
| 
 | ||||
|     if (TEST_FORWARD): | ||||
|         threading.Thread(target=queue, args=(q_one, 1)).start() | ||||
|         threading.Thread(target=queue, args=(q_two, 2)).start() | ||||
| 
 | ||||
|     else: | ||||
|         queue(print_and_accept, 1) | ||||
|         queue(CALLBACK, 1) | ||||
|  | ||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user
	 DOWRIGHT
						DOWRIGHT