/* * tun.cpp * * Created on: Oct 26, 2017 * Author: root */ #include "tun_dev.h" my_time_t last_keep_alive_time = 0; int get_tun_fd(char *dev_name) { int tun_fd = open("/dev/net/tun", O_RDWR); if (tun_fd < 0) { mylog(log_fatal, "open /dev/net/tun failed"); myexit(-1); } struct ifreq ifr; memset(&ifr, 0, sizeof(ifr)); ifr.ifr_flags = IFF_TUN | IFF_NO_PI; strncpy(ifr.ifr_name, dev_name, IFNAMSIZ); if (ioctl(tun_fd, TUNSETIFF, (void *)&ifr) != 0) { mylog(log_fatal, "open /dev/net/tun failed"); myexit(-1); } if (persist_tun == 1) { if (ioctl(tun_fd, TUNSETPERSIST, 1) != 0) { mylog(log_warn, "failed to set tun persistent"); } } return tun_fd; } int set_tun(char *if_name, u32_t local_ip, u32_t remote_ip, int mtu) { if (manual_set_tun) return 0; // printf("i m here1\n"); struct ifreq ifr; struct sockaddr_in sai; memset(&ifr, 0, sizeof(ifr)); memset(&sai, 0, sizeof(struct sockaddr)); int sockfd = socket(AF_INET, SOCK_DGRAM, 0); strncpy(ifr.ifr_name, if_name, IFNAMSIZ); sai.sin_family = AF_INET; sai.sin_port = 0; sai.sin_addr.s_addr = local_ip; memcpy(&ifr.ifr_addr, &sai, sizeof(struct sockaddr)); assert(ioctl(sockfd, SIOCSIFADDR, &ifr) == 0); // set source ip sai.sin_addr.s_addr = remote_ip; memcpy(&ifr.ifr_addr, &sai, sizeof(struct sockaddr)); assert(ioctl(sockfd, SIOCSIFDSTADDR, &ifr) == 0); // set dest ip ifr.ifr_mtu = mtu; assert(ioctl(sockfd, SIOCSIFMTU, &ifr) == 0); // set mtu assert(ioctl(sockfd, SIOCGIFFLAGS, &ifr) == 0); // ifr.ifr_flags |= ( IFF_UP|IFF_POINTOPOINT|IFF_RUNNING|IFF_NOARP|IFF_MULTICAST ); ifr.ifr_flags = (IFF_UP | IFF_POINTOPOINT | IFF_RUNNING | IFF_NOARP | IFF_MULTICAST); // set interface flags assert(ioctl(sockfd, SIOCSIFFLAGS, &ifr) == 0); // printf("i m here2\n"); return 0; } int put_header(char header, char *data, int &len) { assert(len >= 0); data[len] = header; len += 1; return 0; } int get_header(char &header, char *data, int &len) { assert(len >= 0); if (len < 1) return -1; len -= 1; header = data[len]; return 0; } int from_normal_to_fec2(conn_info_t &conn_info, dest_t &dest, char *data, int len, char header) { int out_n; char **out_arr; int *out_len; my_time_t *out_delay; from_normal_to_fec(conn_info, data, len, out_n, out_arr, out_len, out_delay); for (int i = 0; i < out_n; i++) { char tmp_buf[buf_len]; int tmp_len = out_len[i]; memcpy(tmp_buf, out_arr[i], out_len[i]); put_header(header, tmp_buf, tmp_len); delay_send(out_delay[i], dest, tmp_buf, tmp_len); // this is slow but safer.just use this one // put_header(header,out_arr[i],out_len[i]);//modify in place // delay_send(out_delay[i],dest,out_arr[i],out_len[i]);//warning this is currently okay,but if you modified fec encoder,you may have to use the above code } return 0; } int from_fec_to_normal2(conn_info_t &conn_info, dest_t &dest, char *data, int len) { int out_n; char **out_arr; int *out_len; my_time_t *out_delay; from_fec_to_normal(conn_info, data, len, out_n, out_arr, out_len, out_delay); for (int i = 0; i < out_n; i++) { #if 0 if (program_mode == server_mode) { char *tmp_data = out_arr[i]; int tmp_len = out_len[i]; iphdr *iph; iph = (struct iphdr *)tmp_data; if (tmp_len >= int(sizeof(iphdr)) && iph->version == 4) { u32_t dest_ip = iph->daddr; // printf("%s\n",my_ntoa(dest_ip)); if ((ntohl(sub_net_uint32) & 0xFFFFFF00) != (ntohl(dest_ip) & 0xFFFFFF00)) { string sub = my_ntoa(dest_ip); string dst = my_ntoa(htonl(ntohl(sub_net_uint32) & 0xFFFFFF00)); mylog(log_warn, "[restriction]packet's dest ip [%s] not in subnet [%s],dropped, maybe you need to compile an un-restricted server\n", sub.c_str(), dst.c_str()); continue; } } } #endif delay_send(out_delay[i], dest, out_arr[i], out_len[i]); } return 0; } int do_mssfix(char *s, int len) // currently only for ipv4 { if (mssfix == 0) { return 0; } if (len < int(sizeof(iphdr))) { mylog(log_debug, "packet from tun len=%d <20\n", len); return -1; } iphdr *iph; iph = (struct iphdr *)s; if (iph->version != 4) { // mylog(log_trace,"not ipv4"); return 0; } if (iph->protocol != IPPROTO_TCP) { // mylog(log_trace,"not tcp"); return 0; } int ip_len = ntohs(iph->tot_len); int ip_hdr_len = iph->ihl * 4; if (len < ip_hdr_len) { mylog(log_debug, "len ip_len) { mylog(log_debug, "ip_hdr_lenfrag_off) & (short)(0x1FFF)) != 0) { // not first segment // printf("line=%d %x %x \n",__LINE__,(u32_t)ntohs(iph->frag_off),u32_t( ntohs(iph->frag_off) &0xFFF8)); return 0; } if ((ntohs(iph->frag_off) & (short)(0x80FF)) != 0) { // not whole segment // printf("line=%d \n",__LINE__); return 0; } char *tcp_begin = s + ip_hdr_len; int tcp_len = ip_len - ip_hdr_len; if (tcp_len < 20) { mylog(log_debug, "tcp_len<20,%d\n", tcp_len); return -1; } tcphdr *tcph = (struct tcphdr *)tcp_begin; if (int(tcph->syn) == 0) // fast fail { mylog(log_trace, "tcph->syn==0\n"); return 0; } int tcp_hdr_len = tcph->doff * 4; if (tcp_len < tcp_hdr_len) { mylog(log_debug, "tcp_len = option_end) { mylog(log_debug, "invaild option ptr+1==option_end,for mss\n"); return -1; } if (*(ptr + 1) != 4) { mylog(log_debug, "invaild mss len\n"); return -1; } if (ptr + 3 >= option_end) { mylog(log_debug, "ptr+4>option_end for mss\n"); return -1; } int mss = read_u16(ptr + 2); // uint8_t(ptr[2])*256+uint8_t(ptr[3]); int new_mss = mss; if (new_mss > ::mssfix - 40 - 10) // minus extra 10 for safe { new_mss = ::mssfix - 40 - 10; } write_u16(ptr + 2, (unsigned short)new_mss); pseudo_header psh; psh.source_address = iph->saddr; psh.dest_address = iph->daddr; psh.placeholder = 0; psh.protocol = iph->protocol; psh.tcp_length = htons(tcp_len); tcph->check = 0; tcph->check = tcp_csum(psh, (unsigned short *)tcph, tcp_len); mylog(log_trace, "mss=%d syn=%d ack=%d, changed mss to %d \n", mss, (int)tcph->syn, (int)tcph->ack, new_mss); // printf("test=%x\n",u32_t(1)); // printf("frag=%x\n",u32_t( ntohs(iph->frag_off) )); return 0; } else { if (ptr + 1 >= option_end) { mylog(log_debug, "invaild option ptr+1==option_end\n"); return -1; } else { int len = (unsigned char)*(ptr + 1); if (len <= 1) { mylog(log_debug, "invaild option len %d\n", len); return -1; } ptr += len; } } } return 0; } int do_keep_alive(dest_t &dest) { if (get_current_time() - last_keep_alive_time > u64_t(keep_alive_interval)) { last_keep_alive_time = get_current_time(); char data[buf_len]; int len; data[0] = header_keep_alive; len = 1; assert(dest.cook == 1); // do_cook(data,len); delay_send(0, dest, data, len); } return 0; }