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>