--- /dev/null
+/*
+ dropin.c -- a set of drop-in replacements for libc functions
+ Copyright (C) 2000-2005 Ivo Timmermans,
+ 2000-2009 Guus Sliepen <guus@tinc-vpn.org>
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License along
+ with this program; if not, write to the Free Software Foundation, Inc.,
+ 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+*/
+
+#include "system.h"
+
+#include "xalloc.h"
+
+#ifndef HAVE_DAEMON
+/*
+ Replacement for the daemon() function.
+
+ The daemon() function is for programs wishing to detach themselves
+ from the controlling terminal and run in the background as system
+ daemons.
+
+ Unless the argument nochdir is non-zero, daemon() changes the
+ current working directory to the root (``/'').
+
+ Unless the argument noclose is non-zero, daemon() will redirect
+ standard input, standard output and standard error to /dev/null.
+*/
+int daemon(int nochdir, int noclose) {
+#ifdef HAVE_FORK
+ pid_t pid;
+ int fd;
+
+ pid = fork();
+
+ /* Check if forking failed */
+ if(pid < 0) {
+ perror("fork");
+ exit(-1);
+ }
+
+ /* If we are the parent, terminate */
+ if(pid)
+ exit(0);
+
+ /* Detach by becoming the new process group leader */
+ if(setsid() < 0) {
+ perror("setsid");
+ return -1;
+ }
+
+ /* Change working directory to the root (to avoid keeping mount
+ points busy) */
+ if(!nochdir) {
+ chdir("/");
+ }
+
+ /* Redirect stdin/out/err to /dev/null */
+ if(!noclose) {
+ fd = open("/dev/null", O_RDWR);
+
+ if(fd < 0) {
+ perror("opening /dev/null");
+ return -1;
+ } else {
+ dup2(fd, 0);
+ dup2(fd, 1);
+ dup2(fd, 2);
+ }
+ }
+
+ return 0;
+#else
+ return -1;
+#endif
+}
+#endif
+
+#ifndef HAVE_GET_CURRENT_DIR_NAME
+/*
+ Replacement for the GNU get_current_dir_name function:
+
+ get_current_dir_name will malloc(3) an array big enough to hold the
+ current directory name. If the environment variable PWD is set, and
+ its value is correct, then that value will be returned.
+*/
+char *get_current_dir_name(void) {
+ size_t size;
+ char *buf;
+ char *r;
+
+ /* Start with 100 bytes. If this turns out to be insufficient to
+ contain the working directory, double the size. */
+ size = 100;
+ buf = xmalloc(size);
+
+ errno = 0; /* Success */
+ r = getcwd(buf, size);
+
+ /* getcwd returns NULL and sets errno to ERANGE if the bufferspace
+ is insufficient to contain the entire working directory. */
+ while(r == NULL && errno == ERANGE) {
+ free(buf);
+ size <<= 1; /* double the size */
+ buf = xmalloc(size);
+ r = getcwd(buf, size);
+ }
+
+ return buf;
+}
+#endif
+
+#ifndef HAVE_ASPRINTF
+int asprintf(char **buf, const char *fmt, ...) {
+ int result;
+ va_list ap;
+ va_start(ap, fmt);
+ result = vasprintf(buf, fmt, ap);
+ va_end(ap);
+ return result;
+}
+
+int vasprintf(char **buf, const char *fmt, va_list ap) {
+ int status;
+ va_list aq;
+ int len;
+
+ len = 4096;
+ *buf = xmalloc(len);
+
+ va_copy(aq, ap);
+ status = vsnprintf(*buf, len, fmt, aq);
+ va_end(aq);
+
+ if(status >= 0)
+ *buf = xrealloc(*buf, status + 1);
+
+ if(status > len - 1) {
+ len = status;
+ va_copy(aq, ap);
+ status = vsnprintf(*buf, len, fmt, aq);
+ va_end(aq);
+ }
+
+ return status;
+}
+#endif
+
+#ifndef HAVE_GETTIMEOFDAY
+int gettimeofday(struct timeval *tv, void *tz) {
+ tv->tv_sec = time(NULL);
+ tv->tv_usec = 0;
+ return 0;
+}
+#endif
++
++#ifdef HAVE_MINGW
++int usleep(long usec) {
++ Sleep(usec / 1000);
++ return 0;
++}
++#endif
extern listen_socket_t listen_socket[MAXSOCKETS];
extern int listen_sockets;
-extern int keyexpires;
extern int keylifetime;
+ extern int udp_rcvbuf;
+ extern int udp_sndbuf;
extern bool do_prune;
-extern bool do_purge;
extern char *myport;
-extern time_t now;
extern int contradicting_add_edge;
extern int contradicting_del_edge;
/* Check the sequence number */
- inpkt->len -= sizeof(inpkt->seqno);
+ inpkt->len -= sizeof inpkt->seqno;
inpkt->seqno = ntohl(inpkt->seqno);
- if(inpkt->seqno != n->received_seqno + 1) {
- if(inpkt->seqno >= n->received_seqno + sizeof n->late * 8) {
- logger(LOG_WARNING, "Lost %d packets from %s (%s)",
- inpkt->seqno - n->received_seqno - 1, n->name, n->hostname);
-
- memset(n->late, 0, sizeof n->late);
- } else if (inpkt->seqno <= n->received_seqno) {
- if((n->received_seqno >= sizeof n->late * 8 && inpkt->seqno <= n->received_seqno - sizeof n->late * 8) || !(n->late[(inpkt->seqno / 8) % sizeof n->late] & (1 << inpkt->seqno % 8))) {
- logger(LOG_WARNING, "Got late or replayed packet from %s (%s), seqno %d, last received %d",
- n->name, n->hostname, inpkt->seqno, n->received_seqno);
- return;
+ if(replaywin) {
+ if(inpkt->seqno != n->received_seqno + 1) {
+ if(inpkt->seqno >= n->received_seqno + replaywin * 8) {
+ if(n->farfuture++ < replaywin >> 2) {
+ logger(LOG_WARNING, "Packet from %s (%s) is %d seqs in the future, dropped (%u)",
+ n->name, n->hostname, inpkt->seqno - n->received_seqno - 1, n->farfuture);
+ return;
+ }
+ logger(LOG_WARNING, "Lost %d packets from %s (%s)",
+ inpkt->seqno - n->received_seqno - 1, n->name, n->hostname);
+ memset(n->late, 0, replaywin);
+ } else if (inpkt->seqno <= n->received_seqno) {
+ if((n->received_seqno >= replaywin * 8 && inpkt->seqno <= n->received_seqno - replaywin * 8) || !(n->late[(inpkt->seqno / 8) % replaywin] & (1 << inpkt->seqno % 8))) {
+ logger(LOG_WARNING, "Got late or replayed packet from %s (%s), seqno %d, last received %d",
+ n->name, n->hostname, inpkt->seqno, n->received_seqno);
+ return;
+ }
+ } else {
+ for(i = n->received_seqno + 1; i < inpkt->seqno; i++)
+ n->late[(i / 8) % replaywin] |= 1 << i % 8;
}
- } else {
- for(i = n->received_seqno + 1; i < inpkt->seqno; i++)
- n->late[(i / 8) % sizeof n->late] |= 1 << i % 8;
}
+
+ n->farfuture = 0;
+ n->late[(inpkt->seqno / 8) % replaywin] &= ~(1 << inpkt->seqno % 8);
}
-
- n->late[(inpkt->seqno / 8) % sizeof n->late] &= ~(1 << inpkt->seqno % 8);
if(inpkt->seqno > n->received_seqno)
n->received_seqno = inpkt->seqno;
#endif
option = 1;
- setsockopt(nfd, SOL_SOCKET, SO_REUSEADDR, (void *)&option, sizeof(option));
+ setsockopt(nfd, SOL_SOCKET, SO_REUSEADDR, (void *)&option, sizeof option);
+ if(udp_rcvbuf && setsockopt(nfd, SOL_SOCKET, SO_RCVBUF, (void *)&udp_rcvbuf, sizeof(udp_rcvbuf)))
+ logger(LOG_WARNING, "Can't set UDP SO_RCVBUF to %i: %s", udp_rcvbuf, strerror(errno));
+
+ if(udp_sndbuf && setsockopt(nfd, SOL_SOCKET, SO_SNDBUF, (void *)&udp_sndbuf, sizeof(udp_sndbuf)))
+ logger(LOG_WARNING, "Can't set UDP SO_SNDBUF to %i: %s", udp_sndbuf, strerror(errno));
+
#if defined(IPPROTO_IPV6) && defined(IPV6_V6ONLY)
if(sa->sa.sa_family == AF_INET6)
setsockopt(nfd, IPPROTO_IPV6, IPV6_V6ONLY, (void *)&option, sizeof option);
}
node_t *new_node(void) {
- node_t *n = xmalloc_and_zero(sizeof(*n));
+ node_t *n = xmalloc_and_zero(sizeof *n);
+ if(replaywin) n->late = xmalloc_and_zero(replaywin);
n->subnet_tree = new_subnet_tree();
n->edge_tree = new_edge_tree();
- EVP_CIPHER_CTX_init(&n->inctx);
- EVP_CIPHER_CTX_init(&n->outctx);
n->mtu = MTU;
n->maxmtu = MTU;
// Reset sequence number and late packet window
mykeyused = true;
to->received_seqno = 0;
- memset(to->late, 0, sizeof(to->late));
+ if(replaywin) memset(to->late, 0, replaywin);
- // Convert to hexadecimal and send
- char key[2 * to->inkeylength + 1];
- bin2hex(to->inkey, key, to->inkeylength);
- key[to->inkeylength * 2] = '\0';
-
- return send_request(to->nexthop->connection, "%d %s %s %s %d %d %d %d", ANS_KEY,
- myself->name, to->name, key,
- to->incipher ? to->incipher->nid : 0,
- to->indigest ? to->indigest->type : 0, to->inmaclength,
- to->incompression);
+ return send_request(to->nexthop->connection, "%d %s %s %s %d %d %zu %d", ANS_KEY,
+ myself->name, to->name, key,
+ cipher_get_nid(&to->incipher),
+ digest_get_nid(&to->indigest),
+ digest_length(&to->indigest),
+ to->incompression);
}
-bool ans_key_h(connection_t *c) {
+bool ans_key_h(connection_t *c, char *request) {
char from_name[MAX_STRING_SIZE];
char to_name[MAX_STRING_SIZE];
char key[MAX_STRING_SIZE];