/* replicate packets for multiple-copying */ static void replicate_packs(char *packet, int length, int replica_num) { int i; uint16_t orig_port, addition, dest_port, rand_port; uint32_t size_ip; tc_tcp_header_t *tcp_header; tc_ip_header_t *ip_header; ip_header = (tc_ip_header_t *) packet; size_ip = ip_header->ihl << 2; tcp_header = (tc_tcp_header_t *) ((char *) ip_header + size_ip); rand_port = clt_settings.rand_port_shifted; orig_port = ntohs(tcp_header->source); tc_log_debug1(LOG_DEBUG, 0, "orig port:%u", orig_port); for (i = 1; i < replica_num; i++) { addition = (((i << 1) - 1) << 5) + rand_port; dest_port = get_appropriate_port(orig_port, addition); tcp_header->source = htons(dest_port); process_packet(true, packet, length); tc_log_debug2(LOG_DEBUG, 0, "new port:%u,add:%u", dest_port, addition); } }
static void replicate_packs(unsigned char *frame, int frame_len, int replica_num) { int i; uint32_t size_ip; uint16_t orig_port, addition, dest_port, rand_port; unsigned char *packet; tc_ip_header_t *ip_header; tc_udp_header_t *udp_header; packet = frame + ETHERNET_HDR_LEN; ip_header = (tc_ip_header_t *) packet; size_ip = ip_header->ihl << 2; udp_header = (tc_udp_header_t *) ((char *) ip_header + size_ip); orig_port = ntohs(udp_header->source); tc_log_debug1(LOG_DEBUG, 0, "orig port:%u", orig_port); rand_port = clt_settings.rand_port_shifted; for (i = 1; i < replica_num; i++) { addition = (((i << 1) - 1) << 5) + rand_port; dest_port = get_appropriate_port(orig_port, addition); tc_log_debug2(LOG_DEBUG, 0, "new port:%u,add:%u", dest_port, addition); udp_header->source = htons(dest_port); process_packet(true, frame, frame_len); } }
int tc_socket_send(int fd, char *buffer, int len) { ssize_t send_len; while (len > 0) { send_len = send(fd, (const void *) buffer, len, 0); if (-1 == send_len) { tc_log_info(LOG_ERR, errno, "fd:%d", fd); return TC_ERROR; } tc_log_debug2(LOG_DEBUG, 0, "send len:%d, requested len:%d", send_len, len); if (send_len != len) { tc_log_info(LOG_WARN, 0, "fd:%d, send len:%ld, buffer size:%ld", fd, send_len, len); } buffer += send_len; len -= send_len; } return TC_OK; }
int tc_socket_cmb_recv(int fd, int *num, char *buffer) { int read_num = 0; size_t last; ssize_t n, len; last = 0; len = sizeof(uint16_t); for ( ;; ) { n = recv(fd, buffer + last, len, 0); if (n == -1) { if (errno == EAGAIN || errno == EINTR) { continue; } else { tc_log_info(LOG_NOTICE, errno, "return -1,fd:%d", fd); return TC_ERROR; } } if (n == 0) { tc_log_info(LOG_NOTICE, 0, "recv length 0,fd:%d", fd); return TC_ERROR; } last += n; tc_log_debug1(LOG_DEBUG, 0, "current len:%d", len); if ((!read_num) && last >= sizeof(uint16_t)) { *num = (int) ntohs(*(uint16_t *) buffer); if (*num > COMB_MAX_NUM) { tc_log_info(LOG_WARN, 0, "num:%d larger than threshold", *num); return TC_ERROR; } read_num = 1; len = ((*num) * MSG_SERVER_SIZE) + len; tc_log_debug2(LOG_DEBUG, 0, "all bytes needed reading:%d,num:%d", len, *num); } tc_log_debug1(LOG_DEBUG, 0, "this time reading:%d", n); if ((len -= n) == 0) { tc_log_debug1(LOG_DEBUG, 0, "remain readed:%d", len); break; } if (len < 0) { tc_log_info(LOG_WARN, 0, "read:%d,num packs:%d, remain:%d", n, *num, len); break; } tc_log_debug1(LOG_DEBUG, 0, "remain readed:%d", len); } return TC_OK; }
static void update_timestamp(tc_user_t *u, tc_tcp_header_t *tcp_header) { uint32_t ts; unsigned int opt, opt_len; unsigned char *p, *end; p = ((unsigned char *) tcp_header) + TCP_HEADER_MIN_LEN; end = ((unsigned char *) tcp_header) + (tcp_header->doff << 2); while (p < end) { opt = p[0]; switch (opt) { case TCPOPT_TIMESTAMP: if ((p + 1) >= end) { return; } opt_len = p[1]; if ((p + opt_len) <= end) { ts = htonl(u->ts_ec_r); tc_log_debug2(LOG_DEBUG, 0, "set ts reply:%u,p:%u", u->ts_ec_r, ntohs(u->src_port)); bcopy((void *) &ts, (void *) (p + 6), sizeof(ts)); ts = EXTRACT_32BITS(p + 2); if (ts < u->ts_value) { tc_log_debug1(LOG_DEBUG, 0, "ts < history,p:%u", ntohs(u->src_port)); ts = htonl(u->ts_value); bcopy((void *) &ts, (void *) (p + 2), sizeof(ts)); } else { u->ts_value = ts; } } return; case TCPOPT_NOP: p = p + 1; break; case TCPOPT_EOL: return; default: if ((p + 1) >= end) { return; } opt_len = p[1]; if (opt_len < 2) { tc_log_info(LOG_WARN, 0, "opt len:%d", opt_len); return; } p += opt_len; break; } } return; }
static bool check_read_stop() { uint64_t history_diff = timeval_diff(&first_pack_time, &last_pack_time); uint64_t cur_diff = timeval_diff(&base_time, &cur_time); uint64_t diff; tc_log_debug2(LOG_DEBUG, "diff,old:%llu,new:%llu", history_diff, cur_diff); if(history_diff <= cur_diff){ return false; } diff = history_diff - cur_diff; /* More than 1 seconds */ if(diff > 1000){ return true; } return false; }
static bool check_read_stop() { uint64_t diff, history_diff, cur_diff; history_diff = timeval_diff(&first_pack_time, &last_pack_time); cur_diff = timeval_diff(&base_time, &cur_time); tc_log_debug2(LOG_DEBUG, 0, "diff,old:%llu,new:%llu", history_diff, cur_diff); if (history_diff <= cur_diff) { return false; } diff = history_diff - cur_diff; if (diff > 0) { return true; } return false; }
void tc_add_session(p_session_entry entry) { uint32_t h = supplemental_hash((uint32_t) entry->key); uint32_t index = table_index(h, s_table->size); p_session_entry e = NULL, last = NULL; for(e = s_table->entries[index]; e != NULL; e = e->next) { last = e; } if (last == NULL) { s_table->entries[index] = entry; } else { last->next = entry; } s_table->num_of_sessions++; tc_log_debug2(LOG_DEBUG, 0, "index:%d,sessions in table:%d", index, s_table->num_of_sessions); }
static void process_user_packet(tc_user_t *u) { unsigned char frame[MAX_FRAME_LENGTH]; if (send_stop(u)) { return; } while (true) { if (u->orig_frame->frame_len > MAX_FRAME_LENGTH) { tc_log_info(LOG_NOTICE, 0, " frame length may be damaged"); } memcpy(frame, u->orig_frame->frame_data, u->orig_frame->frame_len); process_packet(u, frame); u->total_packets_sent++; u->orig_frame = u->orig_frame->next; if (send_stop(u)) { break; } tc_log_debug1(LOG_DEBUG, 0, "check resp waiting:%u", ntohs(u->src_port)); if (!u->orig_frame->belong_to_the_same_req) { tc_log_debug2(LOG_DEBUG, 0, "user state:%d,port:%u", u->state.status, ntohs(u->src_port)); if (u->state.status & SYN_CONFIRM) { tc_log_debug1(LOG_DEBUG, 0, "set resp waiting:%u", ntohs(u->src_port)); u->state.resp_waiting = 1; } break; } else { tc_log_debug1(LOG_DEBUG, 0, "the same req:%u", ntohs(u->src_port)); } } }
static bool process_packet(tc_user_t *u, unsigned char *frame) { bool result; uint16_t size_ip, size_tcp, tot_len, cont_len; uint32_t h_ack, h_last_ack; tc_ip_header_t *ip_header; tc_tcp_header_t *tcp_header; ip_port_pair_mapping_t *test; ip_header = (tc_ip_header_t *) (frame + ETHERNET_HDR_LEN); size_ip = ip_header->ihl << 2; tcp_header = (tc_tcp_header_t *) ((char *) ip_header + size_ip); size_tcp = tcp_header->doff << 2; tot_len = ntohs(ip_header->tot_len); cont_len = tot_len - size_tcp - size_ip; if (u->dst_port == 0) { test = get_test_pair(&(clt_settings.transfer), ip_header->daddr, tcp_header->dest); if (test == NULL) { tc_log_info(LOG_NOTICE, 0, " test null:%u", ntohs(tcp_header->dest)); tc_log_trace(LOG_WARN, 0, TO_BAKEND_FLAG, ip_header, tcp_header); return false; } u->dst_addr = test->target_ip; u->dst_port = test->target_port; #if (GRYPHON_PCAP_SEND) u->src_mac = test->src_mac; u->dst_mac = test->dst_mac; #endif } if (u->state.last_ack_recorded) { if (u->state.status < SEND_REQ && (u->state.status & SYN_CONFIRM)) { h_ack = ntohl(tcp_header->ack_seq); h_last_ack = ntohl(u->history_last_ack_seq); if (after(h_ack, h_last_ack)) { tc_log_debug1(LOG_DEBUG, 0, "server resp first, wait, p:%u", ntohs(u->src_port)); u->state.resp_waiting = 1; return false; } } } ip_header->saddr = u->src_addr; tcp_header->source = u->src_port; u->history_last_ack_seq = tcp_header->ack_seq; u->state.last_ack_recorded = 1; tcp_header->ack_seq = u->exp_ack_seq; ip_header->daddr = u->dst_addr; tcp_header->dest = u->dst_port; tc_log_debug2(LOG_DEBUG, 0, "set ack seq:%u, p:%u", ntohl(u->exp_ack_seq), ntohs(u->src_port)); packs_sent_cnt++; if (tcp_header->syn) { syn_sent_cnt++; #if (!GRYPHON_SINGLE) if (!send_router_info(u, CLIENT_ADD)) { return false; } #endif u->state.last_ack_recorded = 0; u->state.status |= SYN_SENT; } else if (tcp_header->fin) { fin_sent_cnt++; u->state.status |= CLIENT_FIN; } else if (tcp_header->rst) { rst_sent_cnt++; u->state.status |= CLIENT_FIN; tc_log_debug1(LOG_DEBUG, 0, "a reset packet to back:%u", ntohs(u->src_port)); } if (cont_len > 0) { cont_sent_cnt++; u->state.status |= SEND_REQ; } if (u->state.timestamped) { update_timestamp(u, tcp_header); } tcp_header->check = 0; tcp_header->check = tcpcsum((unsigned char *) ip_header, (unsigned short *) tcp_header, (int) (tot_len - size_ip)); #if (GRYPHON_PCAP_SEND) ip_header->check = 0; ip_header->check = csum((unsigned short *) ip_header,size_ip); #endif tc_log_debug_trace(LOG_DEBUG, 0, TO_BAKEND_FLAG, ip_header, tcp_header); #if (!GRYPHON_PCAP_SEND) result = tc_raw_socket_send(tc_raw_socket_out, ip_header, tot_len, ip_header->daddr); #else fill_frame((struct ethernet_hdr *) frame, u->src_mac, u->dst_mac); result = tc_pcap_send(frame, tot_len + ETHERNET_HDR_LEN); #endif if (result == TC_OK) { u->last_sent_time = tc_time(); return true; } else { tc_log_info(LOG_ERR, 0, "send to back error,tot_len is:%d,cont_len:%d", tot_len,cont_len); #if (!TCPCOPY_PCAP_SEND) tc_raw_socket_out = TC_INVALID_SOCKET; #endif tc_over = SIGRTMAX; return false; } }
bool tc_build_users(int port_prioritized, int num_users, uint32_t *ips, int num_ip) { int i, j, k, count, sub_key, slot_avg, *stat, *accum, *slot_cnt, *sub_keys; uint16_t *buf_ports, port; uint32_t ip, *buf_ips; uint64_t key, *keys; tc_log_info(LOG_INFO, 0, "enter tc_build_users"); size_of_users = num_users; slot_avg = SLOT_AVG; if (size_of_users < slot_avg) { slot_avg = size_of_users; } size_of_user_index = size_of_users / slot_avg; user_array = (tc_user_t *) calloc (size_of_users, sizeof (tc_user_t)); user_index_array = (tc_user_index_t *) calloc (size_of_user_index, sizeof(tc_user_index_t)); if (user_index_array == NULL || user_array == NULL) { tc_log_info(LOG_WARN, 0, "calloc error for users"); return false; } count = 0; keys = (uint64_t *) malloc (sizeof(uint64_t) * size_of_users); sub_keys = (int *) malloc (sizeof(int) * size_of_users); buf_ips = (uint32_t *) malloc (sizeof(uint32_t) * size_of_users); buf_ports = (uint16_t *) malloc (sizeof(uint16_t) * size_of_users); accum = (int *) malloc (sizeof(int) * size_of_users); stat = (int *) malloc (sizeof(int) * size_of_user_index); slot_cnt = (int *) malloc (sizeof(int) * size_of_user_index); if (keys == NULL || sub_keys == NULL || buf_ips == NULL || buf_ports == NULL || accum == NULL || stat == NULL || slot_cnt == NULL) { free(keys); free(sub_keys); free(buf_ips); free(buf_ports); free(accum); free(stat); free(slot_cnt); tc_log_info(LOG_WARN, 0, "calloc error for building users"); return false; } memset(stat, 0 ,sizeof(int) * size_of_user_index); memset(slot_cnt, 0 ,sizeof(int) * size_of_user_index); memset(sub_keys, 0, sizeof(int) * size_of_users); if (port_prioritized) { for ( i = 0; i < num_ip; i++) { ip = ips[i]; for (j = FIRST_PORT; j <= LAST_PORT; j++) { port = get_port(j); key = tc_get_key(ip, port); if (count >= size_of_users) { break; } sub_key = key % size_of_user_index; if (stat[sub_key] >= SLOT_MAX) { continue; } buf_ips[count] = ip; buf_ports[count] = port; sub_keys[count] = sub_key; keys[count++] = key; stat[sub_key]++; } } } else { for (j = FIRST_PORT; j <= LAST_PORT; j++) { port = get_port(j); for ( i = 0; i < num_ip; i++) { ip = ips[i]; key = tc_get_key(ip, port); if (count >= size_of_users) { break; } sub_key = key % size_of_user_index; if (stat[sub_key] >= SLOT_MAX) { continue; } buf_ips[count] = ip; buf_ports[count] = port; sub_keys[count] = sub_key; keys[count++] = key; stat[sub_key]++; } } } if (count < size_of_users) { tc_log_info(LOG_WARN, 0, "insuffient ips:%d for creating users:%d", num_ip, size_of_users); tc_log_info(LOG_NOTICE, 0, "change users from %d to %d", size_of_users, count); size_of_users = count; size_of_user_index = size_of_users / slot_avg; } user_index_array[0].index = 0; for ( i = 1; i < size_of_user_index; i++) { user_index_array[i].index = stat[i - 1] + user_index_array[i - 1].index; } for ( i = 0; i < size_of_users; i++) { sub_key = sub_keys[i]; if (sub_key > 0) { accum[i] = user_index_array[sub_key].index + slot_cnt[sub_key]; } else { accum[i] = slot_cnt[sub_key]; } k = accum[i]; user_array[k].src_addr = buf_ips[i]; user_array[k].src_port = buf_ports[i]; user_array[k].key = keys[i]; tc_log_debug2(LOG_DEBUG, 0, "usr key :%llu,pos=%d", keys[i], k); slot_cnt[sub_key]++; } free(sub_keys); free(buf_ports); free(buf_ips); free(accum); free(stat); free(keys); free(slot_cnt); tc_init_session_for_users(); tc_log_info(LOG_INFO, 0, "leave tc_build_users"); return true; }
void process_outgress(unsigned char *packet) { uint16_t size_ip, size_tcp, tot_len, cont_len; uint32_t seq, ack_seq; uint64_t key; tc_user_t *u; tc_ip_header_t *ip_header; tc_tcp_header_t *tcp_header; last_resp_time = tc_time(); resp_cnt++; ip_header = (tc_ip_header_t *) packet; size_ip = ip_header->ihl << 2; tcp_header = (tc_tcp_header_t *) ((char *) ip_header + size_ip); key = tc_get_key(ip_header->daddr, tcp_header->dest); tc_log_debug1(LOG_DEBUG, 0, "key from bak:%llu", key); u = tc_retrieve_user(key); if (u != NULL) { tc_log_debug_trace(LOG_DEBUG, 0, BACKEND_FLAG, ip_header, tcp_header); u->srv_window = ntohs(tcp_header->window); if (u->wscale) { u->srv_window = u->srv_window << (u->wscale); tc_log_debug1(LOG_DEBUG, 0, "window size:%u", u->srv_window); } if (u->state.timestamped) { retrieve_options(u, REMOTE, tcp_header); } size_tcp = tcp_header->doff << 2; tot_len = ntohs(ip_header->tot_len); cont_len = tot_len - size_tcp - size_ip; if (ip_header->daddr != u->src_addr || tcp_header->dest!= u->src_port) { tc_log_info(LOG_NOTICE, 0, " key conflict"); } seq = ntohl(tcp_header->seq); u->exp_seq = tcp_header->ack_seq; ack_seq = ntohl(tcp_header->ack_seq); if (u->last_seq == seq && u->last_ack_seq == ack_seq) { u->fast_retransmit_cnt++; if (u->fast_retransmit_cnt == 3) { fast_retransmit(u, ack_seq); return; } } else { update_ack_packets(u, ack_seq); u->fast_retransmit_cnt = 0; } u->last_ack_seq = ack_seq; u->last_seq = seq; if (cont_len > 0) { u->last_recv_resp_cont_time = tc_milliscond_time(); resp_cont_cnt++; u->state.resp_waiting = 0; u->exp_ack_seq = htonl(seq + cont_len); send_faked_ack(u); } else { u->exp_ack_seq = tcp_header->seq; } if (tcp_header->syn) { tc_log_debug1(LOG_DEBUG, 0, "recv syn from back:%u", ntohs(u->src_port)); u->exp_ack_seq = htonl(ntohl(u->exp_ack_seq) + 1); if (!u->state.resp_syn_received) { conn_cnt++; active_conn_cnt++; u->state.resp_syn_received = 1; u->state.status |= SYN_CONFIRM; tc_log_debug2(LOG_DEBUG, 0, "exp ack seq:%u, p:%u", ntohl(u->exp_ack_seq), ntohs(u->src_port)); if (size_tcp > TCP_HEADER_MIN_LEN) { retrieve_options(u, REMOTE, tcp_header); if (u->wscale > 0) { tc_log_debug2(LOG_DEBUG, 0, "wscale:%u, p:%u", u->wscale, ntohs(u->src_port)); } } process_user_packet(u); } else { tc_log_debug1(LOG_DEBUG, 0, "syn, but already syn received:%u", ntohs(u->src_port)); } } else if (tcp_header->fin) { tc_log_debug1(LOG_DEBUG, 0, "recv fin from back:%u", ntohs(u->src_port)); u->exp_ack_seq = htonl(ntohl(u->exp_ack_seq) + 1); u->state.status |= SERVER_FIN; send_faked_ack(u); process_user_packet(u); fin_recv_cnt++; } else if (tcp_header->rst) { tc_log_info(LOG_NOTICE, 0, "recv rst from back:%u", ntohs(u->src_port)); rst_recv_cnt++; if (u->state.status == SYN_SENT) { if (!u->state.over) { conn_reject_cnt++; } } u->state.over = 1; u->state.status |= SERVER_FIN; } } else { tc_log_debug_trace(LOG_DEBUG, 0, BACKEND_FLAG, ip_header, tcp_header); tc_log_debug0(LOG_DEBUG, 0, "no active session for me"); } }
static void send_packets_from_pcap(int first) { int l2_len, ip_pack_len, p_valid_flag = 0; bool stop; pcap_t *pcap; unsigned char *pkt_data, *frame, *ip_data; struct pcap_pkthdr pkt_hdr; pcap = clt_settings.pcap; if (pcap == NULL || read_pcap_over) { return; } gettimeofday(&cur_time, NULL); stop = check_read_stop(); while (!stop) { pkt_data = (u_char *) pcap_next(pcap, &pkt_hdr); if (pkt_data != NULL) { if (pkt_hdr.caplen < pkt_hdr.len) { tc_log_info(LOG_WARN, 0, "truncated packets,drop"); } else { ip_data = get_ip_data(clt_settings.pcap, pkt_data, pkt_hdr.len, &l2_len); if (l2_len < ETHERNET_HDR_LEN) { tc_log_info(LOG_WARN, 0, "l2 len is %d", l2_len); continue; } last_pack_time = pkt_hdr.ts; if (ip_data != NULL) { clt_settings.pcap_time = last_pack_time.tv_sec * 1000 + last_pack_time.tv_usec / 1000; ip_pack_len = pkt_hdr.len - l2_len; tc_log_debug2(LOG_DEBUG, 0, "frame len:%d, ip len:%d", pkt_hdr.len, ip_pack_len); frame = ip_data - ETHERNET_HDR_LEN; dispose_packet(frame, ip_pack_len + ETHERNET_HDR_LEN, ip_pack_len, &p_valid_flag); if (p_valid_flag) { tc_log_debug0(LOG_DEBUG, 0, "valid flag for packet"); if (first) { first_pack_time = pkt_hdr.ts; first = 0; } else { adj_v_pack_diff = timeval_diff(&last_v_pack_time, &last_pack_time); } /* set last valid packet time in pcap file */ last_v_pack_time = last_pack_time; stop = check_read_stop(); } else { tc_log_debug0(LOG_DEBUG, 0, "invalid flag"); } } } } else { tc_log_info(LOG_WARN, 0, "stop, null from pcap_next"); stop = true; read_pcap_over = true; } } }
static int prepare_for_renew_session(tc_sess_t *s, tc_iph_t *ip, tc_tcph_t *tcp) { uint16_t size_ip; uint32_t tot_clen, base_seq; tc_iph_t *fir_ip, *t_ip; tc_tcph_t *fir_tcp, *t_tcp; p_link_node ln; unsigned char *p; mysql_table_item_t *item; tc_mysql_session *mysql_sess; if (!ctx.fir_auth_pack) { tc_log_info(LOG_WARN, 0, "no first auth pack here"); return TC_ERR; } mysql_sess = s->data; if (mysql_sess == NULL) { tc_log_info(LOG_WARN, 0, "mysql session structure is not allocated"); return TC_ERR; } else if (mysql_sess->fir_auth_added) { tc_log_info(LOG_NOTICE, 0, "dup visit prepare_for_renew_session"); return TC_OK; } s->sm.need_rep_greet = 1; fir_ip = ctx.fir_auth_pack; fir_ip->saddr = ip->saddr; size_ip = fir_ip->ihl << 2; fir_tcp = (tc_tcph_t *) ((char *) fir_ip + size_ip); fir_tcp->source = tcp->source; tot_clen = ctx.fir_auth_cont_len; item = hash_find(ctx.table, s->hash_key); if (item) { tot_clen += item->tot_cont_len; } tc_log_debug2(LOG_INFO, 0, "total len subtracted:%u,p:%u", tot_clen, ntohs(s->src_port)); tcp->seq = htonl(ntohl(tcp->seq) - tot_clen); fir_tcp->seq = htonl(ntohl(tcp->seq) + 1); tc_save_pack(s, s->slide_win_packs, fir_ip, fir_tcp); mysql_sess->fir_auth_added = 1; base_seq = ntohl(fir_tcp->seq) + ctx.fir_auth_cont_len; if (item) { ln = link_list_first(item->list); while (ln) { p = (unsigned char *) ln->data; t_ip = (tc_iph_t *) (p + ETHERNET_HDR_LEN); t_tcp = (tc_tcph_t *) ((char *) t_ip + size_ip); t_tcp->seq = htonl(base_seq); tc_save_pack(s, s->slide_win_packs, t_ip, t_tcp); base_seq += TCP_PAYLOAD_LENGTH(t_ip, t_tcp); ln = link_list_get_next(item->list, ln); } } mysql_sess->old_ps_cleaned = 0; return TC_OK; }