Annotation of embedaddon/hping2/ars.c, revision 1.1
1.1 ! misho 1: /* Copyright (C) 2000,2001 Salvatore Sanfilippo <antirez@invece.org>
! 2: * See the LICENSE file for more information.
! 3: *
! 4: * TODO:
! 5: * o Functions to add addresses and timestamps for some IP and TCP option
! 6: * o IGMP support
! 7: * o DNS support
! 8: * o ARS add_build_layer() facility and Co., read the PROPOSAL file.
! 9: */
! 10:
! 11: /* $Id: ars.c,v 1.4 2003/07/28 09:00:54 njombart Exp $ */
! 12:
! 13: #include <stdio.h>
! 14: #include <stdlib.h>
! 15: #include <assert.h>
! 16: #include <string.h>
! 17: #include <sys/types.h>
! 18: #include <netinet/in.h>
! 19: #include <arpa/inet.h>
! 20: #include <netdb.h>
! 21: #include <unistd.h>
! 22: #include "ars.h"
! 23:
! 24: /* prototypes */
! 25: int ars_compiler_ip(struct ars_packet *pkt, int layer);
! 26: int ars_compiler_ipopt(struct ars_packet *pkt, int layer);
! 27: int ars_compiler_tcp(struct ars_packet *pkt, int layer);
! 28: int ars_compiler_tcpopt(struct ars_packet *pkt, int layer);
! 29: int ars_compiler_udp(struct ars_packet *pkt, int layer);
! 30: int ars_compiler_icmp(struct ars_packet *pkt, int layer);
! 31: int ars_compiler_abort(struct ars_packet *pkt, int layer) { return 0; }
! 32:
! 33: /* Initialize a packets context:
! 34: * must be called before to work with the packet's layers */
! 35: int ars_init(struct ars_packet *pkt)
! 36: {
! 37: int j;
! 38:
! 39: pkt->p_error = NULL;
! 40: pkt->p_layer_nr = 0;
! 41: for (j = 0; j < ARS_MAX_LAYER; j++) {
! 42: pkt->p_layer[j].l_size = 0;
! 43: pkt->p_layer[j].l_flags = 0;
! 44: pkt->p_layer[j].l_type = ARS_TYPE_NULL;
! 45: pkt->p_layer[j].l_data = NULL;
! 46: pkt->p_layer[j].l_packet = pkt;
! 47: }
! 48: for (j = 0; j < ARS_TYPE_SIZE; j++)
! 49: pkt->p_default[j] = NULL;
! 50: return -ARS_OK;
! 51: }
! 52:
! 53: /* Destroy (free the allocated memory) a packet context */
! 54: int ars_destroy(struct ars_packet *pkt)
! 55: {
! 56: int j;
! 57:
! 58: free(pkt->p_error);
! 59: for (j = 0; j < ARS_MAX_LAYER; j++) {
! 60: if (pkt->p_layer[j].l_type != ARS_TYPE_NULL &&
! 61: pkt->p_layer[j].l_data != NULL)
! 62: free(pkt->p_layer[j].l_data);
! 63: }
! 64: return ars_init(pkt); /* Re-initialize it */
! 65: }
! 66:
! 67: /* THe out of memory message must be statically allocated */
! 68: char *ars_error_nomem = "Out of memory";
! 69:
! 70: /* Set the error description */
! 71: int ars_set_error(struct ars_packet *pkt, char *error)
! 72: {
! 73: if (pkt == NULL)
! 74: return -ARS_OK;
! 75:
! 76: free(pkt->p_error); /* p_error is initialized to NULL */
! 77: if ((pkt->p_error = strdup(error)) == NULL) {
! 78: /* To put the error description for the -KO_NOMEM
! 79: * error we needs a statically allocated error message:
! 80: * Note that all other functions don't need to report
! 81: * a statically allocated error message for -KO_NOMEM
! 82: * it will be auto-selected if strdup() returns NULL */
! 83: pkt->p_error = ars_error_nomem;
! 84: }
! 85: return -ARS_OK; /* report anyway success */
! 86: }
! 87:
! 88: /* Set the default for a layer */
! 89: int ars_set_default(struct ars_packet *pkt, int layer_type, void *def)
! 90: {
! 91: pkt->p_default[layer_type] = def;
! 92: return -ARS_OK;
! 93: }
! 94:
! 95: /* return nonzero if the packet is full */
! 96: int ars_nospace(struct ars_packet *pkt)
! 97: {
! 98: return (pkt->p_layer_nr == ARS_MAX_LAYER);
! 99: }
! 100:
! 101: /* Check if the layer number is valid */
! 102: int ars_valid_layer(int layer)
! 103: {
! 104: if (layer < 0 || layer >= ARS_MAX_LAYER)
! 105: return -ARS_INVALID;
! 106: return -ARS_OK;
! 107: }
! 108:
! 109: /* Add an a generic layer */
! 110: int ars_add_generic(struct ars_packet *pkt, size_t size, int type)
! 111: {
! 112: int layer;
! 113:
! 114: if (ars_nospace(pkt)) {
! 115: ars_set_error(pkt, "No space for the next layer");
! 116: return -ARS_NOSPACE;
! 117: }
! 118: layer = pkt->p_layer_nr;
! 119: /* You may want to create a 0 len layer and then realloc */
! 120: if (size != 0) {
! 121: pkt->p_layer[layer].l_data = malloc(size);
! 122: if (pkt->p_layer[layer].l_data == NULL) {
! 123: ars_set_error(pkt, "Out of memory adding a new layer");
! 124: return -ARS_NOMEM;
! 125: }
! 126: memset(pkt->p_layer[layer].l_data, 0, size);
! 127: /* Copy the default if any */
! 128: if (pkt->p_default[type] != NULL) {
! 129: memcpy(pkt->p_layer[layer].l_data,
! 130: pkt->p_default[type], size);
! 131: }
! 132: }
! 133: pkt->p_layer[layer].l_type = type;
! 134: pkt->p_layer[layer].l_size = size;
! 135: return -ARS_OK;
! 136: }
! 137:
! 138: /* Add an IP layer */
! 139: void *ars_add_iphdr(struct ars_packet *pkt, int unused)
! 140: {
! 141: int retval;
! 142:
! 143: retval = ars_add_generic(pkt, sizeof(struct ars_iphdr), ARS_TYPE_IP);
! 144: if (retval != -ARS_OK)
! 145: return NULL;
! 146: pkt->p_layer_nr++;
! 147: return pkt->p_layer[pkt->p_layer_nr-1].l_data;
! 148: }
! 149:
! 150: /* Add on IP option */
! 151: void *ars_add_ipopt(struct ars_packet *pkt, int option)
! 152: {
! 153: int retval;
! 154: struct ars_ipopt *ipopt;
! 155: int opt_len;
! 156:
! 157: switch(option) {
! 158: case ARS_IPOPT_END:
! 159: case ARS_IPOPT_NOOP:
! 160: opt_len = 1;
! 161: break;
! 162: case ARS_IPOPT_SEC:
! 163: opt_len = 11;
! 164: break;
! 165: case ARS_IPOPT_SID:
! 166: opt_len = 4;
! 167: break;
! 168: case ARS_IPOPT_LSRR:
! 169: case ARS_IPOPT_SSRR:
! 170: case ARS_IPOPT_RR:
! 171: case ARS_IPOPT_TIMESTAMP:
! 172: /* We allocate the max (40 bytes) but the real layer size
! 173: * may be modified by ars_ipopt_set*() functions */
! 174: opt_len = 40;
! 175: break;
! 176: default:
! 177: return NULL; /* Unsupported option */
! 178: break;
! 179: }
! 180:
! 181: retval = ars_add_generic(pkt, opt_len, ARS_TYPE_IPOPT);
! 182: if (retval != -ARS_OK)
! 183: return NULL;
! 184: ipopt = pkt->p_layer[pkt->p_layer_nr].l_data;
! 185: pkt->p_layer_nr++;
! 186:
! 187: ipopt->kind = option;
! 188: ipopt->len = opt_len; /* the default, can be modified inside switch() */
! 189: /* Perform some special operation for some option */
! 190: switch(option) {
! 191: case ARS_IPOPT_LSRR: /* ars_ipopt_setls() will change some field */
! 192: case ARS_IPOPT_SSRR: /* ars_ipopt_setss() will change some field */
! 193: case ARS_IPOPT_RR: /* ars_ipopt_setrr() will change some field */
! 194: /* RFC 791 needs the roomlen - 3 octects, so the gateways
! 195: * can compare len and ptr to check for room.
! 196: * Try to break this to stress lame TCP/IP implementation */
! 197: ipopt->len = opt_len - 2 - 3;
! 198: ipopt->un.rr.ptr = 4;
! 199: break;
! 200: case ARS_IPOPT_TIMESTAMP:
! 201: ipopt->un.tstamp.ptr = 5;
! 202: ipopt->un.tstamp.flags = ARS_IPOPT_TS_TSONLY; /* default */
! 203: break;
! 204: }
! 205: return ipopt;
! 206: }
! 207:
! 208: /* Add a UDP layer */
! 209: void *ars_add_udphdr(struct ars_packet *pkt, int unused)
! 210: {
! 211: int retval;
! 212:
! 213: retval = ars_add_generic(pkt, sizeof(struct ars_udphdr), ARS_TYPE_UDP);
! 214: if (retval != -ARS_OK)
! 215: return NULL;
! 216: pkt->p_layer_nr++;
! 217: return pkt->p_layer[pkt->p_layer_nr-1].l_data;
! 218: }
! 219:
! 220: /* Add a TCP layer */
! 221: void *ars_add_tcphdr(struct ars_packet *pkt, int unused)
! 222: {
! 223: int retval;
! 224:
! 225: retval = ars_add_generic(pkt, sizeof(struct ars_tcphdr), ARS_TYPE_TCP);
! 226: if (retval != -ARS_OK)
! 227: return NULL;
! 228: pkt->p_layer_nr++;
! 229: return pkt->p_layer[pkt->p_layer_nr-1].l_data;
! 230: }
! 231:
! 232: /* Add TCP options */
! 233: void *ars_add_tcpopt(struct ars_packet *pkt, int option)
! 234: {
! 235: int retval;
! 236: struct ars_tcpopt *tcpopt;
! 237: int opt_len;
! 238:
! 239: switch(option) {
! 240: case ARS_TCPOPT_NOP:
! 241: case ARS_TCPOPT_EOL:
! 242: opt_len = 1;
! 243: break;
! 244: case ARS_TCPOPT_MAXSEG:
! 245: opt_len = 4;
! 246: break;
! 247: case ARS_TCPOPT_WINDOW:
! 248: opt_len = 3;
! 249: break;
! 250: case ARS_TCPOPT_SACK_PERM: /* ars_tcpopt_setsack() must change this */
! 251: case ARS_TCPOPT_SACK:
! 252: opt_len = 2;
! 253: break;
! 254: case ARS_TCPOPT_ECHOREQUEST:
! 255: case ARS_TCPOPT_ECHOREPLY:
! 256: opt_len = 6;
! 257: break;
! 258: case ARS_TCPOPT_TIMESTAMP:
! 259: opt_len = 10;
! 260: break;
! 261: default:
! 262: return NULL; /* Unsupported option */
! 263: break;
! 264: }
! 265:
! 266: retval = ars_add_generic(pkt, opt_len, ARS_TYPE_TCPOPT);
! 267: if (retval != -ARS_OK)
! 268: return NULL;
! 269: tcpopt = pkt->p_layer[pkt->p_layer_nr].l_data;
! 270: pkt->p_layer_nr++;
! 271:
! 272: tcpopt->kind = option;
! 273: /* EOL and NOP lacks the len field */
! 274: if (option != ARS_TCPOPT_EOL && option != ARS_TCPOPT_NOP)
! 275: tcpopt->len = opt_len;
! 276:
! 277: /* Perform some special operation for the option */
! 278: switch(option) {
! 279: case ARS_TCPOPT_ECHOREQUEST:
! 280: case ARS_TCPOPT_ECHOREPLY:
! 281: memset(tcpopt->un.echo.info, 0, 4);
! 282: break;
! 283: case ARS_TCPOPT_TIMESTAMP:
! 284: memset(tcpopt->un.timestamp.tsval, 0, 4);
! 285: memset(tcpopt->un.timestamp.tsecr, 0, 4);
! 286: break;
! 287: }
! 288: return tcpopt;
! 289: }
! 290:
! 291: /* Add an ICMP layer */
! 292: void *ars_add_icmphdr(struct ars_packet *pkt, int unused)
! 293: {
! 294: int retval;
! 295: struct ars_icmphdr *icmp;
! 296:
! 297: retval = ars_add_generic(pkt, sizeof(struct ars_icmphdr),ARS_TYPE_ICMP);
! 298: if (retval != -ARS_OK)
! 299: return NULL;
! 300: icmp = pkt->p_layer[pkt->p_layer_nr].l_data;
! 301: pkt->p_layer_nr++;
! 302: return (struct ars_icmphdr*) pkt->p_layer[pkt->p_layer_nr-1].l_data;
! 303: }
! 304:
! 305: /* Add data, for IP-RAW, TCP, UDP, and so on */
! 306: void *ars_add_data(struct ars_packet *pkt, int size)
! 307: {
! 308: int retval;
! 309: void *boguspointer = "zzappt"; /* we can't return NULL for size == 0 */
! 310:
! 311: if (size < 0) {
! 312: ars_set_error(pkt, "Tryed to add a DATA layer with size < 0");
! 313: return NULL;
! 314: }
! 315: retval = ars_add_generic(pkt, size, ARS_TYPE_DATA);
! 316: if (retval != -ARS_OK)
! 317: return NULL;
! 318: pkt->p_layer_nr++;
! 319: if (size > 0)
! 320: return pkt->p_layer[pkt->p_layer_nr-1].l_data;
! 321: else
! 322: return boguspointer;
! 323: }
! 324:
! 325: /* Remove a layer */
! 326: int ars_remove_layer(struct ars_packet *pkt, int layer)
! 327: {
! 328: if (layer == ARS_LAST_LAYER)
! 329: layer = pkt->p_layer_nr -1;
! 330: if (ars_valid_layer(layer) != -ARS_OK)
! 331: return -ARS_INVALID;
! 332:
! 333: free(pkt->p_layer[layer].l_data); /* No problem if it's NULL */
! 334: pkt->p_layer[layer].l_type = ARS_TYPE_NULL;
! 335: pkt->p_layer[layer].l_size = 0;
! 336: pkt->p_layer[layer].l_flags = 0;
! 337: pkt->p_layer[layer].l_data = NULL;
! 338: pkt->p_layer[layer].l_packet = pkt;
! 339: return -ARS_OK;
! 340: }
! 341:
! 342: /* Return the sum of the size of the specifed layer and of all the
! 343: * following layers */
! 344: size_t ars_relative_size(struct ars_packet *pkt, int layer_nr)
! 345: {
! 346: int j = layer_nr, rel_size = 0;
! 347:
! 348: while (j < ARS_MAX_LAYER && pkt->p_layer[j].l_type != ARS_TYPE_NULL) {
! 349: rel_size += pkt->p_layer[j].l_size;
! 350: j++;
! 351: }
! 352: return rel_size;
! 353: }
! 354:
! 355: /* Just a short cut for ars_relative_size(), to get the total size */
! 356: size_t ars_packet_size(struct ars_packet *pkt)
! 357: {
! 358: return ars_relative_size(pkt, 0);
! 359: }
! 360:
! 361: /* from R. Stevens's Network Programming */
! 362: u_int16_t ars_cksum(void *vbuf, size_t nbytes)
! 363: {
! 364: u_int16_t *buf = (u_int16_t*) vbuf;
! 365: u_int32_t sum;
! 366: u_int16_t oddbyte;
! 367:
! 368: sum = 0;
! 369: while (nbytes > 1) {
! 370: sum += *buf++;
! 371: nbytes -= 2;
! 372: }
! 373: if (nbytes == 1) {
! 374: oddbyte = 0;
! 375: *((u_int16_t *) &oddbyte) = *(u_int8_t *) buf;
! 376: sum += oddbyte;
! 377: }
! 378: sum = (sum >> 16) + (sum & 0xffff);
! 379: sum += (sum >> 16);
! 380: return (u_int16_t) ~sum;
! 381: }
! 382:
! 383: /* Multiple buffers checksum facility */
! 384: u_int16_t ars_multi_cksum(struct mc_context *c, int op, void *vbuf,
! 385: size_t nbytes)
! 386: {
! 387: u_int16_t *buf = (u_int16_t*) vbuf;
! 388: u_int32_t sum;
! 389: u_int16_t oddbyte;
! 390: void *tmp;
! 391:
! 392: if (op == ARS_MC_INIT) {
! 393: c->oddbyte_flag = 0;
! 394: c->old = 0;
! 395: return -ARS_OK;
! 396: } else if (op == ARS_MC_UPDATE) {
! 397: if (c->oddbyte_flag) {
! 398: u_int8_t *x = (u_int8_t*)&oddbyte;
! 399: oddbyte = 0;
! 400: *((u_int16_t *) &oddbyte) = c->oddbyte << 8;
! 401: *((u_int16_t *) &oddbyte) |= *(u_int8_t *) buf;
! 402: oddbyte = (x[0] << 8) | x[1]; /* fix endianess */
! 403: c->old += oddbyte;
! 404: nbytes--;
! 405: c->oddbyte_flag = 0;
! 406: /* We need to stay aligned -- bad slowdown, fix? */
! 407: tmp = alloca(nbytes);
! 408: memcpy(tmp, vbuf+1, nbytes);
! 409: buf = tmp;
! 410: }
! 411: sum = c->old;
! 412: while (nbytes > 1) {
! 413: sum += *buf++;
! 414: nbytes -= 2;
! 415: }
! 416: c->old = sum;
! 417: if (nbytes == 1) {
! 418: c->oddbyte = *(u_int8_t*) buf;
! 419: c->oddbyte_flag++;
! 420: }
! 421: return -ARS_OK;
! 422: } else if (op == ARS_MC_FINAL) {
! 423: sum = c->old;
! 424: if (c->oddbyte_flag == 1) {
! 425: oddbyte = 0;
! 426: *((u_int16_t *) &oddbyte) = c->oddbyte;
! 427: sum += oddbyte;
! 428: }
! 429: sum = (sum >> 16) + (sum & 0xffff);
! 430: sum += (sum >> 16);
! 431: return (u_int16_t) ~sum;
! 432: } else {
! 433: assert("else reached in ars_multi_cksum()" == "");
! 434: }
! 435: return 0; /* unreached, here to prevent warnings */
! 436: }
! 437:
! 438: /* The ARS compiler table is just a function pointers array:
! 439: * For example to select the right function to compile an IP
! 440: * layer use: ars_compiler[ARS_TYPE_IP](pkt, layer);
! 441: * You can, of course, add your protocols and compilers:
! 442: *
! 443: * WARNING: take it syncronized with ars.h ARS_TYPE_* defines
! 444: */
! 445: struct ars_layer_info ars_linfo[ARS_TYPE_SIZE] = {
! 446: /* NAME COMPILER ID *
! 447: * ---- -------- -- */
! 448: { "NULL", ars_compiler_abort, 0 },
! 449: { "IP", ars_compiler_ip, 1 },
! 450: { "IPOPT", ars_compiler_ipopt, 2 },
! 451: { "ICMP", ars_compiler_icmp, 3 },
! 452: { "UDP", ars_compiler_udp, 4 },
! 453: { "TCP", ars_compiler_tcp, 5 },
! 454: { "TCPOPT", ars_compiler_tcpopt, 6 },
! 455: { NULL, NULL, 7 },
! 456: { NULL, NULL, 8 },
! 457: { NULL, NULL, 9 },
! 458: { NULL, NULL, 10 },
! 459: { NULL, NULL, 11 },
! 460: { NULL, NULL, 12 },
! 461: { NULL, NULL, 13 },
! 462: { NULL, NULL, 14 },
! 463: { NULL, NULL, 15 },
! 464: { NULL, NULL, 16 },
! 465: { NULL, NULL, 17 },
! 466: { NULL, NULL, 18 },
! 467: { NULL, NULL, 19 },
! 468: { NULL, NULL, 20 },
! 469: { NULL, NULL, 21 },
! 470: { NULL, NULL, 22 },
! 471: { NULL, NULL, 23 },
! 472: { NULL, NULL, 24 },
! 473: { NULL, NULL, 25 },
! 474: { NULL, NULL, 26 },
! 475: { NULL, NULL, 27 },
! 476: { NULL, NULL, 28 },
! 477: { NULL, NULL, 29 },
! 478: { NULL, NULL, 30 },
! 479: { "DATA", NULL, 31 }
! 480: };
! 481:
! 482: /* This function call the right compiler for all the layers of the packet:
! 483: * A compiler just set the protocol fields like the checksum, len, and so on
! 484: * accordly to the following layers.
! 485: * Note that the layers are compiled from the last to the first, to ensure
! 486: * that the checksum and other dependences are sane. */
! 487: int ars_compile(struct ars_packet *pkt)
! 488: {
! 489: int j, err;
! 490:
! 491: for (j = pkt->p_layer_nr - 1; j >= 0; j--) {
! 492: __D(printf("Compiling layer %d\n", j);)
! 493: /* Skip NULL compilers */
! 494: if (ars_linfo[pkt->p_layer[j].l_type].li_compiler != NULL) {
! 495: /* Call the compiler */
! 496: err = ars_linfo[pkt->p_layer[j].l_type].li_compiler(pkt, j);
! 497: if (err != -ARS_OK)
! 498: return err;
! 499: }
! 500: }
! 501: return -ARS_OK;
! 502: }
! 503:
! 504: /* The IP compiler: probably the more complex, but still simple */
! 505: int ars_compiler_ip(struct ars_packet *pkt, int layer)
! 506: {
! 507: struct ars_iphdr *ip = pkt->p_layer[layer].l_data;
! 508: int j = layer, err;
! 509: int flags = pkt->p_layer[layer].l_flags;
! 510: int ipoptlen = 0;
! 511: struct mc_context mc; /* multi-buffer checksum context */
! 512:
! 513: /* IP version */
! 514: if (ARS_DONTTAKE(flags, ARS_TAKE_IP_VERSION))
! 515: ip->version = 4;
! 516: /* IP header len */
! 517: if (ARS_DONTTAKE(flags, ARS_TAKE_IP_HDRLEN)) {
! 518: ip->ihl = (ARS_IPHDR_SIZE >> 2);
! 519: /* Add IP options len */
! 520: for (j = layer+1; j < ARS_MAX_LAYER; j++) {
! 521: if (pkt->p_layer[j].l_type != ARS_TYPE_IPOPT)
! 522: break;
! 523: ipoptlen += pkt->p_layer[j].l_size;
! 524: }
! 525: ip->ihl += ipoptlen >> 2;
! 526: }
! 527: /* IP tot len */
! 528: if (ARS_DONTTAKE(flags, ARS_TAKE_IP_TOTLEN))
! 529: ip->tot_len = htons(ars_relative_size(pkt, layer));
! 530: /* IP protocol field */
! 531: if (ARS_DONTTAKE(flags, ARS_TAKE_IP_PROTOCOL)) {
! 532: ip->protocol = ARS_IPPROTO_RAW; /* This is the default */
! 533: while (j < ARS_MAX_LAYER) {
! 534: if (pkt->p_layer[j].l_type == ARS_TYPE_IPOPT) {
! 535: j++;
! 536: continue;
! 537: }
! 538: switch(pkt->p_layer[j].l_type) {
! 539: case ARS_TYPE_IP:
! 540: ip->protocol = ARS_IPPROTO_IPIP;
! 541: break;
! 542: case ARS_TYPE_ICMP:
! 543: ip->protocol = ARS_IPPROTO_ICMP;
! 544: break;
! 545: case ARS_TYPE_UDP:
! 546: ip->protocol = ARS_IPPROTO_UDP;
! 547: break;
! 548: case ARS_TYPE_TCP:
! 549: ip->protocol = ARS_IPPROTO_TCP;
! 550: break;
! 551: }
! 552: break;
! 553: }
! 554: }
! 555: /* We always calculate the IP checksum, since the kernel
! 556: * do it only for the first IP header in the datagram */
! 557: if (ARS_DONTTAKE(flags, ARS_TAKE_IP_CKSUM)) {
! 558: ip->check = 0;
! 559: ars_multi_cksum(&mc, ARS_MC_INIT, NULL, 0);
! 560: err = ars_multi_cksum(&mc, ARS_MC_UPDATE, ip, ARS_IPHDR_SIZE);
! 561: if (err != -ARS_OK)
! 562: return err;
! 563: for (j = layer+1; j < ARS_MAX_LAYER; j++) {
! 564: if (pkt->p_layer[j].l_type != ARS_TYPE_IPOPT)
! 565: break;
! 566: err = ars_multi_cksum(&mc, ARS_MC_UPDATE,
! 567: pkt->p_layer[j].l_data,
! 568: pkt->p_layer[j].l_size);
! 569: if (err != -ARS_OK)
! 570: return err;
! 571: }
! 572: ip->check = ars_multi_cksum(&mc, ARS_MC_FINAL, NULL, 0);
! 573: }
! 574: return -ARS_OK;
! 575: }
! 576:
! 577: /* The ip options compiler: do just option padding with NOP options */
! 578: int ars_compiler_ipopt(struct ars_packet *pkt, int layer)
! 579: {
! 580: int j, opt_size;
! 581:
! 582: /* Padding is needed only in the last IP option */
! 583: if (layer != ARS_MAX_LAYER-1 &&
! 584: pkt->p_layer[layer+1].l_type == ARS_TYPE_IPOPT)
! 585: return ARS_OK;
! 586:
! 587: /* Search the layer of the relative first TCP option */
! 588: j = layer - 1; /* We know that 'layer' is a tcp option */
! 589: while (j < ARS_MAX_LAYER && j >= 0 &&
! 590: pkt->p_layer[j].l_type == ARS_TYPE_IPOPT)
! 591: j--;
! 592: j++;
! 593: __D(printf("First IP OPTION layer is %d\n", j);)
! 594: opt_size = ars_relative_size(pkt, j) - ars_relative_size(pkt, layer+1);
! 595: __D(printf("IP OPTION size %d\n", opt_size);)
! 596: if (opt_size % 4) {
! 597: int padding = 4 - (opt_size % 4);
! 598: unsigned char *t;
! 599: int cur_size = pkt->p_layer[layer].l_size;
! 600:
! 601: __D(printf("IP OPTION at layer %d needs %d bytes "
! 602: "of padding\n", layer, padding);)
! 603: t = realloc(pkt->p_layer[layer].l_data, cur_size + padding);
! 604: if (t == NULL) {
! 605: ars_set_error(pkt, "Out of memory padding IP options");
! 606: return -ARS_NOMEM;
! 607: }
! 608: memset(t+cur_size, ARS_IPOPT_NOP, padding);
! 609: pkt->p_layer[layer].l_size += padding;
! 610: }
! 611: return -ARS_OK;
! 612: }
! 613:
! 614: /* Compute the UDP and TCP checksum using the pseudoheader.
! 615: * Note that this functions automatically care about TCP/UDP data */
! 616: int ars_udptcp_cksum(struct ars_packet *pkt, int layer, u_int16_t *sum)
! 617: {
! 618: struct ars_iphdr *ip;
! 619: struct ars_pseudohdr pseudo;
! 620: struct mc_context mc; /* multi-buffer checksum context */
! 621: int j = layer - 1, err;
! 622:
! 623: /* search the first IP layer on the left:
! 624: * it returns an error if between the IP and
! 625: * the TCP layer there aren't just IPOPT layers:
! 626: * even with malformed packets this does not
! 627: * makes sense. */
! 628: while (j > 0 && pkt->p_layer[j].l_type == ARS_TYPE_IPOPT)
! 629: j--;
! 630: if (pkt->p_layer[j].l_type != ARS_TYPE_IP) {
! 631: ars_set_error(pkt, "TCP/UDP checksum requested, but IP header "
! 632: "not found");
! 633: return -ARS_INVALID;
! 634: }
! 635: ip = pkt->p_layer[j].l_data;
! 636: memset(&pseudo, 0, sizeof(pseudo)); /* actually not needed */
! 637: /* Copy the src and dst IP address */
! 638: memcpy(&pseudo.saddr, &ip->saddr, 4);
! 639: memcpy(&pseudo.daddr, &ip->daddr, 4);
! 640: pseudo.protocol = (pkt->p_layer[layer].l_type == ARS_TYPE_TCP)
! 641: ? ARS_IPPROTO_TCP : ARS_IPPROTO_UDP;
! 642: pseudo.lenght = htons(ars_relative_size(pkt, layer));
! 643:
! 644: /* Finally do the checksum */
! 645: ars_multi_cksum(&mc, ARS_MC_INIT, NULL, 0);
! 646: err = ars_multi_cksum(&mc, ARS_MC_UPDATE, &pseudo, sizeof(pseudo));
! 647: if (err != -ARS_OK)
! 648: return err;
! 649: for (j = layer; j < ARS_MAX_LAYER; j++) {
! 650: if (pkt->p_layer[j].l_type == ARS_TYPE_NULL)
! 651: break;
! 652: err = ars_multi_cksum(&mc, ARS_MC_UPDATE,
! 653: pkt->p_layer[j].l_data,
! 654: pkt->p_layer[j].l_size);
! 655: if (err != -ARS_OK)
! 656: return err;
! 657: }
! 658: *sum = ars_multi_cksum(&mc, ARS_MC_FINAL, NULL, 0);
! 659: return -ARS_OK;
! 660: }
! 661:
! 662: /* The tcp compiler */
! 663: int ars_compiler_tcp(struct ars_packet *pkt, int layer)
! 664: {
! 665: struct ars_tcphdr *tcp = pkt->p_layer[layer].l_data;
! 666: int j, err, tcpoptlen = 0;
! 667: int flags = pkt->p_layer[layer].l_flags;
! 668:
! 669: if (ARS_DONTTAKE(flags, ARS_TAKE_TCP_HDRLEN)) {
! 670: tcp->th_off = ARS_TCPHDR_SIZE >> 2;
! 671: /* Add the len of the options */
! 672: for (j = layer+1; j < ARS_MAX_LAYER; j++) {
! 673: if (pkt->p_layer[j].l_type != ARS_TYPE_TCPOPT)
! 674: break;
! 675: tcpoptlen += pkt->p_layer[j].l_size;
! 676: }
! 677: tcp->th_off += tcpoptlen >> 2;
! 678: }
! 679: if (ARS_DONTTAKE(flags, ARS_TAKE_TCP_CKSUM)) {
! 680: tcp->th_sum = 0;
! 681: err = ars_udptcp_cksum(pkt, layer, &tcp->th_sum);
! 682: if (err != -ARS_OK)
! 683: return err;
! 684: }
! 685: return -ARS_OK;
! 686: }
! 687:
! 688: /* The tcp options compiler: do just option padding with NOP options */
! 689: int ars_compiler_tcpopt(struct ars_packet *pkt, int layer)
! 690: {
! 691: int j, opt_size;
! 692:
! 693: /* Padding is needed only in the last TCP option */
! 694: if (layer != ARS_MAX_LAYER-1 &&
! 695: pkt->p_layer[layer+1].l_type == ARS_TYPE_TCPOPT)
! 696: return ARS_OK;
! 697:
! 698: /* Search the layer of the relative first TCP option */
! 699: j = layer - 1; /* We know that 'layer' is a tcp option */
! 700: while (j < ARS_MAX_LAYER && j >= 0 &&
! 701: pkt->p_layer[j].l_type == ARS_TYPE_TCPOPT)
! 702: j--;
! 703: j++;
! 704: __D(printf("First TCP OPTION layer is %d\n", j);)
! 705: opt_size = ars_relative_size(pkt, j) - ars_relative_size(pkt, layer+1);
! 706: __D(printf("TCP OPTION size %d\n", opt_size);)
! 707: if (opt_size % 4) {
! 708: int padding = 4 - (opt_size % 4);
! 709: unsigned char *t;
! 710: int cur_size = pkt->p_layer[layer].l_size;
! 711:
! 712: __D(printf("TCP OPTION at layer %d needs %d bytes "
! 713: "of padding\n", layer, padding);)
! 714: t = realloc(pkt->p_layer[layer].l_data, cur_size + padding);
! 715: if (t == NULL) {
! 716: ars_set_error(pkt, "Out of memory padding TCP options");
! 717: return -ARS_NOMEM;
! 718: }
! 719: memset(t+cur_size, ARS_TCPOPT_NOP, padding);
! 720: pkt->p_layer[layer].l_size += padding;
! 721: }
! 722: return -ARS_OK;
! 723: }
! 724:
! 725: /* The udp compiler, very simple */
! 726: int ars_compiler_udp(struct ars_packet *pkt, int layer)
! 727: {
! 728: struct ars_udphdr *udp = pkt->p_layer[layer].l_data;
! 729: int err;
! 730: int flags = pkt->p_layer[layer].l_flags;
! 731:
! 732: if (ARS_DONTTAKE(flags, ARS_TAKE_UDP_LEN))
! 733: udp->uh_ulen = htons(ars_relative_size(pkt, layer));
! 734:
! 735: if (ARS_DONTTAKE(flags, ARS_TAKE_UDP_CKSUM)) {
! 736: udp->uh_sum = 0;
! 737: err = ars_udptcp_cksum(pkt, layer, &udp->uh_sum);
! 738: if (err != -ARS_OK)
! 739: return err;
! 740: }
! 741: return -ARS_OK;
! 742: }
! 743:
! 744: /* The icmp compiler, just compute the checksum */
! 745: int ars_compiler_icmp(struct ars_packet *pkt, int layer)
! 746: {
! 747: struct ars_icmphdr *icmp = pkt->p_layer[layer].l_data;
! 748: struct mc_context mc; /* multi-buffer checksum context */
! 749: int err, j;
! 750: int flags = pkt->p_layer[layer].l_flags;
! 751:
! 752: if (ARS_DONTTAKE(flags, ARS_TAKE_ICMP_CKSUM)) {
! 753: icmp->checksum = 0;
! 754: ars_multi_cksum(&mc, ARS_MC_INIT, NULL, 0);
! 755: for (j = layer; j < ARS_MAX_LAYER; j++) {
! 756: if (pkt->p_layer[j].l_type == ARS_TYPE_NULL)
! 757: break;
! 758: err = ars_multi_cksum(&mc, ARS_MC_UPDATE,
! 759: pkt->p_layer[j].l_data,
! 760: pkt->p_layer[j].l_size);
! 761: if (err != -ARS_OK)
! 762: return err;
! 763: }
! 764: icmp->checksum = ars_multi_cksum(&mc, ARS_MC_FINAL, NULL, 0);
! 765: }
! 766: return -ARS_OK;
! 767: }
! 768:
! 769: /* Open a raw socket, ready for IP header creation and broadcast addresses */
! 770: int ars_open_rawsocket(struct ars_packet *pkt)
! 771: {
! 772: int s;
! 773: const int one = 1;
! 774:
! 775: if ((s = socket(AF_INET, SOCK_RAW, IPPROTO_RAW)) == -1) {
! 776: ars_set_error(pkt, "Can't open the raw socket");
! 777: return -ARS_ERROR;
! 778: }
! 779: if (setsockopt(s, SOL_SOCKET, SO_BROADCAST, (char*)&one,
! 780: sizeof(one)) == -1 ||
! 781: setsockopt(s, IPPROTO_IP, IP_HDRINCL, (char*)&one,
! 782: sizeof(one)) == -1)
! 783: {
! 784: close(s);
! 785: ars_set_error(pkt, "Can't set socket options");
! 786: return -ARS_ERROR;
! 787: }
! 788: return s;
! 789: }
! 790:
! 791: /* Create the packets using the layers. This function is often called
! 792: * after the layers compilation. Note that since the packet created
! 793: * is sane the strange-rawsocket-behaviour of some *BSD will not
! 794: * be able to send this packet. Use the function ars_bsd_fix() to fix it.
! 795: * WARNING: The packets returned is malloc()ated, free it */
! 796: int ars_build_packet(struct ars_packet *pkt, unsigned char **packet, size_t *size)
! 797: {
! 798: size_t tot_size, offset = 0;
! 799: int j = 0;
! 800:
! 801: if ((tot_size = ars_packet_size(pkt)) == 0) {
! 802: ars_set_error(pkt, "Total size 0 building the packet");
! 803: return -ARS_INVALID;
! 804: }
! 805: if ((*packet = malloc(tot_size)) == NULL) {
! 806: ars_set_error(pkt, "Out of memory building the packet");
! 807: return -ARS_NOMEM;
! 808: }
! 809: while (j < ARS_MAX_LAYER && pkt->p_layer[j].l_type != ARS_TYPE_NULL) {
! 810: memcpy((*packet)+offset, pkt->p_layer[j].l_data,
! 811: pkt->p_layer[j].l_size);
! 812: offset += pkt->p_layer[j].l_size;
! 813: j++;
! 814: }
! 815: *size = tot_size;
! 816: return -ARS_OK;
! 817: }
! 818:
! 819: /* FreeBSD and NetBSD have a strange raw socket layer :(
! 820: * Call this function anyway to increase portability
! 821: * since it does not perform any operation if the
! 822: * system isn't FreeBSD or NetBSD. */
! 823: int ars_bsd_fix(struct ars_packet *pkt, unsigned char *packet, size_t size)
! 824: {
! 825: struct ars_iphdr *ip;
! 826:
! 827: if (pkt->p_layer[0].l_type != ARS_TYPE_IP ||
! 828: size < sizeof(struct ars_iphdr)) {
! 829: ars_set_error(pkt, "BSD fix requested, but layer 0 not IP");
! 830: return -ARS_INVALID;
! 831: }
! 832: ip = (struct ars_iphdr*) packet;
! 833: #if defined OSTYPE_FREEBSD || defined OSTYPE_NETBSD || defined OSTYPE_BSDI
! 834: ip->tot_len = ntohs(ip->tot_len);
! 835: ip->frag_off = ntohs(ip->frag_off);
! 836: #endif
! 837: return -ARS_OK;
! 838: }
! 839:
! 840: /* Set the flags for some layer: if layer == -1 the last layer will be used */
! 841: int ars_set_flags(struct ars_packet *pkt, int layer, int flags)
! 842: {
! 843: if (layer == ARS_LAST_LAYER)
! 844: layer = pkt->p_layer_nr - 1;
! 845: if (layer < 0 || layer >= ARS_MAX_LAYER) {
! 846: ars_set_error(pkt, "Invalid layer setting layer flags");
! 847: return -ARS_INVALID;
! 848: }
! 849: pkt->p_layer[layer].l_flags = flags;
! 850: return -ARS_OK;
! 851: }
! 852:
! 853: /* Build, fix, and send the packet */
! 854: int ars_send(int s, struct ars_packet *pkt, struct sockaddr *sa, socklen_t slen)
! 855: {
! 856: struct sockaddr_in sain;
! 857: struct sockaddr *_sa = sa;
! 858: unsigned char *packet;
! 859: size_t size;
! 860: int error;
! 861:
! 862: /* Perform the socket address completion if sa == NULL */
! 863: if (sa == NULL) {
! 864: struct ars_iphdr *ip;
! 865:
! 866: memset(&sain, 0, sizeof(sain));
! 867: sain.sin_family = AF_INET;
! 868: /* The first layer MUST be IP if the user requested
! 869: * the socket address completion */
! 870: if (pkt->p_layer[0].l_type != ARS_TYPE_IP) {
! 871: ars_set_error(pkt, "socket address completion"
! 872: "requested, but layer 0 isn't IP");
! 873: return -ARS_ERROR;
! 874: }
! 875: ip = (struct ars_iphdr*) pkt->p_layer[0].l_data;
! 876: memcpy(&sain.sin_addr.s_addr, &ip->daddr, 4);
! 877: _sa = (struct sockaddr*) &sain;
! 878: slen = sizeof(sain);
! 879: }
! 880: if ((error = ars_build_packet(pkt, &packet, &size)) != ARS_OK)
! 881: return error;
! 882: if ((error = ars_bsd_fix(pkt, packet, size)) != ARS_OK)
! 883: return error;
! 884: error = sendto(s, packet, size, 0, _sa, slen);
! 885: free(packet);
! 886: return (error != -1) ? -ARS_OK : -ARS_ERROR;
! 887: }
! 888:
! 889: /* Resolve an hostname and write to 'dest' the IP */
! 890: int ars_resolve(struct ars_packet *pkt, u_int32_t *dest, char *hostname)
! 891: {
! 892: struct sockaddr_in sa;
! 893:
! 894: if (inet_aton(hostname, &sa.sin_addr) == 0) {
! 895: struct hostent *he;
! 896: he = gethostbyname(hostname);
! 897: if (he == NULL) {
! 898: ars_set_error(pkt, "Can't resolve the hostname");
! 899: return -ARS_ERROR;
! 900: }
! 901: sa.sin_addr.s_addr = ((struct in_addr*) he->h_addr)->s_addr;
! 902: }
! 903: memcpy(dest, &sa.sin_addr.s_addr, sizeof(u_int32_t));
! 904: return -ARS_OK;
! 905: }
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>