Import Upstream version 1.1~pre7

This commit is contained in:
Guus Sliepen 2019-08-26 13:44:50 +02:00
parent 26033edb96
commit 2ebbac3278
36 changed files with 1358 additions and 860 deletions

View file

@ -1,6 +1,6 @@
## Produce this file with automake to get Makefile.in
sbin_PROGRAMS = tincd tincctl sptps_test
sbin_PROGRAMS = tincd tinc sptps_test
EXTRA_DIST = linux bsd solaris cygwin mingw openssl gcrypt
@ -22,11 +22,11 @@ endif
nodist_tincd_SOURCES = \
device.c cipher.c crypto.c ecdh.c ecdsa.c digest.c prf.c rsa.c
tincctl_SOURCES = \
tinc_SOURCES = \
utils.c getopt.c getopt1.c dropin.c \
info.c list.c subnet_parse.c tincctl.c top.c names.c
nodist_tincctl_SOURCES = \
nodist_tinc_SOURCES = \
ecdsagen.c rsagen.c
sptps_test_SOURCES = \
@ -37,7 +37,7 @@ if TUNEMU
tincd_SOURCES += bsd/tunemu.c
endif
tincctl_LDADD = $(READLINE_LIBS) $(CURSES_LIBS)
tinc_LDADD = $(READLINE_LIBS) $(CURSES_LIBS)
DEFAULT_INCLUDES =

View file

