diff -cr ../src.orig/client.c ./client.c
*** ../src.orig/client.c	Thu Mar 13 13:13:59 2003
--- ./client.c	Wed Mar 19 13:48:55 2003
***************
*** 92,97 ****
--- 92,112 ----
      c->opt=opt;
      c->local_rfd.fd=rfd;
      c->local_wfd.fd=wfd;
+ 
+     if(options.info_dir) {
+ 	sprintf(c->info_fname, "%s/pid.%d", options.info_dir, getpid());
+ 	c->info_file = fopen(c->info_fname, "w");
+ 	if(!c->info_file) {
+ 	    log(LOG_ERR, "failed to create: %s (continuing)", c->info_fname);
+ 	    c->info_fname[0] = 0;
+ 	} else {
+ 	    log(LOG_DEBUG, "connection detail to be written to: %s",
+ 					c->info_fname);
+ 	    fprintf(c->info_file, "# connection details\n"
+ 				"STUNNEL_PID=%d\n", getpid());
+ 	}
+     }
+ 
      return c;
  }
  
***************
*** 184,189 ****
--- 199,209 ----
          log(LOG_NOTICE, "%s connected from %s:%d", c->opt->servname,
              c->accepting_address, ntohs(c->addr.sin_port));
      }
+     if(c->info_file) {
+ 	fprintf(c->info_file, "SERVICE=\"%s\"\n", c->opt->servname);
+ 	fprintf(c->info_file, "REMOTE_HOST=\"%s\"\nREMOTE_PORT=%d\n",
+ 		c->accepting_address, ntohs(c->addr.sin_port));
+     }
      return 0; /* OK */
  }
  
***************
*** 220,225 ****
--- 240,274 ----
      }
  #endif
      log(LOG_DEBUG, "Remote FD=%d initialized", fd);
+ 
+     if(c->info_file) {
+ 	struct sockaddr_in addr;
+ 	int addrlen = sizeof(addr);
+ 	if(getsockname(fd, (struct sockaddr *)&addr, &addrlen)) {
+ 	    // ignore error
+ 	} else {
+ 	    char newname[STRLEN];
+ 
+ 	    /* record our end of the tunnel, and change name of file to match */
+ 	    enter_critical_section(CRIT_NTOA); /* inet_ntoa is not mt-safe */
+ 		fprintf(c->info_file, "LOCAL_HOST=\"%s\"\nLOCAL_PORT=%d\n",
+ 		    inet_ntoa(addr.sin_addr), ntohs(addr.sin_port));
+ 		sprintf(newname, "%s/conn.%s:%d", 
+ 		    options.info_dir, 
+ 		    inet_ntoa(addr.sin_addr), ntohs(addr.sin_port));
+ 	    leave_critical_section(CRIT_NTOA);
+ 
+ 	    /* done with file, close it now */
+ 	    fprintf(c->info_file, "# EOF\n");
+ 	    fclose(c->info_file);
+ 	    c->info_file = NULL;
+ 
+ 	    /* rename so it's easy for the client to find */
+ 	    rename(c->info_fname, newname);
+ 	    strcpy(c->info_fname, newname);
+ 	}
+     }
+ 
      c->remote_fd.fd=fd;
      c->remote_fd.is_socket=1; /* Always! */
      if(set_socket_options(fd, 2)<0)
***************
*** 567,572 ****
--- 616,632 ----
                  reset(c->local_wfd.fd, "linger (local_wfd)");
         }
      }
