mod_ip_frag.c 7.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316
  1. /*
  2. * mod_ip_frag.c
  3. *
  4. * Copyright (c) 2001 Dug Song <dugsong@monkey.org>
  5. *
  6. * $Id$
  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 int
  23. ip_frag_apply_ipv4(void *d, struct pktq *pktq);
  24. static int
  25. ip_frag_apply_ipv6(void *d, struct pktq *pktq);
  26. static struct ip_frag_data
  27. {
  28. rand_t *rnd;
  29. int size;
  30. int overlap;
  31. uint32_t ident;
  32. } ip_frag_data;
  33. void *
  34. ip_frag_close(void *d)
  35. {
  36. if (ip_frag_data.rnd != NULL)
  37. rand_close(ip_frag_data.rnd);
  38. ip_frag_data.size = 0;
  39. return (NULL);
  40. }
  41. void *
  42. ip_frag_open(int argc, char *argv[])
  43. {
  44. if (argc < 2) {
  45. warn("need fragment <size> in bytes");
  46. return (NULL);
  47. }
  48. ip_frag_data.rnd = rand_open();
  49. ip_frag_data.size = atoi(argv[1]);
  50. if (ip_frag_data.size == 0 || (ip_frag_data.size % 8) != 0) {
  51. warn("fragment size must be a multiple of 8");
  52. return (ip_frag_close(&ip_frag_data));
  53. }
  54. if (argc == 3) {
  55. if (strcmp(argv[2], "old") == 0 ||
  56. strcmp(argv[2], "win32") == 0)
  57. ip_frag_data.overlap = FAVOR_OLD;
  58. else if (strcmp(argv[2], "new") == 0 ||
  59. strcmp(argv[2], "unix") == 0)
  60. ip_frag_data.overlap = FAVOR_NEW;
  61. else
  62. return (ip_frag_close(&ip_frag_data));
  63. }
  64. ip_frag_data.ident = rand_uint32(ip_frag_data.rnd);
  65. return (&ip_frag_data);
  66. }
  67. int
  68. ip_frag_apply(void *d, struct pktq *pktq)
  69. {
  70. struct pkt *pkt;
  71. /* Select eth protocol via first packet in que: */
  72. pkt = TAILQ_FIRST(pktq);
  73. if (pkt != TAILQ_END(pktq)) {
  74. uint16_t eth_type = htons(pkt->pkt_eth->eth_type);
  75. if (eth_type == ETH_TYPE_IP) {
  76. ip_frag_apply_ipv4(d, pktq);
  77. } else if (eth_type == ETH_TYPE_IPV6) {
  78. ip_frag_apply_ipv6(d, pktq);
  79. }
  80. return 0;
  81. }
  82. return 0;
  83. }
  84. static int
  85. ip_frag_apply_ipv4(void *d, struct pktq *pktq)
  86. {
  87. struct pkt *pkt, *new, *next, tmp;
  88. int hl, fraglen, off;
  89. u_char *p, *p1, *p2;
  90. for (pkt = TAILQ_FIRST(pktq); pkt != TAILQ_END(pktq); pkt = next) {
  91. next = TAILQ_NEXT(pkt, pkt_next);
  92. if (pkt->pkt_ip == NULL || pkt->pkt_ip_data == NULL)
  93. continue;
  94. hl = pkt->pkt_ip->ip_hl << 2;
  95. /*
  96. * Preserve transport protocol header in first frag,
  97. * to bypass filters that block `short' fragments.
  98. */
  99. switch (pkt->pkt_ip->ip_p) {
  100. case IP_PROTO_ICMP:
  101. fraglen = MAX(ICMP_LEN_MIN, ip_frag_data.size);
  102. break;
  103. case IP_PROTO_UDP:
  104. fraglen = MAX(UDP_HDR_LEN, ip_frag_data.size);
  105. break;
  106. case IP_PROTO_TCP:
  107. fraglen = MAX(pkt->pkt_tcp->th_off << 2,
  108. ip_frag_data.size);
  109. break;
  110. default:
  111. fraglen = ip_frag_data.size;
  112. break;
  113. }
  114. if (fraglen & 7)
  115. fraglen = (fraglen & ~7) + 8;
  116. if (pkt->pkt_end - pkt->pkt_ip_data < fraglen)
  117. continue;
  118. for (p = pkt->pkt_ip_data; p < pkt->pkt_end; ) {
  119. new = pkt_new();
  120. memcpy(new->pkt_eth, pkt->pkt_eth, (u_char*)pkt->pkt_eth_data - (u_char*)pkt->pkt_eth);
  121. memcpy(new->pkt_ip, pkt->pkt_ip, hl);
  122. new->pkt_ip_data = new->pkt_eth_data + hl;
  123. p1 = p, p2 = NULL;
  124. off = (p - pkt->pkt_ip_data) >> 3;
  125. if (ip_frag_data.overlap != 0 && (off & 1) != 0 &&
  126. p + (fraglen << 1) < pkt->pkt_end) {
  127. rand_strset(ip_frag_data.rnd, tmp.pkt_buf,
  128. fraglen);
  129. if (ip_frag_data.overlap == FAVOR_OLD) {
  130. p1 = p + fraglen;
  131. p2 = tmp.pkt_buf;
  132. } else if (ip_frag_data.overlap == FAVOR_NEW) {
  133. p1 = tmp.pkt_buf;
  134. p2 = p + fraglen;
  135. }
  136. new->pkt_ip->ip_off = htons(IP_MF |
  137. (off + (fraglen >> 3)));
  138. } else {
  139. new->pkt_ip->ip_off = htons(off |
  140. ((p + fraglen < pkt->pkt_end) ? IP_MF: 0));
  141. }
  142. new->pkt_ip->ip_len = htons(hl + fraglen);
  143. ip_checksum(new->pkt_ip, hl + fraglen);
  144. memcpy(new->pkt_ip_data, p1, fraglen);
  145. new->pkt_end = new->pkt_ip_data + fraglen;
  146. TAILQ_INSERT_BEFORE(pkt, new, pkt_next);
  147. if (p2 != NULL) {
  148. new = pkt_dup(new);
  149. new->pkt_ts.tv_usec = 1;
  150. new->pkt_ip->ip_off = htons(IP_MF | off);
  151. new->pkt_ip->ip_len = htons(hl + (fraglen<<1));
  152. ip_checksum(new->pkt_ip, hl + (fraglen<<1));
  153. memcpy(new->pkt_ip_data, p, fraglen);
  154. memcpy(new->pkt_ip_data+fraglen, p2, fraglen);
  155. new->pkt_end = new->pkt_ip_data + (fraglen<<1);
  156. TAILQ_INSERT_BEFORE(pkt, new, pkt_next);
  157. p += (fraglen << 1);
  158. } else
  159. p += fraglen;
  160. if ((fraglen = pkt->pkt_end - p) > ip_frag_data.size)
  161. fraglen = ip_frag_data.size;
  162. }
  163. TAILQ_REMOVE(pktq, pkt, pkt_next);
  164. pkt_free(pkt);
  165. }
  166. return (0);
  167. }
  168. static int
  169. ip_frag_apply_ipv6(void *d, struct pktq *pktq)
  170. {
  171. struct pkt *pkt, *new, *next, tmp;
  172. struct ip6_ext_hdr *ext;
  173. int hl, fraglen, off;
  174. u_char *p, *p1, *p2;
  175. uint8_t next_hdr;
  176. ip_frag_data.ident++;
  177. for (pkt = TAILQ_FIRST(pktq); pkt != TAILQ_END(pktq); pkt = next) {
  178. next = TAILQ_NEXT(pkt, pkt_next);
  179. if (pkt->pkt_ip == NULL || pkt->pkt_ip_data == NULL)
  180. continue;
  181. hl = IP6_HDR_LEN;
  182. /*
  183. * Preserve transport protocol header in first frag,
  184. * to bypass filters that block `short' fragments.
  185. */
  186. switch (pkt->pkt_ip->ip_p) {
  187. case IP_PROTO_ICMP:
  188. fraglen = MAX(ICMP_LEN_MIN, ip_frag_data.size);
  189. break;
  190. case IP_PROTO_UDP:
  191. fraglen = MAX(UDP_HDR_LEN, ip_frag_data.size);
  192. break;
  193. case IP_PROTO_TCP:
  194. fraglen = MAX(pkt->pkt_tcp->th_off << 2,
  195. ip_frag_data.size);
  196. break;
  197. default:
  198. fraglen = ip_frag_data.size;
  199. break;
  200. }
  201. if (fraglen & 7)
  202. fraglen = (fraglen & ~7) + 8;
  203. if (pkt->pkt_end - pkt->pkt_ip_data < fraglen)
  204. continue;
  205. next_hdr = pkt->pkt_ip6->ip6_nxt;
  206. for (p = pkt->pkt_ip_data; p < pkt->pkt_end; ) {
  207. new = pkt_new();
  208. memcpy(new->pkt_eth, pkt->pkt_eth, (u_char*)pkt->pkt_eth_data - (u_char*)pkt->pkt_eth);
  209. memcpy(new->pkt_ip, pkt->pkt_ip, hl);
  210. ext = (struct ip6_ext_hdr *)((u_char*)new->pkt_eth_data + hl);
  211. new->pkt_ip_data = (u_char *)(ext) + 2 +
  212. sizeof(struct ip6_ext_data_fragment);
  213. new->pkt_ip6->ip6_nxt = IP_PROTO_FRAGMENT;
  214. ext->ext_nxt = next_hdr;
  215. ext->ext_len = 0; /* ip6 fragf reserved */
  216. ext->ext_data.fragment.ident = ip_frag_data.ident;
  217. p1 = p, p2 = NULL;
  218. off = (p - pkt->pkt_ip_data) >> 3;
  219. if (ip_frag_data.overlap != 0 && (off & 1) != 0 &&
  220. p + (fraglen << 1) < pkt->pkt_end) {
  221. rand_strset(ip_frag_data.rnd, tmp.pkt_buf,
  222. fraglen);
  223. if (ip_frag_data.overlap == FAVOR_OLD) {
  224. p1 = p + fraglen;
  225. p2 = tmp.pkt_buf;
  226. } else if (ip_frag_data.overlap == FAVOR_NEW) {
  227. p1 = tmp.pkt_buf;
  228. p2 = p + fraglen;
  229. }
  230. ext->ext_data.fragment.offlg =
  231. htons((off /*+ (fraglen >> 3)*/) << 3) | IP6_MORE_FRAG;
  232. } else {
  233. ext->ext_data.fragment.offlg = htons(off << 3) |
  234. ((p + fraglen < pkt->pkt_end) ? IP6_MORE_FRAG : 0);
  235. }
  236. new->pkt_ip6->ip6_plen = htons(fraglen + 8);
  237. memcpy(new->pkt_ip_data, p1, fraglen);
  238. new->pkt_end = new->pkt_ip_data + fraglen;
  239. TAILQ_INSERT_BEFORE(pkt, new, pkt_next);
  240. if (p2 != NULL) {
  241. new = pkt_dup(new);
  242. new->pkt_ts.tv_usec = 1;
  243. ext->ext_data.fragment.offlg = htons(off << 3) | IP6_MORE_FRAG;
  244. new->pkt_ip6->ip6_plen = htons((fraglen << 1) + 8);
  245. memcpy(new->pkt_ip_data, p, fraglen);
  246. memcpy(new->pkt_ip_data + fraglen, p2, fraglen);
  247. new->pkt_end = new->pkt_ip_data + (fraglen << 1);
  248. TAILQ_INSERT_BEFORE(pkt, new, pkt_next);
  249. p += (fraglen << 1);
  250. } else {
  251. p += fraglen;
  252. }
  253. if ((fraglen = pkt->pkt_end - p) > ip_frag_data.size)
  254. fraglen = ip_frag_data.size;
  255. }
  256. TAILQ_REMOVE(pktq, pkt, pkt_next);
  257. pkt_free(pkt);
  258. }
  259. return 0;
  260. }
  261. struct mod mod_ip_frag = {
  262. "ip_frag", /* name */
  263. "ip_frag <size> [old|new]", /* usage */
  264. ip_frag_open, /* open */
  265. ip_frag_apply, /* apply */
  266. ip_frag_close /* close */
  267. };