• <ins id="pjuwb"></ins>
    <blockquote id="pjuwb"><pre id="pjuwb"></pre></blockquote>
    <noscript id="pjuwb"></noscript>
          <sup id="pjuwb"><pre id="pjuwb"></pre></sup>
            <dd id="pjuwb"></dd>
            <abbr id="pjuwb"></abbr>

            S.l.e!ep.¢%

            像打了激速一樣,以四倍的速度運轉,開心的工作
            簡單、開放、平等的公司文化;尊重個性、自由與個人價值;
            posts - 1098, comments - 335, trackbacks - 0, articles - 1
              C++博客 :: 首頁 :: 新隨筆 :: 聯系 :: 聚合  :: 管理

            實現Sock5代理(轉)

            Posted on 2009-01-04 22:47 S.l.e!ep.¢% 閱讀(3983) 評論(0)  編輯 收藏 引用
            有很多公司不能直接和Internet相連,必須通過代理和www連接,瀏覽、下載資料。
            代理服務器支持的協議也有所不同,有支持Sock、HTTP代理的這樣我們做的客戶端軟件就需要支持這些代理,使用戶能夠通過這些代理透過防火墻和外網相連,一般Sock分為Sock4和Sock5,這里我們只實現Sock5協議。
            RFC1928描述了Socks協議的細節,告訴我們客戶程序如何同Socks代理協商,取得透過該協議對外傳輸的途徑。英文的URL為:http://www.ietf.org/rfc/rfc1928.txt,建議先了解以上鏈接內容后在閱讀下文。另外給大家推薦學習協議的好地方:http://www.cnpaf.com中國協議分析網,有很多好東東,可以去看看。
            下面說明一下實現的方法。
            代理的實現方法實際就是Socket編程,只要通訊時遵循它們的協議就可以。首先理解它們的協議是關鍵。
            示意圖:

            1.1??? Sock5協議實現

            1.1.1??????? Sock5協議內容

            1.? 客戶端首先要與代理服務器連接,連接后要向代理發送版本號、認證方法、方法選擇格式如下:
            版本號(1字節) |? 供選擇的認證方法(1字節) ?|? 方法序列(1-255個字節長度)
            如果你支持的版本為SOCK5那么版本號就為0x05;可供選擇的方法是指你的協議支持幾種認證方式,因為我們實現只支持一種所以就填0x01,如果你是兩種就寫0x02;認證方法序列包括(0x00為不需認證、0x02為需要用戶名和密碼認證,通常是這兩種,如果想了解更多請參看Rfc1928)。
            這樣組合你的報文應該為:0x05 0x01 0x00
            如果需要認證那么為:0x05 0x01 0x02
            2.? 代理接收到客戶端的請求,會向客戶端返回信息,格式為:
            版本號 | 服務器選定的方法
            如果服務器支持驗證方式,返回的報文為:
            0x05 0x02
            3.? 接下來根據服務器的驗證方式,發送驗證信息了,報文格式為:
            0x01 | 用戶名長度(1字節)| 用戶名(長度根據用戶名長度域指定) | 口令長度(1字節) | 口令(長度由口令長度域指定)
            4.? 服務器接收信息后進行驗證,返回如下格式:
            0x01 | 驗證結果標志
            驗證結果標志:0x00表示驗證成功,其他值均為錯誤碼

            1.1.2??????? Sock5協議實現

            根據上面所述的步驟和協議內容,就可以實現SOCK5代理了。下面我給出我寫的實現SOCKT5代理的函數代碼和注釋,供參考(delphi6+win2K+sp4調試通過,代理服務器用的是CCProxy6.0)
            function?TBZSock5ProxyApi.SetProxy(ASocket:?Pointer):?Integer;
            var
            ??proxyUser,?proxyPwd:?String;
            ??bIsValid:?Boolean;
            ??sock:?
            ^ TSocket;
            ??sockServer:?TSockAddrIn;
            ??command:?array?[
            0 .. 9 ]?of?Byte;
            ??re,?len,?ulen,?plen:?Integer;
            // ??buffer:?PByte;
            ??buffer:?array?[ 0 .. 1023 ]?of?Byte;
            begin
            ??sock?:
            = ?ASocket;
            ??
            if ?FProxyParam.GetServer? = ? '' ?then
            ??begin
            ????Result?:
            = ? 0 ;
            ????Exit;
            ??end
            ??
            else
            ??begin
            ????Result?:
            = ? 0 ;
            ????sock
            ^ ?: = ?socket(AF_INET,?SOCK_STREAM,? 0 );
            ????
            if ?sock ^ ? = ?INVALID_SOCKET?then
            ????begin
            ??????Result?:
            = ? 1 ;
            ??????Exit;
            ????end;
            ?
            ????sockServer.sin_family?:
            = ?AF_INET;
            ????sockServer.sin_port?:
            = ?htons(FProxyParam.GetPort);???? // 將整形數變為網絡字節流
            ????sockServer.sin_addr.S_addr?: = ?inet_addr(PChar(FProxyParam.GetServer));
            ?
            ????
            // 連接遠程主機
            ???? if ?WinSock.connect(sock ^ ,?sockServer,?SizeOf(sockServer))? <> ? 0 ?then
            ????begin
            ??????Result?:
            = ? 1 ;
            ??????Exit;
            ????end;
            ?
            ????bIsValid?:
            = ?FProxyParam.GetProxyValid;
            ?
            ????
            // 發送SOCK5協議指令
            ????FillChar(command,? 10 ,? 0 );
            ????command[
            0 ]?: = ? 5 ;
            ????
            if ?bIsValid?then
            ??????command[
            1 ]?: = ? 2
            ????
            else
            ??????command[
            1 ]?: = ? 1 ;
            ????
            if ?bIsValid?then
            ??????command[
            2 ]?: = ? 2
            ????
            else
            ??????command[
            2 ]?: = ? 0 ;
            ?
            ????
            // 發送登陸指令
            ???? if ?bIsValid?then
            ??????re?:
            = ?WinSock.send(sock ^ ,?command,? 4 ,? 0 )
            ????
            else
            ??????re?:
            = ?WinSock.send(sock ^ ,?command,? 3 ,? 0 );
            ????
            if ?re? = ?SOCKET_ERROR?then
            ????begin
            ??????Result?:
            = ? 1 ;
            ??????Exit;
            ????end;
            ?
            ????
            // 接收返回的消息
            ????fillchar(command,? 10 ,? 0 );????????????????????????? // 接收前用0再次填充
            ????re?: = ?WinSock.recv(sock ^ ,?command,? 2 ,? 0 );
            ????
            if ?re? <> ? 2 ?then
            ????begin
            ??????Result?:
            = ? 1 ;
            ??????Exit;
            ????end;
            ????
            if ?command[ 1 ] = $FF?then
            ????begin
            ??????Result?:
            = ? 1 ;
            ??????Exit;
            ????end;
            ?
            ????
            if ?(not?bIsValid)?and?(command[ 1 ] = 0 )?then
            ????begin
            ??????Exit;
            ????end;
            ?
            ????proxyUser?:
            = ?FProxyParam.GetUsername;
            ????proxyPwd?:
            = ?FProxyParam.GetPassword;
            ?
            ????
            if ?command[ 1 ]? <> ? 0 ?then
            ????begin
            ??????
            if ?command[ 1 ]? <> ? 2 ?then
            ??????begin
            ????????Result?:
            = ? 1 ;
            ????????Exit;
            ??????end;
            ??????
            if ?bIsValid?then
            ??????begin
            ????????ulen?:
            = ?Length(proxyUser);
            ????????plen?:
            = ?Length(proxyPwd);
            ????????len?:
            = ? 3 ? + ?ulen? + ?plen;
            ????????fillchar(buffer,?
            1024 ,? 0 );
            ?
            ????????buffer[
            0 ]?: = ? 5 ;
            ????????buffer[
            1 ]?: = ?ulen;
            ????????StrPCopy(@buffer[
            2 ],?proxyuser);
            ????????buffer[
            2 ? + ?ulen]?: = ?plen;
            ????????StrPCopy(@buffer[
            2 ? + ?ulen? + ? 1 ],?proxyPwd);
            ?
            ????????
            // 發送驗證信息
            ????????re?: = ?send(sock ^ ,?buffer,?len,? 0 );
            ????????
            if ?re? = ?SOCKET_ERROR?then
            ????????begin
            ??????????Result?:
            = ? 1 ;
            ??????????Exit;
            ????????end;
            ?
            ????????
            // 接收驗證返回信息
            ????????fillchar(command,? 10 ,? 0 );
            ????????re?:
            = ?recv(sock ^ ,?command,? 2 ,? 0 );
            ????????
            if ?((re <> 2 )?or?((command[ 0 ] <> 1 )?and?(command[ 1 ] <> 0 ?)))?then
            ????????begin
            ??????????Result?:
            = ? 1 ;
            ??????????Exit;
            ????????end;
            ??????end???
            // if?bisValid
            ?????? else
            ??????begin
            ????????Result?:
            = ? 1 ;
            ????????Exit;
            ??????end;?????????????????????
            //
            ????end;? // ?if?command[1]<>0
            ??end;?? // end?first?if
            ?
            end;
            上面的函數中有一個FproxyParam變量,它是代理參數的值對象,聲明如下:
            ??TProxyParam?
            = ? class
            ??
            private
            ????FUsername,????????
            // 代理驗證用戶名
            ????FPassword,???????? // 代理驗證密碼
            ????FServer:?String;???? // 代理服務器地址
            ????FPort:?Integer;????? // 代理服務器端口號
            ????FIsValid:?Boolean;?? // 是否驗證?????如果代理服務器是驗證的,那么此值應該為true
            ?
            ????procedure?Clear;
            ??
            public
            ????constructor?Create;
            ????procedure?SetUsername(AUsername:?String);
            ????procedure?SetPassword(APassword:?String);
            ????procedure?SetServer(AServer:?String);
            ????procedure?SetPort(APort:?Integer);
            ????procedure?SetProxyValid(AValid:?Boolean);
            ?
            ????function?GetUsername:?String;
            ????function?GetPassword:?String;
            ????function?GetServer:?String;
            ????function?GetPort:?Integer;
            ????function?GetProxyValid:?Boolean;
            ??end;
            使用此函數:
            假設已經創建了一個ClientSocket1(TclientSocket對象),它的IP和Port設置為代理服務器的IP和Port,那么就有下面的代碼:
            ......
            Var
            Re:Integer;
            Begin
            Re:
            = SetProxy(@(ClientSocket.Socket.SocketHandle))?;?? // 如果驗證成功,那么就可以用返回的//socket進行相應的通訊
            If?Re = 0 ?then?
            Begn
            ??ShowMessage(‘Sock5?is?ok’);?????????
            // 代理服務器就會有連接的數據流顯示
            End
            Else?begin
            ??ShowMessage(‘Sock5?is?error’);
            End;
            End;
            ……
            上面的例子如果設置代理成功,那么代理服務器就會有連接的數據流顯示。表示與代理服務器有數據交換,如果沒有成功則務數據流顯示。
            ?
            ?
            ?????????????????????????????????????????????????????????????? 李孟巖
            ????????????????????????????????????????????????????????????????????? mengyan_yl@sohu.com
            ??????????????????????????????????????????????????????????????????????????????????? 2005-07-05實現Sock5代理
            久久精品人人做人人爽97| 国产成人精品久久亚洲高清不卡 | 69久久夜色精品国产69| 思思久久99热只有频精品66| 久久国产成人午夜aⅴ影院| 99久久精品日本一区二区免费| 人妻丰满AV无码久久不卡 | 亚洲AV无码久久| 伊人久久综合成人网| 人妻无码αv中文字幕久久琪琪布 人妻无码久久一区二区三区免费 人妻无码中文久久久久专区 | 日韩人妻无码精品久久免费一| 亚洲国产精品高清久久久| 无码人妻久久一区二区三区免费 | 日韩乱码人妻无码中文字幕久久| 综合人妻久久一区二区精品| 色欲久久久天天天综合网| 久久久精品2019免费观看| 国产精品99久久精品| 久久e热在这里只有国产中文精品99| 成人a毛片久久免费播放| 天堂无码久久综合东京热| 国产69精品久久久久9999APGF| 亚洲国产精品一区二区久久hs| 久久A级毛片免费观看| 久久91这里精品国产2020| A级毛片无码久久精品免费| 国产91色综合久久免费| 亚洲人成无码久久电影网站| 无码人妻精品一区二区三区久久久 | 亚洲第一永久AV网站久久精品男人的天堂AV| 热久久这里只有精品| 伊人久久大香线蕉综合网站| 亚洲国产精品无码久久SM| 国产精品激情综合久久| 亚洲精品美女久久久久99| 色综合久久中文色婷婷| 久久精品国产免费观看三人同眠| 狠色狠色狠狠色综合久久| 午夜精品久久久久| 久久精品成人免费观看97| AV无码久久久久不卡蜜桃|