Compare commits
37 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| f42ecedd42 | |||
| 63a7980329 | |||
| bc54bf520d | |||
| 11aaf1b325 | |||
| 5ca07656a1 | |||
| f20c6fb28e | |||
| 1613e75a48 | |||
| abd892cbd7 | |||
| 4ae95be9db | |||
| 328bf9af1e | |||
| ce83f8244c | |||
| 8a8ff11887 | |||
| 131aee6f08 | |||
| 07f6d0b350 | |||
| 1cc8656368 | |||
| 4c81112840 | |||
| 5dda5661ae | |||
| 628facf286 | |||
| 7225b68f74 | |||
| e188de5501 | |||
| cdf6544c94 | |||
| a28528d260 | |||
| 27f185e8aa | |||
| d207c90577 | |||
| 2afc9f99c3 | |||
| 4ab247ead0 | |||
| 1dd464f35c | |||
| 955b3728a3 | |||
| aa77bc41d0 | |||
| 5b208547c4 | |||
| c8890953b3 | |||
| cfc78ffdf0 | |||
| 637a3d2bf7 | |||
| a912b3f28c | |||
| 27cd8b3a63 | |||
| 2bde385dc7 | |||
| 74c9759932 |
@@ -14,7 +14,7 @@ endif ("${CMAKE_C_COMPILER_ID}" MATCHES "GNU" OR CMAKE_COMPILER_IS_GNUC)
|
|||||||
# Version
|
# Version
|
||||||
set (project_VERSION_MAJOR "0")
|
set (project_VERSION_MAJOR "0")
|
||||||
set (project_VERSION_MINOR "9")
|
set (project_VERSION_MINOR "9")
|
||||||
set (project_VERSION_PATCH "0")
|
set (project_VERSION_PATCH "1")
|
||||||
|
|
||||||
set (project_VERSION "${project_VERSION_MAJOR}")
|
set (project_VERSION "${project_VERSION_MAJOR}")
|
||||||
set (project_VERSION "${project_VERSION}.${project_VERSION_MINOR}")
|
set (project_VERSION "${project_VERSION}.${project_VERSION_MINOR}")
|
||||||
@@ -27,18 +27,26 @@ pkg_check_modules (libssl REQUIRED libssl libcrypto)
|
|||||||
pkg_check_modules (ncursesw ncursesw)
|
pkg_check_modules (ncursesw ncursesw)
|
||||||
|
|
||||||
if ("${CMAKE_SYSTEM_NAME}" MATCHES "BSD")
|
if ("${CMAKE_SYSTEM_NAME}" MATCHES "BSD")
|
||||||
# iconv() doesn't have to be present in libc
|
include_directories(/usr/local/include)
|
||||||
# FIXME: detect if we need the library independently on the platform
|
link_directories(/usr/local/lib)
|
||||||
list (APPEND project_libraries iconv)
|
# Need this for SIGWINCH in FreeBSD and OpenBSD respectively;
|
||||||
# Need this for SIGWINCH; our POSIX version macros make it undefined
|
# our POSIX version macros make it undefined
|
||||||
add_definitions (-D__BSD_VISIBLE=1)
|
add_definitions (-D__BSD_VISIBLE=1 -D_BSD_SOURCE=1)
|
||||||
endif ("${CMAKE_SYSTEM_NAME}" MATCHES "BSD")
|
endif ("${CMAKE_SYSTEM_NAME}" MATCHES "BSD")
|
||||||
|
|
||||||
|
list (APPEND project_libraries ${libssl_LIBRARIES})
|
||||||
|
include_directories (${libssl_INCLUDE_DIRS})
|
||||||
|
link_directories (${libssl_LIBRARY_DIRS})
|
||||||
|
|
||||||
# -lpthread is only there for debugging (gdb & errno)
|
# -lpthread is only there for debugging (gdb & errno)
|
||||||
# -lrt is only for glibc < 2.17
|
# -lrt is only for glibc < 2.17
|
||||||
list (APPEND project_libraries ${libssl_LIBRARIES} rt pthread)
|
# -liconv may or may not be a part of libc
|
||||||
include_directories (${libssl_INCLUDE_DIRS})
|
foreach (extra iconv rt pthread)
|
||||||
link_directories (${libssl_LIBRARY_DIRS})
|
find_library (extra_lib_${extra} ${extra})
|
||||||
|
if (extra_lib_${extra})
|
||||||
|
list (APPEND project_libraries ${extra})
|
||||||
|
endif (extra_lib_${extra})
|
||||||
|
endforeach (extra)
|
||||||
|
|
||||||
if (ncursesw_FOUND)
|
if (ncursesw_FOUND)
|
||||||
list (APPEND project_libraries ${ncursesw_LIBRARIES})
|
list (APPEND project_libraries ${ncursesw_LIBRARIES})
|
||||||
@@ -53,7 +61,13 @@ endif (ncursesw_FOUND)
|
|||||||
if ((WANT_READLINE AND WANT_LIBEDIT) OR (NOT WANT_READLINE AND NOT WANT_LIBEDIT))
|
if ((WANT_READLINE AND WANT_LIBEDIT) OR (NOT WANT_READLINE AND NOT WANT_LIBEDIT))
|
||||||
message (SEND_ERROR "You have to choose either GNU Readline or libedit")
|
message (SEND_ERROR "You have to choose either GNU Readline or libedit")
|
||||||
elseif (WANT_READLINE)
|
elseif (WANT_READLINE)
|
||||||
list (APPEND project_libraries readline)
|
# OpenBSD's default readline is too old
|
||||||
|
if ("${CMAKE_SYSTEM_NAME}" MATCHES "OpenBSD")
|
||||||
|
include_directories (/usr/local/include/ereadline)
|
||||||
|
list (APPEND project_libraries ereadline)
|
||||||
|
else ("${CMAKE_SYSTEM_NAME}" MATCHES "OpenBSD")
|
||||||
|
list (APPEND project_libraries readline)
|
||||||
|
endif ("${CMAKE_SYSTEM_NAME}" MATCHES "OpenBSD")
|
||||||
elseif (WANT_LIBEDIT)
|
elseif (WANT_LIBEDIT)
|
||||||
pkg_check_modules (libedit REQUIRED libedit)
|
pkg_check_modules (libedit REQUIRED libedit)
|
||||||
list (APPEND project_libraries ${libedit_LIBRARIES})
|
list (APPEND project_libraries ${libedit_LIBRARIES})
|
||||||
|
|||||||
31
NEWS
Normal file
31
NEWS
Normal file
@@ -0,0 +1,31 @@
|
|||||||
|
0.9.1 (2015-09-25)
|
||||||
|
|
||||||
|
* All "ssl" options have been renamed to "tls"
|
||||||
|
|
||||||
|
* The project now builds on OpenBSD
|
||||||
|
|
||||||
|
* Pulled in kqueue support
|
||||||
|
|
||||||
|
* degesch: added backlog/scrollback functionality using less(1)
|
||||||
|
|
||||||
|
* degesch: made showing the entire set of channel mode user prefixes optional
|
||||||
|
|
||||||
|
* degesch: nicknames in /names are now ordered
|
||||||
|
|
||||||
|
* degesch: nicknames now use the 256-color terminal palette if available
|
||||||
|
|
||||||
|
* degesch: now we skip entries in the "addresses" list that can't be resolved
|
||||||
|
to an address, along with displaying a more helpful message
|
||||||
|
|
||||||
|
* degesch: joins, parts, nick changes and quits don't count as new buffer
|
||||||
|
activity anymore
|
||||||
|
|
||||||
|
* degesch: add Meta-H to open the full log file
|
||||||
|
|
||||||
|
* degesch: various bugfixes and little improvements
|
||||||
|
|
||||||
|
|
||||||
|
0.9.0 (2015-07-23)
|
||||||
|
|
||||||
|
* Initial release
|
||||||
|
|
||||||
2
README
2
README
@@ -30,7 +30,7 @@ a small network of respectful users (or bots), or testing, this one will do it.
|
|||||||
Notable features:
|
Notable features:
|
||||||
- TLS autodetection (why doesn't everyone have this?)
|
- TLS autodetection (why doesn't everyone have this?)
|
||||||
- IRCop authentication through TLS client certificates
|
- IRCop authentication through TLS client certificates
|
||||||
- epoll support on Linux; it should be able to handle quite a number of users
|
- epoll/kqueue support; it should be able to handle quite a number of users
|
||||||
- partial IRCv3 support
|
- partial IRCv3 support
|
||||||
|
|
||||||
Not supported:
|
Not supported:
|
||||||
|
|||||||
382
common.c
382
common.c
@@ -41,12 +41,6 @@
|
|||||||
return false; \
|
return false; \
|
||||||
BLOCK_END
|
BLOCK_END
|
||||||
|
|
||||||
// A few other debugging shorthands
|
|
||||||
#define LOG_FUNC_FAILURE(name, desc) \
|
|
||||||
print_debug ("%s: %s: %s", __func__, (name), (desc))
|
|
||||||
#define LOG_LIBC_FAILURE(name) \
|
|
||||||
print_debug ("%s: %s: %s", __func__, (name), strerror (errno))
|
|
||||||
|
|
||||||
// --- To be moved to liberty --------------------------------------------------
|
// --- To be moved to liberty --------------------------------------------------
|
||||||
|
|
||||||
static void
|
static void
|
||||||
@@ -90,240 +84,6 @@ log_message_syslog (void *user_data, const char *quote, const char *fmt,
|
|||||||
syslog (prio, "%s%s", quote, buf);
|
syslog (prio, "%s%s", quote, buf);
|
||||||
}
|
}
|
||||||
|
|
||||||
// --- Connector ---------------------------------------------------------------
|
|
||||||
|
|
||||||
// This is a helper that tries to establish a connection with any address on
|
|
||||||
// a given list. Sadly it also introduces a bit of a callback hell.
|
|
||||||
|
|
||||||
struct connector_target
|
|
||||||
{
|
|
||||||
LIST_HEADER (struct connector_target)
|
|
||||||
|
|
||||||
char *hostname; ///< Target hostname or address
|
|
||||||
char *service; ///< Target service name or port
|
|
||||||
|
|
||||||
struct addrinfo *results; ///< Resolved target
|
|
||||||
struct addrinfo *iter; ///< Current endpoint
|
|
||||||
};
|
|
||||||
|
|
||||||
static struct connector_target *
|
|
||||||
connector_target_new (void)
|
|
||||||
{
|
|
||||||
struct connector_target *self = xmalloc (sizeof *self);
|
|
||||||
return self;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void
|
|
||||||
connector_target_destroy (struct connector_target *self)
|
|
||||||
{
|
|
||||||
free (self->hostname);
|
|
||||||
free (self->service);
|
|
||||||
freeaddrinfo (self->results);
|
|
||||||
free (self);
|
|
||||||
}
|
|
||||||
|
|
||||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
|
||||||
|
|
||||||
struct connector
|
|
||||||
{
|
|
||||||
int socket; ///< Socket FD for the connection
|
|
||||||
struct poller_fd connected_event; ///< We've connected or failed
|
|
||||||
struct connector_target *targets; ///< Targets
|
|
||||||
struct connector_target *targets_t; ///< Tail of targets
|
|
||||||
|
|
||||||
void *user_data; ///< User data for callbacks
|
|
||||||
|
|
||||||
// You may destroy the connector object in these two main callbacks:
|
|
||||||
|
|
||||||
/// Connection has been successfully established
|
|
||||||
void (*on_connected) (void *user_data, int socket);
|
|
||||||
/// Failed to establish a connection to either target
|
|
||||||
void (*on_failure) (void *user_data);
|
|
||||||
|
|
||||||
// Optional:
|
|
||||||
|
|
||||||
/// Connecting to a new address
|
|
||||||
void (*on_connecting) (void *user_data, const char *address);
|
|
||||||
/// Connecting to the last address has failed
|
|
||||||
void (*on_error) (void *user_data, const char *error);
|
|
||||||
};
|
|
||||||
|
|
||||||
static void
|
|
||||||
connector_notify_connecting (struct connector *self,
|
|
||||||
struct connector_target *target, struct addrinfo *gai_iter)
|
|
||||||
{
|
|
||||||
if (!self->on_connecting)
|
|
||||||
return;
|
|
||||||
|
|
||||||
const char *real_host = target->hostname;
|
|
||||||
|
|
||||||
// We don't really need this, so we can let it quietly fail
|
|
||||||
char buf[NI_MAXHOST];
|
|
||||||
int err = getnameinfo (gai_iter->ai_addr, gai_iter->ai_addrlen,
|
|
||||||
buf, sizeof buf, NULL, 0, NI_NUMERICHOST);
|
|
||||||
if (err)
|
|
||||||
LOG_FUNC_FAILURE ("getnameinfo", gai_strerror (err));
|
|
||||||
else
|
|
||||||
real_host = buf;
|
|
||||||
|
|
||||||
char *address = format_host_port_pair (real_host, target->service);
|
|
||||||
self->on_connecting (self->user_data, address);
|
|
||||||
free (address);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void
|
|
||||||
connector_notify_error (struct connector *self, const char *error)
|
|
||||||
{
|
|
||||||
if (self->on_error)
|
|
||||||
self->on_error (self->user_data, error);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void
|
|
||||||
connector_prepare_next (struct connector *self)
|
|
||||||
{
|
|
||||||
struct connector_target *target = self->targets;
|
|
||||||
if (!(target->iter = target->iter->ai_next))
|
|
||||||
{
|
|
||||||
LIST_UNLINK_WITH_TAIL (self->targets, self->targets_t, target);
|
|
||||||
connector_target_destroy (target);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static void
|
|
||||||
connector_step (struct connector *self)
|
|
||||||
{
|
|
||||||
struct connector_target *target = self->targets;
|
|
||||||
if (!target)
|
|
||||||
{
|
|
||||||
// Total failure, none of the targets has succeeded
|
|
||||||
self->on_failure (self->user_data);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
struct addrinfo *gai_iter = target->iter;
|
|
||||||
hard_assert (gai_iter != NULL);
|
|
||||||
|
|
||||||
connector_notify_connecting (self, target, gai_iter);
|
|
||||||
|
|
||||||
int fd = socket (gai_iter->ai_family,
|
|
||||||
gai_iter->ai_socktype, gai_iter->ai_protocol);
|
|
||||||
if (fd == -1)
|
|
||||||
{
|
|
||||||
connector_notify_error (self, strerror (errno));
|
|
||||||
|
|
||||||
connector_prepare_next (self);
|
|
||||||
connector_step (self);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
set_cloexec (fd);
|
|
||||||
set_blocking (fd, false);
|
|
||||||
|
|
||||||
int yes = 1;
|
|
||||||
soft_assert (setsockopt (fd, SOL_SOCKET, SO_KEEPALIVE,
|
|
||||||
&yes, sizeof yes) != -1);
|
|
||||||
|
|
||||||
if (!connect (fd, gai_iter->ai_addr, gai_iter->ai_addrlen))
|
|
||||||
{
|
|
||||||
set_blocking (fd, true);
|
|
||||||
self->on_connected (self->user_data, fd);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if (errno != EINPROGRESS)
|
|
||||||
{
|
|
||||||
connector_notify_error (self, strerror (errno));
|
|
||||||
xclose (fd);
|
|
||||||
|
|
||||||
connector_prepare_next (self);
|
|
||||||
connector_step (self);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
self->connected_event.fd = self->socket = fd;
|
|
||||||
poller_fd_set (&self->connected_event, POLLOUT);
|
|
||||||
|
|
||||||
connector_prepare_next (self);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void
|
|
||||||
connector_on_ready (const struct pollfd *pfd, struct connector *self)
|
|
||||||
{
|
|
||||||
// See http://cr.yp.to/docs/connect.html if this doesn't work.
|
|
||||||
// The second connect() method doesn't work with DragonflyBSD.
|
|
||||||
|
|
||||||
int error = 0;
|
|
||||||
socklen_t error_len = sizeof error;
|
|
||||||
hard_assert (!getsockopt (pfd->fd,
|
|
||||||
SOL_SOCKET, SO_ERROR, &error, &error_len));
|
|
||||||
|
|
||||||
if (error)
|
|
||||||
{
|
|
||||||
connector_notify_error (self, strerror (error));
|
|
||||||
|
|
||||||
poller_fd_reset (&self->connected_event);
|
|
||||||
xclose (self->socket);
|
|
||||||
self->socket = -1;
|
|
||||||
|
|
||||||
connector_step (self);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
poller_fd_reset (&self->connected_event);
|
|
||||||
self->socket = -1;
|
|
||||||
|
|
||||||
set_blocking (pfd->fd, true);
|
|
||||||
self->on_connected (self->user_data, pfd->fd);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static void
|
|
||||||
connector_init (struct connector *self, struct poller *poller)
|
|
||||||
{
|
|
||||||
memset (self, 0, sizeof *self);
|
|
||||||
self->socket = -1;
|
|
||||||
poller_fd_init (&self->connected_event, poller, self->socket);
|
|
||||||
self->connected_event.user_data = self;
|
|
||||||
self->connected_event.dispatcher = (poller_fd_fn) connector_on_ready;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void
|
|
||||||
connector_free (struct connector *self)
|
|
||||||
{
|
|
||||||
poller_fd_reset (&self->connected_event);
|
|
||||||
if (self->socket != -1)
|
|
||||||
xclose (self->socket);
|
|
||||||
|
|
||||||
LIST_FOR_EACH (struct connector_target, iter, self->targets)
|
|
||||||
connector_target_destroy (iter);
|
|
||||||
}
|
|
||||||
|
|
||||||
static bool
|
|
||||||
connector_add_target (struct connector *self,
|
|
||||||
const char *hostname, const char *service, struct error **e)
|
|
||||||
{
|
|
||||||
struct addrinfo hints, *results;
|
|
||||||
memset (&hints, 0, sizeof hints);
|
|
||||||
hints.ai_socktype = SOCK_STREAM;
|
|
||||||
|
|
||||||
// TODO: even this should be done asynchronously, most likely in
|
|
||||||
// a thread pool, similarly to how libuv does it
|
|
||||||
int err = getaddrinfo (hostname, service, &hints, &results);
|
|
||||||
if (err)
|
|
||||||
{
|
|
||||||
error_set (e, "%s: %s", "getaddrinfo", gai_strerror (err));
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
struct connector_target *target = connector_target_new ();
|
|
||||||
target->hostname = xstrdup (hostname);
|
|
||||||
target->service = xstrdup (service);
|
|
||||||
target->results = results;
|
|
||||||
target->iter = target->results;
|
|
||||||
|
|
||||||
LIST_APPEND_WITH_TAIL (self->targets, self->targets_t, target);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
// --- SOCKS 5/4a --------------------------------------------------------------
|
// --- SOCKS 5/4a --------------------------------------------------------------
|
||||||
|
|
||||||
// Asynchronous SOCKS connector. Adds more stuff on top of the regular one.
|
// Asynchronous SOCKS connector. Adds more stuff on top of the regular one.
|
||||||
@@ -516,12 +276,11 @@ socks_4a_start (struct socks_connector *self)
|
|||||||
|
|
||||||
struct str *wb = &self->write_buffer;
|
struct str *wb = &self->write_buffer;
|
||||||
str_init (wb);
|
str_init (wb);
|
||||||
str_append_c (wb, 4); // version
|
str_pack_u8 (wb, 4); // version
|
||||||
str_append_c (wb, 1); // connect
|
str_pack_u8 (wb, 1); // connect
|
||||||
|
|
||||||
str_append_c (wb, target->port >> 8); // higher bits of port
|
str_pack_u16 (wb, target->port); // port
|
||||||
str_append_c (wb, target->port); // lower bits of port
|
str_append_data (wb, dest_ipv4, 4); // destination address
|
||||||
str_append_data (wb, dest_ipv4, 4); // destination address
|
|
||||||
|
|
||||||
if (self->username)
|
if (self->username)
|
||||||
str_append (wb, self->username);
|
str_append (wb, self->username);
|
||||||
@@ -613,10 +372,10 @@ socks_5_request_start (struct socks_connector *self)
|
|||||||
{
|
{
|
||||||
struct socks_target *target = self->targets_iter;
|
struct socks_target *target = self->targets_iter;
|
||||||
struct str *wb = &self->write_buffer;
|
struct str *wb = &self->write_buffer;
|
||||||
str_append_c (wb, 0x05); // version
|
str_pack_u8 (wb, 0x05); // version
|
||||||
str_append_c (wb, 0x01); // connect
|
str_pack_u8 (wb, 0x01); // connect
|
||||||
str_append_c (wb, 0x00); // reserved
|
str_pack_u8 (wb, 0x00); // reserved
|
||||||
str_append_c (wb, target->address.type);
|
str_pack_u8 (wb, target->address.type);
|
||||||
|
|
||||||
switch (target->address.type)
|
switch (target->address.type)
|
||||||
{
|
{
|
||||||
@@ -630,7 +389,7 @@ socks_5_request_start (struct socks_connector *self)
|
|||||||
if (dlen > 255)
|
if (dlen > 255)
|
||||||
dlen = 255;
|
dlen = 255;
|
||||||
|
|
||||||
str_append_c (wb, dlen);
|
str_pack_u8 (wb, dlen);
|
||||||
str_append_data (wb, target->address.data.domain, dlen);
|
str_append_data (wb, target->address.data.domain, dlen);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@@ -639,8 +398,7 @@ socks_5_request_start (struct socks_connector *self)
|
|||||||
target->address.data.ipv6, sizeof target->address.data.ipv6);
|
target->address.data.ipv6, sizeof target->address.data.ipv6);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
str_append_c (wb, target->port >> 8);
|
str_pack_u16 (wb, target->port);
|
||||||
str_append_c (wb, target->port);
|
|
||||||
|
|
||||||
SOCKS_GO (socks_5_request_finish, 4);
|
SOCKS_GO (socks_5_request_finish, 4);
|
||||||
}
|
}
|
||||||
@@ -673,10 +431,10 @@ socks_5_userpass_start (struct socks_connector *self)
|
|||||||
plen = 255;
|
plen = 255;
|
||||||
|
|
||||||
struct str *wb = &self->write_buffer;
|
struct str *wb = &self->write_buffer;
|
||||||
str_append_c (wb, 0x01); // version
|
str_pack_u8 (wb, 0x01); // version
|
||||||
str_append_c (wb, ulen); // username length
|
str_pack_u8 (wb, ulen); // username length
|
||||||
str_append_data (wb, self->username, ulen);
|
str_append_data (wb, self->username, ulen);
|
||||||
str_append_c (wb, plen); // password length
|
str_pack_u8 (wb, plen); // password length
|
||||||
str_append_data (wb, self->password, plen);
|
str_append_data (wb, self->password, plen);
|
||||||
|
|
||||||
SOCKS_GO (socks_5_userpass_finish, 2);
|
SOCKS_GO (socks_5_userpass_finish, 2);
|
||||||
@@ -715,11 +473,11 @@ socks_5_auth_start (struct socks_connector *self)
|
|||||||
bool can_auth = self->username && self->password;
|
bool can_auth = self->username && self->password;
|
||||||
|
|
||||||
struct str *wb = &self->write_buffer;
|
struct str *wb = &self->write_buffer;
|
||||||
str_append_c (wb, 0x05); // version
|
str_pack_u8 (wb, 0x05); // version
|
||||||
str_append_c (wb, 1 + can_auth); // number of authentication methods
|
str_pack_u8 (wb, 1 + can_auth); // number of authentication methods
|
||||||
str_append_c (wb, 0x00); // no authentication required
|
str_pack_u8 (wb, 0x00); // no authentication required
|
||||||
if (can_auth)
|
if (can_auth)
|
||||||
str_append_c (wb, 0x02); // username/password
|
str_pack_u8 (wb, 0x02); // username/password
|
||||||
|
|
||||||
SOCKS_GO (socks_5_auth_finish, 2);
|
SOCKS_GO (socks_5_auth_finish, 2);
|
||||||
}
|
}
|
||||||
@@ -1256,7 +1014,7 @@ enum config_item_type
|
|||||||
CONFIG_ITEM_STRING_ARRAY ///< Comma-separated list of strings
|
CONFIG_ITEM_STRING_ARRAY ///< Comma-separated list of strings
|
||||||
};
|
};
|
||||||
|
|
||||||
struct config_item_
|
struct config_item
|
||||||
{
|
{
|
||||||
enum config_item_type type; ///< Type of the item
|
enum config_item_type type; ///< Type of the item
|
||||||
union
|
union
|
||||||
@@ -1282,10 +1040,10 @@ struct config_schema
|
|||||||
|
|
||||||
/// Check if the new value can be accepted.
|
/// Check if the new value can be accepted.
|
||||||
/// In addition to this, "type" and having a default is considered.
|
/// In addition to this, "type" and having a default is considered.
|
||||||
bool (*validate) (const struct config_item_ *, struct error **e);
|
bool (*validate) (const struct config_item *, struct error **e);
|
||||||
|
|
||||||
/// The value has changed
|
/// The value has changed
|
||||||
void (*on_change) (struct config_item_ *);
|
void (*on_change) (struct config_item *);
|
||||||
};
|
};
|
||||||
|
|
||||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||||
@@ -1315,7 +1073,7 @@ config_item_type_is_string (enum config_item_type type)
|
|||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
config_item_free (struct config_item_ *self)
|
config_item_free (struct config_item *self)
|
||||||
{
|
{
|
||||||
switch (self->type)
|
switch (self->type)
|
||||||
{
|
{
|
||||||
@@ -1331,7 +1089,7 @@ config_item_free (struct config_item_ *self)
|
|||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
config_item_destroy (struct config_item_ *self)
|
config_item_destroy (struct config_item *self)
|
||||||
{
|
{
|
||||||
config_item_free (self);
|
config_item_free (self);
|
||||||
free (self);
|
free (self);
|
||||||
@@ -1340,7 +1098,7 @@ config_item_destroy (struct config_item_ *self)
|
|||||||
/// Doesn't do any validations or handle schemas, just moves source data
|
/// Doesn't do any validations or handle schemas, just moves source data
|
||||||
/// to the target item and destroys the source item
|
/// to the target item and destroys the source item
|
||||||
static void
|
static void
|
||||||
config_item_move (struct config_item_ *self, struct config_item_ *source)
|
config_item_move (struct config_item *self, struct config_item *source)
|
||||||
{
|
{
|
||||||
// Not quite sure how to handle that
|
// Not quite sure how to handle that
|
||||||
hard_assert (!source->schema);
|
hard_assert (!source->schema);
|
||||||
@@ -1351,40 +1109,40 @@ config_item_move (struct config_item_ *self, struct config_item_ *source)
|
|||||||
free (source);
|
free (source);
|
||||||
}
|
}
|
||||||
|
|
||||||
static struct config_item_ *
|
static struct config_item *
|
||||||
config_item_new (enum config_item_type type)
|
config_item_new (enum config_item_type type)
|
||||||
{
|
{
|
||||||
struct config_item_ *self = xcalloc (1, sizeof *self);
|
struct config_item *self = xcalloc (1, sizeof *self);
|
||||||
self->type = type;
|
self->type = type;
|
||||||
return self;
|
return self;
|
||||||
}
|
}
|
||||||
|
|
||||||
static struct config_item_ *
|
static struct config_item *
|
||||||
config_item_null (void)
|
config_item_null (void)
|
||||||
{
|
{
|
||||||
return config_item_new (CONFIG_ITEM_NULL);
|
return config_item_new (CONFIG_ITEM_NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
static struct config_item_ *
|
static struct config_item *
|
||||||
config_item_boolean (bool b)
|
config_item_boolean (bool b)
|
||||||
{
|
{
|
||||||
struct config_item_ *self = config_item_new (CONFIG_ITEM_BOOLEAN);
|
struct config_item *self = config_item_new (CONFIG_ITEM_BOOLEAN);
|
||||||
self->value.boolean = b;
|
self->value.boolean = b;
|
||||||
return self;
|
return self;
|
||||||
}
|
}
|
||||||
|
|
||||||
static struct config_item_ *
|
static struct config_item *
|
||||||
config_item_integer (int64_t i)
|
config_item_integer (int64_t i)
|
||||||
{
|
{
|
||||||
struct config_item_ *self = config_item_new (CONFIG_ITEM_INTEGER);
|
struct config_item *self = config_item_new (CONFIG_ITEM_INTEGER);
|
||||||
self->value.integer = i;
|
self->value.integer = i;
|
||||||
return self;
|
return self;
|
||||||
}
|
}
|
||||||
|
|
||||||
static struct config_item_ *
|
static struct config_item *
|
||||||
config_item_string (const struct str *s)
|
config_item_string (const struct str *s)
|
||||||
{
|
{
|
||||||
struct config_item_ *self = config_item_new (CONFIG_ITEM_STRING);
|
struct config_item *self = config_item_new (CONFIG_ITEM_STRING);
|
||||||
str_init (&self->value.string);
|
str_init (&self->value.string);
|
||||||
hard_assert (utf8_validate
|
hard_assert (utf8_validate
|
||||||
(self->value.string.str, self->value.string.len));
|
(self->value.string.str, self->value.string.len));
|
||||||
@@ -1392,29 +1150,29 @@ config_item_string (const struct str *s)
|
|||||||
return self;
|
return self;
|
||||||
}
|
}
|
||||||
|
|
||||||
static struct config_item_ *
|
static struct config_item *
|
||||||
config_item_string_from_cstr (const char *s)
|
config_item_string_from_cstr (const char *s)
|
||||||
{
|
{
|
||||||
struct str tmp;
|
struct str tmp;
|
||||||
str_init (&tmp);
|
str_init (&tmp);
|
||||||
str_append (&tmp, s);
|
str_append (&tmp, s);
|
||||||
struct config_item_ *self = config_item_string (&tmp);
|
struct config_item *self = config_item_string (&tmp);
|
||||||
str_free (&tmp);
|
str_free (&tmp);
|
||||||
return self;
|
return self;
|
||||||
}
|
}
|
||||||
|
|
||||||
static struct config_item_ *
|
static struct config_item *
|
||||||
config_item_string_array (const struct str *s)
|
config_item_string_array (const struct str *s)
|
||||||
{
|
{
|
||||||
struct config_item_ *self = config_item_string (s);
|
struct config_item *self = config_item_string (s);
|
||||||
self->type = CONFIG_ITEM_STRING_ARRAY;
|
self->type = CONFIG_ITEM_STRING_ARRAY;
|
||||||
return self;
|
return self;
|
||||||
}
|
}
|
||||||
|
|
||||||
static struct config_item_ *
|
static struct config_item *
|
||||||
config_item_object (void)
|
config_item_object (void)
|
||||||
{
|
{
|
||||||
struct config_item_ *self = config_item_new (CONFIG_ITEM_OBJECT);
|
struct config_item *self = config_item_new (CONFIG_ITEM_OBJECT);
|
||||||
str_map_init (&self->value.object);
|
str_map_init (&self->value.object);
|
||||||
self->value.object.free = (void (*)(void *)) config_item_destroy;
|
self->value.object.free = (void (*)(void *)) config_item_destroy;
|
||||||
return self;
|
return self;
|
||||||
@@ -1434,7 +1192,7 @@ config_schema_accepts_type
|
|||||||
}
|
}
|
||||||
|
|
||||||
static bool
|
static bool
|
||||||
config_item_validate_by_schema (struct config_item_ *self,
|
config_item_validate_by_schema (struct config_item *self,
|
||||||
struct config_schema *schema, struct error **e)
|
struct config_schema *schema, struct error **e)
|
||||||
{
|
{
|
||||||
struct error *error = NULL;
|
struct error *error = NULL;
|
||||||
@@ -1453,7 +1211,7 @@ config_item_validate_by_schema (struct config_item_ *self,
|
|||||||
}
|
}
|
||||||
|
|
||||||
static bool
|
static bool
|
||||||
config_item_set_from (struct config_item_ *self, struct config_item_ *source,
|
config_item_set_from (struct config_item *self, struct config_item *source,
|
||||||
struct error **e)
|
struct error **e)
|
||||||
{
|
{
|
||||||
struct config_schema *schema = self->schema;
|
struct config_schema *schema = self->schema;
|
||||||
@@ -1480,8 +1238,8 @@ config_item_set_from (struct config_item_ *self, struct config_item_ *source,
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
static struct config_item_ *
|
static struct config_item *
|
||||||
config_item_get (struct config_item_ *self, const char *path, struct error **e)
|
config_item_get (struct config_item *self, const char *path, struct error **e)
|
||||||
{
|
{
|
||||||
hard_assert (self->type == CONFIG_ITEM_OBJECT);
|
hard_assert (self->type == CONFIG_ITEM_OBJECT);
|
||||||
|
|
||||||
@@ -1489,7 +1247,7 @@ config_item_get (struct config_item_ *self, const char *path, struct error **e)
|
|||||||
str_vector_init (&v);
|
str_vector_init (&v);
|
||||||
split_str (path, '.', &v);
|
split_str (path, '.', &v);
|
||||||
|
|
||||||
struct config_item_ *result = NULL;
|
struct config_item *result = NULL;
|
||||||
size_t i = 0;
|
size_t i = 0;
|
||||||
while (true)
|
while (true)
|
||||||
{
|
{
|
||||||
@@ -1519,7 +1277,7 @@ struct config_writer
|
|||||||
};
|
};
|
||||||
|
|
||||||
static void config_item_write_object_innards
|
static void config_item_write_object_innards
|
||||||
(struct config_writer *self, struct config_item_ *object);
|
(struct config_writer *self, struct config_item *object);
|
||||||
|
|
||||||
static void
|
static void
|
||||||
config_item_write_string (struct str *output, const struct str *s)
|
config_item_write_string (struct str *output, const struct str *s)
|
||||||
@@ -1541,7 +1299,7 @@ config_item_write_string (struct str *output, const struct str *s)
|
|||||||
|
|
||||||
static void
|
static void
|
||||||
config_item_write_object
|
config_item_write_object
|
||||||
(struct config_writer *self, struct config_item_ *value)
|
(struct config_writer *self, struct config_item *value)
|
||||||
{
|
{
|
||||||
char indent[self->indent + 1];
|
char indent[self->indent + 1];
|
||||||
memset (indent, '\t', self->indent);
|
memset (indent, '\t', self->indent);
|
||||||
@@ -1560,7 +1318,7 @@ config_item_write_object
|
|||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
config_item_write_value (struct config_writer *self, struct config_item_ *value)
|
config_item_write_value (struct config_writer *self, struct config_item *value)
|
||||||
{
|
{
|
||||||
switch (value->type)
|
switch (value->type)
|
||||||
{
|
{
|
||||||
@@ -1587,7 +1345,7 @@ config_item_write_value (struct config_writer *self, struct config_item_ *value)
|
|||||||
|
|
||||||
static void
|
static void
|
||||||
config_item_write_kv_pair (struct config_writer *self,
|
config_item_write_kv_pair (struct config_writer *self,
|
||||||
const char *key, struct config_item_ *value)
|
const char *key, struct config_item *value)
|
||||||
{
|
{
|
||||||
char indent[self->indent + 1];
|
char indent[self->indent + 1];
|
||||||
memset (indent, '\t', self->indent);
|
memset (indent, '\t', self->indent);
|
||||||
@@ -1604,20 +1362,20 @@ config_item_write_kv_pair (struct config_writer *self,
|
|||||||
|
|
||||||
static void
|
static void
|
||||||
config_item_write_object_innards
|
config_item_write_object_innards
|
||||||
(struct config_writer *self, struct config_item_ *object)
|
(struct config_writer *self, struct config_item *object)
|
||||||
{
|
{
|
||||||
hard_assert (object->type == CONFIG_ITEM_OBJECT);
|
hard_assert (object->type == CONFIG_ITEM_OBJECT);
|
||||||
|
|
||||||
struct str_map_iter iter;
|
struct str_map_iter iter;
|
||||||
str_map_iter_init (&iter, &object->value.object);
|
str_map_iter_init (&iter, &object->value.object);
|
||||||
|
|
||||||
struct config_item_ *value;
|
struct config_item *value;
|
||||||
while ((value = str_map_iter_next (&iter)))
|
while ((value = str_map_iter_next (&iter)))
|
||||||
config_item_write_kv_pair (self, iter.link->key, value);
|
config_item_write_kv_pair (self, iter.link->key, value);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
config_item_write (struct config_item_ *value,
|
config_item_write (struct config_item *value,
|
||||||
bool object_innards, struct str *output)
|
bool object_innards, struct str *output)
|
||||||
{
|
{
|
||||||
struct config_writer writer = { .output = output, .indent = 0 };
|
struct config_writer writer = { .output = output, .indent = 0 };
|
||||||
@@ -2011,13 +1769,13 @@ config_parser_expect
|
|||||||
#define EXPECT(token) config_parser_expect (self, token, err)
|
#define EXPECT(token) config_parser_expect (self, token, err)
|
||||||
#define SKIP_NL() do {} while (ACCEPT (CONFIG_T_NEWLINE))
|
#define SKIP_NL() do {} while (ACCEPT (CONFIG_T_NEWLINE))
|
||||||
|
|
||||||
static struct config_item_ *config_parser_parse_object
|
static struct config_item *config_parser_parse_object
|
||||||
(struct config_parser *self, jmp_buf out);
|
(struct config_parser *self, jmp_buf out);
|
||||||
|
|
||||||
static struct config_item_ *
|
static struct config_item *
|
||||||
config_parser_parse_value (struct config_parser *self, jmp_buf out)
|
config_parser_parse_value (struct config_parser *self, jmp_buf out)
|
||||||
{
|
{
|
||||||
struct config_item_ *volatile result = NULL;
|
struct config_item *volatile result = NULL;
|
||||||
jmp_buf err;
|
jmp_buf err;
|
||||||
|
|
||||||
if (setjmp (err))
|
if (setjmp (err))
|
||||||
@@ -2052,7 +1810,7 @@ config_parser_parse_value (struct config_parser *self, jmp_buf out)
|
|||||||
/// Parse a single "key = value" assignment into @a object
|
/// Parse a single "key = value" assignment into @a object
|
||||||
static bool
|
static bool
|
||||||
config_parser_parse_kv_pair (struct config_parser *self,
|
config_parser_parse_kv_pair (struct config_parser *self,
|
||||||
struct config_item_ *object, jmp_buf out)
|
struct config_item *object, jmp_buf out)
|
||||||
{
|
{
|
||||||
char *volatile key = NULL;
|
char *volatile key = NULL;
|
||||||
jmp_buf err;
|
jmp_buf err;
|
||||||
@@ -2093,10 +1851,10 @@ config_parser_parse_kv_pair (struct config_parser *self,
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Parse the inside of an object definition
|
/// Parse the inside of an object definition
|
||||||
static struct config_item_ *
|
static struct config_item *
|
||||||
config_parser_parse_object (struct config_parser *self, jmp_buf out)
|
config_parser_parse_object (struct config_parser *self, jmp_buf out)
|
||||||
{
|
{
|
||||||
struct config_item_ *volatile object = config_item_object ();
|
struct config_item *volatile object = config_item_object ();
|
||||||
jmp_buf err;
|
jmp_buf err;
|
||||||
|
|
||||||
if (setjmp (err))
|
if (setjmp (err))
|
||||||
@@ -2119,14 +1877,14 @@ config_parser_parse_object (struct config_parser *self, jmp_buf out)
|
|||||||
|
|
||||||
/// Parse a configuration snippet either as an object or a bare value.
|
/// Parse a configuration snippet either as an object or a bare value.
|
||||||
/// If it's the latter (@a single_value_only), no newlines may follow.
|
/// If it's the latter (@a single_value_only), no newlines may follow.
|
||||||
static struct config_item_ *
|
static struct config_item *
|
||||||
config_item_parse (const char *script, size_t len,
|
config_item_parse (const char *script, size_t len,
|
||||||
bool single_value_only, struct error **e)
|
bool single_value_only, struct error **e)
|
||||||
{
|
{
|
||||||
struct config_parser parser;
|
struct config_parser parser;
|
||||||
config_parser_init (&parser, script, len);
|
config_parser_init (&parser, script, len);
|
||||||
|
|
||||||
struct config_item_ *volatile object = NULL;
|
struct config_item *volatile object = NULL;
|
||||||
jmp_buf err;
|
jmp_buf err;
|
||||||
|
|
||||||
if (setjmp (err))
|
if (setjmp (err))
|
||||||
@@ -2158,14 +1916,14 @@ end:
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Clone an item. Schema assignments aren't retained.
|
/// Clone an item. Schema assignments aren't retained.
|
||||||
struct config_item_ *
|
struct config_item *
|
||||||
config_item_clone (struct config_item_ *self)
|
config_item_clone (struct config_item *self)
|
||||||
{
|
{
|
||||||
// Oh well, it saves code
|
// Oh well, it saves code
|
||||||
struct str tmp;
|
struct str tmp;
|
||||||
str_init (&tmp);
|
str_init (&tmp);
|
||||||
config_item_write (self, false, &tmp);
|
config_item_write (self, false, &tmp);
|
||||||
struct config_item_ *result =
|
struct config_item *result =
|
||||||
config_item_parse (tmp.str, tmp.len, true, NULL);
|
config_item_parse (tmp.str, tmp.len, true, NULL);
|
||||||
str_free (&tmp);
|
str_free (&tmp);
|
||||||
return result;
|
return result;
|
||||||
@@ -2175,9 +1933,9 @@ config_item_clone (struct config_item_ *self)
|
|||||||
|
|
||||||
static void
|
static void
|
||||||
config_schema_initialize_item (struct config_schema *schema,
|
config_schema_initialize_item (struct config_schema *schema,
|
||||||
struct config_item_ *parent, void *user_data)
|
struct config_item *parent, void *user_data)
|
||||||
{
|
{
|
||||||
struct config_item_ *item =
|
struct config_item *item =
|
||||||
str_map_find (&parent->value.object, schema->name);
|
str_map_find (&parent->value.object, schema->name);
|
||||||
|
|
||||||
bool replace = true;
|
bool replace = true;
|
||||||
@@ -2223,7 +1981,7 @@ config_schema_initialize_item (struct config_schema *schema,
|
|||||||
|
|
||||||
static void
|
static void
|
||||||
config_schema_apply_to_object (struct config_schema *schema_array,
|
config_schema_apply_to_object (struct config_schema *schema_array,
|
||||||
struct config_item_ *object, void *user_data)
|
struct config_item *object, void *user_data)
|
||||||
{
|
{
|
||||||
hard_assert (object->type == CONFIG_ITEM_OBJECT);
|
hard_assert (object->type == CONFIG_ITEM_OBJECT);
|
||||||
while (schema_array->name)
|
while (schema_array->name)
|
||||||
@@ -2231,14 +1989,14 @@ config_schema_apply_to_object (struct config_schema *schema_array,
|
|||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
config_schema_call_changed (struct config_item_ *item)
|
config_schema_call_changed (struct config_item *item)
|
||||||
{
|
{
|
||||||
if (item->type == CONFIG_ITEM_OBJECT)
|
if (item->type == CONFIG_ITEM_OBJECT)
|
||||||
{
|
{
|
||||||
struct str_map_iter iter;
|
struct str_map_iter iter;
|
||||||
str_map_iter_init (&iter, &item->value.object);
|
str_map_iter_init (&iter, &item->value.object);
|
||||||
|
|
||||||
struct config_item_ *child;
|
struct config_item *child;
|
||||||
while ((child = str_map_iter_next (&iter)))
|
while ((child = str_map_iter_next (&iter)))
|
||||||
config_schema_call_changed (child);
|
config_schema_call_changed (child);
|
||||||
}
|
}
|
||||||
@@ -2251,7 +2009,7 @@ config_schema_call_changed (struct config_item_ *item)
|
|||||||
// XXX: this doesn't necessarily have to be well designed at all
|
// XXX: this doesn't necessarily have to be well designed at all
|
||||||
|
|
||||||
typedef void (*config_module_load_fn)
|
typedef void (*config_module_load_fn)
|
||||||
(struct config_item_ *subtree, void *user_data);
|
(struct config_item *subtree, void *user_data);
|
||||||
|
|
||||||
struct config_module
|
struct config_module
|
||||||
{
|
{
|
||||||
@@ -2277,7 +2035,7 @@ config_module_destroy (struct config_module *self)
|
|||||||
struct config
|
struct config
|
||||||
{
|
{
|
||||||
struct str_map modules; ///< Toplevel modules
|
struct str_map modules; ///< Toplevel modules
|
||||||
struct config_item_ *root; ///< CONFIG_ITEM_OBJECT
|
struct config_item *root; ///< CONFIG_ITEM_OBJECT
|
||||||
};
|
};
|
||||||
|
|
||||||
static void
|
static void
|
||||||
@@ -2309,7 +2067,7 @@ config_register_module (struct config *self,
|
|||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
config_load (struct config *self, struct config_item_ *root)
|
config_load (struct config *self, struct config_item *root)
|
||||||
{
|
{
|
||||||
hard_assert (root->type == CONFIG_ITEM_OBJECT);
|
hard_assert (root->type == CONFIG_ITEM_OBJECT);
|
||||||
self->root = root;
|
self->root = root;
|
||||||
@@ -2320,7 +2078,7 @@ config_load (struct config *self, struct config_item_ *root)
|
|||||||
struct config_module *module;
|
struct config_module *module;
|
||||||
while ((module = str_map_iter_next (&iter)))
|
while ((module = str_map_iter_next (&iter)))
|
||||||
{
|
{
|
||||||
struct config_item_ *subtree = str_map_find
|
struct config_item *subtree = str_map_find
|
||||||
(&root->value.object, module->name);
|
(&root->value.object, module->name);
|
||||||
// Silently fix inputs that only a lunatic user could create
|
// Silently fix inputs that only a lunatic user could create
|
||||||
if (!subtree || subtree->type != CONFIG_ITEM_OBJECT)
|
if (!subtree || subtree->type != CONFIG_ITEM_OBJECT)
|
||||||
|
|||||||
52
kike.c
52
kike.c
@@ -34,7 +34,7 @@ enum { PIPE_READ, PIPE_WRITE };
|
|||||||
// Just get rid of the crappiest ciphers available by default
|
// Just get rid of the crappiest ciphers available by default
|
||||||
#define DEFAULT_CIPHERS "DEFAULT:!MEDIUM:!LOW"
|
#define DEFAULT_CIPHERS "DEFAULT:!MEDIUM:!LOW"
|
||||||
|
|
||||||
static struct config_item g_config_table[] =
|
static struct simple_config_item g_config_table[] =
|
||||||
{
|
{
|
||||||
{ "pid_file", NULL, "Path or name of the PID file" },
|
{ "pid_file", NULL, "Path or name of the PID file" },
|
||||||
{ "server_name", NULL, "Server name" },
|
{ "server_name", NULL, "Server name" },
|
||||||
@@ -44,9 +44,9 @@ static struct config_item g_config_table[] =
|
|||||||
|
|
||||||
{ "bind_host", NULL, "Address of the IRC server" },
|
{ "bind_host", NULL, "Address of the IRC server" },
|
||||||
{ "bind_port", "6667", "Port of the IRC server" },
|
{ "bind_port", "6667", "Port of the IRC server" },
|
||||||
{ "ssl_cert", NULL, "Server TLS certificate (PEM)" },
|
{ "tls_cert", NULL, "Server TLS certificate (PEM)" },
|
||||||
{ "ssl_key", NULL, "Server TLS private key (PEM)" },
|
{ "tls_key", NULL, "Server TLS private key (PEM)" },
|
||||||
{ "ssl_ciphers", DEFAULT_CIPHERS, "OpenSSL cipher list" },
|
{ "tls_ciphers", DEFAULT_CIPHERS, "OpenSSL cipher list" },
|
||||||
|
|
||||||
{ "operators", NULL, "IRCop TLS cert. fingerprints" },
|
{ "operators", NULL, "IRCop TLS cert. fingerprints" },
|
||||||
|
|
||||||
@@ -666,7 +666,7 @@ server_context_init (struct server_context *self)
|
|||||||
|
|
||||||
str_map_init (&self->config);
|
str_map_init (&self->config);
|
||||||
self->config.free = free;
|
self->config.free = free;
|
||||||
load_config_defaults (&self->config, g_config_table);
|
simple_config_load_defaults (&self->config, g_config_table);
|
||||||
|
|
||||||
str_vector_init (&self->motd);
|
str_vector_init (&self->motd);
|
||||||
self->catalog = (nl_catd) -1;
|
self->catalog = (nl_catd) -1;
|
||||||
@@ -3106,7 +3106,7 @@ irc_try_read (struct client *c)
|
|||||||
}
|
}
|
||||||
|
|
||||||
static bool
|
static bool
|
||||||
irc_try_read_ssl (struct client *c)
|
irc_try_read_tls (struct client *c)
|
||||||
{
|
{
|
||||||
if (c->ssl_tx_want_rx)
|
if (c->ssl_tx_want_rx)
|
||||||
return true;
|
return true;
|
||||||
@@ -3174,7 +3174,7 @@ irc_try_write (struct client *c)
|
|||||||
}
|
}
|
||||||
|
|
||||||
static bool
|
static bool
|
||||||
irc_try_write_ssl (struct client *c)
|
irc_try_write_tls (struct client *c)
|
||||||
{
|
{
|
||||||
if (c->ssl_rx_want_tx)
|
if (c->ssl_rx_want_tx)
|
||||||
return true;
|
return true;
|
||||||
@@ -3212,7 +3212,7 @@ irc_try_write_ssl (struct client *c)
|
|||||||
}
|
}
|
||||||
|
|
||||||
static bool
|
static bool
|
||||||
irc_autodetect_ssl (struct client *c)
|
irc_autodetect_tls (struct client *c)
|
||||||
{
|
{
|
||||||
// Trivial SSL/TLS autodetection. The first block of data returned by
|
// Trivial SSL/TLS autodetection. The first block of data returned by
|
||||||
// recv() must be at least three bytes long for this to work reliably,
|
// recv() must be at least three bytes long for this to work reliably,
|
||||||
@@ -3251,7 +3251,7 @@ start:
|
|||||||
}
|
}
|
||||||
|
|
||||||
static bool
|
static bool
|
||||||
client_initialize_ssl (struct client *c)
|
client_initialize_tls (struct client *c)
|
||||||
{
|
{
|
||||||
const char *error_info = NULL;
|
const char *error_info = NULL;
|
||||||
if (!c->ctx->ssl_ctx)
|
if (!c->ctx->ssl_ctx)
|
||||||
@@ -3288,7 +3288,7 @@ on_client_ready (const struct pollfd *pfd, void *user_data)
|
|||||||
if (!c->initialized)
|
if (!c->initialized)
|
||||||
{
|
{
|
||||||
hard_assert (pfd->events == POLLIN);
|
hard_assert (pfd->events == POLLIN);
|
||||||
if (irc_autodetect_ssl (c) && !client_initialize_ssl (c))
|
if (irc_autodetect_tls (c) && !client_initialize_tls (c))
|
||||||
{
|
{
|
||||||
client_kill (c, NULL);
|
client_kill (c, NULL);
|
||||||
return;
|
return;
|
||||||
@@ -3301,7 +3301,7 @@ on_client_ready (const struct pollfd *pfd, void *user_data)
|
|||||||
{
|
{
|
||||||
// Reads may want to write, writes may want to read, poll() may
|
// Reads may want to write, writes may want to read, poll() may
|
||||||
// return unexpected things in `revents'... let's try both
|
// return unexpected things in `revents'... let's try both
|
||||||
if (!irc_try_read_ssl (c) || !irc_try_write_ssl (c))
|
if (!irc_try_read_tls (c) || !irc_try_write_tls (c))
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
else if (!irc_try_read (c) || !irc_try_write (c))
|
else if (!irc_try_read (c) || !irc_try_write (c))
|
||||||
@@ -3510,7 +3510,7 @@ irc_initialize_ssl_ctx (struct server_context *ctx,
|
|||||||
SSL_CTX_set_options (ctx->ssl_ctx, SSL_OP_NO_SSLv2 | SSL_OP_NO_SSLv3);
|
SSL_CTX_set_options (ctx->ssl_ctx, SSL_OP_NO_SSLv2 | SSL_OP_NO_SSLv3);
|
||||||
|
|
||||||
// XXX: perhaps we should read the files ourselves for better messages
|
// XXX: perhaps we should read the files ourselves for better messages
|
||||||
const char *ciphers = str_map_find (&ctx->config, "ssl_ciphers");
|
const char *ciphers = str_map_find (&ctx->config, "tls_ciphers");
|
||||||
if (!SSL_CTX_set_cipher_list (ctx->ssl_ctx, ciphers))
|
if (!SSL_CTX_set_cipher_list (ctx->ssl_ctx, ciphers))
|
||||||
error_set (e, "failed to select any cipher from the cipher list");
|
error_set (e, "failed to select any cipher from the cipher list");
|
||||||
else if (!SSL_CTX_use_certificate_chain_file (ctx->ssl_ctx, cert_path))
|
else if (!SSL_CTX_use_certificate_chain_file (ctx->ssl_ctx, cert_path))
|
||||||
@@ -3531,33 +3531,33 @@ irc_initialize_ssl_ctx (struct server_context *ctx,
|
|||||||
}
|
}
|
||||||
|
|
||||||
static bool
|
static bool
|
||||||
irc_initialize_ssl (struct server_context *ctx, struct error **e)
|
irc_initialize_tls (struct server_context *ctx, struct error **e)
|
||||||
{
|
{
|
||||||
const char *ssl_cert = str_map_find (&ctx->config, "ssl_cert");
|
const char *tls_cert = str_map_find (&ctx->config, "tls_cert");
|
||||||
const char *ssl_key = str_map_find (&ctx->config, "ssl_key");
|
const char *tls_key = str_map_find (&ctx->config, "tls_key");
|
||||||
|
|
||||||
// Only try to enable SSL support if the user configures it; it is not
|
// Only try to enable SSL support if the user configures it; it is not
|
||||||
// a failure if no one has requested it.
|
// a failure if no one has requested it.
|
||||||
if (!ssl_cert && !ssl_key)
|
if (!tls_cert && !tls_key)
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
if (!ssl_cert)
|
if (!tls_cert)
|
||||||
error_set (e, "no TLS certificate set");
|
error_set (e, "no TLS certificate set");
|
||||||
else if (!ssl_key)
|
else if (!tls_key)
|
||||||
error_set (e, "no TLS private key set");
|
error_set (e, "no TLS private key set");
|
||||||
if (!ssl_cert || !ssl_key)
|
if (!tls_cert || !tls_key)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
bool result = false;
|
bool result = false;
|
||||||
|
|
||||||
char *cert_path = resolve_filename
|
char *cert_path = resolve_filename
|
||||||
(ssl_cert, resolve_relative_config_filename);
|
(tls_cert, resolve_relative_config_filename);
|
||||||
char *key_path = resolve_filename
|
char *key_path = resolve_filename
|
||||||
(ssl_key, resolve_relative_config_filename);
|
(tls_key, resolve_relative_config_filename);
|
||||||
if (!cert_path)
|
if (!cert_path)
|
||||||
error_set (e, "%s: %s", "cannot open file", ssl_cert);
|
error_set (e, "%s: %s", "cannot open file", tls_cert);
|
||||||
else if (!key_path)
|
else if (!key_path)
|
||||||
error_set (e, "%s: %s", "cannot open file", ssl_key);
|
error_set (e, "%s: %s", "cannot open file", tls_key);
|
||||||
else
|
else
|
||||||
result = irc_initialize_ssl_ctx (ctx, cert_path, key_path, e);
|
result = irc_initialize_ssl_ctx (ctx, cert_path, key_path, e);
|
||||||
|
|
||||||
@@ -3982,7 +3982,7 @@ main (int argc, char *argv[])
|
|||||||
printf (PROGRAM_NAME " " PROGRAM_VERSION "\n");
|
printf (PROGRAM_NAME " " PROGRAM_VERSION "\n");
|
||||||
exit (EXIT_SUCCESS);
|
exit (EXIT_SUCCESS);
|
||||||
case 'w':
|
case 'w':
|
||||||
call_write_default_config (optarg, g_config_table);
|
call_simple_config_write_default (optarg, g_config_table);
|
||||||
exit (EXIT_SUCCESS);
|
exit (EXIT_SUCCESS);
|
||||||
default:
|
default:
|
||||||
print_error ("wrong options");
|
print_error ("wrong options");
|
||||||
@@ -4007,7 +4007,7 @@ main (int argc, char *argv[])
|
|||||||
irc_register_cap_handlers (&ctx);
|
irc_register_cap_handlers (&ctx);
|
||||||
|
|
||||||
struct error *e = NULL;
|
struct error *e = NULL;
|
||||||
if (!read_config_file (&ctx.config, &e))
|
if (!simple_config_update_from_file (&ctx.config, &e))
|
||||||
{
|
{
|
||||||
print_error ("error loading configuration: %s", e->message);
|
print_error ("error loading configuration: %s", e->message);
|
||||||
error_free (e);
|
error_free (e);
|
||||||
@@ -4019,7 +4019,7 @@ main (int argc, char *argv[])
|
|||||||
ctx.signal_event.user_data = &ctx;
|
ctx.signal_event.user_data = &ctx;
|
||||||
poller_fd_set (&ctx.signal_event, POLLIN);
|
poller_fd_set (&ctx.signal_event, POLLIN);
|
||||||
|
|
||||||
if (!irc_initialize_ssl (&ctx, &e)
|
if (!irc_initialize_tls (&ctx, &e)
|
||||||
|| !irc_initialize_server_name (&ctx, &e)
|
|| !irc_initialize_server_name (&ctx, &e)
|
||||||
|| !irc_initialize_motd (&ctx, &e)
|
|| !irc_initialize_motd (&ctx, &e)
|
||||||
|| !irc_initialize_catalog (&ctx, &e)
|
|| !irc_initialize_catalog (&ctx, &e)
|
||||||
|
|||||||
2
liberty
2
liberty
Submodule liberty updated: 02708608a9...649c351560
44
zyklonb.c
44
zyklonb.c
@@ -24,7 +24,7 @@
|
|||||||
|
|
||||||
// --- Configuration (application-specific) ------------------------------------
|
// --- Configuration (application-specific) ------------------------------------
|
||||||
|
|
||||||
static struct config_item g_config_table[] =
|
static struct simple_config_item g_config_table[] =
|
||||||
{
|
{
|
||||||
{ "nickname", "ZyklonB", "IRC nickname" },
|
{ "nickname", "ZyklonB", "IRC nickname" },
|
||||||
{ "username", "bot", "IRC user name" },
|
{ "username", "bot", "IRC user name" },
|
||||||
@@ -32,11 +32,11 @@ static struct config_item g_config_table[] =
|
|||||||
|
|
||||||
{ "irc_host", NULL, "Address of the IRC server" },
|
{ "irc_host", NULL, "Address of the IRC server" },
|
||||||
{ "irc_port", "6667", "Port of the IRC server" },
|
{ "irc_port", "6667", "Port of the IRC server" },
|
||||||
{ "ssl", "off", "Whether to use SSL" },
|
{ "tls", "off", "Whether to use TLS" },
|
||||||
{ "ssl_cert", NULL, "Client SSL certificate (PEM)" },
|
{ "tls_cert", NULL, "Client TLS certificate (PEM)" },
|
||||||
{ "ssl_verify", "on", "Whether to verify certificates" },
|
{ "tls_verify", "on", "Whether to verify certificates" },
|
||||||
{ "ssl_ca_file", NULL, "OpenSSL CA bundle file" },
|
{ "tls_ca_file", NULL, "OpenSSL CA bundle file" },
|
||||||
{ "ssl_ca_path", NULL, "OpenSSL CA bundle path" },
|
{ "tls_ca_path", NULL, "OpenSSL CA bundle path" },
|
||||||
{ "autojoin", NULL, "Channels to join on start" },
|
{ "autojoin", NULL, "Channels to join on start" },
|
||||||
{ "reconnect", "on", "Whether to reconnect on error" },
|
{ "reconnect", "on", "Whether to reconnect on error" },
|
||||||
{ "reconnect_delay", "5", "Time between reconnecting" },
|
{ "reconnect_delay", "5", "Time between reconnecting" },
|
||||||
@@ -153,7 +153,7 @@ bot_context_init (struct bot_context *self)
|
|||||||
{
|
{
|
||||||
str_map_init (&self->config);
|
str_map_init (&self->config);
|
||||||
self->config.free = free;
|
self->config.free = free;
|
||||||
load_config_defaults (&self->config, g_config_table);
|
simple_config_load_defaults (&self->config, g_config_table);
|
||||||
self->admin_re = NULL;
|
self->admin_re = NULL;
|
||||||
|
|
||||||
self->irc_fd = -1;
|
self->irc_fd = -1;
|
||||||
@@ -320,7 +320,7 @@ irc_initialize_ssl_ctx (struct bot_context *ctx, struct error **e)
|
|||||||
SSL_CTX_set_options (ctx->ssl_ctx, SSL_OP_NO_SSLv2 | SSL_OP_NO_SSLv3);
|
SSL_CTX_set_options (ctx->ssl_ctx, SSL_OP_NO_SSLv2 | SSL_OP_NO_SSLv3);
|
||||||
|
|
||||||
bool verify;
|
bool verify;
|
||||||
if (!irc_get_boolean_from_config (ctx, "ssl_verify", &verify, e))
|
if (!irc_get_boolean_from_config (ctx, "tls_verify", &verify, e))
|
||||||
return false;
|
return false;
|
||||||
SSL_CTX_set_verify (ctx->ssl_ctx,
|
SSL_CTX_set_verify (ctx->ssl_ctx,
|
||||||
verify ? SSL_VERIFY_PEER : SSL_VERIFY_NONE, NULL);
|
verify ? SSL_VERIFY_PEER : SSL_VERIFY_NONE, NULL);
|
||||||
@@ -363,7 +363,7 @@ ca_error:
|
|||||||
}
|
}
|
||||||
|
|
||||||
static bool
|
static bool
|
||||||
irc_initialize_ssl (struct bot_context *ctx, struct error **e)
|
irc_initialize_tls (struct bot_context *ctx, struct error **e)
|
||||||
{
|
{
|
||||||
const char *error_info = NULL;
|
const char *error_info = NULL;
|
||||||
ctx->ssl_ctx = SSL_CTX_new (SSLv23_client_method ());
|
ctx->ssl_ctx = SSL_CTX_new (SSLv23_client_method ());
|
||||||
@@ -376,17 +376,17 @@ irc_initialize_ssl (struct bot_context *ctx, struct error **e)
|
|||||||
if (!ctx->ssl)
|
if (!ctx->ssl)
|
||||||
goto error_ssl_2;
|
goto error_ssl_2;
|
||||||
|
|
||||||
const char *ssl_cert = str_map_find (&ctx->config, "ssl_cert");
|
const char *tls_cert = str_map_find (&ctx->config, "tls_cert");
|
||||||
if (ssl_cert)
|
if (tls_cert)
|
||||||
{
|
{
|
||||||
char *path = resolve_filename
|
char *path = resolve_filename
|
||||||
(ssl_cert, resolve_relative_config_filename);
|
(tls_cert, resolve_relative_config_filename);
|
||||||
if (!path)
|
if (!path)
|
||||||
print_error ("%s: %s", "cannot open file", ssl_cert);
|
print_error ("%s: %s", "cannot open file", tls_cert);
|
||||||
// XXX: perhaps we should read the file ourselves for better messages
|
// XXX: perhaps we should read the file ourselves for better messages
|
||||||
else if (!SSL_use_certificate_file (ctx->ssl, path, SSL_FILETYPE_PEM)
|
else if (!SSL_use_certificate_file (ctx->ssl, path, SSL_FILETYPE_PEM)
|
||||||
|| !SSL_use_PrivateKey_file (ctx->ssl, path, SSL_FILETYPE_PEM))
|
|| !SSL_use_PrivateKey_file (ctx->ssl, path, SSL_FILETYPE_PEM))
|
||||||
print_error ("%s: %s", "setting the SSL client certificate failed",
|
print_error ("%s: %s", "setting the TLS client certificate failed",
|
||||||
ERR_error_string (ERR_get_error (), NULL));
|
ERR_error_string (ERR_get_error (), NULL));
|
||||||
free (path);
|
free (path);
|
||||||
}
|
}
|
||||||
@@ -418,7 +418,7 @@ error_ssl_1:
|
|||||||
// multiple errors on the OpenSSL stack.
|
// multiple errors on the OpenSSL stack.
|
||||||
if (!error_info)
|
if (!error_info)
|
||||||
error_info = ERR_error_string (ERR_get_error (), NULL);
|
error_info = ERR_error_string (ERR_get_error (), NULL);
|
||||||
error_set (e, "%s: %s", "could not initialize SSL", error_info);
|
error_set (e, "%s: %s", "could not initialize TLS", error_info);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1444,7 +1444,7 @@ enum irc_read_result
|
|||||||
};
|
};
|
||||||
|
|
||||||
static enum irc_read_result
|
static enum irc_read_result
|
||||||
irc_fill_read_buffer_ssl (struct bot_context *ctx, struct str *buf)
|
irc_fill_read_buffer_tls (struct bot_context *ctx, struct str *buf)
|
||||||
{
|
{
|
||||||
int n_read;
|
int n_read;
|
||||||
start:
|
start:
|
||||||
@@ -1608,7 +1608,7 @@ on_irc_readable (const struct pollfd *fd, struct bot_context *ctx)
|
|||||||
struct str *buf = &ctx->read_buffer;
|
struct str *buf = &ctx->read_buffer;
|
||||||
enum irc_read_result (*fill_buffer)(struct bot_context *, struct str *)
|
enum irc_read_result (*fill_buffer)(struct bot_context *, struct str *)
|
||||||
= ctx->ssl
|
= ctx->ssl
|
||||||
? irc_fill_read_buffer_ssl
|
? irc_fill_read_buffer_tls
|
||||||
: irc_fill_read_buffer;
|
: irc_fill_read_buffer;
|
||||||
bool disconnected = false;
|
bool disconnected = false;
|
||||||
while (true)
|
while (true)
|
||||||
@@ -1754,8 +1754,8 @@ irc_connect (struct bot_context *ctx, struct error **e)
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool use_ssl;
|
bool use_tls;
|
||||||
if (!irc_get_boolean_from_config (ctx, "ssl", &use_ssl, e))
|
if (!irc_get_boolean_from_config (ctx, "tls", &use_tls, e))
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
bool connected = socks_host
|
bool connected = socks_host
|
||||||
@@ -1765,7 +1765,7 @@ irc_connect (struct bot_context *ctx, struct error **e)
|
|||||||
if (!connected)
|
if (!connected)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
if (use_ssl && !irc_initialize_ssl (ctx, e))
|
if (use_tls && !irc_initialize_tls (ctx, e))
|
||||||
{
|
{
|
||||||
xclose (ctx->irc_fd);
|
xclose (ctx->irc_fd);
|
||||||
ctx->irc_fd = -1;
|
ctx->irc_fd = -1;
|
||||||
@@ -1965,7 +1965,7 @@ main (int argc, char *argv[])
|
|||||||
printf (PROGRAM_NAME " " PROGRAM_VERSION "\n");
|
printf (PROGRAM_NAME " " PROGRAM_VERSION "\n");
|
||||||
exit (EXIT_SUCCESS);
|
exit (EXIT_SUCCESS);
|
||||||
case 'w':
|
case 'w':
|
||||||
call_write_default_config (optarg, g_config_table);
|
call_simple_config_write_default (optarg, g_config_table);
|
||||||
exit (EXIT_SUCCESS);
|
exit (EXIT_SUCCESS);
|
||||||
default:
|
default:
|
||||||
print_error ("wrong options");
|
print_error ("wrong options");
|
||||||
@@ -1988,7 +1988,7 @@ main (int argc, char *argv[])
|
|||||||
bot_context_init (&ctx);
|
bot_context_init (&ctx);
|
||||||
|
|
||||||
struct error *e = NULL;
|
struct error *e = NULL;
|
||||||
if (!read_config_file (&ctx.config, &e)
|
if (!simple_config_update_from_file (&ctx.config, &e)
|
||||||
|| !setup_recovery_handler (&ctx, &e))
|
|| !setup_recovery_handler (&ctx, &e))
|
||||||
{
|
{
|
||||||
print_error ("%s", e->message);
|
print_error ("%s", e->message);
|
||||||
|
|||||||
Reference in New Issue
Block a user