/* * network.cpp * * Created on: Jul 29, 2017 * Author: wangyu */ #include "common.h" #include "network.h" #include "log.h" #include "misc.h" int g_fix_gro = 0; int raw_recv_fd = -1; int raw_send_fd = -1; u32_t link_level_header_len = 0; // set it to 14 if SOCK_RAW is used in socket(PF_PACKET, SOCK_RAW, htons(ETH_P_IP)); int use_tcp_dummy_socket = 0; int seq_mode = 3; int max_seq_mode = 4; int random_drop = 0; int filter_port = -1; int disable_bpf_filter = 0; // for test only,most time no need to disable this // u32_t bind_address_uint32=0; int lower_level = 0; int lower_level_manual = 0; int ifindex = -1; char if_name[100] = ""; char dev[100] = ""; unsigned short g_ip_id_counter = 0; #ifdef UDP2RAW_LINUX unsigned char dest_hw_addr[sizeof(sockaddr_ll::sll_addr)] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0, 0}; #endif //{0x00,0x23,0x45,0x67,0x89,0xb9}; const u32_t receive_window_lower_bound = 40960; const u32_t receive_window_random_range = 512; const unsigned char wscale = 0x05; char g_packet_buf[huge_buf_len]; // looks dirty but works well int g_packet_buf_len = -1; int g_packet_buf_cnt = 0; #ifdef UDP2RAW_LINUX union { sockaddr_ll ll; sockaddr_in ipv4; sockaddr_in6 ipv6; } g_sockaddr; socklen_t g_sockaddr_len = -1; #endif #ifdef UDP2RAW_MP #ifndef NO_LIBNET libnet_t *libnet_handle; libnet_ptag_t g_ptag = 0; int send_with_pcap = 0; #else int send_with_pcap = 1; #endif int pcap_header_captured = 0; int pcap_header_buf[buf_len]; int pcap_captured_full_len = -1; pcap_t *pcap_handle; int pcap_link_header_len = -1; // int pcap_cnt=0; queue_t my_queue; pthread_mutex_t queue_mutex = PTHREAD_MUTEX_INITIALIZER; pthread_mutex_t pcap_mutex = PTHREAD_MUTEX_INITIALIZER; int use_pcap_mutex = 1; ev_async async_watcher; struct ev_loop *g_default_loop; pthread_t pcap_recv_thread; struct bpf_program g_filter; long long g_filter_compile_cnt = 0; #endif #ifdef UDP2RAW_LINUX struct sock_filter code_tcp_old[] = { {0x28, 0, 0, 0x0000000c}, // 0 {0x15, 0, 10, 0x00000800}, // 1 {0x30, 0, 0, 0x00000017}, // 2 {0x15, 0, 8, 0x00000006}, // 3 {0x28, 0, 0, 0x00000014}, // 4 {0x45, 6, 0, 0x00001fff}, // 5 {0xb1, 0, 0, 0x0000000e}, // 6 {0x48, 0, 0, 0x0000000e}, // 7 {0x15, 2, 0, 0x0000ef32}, // 8 {0x48, 0, 0, 0x00000010}, // 9 {0x15, 0, 1, 0x0000ef32}, // 10 {0x6, 0, 0, 0x0000ffff}, // 11 {0x6, 0, 0, 0x00000000}, // 12 }; struct sock_filter code_tcp[] = { //{ 0x5, 0, 0, 0x00000001 },//0 //jump to 2,dirty hack from tcpdump -d's output //{ 0x5, 0, 0, 0x00000000 },//1 {0x30, 0, 0, 0x00000009}, // 2 {0x15, 0, 6, 0x00000006}, // 3 {0x28, 0, 0, 0x00000006}, // 4 {0x45, 4, 0, 0x00001fff}, // 5 {0xb1, 0, 0, 0x00000000}, // 6 {0x48, 0, 0, 0x00000002}, // 7 {0x15, 0, 1, 0x0000fffe}, // 8 //modify this fffe to the port you listen on {0x6, 0, 0, 0x0000ffff}, // 9 {0x6, 0, 0, 0x00000000}, // 10 }; /* { 0x28, 0, 0, 0x0000000c }, { 0x15, 0, 8, 0x00000800 }, { 0x30, 0, 0, 0x00000017 }, { 0x15, 0, 6, 0x00000006 }, { 0x28, 0, 0, 0x00000014 }, { 0x45, 4, 0, 0x00001fff }, { 0xb1, 0, 0, 0x0000000e }, { 0x48, 0, 0, 0x00000010 }, { 0x15, 0, 1, 0x0000fffe }, { 0x6, 0, 0, 0x0000ffff }, { 0x6, 0, 0, 0x00000000 }, */ int code_tcp_port_index = 6; // tcpdump -i ens33 ip6 and tcp and dst port 65534 -dd struct sock_filter code_tcp6[] = { //{ 0x28, 0, 0, 0x0000000c },//0 //{ 0x15, 0, 5, 0x000086dd },//1 {0x30, 0, 0, 0x00000006}, // 2 {0x15, 0, 3, 0x00000006}, // 3 {0x28, 0, 0, 0x0000002a}, // 4 {0x15, 0, 1, 0x0000fffe}, // 5 {0x6, 0, 0, 0x00040000}, // 6 {0x6, 0, 0, 0x00000000}, // 7 }; // note: this filter doesnt support extension headers /* { 0x30, 0, 0, 0x00000014 },//2 { 0x15, 0, 3, 0x00000006 },//3 { 0x28, 0, 0, 0x00000038 },//4 { 0x15, 0, 1, 0x0000fffe },//5 { 0x6, 0, 0, 0x00040000 },//6 { 0x6, 0, 0, 0x00000000 },//7 */ int code_tcp6_port_index = 3; struct sock_filter code_udp[] = { //{ 0x5, 0, 0, 0x00000001 }, //{ 0x5, 0, 0, 0x00000000 }, {0x30, 0, 0, 0x00000009}, {0x15, 0, 6, 0x00000011}, {0x28, 0, 0, 0x00000006}, {0x45, 4, 0, 0x00001fff}, {0xb1, 0, 0, 0x00000000}, {0x48, 0, 0, 0x00000002}, {0x15, 0, 1, 0x0000fffe}, // modify this fffe to the port you listen on {0x6, 0, 0, 0x0000ffff}, {0x6, 0, 0, 0x00000000}, }; int code_udp_port_index = 6; struct sock_filter code_udp6[] = { // { 0x28, 0, 0, 0x0000000c }, // { 0x15, 0, 5, 0x000086dd }, {0x30, 0, 0, 0x00000006}, {0x15, 0, 3, 0x00000011}, {0x28, 0, 0, 0x0000002a}, {0x15, 0, 1, 0x0000fffe}, {0x6, 0, 0, 0x00040000}, {0x6, 0, 0, 0x00000000}, }; int code_udp6_port_index = 3; struct sock_filter code_icmp[] = { //{ 0x5, 0, 0, 0x00000001 }, //{ 0x5, 0, 0, 0x00000000 }, {0x30, 0, 0, 0x00000009}, {0x15, 0, 1, 0x00000001}, {0x6, 0, 0, 0x0000ffff}, {0x6, 0, 0, 0x00000000}, }; struct sock_filter code_icmp6[] = { // { 0x28, 0, 0, 0x0000000c }, // { 0x15, 0, 6, 0x000086dd }, {0x30, 0, 0, 0x00000006}, {0x15, 3, 0, 0x0000003a}, {0x15, 0, 3, 0x0000002c}, {0x30, 0, 0, 0x00000028}, {0x15, 0, 1, 0x0000003a}, {0x6, 0, 0, 0x00040000}, {0x6, 0, 0, 0x00000000}, }; /* tcpdump -i eth1 ip and icmp -d (000) ldh [12] (001) jeq #0x800 jt 2 jf 5 (002) ldb [23] (003) jeq #0x1 jt 4 jf 5 (004) ret #65535 (005) ret #0 tcpdump -i eth1 ip and icmp -dd { 0x28, 0, 0, 0x0000000c }, { 0x15, 0, 3, 0x00000800 }, { 0x30, 0, 0, 0x00000017 }, { 0x15, 0, 1, 0x00000001 }, { 0x6, 0, 0, 0x0000ffff }, { 0x6, 0, 0, 0x00000000 }, */ /* tcpdump -i eth1 ip and tcp and dst port 65534 -dd { 0x28, 0, 0, 0x0000000c }, { 0x15, 0, 8, 0x00000800 }, { 0x30, 0, 0, 0x00000017 }, { 0x15, 0, 6, 0x00000006 }, { 0x28, 0, 0, 0x00000014 }, { 0x45, 4, 0, 0x00001fff }, { 0xb1, 0, 0, 0x0000000e }, { 0x48, 0, 0, 0x00000010 }, { 0x15, 0, 1, 0x0000fffe }, { 0x6, 0, 0, 0x0000ffff }, { 0x6, 0, 0, 0x00000000 }, (000) ldh [12] (001) jeq #0x800 jt 2 jf 10 (002) ldb [23] (003) jeq #0x6 jt 4 jf 10 (004) ldh [20] (005) jset #0x1fff jt 10 jf 6 (006) ldxb 4*([14]&0xf) (007) ldh [x + 16] (008) jeq #0xfffe jt 9 jf 10 (009) ret #65535 (010) ret #0 */ #endif packet_info_t::packet_info_t() { src_port = 0; dst_port = 0; if (raw_mode == mode_faketcp) { protocol = IPPROTO_TCP; ack_seq = get_true_random_number(); seq = get_true_random_number(); has_ts = 0; ts_ack = 0; syn = 0; ack = 1; ack_seq_counter = 0; // mylog(log_info,"\n",ts_ack); } else if (raw_mode == mode_udp) { protocol = IPPROTO_UDP; } else if (raw_mode == mode_icmp) { if (raw_ip_version == AF_INET) { protocol = IPPROTO_ICMP; } else { assert(raw_ip_version == AF_INET6); protocol = IPPROTO_ICMPV6; } my_icmp_seq = 0; } } #ifdef UDP2RAW_MP void my_packet_handler( u_char *args, const struct pcap_pkthdr *packet_header, const u_char *pkt_data) { /*printf("<%d %d>\n",(int)packet_header->caplen,(int)packet_header->len ); for(int i=0;i",int( p[i] )); } printf("\n");*/ // mylog(log_debug,"received a packet!\n"); assert(packet_header->caplen <= packet_header->len); assert(packet_header->caplen <= huge_data_len); // if(packet_header->caplen > max_data_len) return ; if (g_fix_gro == 0 && packet_header->caplen < packet_header->len) return; if ((int)packet_header->caplen < pcap_link_header_len) return; // mylog(log_debug,"and its vaild!\n"); pthread_mutex_lock(&queue_mutex); if (!my_queue.full()) my_queue.push_back((char *)pkt_data, (int)(packet_header->caplen)); pthread_mutex_unlock(&queue_mutex); // pcap_cnt++; ev_async_send(g_default_loop, &async_watcher); return; } void *pcap_recv_thread_entry(void *none) { struct pcap_pkthdr *packet_header; const u_char *pkt_data; while (1) { if (use_pcap_mutex) pthread_mutex_lock(&pcap_mutex); int ret = pcap_loop(pcap_handle, -1, my_packet_handler, NULL); // use -1 instead of 0 as cnt, since 0 is undefined in old versions if (use_pcap_mutex) pthread_mutex_unlock(&pcap_mutex); if (ret == -1) mylog(log_warn, "pcap_loop exited with value %d\n", ret); else { mylog(log_debug, "pcap_loop exited with value %d\n", ret); } ev_sleep(1.0); // myexit(-1); } /* while(1) { //printf("!!!\n"); pthread_mutex_lock(&pcap_mutex); int ret=pcap_next_ex(pcap_handle,&packet_header,&pkt_data); pthread_mutex_unlock(&pcap_mutex); switch (ret) { case 0: continue; case 1: break; case -1: mylog(log_fatal,"pcap_next_ex error [%s]\n",pcap_geterr(pcap_handle)); myexit(-1); break; case -2: assert(0==1);// break; default: assert(0==1);// } } myexit(-1);*/ return 0; } extern void async_cb(struct ev_loop *loop, struct ev_async *watcher, int revents); #endif #ifdef UDP2RAW_LINUX int init_raw_socket() { assert(raw_ip_version == AF_INET || raw_ip_version == AF_INET6); g_ip_id_counter = get_true_random_number() % 65535; if (lower_level == 0) { raw_send_fd = socket(raw_ip_version, SOCK_RAW, IPPROTO_RAW); // IPPROTO_TCP?? if (raw_send_fd == -1) { mylog(log_fatal, "Failed to create raw_send_fd\n"); // perror("Failed to create raw_send_fd"); myexit(1); } /*ETH_P_IP int one = 1; const int *val = &one; if (setsockopt (raw_send_fd, IPPROTO_IP, IP_HDRINCL, val, sizeof (one)) < 0) { mylog(log_fatal,"Error setting IP_HDRINCL %d\n",errno); //perror("Error setting IP_HDRINCL"); myexit(2); }*/ } else { raw_send_fd = socket(PF_PACKET, SOCK_DGRAM, htons(ETH_P_IP)); // todo how to create a recv only raw socket? if (raw_send_fd == -1) { mylog(log_fatal, "Failed to create raw_send_fd\n"); // perror("Failed to create raw_send_fd"); myexit(1); } // init_ifindex(if_name); } int opt = 0; assert(setsockopt(raw_send_fd, SOL_SOCKET, SO_RCVBUF, &opt, sizeof(opt)) == 0); // raw_send_fd is for send only, set its recv buffer to zero if (force_socket_buf) { if (setsockopt(raw_send_fd, SOL_SOCKET, SO_SNDBUFFORCE, &socket_buf_size, sizeof(socket_buf_size)) < 0) { mylog(log_fatal, "SO_SNDBUFFORCE fail socket_buf_size=%d errno=%s\n", socket_buf_size, strerror(errno)); myexit(1); } } else { if (setsockopt(raw_send_fd, SOL_SOCKET, SO_SNDBUF, &socket_buf_size, sizeof(socket_buf_size)) < 0) { mylog(log_fatal, "SO_SNDBUF fail socket_buf_size=%d errno=%s\n", socket_buf_size, strerror(errno)); myexit(1); } } // raw_fd = socket(AF_PACKET, SOCK_DGRAM, htons(ETH_P_ALL)); if (raw_ip_version == AF_INET) raw_recv_fd = socket(PF_PACKET, SOCK_DGRAM, htons(ETH_P_IP)); else raw_recv_fd = socket(PF_PACKET, SOCK_DGRAM, htons(ETH_P_IPV6)); // ETH_P_IP doesnt read outgoing packets // https://stackoverflow.com/questions/20264895/eth-p-ip-is-not-working-as-expected-i-can-only-receive-incoming-packets // to capture both incoming and outgoing packets use ETH_P_ALL if (raw_recv_fd == -1) { mylog(log_fatal, "Failed to create raw_recv_fd\n"); // perror(""); myexit(1); } if (strlen(dev) != 0) { struct sockaddr_ll bind_address; memset(&bind_address, 0, sizeof(bind_address)); int index = -1; assert(init_ifindex(dev, raw_recv_fd, index) == 0); bind_address.sll_family = AF_PACKET; if (raw_ip_version == AF_INET) bind_address.sll_protocol = htons(ETH_P_IP); else bind_address.sll_protocol = htons(ETH_P_IPV6); bind_address.sll_ifindex = index; if (bind(raw_recv_fd, (struct sockaddr *)&bind_address, sizeof(bind_address)) == -1) { mylog(log_fatal, "bind to dev [%s] failed\n", dev); myexit(1); } } if (force_socket_buf) { if (setsockopt(raw_recv_fd, SOL_SOCKET, SO_RCVBUFFORCE, &socket_buf_size, sizeof(socket_buf_size)) < 0) { mylog(log_fatal, "SO_RCVBUFFORCE fail socket_buf_size=%d errno=%s\n", socket_buf_size, strerror(errno)); myexit(1); } } else { if (setsockopt(raw_recv_fd, SOL_SOCKET, SO_RCVBUF, &socket_buf_size, sizeof(socket_buf_size)) < 0) { mylog(log_fatal, "SO_RCVBUF fail socket_buf_size=%d errno=%s\n", socket_buf_size, strerror(errno)); myexit(1); } } // IP_HDRINCL to tell the kernel that headers are included in the packet setnonblocking(raw_send_fd); // not really necessary setnonblocking(raw_recv_fd); return 0; } #endif #ifdef UDP2RAW_MP int init_raw_socket() { #ifndef NO_LIBNET char libnet_errbuf[LIBNET_ERRBUF_SIZE]; if (raw_ip_version == AF_INET) { libnet_handle = libnet_init(LIBNET_RAW4, dev, libnet_errbuf); } else { assert(raw_ip_version == AF_INET6); libnet_handle = libnet_init(LIBNET_RAW6, dev, libnet_errbuf); } if (libnet_handle == 0) { mylog(log_fatal, "libnet_init failed bc of [%s]\n", libnet_errbuf); myexit(-1); } g_ptag = 0; libnet_clear_packet(libnet_handle); #endif char pcap_errbuf[PCAP_ERRBUF_SIZE]; // pcap_handle=pcap_open_live(dev,max_data_len,0,1000,pcap_errbuf); pcap_handle = pcap_create(dev, pcap_errbuf); if (pcap_handle == 0) { mylog(log_fatal, "pcap_create failed bc of [%s]\n", pcap_errbuf); myexit(-1); } assert(pcap_set_snaplen(pcap_handle, huge_data_len) == 0); assert(pcap_set_promisc(pcap_handle, 0) == 0); assert(pcap_set_timeout(pcap_handle, 1) == 0); assert(pcap_set_immediate_mode(pcap_handle, 1) == 0); int ret = pcap_activate(pcap_handle); if (ret < 0) { printf("pcap_activate failed %s\n", pcap_geterr(pcap_handle)); myexit(-1); } if (send_with_pcap) { ret = pcap_setdirection(pcap_handle, PCAP_D_INOUT); // must be used after being actived if (ret != 0) mylog(log_debug, "pcap_setdirection(pcap_handle,PCAP_D_INOUT) failed with value %d, %s\n", ret, pcap_geterr(pcap_handle)); } else { ret = pcap_setdirection(pcap_handle, PCAP_D_IN); if (ret != 0) mylog(log_debug, "pcap_setdirection(pcap_handle,PCAP_D_IN) failed with value %d, %s\n", ret, pcap_geterr(pcap_handle)); } ret = pcap_datalink(pcap_handle); if (ret == DLT_EN10MB) { pcap_link_header_len = 14; } else if (ret == DLT_NULL) { pcap_link_header_len = 4; } else if (ret == DLT_LINUX_SLL) { pcap_link_header_len = 16; } else { mylog(log_fatal, "unknown pcap link type : %d\n", ret); myexit(-1); } char filter_exp[1000]; address_t tmp_addr; if (get_src_adress2(tmp_addr, remote_addr) != 0) { mylog(log_error, "get_src_adress() failed, maybe you dont have internet\n"); myexit(-1); } string src = tmp_addr.get_ip(); string dst = remote_addr.get_ip(); if (raw_ip_version == AF_INET) { // sprintf(filter_exp,"ip and src %s and dst %s and (tcp or udp or icmp)",my_ntoa(source_ip_uint32),dst.c_str()); sprintf(filter_exp, "ip and src %s and dst %s and (tcp or udp or icmp)", src.c_str(), dst.c_str()); } else { assert(raw_ip_version == AF_INET6); sprintf(filter_exp, "ip6 and src %s and dst %s and (tcp or udp or icmp6)", src.c_str(), dst.c_str()); } if (pcap_compile(pcap_handle, &g_filter, filter_exp, 0, PCAP_NETMASK_UNKNOWN) == -1) { printf("Bad filter - %s\n", pcap_geterr(pcap_handle)); myexit(-1); } g_filter_compile_cnt++; if (pcap_setfilter(pcap_handle, &g_filter) == -1) { printf("Error setting filter - %s\n", pcap_geterr(pcap_handle)); myexit(-1); } ///////////////////////////////////////////////////////////////new thread created here if (pthread_create(&pcap_recv_thread, NULL, pcap_recv_thread_entry, 0)) { mylog(log_fatal, "Error creating thread\n"); myexit(-1); } //////////////////////////////////////////////////////////////////////////////// g_ip_id_counter = get_true_random_number() % 65535; /* if(lower_level==0) { raw_send_fd = socket(AF_INET , SOCK_RAW , IPPROTO_TCP); if(raw_send_fd == -1) { mylog(log_fatal,"Failed to create raw_send_fd\n"); //perror("Failed to create raw_send_fd"); myexit(1); } int one = 1; const int *val = &one; if (setsockopt (raw_send_fd, IPPROTO_IP, IP_HDRINCL, val, sizeof (one)) < 0) { mylog(log_fatal,"Error setting IP_HDRINCL %d\n",errno); //perror("Error setting IP_HDRINCL"); myexit(2); } } else { raw_send_fd = socket(PF_PACKET , SOCK_DGRAM , htons(ETH_P_IP)); if(raw_send_fd == -1) { mylog(log_fatal,"Failed to create raw_send_fd\n"); //perror("Failed to create raw_send_fd"); myexit(1); } //init_ifindex(if_name); } if(force_socket_buf) { if(setsockopt(raw_send_fd, SOL_SOCKET, SO_SNDBUFFORCE, &socket_buf_size, sizeof(socket_buf_size))<0) { mylog(log_fatal,"SO_SNDBUFFORCE fail socket_buf_size=%d errno=%s\n",socket_buf_size,strerror(errno)); myexit(1); } } else { if(setsockopt(raw_send_fd, SOL_SOCKET, SO_SNDBUF, &socket_buf_size, sizeof(socket_buf_size))<0) { mylog(log_fatal,"SO_SNDBUF fail socket_buf_size=%d errno=%s\n",socket_buf_size,strerror(errno)); myexit(1); } } //raw_fd = socket(AF_PACKET, SOCK_DGRAM, htons(ETH_P_ALL)); raw_recv_fd= socket(PF_PACKET, SOCK_DGRAM, htons(ETH_P_IP)); if(raw_recv_fd == -1) { mylog(log_fatal,"Failed to create raw_recv_fd\n"); //perror(""); myexit(1); } if(force_socket_buf) { if(setsockopt(raw_recv_fd, SOL_SOCKET, SO_RCVBUFFORCE, &socket_buf_size, sizeof(socket_buf_size))<0) { mylog(log_fatal,"SO_RCVBUFFORCE fail socket_buf_size=%d errno=%s\n",socket_buf_size,strerror(errno)); myexit(1); } } else { if(setsockopt(raw_recv_fd, SOL_SOCKET, SO_RCVBUF, &socket_buf_size, sizeof(socket_buf_size))<0) { mylog(log_fatal,"SO_RCVBUF fail socket_buf_size=%d errno=%s\n",socket_buf_size,strerror(errno)); myexit(1); } } //IP_HDRINCL to tell the kernel that headers are included in the packet setnonblocking(raw_send_fd); //not really necessary setnonblocking(raw_recv_fd);*/ return 0; } #endif #ifdef UDP2RAW_LINUX void init_filter(int port) { sock_fprog bpf; assert(raw_ip_version == AF_INET || raw_ip_version == AF_INET6); if (raw_mode == mode_faketcp || raw_mode == mode_udp) { filter_port = port; } if (disable_bpf_filter) return; // if(raw_mode==mode_icmp) return ; // code_tcp[8].k=code_tcp[10].k=port; if (raw_mode == mode_faketcp) { if (raw_ip_version == AF_INET) { bpf.len = sizeof(code_tcp) / sizeof(code_tcp[0]); code_tcp[code_tcp_port_index].k = port; bpf.filter = code_tcp; } else { bpf.len = sizeof(code_tcp6) / sizeof(code_tcp6[0]); code_tcp6[code_tcp6_port_index].k = port; bpf.filter = code_tcp6; } } else if (raw_mode == mode_udp) { if (raw_ip_version == AF_INET) { bpf.len = sizeof(code_udp) / sizeof(code_udp[0]); code_udp[code_udp_port_index].k = port; bpf.filter = code_udp; } else { bpf.len = sizeof(code_udp6) / sizeof(code_udp6[0]); code_udp6[code_udp6_port_index].k = port; bpf.filter = code_udp6; } } else if (raw_mode == mode_icmp) { if (raw_ip_version == AF_INET) { bpf.len = sizeof(code_icmp) / sizeof(code_icmp[0]); bpf.filter = code_icmp; } else { bpf.len = sizeof(code_icmp6) / sizeof(code_icmp6[0]); bpf.filter = code_icmp6; } } int dummy; int ret = setsockopt(raw_recv_fd, SOL_SOCKET, SO_DETACH_FILTER, &dummy, sizeof(dummy)); // in case i forgot to remove if (ret != 0) { mylog(log_debug, "error remove fiter\n"); // perror("filter"); // exit(-1); } ret = setsockopt(raw_recv_fd, SOL_SOCKET, SO_ATTACH_FILTER, &bpf, sizeof(bpf)); if (ret != 0) { mylog(log_fatal, "error set fiter\n"); // perror("filter"); myexit(-1); } } #endif #ifdef UDP2RAW_MP void init_filter(int port) { /* sock_fprog bpf;*/ if (raw_mode == mode_faketcp || raw_mode == mode_udp) { filter_port = port; } char filter_exp[1000]; if (raw_ip_version == AF_INET) { if (raw_mode == mode_faketcp) { sprintf(filter_exp, "ip and tcp and src %s and src port %d and dst port %d", remote_addr.get_ip(), remote_addr.get_port(), port); } else if (raw_mode == mode_udp) { sprintf(filter_exp, "ip and udp and src %s and src port %d and dst port %d", remote_addr.get_ip(), remote_addr.get_port(), port); } else if (raw_mode == mode_icmp) { sprintf(filter_exp, "ip and icmp and src %s", remote_addr.get_ip()); } else { mylog(log_fatal, "unknow raw mode\n"); myexit(-1); } } else { assert(raw_ip_version == AF_INET6); if (raw_mode == mode_faketcp) { sprintf(filter_exp, "ip6 and tcp and src %s and src port %d and dst port %d", remote_addr.get_ip(), remote_addr.get_port(), port); } else if (raw_mode == mode_udp) { sprintf(filter_exp, "ip6 and udp and src %s and src port %d and dst port %d", remote_addr.get_ip(), remote_addr.get_port(), port); } else if (raw_mode == mode_icmp) { sprintf(filter_exp, "ip6 and icmp6 and src %s", remote_addr.get_ip()); } else { mylog(log_fatal, "unknow raw mode\n"); myexit(-1); } } mylog(log_info, "filter expression is [%s]\n", filter_exp); // pthread_mutex_lock(&pcap_mutex);//not sure if mutex is needed here long long tmp_cnt = 0; if (use_pcap_mutex) { while (pthread_mutex_trylock(&pcap_mutex) != 0) { tmp_cnt++; pcap_breakloop(pcap_handle); if (tmp_cnt == 100) { mylog(log_warn, "%lld attempts of pcap_breakloop()\n", tmp_cnt); } if (tmp_cnt % 1000 == 0) { mylog(log_warn, "%lld attempts of pcap_breakloop()\n", tmp_cnt); if (tmp_cnt > 5000) { mylog(log_fatal, "we might have already run into a deadlock\n"); } } ev_sleep(0.001); } mylog(log_info, "breakloop() succeed after %lld attempt(s)\n", tmp_cnt); } if (1) { int ret = pcap_setdirection(pcap_handle, PCAP_D_IN); if (ret != 0) mylog(log_debug, "pcap_setdirection(pcap_handle,PCAP_D_IN) failed with value %d, %s\n", ret, pcap_geterr(pcap_handle)); } assert(g_filter_compile_cnt != 0); pcap_freecode(&g_filter); if (pcap_compile(pcap_handle, &g_filter, filter_exp, 0, PCAP_NETMASK_UNKNOWN) == -1) { mylog(log_fatal, "Bad filter - %s\n", pcap_geterr(pcap_handle)); myexit(-1); } g_filter_compile_cnt++; if (pcap_setfilter(pcap_handle, &g_filter) == -1) { mylog(log_fatal, "Error setting filter - %s\n", pcap_geterr(pcap_handle)); myexit(-1); } if (use_pcap_mutex) pthread_mutex_unlock(&pcap_mutex); /* if(disable_bpf_filter) return; //if(raw_mode==mode_icmp) return ; //code_tcp[8].k=code_tcp[10].k=port; if(raw_mode==mode_faketcp) { bpf.len = sizeof(code_tcp)/sizeof(code_tcp[0]); code_tcp[code_tcp_port_index].k=port; bpf.filter = code_tcp; } else if(raw_mode==mode_udp) { bpf.len = sizeof(code_udp)/sizeof(code_udp[0]); code_udp[code_udp_port_index].k=port; bpf.filter = code_udp; } else if(raw_mode==mode_icmp) { bpf.len = sizeof(code_icmp)/sizeof(code_icmp[0]); bpf.filter = code_icmp; } int dummy; int ret=setsockopt(raw_recv_fd, SOL_SOCKET, SO_DETACH_FILTER, &dummy, sizeof(dummy)); //in case i forgot to remove if (ret != 0) { mylog(log_debug,"error remove fiter\n"); //perror("filter"); //exit(-1); } ret = setsockopt(raw_recv_fd, SOL_SOCKET, SO_ATTACH_FILTER, &bpf, sizeof(bpf)); if (ret != 0) { mylog(log_fatal,"error set fiter\n"); //perror("filter"); myexit(-1); }*/ } #endif void remove_filter() { filter_port = 0; #ifdef UDP2RAW_LINUX int dummy; int ret = setsockopt(raw_recv_fd, SOL_SOCKET, SO_DETACH_FILTER, &dummy, sizeof(dummy)); if (ret != 0) { mylog(log_debug, "error remove fiter\n"); // perror("filter"); // exit(-1); } #endif } int init_ifindex(const char *if_name, int fd, int &index) { #ifdef UDP2RAW_LINUX struct ifreq ifr; size_t if_name_len = strlen(if_name); if (if_name_len < sizeof(ifr.ifr_name)) { memcpy(ifr.ifr_name, if_name, if_name_len); ifr.ifr_name[if_name_len] = 0; } else { mylog(log_fatal, "interface name is too long\n"); myexit(-1); } if (ioctl(fd, SIOCGIFINDEX, &ifr) == -1) { mylog(log_fatal, "SIOCGIFINDEX fail ,%s\n", strerror(errno)); myexit(-1); } index = ifr.ifr_ifindex; mylog(log_info, "ifname:%s ifindex:%d\n", if_name, index); #endif return 0; } #ifdef UDP2RAW_LINUX bool interface_has_arp(const char *interface) { struct ifreq ifr; // int sock = socket(PF_INET6, SOCK_DGRAM, IPPROTO_IP); int sock = raw_send_fd; memset(&ifr, 0, sizeof(ifr)); strcpy(ifr.ifr_name, interface); if (ioctl(sock, SIOCGIFFLAGS, &ifr) < 0) { // perror("SIOCGIFFLAGS"); mylog(log_fatal, "ioctl(sock, SIOCGIFFLAGS, &ifr) failed for interface %s,errno %s\n", interface, strerror(errno)); myexit(-1); } // close(sock); return !(ifr.ifr_flags & IFF_NOARP); } struct route_info_t { string if_name; u32_t dest; u32_t mask; u32_t gw; u32_t flag; }; int dest_idx = 1; int gw_idx = 2; int if_idx = 0; int mask_idx = 7; int flag_idx = 3; vector find_route_entry(const vector &route_info_vec, u32_t ip) { vector res; for (u32_t i = 0; i <= 32; i++) { u32_t mask = 0xffffffff; // mask >>=i; // if(i==32) mask=0; //why 0xffffffff>>32 equals 0xffffffff?? mask <<= i; if (i == 32) mask = 0; log_bare(log_debug, "(mask:%x)", mask); for (u32_t j = 0; j < route_info_vec.size(); j++) { const route_info_t &info = route_info_vec[j]; if (info.mask != mask) continue; log_bare(log_debug, "<<%d,%d>>", i, j); if ((info.dest & mask) == (ip & mask)) { log_bare(log_debug, "found!"); res.push_back(j); } } if (res.size() != 0) { return res; } } return res; } int find_direct_dest(const vector &route_info_vec, u32_t ip, u32_t &dest_ip, string &if_name) { vector res; for (int i = 0; i < 1000; i++) { res = find_route_entry(route_info_vec, ip); log_bare(log_debug, "", (u32_t)res.size()); if (res.size() == 0) { mylog(log_error, "cant find route entry\n"); return -1; } if (res.size() > 1) { mylog(log_error, "found duplicated entries\n"); return -1; } if ((route_info_vec[res[0]].flag & 2) == 0) { dest_ip = ip; if_name = route_info_vec[res[0]].if_name; return 0; } else { ip = route_info_vec[res[0]].gw; } } mylog(log_error, "dead loop in find_direct_dest\n"); return -1; } struct arp_info_t { u32_t ip; string hw; string if_name; }; int arp_ip_idx = 0; int arp_hw_idx = 3; int arp_if_idx = 5; int find_arp(const vector &arp_info_vec, u32_t ip, string if_name, string &hw) { int pos = -1; int count = 0; for (u32_t i = 0; i < arp_info_vec.size(); i++) { const arp_info_t &info = arp_info_vec[i]; if (info.if_name != if_name) continue; if (info.ip == ip) { count++; pos = i; } } if (count == 0) { // mylog(log_warn,"cant find arp entry for %s %s,using 00:00:00:00:00:00\n",my_ntoa(ip),if_name.c_str()); // hw="00:00:00:00:00:00"; mylog(log_error, "cant find arp entry for %s %s\n", my_ntoa(ip), if_name.c_str()); return -1; } if (count > 1) { mylog(log_error, "find multiple arp entry for %s %s\n", my_ntoa(ip), if_name.c_str()); return -1; } hw = arp_info_vec[pos].hw; return 0; } int find_lower_level_info(u32_t ip, u32_t &dest_ip, string &if_name, string &hw) { ip = htonl(ip); if (ip == htonl(inet_addr("127.0.0.1"))) { dest_ip = ntohl(ip); if_name = "lo"; hw = "00:00:00:00:00:00"; return 0; } string route_file; if (read_file("/proc/net/route", route_file) != 0) return -1; string arp_file; if (read_file("/proc/net/arp", arp_file) != 0) return -1; log_bare(log_debug, "/proc/net/route:<<%s>>\n", route_file.c_str()); log_bare(log_debug, "/proc/net/arp:<<%s>>\n", route_file.c_str()); auto route_vec2 = string_to_vec2(route_file.c_str()); vector route_info_vec; for (u32_t i = 1; i < route_vec2.size(); i++) { log_bare(log_debug, "", (u32_t)route_vec2[i].size()); if (route_vec2[i].size() != 11) { mylog(log_error, "route coloum %d !=11 \n", int(route_vec2[i].size())); return -1; } route_info_t tmp; tmp.if_name = route_vec2[i][if_idx]; if (hex_to_u32_with_endian(route_vec2[i][dest_idx], tmp.dest) != 0) return -1; if (hex_to_u32_with_endian(route_vec2[i][gw_idx], tmp.gw) != 0) return -1; if (hex_to_u32_with_endian(route_vec2[i][mask_idx], tmp.mask) != 0) return -1; if (hex_to_u32(route_vec2[i][flag_idx], tmp.flag) != 0) return -1; route_info_vec.push_back(tmp); for (u32_t j = 0; j < route_vec2[i].size(); j++) { log_bare(log_debug, "<%s>", route_vec2[i][j].c_str()); } log_bare(log_debug, "%s dest:%x mask:%x gw:%x flag:%x", tmp.if_name.c_str(), tmp.dest, tmp.mask, tmp.gw, tmp.flag); log_bare(log_debug, "\n"); } if (find_direct_dest(route_info_vec, ip, dest_ip, if_name) != 0) { mylog(log_error, "find_direct_dest failed for ip %s\n", my_ntoa(ntohl(ip))); return -1; } log_bare(log_debug, "========\n"); auto arp_vec2 = string_to_vec2(arp_file.c_str()); vector arp_info_vec; for (u32_t i = 1; i < arp_vec2.size(); i++) { log_bare(log_debug, "<>", (int)arp_vec2[i].size()); for (u32_t j = 0; j < arp_vec2[i].size(); j++) { log_bare(log_debug, "<%s>", arp_vec2[i][j].c_str()); } if (arp_vec2[i].size() != 6) { mylog(log_error, "arp coloum %d !=11 \n", int(arp_vec2[i].size())); return -1; } arp_info_t tmp; tmp.if_name = arp_vec2[i][arp_if_idx]; tmp.hw = arp_vec2[i][arp_hw_idx]; tmp.ip = htonl(inet_addr(arp_vec2[i][arp_ip_idx].c_str())); arp_info_vec.push_back(tmp); log_bare(log_debug, "\n"); } if (!interface_has_arp(if_name.c_str())) { mylog(log_info, "%s is a noarp interface,using 00:00:00:00:00:00\n", if_name.c_str()); hw = "00:00:00:00:00:00"; } else if (find_arp(arp_info_vec, dest_ip, if_name, hw) != 0) { mylog(log_error, "find_arp failed for dest_ip %s ,if_name %s\n", my_ntoa(ntohl(ip)), if_name.c_str()); return -1; } // printf("%s\n",hw.c_str()); dest_ip = ntohl(dest_ip); return 0; } #endif #ifdef UDP2RAW_LINUX int send_raw_packet(raw_info_t &raw_info, const char *packet, int len) { const packet_info_t &send_info = raw_info.send_info; const packet_info_t &recv_info = raw_info.recv_info; int ret; if (lower_level == 0) { if (raw_ip_version == AF_INET) { struct sockaddr_in sin = {0}; sin.sin_family = raw_ip_version; // sin.sin_port = htons(info.dst_port); //dont need this sin.sin_addr.s_addr = send_info.new_dst_ip.v4; ret = sendto(raw_send_fd, packet, len, 0, (struct sockaddr *)&sin, sizeof(sin)); } else if (raw_ip_version == AF_INET6) { struct sockaddr_in6 sin = {0}; sin.sin6_family = raw_ip_version; // sin.sin_port = htons(info.dst_port); //dont need this sin.sin6_addr = send_info.new_dst_ip.v6; ret = sendto(raw_send_fd, packet, len, 0, (struct sockaddr *)&sin, sizeof(sin)); } else { assert(0 == 1); } } else { struct sockaddr_ll addr = {0}; //={0} not necessary memcpy(&addr, &send_info.addr_ll, sizeof(addr)); ret = sendto(raw_send_fd, packet, len, 0, (struct sockaddr *)&addr, sizeof(addr)); } if (ret == -1) { mylog(log_trace, "sendto failed\n"); // perror("why?"); return -1; } else { // mylog(log_info,"sendto succ\n"); } return 0; } #endif #ifdef UDP2RAW_MP int send_raw_packet(raw_info_t &raw_info, const char *packet, int len) { const packet_info_t &send_info = raw_info.send_info; const packet_info_t &recv_info = raw_info.recv_info; if (!send_with_pcap) { #ifndef NO_LIBNET // g_ptag=libnet_build_ipv4(ip_tot_len, iph->tos, ntohs(iph->id), ntohs(iph->frag_off), // iph->ttl , iph->protocol , iph->check , iph->saddr, iph->daddr, // (const unsigned char *)payload, payloadlen, libnet_handle, g_ptag); // assert(g_ptag!=-1 &&g_ptag!=0); // int ret; // ret= libnet_write(libnet_handle); // assert(ret!=-1); // iph->tot_len=htons(ip_tot_len); // iph->check =csum ((unsigned short *) send_raw_ip_buf, iph->ihl*4); if (raw_ip_version == AF_INET) { libnet_write_raw_ipv4(libnet_handle, (const unsigned char *)packet, len); // todo, this api is marked as internal, maybe we should avoid using it. } else { assert(raw_ip_version == AF_INET6); libnet_write_raw_ipv6(libnet_handle, (const unsigned char *)packet, len); } #endif } else { char buf[buf_len]; assert(pcap_header_captured == 1); assert(pcap_link_header_len != -1); memcpy(buf, pcap_header_buf, pcap_link_header_len); memcpy(buf + pcap_link_header_len, packet, len); // pthread_mutex_lock(&pcap_mutex); looks like this is not necessary, and it harms performance int ret = pcap_sendpacket(pcap_handle, (const unsigned char *)buf, len + pcap_link_header_len); if (ret != 0) { mylog(log_warn, "pcap_sendpcaket failed with vaule %d,%s, data_len=%d\n", ret, pcap_geterr(pcap_handle), len); // pthread_mutex_unlock(&pcap_mutex); // myexit(-1); } // pthread_mutex_unlock(&pcap_mutex); /* unsigned char *p=(unsigned char *)send_raw_ip_buf0; for(int i=0;i",int(p[i])); printf("\n"); assert(pcap_sendpacket(pcap_handle,(const unsigned char *)pcap_header_buf,cap_len)==0); p=(unsigned char *)pcap_header_buf; for(int i=0;i",int(p[i])); printf("\n"); printf("pcap send!\n");*/ } return 0; } #endif int g_should_fragment = 0; int send_raw_ip(raw_info_t &raw_info, const char *payload, int payloadlen) { const packet_info_t &send_info = raw_info.send_info; const packet_info_t &recv_info = raw_info.recv_info; char send_raw_ip_buf[buf_len]; if (raw_info.disabled) { mylog(log_debug, "[%s,%d]connection disabled, no packet will be sent\n", recv_info.new_src_ip.get_str1(), recv_info.src_port); assert(max_rst_allowed >= 0); return 0; } uint16_t ip_tot_len; if (raw_ip_version == AF_INET) { struct my_iphdr *iph = (struct my_iphdr *)send_raw_ip_buf; memset(iph, 0, sizeof(my_iphdr)); iph->ihl = sizeof(my_iphdr) / 4; // we dont use ip options,so the length is just sizeof(iphdr) iph->version = 4; iph->tos = 0; if (lower_level) { // iph->id=0; iph->id = htons(g_ip_id_counter++); // Id of this packet } else // no need to else? { iph->id = htons(g_ip_id_counter++); // Id of this packet // iph->id = 0; //Id of this packet ,kernel will auto fill this if id is zero ,or really?????// todo //seems like there is a problem } if (g_should_fragment) { iph->frag_off = htons(0x0000); //DF cleared,others are zero } else { iph->frag_off = htons(0x4000); // DF set,others are zero } iph->ttl = (unsigned char)ttl_value; iph->protocol = send_info.protocol; iph->check = 0; // Set to 0 before calculating checksum iph->saddr = send_info.new_src_ip.v4; // Spoof the source ip address iph->daddr = send_info.new_dst_ip.v4; ip_tot_len = sizeof(struct my_iphdr) + payloadlen; #ifdef UDP2RAW_LINUX if (lower_level) iph->tot_len = htons(ip_tot_len); // this is not necessary ,kernel will always auto fill this //http://man7.org/linux/man-pages/man7/raw.7.html else iph->tot_len = 0; #endif #ifdef UDP2RAW_MP iph->tot_len = htons(ip_tot_len); // always fill for mp version #endif memcpy(send_raw_ip_buf + sizeof(my_iphdr), payload, payloadlen); #ifdef UDP2RAW_LINUX if (lower_level) iph->check = csum((unsigned short *)send_raw_ip_buf, iph->ihl * 4); // this is not necessary ,kernel will always auto fill this else iph->check = 0; #endif #ifdef UDP2RAW_MP iph->check = csum((unsigned short *)send_raw_ip_buf, iph->ihl * 4); // always cal checksum for mp version #endif } else { assert(raw_ip_version == AF_INET6); struct my_ip6hdr *ip6h = (struct my_ip6hdr *)send_raw_ip_buf; memset(ip6h, 0, sizeof(my_ip6hdr)); ip6h->version = 6; ip6h->payload_len = htons(payloadlen); ip6h->next_header = send_info.protocol; ip6h->hop_limit = (unsigned char)ttl_value; ip6h->src = send_info.new_src_ip.v6; ip6h->dst = send_info.new_dst_ip.v6; ip_tot_len = sizeof(struct my_ip6hdr) + payloadlen; memcpy(send_raw_ip_buf + sizeof(my_ip6hdr), payload, payloadlen); } return send_raw_packet(raw_info, send_raw_ip_buf, ip_tot_len); } int pre_recv_raw_packet() { #ifdef UDP2RAW_LINUX assert(g_packet_buf_cnt == 0); g_sockaddr_len = sizeof(g_sockaddr.ll); g_packet_buf_len = recvfrom(raw_recv_fd, g_packet_buf, huge_data_len + 1, 0, (sockaddr *)&g_sockaddr, &g_sockaddr_len); // assert(g_sockaddr_len==sizeof(g_sockaddr.ll)); //g_sockaddr_len=18, sizeof(g_sockaddr.ll)=20, why its not equal? maybe its bc sll_halen is 6? // assert(g_addr_ll_size==sizeof(g_addr_ll)); if (g_packet_buf_len == huge_data_len + 1) { if (g_fix_gro == 0) { mylog(log_warn, "huge packet, data_len %d > %d,dropped\n", g_packet_buf_len, huge_data_len); return -1; } else { mylog(log_debug, "huge packet, data_len %d > %d,not dropped\n", g_packet_buf_len, huge_data_len); g_packet_buf_len = huge_data_len; } } if (g_packet_buf_len >= max_data_len + 1) { if (g_fix_gro == 0) { mylog(log_warn, "huge packet, data_len %d > %d(max_data_len) dropped, maybe you need to turn down mtu at upper level, or you may take a look at --fix-gro\n", g_packet_buf_len, max_data_len); return -1; } else { mylog(log_debug, "huge packet, data_len %d > %d(max_data_len) not dropped\n", g_packet_buf_len, max_data_len); // return -1; } } if (g_packet_buf_len < 0) { mylog(log_trace, "recv_len %d\n", g_packet_buf_len); return -1; } g_packet_buf_cnt++; #endif return 0; } int discard_raw_packet() { assert(g_packet_buf_cnt == 1); g_packet_buf_cnt--; return 0; } #ifdef UDP2RAW_LINUX int recv_raw_packet(char *&packet, int &len, int peek) { assert(g_packet_buf_cnt == 1); if (!peek) g_packet_buf_cnt--; if (g_packet_buf_len < int(link_level_header_len)) { mylog(log_trace, "packet len %d shorter than link_level_header_len %d\n", g_packet_buf_len, int(link_level_header_len)); return -1; } if (link_level_header_len == 14) { unsigned char a = g_packet_buf[12]; unsigned char b = g_packet_buf[13]; if (!((a == 0x08 && b == 0x00) || (a == 0x86 && b == 0xdd))) { mylog(log_trace, "not an ipv4 or ipv6 packet!\n"); return -1; } } packet = g_packet_buf + int(link_level_header_len); len = g_packet_buf_len - int(link_level_header_len); return 0; } #endif #ifdef UDP2RAW_MP int recv_raw_packet(char *&packet, int &len, int peek) { assert(g_packet_buf_cnt == 1); if (!peek) g_packet_buf_cnt--; packet = g_packet_buf; len = g_packet_buf_len; return 0; } #endif int recv_raw_ip(raw_info_t &raw_info, char *&payload, int &payloadlen) { char *raw_packet_buf; // static char recv_raw_ip_buf[buf_len]; int raw_packet_len; if (recv_raw_packet(raw_packet_buf, raw_packet_len, raw_info.peek) != 0) return -1; // const packet_info_t &send_info=raw_info.send_info; packet_info_t &recv_info = raw_info.recv_info; my_iphdr *iph; my_ip6hdr *ip6h; int flag = 0; // int recv_len = recvfrom(raw_recv_fd, recv_raw_ip_buf, max_data_len+1, flag ,(sockaddr*)&saddr , &saddr_size); char *ip_begin = raw_packet_buf; // 14 is eth net header if (raw_packet_len < 1) { mylog(log_trace, "raw_packet_len <1, dropped\n"); return -1; } iph = (struct my_iphdr *)(ip_begin); ip6h = (struct my_ip6hdr *)(ip_begin); if (raw_ip_version == AF_INET) { if (iph->version != 4) { mylog(log_trace, "expect ipv4 packet, but got something else: %02x\n", iph->version); return -1; } if (raw_packet_len < (int)sizeof(my_iphdr)) { mylog(log_trace, "raw_packet_lenversion != 6) { mylog(log_trace, "expect ipv6 packet, but got something else: %02x\n", ip6h->version); return -1; } if (raw_packet_len < (int)sizeof(my_ip6hdr)) { mylog(log_trace, "raw_packet_lensaddr; recv_info.new_dst_ip.v4 = iph->daddr; recv_info.protocol = iph->protocol; iphdrlen = iph->ihl * 4; ip_len = ntohs(iph->tot_len); } else { // todo flow id assert(raw_ip_version == AF_INET6); recv_info.new_src_ip.v6 = ip6h->src; recv_info.new_dst_ip.v6 = ip6h->dst; iphdrlen = 40; recv_info.protocol = ip6h->next_header; // todo handle extension headers; ip_len = ntohs(ip6h->payload_len) + iphdrlen; } if (bind_addr_used && !recv_info.new_dst_ip.equal(bind_addr)) { mylog(log_trace, "bind adress doenst match %s %s, dropped\n", recv_info.new_dst_ip.get_str1(), bind_addr.get_str2()); // printf(" bind adress doenst match, dropped\n"); return -1; } // if (!(iph->ihl > 0 && iph->ihl <=60)) { // mylog(log_trace,"iph ihl error\n"); // return -1; // } if (raw_packet_len < ip_len) { mylog(log_debug, "incomplete packet\n"); return -1; } if (raw_ip_version == AF_INET) { if (raw_info.peek == 0) // avoid cal it twice { u32_t ip_chk = csum((unsigned short *)ip_begin, iphdrlen); if (ip_chk != 0) { mylog(log_debug, "ip header error %x\n", ip_chk); return -1; } } } else { // do nothing } payload = ip_begin + iphdrlen; payloadlen = ip_len - iphdrlen; if (payloadlen < 0) { mylog(log_warn, "error payload len\n"); return -1; } return 0; } int peek_raw(raw_info_t &raw_info) { // static char peek_raw_buf[buf_len]; // assert(g_packet_buf_cnt==1); // g_packet_buf_cnt--; // char * peek_raw_buf=g_packet_buf; // int recv_len=g_packet_buf_len; // char *ip_begin=peek_raw_buf+link_level_header_len; // struct sockaddr saddr={0}; // socklen_t saddr_size=sizeof(saddr); // int recv_len = recvfrom(raw_recv_fd, peek_raw_buf,max_data_len, MSG_PEEK ,&saddr , &saddr_size);//change max_data_len to something smaller,we only need header here // iphdr * iph = (struct iphdr *) (ip_begin); // mylog(log_info,"recv_len %d\n",recv_len); // if(recv_lensaddr; // unsigned short iphdrlen =iph->ihl*4; // char *payload=ip_begin+iphdrlen; packet_info_t &recv_info = raw_info.recv_info; char *payload; int payload_len; if (recv_raw_ip(raw_info, payload, payload_len) != 0) return -1; // mylog(log_info,"protocol %d\n",iph->protocol); switch (raw_mode) { case mode_faketcp: { if (recv_info.protocol != IPPROTO_TCP) { mylog(log_trace, "failed here"); return -1; } struct my_tcphdr *tcph = (my_tcphdr *)payload; if (payload_len < int(sizeof(my_tcphdr))) { mylog(log_trace, "failed here"); return -1; } recv_info.src_port = ntohs(tcph->source); recv_info.syn = tcph->syn; break; } case mode_udp: { if (recv_info.protocol != IPPROTO_UDP) return -1; struct my_udphdr *udph = (my_udphdr *)payload; if (payload_len < int(sizeof(my_udphdr))) return -1; recv_info.src_port = ntohs(udph->source); break; } case mode_icmp: { if (raw_ip_version == AF_INET) { if (recv_info.protocol != IPPROTO_ICMP) return -1; } else { assert(raw_ip_version == AF_INET6); if (recv_info.protocol != IPPROTO_ICMPV6) return -1; } struct my_icmphdr *icmph = (my_icmphdr *)payload; if (payload_len < int(sizeof(my_udphdr))) return -1; recv_info.src_port = ntohs(icmph->id); break; } default: return -1; } return 0; } int send_raw_icmp(raw_info_t &raw_info, const char *payload, int payloadlen) { const packet_info_t &send_info = raw_info.send_info; const packet_info_t &recv_info = raw_info.recv_info; char send_raw_icmp_buf[buf_len]; my_icmphdr *icmph = (struct my_icmphdr *)(send_raw_icmp_buf); memset(icmph, 0, sizeof(my_icmphdr)); if (raw_ip_version == AF_INET) { if (program_mode == client_mode) { icmph->type = 8; } else { icmph->type = 0; } } else { assert(raw_ip_version == AF_INET6); if (program_mode == client_mode) { icmph->type = 128; } else { icmph->type = 129; } } icmph->code = 0; icmph->id = htons(send_info.src_port); icmph->seq = htons(send_info.my_icmp_seq); /////////////modify memcpy(send_raw_icmp_buf + sizeof(my_icmphdr), payload, payloadlen); if (raw_ip_version == AF_INET) { icmph->check_sum = csum((unsigned short *)send_raw_icmp_buf, sizeof(my_icmphdr) + payloadlen); } else { assert(raw_ip_version == AF_INET6); pseudo_header6 v6; struct pseudo_header6 *psh = &v6; psh->src = send_info.new_src_ip.v6; psh->dst = send_info.new_dst_ip.v6; psh->next_header = IPPROTO_ICMPV6; psh->tcp_length = htons(sizeof(my_icmphdr) + payloadlen); psh->placeholder1 = 0; psh->placeholder2 = 0; icmph->check_sum = csum_with_header((char *)psh, sizeof(pseudo_header6), (unsigned short *)send_raw_icmp_buf, sizeof(my_icmphdr) + payloadlen); } if (send_raw_ip(raw_info, send_raw_icmp_buf, sizeof(my_icmphdr) + payloadlen) != 0) { return -1; } /*if(program_mode==client_mode) { send_info.icmp_seq++; }*/ return 0; } int send_raw_udp(raw_info_t &raw_info, const char *payload, int payloadlen) { const packet_info_t &send_info = raw_info.send_info; const packet_info_t &recv_info = raw_info.recv_info; char send_raw_udp_buf[buf_len]; my_udphdr *udph = (struct my_udphdr *)(send_raw_udp_buf); memset(udph, 0, sizeof(my_udphdr)); udph->source = htons(send_info.src_port); udph->dest = htons(send_info.dst_port); int udp_tot_len = payloadlen + sizeof(my_udphdr); if (udp_tot_len > 65535) { mylog(log_debug, "invalid len\n"); return -1; } mylog(log_trace, "udp_len:%d %d\n", udp_tot_len, udph->len); udph->len = htons(uint16_t(udp_tot_len)); memcpy(send_raw_udp_buf + sizeof(my_udphdr), payload, payloadlen); if (raw_ip_version == AF_INET) { pseudo_header v4; struct pseudo_header *psh = &v4; psh->source_address = send_info.new_src_ip.v4; psh->dest_address = send_info.new_dst_ip.v4; psh->placeholder = 0; psh->protocol = IPPROTO_UDP; psh->tcp_length = htons(udp_tot_len); udph->check = csum_with_header((char *)psh, sizeof(pseudo_header), (unsigned short *)send_raw_udp_buf, udp_tot_len); } else { assert(raw_ip_version == AF_INET6); pseudo_header6 v6; struct pseudo_header6 *psh = &v6; psh->src = send_info.new_src_ip.v6; psh->dst = send_info.new_dst_ip.v6; psh->next_header = IPPROTO_UDP; psh->tcp_length = htons(udp_tot_len); psh->placeholder1 = 0; psh->placeholder2 = 0; udph->check = csum_with_header((char *)psh, sizeof(pseudo_header6), (unsigned short *)send_raw_udp_buf, udp_tot_len); } if (send_raw_ip(raw_info, send_raw_udp_buf, udp_tot_len) != 0) { return -1; } return 0; } int send_raw_tcp(raw_info_t &raw_info, const char *payload, int payloadlen) { // TODO seq increase const packet_info_t &send_info = raw_info.send_info; const packet_info_t &recv_info = raw_info.recv_info; // mylog(log_debug,"syn %d\n",send_info.syn); char send_raw_tcp_buf[buf_len]; // char *send_raw_tcp_buf=send_raw_tcp_buf0; struct my_tcphdr *tcph = (struct my_tcphdr *)(send_raw_tcp_buf); memset(tcph, 0, sizeof(my_tcphdr)); // TCP Header tcph->source = htons(send_info.src_port); tcph->dest = htons(send_info.dst_port); tcph->seq = htonl(send_info.seq); tcph->ack_seq = htonl(send_info.ack_seq); tcph->fin = 0; tcph->syn = send_info.syn; tcph->rst = 0; tcph->psh = send_info.psh; tcph->ack = send_info.ack; if (tcph->syn == 1) { tcph->doff = 10; // tcp header size int i = sizeof(my_tcphdr); send_raw_tcp_buf[i++] = 0x02; // mss send_raw_tcp_buf[i++] = 0x04; send_raw_tcp_buf[i++] = 0x05; send_raw_tcp_buf[i++] = (char)0xb4; // raw_send_buf[i++]=0x01; // raw_send_buf[i++]=0x01; send_raw_tcp_buf[i++] = 0x04; // sack ok send_raw_tcp_buf[i++] = 0x02; // sack ok send_raw_tcp_buf[i++] = 0x08; // ts i=6 send_raw_tcp_buf[i++] = 0x0a; // i=7 //*(u32_t*) (&send_raw_tcp_buf[i]) = htonl( // (u32_t) get_current_time()); u32_t ts = htonl((u32_t)get_current_time()); memcpy(&send_raw_tcp_buf[i], &ts, sizeof(ts)); i += 4; // mylog(log_info,"[syn]\n",send_info.ts_ack); //*(u32_t*) (&send_raw_tcp_buf[i]) = htonl(send_info.ts_ack); u32_t ts_ack = htonl(send_info.ts_ack); memcpy(&send_raw_tcp_buf[i], &ts_ack, sizeof(ts_ack)); i += 4; send_raw_tcp_buf[i++] = 0x01; send_raw_tcp_buf[i++] = 0x03; send_raw_tcp_buf[i++] = 0x03; send_raw_tcp_buf[i++] = wscale; } else { tcph->doff = 8; int i = sizeof(my_tcphdr); send_raw_tcp_buf[i++] = 0x01; send_raw_tcp_buf[i++] = 0x01; send_raw_tcp_buf[i++] = 0x08; // ts //i=2 send_raw_tcp_buf[i++] = 0x0a; // i=3; //*(u32_t*) (&send_raw_tcp_buf[i]) = htonl( // (u32_t) get_current_time()); u32_t ts = htonl((u32_t)get_current_time()); memcpy(&send_raw_tcp_buf[i], &ts, sizeof(ts)); i += 4; // mylog(log_info,"\n",send_info.ts_ack); //*(u32_t*) (&send_raw_tcp_buf[i]) = htonl(send_info.ts_ack); u32_t ts_ack = htonl(send_info.ts_ack); memcpy(&send_raw_tcp_buf[i], &ts_ack, sizeof(ts_ack)); i += 4; } tcph->urg = 0; // tcph->window = htons((uint16_t)(1024)); tcph->window = htons((uint16_t)(receive_window_lower_bound + get_true_random_number() % receive_window_random_range)); tcph->check = 0; // leave checksum 0 now, filled later by pseudo header tcph->urg_ptr = 0; char *tcp_data = send_raw_tcp_buf + +tcph->doff * 4; memcpy(tcp_data, payload, payloadlen); int tcp_totlen = tcph->doff * 4 + payloadlen; if (raw_ip_version == AF_INET) { pseudo_header v4; struct pseudo_header *psh = &v4; psh->source_address = send_info.new_src_ip.v4; psh->dest_address = send_info.new_dst_ip.v4; psh->placeholder = 0; psh->protocol = IPPROTO_TCP; psh->tcp_length = htons(tcp_totlen); tcph->check = csum_with_header((char *)psh, sizeof(pseudo_header), (unsigned short *)send_raw_tcp_buf, tcp_totlen); } else { assert(raw_ip_version == AF_INET6); pseudo_header6 v6; struct pseudo_header6 *psh = &v6; psh->src = send_info.new_src_ip.v6; psh->dst = send_info.new_dst_ip.v6; psh->next_header = IPPROTO_TCP; psh->tcp_length = htons(tcp_totlen); psh->placeholder1 = 0; psh->placeholder2 = 0; tcph->check = csum_with_header((char *)psh, sizeof(pseudo_header6), (unsigned short *)send_raw_tcp_buf, tcp_totlen); } if (send_raw_ip(raw_info, send_raw_tcp_buf, tcp_totlen) != 0) { return -1; } raw_info.send_info.data_len = payloadlen; return 0; } /* int send_raw_tcp_deprecated(const packet_info_t &info,const char * payload,int payloadlen) { static uint16_t ip_id=1; char raw_send_buf[buf_len]; char raw_send_buf2[buf_len]; //if((prog_mode==client_mode&& payloadlen!=9) ||(prog_mode==server_mode&& payloadlen!=5 ) ) mylog(log_trace,"send raw from to %d %d %d %d\n",info.src_ip,info.src_port,info.dst_ip,info.dst_port); char *data; memset(raw_send_buf,0,payloadlen+100); struct iphdr *iph = (struct iphdr *) raw_send_buf; //TCP header struct tcphdr *tcph = (struct tcphdr *) (raw_send_buf + sizeof (struct ip)); struct sockaddr_in sin; struct pseudo_header psh; //some address resolution sin.sin_family = AF_INET; sin.sin_port = htons(info.dst_port); sin.sin_addr.s_addr = info.dst_ip; //Fill in the IP Header iph->ihl = 5; iph->version = 4; iph->tos = 0; iph->id = htonl (ip_id++); //Id of this packet iph->frag_off = htons(0x4000); //DF set,others are zero iph->ttl = (unsigned char)ttl_value; iph->protocol = IPPROTO_TCP; iph->check = 0; //Set to 0 before calculating checksum iph->saddr = info.src_ip; //Spoof the source ip address iph->daddr = info.dst_ip; //TCP Header tcph->source = htons(info.src_port); tcph->dest = htons(info.dst_port); tcph->seq =htonl(info.seq); tcph->ack_seq = htonl(info.ack_seq); tcph->fin=0; tcph->syn=info.syn; tcph->rst=0; tcph->psh=info.psh; tcph->ack=info.ack; if(tcph->syn==1) { tcph->doff = 10; //tcp header size int i=sizeof (struct iphdr)+20; raw_send_buf[i++]=0x02;//mss raw_send_buf[i++]=0x04; raw_send_buf[i++]=0x05; raw_send_buf[i++]=0xb4; //raw_send_buf[i++]=0x01; //raw_send_buf[i++]=0x01; raw_send_buf[i++]=0x04; //sack ok raw_send_buf[i++]=0x02; //sack ok raw_send_buf[i++]=0x08; //i=6; raw_send_buf[i++]=0x0a; *(uint32_t*)(& raw_send_buf[i])=htonl((uint32_t)get_current_time()); i+=4; *(uint32_t*)(& raw_send_buf[i])=htonl(info.ts_ack); i+=4; raw_send_buf[i++]=0x01; raw_send_buf[i++]=0x03; raw_send_buf[i++]=0x03; raw_send_buf[i++]=0x05; } else { tcph->doff=8; int i=sizeof (struct iphdr)+20; raw_send_buf[i++]=0x01; raw_send_buf[i++]=0x01; raw_send_buf[i++]=0x08; //i=0; raw_send_buf[i++]=0x0a; *(uint32_t*)(& raw_send_buf[i])=htonl((uint32_t)get_current_time()); i+=4; *(uint32_t*)(& raw_send_buf[i])=htonl(info.ts_ack); i+=4; } tcph->urg=0; //tcph->window = htons((uint16_t)(1024)); tcph->window = htons((uint16_t)(10240+random()%100)); tcph->check = 0; //leave checksum 0 now, filled later by pseudo header tcph->urg_ptr = 0; //Data part data = raw_send_buf + sizeof(struct iphdr) + tcph->doff*4; iph->tot_len = sizeof (struct iphdr) + tcph->doff*4 + payloadlen; memcpy(data , payload, payloadlen); psh.source_address = info.src_ip; psh.dest_address = sin.sin_addr.s_addr; psh.placeholder = 0; psh.protocol = IPPROTO_TCP; psh.tcp_length = htons(tcph->doff*4 + payloadlen ); int psize = sizeof(struct pseudo_header) + tcph->doff*4 + payloadlen; memcpy(raw_send_buf2 , (char*) &psh , sizeof (struct pseudo_header)); memcpy(raw_send_buf2 + sizeof(struct pseudo_header) , tcph , tcph->doff*4 + payloadlen); tcph->check = csum( (unsigned short*) raw_send_buf2, psize); //Ip checksum iph->check = csum ((unsigned short *) raw_send_buf, iph->tot_len); mylog(log_trace,"sent seq ack_seq len<%u %u %d>\n",g_packet_info_send.seq,g_packet_info_send.ack_seq,payloadlen); int ret = sendto(raw_send_fd, raw_send_buf, iph->tot_len , 0, (struct sockaddr *) &sin, sizeof (sin)); if(g_packet_info_send.syn==0&&g_packet_info_send.ack==1&&payloadlen!=0) { if(seq_mode==0) { } else if(seq_mode==1) { g_packet_info_send.seq+=payloadlen; } else if(seq_mode==2) { if(random()% 5==3 ) g_packet_info_send.seq+=payloadlen; } } mylog(log_trace,"\n",ret); if(ret<0) { mylog(log_fatal,""); perror("raw send error\n"); //printf("send error\n"); } return 0; } */ int recv_raw_icmp(raw_info_t &raw_info, char *&payload, int &payloadlen) { const packet_info_t &send_info = raw_info.send_info; packet_info_t &recv_info = raw_info.recv_info; static char recv_raw_icmp_buf[buf_len]; char *ip_payload; int ip_payloadlen; if (recv_raw_ip(raw_info, ip_payload, ip_payloadlen) != 0) { mylog(log_debug, "recv_raw_ip error\n"); return -1; } mylog(log_trace, "ip_payloadlen=%d\n", ip_payloadlen); if (raw_ip_version == AF_INET) { if (recv_info.protocol != IPPROTO_ICMP) { // printf("not udp protocol\n"); return -1; } } else { assert(raw_ip_version == AF_INET6); if (recv_info.protocol != IPPROTO_ICMPV6) { // printf("not udp protocol\n"); return -1; } } if (ip_payloadlen < int(sizeof(my_icmphdr))) { mylog(log_debug, "too short to hold icmp header\n"); return -1; } my_icmphdr *icmph = (struct my_icmphdr *)(ip_payload); if (ntohs(icmph->id) != send_info.src_port) { mylog(log_debug, "icmp id mis-match,ignored\n"); return -1; } recv_info.src_port = recv_info.dst_port = ntohs(icmph->id); recv_info.my_icmp_seq = ntohs(icmph->seq); if (icmph->code != 0) return -1; unsigned short check; if (raw_ip_version == AF_INET) { if (program_mode == client_mode) { if (icmph->type != 0) return -1; } else { if (icmph->type != 8) return -1; } check = csum((unsigned short *)ip_payload, ip_payloadlen); } else { assert(raw_ip_version == AF_INET6); if (program_mode == client_mode) { if (icmph->type != 129) return -1; } else { if (icmph->type != 128) return -1; } pseudo_header6 tmp_header; struct pseudo_header6 *psh = &tmp_header; psh->src = recv_info.new_src_ip.v6; psh->dst = recv_info.new_dst_ip.v6; psh->placeholder1 = 0; psh->placeholder2 = 0; psh->next_header = IPPROTO_ICMPV6; psh->tcp_length = htons(ip_payloadlen); check = csum_with_header((char *)psh, sizeof(pseudo_header6), (unsigned short *)ip_payload, ip_payloadlen); } if (check != 0) { mylog(log_debug, "icmp checksum fail %x\n", check); return -1; } // mylog(log_info,"program_mode=%d\n",program_mode); /* if(program_mode==server_mode) { send_info.icmp_seq=ntohs(icmph->seq); //mylog(log_info,"send_info.seq=%d\n",send_info.seq); }*/ payload = ip_payload + sizeof(my_icmphdr); payloadlen = ip_payloadlen - sizeof(my_icmphdr); mylog(log_trace, "get a packet len=%d\n", payloadlen); return 0; } int recv_raw_udp(raw_info_t &raw_info, char *&payload, int &payloadlen) { const packet_info_t &send_info = raw_info.send_info; packet_info_t &recv_info = raw_info.recv_info; // static char recv_raw_udp_buf[buf_len]; char *ip_payload; int ip_payloadlen; if (recv_raw_ip(raw_info, ip_payload, ip_payloadlen) != 0) { mylog(log_debug, "recv_raw_ip error\n"); return -1; } if (recv_info.protocol != IPPROTO_UDP) { // printf("not udp protocol\n"); return -1; } if (ip_payloadlen < int(sizeof(my_udphdr))) { mylog(log_debug, "too short to hold udpheader\n"); return -1; } my_udphdr *udph = (struct my_udphdr *)ip_payload; if (int(ntohs(udph->len)) != ip_payloadlen) { mylog(log_debug, "udp length error %d %d \n", ntohs(udph->len), ip_payloadlen); return -1; } if (udph->dest != ntohs(uint16_t(filter_port))) { // printf("%x %x",tcph->dest,); return -1; } // memcpy(recv_raw_udp_buf+ sizeof(struct pseudo_header) , ip_payload , ip_payloadlen); /* pseudo_header tmp_header={0}; struct pseudo_header *psh=&tmp_header ; psh->source_address = recv_info.new_src_ip.v4; psh->dest_address = recv_info.new_dst_ip.v4; psh->placeholder = 0; psh->protocol = IPPROTO_UDP; psh->tcp_length = htons(ip_payloadlen); int csum_len=ip_payloadlen; uint16_t udp_chk = csum_with_header((char *)psh,sizeof(pseudo_header), (unsigned short*) ip_payload, csum_len); */ uint16_t udp_chk; int csum_len = ip_payloadlen; if (raw_ip_version == AF_INET) { pseudo_header tmp_header; struct pseudo_header *psh = &tmp_header; psh->source_address = recv_info.new_src_ip.v4; psh->dest_address = recv_info.new_dst_ip.v4; psh->placeholder = 0; psh->protocol = IPPROTO_UDP; psh->tcp_length = htons(ip_payloadlen); udp_chk = csum_with_header((char *)psh, sizeof(pseudo_header), (unsigned short *)ip_payload, csum_len); } else { assert(raw_ip_version == AF_INET6); pseudo_header6 tmp_header; struct pseudo_header6 *psh = &tmp_header; psh->src = recv_info.new_src_ip.v6; psh->dst = recv_info.new_dst_ip.v6; psh->placeholder1 = 0; psh->placeholder2 = 0; psh->next_header = IPPROTO_UDP; psh->tcp_length = htons(ip_payloadlen); udp_chk = csum_with_header((char *)psh, sizeof(pseudo_header6), (unsigned short *)ip_payload, csum_len); } if (udp_chk != 0) { mylog(log_debug, "udp_chk:%x\n", udp_chk); mylog(log_debug, "udp header error\n"); return -1; } char *udp_begin = ip_payload; recv_info.src_port = ntohs(udph->source); recv_info.dst_port = ntohs(udph->dest); payloadlen = ip_payloadlen - sizeof(my_udphdr); payload = udp_begin + sizeof(my_udphdr); return 0; } int parse_tcp_option(char *option_begin, char *option_end, packet_info_t &recv_info) { recv_info.has_ts = 0; recv_info.ts = 0; char *ptr = option_begin; // char *option_end=tcp_begin+tcp_hdr_len; while (ptr < option_end) { if (*ptr == 0) { return 0; } else if (*ptr == 1) { ptr++; } else if (*ptr == 8) { if (ptr + 1 >= option_end) { mylog(log_trace, "invaild option ptr+1==option_end,for ts\n"); return -1; } if (*(ptr + 1) != 10) { mylog(log_trace, "invaild ts len\n"); return -1; } if (ptr + 10 > option_end) { mylog(log_trace, "ptr+10>option_end for ts\n"); return -1; } recv_info.has_ts = 1; recv_info.ts = read_u32(ptr + 2); recv_info.ts_ack = read_u32(ptr + 6); // printf("<%d %d>!\n",recv_info.ts,recv_info.ts_ack); // return 0;//we currently only parse ts, so just return after its found ptr += 10; } else { if (ptr + 1 >= option_end) { mylog(log_trace, "invaild option ptr+1==option_end\n"); return -1; } else { int len = (unsigned char)*(ptr + 1); if (len <= 1) { mylog(log_trace, "invaild option len %d\n", len); return -1; } // omit check ptr += len; } } // printf("!"); } // printf("\n"); return 0; } int recv_raw_tcp(raw_info_t &raw_info, char *&payload, int &payloadlen) { const packet_info_t &send_info = raw_info.send_info; packet_info_t &recv_info = raw_info.recv_info; // static char recv_raw_tcp_buf[buf_len]; char *ip_payload; int ip_payloadlen; if (recv_raw_ip(raw_info, ip_payload, ip_payloadlen) != 0) { mylog(log_debug, "recv_raw_ip error\n"); return -1; } if (recv_info.protocol != IPPROTO_TCP) { // printf("not tcp protocol\n"); return -1; } my_tcphdr *tcph = (struct my_tcphdr *)ip_payload; unsigned short tcphdrlen = tcph->doff * 4; if (!(tcphdrlen > 0 && tcphdrlen <= 60)) { mylog(log_debug, "tcph error\n"); return 0; } if (tcphdrlen > ip_payloadlen) { mylog(log_debug, "error,tcphdrlen >ip_payloadlen\n"); return 0; } if (tcph->dest != ntohs(uint16_t(filter_port))) { // printf("%x %x",tcph->dest,); return -1; } // memcpy(recv_raw_tcp_buf+ sizeof(struct pseudo_header) , ip_payload , ip_payloadlen); uint16_t tcp_chk; int csum_len = ip_payloadlen; if (raw_ip_version == AF_INET) { pseudo_header tmp_header; struct pseudo_header *psh = &tmp_header; psh->source_address = recv_info.new_src_ip.v4; psh->dest_address = recv_info.new_dst_ip.v4; psh->placeholder = 0; psh->protocol = IPPROTO_TCP; psh->tcp_length = htons(ip_payloadlen); tcp_chk = csum_with_header((char *)psh, sizeof(pseudo_header), (unsigned short *)ip_payload, csum_len); } else { assert(raw_ip_version == AF_INET6); pseudo_header6 tmp_header; struct pseudo_header6 *psh = &tmp_header; psh->src = recv_info.new_src_ip.v6; psh->dst = recv_info.new_dst_ip.v6; psh->placeholder1 = 0; psh->placeholder2 = 0; psh->next_header = IPPROTO_TCP; psh->tcp_length = htons(ip_payloadlen); tcp_chk = csum_with_header((char *)psh, sizeof(pseudo_header6), (unsigned short *)ip_payload, csum_len); } /*for(int i=0;i",int(ip_payload[i])); } printf("\n");*/ if (tcp_chk != 0) { mylog(log_debug, "tcp_chk:%x, tcp checksum failed, ignored\n", tcp_chk); // return -1; } char *tcp_begin = ip_payload; // ip packet's data part char *tcp_option = ip_payload + sizeof(my_tcphdr); char *option_end = ip_payload + tcphdrlen; /* //old ts parse code recv_info.has_ts=0; recv_info.ts=0; if(tcph->doff==10) { if(tcp_option[6]==0x08 &&tcp_option[7]==0x0a) { recv_info.has_ts=1; //recv_info.ts=ntohl(*(u32_t*)(&tcp_option[8])); memcpy(&recv_info.ts,&tcp_option[8],sizeof(recv_info.ts)); recv_info.ts=ntohl(recv_info.ts); //recv_info.ts_ack=ntohl(*(u32_t*)(&tcp_option[12])); memcpy(&recv_info.ts_ack,&tcp_option[12],sizeof(recv_info.ts_ack)); recv_info.ts_ack=ntohl(recv_info.ts_ack); //g_packet_info_send.ts_ack= ntohl(*(uint32_t*)(&tcp_option[8])); } else { // mylog(log_info,"\n"); } } else if(tcph->doff==8) { if(tcp_option[2]==0x08 &&tcp_option[3]==0x0a) { recv_info.has_ts=1; //recv_info.ts=ntohl(*(u32_t*)(&tcp_option[4])); memcpy(&recv_info.ts,&tcp_option[4],sizeof(recv_info.ts)); recv_info.ts=ntohl(recv_info.ts); //recv_info.ts_ack=ntohl(*(u32_t*)(&tcp_option[8])); memcpy(&recv_info.ts_ack,&tcp_option[8],sizeof(recv_info.ts_ack)); recv_info.ts_ack=ntohl(recv_info.ts_ack); //g_packet_info_send.ts_ack= ntohl(*(uint32_t*)(&tcp_option[0])); } else { //mylog(log_info,"!!!\n"); } } else { //mylog(log_info,"tcph->doff= %u\n",tcph->doff); } printf("<%d %d>\n",recv_info.ts,recv_info.ts_ack); */ parse_tcp_option(tcp_option, option_end, recv_info); recv_info.ack = tcph->ack; recv_info.syn = tcph->syn; recv_info.rst = tcph->rst; recv_info.src_port = ntohs(tcph->source); recv_info.dst_port = ntohs(tcph->dest); recv_info.seq = ntohl(tcph->seq); // recv_info.last_last_ack_seq=recv_info.last_ack_seq; // recv_info.last_ack_seq=recv_info.ack_seq; u32_t last_ack_seq = recv_info.ack_seq; recv_info.ack_seq = ntohl(tcph->ack_seq); if (recv_info.ack_seq == last_ack_seq) { recv_info.ack_seq_counter++; } else { recv_info.ack_seq_counter = 0; } recv_info.psh = tcph->psh; if (tcph->rst == 1) { raw_info.rst_received++; if (max_rst_to_show > 0) { if (raw_info.rst_received < max_rst_to_show) { mylog(log_warn, "[%s,%d]rst==1,cnt=%d\n", recv_info.new_src_ip.get_str1(), recv_info.src_port, (int)raw_info.rst_received); } else if (raw_info.rst_received == max_rst_to_show) { mylog(log_warn, "[%s,%d]rst==1,cnt=%d >=max_rst_to_show, this log will be muted for current connection\n", recv_info.new_src_ip.get_str1(), recv_info.src_port, (int)raw_info.rst_received); } else { mylog(log_debug, "[%s,%d]rst==1,cnt=%d\n", recv_info.new_src_ip.get_str1(), recv_info.src_port, (int)raw_info.rst_received); } } else if (max_rst_to_show == 0) { mylog(log_debug, "[%s,%d]rst==1,cnt=%d\n", recv_info.new_src_ip.get_str1(), recv_info.src_port, (int)raw_info.rst_received); } else { mylog(log_warn, "[%s,%d]rst==1,cnt=%d\n", recv_info.new_src_ip.get_str1(), recv_info.src_port, (int)raw_info.rst_received); } if (max_rst_allowed >= 0 && raw_info.rst_received == max_rst_allowed + 1) { mylog(log_warn, "[%s,%d]connection disabled because of rst_received=%d > max_rst_allow=%d\n", recv_info.new_src_ip.get_str1(), recv_info.src_port, (int)raw_info.rst_received, (int)max_rst_allowed); raw_info.disabled = 1; } } /* if(recv_info.has_ts) { send_info.ts_ack=recv_info.ts; //////////////////////////////////////////////modify }*/ payloadlen = ip_payloadlen - tcphdrlen; payload = tcp_begin + tcphdrlen; /*if (recv_info.syn == 0 && recv_info.ack == 1&& payloadlen != 0) //only modify send_info when the packet is not part of handshake { send_info.ack_seq=recv_info.seq; }*/ raw_info.recv_info.data_len = payloadlen; return 0; } /* int recv_raw_tcp_deprecated(packet_info_t &info,char * &payload,int &payloadlen) { static char buf[buf_len]; char raw_recv_buf[buf_len]; char raw_recv_buf2[buf_len]; char raw_recv_buf3[buf_len]; iphdr * iph; tcphdr * tcph; int size; struct sockaddr saddr; socklen_t saddr_size; saddr_size = sizeof(saddr); mylog(log_trace,"raw!\n"); size = recvfrom(raw_recv_fd, buf, max_data_len, 0 ,&saddr , &saddr_size); if(buf[12]!=8||buf[13]!=0) { mylog(log_debug,"not an ipv4 packet!\n"); return -1; } char *ip_begin=buf+14; iph = (struct iphdr *) (ip_begin); if (!(iph->ihl > 0 && iph->ihl <=60)) { mylog(log_debug,"iph ihl error"); return -1; } if (iph->protocol != IPPROTO_TCP) { mylog(log_debug,"iph protocal != tcp\n"); return -1; } int ip_len=ntohs(iph->tot_len); unsigned short iphdrlen =iph->ihl*4; tcph=(struct tcphdr*)(ip_begin+ iphdrlen); unsigned short tcphdrlen = tcph->doff*4; if (!(tcph->doff > 0 && tcph->doff <=60)) { mylog(log_debug,"tcph error"); return 0; } if(tcph->dest!=ntohs(uint16_t(filter_port))) { //printf("%x %x",tcph->dest,); return -1; } /////ip uint32_t ip_chk=csum ((unsigned short *) ip_begin, iphdrlen); int psize = sizeof(struct pseudo_header) + ip_len-iphdrlen; /////ip end ///tcp struct pseudo_header psh; psh.source_address = iph->saddr; psh.dest_address = iph->daddr; psh.placeholder = 0; psh.protocol = IPPROTO_TCP; psh.tcp_length = htons(ip_len-iphdrlen); memcpy(raw_recv_buf2 , (char*) &psh , sizeof (struct pseudo_header)); memcpy(raw_recv_buf2 + sizeof(struct pseudo_header) , ip_begin+ iphdrlen , ip_len-iphdrlen); uint16_t tcp_chk = csum( (unsigned short*) raw_recv_buf2, psize); if(ip_chk!=0) { mylog(log_debug,"ip header error %d\n",ip_chk); return -1; } if(tcp_chk!=0) { mylog(log_debug,"tcp_chk:%x\n",tcp_chk); mylog(log_debug,"tcp header error\n"); return -1; } char *tcp_begin=raw_recv_buf2+sizeof(struct pseudo_header); //ip packet's data part char *tcp_option=raw_recv_buf2+sizeof(struct pseudo_header)+sizeof(tcphdr); info.has_ts=0; if(tcph->doff==10) { if(tcp_option[6]==0x08 &&tcp_option[7]==0x0a) { info.has_ts=1; info.ts=ntohl(*(uint32_t*)(&tcp_option[8])); info.ts_ack=ntohl(*(uint32_t*)(&tcp_option[12])); //g_packet_info_send.ts_ack= ntohl(*(uint32_t*)(&tcp_option[8])); } } else if(tcph->doff==8) { if(tcp_option[3]==0x08 &&tcp_option[4]==0x0a) { info.has_ts=1; info.ts=ntohl(*(uint32_t*)(&tcp_option[0])); info.ts_ack=ntohl(*(uint32_t*)(&tcp_option[4])); //g_packet_info_send.ts_ack= ntohl(*(uint32_t*)(&tcp_option[0])); } } if(tcph->rst==1) { mylog(log_warn,"%%%%%%%%%%rst==1%%%%%%%%%%%%%\n"); } info.ack=tcph->ack; info.syn=tcph->syn; info.rst=tcph->rst; info.src_port=ntohs(tcph->source); info.src_ip=iph->saddr; info.seq=ntohl(tcph->seq); info.ack_seq=ntohl(tcph->ack_seq); info.psh=tcph->psh; if(info.has_ts) { g_packet_info_send.ts_ack=info.ts; } ////tcp end payloadlen = ip_len-tcphdrlen-iphdrlen; payload=ip_begin+tcphdrlen+iphdrlen; if(payloadlen>0&&payload[0]=='h') { mylog(log_debug,"recvd <%u %u %d>\n",ntohl(tcph->seq ),ntohl(tcph->ack_seq), payloadlen); } if(payloadlen>0&&tcph->syn==0&&tcph->ack==1) { //if(seq_increse) g_packet_info_send.ack_seq=ntohl(tcph->seq)+(uint32_t)payloadlen; } //printf("%d\n",ip_len); mylog(log_trace,"<%u,%u,%u,%u,%d>\n",(unsigned int)iphdrlen,(unsigned int)tcphdrlen,(unsigned int)tcph->syn,(unsigned int)tcph->ack,payloadlen); return 0; }*/ int send_raw0(raw_info_t &raw_info, const char *payload, int payloadlen) { if (random_drop != 0) { if (get_true_random_number() % 10000 < (u32_t)random_drop) { return 0; } } packet_info_t &send_info = raw_info.send_info; packet_info_t &recv_info = raw_info.recv_info; mylog(log_trace, "send_raw : from %s %d to %s %d\n", send_info.new_src_ip.get_str1(), send_info.src_port, send_info.new_dst_ip.get_str2(), send_info.dst_port); switch (raw_mode) { case mode_faketcp: return send_raw_tcp(raw_info, payload, payloadlen); case mode_udp: return send_raw_udp(raw_info, payload, payloadlen); case mode_icmp: return send_raw_icmp(raw_info, payload, payloadlen); default: return -1; } } int recv_raw0(raw_info_t &raw_info, char *&payload, int &payloadlen) { packet_info_t &send_info = raw_info.send_info; packet_info_t &recv_info = raw_info.recv_info; switch (raw_mode) { case mode_faketcp: return recv_raw_tcp(raw_info, payload, payloadlen); case mode_udp: return recv_raw_udp(raw_info, payload, payloadlen); case mode_icmp: return recv_raw_icmp(raw_info, payload, payloadlen); default: return -1; } } int after_send_raw0(raw_info_t &raw_info) { packet_info_t &send_info = raw_info.send_info; packet_info_t &recv_info = raw_info.recv_info; if (raw_mode == mode_faketcp) { if (send_info.syn == 0 && send_info.ack == 1 && raw_info.send_info.data_len != 0) // only modify send_info when the packet is not part of handshake { if (seq_mode == 0) { } else if (seq_mode == 1) { send_info.seq += raw_info.send_info.data_len; //////////////////modify } else if (seq_mode == 2) { if (get_true_random_number() % 5 == 3) send_info.seq += raw_info.send_info.data_len; //////////////////modify } else if (seq_mode == 3 || seq_mode == 4) { send_info.seq += raw_info.send_info.data_len; u32_t window_size; if (seq_mode == 3) { window_size = (u32_t)((u32_t)receive_window_lower_bound << (u32_t)wscale); } else // seq_mode==4 { window_size = (u32_t)((u32_t)receive_window_lower_bound); } if (larger_than_u32(send_info.seq + max_data_len, recv_info.ack_seq + window_size)) { send_info.seq = raw_info.recv_info.ack_seq; } if (recv_info.ack_seq_counter >= 3) // simulate tcp fast re-transmit { recv_info.ack_seq_counter = 0; send_info.seq = raw_info.recv_info.ack_seq; } if (larger_than_u32(raw_info.recv_info.ack_seq, send_info.seq)) // for further use,currently no effect. { send_info.seq = raw_info.recv_info.ack_seq; } } } } if (raw_mode == mode_icmp) { if (program_mode == client_mode) { send_info.my_icmp_seq++; } } return 0; } int after_recv_raw0(raw_info_t &raw_info) { packet_info_t &send_info = raw_info.send_info; packet_info_t &recv_info = raw_info.recv_info; if (raw_mode == mode_faketcp) { if (recv_info.has_ts) send_info.ts_ack = recv_info.ts; if (recv_info.syn == 0 && recv_info.ack == 1 && raw_info.recv_info.data_len != 0) // only modify send_info when the packet is not part of handshake { if (seq_mode == 0 || seq_mode == 1 || seq_mode == 2) { if (larger_than_u32(recv_info.seq + raw_info.recv_info.data_len, send_info.ack_seq)) send_info.ack_seq = recv_info.seq + raw_info.recv_info.data_len; // TODO only update if its larger } else if (seq_mode == 3 || seq_mode == 4) { if (recv_info.seq == send_info.ack_seq) { send_info.ack_seq = recv_info.seq + raw_info.recv_info.data_len; // currently we dont remembr tcp segments,this is the simplest way // TODO implement tcp segment remembering and SACK. } } } } if (raw_mode == mode_icmp) { if (program_mode == server_mode) { if (larger_than_u16(recv_info.my_icmp_seq, send_info.my_icmp_seq)) send_info.my_icmp_seq = recv_info.my_icmp_seq; // TODO only update if its larger } } return 0; } /* int send_raw(raw_info_t &raw_info,const char * payload,int payloadlen) { packet_info_t &send_info=raw_info.send_info; packet_info_t &recv_info=raw_info.recv_info; int ret=send_raw0(raw_info,payload,payloadlen); if(ret<0) return ret; else { after_send_raw0(raw_info); return ret; } } int recv_raw(raw_info_t &raw_info,char *& payload,int & payloadlen) { packet_info_t &send_info=raw_info.send_info; packet_info_t &recv_info=raw_info.recv_info; int ret=recv_raw0(raw_info,payload,payloadlen); if(ret<0) return ret; else { after_recv_raw0(raw_info); return ret; } }*/ /* int get_src_adress(u32_t &ip,u32_t remote_ip_uint32,int remote_port) //a trick to get src adress for a dest adress,so that we can use the src address in raw socket as source ip { struct sockaddr_in remote_addr_in={0}; socklen_t slen = sizeof(sockaddr_in); //memset(&remote_addr_in, 0, sizeof(remote_addr_in)); remote_addr_in.sin_family = AF_INET; remote_addr_in.sin_port = htons(remote_port); remote_addr_in.sin_addr.s_addr = remote_ip_uint32; int new_udp_fd=socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP); if(new_udp_fd<0) { mylog(log_warn,"create udp_fd error\n"); return -1; } //set_buf_size(new_udp_fd); mylog(log_debug,"created new udp_fd %d\n",new_udp_fd); int ret = connect(new_udp_fd, (struct sockaddr *) &remote_addr_in, slen); if(ret!=0) { mylog(log_warn,"udp fd connect fail\n"); close(new_udp_fd); return -1; } struct sockaddr_in my_addr={0}; socklen_t len=sizeof(my_addr); if(getsockname(new_udp_fd, (struct sockaddr *) &my_addr, &len)!=0){close(new_udp_fd); return -1;} ip=my_addr.sin_addr.s_addr; close(new_udp_fd); return 0; }*/ int get_src_adress2(address_t &output_addr, address_t remote_addr) { int new_udp_fd = remote_addr.new_connected_udp_fd(); if (new_udp_fd < 0) { mylog(log_warn, "create udp_fd error\n"); return -1; } socklen_t len = sizeof(output_addr.inner); if (getsockname(new_udp_fd, (struct sockaddr *)&output_addr.inner, &len) != 0) { close(new_udp_fd); return -1; } assert(output_addr.get_type() == remote_addr.get_type()); close(new_udp_fd); return 0; } /* int try_to_list_and_bind(int &fd,u32_t local_ip_uint32,int port) //try to bind to a port,may fail. { int old_bind_fd=fd; if(raw_mode==mode_faketcp) { fd=socket(AF_INET,SOCK_STREAM,0); } else if(raw_mode==mode_udp||raw_mode==mode_icmp) { fd=socket(AF_INET,SOCK_DGRAM,0); } if(old_bind_fd!=-1) { close(old_bind_fd); } struct sockaddr_in temp_bind_addr={0}; //bzero(&temp_bind_addr, sizeof(temp_bind_addr)); temp_bind_addr.sin_family = AF_INET; temp_bind_addr.sin_port = htons(port); temp_bind_addr.sin_addr.s_addr = local_ip_uint32; if (bind(fd, (struct sockaddr*)&temp_bind_addr, sizeof(temp_bind_addr)) !=0) { mylog(log_debug,"bind fail\n"); return -1; } if(raw_mode==mode_faketcp) { if (listen(fd, SOMAXCONN) != 0) { mylog(log_warn,"listen fail\n"); return -1; } } return 0; }*/ int try_to_list_and_bind2(int &fd, address_t address) // try to bind to a port,may fail. { if (fd != -1) { close(fd); } if (raw_mode == mode_faketcp) { fd = socket(address.get_type(), SOCK_STREAM, 0); } else if (raw_mode == mode_udp || raw_mode == mode_icmp) { fd = socket(address.get_type(), SOCK_DGRAM, 0); } if (fd == -1) { mylog(log_debug, "create fd fail\n"); return -1; } /*struct sockaddr_in temp_bind_addr={0}; //bzero(&temp_bind_addr, sizeof(temp_bind_addr)); temp_bind_addr.sin_family = AF_INET; temp_bind_addr.sin_port = htons(port); temp_bind_addr.sin_addr.s_addr = local_ip_uint32;*/ if (::bind(fd, (struct sockaddr *)&address.inner, address.get_len()) != 0) { mylog(log_debug, "bind fail\n"); return -1; } if (raw_mode == mode_faketcp && !use_tcp_dummy_socket) { if (listen(fd, SOMAXCONN) != 0) { mylog(log_warn, "listen fail\n"); return -1; } } return 0; } /* int client_bind_to_a_new_port(int &fd,u32_t local_ip_uint32)//find a free port and bind to it. { int raw_send_port=10000+get_true_random_number()%(65535-10000); for(int i=0;i<1000;i++)//try 1000 times at max,this should be enough { if (try_to_list_and_bind(fd,local_ip_uint32,raw_send_port)==0) { return raw_send_port; } } mylog(log_fatal,"bind port fail\n"); myexit(-1); return -1;////for compiler check }*/ int client_bind_to_a_new_port2(int &fd, const address_t &address) // find a free port and bind to it. { address_t tmp = address; for (int i = 0; i < 1000; i++) // try 1000 times at max,this should be enough { int raw_send_port = 10000 + get_true_random_number() % (65535 - 10000); tmp.set_port(raw_send_port); if (try_to_list_and_bind2(fd, tmp) == 0) { return raw_send_port; } } mylog(log_fatal, "bind port fail\n"); myexit(-1); return -1; ////for compiler check }