SOCKS代理服务器

项目初衷:

时序图:

目录结构:

代码:

protocol.h

//定义了需要协商的四个协议

#pragma once
#pragma pack(1)
 
struct startReq//请求
{
    char ver;//5
    char n_methods;//方法数量
};
                                                                                                                                      
struct startRep//回复
{
    char ver;//5
    char method;
};
 
// VER    CMD    RSV    ATYP    DST.ADDR    DST.PROT 
//  1      1    X’00’    1      Variable       2
struct addrReq
{   
    char ver;
    char cmd;//CONNECT:X’01‘    BIND:X’02’   UDP ASSOCIATE:X’03’
    char rsv;//保留
    char atyp;//后面的地址类型
};  
    
// VER   REP   RSV   ATYP   BND.ADDR   BND.PORT 
//  1     1   X’00’   1     Variable     2 
struct addrRep
{   
    char ver;
    char rep;                                                                                                                         
    char rsv;
    char atpy;
};

comm.h

服务器端和客户端共同使用的函数,客户端暂未实现

#pragma once
 
#include <iostream>
#include <sys/types.h>
#include <sys/socket.h>
#include <pthread.h>
#include <string.h>
#include <errno.h>
#include <stdio.h>
 
#define SIZE 1024
 
int recv_data(int sock,void* buf,size_t size);
int send_data(int sock,void* buf,size_t size);

comm.cpp

#include "comm.h"
using namespace std;                                                                                                                  
 
int recv_data(int sock,void* buf,size_t len)
{
    char* data_buf=(char*)buf;
    int ret=0;
    int size=len;
    int left=size;
    while(left){
        ret=recv(sock,data_buf+size-left,left,0);
        if(ret<=0){
            return -1; 
        }
        left-=ret;
    }   
    return 0;
}
 
int send_data(int sock,void* buf,size_t len)
{
    char* data_buf=(char*)buf;
    int ret=0;
    int size=len;
     int left=size;
    while(left){
        int ret=0;
        ret=send(sock,(char*)buf+size-left,left,0);
        if(ret<=0){
            return -1;
        }
        left-=ret;
    }
    data_buf[size-left]=‘\0‘;
    return 0;
}

server.cpp

#include <iostream>
#include <sys/types.h>          
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <pthread.h>
#include <sys/wait.h>
#include <netdb.h>
#include <stdlib.h>
#include "protocol.h"                                                                                                                 
#include "comm.h"
#include <assert.h>
 
extern int h_errno;
 
using namespace std;
 
struct ThreadInfo
{
    int in; 
    int out;
    pthread_t id; 
};

void proc_handler(int sock);
void* thre_handler(void* argc);
    
int main(int argc,char* argv[])
{   
    if(argc!=2){
        cout<<"Usage:[proc] [port] "<<endl;
        return -1;
    }
    
    int listen_sock=socket(AF_INET,SOCK_STREAM,0);
    if(listen_sock<0){
        perror("socket");
    }
    sockaddr_in local;                                                                                                                
    local.sin_family=AF_INET;
    local.sin_addr.s_addr=INADDR_ANY;
    //local.sin_addr.s_addr=inet_addr(argv[1]);
    local.sin_port=ntohs(atoi(argv[1]));
    socklen_t len=sizeof(local);
    if(0!=bind(listen_sock,(sockaddr*)&local,len)){
        perror("bind");
        return -1;
    }
    if(0!=listen(listen_sock,5)){
        perror("listen");
        return -1;
    }
    int done=0;
    while(!done){
        sockaddr_in cli_addr;
        socklen_t len;
        int sock=accept(listen_sock,(sockaddr*)&cli_addr,&len);                                                                       
        cout<<"connection new sock:"<<inet_ntoa(cli_addr.sin_addr)<<endl;
    
        pid_t pid1=fork();
        if(pid1<0){
            perror("fork");
            return -1;
        }else if(pid1>0){
            waitpid(pid1,NULL,0);
        }else{
            pid_t pid2=fork();
            if(pid2<0){
                perror("fork");
                return -1;
            }else if(pid2>0){
                return 0;
            }else{
                proc_handler(sock);                                                                                                   
                //close(sock);
                return 0;
            }
        }
    }
    return 0;
}

