File:  [ELWIX - Embedded LightWeight unIX -] / embedaddon / hping2 / split.c
Revision 1.1.1.1 (vendor branch): download - view: text, annotated - select for diffs - revision graph
Tue Feb 21 22:11:37 2012 UTC (12 years, 3 months ago) by misho
Branches: hping2, MAIN
CVS tags: v2_0_0rc3p7, v2_0_0rc3p5, v2_0_0rc3p4, v2_0_0rc3p0, v2_0_0rc3, HEAD
hping2

    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>