#include "stellar/exdata.h" #include "session_internal.h" #include "session_manager_stat.h" void session_init(struct session *sess) { memset(sess, 0, sizeof(struct session)); sess->empty_seg.data = NULL; sess->empty_seg.len = 0; sess->empty_seg.user_data = sess; } void session_set_id(struct session *sess, uint64_t id) { sess->id = id; } uint64_t session_get_id(const struct session *sess) { return sess->id; } void session_set_tuple6(struct session *sess, const struct tuple6 *tuple) { memcpy(&sess->tuple, tuple, sizeof(struct tuple6)); } const struct tuple6 *session_get_tuple6(const struct session *sess) { return &sess->tuple; } const char *session_get_readable_addr(const struct session *sess) { return sess->tuple_str; } void session_set_direction(struct session *sess, enum session_direction dir) { sess->sess_dir = dir; } enum session_direction session_get_direction(const struct session *sess) { return sess->sess_dir; } void session_set_flow_type(struct session *sess, enum flow_type type) { sess->flow_type = type; } enum flow_type session_get_flow_type(const struct session *sess) { return sess->flow_type; } void session_set_current_state(struct session *sess, enum session_state state) { sess->state = state; } enum session_state session_get_current_state(const struct session *sess) { return sess->state; } void session_set_type(struct session *sess, enum session_type type) { sess->sess_type = type; } enum session_type session_get_type(const struct session *sess) { return sess->sess_type; } void session_set_duplicate_traffic(struct session *sess) { sess->dup = 1; } int session_has_duplicate_traffic(const struct session *sess) { return sess->dup; } void session_set_closing_reason(struct session *sess, enum closing_reason reason) { sess->reason = reason; } enum closing_reason session_get_closing_reason(const struct session *sess) { return sess->reason; } void session_inc_stat(struct session *sess, enum flow_type type, enum session_stat stat, uint64_t val) { sess->stats[type][stat] += val; } uint64_t session_get_stat(const struct session *sess, enum flow_type type, enum session_stat stat) { return sess->stats[type][stat]; } void session_set_timestamp(struct session *sess, enum session_timestamp type, uint64_t value) { sess->timestamps[type] = value; } uint64_t session_get_timestamp(const struct session *sess, enum session_timestamp type) { return sess->timestamps[type]; } void session_clear_sids(struct session *sess, enum flow_type type) { memset(&sess->sids[type], 0, sizeof(struct sids)); } void session_set_sids(struct session *sess, enum flow_type type, const struct sids *sids) { sess->sids[type] = *sids; } const struct sids *session_get_sids(const struct session *sess, enum flow_type type) { return &sess->sids[type]; } void session_clear_route_ctx(struct session *sess, enum flow_type type) { memset(&sess->route_ctx[type], 0, sizeof(struct route_ctx)); } void session_set_route_ctx(struct session *sess, enum flow_type type, const struct route_ctx *ctx) { sess->route_ctx[type] = *ctx; } const struct route_ctx *session_get_route_ctx(const struct session *sess, enum flow_type type) { return &sess->route_ctx[type]; } void session_set_first_packet(struct session *sess, enum flow_type type, const struct packet *pkt) { sess->first_pkt[type] = pkt; } const struct packet *session_get_first_packet(const struct session *sess, enum flow_type type) { return sess->first_pkt[type]; } void session_set_current_packet(struct session *sess, const struct packet *pkt) { sess->curr_pkt = pkt; } const struct packet *session_get_current_packet(const struct session *sess) { return sess->curr_pkt; } int session_is_symmetric(const struct session *sess, unsigned char *flag) { int is_symmetric = 0; if (sess->first_pkt[FLOW_TYPE_C2S] && sess->first_pkt[FLOW_TYPE_S2C]) { if (flag) { *flag = (SESSION_SEEN_C2S_FLOW | SESSION_SEEN_S2C_FLOW); } is_symmetric = 1; } else if (sess->first_pkt[FLOW_TYPE_C2S]) { if (flag) { *flag = SESSION_SEEN_C2S_FLOW; } } else if (sess->first_pkt[FLOW_TYPE_S2C]) { if (flag) { *flag = SESSION_SEEN_S2C_FLOW; } } return is_symmetric; } void session_set_user_data(struct session *sess, void *user_data) { sess->user_data = user_data; } void *session_get_user_data(const struct session *sess) { return sess->user_data; } struct tcp_segment *session_get_tcp_segment(struct session *sess) { enum flow_type type = session_get_flow_type(sess); struct tcp_half *half = &sess->tcp_halfs[type]; if (half->inorder_seg.data != NULL && half->inorder_seg.len > 0 && !half->inorder_seg_consumed) { sess->sess_mgr_stat->tcp_segs_consumed++; half->inorder_seg_consumed = 1; half->inorder_seg.user_data = sess; return &half->inorder_seg; } else { struct tcp_segment *seg = tcp_reassembly_pop(half->tcp_reass); if (seg) { session_inc_stat(sess, type, STAT_TCP_SEGMENTS_REORDERED, 1); session_inc_stat(sess, type, STAT_TCP_PAYLOADS_REORDERED, seg->len); // TODO sess->sess_mgr_stat->tcp_segs_consumed++; sess->sess_mgr_stat->tcp_segs_reordered++; seg->user_data = sess; } return seg; } } void session_free_tcp_segment(struct session *sess, struct tcp_segment *seg) { if (seg == NULL) { return; } // empty segment for end of session if (seg == &sess->empty_seg) { return; } enum flow_type type = session_get_flow_type(sess); struct tcp_half *half = &sess->tcp_halfs[type]; // in order segment if (seg == &half->inorder_seg) { half->inorder_seg.data = NULL; half->inorder_seg.len = 0; return; } // tcp reassembly segment else { session_inc_stat(sess, type, STAT_TCP_SEGMENTS_RELEASED, 1); session_inc_stat(sess, type, STAT_TCP_PAYLOADS_RELEASED, seg->len); sess->sess_mgr_stat->tcp_segs_freed++; tcp_segment_free(seg); } } const char *closing_reason_to_str(enum closing_reason reason) { switch (reason) { case CLOSING_BY_TIMEOUT: return "closing by timeout"; case CLOSING_BY_LRU_EVICTED: return "closing by lru evicted"; case CLOSING_BY_PORT_REUSE_EVICTED: return "closing by port reuse evicted"; case CLOSING_BY_CLIENT_FIN: return "closing by client FIN"; case CLOSING_BY_CLIENT_RST: return "closing by client RST"; case CLOSING_BY_SERVER_FIN: return "closing by server FIN"; case CLOSING_BY_SERVER_RST: return "closing by server RST"; default: return "unknown"; } } const char *session_state_to_str(enum session_state state) { switch (state) { case SESSION_STATE_INIT: return "init"; case SESSION_STATE_OPENING: return "opening"; case SESSION_STATE_ACTIVE: return "active"; case SESSION_STATE_CLOSING: return "closing"; case SESSION_STATE_DISCARD: return "discard"; case SESSION_STATE_CLOSED: return "closed"; default: return "unknown"; } } const char *session_type_to_str(enum session_type type) { switch (type) { case SESSION_TYPE_TCP: return "TCP"; case SESSION_TYPE_UDP: return "UDP"; default: return "unknown"; } } const char *flow_direction_to_str(enum flow_type type) { switch (type) { case FLOW_TYPE_C2S: return "C2S"; case FLOW_TYPE_S2C: return "S2C"; default: return "unknown"; } } static void tcp_flags_to_str(uint8_t flags, char *buffer, size_t len) { int used = 0; if (flags & TH_SYN) { used += snprintf(buffer + used, len - used, "SYN "); } if (flags & TH_ACK) { used += snprintf(buffer + used, len - used, "ACK "); } if (flags & TH_FIN) { used += snprintf(buffer + used, len - used, "FIN "); } if (flags & TH_RST) { used += snprintf(buffer + used, len - used, "RST "); } } 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; if (bref) { 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_get_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_flow_type(sess)), session_get_stat(sess, FLOW_TYPE_C2S, STAT_RAW_PACKETS_RECEIVED), session_get_stat(sess, FLOW_TYPE_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_ms\":%" PRIu64 ",", session_get_timestamp(sess, SESSION_TIMESTAMP_START)); used += snprintf(buff + used, size - used, "\"last_timestamp_ms\":%" PRIu64 ",", session_get_timestamp(sess, SESSION_TIMESTAMP_LAST)); used += snprintf(buff + used, size - used, "\"tuple\":\"%s\",", session_get_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_get_current_packet(sess)); const char *str[] = {"c2s", "s2c"}; enum flow_type type[] = {FLOW_TYPE_C2S, FLOW_TYPE_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, type[i], STAT_RAW_PACKETS_RECEIVED)); used += snprintf(buff + used, size - used, "\"%s_raw_bytes_received\":%" PRIu64 ",", str[i], session_get_stat(sess, type[i], STAT_RAW_BYTES_RECEIVED)); used += snprintf(buff + used, size - used, "\"%s_raw_packets_transmitted\":%" PRIu64 ",", str[i], session_get_stat(sess, type[i], STAT_RAW_PACKETS_TRANSMITTED)); used += snprintf(buff + used, size - used, "\"%s_raw_bytes_transmitted\":%" PRIu64 ",", str[i], session_get_stat(sess, type[i], STAT_RAW_BYTES_TRANSMITTED)); used += snprintf(buff + used, size - used, "\"%s_raw_packets_dropped\":%" PRIu64 ",", str[i], session_get_stat(sess, type[i], STAT_RAW_PACKETS_DROPPED)); used += snprintf(buff + used, size - used, "\"%s_raw_bytes_dropped\":%" PRIu64 ",", str[i], session_get_stat(sess, type[i], STAT_RAW_BYTES_DROPPED)); // duplicate packets used += snprintf(buff + used, size - used, "\"%s_duplicate_packets_bypass\":%" PRIu64 ",", str[i], session_get_stat(sess, type[i], STAT_DUPLICATE_PACKETS_BYPASS)); used += snprintf(buff + used, size - used, "\"%s_duplicate_bytes_bypass\":%" PRIu64 ",", str[i], session_get_stat(sess, type[i], STAT_DUPLICATE_BYTES_BYPASS)); // injected packets used += snprintf(buff + used, size - used, "\"%s_injected_packets_failed\":%" PRIu64 ",", str[i], session_get_stat(sess, type[i], STAT_INJECTED_PACKETS_FAILED)); used += snprintf(buff + used, size - used, "\"%s_injected_packets_success\":%" PRIu64 ",", str[i], session_get_stat(sess, type[i], STAT_INJECTED_PACKETS_SUCCESS)); used += snprintf(buff + used, size - used, "\"%s_injected_bytes_success\":%" PRIu64 ",", str[i], session_get_stat(sess, type[i], STAT_INJECTED_BYTES_SUCCESS)); // control packets used += snprintf(buff + used, size - used, "\"%s_control_packets_received\":%" PRIu64 ",", str[i], session_get_stat(sess, type[i], STAT_CONTROL_PACKETS_RECEIVED)); used += snprintf(buff + used, size - used, "\"%s_control_bytes_received\":%" PRIu64 ",", str[i], session_get_stat(sess, type[i], STAT_CONTROL_BYTES_RECEIVED)); used += snprintf(buff + used, size - used, "\"%s_control_packets_transmitted\":%" PRIu64 ",", str[i], session_get_stat(sess, type[i], STAT_CONTROL_PACKETS_TRANSMITTED)); used += snprintf(buff + used, size - used, "\"%s_control_bytes_transmitted\":%" PRIu64 ",", str[i], session_get_stat(sess, type[i], STAT_CONTROL_BYTES_TRANSMITTED)); used += snprintf(buff + used, size - used, "\"%s_control_packets_dropped\":%" PRIu64 ",", str[i], session_get_stat(sess, type[i], STAT_CONTROL_PACKETS_DROPPED)); used += snprintf(buff + used, size - used, "\"%s_control_bytes_dropped\":%" PRIu64 ",", str[i], session_get_stat(sess, type[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[type[i]].seq); used += snprintf(buff + used, size - used, "\"%s_tcp_last_ack\":%u,", str[i], sess->tcp_halfs[type[i]].ack); memset(flags, 0, sizeof(flags)); tcp_flags_to_str(sess->tcp_halfs[type[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, type[i], STAT_TCP_SEGMENTS_RECEIVED)); used += snprintf(buff + used, size - used, "\"%s_tcp_payloads_received\":%" PRIu64 ",", str[i], session_get_stat(sess, type[i], STAT_TCP_PAYLOADS_RECEIVED)); used += snprintf(buff + used, size - used, "\"%s_tcp_segments_expired\":%" PRIu64 ",", str[i], session_get_stat(sess, type[i], STAT_TCP_SEGMENTS_EXPIRED)); used += snprintf(buff + used, size - used, "\"%s_tcp_payloads_expired\":%" PRIu64 ",", str[i], session_get_stat(sess, type[i], STAT_TCP_PAYLOADS_EXPIRED)); used += snprintf(buff + used, size - used, "\"%s_tcp_segments_retransmit\":%" PRIu64 ",", str[i], session_get_stat(sess, type[i], STAT_TCP_SEGMENTS_RETRANSMIT)); used += snprintf(buff + used, size - used, "\"%s_tcp_payloads_retransmit\":%" PRIu64 ",", str[i], session_get_stat(sess, type[i], STAT_TCP_PAYLOADS_RETRANSMIT)); used += snprintf(buff + used, size - used, "\"%s_tcp_segments_overlap\":%" PRIu64 ",", str[i], session_get_stat(sess, type[i], STAT_TCP_SEGMENTS_OVERLAP)); used += snprintf(buff + used, size - used, "\"%s_tcp_payloads_overlap\":%" PRIu64 ",", str[i], session_get_stat(sess, type[i], STAT_TCP_PAYLOADS_OVERLAP)); used += snprintf(buff + used, size - used, "\"%s_tcp_segments_nospace\":%" PRIu64 ",", str[i], session_get_stat(sess, type[i], STAT_TCP_SEGMENTS_NOSPACE)); used += snprintf(buff + used, size - used, "\"%s_tcp_payloads_nospace\":%" PRIu64 ",", str[i], session_get_stat(sess, type[i], STAT_TCP_PAYLOADS_NOSPACE)); used += snprintf(buff + used, size - used, "\"%s_tcp_segments_inorder\":%" PRIu64 ",", str[i], session_get_stat(sess, type[i], STAT_TCP_SEGMENTS_INORDER)); used += snprintf(buff + used, size - used, "\"%s_tcp_payloads_inorder\":%" PRIu64 ",", str[i], session_get_stat(sess, type[i], STAT_TCP_PAYLOADS_INORDER)); used += snprintf(buff + used, size - used, "\"%s_tcp_segments_reordered\":%" PRIu64 ",", str[i], session_get_stat(sess, type[i], STAT_TCP_SEGMENTS_REORDERED)); used += snprintf(buff + used, size - used, "\"%s_tcp_payloads_reordered\":%" PRIu64 ",", str[i], session_get_stat(sess, type[i], STAT_TCP_PAYLOADS_REORDERED)); used += snprintf(buff + used, size - used, "\"%s_tcp_segments_buffered\":%" PRIu64 ",", str[i], session_get_stat(sess, type[i], STAT_TCP_SEGMENTS_BUFFERED)); used += snprintf(buff + used, size - used, "\"%s_tcp_payloads_buffered\":%" PRIu64 ",", str[i], session_get_stat(sess, type[i], STAT_TCP_PAYLOADS_BUFFERED)); used += snprintf(buff + used, size - used, "\"%s_tcp_segments_released\":%" PRIu64 ",", str[i], session_get_stat(sess, type[i], STAT_TCP_SEGMENTS_RELEASED)); used += snprintf(buff + used, size - used, "\"%s_tcp_payloads_released\":%" PRIu64 ",", str[i], session_get_stat(sess, type[i], STAT_TCP_PAYLOADS_RELEASED)); } used += snprintf(buff + used, size - used, "\"%s_first_packet\":\"%p\"", str[i], session_get_first_packet(sess, type[i])); if (i == 0) { used += snprintf(buff + used, size - used, ","); } } used += snprintf(buff + used, size - used, "}"); } return used; } void session_print(const struct session *sess) { char buff[4096]; session_to_str(sess, 0, buff, sizeof(buff)); printf("%s\n", buff); } void session_set_exdata(struct session *sess, int idx, void *ex_ptr) { struct exdata_runtime *rte = (struct exdata_runtime *)session_get_user_data(sess); exdata_set(rte, idx, ex_ptr); } void *session_get_exdata(const struct session *sess, int idx) { struct exdata_runtime *rte = (struct exdata_runtime *)session_get_user_data(sess); return exdata_get(rte, idx); }