Annotation of embedaddon/hping2/split.c, revision 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>