Annotation of embedaddon/hping2/split.c, revision 1.1.1.1
1.1 misho 1: #include <stdio.h>
2: #include <sys/types.h>
3: #include <netinet/in.h>
4: #include <stdlib.h>
5: #include <string.h>
6:
7: #include "ars.h"
8:
9: int ars_seems_ip(struct ars_iphdr *ip, size_t size)
10: {
11: if (ip->version == 4 &&
12: ip->ihl >= 5 &&
13: (ip->ihl << 2) <= size &&
14: ars_check_ip_cksum(ip) == 1)
15: return 1;
16: return 0;
17: }
18:
19: int ars_guess_ipoff(void *packet, size_t size, int *lhs)
20: {
21: size_t orig_size = size;
22:
23: while(1) {
24: struct ars_iphdr *ip = packet;
25: if (size < sizeof (struct ars_iphdr))
26: break;
27: if (ars_seems_ip(ip, size) == 0) {
28: /* We may probably assume the link header size
29: * to be multiple of two */
30: packet++;
31: size--;
32: continue;
33: }
34: *lhs = orig_size - size;
35: return -ARS_OK;
36: }
37: return -ARS_ERROR;
38: }
39:
40: int ars_check_ip_cksum(struct ars_iphdr *ip)
41: {
42: int ip_hdrsize = ip->ihl << 2;
43: struct ars_iphdr *ip2;
44:
45: ip2 = alloca(ip_hdrsize);
46: memcpy(ip2, ip, ip_hdrsize);
47: ip2->check = 0;
48: ip2->check = ars_cksum(ip2, ip_hdrsize);
49: return (ip->check == ip2->check);
50: }
51:
52: int ars_check_icmp_cksum(struct ars_icmphdr *icmp, size_t size)
53: {
54: struct ars_icmphdr *icmp2;
55:
56: icmp2 = alloca(size);
57: memcpy(icmp2, icmp, size);
58: icmp2->checksum = 0;
59: icmp2->checksum = ars_cksum(icmp2, size);
60: return (icmp->checksum == icmp2->checksum);
61: }
62:
63: #define ARS_SPLIT_DONE 0
64: #define ARS_SPLIT_GET_IP 1
65: #define ARS_SPLIT_GET_IPOPT 2
66: #define ARS_SPLIT_GET_ICMP 3
67: #define ARS_SPLIT_GET_UDP 4
68: #define ARS_SPLIT_GET_TCP 5
69: #define ARS_SPLIT_GET_TCPOPT 6
70: #define ARS_SPLIT_GET_DATA 7
71:
72: int ars_split_ip(struct ars_packet *pkt, void *packet, size_t size,
73: int *state, int *len);
74: int ars_split_ipopt(struct ars_packet *pkt, void *packet, size_t size,
75: int *state, int *len);
76: int ars_split_icmp(struct ars_packet *pkt, void *packet, size_t size,
77: int *state, int *len);
78: int ars_split_udp(struct ars_packet *pkt, void *packet, size_t size,
79: int *state, int *len);
80: int ars_split_tcp(struct ars_packet *pkt, void *packet, size_t size,
81: int *state, int *len);
82: int ars_split_tcpopt(struct ars_packet *pkt, void *packet, size_t size,
83: int *state, int *len);
84: int ars_split_data(struct ars_packet *pkt, void *packet, size_t size,
85: int *state, int *len);
86:
87: /* Take it in sync with ARS_SPLIT_* defines */
88: int (*ars_split_state_handler[])(struct ars_packet *pkt, void *packet,
89: size_t size, int *state, int *len) =
90: {
91: NULL,
92: ars_split_ip,
93: ars_split_ipopt,
94: ars_split_icmp,
95: ars_split_udp,
96: ars_split_tcp,
97: ars_split_tcpopt,
98: ars_split_data
99: };
100:
101: int ars_split_packet(void *packet, size_t size, int ipoff, struct ars_packet *pkt)
102: {
103: int offset = 0;
104: int state = ARS_SPLIT_GET_IP;
105:
106: /* User asks for IP offset auto detection */
107: if (ipoff == -1 && ars_guess_ipoff(packet, size, &ipoff) != -ARS_OK) {
108: ars_set_error(pkt, "IP offset autodetection failed");
109: return -ARS_INVALID;
110: }
111: offset += ipoff;
112: size -= ipoff;
113:
114: /* Implemented as a finite state machine:
115: * every state is handled with a protocol specific function */
116: while (state != ARS_SPLIT_DONE) {
117: int error;
118: int len = 0;
119:
120: error = ars_split_state_handler[state](pkt, packet + offset,
121: size, &state, &len);
122: if (error != -ARS_OK)
123: return error;
124: /* put off the link layer padding */
125: if (pkt->p_layer_nr == 1 &&
126: pkt->p_layer[0].l_type == ARS_TYPE_IP) {
127: struct ars_iphdr *ip = pkt->p_layer[0].l_data;
128: size = MIN(size, ntohs(ip->tot_len));
129: }
130: offset += len;
131: size -= len;
132: /* Force the DONE state if we reached the end */
133: if (size == 0)
134: state = ARS_SPLIT_DONE;
135: }
136: return -ARS_OK;
137: }
138:
139: int ars_split_ip(struct ars_packet *pkt, void *packet, size_t size, int *state, int *len)
140: {
141: struct ars_iphdr *ip = packet, *newip;
142: int flags = 0;
143: int ipsize = ip->ihl << 2;
144:
145: /* Check for bad header size and checksum */
146: if (size < ipsize) {
147: flags |= ARS_SPLIT_FTRUNC;
148: ipsize = size;
149: }
150: else if (ars_check_ip_cksum(ip) == 0)
151: flags |= ARS_SPLIT_FBADCKSUM;
152: ipsize = MIN(ipsize, 20);
153:
154: if ((newip = ars_add_iphdr(pkt, 0)) == NULL)
155: return -ARS_NOMEM;
156: memcpy(newip, ip, ipsize);
157: ars_set_flags(pkt, ARS_LAST_LAYER, flags);
158:
159: *len = ipsize;
160:
161: if (flags & ARS_SPLIT_FTRUNC) {
162: *state = ARS_SPLIT_GET_DATA;
163: return -ARS_OK;
164: }
165:
166: if (ip->ihl > 5) { /* IP options */
167: *state = ARS_SPLIT_GET_IPOPT;
168: pkt->aux = (ip->ihl - 5) << 2;
169: return -ARS_OK;
170: }
171:
172: switch(ip->protocol) {
173: case ARS_IPPROTO_IPIP:
174: *state = ARS_SPLIT_GET_IP;
175: break;
176: case ARS_IPPROTO_ICMP:
177: *state = ARS_SPLIT_GET_ICMP;
178: break;
179: case ARS_IPPROTO_TCP:
180: *state = ARS_SPLIT_GET_TCP;
181: break;
182: case ARS_IPPROTO_UDP:
183: *state = ARS_SPLIT_GET_UDP;
184: break;
185: default:
186: *state = ARS_SPLIT_GET_DATA;
187: break;
188: }
189: return -ARS_OK;
190: }
191:
192: int ars_split_ipopt(struct ars_packet *pkt, void *packet, size_t size, int *state, int *len)
193: {
194: struct ars_ipopt *ipopt = packet;
195: int flags = 0;
196: int optsize;
197: int error;
198:
199: if (ipopt->kind == ARS_IPOPT_END || ipopt->kind == ARS_IPOPT_NOOP)
200: optsize = 1;
201: else
202: optsize = ipopt->len;
203:
204: /* pkt->aux was set by ars_split_ip, or by ars_split_ipopt itself */
205: size = MIN(size, pkt->aux);
206: if (size == 0) {
207: *len = 0;
208: *state = ARS_SPLIT_GET_DATA;
209: return -ARS_OK;
210: }
211:
212: if (size < optsize) {
213: flags |= ARS_SPLIT_FTRUNC;
214: optsize = size;
215: }
216:
217: pkt->aux -= optsize;
218: error = ars_add_generic(pkt, optsize, ARS_TYPE_IPOPT);
219: if (error != -ARS_OK)
220: return error;
221: memcpy(pkt->p_layer[pkt->p_layer_nr].l_data, ipopt, optsize);
222: pkt->p_layer_nr++;
223: ars_set_flags(pkt, ARS_LAST_LAYER, flags);
224:
225: *len = optsize;
226:
227: if (pkt->aux > 0)
228: *state = ARS_SPLIT_GET_IPOPT;
229: else
230: *state = ARS_SPLIT_GET_DATA;
231:
232: return -ARS_OK;
233: }
234:
235: int ars_split_icmp(struct ars_packet *pkt, void *packet, size_t size, int *state, int *len)
236: {
237: struct ars_icmphdr *icmp = packet, *newicmp;
238: int flags = 0;
239: int icmpsize = ARS_ICMPHDR_SIZE;
240:
241: /* Check for bad header size and checksum */
242: if (size < icmpsize) {
243: flags |= ARS_SPLIT_FTRUNC;
244: icmpsize = size;
245: }
246: else if (ars_check_icmp_cksum(icmp, size) == 0)
247: flags |= ARS_SPLIT_FBADCKSUM;
248:
249: if ((newicmp = ars_add_icmphdr(pkt, 0)) == NULL)
250: return -ARS_NOMEM;
251: memcpy(newicmp, icmp, icmpsize);
252: ars_set_flags(pkt, ARS_LAST_LAYER, flags);
253:
254: *len = icmpsize;
255:
256: if (flags & ARS_SPLIT_FTRUNC) {
257: *state = ARS_SPLIT_GET_DATA;
258: return -ARS_OK;
259: }
260:
261: switch(icmp->type) {
262: case ARS_ICMP_ECHO:
263: case ARS_ICMP_ECHOREPLY:
264: *state = ARS_SPLIT_GET_DATA;
265: break;
266: default:
267: *state = ARS_SPLIT_GET_IP;
268: break;
269: }
270: return -ARS_OK;
271: }
272:
273: int ars_split_data(struct ars_packet *pkt, void *packet, size_t size, int *state, int *len)
274: {
275: void *newdata;
276:
277: if ((newdata = ars_add_data(pkt, size)) == NULL)
278: return -ARS_NOMEM;
279: memcpy(newdata, packet, size);
280:
281: *len = size;
282:
283: *state = ARS_SPLIT_DONE;
284: return -ARS_OK;
285: }
286:
287: int ars_split_udp(struct ars_packet *pkt, void *packet, size_t size, int *state, int *len)
288: {
289: struct ars_udphdr *udp = packet, *newudp;
290: int flags = 0;
291: int udpsize = ARS_UDPHDR_SIZE;
292: int error;
293: u_int16_t udpcksum;
294:
295: /* XXX hack, we need to add a temp unusual layer (UDP+UDP_DATA) to
296: * use the ars_udptcp_cksum() function. */
297:
298: /* --- HACK START --- */
299: error = ars_add_generic(pkt, size, ARS_TYPE_UDP);
300: if (error != -ARS_OK)
301: return error;
302: newudp = pkt->p_layer[pkt->p_layer_nr].l_data;
303: memcpy(newudp, udp, size);
304: newudp->uh_sum = 0;
305: error = ars_udptcp_cksum(pkt, pkt->p_layer_nr, &udpcksum);
306: if (error != ARS_OK) {
307: printf("---ERROR DOING CHECKSUM\n");
308: pkt->p_layer_nr++; /* just to be sane */
309: return error;
310: }
311: error = ars_remove_layer(pkt, pkt->p_layer_nr);
312: if (error != ARS_OK)
313: return error;
314: /* --- HACK END --- */
315:
316: /* Check for bad header size and checksum */
317: if (size < udpsize) {
318: flags |= ARS_SPLIT_FTRUNC;
319: udpsize = size;
320: }
321: else if (udp->uh_sum != udpcksum)
322: flags |= ARS_SPLIT_FBADCKSUM;
323:
324: if ((newudp = ars_add_udphdr(pkt, 0)) == NULL)
325: return -ARS_NOMEM;
326: memcpy(newudp, udp, udpsize);
327: ars_set_flags(pkt, ARS_LAST_LAYER, flags);
328:
329: *len = udpsize;
330: *state = ARS_SPLIT_GET_DATA;
331: return -ARS_OK;
332: }
333:
334: int ars_split_tcp(struct ars_packet *pkt, void *packet, size_t size, int *state, int *len)
335: {
336: struct ars_tcphdr *tcp = packet, *newtcp;
337: int flags = 0;
338: int tcpsize = tcp->th_off << 2;
339: int error;
340: u_int16_t tcpcksum;
341:
342: /* XXX hack, we need to add a temp unusual layer (TCP+TCP_DATA) to
343: * use the ars_udptcp_cksum() function. */
344:
345: /* --- HACK START --- */
346: error = ars_add_generic(pkt, size, ARS_TYPE_TCP);
347: if (error != -ARS_OK)
348: return error;
349: newtcp = pkt->p_layer[pkt->p_layer_nr].l_data;
350: memcpy(newtcp, tcp, size);
351: newtcp->th_sum = 0;
352: error = ars_udptcp_cksum(pkt, pkt->p_layer_nr, &tcpcksum);
353: if (error != ARS_OK) {
354: pkt->p_layer_nr++; /* just to be sane */
355: return error;
356: }
357: error = ars_remove_layer(pkt, pkt->p_layer_nr);
358: if (error != ARS_OK)
359: return error;
360: /* --- HACK END --- */
361:
362: /* Check for bad header size and checksum */
363: if (size < tcpsize) {
364: flags |= ARS_SPLIT_FTRUNC;
365: tcpsize = size;
366: }
367: else if (tcp->th_sum != tcpcksum)
368: flags |= ARS_SPLIT_FBADCKSUM;
369:
370: tcpsize = MIN(tcpsize, 20);
371:
372: if ((newtcp = ars_add_tcphdr(pkt, 0)) == NULL)
373: return -ARS_NOMEM;
374: memcpy(newtcp, tcp, tcpsize);
375: ars_set_flags(pkt, ARS_LAST_LAYER, flags);
376:
377: *len = tcpsize;
378: if (tcp->th_off > 5) {
379: *state = ARS_SPLIT_GET_TCPOPT;
380: pkt->aux = (tcp->th_off - 5) << 2;
381: } else {
382: *state = ARS_SPLIT_GET_DATA;
383: }
384: return -ARS_OK;
385: }
386:
387: int ars_split_tcpopt(struct ars_packet *pkt, void *packet, size_t size, int *state, int *len)
388: {
389: struct ars_tcpopt *tcpopt = packet;
390: int flags = 0;
391: int optsize;
392: int error;
393:
394: if (tcpopt->kind == ARS_TCPOPT_EOL || tcpopt->kind == ARS_TCPOPT_NOP)
395: optsize = 1;
396: else
397: optsize = tcpopt->len;
398:
399: /* pkt->aux was set by ars_split_tcp, or by ars_split_tcpopt itself */
400: size = MIN(size, pkt->aux);
401: if (size == 0) {
402: *len = 0;
403: *state = ARS_SPLIT_GET_DATA;
404: return -ARS_OK;
405: }
406:
407: if (size < optsize) {
408: flags |= ARS_SPLIT_FTRUNC;
409: optsize = size;
410: }
411:
412: pkt->aux -= optsize;
413: error = ars_add_generic(pkt, optsize, ARS_TYPE_TCPOPT);
414: if (error != -ARS_OK)
415: return error;
416: memcpy(pkt->p_layer[pkt->p_layer_nr].l_data, tcpopt, optsize);
417: pkt->p_layer_nr++;
418: ars_set_flags(pkt, ARS_LAST_LAYER, flags);
419:
420: *len = optsize;
421:
422: if (pkt->aux > 0)
423: *state = ARS_SPLIT_GET_TCPOPT;
424: else
425: *state = ARS_SPLIT_GET_DATA;
426:
427: return -ARS_OK;
428: }
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>