summaryrefslogtreecommitdiffstats
path: root/traceroute/mod-raw.c
diff options
context:
space:
mode:
Diffstat (limited to 'traceroute/mod-raw.c')
-rw-r--r--traceroute/mod-raw.c163
1 files changed, 163 insertions, 0 deletions
diff --git a/traceroute/mod-raw.c b/traceroute/mod-raw.c
new file mode 100644
index 0000000..8eaac35
--- /dev/null
+++ b/traceroute/mod-raw.c
@@ -0,0 +1,163 @@
+/*
+ Copyright (c) 2006, 2007 Dmitry Butskoy
+ <dmitry@butskoy.name>
+ License: GPL v2 or any later
+
+ See COPYING for the status of this software.
+*/
+
+#include <stdlib.h>
+#include <unistd.h>
+#include <sys/socket.h>
+#include <poll.h>
+#include <netinet/icmp6.h>
+#include <netinet/ip_icmp.h>
+#include <netinet/in.h>
+#include <netinet/ip.h>
+#include <netinet/ip6.h>
+#include <netdb.h>
+
+#include "traceroute.h"
+
+
+static sockaddr_any dest_addr = {{ 0, }, };
+static int protocol = DEF_RAW_PROT;
+
+static char *data = NULL;
+static size_t *length_p;
+
+static int raw_sk = -1;
+static int last_ttl = 0;
+static int seq = 0;
+
+
+static int set_protocol (CLIF_option *optn, char *arg) {
+ char *q;
+
+ protocol = strtoul (arg, &q, 0);
+ if (q == arg) {
+ struct protoent *p = getprotobyname (arg);
+
+ if (!p) return -1;
+ protocol = p->p_proto;
+ }
+
+ return 0;
+}
+
+
+static CLIF_option raw_options[] = {
+ { 0, "protocol", "PROT", "Use protocol %s (default is "
+ _TEXT (DEF_RAW_PROT) ")",
+ set_protocol, 0, 0, CLIF_ABBREV },
+ CLIF_END_OPTION
+};
+
+
+static int raw_init (const sockaddr_any *dest,
+ unsigned int port_seq, size_t *packet_len_p) {
+ int i;
+ int af = dest->sa.sa_family;
+
+ dest_addr = *dest;
+ dest_addr.sin.sin_port = 0;
+
+ if (port_seq) protocol = port_seq;
+
+
+ length_p = packet_len_p;
+
+ if (*length_p &&
+ !(data = malloc (*length_p))
+ ) error ("malloc");
+
+ for (i = 0; i < *length_p; i++)
+ data[i] = 0x40 + (i & 0x3f);
+
+
+ raw_sk = socket (af, SOCK_RAW, protocol);
+ if (raw_sk < 0)
+ error_or_perm ("socket");
+
+ tune_socket (raw_sk);
+
+ /* Don't want to catch packets from another hosts */
+ if (raw_can_connect () &&
+ connect (raw_sk, &dest_addr.sa, sizeof (dest_addr)) < 0
+ ) error ("connect");
+
+ use_recverr (raw_sk);
+
+
+ add_poll (raw_sk, POLLIN | POLLERR);
+
+ return 0;
+}
+
+
+static void raw_send_probe (probe *pb, int ttl) {
+
+ if (ttl != last_ttl) {
+
+ set_ttl (raw_sk, ttl);
+
+ last_ttl = ttl;
+ }
+
+
+ pb->send_time = get_time ();
+
+ if (do_send (raw_sk, data, *length_p, &dest_addr) < 0) {
+ pb->send_time = 0;
+ return;
+ }
+
+
+ pb->seq = ++seq;
+
+ return;
+}
+
+
+static probe *raw_check_reply (int sk, int err, sockaddr_any *from,
+ char *buf, size_t len) {
+ probe *pb;
+
+ if (!equal_addr (&dest_addr, from))
+ return NULL;
+
+ pb = probe_by_seq (seq);
+ if (!pb) return NULL;
+
+ if (!err) pb->final = 1;
+
+ return pb;
+}
+
+
+static void raw_recv_probe (int sk, int revents) {
+
+ if (!(revents & (POLLIN | POLLERR)))
+ return;
+
+ recv_reply (sk, !!(revents & POLLERR), raw_check_reply);
+}
+
+
+static void raw_expire_probe (probe *pb) {
+
+ probe_done (pb);
+}
+
+
+static tr_module raw_ops = {
+ .name = "raw",
+ .init = raw_init,
+ .send_probe = raw_send_probe,
+ .recv_probe = raw_recv_probe,
+ .expire_probe = raw_expire_probe,
+ .options = raw_options,
+ .one_per_time = 1,
+};
+
+TR_MODULE (raw_ops);