2020.9.11
网上看的都比较复杂,GITHUB找了一个多线程的相对简单的MicroSocks项目,花了几周时间(没办法,菜鸟一个)改了一下,改成单文件,测试OK。
/* wxl_socks5_proxy_server_v1.0
linux下最简单多线程单文件socks5代理proxy服务器程序(仅一个c文件,带详细注解)
wxleasyland@sina.com
2020.9
说明:
编译方法:gcc xxxx.c -pthread -o xxxx
一个线程对应一个客户端。
只支持TCP CONNECT方式和无用户验证。
*/
/* 感谢原作者。
程序主要在github开源项目MicroSocks基础上修改得到的:
https://github.com/rofl0r/microsocks
也少量参考了github开源项目HevSocks5Server:
https://github.com/heiher/hev-socks5-server
*/
/*
firefox可以选socks4还是socks5。
chrome 设置代理是在IE。 然后打开网页失败,抓包发现chrome是走SOCKS4版本。
在IE的“代理服务器设置”的“套接字”中,写成socks5://xxx.xxx.xxx.xxx就可以了,
chrome就会走SOCKS5版本了。 如果写成socks4://xxx.xxx.xxx.xxx,就又会走SOCKS4版本了。
firefox一下打开好几个网页窗口,大约线程数是接近200个,突发起来还是挺猛的。
chrome一下打开好几个网页窗口,大约线程数是50个,看来对socket的数量控制得比较好。
取单个线程堆栈为64K,占用内存不大,自己用用可以。
*/
#include <unistd.h>
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
#include <pthread.h>
#include <signal.h>
#include <sys/select.h>
#include <arpa/inet.h>
#include <errno.h>
#include <limits.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netdb.h>
#include <netinet/in.h>
#include <stddef.h>
union sockaddr_union
{
struct sockaddr_in v4;
struct sockaddr_in6 v6;
};
// static pthread_mutex_t auth_ips_mutex = PTHREAD_MUTEX_INITIALIZER; //静态初始化互斥锁(暂未用到)
int g_totalthread=0; //总线程数量统计
int g_proxymode=0; //1表示正常CONNECT类型 4表示我自定义的DNS获取IP地址
int my_resolve(const char *host, unsigned short port, struct addrinfo** addr) //主要是getaddrinfo()得到远程主机的IP
{
struct addrinfo hints =
{
.ai_family = AF_UNSPEC, // AF_INET是IPV4 //AF_INET6是IPV6
.ai_socktype = SOCK_STREAM,
.ai_flags = AI_PASSIVE,
};
char port_buf[8];
snprintf(port_buf, sizeof port_buf, "%u", port);
return getaddrinfo(host, port_buf, &hints, addr);
//getaddrinfo函数用域名或主机名获取IP地址,返回的是一个sockaddr结构的链表。
//int getaddrinfo( const char *hostname, const char *service, const struct addrinfo *hints, struct addrinfo **result );
//返回值:0——成功,非0——出错
}
//ssize_t recv(int sockfd, void *buf, size_t len, int flags);
//return the number of bytes received, or -1 if an error occurred.
//When a stream socket peer has performed an orderly shutdown, the return value will be 0
ssize_t my_recv_all (int fd, void *buf, size_t len) //引用自HevSocks5Server项目
{
ssize_t s;
size_t size = 0;
if(len<=0) return len;
retry:
s = recv (fd, buf + size, len - size, MSG_WAITALL);
if (s < 0) //阻塞下出错
{
return s;
}
if (s == 0) //对方中止连接
return -1;
size += s;
if (size < len)
goto retry;
return size;
}
void send_error1(int fd, unsigned char d) //返回错误信息给客户
{
unsigned char buf[2];
buf[0] = 5;
buf[1] = d;
write(fd, buf, 2); //不用做发送错误检查了
}
void send_error2(int fd, unsigned char d) //返回错误信息给客户
{
/* position 4 contains ATYP, the address type, which is the same as used in the connect
request. we're lazy and return always IPV4 address type in errors. */
char buf[10] = { 5, d, 0, 1 /*AT_IPV4*/, 0,0,0,0, 0,0 };
write(fd, buf, 10); //不用做发送错误检查了
}
void mycopyloop(int fd1, int fd2) // 用select()做转发数据,fd1与fd2无所谓哪个是源哪个是目标
{
int maxfd = fd2;
if(fd1 > fd2) maxfd = fd1;
fd_set fdsc, fds;
FD_ZERO(&fdsc); //清空集合
FD_SET(fd1, &fdsc); //添加文件描述符
FD_SET(fd2, &fdsc); //添加文件描述符
while(1)
{
memcpy(&fds, &fdsc, sizeof(fds)); //每次循环都要重新设置集合,否则不能检测文件描述符变化
/* inactive connections are reaped after 15 min to free resources.
usually programs send keep-alive packets so this should only happen
when a connection is really unused. */
struct timeval timeout = {.tv_sec = 60*15, .tv_usec = 0}; //select函数会不断修改timeout的值,所以每次循环都应该重新赋值
switch(sele

最低0.47元/天 解锁文章
1万+

被折叠的 条评论
为什么被折叠?