+ 	/* Cleanup connection info file which isn't useful anymore */
+     if(options.info_dir) {
+ 	if(c->info_file) {
+ 	    fclose(c->info_file);
+ 	    c->info_file = NULL;
+ 	}
+ 	if(c->info_fname) {
+ 	    unlink(c->info_fname);		/* ignore errors */
+ 	    log(LOG_INFO, "removed info file: %s", c->info_fname);
+ 	}
+     }
  }
  
  static void print_cipher(CLI *c) { /* print negotiated cipher */
***************
*** 584,589 ****
--- 644,670 ----
      if(len>0)
          buf[len-1]='\0';
      log(LOG_INFO, "Negotiated ciphers: %s", buf);
+ 
+     if(c->info_file) {
+ 	X509 *peer;
+ 
+ 	fprintf(c->info_file, "CIPHER_DESC=\"%s\"\n", buf);
+ 	fprintf(c->info_file, "CIPHER_ALGO=\"%s\"\n",
+ 					SSL_CIPHER_get_name(cipher));
+ 	fprintf(c->info_file, "CIPHER_BITS=%d\n",
+ 					SSL_CIPHER_get_bits(cipher, NULL));
+ 
+ 	peer = SSL_get_peer_certificate(c->ssl);
+ 	if(peer) {
+ 	    X509_NAME_oneline(X509_get_subject_name(peer), buf, STRLEN);
+ 	    fprintf(c->info_file, "SSL_CLIENT_DN=\"%s\"\n", buf);
+ 
+ 	    X509_NAME_oneline(X509_get_issuer_name(peer), buf, STRLEN);
+ 	    fprintf(c->info_file, "SSL_CLIENT_I_DN=\"%s\"\n", buf);
+ 
+ 	    X509_free(peer);
+ 	}
+     }
  #endif
  }
  
***************
*** 860,865 ****
--- 941,950 ----
          safe_ntoa(c->connecting_address, addr.sin_addr);
          log(LOG_DEBUG, "%s connecting %s:%d", c->opt->servname,
              c->connecting_address, ntohs(addr.sin_port));
+ 	if(c->info_file) {
+ 	    fprintf(c->info_file, "TUNNEL_HOST=\"%s\"\nTUNNEL_PORT=%d\n",
+ 			c->connecting_address, ntohs(addr.sin_port));
+ 	}
          if(!connect(s, (struct sockaddr *)&addr, sizeof(addr)))
              return s; /* no error -> success */
          error=get_last_socket_error();
diff -cr ../src.orig/options.c ./options.c
*** ../src.orig/options.c	Thu Mar 13 13:13:59 2003
--- ./options.c	Thu Mar 13 14:39:30 2003
***************
*** 555,560 ****
--- 555,584 ----
          break;
      }
  
+     /* infodir */
+     switch(cmd) {
+     case CMD_INIT:
+         options.info_dir=NULL;
+         break;
+     case CMD_EXEC:
+         if(strcasecmp(opt, "infodir"))
+             break;
+         if(arg[0]) { /* not empty */
+ 	    if(strlen(arg) > STRLEN - 20) return "infodir pathname too long";
+             options.info_dir=stralloc(arg);
+         } else {
+             options.info_dir=NULL;
+ 	}
+         return NULL; /* OK */
+     case CMD_DEFAULT:
+         break;
+     case CMD_HELP:
+         log_raw("%-15s = writable directory to store connection info into",
+             "infodir");
+         break;
+     }
+ 
+ 
      if(cmd==CMD_EXEC)
          return option_not_found;
      return NULL; /* OK */
diff -cr ../src.orig/prototypes.h ./prototypes.h
*** ../src.orig/prototypes.h	Thu Mar 13 13:13:59 2003
--- ./prototypes.h	Thu Mar 13 15:18:55 2003
***************
*** 104,109 ****
--- 104,110 ----
      int verify_level;
      int verify_use_only_my;
      long ssl_options;
+     char *info_dir;                         /* directory for connection info */
  
          /* some global data for stunnel.c */
  #ifndef USE_WIN32
***************
*** 228,233 ****
--- 229,236 ----
      FD *sock_rfd, *sock_wfd; /* Read and write socket descriptors */
      FD *ssl_rfd, *ssl_wfd; /* Read and write SSL descriptors */
      int sock_bytes, ssl_bytes; /* Bytes written to socket and ssl */
+     FILE *info_file; /* text file with connection information */
+     char info_fname[STRLEN]; /* file name (full path) for info_file */
  } CLI;
  
  extern int max_clients;
