Skip to content

Instantly share code, notes, and snippets.

@temoto
Created August 5, 2009 17:12
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save temoto/162834 to your computer and use it in GitHub Desktop.
Save temoto/162834 to your computer and use it in GitHub Desktop.
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