Created
August 5, 2009 17:12
-
-
Save temoto/162834 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
static struct addrinfo tcp_hints = { | |
.ai_flags = AI_NUMERICSERV, | |
.ai_socktype = SOCK_STREAM, | |
.ai_family = AF_INET, | |
}; | |
static struct addrinfo https_ai; | |
static struct addrinfo | |
make_https_addrinfo (void) { | |
int r = 0; | |
struct addrinfo *res, out; | |
r = getaddrinfo("localhost", "443", &tcp_hints, &res); | |
if (0 != r) | |
error(1, 0, "crawl_item: error making addrinfo template"); | |
out = res[0]; | |
freeaddrinfo(res); | |
return out; | |
} | |
static int | |
check_socket_errors (evcom_socket *socket) { | |
crawl_item *self; | |
const char *domain; | |
assert(NULL != socket); | |
self = (crawl_item *)socket->data; | |
domain = (const char *)self->domain; | |
if (0 != socket->errorno) { | |
printf("%s\terror\tsocket error\n", domain); | |
error(0, 0, "check_domain: socket error: %d\n", socket->errorno); | |
evcom_socket_force_close(socket); | |
return socket->errorno; | |
} | |
if (GNUTLS_E_SUCCESS != socket->gnutls_errorno) { | |
printf("%s\terror\tGNU TLS error\n", domain); | |
if (GNUTLS_E_FATAL_ALERT_RECEIVED == socket->gnutls_errorno) | |
error(0, 0, "check_domain: GNU TLS fatal alert: %s\n", gnutls_alert_get_name(gnutls_alert_get(socket->session))); | |
else | |
error(0, 0, "check_domain: GNU TLS: %s\n", gnutls_strerror(socket->gnutls_errorno)); | |
evcom_socket_force_close(socket); | |
return socket->gnutls_errorno; | |
} | |
return 0; | |
} | |
static void | |
on_connect (evcom_socket *socket) { | |
int r = 0; | |
crawl_item *self; | |
assert(NULL != socket); | |
self = (crawl_item *)socket->data; | |
printf("debug: connected\n"); | |
r = check_socket_errors(socket); | |
if (0 == r) | |
crawl_item_finish(self); | |
evcom_socket_force_close(socket); | |
} | |
static void | |
on_close (evcom_socket *socket) { | |
crawl_item *self; | |
assert(NULL != socket); | |
self = (crawl_item *)socket->data; | |
check_socket_errors(socket); | |
// important resource freeing is done here | |
crawl_item_free(self); | |
printf("debug: connection closed\n"); | |
} | |
static void | |
on_timeout (evcom_socket *socket) { | |
const crawl_item *self; | |
const char *domain; | |
assert(NULL != socket); | |
self = (const crawl_item *)socket->data; | |
domain = (const char *)self->domain; | |
printf("%s\ttimeout\n", domain); | |
evcom_socket_force_close(socket); | |
} | |
int | |
crawl_item_init (/*@notnull@*/ crawl_item *self, | |
/*@notnull@*/ const char *domain, | |
unsigned int timeout) { | |
self->domain[0] = '\0'; | |
strncat(self->domain, domain, sizeof(self->domain) - 1); | |
evcom_socket_init(&self->socket, timeout); | |
self->socket.on_connect = on_connect; | |
self->socket.on_close = on_close; | |
self->socket.on_timeout = on_timeout; | |
// self backpointer for callbacks | |
self->socket.data = self; | |
return 0; | |
} | |
int | |
crawl_item_start (/*@notnull@*/ crawl_item *self) { | |
int r = 0; | |
const char *domain; | |
assert(NULL != self); | |
domain = (const char *)self->domain; | |
assert(NULL != domain); | |
r = crawler_dns_resolve4_start(self); | |
if (0 != r) { | |
printf("%s\terror\tresolve start error\n", self->domain); | |
return r; | |
} | |
//https_ai = make_https_addrinfo(); | |
//crawl_item_connect(self); | |
return 0; | |
} | |
int | |
crawl_item_connect (/*@notnull@*/ crawl_item *self) { | |
int r = 0; | |
size_t i = 0; | |
const char *domain; | |
printf("debug: crawl_item: connecting\n"); | |
https_ai = make_https_addrinfo(); | |
assert(NULL != self); | |
domain = (const char *)self->domain; | |
//self->addr_count++; | |
for (i = 0; i < self->addr_count; i++) { | |
self->ainfo[i] = https_ai; // use HTTPS addrinfo template | |
self->ainfo[i].ai_addrlen = sizeof(struct sockaddr_in); | |
self->ainfo[i].ai_addr = (struct sockaddr*)&(self->saddr[i]); | |
if (i + 1 < self->addr_count) | |
self->ainfo[i].ai_next = &(self->ainfo[i + 1]); | |
tls_session_init(self); | |
r = evcom_socket_connect(&self->socket, &(self->ainfo[i])); | |
if (0 == r) { | |
printf("debug: crawl_item: socket_connect ok\n"); | |
evcom_socket_attach(EV_DEFAULT_ &self->socket); | |
return 0; | |
} | |
printf("debug: crawl_item: cleaning failed session\n"); | |
gnutls_deinit(self->socket.session); | |
} | |
// no successful connect happened. propagate fail | |
printf("%s\terror\tconnect\n", domain); | |
self->socket.session = NULL; | |
return r; | |
} | |
/* | |
* Reads certificate info, if any. Outputs crawling results. | |
*/ | |
void | |
crawl_item_finish (/*@notnull@*/ crawl_item *self) { | |
int r; | |
const gnutls_datum_t *cert_list = NULL; | |
unsigned int cert_list_size = 0; | |
gnutls_x509_crt_t cert; | |
time_t expiration_time, activation_time; | |
const struct tm *expiration_time_tm = NULL, *activation_time_tm = NULL; | |
char expiration_time_str[64], activation_time_str[64]; | |
gnutls_pk_algorithm_t algo = 0; | |
unsigned int bits = 0; | |
const char *algo_name = NULL; | |
size_t size = 0; | |
char dn[1024], issuer_dn[1024]; | |
evcom_socket *client; | |
const char *domain; | |
printf("debug: crawl_item: finishing\n"); | |
assert(NULL != self); | |
client = &self->socket; | |
assert(NULL != client); | |
assert(NULL != client->session); | |
domain = (const char *)self->domain; | |
if (GNUTLS_CRT_X509 != gnutls_certificate_type_get(client->session)) { | |
printf("%s\terror\tcertificate type is not x.509\n", domain); | |
return; | |
} | |
cert_list = gnutls_certificate_get_peers(client->session, &cert_list_size); | |
if (NULL == cert_list) { | |
printf("%s\terror\tgetting certificates. Got: %u\n", domain, cert_list_size); | |
return; | |
} | |
r = gnutls_x509_crt_init(&cert); | |
if (GNUTLS_E_SUCCESS != r) { | |
printf("%s\terror\tinit certificate variable\n", domain); | |
goto cleanup; | |
} | |
r = gnutls_x509_crt_import(cert, &cert_list[0], GNUTLS_X509_FMT_DER); | |
if (GNUTLS_E_SUCCESS != r) { | |
printf("%s\terror\tGNU TLS import certificate\n", domain); | |
goto cleanup; | |
} | |
activation_time = gnutls_x509_crt_get_activation_time(cert); | |
activation_time_tm = gmtime(&activation_time); | |
size = strftime(activation_time_str, sizeof(activation_time_str) - 1, "%FT%T", activation_time_tm); | |
if (0 == size) { | |
printf("%s\terror\tin strftime for cert activation time: %ld\n", domain, activation_time); | |
goto cleanup; | |
} | |
expiration_time = gnutls_x509_crt_get_expiration_time(cert); | |
expiration_time_tm = gmtime(&expiration_time); | |
size = strftime(expiration_time_str, sizeof(expiration_time_str) - 1, "%FT%T", expiration_time_tm); | |
if (0 == size) { | |
printf("%s\terror\tin strftime for cert expiration time: %ld\n", domain, expiration_time); | |
goto cleanup; | |
} | |
algo = gnutls_x509_crt_get_pk_algorithm (cert, &bits); | |
size = sizeof(dn); | |
memset(dn, 0, size); | |
r = gnutls_x509_crt_get_dn(cert, dn, &size); | |
if (GNUTLS_E_SUCCESS != r) { | |
printf("%s\terror\tgetting DN from cert\n", domain); | |
goto cleanup; | |
} | |
size = sizeof(issuer_dn); | |
memset(issuer_dn, 0, size); | |
r = gnutls_x509_crt_get_issuer_dn(cert, issuer_dn, &size); | |
if (GNUTLS_E_SUCCESS != r) { | |
printf("%s\terror\tgetting Issuer DN from cert\n", domain); | |
goto cleanup; | |
} | |
algo_name = gnutls_pk_algorithm_get_name(algo); | |
printf("%s\tok\tDN\t%s\tIDN\t%s\tSINCE\t%s\tEXPIRES\t%s\tPK-ALGO\t%s\n", | |
domain, dn, issuer_dn, activation_time_str, expiration_time_str, algo_name); | |
cleanup: | |
gnutls_x509_crt_deinit (cert); | |
} | |
void | |
crawl_item_free (/*@notnull@*/ crawl_item *self) { | |
evcom_socket_detach(&self->socket); | |
if (NULL != self->socket.session) { | |
gnutls_deinit(self->socket.session); | |
self->socket.session = NULL; | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment