xref: /freebsd/contrib/tcpdump/print-esp.c (revision a90e161be323456b08b7fe13acb201536809510f)
1b0453382SBill Fenner /*	$NetBSD: print-ah.c,v 1.4 1996/05/20 00:41:16 fvdl Exp $	*/
2b0453382SBill Fenner 
3b0453382SBill Fenner /*
4b0453382SBill Fenner  * Copyright (c) 1988, 1989, 1990, 1991, 1992, 1993, 1994
5b0453382SBill Fenner  *	The Regents of the University of California.  All rights reserved.
6b0453382SBill Fenner  *
7b0453382SBill Fenner  * Redistribution and use in source and binary forms, with or without
8b0453382SBill Fenner  * modification, are permitted provided that: (1) source code distributions
9b0453382SBill Fenner  * retain the above copyright notice and this paragraph in its entirety, (2)
10b0453382SBill Fenner  * distributions including binary code include the above copyright notice and
11b0453382SBill Fenner  * this paragraph in its entirety in the documentation or other materials
12b0453382SBill Fenner  * provided with the distribution, and (3) all advertising materials mentioning
13b0453382SBill Fenner  * features or use of this software display the following acknowledgement:
14b0453382SBill Fenner  * ``This product includes software developed by the University of California,
15b0453382SBill Fenner  * Lawrence Berkeley Laboratory and its contributors.'' Neither the name of
16b0453382SBill Fenner  * the University nor the names of its contributors may be used to endorse
17b0453382SBill Fenner  * or promote products derived from this software without specific prior
18b0453382SBill Fenner  * written permission.
19b0453382SBill Fenner  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED
20b0453382SBill Fenner  * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
21b0453382SBill Fenner  * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
22b0453382SBill Fenner  */
23b0453382SBill Fenner 
24b0453382SBill Fenner #ifndef lint
25b0453382SBill Fenner static const char rcsid[] =
26a90e161bSBill Fenner     "@(#) $Header: /tcpdump/master/tcpdump/print-esp.c,v 1.20 2002/01/21 11:39:59 mcr Exp $ (LBL)";
27b0453382SBill Fenner #endif
28b0453382SBill Fenner 
29b0453382SBill Fenner #ifdef HAVE_CONFIG_H
30b0453382SBill Fenner #include "config.h"
31b0453382SBill Fenner #endif
32b0453382SBill Fenner 
33b0453382SBill Fenner #include <string.h>
34b0453382SBill Fenner #include <sys/param.h>
35b0453382SBill Fenner #include <sys/time.h>
36b0453382SBill Fenner #include <sys/types.h>
37b0453382SBill Fenner #include <sys/socket.h>
38b0453382SBill Fenner 
39b0453382SBill Fenner #include <netinet/in.h>
40b0453382SBill Fenner 
41685295f4SBill Fenner #ifdef HAVE_LIBCRYPTO
42a90e161bSBill Fenner #include <openssl/des.h>
43a90e161bSBill Fenner #include <openssl/blowfish.h>
44b0453382SBill Fenner #ifdef HAVE_RC5_H
45a90e161bSBill Fenner #include <openssl/rc5.h>
46b0453382SBill Fenner #endif
47b0453382SBill Fenner #ifdef HAVE_CAST_H
48a90e161bSBill Fenner #include <openssl/cast.h>
49b0453382SBill Fenner #endif
50b0453382SBill Fenner #endif
51b0453382SBill Fenner 
52b0453382SBill Fenner #include <stdio.h>
53b0453382SBill Fenner 
54685295f4SBill Fenner #include "ip.h"
55685295f4SBill Fenner #include "esp.h"
56b0453382SBill Fenner #ifdef INET6
57685295f4SBill Fenner #include "ip6.h"
58b0453382SBill Fenner #endif
59b0453382SBill Fenner 
60a90e161bSBill Fenner #define AVOID_CHURN 1
61b0453382SBill Fenner #include "interface.h"
62b0453382SBill Fenner #include "addrtoname.h"
63b0453382SBill Fenner 
64a90e161bSBill Fenner static struct esp_algorithm *espsecret_xform=NULL;  /* cache of decoded alg. */
65a90e161bSBill Fenner static char                 *espsecret_key=NULL;
66a90e161bSBill Fenner 
67a90e161bSBill Fenner 
68a90e161bSBill Fenner enum cipher { NONE,
69a90e161bSBill Fenner 	      DESCBC,
70a90e161bSBill Fenner 	      BLOWFISH,
71a90e161bSBill Fenner 	      RC5,
72a90e161bSBill Fenner 	      CAST128,
73a90e161bSBill Fenner 	      DES3CBC};
74a90e161bSBill Fenner 
75a90e161bSBill Fenner 
76a90e161bSBill Fenner 
77a90e161bSBill Fenner struct esp_algorithm {
78a90e161bSBill Fenner 	char        *name;
79a90e161bSBill Fenner 	enum  cipher algo;
80a90e161bSBill Fenner 	int          ivlen;
81a90e161bSBill Fenner 	int          authlen;
82a90e161bSBill Fenner 	int          replaysize;
83a90e161bSBill Fenner };
84a90e161bSBill Fenner 
85a90e161bSBill Fenner struct esp_algorithm esp_xforms[]={
86a90e161bSBill Fenner 	{"none",                  NONE,    0,  0, 0},
87a90e161bSBill Fenner 	{"des-cbc",               DESCBC,  8,  0, 0},
88a90e161bSBill Fenner 	{"des-cbc-hmac96",        DESCBC,  8, 12, 4},
89a90e161bSBill Fenner 	{"blowfish-cbc",          BLOWFISH,8,  0, 0},
90a90e161bSBill Fenner 	{"blowfish-cbc-hmac96",   BLOWFISH,8, 12, 4},
91a90e161bSBill Fenner 	{"rc5-cbc",               RC5,     8,  0, 0},
92a90e161bSBill Fenner 	{"rc5-cbc-hmac96",        RC5,     8, 12, 4},
93a90e161bSBill Fenner 	{"cast128-cbc",           CAST128, 8,  0, 0},
94a90e161bSBill Fenner 	{"cast128-cbc-hmac96",    CAST128, 8, 12, 4},
95a90e161bSBill Fenner 	{"3des-cbc-hmac96",       DES3CBC, 8, 12, 4},
96a90e161bSBill Fenner };
97a90e161bSBill Fenner 
98a90e161bSBill Fenner static int hexdigit(char hex)
99a90e161bSBill Fenner {
100a90e161bSBill Fenner 	if(hex >= '0' && hex <= '9') {
101a90e161bSBill Fenner 		return (hex - '0');
102a90e161bSBill Fenner 	} else if(hex >= 'A' && hex <= 'F') {
103a90e161bSBill Fenner 		return (hex - 'A' + 10);
104a90e161bSBill Fenner 	} else if(hex >= 'a' && hex <= 'f') {
105a90e161bSBill Fenner 		return (hex - 'a' + 10);
106a90e161bSBill Fenner 	} else {
107a90e161bSBill Fenner 		printf("invalid hex digit %c in espsecret\n", hex);
108a90e161bSBill Fenner 		return 0;
109a90e161bSBill Fenner 	}
110a90e161bSBill Fenner }
111a90e161bSBill Fenner 
112a90e161bSBill Fenner static int hex2byte(char *hexstring)
113a90e161bSBill Fenner {
114a90e161bSBill Fenner 	int byte;
115a90e161bSBill Fenner 
116a90e161bSBill Fenner 	byte = (hexdigit(hexstring[0]) << 4) +
117a90e161bSBill Fenner 		hexdigit(hexstring[1]);
118a90e161bSBill Fenner 	return byte;
119a90e161bSBill Fenner }
120a90e161bSBill Fenner 
121a90e161bSBill Fenner 
122a90e161bSBill Fenner void esp_print_decodesecret()
123a90e161bSBill Fenner {
124a90e161bSBill Fenner 	char *colon;
125a90e161bSBill Fenner 	int   len, i;
126a90e161bSBill Fenner 	struct esp_algorithm *xf;
127a90e161bSBill Fenner 
128a90e161bSBill Fenner 	if(espsecret == NULL) {
129a90e161bSBill Fenner 		/* set to NONE transform */
130a90e161bSBill Fenner 		espsecret_xform = esp_xforms;
131a90e161bSBill Fenner 		return;
132a90e161bSBill Fenner 	}
133a90e161bSBill Fenner 
134a90e161bSBill Fenner 	if(espsecret_key != NULL) {
135a90e161bSBill Fenner 		return;
136a90e161bSBill Fenner 	}
137a90e161bSBill Fenner 
138a90e161bSBill Fenner 	colon = strchr(espsecret, ':');
139a90e161bSBill Fenner 	if(colon == NULL) {
140a90e161bSBill Fenner 		printf("failed to decode espsecret: %s\n",
141a90e161bSBill Fenner 		       espsecret);
142a90e161bSBill Fenner 		/* set to NONE transform */
143a90e161bSBill Fenner 		espsecret_xform = esp_xforms;
144a90e161bSBill Fenner 	}
145a90e161bSBill Fenner 
146a90e161bSBill Fenner 	len   = colon - espsecret;
147a90e161bSBill Fenner 	xf = esp_xforms;
148a90e161bSBill Fenner 	while(xf->name && strncasecmp(espsecret, xf->name, len)!=0) {
149a90e161bSBill Fenner 		xf++;
150a90e161bSBill Fenner 	}
151a90e161bSBill Fenner 	if(xf->name == NULL) {
152a90e161bSBill Fenner 		printf("failed to find cipher algo %s\n",
153a90e161bSBill Fenner 		       espsecret);
154a90e161bSBill Fenner 		espsecret_xform = esp_xforms;
155a90e161bSBill Fenner 		return;
156a90e161bSBill Fenner 	}
157a90e161bSBill Fenner 	espsecret_xform = xf;
158a90e161bSBill Fenner 
159a90e161bSBill Fenner 	colon++;
160a90e161bSBill Fenner 	if(colon[0]=='0' && colon[1]=='x') {
161a90e161bSBill Fenner 		/* decode some hex! */
162a90e161bSBill Fenner 		colon+=2;
163a90e161bSBill Fenner 		len = strlen(colon) / 2;
164a90e161bSBill Fenner 		espsecret_key = (char *)malloc(len);
165a90e161bSBill Fenner 		if(espsecret_key == NULL) {
166a90e161bSBill Fenner 		  fprintf(stderr, "%s: ran out of memory (%d) to allocate secret key\n",
167a90e161bSBill Fenner 			  program_name, len);
168a90e161bSBill Fenner 		  exit(2);
169a90e161bSBill Fenner 		}
170a90e161bSBill Fenner 		i = 0;
171a90e161bSBill Fenner 		while(colon[0] != '\0' && colon[1]!='\0') {
172a90e161bSBill Fenner 			espsecret_key[i]=hex2byte(colon);
173a90e161bSBill Fenner 			colon+=2;
174a90e161bSBill Fenner 			i++;
175a90e161bSBill Fenner 		}
176a90e161bSBill Fenner 	} else {
177a90e161bSBill Fenner 		espsecret_key = colon;
178a90e161bSBill Fenner 	}
179a90e161bSBill Fenner }
180a90e161bSBill Fenner 
181b0453382SBill Fenner int
182a90e161bSBill Fenner esp_print(register const u_char *bp, register const u_char *bp2,
183a90e161bSBill Fenner 	  int *nhdr, int *padlen)
184b0453382SBill Fenner {
185b0453382SBill Fenner 	register const struct esp *esp;
186b0453382SBill Fenner 	register const u_char *ep;
187b0453382SBill Fenner 	u_int32_t spi;
188b0453382SBill Fenner 	struct ip *ip = NULL;
189b0453382SBill Fenner #ifdef INET6
190b0453382SBill Fenner 	struct ip6_hdr *ip6 = NULL;
191b0453382SBill Fenner #endif
192b0453382SBill Fenner 	int advance;
193b0453382SBill Fenner 	int len;
194a90e161bSBill Fenner 	char *secret;
195b0453382SBill Fenner 	int ivlen = 0;
196b0453382SBill Fenner 	u_char *ivoff;
197a90e161bSBill Fenner 	u_char *p;
198b0453382SBill Fenner 
199b0453382SBill Fenner 	esp = (struct esp *)bp;
200b0453382SBill Fenner 	spi = (u_int32_t)ntohl(esp->esp_spi);
201a90e161bSBill Fenner 	secret = NULL;
202a90e161bSBill Fenner 
203a90e161bSBill Fenner #if 0
204a90e161bSBill Fenner 	/* keep secret out of a register */
205a90e161bSBill Fenner 	p = (u_char *)&secret;
206a90e161bSBill Fenner #endif
207b0453382SBill Fenner 
208685295f4SBill Fenner 	/* 'ep' points to the end of available data. */
209b0453382SBill Fenner 	ep = snapend;
210b0453382SBill Fenner 
211b0453382SBill Fenner 	if ((u_char *)(esp + 1) >= ep - sizeof(struct esp)) {
212b0453382SBill Fenner 		fputs("[|ESP]", stdout);
213b0453382SBill Fenner 		goto fail;
214b0453382SBill Fenner 	}
215685295f4SBill Fenner 	printf("ESP(spi=0x%08x", spi);
216b0453382SBill Fenner 	printf(",seq=0x%x", (u_int32_t)ntohl(*(u_int32_t *)(esp + 1)));
217b0453382SBill Fenner 	printf(")");
218b0453382SBill Fenner 
219b0453382SBill Fenner 	/* if we don't have decryption key, we can't decrypt this packet. */
220b0453382SBill Fenner 	if (!espsecret)
221b0453382SBill Fenner 		goto fail;
222b0453382SBill Fenner 
223a90e161bSBill Fenner 	if(!espsecret_xform) {
224a90e161bSBill Fenner 		esp_print_decodesecret();
225a90e161bSBill Fenner 	}
226a90e161bSBill Fenner 	if(espsecret_xform->algo == NONE) {
227a90e161bSBill Fenner 		goto fail;
228b0453382SBill Fenner 	}
229b0453382SBill Fenner 
230b0453382SBill Fenner 	ip = (struct ip *)bp2;
231685295f4SBill Fenner 	switch (IP_V(ip)) {
232b0453382SBill Fenner #ifdef INET6
233b0453382SBill Fenner 	case 6:
234b0453382SBill Fenner 		ip6 = (struct ip6_hdr *)bp2;
235b0453382SBill Fenner 		ip = NULL;
236b0453382SBill Fenner 		/* we do not attempt to decrypt jumbograms */
237b0453382SBill Fenner 		if (!ntohs(ip6->ip6_plen))
238b0453382SBill Fenner 			goto fail;
239b0453382SBill Fenner 		/* if we can't get nexthdr, we do not need to decrypt it */
240b0453382SBill Fenner 		len = sizeof(struct ip6_hdr) + ntohs(ip6->ip6_plen);
241b0453382SBill Fenner 		break;
242b0453382SBill Fenner #endif /*INET6*/
243b0453382SBill Fenner 	case 4:
244a90e161bSBill Fenner 		/* nexthdr & padding are in the last fragment */
245a90e161bSBill Fenner 		if (ntohs(ip->ip_off) & IP_MF)
246a90e161bSBill Fenner 			goto fail;
247b0453382SBill Fenner #ifdef INET6
248b0453382SBill Fenner 		ip6 = NULL;
249b0453382SBill Fenner #endif
250b0453382SBill Fenner 		len = ntohs(ip->ip_len);
251b0453382SBill Fenner 		break;
252b0453382SBill Fenner 	default:
253b0453382SBill Fenner 		goto fail;
254b0453382SBill Fenner 	}
255b0453382SBill Fenner 
256b0453382SBill Fenner 	/* if we can't get nexthdr, we do not need to decrypt it */
257b0453382SBill Fenner 	if (ep - bp2 < len)
258b0453382SBill Fenner 		goto fail;
259b0453382SBill Fenner 
260a90e161bSBill Fenner 	ivoff = (u_char *)(esp + 1) + espsecret_xform->replaysize;
261a90e161bSBill Fenner 	ivlen = espsecret_xform->ivlen;
262a90e161bSBill Fenner 	secret = espsecret_key;
263b0453382SBill Fenner 
264a90e161bSBill Fenner 	switch (espsecret_xform->algo) {
265b0453382SBill Fenner 	case DESCBC:
266685295f4SBill Fenner #ifdef HAVE_LIBCRYPTO
267b0453382SBill Fenner 	    {
268b0453382SBill Fenner 		u_char iv[8];
269b0453382SBill Fenner 		des_key_schedule schedule;
270b0453382SBill Fenner 
271b0453382SBill Fenner 		switch (ivlen) {
272b0453382SBill Fenner 		case 4:
273b0453382SBill Fenner 			memcpy(iv, ivoff, 4);
274b0453382SBill Fenner 			memcpy(&iv[4], ivoff, 4);
275b0453382SBill Fenner 			p = &iv[4];
276b0453382SBill Fenner 			*p++ ^= 0xff;
277b0453382SBill Fenner 			*p++ ^= 0xff;
278b0453382SBill Fenner 			*p++ ^= 0xff;
279b0453382SBill Fenner 			*p++ ^= 0xff;
280b0453382SBill Fenner 			break;
281b0453382SBill Fenner 		case 8:
282b0453382SBill Fenner 			memcpy(iv, ivoff, 8);
283b0453382SBill Fenner 			break;
284b0453382SBill Fenner 		default:
285b0453382SBill Fenner 			goto fail;
286b0453382SBill Fenner 		}
287b0453382SBill Fenner 
288b0453382SBill Fenner 		des_check_key = 0;
289b0453382SBill Fenner 		des_set_key((void *)secret, schedule);
290b0453382SBill Fenner 
291b0453382SBill Fenner 		p = ivoff + ivlen;
292b0453382SBill Fenner 		des_cbc_encrypt((void *)p, (void *)p,
293b0453382SBill Fenner 			(long)(ep - p), schedule, (void *)iv,
294b0453382SBill Fenner 			DES_DECRYPT);
295b0453382SBill Fenner 		advance = ivoff - (u_char *)esp + ivlen;
296b0453382SBill Fenner 		break;
297b0453382SBill Fenner 	    }
298b0453382SBill Fenner #else
299b0453382SBill Fenner 		goto fail;
300685295f4SBill Fenner #endif /*HAVE_LIBCRYPTO*/
301b0453382SBill Fenner 
302b0453382SBill Fenner 	case BLOWFISH:
303685295f4SBill Fenner #ifdef HAVE_LIBCRYPTO
304b0453382SBill Fenner 	    {
305b0453382SBill Fenner 		BF_KEY schedule;
306b0453382SBill Fenner 
307b0453382SBill Fenner 		BF_set_key(&schedule, strlen(secret), secret);
308b0453382SBill Fenner 
309b0453382SBill Fenner 		p = ivoff + ivlen;
310b0453382SBill Fenner 		BF_cbc_encrypt(p, p, (long)(ep - p), &schedule, ivoff,
311b0453382SBill Fenner 			BF_DECRYPT);
312b0453382SBill Fenner 		advance = ivoff - (u_char *)esp + ivlen;
313b0453382SBill Fenner 		break;
314b0453382SBill Fenner 	    }
315b0453382SBill Fenner #else
316b0453382SBill Fenner 		goto fail;
317685295f4SBill Fenner #endif /*HAVE_LIBCRYPTO*/
318b0453382SBill Fenner 
319b0453382SBill Fenner 	case RC5:
320685295f4SBill Fenner #if defined(HAVE_LIBCRYPTO) && defined(HAVE_RC5_H)
321b0453382SBill Fenner 	    {
322b0453382SBill Fenner 		RC5_32_KEY schedule;
323b0453382SBill Fenner 
324b0453382SBill Fenner 		RC5_32_set_key(&schedule, strlen(secret), secret,
325b0453382SBill Fenner 			RC5_16_ROUNDS);
326b0453382SBill Fenner 
327b0453382SBill Fenner 		p = ivoff + ivlen;
328b0453382SBill Fenner 		RC5_32_cbc_encrypt(p, p, (long)(ep - p), &schedule, ivoff,
329b0453382SBill Fenner 			RC5_DECRYPT);
330b0453382SBill Fenner 		advance = ivoff - (u_char *)esp + ivlen;
331b0453382SBill Fenner 		break;
332b0453382SBill Fenner 	    }
333b0453382SBill Fenner #else
334b0453382SBill Fenner 		goto fail;
335685295f4SBill Fenner #endif /*HAVE_LIBCRYPTO*/
336b0453382SBill Fenner 
337b0453382SBill Fenner 	case CAST128:
338685295f4SBill Fenner #if defined(HAVE_LIBCRYPTO) && defined(HAVE_CAST_H) && !defined(HAVE_BUGGY_CAST128)
339b0453382SBill Fenner 	    {
340b0453382SBill Fenner 		CAST_KEY schedule;
341b0453382SBill Fenner 
342b0453382SBill Fenner 		CAST_set_key(&schedule, strlen(secret), secret);
343b0453382SBill Fenner 
344b0453382SBill Fenner 		p = ivoff + ivlen;
345b0453382SBill Fenner 		CAST_cbc_encrypt(p, p, (long)(ep - p), &schedule, ivoff,
346b0453382SBill Fenner 			CAST_DECRYPT);
347b0453382SBill Fenner 		advance = ivoff - (u_char *)esp + ivlen;
348b0453382SBill Fenner 		break;
349b0453382SBill Fenner 	    }
350b0453382SBill Fenner #else
351b0453382SBill Fenner 		goto fail;
352685295f4SBill Fenner #endif /*HAVE_LIBCRYPTO*/
353b0453382SBill Fenner 
354b0453382SBill Fenner 	case DES3CBC:
355685295f4SBill Fenner #if defined(HAVE_LIBCRYPTO)
356b0453382SBill Fenner 	    {
357b0453382SBill Fenner 		des_key_schedule s1, s2, s3;
358b0453382SBill Fenner 
359a90e161bSBill Fenner 		des_check_key = 1;
360a90e161bSBill Fenner 		des_set_odd_parity((void *)secret);
361a90e161bSBill Fenner 		des_set_odd_parity((void *)secret+8);
362a90e161bSBill Fenner 		des_set_odd_parity((void *)secret+16);
363a90e161bSBill Fenner 		if(des_set_key((void *)secret, s1) != 0) {
364a90e161bSBill Fenner 		  printf("failed to schedule key 1\n");
365a90e161bSBill Fenner 		}
366a90e161bSBill Fenner 		if(des_set_key((void *)(secret + 8), s2)!=0) {
367a90e161bSBill Fenner 		  printf("failed to schedule key 2\n");
368a90e161bSBill Fenner 		}
369a90e161bSBill Fenner 		if(des_set_key((void *)(secret + 16), s3)!=0) {
370a90e161bSBill Fenner 		  printf("failed to schedule key 3\n");
371a90e161bSBill Fenner 		}
372b0453382SBill Fenner 
373b0453382SBill Fenner 		p = ivoff + ivlen;
374b0453382SBill Fenner 		des_ede3_cbc_encrypt((void *)p, (void *)p,
375a90e161bSBill Fenner 				     (long)(ep - p),
376a90e161bSBill Fenner 				     s1, s2, s3,
377a90e161bSBill Fenner 				     (void *)ivoff, DES_DECRYPT);
378b0453382SBill Fenner 		advance = ivoff - (u_char *)esp + ivlen;
379b0453382SBill Fenner 		break;
380b0453382SBill Fenner 	    }
381b0453382SBill Fenner #else
382b0453382SBill Fenner 		goto fail;
383685295f4SBill Fenner #endif /*HAVE_LIBCRYPTO*/
384b0453382SBill Fenner 
385b0453382SBill Fenner 	case NONE:
386b0453382SBill Fenner 	default:
387a90e161bSBill Fenner 		advance = sizeof(struct esp) + espsecret_xform->replaysize;
388b0453382SBill Fenner 		break;
389b0453382SBill Fenner 	}
390b0453382SBill Fenner 
391a90e161bSBill Fenner 	ep = ep - espsecret_xform->authlen;
392b0453382SBill Fenner 	/* sanity check for pad length */
393b0453382SBill Fenner 	if (ep - bp < *(ep - 2))
394b0453382SBill Fenner 		goto fail;
395b0453382SBill Fenner 
396a90e161bSBill Fenner 	if (padlen)
397a90e161bSBill Fenner 		*padlen = *(ep - 2) + 2;
398a90e161bSBill Fenner 
399b0453382SBill Fenner 	if (nhdr)
400b0453382SBill Fenner 		*nhdr = *(ep - 1);
401b0453382SBill Fenner 
402b0453382SBill Fenner 	printf(": ");
403b0453382SBill Fenner 	return advance;
404b0453382SBill Fenner 
405b0453382SBill Fenner fail:
406b0453382SBill Fenner 	if (nhdr)
407b0453382SBill Fenner 		*nhdr = -1;
408b0453382SBill Fenner 	return 65536;
409b0453382SBill Fenner }
410