@ -52,7 +52,7 @@ PRE_UNINSTALL = :
POST_UNINSTALL = :
build_triplet = @build@
host_triplet = @host@
sbin_PROGRAMS = tincd$(EXEEXT) tincctl$(EXEEXT) sptps_test$(EXEEXT)
sbin_PROGRAMS = tincd$(EXEEXT) tinc$(EXEEXT) sptps_test$(EXEEXT)
@UML_TRUE@am__append_1 = uml_device.c
@VDE_TRUE@am__append_2 = vde_device.c
@TUNEMU_TRUE@am__append_3 = bsd/tunemu.c
@ -79,14 +79,14 @@ am_sptps_test_OBJECTS = logger.$(OBJEXT) cipher.$(OBJEXT) \
sptps_test.$(OBJEXT) utils.$(OBJEXT)
sptps_test_OBJECTS = $(am_sptps_test_OBJECTS)
sptps_test_LDADD = $(LDADD)
am_tincctl_OBJECTS = utils.$(OBJEXT) getopt.$(OBJEXT) \
getopt1.$(OBJEXT) dropin.$(OBJEXT) info.$(OBJEXT) \
list.$(OBJEXT) subnet_parse.$(OBJEXT) tincctl.$(OBJEXT) \
top.$(OBJEXT) names.$(OBJEXT)
nodist_tincctl_OBJECTS = ecdsagen.$(OBJEXT) rsagen.$(OBJEXT)
tincctl_OBJECTS = $(am_tincctl_OBJECTS) $(nodist_tincctl_OBJECTS)
am_tinc_OBJECTS = utils.$(OBJEXT) getopt.$(OBJEXT) getopt1.$(OBJEXT) \
dropin.$(OBJEXT) info.$(OBJEXT) list.$(OBJEXT) \
subnet_parse.$(OBJEXT) tincctl.$(OBJEXT) top.$(OBJEXT) \
names.$(OBJEXT)
nodist_tinc_OBJECTS = ecdsagen.$(OBJEXT) rsagen.$(OBJEXT)
tinc_OBJECTS = $(am_tinc_OBJECTS) $(nodist_tinc_OBJECTS)
am__DEPENDENCIES_1 =
tincctl_DEPENDENCIES = $(am__DEPENDENCIES_1) $(am__DEPENDENCIES_1)
tinc_DEPENDENCIES = $(am__DEPENDENCIES_1) $(am__DEPENDENCIES_1)
am__tincd_SOURCES_DIST = utils.c getopt.c getopt1.c list.c \
splay_tree.c dropin.c fake-getaddrinfo.c fake-getnameinfo.c \
hash.c buffer.c conf.c connection.c control.c edge.c graph.c \
@ -128,10 +128,9 @@ COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \
$(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS)
CCLD = $(CC)
LINK = $(CCLD) $(AM_CFLAGS) $(CFLAGS) $(AM_LDFLAGS) $(LDFLAGS) -o $@
SOURCES = $(sptps_test_SOURCES) $(tincctl_SOURCES) \
$(nodist_tincctl_SOURCES) $(tincd_SOURCES) \
$(nodist_tincd_SOURCES)
DIST_SOURCES = $(sptps_test_SOURCES) $(tincctl_SOURCES) \
SOURCES = $(sptps_test_SOURCES) $(tinc_SOURCES) $(nodist_tinc_SOURCES) \
$(tincd_SOURCES) $(nodist_tincd_SOURCES)
DIST_SOURCES = $(sptps_test_SOURCES) $(tinc_SOURCES) \
$(am__tincd_SOURCES_DIST)
am__can_run_installinfo = \
case $$AM_UPDATE_INFO_DIR in \
@ -258,18 +257,18 @@ tincd_SOURCES = utils.c getopt.c getopt1.c list.c splay_tree.c \
nodist_tincd_SOURCES = \
device.c cipher.c crypto.c ecdh.c ecdsa.c digest.c prf.c rsa.c
tincctl_SOURCES = \
tinc_SOURCES = \
utils.c getopt.c getopt1.c dropin.c \
info.c list.c subnet_parse.c tincctl.c top.c names.c
nodist_tincctl_SOURCES = \
nodist_tinc_SOURCES = \
ecdsagen.c rsagen.c
sptps_test_SOURCES = \
logger.c cipher.c crypto.c ecdh.c ecdsa.c digest.c prf.c \
sptps.c sptps_test.c utils.c
tincctl_LDADD = $(READLINE_LIBS) $(CURSES_LIBS)
tinc_LDADD = $(READLINE_LIBS) $(CURSES_LIBS)
DEFAULT_INCLUDES =
noinst_HEADERS = \
xalloc.h utils.h getopt.h list.h splay_tree.h dropin.h fake-getaddrinfo.h fake-getnameinfo.h fake-gai-errnos.h ipv6.h ipv4.h ethernet.h \
@ -357,9 +356,9 @@ clean-sbinPROGRAMS:
sptps_test$(EXEEXT): $(sptps_test_OBJECTS) $(sptps_test_DEPENDENCIES) $(EXTRA_sptps_test_DEPENDENCIES)
@rm -f sptps_test$(EXEEXT)
$(LINK) $(sptps_test_OBJECTS) $(sptps_test_LDADD) $(LIBS)
tincctl$(EXEEXT): $(tincctl_OBJECTS) $(tincctl_DEPENDENCIES) $(EXTRA_tincctl_DEPENDENCIES)
@rm -f tincctl$(EXEEXT)
$(LINK) $(tincctl_OBJECTS) $(tincctl_LDADD) $(LIBS)
tinc$(EXEEXT): $(tinc_OBJECTS) $(tinc_DEPENDENCIES) $(EXTRA_tinc_DEPENDENCIES)
@rm -f tinc$(EXEEXT)
$(LINK) $(tinc_OBJECTS) $(tinc_LDADD) $(LIBS)
tincd$(EXEEXT): $(tincd_OBJECTS) $(tincd_DEPENDENCIES) $(EXTRA_tincd_DEPENDENCIES)
@rm -f tincd$(EXEEXT)
$(LINK) $(tincd_OBJECTS) $(tincd_LDADD) $(LIBS)

View file

@ -245,6 +245,12 @@ bool event_loop(void) {
return true;
}
void event_flush_output(void) {
for splay_each(io_t, io, &io_tree)
if(FD_ISSET(io->fd, &writefds))
io->cb(io->data, IO_WRITE);
}
void event_exit(void) {
running = false;
}

View file

@ -65,6 +65,7 @@ extern void signal_add(signal_t *sig, signal_cb_t cb, void *data, int signum);
extern void signal_del(signal_t *sig);
extern bool event_loop(void);
extern void event_flush_output(void);
extern void event_exit(void);
#endif

View file

