myssl_openssl.c

来自「网络爬虫程序」· C语言 代码 · 共 788 行 · 第 1/2 页

C
788
字号
/***************************************************************************//*    This code is part of WWW grabber called pavuk                        *//*    Copyright (c) 1997 - 2001 Stefan Ondrejicka                          *//*    Distributed under GPL 2 or later                                     *//***************************************************************************/#include "config.h"#if defined(USE_SSL) && defined(USE_SSL_IMPL_OPENSSL)#include <arpa/inet.h>#include <assert.h>#include <netdb.h>#include <netinet/in.h>#include <stdio.h>#include <string.h>#include <sys/socket.h>#include <time.h>#include "bufio.h"#include "errcode.h"#include "http.h"#include "myssl.h"#include "tools.h"/* Let's try to cache session ids! *//* Very unlikely to have more than 4 session ids active, * so use cheap slow lookup */typedef struct session_entry{  int len;  int family;  struct sockaddr_in addr;  SSL_SESSION *session;} session_entry;#define N_SESSIONS 10static session_entry *session_map[N_SESSIONS];static int session_map_init = -1;static int cmp_sockaddr(struct sockaddr_in *a, struct sockaddr_in *b){  return (a->sin_addr.s_addr != b->sin_addr.s_addr)    || (a->sin_port != b->sin_port);}static void dump_session_id(SSL_SESSION * s){  int i;  if(!s)  {    DEBUG_SSL("No session ID to dump?\n");    return;  }  DEBUG_SSL("ssl_session_id(%d) = [", s->session_id_length);  for(i = 0; i < s->session_id_length; i++)  {    DEBUG_SSL(" %02x", s->session_id[i]);  }  DEBUG_SSL("]\n");  return;}static void map_init(void){  int i;  if(session_map_init != -1)    return;  LOCK_SSL_MAP;  if(session_map_init == -1)  {    for(i = 0; i < N_SESSIONS; i++)      session_map[i] = 0;    session_map_init = 1;  }  UNLOCK_SSL_MAP;}static SSL_SESSION *cache_locate_session_by_addr(struct sockaddr_in *addr,  int dolock){  int i;  map_init();  if(!addr)  {    DEBUG_SSL("No addr to locate session id by?\n");    return 0;  }  DEBUG_SSL("Trying to locate session id for ip %s:%d\n",    inet_ntoa(addr->sin_addr), ntohs(addr->sin_port));  if(dolock)  {    LOCK_SSL_MAP;  }  for(i = 0; i < N_SESSIONS; i++)  {    if(session_map[i] && !cmp_sockaddr(addr, &session_map[i]->addr))    {      if(dolock)      {        UNLOCK_SSL_MAP;      }      DEBUG_SSL("returning slot %d id for %s:%d\n", i,        inet_ntoa(session_map[i]->addr.sin_addr),        ntohs(session_map[i]->addr.sin_port));      dump_session_id(session_map[i]->session);      return session_map[i]->session;    }  }  if(dolock)  {    UNLOCK_SSL_MAP;  }  DEBUG_SSL("not cached\n");  return 0;}static void cache_session_by_addr(struct sockaddr_in *addr, SSL * con){  session_entry *p;  int i;  SSL_SESSION *s;  map_init();  LOCK_SSL_MAP;  /* see if this session is already in the map */  s = cache_locate_session_by_addr(addr, 0);  if(s)  {    /* Yes, so simply return */    UNLOCK_SSL_MAP;    DEBUG_SSL("session id for %s:%d already cached\n",      inet_ntoa(addr->sin_addr), ntohs(addr->sin_port));    dump_session_id(s);    return;  }  /* Install session in empty entry in map */  assert(con);  s = SSL_get1_session(con);  if(s == 0)  {    DEBUG_SSL("(cache session) No session id to cache?\n");    UNLOCK_SSL_MAP;    return;  }  for(i = 0; i < N_SESSIONS; i++)  {    if(session_map[i] == 0)    {      p = malloc(sizeof(session_entry));      p->addr = *addr;      p->session = s;      session_map[i] = p;      UNLOCK_SSL_MAP;      DEBUG_SSL("(cache_session) session for %s:%d cached in slot %d\n",        inet_ntoa(addr->sin_addr), ntohs(addr->sin_port), i);      dump_session_id(p->session);      return;    }  }  DEBUG_SSL("(cache_session) You don't have a big enough map\n");  /* FIXME: Replace oldest entry */  UNLOCK_SSL_MAP;  return;}static void cache_remove_session(SSL_SESSION * sess){  DEBUG_SSL("Turn your head and cough\n");  /* FIXME: WRITE ME */}static int SSL_FD(SSL * ssl){  if(ssl == NULL)  {    return -1;  }  return BIO_get_fd(SSL_get_rbio(ssl), NULL);}static int ssl_new_session_cb(SSL * ssl, SSL_SESSION * sess){  int sock = SSL_FD(ssl);  struct sockaddr_in sa;  struct sockaddr_in *sp;  socklen_t alen = sizeof(sa);  SSL_SESSION *cached;  assert(sock != -1);  DEBUG_SSL("ssl_new_session_cb() called\n");  if(getpeername(sock, (struct sockaddr *) &sa, &alen))    return 1;  DEBUG_SSL("ssl_new_session_cb(%s:%d)\n",    inet_ntoa(sa.sin_addr), ntohs(sa.sin_port));  /*   * Search in cache.   */  cached = cache_locate_session_by_addr(&sa, 1);  if(cached)  {    DEBUG_SSL("SSL session for %s:%d already cached.\n",      inet_ntoa(sa.sin_addr), ntohs(sa.sin_port));    return 1;  }  sp = malloc(sizeof(struct sockaddr_in));  if(sp == NULL)    return 1;  *sp = sa;  cached = SSL_get1_session(ssl);  assert(cached == sess);  cache_session_by_addr(sp, ssl);  DEBUG_SSL("SSL session for %s:%d now cached\n",    inet_ntoa(sa.sin_addr), ntohs(sa.sin_port));  return 1;}static SSL_SESSION *ssl_get_session_cb(SSL * ssl, unsigned char *data,  int len, int *copy){  DEBUG_SSL("ssl_get_session_cb()\n");  return NULL;}static void ssl_remove_session_cb(SSL_CTX * ssl, SSL_SESSION * sess){  cache_remove_session(sess);}static void ssl_assign_cached_session(SSL * ssl, struct sockaddr_in *peer){  SSL_SESSION *sess;  DEBUG_SSL("ssl_assign_cached_session() called\n");  if(peer == NULL)    return;  DEBUG_SSL("ssl_assign_cached_session(%s:%d)\n",    inet_ntoa(peer->sin_addr), ntohs(peer->sin_port));  sess = cache_locate_session_by_addr(peer, 1);  if(sess == NULL)  {    DEBUG_SSL("SSL session for %s:%d not cached yet\n",      inet_ntoa(peer->sin_addr), ntohs(peer->sin_port));    return;  }  DEBUG_SSL("Setting SSL session for %s:%d\n",    inet_ntoa(peer->sin_addr), ntohs(peer->sin_port));  dump_session_id(sess);  if(SSL_set_session(ssl, sess) == 0)  {    DEBUG_SSL("Failed to assign cached SSL session for %s:%d\n",      inet_ntoa(peer->sin_addr), ntohs(peer->sin_port));    return;  }  DEBUG_SSL("SSL session for %s:%d found in cache\n",    inet_ntoa(peer->sin_addr), ntohs(peer->sin_port));}static void ssl_assign_cached_session_by_doc(SSL * ssl, doc * docp){  char *hp;  int alen;  struct sockaddr_in addr;  int family;  map_init();  DEBUG_SSL("assign_cached_session_by_doc()\n");  if(!docp)  {    DEBUG_SSL("(assign cached session by doc) No doc?\n");    return;  }  if(!docp->doc_url)  {    DEBUG_SSL("(assign cached session by doc) Doc has no url?\n");    return;  }  hp = docp->doc_url->p.http.host;  if(dns_gethostbyname(hp, &alen, (char *) &addr.sin_addr, &family) < 0)  {    DEBUG_SSL("(assign cached session by doc) Unable to get dns for %s\n",      hp);    return;  }  assert(family == AF_INET);  assert(alen == sizeof(addr.sin_addr));  addr.sin_port = htons(docp->doc_url->p.http.port);  ssl_assign_cached_session(ssl, &addr);}/* Most of this code is inspired by example programs from SSLeay package */static int my_ssl_passwd_callback(char *buf, int num, int verify){  if(verify)    xprintf(1, "%s\n", buf);  else  {    if(num > strlen(priv_cfg.ssl_cert_passwd))    {      strcpy(buf, priv_cfg.ssl_cert_passwd);      return strlen(buf);    }  }  return 0;}static void my_ssl_info_callback(const SSL * con, int where, int ret){  if(where & SSL_CB_LOOP)  {    DEBUG_SSL("SSL_CB_LOOP: (%s) %s\n", SSL_state_string(con),      SSL_state_string_long(con));  }  else if(where & SSL_CB_ALERT)  {    DEBUG_SSL("SSL_CB_ALERT: %s:%s\n",      SSL_alert_type_string_long(ret), SSL_alert_desc_string_long(ret));  }  else if((where & SSL_CB_EXIT) && (ret <= 0))  {    /* If we print 'unknown' errors, we end up spewing the same */    /* message dozens of times. This avoids that */    if(SSL_alert_type_string(ret)[0] == 'U')      return;    DEBUG_SSL("SSL_CB_EXIT: [%s:%s] (%s) %s\n",      SSL_alert_type_string_long(ret),      SSL_alert_desc_string_long(ret),      SSL_state_string(con), SSL_state_string_long(con));  }}static int my_ssl_verify_callback(int ok, X509_STORE_CTX * ctx){  char buf[256];  X509 *err_cert;  int err, depth;  err_cert = X509_STORE_CTX_get_current_cert(ctx);  err = X509_STORE_CTX_get_error(ctx);  depth = X509_STORE_CTX_get_error_depth(ctx);  X509_NAME_oneline(X509_get_subject_name(err_cert), buf, 256);  DEBUG_SSL("Depth: %d\n", depth);  DEBUG_SSL("Subject: %s\n", buf);  if(!ok)  {    DEBUG_SSL("verify error:num=%d:%s\n", err,      X509_verify_cert_error_string(err));    if(0 >= depth)      ok = 1;    else

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?