1 /* $OpenBSD: log.c,v 1.65 2024/04/28 16:43:42 florian Exp $ */
2 /* $EOM: log.c,v 1.30 2000/09/29 08:19:23 niklas Exp $ */
3
4 /*
5 * Copyright (c) 1998, 1999, 2001 Niklas Hallqvist. All rights reserved.
6 * Copyright (c) 1999, 2000, 2001, 2003 H�kan Olsson. All rights reserved.
7 *
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions
10 * are met:
11 * 1. Redistributions of source code must retain the above copyright
12 * notice, this list of conditions and the following disclaimer.
13 * 2. Redistributions in binary form must reproduce the above copyright
14 * notice, this list of conditions and the following disclaimer in the
15 * documentation and/or other materials provided with the distribution.
16 *
17 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
18 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
19 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
20 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
21 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
22 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
26 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27 */
28
29 /*
30 * This code was written under funding by Ericsson Radio Systems.
31 */
32
33 #include <sys/types.h>
34 #include <sys/time.h>
35
36 #include <sys/socket.h>
37 #include <sys/stat.h>
38 #include <sys/uio.h>
39 #include <netinet/in.h>
40 #include <netinet/ip.h>
41 #include <netinet/ip6.h>
42 #include <netinet/udp.h>
43 #include <arpa/inet.h>
44
45 #include <pcap.h>
46
47 #include <errno.h>
48 #include <stdio.h>
49 #include <stdlib.h>
50 #include <string.h>
51 #include <syslog.h>
52 #include <stdarg.h>
53 #include <unistd.h>
54
55 #include "conf.h"
56 #include "isakmp_num.h"
57 #include "log.h"
58 #include "monitor.h"
59 #include "util.h"
60
61 static void _log_print(int, int, const char *, va_list, int, int);
62
63 static FILE *log_output;
64
65 int verbose_logging = 0;
66 static int log_level[LOG_ENDCLASS];
67
68 #define TCPDUMP_MAGIC 0xa1b2c3d4
69 #define SNAPLEN (64 * 1024)
70
71 struct packhdr {
72 struct pcap_pkthdr pcap;/* pcap file packet header */
73 u_int32_t sa_family; /* address family */
74 union {
75 struct ip ip4; /* IPv4 header (w/o options) */
76 struct ip6_hdr ip6; /* IPv6 header */
77 } ip;
78 };
79
80 struct isakmp_hdr {
81 u_int8_t icookie[8], rcookie[8];
82 u_int8_t next, ver, type, flags;
83 u_int32_t msgid, len;
84 };
85
86 static char *pcaplog_file = NULL;
87 static FILE *packet_log;
88 static u_int8_t *packet_buf = NULL;
89
90 static int udp_cksum(struct packhdr *, const struct udphdr *,
91 u_int16_t *);
92 static u_int16_t in_cksum(const u_int16_t *, int);
93
94 void
log_init(int debug)95 log_init(int debug)
96 {
97 if (debug)
98 log_output = stderr;
99 else
100 log_to(0); /* syslog */
101 }
102
103 void
log_reinit(void)104 log_reinit(void)
105 {
106 struct conf_list *logging;
107 struct conf_list_node *logclass;
108 int class, level;
109
110 logging = conf_get_list("General", "Logverbose");
111 if (logging) {
112 verbose_logging = 1;
113 conf_free_list(logging);
114 }
115 logging = conf_get_list("General", "Loglevel");
116 if (!logging)
117 return;
118
119 for (logclass = TAILQ_FIRST(&logging->fields); logclass;
120 logclass = TAILQ_NEXT(logclass, link)) {
121 if (sscanf(logclass->field, "%d=%d", &class, &level) != 2) {
122 if (sscanf(logclass->field, "A=%d", &level) == 1)
123 for (class = 0; class < LOG_ENDCLASS; class++)
124 log_debug_cmd(class, level);
125 else {
126 log_print("init: invalid logging class or "
127 "level: %s", logclass->field);
128 continue;
129 }
130 } else
131 log_debug_cmd(class, level);
132 }
133 conf_free_list(logging);
134 }
135
136 void
log_to(FILE * f)137 log_to(FILE *f)
138 {
139 if (!log_output && f)
140 closelog();
141 log_output = f;
142 if (!f)
143 openlog("isakmpd", LOG_PID | LOG_CONS, LOG_DAEMON);
144 }
145
146 FILE *
log_current(void)147 log_current(void)
148 {
149 return log_output;
150 }
151
152 static char *
_log_get_class(int error_class)153 _log_get_class(int error_class)
154 {
155 /* XXX For test purposes. To be removed later on? */
156 static char *class_text[] = LOG_CLASSES_TEXT;
157
158 if (error_class < 0)
159 return "Dflt";
160 else if (error_class >= LOG_ENDCLASS)
161 return "Unkn";
162 else
163 return class_text[error_class];
164 }
165
166 static void
_log_print(int error,int syslog_level,const char * fmt,va_list ap,int class,int level)167 _log_print(int error, int syslog_level, const char *fmt, va_list ap,
168 int class, int level)
169 {
170 char buffer[LOG_SIZE], nbuf[LOG_SIZE + 32];
171 static const char fallback_msg[] =
172 "write to log file failed (errno %d), redirecting to syslog";
173 int len;
174 struct tm *tm;
175 struct timeval now;
176 time_t t;
177
178 len = vsnprintf(buffer, sizeof buffer, fmt, ap);
179 if (len > 0 && len < (int) sizeof buffer - 1 && error)
180 snprintf(buffer + len, sizeof buffer - len, ": %s",
181 strerror(errno));
182 if (log_output) {
183 gettimeofday(&now, 0);
184 t = now.tv_sec;
185 if ((tm = localtime(&t)) == NULL) {
186 /* Invalid time, use the epoch. */
187 t = 0;
188 tm = localtime(&t);
189 }
190 if (class >= 0)
191 snprintf(nbuf, sizeof nbuf,
192 "%02d%02d%02d.%06ld %s %02d ",
193 tm->tm_hour, tm->tm_min, tm->tm_sec, now.tv_usec,
194 _log_get_class(class), level);
195 else /* LOG_PRINT (-1) or LOG_REPORT (-2) */
196 snprintf(nbuf, sizeof nbuf, "%02d%02d%02d.%06ld %s ",
197 tm->tm_hour, tm->tm_min, tm->tm_sec, now.tv_usec,
198 class == LOG_PRINT ? "Default" : "Report>");
199 strlcat(nbuf, buffer, sizeof nbuf);
200 strlcat(nbuf, getuid() ? "" : " [priv]", LOG_SIZE + 32);
201 strlcat(nbuf, "\n", sizeof nbuf);
202
203 if (fwrite(nbuf, strlen(nbuf), 1, log_output) == 0) {
204 /* Report fallback. */
205 syslog(LOG_ALERT, fallback_msg, errno);
206 fprintf(log_output, fallback_msg, errno);
207
208 /*
209 * Close log_output to prevent isakmpd from locking
210 * the file. We may need to explicitly close stdout
211 * to do this properly.
212 * XXX - Figure out how to match two FILE *'s and
213 * rewrite.
214 */
215 if (fileno(log_output) != -1 &&
216 fileno(stdout) == fileno(log_output))
217 fclose(stdout);
218 fclose(log_output);
219
220 /* Fallback to syslog. */
221 log_to(0);
222
223 /* (Re)send current message to syslog(). */
224 syslog(class == LOG_REPORT ? LOG_ALERT :
225 syslog_level, "%s", buffer);
226 }
227 } else
228 syslog(class == LOG_REPORT ? LOG_ALERT : syslog_level, "%s",
229 buffer);
230 }
231
232 void
log_debug(int cls,int level,const char * fmt,...)233 log_debug(int cls, int level, const char *fmt, ...)
234 {
235 va_list ap;
236
237 /*
238 * If we are not debugging this class, or the level is too low, just
239 * return.
240 */
241 if (cls >= 0 && (log_level[cls] == 0 || level > log_level[cls]))
242 return;
243 va_start(ap, fmt);
244 _log_print(0, LOG_INFO, fmt, ap, cls, level);
245 va_end(ap);
246 }
247
248 void
log_debug_buf(int cls,int level,const char * header,const u_int8_t * buf,size_t sz)249 log_debug_buf(int cls, int level, const char *header, const u_int8_t *buf,
250 size_t sz)
251 {
252 size_t i, j;
253 char s[73];
254
255 /*
256 * If we are not debugging this class, or the level is too low, just
257 * return.
258 */
259 if (cls >= 0 && (log_level[cls] == 0 || level > log_level[cls]))
260 return;
261
262 log_debug(cls, level, "%s:", header);
263 for (i = j = 0; i < sz;) {
264 snprintf(s + j, sizeof s - j, "%02x", buf[i++]);
265 j += strlen(s + j);
266 if (i % 4 == 0) {
267 if (i % 32 == 0) {
268 s[j] = '\0';
269 log_debug(cls, level, "%s", s);
270 j = 0;
271 } else
272 s[j++] = ' ';
273 }
274 }
275 if (j) {
276 s[j] = '\0';
277 log_debug(cls, level, "%s", s);
278 }
279 }
280
281 void
log_debug_cmd(int cls,int level)282 log_debug_cmd(int cls, int level)
283 {
284 if (cls < 0 || cls >= LOG_ENDCLASS) {
285 log_print("log_debug_cmd: invalid debugging class %d", cls);
286 return;
287 }
288 if (level < 0) {
289 log_print("log_debug_cmd: invalid debugging level %d for "
290 "class %d", level, cls);
291 return;
292 }
293 if (level == log_level[cls])
294 log_print("log_debug_cmd: log level unchanged for class %d",
295 cls);
296 else {
297 log_print("log_debug_cmd: log level changed from %d to %d "
298 "for class %d", log_level[cls], level, cls);
299 log_level[cls] = level;
300 }
301 }
302
303 void
log_debug_toggle(void)304 log_debug_toggle(void)
305 {
306 static int log_level_copy[LOG_ENDCLASS], toggle = 0;
307
308 if (!toggle) {
309 LOG_DBG((LOG_MISC, 50, "log_debug_toggle: "
310 "debug levels cleared"));
311 memcpy(&log_level_copy, &log_level, sizeof log_level);
312 bzero(&log_level, sizeof log_level);
313 } else {
314 memcpy(&log_level, &log_level_copy, sizeof log_level);
315 LOG_DBG((LOG_MISC, 50, "log_debug_toggle: "
316 "debug levels restored"));
317 }
318 toggle = !toggle;
319 }
320
321 void
log_print(const char * fmt,...)322 log_print(const char *fmt, ...)
323 {
324 va_list ap;
325
326 va_start(ap, fmt);
327 _log_print(0, LOG_NOTICE, fmt, ap, LOG_PRINT, 0);
328 va_end(ap);
329 }
330
331 void
log_verbose(const char * fmt,...)332 log_verbose(const char *fmt, ...)
333 {
334 va_list ap;
335
336 if (verbose_logging == 0)
337 return;
338
339 va_start(ap, fmt);
340 _log_print(0, LOG_NOTICE, fmt, ap, LOG_PRINT, 0);
341 va_end(ap);
342 }
343
344 void
log_error(const char * fmt,...)345 log_error(const char *fmt, ...)
346 {
347 va_list ap;
348
349 va_start(ap, fmt);
350 _log_print(1, LOG_ERR, fmt, ap, LOG_PRINT, 0);
351 va_end(ap);
352 }
353
354 void
log_errorx(const char * fmt,...)355 log_errorx(const char *fmt, ...)
356 {
357 va_list ap;
358
359 va_start(ap, fmt);
360 _log_print(0, LOG_ERR, fmt, ap, LOG_PRINT, 0);
361 va_end(ap);
362 }
363
364 void
log_fatal(const char * fmt,...)365 log_fatal(const char *fmt, ...)
366 {
367 va_list ap;
368
369 va_start(ap, fmt);
370 _log_print(1, LOG_CRIT, fmt, ap, LOG_PRINT, 0);
371 va_end(ap);
372 monitor_exit(1);
373 }
374
375 void
log_fatalx(const char * fmt,...)376 log_fatalx(const char *fmt, ...)
377 {
378 va_list ap;
379
380 va_start(ap, fmt);
381 _log_print(0, LOG_CRIT, fmt, ap, LOG_PRINT, 0);
382 va_end(ap);
383 monitor_exit(1);
384 }
385
386 void
log_packet_init(char * newname)387 log_packet_init(char *newname)
388 {
389 struct pcap_file_header sf_hdr;
390 struct stat st;
391 mode_t old_umask;
392 char *mode;
393
394 /* Allocate packet buffer first time through. */
395 if (!packet_buf)
396 packet_buf = malloc(SNAPLEN);
397
398 if (!packet_buf) {
399 log_error("log_packet_init: malloc (%d) failed", SNAPLEN);
400 return;
401 }
402 if (pcaplog_file && strcmp(pcaplog_file, PCAP_FILE_DEFAULT) != 0)
403 free(pcaplog_file);
404
405 pcaplog_file = strdup(newname);
406 if (!pcaplog_file) {
407 log_error("log_packet_init: strdup (\"%s\") failed", newname);
408 return;
409 }
410 /* Does the file already exist? XXX lstat() or stat()? */
411 /* XXX This is a fstat! */
412 if (monitor_stat(pcaplog_file, &st) == 0) {
413 /* Sanity checks. */
414 if (!S_ISREG(st.st_mode)) {
415 log_print("log_packet_init: existing capture file is "
416 "not a regular file");
417 return;
418 }
419 if ((st.st_mode & (S_IRWXG | S_IRWXO)) != 0) {
420 log_print("log_packet_init: existing capture "
421 "file has bad modes");
422 return;
423 }
424 /*
425 * XXX It would be nice to check if it actually is a pcap
426 * file...
427 */
428
429 mode = "a";
430 } else
431 mode = "w";
432
433 old_umask = umask(S_IRWXG | S_IRWXO);
434 packet_log = monitor_fopen(pcaplog_file, mode);
435 umask(old_umask);
436
437 if (!packet_log) {
438 log_error("log_packet_init: fopen (\"%s\", \"%s\") failed",
439 pcaplog_file, mode);
440 return;
441 }
442 log_print("log_packet_init: "
443 "starting IKE packet capture to file \"%s\"", pcaplog_file);
444
445 /* If this is a new file, we need to write a PCAP header to it. */
446 if (*mode == 'w') {
447 sf_hdr.magic = TCPDUMP_MAGIC;
448 sf_hdr.version_major = PCAP_VERSION_MAJOR;
449 sf_hdr.version_minor = PCAP_VERSION_MINOR;
450 sf_hdr.thiszone = 0;
451 sf_hdr.snaplen = SNAPLEN;
452 sf_hdr.sigfigs = 0;
453 sf_hdr.linktype = DLT_LOOP;
454
455 fwrite((char *) &sf_hdr, sizeof sf_hdr, 1, packet_log);
456 fflush(packet_log);
457 }
458 }
459
460 void
log_packet_restart(char * newname)461 log_packet_restart(char *newname)
462 {
463 if (packet_log) {
464 log_print("log_packet_restart: capture already active on "
465 "file \"%s\"", pcaplog_file);
466 return;
467 }
468 if (newname)
469 log_packet_init(newname);
470 else if (!pcaplog_file)
471 log_packet_init(PCAP_FILE_DEFAULT);
472 else
473 log_packet_init(pcaplog_file);
474 }
475
476 void
log_packet_stop(void)477 log_packet_stop(void)
478 {
479 /* Stop capture. */
480 if (packet_log) {
481 fclose(packet_log);
482 log_print("log_packet_stop: stopped capture");
483 }
484 packet_log = 0;
485 }
486
487 void
log_packet_iov(struct sockaddr * src,struct sockaddr * dst,struct iovec * iov,int iovcnt)488 log_packet_iov(struct sockaddr *src, struct sockaddr *dst, struct iovec *iov,
489 int iovcnt)
490 {
491 struct isakmp_hdr *isakmphdr;
492 struct packhdr hdr;
493 struct udphdr udp;
494 struct timeval tv;
495 int off, datalen, hdrlen, i, add_espmarker = 0;
496 const u_int32_t espmarker = 0;
497
498 for (i = 0, datalen = 0; i < iovcnt; i++)
499 datalen += iov[i].iov_len;
500
501 if (!packet_log || datalen > SNAPLEN)
502 return;
503
504 /* copy packet into buffer */
505 for (i = 0, off = 0; i < iovcnt; i++) {
506 memcpy(packet_buf + off, iov[i].iov_base, iov[i].iov_len);
507 off += iov[i].iov_len;
508 }
509
510 bzero(&hdr, sizeof hdr);
511 bzero(&udp, sizeof udp);
512
513 /* isakmp - turn off the encryption bit in the isakmp hdr */
514 isakmphdr = (struct isakmp_hdr *) packet_buf;
515 isakmphdr->flags &= ~(ISAKMP_FLAGS_ENC);
516
517 /* udp */
518 udp.uh_sport = sockaddr_port(src);
519 udp.uh_dport = sockaddr_port(dst);
520 datalen += sizeof udp;
521 if (ntohs(udp.uh_sport) == 4500 ||
522 ntohs(udp.uh_dport) == 4500) { /* XXX Quick and dirty */
523 add_espmarker = 1;
524 datalen += sizeof espmarker;
525 }
526 udp.uh_ulen = htons(datalen);
527
528 /* ip */
529 hdr.sa_family = htonl(src->sa_family);
530 switch (src->sa_family) {
531 default:
532 /* Assume IPv4. XXX Can 'default' ever happen here? */
533 hdr.sa_family = htonl(AF_INET);
534 hdr.ip.ip4.ip_src.s_addr = 0x02020202;
535 hdr.ip.ip4.ip_dst.s_addr = 0x01010101;
536 /* The rest of the setup is common to AF_INET. */
537 goto setup_ip4;
538
539 case AF_INET:
540 hdr.ip.ip4.ip_src.s_addr =
541 ((struct sockaddr_in *)src)->sin_addr.s_addr;
542 hdr.ip.ip4.ip_dst.s_addr =
543 ((struct sockaddr_in *)dst)->sin_addr.s_addr;
544
545 setup_ip4:
546 hdrlen = sizeof hdr.ip.ip4;
547 hdr.ip.ip4.ip_v = 0x4;
548 hdr.ip.ip4.ip_hl = 0x5;
549 hdr.ip.ip4.ip_p = IPPROTO_UDP;
550 hdr.ip.ip4.ip_len = htons(datalen + hdrlen);
551 /* Let's use the IP ID as a "packet counter". */
552 i = ntohs(hdr.ip.ip4.ip_id) + 1;
553 hdr.ip.ip4.ip_id = htons(i);
554 /* Calculate IP header checksum. */
555 hdr.ip.ip4.ip_sum = in_cksum((u_int16_t *) & hdr.ip.ip4,
556 hdr.ip.ip4.ip_hl << 2);
557 break;
558
559 case AF_INET6:
560 hdrlen = sizeof(hdr.ip.ip6);
561 hdr.ip.ip6.ip6_vfc = IPV6_VERSION;
562 hdr.ip.ip6.ip6_nxt = IPPROTO_UDP;
563 hdr.ip.ip6.ip6_plen = udp.uh_ulen;
564 memcpy(&hdr.ip.ip6.ip6_src,
565 &((struct sockaddr_in6 *)src)->sin6_addr,
566 sizeof hdr.ip.ip6.ip6_src);
567 memcpy(&hdr.ip.ip6.ip6_dst,
568 &((struct sockaddr_in6 *)dst)->sin6_addr,
569 sizeof hdr.ip.ip6.ip6_dst);
570 break;
571 }
572
573 /* Calculate UDP checksum. */
574 udp.uh_sum = udp_cksum(&hdr, &udp, (u_int16_t *) packet_buf);
575 hdrlen += sizeof hdr.sa_family;
576
577 /* pcap file packet header */
578 gettimeofday(&tv, 0);
579 hdr.pcap.ts.tv_sec = tv.tv_sec;
580 hdr.pcap.ts.tv_usec = tv.tv_usec;
581 hdr.pcap.caplen = datalen + hdrlen;
582 hdr.pcap.len = datalen + hdrlen;
583
584 hdrlen += sizeof(struct pcap_pkthdr);
585 datalen -= sizeof(struct udphdr);
586
587 /* Write to pcap file. */
588 fwrite(&hdr, hdrlen, 1, packet_log); /* pcap + IP */
589 fwrite(&udp, sizeof(struct udphdr), 1, packet_log); /* UDP */
590 if (add_espmarker) {
591 fwrite(&espmarker, sizeof espmarker, 1, packet_log);
592 datalen -= sizeof espmarker;
593 }
594 fwrite(packet_buf, datalen, 1, packet_log); /* IKE-data */
595 fflush(packet_log);
596 }
597
598 /* Copied from tcpdump/print-udp.c, mostly rewritten. */
599 static int
udp_cksum(struct packhdr * hdr,const struct udphdr * u,u_int16_t * d)600 udp_cksum(struct packhdr *hdr, const struct udphdr *u, u_int16_t *d)
601 {
602 struct ip *ip4;
603 struct ip6_hdr *ip6;
604 int i, hdrlen, tlen = ntohs(u->uh_ulen) - sizeof(struct udphdr);
605
606 union phu {
607 struct ip4pseudo {
608 struct in_addr src;
609 struct in_addr dst;
610 u_int8_t z;
611 u_int8_t proto;
612 u_int16_t len;
613 } ip4p;
614 struct ip6pseudo {
615 struct in6_addr src;
616 struct in6_addr dst;
617 u_int32_t plen;
618 u_int16_t z0;
619 u_int8_t z1;
620 u_int8_t nxt;
621 } ip6p;
622 u_int16_t pa[20];
623 } phu;
624 const u_int16_t *sp;
625 u_int32_t sum;
626
627 /* Setup pseudoheader. */
628 bzero(phu.pa, sizeof phu);
629 switch (ntohl(hdr->sa_family)) {
630 case AF_INET:
631 ip4 = &hdr->ip.ip4;
632 memcpy(&phu.ip4p.src, &ip4->ip_src, sizeof(struct in_addr));
633 memcpy(&phu.ip4p.dst, &ip4->ip_dst, sizeof(struct in_addr));
634 phu.ip4p.proto = ip4->ip_p;
635 phu.ip4p.len = u->uh_ulen;
636 hdrlen = sizeof phu.ip4p;
637 break;
638
639 case AF_INET6:
640 ip6 = &hdr->ip.ip6;
641 memcpy(&phu.ip6p.src, &ip6->ip6_src, sizeof(phu.ip6p.src));
642 memcpy(&phu.ip6p.dst, &ip6->ip6_dst, sizeof(phu.ip6p.dst));
643 phu.ip6p.plen = u->uh_ulen;
644 phu.ip6p.nxt = ip6->ip6_nxt;
645 hdrlen = sizeof phu.ip6p;
646 break;
647
648 default:
649 return 0;
650 }
651
652 /* IPv6 wants a 0xFFFF checksum "on error", not 0x0. */
653 if (tlen < 0)
654 return (ntohl(hdr->sa_family) == AF_INET ? 0 : 0xFFFF);
655
656 sum = 0;
657 for (i = 0; i < hdrlen; i += 2)
658 sum += phu.pa[i / 2];
659
660 sp = (const u_int16_t *)u;
661 for (i = 0; i < (int)sizeof(struct udphdr); i += 2)
662 sum += *sp++;
663
664 sp = d;
665 for (i = 0; i < (tlen & ~1); i += 2)
666 sum += *sp++;
667
668 if (tlen & 1)
669 sum += htons((*(const char *)sp) << 8);
670
671 while (sum > 0xffff)
672 sum = (sum & 0xffff) + (sum >> 16);
673 sum = ~sum & 0xffff;
674
675 return sum;
676 }
677
678 /* Copied from tcpdump/print-ip.c, modified. */
679 static u_int16_t
in_cksum(const u_int16_t * w,int len)680 in_cksum(const u_int16_t *w, int len)
681 {
682 int nleft = len, sum = 0;
683 u_int16_t answer;
684
685 while (nleft > 1) {
686 sum += *w++;
687 nleft -= 2;
688 }
689 if (nleft == 1)
690 sum += htons(*(const u_char *)w << 8);
691
692 sum = (sum >> 16) + (sum & 0xffff); /* add hi 16 to low 16 */
693 sum += (sum >> 16); /* add carry */
694 answer = ~sum; /* truncate to 16 bits */
695 return answer;
696 }
697