mod_ip_frag.c 4.0 KB

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