print-esp.c

来自「TCPDUMP的C语言源代码,是在数据链路层的应用」· C语言 代码 · 共 512 行

C
512
字号
/*	$NetBSD: print-ah.c,v 1.4 1996/05/20 00:41:16 fvdl Exp $	*//* * Copyright (c) 1988, 1989, 1990, 1991, 1992, 1993, 1994 *	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-esp.c,v 1.56 2005-04-21 06:44:40 guy Exp $ (LBL)";#endif#ifdef HAVE_CONFIG_H#include "config.h"#endif#include <string.h>#include <tcpdump-stdinc.h>#include <stdlib.h>#ifdef HAVE_LIBCRYPTO#ifdef HAVE_OPENSSL_EVP_H#include <openssl/evp.h>#endif#endif#include <stdio.h>#include "ip.h"#include "esp.h"#ifdef INET6#include "ip6.h"#endif#include "netdissect.h"#include "addrtoname.h"#include "extract.h"#ifndef HAVE_SOCKADDR_STORAGE#ifdef INET6struct sockaddr_storage {	union {		struct sockaddr_in sin;		struct sockaddr_in6 sin6;	} un;};#else#define sockaddr_storage sockaddr#endif#endif /* HAVE_SOCKADDR_STORAGE */#ifdef HAVE_LIBCRYPTOstruct sa_list {	struct sa_list	*next;	struct sockaddr_storage daddr;	u_int32_t	spi;	const EVP_CIPHER *evp;	int		ivlen;	int		authlen;	u_char		secret[256];  /* is that big enough for all secrets? */	int		secretlen;};static void esp_print_addsa(netdissect_options *ndo,			    struct sa_list *sa, int sa_def){	/* copy the "sa" */	struct sa_list *nsa;	nsa = (struct sa_list *)malloc(sizeof(struct sa_list));	if (nsa == NULL)		(*ndo->ndo_error)(ndo, "ran out of memory to allocate sa structure");	*nsa = *sa;	if (sa_def)		ndo->ndo_sa_default = nsa;	nsa->next = ndo->ndo_sa_list_head;	ndo->ndo_sa_list_head = nsa;}static u_int hexdigit(netdissect_options *ndo, char hex){	if (hex >= '0' && hex <= '9')		return (hex - '0');	else if (hex >= 'A' && hex <= 'F')		return (hex - 'A' + 10);	else if (hex >= 'a' && hex <= 'f')		return (hex - 'a' + 10);	else {		(*ndo->ndo_error)(ndo, "invalid hex digit %c in espsecret\n", hex);		return 0;	}}static u_int hex2byte(netdissect_options *ndo, char *hexstring){	u_int byte;	byte = (hexdigit(ndo, hexstring[0]) << 4) + hexdigit(ndo, hexstring[1]);	return byte;}/* * decode the form:    SPINUM@IP <tab> ALGONAME:0xsecret * * special form: file /name * causes us to go read from this file instead. * */static void esp_print_decode_onesecret(netdissect_options *ndo, char *line){	struct sa_list sa1;	int sa_def;	char *spikey;	char *decode;	spikey = strsep(&line, " \t");	sa_def = 0;	memset(&sa1, 0, sizeof(struct sa_list));	/* if there is only one token, then it is an algo:key token */	if (line == NULL) {		decode = spikey;		spikey = NULL;		/* memset(&sa1.daddr, 0, sizeof(sa1.daddr)); */		/* sa1.spi = 0; */		sa_def    = 1;	} else		decode = line;	if (spikey && strcasecmp(spikey, "file") == 0) {		/* open file and read it */		FILE *secretfile;		char  fileline[1024];		char  *nl;		secretfile = fopen(line, FOPEN_READ_TXT);		if (secretfile == NULL) {			perror(line);			exit(3);		}		while (fgets(fileline, sizeof(fileline)-1, secretfile) != NULL) {			/* remove newline from the line */			nl = strchr(fileline, '\n');			if (nl)				*nl = '\0';			if (fileline[0] == '#') continue;			if (fileline[0] == '\0') continue;			esp_print_decode_onesecret(ndo, fileline);		}		fclose(secretfile);		return;	}	if (spikey) {		char *spistr, *foo;		u_int32_t spino;		struct sockaddr_in *sin;#ifdef INET6		struct sockaddr_in6 *sin6;#endif		spistr = strsep(&spikey, "@");		spino = strtoul(spistr, &foo, 0);		if (spistr == foo || !spikey) {			(*ndo->ndo_warning)(ndo, "print_esp: failed to decode spi# %s\n", foo);			return;		}		sa1.spi = spino;		sin = (struct sockaddr_in *)&sa1.daddr;#ifdef INET6		sin6 = (struct sockaddr_in6 *)&sa1.daddr;		if (inet_pton(AF_INET6, spikey, &sin6->sin6_addr) == 1) {#ifdef HAVE_SOCKADDR_SA_LEN			sin6->sin6_len = sizeof(struct sockaddr_in6);#endif			sin6->sin6_family = AF_INET6;		} else#endif		if (inet_pton(AF_INET, spikey, &sin->sin_addr) == 1) {#ifdef HAVE_SOCKADDR_SA_LEN			sin->sin_len = sizeof(struct sockaddr_in);#endif			sin->sin_family = AF_INET;		} else {			(*ndo->ndo_warning)(ndo, "print_esp: can not decode IP# %s\n", spikey);			return;		}	}	if (decode) {		char *colon, *p;		u_char espsecret_key[256];		int len;		size_t i;		const EVP_CIPHER *evp;		int authlen = 0;		/* skip any blank spaces */		while (isspace((unsigned char)*decode))			decode++;		colon = strchr(decode, ':');		if (colon == NULL) {			(*ndo->ndo_warning)(ndo, "failed to decode espsecret: %s\n", decode);			return;		}		*colon = '\0';		len = colon - decode;		if (strlen(decode) > strlen("-hmac96") &&		    !strcmp(decode + strlen(decode) - strlen("-hmac96"),		    "-hmac96")) {			p = strstr(decode, "-hmac96");			*p = '\0';			authlen = 12;		}		if (strlen(decode) > strlen("-cbc") &&		    !strcmp(decode + strlen(decode) - strlen("-cbc"), "-cbc")) {			p = strstr(decode, "-cbc");			*p = '\0';		}		evp = EVP_get_cipherbyname(decode);		if (!evp) {			(*ndo->ndo_warning)(ndo, "failed to find cipher algo %s\n", decode);			sa1.evp = NULL;			sa1.authlen = 0;			sa1.ivlen = 0;			return;		}		sa1.evp = evp;		sa1.authlen = authlen;		sa1.ivlen = EVP_CIPHER_iv_length(evp);		colon++;		if (colon[0] == '0' && colon[1] == 'x') {			/* decode some hex! */			colon += 2;			len = strlen(colon) / 2;			if (len > 256) {				(*ndo->ndo_warning)(ndo, "secret is too big: %d\n", len);				return;			}			i = 0;			while (colon[0] != '\0' && colon[1]!='\0') {				espsecret_key[i] = hex2byte(ndo, colon);				colon += 2;				i++;			}			memcpy(sa1.secret, espsecret_key, i);			sa1.secretlen = i;		} else {			i = strlen(colon);			if (i < sizeof(sa1.secret)) {				memcpy(sa1.secret, colon, i);				sa1.secretlen = i;			} else {				memcpy(sa1.secret, colon, sizeof(sa1.secret));				sa1.secretlen = sizeof(sa1.secret);			}		}	}	esp_print_addsa(ndo, &sa1, sa_def);}static void esp_print_decodesecret(netdissect_options *ndo){	char *line;	char *p;	p = ndo->ndo_espsecret;	while (ndo->ndo_espsecret && ndo->ndo_espsecret[0] != '\0') {		/* pick out the first line or first thing until a comma */		if ((line = strsep(&ndo->ndo_espsecret, "\n,")) == NULL) {			line = ndo->ndo_espsecret;			ndo->ndo_espsecret = NULL;		}		esp_print_decode_onesecret(ndo, line);	}}static void esp_init(netdissect_options *ndo _U_){	OpenSSL_add_all_algorithms();	EVP_add_cipher_alias(SN_des_ede3_cbc, "3des");}#endifintesp_print(netdissect_options *ndo,	  const u_char *bp, const int length, const u_char *bp2#ifndef HAVE_LIBCRYPTO	_U_#endif	,	int *nhdr#ifndef HAVE_LIBCRYPTO	_U_#endif	,	int *padlen#ifndef HAVE_LIBCRYPTO	_U_#endif	){	register const struct newesp *esp;	register const u_char *ep;#ifdef HAVE_LIBCRYPTO	struct ip *ip;	struct sa_list *sa = NULL;	int espsecret_keylen;#ifdef INET6	struct ip6_hdr *ip6 = NULL;#endif	int advance;	int len;	u_char *secret;	int ivlen = 0;	u_char *ivoff;	u_char *p;	EVP_CIPHER_CTX ctx;	int blocksz;	static int initialized = 0;#endif	esp = (struct newesp *)bp;#ifdef HAVE_LIBCRYPTO	secret = NULL;	advance = 0;	if (!initialized) {		esp_init(ndo);		initialized = 1;	}#endif#if 0	/* keep secret out of a register */	p = (u_char *)&secret;#endif	/* 'ep' points to the end of available data. */	ep = ndo->ndo_snapend;	if ((u_char *)(esp + 1) >= ep) {		fputs("[|ESP]", stdout);		goto fail;	}	(*ndo->ndo_printf)(ndo, "ESP(spi=0x%08x", EXTRACT_32BITS(&esp->esp_spi));	(*ndo->ndo_printf)(ndo, ",seq=0x%x)", EXTRACT_32BITS(&esp->esp_seq));        (*ndo->ndo_printf)(ndo, ", length %u", length);#ifndef HAVE_LIBCRYPTO	goto fail;#else	/* initiailize SAs */	if (ndo->ndo_sa_list_head == NULL) {		if (!ndo->ndo_espsecret)			goto fail;		esp_print_decodesecret(ndo);	}	if (ndo->ndo_sa_list_head == NULL)		goto fail;	ip = (struct ip *)bp2;	switch (IP_V(ip)) {#ifdef INET6	case 6:		ip6 = (struct ip6_hdr *)bp2;		/* we do not attempt to decrypt jumbograms */		if (!EXTRACT_16BITS(&ip6->ip6_plen))			goto fail;		/* if we can't get nexthdr, we do not need to decrypt it */		len = sizeof(struct ip6_hdr) + EXTRACT_16BITS(&ip6->ip6_plen);		/* see if we can find the SA, and if so, decode it */		for (sa = ndo->ndo_sa_list_head; sa != NULL; sa = sa->next) {			struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *)&sa->daddr;			if (sa->spi == ntohl(esp->esp_spi) &&			    sin6->sin6_family == AF_INET6 &&			    memcmp(&sin6->sin6_addr, &ip6->ip6_dst,				   sizeof(struct in6_addr)) == 0) {				break;			}		}		break;#endif /*INET6*/	case 4:		/* nexthdr & padding are in the last fragment */		if (EXTRACT_16BITS(&ip->ip_off) & IP_MF)			goto fail;		len = EXTRACT_16BITS(&ip->ip_len);		/* see if we can find the SA, and if so, decode it */		for (sa = ndo->ndo_sa_list_head; sa != NULL; sa = sa->next) {			struct sockaddr_in *sin = (struct sockaddr_in *)&sa->daddr;			if (sa->spi == ntohl(esp->esp_spi) &&			    sin->sin_family == AF_INET &&			    sin->sin_addr.s_addr == ip->ip_dst.s_addr) {				break;			}		}		break;	default:		goto fail;	}	/* if we didn't find the specific one, then look for	 * an unspecified one.	 */	if (sa == NULL)		sa = ndo->ndo_sa_default;		/* if not found fail */	if (sa == NULL)		goto fail;	/* if we can't get nexthdr, we do not need to decrypt it */	if (ep - bp2 < len)		goto fail;	if (ep - bp2 > len) {		/* FCS included at end of frame (NetBSD 1.6 or later) */		ep = bp2 + len;	}	ivoff = (u_char *)(esp + 1) + 0;	ivlen = sa->ivlen;	secret = sa->secret;	espsecret_keylen = sa->secretlen;	ep = ep - sa->authlen;	if (sa->evp) {		memset(&ctx, 0, sizeof(ctx));		if (EVP_CipherInit(&ctx, sa->evp, secret, NULL, 0) < 0)			(*ndo->ndo_warning)(ndo, "espkey init failed");		blocksz = EVP_CIPHER_CTX_block_size(&ctx);		p = ivoff;		EVP_CipherInit(&ctx, NULL, NULL, p, 0);		EVP_Cipher(&ctx, p + ivlen, p + ivlen, ep - (p + ivlen));		advance = ivoff - (u_char *)esp + ivlen;	} else		advance = sizeof(struct newesp);	/* sanity check for pad length */	if (ep - bp < *(ep - 2))		goto fail;	if (padlen)		*padlen = *(ep - 2) + 2;	if (nhdr)		*nhdr = *(ep - 1);	(ndo->ndo_printf)(ndo, ": ");	return advance;#endiffail:	return -1;}/* * Local Variables: * c-style: whitesmith * c-basic-offset: 8 * End: */

⌨️ 快捷键说明

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