iputil.c 3.4 KB

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