icmp.c 2.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125
  1. /*
  2. * natd - Network Address Translation Daemon for FreeBSD.
  3. *
  4. * This software is provided free of charge, with no
  5. * warranty of any kind, either expressed or implied.
  6. * Use at your own risk.
  7. *
  8. * You may copy, modify and distribute this software (icmp.c) freely.
  9. *
  10. * Ari Suutari <suutari@iki.fi>
  11. */
  12. #include <stdlib.h>
  13. #include <stdio.h>
  14. #include <unistd.h>
  15. #include <string.h>
  16. #include <ctype.h>
  17. #include <sys/types.h>
  18. #include <sys/socket.h>
  19. #include <sys/time.h>
  20. #include <errno.h>
  21. #include <signal.h>
  22. #include <netdb.h>
  23. #include <netinet/in.h>
  24. #include <netinet/in_systm.h>
  25. #include <netinet/ip.h>
  26. #include <netinet/ip_icmp.h>
  27. #include <alias.h>
  28. #include "natd.h"
  29. int SendNeedFragIcmp (int sock, struct ip* failedDgram, int mtu)
  30. {
  31. char icmpBuf[IP_MAXPACKET];
  32. struct ip* ip;
  33. struct icmp* icmp;
  34. int icmpLen;
  35. int failBytes;
  36. int failHdrLen;
  37. struct sockaddr_in addr;
  38. int wrote;
  39. struct in_addr swap;
  40. /*
  41. * Don't send error if packet is
  42. * not the first fragment.
  43. */
  44. if (ntohs (failedDgram->ip_off) & ~(IP_MF | IP_DF))
  45. return 0;
  46. /*
  47. * Dont respond if failed datagram is ICMP.
  48. */
  49. if (failedDgram->ip_p == IPPROTO_ICMP)
  50. return 0;
  51. /*
  52. * Start building the message.
  53. */
  54. ip = (struct ip*) icmpBuf;
  55. icmp = (struct icmp*) (icmpBuf + sizeof (struct ip));
  56. /*
  57. * Complete ICMP part.
  58. */
  59. icmp->icmp_type = ICMP_UNREACH;
  60. icmp->icmp_code = ICMP_UNREACH_NEEDFRAG;
  61. icmp->icmp_cksum = 0;
  62. icmp->icmp_void = 0;
  63. icmp->icmp_nextmtu = htons (mtu);
  64. /*
  65. * Copy header + 64 bits of original datagram.
  66. */
  67. failHdrLen = (failedDgram->ip_hl << 2);
  68. failBytes = failedDgram->ip_len - failHdrLen;
  69. if (failBytes > 8)
  70. failBytes = 8;
  71. failBytes += failHdrLen;
  72. icmpLen = ICMP_MINLEN + failBytes;
  73. memcpy (&icmp->icmp_ip, failedDgram, failBytes);
  74. /*
  75. * Calculate checksum.
  76. */
  77. icmp->icmp_cksum = LibAliasInternetChecksum (mla, (u_short*) icmp,
  78. icmpLen);
  79. /*
  80. * Add IP header using old IP header as template.
  81. */
  82. memcpy (ip, failedDgram, sizeof (struct ip));
  83. ip->ip_v = 4;
  84. ip->ip_hl = 5;
  85. ip->ip_len = htons (sizeof (struct ip) + icmpLen);
  86. ip->ip_p = IPPROTO_ICMP;
  87. ip->ip_tos = 0;
  88. swap = ip->ip_dst;
  89. ip->ip_dst = ip->ip_src;
  90. ip->ip_src = swap;
  91. LibAliasIn (mla, (char*) ip, IP_MAXPACKET);
  92. addr.sin_family = AF_INET;
  93. addr.sin_addr = ip->ip_dst;
  94. addr.sin_port = 0;
  95. /*
  96. * Put packet into processing queue.
  97. */
  98. wrote = sendto (sock,
  99. icmp,
  100. icmpLen,
  101. 0,
  102. (struct sockaddr*) &addr,
  103. sizeof addr);
  104. if (wrote != icmpLen)
  105. Warn ("Cannot send ICMP message.");
  106. return 1;
  107. }