@ -204,7 +204,7 @@ static void check_reachability(void) {
for splay_each(node_t, n, node_tree) {
if(n->status.visited != n->status.reachable) {
n->status.reachable = !n->status.reachable;
n->last_state_change = time(NULL);
n->last_state_change = now.tv_sec;
if(n->status.reachable) {
logger(DEBUG_TRAFFIC, LOG_DEBUG, "Node %s (%s) became reachable",

View file

@ -80,6 +80,7 @@ static DWORD WINAPI tapreader(void *bla) {
packet.len = len;
packet.priority = 0;
route(myself, &packet);
event_flush_output();
LeaveCriticalSection(&mutex);
}
}

View file

@ -406,7 +406,7 @@ int reload_configuration(void) {
free(fname);
}
last_config_check = time(NULL);
last_config_check = now.tv_sec;
return 0;
}

View file

@ -135,6 +135,7 @@ extern int udp_sndbuf;
extern bool do_prune;
extern char *myport;
extern int autoconnect;
extern bool disablebuggypeers;
extern int contradicting_add_edge;
extern int contradicting_del_edge;
extern time_t last_config_check;

View file

@ -443,6 +443,9 @@ static void receive_udppacket(node_t *n, vpn_packet_t *inpkt) {
void receive_tcppacket(connection_t *c, const char *buffer, int len) {
vpn_packet_t outpkt;
if(len > sizeof outpkt.data)
return;
outpkt.len = len;
if(c->options & OPTION_TCPONLY)
outpkt.priority = 0;
@ -458,7 +461,7 @@ static void send_sptps_packet(node_t *n, vpn_packet_t *origpkt) {
logger(DEBUG_TRAFFIC, LOG_INFO, "No valid key known yet for %s (%s)", n->name, n->hostname);
if(!n->status.waitingforkey)
send_req_key(n);
else if(n->last_req_key + 10 < time(NULL)) {
else if(n->last_req_key + 10 < now.tv_sec) {
logger(DEBUG_ALWAYS, LOG_DEBUG, "No key from %s after 10 seconds, restarting SPTPS", n->name);
sptps_stop(&n->sptps);
n->status.waitingforkey = false;

View file

@ -52,6 +52,7 @@ char *proxyuser;
char *proxypass;
proxytype_t proxytype;
int autoconnect;
bool disablebuggypeers;
char *scriptinterpreter;
char *scriptextension;
@ -598,6 +599,8 @@ bool setup_myself_reloadable(void) {
get_config_int(lookup_config(config_tree, "AutoConnect"), &autoconnect);
get_config_bool(lookup_config(config_tree, "DisableBuggyPeers"), &disablebuggypeers);
return true;
}
@ -751,7 +754,7 @@ static bool setup_myself(void) {
myself->nexthop = myself;
myself->via = myself;
myself->status.reachable = true;
myself->last_state_change = time(NULL);
myself->last_state_change = now.tv_sec;
myself->status.sptps = experimental;
node_add(myself);
@ -958,7 +961,7 @@ static bool setup_myself(void) {
return false;
}
last_config_check = time(NULL);
last_config_check = now.tv_sec;
return true;
}

View file

@ -294,7 +294,7 @@ void retry_outgoing(outgoing_t *outgoing) {
void finish_connecting(connection_t *c) {
logger(DEBUG_CONNECTIONS, LOG_INFO, "Connected to %s (%s)", c->name, c->hostname);
c->last_ping_time = time(NULL);
c->last_ping_time = now.tv_sec;
c->status.connecting = false;
send_id(c);
@ -349,6 +349,9 @@ static void do_outgoing_pipe(connection_t *c, char *command) {
}
static void handle_meta_write(connection_t *c) {
if(c->outbuf.len <= c->outbuf.offset)
return;
ssize_t outlen = send(c->socket, c->outbuf.data + c->outbuf.offset, c->outbuf.len - c->outbuf.offset, 0);
if(outlen <= 0) {
if(!errno || errno == EPIPE) {
@ -505,7 +508,7 @@ begin:
c->outdigest = myself->connection->outdigest;
c->outmaclength = myself->connection->outmaclength;
c->outcompression = myself->connection->outcompression;
c->last_ping_time = time(NULL);
c->last_ping_time = now.tv_sec;
connection_add(c);
@ -568,7 +571,7 @@ void handle_new_meta_connection(void *data, int flags) {
c->address = sa;
c->hostname = sockaddr2hostname(&sa);
c->socket = fd;
c->last_ping_time = time(NULL);
c->last_ping_time = now.tv_sec;
logger(DEBUG_CONNECTIONS, LOG_NOTICE, "Connection from %s", c->hostname);
@ -607,7 +610,7 @@ void handle_new_unix_connection(void *data, int flags) {
c->address = sa;
c->hostname = xstrdup("localhost port unix");
c->socket = fd;
c->last_ping_time = time(NULL);
c->last_ping_time = now.tv_sec;
logger(DEBUG_CONNECTIONS, LOG_NOTICE, "Connection from %s", c->hostname);

View file

@ -195,7 +195,7 @@ bool seen_request(const char *request) {
} else {
new = xmalloc(sizeof *new);
new->request = xstrdup(request);
new->firstseen = time(NULL);
new->firstseen = now.tv_sec;
splay_insert(past_request_tree, new);
timeout_add(&past_request_timeout, age_past_requests, NULL, &(struct timeval){10, rand() % 100000});
return false;

View file

@ -160,7 +160,7 @@ bool id_h(connection_t *c, const char *request) {
if(name[0] == '^' && !strcmp(name + 1, controlcookie)) {
c->status.control = true;
c->allow_request = CONTROL;
c->last_ping_time = time(NULL) + 3600;
c->last_ping_time = now.tv_sec + 3600;
free(c->name);
c->name = xstrdup("<control>");
@ -510,6 +510,17 @@ bool send_ack(connection_t *c) {
static void send_everything(connection_t *c) {
/* Send all known subnets and edges */
if(disablebuggypeers) {
static struct {
vpn_packet_t pkt;
char pad[MAXBUFSIZE - MAXSIZE];
} zeropkt;
memset(&zeropkt, 0, sizeof zeropkt);
zeropkt.pkt.len = MAXBUFSIZE;
send_tcppacket(c, &zeropkt.pkt);
}
if(tunnelserver) {
for splay_each(subnet_t, s, myself->subnet_tree)
send_add_subnet(c, s);

View file

@ -111,7 +111,7 @@ bool send_req_key(node_t *to) {
sptps_stop(&to->sptps);
to->status.validkey = false;
to->status.waitingforkey = true;
to->last_req_key = time(NULL);
to->last_req_key = now.tv_sec;
to->incompression = myself->incompression;
return sptps_start(&to->sptps, to, true, true, myself->connection->ecdsa, to->ecdsa, label, sizeof label, send_initial_sptps_data, receive_sptps_record);
}
@ -169,7 +169,7 @@ static bool req_key_ext_h(connection_t *c, const char *request, node_t *from, in
sptps_stop(&from->sptps);
from->status.validkey = false;
from->status.waitingforkey = true;
from->last_req_key = time(NULL);
from->last_req_key = now.tv_sec;
sptps_start(&from->sptps, from, false, true, myself->connection->ecdsa, from->ecdsa, label, sizeof label, send_sptps_data, receive_sptps_record);
sptps_receive_data(&from->sptps, buf, len);
return true;

View file

@ -89,7 +89,7 @@ bool termreq_h(connection_t *c, const char *request) {
bool send_ping(connection_t *c) {
c->status.pinged = true;
c->last_ping_time = time(NULL);
c->last_ping_time = now.tv_sec;
return send_request(c, "%d", PING);
}

View file

@ -229,7 +229,7 @@ static void learn_mac(mac_t *address) {
subnet = new_subnet();
subnet->type = SUBNET_MAC;
subnet->expires = time(NULL) + macexpire;
subnet->expires = now.tv_sec + macexpire;
subnet->net.mac.address = *address;
subnet->weight = 10;
subnet_add(myself, subnet);
@ -244,7 +244,7 @@ static void learn_mac(mac_t *address) {
timeout_add(&age_subnets_timeout, age_subnets, NULL, &(struct timeval){10, rand() % 100000});
} else {
if(subnet->expires)
subnet->expires = time(NULL) + macexpire;
subnet->expires = now.tv_sec + macexpire;
}
}

View file

@ -77,8 +77,8 @@ int main(int argc, char *argv[]) {
memset(&hint, 0, sizeof hint);
hint.ai_family = AF_UNSPEC;
hint.ai_socktype = SOCK_STREAM;
hint.ai_protocol = IPPROTO_TCP;
hint.ai_socktype = datagram ? SOCK_DGRAM : SOCK_STREAM;
hint.ai_protocol = datagram ? IPPROTO_UDP : IPPROTO_TCP;
hint.ai_flags = initiator ? 0 : AI_PASSIVE;
if(getaddrinfo(initiator ? argv[3] : NULL, initiator ? argv[4] : argv[3], &hint, &ai) || !ai) {
@ -86,7 +86,7 @@ int main(int argc, char *argv[]) {
return 1;
}
int sock = socket(ai->ai_family, SOCK_STREAM, IPPROTO_TCP);
int sock = socket(ai->ai_family, ai->ai_socktype, ai->ai_protocol);
if(sock < 0) {
fprintf(stderr, "Could not create socket: %s\n", strerror(errno));
return 1;
@ -106,16 +106,35 @@ int main(int argc, char *argv[]) {
fprintf(stderr, "Could not bind socket: %s\n", strerror(errno));
return 1;
}
if(listen(sock, 1)) {
fprintf(stderr, "Could not listen on socket: %s\n", strerror(errno));
return 1;
}
fprintf(stderr, "Listening...\n");
sock = accept(sock, NULL, NULL);
if(sock < 0) {
fprintf(stderr, "Could not accept connection: %s\n", strerror(errno));
return 1;
if(!datagram) {
if(listen(sock, 1)) {
fprintf(stderr, "Could not listen on socket: %s\n", strerror(errno));
return 1;
}
fprintf(stderr, "Listening...\n");
sock = accept(sock, NULL, NULL);
if(sock < 0) {
fprintf(stderr, "Could not accept connection: %s\n", strerror(errno));
return 1;
}
} else {
fprintf(stderr, "Listening...\n");
char buf[65536];
struct sockaddr addr;
socklen_t addrlen = sizeof addr;
if(recvfrom(sock, buf, sizeof buf, MSG_PEEK, &addr, &addrlen) <= 0) {
fprintf(stderr, "Could not read from socket: %s\n", strerror(errno));
return 1;
}
if(connect(sock, &addr, addrlen)) {
fprintf(stderr, "Could not accept connection: %s\n", strerror(errno));
return 1;
}
}
fprintf(stderr, "Connected\n");

View file

@ -112,11 +112,10 @@ static void usage(bool status) {
"\n"
"Valid commands are:\n"
" init [name] Create initial configuration files.\n"
" config Change configuration:\n"
" [get] VARIABLE - print current value of VARIABLE\n"
" [set] VARIABLE VALUE - set VARIABLE to VALUE\n"
" add VARIABLE VALUE - add VARIABLE with the given VALUE\n"
" del VARIABLE [VALUE] - remove VARIABLE [only ones with watching VALUE]\n"
" get VARIABLE Print current value of VARIABLE\n"
" set VARIABLE VALUE Set VARIABLE to VALUE\n"
" add VARIABLE VALUE Add VARIABLE with the given VALUE\n"
" del VARIABLE [VALUE] Remove VARIABLE [only ones with watching VALUE]\n"
" start [tincd options] Start tincd.\n"
" stop Stop tincd.\n"
" restart Restart tincd.\n"
@ -1148,7 +1147,7 @@ static int cmd_top(int argc, char *argv[]) {
top(fd);
return 0;
#else
fprintf(stderr, "This version of tincctl was compiled without support for the curses library.\n");
fprintf(stderr, "This version of tinc was compiled without support for the curses library.\n");
return 1;
#endif
}
@ -1199,10 +1198,11 @@ static int rstrip(char *value) {
return len;
}
static char *get_my_name() {
static char *get_my_name(bool verbose) {
FILE *f = fopen(tinc_conf, "r");
if(!f) {
fprintf(stderr, "Could not open %s: %s\n", tinc_conf, strerror(errno));
if(verbose)
fprintf(stderr, "Could not open %s: %s\n", tinc_conf, strerror(errno));
return NULL;
}
@ -1228,7 +1228,8 @@ static char *get_my_name() {
}
fclose(f);
fprintf(stderr, "Could not find Name in %s.\n", tinc_conf);
if(verbose)
fprintf(stderr, "Could not find Name in %s.\n", tinc_conf);
return NULL;
}
@ -1309,6 +1310,9 @@ static int cmd_config(int argc, char *argv[]) {
return 1;
}
if(strcasecmp(argv[0], "config"))
argv--, argc++;
int action = -2;
if(!strcasecmp(argv[1], "get")) {
argv++, argc--;
@ -1402,7 +1406,7 @@ static int cmd_config(int argc, char *argv[]) {
/* Should this go into our own host config file? */
if(!node && !(variables[i].type & VAR_SERVER)) {
node = get_my_name();
node = get_my_name(true);
if(!node)
return 1;
}
@ -1692,6 +1696,9 @@ static int cmd_generate_keys(int argc, char *argv[]) {
return 1;
}
if(!name)
name = get_my_name(false);
return !(rsa_keygen(argc > 1 ? atoi(argv[1]) : 2048, true) && ecdsa_keygen(true));
}
@ -1701,6 +1708,9 @@ static int cmd_generate_rsa_keys(int argc, char *argv[]) {
return 1;
}
if(!name)
name = get_my_name(false);
return !rsa_keygen(argc > 1 ? atoi(argv[1]) : 2048, true);
}
@ -1710,6 +1720,9 @@ static int cmd_generate_ecdsa_keys(int argc, char *argv[]) {
return 1;
}
if(!name)
name = get_my_name(false);
return !ecdsa_keygen(true);
}
@ -1831,7 +1844,7 @@ static int cmd_export(int argc, char *argv[]) {
return 1;
}
char *name = get_my_name();
char *name = get_my_name(true);
if(!name)
return 1;
@ -1961,6 +1974,7 @@ static int cmd_exchange_all(int argc, char *argv[]) {
static const struct {
const char *command;
int (*function)(int argc, char *argv[]);
bool hidden;
} commands[] = {
{"start", cmd_start},
{"stop", cmd_stop},
@ -1976,7 +1990,11 @@ static const struct {
{"pcap", cmd_pcap},
{"log", cmd_log},
{"pid", cmd_pid},
{"config", cmd_config},
{"config", cmd_config, true},
{"add", cmd_config},
{"del", cmd_config},
{"get", cmd_config},
{"set", cmd_config},
{"init", cmd_init},
{"generate-keys", cmd_generate_keys},
{"generate-rsa-keys", cmd_generate_rsa_keys},
@ -2003,7 +2021,7 @@ static char *complete_command(const char *text, int state) {
i++;
while(commands[i].command) {
if(!strncasecmp(commands[i].command, text, strlen(text)))
if(!commands[i].hidden && !strncasecmp(commands[i].command, text, strlen(text)))
return xstrdup(commands[i].command);
i++;
}
@ -2030,42 +2048,24 @@ static char *complete_dump(const char *text, int state) {
}
static char *complete_config(const char *text, int state) {
const char *sub[] = {"get", "set", "add", "del"};
static int i;
if(!state) {
i = 0;
if(!strchr(rl_line_buffer + 7, ' '))
i = -4;
else {
bool found = false;
for(int i = 0; i < 4; i++) {
if(!strncasecmp(rl_line_buffer + 7, sub[i], strlen(sub[i])) && rl_line_buffer[7 + strlen(sub[i])] == ' ') {
found = true;
break;
}
}
if(!found)
return NULL;
}
} else {
i++;
}
while(i < 0 || variables[i].name) {
if(i < 0 && !strncasecmp(sub[i + 4], text, strlen(text)))
return xstrdup(sub[i + 4]);
if(i >= 0) {
char *dot = strchr(text, '.');
if(dot) {
if((variables[i].type & VAR_HOST) && !strncasecmp(variables[i].name, dot + 1, strlen(dot + 1))) {
char *match;
xasprintf(&match, "%.*s.%s", dot - text, text, variables[i].name);
return match;
}
} else {
if(!strncasecmp(variables[i].name, text, strlen(text)))
return xstrdup(variables[i].name);
if(!state)
i = 0;
else
i++;
while(variables[i].name) {
char *dot = strchr(text, '.');
if(dot) {
if((variables[i].type & VAR_HOST) && !strncasecmp(variables[i].name, dot + 1, strlen(dot + 1))) {
char *match;
xasprintf(&match, "%.*s.%s", dot - text, text, variables[i].name);
return match;
}
} else {
if(!strncasecmp(variables[i].name, text, strlen(text)))
return xstrdup(variables[i].name);
}
i++;
}
@ -2118,7 +2118,13 @@ static char **completion (const char *text, int start, int end) {
matches = rl_completion_matches(text, complete_command);
else if(!strncasecmp(rl_line_buffer, "dump ", 5))
matches = rl_completion_matches(text, complete_dump);
else if(!strncasecmp(rl_line_buffer, "config ", 7))
else if(!strncasecmp(rl_line_buffer, "add ", 4))
matches = rl_completion_matches(text, complete_config);
else if(!strncasecmp(rl_line_buffer, "del ", 4))
matches = rl_completion_matches(text, complete_config);
else if(!strncasecmp(rl_line_buffer, "get ", 4))
matches = rl_completion_matches(text, complete_config);
else if(!strncasecmp(rl_line_buffer, "set ", 4))
matches = rl_completion_matches(text, complete_config);
else if(!strncasecmp(rl_line_buffer, "info ", 5))
matches = rl_completion_matches(text, complete_info);

View file

@ -346,7 +346,8 @@ int main(int argc, char **argv) {
/* Slllluuuuuuurrrrp! */
srand(time(NULL));
gettimeofday(&now, NULL);
srand(now.tv_sec + now.tv_usec);
crypto_init();
if(!read_server_config())