recv_v6.c 2.3 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283
  1. #include "trace.h"
  2. extern int gotalarm;
  3. /*
  4. * Return: -3 on timeout
  5. * -2 on ICMP time exceeded in transit (caller keeps going)
  6. * -1 on ICMP port unreachable (caller is done)
  7. * >= 0 return value is some other ICMP unreachable code
  8. */
  9. int
  10. recv_v6(int seq, struct timeval *tv)
  11. {
  12. #ifdef IPV6
  13. int hlen2, icmp6len, ret;
  14. ssize_t n;
  15. socklen_t len;
  16. struct ip6_hdr *hip6;
  17. struct icmp6_hdr *icmp6;
  18. struct udphdr *udp;
  19. gotalarm = 0;
  20. alarm(3);
  21. for ( ; ; ) {
  22. if (gotalarm)
  23. return(-3); /* alarm expired */
  24. len = pr->salen;
  25. n = recvfrom(recvfd, recvbuf, sizeof(recvbuf), 0, pr->sarecv, &len);
  26. if (n < 0) {
  27. if (errno == EINTR)
  28. continue;
  29. else
  30. err_sys("recvfrom error");
  31. }
  32. icmp6 = (struct icmp6_hdr *) recvbuf; /* ICMP header */
  33. if ( ( icmp6len = n ) < 8)
  34. continue; /* not enough to look at ICMP header */
  35. if (icmp6->icmp6_type == ICMP6_TIME_EXCEEDED &&
  36. icmp6->icmp6_code == ICMP6_TIME_EXCEED_TRANSIT) {
  37. if (icmp6len < 8 + sizeof(struct ip6_hdr) + 4)
  38. continue; /* not enough data to look at inner header */
  39. hip6 = (struct ip6_hdr *) (recvbuf + 8);
  40. hlen2 = sizeof(struct ip6_hdr);
  41. udp = (struct udphdr *) (recvbuf + 8 + hlen2);
  42. if (hip6->ip6_nxt == IPPROTO_UDP &&
  43. udp->uh_sport == htons(sport) &&
  44. udp->uh_dport == htons(dport + seq))
  45. ret = -2; /* we hit an intermediate router */
  46. break;
  47. } else if (icmp6->icmp6_type == ICMP6_DST_UNREACH) {
  48. if (icmp6len < 8 + sizeof(struct ip6_hdr) + 4)
  49. continue; /* not enough data to look at inner header */
  50. hip6 = (struct ip6_hdr *) (recvbuf + 8);
  51. hlen2 = sizeof(struct ip6_hdr);
  52. udp = (struct udphdr *) (recvbuf + 8 + hlen2);
  53. if (hip6->ip6_nxt == IPPROTO_UDP &&
  54. udp->uh_sport == htons(sport) &&
  55. udp->uh_dport == htons(dport + seq)) {
  56. if (icmp6->icmp6_code == ICMP6_DST_UNREACH_NOPORT)
  57. ret = -1; /* have reached destination */
  58. else
  59. ret = icmp6->icmp6_code; /* 0, 1, 2, ... */
  60. break;
  61. }
  62. } else if (verbose) {
  63. printf(" (from %s: type = %d, code = %d)\n",
  64. Sock_ntop_host(pr->sarecv, pr->salen),
  65. icmp6->icmp6_type, icmp6->icmp6_code);
  66. }
  67. /* Some other ICMP error, recvfrom() again */
  68. }
  69. alarm(0); /* don't leave alarm running */
  70. Gettimeofday(tv, NULL); /* get time of packet arrival */
  71. return(ret);
  72. #endif
  73. }