mod_ip6_opt.c 5.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189
  1. /*
  2. * mod_ip6_opt.c
  3. *
  4. * Copyright (c) 2001 Dug Song <dugsong@monkey.org>
  5. *
  6. */
  7. #include "config.h"
  8. #include "iputil.h"
  9. #include "mod.h"
  10. #include "pkt.h"
  11. #include <err.h>
  12. #include <stdio.h>
  13. #include <stdlib.h>
  14. #include <string.h>
  15. #define MAX_ADDRS 32
  16. #define OPT6_TYPE_ROUTE 1
  17. #define OPT6_TYPE_RAW 2
  18. struct ip6_opt_data_route {
  19. int segments;
  20. struct addr addr[MAX_ADDRS];
  21. };
  22. struct ip6_opt_data_raw {
  23. int len;
  24. uint8_t proto;
  25. uint8_t data8[512];
  26. };
  27. struct ip6_opt_data {
  28. int type;
  29. union {
  30. struct ip6_opt_data_route route;
  31. struct ip6_opt_data_raw raw;
  32. } u;
  33. };
  34. void *
  35. ip6_opt_close(void *d)
  36. {
  37. if (d != NULL)
  38. free(d);
  39. return (NULL);
  40. }
  41. void *
  42. ip6_opt_open(int argc, char *argv[])
  43. {
  44. struct ip6_opt_data *opt;
  45. if (argc < 4)
  46. return (NULL);
  47. if ((opt = calloc(1, sizeof(*opt))) == NULL)
  48. return (NULL);
  49. if (strcasecmp(argv[1], "route") == 0) {
  50. int i, j;
  51. opt->type = OPT6_TYPE_ROUTE;
  52. if ((opt->u.route.segments = (int)strtol(argv[2], NULL, 10)) < 1 || opt->u.route.segments > MAX_ADDRS) {
  53. warnx("<segments> must be >= 1");
  54. return (ip6_opt_close(opt));
  55. }
  56. i = 0;
  57. j = 3;
  58. if (opt->u.route.segments + 3 != argc) {
  59. return (ip6_opt_close(opt));
  60. }
  61. for (; j < argc; i++, j++) {
  62. if (addr_aton(argv[j], &opt->u.route.addr[i]) < 0 || opt->u.route.addr[i].addr_type != ADDR_TYPE_IP6) {
  63. return (ip6_opt_close(opt));
  64. }
  65. }
  66. } else if (strcasecmp(argv[1], "raw") == 0) {
  67. opt->type = OPT6_TYPE_RAW;
  68. if (raw_ip6_opt_parse(argc - 2,
  69. &argv[2],
  70. &opt->u.raw.proto,
  71. &opt->u.raw.len,
  72. &opt->u.raw.data8[2],
  73. sizeof(opt->u.raw.data8) - 2) != 0)
  74. return (ip6_opt_close(opt));
  75. opt->u.raw.len += 2;
  76. opt->u.raw.data8[0] = 0;
  77. opt->u.raw.data8[1] = opt->u.raw.len / 8;
  78. } else {
  79. return (ip6_opt_close(opt));
  80. }
  81. return (opt);
  82. }
  83. int
  84. ip6_opt_apply(void *d, struct pktq *pktq)
  85. {
  86. struct ip6_opt_data *opt = (struct ip6_opt_data *)d;
  87. struct ip6_ext_hdr *ext;
  88. int offset, len;
  89. struct pkt *pkt;
  90. uint8_t nxt, iph_nxt;
  91. uint8_t *p;
  92. int i;
  93. TAILQ_FOREACH(pkt, pktq, pkt_next)
  94. {
  95. uint16_t eth_type = htons(pkt->pkt_eth->eth_type);
  96. if (eth_type != ETH_TYPE_IPV6) {
  97. continue;
  98. }
  99. nxt = pkt->pkt_ip6->ip6_nxt;
  100. ext = (struct ip6_ext_hdr *)(((u_char *)pkt->pkt_ip6) + IP6_HDR_LEN);
  101. if (opt->type == OPT6_TYPE_ROUTE) {
  102. offset = 8 + IP6_ADDR_LEN * opt->u.route.segments;
  103. memmove(((u_char *)ext) + offset, ext, pkt->pkt_end - (u_char *)ext);
  104. pkt->pkt_end += offset;
  105. pkt->pkt_ip_data += offset;
  106. len = (IP6_ADDR_LEN / 8) * opt->u.route.segments;
  107. ext->ext_data.routing.type = 0;
  108. ext->ext_data.routing.segleft = opt->u.route.segments;
  109. ((uint32_t *)ext)[1] = 0; /* reserved */
  110. iph_nxt = IP_PROTO_ROUTING;
  111. p = (uint8_t *)(ext) + 8;
  112. for (i = 0; i < opt->u.route.segments; ++i, p += IP6_ADDR_LEN) {
  113. memcpy(p, opt->u.route.addr[i].addr_data8, IP6_ADDR_LEN);
  114. }
  115. } else if (opt->type == OPT6_TYPE_RAW) {
  116. offset = opt->u.raw.len;
  117. memmove(((u_char *)ext) + offset, ext, pkt->pkt_end - (u_char *)ext);
  118. pkt->pkt_end += offset;
  119. pkt->pkt_ip_data += offset;
  120. iph_nxt = opt->u.raw.proto;
  121. p = (uint8_t *)ext;
  122. memcpy(p, opt->u.raw.data8, opt->u.raw.len);
  123. #if 0
  124. printf("len: %d, data %02x %02x %02x %02x %02x %02x %02x %02x\n",
  125. opt->u.raw.len, opt->u.raw.data8[0], opt->u.raw.data8[1],
  126. opt->u.raw.data8[2], opt->u.raw.data8[3],
  127. opt->u.raw.data8[4], opt->u.raw.data8[5],
  128. opt->u.raw.data8[6], opt->u.raw.data8[7]);
  129. #endif
  130. len = (opt->u.raw.len - 8) / 8;
  131. } else {
  132. continue;
  133. }
  134. ext->ext_nxt = nxt;
  135. ext->ext_len = len;
  136. pkt->pkt_ip6->ip6_nxt = iph_nxt;
  137. pkt->pkt_ip6->ip6_plen = htons(htons(pkt->pkt_ip6->ip6_plen) + offset);
  138. /* XXX: do we need it? */
  139. pkt_decorate(pkt);
  140. /* ip6_checksum(pkt->pkt_ip, pkt->pkt_end - pkt->pkt_eth_data); */
  141. }
  142. return (0);
  143. }
  144. struct mod mod_ip6_opt = {
  145. "ip6_opt", /* name */
  146. "ip6_opt [route <segments> <ip6-addr> ...] | [raw <type> <byte stream>]", /* usage */
  147. ip6_opt_open, /* open */
  148. ip6_opt_apply, /* apply */
  149. ip6_opt_close /* close */
  150. };