"Fossies" - the Fresh Open Source Software Archive

Member "sslproxy-1.1.2/ssl_proxy.c" (27 Feb 2009, 20136 Bytes) of package /linux/privat/old/sslproxy-1.1.2.tar.gz:


As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) C and C++ source code syntax highlighting (style: standard) with prefixed line numbers and code folding option. Alternatively you can here view or download the uninterpreted source code file. For more information about "ssl_proxy.c" see the Fossies "Dox" file reference documentation.

    1 /* Symbion SSL Proxy
    2  * Copyright (C) 2000-2005 Szilard Hajba
    3  *
    4  * This program is free software; you can redistribute it and/or
    5  * modify it under the terms of the GNU General Public License as
    6  * published by the Free Software Foundation; either version 2 of
    7  * the License, or (at your option) any later version.
    8  *
    9  * This program is distributed in the hope that it will be useful,
   10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
   11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
   12  * General Public License for more details.
   13  *
   14  * You should have received a copy of the GNU General Public
   15  * License along with this library; if not, write to the Free
   16  * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
   17  */
   18 
   19 //#define VERSION "1.0.7"
   20 #define MAX_CONNECTION 32
   21 //#define CS_BUFFER_LEN 2
   22 //#define SC_BUFFER_LEN 40
   23 #define CS_BUFFER_LEN 2048
   24 #define SC_BUFFER_LEN 8192
   25 #define PEM_DIR "/etc/symbion"
   26 #define CERT_FILE "cert.pem"
   27 #define KEY_FILE "key.pem"
   28 #define SLEEP_US 50000
   29 
   30 #include <stdio.h>
   31 #include <stdarg.h>
   32 #include <syslog.h>
   33 #include <unistd.h>
   34 #include <signal.h>
   35 #include <netinet/in.h>
   36 #include <sys/un.h>
   37 #include <sys/types.h>
   38 #include <sys/socket.h>
   39 #include <netdb.h>
   40 #include <fcntl.h>
   41 #include <string.h>
   42 #include <pwd.h>
   43 #include <arpa/inet.h>
   44 
   45 #include <openssl/ssl.h>
   46 #include <openssl/err.h>
   47 #include <openssl/x509.h>
   48 #include <openssl/pem.h>
   49 #include <openssl/crypto.h>
   50 #include <openssl/rand.h>
   51 
   52 int debug_flag=0;
   53 int fg_flag=0;
   54 int info_flag=0;
   55 int max_conn=MAX_CONNECTION;
   56 int cs_buflen=CS_BUFFER_LEN, sc_buflen=SC_BUFFER_LEN;
   57 char *server_addr="0.0.0.0";
   58 int server_port=443;
   59 char *client_addr="localhost";
   60 int client_port=80;
   61 char *cert_file=PEM_DIR"/"CERT_FILE, *key_file=PEM_DIR"/"KEY_FILE;
   62 char *chroot_dir=NULL, *set_uid=NULL;
   63 char *verify_ca_file=NULL, *verify_ca_dir=NULL;
   64 struct passwd *pass;
   65 
   66 int server_socket;
   67 SSL_CTX *server_ssl_ctx;
   68 //X509 *ssl_public_cert;
   69 //RSA *ssl_private_key;
   70 
   71 int client_s_family=AF_INET;
   72 struct sockaddr *client_sa;
   73 struct sockaddr_in client_sa_in;
   74 struct sockaddr_un client_sa_un;
   75 int client_sa_len;
   76 
   77 typedef enum {cs_disconnected, cs_accept, cs_connecting, cs_connected, cs_closing} ConnStatus;
   78 typedef struct {
   79     ConnStatus stat;            // Status of the connection
   80     int server_sock;            // Server side socket id
   81     struct sockaddr_in server_sa;   // Server's socket address
   82     int server_sa_len;          // ^^^^^^^^^^^^^^^^^^^^^^^'s len
   83     SSL *ssl_conn;          // SSL connection structure pointer
   84     int client_sock;            // Client side socket id
   85     char *csbuf;            // Server side write buffer
   86     char *csbuf_b;          // Server side write buffer begin ptr
   87     char *csbuf_e;          // Server side write buffer end ptr
   88 //    int c_end_req;            // Client requested connection close
   89     char *scbuf;            // Client side write buffer
   90     char *scbuf_b;          // Client side write buffer begin ptr
   91     char *scbuf_e;          // Client side write buffer end ptr
   92 //    int s_end_req;            // Server requested connection close
   93 } Conn;
   94 Conn *conn=NULL;
   95 
   96 void conn_close_client(Conn *conn);
   97 void conn_close_server(Conn *conn);
   98 
   99 void debug(char *format,...) {
  100     if (debug_flag) {
  101     va_list args;
  102     va_start(args, format);
  103     vfprintf(stderr, format, args);
  104     putc('\n', stderr);
  105     va_end(args);
  106     }
  107 }
  108 
  109 void plog(int level, const char *cls, const char *format,...) {
  110     char str[8192];
  111     va_list args;
  112     va_start(args, format);
  113     vsprintf(str, format, args);
  114     va_end(args);
  115     syslog(level, "%.256s: %.256s\n", cls, str);
  116     if (debug_flag) debug("LOG: %.256s: %.256s", cls, str);
  117 }
  118 
  119 void _sleep()
  120 {
  121     struct timeval tv={0, SLEEP_US};
  122     select(0, NULL, NULL, NULL, &tv);
  123 }
  124 
  125 // ============================================== Server
  126 int server_init(char *addr, int port, int maxconn) {
  127     struct sockaddr_in server;
  128     long ipaddr;
  129 
  130     server_socket=socket(AF_INET, SOCK_STREAM, 0);
  131     if (server_socket<0) {
  132     perror("socket()");
  133     exit(1);
  134     }
  135     server.sin_family=AF_INET;
  136     inet_pton(AF_INET, addr, &ipaddr);
  137     server.sin_addr.s_addr=ipaddr;
  138 //    server.sin_addr.s_addr=htons(INADDR_ANY);
  139     server.sin_port=htons(port);
  140     if (bind(server_socket, (struct sockaddr *)&server, sizeof(server)) < 0) {
  141     perror("bind()");
  142     exit(1);
  143     }
  144     listen(server_socket, maxconn);
  145     fcntl(server_socket, F_SETFL, O_NONBLOCK);
  146     return server_socket;
  147 }
  148 
  149 void server_done(void) {
  150     int ci;
  151     shutdown(server_socket, 2);
  152     _sleep();
  153     close(server_socket);
  154     for (ci=0; ci<max_conn; ci++)
  155     if (conn[ci].stat==cs_accept && conn[ci].stat==cs_connected) {
  156         conn_close_client(&conn[ci]);
  157         conn_close_server(&conn[ci]);
  158     }
  159 }
  160 
  161 // ============================================== Server SSL
  162 static RSA *tmp_rsa_cb(SSL *ssl, int export, int key_len) {
  163     static RSA *rsa=NULL; 
  164     debug("Generating new RSA key.. (ex=%d, kl=%d)", export, key_len);
  165     if (export) {
  166     rsa=RSA_generate_key(key_len, RSA_F4, NULL, NULL);
  167     } else {
  168     plog(LOG_ERR, "tmp_rsa_callback()", "Export not set");
  169     }
  170     return rsa;
  171 }
  172 
  173 static int verify_callback(int preverify_ok, X509_STORE_CTX *ctx)
  174 {
  175     fprintf(stderr, "preverify: %d\n", preverify_ok);
  176     return preverify_ok;
  177 }
  178 
  179 void server_ssl_init(void) {
  180 //    FILE *f;
  181     SSLeay_add_ssl_algorithms();
  182     SSL_load_error_strings();
  183     server_ssl_ctx=SSL_CTX_new(SSLv23_server_method());
  184     SSL_CTX_set_cipher_list(server_ssl_ctx, "HIGH");
  185     if (!SSL_CTX_set_default_verify_paths(server_ssl_ctx))  {
  186     fprintf(stderr, "cannot set default path\n");
  187     exit(1);
  188     }
  189 
  190     if (!SSL_CTX_use_certificate_chain_file(server_ssl_ctx, cert_file)) {
  191     fprintf(stderr,"error reading certificate: %.256s\n",
  192         ERR_error_string(ERR_get_error(), NULL));
  193     exit(1);
  194     }
  195     if (!SSL_CTX_use_PrivateKey_file(server_ssl_ctx, key_file, SSL_FILETYPE_PEM)) {
  196     fprintf(stderr,"error reading private key: %.256s\n",
  197         ERR_error_string(ERR_get_error(), NULL));
  198     exit(1);
  199     }
  200     SSL_CTX_set_tmp_rsa_callback(server_ssl_ctx, tmp_rsa_cb);
  201 
  202     if (verify_ca_file || verify_ca_dir) {
  203 /*
  204     STACK_OF(X509_NAME) *certs;
  205     certs=SSL_load_client_CA_file(verify_ca_file);
  206     if (certs) {
  207         SSL_CTX_set_client_CA_list(server_ssl_ctx, certs);
  208     } else {
  209         fprintf(stderr,"error reading client CA list: %.256s\n",
  210             ERR_error_string(ERR_get_error(), NULL));
  211         exit(1);
  212     }
  213 */
  214     SSL_CTX_load_verify_locations(server_ssl_ctx, verify_ca_file, verify_ca_dir);
  215     SSL_CTX_set_verify(server_ssl_ctx, SSL_VERIFY_PEER | SSL_VERIFY_FAIL_IF_NO_PEER_CERT | SSL_VERIFY_CLIENT_ONCE, verify_callback);
  216     }
  217 
  218 //    SSL_CTX_set_session_cache_mode(server_ssl_ctx, SSL_SESS_CACHE_OFF);
  219 }
  220 
  221 // ============================================== CLient
  222 void client_init(char *addr, int port) {
  223     if (port) { // TCP connection
  224     struct hostent *hp;
  225     client_sa_in.sin_family=AF_INET;
  226     hp=gethostbyname(addr);
  227     if (!hp) {
  228         perror("gethostbyname()");
  229         exit(1);
  230     }
  231     bcopy(hp->h_addr, &client_sa_in.sin_addr, hp->h_length);
  232     client_sa_in.sin_port=htons(port);
  233     client_sa=(struct sockaddr *)&client_sa_in;
  234     client_sa_len=sizeof(client_sa_in);
  235     } else { // UNIX domain socket
  236     client_sa_un.sun_family=AF_UNIX;
  237     if (addr) {
  238         if (strlen(addr)>=sizeof(client_sa_un.sun_path)) {
  239         fprintf(stderr, "client_init(): client address too long (allowed: %d)\n",
  240             (int)sizeof(client_sa_un.sun_path));
  241         exit(1);
  242         } else strcpy(client_sa_un.sun_path, addr);
  243     } else {
  244         fprintf(stderr, "client_init(): client address missing\n");
  245         exit(1);
  246     }
  247     client_sa=(struct sockaddr *)&client_sa_un;
  248     client_sa_len=sizeof(client_sa_un);
  249     }
  250 }
  251 
  252 // ============================================== Connection
  253 struct sockaddr_in server_sa;
  254 unsigned int server_sa_len;
  255 int conn_accept(void) {
  256     int i;
  257     // Initialize SSL connection (server side)
  258     int s=accept(server_socket, (struct sockaddr *)&server_sa, &server_sa_len);
  259     if (s<=0) return 0;
  260     debug("conn_accept(): Client connected");
  261     for (i=0; i<max_conn && conn[i].stat!=cs_disconnected; i++);
  262     if (i==max_conn) {
  263     plog(LOG_ERR, "accept()", "Internal error");
  264     close(s);
  265     return 0;
  266     }
  267     debug("accept(): sn=%d sock=%d", i, s);
  268     conn[i].server_sock=s;
  269     bcopy(&server_sa, &conn[i].server_sa, server_sa_len);
  270     conn[i].server_sa_len=server_sa_len;
  271     conn[i].ssl_conn=SSL_new(server_ssl_ctx);
  272     SSL_set_fd(conn[i].ssl_conn, conn[i].server_sock);
  273 //    if (!SSL_use_RSAPrivateKey(conn[i].ssl_conn, ssl_private_key)) {
  274 //  plog(LOG_ERR, "accept()", "Error reading private key");
  275 //  SSL_free(conn[i].ssl_conn);
  276 //  close(conn[i].server_sock);
  277 //  return -1;
  278 //    }
  279 //    if (!SSL_use_certificate(conn[i].ssl_conn, ssl_public_cert)) {
  280 //  plog(LOG_ERR, "accept()", "Error reading public certificate");
  281 //  SSL_free(conn[i].ssl_conn);
  282 //  close(conn[i].server_sock);
  283 //  return -1;
  284 //    }
  285 //    SSL_set_verify(conn[i].ssl_conn, 0, NULL);
  286     BIO_set_nbio(SSL_get_rbio(conn[i].ssl_conn), 0);
  287     BIO_set_nbio(SSL_get_wbio(conn[i].ssl_conn), 0);
  288     fcntl(conn[i].server_sock, F_SETFL, O_NONBLOCK);
  289     conn[i].stat=cs_accept;
  290     conn[i].scbuf_b=conn[i].scbuf; conn[i].scbuf_e=conn[i].scbuf;
  291     conn[i].csbuf_b=conn[i].csbuf; conn[i].csbuf_e=conn[i].csbuf;
  292     return conn[i].server_sock;
  293 }
  294 
  295 int conn_ssl_accept(Conn *conn) {
  296     int ret=SSL_accept(conn->ssl_conn);
  297 //    debug("SSL_accept: %d, SSL_want=%d", ret, SSL_want(conn->ssl_conn));
  298     if (ret<=0) {
  299     unsigned long err=SSL_get_error(conn->ssl_conn, ret);
  300 //  debug("SSL_accept: error:%d", err);
  301     if (err==SSL_ERROR_WANT_READ || err==SSL_ERROR_WANT_WRITE) {
  302         return 1;
  303     } else {
  304         plog(LOG_ERR, "accept()", "Accept failed: %.256s", ERR_error_string(err, NULL));
  305         ERR_print_errors_fp(stderr);
  306     }
  307 
  308 //  if ((err=ERR_get_error())) {
  309 //      plog(LOG_ERR, "accept()", "Access failed: %.256s", ERR_error_string(err, NULL));
  310 //  } else if (SSL_want(conn->ssl_conn)>1) return 0;;
  311     debug("SSL_accept: disconnected.");
  312     SSL_free(conn->ssl_conn);
  313     close(conn->server_sock);
  314     conn->server_sock=conn->client_sock=0;
  315     conn->stat=cs_disconnected;
  316     return -1;
  317 /*
  318     } else if (ret==1) {
  319     // Successfull negotiation
  320     X509 *peer;
  321     if (!(peer=SSL_get_peer_certificate(conn->ssl_conn))
  322         || SSL_get_verify_result(conn->ssl_conn)!=X509_V_OK) {
  323         unsigned long err=SSL_get_error(conn->ssl_conn, ret);
  324         plog(LOG_ERR, "accept()", "SSL handshake: %.256s", ERR_error_string(err, NULL));
  325         ERR_print_errors_fp(stderr);
  326         debug("SSL_accept: disconnected.");
  327         SSL_free(conn->ssl_conn);
  328         close(conn->server_sock);
  329         conn->stat=cs_disconnected;
  330         return -1;
  331     }
  332 */
  333     }
  334 
  335     // Connect to server (client side)
  336     conn->client_sock=socket(client_s_family, SOCK_STREAM, 0);
  337     if (conn->client_sock<0) {
  338     plog(LOG_ERR, "socket()", strerror(errno));
  339     SSL_free(conn->ssl_conn);
  340     close(conn->server_sock);
  341     conn->server_sock=conn->client_sock=0;
  342     conn->stat=cs_disconnected;
  343     return -1;
  344     }
  345     fcntl(conn->client_sock, F_SETFL, O_NONBLOCK);
  346     conn->stat=cs_connecting;
  347 /*
  348     ret=connect(conn->client_sock, client_sa, client_sa_len);
  349     if (ret<0) {
  350     if (errno==EINPROGRESS) return 0;
  351     plog(LOG_ERR, "connect()", strerror(errno));
  352     close(conn->client_sock);
  353     SSL_free(conn->ssl_conn);
  354     close(conn->server_sock);
  355     conn->stat=cs_disconnected;
  356     return -1;
  357     } else {
  358     conn->stat=cs_connected;
  359     debug("Connection negotiated");
  360     if (info_flag) {
  361         conn->csbuf_e+=snprintf(conn->csbuf_b, cs_buflen, "#@ip=%s \r\n", "1.1.1.1");
  362         debug("INFO: %s", conn->csbuf);
  363     }
  364     }
  365 */
  366     return 0;
  367 }
  368 
  369 /*
  370 void conn_close(Conn *conn) {
  371     debug("conn_close(): s=%d", conn->server_sock);
  372     shutdown(conn->client_sock, 2);
  373     close(conn->client_sock);
  374     SSL_free(conn->ssl_conn);
  375     shutdown(conn->server_sock, 2);
  376     close(conn->server_sock);
  377     conn->stat=cs_disconnected;
  378 }
  379 */
  380 
  381 void conn_close_client(Conn *conn) {
  382     debug("conn_close_client(): s=%d", conn->client_sock);
  383     shutdown(conn->client_sock, 2);
  384     close(conn->client_sock);
  385     conn->client_sock=-1;
  386     if (conn->server_sock==-1) conn->stat=cs_disconnected;
  387 }
  388 
  389 void conn_close_server(Conn *conn) {
  390     debug("conn_close_server(): s=%d", conn->server_sock);
  391     SSL_free(conn->ssl_conn);
  392     shutdown(conn->server_sock, 2);
  393     close(conn->server_sock);
  394     conn->server_sock=-1;
  395     if (conn->client_sock==-1) conn->stat=cs_disconnected;
  396 }
  397 
  398 void sighandler(int signum) {
  399     switch (signum) {
  400     case SIGINT:
  401     case SIGTERM:
  402         plog(LOG_NOTICE, "signal", "Interrupt/terminate");
  403         server_done();
  404         // If it's possible to remove pid file, try it..
  405         // It's not guaranteed to succeed, because of setuid
  406         if (!chroot_dir) unlink("/var/run/ssl_proxy.pid");
  407         exit(0);
  408     default:;
  409     }
  410 }
  411 
  412 int main(int argc, char **argv) {
  413     FILE *pidfile;
  414     int c, pid, i;
  415     char *p1, *p2;
  416 
  417     while ((c=getopt(argc, argv, "hdfim:s:c:C:K:u:r:v:V:U:D:")) != EOF)
  418     switch (c) {
  419         case 'h':
  420         fprintf(stderr, "Symbion SSL proxy " VERSION "\n"
  421             "usage: %.256s [-d] [-f] [-i] [-s <listen address>] [-c <client address>]\n"
  422             "              [-m <max connection>] [-C <certificate file>] [-K <key file>]\n"
  423             "              [-u <user/uid>] [-r <chroot dir>]\n"
  424             "              [-v <trusted CA file>] [-V <trusted CA dir>]\n"
  425             "              [-U <upward buffer (default 2048)>] [-D <downward buffer (default 8192)>]\n"
  426             "        <lister address> = [<host>:]<port>\n"
  427             "        <client address> = [<host>:]<port> | unix:<path>\n", argv[0]);
  428         fprintf(stderr, "       %.256s -h\n", argv[0]);
  429         exit(0);
  430         case 'd':
  431         debug_flag=1;
  432         break;
  433         case 'f':
  434         fg_flag=1;
  435         break;
  436         case 'i':
  437         info_flag=1;
  438         break;
  439         case 'm':
  440         max_conn=atoi(optarg);
  441         break;
  442         case 's':
  443         server_port=atoi(optarg);
  444         p1=strtok(optarg, ":");
  445         p2=strtok(NULL, "");
  446         if (p2) {
  447             server_addr=p1;
  448             server_port=atoi(p2);
  449         } else {
  450             server_addr="0.0.0.0"; server_port=atoi(p1);
  451         }
  452         break;
  453         case 'c':
  454         p1=strtok(optarg, ":");
  455         p2=strtok(NULL, "");
  456         if (p2) {
  457             if (!strcmp(p1, "unix")) {
  458             client_s_family=AF_UNIX;
  459             client_addr=p2;
  460             client_port=0;
  461             } else {
  462             client_addr=p1;
  463             client_port=atoi(p2);
  464             }
  465         } else {
  466             client_addr="localhost"; client_port=atoi(p1);
  467         }
  468         break;
  469         case 'C':
  470         cert_file=optarg;
  471         break;
  472         case 'K':
  473         key_file=optarg;
  474         break;
  475         case 'u':
  476         set_uid=optarg;
  477         break;
  478         case 'r':
  479         chroot_dir=optarg;
  480         break;
  481         case 'v':
  482         verify_ca_file=optarg;
  483         break;
  484         case 'V':
  485         verify_ca_dir=optarg;
  486         break;
  487         case 'U':
  488         cs_buflen=atoi(optarg);
  489         break;
  490         case 'D':
  491         sc_buflen=atoi(optarg);
  492         break;
  493     }
  494     debug("Symbion SSL proxy " VERSION);
  495     signal(SIGINT, sighandler);
  496     signal(SIGTERM, sighandler);
  497     signal(SIGPIPE, SIG_IGN);
  498     // This must be done before process_security_init(), because server_port
  499     // can be a privileged port, ssl_init use files from the filesystem.
  500     if (client_s_family==AF_INET)
  501     debug("Using server: family=INET host=%.256s port=%d", client_addr, client_port);
  502     else
  503     debug("Using server: family=UNIX path=%.256s", client_addr);
  504     server_init(server_addr, server_port, max_conn);
  505     server_ssl_init();
  506     client_init(client_addr, client_port);
  507     if (!debug_flag && !fg_flag && (pid=fork())) {
  508     pidfile=fopen("/var/run/ssl_proxy.pid", "w");
  509     if (pidfile) {
  510         fprintf(pidfile, "%d\n", pid);
  511         fclose(pidfile);
  512     }
  513     exit(0);
  514     }
  515 
  516     // Process security
  517     if (set_uid) {
  518     if (!(pass=getpwnam(set_uid))) {perror("getpwnam()"); exit(1);}
  519     }
  520     if (chroot_dir) {
  521     debug("Changing root directory to '%.256s'..", chroot_dir);
  522     if (chroot(chroot_dir)<0) {perror("chroot()"); exit(1);}
  523     chdir("/");
  524     }
  525     if (set_uid) {
  526     debug("Changing userID to %.256s..", set_uid);
  527     setgid(pass->pw_gid);
  528     setuid(pass->pw_uid);
  529     }
  530 
  531     conn=malloc(max_conn*sizeof(Conn));
  532     bzero(conn, max_conn*sizeof(Conn));
  533     for (i=0; i<max_conn; i++) {
  534     Conn *c=&conn[i];
  535     c->scbuf=malloc(sc_buflen);
  536     c->scbuf_b=c->scbuf; c->scbuf_e=c->scbuf;
  537     c->csbuf=malloc(cs_buflen);
  538     c->csbuf_b=c->csbuf; c->csbuf_e=c->csbuf;
  539     }
  540 
  541     openlog("sslproxy", LOG_PID, LOG_DAEMON);
  542     if (client_s_family==AF_INET)
  543     plog(LOG_NOTICE, "init", "version " VERSION " started (family=INET host=%.256s port=%d).",
  544         client_addr, client_port);
  545     else
  546     plog(LOG_NOTICE, "init", "version " VERSION " started (family=UNIX path=%.256s).",
  547         client_addr);
  548 
  549     while (1) {
  550     int event=0, ci;
  551     // Check for incoming connections
  552     if ((i=conn_accept())>0) {
  553         debug("Client connected");
  554         event=1;
  555     }
  556     for (ci=0; ci<max_conn; ci++) {
  557         Conn *cn=&conn[ci];
  558         int l;
  559         switch (cn->stat) {
  560         case cs_accept:
  561             i=conn_ssl_accept(cn);
  562 //          cn->c_end_req=0; cn->s_end_req=0;
  563             event|=(i==0);
  564             break;
  565         case cs_connecting:
  566             if (connect(cn->client_sock, client_sa, client_sa_len)<0) {
  567             if (errno==EINPROGRESS) break;
  568 //          if (errno==EALREADY) break;
  569 perror("connecting()");
  570             plog(LOG_ERR, "connect()", strerror(errno));
  571             close(cn->client_sock);
  572             SSL_free(cn->ssl_conn);
  573             close(cn->server_sock);
  574             cn->stat=cs_disconnected;
  575             } else {
  576             cn->stat=cs_connected;
  577             debug("Connection negotiated");
  578             if (info_flag) {
  579                 struct sockaddr_in client_addr;
  580                 unsigned int client_addr_len=sizeof(client_addr);
  581                 X509 *cert;
  582                 X509_NAME *xn=NULL;
  583                 char peer_cn[256]="";
  584                 getpeername(cn->server_sock,
  585                     (struct sockaddr *)&client_addr,
  586                     &client_addr_len);
  587                 cert=SSL_get_peer_certificate(cn->ssl_conn);
  588                 if (cert) {
  589                 xn=X509_get_subject_name(cert);
  590                 X509_NAME_get_text_by_NID(xn, NID_commonName, peer_cn, 256);
  591                 }
  592                 cn->csbuf_e+=snprintf(cn->csbuf_b, cs_buflen,
  593                     "#@ip=%s port=%d%s%s%s\r\n",
  594                     inet_ntoa(client_addr.sin_addr),
  595                     htons(client_addr.sin_port), xn?" cn='":"", peer_cn, xn?"'":"");
  596                 debug("INFO: %p %d %s", cn, cn->server_sock, cn->csbuf);
  597             }
  598             }
  599             break;
  600         case cs_connected:
  601             // Check if data is available on client side
  602             if ((l=cs_buflen-(cn->csbuf_e-cn->csbuf))) {
  603             i=SSL_read(cn->ssl_conn, cn->csbuf_e, l);
  604             if (!i) { // End of connection
  605                 debug("Close request: %d", ci);
  606                 cn->stat=cs_closing; event=1;
  607 //              cn->c_end_req=1;
  608             } else if (i<0) { // Error
  609                 if (errno!=EAGAIN) {
  610                 debug("SSL_read() errno: %d", errno);
  611                 cn->stat=cs_closing; event=1;
  612 //              cn->c_end_req=1;
  613                 }
  614             } else cn->csbuf_e+=i;
  615             }
  616         case cs_closing:
  617             // Send buffered data to server
  618             if ((l=cn->csbuf_e-cn->csbuf_b)>0) {
  619             i=write(cn->client_sock, cn->csbuf_b, l); event=1;
  620             if (debug_flag) write(2, cn->csbuf_b, l);
  621             if (i>=0) {
  622                 cn->csbuf_b+=i;
  623             } else {
  624                 if (errno!=EAGAIN) {
  625                 debug("write() errno: %d", errno);
  626                 cn->csbuf_b=cn->csbuf_e=cn->csbuf;
  627                 cn->stat=cs_closing;
  628                 }
  629             }
  630             if (cn->csbuf_b==cn->csbuf_e) {
  631                 cn->csbuf_b=cn->csbuf_e=cn->csbuf;
  632 //              if (cn->c_end_req) conn_close(cn);
  633             }
  634             }
  635             if (cn->stat==cs_closing && cn->csbuf_e==cn->csbuf_b) conn_close_client(cn);
  636         default:;
  637         }
  638         if (cn->stat==cs_connected || cn->stat==cs_closing) {
  639         // Check if data is available on server side
  640         if ((l=sc_buflen-(cn->scbuf_e-cn->scbuf)) && cn->client_sock>=0) {
  641             i=read(cn->client_sock, cn->scbuf_e, l);
  642             if (!i) { // End of connection
  643             cn->stat=cs_closing; event=1;
  644 //          cn->s_end_req=1;
  645             } else if (i<0) { // Error
  646             if (errno!=EAGAIN) {
  647                 debug("read errno: %d", errno);
  648                 cn->stat=cs_closing; event=1;
  649 //              cn->s_end_req=1;
  650             }
  651             } else cn->scbuf_e+=i;
  652         }
  653         // Send buffered data to client
  654         if ((l=cn->scbuf_e-cn->scbuf_b)>0 && cn->server_sock>=0) {
  655             i=SSL_write(cn->ssl_conn, cn->scbuf_b, l);
  656             if (i>0) debug("transfer: buf=%d, b=%d, l=%d, i=%d", cn->scbuf,
  657                 cn->scbuf_b, l, i);
  658             if (i>=0) {
  659             cn->scbuf_b+=i; event=1;
  660             } else if (errno!=EAGAIN) {
  661             debug("SSL_write() errno: %d", errno);
  662             cn->scbuf_b=cn->scbuf_e=cn->scbuf;
  663             event=1;
  664             }
  665             if (cn->scbuf_b==cn->scbuf_e) {
  666             cn->scbuf_b=cn->scbuf_e=cn->scbuf;
  667 //          if (cn->s_end_req) conn_close(cn);
  668             }
  669         }
  670         if (cn->stat==cs_closing && cn->scbuf_e==cn->scbuf_b) conn_close_server(cn);
  671         }
  672     }
  673     if (!event) _sleep();
  674     }
  675     return 0;
  676 }