2005-04-28 10:26:44 +02:00
|
|
|
|
/*
|
|
|
|
|
* $Id: connection.c,v 1.98 2005/04/12 19:34:35 nohar Exp $
|
|
|
|
|
*
|
|
|
|
|
* This file is part of the bip project
|
2022-01-09 21:20:49 +01:00
|
|
|
|
* Copyright (C) 2004,2005 Arnaud Cornet
|
|
|
|
|
* Copyright (C) 2004,2005,2022 Loïc Gomez
|
2005-04-28 10:26:44 +02:00
|
|
|
|
*
|
|
|
|
|
* This program is free software; you can redistribute it and/or modify
|
|
|
|
|
* it under the terms of the GNU General Public License as published by
|
|
|
|
|
* the Free Software Foundation; either version 2 of the License, or
|
|
|
|
|
* (at your option) any later version.
|
|
|
|
|
* See the file "COPYING" for the exact licensing terms.
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
#include "config.h"
|
|
|
|
|
#include <sys/time.h>
|
|
|
|
|
#include <time.h>
|
|
|
|
|
#include "connection.h"
|
2018-03-21 11:12:21 +01:00
|
|
|
|
#include "path_util.h"
|
2005-04-28 10:26:44 +02:00
|
|
|
|
|
2022-01-09 20:37:55 +01:00
|
|
|
|
#pragma GCC diagnostic push
|
|
|
|
|
#pragma GCC diagnostic ignored "-Wstrict-prototypes"
|
2005-04-28 10:26:44 +02:00
|
|
|
|
extern int errno;
|
2022-01-09 20:37:55 +01:00
|
|
|
|
#pragma GCC diagnostic pop
|
2005-04-28 10:26:44 +02:00
|
|
|
|
#ifdef HAVE_LIBSSL
|
2005-06-04 13:05:54 +02:00
|
|
|
|
static int ssl_initialized = 0;
|
2005-04-28 10:26:44 +02:00
|
|
|
|
static SSL_CTX *sslctx = NULL;
|
2005-06-04 13:05:54 +02:00
|
|
|
|
static int ssl_cx_idx;
|
2012-01-25 05:08:52 +01:00
|
|
|
|
extern FILE *conf_global_log_file;
|
2005-04-28 10:26:44 +02:00
|
|
|
|
static BIO *errbio = NULL;
|
|
|
|
|
extern char *conf_ssl_certfile;
|
2018-03-21 11:12:21 +01:00
|
|
|
|
extern char *conf_biphome;
|
2016-04-13 01:04:33 +02:00
|
|
|
|
extern char *conf_client_ciphers;
|
2016-07-05 09:18:07 +02:00
|
|
|
|
extern char *conf_client_dh_file;
|
2005-05-12 10:29:27 +02:00
|
|
|
|
static int SSLize(connection_t *cn, int *nc);
|
2016-04-13 01:04:33 +02:00
|
|
|
|
static SSL_CTX *SSL_init_context(char *ciphers);
|
2005-08-25 10:17:10 +02:00
|
|
|
|
/* SSH like trust management */
|
|
|
|
|
int link_add_untrusted(void *ls, X509 *cert);
|
2005-04-28 10:26:44 +02:00
|
|
|
|
#endif
|
|
|
|
|
|
2013-11-04 08:49:06 +01:00
|
|
|
|
static int cn_want_write(connection_t *cn);
|
2005-04-28 10:26:44 +02:00
|
|
|
|
static int connection_timedout(connection_t *cn);
|
|
|
|
|
static int socket_set_nonblock(int s);
|
2007-12-21 12:45:49 +01:00
|
|
|
|
static void connection_connected(connection_t *c);
|
2005-04-28 10:26:44 +02:00
|
|
|
|
|
2022-03-10 13:52:03 +01:00
|
|
|
|
struct connecting_data {
|
2005-04-28 10:26:44 +02:00
|
|
|
|
struct addrinfo *dst;
|
|
|
|
|
struct addrinfo *src;
|
|
|
|
|
struct addrinfo *cur;
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
static void connecting_data_free(struct connecting_data *t)
|
|
|
|
|
{
|
|
|
|
|
if (t->dst)
|
|
|
|
|
freeaddrinfo(t->dst);
|
|
|
|
|
if (t->src)
|
|
|
|
|
freeaddrinfo(t->src);
|
|
|
|
|
free(t);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void connection_close(connection_t *cn)
|
|
|
|
|
{
|
2018-05-30 03:34:12 +02:00
|
|
|
|
mylog(LOG_DEBUG, "Connection close asked. FD:%d (status: %d)",
|
2022-03-10 13:52:03 +01:00
|
|
|
|
(long)cn->handle, cn->connected);
|
2007-10-20 21:26:21 +02:00
|
|
|
|
if (cn->connected != CONN_DISCONN && cn->connected != CONN_ERROR) {
|
2005-08-16 16:03:33 +02:00
|
|
|
|
cn->connected = CONN_DISCONN;
|
2007-07-20 16:45:33 +02:00
|
|
|
|
if (close(cn->handle) == -1)
|
|
|
|
|
mylog(LOG_WARN, "Error on socket close: %s",
|
2022-03-10 13:52:03 +01:00
|
|
|
|
strerror(errno));
|
2005-08-16 16:03:33 +02:00
|
|
|
|
}
|
2005-04-28 10:26:44 +02:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void connection_free(connection_t *cn)
|
|
|
|
|
{
|
|
|
|
|
connection_close(cn);
|
|
|
|
|
|
|
|
|
|
if (cn->outgoing) {
|
|
|
|
|
char *l;
|
|
|
|
|
while ((l = list_remove_first(cn->outgoing)))
|
|
|
|
|
free(l);
|
|
|
|
|
list_free(cn->outgoing);
|
|
|
|
|
}
|
|
|
|
|
if (cn->incoming_lines)
|
|
|
|
|
list_free(cn->incoming_lines);
|
|
|
|
|
if (cn->incoming)
|
|
|
|
|
free(cn->incoming);
|
|
|
|
|
if (cn->connecting_data)
|
|
|
|
|
connecting_data_free(cn->connecting_data);
|
2022-03-10 13:52:03 +01:00
|
|
|
|
/* conn->user_data */
|
2005-04-28 10:26:44 +02:00
|
|
|
|
#ifdef HAVE_LIBSSL
|
|
|
|
|
if (cn->ssl) {
|
|
|
|
|
if (cn->cert) {
|
|
|
|
|
X509_free(cn->cert);
|
|
|
|
|
cn->cert = NULL;
|
|
|
|
|
}
|
|
|
|
|
if (cn->ssl_h) {
|
|
|
|
|
SSL_shutdown(cn->ssl_h);
|
|
|
|
|
SSL_free(cn->ssl_h);
|
|
|
|
|
cn->ssl_h = NULL;
|
|
|
|
|
}
|
2005-06-04 13:05:54 +02:00
|
|
|
|
if (cn->ssl_ctx_h) {
|
|
|
|
|
SSL_CTX_free(cn->ssl_ctx_h);
|
|
|
|
|
cn->ssl_ctx_h = NULL;
|
|
|
|
|
}
|
2005-04-28 10:26:44 +02:00
|
|
|
|
}
|
|
|
|
|
#endif
|
2007-12-21 12:45:49 +01:00
|
|
|
|
if (cn->localip) {
|
2007-12-21 12:20:21 +01:00
|
|
|
|
free(cn->localip);
|
2007-12-21 12:45:49 +01:00
|
|
|
|
cn->localip = NULL;
|
|
|
|
|
}
|
|
|
|
|
if (cn->remoteip) {
|
2007-12-21 12:20:21 +01:00
|
|
|
|
free(cn->remoteip);
|
2007-12-21 12:45:49 +01:00
|
|
|
|
cn->remoteip = NULL;
|
|
|
|
|
}
|
2005-04-28 10:26:44 +02:00
|
|
|
|
free(cn);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void connect_trynext(connection_t *cn)
|
|
|
|
|
{
|
|
|
|
|
struct addrinfo *cur;
|
|
|
|
|
int err;
|
2007-02-08 23:53:48 +01:00
|
|
|
|
|
2005-04-28 10:26:44 +02:00
|
|
|
|
if (!cn->connecting_data)
|
|
|
|
|
fatal("called connect_trynext with a connection not "
|
2022-03-10 13:52:03 +01:00
|
|
|
|
"connecting\n");
|
2005-04-28 10:26:44 +02:00
|
|
|
|
|
|
|
|
|
cur = cn->connecting_data->cur;
|
|
|
|
|
|
2022-03-10 13:52:03 +01:00
|
|
|
|
for (cur = cn->connecting_data->cur; cur; cur = cur->ai_next) {
|
2005-04-28 10:26:44 +02:00
|
|
|
|
if ((cn->handle = socket(cur->ai_family, cur->ai_socktype,
|
2022-03-10 13:52:03 +01:00
|
|
|
|
cur->ai_protocol))
|
|
|
|
|
< 0) {
|
2005-04-28 10:26:44 +02:00
|
|
|
|
mylog(LOG_WARN, "socket() : %s", strerror(errno));
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
|
2012-01-07 11:41:02 +01:00
|
|
|
|
if (cn->handle >= FD_SETSIZE) {
|
|
|
|
|
mylog(LOG_WARN, "too many fd used, close socket %d",
|
2022-03-10 13:52:03 +01:00
|
|
|
|
cn->handle);
|
2012-01-07 11:41:02 +01:00
|
|
|
|
|
|
|
|
|
if (close(cn->handle) == -1)
|
|
|
|
|
mylog(LOG_WARN, "Error on socket close: %s",
|
2022-03-10 13:52:03 +01:00
|
|
|
|
strerror(errno));
|
2012-01-07 11:41:02 +01:00
|
|
|
|
|
|
|
|
|
cn->handle = -1;
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
2005-04-28 10:26:44 +02:00
|
|
|
|
socket_set_nonblock(cn->handle);
|
|
|
|
|
|
|
|
|
|
if (cn->connecting_data->src) {
|
|
|
|
|
/* local bind */
|
|
|
|
|
err = bind(cn->handle,
|
2022-03-10 13:52:03 +01:00
|
|
|
|
cn->connecting_data->src->ai_addr,
|
|
|
|
|
cn->connecting_data->src->ai_addrlen);
|
2005-04-28 10:26:44 +02:00
|
|
|
|
if (err == -1)
|
|
|
|
|
mylog(LOG_WARN, "bind() before connect: %s",
|
2022-03-10 13:52:03 +01:00
|
|
|
|
strerror(errno));
|
2005-04-28 10:26:44 +02:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
err = connect(cn->handle, cur->ai_addr, cur->ai_addrlen);
|
|
|
|
|
if (err == -1 && errno == EINPROGRESS) {
|
|
|
|
|
/* ok for now, see later */
|
|
|
|
|
/* next time try the next in the list */
|
|
|
|
|
cn->connecting_data->cur = cur->ai_next;
|
|
|
|
|
cn->connect_time = time(NULL);
|
|
|
|
|
cn->connected = CONN_INPROGRESS;
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (!err) {
|
|
|
|
|
/* connect() successful */
|
|
|
|
|
connecting_data_free(cn->connecting_data);
|
|
|
|
|
cn->connecting_data = NULL;
|
|
|
|
|
cn->connected = cn->ssl ? CONN_NEED_SSLIZE : CONN_OK;
|
2007-12-21 12:45:49 +01:00
|
|
|
|
connection_connected(cn);
|
2005-04-28 10:26:44 +02:00
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* connect() failed */
|
|
|
|
|
char ip[256];
|
|
|
|
|
mylog(LOG_WARN, "connect(%s) : %s",
|
2022-03-10 13:52:03 +01:00
|
|
|
|
inet_ntop(cur->ai_family, cur->ai_addr, ip, 256),
|
|
|
|
|
strerror(errno));
|
2005-04-28 10:26:44 +02:00
|
|
|
|
close(cn->handle);
|
|
|
|
|
cn->handle = -1;
|
|
|
|
|
}
|
2005-11-16 19:34:25 +01:00
|
|
|
|
|
2005-04-28 10:26:44 +02:00
|
|
|
|
cn->connected = CONN_ERROR;
|
|
|
|
|
connecting_data_free(cn->connecting_data);
|
|
|
|
|
cn->connecting_data = NULL;
|
|
|
|
|
mylog(LOG_ERROR, "connect() failed.");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#ifdef HAVE_LIBSSL
|
|
|
|
|
static X509 *mySSL_get_cert(SSL *ssl)
|
|
|
|
|
{
|
|
|
|
|
X509 *cert;
|
2005-11-16 19:34:25 +01:00
|
|
|
|
|
2005-04-28 10:26:44 +02:00
|
|
|
|
if (!ssl) {
|
2007-09-26 21:22:44 +02:00
|
|
|
|
mylog(LOG_ERROR, "mySSL_get_cert() No SSL context");
|
2005-04-28 10:26:44 +02:00
|
|
|
|
return NULL;
|
|
|
|
|
}
|
|
|
|
|
cert = SSL_get_peer_certificate(ssl);
|
|
|
|
|
if (cert == NULL)
|
2022-03-10 13:52:03 +01:00
|
|
|
|
mylog(LOG_WARN,
|
|
|
|
|
"mySSL_get_cert() SSL server supplied no "
|
|
|
|
|
"certificate !");
|
2005-04-28 10:26:44 +02:00
|
|
|
|
return cert;
|
|
|
|
|
}
|
|
|
|
|
|
2022-03-10 13:52:03 +01:00
|
|
|
|
static int _write_socket_SSL(connection_t *cn, char *message)
|
2005-04-28 10:26:44 +02:00
|
|
|
|
{
|
2022-01-09 20:59:59 +01:00
|
|
|
|
int count;
|
|
|
|
|
size_t size;
|
2005-09-02 14:50:59 +02:00
|
|
|
|
|
2022-03-10 13:52:03 +01:00
|
|
|
|
size = sizeof(char) * strlen(message);
|
2005-04-28 10:26:44 +02:00
|
|
|
|
|
2022-01-09 20:24:40 +01:00
|
|
|
|
// let's not ERR (SSL_write doesn't allow 0 len writes)
|
|
|
|
|
if (size == 0)
|
|
|
|
|
return WRITE_OK;
|
|
|
|
|
|
|
|
|
|
// this will fail anyways
|
|
|
|
|
if (size > INT_MAX) {
|
|
|
|
|
mylog(LOG_ERROR, "Message too long in SSL write_socket");
|
|
|
|
|
return WRITE_ERROR;
|
|
|
|
|
}
|
|
|
|
|
|
2005-04-28 10:26:44 +02:00
|
|
|
|
if (!cn->client && cn->cert == NULL) {
|
|
|
|
|
cn->cert = mySSL_get_cert(cn->ssl_h);
|
|
|
|
|
if (cn->cert == NULL) {
|
2007-09-26 21:22:44 +02:00
|
|
|
|
mylog(LOG_ERROR, "No certificate in SSL write_socket");
|
2005-04-28 10:26:44 +02:00
|
|
|
|
return WRITE_ERROR;
|
|
|
|
|
}
|
|
|
|
|
}
|
2022-01-09 20:24:40 +01:00
|
|
|
|
count = SSL_write(cn->ssl_h, (const void *)message, (int)size);
|
2005-04-28 10:26:44 +02:00
|
|
|
|
ERR_print_errors(errbio);
|
|
|
|
|
if (count <= 0) {
|
|
|
|
|
int err = SSL_get_error(cn->ssl_h, count);
|
2006-07-02 14:44:22 +02:00
|
|
|
|
if (err == SSL_ERROR_WANT_READ || err == SSL_ERROR_WANT_WRITE
|
2022-03-10 13:52:03 +01:00
|
|
|
|
|| err == SSL_ERROR_WANT_CONNECT
|
|
|
|
|
|| err == SSL_ERROR_WANT_ACCEPT)
|
2005-04-28 10:26:44 +02:00
|
|
|
|
return WRITE_KEEP;
|
|
|
|
|
if (cn_is_connected(cn)) {
|
2022-03-10 13:52:03 +01:00
|
|
|
|
mylog(LOG_ERROR, "fd %d: Connection error", cn->handle);
|
2005-04-28 10:26:44 +02:00
|
|
|
|
cn->connected = CONN_ERROR;
|
|
|
|
|
}
|
|
|
|
|
return WRITE_ERROR;
|
|
|
|
|
}
|
2022-01-09 20:24:40 +01:00
|
|
|
|
if (count != (int)size) {
|
2005-04-28 10:26:44 +02:00
|
|
|
|
/* abnormal : openssl keeps writing until message is not fully
|
|
|
|
|
* sent */
|
2022-03-10 13:52:03 +01:00
|
|
|
|
mylog(LOG_ERROR,
|
|
|
|
|
"SSL_write wrote only %d while message length is %d",
|
|
|
|
|
count, size);
|
2005-04-28 10:26:44 +02:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
mylog(LOG_DEBUGVERB, "%d/%d bytes sent", count, size);
|
|
|
|
|
return WRITE_OK;
|
|
|
|
|
}
|
2016-06-29 19:40:32 +02:00
|
|
|
|
|
|
|
|
|
#if OPENSSL_VERSION_NUMBER < 0x10100000L
|
|
|
|
|
#define X509_OBJECT_get0_X509(o) ((o)->data.x509)
|
2022-03-10 13:52:03 +01:00
|
|
|
|
#define X509_STORE_CTX_get_by_subject(vs, type, name, ret) \
|
|
|
|
|
X509_STORE_get_by_subject(vs, type, name, ret)
|
2016-06-29 19:40:32 +02:00
|
|
|
|
|
|
|
|
|
int DH_set0_pqg(DH *dh, BIGNUM *p, BIGNUM *q, BIGNUM *g)
|
|
|
|
|
{
|
|
|
|
|
// bip doesn't use q parameter
|
|
|
|
|
assert(q == NULL);
|
|
|
|
|
dh->p = p;
|
|
|
|
|
dh->g = g;
|
|
|
|
|
|
|
|
|
|
return 1;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
X509_OBJECT *X509_OBJECT_new()
|
|
|
|
|
{
|
|
|
|
|
X509_OBJECT *ret = OPENSSL_malloc(sizeof(*ret));
|
|
|
|
|
|
|
|
|
|
if (ret != NULL) {
|
|
|
|
|
memset(ret, 0, sizeof(*ret));
|
|
|
|
|
ret->type = X509_LU_FAIL;
|
2016-11-12 00:58:18 +01:00
|
|
|
|
} else {
|
|
|
|
|
X509err(X509_F_X509_VERIFY_CERT, ERR_R_MALLOC_FAILURE);
|
2016-06-29 19:40:32 +02:00
|
|
|
|
}
|
|
|
|
|
return ret;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void X509_OBJECT_free(X509_OBJECT *a)
|
|
|
|
|
{
|
|
|
|
|
if (a == NULL)
|
|
|
|
|
return;
|
|
|
|
|
switch (a->type) {
|
|
|
|
|
default:
|
|
|
|
|
break;
|
|
|
|
|
case X509_LU_X509:
|
|
|
|
|
X509_free(a->data.x509);
|
|
|
|
|
break;
|
|
|
|
|
case X509_LU_CRL:
|
|
|
|
|
X509_CRL_free(a->data.crl);
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
OPENSSL_free(a);
|
|
|
|
|
}
|
|
|
|
|
#endif
|
2005-04-28 10:26:44 +02:00
|
|
|
|
#endif
|
|
|
|
|
|
2005-05-23 08:27:26 +02:00
|
|
|
|
static int _write_socket(connection_t *cn, char *message)
|
2005-04-28 10:26:44 +02:00
|
|
|
|
{
|
|
|
|
|
size_t size;
|
|
|
|
|
size_t tcount = 0;
|
|
|
|
|
ssize_t count;
|
|
|
|
|
|
2005-05-21 15:44:09 +02:00
|
|
|
|
size = strlen(message);
|
2009-08-19 22:02:56 +02:00
|
|
|
|
if (size == 0)
|
|
|
|
|
return WRITE_OK;
|
|
|
|
|
/* loop if we wrote some data but not everything, or if error is
|
|
|
|
|
* EINTR */
|
2005-05-23 08:27:26 +02:00
|
|
|
|
do {
|
2009-08-19 02:09:16 +02:00
|
|
|
|
count = write(cn->handle, ((const char *)message) + tcount,
|
2022-03-10 13:52:03 +01:00
|
|
|
|
size - tcount);
|
2009-08-19 02:09:16 +02:00
|
|
|
|
if (count > 0) {
|
2022-01-09 20:59:59 +01:00
|
|
|
|
tcount += (size_t)count;
|
2005-05-23 08:27:26 +02:00
|
|
|
|
if (tcount == size)
|
2009-08-19 22:02:56 +02:00
|
|
|
|
return WRITE_OK;
|
2005-05-23 08:27:26 +02:00
|
|
|
|
}
|
2009-08-19 22:02:56 +02:00
|
|
|
|
} while (count > 0 || (count < 0 && errno == EINTR));
|
|
|
|
|
|
|
|
|
|
/* If we reach this point, we have a partial write */
|
|
|
|
|
assert(count != 0);
|
|
|
|
|
|
|
|
|
|
/* if no fatal error, return WRITE_KEEP, which makes caller keep line
|
|
|
|
|
* in its FIFO
|
|
|
|
|
*
|
|
|
|
|
* Shitty: we might have written a partial line, so we hack the line...
|
|
|
|
|
* Callers of _write_socket muse provide a writable message
|
|
|
|
|
*/
|
2022-01-09 21:20:49 +01:00
|
|
|
|
// this might be the same
|
|
|
|
|
#if EWOULDBLOCK == EAGAIN
|
|
|
|
|
if (errno == EAGAIN || errno == EINPROGRESS) {
|
|
|
|
|
#else
|
2009-08-19 22:02:56 +02:00
|
|
|
|
if (errno == EAGAIN || errno == EWOULDBLOCK || errno == EINPROGRESS) {
|
2022-01-09 21:20:49 +01:00
|
|
|
|
#endif
|
2009-08-19 22:02:56 +02:00
|
|
|
|
memmove(message, message + tcount, size - tcount + 1);
|
|
|
|
|
return WRITE_KEEP;
|
2005-04-28 10:26:44 +02:00
|
|
|
|
}
|
2009-08-19 22:02:56 +02:00
|
|
|
|
/* other errors, EPIPE or worse, close the connection, repport error */
|
|
|
|
|
if (cn_is_connected(cn)) {
|
|
|
|
|
if (errno != EPIPE)
|
|
|
|
|
mylog(LOG_INFO, "Broken socket: %s.", strerror(errno));
|
|
|
|
|
connection_close(cn);
|
|
|
|
|
cn->connected = CONN_ERROR;
|
|
|
|
|
}
|
|
|
|
|
mylog(LOG_DEBUGVERB, "write: %d, %s", cn->handle, strerror(errno));
|
|
|
|
|
return WRITE_ERROR;
|
2005-04-28 10:26:44 +02:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static int write_socket(connection_t *cn, char *line)
|
|
|
|
|
{
|
|
|
|
|
#ifdef HAVE_LIBSSL
|
|
|
|
|
if (cn->ssl)
|
|
|
|
|
return _write_socket_SSL(cn, line);
|
|
|
|
|
else
|
|
|
|
|
#endif
|
|
|
|
|
return _write_socket(cn, line);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* returns 1 if connection must be notified */
|
|
|
|
|
static int real_write_all(connection_t *cn)
|
|
|
|
|
{
|
|
|
|
|
int ret;
|
|
|
|
|
char *line;
|
|
|
|
|
|
|
|
|
|
if (cn == NULL)
|
|
|
|
|
fatal("real_write_all: wrong arguments");
|
2005-09-16 00:23:26 +02:00
|
|
|
|
|
2009-08-19 02:09:16 +02:00
|
|
|
|
if (cn->partial) {
|
|
|
|
|
line = cn->partial;
|
|
|
|
|
cn->partial = NULL;
|
|
|
|
|
} else {
|
|
|
|
|
line = list_remove_first(cn->outgoing);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
do {
|
2010-02-17 13:32:22 +01:00
|
|
|
|
ret = write_socket(cn, line);
|
2010-02-17 13:32:15 +01:00
|
|
|
|
|
2005-04-28 10:26:44 +02:00
|
|
|
|
switch (ret) {
|
|
|
|
|
case WRITE_ERROR:
|
2008-06-01 11:05:22 +02:00
|
|
|
|
/* we might as well free(line) here */
|
|
|
|
|
list_add_first(cn->outgoing, line);
|
2005-04-28 10:26:44 +02:00
|
|
|
|
return 1;
|
|
|
|
|
case WRITE_KEEP:
|
|
|
|
|
/* interrupted or not ready */
|
2009-08-19 02:09:16 +02:00
|
|
|
|
assert(cn->partial == NULL);
|
|
|
|
|
cn->partial = line;
|
2005-04-28 10:26:44 +02:00
|
|
|
|
return 0;
|
|
|
|
|
case WRITE_OK:
|
|
|
|
|
free(line);
|
|
|
|
|
break;
|
|
|
|
|
default:
|
|
|
|
|
fatal("internal error 6");
|
|
|
|
|
break;
|
|
|
|
|
}
|
2010-02-17 13:32:22 +01:00
|
|
|
|
|
|
|
|
|
if (cn->anti_flood)
|
|
|
|
|
/* one line at a time */
|
|
|
|
|
break;
|
2010-02-17 13:32:15 +01:00
|
|
|
|
} while ((line = list_remove_first(cn->outgoing)));
|
2005-09-16 00:23:26 +02:00
|
|
|
|
return 0;
|
2005-04-28 10:26:44 +02:00
|
|
|
|
}
|
|
|
|
|
|
2013-07-08 12:18:03 +02:00
|
|
|
|
/*
|
|
|
|
|
* May only be used when writing to the client or when sending
|
|
|
|
|
* timing-sensitive data to the server (PONG, PING for lagtest, QUIT)
|
|
|
|
|
* because fakelag is not enforced.
|
|
|
|
|
*/
|
2005-04-28 10:26:44 +02:00
|
|
|
|
void write_line_fast(connection_t *cn, char *line)
|
|
|
|
|
{
|
|
|
|
|
int r;
|
2009-08-19 02:09:16 +02:00
|
|
|
|
char *nline = bip_strdup(line);
|
|
|
|
|
|
|
|
|
|
if (cn->partial) {
|
|
|
|
|
list_add_first(cn->outgoing, nline);
|
|
|
|
|
} else {
|
|
|
|
|
r = write_socket(cn, nline);
|
|
|
|
|
switch (r) {
|
|
|
|
|
case WRITE_KEEP:
|
2009-08-19 22:02:56 +02:00
|
|
|
|
cn->partial = nline;
|
2009-08-19 02:09:16 +02:00
|
|
|
|
break;
|
|
|
|
|
case WRITE_ERROR:
|
|
|
|
|
case WRITE_OK:
|
|
|
|
|
free(nline);
|
|
|
|
|
break;
|
|
|
|
|
default:
|
|
|
|
|
fatal("internal error 7");
|
|
|
|
|
break;
|
|
|
|
|
}
|
2005-04-28 10:26:44 +02:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2008-12-18 14:27:16 +01:00
|
|
|
|
void write_lines(connection_t *cn, list_t *lines)
|
|
|
|
|
{
|
|
|
|
|
list_append(cn->outgoing, lines);
|
2013-07-08 12:18:03 +02:00
|
|
|
|
if (cn_want_write(cn))
|
|
|
|
|
real_write_all(cn);
|
2008-12-18 14:27:16 +01:00
|
|
|
|
}
|
|
|
|
|
|
2005-04-28 10:26:44 +02:00
|
|
|
|
void write_line(connection_t *cn, char *line)
|
|
|
|
|
{
|
2008-12-15 19:19:27 +01:00
|
|
|
|
list_add_last(cn->outgoing, bip_strdup(line));
|
2013-07-08 12:18:03 +02:00
|
|
|
|
if (cn_want_write(cn))
|
|
|
|
|
real_write_all(cn);
|
2005-04-28 10:26:44 +02:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
list_t *read_lines(connection_t *cn, int *error)
|
|
|
|
|
{
|
|
|
|
|
list_t *ret = NULL;
|
|
|
|
|
|
|
|
|
|
switch (cn->connected) {
|
|
|
|
|
case CONN_TIMEOUT:
|
|
|
|
|
case CONN_ERROR:
|
|
|
|
|
case CONN_DISCONN:
|
|
|
|
|
case CONN_EXCEPT:
|
2005-08-25 10:17:10 +02:00
|
|
|
|
case CONN_UNTRUSTED:
|
2005-04-28 10:26:44 +02:00
|
|
|
|
*error = 1;
|
|
|
|
|
ret = NULL;
|
|
|
|
|
break;
|
|
|
|
|
case CONN_NEW:
|
|
|
|
|
case CONN_INPROGRESS:
|
|
|
|
|
case CONN_NEED_SSLIZE:
|
|
|
|
|
*error = 0;
|
|
|
|
|
ret = NULL;
|
|
|
|
|
break;
|
|
|
|
|
case CONN_OK:
|
|
|
|
|
*error = 0;
|
|
|
|
|
ret = cn->incoming_lines;
|
|
|
|
|
cn->incoming_lines = NULL;
|
|
|
|
|
break;
|
|
|
|
|
default:
|
|
|
|
|
fatal("internal error 8");
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
return ret;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#ifdef HAVE_LIBSSL
|
|
|
|
|
/* returns 1 if connection must be notified */
|
|
|
|
|
static int read_socket_SSL(connection_t *cn)
|
|
|
|
|
{
|
2022-01-09 20:24:40 +01:00
|
|
|
|
int count;
|
|
|
|
|
size_t max;
|
|
|
|
|
|
|
|
|
|
if (cn == NULL)
|
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
|
|
if (cn->incoming_end >= CONN_BUFFER_SIZE) {
|
|
|
|
|
mylog(LOG_ERROR, "read_socket_SSL: internal error");
|
|
|
|
|
return -1;
|
|
|
|
|
}
|
|
|
|
|
|
2022-03-10 13:52:03 +01:00
|
|
|
|
max = sizeof(char) * (CONN_BUFFER_SIZE - cn->incoming_end);
|
2022-01-09 20:24:40 +01:00
|
|
|
|
if (max > INT_MAX) {
|
|
|
|
|
mylog(LOG_ERROR, "read_socket_SSL: cannot read that much data");
|
|
|
|
|
return -1;
|
|
|
|
|
}
|
2005-04-28 10:26:44 +02:00
|
|
|
|
|
|
|
|
|
if (!cn->client && cn->cert == NULL) {
|
|
|
|
|
cn->cert = mySSL_get_cert(cn->ssl_h);
|
|
|
|
|
if (cn->cert == NULL) {
|
|
|
|
|
mylog(LOG_ERROR, "No certificate in SSL read_socket");
|
|
|
|
|
return -1;
|
|
|
|
|
}
|
|
|
|
|
}
|
2022-01-09 20:24:40 +01:00
|
|
|
|
count = SSL_read(cn->ssl_h, (void *)(cn->incoming + cn->incoming_end),
|
2022-03-10 13:52:03 +01:00
|
|
|
|
(int)max);
|
2005-04-28 10:26:44 +02:00
|
|
|
|
ERR_print_errors(errbio);
|
|
|
|
|
if (count < 0) {
|
|
|
|
|
int err = SSL_get_error(cn->ssl_h, count);
|
|
|
|
|
if (err == SSL_ERROR_WANT_READ || err == SSL_ERROR_WANT_WRITE
|
2022-03-10 13:52:03 +01:00
|
|
|
|
|| err == SSL_ERROR_WANT_CONNECT
|
|
|
|
|
|| err == SSL_ERROR_WANT_ACCEPT)
|
2005-04-28 10:26:44 +02:00
|
|
|
|
return 0;
|
|
|
|
|
if (cn_is_connected(cn)) {
|
2022-03-10 13:52:03 +01:00
|
|
|
|
mylog(LOG_ERROR, "fd %d: Connection error", cn->handle);
|
2005-04-28 10:26:44 +02:00
|
|
|
|
cn->connected = CONN_ERROR;
|
|
|
|
|
}
|
|
|
|
|
return 1;
|
|
|
|
|
} else if (count == 0) {
|
2022-03-10 13:52:03 +01:00
|
|
|
|
/* int err = SSL_get_error(cn->ssl_h,count);
|
|
|
|
|
if (err == SSL_ERROR_WANT_READ || err ==
|
|
|
|
|
SSL_ERROR_WANT_WRITE
|
|
|
|
|
|| err == SSL_ERROR_WANT_CONNECT
|
|
|
|
|
|| err == SSL_ERROR_WANT_ACCEPT)
|
|
|
|
|
return 0;*/
|
2005-04-28 10:26:44 +02:00
|
|
|
|
if (cn_is_connected(cn)) {
|
2022-03-10 13:52:03 +01:00
|
|
|
|
mylog(LOG_ERROR, "fd %d: Connection lost", cn->handle);
|
2007-07-20 16:45:33 +02:00
|
|
|
|
connection_close(cn);
|
2005-04-28 10:26:44 +02:00
|
|
|
|
}
|
|
|
|
|
return 1;
|
2022-01-09 20:24:40 +01:00
|
|
|
|
} else {
|
|
|
|
|
cn->incoming_end += (size_t)count;
|
|
|
|
|
return 0;
|
2005-04-28 10:26:44 +02:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
/* returns 1 if connection must be notified */
|
|
|
|
|
static int read_socket(connection_t *cn)
|
|
|
|
|
{
|
2022-01-09 20:24:40 +01:00
|
|
|
|
ssize_t count;
|
|
|
|
|
size_t max;
|
2007-02-08 23:53:48 +01:00
|
|
|
|
|
2005-04-28 10:26:44 +02:00
|
|
|
|
if (cn == NULL)
|
|
|
|
|
return 0;
|
2022-01-09 20:24:40 +01:00
|
|
|
|
|
|
|
|
|
if (cn->incoming_end >= CONN_BUFFER_SIZE) {
|
|
|
|
|
mylog(LOG_ERROR, "read_socket: internal error");
|
|
|
|
|
return -1;
|
|
|
|
|
}
|
|
|
|
|
|
2022-03-10 13:52:03 +01:00
|
|
|
|
max = sizeof(char) * (CONN_BUFFER_SIZE - cn->incoming_end);
|
|
|
|
|
count = read(cn->handle, cn->incoming + cn->incoming_end, max);
|
2005-04-28 10:26:44 +02:00
|
|
|
|
if (count < 0) {
|
|
|
|
|
if (errno == EAGAIN || errno == EINTR || errno == EINPROGRESS)
|
|
|
|
|
return 0;
|
|
|
|
|
if (cn_is_connected(cn)) {
|
2007-09-26 21:22:44 +02:00
|
|
|
|
mylog(LOG_ERROR, "read(fd=%d): Connection error: %s",
|
2022-03-10 13:52:03 +01:00
|
|
|
|
cn->handle, strerror(errno));
|
2005-04-28 10:26:44 +02:00
|
|
|
|
cn->connected = CONN_ERROR;
|
|
|
|
|
}
|
|
|
|
|
return 1;
|
|
|
|
|
} else if (count == 0) {
|
|
|
|
|
if (cn_is_connected(cn)) {
|
2007-09-26 21:22:44 +02:00
|
|
|
|
mylog(LOG_ERROR, "read(fd=%d): Connection lost: %s",
|
2022-03-10 13:52:03 +01:00
|
|
|
|
cn->handle, strerror(errno));
|
2007-07-20 16:45:33 +02:00
|
|
|
|
connection_close(cn);
|
2005-04-28 10:26:44 +02:00
|
|
|
|
}
|
|
|
|
|
return 1;
|
2022-01-09 20:24:40 +01:00
|
|
|
|
} else {
|
|
|
|
|
cn->incoming_end += (unsigned)count;
|
|
|
|
|
return 0;
|
2005-04-28 10:26:44 +02:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void data_find_lines(connection_t *cn)
|
|
|
|
|
{
|
|
|
|
|
size_t len = 0, lastlen = 0, ssz;
|
|
|
|
|
char *p = cn->incoming;
|
|
|
|
|
char *buf;
|
|
|
|
|
|
|
|
|
|
for (;;) {
|
|
|
|
|
while (len < cn->incoming_end && p[len] != '\n')
|
|
|
|
|
len++;
|
|
|
|
|
if (len >= cn->incoming_end || p[len] != '\n')
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
ssz = len - lastlen;
|
|
|
|
|
if (ssz >= 1) {
|
|
|
|
|
if (p[len - 1] == '\r')
|
|
|
|
|
ssz--;
|
2008-12-10 23:26:37 +01:00
|
|
|
|
buf = bip_malloc(ssz + 1);
|
2005-04-28 10:26:44 +02:00
|
|
|
|
memcpy(buf, p + lastlen, ssz);
|
|
|
|
|
buf[ssz] = 0;
|
|
|
|
|
|
|
|
|
|
list_add_last(cn->incoming_lines, buf);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
len++;
|
|
|
|
|
lastlen = len;
|
|
|
|
|
}
|
|
|
|
|
if (lastlen) {
|
|
|
|
|
unsigned i;
|
|
|
|
|
for (i = 0; i < cn->incoming_end - lastlen; i++)
|
|
|
|
|
p[i] = p[i + lastlen];
|
|
|
|
|
cn->incoming_end -= lastlen;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
int cn_is_new(connection_t *cn)
|
|
|
|
|
{
|
|
|
|
|
switch (cn->connected) {
|
|
|
|
|
case CONN_TIMEOUT:
|
|
|
|
|
case CONN_ERROR:
|
|
|
|
|
case CONN_DISCONN:
|
|
|
|
|
case CONN_EXCEPT:
|
|
|
|
|
case CONN_NEED_SSLIZE:
|
|
|
|
|
case CONN_OK:
|
2005-08-25 10:17:10 +02:00
|
|
|
|
case CONN_UNTRUSTED:
|
2005-04-28 10:26:44 +02:00
|
|
|
|
return 0;
|
|
|
|
|
case CONN_NEW:
|
|
|
|
|
case CONN_INPROGRESS:
|
|
|
|
|
return 1;
|
|
|
|
|
default:
|
|
|
|
|
fatal("internal error 9");
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
int cn_is_in_error(connection_t *cn)
|
|
|
|
|
{
|
|
|
|
|
switch (cn->connected) {
|
|
|
|
|
case CONN_TIMEOUT:
|
|
|
|
|
case CONN_ERROR:
|
|
|
|
|
case CONN_DISCONN:
|
|
|
|
|
case CONN_EXCEPT:
|
2005-08-25 10:17:10 +02:00
|
|
|
|
case CONN_UNTRUSTED:
|
2005-04-28 10:26:44 +02:00
|
|
|
|
return 1;
|
|
|
|
|
case CONN_NEW:
|
|
|
|
|
case CONN_INPROGRESS:
|
|
|
|
|
case CONN_NEED_SSLIZE:
|
|
|
|
|
case CONN_OK:
|
|
|
|
|
return 0;
|
|
|
|
|
default:
|
|
|
|
|
fatal("internal error 10");
|
|
|
|
|
return 1;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2005-09-16 00:23:26 +02:00
|
|
|
|
int cn_is_connected(connection_t *cn)
|
2005-04-28 10:26:44 +02:00
|
|
|
|
{
|
|
|
|
|
if (cn == NULL)
|
|
|
|
|
fatal("cn_is_connected, wrong argument");
|
|
|
|
|
return (cn->connected == CONN_OK ? 1 : 0);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static int check_event_except(fd_set *fds, connection_t *cn)
|
|
|
|
|
{
|
|
|
|
|
if (!cn_is_connected(cn))
|
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
|
|
if (cn_is_in_error(cn)) {
|
2018-05-30 03:34:12 +02:00
|
|
|
|
mylog(LOG_ERROR, "Error on fd %d (except, state %d)",
|
2022-03-10 13:52:03 +01:00
|
|
|
|
cn->handle, cn->connected);
|
2005-04-28 10:26:44 +02:00
|
|
|
|
return 1;
|
|
|
|
|
}
|
2007-02-08 23:53:48 +01:00
|
|
|
|
|
2005-04-28 10:26:44 +02:00
|
|
|
|
if (!FD_ISSET(cn->handle, fds))
|
|
|
|
|
return 0;
|
2007-02-08 23:53:48 +01:00
|
|
|
|
|
2022-03-10 13:52:03 +01:00
|
|
|
|
mylog(LOG_DEBUGTOOMUCH, "fd %d is in exceptions list", cn->handle);
|
2005-04-28 10:26:44 +02:00
|
|
|
|
cn->connected = CONN_EXCEPT;
|
|
|
|
|
return 1;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static int check_event_read(fd_set *fds, connection_t *cn)
|
|
|
|
|
{
|
|
|
|
|
int ret;
|
|
|
|
|
|
|
|
|
|
if (cn_is_in_error(cn)) {
|
2022-03-10 13:52:03 +01:00
|
|
|
|
mylog(LOG_ERROR, "Error on fd %d (read, state %d)", cn->handle,
|
|
|
|
|
cn->connected);
|
2005-04-28 10:26:44 +02:00
|
|
|
|
return 1;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (!FD_ISSET(cn->handle, fds))
|
|
|
|
|
return 0;
|
|
|
|
|
|
2007-09-26 21:22:44 +02:00
|
|
|
|
mylog(LOG_DEBUGTOOMUCH, "Read positive on fd %d (state %d)", cn->handle,
|
2022-03-10 13:52:03 +01:00
|
|
|
|
cn->connected);
|
2005-04-28 10:26:44 +02:00
|
|
|
|
|
|
|
|
|
/* notify caller to make it check for a new client */
|
|
|
|
|
if (cn->listening)
|
|
|
|
|
return 1;
|
|
|
|
|
|
|
|
|
|
#ifdef HAVE_LIBSSL
|
|
|
|
|
if (cn->ssl)
|
|
|
|
|
ret = read_socket_SSL(cn);
|
|
|
|
|
else
|
|
|
|
|
#endif
|
|
|
|
|
ret = read_socket(cn);
|
2007-02-08 23:53:48 +01:00
|
|
|
|
|
2005-04-28 10:26:44 +02:00
|
|
|
|
if (ret) {
|
2022-03-10 13:52:03 +01:00
|
|
|
|
mylog(LOG_ERROR, "Error while reading on fd %d", cn->handle);
|
2007-12-21 12:20:21 +01:00
|
|
|
|
return 1;
|
|
|
|
|
}
|
2006-06-08 20:55:26 +02:00
|
|
|
|
|
2005-04-28 10:26:44 +02:00
|
|
|
|
if (!cn->incoming_lines)
|
|
|
|
|
cn->incoming_lines = list_new(NULL);
|
|
|
|
|
data_find_lines(cn);
|
|
|
|
|
if (list_is_empty(cn->incoming_lines))
|
|
|
|
|
return 0;
|
2006-06-08 20:55:26 +02:00
|
|
|
|
|
2007-09-26 21:22:44 +02:00
|
|
|
|
mylog(LOG_DEBUGTOOMUCH, "newlines on fd %d (state %d)", cn->handle,
|
2022-03-10 13:52:03 +01:00
|
|
|
|
cn->connected);
|
2005-04-28 10:26:44 +02:00
|
|
|
|
return 1;
|
|
|
|
|
}
|
|
|
|
|
|
2007-12-21 12:20:21 +01:00
|
|
|
|
static void connection_connected(connection_t *c)
|
|
|
|
|
{
|
2007-12-21 12:21:23 +01:00
|
|
|
|
if (c->localip)
|
|
|
|
|
free(c->localip);
|
2007-12-21 12:20:21 +01:00
|
|
|
|
c->localip = connection_localip(c);
|
|
|
|
|
c->localport = connection_localport(c);
|
2007-12-21 12:21:23 +01:00
|
|
|
|
if (c->remoteip)
|
|
|
|
|
free(c->remoteip);
|
2007-12-21 12:45:49 +01:00
|
|
|
|
c->remoteip = connection_remoteip(c);
|
2007-12-21 12:20:21 +01:00
|
|
|
|
c->remoteport = connection_remoteport(c);
|
|
|
|
|
}
|
|
|
|
|
|
2005-05-12 10:29:27 +02:00
|
|
|
|
static int check_event_write(fd_set *fds, connection_t *cn, int *nc)
|
2005-04-28 10:26:44 +02:00
|
|
|
|
{
|
|
|
|
|
if (cn_is_in_error(cn)) {
|
2022-03-10 13:52:03 +01:00
|
|
|
|
mylog(LOG_ERROR, "Error on fd %d (write, state %d)", cn->handle,
|
|
|
|
|
cn->connected);
|
2005-04-28 10:26:44 +02:00
|
|
|
|
return 1;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (!FD_ISSET(cn->handle, fds)) {
|
2010-02-17 13:32:15 +01:00
|
|
|
|
if (cn_is_connected(cn))
|
2005-04-28 10:26:44 +02:00
|
|
|
|
return 0;
|
2005-09-16 00:23:26 +02:00
|
|
|
|
|
2007-09-26 21:22:44 +02:00
|
|
|
|
mylog(LOG_DEBUG, "New socket still not connected (%d)",
|
2022-03-10 13:52:03 +01:00
|
|
|
|
cn->handle);
|
2005-04-28 10:26:44 +02:00
|
|
|
|
/* check timeout (handles connect_trynext) */
|
|
|
|
|
return connection_timedout(cn);
|
|
|
|
|
}
|
|
|
|
|
|
2007-09-26 21:22:44 +02:00
|
|
|
|
mylog(LOG_DEBUGTOOMUCH, "Write positive on fd %d (state %d)",
|
2022-03-10 13:52:03 +01:00
|
|
|
|
cn->handle, cn->connected);
|
2005-09-16 00:23:26 +02:00
|
|
|
|
|
2005-04-28 10:26:44 +02:00
|
|
|
|
if (cn_is_new(cn)) {
|
|
|
|
|
int err, err2;
|
|
|
|
|
socklen_t errSize = sizeof(err);
|
|
|
|
|
|
2005-05-12 10:29:27 +02:00
|
|
|
|
err2 = getsockopt(cn->handle, SOL_SOCKET, SO_ERROR,
|
2022-03-10 13:52:03 +01:00
|
|
|
|
(void *)&err, &errSize);
|
2005-09-16 00:23:26 +02:00
|
|
|
|
|
2005-04-28 10:26:44 +02:00
|
|
|
|
if (err2 < 0) {
|
2007-09-26 21:22:44 +02:00
|
|
|
|
mylog(LOG_ERROR, "fd:%d getsockopt error: %s",
|
2022-03-10 13:52:03 +01:00
|
|
|
|
cn->handle, strerror(errno));
|
2007-02-10 15:05:37 +01:00
|
|
|
|
if (cn->connecting_data) {
|
|
|
|
|
close(cn->handle);
|
|
|
|
|
cn->handle = -1;
|
2005-05-02 00:29:31 +02:00
|
|
|
|
connect_trynext(cn);
|
2007-02-10 15:05:37 +01:00
|
|
|
|
}
|
2022-03-10 13:52:03 +01:00
|
|
|
|
return (cn_is_new(cn)
|
|
|
|
|
|| cn->connected == CONN_NEED_SSLIZE)
|
|
|
|
|
? 0
|
|
|
|
|
: 1;
|
2005-09-16 00:23:26 +02:00
|
|
|
|
|
2005-04-28 10:26:44 +02:00
|
|
|
|
} else if (err == EINPROGRESS || err == EALREADY) {
|
2005-05-12 10:29:27 +02:00
|
|
|
|
mylog(LOG_DEBUG, "fd:%d Connection in progress...",
|
2022-03-10 13:52:03 +01:00
|
|
|
|
cn->handle);
|
2005-04-28 10:26:44 +02:00
|
|
|
|
return connection_timedout(cn);
|
|
|
|
|
} else if (err == EISCONN || err == 0) {
|
|
|
|
|
#ifdef HAVE_LIBSSL
|
|
|
|
|
if (cn->ssl) {
|
|
|
|
|
cn->connected = CONN_NEED_SSLIZE;
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
#endif
|
|
|
|
|
cn->connected = CONN_OK;
|
2007-12-21 12:20:21 +01:00
|
|
|
|
connection_connected(cn);
|
2005-05-12 10:29:27 +02:00
|
|
|
|
*nc = 1;
|
|
|
|
|
mylog(LOG_DEBUG, "fd:%d Connection established !",
|
2022-03-10 13:52:03 +01:00
|
|
|
|
cn->handle);
|
2005-04-28 10:26:44 +02:00
|
|
|
|
return 1;
|
|
|
|
|
} else {
|
|
|
|
|
mylog(LOG_WARN, "fd:%d Socket error: %s", cn->handle,
|
2022-03-10 13:52:03 +01:00
|
|
|
|
strerror(err));
|
2007-02-10 15:05:37 +01:00
|
|
|
|
if (cn->connecting_data) {
|
|
|
|
|
close(cn->handle);
|
|
|
|
|
cn->handle = -1;
|
2005-05-02 00:29:31 +02:00
|
|
|
|
connect_trynext(cn);
|
2007-02-10 15:05:37 +01:00
|
|
|
|
}
|
2022-03-10 13:52:03 +01:00
|
|
|
|
return (cn_is_new(cn)
|
|
|
|
|
|| cn->connected == CONN_NEED_SSLIZE)
|
|
|
|
|
? 0
|
|
|
|
|
: 1;
|
2005-04-28 10:26:44 +02:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#ifdef HAVE_LIBSSL
|
|
|
|
|
if (cn->connected == CONN_NEED_SSLIZE) {
|
2005-05-12 10:29:27 +02:00
|
|
|
|
if (SSLize(cn, nc))
|
2005-04-28 10:26:44 +02:00
|
|
|
|
return connection_timedout(cn);
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
if (cn_is_connected(cn) && !list_is_empty(cn->outgoing))
|
|
|
|
|
real_write_all(cn);
|
|
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* starts empty */
|
|
|
|
|
/* capacity: 4 token */
|
|
|
|
|
#define TOKEN_MAX 4
|
|
|
|
|
/* token generation interval: 1200ms */
|
|
|
|
|
#define TOKEN_INTERVAL 1200
|
|
|
|
|
|
2013-07-08 12:18:03 +02:00
|
|
|
|
static int cn_want_write(connection_t *cn)
|
2005-04-28 10:26:44 +02:00
|
|
|
|
{
|
2010-02-17 13:32:22 +01:00
|
|
|
|
if (cn->anti_flood) {
|
2015-07-10 11:49:30 +02:00
|
|
|
|
struct timespec tv;
|
2010-02-17 13:32:22 +01:00
|
|
|
|
unsigned long now;
|
|
|
|
|
|
|
|
|
|
/* fill the bucket */
|
|
|
|
|
/* we do not control when we are called */
|
|
|
|
|
/* now is the number of milliseconds since the Epoch,
|
|
|
|
|
* cn->lasttoken is the number of milliseconds when we
|
|
|
|
|
* last added a token to the bucket */
|
2015-07-10 11:49:30 +02:00
|
|
|
|
if (!clock_gettime(CLOCK_MONOTONIC, &tv)) {
|
2022-01-09 20:59:59 +01:00
|
|
|
|
if (tv.tv_sec < 0 || tv.tv_nsec < 0)
|
|
|
|
|
fatal("clock_gettime returned negative time");
|
2022-03-10 13:52:03 +01:00
|
|
|
|
now = (unsigned long)(tv.tv_sec * 1000
|
|
|
|
|
+ tv.tv_nsec / 1000000);
|
2010-02-17 13:32:22 +01:00
|
|
|
|
/* round now to TOKEN_INTERVAL multiple */
|
|
|
|
|
now -= now % TOKEN_INTERVAL;
|
|
|
|
|
if (now < cn->lasttoken) {
|
|
|
|
|
/* time shift or integer overflow */
|
2010-02-15 15:06:50 +01:00
|
|
|
|
cn->token = 1;
|
2010-02-17 13:32:22 +01:00
|
|
|
|
cn->lasttoken = now;
|
|
|
|
|
} else if (now > cn->lasttoken + TOKEN_INTERVAL) {
|
2022-03-10 13:52:03 +01:00
|
|
|
|
cn->token += (unsigned)((now - cn->lasttoken)
|
|
|
|
|
/ TOKEN_INTERVAL);
|
2010-02-17 13:32:22 +01:00
|
|
|
|
if (cn->token > TOKEN_MAX)
|
|
|
|
|
cn->token = TOKEN_MAX;
|
|
|
|
|
if (!cn->token)
|
|
|
|
|
cn->token = 1;
|
|
|
|
|
cn->lasttoken = now;
|
|
|
|
|
}
|
|
|
|
|
} else
|
2015-07-10 11:49:30 +02:00
|
|
|
|
/* if clock_gettime() fails, juste ignore
|
2010-02-17 13:32:22 +01:00
|
|
|
|
* antiflood */
|
|
|
|
|
cn->token = 1;
|
2010-02-15 15:06:50 +01:00
|
|
|
|
|
2010-02-17 13:32:22 +01:00
|
|
|
|
/* use a token if needed and available */
|
|
|
|
|
if (!list_is_empty(cn->outgoing) && cn->token > 0) {
|
|
|
|
|
cn->token--;
|
|
|
|
|
return 1;
|
|
|
|
|
}
|
|
|
|
|
return 0;
|
2010-02-17 13:32:15 +01:00
|
|
|
|
}
|
2010-02-17 13:32:22 +01:00
|
|
|
|
return !list_is_empty(cn->outgoing);
|
2005-04-28 10:26:44 +02:00
|
|
|
|
}
|
|
|
|
|
|
2015-07-10 11:49:30 +02:00
|
|
|
|
|
2022-01-09 20:59:59 +01:00
|
|
|
|
list_t *wait_event(list_t *cn_list, time_t *msec, int *nc)
|
2005-04-28 10:26:44 +02:00
|
|
|
|
{
|
|
|
|
|
fd_set fds_read, fds_write, fds_except;
|
2022-01-09 21:02:48 +01:00
|
|
|
|
int maxfd = -1, err;
|
2005-04-28 10:26:44 +02:00
|
|
|
|
list_t *cn_newdata;
|
|
|
|
|
list_iterator_t it;
|
|
|
|
|
struct timeval tv;
|
2015-07-10 11:49:30 +02:00
|
|
|
|
struct timespec btv, etv;
|
2005-05-12 10:29:27 +02:00
|
|
|
|
*nc = 0;
|
2005-04-28 10:26:44 +02:00
|
|
|
|
|
2007-12-14 22:06:20 +01:00
|
|
|
|
cn_newdata = list_new(list_ptr_cmp);
|
2005-04-28 10:26:44 +02:00
|
|
|
|
FD_ZERO(&fds_read);
|
|
|
|
|
FD_ZERO(&fds_write);
|
|
|
|
|
FD_ZERO(&fds_except);
|
|
|
|
|
for (list_it_init(cn_list, &it); list_it_item(&it); list_it_next(&it)) {
|
|
|
|
|
connection_t *cn = list_it_item(&it);
|
|
|
|
|
if (cn == NULL)
|
|
|
|
|
fatal("wait_event: wrong argument");
|
|
|
|
|
|
|
|
|
|
mylog(LOG_DEBUGTOOMUCH, "I've seen socket %d !", cn->handle);
|
|
|
|
|
if (cn->connected == CONN_DISCONN) {
|
2007-12-14 22:06:20 +01:00
|
|
|
|
list_add_first_uniq(cn_newdata, cn);
|
2005-04-28 10:26:44 +02:00
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* This shouldn't happen ! just in case...
|
|
|
|
|
*/
|
2012-01-07 11:41:02 +01:00
|
|
|
|
if (cn->handle < 0 || cn->handle >= FD_SETSIZE)
|
|
|
|
|
fatal("wait_event invalid socket %d", cn->handle);
|
2005-04-28 10:26:44 +02:00
|
|
|
|
|
|
|
|
|
/* exceptions are OOB and disconnections */
|
|
|
|
|
FD_SET(cn->handle, &fds_except);
|
|
|
|
|
maxfd = (cn->handle > maxfd ? cn->handle : maxfd);
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* if connected, we're looking for new incoming data
|
|
|
|
|
* if new or lines waiting to be sent, we want
|
|
|
|
|
* to know if it's ready or not.
|
|
|
|
|
*/
|
|
|
|
|
if (cn_is_connected(cn)) {
|
|
|
|
|
FD_SET(cn->handle, &fds_read);
|
2007-09-26 21:22:44 +02:00
|
|
|
|
mylog(LOG_DEBUGTOOMUCH, "Test read on fd %d %d:%d",
|
2022-03-10 13:52:03 +01:00
|
|
|
|
cn->handle, cn->connected, cn_is_connected(cn));
|
2005-04-28 10:26:44 +02:00
|
|
|
|
}
|
2005-09-16 00:23:26 +02:00
|
|
|
|
|
2005-04-28 10:26:44 +02:00
|
|
|
|
/* we NEVER want to check write on a listening socket */
|
|
|
|
|
if (cn->listening)
|
|
|
|
|
continue;
|
2005-09-16 00:23:26 +02:00
|
|
|
|
|
2010-02-17 13:32:22 +01:00
|
|
|
|
if (!cn_is_connected(cn) || cn_want_write(cn)) {
|
2010-02-17 13:32:15 +01:00
|
|
|
|
FD_SET(cn->handle, &fds_write);
|
|
|
|
|
mylog(LOG_DEBUGTOOMUCH, "Test write on fd %d %d:%d",
|
2022-03-10 13:52:03 +01:00
|
|
|
|
cn->handle, cn->connected, cn_is_connected(cn));
|
2005-04-28 10:26:44 +02:00
|
|
|
|
}
|
|
|
|
|
}
|
2005-09-16 00:23:26 +02:00
|
|
|
|
|
2005-04-28 10:26:44 +02:00
|
|
|
|
/* if no connection is active, return the list... empty... */
|
2005-05-27 17:00:11 +02:00
|
|
|
|
if (maxfd == -1) {
|
2009-01-17 15:03:06 +01:00
|
|
|
|
struct timespec req, rem;
|
|
|
|
|
req.tv_sec = *msec * 1000;
|
|
|
|
|
req.tv_nsec = 0;
|
|
|
|
|
nanosleep(&req, &rem);
|
|
|
|
|
*msec = rem.tv_sec;
|
2005-04-28 10:26:44 +02:00
|
|
|
|
return cn_newdata;
|
2005-05-27 17:00:11 +02:00
|
|
|
|
}
|
2005-04-28 10:26:44 +02:00
|
|
|
|
|
|
|
|
|
tv.tv_sec = *msec / 1000;
|
|
|
|
|
tv.tv_usec = (*msec % 1000) * 1000;
|
2007-09-26 21:22:44 +02:00
|
|
|
|
mylog(LOG_DEBUGTOOMUCH, "msec: %d, sec: %d, usec: %d", *msec, tv.tv_sec,
|
2022-03-10 13:52:03 +01:00
|
|
|
|
tv.tv_usec);
|
2015-07-10 11:49:30 +02:00
|
|
|
|
|
2022-01-09 21:02:48 +01:00
|
|
|
|
bip_clock_gettime(CLOCK_MONOTONIC, &btv);
|
2005-04-28 10:26:44 +02:00
|
|
|
|
err = select(maxfd + 1, &fds_read, &fds_write, &fds_except, &tv);
|
2015-07-10 11:49:30 +02:00
|
|
|
|
|
|
|
|
|
if (err == 0) {
|
|
|
|
|
/* select timed-out */
|
|
|
|
|
mylog(LOG_DEBUGTOOMUCH, "Select timed-out. irc.o timer !");
|
|
|
|
|
*msec = 0;
|
|
|
|
|
return cn_newdata;
|
|
|
|
|
} else {
|
|
|
|
|
mylog(LOG_DEBUGTOOMUCH, "msec: %d, sec: %d, usec: %d", *msec,
|
2022-03-10 13:52:03 +01:00
|
|
|
|
tv.tv_sec, tv.tv_usec);
|
2015-07-10 11:49:30 +02:00
|
|
|
|
}
|
|
|
|
|
|
2022-01-09 21:02:48 +01:00
|
|
|
|
bip_clock_gettime(CLOCK_MONOTONIC, &etv);
|
2005-04-28 10:26:44 +02:00
|
|
|
|
if (etv.tv_sec < btv.tv_sec)
|
|
|
|
|
mylog(LOG_ERROR, "Time rewinded ! not touching interval");
|
2015-07-10 11:49:30 +02:00
|
|
|
|
else {
|
2005-04-28 10:26:44 +02:00
|
|
|
|
*msec -= (etv.tv_sec - btv.tv_sec) * 1000
|
2022-03-10 13:52:03 +01:00
|
|
|
|
+ (etv.tv_nsec - btv.tv_nsec) / 1000000;
|
2015-07-10 11:49:30 +02:00
|
|
|
|
/* in case we go forward in time */
|
|
|
|
|
if (*msec < 0)
|
|
|
|
|
*msec = 0;
|
|
|
|
|
}
|
|
|
|
|
|
2005-04-28 10:26:44 +02:00
|
|
|
|
if (err < 0) {
|
|
|
|
|
if (errno == EINTR)
|
|
|
|
|
return cn_newdata;
|
|
|
|
|
fatal("select(): %s", strerror(errno));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
for (list_it_init(cn_list, &it); list_it_item(&it); list_it_next(&it)) {
|
|
|
|
|
connection_t *cn = list_it_item(&it);
|
2005-05-28 15:23:51 +02:00
|
|
|
|
int toadd = 0;
|
2005-04-28 10:26:44 +02:00
|
|
|
|
|
|
|
|
|
if (check_event_except(&fds_except, cn)) {
|
2007-09-26 21:22:44 +02:00
|
|
|
|
mylog(LOG_DEBUGTOOMUCH, "Notify on FD %d (state %d)",
|
2022-03-10 13:52:03 +01:00
|
|
|
|
cn->handle, cn->connected);
|
2007-12-14 22:06:20 +01:00
|
|
|
|
list_add_first_uniq(cn_newdata, cn);
|
2005-04-28 10:26:44 +02:00
|
|
|
|
continue;
|
2007-12-14 22:06:20 +01:00
|
|
|
|
}
|
2005-05-28 15:23:51 +02:00
|
|
|
|
if (check_event_write(&fds_write, cn, nc)) {
|
|
|
|
|
if (cn_is_in_error(cn))
|
|
|
|
|
toadd = 1;
|
|
|
|
|
}
|
2005-04-28 10:26:44 +02:00
|
|
|
|
|
|
|
|
|
if (check_event_read(&fds_read, cn)) {
|
2007-09-26 21:22:44 +02:00
|
|
|
|
mylog(LOG_DEBUGTOOMUCH, "Notify on FD %d (state %d)",
|
2022-03-10 13:52:03 +01:00
|
|
|
|
cn->handle, cn->connected);
|
2005-05-28 15:23:51 +02:00
|
|
|
|
toadd = 1;
|
2005-04-28 10:26:44 +02:00
|
|
|
|
}
|
2005-05-28 15:23:51 +02:00
|
|
|
|
if (toadd)
|
2007-12-14 22:06:20 +01:00
|
|
|
|
list_add_first_uniq(cn_newdata, cn);
|
2005-04-28 10:26:44 +02:00
|
|
|
|
}
|
|
|
|
|
return cn_newdata;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void create_socket(char *dsthostname, char *dstport, char *srchostname,
|
2022-03-10 13:52:03 +01:00
|
|
|
|
char *srcport, connection_t *cn)
|
2005-04-28 10:26:44 +02:00
|
|
|
|
{
|
|
|
|
|
int err;
|
|
|
|
|
struct connecting_data *cdata;
|
|
|
|
|
struct addrinfo hint;
|
2005-12-12 20:03:02 +01:00
|
|
|
|
|
2005-04-28 10:26:44 +02:00
|
|
|
|
memset(&hint, 0, sizeof(hint));
|
|
|
|
|
hint.ai_flags = AI_PASSIVE;
|
|
|
|
|
hint.ai_family = PF_UNSPEC;
|
|
|
|
|
hint.ai_socktype = SOCK_STREAM;
|
|
|
|
|
hint.ai_protocol = 0;
|
2005-12-12 20:03:02 +01:00
|
|
|
|
|
2005-04-28 10:26:44 +02:00
|
|
|
|
cn->connected = CONN_ERROR;
|
2022-03-10 13:52:03 +01:00
|
|
|
|
cdata = (struct connecting_data *)bip_malloc(
|
|
|
|
|
sizeof(struct connecting_data));
|
2005-04-28 10:26:44 +02:00
|
|
|
|
cdata->dst = cdata->src = cdata->cur = NULL;
|
|
|
|
|
|
|
|
|
|
err = getaddrinfo(dsthostname, dstport, &hint, &cdata->dst);
|
|
|
|
|
if (err) {
|
2007-10-20 21:26:21 +02:00
|
|
|
|
mylog(LOG_ERROR, "getaddrinfo(%s): %s", dsthostname,
|
2022-03-10 13:52:03 +01:00
|
|
|
|
gai_strerror(err));
|
2005-04-28 10:26:44 +02:00
|
|
|
|
connecting_data_free(cdata);
|
|
|
|
|
cdata = NULL;
|
|
|
|
|
return;
|
2007-09-04 00:24:50 +02:00
|
|
|
|
}
|
2005-04-28 10:26:44 +02:00
|
|
|
|
|
|
|
|
|
if (srchostname || srcport) {
|
|
|
|
|
if ((err = getaddrinfo(srchostname, srcport, &hint,
|
2022-03-10 13:52:03 +01:00
|
|
|
|
&cdata->src))) {
|
2005-04-28 10:26:44 +02:00
|
|
|
|
/* not fatal ? maybe a config option is needed */
|
2007-09-26 21:22:44 +02:00
|
|
|
|
mylog(LOG_ERROR, "getaddrinfo(src): %s",
|
2022-03-10 13:52:03 +01:00
|
|
|
|
gai_strerror(err));
|
2005-04-28 10:26:44 +02:00
|
|
|
|
cdata->src = NULL;
|
|
|
|
|
}
|
|
|
|
|
}
|
2005-12-12 20:03:02 +01:00
|
|
|
|
|
2005-04-28 10:26:44 +02:00
|
|
|
|
cdata->cur = cdata->dst;
|
|
|
|
|
cn->connecting_data = cdata;
|
|
|
|
|
|
|
|
|
|
connect_trynext(cn);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
static void create_listening_socket(char *hostname, char *port,
|
2022-03-10 13:52:03 +01:00
|
|
|
|
connection_t *cn)
|
2005-04-28 10:26:44 +02:00
|
|
|
|
{
|
|
|
|
|
int multi_client = 1;
|
|
|
|
|
int err;
|
|
|
|
|
struct addrinfo *res, *cur;
|
2022-03-10 13:52:03 +01:00
|
|
|
|
struct addrinfo hint = {.ai_flags = AI_PASSIVE,
|
|
|
|
|
.ai_family = AF_UNSPEC,
|
|
|
|
|
.ai_socktype = SOCK_STREAM,
|
|
|
|
|
.ai_protocol = 0,
|
|
|
|
|
|
|
|
|
|
.ai_addrlen = 0,
|
|
|
|
|
.ai_addr = 0,
|
|
|
|
|
.ai_canonname = 0,
|
|
|
|
|
.ai_next = 0};
|
2007-02-08 23:53:48 +01:00
|
|
|
|
|
2005-04-28 10:26:44 +02:00
|
|
|
|
cn->connected = CONN_ERROR;
|
2007-02-08 23:53:48 +01:00
|
|
|
|
|
2005-04-28 10:26:44 +02:00
|
|
|
|
err = getaddrinfo(hostname, port, &hint, &res);
|
|
|
|
|
if (err) {
|
2007-09-26 21:22:44 +02:00
|
|
|
|
mylog(LOG_ERROR, "getaddrinfo(): %s", gai_strerror(err));
|
2005-04-28 10:26:44 +02:00
|
|
|
|
return;
|
2007-09-04 00:24:50 +02:00
|
|
|
|
}
|
2007-02-08 23:53:48 +01:00
|
|
|
|
|
2022-03-10 13:52:03 +01:00
|
|
|
|
for (cur = res; cur; cur = cur->ai_next) {
|
2005-04-28 10:26:44 +02:00
|
|
|
|
if ((cn->handle = socket(cur->ai_family, cur->ai_socktype,
|
2022-03-10 13:52:03 +01:00
|
|
|
|
cur->ai_protocol))
|
|
|
|
|
< 0) {
|
2005-04-28 10:26:44 +02:00
|
|
|
|
mylog(LOG_WARN, "socket : %s", strerror(errno));
|
|
|
|
|
continue;
|
|
|
|
|
}
|
2007-02-08 23:53:48 +01:00
|
|
|
|
|
2012-01-07 11:41:02 +01:00
|
|
|
|
if (cn->handle >= FD_SETSIZE) {
|
2022-03-10 13:52:03 +01:00
|
|
|
|
mylog(LOG_WARN,
|
|
|
|
|
"too many fd used, close listening socket %d",
|
|
|
|
|
cn->handle);
|
2012-01-07 11:41:02 +01:00
|
|
|
|
|
|
|
|
|
if (close(cn->handle) == -1)
|
|
|
|
|
mylog(LOG_WARN, "Error on socket close: %s",
|
2022-03-10 13:52:03 +01:00
|
|
|
|
strerror(errno));
|
2012-01-07 11:41:02 +01:00
|
|
|
|
|
|
|
|
|
cn->handle = -1;
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
2005-04-28 10:26:44 +02:00
|
|
|
|
if (setsockopt(cn->handle, SOL_SOCKET, SO_REUSEADDR,
|
2022-03-10 13:52:03 +01:00
|
|
|
|
(char *)&multi_client,
|
|
|
|
|
(socklen_t)sizeof(multi_client))
|
|
|
|
|
< 0) {
|
2005-04-28 10:26:44 +02:00
|
|
|
|
mylog(LOG_WARN, "setsockopt() : %s", strerror(errno));
|
|
|
|
|
close(cn->handle);
|
|
|
|
|
cn->handle = -1;
|
|
|
|
|
continue;
|
|
|
|
|
}
|
2007-02-08 23:53:48 +01:00
|
|
|
|
|
2005-04-28 10:26:44 +02:00
|
|
|
|
socket_set_nonblock(cn->handle);
|
2007-02-08 23:53:48 +01:00
|
|
|
|
|
2005-04-28 10:26:44 +02:00
|
|
|
|
if (bind(cn->handle, cur->ai_addr, cur->ai_addrlen) < 0) {
|
|
|
|
|
mylog(LOG_WARN, "bind() : %s", strerror(errno));
|
|
|
|
|
close(cn->handle);
|
|
|
|
|
cn->handle = -1;
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
|
2006-04-20 14:49:50 +02:00
|
|
|
|
err = listen(cn->handle, 256);
|
2005-04-28 10:26:44 +02:00
|
|
|
|
if (err == -1) {
|
|
|
|
|
mylog(LOG_WARN, "listen() : %s", strerror(errno));
|
|
|
|
|
close(cn->handle);
|
|
|
|
|
cn->handle = -1;
|
|
|
|
|
continue;
|
|
|
|
|
}
|
2007-02-08 23:53:48 +01:00
|
|
|
|
|
2005-04-28 10:26:44 +02:00
|
|
|
|
freeaddrinfo(res);
|
|
|
|
|
cn->connected = CONN_OK;
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
freeaddrinfo(res);
|
|
|
|
|
mylog(LOG_ERROR, "Unable to bind/listen");
|
|
|
|
|
cn->connected = CONN_ERROR;
|
|
|
|
|
}
|
|
|
|
|
|
2022-01-09 20:59:59 +01:00
|
|
|
|
static connection_t *connection_init(int anti_flood, int ssl, time_t timeout,
|
2022-03-10 13:52:03 +01:00
|
|
|
|
int listen)
|
2005-04-28 10:26:44 +02:00
|
|
|
|
{
|
|
|
|
|
connection_t *conn;
|
|
|
|
|
char *incoming;
|
2005-05-30 01:00:30 +02:00
|
|
|
|
list_t *outgoing;
|
2005-04-28 10:26:44 +02:00
|
|
|
|
|
2022-01-09 21:20:49 +01:00
|
|
|
|
conn = (connection_t *)bip_calloc(sizeof(connection_t), (size_t)1);
|
|
|
|
|
incoming = (char *)bip_malloc((size_t)CONN_BUFFER_SIZE);
|
2005-04-28 10:26:44 +02:00
|
|
|
|
outgoing = list_new(NULL);
|
|
|
|
|
|
2010-02-17 13:32:22 +01:00
|
|
|
|
conn->anti_flood = anti_flood;
|
2005-04-28 10:26:44 +02:00
|
|
|
|
conn->ssl = ssl;
|
|
|
|
|
conn->lasttoken = 0;
|
|
|
|
|
conn->token = TOKEN_MAX;
|
|
|
|
|
conn->timeout = (listen ? 0 : timeout);
|
|
|
|
|
conn->connect_time = 0;
|
|
|
|
|
conn->incoming = incoming;
|
|
|
|
|
conn->incoming_end = 0;
|
|
|
|
|
conn->outgoing = outgoing;
|
|
|
|
|
conn->incoming_lines = NULL;
|
|
|
|
|
conn->user_data = NULL;
|
|
|
|
|
conn->listening = listen;
|
|
|
|
|
conn->handle = -1;
|
|
|
|
|
conn->client = 0;
|
|
|
|
|
conn->connecting_data = NULL;
|
|
|
|
|
#ifdef HAVE_LIBSSL
|
2005-06-04 13:05:54 +02:00
|
|
|
|
conn->ssl_ctx_h = NULL;
|
2005-04-28 10:26:44 +02:00
|
|
|
|
conn->ssl_h = NULL;
|
|
|
|
|
conn->cert = NULL;
|
2005-06-04 13:05:54 +02:00
|
|
|
|
conn->ssl_check_mode = SSL_CHECK_NONE;
|
2005-04-28 10:26:44 +02:00
|
|
|
|
#endif
|
|
|
|
|
conn->connected = CONN_NEW;
|
|
|
|
|
return conn;
|
|
|
|
|
}
|
|
|
|
|
|
2009-01-25 14:24:22 +01:00
|
|
|
|
#ifdef HAVE_LIBSSL
|
2016-07-05 09:18:07 +02:00
|
|
|
|
static int ctx_set_dh(SSL_CTX *ctx)
|
2009-01-25 14:24:22 +01:00
|
|
|
|
{
|
2016-07-05 09:18:07 +02:00
|
|
|
|
/* Return ephemeral DH parameters. */
|
|
|
|
|
DH *dh = NULL;
|
|
|
|
|
FILE *f;
|
2022-01-09 20:59:59 +01:00
|
|
|
|
long ret;
|
2016-06-29 19:40:32 +02:00
|
|
|
|
|
2016-07-05 09:18:07 +02:00
|
|
|
|
if ((f = fopen(conf_client_dh_file, "r")) == NULL) {
|
|
|
|
|
mylog(LOG_ERROR, "Unable to open DH parameters (%s): %s",
|
2022-03-10 13:52:03 +01:00
|
|
|
|
conf_client_dh_file, strerror(errno));
|
2016-07-05 09:18:07 +02:00
|
|
|
|
return 0;
|
2009-01-25 14:24:22 +01:00
|
|
|
|
}
|
|
|
|
|
|
2016-07-05 09:18:07 +02:00
|
|
|
|
dh = PEM_read_DHparams(f, NULL, NULL, NULL);
|
|
|
|
|
fclose(f);
|
2016-06-29 19:40:32 +02:00
|
|
|
|
|
2016-07-05 09:18:07 +02:00
|
|
|
|
if (dh == NULL) {
|
|
|
|
|
mylog(LOG_ERROR, "Could not parse DH parameters from: %s",
|
2022-03-10 13:52:03 +01:00
|
|
|
|
conf_client_dh_file);
|
2016-07-05 09:18:07 +02:00
|
|
|
|
return 0;
|
2009-01-25 14:24:22 +01:00
|
|
|
|
}
|
|
|
|
|
|
2022-03-10 13:52:03 +01:00
|
|
|
|
// SSL crap: passing argument 3 of ‘SSL_CTX_ctrl’ with different width due to
|
|
|
|
|
// prototype
|
2022-01-09 20:37:55 +01:00
|
|
|
|
#pragma GCC diagnostic push
|
|
|
|
|
#pragma GCC diagnostic ignored "-Wtraditional-conversion"
|
2016-07-05 09:18:07 +02:00
|
|
|
|
ret = SSL_CTX_set_tmp_dh(ctx, dh);
|
2022-01-09 20:37:55 +01:00
|
|
|
|
#pragma GCC diagnostic pop
|
2016-07-05 09:18:07 +02:00
|
|
|
|
DH_free(dh);
|
2009-01-25 14:24:22 +01:00
|
|
|
|
|
2016-07-05 09:18:07 +02:00
|
|
|
|
if (ret != 1) {
|
|
|
|
|
mylog(LOG_ERROR, "Unable to set DH parameters: %s",
|
2022-03-10 13:52:03 +01:00
|
|
|
|
ERR_error_string(ERR_get_error(), NULL));
|
2016-07-05 09:18:07 +02:00
|
|
|
|
return 0;
|
2009-01-25 14:41:19 +01:00
|
|
|
|
}
|
2016-07-05 09:18:07 +02:00
|
|
|
|
|
|
|
|
|
return 1;
|
2009-01-25 14:24:22 +01:00
|
|
|
|
}
|
|
|
|
|
#endif
|
|
|
|
|
|
2005-04-28 10:26:44 +02:00
|
|
|
|
connection_t *accept_new(connection_t *cn)
|
|
|
|
|
{
|
|
|
|
|
connection_t *conn;
|
|
|
|
|
int err;
|
2022-03-10 13:52:03 +01:00
|
|
|
|
socklen_t sa_len = sizeof(struct sockaddr);
|
2005-04-28 10:26:44 +02:00
|
|
|
|
struct sockaddr sa;
|
|
|
|
|
|
|
|
|
|
mylog(LOG_DEBUG, "Trying to accept new client on %d", cn->handle);
|
|
|
|
|
err = accept(cn->handle, &sa, &sa_len);
|
2012-01-07 11:41:02 +01:00
|
|
|
|
|
2007-10-20 23:12:22 +02:00
|
|
|
|
if (err < 0) {
|
2012-01-07 11:41:02 +01:00
|
|
|
|
fatal("accept failed: %s", strerror(errno));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (err >= FD_SETSIZE) {
|
|
|
|
|
mylog(LOG_WARN, "too many client connected, close %d", err);
|
|
|
|
|
|
|
|
|
|
if (close(err) == -1)
|
|
|
|
|
mylog(LOG_WARN, "Error on socket close: %s",
|
2022-03-10 13:52:03 +01:00
|
|
|
|
strerror(errno));
|
2012-01-07 11:41:02 +01:00
|
|
|
|
|
2005-04-28 10:26:44 +02:00
|
|
|
|
return NULL;
|
2007-10-20 23:12:22 +02:00
|
|
|
|
}
|
2012-01-07 11:41:02 +01:00
|
|
|
|
|
2005-04-28 10:26:44 +02:00
|
|
|
|
socket_set_nonblock(err);
|
2007-02-08 23:53:48 +01:00
|
|
|
|
|
2010-02-17 13:32:22 +01:00
|
|
|
|
conn = connection_init(cn->anti_flood, cn->ssl, cn->timeout, 0);
|
2005-04-28 10:26:44 +02:00
|
|
|
|
conn->connect_time = time(NULL);
|
|
|
|
|
conn->user_data = cn->user_data;
|
|
|
|
|
conn->handle = err;
|
|
|
|
|
conn->client = 1;
|
|
|
|
|
#ifdef HAVE_LIBSSL
|
|
|
|
|
if (cn->ssl) {
|
|
|
|
|
if (!sslctx) {
|
2022-03-10 13:52:03 +01:00
|
|
|
|
mylog(LOG_DEBUG,
|
|
|
|
|
"No SSL context available for "
|
|
|
|
|
"accepted connections. "
|
|
|
|
|
"Initializing...");
|
2016-04-13 01:04:33 +02:00
|
|
|
|
if (!(sslctx = SSL_init_context(conf_client_ciphers))) {
|
2022-03-10 13:52:03 +01:00
|
|
|
|
mylog(LOG_ERROR,
|
|
|
|
|
"SSL context initialization "
|
|
|
|
|
"failed");
|
2005-04-28 10:26:44 +02:00
|
|
|
|
connection_free(conn);
|
|
|
|
|
return NULL;
|
|
|
|
|
}
|
2016-07-05 09:18:07 +02:00
|
|
|
|
|
2018-03-21 11:12:21 +01:00
|
|
|
|
if (!conf_client_dh_file) {
|
2022-03-10 13:52:03 +01:00
|
|
|
|
// try with a default path but don't fail if it
|
|
|
|
|
// doesn't exist
|
|
|
|
|
conf_client_dh_file =
|
|
|
|
|
default_path(conf_biphome, "dh.pem",
|
|
|
|
|
"DH parameters");
|
2018-03-21 11:12:21 +01:00
|
|
|
|
|
|
|
|
|
struct stat st_buf;
|
|
|
|
|
if (stat(conf_client_dh_file, &st_buf) != 0) {
|
|
|
|
|
free(conf_client_dh_file);
|
|
|
|
|
conf_client_dh_file = NULL;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (conf_client_dh_file) {
|
|
|
|
|
if (!ctx_set_dh(sslctx)) {
|
2022-03-10 13:52:03 +01:00
|
|
|
|
mylog(LOG_ERROR,
|
|
|
|
|
"SSL Unable to load DH "
|
|
|
|
|
"parameters");
|
2018-03-21 11:12:21 +01:00
|
|
|
|
connection_free(conn);
|
|
|
|
|
return NULL;
|
|
|
|
|
}
|
2016-07-05 09:18:07 +02:00
|
|
|
|
}
|
|
|
|
|
|
2022-03-10 13:52:03 +01:00
|
|
|
|
if (!SSL_CTX_use_certificate_chain_file(
|
|
|
|
|
sslctx, conf_ssl_certfile))
|
|
|
|
|
mylog(LOG_WARN,
|
|
|
|
|
"SSL: Unable to load "
|
|
|
|
|
"certificate file");
|
2008-01-20 18:49:44 +01:00
|
|
|
|
if (!SSL_CTX_use_PrivateKey_file(sslctx,
|
2022-03-10 13:52:03 +01:00
|
|
|
|
conf_ssl_certfile,
|
|
|
|
|
SSL_FILETYPE_PEM))
|
2008-01-20 18:49:44 +01:00
|
|
|
|
mylog(LOG_WARN, "SSL: Unable to load key file");
|
2005-04-28 10:26:44 +02:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
conn->ssl_h = SSL_new(sslctx);
|
|
|
|
|
if (!conn->ssl_h) {
|
|
|
|
|
connection_free(conn);
|
2016-04-13 01:15:43 +02:00
|
|
|
|
SSL_CTX_free(sslctx);
|
2005-04-28 10:26:44 +02:00
|
|
|
|
return NULL;
|
|
|
|
|
}
|
|
|
|
|
SSL_set_accept_state(conn->ssl_h);
|
|
|
|
|
}
|
|
|
|
|
#endif
|
2022-03-10 13:52:03 +01:00
|
|
|
|
mylog(LOG_DEBUG, "New client on socket %d !", conn->handle);
|
2005-04-28 10:26:44 +02:00
|
|
|
|
|
|
|
|
|
return conn;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
connection_t *listen_new(char *hostname, int port, int ssl)
|
|
|
|
|
{
|
|
|
|
|
connection_t *conn;
|
|
|
|
|
char portbuf[20];
|
|
|
|
|
/* TODO: allow litteral service name in the function interface */
|
2022-01-09 21:20:49 +01:00
|
|
|
|
if (snprintf(portbuf, (size_t)20, "%d", port) >= 20)
|
2005-04-28 10:26:44 +02:00
|
|
|
|
portbuf[19] = '\0';
|
2007-02-10 15:05:37 +01:00
|
|
|
|
|
2005-04-28 10:26:44 +02:00
|
|
|
|
/*
|
|
|
|
|
* SSL flag is only here to tell program to convert socket to SSL after
|
|
|
|
|
* accept(). Listening socket will NOT be SSL
|
|
|
|
|
*/
|
2022-01-09 20:59:59 +01:00
|
|
|
|
conn = connection_init(0, ssl, (time_t)0, 1);
|
2005-04-28 10:26:44 +02:00
|
|
|
|
create_listening_socket(hostname, portbuf, conn);
|
|
|
|
|
|
|
|
|
|
return conn;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static connection_t *_connection_new(char *dsthostname, char *dstport,
|
2022-03-10 13:52:03 +01:00
|
|
|
|
char *srchostname, char *srcport,
|
|
|
|
|
time_t timeout)
|
2005-04-28 10:26:44 +02:00
|
|
|
|
{
|
|
|
|
|
connection_t *conn;
|
2005-11-16 19:34:25 +01:00
|
|
|
|
|
2010-02-17 13:32:22 +01:00
|
|
|
|
conn = connection_init(1, 0, timeout, 0);
|
2005-04-28 10:26:44 +02:00
|
|
|
|
create_socket(dsthostname, dstport, srchostname, srcport, conn);
|
2005-11-16 19:34:25 +01:00
|
|
|
|
|
2005-04-28 10:26:44 +02:00
|
|
|
|
return conn;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#ifdef HAVE_LIBSSL
|
2016-04-13 01:04:33 +02:00
|
|
|
|
static SSL_CTX *SSL_init_context(char *ciphers)
|
2005-04-28 10:26:44 +02:00
|
|
|
|
{
|
2022-01-09 20:59:59 +01:00
|
|
|
|
int fd, flags, rng;
|
|
|
|
|
ssize_t ret;
|
2005-04-28 10:26:44 +02:00
|
|
|
|
char buf[1025];
|
2005-06-04 13:05:54 +02:00
|
|
|
|
SSL_CTX *ctx;
|
2006-06-22 14:13:34 +02:00
|
|
|
|
|
2005-06-04 13:05:54 +02:00
|
|
|
|
if (!ssl_initialized) {
|
2022-03-10 13:52:03 +01:00
|
|
|
|
// SSL crap: passing argument 1 of ‘OPENSSL_init_ssl’ with different width due
|
|
|
|
|
// to prototype
|
2022-01-09 20:37:55 +01:00
|
|
|
|
#pragma GCC diagnostic push
|
|
|
|
|
#pragma GCC diagnostic ignored "-Wtraditional-conversion"
|
2005-06-04 13:05:54 +02:00
|
|
|
|
SSL_library_init();
|
2022-01-09 20:37:55 +01:00
|
|
|
|
#pragma GCC diagnostic pop
|
2005-06-04 13:05:54 +02:00
|
|
|
|
SSL_load_error_strings();
|
2012-01-25 05:08:52 +01:00
|
|
|
|
errbio = BIO_new_fp(conf_global_log_file, BIO_NOCLOSE);
|
2006-06-22 14:13:34 +02:00
|
|
|
|
|
2022-01-09 21:20:49 +01:00
|
|
|
|
ssl_cx_idx = SSL_get_ex_new_index((size_t)0, "bip connection_t",
|
2022-03-10 13:52:03 +01:00
|
|
|
|
NULL, NULL, NULL);
|
2006-06-22 14:13:34 +02:00
|
|
|
|
|
2005-06-04 13:05:54 +02:00
|
|
|
|
flags = O_RDONLY;
|
|
|
|
|
flags |= O_NONBLOCK;
|
|
|
|
|
fd = open("/dev/random", flags);
|
|
|
|
|
if (fd < 0) {
|
2022-03-10 13:52:03 +01:00
|
|
|
|
mylog(LOG_WARN,
|
|
|
|
|
"SSL: /dev/random not ready, unable "
|
|
|
|
|
"to manually seed PRNG.");
|
2005-06-04 13:05:54 +02:00
|
|
|
|
goto prng_end;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
do {
|
2022-01-09 21:20:49 +01:00
|
|
|
|
ret = read(fd, buf, (size_t)1024);
|
2005-06-04 13:05:54 +02:00
|
|
|
|
if (ret <= 0) {
|
2022-03-10 13:52:03 +01:00
|
|
|
|
mylog(LOG_ERROR, "/dev/random: %s",
|
|
|
|
|
strerror(errno));
|
2005-06-04 13:05:54 +02:00
|
|
|
|
goto prng_end;
|
|
|
|
|
}
|
2022-03-10 13:52:03 +01:00
|
|
|
|
mylog(LOG_DEBUG,
|
|
|
|
|
"PRNG seeded with %d /dev/random "
|
|
|
|
|
"bytes",
|
|
|
|
|
ret);
|
2022-01-09 20:59:59 +01:00
|
|
|
|
RAND_seed(buf, (int)ret);
|
2005-06-04 13:05:54 +02:00
|
|
|
|
} while (!(rng = RAND_status()));
|
|
|
|
|
|
2022-03-10 13:52:03 +01:00
|
|
|
|
prng_end:
|
2005-06-04 13:05:54 +02:00
|
|
|
|
do {
|
|
|
|
|
ret = close(fd);
|
|
|
|
|
} while (ret != 0 && errno == EINTR);
|
|
|
|
|
if (RAND_status()) {
|
|
|
|
|
mylog(LOG_DEBUG, "SSL: PRNG is seeded !");
|
|
|
|
|
} else {
|
|
|
|
|
mylog(LOG_WARN, "SSL: PRNG is not seeded enough");
|
2022-03-10 13:52:03 +01:00
|
|
|
|
mylog(LOG_WARN,
|
|
|
|
|
" OpenSSL will use /dev/urandom if "
|
|
|
|
|
"available.");
|
2005-06-04 13:05:54 +02:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
ssl_initialized = 1;
|
|
|
|
|
}
|
2007-02-08 23:53:48 +01:00
|
|
|
|
|
2005-04-28 10:26:44 +02:00
|
|
|
|
/* allocated by function */
|
2016-04-13 01:14:36 +02:00
|
|
|
|
if (!(ctx = SSL_CTX_new(SSLv23_method()))) {
|
|
|
|
|
ERR_print_errors(errbio);
|
|
|
|
|
return NULL;
|
|
|
|
|
}
|
2022-01-09 20:37:55 +01:00
|
|
|
|
#pragma GCC diagnostic push
|
|
|
|
|
#pragma GCC diagnostic ignored "-Wtraditional-conversion"
|
2022-03-10 13:52:03 +01:00
|
|
|
|
// SSL crap: passing argument 3 of ‘SSL_CTX_ctrl’ with different width
|
|
|
|
|
// due to prototype
|
2005-06-04 13:05:54 +02:00
|
|
|
|
SSL_CTX_set_session_cache_mode(ctx, SSL_SESS_CACHE_BOTH);
|
2008-01-20 18:49:44 +01:00
|
|
|
|
SSL_CTX_set_timeout(ctx, (long)60);
|
2022-03-10 13:52:03 +01:00
|
|
|
|
// SSL crap: passing argument 2 of ‘SSL_CTX_set_options’ with different
|
|
|
|
|
// width due to prototype
|
2005-06-04 13:05:54 +02:00
|
|
|
|
SSL_CTX_set_options(ctx, SSL_OP_ALL);
|
2022-01-09 20:37:55 +01:00
|
|
|
|
#pragma GCC diagnostic pop
|
2016-04-13 01:04:33 +02:00
|
|
|
|
if (ciphers && !SSL_CTX_set_cipher_list(ctx, ciphers)) {
|
|
|
|
|
SSL_CTX_free(ctx);
|
|
|
|
|
return NULL;
|
|
|
|
|
}
|
2005-04-28 10:26:44 +02:00
|
|
|
|
|
2005-06-04 13:05:54 +02:00
|
|
|
|
return ctx;
|
|
|
|
|
}
|
2005-04-28 10:26:44 +02:00
|
|
|
|
|
2005-06-04 13:05:54 +02:00
|
|
|
|
static int bip_ssl_verify_callback(int preverify_ok, X509_STORE_CTX *ctx)
|
|
|
|
|
{
|
|
|
|
|
char subject[256];
|
|
|
|
|
char issuer[256];
|
|
|
|
|
X509 *err_cert;
|
|
|
|
|
int err, depth;
|
|
|
|
|
SSL *ssl;
|
|
|
|
|
connection_t *c;
|
2016-06-29 19:40:32 +02:00
|
|
|
|
X509_OBJECT *xobj;
|
2005-06-04 13:05:54 +02:00
|
|
|
|
int result;
|
|
|
|
|
|
|
|
|
|
err_cert = X509_STORE_CTX_get_current_cert(ctx);
|
|
|
|
|
err = X509_STORE_CTX_get_error(ctx);
|
|
|
|
|
depth = X509_STORE_CTX_get_error_depth(ctx);
|
|
|
|
|
|
|
|
|
|
/* Retrieve the SSL and connection_t objects from the store */
|
|
|
|
|
ssl = X509_STORE_CTX_get_ex_data(ctx,
|
2022-03-10 13:52:03 +01:00
|
|
|
|
SSL_get_ex_data_X509_STORE_CTX_idx());
|
2005-06-04 13:05:54 +02:00
|
|
|
|
c = SSL_get_ex_data(ssl, ssl_cx_idx);
|
|
|
|
|
|
|
|
|
|
mylog(LOG_INFO, "SSL cert check: now at depth=%d", depth);
|
|
|
|
|
X509_NAME_oneline(X509_get_subject_name(err_cert), subject, 256);
|
|
|
|
|
X509_NAME_oneline(X509_get_issuer_name(err_cert), issuer, 256);
|
|
|
|
|
mylog(LOG_INFO, "Subject: %s", subject);
|
|
|
|
|
mylog(LOG_INFO, "Issuer: %s", issuer);
|
|
|
|
|
|
|
|
|
|
result = preverify_ok;
|
2007-02-08 23:53:48 +01:00
|
|
|
|
|
2005-06-04 13:05:54 +02:00
|
|
|
|
/* in basic mode (mode 1), accept a leaf certificate if we can find it
|
|
|
|
|
* in the store */
|
2022-03-10 13:52:03 +01:00
|
|
|
|
if (c->ssl_check_mode == SSL_CHECK_BASIC && result == 0
|
|
|
|
|
&& (err == X509_V_ERR_UNABLE_TO_GET_ISSUER_CERT_LOCALLY
|
|
|
|
|
|| err == X509_V_ERR_CERT_UNTRUSTED
|
|
|
|
|
|| err == X509_V_ERR_UNABLE_TO_VERIFY_LEAF_SIGNATURE
|
|
|
|
|
|| err == X509_V_ERR_DEPTH_ZERO_SELF_SIGNED_CERT
|
|
|
|
|
|| err == X509_V_ERR_CERT_HAS_EXPIRED
|
|
|
|
|
|| err == X509_V_ERR_SELF_SIGNED_CERT_IN_CHAIN)) {
|
2007-02-08 23:53:48 +01:00
|
|
|
|
|
2016-11-12 00:52:50 +01:00
|
|
|
|
if (!(xobj = X509_OBJECT_new())) {
|
|
|
|
|
result = 0;
|
2005-06-04 13:05:54 +02:00
|
|
|
|
} else {
|
2022-03-10 13:52:03 +01:00
|
|
|
|
if (X509_STORE_CTX_get_by_subject(
|
|
|
|
|
ctx, X509_LU_X509,
|
|
|
|
|
X509_get_subject_name(err_cert), xobj)
|
|
|
|
|
> 0
|
|
|
|
|
&& !X509_cmp(X509_OBJECT_get0_X509(xobj),
|
|
|
|
|
err_cert)) {
|
2016-11-12 00:52:50 +01:00
|
|
|
|
if (err == X509_V_ERR_CERT_HAS_EXPIRED)
|
2022-03-10 13:52:03 +01:00
|
|
|
|
mylog(LOG_INFO,
|
|
|
|
|
"Basic mode; Accepting "
|
|
|
|
|
"*expired* peer certificate "
|
|
|
|
|
"found in store.");
|
2016-11-12 00:52:50 +01:00
|
|
|
|
else
|
2022-03-10 13:52:03 +01:00
|
|
|
|
mylog(LOG_INFO,
|
|
|
|
|
"Basic mode; Accepting peer "
|
|
|
|
|
"certificate found in store.");
|
2016-11-12 00:52:50 +01:00
|
|
|
|
|
|
|
|
|
result = 1;
|
|
|
|
|
err = X509_V_OK;
|
|
|
|
|
X509_STORE_CTX_set_error(ctx, err);
|
|
|
|
|
} else {
|
2022-03-10 13:52:03 +01:00
|
|
|
|
mylog(LOG_INFO,
|
|
|
|
|
"Basic mode; peer certificate NOT "
|
|
|
|
|
"in store, rejecting it!");
|
2016-11-12 00:52:50 +01:00
|
|
|
|
err = X509_V_ERR_CERT_REJECTED;
|
|
|
|
|
X509_STORE_CTX_set_error(ctx, err);
|
|
|
|
|
|
2022-03-10 13:52:03 +01:00
|
|
|
|
link_add_untrusted(c->user_data,
|
|
|
|
|
X509_dup(err_cert));
|
2016-11-12 00:52:50 +01:00
|
|
|
|
}
|
|
|
|
|
X509_OBJECT_free(xobj);
|
2005-06-04 13:05:54 +02:00
|
|
|
|
}
|
2005-04-28 10:26:44 +02:00
|
|
|
|
}
|
2007-02-08 23:53:48 +01:00
|
|
|
|
|
2005-06-04 13:05:54 +02:00
|
|
|
|
if (!result) {
|
|
|
|
|
/* We have a verify error! Log it */
|
|
|
|
|
mylog(LOG_ERROR, "SSL cert check failed at depth=%d: %s (%d)",
|
2022-03-10 13:52:03 +01:00
|
|
|
|
depth, X509_verify_cert_error_string((long)err), err);
|
2005-06-04 13:05:54 +02:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return result;
|
2005-04-28 10:26:44 +02:00
|
|
|
|
}
|
|
|
|
|
|
2005-05-12 10:29:27 +02:00
|
|
|
|
static int SSLize(connection_t *cn, int *nc)
|
2005-04-28 10:26:44 +02:00
|
|
|
|
{
|
|
|
|
|
int err, err2;
|
2022-01-09 20:59:59 +01:00
|
|
|
|
long errl;
|
2007-02-08 23:53:48 +01:00
|
|
|
|
|
2005-04-28 10:26:44 +02:00
|
|
|
|
if (cn == NULL)
|
|
|
|
|
return 1;
|
|
|
|
|
|
|
|
|
|
if (cn->listening) {
|
2007-09-26 21:22:44 +02:00
|
|
|
|
mylog(LOG_ERROR, "Can't use SSL with listening socket.");
|
2005-04-28 10:26:44 +02:00
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
2005-05-28 15:23:51 +02:00
|
|
|
|
if (!SSL_set_fd(cn->ssl_h, cn->handle)) {
|
2007-09-26 21:22:44 +02:00
|
|
|
|
mylog(LOG_ERROR, "unable to associate FD to SSL structure");
|
2005-05-28 15:23:51 +02:00
|
|
|
|
cn->connected = CONN_ERROR;
|
2005-04-28 10:26:44 +02:00
|
|
|
|
return 1;
|
|
|
|
|
}
|
2007-02-08 23:53:48 +01:00
|
|
|
|
|
2005-04-28 10:26:44 +02:00
|
|
|
|
if (cn->client)
|
|
|
|
|
err = SSL_accept(cn->ssl_h);
|
|
|
|
|
else
|
|
|
|
|
err = SSL_connect(cn->ssl_h);
|
|
|
|
|
|
|
|
|
|
err2 = SSL_get_error(cn->ssl_h, err);
|
|
|
|
|
ERR_print_errors(errbio);
|
2007-12-21 12:20:21 +01:00
|
|
|
|
|
2005-04-28 10:26:44 +02:00
|
|
|
|
if (err2 == SSL_ERROR_NONE) {
|
2011-10-03 08:25:26 +02:00
|
|
|
|
const SSL_CIPHER *cipher;
|
2005-04-28 10:26:44 +02:00
|
|
|
|
char buf[128];
|
2022-01-09 20:59:59 +01:00
|
|
|
|
size_t len;
|
2005-04-28 10:26:44 +02:00
|
|
|
|
|
|
|
|
|
cipher = SSL_get_current_cipher(cn->ssl_h);
|
|
|
|
|
SSL_CIPHER_description(cipher, buf, 128);
|
|
|
|
|
len = strlen(buf);
|
|
|
|
|
if (len > 0)
|
2005-08-25 10:17:10 +02:00
|
|
|
|
buf[len - 1] = '\0';
|
2021-10-17 12:09:45 +02:00
|
|
|
|
mylog(LOG_DEBUG, "Negotiated ciphers: %s", buf);
|
2005-06-04 13:05:54 +02:00
|
|
|
|
|
2005-04-28 10:26:44 +02:00
|
|
|
|
cn->connected = CONN_OK;
|
2007-12-21 12:20:21 +01:00
|
|
|
|
connection_connected(cn);
|
2005-05-12 10:29:27 +02:00
|
|
|
|
*nc = 1;
|
2005-04-28 10:26:44 +02:00
|
|
|
|
return 0;
|
|
|
|
|
}
|
2005-08-25 10:17:10 +02:00
|
|
|
|
|
|
|
|
|
switch (cn->ssl_check_mode) {
|
|
|
|
|
case SSL_CHECK_NONE:
|
|
|
|
|
break;
|
|
|
|
|
case SSL_CHECK_BASIC:
|
2022-03-10 13:52:03 +01:00
|
|
|
|
if ((errl = SSL_get_verify_result(cn->ssl_h)) != X509_V_OK) {
|
2022-01-09 20:59:59 +01:00
|
|
|
|
mylog(LOG_ERROR, "Certificate check failed: %s (%ld)!",
|
2022-03-10 13:52:03 +01:00
|
|
|
|
X509_verify_cert_error_string(errl), errl);
|
2005-08-25 10:17:10 +02:00
|
|
|
|
cn->connected = CONN_UNTRUSTED;
|
|
|
|
|
return 1;
|
|
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
case SSL_CHECK_CA:
|
2022-03-10 13:52:03 +01:00
|
|
|
|
if ((errl = SSL_get_verify_result(cn->ssl_h)) != X509_V_OK) {
|
2022-01-09 20:59:59 +01:00
|
|
|
|
mylog(LOG_ERROR, "Certificate check failed: %s (%ld)!",
|
2022-03-10 13:52:03 +01:00
|
|
|
|
X509_verify_cert_error_string(errl), errl);
|
2005-08-25 10:17:10 +02:00
|
|
|
|
cn->connected = CONN_UNTRUSTED;
|
|
|
|
|
return 1;
|
|
|
|
|
}
|
|
|
|
|
break;
|
2022-01-09 19:34:49 +01:00
|
|
|
|
default:
|
2022-03-10 13:52:03 +01:00
|
|
|
|
mylog(LOG_ERROR, "Unknown ssl_check_mode (%d)!",
|
|
|
|
|
cn->ssl_check_mode);
|
2022-01-09 19:34:49 +01:00
|
|
|
|
return 1;
|
2005-08-25 10:17:10 +02:00
|
|
|
|
}
|
|
|
|
|
|
2005-05-28 15:23:51 +02:00
|
|
|
|
if (err2 == SSL_ERROR_SYSCALL) {
|
2018-12-09 20:27:59 +01:00
|
|
|
|
mylog(LOG_ERROR, "Error with socket during ssl handshake.");
|
|
|
|
|
connection_close(cn);
|
2005-05-28 15:23:51 +02:00
|
|
|
|
cn->connected = CONN_ERROR;
|
|
|
|
|
return 1;
|
|
|
|
|
}
|
2005-05-19 01:31:14 +02:00
|
|
|
|
/* From now on, we are on error, thus we return 1 to check timeout */
|
2005-04-28 10:26:44 +02:00
|
|
|
|
if (err2 == SSL_ERROR_ZERO_RETURN || err2 == SSL_ERROR_SSL) {
|
2007-09-26 21:22:44 +02:00
|
|
|
|
mylog(LOG_ERROR, "Error in SSL handshake.");
|
2012-01-25 05:08:52 +01:00
|
|
|
|
connection_close(cn);
|
2005-04-28 10:26:44 +02:00
|
|
|
|
cn->connected = CONN_ERROR;
|
|
|
|
|
return 1;
|
|
|
|
|
}
|
2005-05-19 01:31:14 +02:00
|
|
|
|
/* Here are unhandled errors/resource waiting. Timeout must be
|
|
|
|
|
* checked but connection may still be valid */
|
|
|
|
|
return 1;
|
2005-04-28 10:26:44 +02:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static connection_t *_connection_new_SSL(char *dsthostname, char *dstport,
|
2022-03-10 13:52:03 +01:00
|
|
|
|
char *srchostname, char *srcport,
|
|
|
|
|
char *ciphers, int check_mode,
|
|
|
|
|
char *check_store,
|
|
|
|
|
char *ssl_client_certfile,
|
|
|
|
|
time_t timeout)
|
2005-04-28 10:26:44 +02:00
|
|
|
|
{
|
|
|
|
|
connection_t *conn;
|
|
|
|
|
|
2010-02-17 13:32:22 +01:00
|
|
|
|
conn = connection_init(1, 1, timeout, 0);
|
2016-04-13 01:04:33 +02:00
|
|
|
|
if (!(conn->ssl_ctx_h = SSL_init_context(ciphers))) {
|
2007-09-26 21:22:44 +02:00
|
|
|
|
mylog(LOG_ERROR, "SSL context initialization failed");
|
2005-06-04 13:05:54 +02:00
|
|
|
|
return conn;
|
2005-04-28 10:26:44 +02:00
|
|
|
|
}
|
2008-01-20 18:49:44 +01:00
|
|
|
|
|
2005-04-28 10:26:44 +02:00
|
|
|
|
conn->cert = NULL;
|
2005-06-04 13:05:54 +02:00
|
|
|
|
conn->ssl_check_mode = check_mode;
|
2005-08-25 10:17:10 +02:00
|
|
|
|
|
|
|
|
|
switch (conn->ssl_check_mode) {
|
2022-03-10 13:52:03 +01:00
|
|
|
|
struct stat st_buf;
|
2022-01-09 19:34:49 +01:00
|
|
|
|
case SSL_CHECK_NONE:
|
|
|
|
|
break;
|
2005-08-25 10:17:10 +02:00
|
|
|
|
case SSL_CHECK_BASIC:
|
|
|
|
|
if (!SSL_CTX_load_verify_locations(conn->ssl_ctx_h, check_store,
|
2022-03-10 13:52:03 +01:00
|
|
|
|
NULL)) {
|
|
|
|
|
mylog(LOG_ERROR,
|
|
|
|
|
"Can't assign check store to "
|
|
|
|
|
"SSL connection! Proceeding without!");
|
2005-08-25 10:17:10 +02:00
|
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
case SSL_CHECK_CA:
|
2014-09-20 03:04:53 +02:00
|
|
|
|
if (!check_store) {
|
|
|
|
|
if (SSL_CTX_set_default_verify_paths(conn->ssl_ctx_h)) {
|
2022-03-10 13:52:03 +01:00
|
|
|
|
mylog(LOG_INFO,
|
|
|
|
|
"No SSL certificate check store configured. "
|
|
|
|
|
"Default store will be used.");
|
2014-09-20 03:04:53 +02:00
|
|
|
|
break;
|
|
|
|
|
} else {
|
2022-03-10 13:52:03 +01:00
|
|
|
|
mylog(LOG_ERROR,
|
|
|
|
|
"No SSL certificate check store configured "
|
|
|
|
|
"and cannot use default store!");
|
2014-09-20 03:04:53 +02:00
|
|
|
|
return conn;
|
|
|
|
|
}
|
|
|
|
|
}
|
2014-09-19 22:01:53 +02:00
|
|
|
|
// Check if check_store is a file or directory
|
|
|
|
|
if (stat(check_store, &st_buf) == 0) {
|
|
|
|
|
if (st_buf.st_mode & S_IFDIR) {
|
2022-03-10 13:52:03 +01:00
|
|
|
|
if (!SSL_CTX_load_verify_locations(
|
|
|
|
|
conn->ssl_ctx_h, NULL,
|
|
|
|
|
check_store)) {
|
|
|
|
|
mylog(LOG_ERROR,
|
|
|
|
|
"Can't assign check store to "
|
|
|
|
|
"SSL connection!");
|
2014-09-19 22:01:53 +02:00
|
|
|
|
return conn;
|
|
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
if (st_buf.st_mode & S_IFREG) {
|
2022-03-10 13:52:03 +01:00
|
|
|
|
if (!SSL_CTX_load_verify_locations(
|
|
|
|
|
conn->ssl_ctx_h, check_store,
|
|
|
|
|
NULL)) {
|
|
|
|
|
mylog(LOG_ERROR,
|
|
|
|
|
"Can't assign check store to "
|
|
|
|
|
"SSL connection!");
|
2014-09-19 22:01:53 +02:00
|
|
|
|
return conn;
|
|
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
}
|
2022-03-10 13:52:03 +01:00
|
|
|
|
mylog(LOG_ERROR,
|
|
|
|
|
"Specified SSL certificate check store is neither "
|
|
|
|
|
"a file nor a directory.");
|
2005-08-25 10:17:10 +02:00
|
|
|
|
return conn;
|
|
|
|
|
}
|
2022-03-10 13:52:03 +01:00
|
|
|
|
mylog(LOG_ERROR,
|
|
|
|
|
"Can't open SSL certificate check store! Check path "
|
|
|
|
|
"and permissions.");
|
2014-09-19 22:01:53 +02:00
|
|
|
|
return conn;
|
2022-01-09 21:20:49 +01:00
|
|
|
|
default:
|
|
|
|
|
fatal("Unknown SSL cert check mode.");
|
2005-06-04 13:05:54 +02:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
switch (conn->ssl_check_mode) {
|
|
|
|
|
case SSL_CHECK_NONE:
|
|
|
|
|
SSL_CTX_set_verify(conn->ssl_ctx_h, SSL_VERIFY_NONE, NULL);
|
|
|
|
|
break;
|
|
|
|
|
case SSL_CHECK_BASIC:
|
|
|
|
|
SSL_CTX_set_verify(conn->ssl_ctx_h, SSL_VERIFY_PEER,
|
2022-03-10 13:52:03 +01:00
|
|
|
|
bip_ssl_verify_callback);
|
2009-07-02 18:05:51 +02:00
|
|
|
|
/* SSL_CTX_set_verify_depth(conn->ssl_ctx_h, 0); */
|
2005-06-04 13:05:54 +02:00
|
|
|
|
break;
|
|
|
|
|
case SSL_CHECK_CA:
|
|
|
|
|
SSL_CTX_set_verify(conn->ssl_ctx_h, SSL_VERIFY_PEER,
|
2022-03-10 13:52:03 +01:00
|
|
|
|
bip_ssl_verify_callback);
|
2005-06-04 13:05:54 +02:00
|
|
|
|
break;
|
|
|
|
|
default:
|
|
|
|
|
fatal("Unknown SSL cert check mode.");
|
|
|
|
|
}
|
2007-02-08 23:53:48 +01:00
|
|
|
|
|
2008-01-20 18:49:44 +01:00
|
|
|
|
if (ssl_client_certfile) {
|
|
|
|
|
if (!SSL_CTX_use_certificate_chain_file(conn->ssl_ctx_h,
|
2022-03-10 13:52:03 +01:00
|
|
|
|
ssl_client_certfile))
|
2008-01-20 18:49:44 +01:00
|
|
|
|
mylog(LOG_WARN, "SSL: Unable to load certificate file");
|
|
|
|
|
else if (!SSL_CTX_use_PrivateKey_file(conn->ssl_ctx_h,
|
2022-03-10 13:52:03 +01:00
|
|
|
|
ssl_client_certfile,
|
|
|
|
|
SSL_FILETYPE_PEM))
|
2008-01-20 18:49:44 +01:00
|
|
|
|
mylog(LOG_WARN, "SSL: Unable to load key file");
|
|
|
|
|
else
|
2022-03-10 13:52:03 +01:00
|
|
|
|
mylog(LOG_INFO,
|
|
|
|
|
"SSL: using %s pem file as client SSL "
|
|
|
|
|
"certificate",
|
|
|
|
|
ssl_client_certfile);
|
2008-01-20 18:49:44 +01:00
|
|
|
|
}
|
|
|
|
|
|
2005-06-04 13:05:54 +02:00
|
|
|
|
conn->ssl_h = SSL_new(conn->ssl_ctx_h);
|
2005-04-28 10:26:44 +02:00
|
|
|
|
if (conn->ssl_h == NULL) {
|
2007-09-26 21:22:44 +02:00
|
|
|
|
mylog(LOG_ERROR, "Unable to allocate SSL structures");
|
2005-04-28 10:26:44 +02:00
|
|
|
|
return conn;
|
|
|
|
|
}
|
2005-06-04 13:05:54 +02:00
|
|
|
|
/* ys: useless as long as we have a context by connection
|
2005-04-28 10:26:44 +02:00
|
|
|
|
if (sslctx->session_cache_head)
|
|
|
|
|
if (!SSL_set_session(conn->ssl_h, sslctx->session_cache_head))
|
2007-09-26 21:22:44 +02:00
|
|
|
|
mylog(LOG_ERROR, "unable to set SSL session id to"
|
2005-04-28 10:26:44 +02:00
|
|
|
|
" most recent used");
|
2005-06-04 13:05:54 +02:00
|
|
|
|
*/
|
2005-04-28 10:26:44 +02:00
|
|
|
|
SSL_set_connect_state(conn->ssl_h);
|
2005-11-16 19:34:25 +01:00
|
|
|
|
|
2005-06-04 13:05:54 +02:00
|
|
|
|
/* Put our connection_t in the SSL object for the verify callback */
|
|
|
|
|
SSL_set_ex_data(conn->ssl_h, ssl_cx_idx, conn);
|
2005-11-16 19:34:25 +01:00
|
|
|
|
|
2005-04-28 10:26:44 +02:00
|
|
|
|
create_socket(dsthostname, dstport, srchostname, srcport, conn);
|
|
|
|
|
|
|
|
|
|
return conn;
|
|
|
|
|
}
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
connection_t *connection_new(char *dsthostname, int dstport, char *srchostname,
|
2022-03-10 13:52:03 +01:00
|
|
|
|
int srcport, int ssl, char *ssl_ciphers,
|
|
|
|
|
int ssl_check_mode, char *ssl_check_store,
|
|
|
|
|
char *ssl_client_certfile, time_t timeout)
|
2005-04-28 10:26:44 +02:00
|
|
|
|
{
|
|
|
|
|
char dstportbuf[20], srcportbuf[20], *tmp;
|
2005-08-25 10:17:10 +02:00
|
|
|
|
#ifndef HAVE_LIBSSL
|
|
|
|
|
(void)ssl;
|
2016-04-13 01:04:33 +02:00
|
|
|
|
(void)ssl_ciphers;
|
2005-08-25 10:17:10 +02:00
|
|
|
|
(void)ssl_check_mode;
|
|
|
|
|
(void)ssl_check_store;
|
2013-11-04 08:49:06 +01:00
|
|
|
|
(void)ssl_client_certfile;
|
2005-08-25 10:17:10 +02:00
|
|
|
|
#endif
|
2005-04-28 10:26:44 +02:00
|
|
|
|
/* TODO: allow litteral service name in the function interface */
|
2022-01-09 21:20:49 +01:00
|
|
|
|
if (snprintf(dstportbuf, (size_t)20, "%d", dstport) >= 20)
|
2005-04-28 10:26:44 +02:00
|
|
|
|
dstportbuf[19] = '\0';
|
|
|
|
|
if (srcport) {
|
2022-01-09 21:20:49 +01:00
|
|
|
|
if (snprintf(srcportbuf, (size_t)20, "%d", srcport) >= 20)
|
2005-04-28 10:26:44 +02:00
|
|
|
|
srcportbuf[19] = '\0';
|
|
|
|
|
tmp = srcportbuf;
|
|
|
|
|
} else
|
|
|
|
|
tmp = NULL;
|
|
|
|
|
#ifdef HAVE_LIBSSL
|
|
|
|
|
if (ssl)
|
|
|
|
|
return _connection_new_SSL(dsthostname, dstportbuf, srchostname,
|
2022-03-10 13:52:03 +01:00
|
|
|
|
tmp, ssl_ciphers, ssl_check_mode,
|
|
|
|
|
ssl_check_store, ssl_client_certfile,
|
|
|
|
|
timeout);
|
2005-04-28 10:26:44 +02:00
|
|
|
|
else
|
|
|
|
|
#endif
|
|
|
|
|
return _connection_new(dsthostname, dstportbuf, srchostname,
|
2022-03-10 13:52:03 +01:00
|
|
|
|
tmp, timeout);
|
2005-04-28 10:26:44 +02:00
|
|
|
|
}
|
|
|
|
|
|
2007-02-08 23:53:48 +01:00
|
|
|
|
int cn_is_listening(connection_t *cn)
|
2005-04-28 10:26:44 +02:00
|
|
|
|
{
|
|
|
|
|
if (cn == NULL)
|
|
|
|
|
return 0;
|
|
|
|
|
else
|
|
|
|
|
return cn->listening;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* returns 1 if connection must be notified */
|
|
|
|
|
static int connection_timedout(connection_t *cn)
|
|
|
|
|
{
|
|
|
|
|
if (cn_is_connected(cn) || !cn->timeout)
|
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
|
|
if (!cn->connecting_data)
|
|
|
|
|
fatal("connection_timedout called with no connecting_data!\n");
|
2007-02-10 15:05:37 +01:00
|
|
|
|
|
|
|
|
|
if (time(NULL) - cn->connect_time > cn->timeout) {
|
2005-04-28 10:26:44 +02:00
|
|
|
|
/* connect() completion timed out */
|
2007-02-10 15:05:37 +01:00
|
|
|
|
close(cn->handle);
|
|
|
|
|
cn->handle = -1;
|
2005-04-28 10:26:44 +02:00
|
|
|
|
connect_trynext(cn);
|
|
|
|
|
if (!cn_is_new(cn) && cn->connected != CONN_NEED_SSLIZE)
|
|
|
|
|
return 1;
|
|
|
|
|
}
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static int socket_set_nonblock(int s)
|
|
|
|
|
{
|
2007-06-14 10:48:04 +02:00
|
|
|
|
int flags;
|
|
|
|
|
|
|
|
|
|
if ((flags = fcntl(s, F_GETFL, 0)) < 0) {
|
2022-03-10 13:52:03 +01:00
|
|
|
|
mylog(LOG_ERROR, "Cannot set socket %d to non blocking : %s", s,
|
|
|
|
|
strerror(errno));
|
2007-06-14 10:48:04 +02:00
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (fcntl(s, F_SETFL, flags | O_NONBLOCK) < 0) {
|
2022-03-10 13:52:03 +01:00
|
|
|
|
mylog(LOG_ERROR, "Cannot set socket %d to non blocking : %s", s,
|
|
|
|
|
strerror(errno));
|
2005-04-28 10:26:44 +02:00
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
return 1;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#ifdef TEST
|
2022-03-10 13:52:03 +01:00
|
|
|
|
int main(int argc, char *argv[])
|
2005-04-28 10:26:44 +02:00
|
|
|
|
{
|
|
|
|
|
connection_t *conn, *conn2;
|
|
|
|
|
int s, cont = 1;
|
|
|
|
|
|
|
|
|
|
if (argc != 3) {
|
2022-03-10 13:52:03 +01:00
|
|
|
|
fprintf(stderr, "Usage: %s host port\n", argv[0]);
|
2005-04-28 10:26:44 +02:00
|
|
|
|
exit(1);
|
|
|
|
|
}
|
2022-01-09 20:59:59 +01:00
|
|
|
|
conn = connection_init(0, 0, (time_t)0, 1);
|
2005-04-28 10:26:44 +02:00
|
|
|
|
conn->connect_time = time(NULL);
|
2022-03-10 13:52:03 +01:00
|
|
|
|
create_listening_socket(argv[1], argv[2], &conn);
|
2005-04-28 10:26:44 +02:00
|
|
|
|
if (s == -1) {
|
|
|
|
|
mylog(LOG_ERROR, "socket() : %s", strerror(errno));
|
|
|
|
|
exit(1);
|
|
|
|
|
}
|
2022-03-10 13:52:03 +01:00
|
|
|
|
mylog(LOG_DEBUG, "Socket number %d", s);
|
2005-04-28 10:26:44 +02:00
|
|
|
|
|
|
|
|
|
while (cont) {
|
|
|
|
|
conn2 = accept_new(conn);
|
|
|
|
|
if (conn2) {
|
2005-05-12 10:29:27 +02:00
|
|
|
|
mylog(LOG_DEBUG, "New client");
|
2005-04-28 10:26:44 +02:00
|
|
|
|
cont = 0;
|
|
|
|
|
}
|
|
|
|
|
sleep(1);
|
|
|
|
|
}
|
|
|
|
|
while (1) {
|
|
|
|
|
int ret = read_socket(conn2);
|
2022-03-10 13:52:03 +01:00
|
|
|
|
mylog(LOG_DEBUGTOOMUCH, "READ: %d %*s", ret, conn2->incoming,
|
|
|
|
|
conn2->incoming_end);
|
2005-04-28 10:26:44 +02:00
|
|
|
|
conn2->incoming_end = 0;
|
|
|
|
|
sleep(1);
|
|
|
|
|
}
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
2007-02-08 23:53:48 +01:00
|
|
|
|
#endif
|
2005-04-28 10:26:44 +02:00
|
|
|
|
|
2022-01-09 20:59:59 +01:00
|
|
|
|
uint16_t connection_localport(connection_t *cn)
|
2005-05-11 16:09:20 +02:00
|
|
|
|
{
|
|
|
|
|
struct sockaddr_in addr;
|
2005-05-13 10:43:50 +02:00
|
|
|
|
int err;
|
|
|
|
|
socklen_t addrlen;
|
2007-02-08 23:53:48 +01:00
|
|
|
|
|
2005-05-11 16:09:20 +02:00
|
|
|
|
if (cn->handle <= 0)
|
2022-01-09 20:59:59 +01:00
|
|
|
|
return 0;
|
2007-02-08 23:53:48 +01:00
|
|
|
|
|
2005-05-11 16:09:20 +02:00
|
|
|
|
addrlen = sizeof(addr);
|
|
|
|
|
err = getsockname(cn->handle, (struct sockaddr *)&addr, &addrlen);
|
|
|
|
|
if (err != 0) {
|
|
|
|
|
mylog(LOG_ERROR, "in getsockname(%d): %s", cn->handle,
|
2022-03-10 13:52:03 +01:00
|
|
|
|
strerror(errno));
|
2022-01-09 20:59:59 +01:00
|
|
|
|
return 0;
|
2005-05-11 16:09:20 +02:00
|
|
|
|
}
|
|
|
|
|
|
2022-01-09 20:37:55 +01:00
|
|
|
|
// ntohs() expects uint16_t, while sockaddr_in.sin_port is an in_port_t...
|
|
|
|
|
#pragma GCC diagnostic push
|
|
|
|
|
#pragma GCC diagnostic ignored "-Wtraditional-conversion"
|
2005-05-11 16:09:20 +02:00
|
|
|
|
return ntohs(addr.sin_port);
|
2022-01-09 20:37:55 +01:00
|
|
|
|
#pragma GCC diagnostic pop
|
2005-05-11 16:09:20 +02:00
|
|
|
|
}
|
|
|
|
|
|
2022-01-09 20:59:59 +01:00
|
|
|
|
uint16_t connection_remoteport(connection_t *cn)
|
2005-05-11 16:09:20 +02:00
|
|
|
|
{
|
|
|
|
|
struct sockaddr_in addr;
|
2005-05-13 10:43:50 +02:00
|
|
|
|
int err;
|
|
|
|
|
socklen_t addrlen;
|
2006-09-23 16:13:27 +02:00
|
|
|
|
|
2005-05-11 16:09:20 +02:00
|
|
|
|
if (cn->handle <= 0)
|
2022-01-09 20:59:59 +01:00
|
|
|
|
return 0;
|
2006-09-23 16:13:27 +02:00
|
|
|
|
|
2005-05-11 16:09:20 +02:00
|
|
|
|
addrlen = sizeof(addr);
|
|
|
|
|
err = getpeername(cn->handle, (struct sockaddr *)&addr, &addrlen);
|
|
|
|
|
if (err != 0) {
|
|
|
|
|
mylog(LOG_ERROR, "in getpeername(%d): %s", cn->handle,
|
2022-03-10 13:52:03 +01:00
|
|
|
|
strerror(errno));
|
2022-01-09 20:59:59 +01:00
|
|
|
|
return 0;
|
2005-05-11 16:09:20 +02:00
|
|
|
|
}
|
|
|
|
|
|
2022-01-09 20:37:55 +01:00
|
|
|
|
// ntohs() expects uint16_t, while sockaddr_in.sin_port is an in_port_t...
|
|
|
|
|
#pragma GCC diagnostic push
|
|
|
|
|
#pragma GCC diagnostic ignored "-Wtraditional-conversion"
|
2005-05-11 16:09:20 +02:00
|
|
|
|
return ntohs(addr.sin_port);
|
2022-01-09 20:37:55 +01:00
|
|
|
|
#pragma GCC diagnostic pop
|
2005-05-11 16:09:20 +02:00
|
|
|
|
}
|
|
|
|
|
|
2006-09-23 16:13:27 +02:00
|
|
|
|
static char *socket_ip(int fd, int remote)
|
2005-05-11 16:09:20 +02:00
|
|
|
|
{
|
2006-09-23 16:13:27 +02:00
|
|
|
|
struct sockaddr addr;
|
|
|
|
|
struct sockaddr_in addr4;
|
|
|
|
|
struct sockaddr_in6 addr6;
|
|
|
|
|
socklen_t addrlen;
|
|
|
|
|
socklen_t addrlen4;
|
|
|
|
|
socklen_t addrlen6;
|
2005-05-13 10:43:50 +02:00
|
|
|
|
int err;
|
2005-05-11 16:09:20 +02:00
|
|
|
|
char *ip;
|
|
|
|
|
const char *ret;
|
2006-09-23 16:13:27 +02:00
|
|
|
|
|
|
|
|
|
if (fd <= 0)
|
2005-05-11 16:09:20 +02:00
|
|
|
|
return NULL;
|
2006-09-23 16:13:27 +02:00
|
|
|
|
|
2005-05-11 16:09:20 +02:00
|
|
|
|
addrlen = sizeof(addr);
|
2006-09-23 16:13:27 +02:00
|
|
|
|
|
2007-02-08 20:12:20 +01:00
|
|
|
|
/* getsockname every time to get IP version */
|
|
|
|
|
err = getsockname(fd, (struct sockaddr *)&addr, &addrlen);
|
|
|
|
|
if (err != 0) {
|
2022-03-10 13:52:03 +01:00
|
|
|
|
mylog(LOG_ERROR, "in getsockname(%d): %s", fd, strerror(errno));
|
2007-02-08 20:12:20 +01:00
|
|
|
|
return NULL;
|
2005-05-11 16:09:20 +02:00
|
|
|
|
}
|
|
|
|
|
|
2022-01-09 21:20:49 +01:00
|
|
|
|
ip = bip_malloc((size_t)65);
|
2005-05-11 16:09:20 +02:00
|
|
|
|
|
2006-09-23 16:13:27 +02:00
|
|
|
|
switch (addr.sa_family) {
|
|
|
|
|
case AF_INET:
|
|
|
|
|
addrlen4 = sizeof(addr4);
|
2007-02-08 20:12:20 +01:00
|
|
|
|
|
|
|
|
|
if (remote) {
|
|
|
|
|
err = getpeername(fd, (struct sockaddr *)&addr4,
|
2022-03-10 13:52:03 +01:00
|
|
|
|
&addrlen4);
|
2007-02-08 20:12:20 +01:00
|
|
|
|
if (err != 0) {
|
|
|
|
|
mylog(LOG_ERROR, "in getpeername(%d): %s", fd,
|
2022-03-10 13:52:03 +01:00
|
|
|
|
strerror(errno));
|
2007-02-08 20:12:20 +01:00
|
|
|
|
free(ip);
|
|
|
|
|
return NULL;
|
|
|
|
|
}
|
|
|
|
|
} else {
|
|
|
|
|
err = getsockname(fd, (struct sockaddr *)&addr4,
|
2022-03-10 13:52:03 +01:00
|
|
|
|
&addrlen4);
|
2007-02-08 20:12:20 +01:00
|
|
|
|
if (err != 0) {
|
|
|
|
|
mylog(LOG_ERROR, "in getsockname(%d): %s", fd,
|
2022-03-10 13:52:03 +01:00
|
|
|
|
strerror(errno));
|
2007-02-08 20:12:20 +01:00
|
|
|
|
free(ip);
|
|
|
|
|
return NULL;
|
|
|
|
|
}
|
2006-09-23 16:13:27 +02:00
|
|
|
|
}
|
|
|
|
|
ret = inet_ntop(AF_INET, &(addr4.sin_addr.s_addr), ip, 64);
|
|
|
|
|
if (ret == NULL) {
|
|
|
|
|
mylog(LOG_ERROR, "in inet_ntop: %s", strerror(errno));
|
|
|
|
|
free(ip);
|
|
|
|
|
return NULL;
|
|
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
case AF_INET6:
|
|
|
|
|
addrlen6 = sizeof(addr6);
|
2007-02-08 23:53:48 +01:00
|
|
|
|
|
2007-02-08 20:12:20 +01:00
|
|
|
|
if (remote) {
|
|
|
|
|
err = getpeername(fd, (struct sockaddr *)&addr6,
|
2022-03-10 13:52:03 +01:00
|
|
|
|
&addrlen6);
|
2007-02-08 20:12:20 +01:00
|
|
|
|
if (err != 0) {
|
|
|
|
|
mylog(LOG_ERROR, "in getpeername(%d): %s", fd,
|
2022-03-10 13:52:03 +01:00
|
|
|
|
strerror(errno));
|
2007-02-08 20:12:20 +01:00
|
|
|
|
free(ip);
|
|
|
|
|
return NULL;
|
|
|
|
|
}
|
|
|
|
|
} else {
|
|
|
|
|
err = getsockname(fd, (struct sockaddr *)&addr6,
|
2022-03-10 13:52:03 +01:00
|
|
|
|
&addrlen6);
|
2007-02-08 20:12:20 +01:00
|
|
|
|
if (err != 0) {
|
|
|
|
|
mylog(LOG_ERROR, "in getsockname(%d): %s", fd,
|
2022-03-10 13:52:03 +01:00
|
|
|
|
strerror(errno));
|
2007-02-08 20:12:20 +01:00
|
|
|
|
free(ip);
|
|
|
|
|
return NULL;
|
|
|
|
|
}
|
2006-09-23 16:13:27 +02:00
|
|
|
|
}
|
|
|
|
|
ret = inet_ntop(AF_INET6, &(addr6.sin6_addr), ip, 64);
|
|
|
|
|
if (ret == NULL) {
|
|
|
|
|
mylog(LOG_ERROR, "in inet_ntop: %s", strerror(errno));
|
|
|
|
|
free(ip);
|
|
|
|
|
return NULL;
|
|
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
default:
|
|
|
|
|
mylog(LOG_ERROR, "Unknown socket family, that's bad.");
|
|
|
|
|
free(ip);
|
2005-05-11 16:09:20 +02:00
|
|
|
|
return NULL;
|
|
|
|
|
}
|
|
|
|
|
return ip;
|
|
|
|
|
}
|
|
|
|
|
|
2006-09-23 16:13:27 +02:00
|
|
|
|
char *connection_localip(connection_t *cn)
|
2005-05-11 16:09:20 +02:00
|
|
|
|
{
|
|
|
|
|
if (cn->handle <= 0)
|
|
|
|
|
return NULL;
|
|
|
|
|
|
2006-09-23 16:13:27 +02:00
|
|
|
|
return socket_ip(cn->handle, 0);
|
|
|
|
|
}
|
2005-05-11 16:09:20 +02:00
|
|
|
|
|
2006-09-23 16:13:27 +02:00
|
|
|
|
char *connection_remoteip(connection_t *cn)
|
|
|
|
|
{
|
|
|
|
|
if (cn->handle <= 0)
|
2005-05-11 16:09:20 +02:00
|
|
|
|
return NULL;
|
2006-09-23 16:13:27 +02:00
|
|
|
|
|
|
|
|
|
return socket_ip(cn->handle, 1);
|
2005-05-11 16:09:20 +02:00
|
|
|
|
}
|