iputil.c 3.4 KB

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