PageRenderTime 724ms CodeModel.GetById 24ms RepoModel.GetById 0ms app.codeStats 0ms

/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
  1. /*
  2. Copyright (c) 2006, 2007 Dmitry Butskoy
  3. <buc@citadel.stu.neva.ru>
  4. License: GPL v2 or any later
  5. See COPYING for the status of this software.
  6. */
  7. #include <stdlib.h>
  8. #include <string.h>
  9. #include <unistd.h>
  10. #include <sys/socket.h>
  11. #include <sys/poll.h>
  12. #include <netinet/in.h>
  13. #include <netinet/udp.h>
  14. #include "traceroute.h"
  15. #ifndef IPPROTO_UDPLITE
  16. #define IPPROTO_UDPLITE 136
  17. #endif
  18. #ifndef UDPLITE_SEND_CSCOV
  19. #define UDPLITE_SEND_CSCOV 10
  20. #define UDPLITE_RECV_CSCOV 11
  21. #endif
  22. static sockaddr_any dest_addr = {{ 0, }, };
  23. static unsigned int curr_port = 0;
  24. static unsigned int protocol = IPPROTO_UDP;
  25. static char *data = NULL;
  26. static size_t *length_p;
  27. static void fill_data (size_t *packet_len_p) {
  28. int i;
  29. length_p = packet_len_p;
  30. if (*length_p &&
  31. !(data = malloc (*length_p))
  32. ) error ("malloc");
  33. for (i = 0; i < *length_p; i++)
  34. data[i] = 0x40 + (i & 0x3f);
  35. return;
  36. }
  37. static int udp_default_init (const sockaddr_any *dest,
  38. unsigned int port_seq, size_t *packet_len_p) {
  39. curr_port = port_seq ? port_seq : DEF_START_PORT;
  40. dest_addr = *dest;
  41. dest_addr.sin.sin_port = htons (curr_port);
  42. fill_data (packet_len_p);
  43. return 0;
  44. }
  45. static int udp_init (const sockaddr_any *dest,
  46. unsigned int port_seq, size_t *packet_len_p) {
  47. dest_addr = *dest;
  48. if (!port_seq) port_seq = DEF_UDP_PORT;
  49. dest_addr.sin.sin_port = htons ((u_int16_t) port_seq);
  50. fill_data (packet_len_p);
  51. return 0;
  52. }
  53. static unsigned int coverage = 0;
  54. #define MIN_COVERAGE (sizeof (struct udphdr))
  55. static void set_coverage (int sk) {
  56. int val = MIN_COVERAGE;
  57. if (setsockopt (sk, IPPROTO_UDPLITE, UDPLITE_SEND_CSCOV,
  58. &coverage, sizeof (coverage)) < 0
  59. ) error ("UDPLITE_SEND_CSCOV");
  60. if (setsockopt (sk, IPPROTO_UDPLITE, UDPLITE_RECV_CSCOV,
  61. &val, sizeof (val)) < 0
  62. ) error ("UDPLITE_RECV_CSCOV");
  63. }
  64. static CLIF_option udplite_options[] = {
  65. { 0, "coverage", "NUM", "Set udplite send coverage to %s (default is "
  66. _TEXT(MIN_COVERAGE) ")",
  67. CLIF_set_uint, &coverage, 0, CLIF_ABBREV },
  68. CLIF_END_OPTION
  69. };
  70. static int udplite_init (const sockaddr_any *dest,
  71. unsigned int port_seq, size_t *packet_len_p) {
  72. dest_addr = *dest;
  73. if (!port_seq) port_seq = DEF_UDP_PORT; /* XXX: Hmmm... */
  74. dest_addr.sin.sin_port = htons ((u_int16_t) port_seq);
  75. protocol = IPPROTO_UDPLITE;
  76. if (!coverage) coverage = MIN_COVERAGE;
  77. fill_data (packet_len_p);
  78. return 0;
  79. }
  80. static void udp_send_probe (probe *pb, int ttl) {
  81. int sk;
  82. int af = dest_addr.sa.sa_family;
  83. sk = socket (af, SOCK_DGRAM, protocol);
  84. if (sk < 0) error ("socket");
  85. tune_socket (sk); /* common stuff */
  86. if (coverage) set_coverage (sk); /* udplite case */
  87. set_ttl (sk, ttl);
  88. if (connect (sk, &dest_addr.sa, sizeof (dest_addr)) < 0)
  89. error ("connect");
  90. use_recverr (sk);
  91. pb->send_time = get_time ();
  92. if (do_send (sk, data, *length_p, NULL) < 0) {
  93. close (sk);
  94. pb->send_time = 0;
  95. return;
  96. }
  97. pb->sk = sk;
  98. add_poll (sk, POLLIN | POLLERR);
  99. pb->seq = dest_addr.sin.sin_port;
  100. if (curr_port) { /* traditional udp method */
  101. curr_port++;
  102. dest_addr.sin.sin_port = htons (curr_port); /* both ipv4 and ipv6 */
  103. }
  104. return;
  105. }
  106. static probe *udp_check_reply (int sk, int err, sockaddr_any *from,
  107. char *buf, size_t len) {
  108. probe *pb;
  109. pb = probe_by_sk (sk);
  110. if (!pb) return NULL;
  111. if (pb->seq != from->sin.sin_port)
  112. return NULL;
  113. if (!err) pb->final = 1;
  114. return pb;
  115. }
  116. static void udp_recv_probe (int sk, int revents) {
  117. if (!(revents & (POLLIN | POLLERR)))
  118. return;
  119. recv_reply (sk, !!(revents & POLLERR), udp_check_reply);
  120. }
  121. static void udp_expire_probe (probe *pb) {
  122. probe_done (pb);
  123. }
  124. /* All three modules share the same methods except the init... */
  125. static tr_module default_ops = {
  126. .name = "default",
  127. .init = udp_default_init,
  128. .send_probe = udp_send_probe,
  129. .recv_probe = udp_recv_probe,
  130. .expire_probe = udp_expire_probe,
  131. .header_len = sizeof (struct udphdr),
  132. };
  133. TR_MODULE (default_ops);
  134. static tr_module udp_ops = {
  135. .name = "udp",
  136. .init = udp_init,
  137. .send_probe = udp_send_probe,
  138. .recv_probe = udp_recv_probe,
  139. .expire_probe = udp_expire_probe,
  140. .header_len = sizeof (struct udphdr),
  141. };
  142. TR_MODULE (udp_ops);
  143. static tr_module udplite_ops = {
  144. .name = "udplite",
  145. .init = udplite_init,
  146. .send_probe = udp_send_probe,
  147. .recv_probe = udp_recv_probe,
  148. .expire_probe = udp_expire_probe,
  149. .header_len = sizeof (struct udphdr),
  150. .options = udplite_options,
  151. };
  152. TR_MODULE (udplite_ops);