int ars_split_tcp(struct ars_packet *pkt, void *packet, size_t size, int *state, int *len) { struct ars_tcphdr *tcp = packet, *newtcp; int flags = 0; int tcpsize = tcp->th_off << 2; int error; u_int16_t tcpcksum; /* XXX hack, we need to add a temp unusual layer (TCP+TCP_DATA) to * use the ars_udptcp_cksum() function. */ /* --- HACK START --- */ error = ars_add_generic(pkt, size, ARS_TYPE_TCP); if (error != -ARS_OK) return error; newtcp = pkt->p_layer[pkt->p_layer_nr].l_data; memcpy(newtcp, tcp, size); newtcp->th_sum = 0; error = ars_udptcp_cksum(pkt, pkt->p_layer_nr, &tcpcksum); if (error != ARS_OK) { pkt->p_layer_nr++; /* just to be sane */ return error; } error = ars_remove_layer(pkt, pkt->p_layer_nr); if (error != ARS_OK) return error; /* --- HACK END --- */ /* Check for bad header size and checksum */ if (size < tcpsize) { flags |= ARS_SPLIT_FTRUNC; tcpsize = size; } else if (tcp->th_sum != tcpcksum) flags |= ARS_SPLIT_FBADCKSUM; tcpsize = MIN(tcpsize, 20); if ((newtcp = ars_add_tcphdr(pkt, 0)) == NULL) return -ARS_NOMEM; memcpy(newtcp, tcp, tcpsize); ars_set_flags(pkt, ARS_LAST_LAYER, flags); *len = tcpsize; if (tcp->th_off > 5) { *state = ARS_SPLIT_GET_TCPOPT; pkt->aux = (tcp->th_off - 5) << 2; } else { *state = ARS_SPLIT_GET_DATA; } return -ARS_OK; }
int ars_split_ip(struct ars_packet *pkt, void *packet, size_t size, int *state, int *len) { struct ars_iphdr *ip = packet, *newip; int flags = 0; int ipsize = ip->ihl << 2; /* Check for bad header size and checksum */ if (size < ipsize) { flags |= ARS_SPLIT_FTRUNC; ipsize = size; } else if (ars_check_ip_cksum(ip) == 0) flags |= ARS_SPLIT_FBADCKSUM; ipsize = MIN(ipsize, 20); if ((newip = ars_add_iphdr(pkt, 0)) == NULL) return -ARS_NOMEM; memcpy(newip, ip, ipsize); ars_set_flags(pkt, ARS_LAST_LAYER, flags); *len = ipsize; if (flags & ARS_SPLIT_FTRUNC) { *state = ARS_SPLIT_GET_DATA; return -ARS_OK; } if (ip->ihl > 5) { /* IP options */ *state = ARS_SPLIT_GET_IPOPT; pkt->aux = (ip->ihl - 5) << 2; return -ARS_OK; } switch(ip->protocol) { case ARS_IPPROTO_IPIP: *state = ARS_SPLIT_GET_IP; break; case ARS_IPPROTO_ICMP: *state = ARS_SPLIT_GET_ICMP; break; case ARS_IPPROTO_TCP: *state = ARS_SPLIT_GET_TCP; break; case ARS_IPPROTO_UDP: *state = ARS_SPLIT_GET_UDP; break; default: *state = ARS_SPLIT_GET_DATA; break; } return -ARS_OK; }
int ars_split_tcpopt(struct ars_packet *pkt, void *packet, size_t size, int *state, int *len) { struct ars_tcpopt *tcpopt = packet; int flags = 0; int optsize; int error; if (tcpopt->kind == ARS_TCPOPT_EOL || tcpopt->kind == ARS_TCPOPT_NOP || tcpopt->kind == ARS_TCPOPT_SACK_PERM) optsize = 1; else optsize = tcpopt->len; /* Avoid infinite loop with broken packets */ if (optsize == 0) optsize = 1; /* pkt->aux was set by ars_split_tcp, or by ars_split_tcpopt itself */ size = MIN(size, pkt->aux); if (size == 0) { *len = 0; *state = ARS_SPLIT_GET_DATA; return -ARS_OK; } if (size < optsize) { flags |= ARS_SPLIT_FTRUNC; optsize = size; } pkt->aux -= optsize; error = ars_add_generic(pkt, optsize, ARS_TYPE_TCPOPT); if (error != -ARS_OK) return error; memcpy(pkt->p_layer[pkt->p_layer_nr].l_data, tcpopt, optsize); pkt->p_layer_nr++; ars_set_flags(pkt, ARS_LAST_LAYER, flags); *len = optsize; if (pkt->aux > 0) *state = ARS_SPLIT_GET_TCPOPT; else *state = ARS_SPLIT_GET_DATA; return -ARS_OK; }
int ars_split_udp(struct ars_packet *pkt, void *packet, size_t size, int *state, int *len) { struct ars_udphdr *udp = packet, *newudp; int flags = 0; int udpsize = ARS_UDPHDR_SIZE; int error; u_int16_t udpcksum; /* XXX hack, we need to add a temp unusual layer (UDP+UDP_DATA) to * use the ars_udptcp_cksum() function. */ /* --- HACK START --- */ error = ars_add_generic(pkt, size, ARS_TYPE_UDP); if (error != -ARS_OK) return error; newudp = pkt->p_layer[pkt->p_layer_nr].l_data; memcpy(newudp, udp, size); newudp->uh_sum = 0; error = ars_udptcp_cksum(pkt, pkt->p_layer_nr, &udpcksum); if (error != ARS_OK) { printf("---ERROR DOING CHECKSUM\n"); pkt->p_layer_nr++; /* just to be sane */ return error; } error = ars_remove_layer(pkt, pkt->p_layer_nr); if (error != ARS_OK) return error; /* --- HACK END --- */ /* Check for bad header size and checksum */ if (size < udpsize) { flags |= ARS_SPLIT_FTRUNC; udpsize = size; } else if (udp->uh_sum != udpcksum) flags |= ARS_SPLIT_FBADCKSUM; if ((newudp = ars_add_udphdr(pkt, 0)) == NULL) return -ARS_NOMEM; memcpy(newudp, udp, udpsize); ars_set_flags(pkt, ARS_LAST_LAYER, flags); *len = udpsize; *state = ARS_SPLIT_GET_DATA; return -ARS_OK; }
int ars_split_ipopt(struct ars_packet *pkt, void *packet, size_t size, int *state, int *len) { struct ars_ipopt *ipopt = packet; int flags = 0; int optsize; int error; if (ipopt->kind == ARS_IPOPT_END || ipopt->kind == ARS_IPOPT_NOOP) optsize = 1; else optsize = ipopt->len; /* Avoid infinite loop with broken packets */ if (optsize == 0) optsize = 1; /* pkt->aux was set by ars_split_ip, or by ars_split_ipopt itself */ size = MIN(size, pkt->aux); if (size == 0) { *len = 0; *state = ARS_SPLIT_GET_DATA; return -ARS_OK; } if (size < optsize) { flags |= ARS_SPLIT_FTRUNC; optsize = size; } pkt->aux -= optsize; error = ars_add_generic(pkt, optsize, ARS_TYPE_IPOPT); if (error != -ARS_OK) return error; memcpy(pkt->p_layer[pkt->p_layer_nr].l_data, ipopt, optsize); pkt->p_layer_nr++; ars_set_flags(pkt, ARS_LAST_LAYER, flags); *len = optsize; if (pkt->aux > 0) { *state = ARS_SPLIT_GET_IPOPT; } else { ars_ip_next_state(pkt->aux_ipproto, state); } return -ARS_OK; }
int ars_split_ip(struct ars_packet *pkt, void *packet, size_t size, int *state, int *len) { struct ars_iphdr *ip = packet, *newip; int flags = 0; int ipsize; /* Check for bad header size and checksum */ if (size < sizeof(struct ars_iphdr)) { flags |= ARS_SPLIT_FTRUNC; ipsize = size; } else { ipsize = ip->ihl << 2; if (size < ipsize) { flags |= ARS_SPLIT_FTRUNC; ipsize = size; } else if (ip->ihl < 4 || ars_check_ip_cksum(ip) == 0) flags |= ARS_SPLIT_FBADCKSUM; ipsize = MIN(ipsize, 20); } if ((newip = ars_add_iphdr(pkt, 0)) == NULL) return -ARS_NOMEM; memcpy(newip, ip, ipsize); ars_set_flags(pkt, ARS_LAST_LAYER, flags); *len = ipsize; if (flags & ARS_SPLIT_FTRUNC) { *state = ARS_SPLIT_GET_DATA; return -ARS_OK; } if (ip->ihl > 5) { /* IP options */ /* IP protocol saved so after the IP option * processing we can start with the right status */ pkt->aux_ipproto = ip->protocol; *state = ARS_SPLIT_GET_IPOPT; pkt->aux = (ip->ihl - 5) << 2; return -ARS_OK; } ars_ip_next_state(ip->protocol, state); return -ARS_OK; }
int ars_split_igrpentry(struct ars_packet *pkt, void *packet, size_t size, int *state, int *len) { struct ars_igrpentry *entry = packet; int flags = 0, entrysize = sizeof(*entry); int error; if (size < sizeof(*entry)) { flags |= ARS_SPLIT_FTRUNC; entrysize = size; } error = ars_add_generic(pkt, sizeof(*entry), ARS_TYPE_IGRPENTRY); if (error != -ARS_OK) return error; memcpy(pkt->p_layer[pkt->p_layer_nr].l_data, entry, entrysize); pkt->p_layer_nr++; ars_set_flags(pkt, ARS_LAST_LAYER, flags); *len = entrysize; *state = ARS_SPLIT_GET_IGRPENTRY; return -ARS_OK; }
int ars_split_icmp(struct ars_packet *pkt, void *packet, size_t size, int *state, int *len) { struct ars_icmphdr *icmp = packet, *newicmp; int flags = 0; int icmpsize = ARS_ICMPHDR_SIZE; /* Check for bad header size and checksum */ if (size < icmpsize) { flags |= ARS_SPLIT_FTRUNC; icmpsize = size; } else if (ars_check_icmp_cksum(icmp, size) == 0) flags |= ARS_SPLIT_FBADCKSUM; if ((newicmp = ars_add_icmphdr(pkt, 0)) == NULL) return -ARS_NOMEM; memcpy(newicmp, icmp, icmpsize); ars_set_flags(pkt, ARS_LAST_LAYER, flags); *len = icmpsize; if (flags & ARS_SPLIT_FTRUNC) { *state = ARS_SPLIT_GET_DATA; return -ARS_OK; } switch(icmp->type) { case ARS_ICMP_ECHO: case ARS_ICMP_ECHOREPLY: case ARS_ICMP_TIMESTAMP: case ARS_ICMP_TIMESTAMPREPLY: case ARS_ICMP_INFO_REQUEST: case ARS_ICMP_INFO_REPLY: *state = ARS_SPLIT_GET_DATA; break; default: *state = ARS_SPLIT_GET_IP; break; } return -ARS_OK; }