print-ip.c

来自「TCPDUMP的C语言源代码,是在数据链路层的应用」· C语言 代码 · 共 741 行 · 第 1/2 页

C
741
字号
/* * Copyright (c) 1988, 1989, 1990, 1991, 1992, 1993, 1994, 1995, 1996, 1997 *	The Regents of the University of California.  All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that: (1) source code distributions * retain the above copyright notice and this paragraph in its entirety, (2) * distributions including binary code include the above copyright notice and * this paragraph in its entirety in the documentation or other materials * provided with the distribution, and (3) all advertising materials mentioning * features or use of this software display the following acknowledgement: * ``This product includes software developed by the University of California, * Lawrence Berkeley Laboratory and its contributors.'' Neither the name of * the University nor the names of its contributors may be used to endorse * or promote products derived from this software without specific prior * written permission. * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. */#ifndef lintstatic const char rcsid[] _U_ =    "@(#) $Header: /tcpdump/master/tcpdump/print-ip.c,v 1.159 2007-09-14 01:29:28 guy Exp $ (LBL)";#endif#ifdef HAVE_CONFIG_H#include "config.h"#endif#include <tcpdump-stdinc.h>#include <stdio.h>#include <stdlib.h>#include <string.h>#include "addrtoname.h"#include "interface.h"#include "extract.h"			/* must come after interface.h */#include "ip.h"#include "ipproto.h"struct tok ip_option_values[] = {    { IPOPT_EOL, "EOL" },    { IPOPT_NOP, "NOP" },    { IPOPT_TS, "timestamp" },    { IPOPT_SECURITY, "security" },    { IPOPT_RR, "RR" },    { IPOPT_SSRR, "SSRR" },    { IPOPT_LSRR, "LSRR" },    { IPOPT_RA, "RA" },    { IPOPT_RFC1393, "traceroute" },    { 0, NULL }};/* * print the recorded route in an IP RR, LSRR or SSRR option. */static voidip_printroute(register const u_char *cp, u_int length){	register u_int ptr;	register u_int len;	if (length < 3) {		printf(" [bad length %u]", length);		return;	}	if ((length + 1) & 3)		printf(" [bad length %u]", length);	ptr = cp[2] - 1;	if (ptr < 3 || ((ptr + 1) & 3) || ptr > length + 1)		printf(" [bad ptr %u]", cp[2]);	for (len = 3; len < length; len += 4) {		printf(" %s", ipaddr_string(&cp[len]));                if (ptr > len)                        printf(",");	}}/* * If source-routing is present and valid, return the final destination. * Otherwise, return IP destination. * * This is used for UDP and TCP pseudo-header in the checksum * calculation. */u_int32_tip_finddst(const struct ip *ip){	int length;	int len;	const u_char *cp;	u_int32_t retval;	cp = (const u_char *)(ip + 1);	length = (IP_HL(ip) << 2) - sizeof(struct ip);	for (; length > 0; cp += len, length -= len) {		int tt;		TCHECK(*cp);		tt = *cp;		if (tt == IPOPT_EOL)			break;		else if (tt == IPOPT_NOP)			len = 1;		else {			TCHECK(cp[1]);			len = cp[1];			if (len < 2)				break;		}		TCHECK2(*cp, len);		switch (tt) {		case IPOPT_SSRR:		case IPOPT_LSRR:			if (len < 7)				break;			memcpy(&retval, cp + len - 4, 4);			return retval;		}	}trunc:	memcpy(&retval, &ip->ip_dst.s_addr, sizeof(u_int32_t));	return retval;}static voidip_printts(register const u_char *cp, u_int length){	register u_int ptr;	register u_int len;	int hoplen;	const char *type;	if (length < 4) {		printf("[bad length %u]", length);		return;	}	printf(" TS{");	hoplen = ((cp[3]&0xF) != IPOPT_TS_TSONLY) ? 8 : 4;	if ((length - 4) & (hoplen-1))		printf("[bad length %u]", length);	ptr = cp[2] - 1;	len = 0;	if (ptr < 4 || ((ptr - 4) & (hoplen-1)) || ptr > length + 1)		printf("[bad ptr %u]", cp[2]);	switch (cp[3]&0xF) {	case IPOPT_TS_TSONLY:		printf("TSONLY");		break;	case IPOPT_TS_TSANDADDR:		printf("TS+ADDR");		break;	/*	 * prespecified should really be 3, but some ones might send 2	 * instead, and the IPOPT_TS_PRESPEC constant can apparently	 * have both values, so we have to hard-code it here.	 */	case 2:		printf("PRESPEC2.0");		break;	case 3:			/* IPOPT_TS_PRESPEC */		printf("PRESPEC");		break;	default:		printf("[bad ts type %d]", cp[3]&0xF);		goto done;	}	type = " ";	for (len = 4; len < length; len += hoplen) {		if (ptr == len)			type = " ^ ";		printf("%s%d@%s", type, EXTRACT_32BITS(&cp[len+hoplen-4]),		       hoplen!=8 ? "" : ipaddr_string(&cp[len]));		type = " ";	}done:	printf("%s", ptr == len ? " ^ " : "");	if (cp[3]>>4)		printf(" [%d hops not recorded]} ", cp[3]>>4);	else		printf("}");}/* * print IP options. */static voidip_optprint(register const u_char *cp, u_int length){	register u_int option_len;	const char *sep = "";	for (; length > 0; cp += option_len, length -= option_len) {		u_int option_code;		printf("%s", sep);		sep = ",";		TCHECK(*cp);		option_code = *cp;                printf("%s",                        tok2str(ip_option_values,"unknown %u",option_code));		if (option_code == IPOPT_NOP ||                    option_code == IPOPT_EOL)			option_len = 1;		else {			TCHECK(cp[1]);			option_len = cp[1];			if (option_len < 2) {		                printf(" [bad length %u]", option_len);				return;			}		}		if (option_len > length) {	                printf(" [bad length %u]", option_len);			return;		}                TCHECK2(*cp, option_len);		switch (option_code) {		case IPOPT_EOL:			return;		case IPOPT_TS:			ip_printts(cp, option_len);			break;		case IPOPT_RR:       /* fall through */		case IPOPT_SSRR:		case IPOPT_LSRR:			ip_printroute(cp, option_len);			break;		case IPOPT_RA:			if (option_len < 4) {				printf(" [bad length %u]", option_len);				break;			}                        TCHECK(cp[3]);                        if (EXTRACT_16BITS(&cp[2]) != 0)                            printf(" value %u", EXTRACT_16BITS(&cp[2]));			break;		case IPOPT_NOP:       /* nothing to print - fall through */		case IPOPT_SECURITY:		default:			break;		}	}	return;trunc:	printf("[|ip]");}/* * compute an IP header checksum. * don't modifiy the packet. */u_shortin_cksum(const u_short *addr, register u_int len, int csum){	int nleft = len;	const u_short *w = addr;	u_short answer;	int sum = csum;	/*	 *  Our algorithm is simple, using a 32 bit accumulator (sum),	 *  we add sequential 16 bit words to it, and at the end, fold	 *  back all the carry bits from the top 16 bits into the lower	 *  16 bits.	 */	while (nleft > 1)  {		sum += *w++;		nleft -= 2;	}	if (nleft == 1)		sum += htons(*(u_char *)w<<8);	/*	 * add back carry outs from top 16 bits to low 16 bits	 */	sum = (sum >> 16) + (sum & 0xffff);	/* add hi 16 to low 16 */	sum += (sum >> 16);			/* add carry */	answer = ~sum;				/* truncate to 16 bits */	return (answer);}/* * Given the host-byte-order value of the checksum field in a packet * header, and the network-byte-order computed checksum of the data * that the checksum covers (including the checksum itself), compute * what the checksum field *should* have been. */u_int16_tin_cksum_shouldbe(u_int16_t sum, u_int16_t computed_sum){	u_int32_t shouldbe;	/*	 * The value that should have gone into the checksum field	 * is the negative of the value gotten by summing up everything	 * *but* the checksum field.	 *	 * We can compute that by subtracting the value of the checksum	 * field from the sum of all the data in the packet, and then	 * computing the negative of that value.	 *	 * "sum" is the value of the checksum field, and "computed_sum"	 * is the negative of the sum of all the data in the packets,	 * so that's -(-computed_sum - sum), or (sum + computed_sum).	 *	 * All the arithmetic in question is one's complement, so the	 * addition must include an end-around carry; we do this by	 * doing the arithmetic in 32 bits (with no sign-extension),	 * and then adding the upper 16 bits of the sum, which contain	 * the carry, to the lower 16 bits of the sum, and then do it	 * again in case *that* sum produced a carry.	 *	 * As RFC 1071 notes, the checksum can be computed without	 * byte-swapping the 16-bit words; summing 16-bit words	 * on a big-endian machine gives a big-endian checksum, which	 * can be directly stuffed into the big-endian checksum fields	 * in protocol headers, and summing words on a little-endian	 * machine gives a little-endian checksum, which must be	 * byte-swapped before being stuffed into a big-endian checksum	 * field.	 *	 * "computed_sum" is a network-byte-order value, so we must put	 * it in host byte order before subtracting it from the	 * host-byte-order value from the header; the adjusted checksum	 * will be in host byte order, which is what we'll return.	 */	shouldbe = sum;	shouldbe += ntohs(computed_sum);	shouldbe = (shouldbe & 0xFFFF) + (shouldbe >> 16);	shouldbe = (shouldbe & 0xFFFF) + (shouldbe >> 16);	return shouldbe;}#define IP_RES 0x8000static struct tok ip_frag_values[] = {        { IP_MF,        "+" },        { IP_DF,        "DF" },	{ IP_RES,       "rsvd" }, /* The RFC3514 evil ;-) bit */        { 0,            NULL }};struct ip_print_demux_state {	const struct ip *ip;	const u_char *cp;	u_int   len, off;	u_char  nh;	int     advance;

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?