ssltap.c
上传用户:lyxiangda
上传日期:2007-01-12
资源大小:3042k
文件大小:38k
源码类别:

CA认证

开发平台:

WINDOWS

  1. /*
  2.  * The contents of this file are subject to the Mozilla Public
  3.  * License Version 1.1 (the "License"); you may not use this file
  4.  * except in compliance with the License. You may obtain a copy of
  5.  * the License at http://www.mozilla.org/MPL/
  6.  * 
  7.  * Software distributed under the License is distributed on an "AS
  8.  * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
  9.  * implied. See the License for the specific language governing
  10.  * rights and limitations under the License.
  11.  * 
  12.  * The Original Code is the Netscape security libraries.
  13.  * 
  14.  * The Initial Developer of the Original Code is Netscape
  15.  * Communications Corporation.  Portions created by Netscape are 
  16.  * Copyright (C) 1994-2000 Netscape Communications Corporation.  All
  17.  * Rights Reserved.
  18.  * 
  19.  * Contributor(s):
  20.  * 
  21.  * Alternatively, the contents of this file may be used under the
  22.  * terms of the GNU General Public License Version 2 or later (the
  23.  * "GPL"), in which case the provisions of the GPL are applicable 
  24.  * instead of those above.  If you wish to allow use of your 
  25.  * version of this file only under the terms of the GPL and not to
  26.  * allow others to use your version of this file under the MPL,
  27.  * indicate your decision by deleting the provisions above and
  28.  * replace them with the notice and other provisions required by
  29.  * the GPL.  If you do not delete the provisions above, a recipient
  30.  * may use your version of this file under either the MPL or the
  31.  * GPL.
  32.  */
  33. /*
  34.  * ssltap.c
  35.  *
  36.  * Version 1.0 : Frederick Roeber : 11 June 1997
  37.  * Version 2.0 : Steve Parkinson  : 13 November 1997
  38.  * Version 3.0 : Nelson Bolyard   : 22 July 1998
  39.  * Version 3.1 : Nelson Bolyard   : 24 May  1999
  40.  *
  41.  * changes in version 2.0:
  42.  *  Uses NSPR20
  43.  *  Shows structure of SSL negotiation, if enabled.
  44.  *
  45.  * This "proxies" a socket connection (like a socks tunnel), but displays the
  46.  * data is it flies by.
  47.  *
  48.  * In the code, the 'client' socket is the one on the client side of the
  49.  * proxy, and the server socket is on the server side.
  50.  *
  51.  */
  52. #include "nspr.h"
  53. #include "plstr.h"
  54. #include "secutil.h"
  55. #include <memory.h> /* for memcpy, etc. */
  56. #include <string.h>
  57. #include <time.h>
  58. #include "plgetopt.h"
  59. #define VERSIONSTRING "$Revision: 1.1 $ ($Date: 2000/03/31 20:12:54 $) $Author: relyea%netscape.com $"
  60. struct _DataBufferList;
  61. struct _DataBuffer;
  62. typedef struct _DataBufferList {
  63.   struct _DataBuffer *first,*last;
  64.   int size;
  65.   int isEncrypted;
  66. } DataBufferList;
  67. typedef struct _DataBuffer {
  68.   unsigned char *buffer;
  69.   int length;
  70.   int offset;  /* offset of first good byte */
  71.   struct _DataBuffer *next;
  72. } DataBuffer;
  73. DataBufferList
  74.   clientstream = {NULL, NULL, 0, 0},
  75.   serverstream = {NULL, NULL, 0, 0};
  76. struct sslhandshake {
  77.   PRUint8 type;
  78.   PRUint32 length;
  79. };
  80. typedef struct _SSLRecord {
  81.   PRUint8 type;
  82.   PRUint8 ver_maj,ver_min;
  83.   PRUint8 length[2];
  84. } SSLRecord;
  85. typedef struct _ClientHelloV2 {
  86.   PRUint8 length[2];
  87.   PRUint8 type;
  88.   PRUint8 version[2];
  89.   PRUint8 cslength[2];
  90.   PRUint8 sidlength[2];
  91.   PRUint8 rndlength[2];
  92.   PRUint8 csuites[1];
  93. } ClientHelloV2;
  94. typedef struct _ServerHelloV2 {
  95.   PRUint8 length[2];
  96.   PRUint8 type;
  97.   PRUint8 sidhit;
  98.   PRUint8 certtype;
  99.   PRUint8 version[2];
  100.   PRUint8 certlength[2];
  101.   PRUint8 cslength[2];
  102.   PRUint8 cidlength[2];
  103. } ServerHelloV2;
  104. typedef struct _ClientMasterKeyV2 {
  105.   PRUint8 length[2];
  106.   PRUint8 type;
  107.   PRUint8 cipherkind[3];
  108.   PRUint8 clearkey[2];
  109.   PRUint8 secretkey[2];
  110. } ClientMasterKeyV2;
  111. #define TAPBUFSIZ 16384
  112. #define DEFPORT 1924
  113. #include <ctype.h>
  114. int hexparse=0;
  115. int sslparse=0;
  116. int sslhexparse=0;
  117. int looparound=0;
  118. int fancy=0;
  119. int isV2Session=0;
  120. #define GET_SHORT(x) ((PRUint16)(((PRUint16)((PRUint8*)x)[0]) << 8) + ((PRUint16)((PRUint8*)x)[1]))
  121. #define GET_24(x) ((PRUint32)   (  
  122.  (((PRUint32)((PRUint8*)x)[0]) << 16) 
  123.  +                          
  124.  (((PRUint32)((PRUint8*)x)[1]) << 8)  
  125.  +                          
  126.  (((PRUint32)((PRUint8*)x)[2]) << 0)  
  127.  ) )
  128. void print_hex(int amt, unsigned char *buf);
  129. void read_stream_bytes(unsigned char *d, DataBufferList *db, int length);
  130. void myhalt(int dblsize,int collectedsize) {
  131.   while(1) ;
  132. }
  133. const char *get_error_text(int error) {
  134.   switch (error) {
  135.   case PR_IO_TIMEOUT_ERROR:
  136.     return "Timeout";
  137.     break;
  138.   case PR_CONNECT_REFUSED_ERROR:
  139.     return "Connection refused";
  140.     break;
  141.   case PR_NETWORK_UNREACHABLE_ERROR:
  142.     return "Network unreachable";
  143.     break;
  144.   case PR_BAD_ADDRESS_ERROR:
  145.     return "Bad address";
  146.     break;
  147.   case PR_CONNECT_RESET_ERROR:
  148.     return "Connection reset";
  149.     break;
  150.   case PR_PIPE_ERROR:
  151.     return "Pipe error";
  152.     break;
  153.   }
  154.   return "";
  155. }
  156. void check_integrity(DataBufferList *dbl) {
  157.   DataBuffer *db;
  158.   int i;
  159.   db = dbl->first;
  160.   i =0;
  161.   while (db) {
  162.     i+= db->length - db->offset;
  163.     db = db->next;
  164.   }
  165.   if (i != dbl->size) {
  166.     myhalt(dbl->size,i);
  167.   }
  168. }
  169. /* Free's the DataBuffer at the head of the list and returns the pointer
  170.  * to the new head of the list.
  171.  */
  172. DataBuffer * 
  173. free_head(DataBufferList *dbl)
  174. {
  175.   DataBuffer *db       = dbl->first;
  176.   PR_ASSERT(db->offset >= db->length);
  177.   if (db->offset >= db->length) {
  178.     dbl->first = db->next;
  179.     if (dbl->first == NULL) {
  180.       dbl->last = NULL;
  181.     }
  182.     PR_Free(db->buffer);
  183.     PR_Free(db);
  184.     db = dbl->first;
  185.   }
  186.   return db;
  187. }
  188. void 
  189. read_stream_bytes(unsigned char *d, DataBufferList *dbl, int length) {
  190.   int         copied  = 0;
  191.   DataBuffer *db = dbl->first;
  192.   if (!db) {
  193.     PR_fprintf(PR_STDERR,"assert failed - dbl->first is nulln");
  194.     exit(8);
  195.   }
  196.   while (length) {
  197.     int         toCopy;
  198.     /* find the number of bytes to copy from the head buffer */
  199.     /* if there's too many in this buffer, then only copy 'length' */
  200.     toCopy = PR_MIN(db->length - db->offset, length);
  201.     memcpy(d + copied, db->buffer + db->offset, toCopy);
  202.     copied     += toCopy;
  203.     db->offset += toCopy;
  204.     length     -= toCopy;
  205.     dbl->size  -= toCopy;
  206.     /* if we emptied the head buffer */
  207.     if (db->offset >= db->length) {
  208.       db = free_head(dbl);
  209.     }
  210.   }
  211.   check_integrity(dbl);
  212. }
  213. void
  214. flush_stream(DataBufferList *dbl)
  215. {
  216.     DataBuffer *db = dbl->first;
  217.     check_integrity(dbl);
  218.     while (db) {
  219. db->offset = db->length;
  220.      db = free_head(dbl);
  221.     }
  222.     dbl->size = 0;
  223.     check_integrity(dbl);
  224. }
  225. const char * V2CipherString(int cs_int) {
  226.   char *cs_str;
  227.   cs_str = NULL;
  228.   switch (cs_int) {
  229.   case 0x010080:    cs_str = "SSL2/RSA/RC4-128/MD5";       break;
  230.   case 0x020080:    cs_str = "SSL2/RSA/RC4-40/MD5";    break;
  231.   case 0x030080:    cs_str = "SSL2/RSA/RC2CBC128/MD5";     break;
  232.   case 0x040080:    cs_str = "SSL2/RSA/RC2CBC40/MD5";  break;
  233.   case 0x050080:    cs_str = "SSL2/RSA/IDEA128CBC/MD5";    break;
  234.   case 0x060040:    cs_str = "SSL2/RSA/DES56-CBC/MD5";      break;
  235.   case 0x0700C0:    cs_str = "SSL2/RSA/3DES192EDE-CBC/MD5"; break;
  236.   case 0x000001:    cs_str = "SSL3/RSA/NULL/MD5";             break;
  237.   case 0x000002:    cs_str = "SSL3/RSA/NULL/SHA";             break;
  238.   case 0x000003:    cs_str = "SSL3/RSA/RC4-40/MD5";       break;
  239.   case 0x000004:    cs_str = "SSL3/RSA/RC4-128/MD5";          break;
  240.   case 0x000005:    cs_str = "SSL3/RSA/RC4-128/SHA";          break;
  241.   case 0x000006:    cs_str = "SSL3/RSA/RC2CBC40/MD5";     break;
  242.   case 0x000007:    cs_str = "SSL3/RSA/IDEA128CBC/SHA";       break;
  243.   case 0x000008:    cs_str = "SSL3/RSA/DES40-CBC/SHA";         break;
  244.   case 0x000009:    cs_str = "SSL3/RSA/DES56-CBC/SHA";         break;
  245.   case 0x00000A:    cs_str = "SSL3/RSA/3DES192EDE-CBC/SHA";    break;
  246.   case 0x00000B:    cs_str = "SSL3/DH-DSS/DES40-CBC/SHA";      break;
  247.   case 0x00000C:    cs_str = "SSL3/DH_DSS/DES56-CBC/SHA";      break;
  248.   case 0x00000D:    cs_str = "SSL3/DH-DSS/DES192EDE3CBC/SHA"; break;
  249.   case 0x00000E:    cs_str = "SSL3/DH-RSA/DES40-CBC/SHA";      break;
  250.   case 0x00000F:    cs_str = "SSL3/DH_RSA/DES56-CBC/SHA";      break;
  251.   case 0x000010:    cs_str = "SSL3/DH-RSA/3DES192EDE-CBC/SHA"; break;
  252.   case 0x000011:    cs_str = "SSL3/DHE-DSS/DES40-CBC/SHA";      break;
  253.   case 0x000012:    cs_str = "SSL3/DHE_DSS/DES56-CBC/SHA";      break;
  254.   case 0x000013:    cs_str = "SSL3/DHE-DSS/DES192EDE3CBC/SHA"; break;
  255.   case 0x000014:    cs_str = "SSL3/DHE-RSA/DES40-CBC/SHA";      break;
  256.   case 0x000015:    cs_str = "SSL3/DHE_RSA/DES56-CBC/SHA";      break;
  257.   case 0x000016:    cs_str = "SSL3/DHE-RSA/3DES192EDE-CBC/SHA"; break;
  258.   case 0x000017:    cs_str = "SSL3/DH-anon/RC4-40/MD5";     break;
  259.   case 0x000018:    cs_str = "SSL3/DH-anon/RC4-128/MD5";        break;
  260.   case 0x000019:    cs_str = "SSL3/DH-anon/DES40-CBC/SHA";       break;
  261.   case 0x00001A:    cs_str = "SSL3/DH-anon/DES56-CBC/SHA";       break;
  262.   case 0x00001B:    cs_str = "SSL3/DH-anon/3DES192EDE-CBC/SHA"; break;
  263.   case 0x00001C:    cs_str = "SSL3/FORTEZZA-DMS/NULL/SHA";      break;
  264.   case 0x00001D:    cs_str = "SSL3/FORTEZZA-DMS/FORTEZZA-CBC/SHA";  break;
  265.   case 0x00001E:    cs_str = "SSL3/FORTEZZA-DMS/RC4-128/SHA";  break;
  266.   case 0x000062:    cs_str = "TLS/RSA_EXPORT1024/DES56_CBC/SHA";   break;
  267.   case 0x000064:    cs_str = "TLS/RSA_EXPORT1024/RC4-56/SHA";    break;
  268.   case 0x000063:    cs_str = "TLS/DHE-DSS_EXPORT1024/DES56-CBC/SHA"; break;
  269.   case 0x000065:    cs_str = "TLS/DHE-DSS_EXPORT1024/RC4-56/SHA";  break;
  270.   case 0x000066:    cs_str = "TLS/DHE-DSS/RC4-128/SHA";    break;
  271.   case 0x00ffe1:    cs_str = "SSL3/RSA-FIPS/DES56-CBC/SHA";         break;
  272.   case 0x00ffe0:    cs_str = "SSL3/RSA-FIPS/3DES192EDE-CBC/SHA";    break;
  273.   default:          cs_str = "????/????????/?????????/???";     break;
  274.   }
  275.   return cs_str;
  276. }
  277. void partial_packet(int thispacket, int size, int needed)
  278. {
  279.   PR_fprintf(PR_STDOUT,"(%u bytes", thispacket);
  280.   if (thispacket < needed) {
  281.     PR_fprintf(PR_STDOUT,", making %u", size);
  282.   }
  283.   PR_fprintf(PR_STDOUT," of %u", needed);
  284.   if (size > needed) {
  285.     PR_fprintf(PR_STDOUT,", with %u left over", size - needed);
  286.   }
  287.   PR_fprintf(PR_STDOUT,")n");
  288. }
  289. char * get_time_string(void)
  290. {
  291.   struct tm *tm;
  292.   char      *cp;
  293.   char      *eol;
  294.   time_t     tt;
  295.   time(&tt);
  296. #if 0
  297.   tm = localtime(&tt);
  298.   cp = asctime(tm);
  299. #else
  300.   cp = ctime(&tt);
  301. #endif
  302.   eol = strchr(cp, 'n');
  303.   if (eol) 
  304.     *eol = 0;
  305.   return cp;
  306. }
  307. void print_sslv2(DataBufferList *s, unsigned char *tbuf, unsigned int alloclen)
  308. {
  309.   ClientHelloV2 *chv2;
  310.   ServerHelloV2 *shv2;
  311.   unsigned char *pos;
  312.   unsigned int   p;
  313.   unsigned int   q;
  314.   PRUint32       len;
  315.   chv2 = (ClientHelloV2 *)tbuf;
  316.   shv2 = (ServerHelloV2 *)tbuf;
  317.   if (s->isEncrypted) {
  318.     PR_fprintf(PR_STDOUT," [ssl2]  Encrypted {...}n");
  319.     return;
  320.   }
  321.   PR_fprintf(PR_STDOUT," [%s]", get_time_string() );
  322.   switch(chv2->type) {
  323.   case 1:
  324.     PR_fprintf(PR_STDOUT," [ssl2]  ClientHelloV2 {n");
  325.     PR_fprintf(PR_STDOUT,"           version = {0x%02x, 0x%02x}n",
  326.        (PRUint32)chv2->version[0],(PRUint32)chv2->version[1]);
  327.     PR_fprintf(PR_STDOUT,"           cipher-specs-length = %d (0x%02x)n",
  328.        (PRUint32)(GET_SHORT((chv2->cslength))),
  329.        (PRUint32)(GET_SHORT((chv2->cslength))));
  330.     PR_fprintf(PR_STDOUT,"           sid-length = %d (0x%02x)n",
  331.        (PRUint32)(GET_SHORT((chv2->sidlength))),
  332.        (PRUint32)(GET_SHORT((chv2->sidlength))));
  333.     PR_fprintf(PR_STDOUT,"           challenge-length = %d (0x%02x)n",
  334.        (PRUint32)(GET_SHORT((chv2->rndlength))),
  335.        (PRUint32)(GET_SHORT((chv2->rndlength))));
  336.     PR_fprintf(PR_STDOUT,"           cipher-suites = { n");
  337.     for (p=0;p<GET_SHORT((chv2->cslength));p+=3) {
  338.       const char *cs_str=NULL;
  339.       PRUint32 cs_int=0;
  340.       cs_int = GET_24((&chv2->csuites[p]));
  341.       cs_str = V2CipherString(cs_int);
  342.       PR_fprintf(PR_STDOUT,"                (0x%06x) %sn",
  343.   cs_int, cs_str);
  344.     }
  345.     q = p;
  346.     PR_fprintf(PR_STDOUT,"                }n");
  347.     if (chv2->sidlength) {
  348.       PR_fprintf(PR_STDOUT,"           session-id = { ");
  349.       for (p=0;p<GET_SHORT((chv2->sidlength));p+=2) {
  350. PR_fprintf(PR_STDOUT,"0x%04x ",(PRUint32)(GET_SHORT((&chv2->csuites[p+q]))));
  351.       }
  352.     }
  353.     q += p;
  354.     PR_fprintf(PR_STDOUT,"}n");
  355.     if (chv2->rndlength) {
  356.       PR_fprintf(PR_STDOUT,"           challenge = { ");
  357.       for (p=0;p<GET_SHORT((chv2->rndlength));p+=2) {
  358. PR_fprintf(PR_STDOUT,"0x%04x ",(PRUint32)(GET_SHORT((&chv2->csuites[p+q]))));
  359.       }
  360.       PR_fprintf(PR_STDOUT,"}n");
  361.     }
  362.     PR_fprintf(PR_STDOUT,"}n");
  363.     break;
  364.     /* end of V2 CLientHello Parsing */
  365.   case 2:  /* Client Master Key  */
  366.     {
  367.     const char *cs_str=NULL;
  368.     PRUint32 cs_int=0;
  369.     ClientMasterKeyV2 *cmkv2;
  370.     cmkv2 = (ClientMasterKeyV2 *)chv2;
  371.     isV2Session = 1;
  372.     PR_fprintf(PR_STDOUT," [ssl2]  ClientMasterKeyV2 { n");
  373.     cs_int = GET_24(&cmkv2->cipherkind[0]);
  374.     cs_str = V2CipherString(cs_int);
  375.     PR_fprintf(PR_STDOUT,"         cipher-spec-chosen = (0x%06x) %sn",
  376.        cs_int, cs_str);
  377.     PR_fprintf(PR_STDOUT,"         clear-portion = %d bitsn",
  378.        8*(PRUint32)(GET_SHORT((cmkv2->clearkey))));
  379.     PR_fprintf(PR_STDOUT,"      }n");
  380.     clientstream.isEncrypted = 1;
  381.     serverstream.isEncrypted = 1;
  382.     }
  383.     break;
  384.   case 3:
  385.     PR_fprintf(PR_STDOUT," [ssl2]  Client Finished V2 {...}n");
  386.     isV2Session = 1;
  387.     break;
  388.   case 4:  /* V2 Server Hello */
  389.     isV2Session = 1;
  390.     PR_fprintf(PR_STDOUT," [ssl2]  ServerHelloV2 {n");
  391.     PR_fprintf(PR_STDOUT,"           sid hit = {0x%02x}n",
  392.        (PRUintn)shv2->sidhit);
  393.     PR_fprintf(PR_STDOUT,"           version = {0x%02x, 0x%02x}n",
  394.        (PRUint32)shv2->version[0],(PRUint32)shv2->version[1]);
  395.     PR_fprintf(PR_STDOUT,"           cipher-specs-length = %d (0x%02x)n",
  396.        (PRUint32)(GET_SHORT((shv2->cslength))),
  397.        (PRUint32)(GET_SHORT((shv2->cslength))));
  398.     PR_fprintf(PR_STDOUT,"           sid-length = %d (0x%02x)n",
  399.        (PRUint32)(GET_SHORT((shv2->cidlength))),
  400.        (PRUint32)(GET_SHORT((shv2->cidlength))));
  401.     pos = (unsigned char *)shv2;
  402.     pos += 2;   /* skip length header */
  403.     pos += 11;  /* position pointer to Certificate data area */
  404.     q = GET_SHORT(&shv2->certlength);
  405.     if (q >alloclen) {
  406.       goto eosh;
  407.     }
  408.     pos += q;  /* skip certificate */
  409.     PR_fprintf(PR_STDOUT,"           cipher-suites = { ");
  410.     len = GET_SHORT((shv2->cslength));
  411.     for (p = 0; p < len; p += 3) {
  412.       const char *cs_str=NULL;
  413.       PRUint32 cs_int=0;
  414.       cs_int = GET_24((pos+p));
  415.       cs_str = V2CipherString(cs_int);
  416.       PR_fprintf(PR_STDOUT,"n              ");
  417.       PR_fprintf(PR_STDOUT,"(0x%06x) %s", cs_int, cs_str);
  418.     }
  419.     pos += len;
  420.     PR_fprintf(PR_STDOUT,"   }n"); /* End of cipher suites */
  421.     len = (PRUint32)GET_SHORT((shv2->cidlength));
  422.     if (len) {
  423.       PR_fprintf(PR_STDOUT,"           connection-id = { ");
  424.       for (p = 0; p < len; p += 2) {
  425. PR_fprintf(PR_STDOUT,"0x%04x ", (PRUint32)(GET_SHORT((pos + p))));
  426.       }
  427.       PR_fprintf(PR_STDOUT,"   }n"); /* End of connection id */
  428.     }
  429. eosh:
  430.     PR_fprintf(PR_STDOUT,"n              }n"); /* end of ServerHelloV2 */
  431.     if (shv2->sidhit) {
  432.       clientstream.isEncrypted = 1;
  433.       serverstream.isEncrypted = 1;
  434.     }
  435.     break;
  436.   case 5:
  437.     PR_fprintf(PR_STDOUT," [ssl2]  Server Verify V2 {...}n");
  438.     isV2Session = 1;
  439.     break;
  440.   case 6:
  441.     PR_fprintf(PR_STDOUT," [ssl2]  Server Finished V2 {...}n");
  442.     isV2Session = 1;
  443.     break;
  444.   case 7:
  445.     PR_fprintf(PR_STDOUT," [ssl2]  Request Certificate V2 {...}n");
  446.     isV2Session = 1;
  447.     break;
  448.   case 8:
  449.     PR_fprintf(PR_STDOUT," [ssl2]  Client Certificate V2 {...}n");
  450.     isV2Session = 1;
  451.     break;
  452.   default:
  453.     PR_fprintf(PR_STDOUT," [ssl2]  UnknownType 0x%02x {...}n",
  454.   (PRUint32)chv2->type);
  455.     break;
  456.   }
  457. }
  458. void print_ssl3_handshake(unsigned char *tbuf, 
  459.                           unsigned int   alloclen,
  460.                           SSLRecord *    sr)
  461. {
  462.   struct sslhandshake sslh; 
  463.   unsigned char *     hsdata;  
  464.   int                 offset=0;
  465.   PR_fprintf(PR_STDOUT,"   handshake {n");
  466.   while (offset < alloclen) {
  467.     sslh.type = tbuf[offset]; 
  468.     sslh.length = GET_24(tbuf+offset+1);
  469.     hsdata= &tbuf[offset+4];
  470.     if (sslhexparse) print_hex(4,tbuf+offset);
  471.     PR_fprintf(PR_STDOUT,"      type = %d (",sslh.type);
  472.     switch(sslh.type) {
  473.     case 0:  PR_fprintf(PR_STDOUT,"hello_request)n");   break;
  474.     case 1:  PR_fprintf(PR_STDOUT,"client_hello)n");    break;
  475.     case 2:  PR_fprintf(PR_STDOUT,"server_hello)n");    break;
  476.     case 11: PR_fprintf(PR_STDOUT,"certificate)n");     break;
  477.     case 12: PR_fprintf(PR_STDOUT,"server_key_exchange)n");  break;
  478.     case 13: PR_fprintf(PR_STDOUT,"certificate_request)n");  break;
  479.     case 14: PR_fprintf(PR_STDOUT,"server_hello_done)n");    break;
  480.     case 15: PR_fprintf(PR_STDOUT,"certificate_verify)n");   break;
  481.     case 16: PR_fprintf(PR_STDOUT,"client_key_exchange)n");  break;
  482.     case 20: PR_fprintf(PR_STDOUT,"finished)n");         break;
  483.     default: PR_fprintf(PR_STDOUT,"unknown)n");
  484.     }
  485.     PR_fprintf(PR_STDOUT,"      length = %d (0x%06x)n",sslh.length,sslh.length);
  486.     switch (sslh.type) {
  487.     case 1: /* client hello */
  488.       switch (sr->ver_maj)  {
  489.       case 2:  /* ssl version 2 */
  490. PR_fprintf(PR_STDOUT,"         ClientHelloV2 {...}n");
  491. break;
  492.       case 3:  /* ssl version 3 */
  493. {
  494.   int sidlength,pos,csuitelength,w;
  495.   PR_fprintf(PR_STDOUT,"         ClientHelloV3 {n");
  496.   PR_fprintf(PR_STDOUT,"            client_version = {%d, %d}n",
  497.      (PRUint8)hsdata[0],(PRUint8)hsdata[1]);
  498.   PR_fprintf(PR_STDOUT,"            random = {...}n");
  499.   if (sslhexparse) print_hex(32,&hsdata[2]);
  500.   PR_fprintf(PR_STDOUT,"            session ID = {n");
  501.   sidlength = (int)hsdata[2+32];
  502.   PR_fprintf(PR_STDOUT,"                length = %dn",sidlength);
  503.   PR_fprintf(PR_STDOUT,"                contents = {..}n");
  504.   if (sslhexparse) print_hex(sidlength,&hsdata[2+32+1]);
  505.   PR_fprintf(PR_STDOUT,"            }n");
  506.   pos = 2+32+1+sidlength;
  507.   csuitelength = GET_SHORT((hsdata+pos));
  508.   PR_fprintf(PR_STDOUT,"            cipher_suites[%d] = { n",
  509.      csuitelength/2);
  510.   if (csuitelength%1) {
  511.     PR_fprintf(PR_STDOUT,
  512.        "*error in protocol - csuitelength shouldn't be odd*n");
  513.   }
  514.   for (w=0; w<csuitelength; w+=2) {
  515.     const char *cs_str=NULL;
  516.     PRUint32 cs_int=0;
  517.     cs_int = GET_SHORT((hsdata+pos+2+w));
  518.     cs_str = V2CipherString(cs_int);
  519.     PR_fprintf(PR_STDOUT,
  520.       "                (0x%04x) %sn", cs_int, cs_str);
  521.   }
  522.   /*   for (w=0;w<csuitelength;w+=2) {
  523.     PR_fprintf(PR_STDOUT,"0x%04x ",GET_SHORT((hsdata+pos+2+w)));
  524.   } */
  525.   PR_fprintf(PR_STDOUT,"n               }n");
  526.   PR_fprintf(PR_STDOUT,"         }n");
  527. } /* end of ssl version 3 */
  528. break;
  529.       default:
  530. PR_fprintf(PR_STDOUT,"           ClientHelloUndefinedVersion{}n");
  531.       } /* end of switch sr->ver_maj */
  532.       break;
  533.     case 2: /* server hello */
  534.       {
  535. int sidlength, pos;
  536. const char *cs_str=NULL;
  537. PRUint32 cs_int=0;
  538. PR_fprintf(PR_STDOUT,"         ServerHello {n");
  539. PR_fprintf(PR_STDOUT,"            server_version = {%d, %d}n",
  540.    (PRUint8)hsdata[0],(PRUint8)hsdata[1]);
  541. PR_fprintf(PR_STDOUT,"            random = {...}n");
  542. if (sslhexparse) print_hex(32,&hsdata[2]);
  543. PR_fprintf(PR_STDOUT,"            session ID = {n");
  544. sidlength = (int)hsdata[2+32];
  545. PR_fprintf(PR_STDOUT,"                length = %dn",sidlength);
  546. PR_fprintf(PR_STDOUT,"                contents = {..}n");
  547. if (sslhexparse) print_hex(sidlength,&hsdata[2+32+1]);
  548. PR_fprintf(PR_STDOUT,"            }n");
  549. pos = 2+32+1+sidlength;
  550. cs_int = GET_SHORT((hsdata+pos));
  551. cs_str = V2CipherString(cs_int);
  552. PR_fprintf(PR_STDOUT,"            cipher_suite = (0x%04x) %sn",
  553.    cs_int, cs_str);
  554. PR_fprintf(PR_STDOUT,"         }n");
  555.       }
  556.       break;
  557.     case 11: /* certificate */
  558.       {
  559. PRFileDesc *cfd;
  560. int         pos;
  561. int         certslength;
  562. int         certlength;
  563. int         certbytesread = 0;
  564. static int  certFileNumber;
  565. char        certFileName[20];
  566. PR_fprintf(PR_STDOUT,"         CertificateChain {n");
  567. certslength = GET_24(hsdata);
  568. PR_fprintf(PR_STDOUT,"            chainlength = %d (0x%04x)n",
  569. certslength,certslength);
  570. pos = 3;
  571. while (certbytesread < certslength) {
  572.   certlength = GET_24((hsdata+pos));
  573.   pos += 3;
  574.   PR_fprintf(PR_STDOUT,"            Certificate {n");
  575.   PR_fprintf(PR_STDOUT,"               size = %d (0x%04x)n",
  576. certlength,certlength);
  577.   PR_snprintf(certFileName, sizeof certFileName, "cert.%03d",
  578.               ++certFileNumber);
  579.   cfd = PR_Open(certFileName, PR_WRONLY|PR_CREATE_FILE, 0664);
  580.   if (!cfd) {
  581.     PR_fprintf(PR_STDOUT,
  582.                "               data = { couldn't save file '%s' }n",
  583.        certFileName);
  584.   } else {
  585.     PR_Write(cfd, (hsdata+pos), certlength);
  586.     PR_fprintf(PR_STDOUT,
  587.                "               data = { saved in file '%s' }n",
  588.        certFileName);
  589.     PR_Close(cfd);
  590.   }
  591.   PR_fprintf(PR_STDOUT,"            }n");
  592.   pos           += certlength;
  593.   certbytesread += certlength+3;
  594. }
  595. PR_fprintf(PR_STDOUT,"         }n");
  596.       }
  597.       break;
  598.     case 13: /* certificate request */
  599.       if (sslhexparse) { 
  600. PR_fprintf(PR_STDOUT,"         CertificateRequest {n");
  601.         print_hex(sslh.length, hsdata);
  602. PR_fprintf(PR_STDOUT,"         }n");
  603.       }
  604.       break;
  605.     case 16: /* client key exchange */
  606.       {
  607. PR_fprintf(PR_STDOUT,"         ClientKeyExchange {n");
  608. PR_fprintf(PR_STDOUT,"            message = {...}n");
  609. PR_fprintf(PR_STDOUT,"         }n");
  610.       }
  611.       break;
  612.     }  /* end of switch sslh.type */
  613.     offset += sslh.length + 4; /* +4 because of length (3 bytes) and type (1 byte) */
  614.   } /* while */
  615.   PR_fprintf(PR_STDOUT,"   }n");
  616. }
  617. void print_ssl(DataBufferList *s, int length, unsigned char *buffer)
  618. {
  619.   /* --------------------------------------------------------  */
  620.   /* first, create a new buffer object for this piece of data. */
  621.   DataBuffer *db;
  622.   int i,l;
  623.   if (s->size == 0 && length > 0 && buffer[0] >= 32 && buffer[0] < 128) {
  624.     /* Not an SSL record, treat entire buffer as plaintext */
  625.     PR_Write(PR_STDOUT,buffer,length);
  626.     return;
  627.   }
  628.   check_integrity(s);
  629.   i = 0;
  630.   l = length;
  631.   db = PR_NEW(struct _DataBuffer);
  632.   db->buffer = (unsigned char*)PR_Malloc(length);
  633.   db->length = length;
  634.   db->offset = 0;
  635.   memcpy(db->buffer, buffer, length);
  636.   db->next = NULL;
  637.   /* now, add it to the stream */
  638.   if (s->last != NULL) s->last->next = db;
  639.   s->last = db;
  640.   s->size += length;
  641.   if (s->first == NULL) s->first = db;
  642.   check_integrity(s);
  643.   /*------------------------------------------------------- */
  644.   /* now we look at the stream to see if we have enough data to
  645.      decode  */
  646.   while (s->size > 0 ) {
  647.     unsigned char *tbuf = NULL;
  648.     SSLRecord sr;
  649.     unsigned alloclen;
  650.     unsigned recordsize;
  651.     check_integrity(s);
  652.     if ( s->first == NULL) {
  653.       PR_fprintf(PR_STDOUT,"ERROR: s->first is nulln");
  654.       exit(9);
  655.     }
  656.     /* in the case of an SSL 2 client-hello (which is all ssltap supports) */
  657.     /* will have the high-bit set, whereas an SSL 3 client-hello will not  */
  658.     /* SSL2 can also send records that begin with the high bit clear.
  659.      * This code will incorrectly handle them. XXX
  660.      */
  661.     if (isV2Session || s->first->buffer[s->first->offset] & 0x80) {
  662.       /* it's an SSL 2 packet */
  663.       unsigned char lenbuf[3];
  664.       /* first, we check if there's enough data for it to be an SSL2-type
  665.        * record.  What a pain.*/
  666.       if (s->size < sizeof lenbuf) {
  667. partial_packet(length, s->size, sizeof lenbuf);
  668. return;
  669.       }
  670.       /* read the first two bytes off the stream. */
  671.       read_stream_bytes(lenbuf, s, sizeof(lenbuf));
  672.       alloclen = ((unsigned int)(lenbuf[0] & 0x7f) << 8) + lenbuf[1] + 
  673.                  ((lenbuf[0] & 0x80) ? 2 : 3);
  674.       PR_fprintf(PR_STDOUT, "alloclen = %u bytesn", alloclen);
  675.       /* put 'em back on the head of the stream. */
  676.       db = PR_NEW(struct _DataBuffer);
  677.       db->length = sizeof lenbuf;
  678.       db->buffer = (unsigned char*) PR_Malloc(db->length);
  679.       db->offset = 0;
  680.       memcpy(db->buffer, lenbuf, sizeof lenbuf);
  681.       db->next = s->first;
  682.       s->first = db;
  683.       if (s->last == NULL) 
  684. s->last = db;
  685.       s->size += db->length;
  686.       /* if there wasn't enough, go back for more. */
  687.       if (s->size < alloclen) {
  688. check_integrity(s);
  689. partial_packet(length, s->size, alloclen);
  690. return;
  691.       }
  692.       partial_packet(length, s->size, alloclen);
  693.       /* read in the whole record. */
  694.       tbuf = PR_Malloc(alloclen);
  695.       read_stream_bytes(tbuf, s, alloclen);
  696.       print_sslv2(s, tbuf, alloclen);
  697.       PR_FREEIF(tbuf);
  698.       check_integrity(s);
  699.       continue;
  700.     }
  701.     /***********************************************************/
  702.     /* It's SSL v3 */
  703.     /***********************************************************/
  704.     check_integrity(s);
  705.     if (s->size < sizeof(SSLRecord)) {
  706.       partial_packet(length, s->size, sizeof(SSLRecord));
  707.       return;
  708.     }
  709.     read_stream_bytes((unsigned char *)&sr, s, sizeof sr);
  710.     /* we have read the stream bytes. Look at the length of
  711.        the ssl record. If we don't have enough data to satisfy this
  712.        request, then put the bytes we just took back at the head
  713.        of the queue */
  714.     recordsize = GET_SHORT(sr.length);
  715.     if (recordsize > s->size) {
  716.       db = PR_NEW(struct _DataBuffer);
  717.       db->length = sizeof sr;
  718.       db->buffer = (unsigned char*) PR_Malloc(db->length);
  719.       db->offset = 0;
  720.       memcpy(db->buffer, &sr, sizeof sr);
  721.       db->next = s->first;
  722.       /* now, add it back on to the head of the stream */
  723.       s->first = db;
  724.       if (s->last == NULL) 
  725.         s->last = db;
  726.       s->size += db->length;
  727.       check_integrity(s);
  728.       partial_packet(length, s->size, recordsize);
  729.       return;
  730.     }
  731.     partial_packet(length, s->size, recordsize);
  732.     PR_fprintf(PR_STDOUT,"SSLRecord { [%s]n", get_time_string() );
  733.     if (sslhexparse) {
  734.       print_hex(5,(unsigned char*)&sr);
  735.     }
  736.     check_integrity(s);
  737.     PR_fprintf(PR_STDOUT,"   type    = %d (",sr.type);
  738.     switch(sr.type) {
  739.     case 20 :
  740.       PR_fprintf(PR_STDOUT,"change_cipher_spec)n");
  741.       break;
  742.     case 21 :
  743.       PR_fprintf(PR_STDOUT,"alert)n");
  744.       break;
  745.     case 22 :
  746.       PR_fprintf(PR_STDOUT,"handshake)n");
  747.       break;
  748.     case 23 :
  749.       PR_fprintf(PR_STDOUT,"application_data)n");
  750.       break;
  751.     default:
  752.       PR_fprintf(PR_STDOUT,"unknown)n");
  753.       break;
  754.     }
  755.     PR_fprintf(PR_STDOUT,"   version = { %d,%d }n",
  756.        (PRUint32)sr.ver_maj,(PRUint32)sr.ver_min);
  757.     PR_fprintf(PR_STDOUT,"   length  = %d (0x%x)n",
  758.      (PRUint32)GET_SHORT(sr.length), (PRUint32)GET_SHORT(sr.length));
  759.     alloclen = recordsize;
  760.     PR_ASSERT(s->size >= alloclen);
  761.     if (s->size >= alloclen) {
  762.       tbuf = (unsigned char*) PR_Malloc(alloclen);
  763.       read_stream_bytes(tbuf, s, alloclen);
  764.       if (s->isEncrypted) {
  765. PR_fprintf(PR_STDOUT,"            < encrypted >n");
  766.       } else 
  767.       switch(sr.type) {
  768.       case 20 : /* change_cipher_spec */
  769. if (sslhexparse) print_hex(alloclen,tbuf);
  770. s->isEncrypted = 1;  /* mark to say we can only dump hex form now on */
  771. break;
  772.       case 21 : /* alert */
  773. switch(tbuf[0]) {
  774. case 1: PR_fprintf(PR_STDOUT, "   warning: "); break;
  775. case 2: PR_fprintf(PR_STDOUT, "   fatal: "); break;
  776. default: PR_fprintf(PR_STDOUT, "   unknown level %d: ", tbuf[0]); break;
  777. }
  778. switch(tbuf[1]) {
  779. case 0:   PR_fprintf(PR_STDOUT, "close notifyn"); break;
  780. case 10:  PR_fprintf(PR_STDOUT, "unexpected messagen"); break;
  781. case 20:  PR_fprintf(PR_STDOUT, "bad record macn"); break;
  782. case 21:  PR_fprintf(PR_STDOUT, "decryption failedn"); break;
  783. case 22:  PR_fprintf(PR_STDOUT, "record overflown"); break;
  784. case 30:  PR_fprintf(PR_STDOUT, "decompression failuren"); break;
  785. case 40:  PR_fprintf(PR_STDOUT, "handshake failuren"); break;
  786. case 41:  PR_fprintf(PR_STDOUT, "no certificaten"); break;
  787. case 42:  PR_fprintf(PR_STDOUT, "bad certificaten"); break;
  788. case 43:  PR_fprintf(PR_STDOUT, "unsupported certificaten"); break;
  789. case 44:  PR_fprintf(PR_STDOUT, "certificate revokedn"); break;
  790. case 45:  PR_fprintf(PR_STDOUT, "certificate expiredn"); break;
  791. case 46:  PR_fprintf(PR_STDOUT, "certificate unknownn"); break;
  792. case 47:  PR_fprintf(PR_STDOUT, "illegal parametern"); break;
  793. case 48:  PR_fprintf(PR_STDOUT, "unknown CAn"); break;
  794. case 49:  PR_fprintf(PR_STDOUT, "access deniedn"); break;
  795. case 50:  PR_fprintf(PR_STDOUT, "decode errorn"); break;
  796. case 51:  PR_fprintf(PR_STDOUT, "decrypt errorn"); break;
  797. case 60:  PR_fprintf(PR_STDOUT, "export restrictionn"); break;
  798. case 70:  PR_fprintf(PR_STDOUT, "protocol versionn"); break;
  799. case 71:  PR_fprintf(PR_STDOUT, "insufficient securityn"); break;
  800. case 80:  PR_fprintf(PR_STDOUT, "internal errorn"); break;
  801. case 90:  PR_fprintf(PR_STDOUT, "user canceledn"); break;
  802. case 100: PR_fprintf(PR_STDOUT, "no renegotiationn"); break;
  803. default:  PR_fprintf(PR_STDOUT, "unknown error %dn", tbuf[1]); break;
  804. }
  805. if (sslhexparse) print_hex(alloclen,tbuf);
  806. break;
  807.       case 22 : /* handshake */ 
  808.         print_ssl3_handshake( tbuf, alloclen, &sr );
  809. break;
  810.       case 23 : /* application data */
  811.       default:
  812. print_hex(alloclen,tbuf);
  813. break;
  814.       }
  815.     }
  816.     PR_fprintf(PR_STDOUT,"}n");
  817.     PR_FREEIF(tbuf);
  818.     check_integrity(s);
  819.   }
  820. }
  821. void print_hex(int amt, unsigned char *buf) {
  822.   int i,j,k;
  823.   char *string = (char*)PR_Malloc(5000);
  824.   char t[20];
  825.   for(i=0;i<amt;i++) {
  826.     t[1] =0;
  827.     if (i%16 ==0) {  /* if we are at the beginning of a line */
  828.       PR_fprintf(PR_STDOUT,"%4x:",i); /* print the line number  */
  829.       strcpy(string,"");
  830.     }
  831.     if (i%4 == 0) {
  832.       PR_fprintf(PR_STDOUT," ");
  833.     }
  834.     t[0] = buf[i];
  835.     if (!isprint(t[0])) {
  836.       t[0] = '.';
  837.     }
  838.     if (fancy)  {
  839.       switch (t[0]) {
  840.       case '<':
  841.         strcpy(t,"&lt;");
  842.         break;
  843.       case '>':
  844.         strcpy(t,"&gt;");
  845.         break;
  846.       case '&':
  847.         strcpy(t,"&amp;");
  848.         break;
  849.       }
  850.     }
  851.     strcat(string,t);
  852.     PR_fprintf(PR_STDOUT,"%02x ",(PRUint8) buf[i]);
  853.     /* if we've reached the end of the line - add the string */
  854.     if (i%16 == 15) PR_fprintf(PR_STDOUT," | %sn",string);
  855.   }
  856.   /* we reached the end of the buffer,*/
  857.   /* do we have buffer left over? */
  858.   j = i%16;
  859.   if (j > 0) {
  860.     for (k=0;k<(16-j);k++) PR_fprintf(PR_STDOUT,"   ");
  861.     PR_fprintf(PR_STDOUT," |%sn",string);
  862.   }
  863.   PR_Free(string);
  864. }
  865. void Usage(void) {
  866.   PR_fprintf(PR_STDERR, "SSLTAP (C) 1997, 1998 Netscape Communications Corporation.n");
  867.   PR_fprintf(PR_STDERR, "Usage: ssltap [-vhfsxl] [-p port] hostname:portn");
  868.   PR_fprintf(PR_STDERR, "   -v      [prints version string]n");
  869.   PR_fprintf(PR_STDERR, "   -h      [outputs hex instead of ASCII]n");
  870.   PR_fprintf(PR_STDERR, "   -f      [turn on Fancy HTML coloring]n");
  871.   PR_fprintf(PR_STDERR, "   -s      [turn on SSL decoding]n");
  872.   PR_fprintf(PR_STDERR, "   -x      [turn on extra SSL hex dumps]n");
  873.   PR_fprintf(PR_STDERR, "   -p port [specify rendezvous port (default 1924)]n");
  874.   PR_fprintf(PR_STDERR, "   -l      [loop - continue to wait for more connections]n");
  875. }
  876. void
  877. showErr(const char * msg) {
  878.   PRErrorCode  err       = PR_GetError();
  879.   const char * errString;
  880.   if (err == PR_UNKNOWN_ERROR)
  881.     err = PR_CONNECT_RESET_ERROR; /* bug in NSPR. */
  882.   errString = SECU_Strerror(err);
  883.   if (!errString)
  884.     errString = "(no text available)";
  885.   PR_fprintf(PR_STDERR, "Error %d: %s: %s", err, errString, msg);
  886. }
  887. int main(int argc,  char *argv[])
  888. {
  889.   char *hostname;
  890.   PRUint16 rendport=DEFPORT,port;
  891.   PRHostEnt hp;
  892.   PRStatus r;
  893.   PRNetAddr na_client,na_server,na_rend;
  894.   PRFileDesc *s_server,*s_client,*s_rend; /*rendezvous */
  895.   char netdbbuf[PR_NETDB_BUF_SIZE];
  896.   int c_count=0;
  897.   PLOptState *optstate;
  898.   PLOptStatus status;
  899.   optstate = PL_CreateOptState(argc,argv,"fvxhslp:");
  900.     while ((status = PL_GetNextOpt(optstate)) == PL_OPT_OK) {
  901.     switch (optstate->option) {
  902.     case 'f':
  903.       fancy++;
  904.       break;
  905.     case 'h':
  906.       hexparse++;
  907.       break;
  908.     case 'v':
  909.       PR_fprintf(PR_STDOUT,"Version: %sn",VERSIONSTRING);
  910.       break;
  911.     case 's':
  912.       sslparse++;
  913.       break;
  914.     case 'x':
  915.       sslhexparse++;
  916.       break;
  917.     case 'l':
  918.       looparound++;
  919.       break;
  920.     case 'p':
  921.       rendport = atoi(optstate->value);
  922.       break;
  923.     case '':
  924.       hostname = PL_strdup(optstate->value);
  925.     }
  926.   }
  927.   if (status == PL_OPT_BAD)
  928.     Usage();
  929.   if (fancy) {
  930.     if (!hexparse && !sslparse) {
  931.       PR_fprintf(PR_STDERR,
  932. "Note: use of -f without -s or -h not recommended, n"
  933. "as the output looks a little strange. It may be useful, howevern");
  934.     }
  935.   }
  936.   if(! hostname ) Usage(), exit(2);
  937.   {
  938.     char *colon = (char *)strchr(hostname, ':');
  939.     if (!colon) {
  940.       PR_fprintf(PR_STDERR,
  941.       "You must specify the host AND port you wish to connect ton");
  942.       Usage(), exit(3);
  943.     }
  944.     port = atoi(&colon[1]);
  945.     *colon = '';
  946.     if (port == 0) {
  947. PR_fprintf(PR_STDERR, "Port must be a nonzero number.n");
  948. exit(4);
  949.       }
  950.   }
  951.   /* find the 'server' IP address so we don't have to look it up later */
  952.   if (fancy) {
  953.       PR_fprintf(PR_STDOUT,"<HTML><HEAD><TITLE>SSLTAP output</TITLE></HEAD>n");
  954.       PR_fprintf(PR_STDOUT,"<BODY><PRE>n");
  955.     }
  956.   PR_fprintf(PR_STDERR,"Looking up "%s"...n", hostname);
  957.   r = PR_GetHostByName(hostname,netdbbuf,PR_NETDB_BUF_SIZE,&hp);
  958.   if (r) {
  959.     showErr("Host Name lookup failedn");
  960.     exit(5);
  961.   }
  962.   PR_EnumerateHostEnt(0,&hp,0,&na_server);
  963.   PR_InitializeNetAddr(PR_IpAddrNull,port,&na_server);
  964.   /* set up the port which the client will connect to */
  965.   r = PR_InitializeNetAddr(PR_IpAddrAny,rendport,&na_rend);
  966.   if (r == PR_FAILURE) {
  967.     PR_fprintf(PR_STDERR,
  968.     "PR_InitializeNetAddr(,%d,) failed with error %dn",PR_GetError());
  969.     exit(0);
  970.   }
  971.   s_rend = PR_NewTCPSocket();
  972.   if (!s_rend) {
  973.     showErr("Couldn't create socketn");
  974.     exit(6);
  975.   }
  976.   if (PR_Bind(s_rend, &na_rend )) {
  977.     PR_fprintf(PR_STDERR,"Couldn't bind to port %d (error %d)n",rendport, PR_GetError());
  978.     exit(-1);
  979.   }
  980.   if ( PR_Listen(s_rend, 5)) {
  981.     showErr("Couldn't listenn");
  982.     exit(-1);
  983.   }
  984.   PR_fprintf(PR_STDERR,"Proxy socket ready and listeningn");
  985.   do { /* accept one connection and process it. */
  986.       PRPollDesc pds[2];
  987.       s_client = PR_Accept(s_rend,&na_client,PR_SecondsToInterval(3600));
  988.       if (s_client == NULL) {
  989. showErr("accept timed outn");
  990. exit(7);
  991.       }
  992.       s_server = PR_NewTCPSocket();
  993.       if (s_server == NULL) {
  994. showErr("couldn't open new socket to connect to server n");
  995. exit(8);
  996.       }
  997.       r = PR_Connect(s_server,&na_server,PR_SecondsToInterval(5));
  998.       if ( r == PR_FAILURE )
  999.         {
  1000.   showErr("Couldn't connectn");
  1001.   return -1;
  1002.         }
  1003.       if (looparound) {
  1004. if (fancy)  PR_fprintf(PR_STDOUT,"<p><HR><H2>");
  1005. PR_fprintf(PR_STDOUT,"Connection #%d [%s]n", c_count+1,
  1006.                      get_time_string());
  1007. if (fancy)  PR_fprintf(PR_STDOUT,"</H2>");
  1008. }
  1009.       PR_fprintf(PR_STDOUT,"Connected to %s:%dn", hostname, port);
  1010. #define PD_C 0
  1011. #define PD_S 1
  1012.       pds[PD_C].fd = s_client;
  1013.       pds[PD_S].fd = s_server;
  1014.       pds[PD_C].in_flags = PR_POLL_READ;
  1015.       pds[PD_S].in_flags = PR_POLL_READ;
  1016.       /* make sure the new connections don't start out encrypted. */
  1017.       clientstream.isEncrypted = 0;
  1018.       serverstream.isEncrypted = 0;
  1019.       isV2Session = 0;
  1020.       while( (pds[PD_C].in_flags & PR_POLL_READ) != 0 ||
  1021.              (pds[PD_S].in_flags & PR_POLL_READ) != 0 )
  1022.         {  /* Handle all messages on the connection */
  1023.   PRInt32 amt;
  1024.   PRInt32 wrote;
  1025.   unsigned char buffer[ TAPBUFSIZ ];
  1026.   amt = PR_Poll(pds,2,PR_INTERVAL_NO_TIMEOUT);
  1027.   if (amt <= 0) {
  1028.     if (amt)
  1029. showErr( "PR_Poll failed.n");
  1030.     else
  1031. showErr( "PR_Poll timed out.n");
  1032.     break;
  1033.   }
  1034.   if (pds[PD_C].out_flags & PR_POLL_EXCEPT) {
  1035.     showErr( "Exception on client-side socket.n");
  1036.     break;
  1037.   }
  1038.   if (pds[PD_S].out_flags & PR_POLL_EXCEPT) {
  1039.     showErr( "Exception on server-side socket.n");
  1040.     break;
  1041.   }
  1042. /* read data, copy it to stdout, and write to other socket */
  1043.   if ((pds[PD_C].in_flags  & PR_POLL_READ) != 0 &&
  1044.       (pds[PD_C].out_flags & PR_POLL_READ) != 0 ) {
  1045.     amt = PR_Read(s_client, buffer, sizeof(buffer));
  1046.     if ( amt < 0)  {
  1047.       showErr( "Client socket read failed.n");
  1048.       break;
  1049.     }
  1050.     if( amt == 0 ) {
  1051.       PR_fprintf(PR_STDOUT, "Read EOF on Client socket. [%s]n",
  1052.                             get_time_string() );
  1053.       pds[PD_C].in_flags &= ~PR_POLL_READ;
  1054.       PR_Shutdown(s_server, PR_SHUTDOWN_SEND);
  1055.       continue;
  1056.     }
  1057.     PR_fprintf(PR_STDOUT,"--> [n");
  1058.     if (fancy) PR_fprintf(PR_STDOUT,"<font color=blue>");
  1059.     if (hexparse)  print_hex(amt, buffer);
  1060.     if (sslparse)  print_ssl(&clientstream,amt,buffer);
  1061.     if (!hexparse && !sslparse)  PR_Write(PR_STDOUT,buffer,amt);
  1062.     if (fancy) PR_fprintf(PR_STDOUT,"</font>");
  1063.     PR_fprintf(PR_STDOUT,"]n");
  1064.     wrote = PR_Write(s_server, buffer, amt);
  1065.     if (wrote != amt )  {
  1066.       if (wrote < 0) {
  1067.         showErr("Write to server socket failed.n");
  1068. break;
  1069.       } else {
  1070. PR_fprintf(PR_STDERR, "Short write to server socket!n");
  1071.       }
  1072.     }
  1073.   }  /* end of read from client socket. */
  1074. /* read data, copy it to stdout, and write to other socket */
  1075.   if ((pds[PD_S].in_flags  & PR_POLL_READ) != 0 &&
  1076.       (pds[PD_S].out_flags & PR_POLL_READ) != 0 ) {
  1077.     amt = PR_Read(s_server, buffer, sizeof(buffer));
  1078.     if ( amt < 0)  {
  1079.       showErr( "error on server-side socket.n");
  1080.       break;
  1081.     }
  1082.     if( amt == 0 ) {
  1083.       PR_fprintf(PR_STDOUT, "Read EOF on Server socket. [%s]n",
  1084.                             get_time_string() );
  1085.       pds[PD_S].in_flags &= ~PR_POLL_READ;
  1086.       PR_Shutdown(s_client, PR_SHUTDOWN_SEND);
  1087.       continue;
  1088.     } 
  1089.     PR_fprintf(PR_STDOUT,"<-- [n");
  1090.     if (fancy) PR_fprintf(PR_STDOUT,"<font color=red>");
  1091.     if (hexparse)  print_hex(amt, (unsigned char *)buffer);
  1092.     if (sslparse)  print_ssl(&serverstream,amt,(unsigned char *)buffer);
  1093.     if (!hexparse && !sslparse)  PR_Write(PR_STDOUT,buffer,amt);
  1094.     if (fancy) PR_fprintf(PR_STDOUT,"</font>");
  1095.     PR_fprintf(PR_STDOUT,"]n");
  1096.     wrote = PR_Write(s_client, buffer, amt);
  1097.     if (wrote != amt )  {
  1098.       if (wrote < 0) {
  1099.         showErr("Write to client socket failed.n");
  1100. break;
  1101.       } else {
  1102. PR_fprintf(PR_STDERR, "Short write to client socket!n");
  1103.       }
  1104.     }
  1105.   } /* end of read from server socket. */
  1106. /* Loop, handle next message. */
  1107.         } /* handle messages during a connection loop */
  1108.       PR_Close(s_client);
  1109.       PR_Close(s_server);
  1110.       flush_stream(&clientstream);
  1111.       flush_stream(&serverstream);
  1112.       c_count++;
  1113.       PR_fprintf(PR_STDERR,"Connection %d Complete [%s]n", c_count,
  1114.                             get_time_string() );
  1115.     }  while (looparound); /* accept connection and process it. */
  1116.     PR_Close(s_rend);
  1117.     return 0;
  1118. }