This commit is contained in:
Zhi Guan
2015-08-15 15:02:15 +08:00
parent 06df2fab54
commit 3bdc0ea895
2536 changed files with 417052 additions and 271997 deletions

View File

@@ -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

View File

@@ -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) */

View File

@@ -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) */

View File

@@ -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) */

View File

@@ -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

View File

@@ -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) */