/traceroute-2.0.18/traceroute/mod-udp.c
C | 234 lines | 145 code | 81 blank | 8 comment | 17 complexity | 34b6da4e2c3eb1f69506aac6dbe8d624 MD5 | raw file
Possible License(s): GPL-2.0, LGPL-2.1
- /*
- Copyright (c) 2006, 2007 Dmitry Butskoy
- <buc@citadel.stu.neva.ru>
- License: GPL v2 or any later
- See COPYING for the status of this software.
- */
- #include <stdlib.h>
- #include <string.h>
- #include <unistd.h>
- #include <sys/socket.h>
- #include <sys/poll.h>
- #include <netinet/in.h>
- #include <netinet/udp.h>
- #include "traceroute.h"
- #ifndef IPPROTO_UDPLITE
- #define IPPROTO_UDPLITE 136
- #endif
- #ifndef UDPLITE_SEND_CSCOV
- #define UDPLITE_SEND_CSCOV 10
- #define UDPLITE_RECV_CSCOV 11
- #endif
- static sockaddr_any dest_addr = {{ 0, }, };
- static unsigned int curr_port = 0;
- static unsigned int protocol = IPPROTO_UDP;
- static char *data = NULL;
- static size_t *length_p;
- static void fill_data (size_t *packet_len_p) {
- int i;
- 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);
-
- return;
- }
- static int udp_default_init (const sockaddr_any *dest,
- unsigned int port_seq, size_t *packet_len_p) {
- curr_port = port_seq ? port_seq : DEF_START_PORT;
- dest_addr = *dest;
- dest_addr.sin.sin_port = htons (curr_port);
- fill_data (packet_len_p);
- return 0;
- }
- static int udp_init (const sockaddr_any *dest,
- unsigned int port_seq, size_t *packet_len_p) {
- dest_addr = *dest;
- if (!port_seq) port_seq = DEF_UDP_PORT;
- dest_addr.sin.sin_port = htons ((u_int16_t) port_seq);
-
- fill_data (packet_len_p);
-
- return 0;
- }
- static unsigned int coverage = 0;
- #define MIN_COVERAGE (sizeof (struct udphdr))
- static void set_coverage (int sk) {
- int val = MIN_COVERAGE;
- if (setsockopt (sk, IPPROTO_UDPLITE, UDPLITE_SEND_CSCOV,
- &coverage, sizeof (coverage)) < 0
- ) error ("UDPLITE_SEND_CSCOV");
- if (setsockopt (sk, IPPROTO_UDPLITE, UDPLITE_RECV_CSCOV,
- &val, sizeof (val)) < 0
- ) error ("UDPLITE_RECV_CSCOV");
- }
-
- static CLIF_option udplite_options[] = {
- { 0, "coverage", "NUM", "Set udplite send coverage to %s (default is "
- _TEXT(MIN_COVERAGE) ")",
- CLIF_set_uint, &coverage, 0, CLIF_ABBREV },
- CLIF_END_OPTION
- };
- static int udplite_init (const sockaddr_any *dest,
- unsigned int port_seq, size_t *packet_len_p) {
- dest_addr = *dest;
- if (!port_seq) port_seq = DEF_UDP_PORT; /* XXX: Hmmm... */
- dest_addr.sin.sin_port = htons ((u_int16_t) port_seq);
- protocol = IPPROTO_UDPLITE;
- if (!coverage) coverage = MIN_COVERAGE;
-
- fill_data (packet_len_p);
-
- return 0;
- }
- static void udp_send_probe (probe *pb, int ttl) {
- int sk;
- int af = dest_addr.sa.sa_family;
- sk = socket (af, SOCK_DGRAM, protocol);
- if (sk < 0) error ("socket");
- tune_socket (sk); /* common stuff */
- if (coverage) set_coverage (sk); /* udplite case */
- set_ttl (sk, ttl);
- if (connect (sk, &dest_addr.sa, sizeof (dest_addr)) < 0)
- error ("connect");
- use_recverr (sk);
- pb->send_time = get_time ();
- if (do_send (sk, data, *length_p, NULL) < 0) {
- close (sk);
- pb->send_time = 0;
- return;
- }
- pb->sk = sk;
- add_poll (sk, POLLIN | POLLERR);
- pb->seq = dest_addr.sin.sin_port;
- if (curr_port) { /* traditional udp method */
- curr_port++;
- dest_addr.sin.sin_port = htons (curr_port); /* both ipv4 and ipv6 */
- }
- return;
- }
- static probe *udp_check_reply (int sk, int err, sockaddr_any *from,
- char *buf, size_t len) {
- probe *pb;
- pb = probe_by_sk (sk);
- if (!pb) return NULL;
- if (pb->seq != from->sin.sin_port)
- return NULL;
- if (!err) pb->final = 1;
- return pb;
- }
- static void udp_recv_probe (int sk, int revents) {
- if (!(revents & (POLLIN | POLLERR)))
- return;
- recv_reply (sk, !!(revents & POLLERR), udp_check_reply);
- }
- static void udp_expire_probe (probe *pb) {
- probe_done (pb);
- }
- /* All three modules share the same methods except the init... */
- static tr_module default_ops = {
- .name = "default",
- .init = udp_default_init,
- .send_probe = udp_send_probe,
- .recv_probe = udp_recv_probe,
- .expire_probe = udp_expire_probe,
- .header_len = sizeof (struct udphdr),
- };
- TR_MODULE (default_ops);
- static tr_module udp_ops = {
- .name = "udp",
- .init = udp_init,
- .send_probe = udp_send_probe,
- .recv_probe = udp_recv_probe,
- .expire_probe = udp_expire_probe,
- .header_len = sizeof (struct udphdr),
- };
- TR_MODULE (udp_ops);
- static tr_module udplite_ops = {
- .name = "udplite",
- .init = udplite_init,
- .send_probe = udp_send_probe,
- .recv_probe = udp_recv_probe,
- .expire_probe = udp_expire_probe,
- .header_len = sizeof (struct udphdr),
- .options = udplite_options,
- };
- TR_MODULE (udplite_ops);