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>