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