/* * filter packets */ bool is_packet_needed(const char *packet) { bool is_needed = false; uint16_t size_ip, size_udp, tot_len; struct iphdr *ip_header; struct udphdr *udp_header; ip_header = (struct iphdr*)packet; /* check if it is a udp packet */ if(ip_header->protocol != IPPROTO_UDP){ return is_needed; } size_ip = ip_header->ihl << 2; tot_len = ntohs(ip_header->tot_len); if (size_ip < 20) { log_info(LOG_WARN, "Invalid IP header length: %d", size_ip); return is_needed; } udp_header = (struct udphdr*)((char *)ip_header + size_ip); size_udp = ntohs(udp_header->len); if (size_udp < sizeof(struct udphdr)) { log_info(LOG_WARN, "Invalid udp header len: %d bytes,pack len:%d", size_udp, tot_len); return is_needed; } /* filter the packets we do care about */ if(LOCAL == check_pack_src(&(clt_settings.transfer), ip_header->daddr, udp_header->dest, CHECK_DEST)){ is_needed = true; clt_udp_cnt++; strace_pack(LOG_DEBUG, ip_header, udp_header); } return is_needed; }
static int dispose_packet(char *recv_buf, int recv_len, int *p_valid_flag) { char *packet, tmp_buf[RECV_BUF_SIZE]; int replica_num, i, last, packet_num, max_payload; int index, payload_len; bool packet_valid = false; uint16_t id, size_ip, size_tcp, tot_len, cont_len, pack_len, head_len; uint32_t seq; struct tcphdr *tcp_header; struct iphdr *ip_header; packet = recv_buf; if(is_packet_needed((const char *)packet)){ replica_num = clt_settings.replica_num; packet_num = 1; ip_header = (struct iphdr*)packet; if(localhost == ip_header->saddr){ if(0 != clt_settings.lo_tf_ip){ ip_header->saddr = clt_settings.lo_tf_ip; } } /* * If packet length larger than MTU, then we split it. * This is to solve the ip fragmentation problem */ if(recv_len > clt_settings.mtu){ /* Calculate number of packets */ size_ip = ip_header->ihl << 2; tot_len = ntohs(ip_header -> tot_len); if(tot_len != recv_len){ log_info(LOG_WARN, "packet len:%u, recv len:%u", tot_len, recv_len); return FAILURE; } tcp_header = (struct tcphdr*)((char *)ip_header + size_ip); size_tcp = tcp_header->doff << 2; cont_len = tot_len - size_tcp - size_ip; head_len = size_ip + size_tcp; max_payload = clt_settings.mtu - head_len; packet_num = (cont_len + max_payload - 1)/max_payload; seq = ntohl(tcp_header->seq); last = packet_num - 1; id = ip_header->id; #if (TCPCOPY_DEBUG) strace_pack(LOG_NOTICE, CLIENT_FLAG, ip_header, tcp_header); #endif tc_log_debug1(LOG_INFO, "recv:%d, more than MTU", recv_len); index = head_len; for(i = 0 ; i < packet_num; i++){ tcp_header->seq = htonl(seq + i * max_payload); if(i != last){ pack_len = clt_settings.mtu; }else{ pack_len += (cont_len - packet_num * max_payload); } payload_len = pack_len - head_len; ip_header->tot_len = htons(pack_len); ip_header->id = id++; /* Copy header here */ memcpy(tmp_buf, recv_buf, head_len); /* Copy payload here */ memcpy(tmp_buf + head_len, recv_buf + index, payload_len); index = index + payload_len; if(replica_num > 1){ packet_valid = process_packet(true, tmp_buf, pack_len); replicate_packs(tmp_buf, pack_len, replica_num); }else{ packet_valid = process_packet(false, tmp_buf, pack_len); } } }else{ if(replica_num > 1){ packet_valid = process_packet(true, packet, recv_len); replicate_packs(packet, recv_len, replica_num); }else{ packet_valid = process_packet(false, packet, recv_len); } } } if(packet_valid){ *p_valid_flag = 1; } return SUCCESS; }