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