Annotation of embedaddon/hping2/split.c, revision 1.1.1.1

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

FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>