23 #include <stringprep.h> 26 #include <openssl/rand.h> 67 if((f = fopen(pidfile,
"w+")) == NULL) {
68 log_write(s2s->
log, LOG_ERR,
"couldn't open %s for writing: %s", pidfile, strerror(errno));
72 if(fprintf(f,
"%d", pid) < 0) {
73 log_write(s2s->
log, LOG_ERR,
"couldn't write to %s: %s", pidfile, strerror(errno));
80 log_write(s2s->
log, LOG_INFO,
"process id is %d, written to %s", pid, pidfile);
85 char *str, secret[41];
125 if(strcmp(str,
"file") == 0)
127 else if(strcmp(str,
"syslog") == 0)
156 if (!RAND_bytes(secret, 40)) {
157 log_write(s2s->
log, LOG_ERR,
"Failed to pull 40 RAND_bytes");
161 # warning "Using unsecure random number generator for dialback keys" 162 log_write(s2s->
log, LOG_WARNING,
"Using unsecure random number generator for dialback keys - set local.secret to a random string!");
164 for(i = 0; i < 40; i++) {
166 r = (int) (36.0 * secret[i] / 255);
168 r = (int) (36.0 * rand() / RAND_MAX);
170 secret[i] = (r >= 0 && r <= 9) ? (r + 48) : (r + 87);
228 if (elem)
for(i = 0; i < elem->
nvalues; i++) {
231 log_write(s2s->
log, LOG_ERR,
"cannot allocate memory for new host, aborting");
235 realm =
j_attr((
const char **) elem->
attrs[i],
"realm");
238 strncpy(
id, elem->
values[i], 1024);
240 if (stringprep_nameprep(
id, 1024) != 0) {
241 log_write(s2s->
log, LOG_ERR,
"cannot stringprep id %s, aborting",
id);
285 if(s2s->fd == NULL) {
286 if(errno == ECONNREFUSED)
303 time_t now, dialback_time;
318 log_write(s2s->
log, LOG_NOTICE,
"[%d] [%s, port=%d] dialback for %s route '%.*s' timed out", conn->
fd->
fd, conn->
ip, conn->
port, direction, rkeylen, rkey);
359 log_debug(
ZONE,
"running time checks for %.*s", keylen, rkey);
360 c = memchr(rkey,
'/', keylen);
362 c_len = keylen - (c - rkey);
366 if(dns != NULL && dns->pending) {
369 log_write(s2s->
log, LOG_NOTICE,
"dns lookup for %.*s timed out", c_len, c);
377 if (dns->query != NULL) {
378 if (dns->query->query != NULL)
379 dns_cancel(NULL, dns->query->query);
382 free((
void*)dns->query->name);
410 log_write(s2s->
log, LOG_NOTICE,
"[%d] [%s, port=%d] connection to %s timed out", conn->
fd->
fd, conn->
ip, conn->
port, c);
442 log_debug(
ZONE,
"checking dialback state for outgoing conn %.*s", keylen, key);
444 log_debug(
ZONE,
"checking pending verify requests for outgoing conn %.*s", keylen, key);
446 log_write(s2s->
log, LOG_NOTICE,
"[%d] [%s, port=%d] dialback verify request timed out", conn->
fd->
fd, conn->
ip, conn->
port);
459 log_debug(
ZONE,
"checking pending verify requests for outgoing conn %s (%s)", conn->
dkey, conn->
key);
461 log_write(s2s->
log, LOG_NOTICE,
"[%d] [%s, port=%d] dialback verify request timed out", conn->
fd->
fd, conn->
ip, conn->
port);
475 log_debug(
ZONE,
"checking dialback state for incoming conn %.*s", keylen, key);
479 log_write(s2s->
log, LOG_NOTICE,
"[%d] [%s, port=%d] no dialback started", conn->
fd->
fd, conn->
ip, conn->
port);
491 log_debug(
ZONE,
"checking stream connection state for incoming conn %i", conn->
fd->
fd);
493 log_write(s2s->
log, LOG_NOTICE,
"[%d] [%s, port=%d] stream initiation timed out", conn->
fd->
fd, conn->
ip, conn->
port);
536 log_debug(
ZONE,
"checking idle state for %.*s", keylen, key);
560 log_debug(
ZONE,
"checking idle state for %.*s", keylen, key);
590 if (dns->
query != NULL) {
600 else if (dns == NULL) {
609 if (res && now > res->
expiry) {
613 free((
void*)res->
key);
616 else if (res == NULL) {
628 dns_ioevent(0, time(NULL));
643 for (i = 0, j = 0; i < nvalues; i++) {
644 elem_len = strlen(values[i]);
646 log_debug(
ZONE,
"whitelist domain element is too large, skipping");
650 log_debug(
ZONE,
"whitelist domain element is blank, skipping");
673 char **segments = NULL;
675 char *seg_tmp = NULL;
684 char *domain_ptr = &domain[0];
687 strncpy(domain, in_domain,
sizeof(domain));
688 domain[
sizeof(domain)-1] =
'\0';
689 domain_len = strlen((
const char *)&domain);
691 if (domain_len <= 0) {
692 log_write(s2s->
log, LOG_NOTICE,
"s2s_domain_in_whitelist: in_domain is empty");
707 if (!strncmp((
const char *)&domain, s2s->
whitelist_domains[wl_index], (domain_len > wl_len) ? domain_len : wl_len)) {
708 log_debug(
ZONE,
"domain \"%s\" matches whitelist entry", &domain);
717 for (dotcount = 0, x = 0; domain[x] !=
'\0'; x++) {
718 if (domain[x] ==
'.')
722 segments = (
char **)malloc(
sizeof(
char*) * (dotcount + 1));
723 if (segments == NULL) {
724 log_write(s2s->
log, LOG_ERR,
"s2s_domain_in_whitelist: malloc() error");
727 memset((
char **)segments, 0, (
sizeof(
char*) * (dotcount + 1)));
730 if (segcount > (dotcount+1)) {
731 log_write(s2s->
log, LOG_ERR,
"s2s_domain_in_whitelist: did not malloc enough room for domain segments; should never get here");
732 if (seg_tmp != NULL) {
736 for (x = 0; x < segcount; x++) {
744 seg_tmp = strsep(&domain_ptr,
".");
745 if (seg_tmp == NULL) {
749 seg_tmp_len = strlen(seg_tmp);
754 for (x = 0; x < segcount; x++) {
762 dst = &segments[segcount];
763 *dst = (
char *)malloc(seg_tmp_len + 1);
765 strncpy(*dst, seg_tmp, seg_tmp_len + 1);
766 (*dst)[seg_tmp_len] =
'\0';
770 for (x = 0; x < segcount; x++) {
776 log_write(s2s->
log, LOG_ERR,
"s2s_domain_in_whitelist: malloc() error");
780 }
while (seg_tmp != NULL);
783 for (domain_index = segcount-2; domain_index > 0; domain_index--) {
785 for (i = domain_index; i < segcount; i++) {
786 if (i > domain_index) {
787 strncat((
char *)&matchstr,
".",
sizeof(matchstr));
788 matchstr[
sizeof(matchstr)-1] =
'\0';
790 strncat((
char *)&matchstr, (
char *)segments[i],
sizeof(matchstr)-strlen(matchstr)-1);
791 matchstr[
sizeof(matchstr)-1] =
'\0';
795 matchstr_len = strlen((
const char *)&matchstr);
796 if (!strncmp((
const char *)&matchstr, s2s->
whitelist_domains[wl_index], (wl_len > matchstr_len ? wl_len : matchstr_len))) {
797 log_debug(
ZONE,
"matchstr \"%s\" matches whitelist entry", &matchstr);
798 for (x = 0; x < segcount; x++) {
812 for (x = 0; x < segcount; x++) {
822 JABBER_MAIN(
"jabberd2s2s",
"Jabber 2 S2S",
"Jabber Open Source Server: Server to Server",
"jabberd2router\0")
832 time_t check_time = 0, now = 0;
833 const char *cli_id = 0;
836 umask((mode_t) 0027);
841 #ifdef HAVE_WINSOCK2_H 844 WORD wVersionRequested;
848 wVersionRequested = MAKEWORD( 2, 2 );
850 err = WSAStartup( wVersionRequested, &wsaData );
875 config_file = CONFIG_DIR
"/s2s.xml";
878 while((optchar = getopt(argc, argv,
"Dc:hi:?")) >= 0)
883 config_file = optarg;
889 printf(
"WARN: Debugging not enabled. Ignoring -D.\n");
895 case 'h':
case '?':
default:
897 "s2s - jabberd server-to-server connector (" VERSION
")\n" 898 "Usage: s2s <options>\n" 900 " -c <config> config file to use [default: " CONFIG_DIR
"/s2s.xml]\n" 901 " -i id Override <id> config element\n" 903 " -D Show debug output\n" 914 fputs(
"s2s: couldn't load config, aborting\n", stderr);
946 log_write(s2s->
log, LOG_ERR,
"failed to load local SSL pemfile, SSL will not be available to peers");
949 log_debug(
ZONE,
"loaded pemfile for SSL connections to peers");
956 log_write(s2s->
log, LOG_ERR,
"failed to load router SSL pemfile, channel to router will not be SSL encrypted");
971 log_write(s2s->
log, LOG_ERR,
"failed to initialise SASL context, aborting");
983 if((s2s->
udns_fd = dns_init(NULL, 1)) < 0) {
984 log_write(s2s->
log, LOG_ERR,
"unable to initialize dns library, aborting");
989 s2s->retry_left = s2s->retry_init;
993 mio_run(s2s->mio, dns_timeouts(0, 5, time(NULL)));
1000 log_write(s2s->log, LOG_NOTICE,
"reopening log ...");
1002 s2s->log =
log_new(s2s->log_type, s2s->log_ident, s2s->log_facility);
1003 log_write(s2s->log, LOG_NOTICE,
"log started");
1009 if(s2s->retry_left < 0) {
1010 log_write(s2s->log, LOG_NOTICE,
"attempting reconnect");
1011 sleep(s2s->retry_sleep);
1013 if (s2s->router)
sx_free(s2s->router);
1017 else if(s2s->retry_left == 0) {
1022 log_write(s2s->log, LOG_NOTICE,
"attempting reconnect (%d left)", s2s->retry_left);
1024 sleep(s2s->retry_sleep);
1026 if (s2s->router)
sx_free(s2s->router);
1032 mio_read(s2s->mio, s2s->udns_mio_fd);
1045 free((
void*)conn->
key);
1046 free((
void*)conn->
dkey);
1051 if(s2s->check_interval > 0 && now >= s2s->next_check) {
1056 s2s->next_check = now + s2s->check_interval;
1061 if(s2s->check_dnscache > 0 && now >= s2s->next_expiry) {
1066 s2s->next_expiry = now + s2s->check_dnscache;
1070 if(now > check_time + 60) {
1074 if(s2s->packet_stats != NULL) {
1075 int fd = open(s2s->packet_stats, O_TRUNC | O_CREAT | O_WRONLY, S_IRUSR | S_IWUSR | S_IRGRP);
1078 int len = snprintf(buf, 100,
"%lld\n", s2s->packet_count);
1079 write(fd, buf, len);
1082 log_write(s2s->log, LOG_ERR,
"failed to write packet statistics to: %s (%s)", s2s->packet_stats, strerror(errno));
1091 log_write(s2s->log, LOG_NOTICE,
"shutting down");
1095 if(s2s->out_reuse) {
1148 if(conn->
key != NULL) free((
void*)conn->
key);
1149 if(conn->
dkey != NULL) free((
void*)conn->
dkey);
1170 if (dns->
query != NULL) {
1185 free((
void*)res->
key);
1189 if (dns_active(NULL) > 0)
1190 log_debug(
ZONE,
"there are still active dns queries (%d)", dns_active(NULL));
1197 if(s2s->server_fd != NULL)
1223 free((
void*)s2s->local_secret);
static sig_atomic_t s2s_logrotate
int retry_init
connect retry
char ip[INET6_ADDRSTRLEN+1]
int config_load_with_id(config_t c, const char *file, const char *id)
turn an xml file into a config hash
static int _s2s_populate_whitelist_domains(s2s_t s2s, const char **values, int nvalues)
const char * local_ip
ip/port to listen on
time_t expiry
time that this entry expires
int s2s_router_mio_callback(mio_t m, mio_action_t a, mio_fd_t fd, void *data, void *arg)
void config_free(config_t c)
cleanup
int s2s_db_init(sx_env_t env, sx_plugin_t p, va_list args)
xht hosts
srv lookup results (key host/port)
mio_t mio_new(int maxfd)
create/free the mio subsytem
#define mio_run(m, timeout)
give some cpu time to mio to check it's sockets, 0 is non-blocking
jqueue_t dead
list of sx_t on the way out
struct dnsres_st * dnsres_t
void * xhash_getx(xht h, const char *key, int len)
int jqueue_size(jqueue_t q)
char ** whitelist_domains
const char * host_ciphers
list of TLS ciphers
void log_write(log_t log, int level, const char *msgfmt,...)
const char * router_ip
how to connect to the router
void xhash_iter_zap(xht h)
xht in_accept
incoming conns prior to stream initiation (key is ip/port)
int s2s_router_sx_callback(sx_t s, sx_event_t e, void *data, void *arg)
our master callback
sx_t sx_new(sx_env_t env, int tag, sx_callback_t cb, void *arg)
if you change these, reflect your changes in the table in error.c
config_t config_new(void)
new config structure
const char ** lookup_srv
srvs to lookup
int sx_ssl_server_addcert(sx_plugin_t p, const char *name, const char *pemfile, const char *cachain, int mode, const char *password, const char *ciphers)
args: name, pemfile, cachain, mode
static char * config_file
int verify
number and last timestamp of outstanding db:verify requests
char * host_private_key_password
private key password
void sx_raw_write(sx_t s, const char *buf, int len)
app version
xht states
states of outgoing dialbacks (key is local/remote)
int j_atoi(const char *a, int def)
int out_bounce_route_queue(s2s_t s2s, const char *rkey, int rkeylen, int err)
void out_pkt_free(pkt_t pkt)
mio_action_t
these are the actions and a handler type assigned by the applicaiton using mio
int host_verify_mode
verify-mode
xht outq
queues of packets waiting to go out (key is route)
const char * packet_stats
time_t expiry
time that this entry expires
xht out_host
outgoing conns (key is ip/port)
int xhash_iter_next(xht h)
sx_env_t sx_env_new(void)
#define mio_connect(m, port, hostip, srcip, app, arg)
for creating a new socket connected to this ip:port (returns new fd or <0, use mio_read/write first) ...
xht dnscache
dns resolution cache
xht out_dest
outgoing conns (key is dest)
xht routes
routes that this conn handles (key is local/remote)
#define mio_read(m, fd)
process read events for this fd
static void _s2s_pidfile(s2s_t s2s)
store the process id
char * config_get_attr(config_t c, const char *key, int num, const char *attr)
get an attr for this value
void jqueue_free(jqueue_t q)
xht dns_bad
dns resolution bad host cache
#define MIO_ERROR
all MIO related routines should use those for error reporting
sx_env_t sx_env
sx environment
#define stanza_err_REMOTE_SERVER_TIMEOUT
int compression
enable Stream Compression
static void _s2s_signal(int signum)
int etc_hosts_ttl
/etc/hosts ttl limits
int pending
set when we're waiting for a resolve response
sx_plugin_t sx_env_plugin(sx_env_t env, sx_plugin_init_t init,...)
load a plugin into the environment
int stanza_size_limit
maximum stanza size
holds the state for a single stream
#define stream_err_SYSTEM_SHUTDOWN
int local_verify_mode
verify-mode
const char * local_cachain
certificate chain
packet summary data wrapper
void * pmalloco(pool_t p, int size)
easy safety utility (for creating blank mem for structs, etc)
void sx_client_init(sx_t s, unsigned int flags, const char *ns, const char *to, const char *from, const char *version)
void set_debug_log_from_config(config_t c)
const char * log_facility
xht results
results (key ip/port)
char name[1024]
the name proper
int s2s_domain_in_whitelist(s2s_t s2s, const char *in_domain)
const char * realm
our realm (SASL)
jqueue_t dead_conn
list of conn_t on the way out
void xhash_put(xht h, const char *key, void *val)
xht states_time
time of the last state change (key is local/remote)
xht results
host lookup results (key ip/port)
const char * local_secret
dialback secret
int xhash_iter_get(xht h, const char **key, int *keylen, void **val)
#define stanza_err_REMOTE_SERVER_NOT_FOUND
const char * host_pemfile
starttls pemfile
JABBER_MAIN("jabberd2c2s", "Jabber 2 C2S", "Jabber Open Source Server: Client to Server", "jabberd2router\)
static int _s2s_router_connect(s2s_t s2s)
void xhash_zap(xht h, const char *key)
jsighandler_t * jabber_signal(int signo, jsighandler_t *func)
const char * name
domain name
int out_reuse
reuse outgoing conns keyed by ip/port
void xhash_zapx(xht h, const char *key, int len)
const char * router_pemfile
const char * local_ciphers
list of TLS ciphers
int check_interval
time checks
char * dns_make_ipport(const char *host, int port)
void sx_error(sx_t s, int err, const char *text)
static void _s2s_signal_hup(int signum)
JABBERD2_API int sx_sasl_init(sx_env_t env, sx_plugin_t p, va_list args)
init function
static void _s2s_time_checks(s2s_t s2s)
config_elem_t config_get(config_t c, const char *key)
get the config element for this key
int io_max_fds
max file descriptors
#define stream_err_CONNECTION_TIMEOUT
int resolve_aaaa
if we resolve AAAA records
void * jqueue_pull(jqueue_t q)
int xhash_count(xht h)
return the total number of entries in this xht
const char ** origin_ips
ip(s) to originate connections from
static void _s2s_config_expand(s2s_t s2s)
pull values out of the config file
struct dns_query * query
set when we're waiting for a resolve response
int xhash_iter_first(xht h)
iteration
const char * router_ciphers
jqueue_t jqueue_new(void)
sig_atomic_t s2s_lost_router
void set_debug_flag(int v)
const char * router_private_key_password
int sx_ssl_init(sx_env_t env, sx_plugin_t p, va_list args)
args: name, pemfile, cachain, mode
int _s2s_check_conn_routes(s2s_t s2s, conn_t conn, const char *direction)
static void _s2s_signal_usr2(int signum)
static void _s2s_hosts_expand(s2s_t s2s)
int sx_compress_init(sx_env_t env, sx_plugin_t p, va_list args)
args: none
pool_t xhash_pool(xht h)
get our pool
int out_bounce_conn_queues(conn_t out, int err)
const char * id
our id (hostname) with the router
log_type_t log_type
log data
char * pstrdup(pool_t p, const char *src)
XXX efficient: move this to const char * and then loop throug the existing heaps to see if src is wit...
const char * router_cachain
xht in
incoming conns (key is stream id)
void * xhash_get(xht h, const char *key)
#define mio_close(m, fd)
request that mio close this fd
char * j_attr(const char **atts, const char *attr)
const char * local_private_key_password
private key password for local pemfile, if encrypted
static sig_atomic_t s2s_shutdown
log_t log_new(log_type_t type, const char *ident, const char *facility)
int require_tls
Apple security options.
one item in the dns resolution cache
const char * config_get_one(config_t c, const char *key, int num)
get config value n for this key
void sx_env_free(sx_env_t env)
static void _s2s_signal_usr1(int signum)
#define mio_register(m, fd, app, arg)
for adding an existing socket connected to this mio
#define stanza_err_SERVICE_UNAVAILABLE
int config_count(config_t c, const char *key)
how many values for this key?
static int _mio_resolver_callback(mio_t m, mio_action_t a, mio_fd_t fd, void *data, void *arg)
responses from the resolver
const char * local_pemfile
pemfile for peer connections
time_t last_activity
timestamps for idle timeouts
int dns_min_ttl
dns ttl limits
static void _s2s_dns_expiry(s2s_t s2s)
const char * host_cachain
certificate chain