/*
tincctl.c -- Controlling a running tincd
- Copyright (C) 2007-2009 Guus Sliepen <guus@tinc-vpn.org>
+ Copyright (C) 2007-2011 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
#include "control_common.h"
#include "rsagen.h"
#include "utils.h"
+#include "tincctl.h"
+#include "top.h"
/* The name this program was run with. */
-char *program_name = NULL;
+static char *program_name = NULL;
/* If nonzero, display usage information and exit. */
-bool show_help = false;
+static bool show_help = false;
/* If nonzero, print the version on standard output and exit. */
-bool show_version = false;
+static bool show_version = false;
/* If nonzero, it will attempt to kill a running tincd and exit. */
-int kill_tincd = 0;
+static int kill_tincd = 0;
/* If nonzero, generate public/private keypair for this host/net. */
-int generate_keys = 0;
+static int generate_keys = 0;
static char *name = NULL;
static char *identname = NULL; /* program name for syslog */
{"net", required_argument, NULL, 'n'},
{"help", no_argument, NULL, 1},
{"version", no_argument, NULL, 2},
- {"controlsocket", required_argument, NULL, 5},
+ {"controlcookie", required_argument, NULL, 5},
{NULL, 0, NULL, 0}
};
" debug N Set debug level\n"
" retry Retry all outgoing connections\n"
" reload Partial reload of configuration\n"
+ " disconnect NODE Close meta connection with NODE\n"
+#ifdef HAVE_CURSES
+ " top Show real-time statistics\n"
+#endif
+ " pcap Dump traffic in pcap format\n"
"\n");
printf("Report bugs to tinc@tinc-vpn.org.\n");
}
#endif
if(!controlcookiename)
- xasprintf(&controlcookiename, "%s/run/%s.control/socket", LOCALSTATEDIR, identname);
+ xasprintf(&controlcookiename, "%s/run/%s.cookie", LOCALSTATEDIR, identname);
if(netname) {
if(!confbase)
}
}
-static bool recvline(int fd, char *line, size_t len) {
- static char buffer[4096];
- static size_t blen = 0;
+static char buffer[4096];
+static size_t blen = 0;
+
+bool recvline(int fd, char *line, size_t len) {
char *newline = NULL;
while(!(newline = memchr(buffer, '\n', blen))) {
return true;
}
-static bool sendline(int fd, char *format, ...) {
+bool recvdata(int fd, char *data, size_t len) {
+ while(blen < len) {
+ int result = recv(fd, buffer + blen, sizeof buffer - blen, 0);
+ if(result == -1 && errno == EINTR)
+ continue;
+ else if(result <= 0)
+ return false;
+ blen += result;
+ }
+
+ memcpy(data, buffer, len);
+ memmove(buffer, buffer + len, blen - len);
+ blen -= len;
+
+ return true;
+}
+
+bool sendline(int fd, char *format, ...) {
static char buffer[4096];
char *p = buffer;
size_t blen = 0;
return true;
}
+void pcap(int fd, FILE *out) {
+ sendline(fd, "%d %d", CONTROL, REQ_PCAP);
+ char data[9018];
+
+ struct {
+ uint32_t magic;
+ uint16_t major;
+ uint16_t minor;
+ uint32_t tz_offset;
+ uint32_t tz_accuracy;
+ uint32_t snaplen;
+ uint32_t ll_type;
+ } header = {
+ 0xa1b2c3d4,
+ 2, 4,
+ 0, 0,
+ sizeof data,
+ 1,
+ };
+
+ struct {
+ uint32_t tv_sec;
+ uint32_t tv_usec;
+ uint32_t len;
+ uint32_t origlen;
+ } packet;
+
+ struct timeval tv;
+
+ fwrite(&header, sizeof header, 1, out);
+ fflush(out);
+
+ char line[32];
+ while(recvline(fd, line, sizeof line)) {
+ int code, req, len;
+ int n = sscanf(line, "%d %d %d", &code, &req, &len);
+ gettimeofday(&tv, NULL);
+ if(n != 3 || code != CONTROL || req != REQ_PCAP || len < 0 || len > sizeof data)
+ break;
+ if(!recvdata(fd, data, len))
+ break;
+ packet.tv_sec = tv.tv_sec;
+ packet.tv_usec = tv.tv_usec;
+ packet.len = len;
+ packet.origlen = len;
+ fwrite(&packet, sizeof packet, 1, out);
+ fwrite(data, len, 1, out);
+ fflush(out);
+ }
+}
+
int main(int argc, char *argv[], char *envp[]) {
int fd;
int result;
return 1;
}
+#ifdef HAVE_MINGW
unsigned long arg = 0;
if(ioctlsocket(fd, FIONBIO, &arg) != 0) {
fprintf(stderr, "ioctlsocket failed: %s", sockstrerror(sockerrno));
}
+#endif
if(connect(fd, (struct sockaddr *)&addr, sizeof addr) < 0) {
}
bool do_graph = false;
- int dumps = 1;
if(!strcasecmp(argv[optind+1], "nodes"))
sendline(fd, "%d %d", CONTROL, REQ_DUMP_NODES);
sendline(fd, "%d %d", CONTROL, REQ_DUMP_NODES);
sendline(fd, "%d %d", CONTROL, REQ_DUMP_EDGES);
do_graph = true;
- dumps = 2;
printf("digraph {\n");
} else {
fprintf(stderr, "Unknown dump type '%s'.\n", argv[optind+1]);
while(recvline(fd, line, sizeof line)) {
char node1[4096], node2[4096];
- int n = sscanf(line, "%d %d %s to %s", &code, &req, &node1, &node2);
+ int n = sscanf(line, "%d %d %s to %s", &code, &req, node1, node2);
if(n == 2) {
if(do_graph && req == REQ_DUMP_NODES)
continue;
debuglevel = atoi(argv[optind+1]);
sendline(fd, "%d %d %d", CONTROL, REQ_SET_DEBUG, debuglevel);
- if(!recvline(fd, line, sizeof line) || sscanf(line, "%d %d %d", &code, &req, &result) != 3 || code != CONTROL || req != REQ_SET_DEBUG) {
+ if(!recvline(fd, line, sizeof line) || sscanf(line, "%d %d %d", &code, &req, &origlevel) != 3 || code != CONTROL || req != REQ_SET_DEBUG) {
fprintf(stderr, "Could not purge tinc daemon\n");
return 1;
}
return 0;
}
+ if(!strcasecmp(argv[optind], "connect")) {
+ if(argc != optind + 2) {
+ fprintf(stderr, "Invalid arguments.\n");
+ return 1;
+ }
+ char *name = argv[optind + 1];
+
+ sendline(fd, "%d %d %s", CONTROL, REQ_CONNECT, name);
+ if(!recvline(fd, line, sizeof line) || sscanf(line, "%d %d %d", &code, &req, &result) != 3 || code != CONTROL || req != REQ_CONNECT || result) {
+ fprintf(stderr, "Could not connect to %s\n", name);
+ return 1;
+ }
+ return 0;
+ }
+
+ if(!strcasecmp(argv[optind], "disconnect")) {
+ if(argc != optind + 2) {
+ fprintf(stderr, "Invalid arguments.\n");
+ return 1;
+ }
+ char *name = argv[optind + 1];
+
+ sendline(fd, "%d %d %s", CONTROL, REQ_DISCONNECT, name);
+ if(!recvline(fd, line, sizeof line) || sscanf(line, "%d %d %d", &code, &req, &result) != 3 || code != CONTROL || req != REQ_DISCONNECT || result) {
+ fprintf(stderr, "Could not disconnect %s\n", name);
+ return 1;
+ }
+ return 0;
+ }
+
+#ifdef HAVE_CURSES
+ if(!strcasecmp(argv[optind], "top")) {
+ top(fd);
+ return 0;
+ }
+#endif
+
+ if(!strcasecmp(argv[optind], "pcap")) {
+ pcap(fd, stdout);
+ return 0;
+ }
+
fprintf(stderr, "Unknown command `%s'.\n", argv[optind]);
usage(true);