mod_ip_frag.c 4.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171
  1. /*
  2. * mod_ip_frag.c
  3. *
  4. * Copyright (c) 2001 Dug Song <dugsong@monkey.org>
  5. *
  6. * $Id: mod_ip_frag.c 2000 2008-04-27 06:17:35Z aturner $
  7. */
  8. #include "config.h"
  9. #include <err.h>
  10. #include <stdio.h>
  11. #include <stdlib.h>
  12. #include <string.h>
  13. #include "mod.h"
  14. #include "pkt.h"
  15. #include "randutil.h"
  16. #ifndef MAX
  17. #define MAX(a,b) (((a)>(b))?(a):(b))
  18. #endif
  19. #define FAVOR_OLD 1
  20. #define FAVOR_NEW 2
  21. static struct ip_frag_data {
  22. rand_t *rnd;
  23. int size;
  24. int overlap;
  25. } ip_frag_data;
  26. void *
  27. ip_frag_close(void *d)
  28. {
  29. if (ip_frag_data.rnd != NULL)
  30. rand_close(ip_frag_data.rnd);
  31. ip_frag_data.size = 0;
  32. return (NULL);
  33. }
  34. void *
  35. ip_frag_open(int argc, char *argv[])
  36. {
  37. if (argc < 2) {
  38. warnx("need fragment <size> in bytes");
  39. return (NULL);
  40. }
  41. ip_frag_data.rnd = rand_open();
  42. ip_frag_data.size = atoi(argv[1]);
  43. if (ip_frag_data.size == 0 || (ip_frag_data.size % 8) != 0) {
  44. warnx("fragment size must be a multiple of 8");
  45. return (ip_frag_close(&ip_frag_data));
  46. }
  47. if (argc == 3) {
  48. if (strcmp(argv[2], "old") == 0 ||
  49. strcmp(argv[2], "win32") == 0)
  50. ip_frag_data.overlap = FAVOR_OLD;
  51. else if (strcmp(argv[2], "new") == 0 ||
  52. strcmp(argv[2], "unix") == 0)
  53. ip_frag_data.overlap = FAVOR_NEW;
  54. else
  55. return (ip_frag_close(&ip_frag_data));
  56. }
  57. return (&ip_frag_data);
  58. }
  59. int
  60. ip_frag_apply(void *d, struct pktq *pktq)
  61. {
  62. struct pkt *pkt, *new, *next, tmp;
  63. int hl, fraglen, off;
  64. u_char *p, *p1, *p2;
  65. for (pkt = TAILQ_FIRST(pktq); pkt != TAILQ_END(pktq); pkt = next) {
  66. next = TAILQ_NEXT(pkt, pkt_next);
  67. if (pkt->pkt_ip == NULL || pkt->pkt_ip_data == NULL)
  68. continue;
  69. hl = pkt->pkt_ip->ip_hl << 2;
  70. /*
  71. * Preserve transport protocol header in first frag,
  72. * to bypass filters that block `short' fragments.
  73. */
  74. switch (pkt->pkt_ip->ip_p) {
  75. case IP_PROTO_ICMP:
  76. fraglen = MAX(ICMP_LEN_MIN, ip_frag_data.size);
  77. break;
  78. case IP_PROTO_UDP:
  79. fraglen = MAX(UDP_HDR_LEN, ip_frag_data.size);
  80. break;
  81. case IP_PROTO_TCP:
  82. fraglen = MAX(pkt->pkt_tcp->th_off << 2,
  83. ip_frag_data.size);
  84. break;
  85. default:
  86. fraglen = ip_frag_data.size;
  87. break;
  88. }
  89. if (fraglen & 7)
  90. fraglen = (fraglen & ~7) + 8;
  91. if (pkt->pkt_end - pkt->pkt_ip_data < fraglen)
  92. continue;
  93. for (p = pkt->pkt_ip_data; p < pkt->pkt_end; ) {
  94. new = pkt_new();
  95. memcpy(new->pkt_ip, pkt->pkt_ip, hl);
  96. new->pkt_ip_data = new->pkt_eth_data + hl;
  97. p1 = p, p2 = NULL;
  98. off = (p - pkt->pkt_ip_data) >> 3;
  99. if (ip_frag_data.overlap != 0 && (off & 1) != 0 &&
  100. p + (fraglen << 1) < pkt->pkt_end) {
  101. rand_strset(ip_frag_data.rnd, tmp.pkt_buf,
  102. fraglen);
  103. if (ip_frag_data.overlap == FAVOR_OLD) {
  104. p1 = p + fraglen;
  105. p2 = tmp.pkt_buf;
  106. } else if (ip_frag_data.overlap == FAVOR_NEW) {
  107. p1 = tmp.pkt_buf;
  108. p2 = p + fraglen;
  109. }
  110. new->pkt_ip->ip_off = htons(IP_MF |
  111. (off + (fraglen >> 3)));
  112. } else {
  113. new->pkt_ip->ip_off = htons(off |
  114. ((p + fraglen < pkt->pkt_end) ? IP_MF: 0));
  115. }
  116. new->pkt_ip->ip_len = htons(hl + fraglen);
  117. ip_checksum(new->pkt_ip, hl + fraglen);
  118. memcpy(new->pkt_ip_data, p1, fraglen);
  119. new->pkt_end = new->pkt_ip_data + fraglen;
  120. TAILQ_INSERT_BEFORE(pkt, new, pkt_next);
  121. if (p2 != NULL) {
  122. new = pkt_dup(new);
  123. new->pkt_ts.tv_usec = 1;
  124. new->pkt_ip->ip_off = htons(IP_MF | off);
  125. new->pkt_ip->ip_len = htons(hl + (fraglen<<1));
  126. ip_checksum(new->pkt_ip, hl + (fraglen<<1));
  127. memcpy(new->pkt_ip_data, p, fraglen);
  128. memcpy(new->pkt_ip_data+fraglen, p2, fraglen);
  129. new->pkt_end = new->pkt_ip_data + (fraglen<<1);
  130. TAILQ_INSERT_BEFORE(pkt, new, pkt_next);
  131. p += (fraglen << 1);
  132. } else
  133. p += fraglen;
  134. if ((fraglen = pkt->pkt_end - p) > ip_frag_data.size)
  135. fraglen = ip_frag_data.size;
  136. }
  137. TAILQ_REMOVE(pktq, pkt, pkt_next);
  138. pkt_free(pkt);
  139. }
  140. return (0);
  141. }
  142. struct mod mod_ip_frag = {
  143. "ip_frag", /* name */
  144. "ip_frag <size> [old|new]", /* usage */
  145. ip_frag_open, /* open */
  146. ip_frag_apply, /* apply */
  147. ip_frag_close /* close */
  148. };