diff options
Diffstat (limited to 'traceroute/mod-raw.c')
-rw-r--r-- | traceroute/mod-raw.c | 163 |
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); |