void proc_handler(int in)//in是和客户端通信的socket
{   
    cout<<"proc_handler start..."<<endl;
    //VER     NMETHODS     METHODS 
    // 1          1       1 to 255 
    startReq req;
    if(0!=recv_data(in,&req,sizeof(req))){
        cout<<"recv error in protocol!"<<endl;
        return;
    }   
    if(req.ver!=5 || req.n_methods<1){
        cout<<"recv error in protocol!"<<endl;
        return;
    }
    
    //选择methods,八位组0-255                                                                                                         
    startRep rep;
    // VER    METHOD 
    //  1       1 
    char methods[256];
    if(req.n_methods==1){
        if(0!=recv_data(in,methods,1)){
            cout<<"recv error in protocol!"<<endl;
            return;
        }
        if(methods[0]==0xFF){//FF没有可接受的方法
            return;
        }
        else if(methods[0]==0x00){//不需要认证
            rep.ver=5;
            rep.method=0;
            if(0!=send_data(in,&rep,sizeof(rep))){
                cout<<"send error in protocol!"<<endl;
                return;
            }                                                                                                                         
        }else{
        }
    }else{//选择methods
    }
    
    //接受目标server addr
    // VER    CMD    RSV    ATYP    DST.ADDR    DST.PROT 
    //  1      1     X’00’   1      Variable      2
    addrReq reqaddr;
    if(0!=recv_data(in,&reqaddr,sizeof(reqaddr))){
        cout<<"recv error in dstaddr!"<<endl;
        return;
    }   
    if(reqaddr.ver!=5 ||reqaddr.rsv!=0){
        cout<<"recv error in dstaddr!"<<endl;
        return;
    }
    
    sockaddr_in remote;
    remote.sin_family=AF_INET;                                                                                                        
    
    if(reqaddr.atyp==1){//ipv4
        cout<<"accept dst_addr ipv4"<<endl;
        in_addr_t dstip;
        if(0!=recv_data(in,&remote.sin_addr.s_addr,4)){
            cout<<"recv error in dstaddr!"<<endl;
            return;
        }
    }else if(reqaddr.atyp==3){//域名
        cout<<"accept dst_addr domain"<<endl;
        char domain[SIZE];
        if(0!=recv_data(in,&domain,sizeof(domain))){
            cout<<"recv error in dstaddr!"<<endl;
            return;
        }
        cout<<"connect to domain: "<<domain<<endl;
        struct hostent* ht;
        if((ht=gethostbyname(domain))==NULL){
            herror("gethostbyname"); 
            return;
        }                                                                                                                             
        memcpy(&remote.sin_addr.s_addr,ht->h_addr_list[0],sizeof(remote.sin_addr.s_addr));//web服务端可能有多个ip,选择一个
    }else{//ipv6 or error
        return;
    }
    
    //获取目的port
    if(0!=recv_data(in,&remote.sin_port,2)){
        cout<<"recv error in dstport!"<<endl;
        return;
    }
   
    cout<<"web ip: "<<inet_ntoa(remote.sin_addr)<<" web port: "<<ntohs(remote.sin_port)<<endl;
   
    //至此获得客户端想要连接服务器的ip,port
    // VER   REP   RSV   ATYP   BND.ADDR   BND.PORT 
    //  1     1   X’00’   1     Variable    2 
    addrRep repaddr;
    repaddr.ver=5;
    repaddr.rsv=0;//标识为RSV 的字段必须设为X’00’ 
                                                                                                                                      
    int out=socket(AF_INET,SOCK_STREAM,0);
    socklen_t rlen=sizeof(remote);
    if(0!=connect(out,(sockaddr*)&remote,rlen)){
        perror("connect");
        repaddr.rep=3;//网络不可达 
        if(0!=send_data(in,&repaddr,sizeof(repaddr))){
            cout<<"error in connect remote!"<<endl;
            return;
        }
    }
    cout<<"connect success!"<<endl;
   
    repaddr.rep=0;//成功
    repaddr.atpy=1;//ipv4
    if(0!=send_data(in,&repaddr,sizeof(repaddr))){
        cout<<"send error to client!"<<endl;
        return;
    }
                                                                                                                                      
    struct sockaddr_in local;
    socklen_t locallen=sizeof(local);
    if(0!=getsockname(out,(sockaddr*)&local,&locallen)){
        perror("getsockname");
        return;
    }
    
    cout<<"ip: "<<inet_ntoa(local.sin_addr)<<" port: "<<ntohs(local.sin_port)<<endl;
    
    //sleep(5);
    int len=sizeof(local.sin_addr)+sizeof(local.sin_port);
    if(0!=send_data(in,&local,len)){
        cout<<"send error to client!"<<endl;
        return;
    }
    cout<<"协商完成"<<endl;
    ///////////////////////////////////////////////////////////////////
    //至此,完成了协商过程,
    
    //以下为正式处理HTTP请求
    pthread_t th1,th2;
    
    ThreadInfo thInfo1={in,out,th2};                                                                                                  
    ThreadInfo thInfo2={out,in,th1};
    
    pthread_create(&th1,NULL,thre_handler,&thInfo1);
    pthread_create(&th2,NULL,thre_handler,&thInfo2);   
}   
    
