├── README.md ├── mproxy ├── mproxy-mod.c └── tiny.conf /README.md: -------------------------------------------------------------------------------- 1 | # mproxy-mod 2 | 同时支持http和https自定义头域代理的mproxy实现。 3 | 4 | ## 更新 5 | 重新修改了源码,在保证其原有功能的基础上,新加了两个参数"-r" 和"-m"。 6 | 7 | ### "-r ":将流量无条件转发至指定的[服务器:端口] 8 | ./mproxy -l 8080 -r 127.0.0.1:443 9 | "-r"参数转发流量时,与"-h"参数的区别在于,其不转发CONNECT(http_tunnel)连接的header信息,而"-h"参数是不处理数据,全部转发(header+data)。 10 | 11 | ### -m :指定头域关键字以替换并行使原"Host:"的功能 12 | ./mproxy -l 8080 -m Lbxx: 13 | "-m"参数指定的字符串将被用来确定真实的remote host和port,使用时将忽略原"Host:"头域的内容。 14 | #### 注意:-h -r -m三个参数尽量不要一起用,优先级-h > -m > -r 。 15 | ./mproxy -l 8080 -h xxxx -m xxxx -r xxxx 16 | 如上的命令只有-h起作用,-m和-r将失效。 17 | 18 | ./mproxy -l 8080 -m Lbxx: -r 127.0.0.1:443 19 | 上面的命令,只有当连接header中不包含"Lbxx:"时,才会转发至127.0.0.1:443;如果包含,则仍将转发至"Lbxx:"所确定的地址。 20 | 21 | 原使用参数-h等可参照原项目地址。 22 | 23 | ## 使用 24 | - 上传源码,秒编译一下:gcc -o mproxy mproxy.c 25 | - 启动mproxy:./mproxy -l 8080 -m Lbxx: -d 26 | - 关闭mproxy: ps -ef | grep mproxy | grep -v grep | cut -c 9-15 | xargs kill -s 9 27 | - 查看端口:netstat -tupnl 看到8080端口有了,就成功了,此端口支持同时代理包含自定义头域"Lbxx:"的HTTP和CONNECT流量。 28 | 29 | ## 对于云免应用 30 | - 本代理适用于搭配tiny、http注射器、openvpn等使用,模式可自行指定 31 | - 对于tiny 32 | 33 | ./mproxy -l 8080 -m Lbxx: -r 127.0.0.1:443 34 | 35 | 接入点APN可以设置cmnet加上127.0.0.1:65080的代理。 36 | 文件中包含一个已失效的tiny模式示例。 37 | 参考[云代理搭建](http://bybbs.org/read-65245-1.html)提到的教程 38 | - 对于http注射器 39 | 40 | ./mproxy -l 8080 -m Lbxx: -r 127.0.0.1:22(22 is your ssh port) 41 | 42 | 参考: 43 | > 1.远程代理[your VPS ip]:8080 44 | > 2.有效载荷(参考):CONNECT migumovie.lovev.com:443 [protocol][crlf][delay_split]GET http://miguvod.lovev.com:8080/ [protocol][crlf]User-Agent: MGPlayer4Android/v6.6.3[crlf]Accept: */*[crlf]Range: bytes=0-[crlf]Connection: Keep-Alive[crlf]Host: miguvod.lovev.com:8080[crlf]Icy-MetaData: 1[crlf][crlf] 45 | > 3.启动ssh 46 | 47 | - 对于OPENVPN 48 | 49 | ./mproxy -l 8080 -m Lbxx: -r 127.0.0.1:443 50 | 51 | 参考: 52 | > http-proxy-option EXT1 "GET http://miguvod.lovev.com:8080/?" 53 | > http-proxy-option EXT1 "Accept: */*" 54 | > http-proxy-option EXT1 "Host: miguvod.lovev.com:8080" 55 | > http-proxy-option EXT1 "User-Agent: MGPlayer4Android/v6.6.3" 56 | > http-proxy-option EXT1 "Icy-MetaData: 1" 57 | > http-proxy [your VPS ip] 8080 58 | > 59 | > remote miguvod.lovev.com 443 tcp-client 60 | 61 | ## 注意 62 | - 示例中代理支持的自定义头域为'Lbxx:',可以自行指定为其他任意适当长度的字符串,达到防盗用的目的。 63 | - 模式中要求http部分Lbxx: [H]要紧跟Host:头域之后,https无要求 64 | - 云免知识从八云论坛的蜡笔小新。同学处学得很多,谢谢! 65 | - 源码修改自[examplecode/mproxy](https://github.com/examplecode/mproxy),感谢! 66 | 67 | -------------------------------------------------------------------------------- /mproxy: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lonsx/mproxy-mod/ea3abaa40c901da6bb8e655cde63d3cac28b83ec/mproxy -------------------------------------------------------------------------------- /mproxy-mod.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | 15 | 16 | #include 17 | 18 | #define BUF_SIZE 8192 19 | 20 | #define READ 0 21 | #define WRITE 1 22 | 23 | #define DEFAULT_LOCAL_PORT 8080 24 | #define DEFAULT_REMOTE_PORT 8081 25 | #define DEFAULT_R_P 1024 /* 定义-r 时默认的转发CONNECT流的端口 */ 26 | #define DEFAULT_M_S Lbxx: /* 定义-m 时默认的ML关键字符串(经判断无用,可舍弃) */ 27 | #define SERVER_SOCKET_ERROR -1 28 | #define SERVER_SETSOCKOPT_ERROR -2 29 | #define SERVER_BIND_ERROR -3 30 | #define SERVER_LISTEN_ERROR -4 31 | #define CLIENT_SOCKET_ERROR -5 32 | #define CLIENT_RESOLVE_ERROR -6 33 | #define CLIENT_CONNECT_ERROR -7 34 | #define CREATE_PIPE_ERROR -8 35 | #define BROKEN_PIPE_ERROR -9 36 | #define HEADER_BUFFER_FULL -10 37 | #define BAD_HTTP_PROTOCOL -11 38 | 39 | #define MAX_HEADER_SIZE 8192 40 | 41 | 42 | #if defined(OS_ANDROID) 43 | #include 44 | 45 | #define LOG(fmt...) __android_log_print(ANDROID_LOG_DEBUG,__FILE__,##fmt) 46 | 47 | #else 48 | #define LOG(fmt...) do { fprintf(stderr,"%s %s ",__DATE__,__TIME__); fprintf(stderr, ##fmt); } while(0) 49 | #endif 50 | 51 | 52 | char remote_host[128]; 53 | int remote_port; 54 | int local_port; 55 | char r_h[128]; 56 | int r_p; 57 | char m_s[128]; 58 | 59 | int server_sock; 60 | int client_sock; 61 | int remote_sock; 62 | 63 | 64 | 65 | 66 | char * header_buffer ; 67 | 68 | 69 | enum 70 | { 71 | FLG_NONE = 0, /* 正常数据流不进行编解码 */ 72 | R_C_DEC = 1, /* 读取客户端数据仅进行解码 */ 73 | W_S_ENC = 2 /* 发送到服务端进行编码 */ 74 | }; 75 | 76 | static int io_flag; /* 网络io的一些标志位 */ 77 | static int r_flag; /* 是否启用-r 匹配免流host直接转发CONNECT流量模式 */ 78 | static int m_flag; /* 是否启用-m 关键字头匹配免流模式 */ 79 | static int m_pid; /* 保存主进程id */ 80 | 81 | 82 | 83 | void server_loop(); 84 | void stop_server(); 85 | void handle_client(int client_sock, struct sockaddr_in client_addr); 86 | void forward_header(int destination_sock); 87 | void forward_data(int source_sock, int destination_sock); 88 | void rewrite_header(); 89 | int send_data(int socket,char * buffer,int len ); 90 | int receive_data(int socket, char * buffer, int len); 91 | void hand_mproxy_info_req(int sock,char * header_buffer) ; 92 | void get_info(char * output); 93 | const char * get_work_mode() ; 94 | int create_connection() ; 95 | int _main(int argc, char *argv[]) ; 96 | 97 | 98 | 99 | 100 | ssize_t readLine(int fd, void *buffer, size_t n) 101 | { 102 | ssize_t numRead; 103 | size_t totRead; 104 | char *buf; 105 | char ch; 106 | 107 | if (n <= 0 || buffer == NULL) { 108 | errno = EINVAL; 109 | return -1; 110 | } 111 | 112 | buf = buffer; 113 | 114 | totRead = 0; 115 | for (;;) { 116 | numRead = receive_data(fd, &ch, 1); 117 | 118 | if (numRead == -1) { 119 | if (errno == EINTR) 120 | continue; 121 | else 122 | return -1; /* 未知错误 */ 123 | 124 | } else if (numRead == 0) { /* EOF */ 125 | if (totRead == 0) /* No bytes read; return 0 */ 126 | return 0; 127 | else /* Some bytes read; add '\0' */ 128 | break; 129 | 130 | } else { 131 | 132 | if (totRead < n - 1) { /* Discard > (n - 1) bytes */ 133 | totRead++; 134 | *buf++ = ch; 135 | } 136 | 137 | if (ch == '\n') 138 | break; 139 | } 140 | } 141 | 142 | *buf = '\0'; 143 | return totRead; 144 | } 145 | 146 | int read_header(int fd, void * buffer) 147 | { 148 | // bzero(header_buffer,sizeof(MAX_HEADER_SIZE)); 149 | memset(header_buffer,0,MAX_HEADER_SIZE); 150 | char line_buffer[2048]; 151 | char * base_ptr = header_buffer; 152 | 153 | for(;;) 154 | { 155 | memset(line_buffer,0,2048); 156 | 157 | int total_read = readLine(fd,line_buffer,2048); 158 | if(total_read <= 0) 159 | { 160 | return CLIENT_SOCKET_ERROR; 161 | } 162 | //防止header缓冲区蛮越界 163 | if(base_ptr + total_read - header_buffer <= MAX_HEADER_SIZE) 164 | { 165 | strncpy(base_ptr,line_buffer,total_read); 166 | base_ptr += total_read; 167 | } else 168 | { 169 | return HEADER_BUFFER_FULL; 170 | } 171 | 172 | //读到了空行,http头结束 173 | if(strcmp(line_buffer,"\r\n") == 0 || strcmp(line_buffer,"\n") == 0) 174 | { 175 | break; 176 | } 177 | 178 | } 179 | return 0; 180 | 181 | } 182 | 183 | void extract_server_path(const char * header,char * output) 184 | { 185 | char * p = strstr(header,"GET /"); 186 | if(p) { 187 | char * p1 = strchr(p+4,' '); 188 | strncpy(output,p+4,(int)(p1 - p - 4) ); 189 | } 190 | 191 | } 192 | 193 | int extract_host(const char * header) 194 | { 195 | if(!m_flag) 196 | { 197 | if(!r_flag) 198 | { 199 | char * _p = strstr(header,"CONNECT"); /* 在 CONNECT 方法中解析 隧道主机名称及端口号 */ 200 | if(_p) 201 | { 202 | char * _p1 = strchr(_p,' '); 203 | 204 | char * _p2 = strchr(_p1 + 1,':'); 205 | char * _p3 = strchr(_p1 + 1,' '); 206 | 207 | if(_p2) 208 | { 209 | char s_port[10]; 210 | bzero(s_port,10); 211 | 212 | strncpy(remote_host,_p1+1,(int)(_p2 - _p1) - 1); 213 | strncpy(s_port,_p2+1,(int) (_p3 - _p2) -1); 214 | remote_port = atoi(s_port); 215 | 216 | } else 217 | { 218 | strncpy(remote_host,_p1+1,(int)(_p3 - _p1) -1); 219 | remote_port = 80; 220 | } 221 | 222 | 223 | return 0; 224 | } 225 | 226 | 227 | char * p = strstr(header,"Host:"); 228 | if(!p) 229 | { 230 | return BAD_HTTP_PROTOCOL; 231 | } 232 | char * p1 = strchr(p,'\n'); 233 | if(!p1) 234 | { 235 | return BAD_HTTP_PROTOCOL; 236 | } 237 | 238 | char * p2 = strchr(p + 5,':'); /* 5是指'Host:'的长度 */ 239 | 240 | if(p2 && p2 < p1) 241 | { 242 | 243 | int p_len = (int)(p1 - p2 -1); 244 | char s_port[p_len]; 245 | strncpy(s_port,p2+1,p_len); 246 | s_port[p_len] = '\0'; 247 | remote_port = atoi(s_port); 248 | 249 | int h_len = (int)(p2 - p -5 -1 ); 250 | strncpy(remote_host,p + 5 + 1 ,h_len); //Host: 251 | //assert h_len < 128; 252 | remote_host[h_len] = '\0'; 253 | } else 254 | { 255 | int h_len = (int)(p1 - p - 5 -1 -1); 256 | strncpy(remote_host,p + 5 + 1,h_len); 257 | //assert h_len < 128; 258 | remote_host[h_len] = '\0'; 259 | remote_port = 80; 260 | } 261 | } else 262 | { 263 | strncpy(remote_host, r_h, strlen(r_h)); 264 | remote_port = r_p; 265 | } 266 | } else 267 | { 268 | char * __p = strstr(header,"CONNECT"); /* 在 CONNECT 方法中解析 隧道主机名称及端口号 */ 269 | char * _p = strstr(header,m_s); 270 | //printf("Show: %s\n",_p); 271 | if(_p && __p) 272 | { 273 | char * _p1 = strchr(_p,' '); 274 | 275 | char * _p2 = strchr(_p1 + 1,':'); 276 | char * _p3 = strchr(_p1 + 1,'\r'); 277 | 278 | if(_p2) 279 | { 280 | char s_port[10]; 281 | bzero(s_port,10); 282 | 283 | strncpy(remote_host,_p1+1,(int)(_p2 - _p1) - 1); 284 | strncpy(s_port,_p2+1,(int) (_p3 - _p2) -1); 285 | remote_port = atoi(s_port); 286 | 287 | } else 288 | { 289 | strncpy(remote_host,_p1+1,(int)(_p3 - _p1) -1); 290 | remote_port = 80; 291 | } 292 | 293 | 294 | return 0; 295 | } 296 | 297 | 298 | char * p = strstr(header,m_s); 299 | if(!p) 300 | { 301 | if(r_flag) 302 | { 303 | strncpy(remote_host, r_h, strlen(r_h)); 304 | remote_port = r_p; 305 | return 0; 306 | }else 307 | { 308 | return BAD_HTTP_PROTOCOL; 309 | } 310 | } 311 | char * p1 = strchr(p,'\n'); 312 | if(!p1) 313 | { 314 | return BAD_HTTP_PROTOCOL; 315 | } 316 | 317 | int m_l = strlen(m_s); 318 | char * p2 = strchr(p + m_l,':'); /* m_l是指类似自定义'Lbxx:'的长度 */ 319 | 320 | if(p2 && p2 < p1) 321 | { 322 | 323 | int p_len = (int)(p1 - p2 -1); 324 | char s_port[p_len]; 325 | strncpy(s_port,p2+1,p_len); 326 | s_port[p_len] = '\0'; 327 | remote_port = atoi(s_port); 328 | 329 | int h_len = (int)(p2 - p - m_l -1 ); 330 | strncpy(remote_host,p + m_l + 1 ,h_len); //Host: 331 | //assert h_len < 128; 332 | remote_host[h_len] = '\0'; 333 | } else 334 | { 335 | int h_len = (int)(p1 - p - m_l -1 -1); 336 | strncpy(remote_host,p + m_l + 1,h_len); 337 | //assert h_len < 128; 338 | remote_host[h_len] = '\0'; 339 | remote_port = 80; 340 | } 341 | } 342 | return 0; 343 | } 344 | 345 | /* 响应隧道连接请求 */ 346 | int send_tunnel_ok(int client_sock) 347 | { 348 | char * resp = "HTTP/1.1 200 Connection Established\r\n\r\n"; 349 | int len = strlen(resp); 350 | char buffer[len+1]; 351 | strcpy(buffer,resp); 352 | if(send_data(client_sock,buffer,len) < 0) 353 | { 354 | perror("Send http tunnel response failed\n"); 355 | return -1; 356 | } 357 | return 0; 358 | } 359 | 360 | 361 | //返回mproxy的运行基本信息 362 | void hand_mproxy_info_req(int sock, char * header) { 363 | char server_path[255] ; 364 | char response[8192]; 365 | extract_server_path(header,server_path); 366 | 367 | LOG("server path:%s\n",server_path); 368 | char info_buf[1024]; 369 | get_info(info_buf); 370 | sprintf(response,"HTTP/1.0 200 OK\nServer: MProxy/0.1\n\ 371 | Content-type: text/html; charset=utf-8\n\n\ 372 | \ 373 |
%s
\ 374 | \n",info_buf); 375 | 376 | 377 | write(sock,response,strlen(response)); 378 | 379 | } 380 | 381 | /* 获取运行的基本信息输出到指定的缓冲区 */ 382 | void get_info(char * output) 383 | { 384 | int pos = 0; 385 | char line_buffer[512]; 386 | sprintf(line_buffer,"======= mproxy (v0.1) ========\n"); 387 | int len = strlen(line_buffer); 388 | memcpy(output,line_buffer,len); 389 | pos += len ; 390 | 391 | sprintf(line_buffer,"%s\n",get_work_mode()); 392 | len = strlen(line_buffer); 393 | memcpy(output + pos,line_buffer,len); 394 | pos += len; 395 | 396 | if(strlen(remote_host) > 0) 397 | { 398 | sprintf(line_buffer,"start server on %d and next hop is %s:%d\n",local_port,remote_host,remote_port); 399 | 400 | } else 401 | { 402 | sprintf(line_buffer,"start server on %d\n",local_port); 403 | } 404 | 405 | len = strlen(line_buffer); 406 | memcpy(output+ pos,line_buffer,len); 407 | pos += len ; 408 | 409 | output[pos] = '\0'; 410 | 411 | } 412 | 413 | 414 | const char * get_work_mode() 415 | { 416 | 417 | if(strlen(remote_host) == 0) 418 | { 419 | if(!r_flag && !m_flag) 420 | { 421 | if(io_flag == FLG_NONE) 422 | { 423 | return "start as normal http proxy"; 424 | } else if(io_flag == R_C_DEC) 425 | { 426 | return "start as remote forward proxy and do decode data when recevie data" ; 427 | } 428 | } else 429 | { 430 | return "start as -r or -m mode"; 431 | } 432 | 433 | } else 434 | { 435 | if(io_flag == FLG_NONE) 436 | { 437 | return "start as remote forward proxy"; 438 | } else if(io_flag == W_S_ENC) 439 | { 440 | return "start as forward proxy and do encode data when send data"; 441 | } 442 | } 443 | return "unknow"; 444 | 445 | 446 | } 447 | 448 | /* 处理客户端的连接 */ 449 | void handle_client(int client_sock, struct sockaddr_in client_addr) 450 | { 451 | int is_http_tunnel = 0; 452 | if(strlen(remote_host) == 0) /* 未指定远端主机名称从http 请求 HOST 字段中获取 */ 453 | { 454 | 455 | #ifdef DEBUG 456 | LOG(" ============ handle new client ============\n"); 457 | LOG(">>>Header:%s\n",header_buffer); 458 | #endif 459 | 460 | if(read_header(client_sock,header_buffer) < 0) 461 | { 462 | LOG("Read Http header failed\n"); 463 | return; 464 | } else 465 | { 466 | char * p = strstr(header_buffer,"CONNECT"); /* 判断是否是http 隧道请求 */ 467 | if(p) 468 | { 469 | LOG("receive CONNECT request\n"); 470 | is_http_tunnel = 1; 471 | } 472 | 473 | if(strstr(header_buffer,"GET /mproxy") >0 ) 474 | { 475 | LOG("====== hand mproxy info request ===="); 476 | //返回mproxy的运行基本信息 477 | hand_mproxy_info_req(client_sock,header_buffer); 478 | 479 | return; 480 | } 481 | 482 | if(extract_host(header_buffer) < 0) 483 | { 484 | LOG("Cannot extract host field,bad http protrotol"); 485 | return; 486 | } 487 | LOG("Host:%s port: %d io_flag:%d\n",remote_host,remote_port,io_flag); 488 | 489 | } 490 | } 491 | 492 | if ((remote_sock = create_connection()) < 0) { 493 | LOG("Cannot connect to host [%s:%d]\n",remote_host,remote_port); 494 | return; 495 | } 496 | 497 | if (fork() == 0) { // 创建子进程用于从客户端转发数据到远端socket接口 498 | 499 | if(strlen(header_buffer) > 0 && !is_http_tunnel) 500 | { 501 | forward_header(remote_sock); //普通的http请求先转发header 502 | } 503 | 504 | forward_data(client_sock, remote_sock); 505 | exit(0); 506 | } 507 | 508 | if (fork() == 0) { // 创建子进程用于转发从远端socket接口过来的数据到客户端 509 | 510 | if(io_flag == W_S_ENC) 511 | { 512 | io_flag = R_C_DEC; //发送请求给服务端进行编码,读取服务端的响应则进行解码 513 | } else if (io_flag == R_C_DEC) 514 | { 515 | io_flag = W_S_ENC; //接收客户端请求进行解码,那么响应客户端请求需要编码 516 | } 517 | 518 | if(is_http_tunnel) 519 | { 520 | send_tunnel_ok(client_sock); 521 | } 522 | 523 | forward_data(remote_sock, client_sock); 524 | exit(0); 525 | } 526 | 527 | close(remote_sock); 528 | close(client_sock); 529 | } 530 | 531 | void forward_header(int destination_sock) 532 | { 533 | rewrite_header(); 534 | #ifdef DEBUG 535 | LOG("================ The Forward HEAD ================="); 536 | LOG("%s\n",header_buffer); 537 | #endif 538 | 539 | int len = strlen(header_buffer); 540 | send_data(destination_sock,header_buffer,len) ; 541 | } 542 | 543 | int send_data(int socket,char * buffer,int len) 544 | { 545 | 546 | if(io_flag == W_S_ENC) 547 | { 548 | int i; 549 | for(i = 0; i < len ; i++) 550 | { 551 | buffer[i] ^= 1; 552 | 553 | } 554 | } 555 | 556 | return send(socket,buffer,len,0); 557 | } 558 | 559 | int receive_data(int socket, char * buffer, int len) 560 | { 561 | int n = recv(socket, buffer, len, 0); 562 | if(io_flag == R_C_DEC && n > 0) 563 | { 564 | int i; 565 | for(i = 0; i< n; i++ ) 566 | { 567 | buffer[i] ^= 1; 568 | // printf("%d => %d\n",c,buffer[i]); 569 | } 570 | } 571 | 572 | return n; 573 | } 574 | 575 | 576 | 577 | /* 代理中的完整URL转发前需改成 path 的形式 */ 578 | void rewrite_header() 579 | { 580 | char * p = strstr(header_buffer,"http://"); 581 | char * p0 = strchr(p,'\0'); 582 | char * p5 = strstr(header_buffer,"HTTP/"); /* "HTTP/" 是协议标识 如 "HTTP/1.1" */ 583 | int len = strlen(header_buffer); 584 | if(p) 585 | { 586 | char * p1 = strchr(p + 7,'/'); 587 | if(p1 && (p5 > p1)) 588 | { 589 | //转换url到 path 590 | memcpy(p,p1,(int)(p0 -p1)); 591 | int l = len - (p1 - p) ; 592 | header_buffer[l] = '\0'; 593 | 594 | 595 | } else 596 | { 597 | char * p2 = strchr(p,' '); //GET http://3g.sina.com.cn HTTP/1.1 598 | 599 | // printf("%s\n",p2); 600 | memcpy(p + 1,p2,(int)(p0-p2)); 601 | *p = '/'; //url 没有路径使用根 602 | int l = len - (p2 - p ) + 1; 603 | header_buffer[l] = '\0'; 604 | 605 | } 606 | } 607 | 608 | 609 | if(m_flag) 610 | { 611 | char * p6 = strstr(header_buffer,"Host:"); //...\r\nHost: miguvod.lovev.com:8080\r\nLbxx: tiny.cc\r\n.... 612 | char * p00 = strchr(p6,'\0'); // p6 p7 p8 p9 p00 613 | char * p7 = strchr(p6,' '); 614 | char * p8 = strstr(header_buffer,m_s); 615 | char * p9 = strchr(p8,' '); 616 | if(p6) 617 | { 618 | if(p8 && (p8 > p6)) 619 | { 620 | memcpy(p7,p9,(int)(p00 -p9)); //以Lbxx的值覆盖Host的值,这要求Lbxx在模式中要紧跟在Host后面(仅对http) 621 | int l = len - (p9 - p7) ; 622 | header_buffer[l] = '\0'; 623 | } 624 | } 625 | } 626 | } 627 | 628 | 629 | void forward_data(int source_sock, int destination_sock) { 630 | char buffer[BUF_SIZE]; 631 | int n; 632 | 633 | while ((n = receive_data(source_sock, buffer, BUF_SIZE)) > 0) 634 | { 635 | 636 | send_data(destination_sock, buffer, n); 637 | } 638 | 639 | shutdown(destination_sock, SHUT_RDWR); 640 | 641 | shutdown(source_sock, SHUT_RDWR); 642 | } 643 | 644 | 645 | 646 | int create_connection() { 647 | struct sockaddr_in server_addr; 648 | struct hostent *server; 649 | int sock; 650 | 651 | if ((sock = socket(AF_INET, SOCK_STREAM, 0)) < 0) { 652 | return CLIENT_SOCKET_ERROR; 653 | } 654 | 655 | if ((server = gethostbyname(remote_host)) == NULL) { 656 | errno = EFAULT; 657 | return CLIENT_RESOLVE_ERROR; 658 | } 659 | LOG("======= forward request to remote host:%s port:%d ======= \n",remote_host,remote_port); 660 | memset(&server_addr, 0, sizeof(server_addr)); 661 | server_addr.sin_family = AF_INET; 662 | memcpy(&server_addr.sin_addr.s_addr, server->h_addr, server->h_length); 663 | server_addr.sin_port = htons(remote_port); 664 | 665 | if (connect(sock, (struct sockaddr *) &server_addr, sizeof(server_addr)) < 0) { 666 | return CLIENT_CONNECT_ERROR; 667 | } 668 | 669 | return sock; 670 | } 671 | 672 | 673 | int create_server_socket(int port) { 674 | int server_sock, optval; 675 | struct sockaddr_in server_addr; 676 | 677 | if ((server_sock = socket(AF_INET, SOCK_STREAM, 0)) < 0) { 678 | return SERVER_SOCKET_ERROR; 679 | } 680 | 681 | if (setsockopt(server_sock, SOL_SOCKET, SO_REUSEADDR, &optval, sizeof(optval)) < 0) { 682 | return SERVER_SETSOCKOPT_ERROR; 683 | } 684 | 685 | memset(&server_addr, 0, sizeof(server_addr)); 686 | server_addr.sin_family = AF_INET; 687 | server_addr.sin_port = htons(port); 688 | server_addr.sin_addr.s_addr = INADDR_ANY; 689 | 690 | if (bind(server_sock, (struct sockaddr*)&server_addr, sizeof(server_addr)) != 0) { 691 | return SERVER_BIND_ERROR; 692 | } 693 | 694 | if (listen(server_sock, 20) < 0) { 695 | return SERVER_LISTEN_ERROR; 696 | } 697 | 698 | return server_sock; 699 | } 700 | 701 | /* 处理僵尸进程 */ 702 | void sigchld_handler(int signal) { 703 | while (waitpid(-1, NULL, WNOHANG) > 0); 704 | } 705 | 706 | void server_loop() { 707 | struct sockaddr_in client_addr; 708 | socklen_t addrlen = sizeof(client_addr); 709 | 710 | while (1) { 711 | client_sock = accept(server_sock, (struct sockaddr*)&client_addr, &addrlen); 712 | 713 | if (fork() == 0) { // 创建子进程处理客户端连接请求 714 | close(server_sock); 715 | handle_client(client_sock, client_addr); 716 | exit(0); 717 | } 718 | close(client_sock); 719 | } 720 | 721 | } 722 | 723 | void stop_server() 724 | { 725 | kill(m_pid, SIGKILL); 726 | } 727 | 728 | void usage(void) 729 | { 730 | printf("Usage:\n"); 731 | printf(" -l specifyed local listen port \n"); 732 | printf(" -h specifyed next hop server name to forward all trafic unhandled, prior to -m & -r\n"); 733 | printf(" -r specifyed server name to forward 'HTTP'&'CONNECT' to, no matter what host is\n"); 734 | printf(" -m specifyed key words replaced & recognized as 'Host:' function, prior to -r\n"); 735 | printf(" -d run as daemon\n"); 736 | printf(" -E encode data when forwarding data\n"); 737 | printf(" -D decode data when receiving data\n"); 738 | printf(" Notice:-h -r -m can not be used together.\n"); 739 | exit (8); 740 | } 741 | 742 | void start_server(int daemon) 743 | { 744 | //初始化全局变量 745 | header_buffer = (char *) malloc(MAX_HEADER_SIZE); 746 | 747 | signal(SIGCHLD, sigchld_handler); // 防止子进程变成僵尸进程 748 | 749 | if ((server_sock = create_server_socket(local_port)) < 0) 750 | { // start server 751 | LOG("Cannot run server on %d\n",local_port); 752 | exit(server_sock); 753 | } 754 | 755 | if(daemon) 756 | { 757 | pid_t pid; 758 | if((pid = fork()) == 0) 759 | { 760 | server_loop(); 761 | } else if (pid > 0 ) 762 | { 763 | m_pid = pid; 764 | LOG("mporxy pid is: [%d]\n",pid); 765 | close(server_sock); 766 | } else 767 | { 768 | LOG("Cannot daemonize\n"); 769 | exit(pid); 770 | } 771 | 772 | } else 773 | { 774 | server_loop(); 775 | } 776 | 777 | } 778 | 779 | int main(int argc, char *argv[]) 780 | { 781 | return _main(argc,argv); 782 | } 783 | 784 | int _main(int argc, char *argv[]) 785 | { 786 | local_port = DEFAULT_LOCAL_PORT; 787 | io_flag = FLG_NONE; 788 | r_flag = 0; 789 | m_flag = 0; 790 | //m_s = "DEFAULT_M_S"; 791 | int daemon = 0; 792 | 793 | char info_buf[2048]; 794 | 795 | int opt; 796 | char optstrs[] = ":l:h:r:m:dED"; 797 | char *p = NULL; 798 | while(-1 != (opt = getopt(argc, argv, optstrs))) 799 | { 800 | switch(opt) 801 | { 802 | case 'l': 803 | local_port = atoi(optarg); 804 | break; 805 | case 'h': 806 | p = strchr(optarg, ':'); 807 | if(p) 808 | { 809 | strncpy(remote_host, optarg, p - optarg); 810 | remote_port = atoi(p+1); 811 | } 812 | else 813 | { 814 | strncpy(remote_host, optarg, strlen(optarg)); 815 | remote_port = DEFAULT_REMOTE_PORT; 816 | } 817 | break; 818 | case 'r': 819 | p = strchr(optarg, ':'); 820 | if(p) 821 | { 822 | strncpy(r_h, optarg, p - optarg); 823 | r_p = atoi(p+1); 824 | } 825 | else 826 | { 827 | strncpy(r_h, optarg, strlen(optarg)); 828 | r_p = DEFAULT_R_P; 829 | } 830 | printf("Your forward server is: %s:%d\n",r_h,r_p); 831 | r_flag = 1; 832 | break; 833 | case 'm': 834 | strncpy(m_s, optarg, strlen(optarg)); 835 | printf("Your sting is: %s\n",m_s); 836 | m_flag = 1; 837 | break; 838 | case 'd': 839 | daemon = 1; 840 | break; 841 | case 'E': 842 | io_flag = W_S_ENC; 843 | break; 844 | case 'D': 845 | io_flag = R_C_DEC; 846 | break; 847 | case ':': 848 | printf("\nMissing argument after: -%c\n", optopt); 849 | usage(); 850 | case '?': 851 | printf("\nInvalid argument: %c\n", optopt); 852 | default: 853 | usage(); 854 | } 855 | } 856 | 857 | get_info(info_buf); 858 | LOG("%s\n",info_buf); 859 | start_server(daemon); 860 | return 0; 861 | 862 | } 863 | -------------------------------------------------------------------------------- /tiny.conf: -------------------------------------------------------------------------------- 1 | mode=wap; 2 | listen_port=65080; 3 | daemon=on; 4 | worker_proc=0; 5 | uid=3004; 6 | 7 | http_ip=[your VPS ip]; 8 | http_port=8080; 9 | http_del="Host,X-Online-Host"; 10 | http_first="[M] http://miguvod.lovev.com:8080 [V]\r\nHost: miguvod.lovev.com:8080\r\nLbxx: [H]\r\n"; 11 | 12 | https_connect=on; 13 | https_ip=[your VPS ip]; 14 | https_port=8080; 15 | https_del="Host,X-Online-Host"; 16 | https_first="GET http://miguvod.lovev.com:8080 [V]\r\n[M] miguvod.lovev.com:443 [V]\r\nHost: miguvod.lovev.com:443\r\nLbxx: [H]\r\n"; 17 | 18 | dns_tcp=http; 19 | dns_listen_port=65053; 20 | dns_url="119.29.29.29"; 21 | --------------------------------------------------------------------------------