Add the ability to dump all traffic going through route() over a control connection.

One can get the packet stream in pcap format, which can be decoded using
tcpdump, for example:

tincctl -n <netname> pcap | tcpdump -r -
This commit is contained in:
Guus Sliepen 2011-05-22 14:17:30 +02:00
parent 54c900e961
commit 453c44e7b2
6 changed files with 109 additions and 3 deletions

View file

@ -43,7 +43,8 @@ typedef struct connection_status_t {
int decryptin:1; /* 1 if we have to decrypt incoming traffic */
int mst:1; /* 1 if this connection is part of a minimum spanning tree */
int control:1;
int unused:22;
int pcap:1;
int unused:21;
} connection_status_t;
#include "edge.h"

View file

@ -24,7 +24,11 @@
#include "control_common.h"
#include "graph.h"
#include "logger.h"
#include "meta.h"
#include "net.h"
#include "protocol.h"
#include "route.h"
#include "splay_tree.h"
#include "utils.h"
#include "xalloc.h"
@ -116,6 +120,11 @@ bool control_h(connection_t *c, char *request) {
case REQ_DUMP_TRAFFIC:
return dump_traffic(c);
case REQ_PCAP:
c->status.pcap = true;
pcap = true;
return true;
default:
return send_request(c, "%d %d", CONTROL, REQ_INVALID);
}

View file

@ -38,6 +38,7 @@ enum request_type {
REQ_CONNECT,
REQ_DISCONNECT,
REQ_DUMP_TRAFFIC,
REQ_PCAP,
};
#define TINC_CTL_VERSION_CURRENT 0

View file

@ -22,10 +22,12 @@
#include "splay_tree.h"
#include "connection.h"
#include "control_common.h"
#include "ethernet.h"
#include "ipv4.h"
#include "ipv6.h"
#include "logger.h"
#include "meta.h"
#include "net.h"
#include "protocol.h"
#include "route.h"
@ -39,6 +41,7 @@ bool priorityinheritance = false;
int macexpire = 600;
bool overwrite_mac = false;
mac_t mymac = {{0xFE, 0xFD, 0, 0, 0, 0}};
bool pcap = false;
/* Sizes of various headers */
@ -860,7 +863,23 @@ static void route_mac(node_t *source, vpn_packet_t *packet) {
send_packet(subnet->owner, packet);
}
static void send_pcap(vpn_packet_t *packet) {
pcap = false;
for(splay_node_t *node = connection_tree->head; node; node = node->next) {
connection_t *c = node->data;
if(!c->status.pcap)
continue;
else
pcap = true;
if(send_request(c, "%d %d %d", CONTROL, REQ_PCAP, packet->len))
send_meta(c, (char *)packet->data, packet->len);
}
}
void route(node_t *source, vpn_packet_t *packet) {
if(pcap)
send_pcap(packet);
if(forwarding_mode == FMODE_KERNEL && source != myself) {
send_packet(myself, packet);
return;

View file

@ -42,6 +42,7 @@ extern bool directonly;
extern bool overwrite_mac;
extern bool priorityinheritance;
extern int macexpire;
extern bool pcap;
extern mac_t mymac;

View file

@ -98,6 +98,7 @@ static void usage(bool status) {
#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");
}
@ -301,9 +302,10 @@ static void make_names(void) {
}
}
static char buffer[4096];
static size_t blen = 0;
bool recvline(int fd, char *line, size_t len) {
static char buffer[4096];
static size_t blen = 0;
char *newline = NULL;
while(!(newline = memchr(buffer, '\n', blen))) {
@ -328,6 +330,23 @@ bool recvline(int fd, char *line, size_t len) {
return true;
}
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;
@ -357,6 +376,57 @@ bool sendline(int fd, char *format, ...) {
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;
@ -636,6 +706,11 @@ int main(int argc, char *argv[], char *envp[]) {
}
#endif
if(!strcasecmp(argv[optind], "pcap")) {
pcap(fd, stdout);
return 0;
}
fprintf(stderr, "Unknown command `%s'.\n", argv[optind]);
usage(true);