iputil.c 3.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152
  1. #include "config.h"
  2. #include "defines.h"
  3. #include "common.h"
  4. #include "iputil.h"
  5. #ifdef HAVE_DNET_H
  6. #include <dnet.h>
  7. #endif
  8. #ifdef HAVE_DUMBNET_H
  9. #include <dumbnet.h>
  10. #endif
  11. #include <errno.h>
  12. #include <stdio.h>
  13. #include <string.h>
  14. static ssize_t
  15. inet_add_option_6(void *buf, size_t len, int proto, const void *optbuf, size_t optlen);
  16. ssize_t
  17. inet_add_option(uint16_t eth_type, void *buf, size_t len,
  18. int proto, const void *optbuf, size_t optlen)
  19. {
  20. if (eth_type == ETH_TYPE_IP) {
  21. return ip_add_option(buf, len, proto, optbuf, optlen);
  22. } else if (eth_type == ETH_TYPE_IPV6) {
  23. return inet_add_option_6(buf, len, proto, optbuf, optlen);
  24. } else {
  25. errno = EINVAL;
  26. return -1;
  27. }
  28. }
  29. /*
  30. * IPv6 version of libdnet's ip_add_option():
  31. */
  32. ssize_t
  33. inet_add_option_6(void *buf, size_t len, int proto, const void *optbuf, size_t optlen)
  34. {
  35. struct ip6_hdr *ip6;
  36. struct tcp_hdr *tcp = NULL;
  37. u_char *p;
  38. int hl, datalen, padlen;
  39. if (proto != IP_PROTO_TCP) {
  40. errno = EINVAL;
  41. return (-1);
  42. }
  43. ip6 = (struct ip6_hdr *)buf;
  44. p = (u_char *)buf + IP6_HDR_LEN;
  45. tcp = (struct tcp_hdr *)p;
  46. hl = tcp->th_off << 2;
  47. p = (u_char *)tcp + hl;
  48. datalen = ntohs(ip6->ip6_plen) + IP6_HDR_LEN - (p - (u_char *)buf);
  49. /* Compute padding to next word boundary. */
  50. if ((padlen = 4 - (optlen % 4)) == 4)
  51. padlen = 0;
  52. /* XXX - IP_HDR_LEN_MAX == TCP_HDR_LEN_MAX */
  53. if (hl + optlen + padlen > IP_HDR_LEN_MAX ||
  54. ntohs(ip6->ip6_plen) + IP6_HDR_LEN + optlen + padlen > len) {
  55. errno = EINVAL;
  56. return (-1);
  57. }
  58. /* Shift any existing data. */
  59. if (datalen) {
  60. memmove(p + optlen + padlen, p, datalen);
  61. }
  62. /* XXX - IP_OPT_NOP == TCP_OPT_NOP */
  63. if (padlen) {
  64. memset(p, IP_OPT_NOP, padlen);
  65. p += padlen;
  66. }
  67. memmove(p, optbuf, optlen);
  68. p += optlen;
  69. optlen += padlen;
  70. tcp->th_off = (p - (u_char *)tcp) >> 2;
  71. ip6->ip6_plen = htons(ntohs(ip6->ip6_plen) + optlen);
  72. return (optlen);
  73. }
  74. void
  75. inet_checksum(uint16_t eth_type, void *buf, size_t len)
  76. {
  77. if (eth_type == ETH_TYPE_IP) {
  78. return ip_checksum(buf, len);
  79. } else if (eth_type == ETH_TYPE_IPV6) {
  80. return ip6_checksum(buf, len);
  81. }
  82. }
  83. int
  84. raw_ip_opt_parse(int argc, char *argv[], uint8_t *opt_type, uint8_t *opt_len,
  85. uint8_t *buff, int buff_len)
  86. {
  87. int i, j;
  88. if (sscanf(argv[0], "%hhx", opt_type) != 1) {
  89. warn("invalid opt_type");
  90. return -1;
  91. }
  92. if (sscanf(argv[1], "%hhx", opt_len) != 1) {
  93. warn("invalid opt_len");
  94. return -1;
  95. }
  96. j = 0;
  97. for (i = 2; i < argc && j < buff_len; ++i, ++j) {
  98. if (sscanf(argv[i], "%hhx", &buff[j]) != 1) {
  99. warn("invalid opt_data");
  100. return -1;
  101. }
  102. }
  103. if (*opt_len != j + 2) {
  104. warnx("invalid opt->len (%d) doesn't match data length (%d)",
  105. *opt_len, j);
  106. return -1;
  107. }
  108. return 0;
  109. }
  110. int
  111. raw_ip6_opt_parse(int argc, char *argv[], uint8_t *proto, int *len,
  112. uint8_t *buff, int buff_len)
  113. {
  114. int i, j;
  115. if (sscanf(argv[0], "%hhx", proto) != 1) {
  116. warn("invalid protocol");
  117. return -1;
  118. }
  119. j = 0;
  120. for (i = 1; i < argc && j < buff_len; ++i, ++j) {
  121. if (sscanf(argv[i], "%hhx", &buff[j]) != 1) {
  122. warn("invalid opt_data");
  123. return -1;
  124. }
  125. }
  126. *len = j;
  127. if ((j + 2) % 8 != 0) {
  128. warnx("(opt_len (%d) + 2) %% 8 != 0", j);
  129. return -1;
  130. }
  131. return 0;
  132. }