void* thre_handler(void* argc)
{   
    ThreadInfo* info=(ThreadInfo*)argc;
    int in=info->in;
    int out=info->out;
    pthread_t id=info->id;
    char buf[SIZE*SIZE];
    while(1){
        int ret=0;                                                                                                                    
        ret=recv(in,buf,sizeof(buf),0);
        if(ret<=0){
            perror("recv");
        }
        ret=send(out,buf,ret,0);
    }
    close(in);
    close(out);
    pthread_cancel(id);                                                                                                               
    return NULL;
}

Makefile

.PHONY:all
all:server
                                                                                                                                      
server:server.cpp comm.cpp
    g++ -o [email protected] $^ -lpthread
 
.PHONY:clean
clean:
    rm -f server
时间: 2024-08-30 02:43:28

SOCKS代理服务器的相关文章

Linux VPS上使用kingate搭建socks代理服务器

kingate 是一位国人开发的代理服务器 ,支持http,socks,ftp等多种协议.支持多线程.tcp端口映射.规则控制.时间控制.用户认证.http管理等功能. kingate官网:http://sourceforge.net/projects/kingate/ 安装所需的依赖包 Debian: apt-get install build-essential automake make gcc g++CentOS: yum install make automake gcc gcc-c+

BadVPN详解之--始记:透明socks代理与tun2socks

上周六晚上闲来无事跟以前的同事聊天,问之最近有没有接触到什么比较好玩的技术,答曰tun2socks.这个正合我的胃口,我所谓的好玩的技术是那种简单,有用的技术点或者技术框架,能在10分钟内领略其原理和思想,能在20分钟内跑起来,能在半天内彻底剖析它的结构,能在此后很久的时间受益无穷.OpenVPN就是这样的"好玩"的东西,网卡点灯也算,tun2socks是另一个,当然还有一个更好玩的,那就是BadVPN,我要在另外的文章中单独介绍.本文先来介绍tun2socks,它其实是BadVPN的

socks代理

之前的一篇文章,介绍代理服务器  http://lingdandan.blog.51cto.com/10697032/1773489 SOCKS是一种网络传输协议(位于会话层),主要用于客户端与外网服务器之间通讯的中间传递. 当防火墙后的客户端要访问外部的服务器时,就跟SOCKS代理服务器连接.这个代理服务器控制客户端访问外网的资格,允许的话,就将客户端的请求发往外部的服务器. Socks不要求应用程序遵循特定的操作系统平台,Socks 代理与应用层代理. HTTP 层代理不同,Socks代理只

