mirror of
https://github.com/guanzhi/GmSSL.git
synced 2026-08-08 06:03:47 +08:00
update
This commit is contained in:
@@ -3,64 +3,66 @@
|
||||
int int_strtoul(const char *str, unsigned long *val)
|
||||
{
|
||||
#ifdef HAVE_STRTOUL
|
||||
char *tmp;
|
||||
unsigned long ret = strtoul(str, &tmp, 10);
|
||||
if((str == tmp) || (*tmp != '\0'))
|
||||
/* The value didn't parse cleanly */
|
||||
return 0;
|
||||
if(ret == ULONG_MAX)
|
||||
/* We hit a limit */
|
||||
return 0;
|
||||
*val = ret;
|
||||
return 1;
|
||||
char *tmp;
|
||||
unsigned long ret = strtoul(str, &tmp, 10);
|
||||
if ((str == tmp) || (*tmp != '\0'))
|
||||
/* The value didn't parse cleanly */
|
||||
return 0;
|
||||
if (ret == ULONG_MAX)
|
||||
/* We hit a limit */
|
||||
return 0;
|
||||
*val = ret;
|
||||
return 1;
|
||||
#else
|
||||
char buf[2];
|
||||
unsigned long ret = 0;
|
||||
buf[1] = '\0';
|
||||
if(str == '\0')
|
||||
/* An empty string ... */
|
||||
return 0;
|
||||
while(*str != '\0') {
|
||||
/* We have to multiply 'ret' by 10 before absorbing the next
|
||||
* digit. If this will overflow, catch it now. */
|
||||
if(ret && (((ULONG_MAX + 10) / ret) < 10))
|
||||
return 0;
|
||||
ret *= 10;
|
||||
if(!isdigit(*str))
|
||||
return 0;
|
||||
buf[0] = *str;
|
||||
ret += atoi(buf);
|
||||
str++;
|
||||
}
|
||||
*val = ret;
|
||||
return 1;
|
||||
char buf[2];
|
||||
unsigned long ret = 0;
|
||||
buf[1] = '\0';
|
||||
if (str == '\0')
|
||||
/* An empty string ... */
|
||||
return 0;
|
||||
while (*str != '\0') {
|
||||
/*
|
||||
* We have to multiply 'ret' by 10 before absorbing the next digit.
|
||||
* If this will overflow, catch it now.
|
||||
*/
|
||||
if (ret && (((ULONG_MAX + 10) / ret) < 10))
|
||||
return 0;
|
||||
ret *= 10;
|
||||
if (!isdigit(*str))
|
||||
return 0;
|
||||
buf[0] = *str;
|
||||
ret += atoi(buf);
|
||||
str++;
|
||||
}
|
||||
*val = ret;
|
||||
return 1;
|
||||
#endif
|
||||
}
|
||||
|
||||
#ifndef HAVE_STRSTR
|
||||
char *int_strstr(const char *haystack, const char *needle)
|
||||
{
|
||||
const char *sub_haystack = haystack, *sub_needle = needle;
|
||||
unsigned int offset = 0;
|
||||
if(!needle)
|
||||
return haystack;
|
||||
if(!haystack)
|
||||
return NULL;
|
||||
while((*sub_haystack != '\0') && (*sub_needle != '\0')) {
|
||||
if(sub_haystack[offset] == sub_needle) {
|
||||
/* sub_haystack is still a candidate */
|
||||
offset++;
|
||||
sub_needle++;
|
||||
} else {
|
||||
/* sub_haystack is no longer a possibility */
|
||||
sub_haystack++;
|
||||
offset = 0;
|
||||
sub_needle = needle;
|
||||
}
|
||||
}
|
||||
if(*sub_haystack == '\0')
|
||||
/* Found nothing */
|
||||
return NULL;
|
||||
return sub_haystack;
|
||||
const char *sub_haystack = haystack, *sub_needle = needle;
|
||||
unsigned int offset = 0;
|
||||
if (!needle)
|
||||
return haystack;
|
||||
if (!haystack)
|
||||
return NULL;
|
||||
while ((*sub_haystack != '\0') && (*sub_needle != '\0')) {
|
||||
if (sub_haystack[offset] == sub_needle) {
|
||||
/* sub_haystack is still a candidate */
|
||||
offset++;
|
||||
sub_needle++;
|
||||
} else {
|
||||
/* sub_haystack is no longer a possibility */
|
||||
sub_haystack++;
|
||||
offset = 0;
|
||||
sub_needle = needle;
|
||||
}
|
||||
}
|
||||
if (*sub_haystack == '\0')
|
||||
/* Found nothing */
|
||||
return NULL;
|
||||
return sub_haystack;
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -2,204 +2,235 @@
|
||||
|
||||
#ifndef NO_BUFFER
|
||||
|
||||
void buffer_init(buffer_t *buf)
|
||||
void buffer_init(buffer_t * buf)
|
||||
{
|
||||
buf->used = 0;
|
||||
buf->total_in = buf->total_out = 0;
|
||||
buf->used = 0;
|
||||
buf->total_in = buf->total_out = 0;
|
||||
}
|
||||
|
||||
void buffer_close(buffer_t *buf)
|
||||
void buffer_close(buffer_t * buf)
|
||||
{
|
||||
/* Our data is static - nothing needs "release", just reset it */
|
||||
buf->used = 0;
|
||||
/* Our data is static - nothing needs "release", just reset it */
|
||||
buf->used = 0;
|
||||
}
|
||||
|
||||
/* Code these simple ones in compact form */
|
||||
unsigned int buffer_used(buffer_t *buf) {
|
||||
return buf->used; }
|
||||
unsigned int buffer_unused(buffer_t *buf) {
|
||||
return (MAX_DATA_SIZE - buf->used); }
|
||||
int buffer_full(buffer_t *buf) {
|
||||
return (buf->used == MAX_DATA_SIZE ? 1 : 0); }
|
||||
int buffer_notfull(buffer_t *buf) {
|
||||
return (buf->used < MAX_DATA_SIZE ? 1 : 0); }
|
||||
int buffer_empty(buffer_t *buf) {
|
||||
return (buf->used == 0 ? 1 : 0); }
|
||||
int buffer_notempty(buffer_t *buf) {
|
||||
return (buf->used > 0 ? 1 : 0); }
|
||||
unsigned long buffer_total_in(buffer_t *buf) {
|
||||
return buf->total_in; }
|
||||
unsigned long buffer_total_out(buffer_t *buf) {
|
||||
return buf->total_out; }
|
||||
unsigned int buffer_used(buffer_t * buf)
|
||||
{
|
||||
return buf->used;
|
||||
}
|
||||
|
||||
/* These 3 static (internal) functions don't adjust the "total" variables as
|
||||
unsigned int buffer_unused(buffer_t * buf)
|
||||
{
|
||||
return (MAX_DATA_SIZE - buf->used);
|
||||
}
|
||||
|
||||
int buffer_full(buffer_t * buf)
|
||||
{
|
||||
return (buf->used == MAX_DATA_SIZE ? 1 : 0);
|
||||
}
|
||||
|
||||
int buffer_notfull(buffer_t * buf)
|
||||
{
|
||||
return (buf->used < MAX_DATA_SIZE ? 1 : 0);
|
||||
}
|
||||
|
||||
int buffer_empty(buffer_t * buf)
|
||||
{
|
||||
return (buf->used == 0 ? 1 : 0);
|
||||
}
|
||||
|
||||
int buffer_notempty(buffer_t * buf)
|
||||
{
|
||||
return (buf->used > 0 ? 1 : 0);
|
||||
}
|
||||
|
||||
unsigned long buffer_total_in(buffer_t * buf)
|
||||
{
|
||||
return buf->total_in;
|
||||
}
|
||||
|
||||
unsigned long buffer_total_out(buffer_t * buf)
|
||||
{
|
||||
return buf->total_out;
|
||||
}
|
||||
|
||||
/*
|
||||
* These 3 static (internal) functions don't adjust the "total" variables as
|
||||
* it's not sure when they're called how it should be interpreted. Only the
|
||||
* higher-level "buffer_[to|from]_[fd|SSL|BIO]" functions should alter these
|
||||
* values. */
|
||||
#if 0 /* To avoid "unused" warnings */
|
||||
static unsigned int buffer_adddata(buffer_t *buf, const unsigned char *ptr,
|
||||
unsigned int size)
|
||||
* values.
|
||||
*/
|
||||
# if 0 /* To avoid "unused" warnings */
|
||||
static unsigned int buffer_adddata(buffer_t * buf, const unsigned char *ptr,
|
||||
unsigned int size)
|
||||
{
|
||||
unsigned int added = MAX_DATA_SIZE - buf->used;
|
||||
if(added > size)
|
||||
added = size;
|
||||
if(added == 0)
|
||||
return 0;
|
||||
memcpy(buf->data + buf->used, ptr, added);
|
||||
buf->used += added;
|
||||
buf->total_in += added;
|
||||
return added;
|
||||
unsigned int added = MAX_DATA_SIZE - buf->used;
|
||||
if (added > size)
|
||||
added = size;
|
||||
if (added == 0)
|
||||
return 0;
|
||||
memcpy(buf->data + buf->used, ptr, added);
|
||||
buf->used += added;
|
||||
buf->total_in += added;
|
||||
return added;
|
||||
}
|
||||
|
||||
static unsigned int buffer_tobuffer(buffer_t *to, buffer_t *from, int cap)
|
||||
static unsigned int buffer_tobuffer(buffer_t * to, buffer_t * from, int cap)
|
||||
{
|
||||
unsigned int moved, tomove = from->used;
|
||||
if((int)tomove > cap)
|
||||
tomove = cap;
|
||||
if(tomove == 0)
|
||||
return 0;
|
||||
moved = buffer_adddata(to, from->data, tomove);
|
||||
if(moved == 0)
|
||||
return 0;
|
||||
buffer_takedata(from, NULL, moved);
|
||||
return moved;
|
||||
unsigned int moved, tomove = from->used;
|
||||
if ((int)tomove > cap)
|
||||
tomove = cap;
|
||||
if (tomove == 0)
|
||||
return 0;
|
||||
moved = buffer_adddata(to, from->data, tomove);
|
||||
if (moved == 0)
|
||||
return 0;
|
||||
buffer_takedata(from, NULL, moved);
|
||||
return moved;
|
||||
}
|
||||
#endif
|
||||
# endif
|
||||
|
||||
static unsigned int buffer_takedata(buffer_t *buf, unsigned char *ptr,
|
||||
unsigned int size)
|
||||
static unsigned int buffer_takedata(buffer_t * buf, unsigned char *ptr,
|
||||
unsigned int size)
|
||||
{
|
||||
unsigned int taken = buf->used;
|
||||
if(taken > size)
|
||||
taken = size;
|
||||
if(taken == 0)
|
||||
return 0;
|
||||
if(ptr)
|
||||
memcpy(ptr, buf->data, taken);
|
||||
buf->used -= taken;
|
||||
/* Do we have to scroll? */
|
||||
if(buf->used > 0)
|
||||
memmove(buf->data, buf->data + taken, buf->used);
|
||||
return taken;
|
||||
unsigned int taken = buf->used;
|
||||
if (taken > size)
|
||||
taken = size;
|
||||
if (taken == 0)
|
||||
return 0;
|
||||
if (ptr)
|
||||
memcpy(ptr, buf->data, taken);
|
||||
buf->used -= taken;
|
||||
/* Do we have to scroll? */
|
||||
if (buf->used > 0)
|
||||
memmove(buf->data, buf->data + taken, buf->used);
|
||||
return taken;
|
||||
}
|
||||
|
||||
#ifndef NO_IP
|
||||
# ifndef NO_IP
|
||||
|
||||
int buffer_from_fd(buffer_t *buf, int fd)
|
||||
int buffer_from_fd(buffer_t * buf, int fd)
|
||||
{
|
||||
int toread = buffer_unused(buf);
|
||||
if(toread == 0)
|
||||
/* Shouldn't be called in this case! */
|
||||
abort();
|
||||
toread = read(fd, buf->data + buf->used, toread);
|
||||
if(toread > 0) {
|
||||
buf->used += toread;
|
||||
buf->total_in += toread;
|
||||
}
|
||||
return toread;
|
||||
int toread = buffer_unused(buf);
|
||||
if (toread == 0)
|
||||
/* Shouldn't be called in this case! */
|
||||
abort();
|
||||
toread = read(fd, buf->data + buf->used, toread);
|
||||
if (toread > 0) {
|
||||
buf->used += toread;
|
||||
buf->total_in += toread;
|
||||
}
|
||||
return toread;
|
||||
}
|
||||
|
||||
int buffer_to_fd(buffer_t *buf, int fd)
|
||||
int buffer_to_fd(buffer_t * buf, int fd)
|
||||
{
|
||||
int towrite = buffer_used(buf);
|
||||
if(towrite == 0)
|
||||
/* Shouldn't be called in this case! */
|
||||
abort();
|
||||
towrite = write(fd, buf->data, towrite);
|
||||
if(towrite > 0) {
|
||||
buffer_takedata(buf, NULL, towrite);
|
||||
buf->total_out += towrite;
|
||||
}
|
||||
return towrite;
|
||||
int towrite = buffer_used(buf);
|
||||
if (towrite == 0)
|
||||
/* Shouldn't be called in this case! */
|
||||
abort();
|
||||
towrite = write(fd, buf->data, towrite);
|
||||
if (towrite > 0) {
|
||||
buffer_takedata(buf, NULL, towrite);
|
||||
buf->total_out += towrite;
|
||||
}
|
||||
return towrite;
|
||||
}
|
||||
|
||||
#endif /* !defined(NO_IP) */
|
||||
# endif /* !defined(NO_IP) */
|
||||
|
||||
#ifndef NO_OPENSSL
|
||||
# ifndef NO_OPENSSL
|
||||
|
||||
static void int_ssl_check(SSL *s, int ret)
|
||||
{
|
||||
int e = SSL_get_error(s, ret);
|
||||
switch(e) {
|
||||
/* These seem to be harmless and already "dealt with" by our
|
||||
* non-blocking environment. NB: "ZERO_RETURN" is the clean
|
||||
* "error" indicating a successfully closed SSL tunnel. We let
|
||||
* this happen because our IO loop should not appear to have
|
||||
* broken on this condition - and outside the IO loop, the
|
||||
* "shutdown" state is checked. */
|
||||
case SSL_ERROR_NONE:
|
||||
case SSL_ERROR_WANT_READ:
|
||||
case SSL_ERROR_WANT_WRITE:
|
||||
case SSL_ERROR_WANT_X509_LOOKUP:
|
||||
case SSL_ERROR_ZERO_RETURN:
|
||||
return;
|
||||
/* These seem to be indications of a genuine error that should
|
||||
* result in the SSL tunnel being regarded as "dead". */
|
||||
case SSL_ERROR_SYSCALL:
|
||||
case SSL_ERROR_SSL:
|
||||
SSL_set_app_data(s, (char *)1);
|
||||
return;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
/* For any other errors that (a) exist, and (b) crop up - we need to
|
||||
* interpret what to do with them - so "politely inform" the caller that
|
||||
* the code needs updating here. */
|
||||
abort();
|
||||
int e = SSL_get_error(s, ret);
|
||||
switch (e) {
|
||||
/*
|
||||
* These seem to be harmless and already "dealt with" by our
|
||||
* non-blocking environment. NB: "ZERO_RETURN" is the clean "error"
|
||||
* indicating a successfully closed SSL tunnel. We let this happen
|
||||
* because our IO loop should not appear to have broken on this
|
||||
* condition - and outside the IO loop, the "shutdown" state is
|
||||
* checked.
|
||||
*/
|
||||
case SSL_ERROR_NONE:
|
||||
case SSL_ERROR_WANT_READ:
|
||||
case SSL_ERROR_WANT_WRITE:
|
||||
case SSL_ERROR_WANT_X509_LOOKUP:
|
||||
case SSL_ERROR_ZERO_RETURN:
|
||||
return;
|
||||
/*
|
||||
* These seem to be indications of a genuine error that should result
|
||||
* in the SSL tunnel being regarded as "dead".
|
||||
*/
|
||||
case SSL_ERROR_SYSCALL:
|
||||
case SSL_ERROR_SSL:
|
||||
SSL_set_app_data(s, (char *)1);
|
||||
return;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
/*
|
||||
* For any other errors that (a) exist, and (b) crop up - we need to
|
||||
* interpret what to do with them - so "politely inform" the caller that
|
||||
* the code needs updating here.
|
||||
*/
|
||||
abort();
|
||||
}
|
||||
|
||||
void buffer_from_SSL(buffer_t *buf, SSL *ssl)
|
||||
void buffer_from_SSL(buffer_t * buf, SSL *ssl)
|
||||
{
|
||||
int ret;
|
||||
if(!ssl || buffer_full(buf))
|
||||
return;
|
||||
ret = SSL_read(ssl, buf->data + buf->used, buffer_unused(buf));
|
||||
if(ret > 0) {
|
||||
buf->used += ret;
|
||||
buf->total_in += ret;
|
||||
}
|
||||
if(ret < 0)
|
||||
int_ssl_check(ssl, ret);
|
||||
int ret;
|
||||
if (!ssl || buffer_full(buf))
|
||||
return;
|
||||
ret = SSL_read(ssl, buf->data + buf->used, buffer_unused(buf));
|
||||
if (ret > 0) {
|
||||
buf->used += ret;
|
||||
buf->total_in += ret;
|
||||
}
|
||||
if (ret < 0)
|
||||
int_ssl_check(ssl, ret);
|
||||
}
|
||||
|
||||
void buffer_to_SSL(buffer_t *buf, SSL *ssl)
|
||||
void buffer_to_SSL(buffer_t * buf, SSL *ssl)
|
||||
{
|
||||
int ret;
|
||||
if(!ssl || buffer_empty(buf))
|
||||
return;
|
||||
ret = SSL_write(ssl, buf->data, buf->used);
|
||||
if(ret > 0) {
|
||||
buffer_takedata(buf, NULL, ret);
|
||||
buf->total_out += ret;
|
||||
}
|
||||
if(ret < 0)
|
||||
int_ssl_check(ssl, ret);
|
||||
int ret;
|
||||
if (!ssl || buffer_empty(buf))
|
||||
return;
|
||||
ret = SSL_write(ssl, buf->data, buf->used);
|
||||
if (ret > 0) {
|
||||
buffer_takedata(buf, NULL, ret);
|
||||
buf->total_out += ret;
|
||||
}
|
||||
if (ret < 0)
|
||||
int_ssl_check(ssl, ret);
|
||||
}
|
||||
|
||||
void buffer_from_BIO(buffer_t *buf, BIO *bio)
|
||||
void buffer_from_BIO(buffer_t * buf, BIO *bio)
|
||||
{
|
||||
int ret;
|
||||
if(!bio || buffer_full(buf))
|
||||
return;
|
||||
ret = BIO_read(bio, buf->data + buf->used, buffer_unused(buf));
|
||||
if(ret > 0) {
|
||||
buf->used += ret;
|
||||
buf->total_in += ret;
|
||||
}
|
||||
int ret;
|
||||
if (!bio || buffer_full(buf))
|
||||
return;
|
||||
ret = BIO_read(bio, buf->data + buf->used, buffer_unused(buf));
|
||||
if (ret > 0) {
|
||||
buf->used += ret;
|
||||
buf->total_in += ret;
|
||||
}
|
||||
}
|
||||
|
||||
void buffer_to_BIO(buffer_t *buf, BIO *bio)
|
||||
void buffer_to_BIO(buffer_t * buf, BIO *bio)
|
||||
{
|
||||
int ret;
|
||||
if(!bio || buffer_empty(buf))
|
||||
return;
|
||||
ret = BIO_write(bio, buf->data, buf->used);
|
||||
if(ret > 0) {
|
||||
buffer_takedata(buf, NULL, ret);
|
||||
buf->total_out += ret;
|
||||
}
|
||||
int ret;
|
||||
if (!bio || buffer_empty(buf))
|
||||
return;
|
||||
ret = BIO_write(bio, buf->data, buf->used);
|
||||
if (ret > 0) {
|
||||
buffer_takedata(buf, NULL, ret);
|
||||
buf->total_out += ret;
|
||||
}
|
||||
}
|
||||
|
||||
#endif /* !defined(NO_OPENSSL) */
|
||||
# endif /* !defined(NO_OPENSSL) */
|
||||
|
||||
#endif /* !defined(NO_BUFFER) */
|
||||
#endif /* !defined(NO_BUFFER) */
|
||||
|
||||
@@ -5,7 +5,8 @@
|
||||
/* For callbacks generating output, here are their file-descriptors. */
|
||||
static FILE *fp_cb_ssl_info = NULL;
|
||||
static FILE *fp_cb_ssl_verify = NULL;
|
||||
/* Output level:
|
||||
/*-
|
||||
* Output level:
|
||||
* 0 = nothing,
|
||||
* 1 = minimal, just errors,
|
||||
* 2 = minimal, all steps,
|
||||
@@ -15,148 +16,158 @@ static unsigned int cb_ssl_verify_level = 1;
|
||||
/* Other static rubbish (to mirror s_cb.c where required) */
|
||||
static int int_verify_depth = 10;
|
||||
|
||||
/* This function is largely borrowed from the one used in OpenSSL's "s_client"
|
||||
* and "s_server" utilities. */
|
||||
/*
|
||||
* This function is largely borrowed from the one used in OpenSSL's
|
||||
* "s_client" and "s_server" utilities.
|
||||
*/
|
||||
void cb_ssl_info(const SSL *s, int where, int ret)
|
||||
{
|
||||
const char *str1, *str2;
|
||||
int w;
|
||||
const char *str1, *str2;
|
||||
int w;
|
||||
|
||||
if(!fp_cb_ssl_info)
|
||||
return;
|
||||
if (!fp_cb_ssl_info)
|
||||
return;
|
||||
|
||||
w = where & ~SSL_ST_MASK;
|
||||
str1 = (w & SSL_ST_CONNECT ? "SSL_connect" : (w & SSL_ST_ACCEPT ?
|
||||
"SSL_accept" : "undefined")),
|
||||
str2 = SSL_state_string_long(s);
|
||||
w = where & ~SSL_ST_MASK;
|
||||
str1 = (w & SSL_ST_CONNECT ? "SSL_connect" : (w & SSL_ST_ACCEPT ?
|
||||
"SSL_accept" :
|
||||
"undefined")), str2 =
|
||||
SSL_state_string_long(s);
|
||||
|
||||
if (where & SSL_CB_LOOP)
|
||||
fprintf(fp_cb_ssl_info, "(%s) %s\n", str1, str2);
|
||||
else if (where & SSL_CB_EXIT) {
|
||||
if (ret == 0)
|
||||
fprintf(fp_cb_ssl_info, "(%s) failed in %s\n", str1, str2);
|
||||
/* In a non-blocking model, we get a few of these "error"s simply because we're
|
||||
* calling "reads" and "writes" on the state-machine that are virtual NOPs
|
||||
* simply to avoid wasting the time seeing if we *should* call them. Removing
|
||||
* this case makes the "-out_state" output a lot easier on the eye. */
|
||||
#if 0
|
||||
else if (ret < 0)
|
||||
fprintf(fp_cb_ssl_info, "%s:error in %s\n", str1, str2);
|
||||
#endif
|
||||
}
|
||||
if (where & SSL_CB_LOOP)
|
||||
fprintf(fp_cb_ssl_info, "(%s) %s\n", str1, str2);
|
||||
else if (where & SSL_CB_EXIT) {
|
||||
if (ret == 0)
|
||||
fprintf(fp_cb_ssl_info, "(%s) failed in %s\n", str1, str2);
|
||||
/*
|
||||
* In a non-blocking model, we get a few of these "error"s simply
|
||||
* because we're calling "reads" and "writes" on the state-machine
|
||||
* that are virtual NOPs simply to avoid wasting the time seeing if
|
||||
* we *should* call them. Removing this case makes the "-out_state"
|
||||
* output a lot easier on the eye.
|
||||
*/
|
||||
# if 0
|
||||
else if (ret < 0)
|
||||
fprintf(fp_cb_ssl_info, "%s:error in %s\n", str1, str2);
|
||||
# endif
|
||||
}
|
||||
}
|
||||
|
||||
void cb_ssl_info_set_output(FILE *fp)
|
||||
{
|
||||
fp_cb_ssl_info = fp;
|
||||
fp_cb_ssl_info = fp;
|
||||
}
|
||||
|
||||
static const char *int_reason_no_issuer = "X509_V_ERR_UNABLE_TO_GET_ISSUER_CERT";
|
||||
static const char *int_reason_no_issuer =
|
||||
"X509_V_ERR_UNABLE_TO_GET_ISSUER_CERT";
|
||||
static const char *int_reason_not_yet = "X509_V_ERR_CERT_NOT_YET_VALID";
|
||||
static const char *int_reason_before = "X509_V_ERR_ERROR_IN_CERT_NOT_BEFORE_FIELD";
|
||||
static const char *int_reason_before =
|
||||
"X509_V_ERR_ERROR_IN_CERT_NOT_BEFORE_FIELD";
|
||||
static const char *int_reason_expired = "X509_V_ERR_CERT_HAS_EXPIRED";
|
||||
static const char *int_reason_after = "X509_V_ERR_ERROR_IN_CERT_NOT_AFTER_FIELD";
|
||||
static const char *int_reason_after =
|
||||
"X509_V_ERR_ERROR_IN_CERT_NOT_AFTER_FIELD";
|
||||
|
||||
/* Stolen wholesale from apps/s_cb.c :-) And since then, mutilated ... */
|
||||
int cb_ssl_verify(int ok, X509_STORE_CTX *ctx)
|
||||
{
|
||||
char buf1[256]; /* Used for the subject name */
|
||||
char buf2[256]; /* Used for the issuer name */
|
||||
const char *reason = NULL; /* Error reason (if any) */
|
||||
X509 *err_cert;
|
||||
int err, depth;
|
||||
char buf1[256]; /* Used for the subject name */
|
||||
char buf2[256]; /* Used for the issuer name */
|
||||
const char *reason = NULL; /* Error reason (if any) */
|
||||
X509 *err_cert;
|
||||
int err, depth;
|
||||
|
||||
if(!fp_cb_ssl_verify || (cb_ssl_verify_level == 0))
|
||||
return ok;
|
||||
err_cert = X509_STORE_CTX_get_current_cert(ctx);
|
||||
err = X509_STORE_CTX_get_error(ctx);
|
||||
depth = X509_STORE_CTX_get_error_depth(ctx);
|
||||
if (!fp_cb_ssl_verify || (cb_ssl_verify_level == 0))
|
||||
return ok;
|
||||
err_cert = X509_STORE_CTX_get_current_cert(ctx);
|
||||
err = X509_STORE_CTX_get_error(ctx);
|
||||
depth = X509_STORE_CTX_get_error_depth(ctx);
|
||||
|
||||
buf1[0] = buf2[0] = '\0';
|
||||
/* Fill buf1 */
|
||||
X509_NAME_oneline(X509_get_subject_name(err_cert), buf1, 256);
|
||||
/* Fill buf2 */
|
||||
X509_NAME_oneline(X509_get_issuer_name(ctx->current_cert), buf2, 256);
|
||||
switch (ctx->error) {
|
||||
case X509_V_ERR_UNABLE_TO_GET_ISSUER_CERT:
|
||||
reason = int_reason_no_issuer;
|
||||
break;
|
||||
case X509_V_ERR_CERT_NOT_YET_VALID:
|
||||
reason = int_reason_not_yet;
|
||||
break;
|
||||
case X509_V_ERR_ERROR_IN_CERT_NOT_BEFORE_FIELD:
|
||||
reason = int_reason_before;
|
||||
break;
|
||||
case X509_V_ERR_CERT_HAS_EXPIRED:
|
||||
reason = int_reason_expired;
|
||||
break;
|
||||
case X509_V_ERR_ERROR_IN_CERT_NOT_AFTER_FIELD:
|
||||
reason = int_reason_after;
|
||||
break;
|
||||
}
|
||||
buf1[0] = buf2[0] = '\0';
|
||||
/* Fill buf1 */
|
||||
X509_NAME_oneline(X509_get_subject_name(err_cert), buf1, 256);
|
||||
/* Fill buf2 */
|
||||
X509_NAME_oneline(X509_get_issuer_name(ctx->current_cert), buf2, 256);
|
||||
switch (ctx->error) {
|
||||
case X509_V_ERR_UNABLE_TO_GET_ISSUER_CERT:
|
||||
reason = int_reason_no_issuer;
|
||||
break;
|
||||
case X509_V_ERR_CERT_NOT_YET_VALID:
|
||||
reason = int_reason_not_yet;
|
||||
break;
|
||||
case X509_V_ERR_ERROR_IN_CERT_NOT_BEFORE_FIELD:
|
||||
reason = int_reason_before;
|
||||
break;
|
||||
case X509_V_ERR_CERT_HAS_EXPIRED:
|
||||
reason = int_reason_expired;
|
||||
break;
|
||||
case X509_V_ERR_ERROR_IN_CERT_NOT_AFTER_FIELD:
|
||||
reason = int_reason_after;
|
||||
break;
|
||||
}
|
||||
|
||||
if((cb_ssl_verify_level == 1) && ok)
|
||||
return ok;
|
||||
fprintf(fp_cb_ssl_verify, "chain-depth=%d, ", depth);
|
||||
if(reason)
|
||||
fprintf(fp_cb_ssl_verify, "error=%s\n", reason);
|
||||
else
|
||||
fprintf(fp_cb_ssl_verify, "error=%d\n", err);
|
||||
if(cb_ssl_verify_level < 3)
|
||||
return ok;
|
||||
fprintf(fp_cb_ssl_verify, "--> subject = %s\n", buf1);
|
||||
fprintf(fp_cb_ssl_verify, "--> issuer = %s\n", buf2);
|
||||
if(!ok)
|
||||
fprintf(fp_cb_ssl_verify,"--> verify error:num=%d:%s\n",err,
|
||||
X509_verify_cert_error_string(err));
|
||||
fprintf(fp_cb_ssl_verify, "--> verify return:%d\n",ok);
|
||||
return ok;
|
||||
if ((cb_ssl_verify_level == 1) && ok)
|
||||
return ok;
|
||||
fprintf(fp_cb_ssl_verify, "chain-depth=%d, ", depth);
|
||||
if (reason)
|
||||
fprintf(fp_cb_ssl_verify, "error=%s\n", reason);
|
||||
else
|
||||
fprintf(fp_cb_ssl_verify, "error=%d\n", err);
|
||||
if (cb_ssl_verify_level < 3)
|
||||
return ok;
|
||||
fprintf(fp_cb_ssl_verify, "--> subject = %s\n", buf1);
|
||||
fprintf(fp_cb_ssl_verify, "--> issuer = %s\n", buf2);
|
||||
if (!ok)
|
||||
fprintf(fp_cb_ssl_verify, "--> verify error:num=%d:%s\n", err,
|
||||
X509_verify_cert_error_string(err));
|
||||
fprintf(fp_cb_ssl_verify, "--> verify return:%d\n", ok);
|
||||
return ok;
|
||||
}
|
||||
|
||||
void cb_ssl_verify_set_output(FILE *fp)
|
||||
{
|
||||
fp_cb_ssl_verify = fp;
|
||||
fp_cb_ssl_verify = fp;
|
||||
}
|
||||
|
||||
void cb_ssl_verify_set_depth(unsigned int verify_depth)
|
||||
{
|
||||
int_verify_depth = verify_depth;
|
||||
int_verify_depth = verify_depth;
|
||||
}
|
||||
|
||||
void cb_ssl_verify_set_level(unsigned int level)
|
||||
{
|
||||
if(level < 4)
|
||||
cb_ssl_verify_level = level;
|
||||
if (level < 4)
|
||||
cb_ssl_verify_level = level;
|
||||
}
|
||||
|
||||
RSA *cb_generate_tmp_rsa(SSL *s, int is_export, int keylength)
|
||||
{
|
||||
/* TODO: Perhaps make it so our global key can be generated on-the-fly
|
||||
* after certain intervals? */
|
||||
static RSA *rsa_tmp = NULL;
|
||||
BIGNUM *bn = NULL;
|
||||
int ok = 1;
|
||||
if(!rsa_tmp) {
|
||||
ok = 0;
|
||||
if(!(bn = BN_new()))
|
||||
goto end;
|
||||
if(!BN_set_word(bn, RSA_F4))
|
||||
goto end;
|
||||
if(!(rsa_tmp = RSA_new()))
|
||||
goto end;
|
||||
if(!RSA_generate_key_ex(rsa_tmp, keylength, bn, NULL))
|
||||
goto end;
|
||||
ok = 1;
|
||||
}
|
||||
end:
|
||||
if(bn)
|
||||
BN_free(bn);
|
||||
if(!ok) {
|
||||
RSA_free(rsa_tmp);
|
||||
rsa_tmp = NULL;
|
||||
}
|
||||
return rsa_tmp;
|
||||
/*
|
||||
* TODO: Perhaps make it so our global key can be generated on-the-fly
|
||||
* after certain intervals?
|
||||
*/
|
||||
static RSA *rsa_tmp = NULL;
|
||||
BIGNUM *bn = NULL;
|
||||
int ok = 1;
|
||||
if (!rsa_tmp) {
|
||||
ok = 0;
|
||||
if (!(bn = BN_new()))
|
||||
goto end;
|
||||
if (!BN_set_word(bn, RSA_F4))
|
||||
goto end;
|
||||
if (!(rsa_tmp = RSA_new()))
|
||||
goto end;
|
||||
if (!RSA_generate_key_ex(rsa_tmp, keylength, bn, NULL))
|
||||
goto end;
|
||||
ok = 1;
|
||||
}
|
||||
end:
|
||||
if (bn)
|
||||
BN_free(bn);
|
||||
if (!ok) {
|
||||
RSA_free(rsa_tmp);
|
||||
rsa_tmp = NULL;
|
||||
}
|
||||
return rsa_tmp;
|
||||
}
|
||||
|
||||
#endif /* !defined(NO_OPENSSL) */
|
||||
|
||||
#endif /* !defined(NO_OPENSSL) */
|
||||
|
||||
@@ -2,145 +2,148 @@
|
||||
|
||||
#ifndef NO_IP
|
||||
|
||||
#define IP_LISTENER_BACKLOG 511 /* So if it gets masked by 256 or some other
|
||||
such value it'll still be respectable */
|
||||
# define IP_LISTENER_BACKLOG 511/* So if it gets masked by 256 or some other
|
||||
* such value it'll still be respectable */
|
||||
|
||||
/* Any IP-related initialisations. For now, this means blocking SIGPIPE */
|
||||
int ip_initialise(void)
|
||||
{
|
||||
struct sigaction sa;
|
||||
struct sigaction sa;
|
||||
|
||||
sa.sa_handler = SIG_IGN;
|
||||
sa.sa_flags = 0;
|
||||
sigemptyset(&sa.sa_mask);
|
||||
if(sigaction(SIGPIPE, &sa, NULL) != 0)
|
||||
return 0;
|
||||
return 1;
|
||||
sa.sa_handler = SIG_IGN;
|
||||
sa.sa_flags = 0;
|
||||
sigemptyset(&sa.sa_mask);
|
||||
if (sigaction(SIGPIPE, &sa, NULL) != 0)
|
||||
return 0;
|
||||
return 1;
|
||||
}
|
||||
|
||||
int ip_create_listener_split(const char *ip, unsigned short port)
|
||||
{
|
||||
struct sockaddr_in in_addr;
|
||||
int fd = -1;
|
||||
int reuseVal = 1;
|
||||
struct sockaddr_in in_addr;
|
||||
int fd = -1;
|
||||
int reuseVal = 1;
|
||||
|
||||
/* Create the socket */
|
||||
if((fd = socket(PF_INET, SOCK_STREAM, 0)) == -1)
|
||||
goto err;
|
||||
/* Set the SO_REUSEADDR flag - servers act weird without it */
|
||||
if(setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, (char *)(&reuseVal),
|
||||
sizeof(reuseVal)) != 0)
|
||||
goto err;
|
||||
/* Prepare the listen address stuff */
|
||||
in_addr.sin_family = AF_INET;
|
||||
memcpy(&in_addr.sin_addr.s_addr, ip, 4);
|
||||
in_addr.sin_port = htons(port);
|
||||
/* Bind to the required port/address/interface */
|
||||
if(bind(fd, (struct sockaddr *)&in_addr, sizeof(struct sockaddr_in)) != 0)
|
||||
goto err;
|
||||
/* Start "listening" */
|
||||
if(listen(fd, IP_LISTENER_BACKLOG) != 0)
|
||||
goto err;
|
||||
return fd;
|
||||
err:
|
||||
if(fd != -1)
|
||||
close(fd);
|
||||
return -1;
|
||||
/* Create the socket */
|
||||
if ((fd = socket(PF_INET, SOCK_STREAM, 0)) == -1)
|
||||
goto err;
|
||||
/* Set the SO_REUSEADDR flag - servers act weird without it */
|
||||
if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, (char *)(&reuseVal),
|
||||
sizeof(reuseVal)) != 0)
|
||||
goto err;
|
||||
/* Prepare the listen address stuff */
|
||||
in_addr.sin_family = AF_INET;
|
||||
memcpy(&in_addr.sin_addr.s_addr, ip, 4);
|
||||
in_addr.sin_port = htons(port);
|
||||
/* Bind to the required port/address/interface */
|
||||
if (bind(fd, (struct sockaddr *)&in_addr, sizeof(struct sockaddr_in)) !=
|
||||
0)
|
||||
goto err;
|
||||
/* Start "listening" */
|
||||
if (listen(fd, IP_LISTENER_BACKLOG) != 0)
|
||||
goto err;
|
||||
return fd;
|
||||
err:
|
||||
if (fd != -1)
|
||||
close(fd);
|
||||
return -1;
|
||||
}
|
||||
|
||||
int ip_create_connection_split(const char *ip, unsigned short port)
|
||||
{
|
||||
struct sockaddr_in in_addr;
|
||||
int flags, fd = -1;
|
||||
struct sockaddr_in in_addr;
|
||||
int flags, fd = -1;
|
||||
|
||||
/* Create the socket */
|
||||
if((fd = socket(PF_INET, SOCK_STREAM, 0)) == -1)
|
||||
goto err;
|
||||
/* Make it non-blocking */
|
||||
if(((flags = fcntl(fd, F_GETFL, 0)) < 0) ||
|
||||
(fcntl(fd, F_SETFL, flags | O_NONBLOCK) < 0))
|
||||
goto err;
|
||||
/* Prepare the connection address stuff */
|
||||
in_addr.sin_family = AF_INET;
|
||||
memcpy(&in_addr.sin_addr.s_addr, ip, 4);
|
||||
in_addr.sin_port = htons(port);
|
||||
/* Start a connect (non-blocking, in all likelihood) */
|
||||
if((connect(fd, (struct sockaddr *)&in_addr,
|
||||
sizeof(struct sockaddr_in)) != 0) &&
|
||||
(errno != EINPROGRESS))
|
||||
goto err;
|
||||
return fd;
|
||||
err:
|
||||
if(fd != -1)
|
||||
close(fd);
|
||||
return -1;
|
||||
/* Create the socket */
|
||||
if ((fd = socket(PF_INET, SOCK_STREAM, 0)) == -1)
|
||||
goto err;
|
||||
/* Make it non-blocking */
|
||||
if (((flags = fcntl(fd, F_GETFL, 0)) < 0) ||
|
||||
(fcntl(fd, F_SETFL, flags | O_NONBLOCK) < 0))
|
||||
goto err;
|
||||
/* Prepare the connection address stuff */
|
||||
in_addr.sin_family = AF_INET;
|
||||
memcpy(&in_addr.sin_addr.s_addr, ip, 4);
|
||||
in_addr.sin_port = htons(port);
|
||||
/* Start a connect (non-blocking, in all likelihood) */
|
||||
if ((connect(fd, (struct sockaddr *)&in_addr,
|
||||
sizeof(struct sockaddr_in)) != 0) && (errno != EINPROGRESS))
|
||||
goto err;
|
||||
return fd;
|
||||
err:
|
||||
if (fd != -1)
|
||||
close(fd);
|
||||
return -1;
|
||||
}
|
||||
|
||||
static char all_local_ip[] = {0x00,0x00,0x00,0x00};
|
||||
static char all_local_ip[] = { 0x00, 0x00, 0x00, 0x00 };
|
||||
|
||||
int ip_parse_address(const char *address, const char **parsed_ip,
|
||||
unsigned short *parsed_port, int accept_all_ip)
|
||||
unsigned short *parsed_port, int accept_all_ip)
|
||||
{
|
||||
char buf[256];
|
||||
struct hostent *lookup;
|
||||
unsigned long port;
|
||||
const char *ptr = strstr(address, ":");
|
||||
const char *ip = all_local_ip;
|
||||
char buf[256];
|
||||
struct hostent *lookup;
|
||||
unsigned long port;
|
||||
const char *ptr = strstr(address, ":");
|
||||
const char *ip = all_local_ip;
|
||||
|
||||
if(!ptr) {
|
||||
/* We assume we're listening on all local interfaces and have
|
||||
* only specified a port. */
|
||||
if(!accept_all_ip)
|
||||
return 0;
|
||||
ptr = address;
|
||||
goto determine_port;
|
||||
}
|
||||
if((ptr - address) > 255)
|
||||
return 0;
|
||||
memset(buf, 0, 256);
|
||||
memcpy(buf, address, ptr - address);
|
||||
ptr++;
|
||||
if((lookup = gethostbyname(buf)) == NULL) {
|
||||
/* Spit a message to differentiate between lookup failures and
|
||||
* bad strings. */
|
||||
fprintf(stderr, "hostname lookup for '%s' failed\n", buf);
|
||||
return 0;
|
||||
}
|
||||
ip = lookup->h_addr_list[0];
|
||||
determine_port:
|
||||
if(strlen(ptr) < 1)
|
||||
return 0;
|
||||
if(!int_strtoul(ptr, &port) || (port > 65535))
|
||||
return 0;
|
||||
*parsed_ip = ip;
|
||||
*parsed_port = (unsigned short)port;
|
||||
return 1;
|
||||
if (!ptr) {
|
||||
/*
|
||||
* We assume we're listening on all local interfaces and have only
|
||||
* specified a port.
|
||||
*/
|
||||
if (!accept_all_ip)
|
||||
return 0;
|
||||
ptr = address;
|
||||
goto determine_port;
|
||||
}
|
||||
if ((ptr - address) > 255)
|
||||
return 0;
|
||||
memset(buf, 0, 256);
|
||||
memcpy(buf, address, ptr - address);
|
||||
ptr++;
|
||||
if ((lookup = gethostbyname(buf)) == NULL) {
|
||||
/*
|
||||
* Spit a message to differentiate between lookup failures and bad
|
||||
* strings.
|
||||
*/
|
||||
fprintf(stderr, "hostname lookup for '%s' failed\n", buf);
|
||||
return 0;
|
||||
}
|
||||
ip = lookup->h_addr_list[0];
|
||||
determine_port:
|
||||
if (strlen(ptr) < 1)
|
||||
return 0;
|
||||
if (!int_strtoul(ptr, &port) || (port > 65535))
|
||||
return 0;
|
||||
*parsed_ip = ip;
|
||||
*parsed_port = (unsigned short)port;
|
||||
return 1;
|
||||
}
|
||||
|
||||
int ip_create_listener(const char *address)
|
||||
{
|
||||
const char *ip;
|
||||
unsigned short port;
|
||||
const char *ip;
|
||||
unsigned short port;
|
||||
|
||||
if(!ip_parse_address(address, &ip, &port, 1))
|
||||
return -1;
|
||||
return ip_create_listener_split(ip, port);
|
||||
if (!ip_parse_address(address, &ip, &port, 1))
|
||||
return -1;
|
||||
return ip_create_listener_split(ip, port);
|
||||
}
|
||||
|
||||
int ip_create_connection(const char *address)
|
||||
{
|
||||
const char *ip;
|
||||
unsigned short port;
|
||||
const char *ip;
|
||||
unsigned short port;
|
||||
|
||||
if(!ip_parse_address(address, &ip, &port, 0))
|
||||
return -1;
|
||||
return ip_create_connection_split(ip, port);
|
||||
if (!ip_parse_address(address, &ip, &port, 0))
|
||||
return -1;
|
||||
return ip_create_connection_split(ip, port);
|
||||
}
|
||||
|
||||
int ip_accept_connection(int listen_fd)
|
||||
{
|
||||
return accept(listen_fd, NULL, NULL);
|
||||
return accept(listen_fd, NULL, NULL);
|
||||
}
|
||||
|
||||
#endif /* !defined(NO_IP) */
|
||||
|
||||
#endif /* !defined(NO_IP) */
|
||||
|
||||
@@ -2,150 +2,163 @@
|
||||
|
||||
#ifndef NO_TUNALA
|
||||
|
||||
void state_machine_init(state_machine_t *machine)
|
||||
void state_machine_init(state_machine_t * machine)
|
||||
{
|
||||
machine->ssl = NULL;
|
||||
machine->bio_intossl = machine->bio_fromssl = NULL;
|
||||
buffer_init(&machine->clean_in);
|
||||
buffer_init(&machine->clean_out);
|
||||
buffer_init(&machine->dirty_in);
|
||||
buffer_init(&machine->dirty_out);
|
||||
machine->ssl = NULL;
|
||||
machine->bio_intossl = machine->bio_fromssl = NULL;
|
||||
buffer_init(&machine->clean_in);
|
||||
buffer_init(&machine->clean_out);
|
||||
buffer_init(&machine->dirty_in);
|
||||
buffer_init(&machine->dirty_out);
|
||||
}
|
||||
|
||||
void state_machine_close(state_machine_t *machine)
|
||||
void state_machine_close(state_machine_t * machine)
|
||||
{
|
||||
if(machine->ssl)
|
||||
SSL_free(machine->ssl);
|
||||
/* SSL_free seems to decrement the reference counts already so doing this goes
|
||||
* kaboom. */
|
||||
#if 0
|
||||
if(machine->bio_intossl)
|
||||
BIO_free(machine->bio_intossl);
|
||||
if(machine->bio_fromssl)
|
||||
BIO_free(machine->bio_fromssl);
|
||||
#endif
|
||||
buffer_close(&machine->clean_in);
|
||||
buffer_close(&machine->clean_out);
|
||||
buffer_close(&machine->dirty_in);
|
||||
buffer_close(&machine->dirty_out);
|
||||
state_machine_init(machine);
|
||||
if (machine->ssl)
|
||||
SSL_free(machine->ssl);
|
||||
/*
|
||||
* SSL_free seems to decrement the reference counts already so doing this
|
||||
* goes kaboom.
|
||||
*/
|
||||
# if 0
|
||||
if (machine->bio_intossl)
|
||||
BIO_free(machine->bio_intossl);
|
||||
if (machine->bio_fromssl)
|
||||
BIO_free(machine->bio_fromssl);
|
||||
# endif
|
||||
buffer_close(&machine->clean_in);
|
||||
buffer_close(&machine->clean_out);
|
||||
buffer_close(&machine->dirty_in);
|
||||
buffer_close(&machine->dirty_out);
|
||||
state_machine_init(machine);
|
||||
}
|
||||
|
||||
buffer_t *state_machine_get_buffer(state_machine_t *machine, sm_buffer_t type)
|
||||
buffer_t *state_machine_get_buffer(state_machine_t * machine,
|
||||
sm_buffer_t type)
|
||||
{
|
||||
switch(type) {
|
||||
case SM_CLEAN_IN:
|
||||
return &machine->clean_in;
|
||||
case SM_CLEAN_OUT:
|
||||
return &machine->clean_out;
|
||||
case SM_DIRTY_IN:
|
||||
return &machine->dirty_in;
|
||||
case SM_DIRTY_OUT:
|
||||
return &machine->dirty_out;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
/* Should never get here */
|
||||
abort();
|
||||
return NULL;
|
||||
switch (type) {
|
||||
case SM_CLEAN_IN:
|
||||
return &machine->clean_in;
|
||||
case SM_CLEAN_OUT:
|
||||
return &machine->clean_out;
|
||||
case SM_DIRTY_IN:
|
||||
return &machine->dirty_in;
|
||||
case SM_DIRTY_OUT:
|
||||
return &machine->dirty_out;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
/* Should never get here */
|
||||
abort();
|
||||
return NULL;
|
||||
}
|
||||
|
||||
SSL *state_machine_get_SSL(state_machine_t *machine)
|
||||
SSL *state_machine_get_SSL(state_machine_t * machine)
|
||||
{
|
||||
return machine->ssl;
|
||||
return machine->ssl;
|
||||
}
|
||||
|
||||
int state_machine_set_SSL(state_machine_t *machine, SSL *ssl, int is_server)
|
||||
int state_machine_set_SSL(state_machine_t * machine, SSL *ssl, int is_server)
|
||||
{
|
||||
if(machine->ssl)
|
||||
/* Shouldn't ever be set twice */
|
||||
abort();
|
||||
machine->ssl = ssl;
|
||||
/* Create the BIOs to handle the dirty side of the SSL */
|
||||
if((machine->bio_intossl = BIO_new(BIO_s_mem())) == NULL)
|
||||
abort();
|
||||
if((machine->bio_fromssl = BIO_new(BIO_s_mem())) == NULL)
|
||||
abort();
|
||||
/* Hook up the BIOs on the dirty side of the SSL */
|
||||
SSL_set_bio(machine->ssl, machine->bio_intossl, machine->bio_fromssl);
|
||||
if(is_server)
|
||||
SSL_set_accept_state(machine->ssl);
|
||||
else
|
||||
SSL_set_connect_state(machine->ssl);
|
||||
/* If we're the first one to generate traffic - do it now otherwise we
|
||||
* go into the next select empty-handed and our peer will not send data
|
||||
* but will similarly wait for us. */
|
||||
return state_machine_churn(machine);
|
||||
if (machine->ssl)
|
||||
/* Shouldn't ever be set twice */
|
||||
abort();
|
||||
machine->ssl = ssl;
|
||||
/* Create the BIOs to handle the dirty side of the SSL */
|
||||
if ((machine->bio_intossl = BIO_new(BIO_s_mem())) == NULL)
|
||||
abort();
|
||||
if ((machine->bio_fromssl = BIO_new(BIO_s_mem())) == NULL)
|
||||
abort();
|
||||
/* Hook up the BIOs on the dirty side of the SSL */
|
||||
SSL_set_bio(machine->ssl, machine->bio_intossl, machine->bio_fromssl);
|
||||
if (is_server)
|
||||
SSL_set_accept_state(machine->ssl);
|
||||
else
|
||||
SSL_set_connect_state(machine->ssl);
|
||||
/*
|
||||
* If we're the first one to generate traffic - do it now otherwise we go
|
||||
* into the next select empty-handed and our peer will not send data but
|
||||
* will similarly wait for us.
|
||||
*/
|
||||
return state_machine_churn(machine);
|
||||
}
|
||||
|
||||
/* Performs the data-IO loop and returns zero if the machine should close */
|
||||
int state_machine_churn(state_machine_t *machine)
|
||||
int state_machine_churn(state_machine_t * machine)
|
||||
{
|
||||
unsigned int loop;
|
||||
if(machine->ssl == NULL) {
|
||||
if(buffer_empty(&machine->clean_out))
|
||||
/* Time to close this state-machine altogether */
|
||||
return 0;
|
||||
else
|
||||
/* Still buffered data on the clean side to go out */
|
||||
return 1;
|
||||
}
|
||||
/* Do this loop twice to cover any dependencies about which precise
|
||||
* order of reads and writes is required. */
|
||||
for(loop = 0; loop < 2; loop++) {
|
||||
buffer_to_SSL(&machine->clean_in, machine->ssl);
|
||||
buffer_to_BIO(&machine->dirty_in, machine->bio_intossl);
|
||||
buffer_from_SSL(&machine->clean_out, machine->ssl);
|
||||
buffer_from_BIO(&machine->dirty_out, machine->bio_fromssl);
|
||||
}
|
||||
/* We close on the SSL side if the info callback noticed some problems
|
||||
* or an SSL shutdown was underway and shutdown traffic had all been
|
||||
* sent. */
|
||||
if(SSL_get_app_data(machine->ssl) || (SSL_get_shutdown(machine->ssl) &&
|
||||
buffer_empty(&machine->dirty_out))) {
|
||||
/* Great, we can seal off the dirty side completely */
|
||||
if(!state_machine_close_dirty(machine))
|
||||
return 0;
|
||||
}
|
||||
/* Either the SSL is alive and well, or the closing process still has
|
||||
* outgoing data waiting to be sent */
|
||||
return 1;
|
||||
unsigned int loop;
|
||||
if (machine->ssl == NULL) {
|
||||
if (buffer_empty(&machine->clean_out))
|
||||
/* Time to close this state-machine altogether */
|
||||
return 0;
|
||||
else
|
||||
/* Still buffered data on the clean side to go out */
|
||||
return 1;
|
||||
}
|
||||
/*
|
||||
* Do this loop twice to cover any dependencies about which precise order
|
||||
* of reads and writes is required.
|
||||
*/
|
||||
for (loop = 0; loop < 2; loop++) {
|
||||
buffer_to_SSL(&machine->clean_in, machine->ssl);
|
||||
buffer_to_BIO(&machine->dirty_in, machine->bio_intossl);
|
||||
buffer_from_SSL(&machine->clean_out, machine->ssl);
|
||||
buffer_from_BIO(&machine->dirty_out, machine->bio_fromssl);
|
||||
}
|
||||
/*
|
||||
* We close on the SSL side if the info callback noticed some problems or
|
||||
* an SSL shutdown was underway and shutdown traffic had all been sent.
|
||||
*/
|
||||
if (SSL_get_app_data(machine->ssl) || (SSL_get_shutdown(machine->ssl) &&
|
||||
buffer_empty(&machine->dirty_out)))
|
||||
{
|
||||
/* Great, we can seal off the dirty side completely */
|
||||
if (!state_machine_close_dirty(machine))
|
||||
return 0;
|
||||
}
|
||||
/*
|
||||
* Either the SSL is alive and well, or the closing process still has
|
||||
* outgoing data waiting to be sent
|
||||
*/
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* Called when the clean side of the SSL has lost its connection */
|
||||
int state_machine_close_clean(state_machine_t *machine)
|
||||
int state_machine_close_clean(state_machine_t * machine)
|
||||
{
|
||||
/* Well, first thing to do is null out the clean-side buffers - they're
|
||||
* no use any more. */
|
||||
buffer_close(&machine->clean_in);
|
||||
buffer_close(&machine->clean_out);
|
||||
/* And start an SSL shutdown */
|
||||
if(machine->ssl)
|
||||
SSL_shutdown(machine->ssl);
|
||||
/* This is an "event", so flush the SSL of any generated traffic */
|
||||
state_machine_churn(machine);
|
||||
if(buffer_empty(&machine->dirty_in) &&
|
||||
buffer_empty(&machine->dirty_out))
|
||||
return 0;
|
||||
return 1;
|
||||
/*
|
||||
* Well, first thing to do is null out the clean-side buffers - they're
|
||||
* no use any more.
|
||||
*/
|
||||
buffer_close(&machine->clean_in);
|
||||
buffer_close(&machine->clean_out);
|
||||
/* And start an SSL shutdown */
|
||||
if (machine->ssl)
|
||||
SSL_shutdown(machine->ssl);
|
||||
/* This is an "event", so flush the SSL of any generated traffic */
|
||||
state_machine_churn(machine);
|
||||
if (buffer_empty(&machine->dirty_in) && buffer_empty(&machine->dirty_out))
|
||||
return 0;
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* Called when the dirty side of the SSL has lost its connection. This is pretty
|
||||
* terminal as all that can be left to do is send any buffered output on the
|
||||
* clean side - after that, we're done. */
|
||||
int state_machine_close_dirty(state_machine_t *machine)
|
||||
/*
|
||||
* Called when the dirty side of the SSL has lost its connection. This is
|
||||
* pretty terminal as all that can be left to do is send any buffered output
|
||||
* on the clean side - after that, we're done.
|
||||
*/
|
||||
int state_machine_close_dirty(state_machine_t * machine)
|
||||
{
|
||||
buffer_close(&machine->dirty_in);
|
||||
buffer_close(&machine->dirty_out);
|
||||
buffer_close(&machine->clean_in);
|
||||
if(machine->ssl)
|
||||
SSL_free(machine->ssl);
|
||||
machine->ssl = NULL;
|
||||
machine->bio_intossl = machine->bio_fromssl = NULL;
|
||||
if(buffer_empty(&machine->clean_out))
|
||||
return 0;
|
||||
return 1;
|
||||
buffer_close(&machine->dirty_in);
|
||||
buffer_close(&machine->dirty_out);
|
||||
buffer_close(&machine->clean_in);
|
||||
if (machine->ssl)
|
||||
SSL_free(machine->ssl);
|
||||
machine->ssl = NULL;
|
||||
machine->bio_intossl = machine->bio_fromssl = NULL;
|
||||
if (buffer_empty(&machine->clean_out))
|
||||
return 0;
|
||||
return 1;
|
||||
}
|
||||
|
||||
#endif /* !defined(NO_TUNALA) */
|
||||
|
||||
#endif /* !defined(NO_TUNALA) */
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,215 +1,244 @@
|
||||
/* Tunala ("Tunneler with a New Zealand accent")
|
||||
*
|
||||
* Written by Geoff Thorpe, but endorsed/supported by noone. Please use this is
|
||||
* if it's useful or informative to you, but it's only here as a scratchpad for
|
||||
* ideas about how you might (or might not) program with OpenSSL. If you deploy
|
||||
* this is in a mission-critical environment, and have not read, understood,
|
||||
* audited, and modified this code to your satisfaction, and the result is that
|
||||
* all hell breaks loose and you are looking for a new employer, then it proves
|
||||
* nothing except perhaps that Darwinism is alive and well. Let's just say, *I*
|
||||
* don't use this in a mission-critical environment, so it would be stupid for
|
||||
* anyone to assume that it is solid and/or tested enough when even its author
|
||||
* doesn't place that much trust in it. You have been warned.
|
||||
*
|
||||
/*
|
||||
* Tunala ("Tunneler with a New Zealand accent") Written by Geoff Thorpe,
|
||||
* but endorsed/supported by noone. Please use this is if it's useful or
|
||||
* informative to you, but it's only here as a scratchpad for ideas about how
|
||||
* you might (or might not) program with OpenSSL. If you deploy this is in a
|
||||
* mission-critical environment, and have not read, understood, audited, and
|
||||
* modified this code to your satisfaction, and the result is that all hell
|
||||
* breaks loose and you are looking for a new employer, then it proves
|
||||
* nothing except perhaps that Darwinism is alive and well. Let's just say,
|
||||
* *I* don't use this in a mission-critical environment, so it would be
|
||||
* stupid for anyone to assume that it is solid and/or tested enough when
|
||||
* even its author doesn't place that much trust in it. You have been warned.
|
||||
* With thanks to Cryptographic Appliances, Inc.
|
||||
*/
|
||||
|
||||
#ifndef _TUNALA_H
|
||||
#define _TUNALA_H
|
||||
# define _TUNALA_H
|
||||
|
||||
/* pull in autoconf fluff */
|
||||
#ifndef NO_CONFIG_H
|
||||
#include "config.h"
|
||||
#else
|
||||
/* We don't have autoconf, we have to set all of these unless a tweaked Makefile
|
||||
* tells us not to ... */
|
||||
# ifndef NO_CONFIG_H
|
||||
# include "config.h"
|
||||
# else
|
||||
/*
|
||||
* We don't have autoconf, we have to set all of these unless a tweaked
|
||||
* Makefile tells us not to ...
|
||||
*/
|
||||
/* headers */
|
||||
#ifndef NO_HAVE_SELECT
|
||||
#define HAVE_SELECT
|
||||
#endif
|
||||
#ifndef NO_HAVE_SOCKET
|
||||
#define HAVE_SOCKET
|
||||
#endif
|
||||
#ifndef NO_HAVE_UNISTD_H
|
||||
#define HAVE_UNISTD_H
|
||||
#endif
|
||||
#ifndef NO_HAVE_FCNTL_H
|
||||
#define HAVE_FCNTL_H
|
||||
#endif
|
||||
#ifndef NO_HAVE_LIMITS_H
|
||||
#define HAVE_LIMITS_H
|
||||
#endif
|
||||
# ifndef NO_HAVE_SELECT
|
||||
# define HAVE_SELECT
|
||||
# endif
|
||||
# ifndef NO_HAVE_SOCKET
|
||||
# define HAVE_SOCKET
|
||||
# endif
|
||||
# ifndef NO_HAVE_UNISTD_H
|
||||
# define HAVE_UNISTD_H
|
||||
# endif
|
||||
# ifndef NO_HAVE_FCNTL_H
|
||||
# define HAVE_FCNTL_H
|
||||
# endif
|
||||
# ifndef NO_HAVE_LIMITS_H
|
||||
# define HAVE_LIMITS_H
|
||||
# endif
|
||||
/* features */
|
||||
#ifndef NO_HAVE_STRSTR
|
||||
#define HAVE_STRSTR
|
||||
#endif
|
||||
#ifndef NO_HAVE_STRTOUL
|
||||
#define HAVE_STRTOUL
|
||||
#endif
|
||||
#endif
|
||||
# ifndef NO_HAVE_STRSTR
|
||||
# define HAVE_STRSTR
|
||||
# endif
|
||||
# ifndef NO_HAVE_STRTOUL
|
||||
# define HAVE_STRTOUL
|
||||
# endif
|
||||
# endif
|
||||
|
||||
#if !defined(HAVE_SELECT) || !defined(HAVE_SOCKET)
|
||||
#error "can't build without some network basics like select() and socket()"
|
||||
#endif
|
||||
# if !defined(HAVE_SELECT) || !defined(HAVE_SOCKET)
|
||||
# error "can't build without some network basics like select() and socket()"
|
||||
# endif
|
||||
|
||||
#include <stdlib.h>
|
||||
#ifndef NO_SYSTEM_H
|
||||
#include <string.h>
|
||||
#ifdef HAVE_UNISTD_H
|
||||
#include <unistd.h>
|
||||
#endif
|
||||
#ifdef HAVE_FCNTL_H
|
||||
#include <fcntl.h>
|
||||
#endif
|
||||
#ifdef HAVE_LIMITS_H
|
||||
#include <limits.h>
|
||||
#endif
|
||||
#include <netdb.h>
|
||||
#include <signal.h>
|
||||
#include <sys/socket.h>
|
||||
#include <sys/types.h>
|
||||
#include <netinet/in.h>
|
||||
#endif /* !defined(NO_SYSTEM_H) */
|
||||
# include <stdlib.h>
|
||||
# ifndef NO_SYSTEM_H
|
||||
# include <string.h>
|
||||
# ifdef HAVE_UNISTD_H
|
||||
# include <unistd.h>
|
||||
# endif
|
||||
# ifdef HAVE_FCNTL_H
|
||||
# include <fcntl.h>
|
||||
# endif
|
||||
# ifdef HAVE_LIMITS_H
|
||||
# include <limits.h>
|
||||
# endif
|
||||
# include <netdb.h>
|
||||
# include <signal.h>
|
||||
# include <sys/socket.h>
|
||||
# include <sys/types.h>
|
||||
# include <netinet/in.h>
|
||||
# endif /* !defined(NO_SYSTEM_H) */
|
||||
|
||||
#ifndef NO_OPENSSL
|
||||
#include <openssl/err.h>
|
||||
#include <openssl/engine.h>
|
||||
#include <openssl/ssl.h>
|
||||
#endif /* !defined(NO_OPENSSL) */
|
||||
# ifndef NO_OPENSSL
|
||||
# include <openssl/err.h>
|
||||
# include <openssl/engine.h>
|
||||
# include <openssl/ssl.h>
|
||||
# endif /* !defined(NO_OPENSSL) */
|
||||
|
||||
#ifndef OPENSSL_NO_BUFFER
|
||||
/* This is the generic "buffer" type that is used when feeding the
|
||||
# ifndef OPENSSL_NO_BUFFER
|
||||
/*
|
||||
* This is the generic "buffer" type that is used when feeding the
|
||||
* state-machine. It's basically a FIFO with respect to the "adddata" &
|
||||
* "takedata" type functions that operate on it. */
|
||||
#define MAX_DATA_SIZE 16384
|
||||
* "takedata" type functions that operate on it.
|
||||
*/
|
||||
# define MAX_DATA_SIZE 16384
|
||||
typedef struct _buffer_t {
|
||||
unsigned char data[MAX_DATA_SIZE];
|
||||
unsigned int used;
|
||||
/* Statistical values - counts the total number of bytes read in and
|
||||
* read out (respectively) since "buffer_init()" */
|
||||
unsigned long total_in, total_out;
|
||||
unsigned char data[MAX_DATA_SIZE];
|
||||
unsigned int used;
|
||||
/*
|
||||
* Statistical values - counts the total number of bytes read in and read
|
||||
* out (respectively) since "buffer_init()"
|
||||
*/
|
||||
unsigned long total_in, total_out;
|
||||
} buffer_t;
|
||||
|
||||
/* Initialise a buffer structure before use */
|
||||
void buffer_init(buffer_t *buf);
|
||||
/* Cleanup a buffer structure - presently not needed, but if buffer_t is
|
||||
* converted to using dynamic allocation, this would be required - so should be
|
||||
* called to protect against an explosion of memory leaks later if the change is
|
||||
* made. */
|
||||
void buffer_close(buffer_t *buf);
|
||||
void buffer_init(buffer_t * buf);
|
||||
/*
|
||||
* Cleanup a buffer structure - presently not needed, but if buffer_t is
|
||||
* converted to using dynamic allocation, this would be required - so should
|
||||
* be called to protect against an explosion of memory leaks later if the
|
||||
* change is made.
|
||||
*/
|
||||
void buffer_close(buffer_t * buf);
|
||||
|
||||
/* Basic functions to manipulate buffers */
|
||||
|
||||
unsigned int buffer_used(buffer_t *buf); /* How much data in the buffer */
|
||||
unsigned int buffer_unused(buffer_t *buf); /* How much space in the buffer */
|
||||
int buffer_full(buffer_t *buf); /* Boolean, is it full? */
|
||||
int buffer_notfull(buffer_t *buf); /* Boolean, is it not full? */
|
||||
int buffer_empty(buffer_t *buf); /* Boolean, is it empty? */
|
||||
int buffer_notempty(buffer_t *buf); /* Boolean, is it not empty? */
|
||||
unsigned long buffer_total_in(buffer_t *buf); /* Total bytes written to buffer */
|
||||
unsigned long buffer_total_out(buffer_t *buf); /* Total bytes read from buffer */
|
||||
unsigned int buffer_used(buffer_t * buf); /* How much data in the buffer */
|
||||
unsigned int buffer_unused(buffer_t * buf); /* How much space in the buffer */
|
||||
int buffer_full(buffer_t * buf); /* Boolean, is it full? */
|
||||
int buffer_notfull(buffer_t * buf); /* Boolean, is it not full? */
|
||||
int buffer_empty(buffer_t * buf); /* Boolean, is it empty? */
|
||||
int buffer_notempty(buffer_t * buf); /* Boolean, is it not empty? */
|
||||
unsigned long buffer_total_in(buffer_t * buf); /* Total bytes written to
|
||||
* buffer */
|
||||
unsigned long buffer_total_out(buffer_t * buf); /* Total bytes read from
|
||||
* buffer */
|
||||
|
||||
#if 0 /* Currently used only within buffer.c - better to expose only
|
||||
* higher-level functions anyway */
|
||||
/* Add data to the tail of the buffer, returns the amount that was actually
|
||||
* added (so, you need to check if return value is less than size) */
|
||||
unsigned int buffer_adddata(buffer_t *buf, const unsigned char *ptr,
|
||||
unsigned int size);
|
||||
# if 0 /* Currently used only within buffer.c -
|
||||
* better to expose only higher-level
|
||||
* functions anyway */
|
||||
/*
|
||||
* Add data to the tail of the buffer, returns the amount that was actually
|
||||
* added (so, you need to check if return value is less than size)
|
||||
*/
|
||||
unsigned int buffer_adddata(buffer_t * buf, const unsigned char *ptr,
|
||||
unsigned int size);
|
||||
|
||||
/* Take data from the front of the buffer (and scroll the rest forward). If
|
||||
/*
|
||||
* Take data from the front of the buffer (and scroll the rest forward). If
|
||||
* "ptr" is NULL, this just removes data off the front of the buffer. Return
|
||||
* value is the amount actually removed (can be less than size if the buffer has
|
||||
* too little data). */
|
||||
unsigned int buffer_takedata(buffer_t *buf, unsigned char *ptr,
|
||||
unsigned int size);
|
||||
* value is the amount actually removed (can be less than size if the buffer
|
||||
* has too little data).
|
||||
*/
|
||||
unsigned int buffer_takedata(buffer_t * buf, unsigned char *ptr,
|
||||
unsigned int size);
|
||||
|
||||
/* Flushes as much data as possible out of the "from" buffer into the "to"
|
||||
* buffer. Return value is the amount moved. The amount moved can be restricted
|
||||
* to a maximum by specifying "cap" - setting it to -1 means no limit. */
|
||||
unsigned int buffer_tobuffer(buffer_t *to, buffer_t *from, int cap);
|
||||
#endif
|
||||
/*
|
||||
* Flushes as much data as possible out of the "from" buffer into the "to"
|
||||
* buffer. Return value is the amount moved. The amount moved can be
|
||||
* restricted to a maximum by specifying "cap" - setting it to -1 means no
|
||||
* limit.
|
||||
*/
|
||||
unsigned int buffer_tobuffer(buffer_t * to, buffer_t * from, int cap);
|
||||
# endif
|
||||
|
||||
#ifndef NO_IP
|
||||
# ifndef NO_IP
|
||||
/* Read or write between a file-descriptor and a buffer */
|
||||
int buffer_from_fd(buffer_t *buf, int fd);
|
||||
int buffer_to_fd(buffer_t *buf, int fd);
|
||||
#endif /* !defined(NO_IP) */
|
||||
int buffer_from_fd(buffer_t * buf, int fd);
|
||||
int buffer_to_fd(buffer_t * buf, int fd);
|
||||
# endif /* !defined(NO_IP) */
|
||||
|
||||
#ifndef NO_OPENSSL
|
||||
# ifndef NO_OPENSSL
|
||||
/* Read or write between an SSL or BIO and a buffer */
|
||||
void buffer_from_SSL(buffer_t *buf, SSL *ssl);
|
||||
void buffer_to_SSL(buffer_t *buf, SSL *ssl);
|
||||
void buffer_from_BIO(buffer_t *buf, BIO *bio);
|
||||
void buffer_to_BIO(buffer_t *buf, BIO *bio);
|
||||
void buffer_from_SSL(buffer_t * buf, SSL *ssl);
|
||||
void buffer_to_SSL(buffer_t * buf, SSL *ssl);
|
||||
void buffer_from_BIO(buffer_t * buf, BIO *bio);
|
||||
void buffer_to_BIO(buffer_t * buf, BIO *bio);
|
||||
|
||||
/* Callbacks */
|
||||
void cb_ssl_info(const SSL *s, int where, int ret);
|
||||
void cb_ssl_info_set_output(FILE *fp); /* Called if output should be sent too */
|
||||
/* Called if output should be sent too */
|
||||
void cb_ssl_info_set_output(FILE *fp);
|
||||
int cb_ssl_verify(int ok, X509_STORE_CTX *ctx);
|
||||
void cb_ssl_verify_set_output(FILE *fp);
|
||||
void cb_ssl_verify_set_depth(unsigned int verify_depth);
|
||||
void cb_ssl_verify_set_level(unsigned int level);
|
||||
RSA *cb_generate_tmp_rsa(SSL *s, int is_export, int keylength);
|
||||
#endif /* !defined(NO_OPENSSL) */
|
||||
#endif /* !defined(OPENSSL_NO_BUFFER) */
|
||||
# endif /* !defined(NO_OPENSSL) */
|
||||
# endif /* !defined(OPENSSL_NO_BUFFER) */
|
||||
|
||||
#ifndef NO_TUNALA
|
||||
#ifdef OPENSSL_NO_BUFFER
|
||||
#error "TUNALA section of tunala.h requires BUFFER support"
|
||||
#endif
|
||||
# ifndef NO_TUNALA
|
||||
# ifdef OPENSSL_NO_BUFFER
|
||||
# error "TUNALA section of tunala.h requires BUFFER support"
|
||||
# endif
|
||||
typedef struct _state_machine_t {
|
||||
SSL *ssl;
|
||||
BIO *bio_intossl;
|
||||
BIO *bio_fromssl;
|
||||
buffer_t clean_in, clean_out;
|
||||
buffer_t dirty_in, dirty_out;
|
||||
SSL *ssl;
|
||||
BIO *bio_intossl;
|
||||
BIO *bio_fromssl;
|
||||
buffer_t clean_in, clean_out;
|
||||
buffer_t dirty_in, dirty_out;
|
||||
} state_machine_t;
|
||||
typedef enum {
|
||||
SM_CLEAN_IN, SM_CLEAN_OUT,
|
||||
SM_DIRTY_IN, SM_DIRTY_OUT
|
||||
SM_CLEAN_IN, SM_CLEAN_OUT,
|
||||
SM_DIRTY_IN, SM_DIRTY_OUT
|
||||
} sm_buffer_t;
|
||||
void state_machine_init(state_machine_t *machine);
|
||||
void state_machine_close(state_machine_t *machine);
|
||||
buffer_t *state_machine_get_buffer(state_machine_t *machine, sm_buffer_t type);
|
||||
SSL *state_machine_get_SSL(state_machine_t *machine);
|
||||
int state_machine_set_SSL(state_machine_t *machine, SSL *ssl, int is_server);
|
||||
void state_machine_init(state_machine_t * machine);
|
||||
void state_machine_close(state_machine_t * machine);
|
||||
buffer_t *state_machine_get_buffer(state_machine_t * machine,
|
||||
sm_buffer_t type);
|
||||
SSL *state_machine_get_SSL(state_machine_t * machine);
|
||||
int state_machine_set_SSL(state_machine_t * machine, SSL *ssl, int is_server);
|
||||
/* Performs the data-IO loop and returns zero if the machine should close */
|
||||
int state_machine_churn(state_machine_t *machine);
|
||||
/* Is used to handle closing conditions - namely when one side of the tunnel has
|
||||
* closed but the other should finish flushing. */
|
||||
int state_machine_close_clean(state_machine_t *machine);
|
||||
int state_machine_close_dirty(state_machine_t *machine);
|
||||
#endif /* !defined(NO_TUNALA) */
|
||||
int state_machine_churn(state_machine_t * machine);
|
||||
/*
|
||||
* Is used to handle closing conditions - namely when one side of the tunnel
|
||||
* has closed but the other should finish flushing.
|
||||
*/
|
||||
int state_machine_close_clean(state_machine_t * machine);
|
||||
int state_machine_close_dirty(state_machine_t * machine);
|
||||
# endif /* !defined(NO_TUNALA) */
|
||||
|
||||
#ifndef NO_IP
|
||||
/* Initialise anything related to the networking. This includes blocking pesky
|
||||
* SIGPIPE signals. */
|
||||
# ifndef NO_IP
|
||||
/*
|
||||
* Initialise anything related to the networking. This includes blocking
|
||||
* pesky SIGPIPE signals.
|
||||
*/
|
||||
int ip_initialise(void);
|
||||
/* ip is the 4-byte ip address (eg. 127.0.0.1 is {0x7F,0x00,0x00,0x01}), port is
|
||||
* the port to listen on (host byte order), and the return value is the
|
||||
* file-descriptor or -1 on error. */
|
||||
/*
|
||||
* ip is the 4-byte ip address (eg. 127.0.0.1 is {0x7F,0x00,0x00,0x01}), port
|
||||
* is the port to listen on (host byte order), and the return value is the
|
||||
* file-descriptor or -1 on error.
|
||||
*/
|
||||
int ip_create_listener_split(const char *ip, unsigned short port);
|
||||
/* Same semantics as above. */
|
||||
int ip_create_connection_split(const char *ip, unsigned short port);
|
||||
/* Converts a string into the ip/port before calling the above */
|
||||
int ip_create_listener(const char *address);
|
||||
int ip_create_connection(const char *address);
|
||||
/* Just does a string conversion on its own. NB: If accept_all_ip is non-zero,
|
||||
* then the address string could be just a port. Ie. it's suitable for a
|
||||
* listening address but not a connecting address. */
|
||||
/*
|
||||
* Just does a string conversion on its own. NB: If accept_all_ip is
|
||||
* non-zero, then the address string could be just a port. Ie. it's suitable
|
||||
* for a listening address but not a connecting address.
|
||||
*/
|
||||
int ip_parse_address(const char *address, const char **parsed_ip,
|
||||
unsigned short *port, int accept_all_ip);
|
||||
/* Accepts an incoming connection through the listener. Assumes selects and
|
||||
* what-not have deemed it an appropriate thing to do. */
|
||||
unsigned short *port, int accept_all_ip);
|
||||
/*
|
||||
* Accepts an incoming connection through the listener. Assumes selects and
|
||||
* what-not have deemed it an appropriate thing to do.
|
||||
*/
|
||||
int ip_accept_connection(int listen_fd);
|
||||
#endif /* !defined(NO_IP) */
|
||||
# endif /* !defined(NO_IP) */
|
||||
|
||||
/* These functions wrap up things that can be portability hassles. */
|
||||
int int_strtoul(const char *str, unsigned long *val);
|
||||
#ifdef HAVE_STRSTR
|
||||
#define int_strstr strstr
|
||||
#else
|
||||
# ifdef HAVE_STRSTR
|
||||
# define int_strstr strstr
|
||||
# else
|
||||
char *int_strstr(const char *haystack, const char *needle);
|
||||
#endif
|
||||
# endif
|
||||
|
||||
#endif /* !defined(_TUNALA_H) */
|
||||
#endif /* !defined(_TUNALA_H) */
|
||||
|
||||
Reference in New Issue
Block a user