/** * ByteBuffer dispatcher that allocates a new java.nio.ByteBuffer and dispatches * it to java listener. */ void cb_byte_buffer_dispatch(u_char *user, const pcap_pkthdr *pkt_header, const u_char *pkt_data) { cb_byte_buffer_t *data = (cb_byte_buffer_t *)user; JNIEnv *env = data->env; setJMemoryPhysical(env, data->header, toLong((void*)pkt_header)); jobject buffer = env->NewDirectByteBuffer((void *)pkt_data, pkt_header->caplen); if (buffer == NULL) { return; } env->CallVoidMethod( data->obj, data->mid, (jobject) data->header, (jobject) buffer, (jobject) data->user); env->DeleteLocalRef(buffer); if (env->ExceptionCheck() == JNI_TRUE) { data->exception = env->ExceptionOccurred(); pcap_breakloop(data->p); } }
/* * Class: org_jnetpcap_packet_JPacket_State * Method: peerHeaderByIndex * Signature: (ILorg/jnetpcap/packet/JHeader$State;)I */ JNIEXPORT jint JNICALL Java_org_jnetpcap_packet_JPacket_00024State_peerHeaderByIndex (JNIEnv *env, jobject obj, jint index, jobject dst) { packet_state_t *packet = (packet_state_t *)getJMemoryPhysical(env, obj); if (packet == NULL) { return -1; } if (index >= packet->pkt_header_count) { return -1; } setJMemoryPhysical(env, dst, toLong(&packet->pkt_headers[index])); return sizeof(header_t); }
/* * Class: org_jnetpcap_packet_JPacket_State * Method: peerHeaderById * Signature: (IILorg/jnetpcap/packet/JHeader$State;)I */ JNIEXPORT jint JNICALL Java_org_jnetpcap_packet_JPacket_00024State_peerHeaderById (JNIEnv *env, jobject obj, jint id, jint instance, jobject dst) { packet_state_t *packet = (packet_state_t *)getJMemoryPhysical(env, obj); if (packet == NULL) { return -1; } int index = findHeaderById(packet, id, instance); if (index == -1) { return -1; } setJMemoryPhysical(env, dst, toLong(&packet->pkt_headers[index])); jobject keeper = env->GetObjectField(obj, jmemoryKeeperFID); env->SetObjectField(dst, jmemoryKeeperFID, keeper); return sizeof(header_t); }
/* * Class: org_jnetpcap_packet_JHeaderScanner * Method: bindNativeScanner * Signature: (I)V */ JNIEXPORT void JNICALL Java_org_jnetpcap_packet_JHeaderScanner_bindNativeScanner (JNIEnv *env, jobject obj, jint id) { if (id < 0 || id > MAX_ID_COUNT) { sprintf(str_buf, "invalid ID=%d (%s)", id, id2str(id)); throwException(env, UNREGISTERED_SCANNER_EXCEPTION, str_buf); return; } if (native_protocols[id] == NULL) { sprintf(str_buf, "native scanner not registered under ID=%d (%s)", id, id2str(id)); throwException(env, UNREGISTERED_SCANNER_EXCEPTION, str_buf); return; } setJMemoryPhysical(env, obj, toLong((void *)native_protocols[id])); }
/** * Scan packet buffer */ int scan(JNIEnv *env, jobject obj, jobject jpacket, scanner_t *scanner, packet_state_t *p_packet, int first_id, char *buf, int buf_len, uint32_t wirelen) { scan_t scan; // Our current in progress scan's state information scan_t *pscan = &scan; scan.env = env; scan.jscanner = obj; scan.jpacket = jpacket; scan.scanner = scanner; scan.packet = p_packet; scan.header = &p_packet->pkt_headers[0]; scan.buf = buf; scan.buf_len = buf_len; // Changing buffer length, reduced by 'postfix' scan.mem_len = buf_len; // Constant in memory buffer length scan.wire_len = wirelen; scan.offset = 0; scan.length = 0; scan.id = first_id; scan.next_id = PAYLOAD_ID; scan.flags = 0; scan.stack_index = 0; scan.hdr_count = 0; scan.hdr_flags = 0; scan.hdr_prefix = 0; scan.hdr_gap = 0; scan.hdr_payload = 0; scan.hdr_postfix = 0; memset(scan.header, 0, sizeof(header_t)); // Point jscan setJMemoryPhysical(env, scanner->sc_jscan, toLong(&scan)); // Local temp variables register uint64_t mask; #ifdef DEBUG debug_enter("scan"); debug_trace("processing packet", "#%d", p_packet->pkt_frame_num); #endif /* * Main scanner loop, 1st scans for builtin header types then * reverts to calling on JBinding objects to provide the binding chain */ while (scan.id != END_OF_HEADERS) { #ifdef DEBUG debug_trace("", ""); debug_trace("processing header", id2str(scan.id)); debug_scan("loop-top", &scan); #endif /* A flag that keeps track of header recording. Set in record_header()*/ scan.is_recorded = 0; /* * If debugging is compiled in, we can also call on each protocols * debug_* function to print out details about the protocol header * structure. */ #ifdef DEBUG if (native_debug[scan.id]) { native_debug[scan.id](scan.buf + scan.offset); } #endif /* * Scan of each protocol is done through a dispatch function table. * Each protocol that has a protocol header scanner attached, a scanner * designed specifically for that protocol. The protocol id is also the * index into the table. There are 2 types of scanners both have exactly * the same signature and thus both are set in this table. The first is * the native scanner that only performs a direct scan of the header. * The second scanner is a java header scanner. It is based on * JHeaderScanner class. A single dispatch method callJavaHeaderScanner * uses the protocol ID to to dispatch to the appropriate java scanner. * Uses a separate java specific table: sc_java_header_scanners[]. The * java scanner is capable of calling the native scan method from java * but also adds the ability to check all the attached JBinding[] for * any additional registered bindings. Interesting fact is that if the * java scanner doesn't have any bindings nor does it override the * default scan method to perform a scan in java and is also setup to * dispatch to native scanner, it is exactly same thing as if the * native scanner was dispatched directly from here, but round * about way through java land. */ if (scanner->sc_scan_table[scan.id] != NULL) { scanner->sc_scan_table[scan.id](&scan); // Dispatch to scanner } #ifdef DEBUG debug_scan("loop-middle", &scan); #endif if (scan.length == 0) { #ifdef DEBUG debug_scan("loop-length==0", &scan); #endif if (scan.id == PAYLOAD_ID) { if (scan.stack_index == 0) { scan.next_id = END_OF_HEADERS; } else { scan.stack_index --; scan.next_id = scan.stack[scan.stack_index].next_id; scan.offset = scan.stack[scan.stack_index].offset; } } else { scan.next_id = PAYLOAD_ID; } } else { // length != 0 #ifdef DEBUG debug_scan("loop-length > 0", &scan); #endif /****************************************************** * **************************************************** * * If override flag is set, then we reset the * * discovered next protocol. If that is what the user * * wants then that is what he gets. * **************************************************** ******************************************************/ if (scanner->sc_flags[scan.id] & FLAG_OVERRIDE_BINDING) { #ifdef DEBUG debug_scan("TCP OVERRIDE", &scan); #endif scan.next_id = PAYLOAD_ID; } /****************************************************** * **************************************************** * * Now do HEURISTIC discovery scans if the appropriate * * flags are set. Heuristics allow us to provide nxt * * protocol binding, using discovery (an educated * * guess). * **************************************************** ******************************************************/ if (scanner->sc_flags[scan.id] & FLAG_HEURISTIC_BINDING) { /* * Save these critical properties, in case heuristic changes them * for this current header, not the next one its supposed to * check for. */ int saved_offset = scan.offset; int saved_length = scan.length; /* Advance offset to next header, so that heuristics can get a * peek. It will be restored at the end of heuristics block. */ scan.offset += scan.length + scan.hdr_gap; /* * 2 types of heuristic bindings. Pre and post. * Pre - heuristics are run before the direct discovery method * in scanner. Only after the pre-heuristic fail do we * utilize the directly discovered binding. * * Post - heuristics are run after the direct discovery method * didn't produce a binding. * * ------------------------------------------------------------ * * In our case, since we have already ran the direct discovery * in the header scanner, we save scan.next_id value, reset it, * call the heuristic function, check its scan.next_id if it * was set, if it was, then use that instead. Otherwise if it * wasn't restore the original next_id and continue on normally. */ if (scanner->sc_flags[scan.id] & FLAG_HEURISTIC_PRE_BINDING) { #ifdef DEBUG debug_scan("heurists_pre", &scan); #endif int saved_next_id = scan.next_id; scan.next_id = PAYLOAD_ID; for (int i = 0; i < MAX_ID_COUNT; i++) { native_validate_func_t validate_func; validate_func = scanner->sc_heuristics_table[scan.id][i]; if (validate_func == NULL) { break; } if ((scan.next_id = validate_func(&scan)) != INVALID) { break; } } if (scan.next_id == PAYLOAD_ID) { scan.next_id = saved_next_id; } } else if (scan.next_id == PAYLOAD_ID) { #ifdef DEBUG debug_scan("heurists_post", &scan); #endif for (int i = 0; i < MAX_ID_COUNT; i++) { native_validate_func_t validate_func; validate_func = scanner->sc_heuristics_table[scan.id][i]; if (validate_func == NULL) { break; } #ifdef DEBUG debug_trace("heurists_post", "[%d]", i); #endif if ((scan.next_id = validate_func(&scan)) != INVALID) { #ifdef DEBUG debug_scan("heurists_post::found", &scan); #endif break; } } } /* Restore these 2 critical properties */ scan.offset = saved_offset; scan.length = saved_length; } /****************************************************** * **************************************************** * * Now record discovered information in structures * **************************************************** ******************************************************/ record_header(&scan); #ifdef DEBUG debug_header("header_t", scan.header - 1); #endif } // End if len != 0 #ifdef DEBUG debug_scan("loop-bottom", &scan); #endif scan.id = scan.next_id; scan.offset += scan.length + scan.hdr_gap; scan.length = 0; scan.next_id = PAYLOAD_ID; if (scan.offset >= scan.buf_len) { scan.id = END_OF_HEADERS; } } // End for loop /* record number of header entries found */ // scan.packet->pkt_header_count = count; process_flow_key(&scan); #ifdef DEBUG debug_trace("loop-finished", "header_count=%d offset=%d header_map=0x%X", scan.packet->pkt_header_count, scan.offset, scan.packet->pkt_header_map); debug_exit("scan()"); #endif return scan.offset; } // End scan()