#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"
int macexpire = 600;
bool overwrite_mac = false;
mac_t mymac = {{0xFE, 0xFD, 0, 0, 0, 0}};
+bool pcap = false;
/* Sizes of various headers */
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;
#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");
}
}
}
+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))) {
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;
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;
}
#endif
+ if(!strcasecmp(argv[optind], "pcap")) {
+ pcap(fd, stdout);
+ return 0;
+ }
+
fprintf(stderr, "Unknown command `%s'.\n", argv[optind]);
usage(true);