diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 248b236..44718f1 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -1,6 +1,7 @@ add_subdirectory(log) add_subdirectory(times) add_subdirectory(tuple) +add_subdirectory(hexdump) add_subdirectory(packet) add_subdirectory(packet_io) add_subdirectory(id_generator) diff --git a/src/hexdump/CMakeLists.txt b/src/hexdump/CMakeLists.txt new file mode 100644 index 0000000..81215e1 --- /dev/null +++ b/src/hexdump/CMakeLists.txt @@ -0,0 +1,3 @@ +add_library(hexdump hexdump.cpp) +target_include_directories(hexdump PUBLIC ${CMAKE_CURRENT_LIST_DIR}) +target_link_libraries(hexdump) \ No newline at end of file diff --git a/src/hexdump/hexdump.cpp b/src/hexdump/hexdump.cpp new file mode 100644 index 0000000..7025fb0 --- /dev/null +++ b/src/hexdump/hexdump.cpp @@ -0,0 +1,37 @@ +#include "hexdump.h" + +void hexdump_to_fd(int fd, const char *data, uint16_t len) +{ + uint16_t i = 0; + uint16_t used = 0; + uint16_t offset = 0; + +#define LINE_LEN 80 + char line[LINE_LEN]; /* space needed 8+16*3+3+16 == 75 */ + + dprintf(fd, "dump data at [%p], len=%u\n", data, len); + while (offset < len) + { + /* format the line in the buffer, then use printf to usedput to screen */ + used = snprintf(line, LINE_LEN, "%08X:", offset); + for (i = 0; ((offset + i) < len) && (i < 16); i++) + { + used += snprintf(line + used, LINE_LEN - used, " %02X", (data[offset + i] & 0xff)); + } + for (; i <= 16; i++) + { + used += snprintf(line + used, LINE_LEN - used, " | "); + } + for (i = 0; (offset < len) && (i < 16); i++, offset++) + { + unsigned char c = data[offset]; + if ((c < ' ') || (c > '~')) + { + c = '.'; + } + used += snprintf(line + used, LINE_LEN - used, "%c", c); + } + dprintf(fd, "%s\n", line); + } + dprintf(fd, "\n"); +} diff --git a/src/hexdump/hexdump.h b/src/hexdump/hexdump.h new file mode 100644 index 0000000..2e1c053 --- /dev/null +++ b/src/hexdump/hexdump.h @@ -0,0 +1,15 @@ +#pragma once + +#ifdef __cplusplus +extern "C" +{ +#endif + +#include +#include + +void hexdump_to_fd(int fd, const char *data, uint16_t len); + +#ifdef __cplusplus +} +#endif diff --git a/src/packet/CMakeLists.txt b/src/packet/CMakeLists.txt index 7e0ecb9..55f2812 100644 --- a/src/packet/CMakeLists.txt +++ b/src/packet/CMakeLists.txt @@ -2,6 +2,6 @@ add_library(packet packet_parse.cpp packet_craft.cpp packet_dump.cpp packet_util target_include_directories(packet PUBLIC ${CMAKE_CURRENT_LIST_DIR}) target_include_directories(packet PUBLIC ${CMAKE_SOURCE_DIR}/deps/uthash) target_include_directories(packet PUBLIC ${CMAKE_SOURCE_DIR}/include) -target_link_libraries(packet tuple log) +target_link_libraries(packet hexdump tuple log) add_subdirectory(test) \ No newline at end of file diff --git a/src/packet/packet_dump.cpp b/src/packet/packet_dump.cpp index b7ffc43..000079b 100644 --- a/src/packet/packet_dump.cpp +++ b/src/packet/packet_dump.cpp @@ -5,6 +5,7 @@ #include #include "log.h" +#include "hexdump.h" #include "packet_dump.h" #include "packet_utils.h" @@ -78,16 +79,8 @@ int packet_dump_pcap(const struct packet *pkt, const char *file) void packet_dump_hex(const struct packet *pkt, int fd) { - const char *data = packet_get_raw_data(pkt); uint16_t len = packet_get_raw_len(pkt); + const char *data = packet_get_raw_data(pkt); - for (int i = 0; i < len; i++) - { - if (i % 16 == 0) - { - dprintf(fd, "\n"); - } - dprintf(fd, "%02x ", (unsigned char)data[i]); - } - dprintf(fd, "\n"); + hexdump_to_fd(fd, data, len); } \ No newline at end of file diff --git a/src/packet/packet_parse.cpp b/src/packet/packet_parse.cpp index 6a283c0..d40226f 100644 --- a/src/packet/packet_parse.cpp +++ b/src/packet/packet_parse.cpp @@ -986,79 +986,87 @@ const char *packet_parse(struct packet *pkt, const char *data, uint16_t len) return parse_ether(pkt, data, len); } -void packet_print(const struct packet *pkt) +int packet_to_str(const struct packet *pkt, char *buff, int size) { if (pkt == NULL) { - return; + return 0; } - char buffer[2048] = {0}; - printf("packet: %p, data_ptr: %p, data_len: %u, trim_len: %u, layers_used: %u, layers_size: %u\n", - pkt, pkt->data_ptr, pkt->data_len, pkt->trim_len, - pkt->layers_used, pkt->layers_size); + int used = 0; + memset(buff, 0, size); + used += snprintf(buff + used, size - used, "packet: %p, data_ptr: %p, data_len: %u, trim_len: %u, layers_used: %u, layers_size: %u\n", + pkt, pkt->data_ptr, pkt->data_len, pkt->trim_len, + pkt->layers_used, pkt->layers_size); for (uint8_t i = 0; i < pkt->layers_used; i++) { - int used = 0; const struct raw_layer *layer = &pkt->layers[i]; - printf(" layer[%u]: %p, proto: %s, header: {offset: %u, ptr: %p, len: %u}, payload: {ptr: %p, len: %u}\n", - i, layer, layer_proto_to_str(layer->proto), layer->hdr_offset, - layer->hdr_ptr, layer->hdr_len, layer->pld_ptr, layer->pld_len); + used += snprintf(buff + used, size - used, "=> layer[%u]: %p, proto: %s, header: {offset: %u, ptr: %p, len: %u}, payload: {ptr: %p, len: %u}\n", + i, layer, layer_proto_to_str(layer->proto), layer->hdr_offset, + layer->hdr_ptr, layer->hdr_len, layer->pld_ptr, layer->pld_len); switch (layer->proto) { case LAYER_PROTO_ETHER: - used = eth_hdr_to_str((const struct ethhdr *)layer->hdr_ptr, buffer, sizeof(buffer)); + used += eth_hdr_to_str((const struct ethhdr *)layer->hdr_ptr, buff + used, size - used); + used += snprintf(buff + used, size - used, "\n"); break; case LAYER_PROTO_PWETH: break; case LAYER_PROTO_PPP: break; case LAYER_PROTO_L2TP: - used = l2tp_hdr_to_str((const struct l2tp_hdr *)layer->hdr_ptr, buffer, sizeof(buffer)); + used += l2tp_hdr_to_str((const struct l2tp_hdr *)layer->hdr_ptr, buff + used, size - used); + used += snprintf(buff + used, size - used, "\n"); break; case LAYER_PROTO_VLAN: - used = vlan_hdr_to_str((const struct vlan_hdr *)layer->hdr_ptr, buffer, sizeof(buffer)); + used += vlan_hdr_to_str((const struct vlan_hdr *)layer->hdr_ptr, buff + used, size - used); + used += snprintf(buff + used, size - used, "\n"); break; case LAYER_PROTO_PPPOE: break; case LAYER_PROTO_MPLS: - used = mpls_label_to_str((const struct mpls_label *)layer->hdr_ptr, buffer, sizeof(buffer)); - break; + used += mpls_label_to_str((const struct mpls_label *)layer->hdr_ptr, buff + used, size - used); + used += snprintf(buff + used, size - used, "\n"); break; case LAYER_PROTO_IPV4: - used = ip4_hdr_to_str((const struct ip *)layer->hdr_ptr, buffer, sizeof(buffer)); + used += ip4_hdr_to_str((const struct ip *)layer->hdr_ptr, buff + used, size - used); + used += snprintf(buff + used, size - used, "\n"); break; case LAYER_PROTO_IPV6: - used = ip6_hdr_to_str((const struct ip6_hdr *)layer->hdr_ptr, buffer, sizeof(buffer)); + used += ip6_hdr_to_str((const struct ip6_hdr *)layer->hdr_ptr, buff + used, size - used); + used += snprintf(buff + used, size - used, "\n"); break; case LAYER_PROTO_IPAH: break; case LAYER_PROTO_GRE: - used = gre_hdr_to_str(layer->hdr_ptr, layer->hdr_len, buffer, sizeof(buffer)); + used += gre_hdr_to_str(layer->hdr_ptr, layer->hdr_len, buff + used, size - used); + used += snprintf(buff + used, size - used, "\n"); break; case LAYER_PROTO_UDP: - used = udp_hdr_to_str((const struct udphdr *)layer->hdr_ptr, buffer, sizeof(buffer)); + used += udp_hdr_to_str((const struct udphdr *)layer->hdr_ptr, buff + used, size - used); + used += snprintf(buff + used, size - used, "\n"); break; case LAYER_PROTO_TCP: - used = tcp_hdr_to_str((const struct tcphdr *)layer->hdr_ptr, buffer, sizeof(buffer)); + used += tcp_hdr_to_str((const struct tcphdr *)layer->hdr_ptr, buff + used, size - used); + used += snprintf(buff + used, size - used, "\n"); break; case LAYER_PROTO_ICMP: break; case LAYER_PROTO_ICMP6: break; case LAYER_PROTO_VXLAN: - used = vxlan_hdr_to_str((const struct vxlan_hdr *)layer->hdr_ptr, buffer, sizeof(buffer)); + used += vxlan_hdr_to_str((const struct vxlan_hdr *)layer->hdr_ptr, buff + used, size - used); + used += snprintf(buff + used, size - used, "\n"); break; case LAYER_PROTO_GTP_C: case LAYER_PROTO_GTP_U: - used = gtp_hdr_to_str(layer->hdr_ptr, layer->hdr_len, buffer, sizeof(buffer)); + used += gtp_hdr_to_str(layer->hdr_ptr, layer->hdr_len, buff + used, size - used); + used += snprintf(buff + used, size - used, "\n"); break; default: break; } - if (used) - { - printf(" %s\n", buffer); - } } -} + + return used; +} \ No newline at end of file diff --git a/src/packet/packet_parse.h b/src/packet/packet_parse.h index bbd8ea3..5a47ef4 100644 --- a/src/packet/packet_parse.h +++ b/src/packet/packet_parse.h @@ -6,9 +6,20 @@ extern "C" #endif #include +#include const char *packet_parse(struct packet *pkt, const char *data, uint16_t len); -void packet_print(const struct packet *pkt); + +// bref : 1, output packet bref info +// bref : 0, output packet detail info +int packet_to_str(const struct packet *pkt, char *buff, int size); + +static inline void packet_print(const struct packet *pkt) +{ + char buff[4096]; + packet_to_str(pkt, buff, sizeof(buff)); + printf("%s\n", buff); +} #ifdef __cplusplus } diff --git a/src/packet/test/gtest_packet_craft.cpp b/src/packet/test/gtest_packet_craft.cpp index f2872f6..a084862 100644 --- a/src/packet/test/gtest_packet_craft.cpp +++ b/src/packet/test/gtest_packet_craft.cpp @@ -12,6 +12,7 @@ #include "packet_layer.h" #include "packet_parse.h" #include "packet_craft.h" +#include "packet_utils.h" #define PRINT_GREEN(fmt, ...) printf("\033[0;32m" fmt "\033[0m\n", ##__VA_ARGS__) #define PRINT_RED(fmt, ...) printf("\033[0;31m" fmt "\033[0m\n", ##__VA_ARGS__) @@ -191,6 +192,8 @@ TEST(PACKET_CRAFT_TCP, ETH_IP4_TCP) // printf(("idx: %d, orig: %02x, new: %02x\n"), i, orig_pkt_data[i], new_pkt_data[i]); EXPECT_TRUE(orig_pkt_data[i] == new_pkt_data[i]); } + + packet_free(new_pkt); } #endif @@ -336,6 +339,8 @@ TEST(PACKET_CRAFT_TCP, ETH_IP4_IP6_TCP) // printf(("idx: %d, orig: %02x, new: %02x\n"), i, orig_pkt_data[i], new_pkt_data[i]); EXPECT_TRUE(orig_pkt_data[i] == new_pkt_data[i]); } + + packet_free(new_pkt); } #endif @@ -574,6 +579,8 @@ TEST(PACKET_CRAFT_TCP, ETH_IP6_UDP_GTP_IP4_TCP) // printf(("idx: %d, orig: %02x, new: %02x\n"), i, orig_pkt_data[i], new_pkt_data[i]); EXPECT_TRUE(orig_pkt_data[i] == new_pkt_data[i]); } + + packet_free(new_pkt); } #endif @@ -780,6 +787,8 @@ TEST(PACKET_CRAFT_TCP, ETH_IP4_GRE_IP6_TCP) // printf(("idx: %d, orig: %02x, new: %02x\n"), i, orig_pkt_data[i], new_pkt_data[i]); EXPECT_TRUE(orig_pkt_data[i] == new_pkt_data[i]); } + + packet_free(new_pkt); } #endif @@ -1011,6 +1020,8 @@ TEST(PACKET_CRAFT_UDP, ETH_VLAN_IPv6_IPv4_GRE_PPP_IPv4_UDP_DNS) printf(("idx: %d, orig: %02x, new: %02x\n"), i, orig_pkt_data[i], new_pkt_data[i]); EXPECT_TRUE(orig_pkt_data[i] == new_pkt_data[i]); } + + packet_free(new_pkt); } #endif diff --git a/src/session/session_utils.cpp b/src/session/session_utils.cpp index 6d4c007..2cbde33 100644 --- a/src/session/session_utils.cpp +++ b/src/session/session_utils.cpp @@ -494,106 +494,113 @@ static void tcp_flags_to_str(uint8_t flags, char *buffer, size_t len) } } -int session_to_json(struct session *sess, char *buff, int size) +int session_to_str(const struct session *sess, int bref, char *buff, int size) { memset(buff, 0, size); char flags[64] = {0}; int used = 0; - used += snprintf(buff + used, size - used, "{"); - used += snprintf(buff + used, size - used, "\"id\":%" PRIu64 ",", session_get_id(sess)); - used += snprintf(buff + used, size - used, "\"start_timestamp\":%" PRIu64 ",", session_get_timestamp(sess, SESSION_TIMESTAMP_START)); - used += snprintf(buff + used, size - used, "\"last_timestamp\":%" PRIu64 ",", session_get_timestamp(sess, SESSION_TIMESTAMP_LAST)); - used += snprintf(buff + used, size - used, "\"tuple\":\"%s\",", session_get0_readable_addr(sess)); - used += snprintf(buff + used, size - used, "\"type\":\"%s\",", session_type_to_str(session_get_type(sess))); - used += snprintf(buff + used, size - used, "\"state\":\"%s\",", session_state_to_str(session_get_current_state(sess))); - used += snprintf(buff + used, size - used, "\"closing_reason\":\"%s\",", closing_reason_to_str(session_get_closing_reason(sess))); - used += snprintf(buff + used, size - used, "\"duplicate_traffic\":%d,", session_has_duplicate_traffic(sess)); - used += snprintf(buff + used, size - used, "\"current_packet\":\"%p\",", session_get0_current_packet(sess)); - - const char *str[] = {"c2s", "s2c"}; - enum flow_direction dir[] = {FLOW_DIRECTION_C2S, FLOW_DIRECTION_S2C}; - for (int i = 0; i < 2; i++) + if (bref) { - // raw packets - used += snprintf(buff + used, size - used, "\"%s_raw_packets_received\":%" PRIu64 ",", str[i], session_get_stat(sess, dir[i], STAT_RAW_PACKETS_RECEIVED)); - used += snprintf(buff + used, size - used, "\"%s_raw_bytes_received\":%" PRIu64 ",", str[i], session_get_stat(sess, dir[i], STAT_RAW_BYTES_RECEIVED)); - - used += snprintf(buff + used, size - used, "\"%s_raw_packets_transmitted\":%" PRIu64 ",", str[i], session_get_stat(sess, dir[i], STAT_RAW_PACKETS_TRANSMITTED)); - used += snprintf(buff + used, size - used, "\"%s_raw_bytes_transmitted\":%" PRIu64 ",", str[i], session_get_stat(sess, dir[i], STAT_RAW_BYTES_TRANSMITTED)); - - used += snprintf(buff + used, size - used, "\"%s_raw_packets_dropped\":%" PRIu64 ",", str[i], session_get_stat(sess, dir[i], STAT_RAW_PACKETS_DROPPED)); - used += snprintf(buff + used, size - used, "\"%s_raw_bytes_dropped\":%" PRIu64 ",", str[i], session_get_stat(sess, dir[i], STAT_RAW_BYTES_DROPPED)); - - // duplicate packets - used += snprintf(buff + used, size - used, "\"%s_duplicate_packets_bypass\":%" PRIu64 ",", str[i], session_get_stat(sess, dir[i], STAT_DUPLICATE_PACKETS_BYPASS)); - used += snprintf(buff + used, size - used, "\"%s_duplicate_bytes_bypass\":%" PRIu64 ",", str[i], session_get_stat(sess, dir[i], STAT_DUPLICATE_BYTES_BYPASS)); - - // injected packets - used += snprintf(buff + used, size - used, "\"%s_injected_packets_failed\":%" PRIu64 ",", str[i], session_get_stat(sess, dir[i], STAT_INJECTED_PACKETS_FAILED)); - used += snprintf(buff + used, size - used, "\"%s_injected_packets_success\":%" PRIu64 ",", str[i], session_get_stat(sess, dir[i], STAT_INJECTED_PACKETS_SUCCESS)); - used += snprintf(buff + used, size - used, "\"%s_injected_bytes_success\":%" PRIu64 ",", str[i], session_get_stat(sess, dir[i], STAT_INJECTED_BYTES_SUCCESS)); - - // control packets - used += snprintf(buff + used, size - used, "\"%s_control_packets_received\":%" PRIu64 ",", str[i], session_get_stat(sess, dir[i], STAT_CONTROL_PACKETS_RECEIVED)); - used += snprintf(buff + used, size - used, "\"%s_control_bytes_received\":%" PRIu64 ",", str[i], session_get_stat(sess, dir[i], STAT_CONTROL_BYTES_RECEIVED)); - - used += snprintf(buff + used, size - used, "\"%s_control_packets_transmitted\":%" PRIu64 ",", str[i], session_get_stat(sess, dir[i], STAT_CONTROL_PACKETS_TRANSMITTED)); - used += snprintf(buff + used, size - used, "\"%s_control_bytes_transmitted\":%" PRIu64 ",", str[i], session_get_stat(sess, dir[i], STAT_CONTROL_BYTES_TRANSMITTED)); - - used += snprintf(buff + used, size - used, "\"%s_control_packets_dropped\":%" PRIu64 ",", str[i], session_get_stat(sess, dir[i], STAT_CONTROL_PACKETS_DROPPED)); - used += snprintf(buff + used, size - used, "\"%s_control_bytes_dropped\":%" PRIu64 ",", str[i], session_get_stat(sess, dir[i], STAT_CONTROL_BYTES_DROPPED)); - - if (session_get_type(sess) == SESSION_TYPE_TCP) - { - used += snprintf(buff + used, size - used, "\"%s_tcp_last_seq\":%u,", str[i], sess->tcp_halfs[dir[i]].seq); - used += snprintf(buff + used, size - used, "\"%s_tcp_last_ack\":%u,", str[i], sess->tcp_halfs[dir[i]].ack); - memset(flags, 0, sizeof(flags)); - tcp_flags_to_str(sess->tcp_halfs[dir[i]].flags, flags, sizeof(flags)); - used += snprintf(buff + used, size - used, "\"%s_tcp_flags\":\"%s\",", str[i], flags); - - used += snprintf(buff + used, size - used, "\"%s_tcp_segments_received\":%" PRIu64 ",", str[i], session_get_stat(sess, dir[i], STAT_TCP_SEGMENTS_RECEIVED)); - used += snprintf(buff + used, size - used, "\"%s_tcp_payloads_received\":%" PRIu64 ",", str[i], session_get_stat(sess, dir[i], STAT_TCP_PAYLOADS_RECEIVED)); - - used += snprintf(buff + used, size - used, "\"%s_tcp_segments_expired\":%" PRIu64 ",", str[i], session_get_stat(sess, dir[i], STAT_TCP_SEGMENTS_EXPIRED)); - used += snprintf(buff + used, size - used, "\"%s_tcp_payloads_expired\":%" PRIu64 ",", str[i], session_get_stat(sess, dir[i], STAT_TCP_PAYLOADS_EXPIRED)); - - used += snprintf(buff + used, size - used, "\"%s_tcp_segments_retransmit\":%" PRIu64 ",", str[i], session_get_stat(sess, dir[i], STAT_TCP_SEGMENTS_RETRANSMIT)); - used += snprintf(buff + used, size - used, "\"%s_tcp_payloads_retransmit\":%" PRIu64 ",", str[i], session_get_stat(sess, dir[i], STAT_TCP_PAYLOADS_RETRANSMIT)); - - used += snprintf(buff + used, size - used, "\"%s_tcp_segments_overlap\":%" PRIu64 ",", str[i], session_get_stat(sess, dir[i], STAT_TCP_SEGMENTS_OVERLAP)); - used += snprintf(buff + used, size - used, "\"%s_tcp_payloads_overlap\":%" PRIu64 ",", str[i], session_get_stat(sess, dir[i], STAT_TCP_PAYLOADS_OVERLAP)); - - used += snprintf(buff + used, size - used, "\"%s_tcp_segments_nospace\":%" PRIu64 ",", str[i], session_get_stat(sess, dir[i], STAT_TCP_SEGMENTS_NOSPACE)); - used += snprintf(buff + used, size - used, "\"%s_tcp_payloads_nospace\":%" PRIu64 ",", str[i], session_get_stat(sess, dir[i], STAT_TCP_PAYLOADS_NOSPACE)); - - used += snprintf(buff + used, size - used, "\"%s_tcp_segments_inorder\":%" PRIu64 ",", str[i], session_get_stat(sess, dir[i], STAT_TCP_SEGMENTS_INORDER)); - used += snprintf(buff + used, size - used, "\"%s_tcp_payloads_inorder\":%" PRIu64 ",", str[i], session_get_stat(sess, dir[i], STAT_TCP_PAYLOADS_INORDER)); - - used += snprintf(buff + used, size - used, "\"%s_tcp_segments_reordered\":%" PRIu64 ",", str[i], session_get_stat(sess, dir[i], STAT_TCP_SEGMENTS_REORDERED)); - used += snprintf(buff + used, size - used, "\"%s_tcp_payloads_reordered\":%" PRIu64 ",", str[i], session_get_stat(sess, dir[i], STAT_TCP_PAYLOADS_REORDERED)); - - used += snprintf(buff + used, size - used, "\"%s_tcp_segments_buffered\":%" PRIu64 ",", str[i], session_get_stat(sess, dir[i], STAT_TCP_SEGMENTS_BUFFERED)); - used += snprintf(buff + used, size - used, "\"%s_tcp_payloads_buffered\":%" PRIu64 ",", str[i], session_get_stat(sess, dir[i], STAT_TCP_PAYLOADS_BUFFERED)); - - used += snprintf(buff + used, size - used, "\"%s_tcp_segments_released\":%" PRIu64 ",", str[i], session_get_stat(sess, dir[i], STAT_TCP_SEGMENTS_RELEASED)); - used += snprintf(buff + used, size - used, "\"%s_tcp_payloads_released\":%" PRIu64 ",", str[i], session_get_stat(sess, dir[i], STAT_TCP_PAYLOADS_RELEASED)); - } - - used += snprintf(buff + used, size - used, "\"%s_first_packet\":\"%p\"", str[i], session_get_first_packet(sess, dir[i])); - if (i == 0) - { - used += snprintf(buff + used, size - used, ","); - } + used += snprintf(buff + used, size - used, "session id: %lu, addr: %s, type: %s, state: %s, dir: %s, c2s_rx_pkts: %lu, s2c_rx_pkts: %lu", + session_get_id(sess), + session_get0_readable_addr(sess), + session_type_to_str(session_get_type(sess)), + session_state_to_str(session_get_current_state(sess)), + flow_direction_to_str(session_get_current_flow_direction(sess)), + session_get_stat(sess, FLOW_DIRECTION_C2S, STAT_RAW_PACKETS_RECEIVED), + session_get_stat(sess, FLOW_DIRECTION_S2C, STAT_RAW_PACKETS_RECEIVED)); + } + else + { + used += snprintf(buff + used, size - used, "{"); + used += snprintf(buff + used, size - used, "\"id\":%" PRIu64 ",", session_get_id(sess)); + used += snprintf(buff + used, size - used, "\"start_timestamp\":%" PRIu64 ",", session_get_timestamp(sess, SESSION_TIMESTAMP_START)); + used += snprintf(buff + used, size - used, "\"last_timestamp\":%" PRIu64 ",", session_get_timestamp(sess, SESSION_TIMESTAMP_LAST)); + used += snprintf(buff + used, size - used, "\"tuple\":\"%s\",", session_get0_readable_addr(sess)); + used += snprintf(buff + used, size - used, "\"type\":\"%s\",", session_type_to_str(session_get_type(sess))); + used += snprintf(buff + used, size - used, "\"state\":\"%s\",", session_state_to_str(session_get_current_state(sess))); + used += snprintf(buff + used, size - used, "\"closing_reason\":\"%s\",", closing_reason_to_str(session_get_closing_reason(sess))); + used += snprintf(buff + used, size - used, "\"duplicate_traffic\":%d,", session_has_duplicate_traffic(sess)); + used += snprintf(buff + used, size - used, "\"current_packet\":\"%p\",", session_get0_current_packet(sess)); + + const char *str[] = {"c2s", "s2c"}; + enum flow_direction dir[] = {FLOW_DIRECTION_C2S, FLOW_DIRECTION_S2C}; + for (int i = 0; i < 2; i++) + { + // raw packets + used += snprintf(buff + used, size - used, "\"%s_raw_packets_received\":%" PRIu64 ",", str[i], session_get_stat(sess, dir[i], STAT_RAW_PACKETS_RECEIVED)); + used += snprintf(buff + used, size - used, "\"%s_raw_bytes_received\":%" PRIu64 ",", str[i], session_get_stat(sess, dir[i], STAT_RAW_BYTES_RECEIVED)); + + used += snprintf(buff + used, size - used, "\"%s_raw_packets_transmitted\":%" PRIu64 ",", str[i], session_get_stat(sess, dir[i], STAT_RAW_PACKETS_TRANSMITTED)); + used += snprintf(buff + used, size - used, "\"%s_raw_bytes_transmitted\":%" PRIu64 ",", str[i], session_get_stat(sess, dir[i], STAT_RAW_BYTES_TRANSMITTED)); + + used += snprintf(buff + used, size - used, "\"%s_raw_packets_dropped\":%" PRIu64 ",", str[i], session_get_stat(sess, dir[i], STAT_RAW_PACKETS_DROPPED)); + used += snprintf(buff + used, size - used, "\"%s_raw_bytes_dropped\":%" PRIu64 ",", str[i], session_get_stat(sess, dir[i], STAT_RAW_BYTES_DROPPED)); + + // duplicate packets + used += snprintf(buff + used, size - used, "\"%s_duplicate_packets_bypass\":%" PRIu64 ",", str[i], session_get_stat(sess, dir[i], STAT_DUPLICATE_PACKETS_BYPASS)); + used += snprintf(buff + used, size - used, "\"%s_duplicate_bytes_bypass\":%" PRIu64 ",", str[i], session_get_stat(sess, dir[i], STAT_DUPLICATE_BYTES_BYPASS)); + + // injected packets + used += snprintf(buff + used, size - used, "\"%s_injected_packets_failed\":%" PRIu64 ",", str[i], session_get_stat(sess, dir[i], STAT_INJECTED_PACKETS_FAILED)); + used += snprintf(buff + used, size - used, "\"%s_injected_packets_success\":%" PRIu64 ",", str[i], session_get_stat(sess, dir[i], STAT_INJECTED_PACKETS_SUCCESS)); + used += snprintf(buff + used, size - used, "\"%s_injected_bytes_success\":%" PRIu64 ",", str[i], session_get_stat(sess, dir[i], STAT_INJECTED_BYTES_SUCCESS)); + + // control packets + used += snprintf(buff + used, size - used, "\"%s_control_packets_received\":%" PRIu64 ",", str[i], session_get_stat(sess, dir[i], STAT_CONTROL_PACKETS_RECEIVED)); + used += snprintf(buff + used, size - used, "\"%s_control_bytes_received\":%" PRIu64 ",", str[i], session_get_stat(sess, dir[i], STAT_CONTROL_BYTES_RECEIVED)); + + used += snprintf(buff + used, size - used, "\"%s_control_packets_transmitted\":%" PRIu64 ",", str[i], session_get_stat(sess, dir[i], STAT_CONTROL_PACKETS_TRANSMITTED)); + used += snprintf(buff + used, size - used, "\"%s_control_bytes_transmitted\":%" PRIu64 ",", str[i], session_get_stat(sess, dir[i], STAT_CONTROL_BYTES_TRANSMITTED)); + + used += snprintf(buff + used, size - used, "\"%s_control_packets_dropped\":%" PRIu64 ",", str[i], session_get_stat(sess, dir[i], STAT_CONTROL_PACKETS_DROPPED)); + used += snprintf(buff + used, size - used, "\"%s_control_bytes_dropped\":%" PRIu64 ",", str[i], session_get_stat(sess, dir[i], STAT_CONTROL_BYTES_DROPPED)); + + if (session_get_type(sess) == SESSION_TYPE_TCP) + { + used += snprintf(buff + used, size - used, "\"%s_tcp_last_seq\":%u,", str[i], sess->tcp_halfs[dir[i]].seq); + used += snprintf(buff + used, size - used, "\"%s_tcp_last_ack\":%u,", str[i], sess->tcp_halfs[dir[i]].ack); + memset(flags, 0, sizeof(flags)); + tcp_flags_to_str(sess->tcp_halfs[dir[i]].flags, flags, sizeof(flags)); + used += snprintf(buff + used, size - used, "\"%s_tcp_flags\":\"%s\",", str[i], flags); + + used += snprintf(buff + used, size - used, "\"%s_tcp_segments_received\":%" PRIu64 ",", str[i], session_get_stat(sess, dir[i], STAT_TCP_SEGMENTS_RECEIVED)); + used += snprintf(buff + used, size - used, "\"%s_tcp_payloads_received\":%" PRIu64 ",", str[i], session_get_stat(sess, dir[i], STAT_TCP_PAYLOADS_RECEIVED)); + + used += snprintf(buff + used, size - used, "\"%s_tcp_segments_expired\":%" PRIu64 ",", str[i], session_get_stat(sess, dir[i], STAT_TCP_SEGMENTS_EXPIRED)); + used += snprintf(buff + used, size - used, "\"%s_tcp_payloads_expired\":%" PRIu64 ",", str[i], session_get_stat(sess, dir[i], STAT_TCP_PAYLOADS_EXPIRED)); + + used += snprintf(buff + used, size - used, "\"%s_tcp_segments_retransmit\":%" PRIu64 ",", str[i], session_get_stat(sess, dir[i], STAT_TCP_SEGMENTS_RETRANSMIT)); + used += snprintf(buff + used, size - used, "\"%s_tcp_payloads_retransmit\":%" PRIu64 ",", str[i], session_get_stat(sess, dir[i], STAT_TCP_PAYLOADS_RETRANSMIT)); + + used += snprintf(buff + used, size - used, "\"%s_tcp_segments_overlap\":%" PRIu64 ",", str[i], session_get_stat(sess, dir[i], STAT_TCP_SEGMENTS_OVERLAP)); + used += snprintf(buff + used, size - used, "\"%s_tcp_payloads_overlap\":%" PRIu64 ",", str[i], session_get_stat(sess, dir[i], STAT_TCP_PAYLOADS_OVERLAP)); + + used += snprintf(buff + used, size - used, "\"%s_tcp_segments_nospace\":%" PRIu64 ",", str[i], session_get_stat(sess, dir[i], STAT_TCP_SEGMENTS_NOSPACE)); + used += snprintf(buff + used, size - used, "\"%s_tcp_payloads_nospace\":%" PRIu64 ",", str[i], session_get_stat(sess, dir[i], STAT_TCP_PAYLOADS_NOSPACE)); + + used += snprintf(buff + used, size - used, "\"%s_tcp_segments_inorder\":%" PRIu64 ",", str[i], session_get_stat(sess, dir[i], STAT_TCP_SEGMENTS_INORDER)); + used += snprintf(buff + used, size - used, "\"%s_tcp_payloads_inorder\":%" PRIu64 ",", str[i], session_get_stat(sess, dir[i], STAT_TCP_PAYLOADS_INORDER)); + + used += snprintf(buff + used, size - used, "\"%s_tcp_segments_reordered\":%" PRIu64 ",", str[i], session_get_stat(sess, dir[i], STAT_TCP_SEGMENTS_REORDERED)); + used += snprintf(buff + used, size - used, "\"%s_tcp_payloads_reordered\":%" PRIu64 ",", str[i], session_get_stat(sess, dir[i], STAT_TCP_PAYLOADS_REORDERED)); + + used += snprintf(buff + used, size - used, "\"%s_tcp_segments_buffered\":%" PRIu64 ",", str[i], session_get_stat(sess, dir[i], STAT_TCP_SEGMENTS_BUFFERED)); + used += snprintf(buff + used, size - used, "\"%s_tcp_payloads_buffered\":%" PRIu64 ",", str[i], session_get_stat(sess, dir[i], STAT_TCP_PAYLOADS_BUFFERED)); + + used += snprintf(buff + used, size - used, "\"%s_tcp_segments_released\":%" PRIu64 ",", str[i], session_get_stat(sess, dir[i], STAT_TCP_SEGMENTS_RELEASED)); + used += snprintf(buff + used, size - used, "\"%s_tcp_payloads_released\":%" PRIu64 ",", str[i], session_get_stat(sess, dir[i], STAT_TCP_PAYLOADS_RELEASED)); + } + + used += snprintf(buff + used, size - used, "\"%s_first_packet\":\"%p\"", str[i], session_get_first_packet(sess, dir[i])); + if (i == 0) + { + used += snprintf(buff + used, size - used, ","); + } + } + used += snprintf(buff + used, size - used, "}"); } - used += snprintf(buff + used, size - used, "}"); return used; -} - -void session_print(struct session *sess) -{ - char buff[4096]; - session_to_json(sess, buff, sizeof(buff)); - printf("%s\n", buff); } \ No newline at end of file diff --git a/src/session/session_utils.h b/src/session/session_utils.h index cd2811c..65143b9 100644 --- a/src/session/session_utils.h +++ b/src/session/session_utils.h @@ -6,6 +6,7 @@ extern "C" #endif #include +#include #include "stellar/session.h" @@ -131,8 +132,16 @@ const char *session_state_to_str(enum session_state state); const char *session_type_to_str(enum session_type type); const char *flow_direction_to_str(enum flow_direction dir); -int session_to_json(struct session *sess, char *buff, int size); -void session_print(struct session *sess); +// bref : 1, output session bref info +// bref : 0, output session detail info +int session_to_str(const struct session *sess, int bref, char *buff, int size); + +static inline void session_print(const struct session *sess) +{ + char buff[4096]; + session_to_str(sess, 0, buff, sizeof(buff)); + printf("%s\n", buff); +} #ifdef __cplusplus } diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index 3527117..4001cb1 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -1,2 +1,3 @@ add_subdirectory(packet_inject) -add_subdirectory(packet_tool) \ No newline at end of file +add_subdirectory(packet_tool) +add_subdirectory(debug_plugin) \ No newline at end of file diff --git a/test/debug_plugin/CMakeLists.txt b/test/debug_plugin/CMakeLists.txt new file mode 100644 index 0000000..c71e302 --- /dev/null +++ b/test/debug_plugin/CMakeLists.txt @@ -0,0 +1,8 @@ +# build libdebug_plugin.so +add_library(debug_plugin SHARED debug_plugin.cpp) +# Note: The debug plugin here uses stellar_core instead of stellar_devel, in order to output more session/packet information for development debugging. +target_link_libraries(debug_plugin stellar_core toml) +target_include_directories(debug_plugin PUBLIC ${CMAKE_SOURCE_DIR}/include/) +set_target_properties(debug_plugin PROPERTIES LINK_FLAGS "-Wl,--version-script=${CMAKE_CURRENT_LIST_DIR}/version.map") + +file(COPY ./conf/ DESTINATION ./conf/) \ No newline at end of file diff --git a/test/debug_plugin/conf/spec.toml b/test/debug_plugin/conf/spec.toml new file mode 100644 index 0000000..08ecfbf --- /dev/null +++ b/test/debug_plugin/conf/spec.toml @@ -0,0 +1,4 @@ +[[plugin]] +path = "./plugin/libdebug_plugin.so" +init = "debug_plugin_init" +exit = "debug_plugin_exit" diff --git a/test/debug_plugin/debug_plugin.cpp b/test/debug_plugin/debug_plugin.cpp new file mode 100644 index 0000000..f055191 --- /dev/null +++ b/test/debug_plugin/debug_plugin.cpp @@ -0,0 +1,196 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "log.h" +#include "hexdump.h" +#include "session_utils.h" +#include "tcp_reassembly.h" +#include "packet_dump.h" +#include "packet_parse.h" +#include "packet_utils.h" +#include "stellar/session_mq.h" + +// NOTE: packet hexdump or tcp segment hexdump may be too long, so we need direct output to fd, instead of using log_print +static void log_print(int fd, const char *module, const char *fmt, ...) +{ + static unsigned char weekday_str[7][4] = {"Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"}; + static unsigned char month_str[12][4] = {"Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"}; + + int nwrite; + char buf[4096 * 2] = {0}; + char *p = buf; + char *end = buf + sizeof(buf); + va_list args; + struct tm local; + + time_t t; + time(&t); + localtime_r(&t, &local); + + // add time + p += snprintf(p, end - p, "%s %s %d %02d:%02d:%02d %d ", + weekday_str[local.tm_wday], month_str[local.tm_mon], local.tm_mday, local.tm_hour, local.tm_min, local.tm_sec, local.tm_year + 1900); + // add tid + p += snprintf(p, end - p, "%lu ", pthread_self()); + // add module + p += snprintf(p, end - p, "(%s), ", module); + // add content + va_start(args, fmt); + p += vsnprintf(p, end - p, fmt, args); + va_end(args); + // add end of line + p += snprintf(p, end - p, "\n"); + + do + { + nwrite = write(fd, buf, p - buf); + } while (nwrite == -1 && errno == EINTR); +} + +struct plugin_ctx +{ + struct stellar *st; + int sess_plug_id; + int tcp_topic_id; + int udp_topic_id; + int tcp_stream_topic_id; + int fd; + pthread_spinlock_t lock; // for hexdump thread safe +}; + +static void *on_sess_new(struct session *sess, void *plugin_ctx) +{ + char buff[4096]; + struct plugin_ctx *ctx = (struct plugin_ctx *)plugin_ctx; + + memset(buff, 0, sizeof(buff)); + session_to_str(sess, 1, buff, sizeof(buff) - 1); + log_print(ctx->fd, "debug plugin", "sess new: %s", buff); + + return NULL; +} + +static void on_sess_free(struct session *sess, void *sess_ctx, void *plugin_ctx) +{ + char buff[4096]; + struct plugin_ctx *ctx = (struct plugin_ctx *)plugin_ctx; + + memset(buff, 0, sizeof(buff)); + session_to_str(sess, 0, buff, sizeof(buff) - 1); + log_print(ctx->fd, "debug plugin", "sess free: %s", buff); +} + +static void on_sess_udp_msg(struct session *sess, int topic_id, const void *msg, void *sess_ctx, void *plugin_ctx) +{ + char buff[4096]; + struct packet *pkt = (struct packet *)msg; + struct plugin_ctx *ctx = (struct plugin_ctx *)plugin_ctx; + + memset(buff, 0, sizeof(buff)); + session_to_str(sess, 1, buff, sizeof(buff) - 1); + log_print(ctx->fd, "debug plugin", "on UDP msg: %s", buff); + + memset(buff, 0, sizeof(buff)); + packet_to_str(pkt, buff, sizeof(buff) - 1); + log_print(ctx->fd, "debug plugin", "rx UDP packet: \n%s", buff); + + pthread_spin_lock(&ctx->lock); + packet_dump_hex(pkt, ctx->fd); + pthread_spin_unlock(&ctx->lock); +} + +static void on_sess_tcp_msg(struct session *sess, int topic_id, const void *msg, void *sess_ctx, void *plugin_ctx) +{ + char buff[4096]; + struct packet *pkt = (struct packet *)msg; + struct plugin_ctx *ctx = (struct plugin_ctx *)plugin_ctx; + + memset(buff, 0, sizeof(buff)); + session_to_str(sess, 1, buff, sizeof(buff) - 1); + log_print(ctx->fd, "debug plugin", "on TCP msg: %s", buff); + + memset(buff, 0, sizeof(buff)); + packet_to_str(pkt, buff, sizeof(buff) - 1); + log_print(ctx->fd, "debug plugin", "rx TCP packet: \n%s", buff); + + pthread_spin_lock(&ctx->lock); + packet_dump_hex(pkt, ctx->fd); + pthread_spin_unlock(&ctx->lock); +} + +static void on_sess_tcp_stream_msg(struct session *sess, int topic_id, const void *msg, void *sess_ctx, void *plugin_ctx) +{ + char buff[4096]; + struct tcp_segment *seg = (struct tcp_segment *)msg; + struct plugin_ctx *ctx = (struct plugin_ctx *)plugin_ctx; + + memset(buff, 0, sizeof(buff)); + session_to_str(sess, 1, buff, sizeof(buff) - 1); + log_print(ctx->fd, "debug plugin", "on TCP stream msg: %s", buff); + + log_print(ctx->fd, "debug plugin", "rx TCP segment: len: %d, data: %p\n", seg->len, seg->data); + + pthread_spin_lock(&ctx->lock); + hexdump_to_fd(ctx->fd, (const char *)seg->data, seg->len); + pthread_spin_unlock(&ctx->lock); +} + +/****************************************************************************** + * Plugin API + ******************************************************************************/ + +extern "C" +{ + void *debug_plugin_init(struct stellar *st) + { + struct plugin_ctx *ctx = (struct plugin_ctx *)calloc(1, sizeof(struct plugin_ctx)); + if (ctx == NULL) + { + return NULL; + } + + ctx->fd = open("./log/debug_plugin.log", O_WRONLY | O_APPEND | O_CREAT, 0644); + if (ctx->fd == -1) + { + ctx->fd = STDOUT_FILENO; + } + pthread_spin_init(&ctx->lock, PTHREAD_PROCESS_PRIVATE); + + ctx->st = st; + ctx->sess_plug_id = stellar_session_plugin_register(st, on_sess_new, on_sess_free, ctx); + ctx->udp_topic_id = stellar_session_mq_get_topic_id(st, TOPIC_UDP); + ctx->tcp_topic_id = stellar_session_mq_get_topic_id(st, TOPIC_TCP); + ctx->tcp_stream_topic_id = stellar_session_mq_get_topic_id(st, TOPIC_TCP_STREAM); + + stellar_session_mq_subscribe(st, ctx->udp_topic_id, on_sess_udp_msg, ctx->sess_plug_id); + stellar_session_mq_subscribe(st, ctx->tcp_topic_id, on_sess_tcp_msg, ctx->sess_plug_id); + stellar_session_mq_subscribe(st, ctx->tcp_stream_topic_id, on_sess_tcp_stream_msg, ctx->sess_plug_id); + + log_print(ctx->fd, "debug plugin", "init"); + + return ctx; + } + + void debug_plugin_exit(void *plugin_ctx) + { + struct plugin_ctx *ctx = (struct plugin_ctx *)plugin_ctx; + if (ctx) + { + log_print(ctx->fd, "debug plugin", "exit"); + if (ctx->fd > 0) + { + close(ctx->fd); + } + pthread_spin_destroy(&ctx->lock); + free(ctx); + } + } +} \ No newline at end of file diff --git a/test/debug_plugin/version.map b/test/debug_plugin/version.map new file mode 100644 index 0000000..5e56b52 --- /dev/null +++ b/test/debug_plugin/version.map @@ -0,0 +1,7 @@ +DEBUG_PLUGIN { +global: + debug_plugin_init; + debug_plugin_exit; + +local: *; +}; \ No newline at end of file