chrome代理服务器设置

在百度的内网很难访问chrome的相关站点,如果安装一些chrome的插件很不方便,所以呢,研究了一下chrome浏览器的代理模式,翻墙安装插件. Chrome设置代理服务器的方法大体有几种: 1. 设置IE的代理服务器设置,即本机的,Chrome也会起作用. 在chrome的设置里点击高级设置,在网络一项中点击"更改代理服务器设置" 如图所示连接选项勾选"局域网设置",确定之后,做如下的配置即可. 2.Google Chrome浏览器唯一让人不爽的一点就是Wind

java编程,通过代理服务器访问外网的FTP

有些时候我们的网络不能直接连接到外网, 需要使用http或是https或是socket代理来连接到外网, 这里是java使用代理连接到外网的一些方法, 希望对你的程序有用.方法一:使用系统属性来完成代理设置, 这种方法比较简单, 但是不能对单独的连接来设置代理: /** *@paramargs */ /** *@paramargs */ public static void main(String[] args) { Properties prop = System.getProperties(

SOCKS

1 https://zh.wikipedia.org/wiki/SOCKS SOCKS是一种网络传输协议,主要用于客户端与外网服务器之间通讯的中间传递.SOCKS是"SOCKetS"的缩写[1]. 当防火墙后的客户端要访问外部的服务器时,就跟SOCKS代理服务器连接.这个代理服务器控制客户端访问外网的资格,允许的话,就将客户端的请求发往外部的服务器. 这个协议最初由David Koblas开发,而后由NEC的Ying-Da Lee将其扩展到版本4.最新协议是版本5,与前一版本相比,增加

代理服务器和网络地址转换NAT

一.代理服务器 1.代理服务器的基本概念 代理服务器是网络信息的中转站,简单来说就是个人网络和因特网服务商之间的代理机构,它负责转发合法的网络信息,并对转发进行控制和登记. 在使用网络浏览器浏览网络信息的时候,如果使用代理服务器,浏览器就不是直接到web服务器中取回网页,而是向代理服务器发出请求,由代理服务器取回浏览器所需要的信息. 目前使用的因特网是一个典型的客户机/服务器结构,当用户的本地机与因特网连接时通过本地机的客户程序如浏览器或者软件下载工具发出请求,远端的服务器会在接收到请求之后提供

如何使用代理服务器上网

前几天,有两个同事咨询过我,如何使用代理上网,我发现其过程还是挺多的,与其我一步步讲给他们听,不如写一个教程,这样他们也更能理解和操作.下面我就介绍一下我是怎么使用代理服务器的,算是一篇科普教程吧. 什么是代理服务器   代理服务器(Proxy Server)是网上提供转接功能的服务器,在一般情况下,我们使用网络浏览器直接去连接其他Internet站点取得网络信息时,是直接联系到目的站点 服务器,然后由目的站点服务器把信息传送回来.代理服务器是介于客户端和Web服务器之间的另一台服务器,有了它之

代理服务器基本知识普及代理IP使用方法!

本文并未从专业角度进行详细讲解,而是从应用的角度出发来普及一些代理服务器的基本知识.文章明显是搜集多方资料的拼凑,而且比较老了,但往往越老的东西越接近事物的本质,更容易窥探到原理,对于刚接触的人来说,看起来比专业理论资料更易懂哈~ 扫盲篇:  什么是代理服务器?  代理服务器是介于浏览器和Web服务器之间的一台服务器,当你通过代理服务器上网浏览时,浏览器不是直接到Web服务器去取回网页,而是向代理服务器发出请求,由代理服务器来取回浏览器所需要的信息,并传送给你的浏览器. 什么是免费代理服务器 ?