diff --git a/common.h b/common.h index 314caa8..2c01dde 100644 --- a/common.h +++ b/common.h @@ -47,8 +47,11 @@ #include #include -#include -#include +#include +#include +#include +#include +#include using namespace std; diff --git a/connection.cpp b/connection.cpp index 8ef58a8..7c3990b 100644 --- a/connection.cpp +++ b/connection.cpp @@ -15,6 +15,7 @@ const int disable_conv_clear=0;//a udp connection in the multiplexer is called c const int disable_conn_clear=0;//a raw connection is called conn. +conn_manager_t conn_manager; anti_replay_seq_t anti_replay_t::get_new_seq_for_send() { @@ -713,3 +714,33 @@ int recv_safer(conn_info_t &conn_info,char &type,char* &data,int &len)///safer t return parse_safer(conn_info,recv_data,recv_len,type,data,len); } + +void server_clear_function(u64_t u64)//used in conv_manager in server mode.for server we have to use one udp fd for one conv(udp connection), +//so we have to close the fd when conv expires +{ + int fd=int(u64); + int ret; + assert(fd!=0); + /* + epoll_event ev; + + ev.events = EPOLLIN; + ev.data.u64 = u64; + + ret = epoll_ctl(epollfd, EPOLL_CTL_DEL, fd, &ev); + if (ret!=0) + { + mylog(log_fatal,"fd:%d epoll delete failed!!!!\n",fd); + myexit(-1); //this shouldnt happen + }*/ //no need + ret= close(fd); //closed fd should be auto removed from epoll + + if (ret!=0) + { + mylog(log_fatal,"close fd %d failed !!!!\n",fd); + myexit(-1); //this shouldnt happen + } + //mylog(log_fatal,"size:%d !!!!\n",conn_manager.udp_fd_mp.size()); + assert(conn_manager.udp_fd_mp.find(fd)!=conn_manager.udp_fd_mp.end()); + conn_manager.udp_fd_mp.erase(fd); +} diff --git a/connection.h b/connection.h index 308ce18..3ffb28e 100644 --- a/connection.h +++ b/connection.h @@ -14,6 +14,9 @@ extern int disable_anti_replay; #include "common.h" #include "log.h" #include "network.h" +#include "misc.h" + + struct anti_replay_t //its for anti replay attack,similar to openvpn/ipsec 's anti replay window { @@ -142,6 +145,10 @@ int clear_inactive0(); }; +extern conn_manager_t conn_manager; + +void server_clear_function(u64_t u64); + int send_bare(raw_info_t &raw_info,const char* data,int len);//send function with encryption but no anti replay,this is used when client and server verifys each other //you have to design the protocol carefully, so that you wont be affect by relay attack int reserved_parse_bare(const char *input,int input_len,char* & data,int & len); // a sub function used in recv_bare diff --git a/main.cpp b/main.cpp index bb5bc5e..4991238 100755 --- a/main.cpp +++ b/main.cpp @@ -1,52 +1,16 @@ #include "common.h" #include "network.h" #include "connection.h" +#include "misc.h" #include "log.h" #include "lib/md5.h" #include "encrypt.h" -#include "git_version.h" -#include -#include -#include -#include -#include - -char local_ip[100]="0.0.0.0", remote_ip[100]="255.255.255.255",source_ip[100]="0.0.0.0";//local_ip is for -l option,remote_ip for -r option,source for --source-ip -u32_t local_ip_uint32,remote_ip_uint32,source_ip_uint32;//convert from last line. -int local_port = -1, remote_port=-1,source_port=0;//similiar to local_ip remote_ip,buf for port.source_port=0 indicates --source-port is not enabled - -int force_source_ip=0; //if --source-ip is enabled - - -id_t const_id=0;//an id used for connection recovery,its generated randomly,it never change since its generated - - - -int udp_fd=-1; //for client only. client use this fd to listen and handle udp connection -int bind_fd=-1; //bind only,never send or recv. its just a dummy fd for bind,so that other program wont occupy the same port -int epollfd=-1; //fd for epoll -int timer_fd=-1; //the general timer fd for client and server.for server this is not the only timer find,every connection has a timer fd. -int fail_time_counter=0;//determine if the max_fail_time is reached -int epoll_trigger_counter=0;//for debug only -int debug_flag=0;//for debug only - - -int simple_rule=0; //deprecated. -int keep_rule=0; //whether to monitor the iptables rule periodly,re-add if losted -int auto_add_iptables_rule=0;//if -a is set -int generate_iptables_rule=0;//if -g is set -int generate_iptables_rule_add=0;// if --gen-add is set - -int debug_resend=0; // debug only - -char key_string[1000]= "secret key";// -k option - int mtu_warn=1375;//if a packet larger than mtu warn is receviced,there will be a warning //uint64_t current_time_rough=0; -conn_manager_t conn_manager; + int VVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVV; ////////==============================variable divider============================================================= @@ -58,106 +22,13 @@ int server_on_raw_recv_pre_ready(conn_info_t &conn_info,char * ip_port,u32_t tmp int server_on_raw_recv_ready(conn_info_t &conn_info,char * ip_port,char type,char *data,int data_len); int server_on_raw_recv_handshake1(conn_info_t &conn_info,char * ip_port,char * data, int data_len); -void process_arg(int argc, char *argv[]); -int find_lower_level_info(u32_t ip,u32_t &dest_ip,string &if_name,string &hw); int DDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDD; ////////////////=======================declear divider============================= -void server_clear_function(u64_t u64)//used in conv_manager in server mode.for server we have to use one udp fd for one conv(udp connection), -//so we have to close the fd when conv expires -{ - int fd=int(u64); - int ret; - assert(fd!=0); - /* - epoll_event ev; - - ev.events = EPOLLIN; - ev.data.u64 = u64; - - ret = epoll_ctl(epollfd, EPOLL_CTL_DEL, fd, &ev); - if (ret!=0) - { - mylog(log_fatal,"fd:%d epoll delete failed!!!!\n",fd); - myexit(-1); //this shouldnt happen - }*/ //no need - ret= close(fd); //closed fd should be auto removed from epoll - - if (ret!=0) - { - mylog(log_fatal,"close fd %d failed !!!!\n",fd); - myexit(-1); //this shouldnt happen - } - //mylog(log_fatal,"size:%d !!!!\n",conn_manager.udp_fd_mp.size()); - assert(conn_manager.udp_fd_mp.find(fd)!=conn_manager.udp_fd_mp.end()); - conn_manager.udp_fd_mp.erase(fd); -} - - -int set_timer(int epollfd,int &timer_fd)//put a timer_fd into epoll,general function,used both in client and server -{ - int ret; - epoll_event ev; - - itimerspec its; - memset(&its,0,sizeof(its)); - - if((timer_fd=timerfd_create(CLOCK_MONOTONIC,TFD_NONBLOCK)) < 0) - { - mylog(log_fatal,"timer_fd create error\n"); - myexit(1); - } - its.it_interval.tv_sec=(timer_interval/1000); - its.it_interval.tv_nsec=(timer_interval%1000)*1000ll*1000ll; - its.it_value.tv_nsec=1; //imidiately - timerfd_settime(timer_fd,0,&its,0); - - - ev.events = EPOLLIN; - ev.data.u64 = timer_fd; - - ret=epoll_ctl(epollfd, EPOLL_CTL_ADD, timer_fd, &ev); - if (ret < 0) { - mylog(log_fatal,"epoll_ctl return %d\n", ret); - myexit(-1); - } - return 0; -} - - -int set_timer_server(int epollfd,int &timer_fd)//only for server -{ - int ret; - epoll_event ev; - - itimerspec its; - memset(&its,0,sizeof(its)); - - if((timer_fd=timerfd_create(CLOCK_MONOTONIC,TFD_NONBLOCK)) < 0) - { - mylog(log_fatal,"timer_fd create error\n"); - myexit(1); - } - its.it_interval.tv_sec=(timer_interval/1000); - its.it_interval.tv_nsec=(timer_interval%1000)*1000ll*1000ll; - its.it_value.tv_nsec=1; //imidiately - timerfd_settime(timer_fd,0,&its,0); - - - ev.events = EPOLLIN; - ev.data.u64 = pack_u64(2,timer_fd);////difference - - ret=epoll_ctl(epollfd, EPOLL_CTL_ADD, timer_fd, &ev); - if (ret < 0) { - mylog(log_fatal,"epoll_ctl return %d\n", ret); - myexit(-1); - } - return 0; -} int client_on_timer(conn_info_t &conn_info) //for client. called when a timer is ready in epoll { //keep_iptables_rule(); @@ -637,35 +508,7 @@ int client_on_raw_recv(conn_info_t &conn_info) //called when raw fd received a p } return 0; } -int handle_lower_level(raw_info_t &raw_info)//fill lower_level info,when --lower-level is enabled,only for server -{ - packet_info_t &send_info=raw_info.send_info; - packet_info_t &recv_info=raw_info.recv_info; - if(lower_level_manual) - { - memset(&send_info.addr_ll,0,sizeof(send_info.addr_ll)); - send_info.addr_ll.sll_family=AF_PACKET; - send_info.addr_ll.sll_ifindex=ifindex; - send_info.addr_ll.sll_halen=ETHER_ADDR_LEN; - send_info.addr_ll.sll_protocol=htons(ETH_P_IP); - memcpy(&send_info.addr_ll.sll_addr,dest_hw_addr,ETHER_ADDR_LEN); - mylog(log_debug,"[manual]lower level info %x %x\n ",send_info.addr_ll.sll_halen,send_info.addr_ll.sll_protocol); - } - else - { - memset(&send_info.addr_ll,0,sizeof(send_info.addr_ll)); - send_info.addr_ll.sll_family=recv_info.addr_ll.sll_family; - send_info.addr_ll.sll_ifindex=recv_info.addr_ll.sll_ifindex; - send_info.addr_ll.sll_protocol=recv_info.addr_ll.sll_protocol; - send_info.addr_ll.sll_halen=recv_info.addr_ll.sll_halen; - memcpy(send_info.addr_ll.sll_addr,recv_info.addr_ll.sll_addr,sizeof(send_info.addr_ll.sll_addr)); - //other bytes should be kept zero. - - mylog(log_debug,"[auto]lower level info %x %x\n ",send_info.addr_ll.sll_halen,send_info.addr_ll.sll_protocol); - } - return 0; -} int server_on_raw_recv_multi() //called when server received an raw packet { char dummy_buf[buf_len]; @@ -1689,840 +1532,11 @@ int server_event_loop() } return 0; } -//char lower_level_arg[1000]; -int process_lower_level_arg()//handle --lower-level option -{ - lower_level=1; - if(strcmp(optarg,"auto")==0) - { - return 0; - } - lower_level_manual=1; - if (strchr(optarg, '#') == 0) { - mylog(log_fatal, - "lower-level parameter invaild,check help page for format\n"); - myexit(-1); - } - lower_level = 1; - u32_t hw[6]; - memset(hw, 0, sizeof(hw)); - sscanf(optarg, "%[^#]#%x:%x:%x:%x:%x:%x", if_name, &hw[0], &hw[1], &hw[2], - &hw[3], &hw[4], &hw[5]); - mylog(log_warn, - "make sure this is correct: if_name=<%s> dest_mac_adress=<%02x:%02x:%02x:%02x:%02x:%02x> \n", - if_name, hw[0], hw[1], hw[2], hw[3], hw[4], hw[5]); - for (int i = 0; i < 6; i++) { - dest_hw_addr[i] = uint8_t(hw[i]); - } - return 0; -} -void print_help() -{ - char git_version_buf[100]={0}; - strncpy(git_version_buf,gitversion,10); - printf("udp2raw-tunnel\n"); - printf("git version:%s ",git_version_buf); - printf("build date:%s %s\n",__DATE__,__TIME__); - printf("repository: https://github.com/wangyu-/udp2raw-tunnel\n"); - printf("\n"); - printf("usage:\n"); - printf(" run as client : ./this_program -c -l local_listen_ip:local_port -r server_ip:server_port [options]\n"); - printf(" run as server : ./this_program -s -l server_listen_ip:server_port -r remote_ip:remote_port [options]\n"); - printf("\n"); - printf("common options,these options must be same on both side:\n"); - printf(" --raw-mode avaliable values:faketcp(default),udp,icmp\n"); - printf(" -k,--key password to gen symetric key,default:\"secret key\"\n"); - printf(" --cipher-mode avaliable values:aes128cbc(default),xor,none\n"); - printf(" --auth-mode avaliable values:md5(default),crc32,simple,none\n"); - printf(" -a,--auto-rule auto add (and delete) iptables rule\n"); - printf(" -g,--gen-rule generate iptables rule then exit,so that you can copy and\n"); - printf(" add it manually.overrides -a\n"); - printf(" --disable-anti-replay disable anti-replay,not suggested\n"); - //printf("\n"); - printf("client options:\n"); - printf(" --source-ip force source-ip for raw socket\n"); - printf(" --source-port force source-port for raw socket,tcp/udp only\n"); - printf(" this option disables port changing while re-connecting\n"); -// printf(" \n"); - printf("other options:\n"); - printf(" --conf-file read options from a configuration file instead of command line.\n"); - printf(" check example.conf in repo for format\n"); - printf(" --log-level 0:never 1:fatal 2:error 3:warn \n"); - printf(" 4:info (default) 5:debug 6:trace\n"); -// printf("\n"); - printf(" --log-position enable file name,function name,line number in log\n"); - printf(" --disable-color disable log color\n"); - printf(" --disable-bpf disable the kernel space filter,most time its not necessary\n"); - printf(" unless you suspect there is a bug\n"); -// printf("\n"); - printf(" --sock-buf buf size for socket,>=10 and <=10240,unit:kbyte,default:1024\n"); - printf(" --force-sock-buf bypass system limitation while setting sock-buf\n"); - printf(" --seq-mode seq increase mode for faketcp:\n"); - printf(" 0:static header,do not increase seq and ack_seq\n"); - printf(" 1:increase seq for every packet,simply ack last seq\n"); - printf(" 2:increase seq randomly, about every 3 packets,simply ack last seq\n"); - printf(" 3:simulate an almost real seq/ack procedure(default)\n"); - printf(" 4:similiar to 3,but do not consider TCP Option Window_Scale,\n"); - printf(" maybe useful when firewall doesnt support TCP Option \n"); -// printf("\n"); - printf(" --lower-level send packets at OSI level 2, format:'if_name#dest_mac_adress'\n"); - printf(" ie:'eth0#00:23:45:67:89:b9'.or try '--lower-level auto' to obtain\n"); - printf(" the parameter automatically,specify it manually if 'auto' failed\n"); - printf(" --gen-add generate iptables rule and add it permanently,then exit.overrides -g\n"); - printf(" --keep-rule monitor iptables and auto re-add if necessary.implys -a\n"); - printf(" --clear clear any iptables rules added by this program.overrides everything\n"); - printf(" -h,--help print this help message\n"); - //printf("common options,these options must be same on both side\n"); -} - -int load_config(char *file_name, int &argc, vector &argv) //load conf file and append to argv -{ - // Load configurations from config_file instead of the command line. - // See config.example for example configurations - std::ifstream conf_file(file_name); - std::string line; - if(conf_file.fail()) - { - mylog(log_fatal,"conf_file %s open failed,reason :%s\n",file_name,strerror(errno)); - myexit(-1); - } - while(std::getline(conf_file,line)) - { - auto res=parse_conf_line(line); - - argc+=res.size(); - for(int i=0;i<(int)res.size();i++) - { - argv.push_back(res[i]); - } - } - conf_file.close(); - - return 0; -} - -int unit_test() -{ - printf("running unit test\n"); - vector conf_lines= {"---aaa","--aaa bbb","-a bbb"," \t \t \t-a\t \t \t bbbbb\t \t \t "}; - for(int i=0;i",res[j].c_str()); - } - printf("\n"); - } - - char s1[]={1,2,3,4,5}; - - char s2[]={1}; - - short c1=csum((unsigned short*)s1,5); - short c2=csum((unsigned short*)s2,1); - //c2=0; - - printf("%x %x\n",(int)c1,(int)c2); - - const char buf[]={1,2,3,4,5,6,7,8,9,10,11,2,13,14,15,16}; - char key[100]={0}; - char buf2[100]={0}; - char buf3[100]={0}; - char buf4[100]={0}; - int len=16; - for(int i=0;i",buf[i]); - } - printf("\n"); - cipher_encrypt(buf,buf2,len,key); - for(int i=0;i",buf2[i]); - } - printf("\n"); - int temp_len=len; - cipher_decrypt(buf2,buf3,len,key); - for(int i=0;i",buf3[i]); - } - printf("\n"); - cipher_encrypt(buf2,buf4,temp_len,key); - for(int i=0;i",buf4[i]); - } - return 0; -} - -int process_log_level(int argc,char *argv[])//process --log-level and --disable-cloer --log-postion options -{ - int i,j,k; - for (i = 0; i < argc; i++) - { - if(strcmp(argv[i],"--log-level")==0) - { - if(i all_options; - map shortcut_map; - - all_options.insert("--help"); - all_options.insert("-h"); - string dummy=""; - for(i=0;i<(int)strlen(options);i++) - { - - char val=options[i]; - if( ( val>='0'&&val<='9') ||( val>='a'&&val<='z')||(val>='A'&&val<='Z')) - { - all_options.insert(dummy+'-'+val); - } - } - for(i=0;i='0'&&val<='9') ||( val>='a'&&val<='z')||(val>='A'&&val<='Z')) - { - shortcut_map[dummy+"--"+long_options[i].name]= dummy+"-"+ char(val); - } - all_options.insert(dummy+"--"+long_options[i].name); - } - - for (i = 0; i < argc; i++) - { - int len=strlen(argv[i]); - if(len==0) - { - mylog(log_fatal,"found an empty string in options\n"); - myexit(-1); - } - if(len==1&&argv[i][0]=='-' ) - { - mylog(log_fatal,"invaild option '-' in argv\n"); - myexit(-1); - } - if(len==2&&argv[i][0]=='-'&&argv[i][1]=='-' ) - { - mylog(log_fatal,"invaild option '--' in argv\n"); - myexit(-1); - } - } - - mylog(log_info,"argc=%d ", argc); - - for (i = 0; i < argc; i++) { - log_bare(log_info, "%s ", argv[i]); - } - log_bare(log_info, "\n"); - - //string dummy=""; - for(i=+1;i\n",option_index, optopt); - } - break; - default: - mylog(log_fatal,"unknown option ,code:<%c>,<%x>\n",optopt, optopt); - myexit(-1); - } - } - - if (no_l) - mylog(log_fatal,"error: -l not found\n"); - if (no_r) - mylog(log_fatal,"error: -r not found\n"); - if(program_mode==0) - mylog(log_fatal,"error: -c /-s hasnt been set\n"); - if (no_l || no_r||program_mode==0) - { - print_help(); - myexit(-1); - } - //if(lower_level) - //process_lower_level_arg(); - - mylog(log_info,"important variables: "); - - log_bare(log_info,"log_level=%d:%s ",log_level,log_text[log_level]); - log_bare(log_info,"raw_mode=%s ",raw_mode_tostring[raw_mode]); - log_bare(log_info,"cipher_mode=%s ",cipher_mode_tostring[cipher_mode]); - log_bare(log_info,"auth_mode=%s ",auth_mode_tostring[auth_mode]); - - log_bare(log_info,"key=%s ",key_string); - - log_bare(log_info,"local_ip=%s ",local_ip); - log_bare(log_info,"local_port=%d ",local_port); - log_bare(log_info,"remote_ip=%s ",remote_ip); - log_bare(log_info,"remote_port=%d ",remote_port); - log_bare(log_info,"source_ip=%s ",source_ip); - log_bare(log_info,"source_port=%d ",source_port); - - log_bare(log_info,"socket_buf_size=%d ",socket_buf_size); - - log_bare(log_info,"\n"); -} -void pre_process_arg(int argc, char *argv[])//mainly for load conf file -{ - int i,j,k; - for (i = 0; i < argc; i++) - { - if(strcmp(argv[i],"--unit-test")==0) - { - unit_test(); - myexit(0); - } - - } - - for (i = 0; i < argc; i++) - { - if(strcmp(argv[i],"-h")==0||strcmp(argv[i],"--help")==0) - { - print_help(); - myexit(0); - } - - } - - if (argc == 1) - { - print_help(); - myexit(-1); - } - - process_log_level(argc,argv); - - int new_argc=0; - vector new_argv; - - int count=0; - int pos=-1; - - for (i = 0; i < argc; i++) - { - if(strcmp(argv[i],"--conf-file")==0) - { - count++; - pos=i; - if(i==argc) - { - mylog(log_fatal,"--conf-file need a parameter\n"); - myexit(-1); - } - if(argv[i+1][0]=='-') - { - mylog(log_fatal,"--conf-file need a parameter\n"); - myexit(-1); - } - i++; - } - else - { - //printf("<%s>",argv[i]); - new_argc++; - new_argv.push_back(argv[i]); - } - } - if(count>1) - { - mylog(log_fatal,"duplicated --conf-file option\n"); - myexit(-1); - } - - if(count>0) - { - load_config(argv[pos+1],new_argc,new_argv); - } - char* new_argv_char[new_argv.size()]; - - new_argc=0; - for(i=0;i<(int)new_argv.size();i++) - { - if(strcmp(new_argv[i].c_str(),"--conf-file")==0) - { - mylog(log_fatal,"cant have --conf-file in a config file\n"); - myexit(-1); - } - new_argv_char[new_argc++]=(char *)new_argv[i].c_str(); - } - process_arg(new_argc,new_argv_char); - -} -void *run_keep(void *none) //called in a new thread for --keep-rule option -{ - - while(1) - { - sleep(iptables_rule_keep_interval); - keep_iptables_rule(); - if(about_to_exit) //just incase it runs forever if there is some bug,not necessary - { - sleep(10); - keep_thread_running=0; //not thread safe ,but wont cause problem - break; - } - } - return NULL; - -} -void iptables_rule() // handles -a -g --gen-add --keep-rule -{ - if(auto_add_iptables_rule&&generate_iptables_rule) - { - mylog(log_warn," -g overrides -a\n"); - auto_add_iptables_rule=0; - //myexit(-1); - } - if(generate_iptables_rule_add&&generate_iptables_rule) - { - mylog(log_warn," --gen-add overrides -g\n"); - generate_iptables_rule=0; - //myexit(-1); - } - - if(keep_rule&&auto_add_iptables_rule==0) - { - auto_add_iptables_rule=1; - mylog(log_warn," --keep_rule implys -a\n"); - generate_iptables_rule=0; - //myexit(-1); - } - char tmp_pattern[200]; - string pattern=""; - - if(program_mode==client_mode) - { - if(raw_mode==mode_faketcp) - { - sprintf(tmp_pattern,"-s %s/32 -p tcp -m tcp --sport %d",remote_ip,remote_port); - } - if(raw_mode==mode_udp) - { - sprintf(tmp_pattern,"-s %s/32 -p udp -m udp --sport %d",remote_ip,remote_port); - } - if(raw_mode==mode_icmp) - { - sprintf(tmp_pattern,"-s %s/32 -p icmp",remote_ip); - } - pattern=tmp_pattern; - } - if(program_mode==server_mode) - { - - if(raw_mode==mode_faketcp) - { - sprintf(tmp_pattern,"-p tcp -m tcp --dport %d",local_port); - } - if(raw_mode==mode_udp) - { - sprintf(tmp_pattern,"-p udp -m udp --dport %d",local_port); - } - if(raw_mode==mode_icmp) - { - if(local_ip_uint32==0) - { - sprintf(tmp_pattern,"-p icmp"); - } - else - { - sprintf(tmp_pattern,"-d %s/32 -p icmp",local_ip); - } - } - pattern=tmp_pattern; - } -/* - if(!simple_rule) - { - pattern += " -m comment --comment udp2rawDwrW_"; - - char const_id_str[100]; - sprintf(const_id_str, "%x_", const_id); - - pattern += const_id_str; - - time_t timer; - char buffer[26]; - struct tm* tm_info; - - time(&timer); - tm_info = localtime(&timer); - - strftime(buffer, 26, "%Y-%m-%d-%H:%M:%S", tm_info); - - pattern += buffer; - - - }*/ - - if(auto_add_iptables_rule) - { - iptables_rule_init(pattern.c_str(),const_id,keep_rule); - if(keep_rule) - { - if(pthread_create(&keep_thread, NULL, run_keep, 0)) { - - mylog(log_fatal, "Error creating thread\n"); - myexit(-1); - } - keep_thread_running=1; - } - } - if(generate_iptables_rule) - { - string rule="iptables -I INPUT "; - rule+=pattern; - rule+=" -j DROP"; - - printf("generated iptables rule:\n"); - printf("%s\n",rule.c_str()); - myexit(0); - } - if(generate_iptables_rule_add) - { - iptables_gen_add(pattern.c_str(),const_id); - myexit(0); - } - - -} /* int test() diff --git a/makefile b/makefile index 743a861..fcf00eb 100755 --- a/makefile +++ b/makefile @@ -8,7 +8,7 @@ cc_arm= /toolchains/arm-2014.05/bin/arm-none-linux-gnueabi-g++ #cc_bcm2708=/home/wangyu/raspberry/tools/arm-bcm2708/gcc-linaro-arm-linux-gnueabihf-raspbian/bin/arm-linux-gnueabihf-g++ FLAGS= -std=c++11 -Wall -Wextra -Wno-unused-variable -Wno-unused-parameter -Wno-missing-field-initializers -COMMON=main.cpp lib/md5.c encrypt.cpp log.cpp network.cpp common.cpp connection.cpp -lpthread +COMMON=main.cpp lib/md5.c encrypt.cpp log.cpp network.cpp common.cpp connection.cpp misc.cpp -lpthread SOURCES= $(COMMON) lib/aes_faster_c/aes.c lib/aes_faster_c/wrapper.c SOURCES_TINY_AES= $(COMMON) lib/aes.c SOURCES_AES_ACC=$(COMMON) $(wildcard lib/aes_acc/aes*.c) diff --git a/misc.cpp b/misc.cpp new file mode 100644 index 0000000..4c54720 --- /dev/null +++ b/misc.cpp @@ -0,0 +1,976 @@ +/* + * misc.cpp + * + * Created on: Sep 23, 2017 + * Author: root + */ +#include "git_version.h" +#include "common.h" +#include "encrypt.h" +#include "misc.h" +#include "network.h" +#include "connection.h" + + +char local_ip[100]="0.0.0.0", remote_ip[100]="255.255.255.255",source_ip[100]="0.0.0.0";//local_ip is for -l option,remote_ip for -r option,source for --source-ip +u32_t local_ip_uint32,remote_ip_uint32,source_ip_uint32;//convert from last line. +int local_port = -1, remote_port=-1,source_port=0;//similiar to local_ip remote_ip,buf for port.source_port=0 indicates --source-port is not enabled + +int force_source_ip=0; //if --source-ip is enabled + + +id_t const_id=0;//an id used for connection recovery,its generated randomly,it never change since its generated + + + +int udp_fd=-1; //for client only. client use this fd to listen and handle udp connection +int bind_fd=-1; //bind only,never send or recv. its just a dummy fd for bind,so that other program wont occupy the same port +int epollfd=-1; //fd for epoll +int timer_fd=-1; //the general timer fd for client and server.for server this is not the only timer find,every connection has a timer fd. +int fail_time_counter=0;//determine if the max_fail_time is reached +int epoll_trigger_counter=0;//for debug only +int debug_flag=0;//for debug only + + +int simple_rule=0; //deprecated. +int keep_rule=0; //whether to monitor the iptables rule periodly,re-add if losted +int auto_add_iptables_rule=0;//if -a is set +int generate_iptables_rule=0;//if -g is set +int generate_iptables_rule_add=0;// if --gen-add is set + +int debug_resend=0; // debug only + +char key_string[1000]= "secret key";// -k option + + + +//char lower_level_arg[1000]; +int process_lower_level_arg()//handle --lower-level option +{ + lower_level=1; + if(strcmp(optarg,"auto")==0) + { + return 0; + } + + lower_level_manual=1; + if (strchr(optarg, '#') == 0) { + mylog(log_fatal, + "lower-level parameter invaild,check help page for format\n"); + myexit(-1); + } + lower_level = 1; + u32_t hw[6]; + memset(hw, 0, sizeof(hw)); + sscanf(optarg, "%[^#]#%x:%x:%x:%x:%x:%x", if_name, &hw[0], &hw[1], &hw[2], + &hw[3], &hw[4], &hw[5]); + + mylog(log_warn, + "make sure this is correct: if_name=<%s> dest_mac_adress=<%02x:%02x:%02x:%02x:%02x:%02x> \n", + if_name, hw[0], hw[1], hw[2], hw[3], hw[4], hw[5]); + for (int i = 0; i < 6; i++) { + dest_hw_addr[i] = uint8_t(hw[i]); + } + return 0; +} +void print_help() +{ + char git_version_buf[100]={0}; + strncpy(git_version_buf,gitversion,10); + printf("udp2raw-tunnel\n"); + printf("git version:%s ",git_version_buf); + printf("build date:%s %s\n",__DATE__,__TIME__); + + printf("repository: https://github.com/wangyu-/udp2raw-tunnel\n"); + printf("\n"); + printf("usage:\n"); + printf(" run as client : ./this_program -c -l local_listen_ip:local_port -r server_ip:server_port [options]\n"); + printf(" run as server : ./this_program -s -l server_listen_ip:server_port -r remote_ip:remote_port [options]\n"); + printf("\n"); + printf("common options,these options must be same on both side:\n"); + printf(" --raw-mode avaliable values:faketcp(default),udp,icmp\n"); + printf(" -k,--key password to gen symetric key,default:\"secret key\"\n"); + printf(" --cipher-mode avaliable values:aes128cbc(default),xor,none\n"); + printf(" --auth-mode avaliable values:md5(default),crc32,simple,none\n"); + printf(" -a,--auto-rule auto add (and delete) iptables rule\n"); + printf(" -g,--gen-rule generate iptables rule then exit,so that you can copy and\n"); + printf(" add it manually.overrides -a\n"); + printf(" --disable-anti-replay disable anti-replay,not suggested\n"); + + //printf("\n"); + printf("client options:\n"); + printf(" --source-ip force source-ip for raw socket\n"); + printf(" --source-port force source-port for raw socket,tcp/udp only\n"); + printf(" this option disables port changing while re-connecting\n"); +// printf(" \n"); + printf("other options:\n"); + printf(" --conf-file read options from a configuration file instead of command line.\n"); + printf(" check example.conf in repo for format\n"); + printf(" --log-level 0:never 1:fatal 2:error 3:warn \n"); + printf(" 4:info (default) 5:debug 6:trace\n"); +// printf("\n"); + printf(" --log-position enable file name,function name,line number in log\n"); + printf(" --disable-color disable log color\n"); + printf(" --disable-bpf disable the kernel space filter,most time its not necessary\n"); + printf(" unless you suspect there is a bug\n"); +// printf("\n"); + printf(" --sock-buf buf size for socket,>=10 and <=10240,unit:kbyte,default:1024\n"); + printf(" --force-sock-buf bypass system limitation while setting sock-buf\n"); + printf(" --seq-mode seq increase mode for faketcp:\n"); + printf(" 0:static header,do not increase seq and ack_seq\n"); + printf(" 1:increase seq for every packet,simply ack last seq\n"); + printf(" 2:increase seq randomly, about every 3 packets,simply ack last seq\n"); + printf(" 3:simulate an almost real seq/ack procedure(default)\n"); + printf(" 4:similiar to 3,but do not consider TCP Option Window_Scale,\n"); + printf(" maybe useful when firewall doesnt support TCP Option \n"); +// printf("\n"); + printf(" --lower-level send packets at OSI level 2, format:'if_name#dest_mac_adress'\n"); + printf(" ie:'eth0#00:23:45:67:89:b9'.or try '--lower-level auto' to obtain\n"); + printf(" the parameter automatically,specify it manually if 'auto' failed\n"); + printf(" --gen-add generate iptables rule and add it permanently,then exit.overrides -g\n"); + printf(" --keep-rule monitor iptables and auto re-add if necessary.implys -a\n"); + printf(" --clear clear any iptables rules added by this program.overrides everything\n"); + printf(" -h,--help print this help message\n"); + + //printf("common options,these options must be same on both side\n"); +} + +int load_config(char *file_name, int &argc, vector &argv) //load conf file and append to argv +{ + // Load configurations from config_file instead of the command line. + // See config.example for example configurations + std::ifstream conf_file(file_name); + std::string line; + if(conf_file.fail()) + { + mylog(log_fatal,"conf_file %s open failed,reason :%s\n",file_name,strerror(errno)); + myexit(-1); + } + while(std::getline(conf_file,line)) + { + auto res=parse_conf_line(line); + + argc+=res.size(); + for(int i=0;i<(int)res.size();i++) + { + argv.push_back(res[i]); + } + } + conf_file.close(); + + return 0; +} + +int process_log_level(int argc,char *argv[])//process --log-level and --disable-cloer --log-postion options +{ + int i,j,k; + for (i = 0; i < argc; i++) + { + if(strcmp(argv[i],"--log-level")==0) + { + if(i all_options; + map shortcut_map; + + all_options.insert("--help"); + all_options.insert("-h"); + string dummy=""; + for(i=0;i<(int)strlen(options);i++) + { + + char val=options[i]; + if( ( val>='0'&&val<='9') ||( val>='a'&&val<='z')||(val>='A'&&val<='Z')) + { + all_options.insert(dummy+'-'+val); + } + } + for(i=0;i='0'&&val<='9') ||( val>='a'&&val<='z')||(val>='A'&&val<='Z')) + { + shortcut_map[dummy+"--"+long_options[i].name]= dummy+"-"+ char(val); + } + all_options.insert(dummy+"--"+long_options[i].name); + } + + for (i = 0; i < argc; i++) + { + int len=strlen(argv[i]); + if(len==0) + { + mylog(log_fatal,"found an empty string in options\n"); + myexit(-1); + } + if(len==1&&argv[i][0]=='-' ) + { + mylog(log_fatal,"invaild option '-' in argv\n"); + myexit(-1); + } + if(len==2&&argv[i][0]=='-'&&argv[i][1]=='-' ) + { + mylog(log_fatal,"invaild option '--' in argv\n"); + myexit(-1); + } + } + + mylog(log_info,"argc=%d ", argc); + + for (i = 0; i < argc; i++) { + log_bare(log_info, "%s ", argv[i]); + } + log_bare(log_info, "\n"); + + //string dummy=""; + for(i=+1;i\n",option_index, optopt); + } + break; + default: + mylog(log_fatal,"unknown option ,code:<%c>,<%x>\n",optopt, optopt); + myexit(-1); + } + } + + if (no_l) + mylog(log_fatal,"error: -l not found\n"); + if (no_r) + mylog(log_fatal,"error: -r not found\n"); + if(program_mode==0) + mylog(log_fatal,"error: -c /-s hasnt been set\n"); + if (no_l || no_r||program_mode==0) + { + print_help(); + myexit(-1); + } + //if(lower_level) + //process_lower_level_arg(); + + mylog(log_info,"important variables: "); + + log_bare(log_info,"log_level=%d:%s ",log_level,log_text[log_level]); + log_bare(log_info,"raw_mode=%s ",raw_mode_tostring[raw_mode]); + log_bare(log_info,"cipher_mode=%s ",cipher_mode_tostring[cipher_mode]); + log_bare(log_info,"auth_mode=%s ",auth_mode_tostring[auth_mode]); + + log_bare(log_info,"key=%s ",key_string); + + log_bare(log_info,"local_ip=%s ",local_ip); + log_bare(log_info,"local_port=%d ",local_port); + log_bare(log_info,"remote_ip=%s ",remote_ip); + log_bare(log_info,"remote_port=%d ",remote_port); + log_bare(log_info,"source_ip=%s ",source_ip); + log_bare(log_info,"source_port=%d ",source_port); + + log_bare(log_info,"socket_buf_size=%d ",socket_buf_size); + + log_bare(log_info,"\n"); +} + +void pre_process_arg(int argc, char *argv[])//mainly for load conf file +{ + int i,j,k; + for (i = 0; i < argc; i++) + { + if(strcmp(argv[i],"--unit-test")==0) + { + unit_test(); + myexit(0); + } + + } + + for (i = 0; i < argc; i++) + { + if(strcmp(argv[i],"-h")==0||strcmp(argv[i],"--help")==0) + { + print_help(); + myexit(0); + } + + } + + if (argc == 1) + { + print_help(); + myexit(-1); + } + + process_log_level(argc,argv); + + int new_argc=0; + vector new_argv; + + int count=0; + int pos=-1; + + for (i = 0; i < argc; i++) + { + if(strcmp(argv[i],"--conf-file")==0) + { + count++; + pos=i; + if(i==argc) + { + mylog(log_fatal,"--conf-file need a parameter\n"); + myexit(-1); + } + if(argv[i+1][0]=='-') + { + mylog(log_fatal,"--conf-file need a parameter\n"); + myexit(-1); + } + i++; + } + else + { + //printf("<%s>",argv[i]); + new_argc++; + new_argv.push_back(argv[i]); + } + } + if(count>1) + { + mylog(log_fatal,"duplicated --conf-file option\n"); + myexit(-1); + } + + if(count>0) + { + load_config(argv[pos+1],new_argc,new_argv); + } + char* new_argv_char[new_argv.size()]; + + new_argc=0; + for(i=0;i<(int)new_argv.size();i++) + { + if(strcmp(new_argv[i].c_str(),"--conf-file")==0) + { + mylog(log_fatal,"cant have --conf-file in a config file\n"); + myexit(-1); + } + new_argv_char[new_argc++]=(char *)new_argv[i].c_str(); + } + process_arg(new_argc,new_argv_char); + +} +void *run_keep(void *none) //called in a new thread for --keep-rule option +{ + + while(1) + { + sleep(iptables_rule_keep_interval); + keep_iptables_rule(); + if(about_to_exit) //just incase it runs forever if there is some bug,not necessary + { + sleep(10); + keep_thread_running=0; //not thread safe ,but wont cause problem + break; + } + } + return NULL; + +} +void iptables_rule() // handles -a -g --gen-add --keep-rule +{ + if(auto_add_iptables_rule&&generate_iptables_rule) + { + mylog(log_warn," -g overrides -a\n"); + auto_add_iptables_rule=0; + //myexit(-1); + } + if(generate_iptables_rule_add&&generate_iptables_rule) + { + mylog(log_warn," --gen-add overrides -g\n"); + generate_iptables_rule=0; + //myexit(-1); + } + + if(keep_rule&&auto_add_iptables_rule==0) + { + auto_add_iptables_rule=1; + mylog(log_warn," --keep_rule implys -a\n"); + generate_iptables_rule=0; + //myexit(-1); + } + char tmp_pattern[200]; + string pattern=""; + + if(program_mode==client_mode) + { + if(raw_mode==mode_faketcp) + { + sprintf(tmp_pattern,"-s %s/32 -p tcp -m tcp --sport %d",remote_ip,remote_port); + } + if(raw_mode==mode_udp) + { + sprintf(tmp_pattern,"-s %s/32 -p udp -m udp --sport %d",remote_ip,remote_port); + } + if(raw_mode==mode_icmp) + { + sprintf(tmp_pattern,"-s %s/32 -p icmp",remote_ip); + } + pattern=tmp_pattern; + } + if(program_mode==server_mode) + { + + if(raw_mode==mode_faketcp) + { + sprintf(tmp_pattern,"-p tcp -m tcp --dport %d",local_port); + } + if(raw_mode==mode_udp) + { + sprintf(tmp_pattern,"-p udp -m udp --dport %d",local_port); + } + if(raw_mode==mode_icmp) + { + if(local_ip_uint32==0) + { + sprintf(tmp_pattern,"-p icmp"); + } + else + { + sprintf(tmp_pattern,"-d %s/32 -p icmp",local_ip); + } + } + pattern=tmp_pattern; + } +/* + if(!simple_rule) + { + pattern += " -m comment --comment udp2rawDwrW_"; + + char const_id_str[100]; + sprintf(const_id_str, "%x_", const_id); + + pattern += const_id_str; + + time_t timer; + char buffer[26]; + struct tm* tm_info; + + time(&timer); + tm_info = localtime(&timer); + + strftime(buffer, 26, "%Y-%m-%d-%H:%M:%S", tm_info); + + pattern += buffer; + + + }*/ + + if(auto_add_iptables_rule) + { + iptables_rule_init(pattern.c_str(),const_id,keep_rule); + if(keep_rule) + { + if(pthread_create(&keep_thread, NULL, run_keep, 0)) { + + mylog(log_fatal, "Error creating thread\n"); + myexit(-1); + } + keep_thread_running=1; + } + } + if(generate_iptables_rule) + { + string rule="iptables -I INPUT "; + rule+=pattern; + rule+=" -j DROP"; + + printf("generated iptables rule:\n"); + printf("%s\n",rule.c_str()); + myexit(0); + } + if(generate_iptables_rule_add) + { + iptables_gen_add(pattern.c_str(),const_id); + myexit(0); + } + + +} + +int unit_test() +{ + printf("running unit test\n"); + vector conf_lines= {"---aaa","--aaa bbb","-a bbb"," \t \t \t-a\t \t \t bbbbb\t \t \t "}; + for(int i=0;i",res[j].c_str()); + } + printf("\n"); + } + + char s1[]={1,2,3,4,5}; + + char s2[]={1}; + + short c1=csum((unsigned short*)s1,5); + short c2=csum((unsigned short*)s2,1); + //c2=0; + + printf("%x %x\n",(int)c1,(int)c2); + + const char buf[]={1,2,3,4,5,6,7,8,9,10,11,2,13,14,15,16}; + char key[100]={0}; + char buf2[100]={0}; + char buf3[100]={0}; + char buf4[100]={0}; + int len=16; + for(int i=0;i",buf[i]); + } + printf("\n"); + cipher_encrypt(buf,buf2,len,key); + for(int i=0;i",buf2[i]); + } + printf("\n"); + int temp_len=len; + cipher_decrypt(buf2,buf3,len,key); + for(int i=0;i",buf3[i]); + } + printf("\n"); + cipher_encrypt(buf2,buf4,temp_len,key); + for(int i=0;i",buf4[i]); + } + return 0; +} + + +int set_timer(int epollfd,int &timer_fd)//put a timer_fd into epoll,general function,used both in client and server +{ + int ret; + epoll_event ev; + + itimerspec its; + memset(&its,0,sizeof(its)); + + if((timer_fd=timerfd_create(CLOCK_MONOTONIC,TFD_NONBLOCK)) < 0) + { + mylog(log_fatal,"timer_fd create error\n"); + myexit(1); + } + its.it_interval.tv_sec=(timer_interval/1000); + its.it_interval.tv_nsec=(timer_interval%1000)*1000ll*1000ll; + its.it_value.tv_nsec=1; //imidiately + timerfd_settime(timer_fd,0,&its,0); + + + ev.events = EPOLLIN; + ev.data.u64 = timer_fd; + + ret=epoll_ctl(epollfd, EPOLL_CTL_ADD, timer_fd, &ev); + if (ret < 0) { + mylog(log_fatal,"epoll_ctl return %d\n", ret); + myexit(-1); + } + return 0; +} + + +int set_timer_server(int epollfd,int &timer_fd)//only for server +{ + int ret; + epoll_event ev; + + itimerspec its; + memset(&its,0,sizeof(its)); + + if((timer_fd=timerfd_create(CLOCK_MONOTONIC,TFD_NONBLOCK)) < 0) + { + mylog(log_fatal,"timer_fd create error\n"); + myexit(1); + } + its.it_interval.tv_sec=(timer_interval/1000); + its.it_interval.tv_nsec=(timer_interval%1000)*1000ll*1000ll; + its.it_value.tv_nsec=1; //imidiately + timerfd_settime(timer_fd,0,&its,0); + + + ev.events = EPOLLIN; + ev.data.u64 = pack_u64(2,timer_fd);////difference + + ret=epoll_ctl(epollfd, EPOLL_CTL_ADD, timer_fd, &ev); + if (ret < 0) { + mylog(log_fatal,"epoll_ctl return %d\n", ret); + myexit(-1); + } + return 0; +} + +int handle_lower_level(raw_info_t &raw_info)//fill lower_level info,when --lower-level is enabled,only for server +{ + packet_info_t &send_info=raw_info.send_info; + packet_info_t &recv_info=raw_info.recv_info; + + if(lower_level_manual) + { + memset(&send_info.addr_ll,0,sizeof(send_info.addr_ll)); + send_info.addr_ll.sll_family=AF_PACKET; + send_info.addr_ll.sll_ifindex=ifindex; + send_info.addr_ll.sll_halen=ETHER_ADDR_LEN; + send_info.addr_ll.sll_protocol=htons(ETH_P_IP); + memcpy(&send_info.addr_ll.sll_addr,dest_hw_addr,ETHER_ADDR_LEN); + mylog(log_debug,"[manual]lower level info %x %x\n ",send_info.addr_ll.sll_halen,send_info.addr_ll.sll_protocol); + } + else + { + memset(&send_info.addr_ll,0,sizeof(send_info.addr_ll)); + send_info.addr_ll.sll_family=recv_info.addr_ll.sll_family; + send_info.addr_ll.sll_ifindex=recv_info.addr_ll.sll_ifindex; + send_info.addr_ll.sll_protocol=recv_info.addr_ll.sll_protocol; + send_info.addr_ll.sll_halen=recv_info.addr_ll.sll_halen; + memcpy(send_info.addr_ll.sll_addr,recv_info.addr_ll.sll_addr,sizeof(send_info.addr_ll.sll_addr)); + //other bytes should be kept zero. + + mylog(log_debug,"[auto]lower level info %x %x\n ",send_info.addr_ll.sll_halen,send_info.addr_ll.sll_protocol); + } + return 0; +} + + + diff --git a/misc.h b/misc.h new file mode 100644 index 0000000..d2b931b --- /dev/null +++ b/misc.h @@ -0,0 +1,55 @@ +/* + * misc.h + * + * Created on: Sep 23, 2017 + * Author: root + */ + +#ifndef MISC_H_ +#define MISC_H_ + + +#include "common.h" +#include "log.h" +#include "network.h" + +extern char local_ip[100], remote_ip[100],source_ip[100];//local_ip is for -l option,remote_ip for -r option,source for --source-ip +extern u32_t local_ip_uint32,remote_ip_uint32,source_ip_uint32;//convert from last line. +extern int local_port , remote_port,source_port;//similiar to local_ip remote_ip,buf for port.source_port=0 indicates --source-port is not enabled + +extern int force_source_ip; //if --source-ip is enabled + + +extern id_t const_id;//an id used for connection recovery,its generated randomly,it never change since its generated + + + +extern int udp_fd; //for client only. client use this fd to listen and handle udp connection +extern int bind_fd; //bind only,never send or recv. its just a dummy fd for bind,so that other program wont occupy the same port +extern int epollfd; //fd for epoll +extern int timer_fd; //the general timer fd for client and server.for server this is not the only timer find,every connection has a timer fd. +extern int fail_time_counter;//determine if the max_fail_time is reached +extern int epoll_trigger_counter;//for debug only +extern int debug_flag;//for debug only + + +extern int simple_rule; //deprecated. +extern int keep_rule; //whether to monitor the iptables rule periodly,re-add if losted +extern int auto_add_iptables_rule;//if -a is set +extern int generate_iptables_rule;//if -g is set +extern int generate_iptables_rule_add;// if --gen-add is set + +extern int debug_resend; // debug only + +extern char key_string[1000];// -k option + +int process_lower_level_arg(); +void print_help(); +void iptables_rule(); +void pre_process_arg(int argc, char *argv[]);//mainly for load conf file; +int unit_test(); +int set_timer(int epollfd,int &timer_fd); +int set_timer_server(int epollfd,int &timer_fd); +int handle_lower_level(raw_info_t &raw_info); + +#endif /* MISC_H_ */