码迷,mamicode.com
首页 > 其他好文 > 详细

SOCKS代理服务器

时间:2016-08-16 14:54:05      阅读:931      评论:0      收藏:0      [点我收藏+]

标签: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 $@ $^ -lpthread
 
.PHONY:clean
clean:
    rm -f server


本文出自 “零蛋蛋” 博客,谢绝转载!

SOCKS代理服务器

标签:socks代理服务器

原文地址:http://lingdandan.blog.51cto.com/10697032/1839184

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!