| 您的位置:首页 > 文档 > 解决方案 > |
文章分类热门文章 |
一个简易的UDP Proxy程序创建:2005-11-07 00:00:00 作者:Unlinux 来自: http://www.Unlinux.com 一个简易的UDP Proxy程序 作为<<一个简易的proxy程序的开发过程>>的补充 1、为什么开发这个UDP程序 网络状况如上文<<一个简易的proxy程序的开发过程>>。我们的socks代理是有权限的(相信很多公司 都有这种情况存在)。写这个程序的时候,我还没有socks代理的权限,所以不能上OICQ。这让我感到 很不方便。所以,我决定写一个UDP的代理程序来实现我上OICQ的愿望。原理同上文是一样的。只是在 具体实现上略有所不同。 先看看源代码,稍后再来解释。(由于这个版本是一个完全功能版,所以提供了很多sp.c没有提供的功 能。)上文中提到过的部分,这里就不再次一一解释了。 ----------------------------------------------------------------------------------------- /*************************************************** Program: pu.c Description: a smart UDP proxy Author: Alan Chen ( ariesram@may10.ca ) Date: Dec 1, 2000 ***************************************************/ #include #include #include #include #include #include #include #include #define MAX_ID_LEN 12 #define LOGFILE "/usr/tmp/.pu.log" #define ERRLOG "/usr/tmp/.pu.err" void sig_int(int sig); void do_receive(int fd_tran); void p_error(const char * err_msg); void p_log(const char * buffer, int len); int main(int argc, char ** argv) { int fd_listen, fd_tran; struct sockaddr_in sin, out; struct sockaddr_in r_in, r_out; struct sockaddr_in stmp; int port = 1250; int pid; char * ip; int i; fd_set fdset; char buffer[2048*2]; int data_len, alen; struct timeval val; #ifndef _DEBUG signal(SIGINT, SIG_IGN); #endif signal(SIGHUP, SIG_IGN); /* signal(SIGTERM, SIG_IGN); */ signal(SIGABRT, SIG_IGN); signal(SIGSTOP, SIG_IGN); signal(SIGCHLD, SIG_IGN); #ifndef _DEBUG if (fork() != 0) exit(0); setsid(); for (i = 256; i >= 0; i --) #endif #ifdef _DEBUG for (i = 256; i >= 3; i --) #endif close(i); chdir("/usr/tmp"); bzero(&sin, sizeof(sin)); sin.sin_family = AF_INET; sin.sin_port = htons(8000); sin.sin_addr.s_addr = INADDR_ANY; bzero(&out, sizeof(out)); out.sin_family = AF_INET; /* out.sin_port = htons(5000); */ out.sin_port = htons(4000); out.sin_addr.s_addr = INADDR_ANY; /* remote server */ bzero(&r_out, sizeof(r_out)); r_out.sin_family = AF_INET; r_out.sin_port = htons(8000); r_out.sin_addr.s_addr = inet_addr("202.96.170.164"); /* remote client */ bzero(&r_in, sizeof(r_in)); r_in.sin_family = AF_INET; r_in.sin_port = htons(4000); r_in.sin_addr.s_addr = inet_addr("192.168.103.97"); fd_listen = socket(PF_INET, SOCK_DGRAM, 0); if (fd_listen < 0) { p_error("socket1 error"); exit(1); } fd_tran = socket(PF_INET, SOCK_DGRAM, 0); if (fd_tran < 0) { p_error("socket2 error"); exit(1); } if (bind(fd_listen, (struct sockaddr *)&sin, sizeof(sin)) < 0) { p_error("bind error1: "); exit(1); } if (bind(fd_tran, (struct sockaddr *)&out, sizeof(out)) < 0) { p_error("bind error2: "); exit(1); } fcntl(fd_listen, F_SETFL, O_NONBLOCK); fcntl(fd_tran, F_SETFL, O_NONBLOCK); while (1) { FD_ZERO(&fdset); FD_SET(fd_tran, &fdset); FD_SET(fd_listen, &fdset); val.tv_sec = 1; val.tv_usec = 0; if (select(fd_tran + 1, &fdset, NULL, NULL, &val) < 0) { p_error("select error: "); continue; } if (FD_ISSET(fd_listen, &fdset)) { alen = sizeof(r_in); data_len = recvfrom (fd_listen, buffer, sizeof(buffer), 0, (struct sockaddr *)&r_in, &alen); if (data_len <= 0) { p_error("socket closed by remote client"); close(fd_listen); close(fd_tran); exit(0); } #ifdef _DEBUG ip = inet_ntoa(r_in.sin_addr.s_addr); printf("received from %s , socket id: %d ", ip, fd_listen); p_log(" received from inner: ", 23); /* sizeof(" received from inner: "); */ p_log(buffer, data_len); #endif if (sendto(fd_tran, (char *)buffer, data_len, 0, (struct sockaddr *)&r_out, sizeof(r_out)) <=0 ) { p_error("cann't send to remote server"); close(fd_tran); close(fd_listen); exit(0); } #ifdef _DEBUG ip = inet_ntoa(r_out.sin_addr.s_addr); printf("send to %s ", ip); #endif } else if (FD_ISSET(fd_tran, &fdset)) { alen = sizeof(stmp); data_len = recvfrom (fd_tran, buffer, sizeof(buffer), 0, (struct sockaddr *)&stmp, &alen); if (data_len <= 0) { p_error("socket closed by remote server"); close(fd_listen); close(fd_tran); exit(0); } #ifdef _DEBUG ip = inet_ntoa(stmp.sin_addr.s_addr); printf("received from %s , socket id: %d ", ip, fd_tran); p_log(" received from outer: ", 23); /* sizeof(" received from outer: "); */ p_log(buffer, data_len); #endif if (sendto(fd_listen, (char *)buffer, data_len, 0, (struct sockaddr *)&r_in, sizeof(r_in)) <=0 ) { p_error("cann't send to remote server"); close(fd_tran); close(fd_listen); exit(0); } #ifdef _DEBUG ip = inet_ntoa(r_in.sin_addr.s_addr); printf("send to %s ", ip); #endif } } return 0; } void sig_int(int sig) { signal(SIGINT, sig_int); exit(1); } void p_error(const char * err_msg) { FILE * fp; #ifdef _DEBUG printf("%s ", err_msg); #endif fp = fopen(ERRLOG, "a"); if (fp == NULL) return; fprintf(fp, "%s ", err_msg); fclose(fp); } void p_log(const char * buffer, int len) { FILE * fp; fp = fopen(LOGFILE, "ab"); if (fp == NULL) return; fwrite(buffer, len, 1, fp); fclose(fp); } ----------------------------------------------------------------------------------------- 编译,运行是同上文所述相同的。 但是,要注意UDP是没有连接的,所以程序的具体实现方式有所不同。 来看程序。 #ifndef _DEBUG signal(SIGINT, SIG_IGN); #endif signal(SIGHUP, SIG_IGN); /* signal(SIGTERM, SIG_IGN); */ signal(SIGABRT, SIG_IGN); signal(SIGSTOP, SIG_IGN); signal(SIGCHLD, SIG_IGN); 忽略上述信号,使程序以后台方式运行。 #ifndef _DEBUG if (fork() != 0) exit(0); setsid(); for (i = 256; i >= 0; i --) #endif 如果不是DEBUG方式,程序以前台方式运行。 #ifdef _DEBUG for (i = 256; i >= 3; i --) #endif close(i); 关闭描述字。 bzero(&r_in, sizeof(r_in)); r_in.sin_family = AF_INET; r_in.sin_port = htons(4000); r_in.sin_addr.s_addr = inet_addr("192.168.103.97"); 192.168.103.97 是我机器的局域网IP地址。由于这个程序只是给我一个人使用的,所以没有在这上面处理 得更灵活一些。:-) fd_listen = socket(PF_INET, SOCK_DGRAM, 0); if (fd_listen < 0) { p_error("socket1 error"); exit(1); } UDP的socket描述字是这样子建立的。 fcntl(fd_listen, F_SETFL, O_NONBLOCK); fcntl(fd_tran, F_SETFL, O_NONBLOCK); 将这两个监听端口的socket方式设置为非阻塞的。 if (FD_ISSET(fd_listen, &fdset)) { alen = sizeof(r_in); data_len = recvfrom (fd_listen, buffer, sizeof(buffer), 0, (struct sockaddr *)&r_in, &alen); if (data_len <= 0) { p_error("socket closed by remote client"); close(fd_listen); close(fd_tran); exit(0); } #ifdef _DEBUG ip = inet_ntoa(r_in.sin_addr.s_addr); printf("received from %s , socket id: %d ", ip, fd_listen); p_log(" received from inner: ", 23); /* sizeof(" received from inner: "); */ p_log(buffer, data_len); #endif if (sendto(fd_tran, (char *)buffer, data_len, 0, (struct sockaddr *)&r_out, sizeof(r_out)) <=0 ) { p_error("cann't send to remote server"); close(fd_tran); close(fd_listen); exit(0); } #ifdef _DEBUG ip = inet_ntoa(r_out.sin_addr.s_addr); printf("send to %s ", ip); #endif } 对于UDP来说,用的是recvfrom和sendto. 在程序中同时加入了recvfrom时的客户端地址,便于在调试的 时候来检查。同时,这里面也有一些调试的信息,比如,输出接收到的字符串,客户端地址等等。 else if (FD_ISSET(fd_tran, &fdset)) { alen = sizeof(stmp); data_len = recvfrom (fd_tran, buffer, sizeof(buffer), 0, (struct sockaddr *)&stmp, &alen); if (data_len <= 0) { p_error("socket closed by remote server"); close(fd_listen); close(fd_tran); exit(0); } #ifdef _DEBUG ip = inet_ntoa(stmp.sin_addr.s_addr); printf("received from %s , socket id: %d ", ip, fd_tran); p_log(" received from outer: ", 23); /* sizeof(" received from outer: "); */ p_log(buffer, data_len); #endif if (sendto(fd_listen, (char *)buffer, data_len, 0, (struct sockaddr *)&r_in, sizeof(r_in)) <=0 ) { p_error("cann't send to remote server"); close(fd_tran); close(fd_listen); exit(0); } #ifdef _DEBUG ip = inet_ntoa(r_in.sin_addr.s_addr); printf("send to %s ", ip); #endif } 这一段是一样的。所不同的是,从fd_tran中读出来写回到fd_listen中去。 两个日志函数的说明。 void p_error(const char * err_msg) { FILE * fp; #ifdef _DEBUG printf("%s ", err_msg); #endif fp = fopen(ERRLOG, "a"); if (fp == NULL) return; fprintf(fp, "%s ", err_msg); fclose(fp); } 调试的时候,将错误信息输出到标准输出上。 非调试状态的时候,将错误信息输出到/usr/tmp/下的一个隐藏文件中。 void p_log(const char * buffer, int len) { FILE * fp; fp = fopen(LOGFILE, "ab"); if (fp == NULL) return; fwrite(buffer, len, 1, fp); fclose(fp); } 不论调试还是非调试状态,都把日志写到日志文件中。 由于我所使用的代理服务器不是我所管辖,所以我把日志文件写到了/usr/tmp下,这是一个相对来说比较隐蔽 的位置而且我也有权限。呵呵。:-). 正常使用时,可以把日志写到你的特定目录下。这只要修改 #define LOGFILE "/usr/tmp/.pu.log" #define ERRLOG "/usr/tmp/.pu.err" 就行了。 进一步的改进: 为了让这个程序更加有通用性,可以修改一下,让他在命令行中能够设置服务端口号,远程服务器的 IP地址和端口号,能够设置日志文件的路径。 有什么问题,建议,可以通过email和我联系。 这个源代码是基于GNU的,如果你对这个源代码有所改动,也可以email给我。:-) 转载自:http://www.unlinux.com/doc/solution/20051107/8959.html 【评论】 【加入收藏夹】 【大 中 小】 【打印】 【关闭】 ※ 相关链接
|