home *** CD-ROM | disk | FTP | other *** search
/ Celestin Apprentice 4 / Apprentice-Release4.iso / Source Code / Libraries / MacTCP Library 1.1 / Library / LowLevel ƒ / Source ƒ / Socks.c < prev    next >
Encoding:
C/C++ Source or Header  |  1995-12-05  |  9.4 KB  |  349 lines  |  [TEXT/SPM ]

  1. /*
  2.     Socks.c
  3.     
  4.     Socks library for my MacTCP library.
  5.     
  6.     This library provides an API for using MacTCP in conjunction with a Socks daemon
  7.     to control access.  It does not yet support async socks connections.
  8.     
  9.     12/04/95 dn - Prep'd for Apprentice 4
  10. */
  11.  
  12. #include <MyTCPIncludes.h>
  13.  
  14. #include "Socks.h"
  15.  
  16. /*
  17.     Local Prototypes
  18. */
  19. OSErr SockdOpen(SOCKSiopbPtr pb);
  20. OSErr SocksRequest(SOCKSiopbPtr socksPB,char command);
  21. OSErr check_result(char code);
  22. OSErr Socks_ActiveOpenAsync(SOCKSiopb* pb);
  23. OSErr Socks_PassiveOpenAsync(SOCKSiopb* pb);
  24.  
  25. /*
  26.     SockdOpen
  27.     
  28.     Open a connection to the SOCKS daemon.
  29. */
  30. OSErr SockdOpen(SOCKSiopbPtr pb){
  31.     OSErr err;
  32.     ip_addr host;
  33.     tcp_port port;
  34.     TCPiopb open;
  35.     
  36.     open.ioCRefNum=pb->ioCRefNum;
  37.     open.tcpStream=pb->tcpStream;
  38.     open.csParam.open.ulpTimeoutValue=pb->csParam.open.ulpTimeoutValue;
  39.     open.csParam.open.ulpTimeoutAction=pb->csParam.open.ulpTimeoutAction;
  40.     open.csParam.open.validityFlags=pb->csParam.open.validityFlags;
  41.     open.csParam.open.remoteHost=pb->csParam.open.socksHost;
  42.     open.csParam.open.remotePort=pb->csParam.open.socksPort;
  43.     open.csParam.open.tosFlags=pb->csParam.open.tosFlags;
  44.     open.csParam.open.localPort=pb->csParam.open.localPort;
  45.     open.csParam.open.precedence=pb->csParam.open.precedence;
  46.     open.csParam.open.dontFrag=true;
  47.     open.csParam.open.timeToLive=pb->csParam.open.timeToLive;
  48.     open.csParam.open.security=pb->csParam.open.security;
  49.     open.csParam.open.optionCnt=pb->csParam.open.optionCnt;
  50.     if (open.csParam.open.optionCnt>0){
  51.         BlockMoveData((Ptr)pb->csParam.open.options,(Ptr)open.csParam.open.options,
  52.             open.csParam.open.optionCnt*sizeof(SInt8));
  53.     }
  54.     open.csParam.open.userDataPtr=pb->csParam.open.userDataPtr;
  55.     
  56.     // open the connection...
  57.     err=TCP_ActiveOpen(&open,false);
  58.     
  59.     // save the local host and port back into the parm block before returning
  60.     pb->csParam.open.localHost=open.csParam.open.localHost;
  61.     pb->csParam.open.localPort=open.csParam.open.localPort;
  62.     
  63.     return err;
  64. }
  65.  
  66. /*
  67.     SocksRequest
  68.     
  69.     Requests a connection through the SOCKS daemon.
  70.     
  71.     The request works like this:  after the connection to the socks daemon is opened, the
  72.     first thing that must be sent to the daemon is an 8 byte packet which describes where the
  73.     connection really should be made to (includes the address and port of the remote host).  Following
  74.     this packet is a null-terminated C-style string which contains the username of the user making the
  75.     request.  After this is transmitted to the socks daemon, it will process the request and return
  76.     the 8 byte packet with a result code indicating the success/failure of the external connection.
  77.     
  78.     According to the SOCKS documentation, the socks daemon is supposed to use the username passed
  79.     in during the connection request in a call to the local identd server (identd verifies the user actually
  80.     has initiated the request).  During my testing, though, the socks daemon did not fail with the 'no identd'
  81.     error, even though I was not running an identd server.  So either I was connecting to an old socks daemon
  82.     (could be; I don't know what version the server is that was running), our socks daemon doesn't use
  83.     the identd service, our socks daemon doesn't error if no local identd server is running, or the socks
  84.     daemon ignored the absence of the identd server.  I am not completely sure which option it was, but I
  85.     tend to think that we are configured not to use the identd server (although I plan on writing one for
  86.     my mac anyway).
  87. */
  88. OSErr SocksRequest(SOCKSiopbPtr socksPB,char command){
  89.     char c[200];
  90.     OSErr err;
  91.     TCPiopb pb;
  92.     wdsEntry wds[3];
  93.     short have;
  94.     
  95.     union {
  96.         tcp_port port;
  97.         char ch[2];
  98.     } aPort;
  99.     
  100.     union {
  101.         ip_addr addr;
  102.         char ch[4];
  103.     } aAddr;
  104.     
  105.     // set up our TCPiopb
  106.     pb.tcpStream=socksPB->tcpStream;
  107.     pb.ioCRefNum=socksPB->ioCRefNum;
  108.     pb.csParam.send.ulpTimeoutValue=0;
  109.     pb.csParam.send.ulpTimeoutAction=0;
  110.     pb.csParam.send.wdsPtr=(Ptr)wds;
  111.     pb.csParam.send.pushFlag=2; // send right away, no delay
  112.     pb.csParam.send.urgentFlag=0;
  113.     
  114.     c[0]=SOCKS_VERSION;
  115.     c[1]=command;
  116.     aPort.port=socksPB->csParam.open.remotePort;
  117.     c[2]=aPort.ch[0];c[3]=aPort.ch[1];
  118.     aAddr.addr=socksPB->csParam.open.remoteHost;
  119.     c[4]=aAddr.ch[0];c[5]=aAddr.ch[1];
  120.     c[6]=aAddr.ch[2];c[7]=aAddr.ch[3];
  121.     
  122.     // set up the wdsEntry structures
  123.     
  124.     // first is the Socks_t struct
  125.     wds[0].length=8;
  126.     wds[0].ptr=(Ptr)c;
  127.     
  128.     // next is the user's name
  129.     wds[1].length=StrLen(socksPB->csParam.open.socksUser)+1;
  130.     wds[1].ptr=(Ptr)socksPB->csParam.open.socksUser;
  131.     
  132.     wds[2].length=0;
  133.     wds[2].ptr=(Ptr)0;
  134.     
  135.     // send our stuff to the socks daemon
  136.     err=TCP_Send(&pb,false); // send the item...
  137.     
  138.     if (err!=noErr)
  139.         return err;
  140.     
  141.     // info sent, now we have to read the results back from the socks daemon
  142.     // it is sent back in the form of a Socks_t structure.
  143.     
  144.     pb.tcpStream=socksPB->tcpStream;
  145.     have=0;
  146.     
  147.     // loop until the entire Socks_T has been read from the socks host
  148.     while (have<8){
  149.         pb.csParam.receive.commandTimeoutValue=0;
  150.         pb.csParam.receive.rcvBuff=(Ptr)(c+have);
  151.         pb.csParam.receive.rcvBuffLen=200-have;
  152.         
  153.         // now read the Socks_t
  154.         err=TCP_Rcv(&pb,false);
  155.         
  156.         if (err!=noErr)
  157.             return err;
  158.         
  159.         have+=pb.csParam.receive.rcvBuffLen;
  160.     }
  161.     
  162.     // depending on cmd, we may/may not have a connection...
  163.     return check_result(c[1]);
  164. }
  165.  
  166.  
  167. /*
  168.     check_result
  169.     
  170.     Converts the code from the socks daemon into a Mac OSErr.
  171. */
  172. OSErr check_result(char code){
  173.     switch (code) {
  174.         case SOCKS_FAIL:
  175.             return socksConnFail;
  176.         case SOCKS_NO_IDENTD:
  177.             return socksNoIdentd;
  178.         case SOCKS_BAD_ID:
  179.             return socksBadID;
  180.         default:
  181.             return noErr;
  182.     }
  183. }
  184.  
  185. OSErr SOCKS_Create(SOCKSiopb * pb,Boolean async){
  186.     return TCP_Create((TCPiopbPtr)pb,async);
  187. }
  188.  
  189. /*
  190.     SocksActiveOpen
  191.     
  192.     Opens an active connection after fixing the param block to go through
  193.     the Socks daemon.  Opens the connection, sends the Socks data structure,
  194.     and if everything works out returns the correct and open tcp stream to
  195.     the user.
  196. */
  197. OSErr SOCKS_ActiveOpen(SOCKSiopb* pb,Boolean async){
  198.     OSErr err=noErr;
  199.     
  200.     if (async)
  201.         return Socks_ActiveOpenAsync(pb);
  202.     
  203.     err=SockdOpen(pb);
  204.     
  205.     if (err!=noErr)
  206.         return err;
  207.     
  208.     // the connection to the socks daemon is open, finish the open request
  209.     
  210.     err=SocksRequest(pb,SOCKS_ACTIVE_OPEN);
  211.     
  212.     return err;
  213. }
  214.  
  215. OSErr SOCKS_PassiveOpen(SOCKSiopb * pb,Boolean async){
  216.     OSErr err;
  217.     short have=0;
  218.     TCPiopb tcp;
  219.     char c[10];
  220.     
  221.     union {
  222.         tcp_port port;
  223.         char ch[2];
  224.     } aPort;
  225.     
  226.     union {
  227.         ip_addr addr;
  228.         char ch[4];
  229.     } aAddr;
  230.     
  231.     if (async)
  232.         return Socks_PassiveOpenAsync(pb);
  233.     
  234.     // open a connection to the socks daemon
  235.     err=SockdOpen(pb);
  236.     
  237.     if (err!=noErr)
  238.         return err;
  239.     
  240.     err=SocksRequest(pb,SOCKS_PASSIVE_OPEN);
  241.     
  242.     if (err!=noErr)
  243.         return err;
  244.     
  245.     /*
  246.         At this point an active connection has been opened with the socks daemon.  It is listening for
  247.         an incoming connection.  When it returns data back to us (specifically the 8 byte structure mentioned
  248.         in SOCKS_ActiveOpen()), a connection request has been received by the socks daemon, and we can begin.
  249.     */
  250.     
  251.     tcp.tcpStream=pb->tcpStream;
  252.     tcp.ioCRefNum=pb->ioCRefNum;
  253.     
  254.     // loop until the entire Socks_T has been read from the socks host
  255.     while (have<8){
  256.         tcp.csParam.receive.commandTimeoutValue=0;
  257.         tcp.csParam.receive.rcvBuff=(Ptr)(c+have);
  258.         tcp.csParam.receive.rcvBuffLen=10-have;
  259.         
  260.         // now read the Socks_t
  261.         err=TCP_Rcv(&tcp,false);
  262.         
  263.         if (err!=noErr)
  264.             return err;
  265.         
  266.         have+=tcp.csParam.receive.rcvBuffLen;
  267.     }
  268.     
  269.     // the connection request has completed
  270.     // fill out the remaining structures of the SOCKSiopb before returning
  271.     aPort.ch[0]=c[2];aPort.ch[1]=c[3];
  272.     aAddr.ch[0]=c[4];aAddr.ch[1]=c[5];aAddr.ch[2]=c[6];aAddr.ch[3]=c[7];
  273.     
  274.     pb->csParam.open.remoteHost=aAddr.addr;
  275.     pb->csParam.open.remotePort=aPort.port;
  276.     
  277.     return noErr;
  278. }
  279.  
  280. OSErr SOCKS_Send(SOCKSiopb * pb,Boolean async){
  281.     return TCP_Send((TCPiopbPtr)pb,async);
  282. }
  283.  
  284. OSErr SOCKS_NoCopyRcv(SOCKSiopb * pb,Boolean async){
  285.     return TCP_NoCopyRcv((TCPiopbPtr)pb,async);
  286. }
  287.  
  288. OSErr SOCKS_RcvBfrReturn(SOCKSiopb * pb,Boolean async){
  289.     return TCP_RcvBfrReturn((TCPiopbPtr)pb,async);
  290. }
  291.  
  292. OSErr SOCKS_Rcv(SOCKSiopb * pb,Boolean async){
  293.     return TCP_Rcv((TCPiopbPtr)pb,async);
  294. }
  295.  
  296. OSErr SOCKS_Close(SOCKSiopb * pb,Boolean async){
  297.     return TCP_Close((TCPiopbPtr)pb,async);
  298. }
  299.  
  300. OSErr SOCKS_Abort(SOCKSiopb * pb,Boolean async){
  301.     return TCP_Abort((TCPiopbPtr)pb,async);
  302. }
  303.  
  304. OSErr SOCKS_Status(SOCKSiopb * pb,Boolean async){
  305.     return TCP_Status((TCPiopbPtr)pb,async);
  306. }
  307.  
  308. OSErr SOCKS_ExtendedStat(SOCKSiopb * pb,Boolean async){
  309.     return TCP_ExtendedStat((TCPiopbPtr)pb,async);
  310. }
  311.  
  312. OSErr SOCKS_Release(SOCKSiopb * pb,Boolean async){
  313.     return TCP_Release((TCPiopbPtr)pb,async);
  314. }
  315.  
  316. OSErr SOCKS_GlobalInfo(SOCKSiopb * pb,Boolean async){
  317.     return TCP_GlobalInfo((TCPiopbPtr)pb,async);
  318. }
  319.  
  320. /*
  321.     Socks_ActiveOpenAsync
  322.     
  323.     When opening a connection asynchronously, the library is going to have to chain the process together,
  324.     not returning to the user until the connection is finally established.
  325.     
  326.     The best bet is to put the user's ioCompletion routine in the userDataPtr field to pass it around.  Replace
  327.     the completion procs with our procs in the chain.  When done, call the user's proc with the completed
  328.     parm block.
  329. */
  330. OSErr Socks_ActiveOpenAsync(SOCKSiopb* pb){
  331.      return paramErr;
  332. }
  333.  
  334. /*
  335.     Socks_PassiveOpenAsync
  336.     
  337.     When opening a connection asynchronously, the library is going to have to chain the process together,
  338.     not returning to the user until the connection is finally established.
  339.     
  340.     The best bet is to put the user's ioCompletion routine in the userDataPtr field to pass it around.  Replace
  341.     the completion procs with our procs in the chain.  When done, call the user's proc with the completed
  342.     parm block.
  343. */
  344. OSErr Socks_PassiveOpenAsync(SOCKSiopb* pb){
  345.      return paramErr;
  346. }
  347.  
  348.  
  349.