| File: | src/sbin/isakmpd/log.c |
| Warning: | line 401, column 17 Use of memory after it is freed |
Press '?' to see keyboard shortcuts
Keyboard shortcuts:
| 1 | /* $OpenBSD: log.c,v 1.64 2018/01/15 09:54:48 mpi 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(*__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_MAGIC0xa1b2c3d4 0xa1b2c3d4 | |||
| 69 | #define SNAPLEN(64 * 1024) (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((void *)0); | |||
| 87 | static FILE *packet_log; | |||
| 88 | static u_int8_t *packet_buf = NULL((void *)0); | |||
| 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 | |||
| 95 | log_init(int debug) | |||
| 96 | { | |||
| 97 | if (debug) | |||
| 98 | log_output = stderr(&__sF[2]); | |||
| 99 | else | |||
| 100 | log_to(0); /* syslog */ | |||
| 101 | } | |||
| 102 | ||||
| 103 | 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)((&logging->fields)->tqh_first); logclass; | |||
| 120 | logclass = TAILQ_NEXT(logclass, link)((logclass)->link.tqe_next)) { | |||
| 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 | |||
| 137 | log_to(FILE *f) | |||
| 138 | { | |||
| 139 | if (!log_output && f) | |||
| 140 | closelog(); | |||
| 141 | log_output = f; | |||
| 142 | if (!f) | |||
| 143 | openlog("isakmpd", LOG_PID0x01 | LOG_CONS0x02, LOG_DAEMON(3<<3)); | |||
| 144 | } | |||
| 145 | ||||
| 146 | FILE * | |||
| 147 | log_current(void) | |||
| 148 | { | |||
| 149 | return log_output; | |||
| 150 | } | |||
| 151 | ||||
| 152 | static char * | |||
| 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{ "Misc", "Trpt", "Mesg", "Cryp", "Timr", "Sdep", "SA ", "Exch" , "Negt", "Plcy", "UI " }; | |||
| 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 | |||
| 167 | _log_print(int error, int syslog_level, const char *fmt, va_list ap, | |||
| 168 | int class, int level) | |||
| 169 | { | |||
| 170 | char buffer[LOG_SIZE200], nbuf[LOG_SIZE200 + 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(*__errno()))); | |||
| 182 | if (log_output) { | |||
| 183 | gettimeofday(&now, 0); | |||
| 184 | t = now.tv_sec; | |||
| 185 | tm = localtime(&t); | |||
| 186 | if (class >= 0) | |||
| 187 | snprintf(nbuf, sizeof nbuf, | |||
| 188 | "%02d%02d%02d.%06ld %s %02d ", | |||
| 189 | tm->tm_hour, tm->tm_min, tm->tm_sec, now.tv_usec, | |||
| 190 | _log_get_class(class), level); | |||
| 191 | else /* LOG_PRINT (-1) or LOG_REPORT (-2) */ | |||
| 192 | snprintf(nbuf, sizeof nbuf, "%02d%02d%02d.%06ld %s ", | |||
| 193 | tm->tm_hour, tm->tm_min, tm->tm_sec, now.tv_usec, | |||
| 194 | class == LOG_PRINT-1 ? "Default" : "Report>"); | |||
| 195 | strlcat(nbuf, buffer, sizeof nbuf); | |||
| 196 | strlcat(nbuf, getuid() ? "" : " [priv]", LOG_SIZE200 + 32); | |||
| 197 | strlcat(nbuf, "\n", sizeof nbuf); | |||
| 198 | ||||
| 199 | if (fwrite(nbuf, strlen(nbuf), 1, log_output) == 0) { | |||
| 200 | /* Report fallback. */ | |||
| 201 | syslog(LOG_ALERT1, fallback_msg, errno(*__errno())); | |||
| 202 | fprintf(log_output, fallback_msg, errno(*__errno())); | |||
| 203 | ||||
| 204 | /* | |||
| 205 | * Close log_output to prevent isakmpd from locking | |||
| 206 | * the file. We may need to explicitly close stdout | |||
| 207 | * to do this properly. | |||
| 208 | * XXX - Figure out how to match two FILE *'s and | |||
| 209 | * rewrite. | |||
| 210 | */ | |||
| 211 | if (fileno(log_output)(!__isthreaded ? ((log_output)->_file) : (fileno)(log_output )) != -1 && | |||
| 212 | fileno(stdout)(!__isthreaded ? (((&__sF[1]))->_file) : (fileno)((& __sF[1]))) == fileno(log_output)(!__isthreaded ? ((log_output)->_file) : (fileno)(log_output ))) | |||
| 213 | fclose(stdout(&__sF[1])); | |||
| 214 | fclose(log_output); | |||
| 215 | ||||
| 216 | /* Fallback to syslog. */ | |||
| 217 | log_to(0); | |||
| 218 | ||||
| 219 | /* (Re)send current message to syslog(). */ | |||
| 220 | syslog(class == LOG_REPORT-2 ? LOG_ALERT1 : | |||
| 221 | syslog_level, "%s", buffer); | |||
| 222 | } | |||
| 223 | } else | |||
| 224 | syslog(class == LOG_REPORT-2 ? LOG_ALERT1 : syslog_level, "%s", | |||
| 225 | buffer); | |||
| 226 | } | |||
| 227 | ||||
| 228 | void | |||
| 229 | log_debug(int cls, int level, const char *fmt, ...) | |||
| 230 | { | |||
| 231 | va_list ap; | |||
| 232 | ||||
| 233 | /* | |||
| 234 | * If we are not debugging this class, or the level is too low, just | |||
| 235 | * return. | |||
| 236 | */ | |||
| 237 | if (cls >= 0 && (log_level[cls] == 0 || level > log_level[cls])) | |||
| 238 | return; | |||
| 239 | va_start(ap, fmt)__builtin_va_start(ap, fmt); | |||
| 240 | _log_print(0, LOG_INFO6, fmt, ap, cls, level); | |||
| 241 | va_end(ap)__builtin_va_end(ap); | |||
| 242 | } | |||
| 243 | ||||
| 244 | void | |||
| 245 | log_debug_buf(int cls, int level, const char *header, const u_int8_t *buf, | |||
| 246 | size_t sz) | |||
| 247 | { | |||
| 248 | size_t i, j; | |||
| 249 | char s[73]; | |||
| 250 | ||||
| 251 | /* | |||
| 252 | * If we are not debugging this class, or the level is too low, just | |||
| 253 | * return. | |||
| 254 | */ | |||
| 255 | if (cls >= 0 && (log_level[cls] == 0 || level > log_level[cls])) | |||
| 256 | return; | |||
| 257 | ||||
| 258 | log_debug(cls, level, "%s:", header); | |||
| 259 | for (i = j = 0; i < sz;) { | |||
| 260 | snprintf(s + j, sizeof s - j, "%02x", buf[i++]); | |||
| 261 | j += strlen(s + j); | |||
| 262 | if (i % 4 == 0) { | |||
| 263 | if (i % 32 == 0) { | |||
| 264 | s[j] = '\0'; | |||
| 265 | log_debug(cls, level, "%s", s); | |||
| 266 | j = 0; | |||
| 267 | } else | |||
| 268 | s[j++] = ' '; | |||
| 269 | } | |||
| 270 | } | |||
| 271 | if (j) { | |||
| 272 | s[j] = '\0'; | |||
| 273 | log_debug(cls, level, "%s", s); | |||
| 274 | } | |||
| 275 | } | |||
| 276 | ||||
| 277 | void | |||
| 278 | log_debug_cmd(int cls, int level) | |||
| 279 | { | |||
| 280 | if (cls < 0 || cls >= LOG_ENDCLASS) { | |||
| 281 | log_print("log_debug_cmd: invalid debugging class %d", cls); | |||
| 282 | return; | |||
| 283 | } | |||
| 284 | if (level < 0) { | |||
| 285 | log_print("log_debug_cmd: invalid debugging level %d for " | |||
| 286 | "class %d", level, cls); | |||
| 287 | return; | |||
| 288 | } | |||
| 289 | if (level == log_level[cls]) | |||
| 290 | log_print("log_debug_cmd: log level unchanged for class %d", | |||
| 291 | cls); | |||
| 292 | else { | |||
| 293 | log_print("log_debug_cmd: log level changed from %d to %d " | |||
| 294 | "for class %d", log_level[cls], level, cls); | |||
| 295 | log_level[cls] = level; | |||
| 296 | } | |||
| 297 | } | |||
| 298 | ||||
| 299 | void | |||
| 300 | log_debug_toggle(void) | |||
| 301 | { | |||
| 302 | static int log_level_copy[LOG_ENDCLASS], toggle = 0; | |||
| 303 | ||||
| 304 | if (!toggle) { | |||
| 305 | LOG_DBG((LOG_MISC, 50, "log_debug_toggle: "log_debug (LOG_MISC, 50, "log_debug_toggle: " "debug levels cleared" ) | |||
| 306 | "debug levels cleared"))log_debug (LOG_MISC, 50, "log_debug_toggle: " "debug levels cleared" ); | |||
| 307 | memcpy(&log_level_copy, &log_level, sizeof log_level); | |||
| 308 | bzero(&log_level, sizeof log_level); | |||
| 309 | } else { | |||
| 310 | memcpy(&log_level, &log_level_copy, sizeof log_level); | |||
| 311 | LOG_DBG((LOG_MISC, 50, "log_debug_toggle: "log_debug (LOG_MISC, 50, "log_debug_toggle: " "debug levels restored" ) | |||
| 312 | "debug levels restored"))log_debug (LOG_MISC, 50, "log_debug_toggle: " "debug levels restored" ); | |||
| 313 | } | |||
| 314 | toggle = !toggle; | |||
| 315 | } | |||
| 316 | ||||
| 317 | void | |||
| 318 | log_print(const char *fmt, ...) | |||
| 319 | { | |||
| 320 | va_list ap; | |||
| 321 | ||||
| 322 | va_start(ap, fmt)__builtin_va_start(ap, fmt); | |||
| 323 | _log_print(0, LOG_NOTICE5, fmt, ap, LOG_PRINT-1, 0); | |||
| 324 | va_end(ap)__builtin_va_end(ap); | |||
| 325 | } | |||
| 326 | ||||
| 327 | void | |||
| 328 | log_verbose(const char *fmt, ...) | |||
| 329 | { | |||
| 330 | va_list ap; | |||
| 331 | ||||
| 332 | if (verbose_logging == 0) | |||
| 333 | return; | |||
| 334 | ||||
| 335 | va_start(ap, fmt)__builtin_va_start(ap, fmt); | |||
| 336 | _log_print(0, LOG_NOTICE5, fmt, ap, LOG_PRINT-1, 0); | |||
| 337 | va_end(ap)__builtin_va_end(ap); | |||
| 338 | } | |||
| 339 | ||||
| 340 | void | |||
| 341 | log_error(const char *fmt, ...) | |||
| 342 | { | |||
| 343 | va_list ap; | |||
| 344 | ||||
| 345 | va_start(ap, fmt)__builtin_va_start(ap, fmt); | |||
| 346 | _log_print(1, LOG_ERR3, fmt, ap, LOG_PRINT-1, 0); | |||
| 347 | va_end(ap)__builtin_va_end(ap); | |||
| 348 | } | |||
| 349 | ||||
| 350 | void | |||
| 351 | log_errorx(const char *fmt, ...) | |||
| 352 | { | |||
| 353 | va_list ap; | |||
| 354 | ||||
| 355 | va_start(ap, fmt)__builtin_va_start(ap, fmt); | |||
| 356 | _log_print(0, LOG_ERR3, fmt, ap, LOG_PRINT-1, 0); | |||
| 357 | va_end(ap)__builtin_va_end(ap); | |||
| 358 | } | |||
| 359 | ||||
| 360 | void | |||
| 361 | log_fatal(const char *fmt, ...) | |||
| 362 | { | |||
| 363 | va_list ap; | |||
| 364 | ||||
| 365 | va_start(ap, fmt)__builtin_va_start(ap, fmt); | |||
| 366 | _log_print(1, LOG_CRIT2, fmt, ap, LOG_PRINT-1, 0); | |||
| 367 | va_end(ap)__builtin_va_end(ap); | |||
| 368 | monitor_exit(1); | |||
| 369 | } | |||
| 370 | ||||
| 371 | void | |||
| 372 | log_fatalx(const char *fmt, ...) | |||
| 373 | { | |||
| 374 | va_list ap; | |||
| 375 | ||||
| 376 | va_start(ap, fmt)__builtin_va_start(ap, fmt); | |||
| 377 | _log_print(0, LOG_CRIT2, fmt, ap, LOG_PRINT-1, 0); | |||
| 378 | va_end(ap)__builtin_va_end(ap); | |||
| 379 | monitor_exit(1); | |||
| 380 | } | |||
| 381 | ||||
| 382 | void | |||
| 383 | log_packet_init(char *newname) | |||
| 384 | { | |||
| 385 | struct pcap_file_header sf_hdr; | |||
| 386 | struct stat st; | |||
| 387 | mode_t old_umask; | |||
| 388 | char *mode; | |||
| 389 | ||||
| 390 | /* Allocate packet buffer first time through. */ | |||
| 391 | if (!packet_buf) | |||
| 392 | packet_buf = malloc(SNAPLEN(64 * 1024)); | |||
| 393 | ||||
| 394 | if (!packet_buf
| |||
| 395 | log_error("log_packet_init: malloc (%d) failed", SNAPLEN(64 * 1024)); | |||
| 396 | return; | |||
| 397 | } | |||
| 398 | if (pcaplog_file
| |||
| 399 | free(pcaplog_file); | |||
| 400 | ||||
| 401 | pcaplog_file = strdup(newname); | |||
| ||||
| 402 | if (!pcaplog_file) { | |||
| 403 | log_error("log_packet_init: strdup (\"%s\") failed", newname); | |||
| 404 | return; | |||
| 405 | } | |||
| 406 | /* Does the file already exist? XXX lstat() or stat()? */ | |||
| 407 | /* XXX This is a fstat! */ | |||
| 408 | if (monitor_stat(pcaplog_file, &st) == 0) { | |||
| 409 | /* Sanity checks. */ | |||
| 410 | if (!S_ISREG(st.st_mode)((st.st_mode & 0170000) == 0100000)) { | |||
| 411 | log_print("log_packet_init: existing capture file is " | |||
| 412 | "not a regular file"); | |||
| 413 | return; | |||
| 414 | } | |||
| 415 | if ((st.st_mode & (S_IRWXG0000070 | S_IRWXO0000007)) != 0) { | |||
| 416 | log_print("log_packet_init: existing capture " | |||
| 417 | "file has bad modes"); | |||
| 418 | return; | |||
| 419 | } | |||
| 420 | /* | |||
| 421 | * XXX It would be nice to check if it actually is a pcap | |||
| 422 | * file... | |||
| 423 | */ | |||
| 424 | ||||
| 425 | mode = "a"; | |||
| 426 | } else | |||
| 427 | mode = "w"; | |||
| 428 | ||||
| 429 | old_umask = umask(S_IRWXG0000070 | S_IRWXO0000007); | |||
| 430 | packet_log = monitor_fopen(pcaplog_file, mode); | |||
| 431 | umask(old_umask); | |||
| 432 | ||||
| 433 | if (!packet_log) { | |||
| 434 | log_error("log_packet_init: fopen (\"%s\", \"%s\") failed", | |||
| 435 | pcaplog_file, mode); | |||
| 436 | return; | |||
| 437 | } | |||
| 438 | log_print("log_packet_init: " | |||
| 439 | "starting IKE packet capture to file \"%s\"", pcaplog_file); | |||
| 440 | ||||
| 441 | /* If this is a new file, we need to write a PCAP header to it. */ | |||
| 442 | if (*mode == 'w') { | |||
| 443 | sf_hdr.magic = TCPDUMP_MAGIC0xa1b2c3d4; | |||
| 444 | sf_hdr.version_major = PCAP_VERSION_MAJOR2; | |||
| 445 | sf_hdr.version_minor = PCAP_VERSION_MINOR4; | |||
| 446 | sf_hdr.thiszone = 0; | |||
| 447 | sf_hdr.snaplen = SNAPLEN(64 * 1024); | |||
| 448 | sf_hdr.sigfigs = 0; | |||
| 449 | sf_hdr.linktype = DLT_LOOP12; | |||
| 450 | ||||
| 451 | fwrite((char *) &sf_hdr, sizeof sf_hdr, 1, packet_log); | |||
| 452 | fflush(packet_log); | |||
| 453 | } | |||
| 454 | } | |||
| 455 | ||||
| 456 | void | |||
| 457 | log_packet_restart(char *newname) | |||
| 458 | { | |||
| 459 | if (packet_log) { | |||
| ||||
| 460 | log_print("log_packet_restart: capture already active on " | |||
| 461 | "file \"%s\"", pcaplog_file); | |||
| 462 | return; | |||
| 463 | } | |||
| 464 | if (newname) | |||
| 465 | log_packet_init(newname); | |||
| 466 | else if (!pcaplog_file) | |||
| 467 | log_packet_init(PCAP_FILE_DEFAULT"/var/run/isakmpd.pcap"); | |||
| 468 | else | |||
| 469 | log_packet_init(pcaplog_file); | |||
| 470 | } | |||
| 471 | ||||
| 472 | void | |||
| 473 | log_packet_stop(void) | |||
| 474 | { | |||
| 475 | /* Stop capture. */ | |||
| 476 | if (packet_log) { | |||
| 477 | fclose(packet_log); | |||
| 478 | log_print("log_packet_stop: stopped capture"); | |||
| 479 | } | |||
| 480 | packet_log = 0; | |||
| 481 | } | |||
| 482 | ||||
| 483 | void | |||
| 484 | log_packet_iov(struct sockaddr *src, struct sockaddr *dst, struct iovec *iov, | |||
| 485 | int iovcnt) | |||
| 486 | { | |||
| 487 | struct isakmp_hdr *isakmphdr; | |||
| 488 | struct packhdr hdr; | |||
| 489 | struct udphdr udp; | |||
| 490 | struct timeval tv; | |||
| 491 | int off, datalen, hdrlen, i, add_espmarker = 0; | |||
| 492 | const u_int32_t espmarker = 0; | |||
| 493 | ||||
| 494 | for (i = 0, datalen = 0; i < iovcnt; i++) | |||
| 495 | datalen += iov[i].iov_len; | |||
| 496 | ||||
| 497 | if (!packet_log || datalen > SNAPLEN(64 * 1024)) | |||
| 498 | return; | |||
| 499 | ||||
| 500 | /* copy packet into buffer */ | |||
| 501 | for (i = 0, off = 0; i < iovcnt; i++) { | |||
| 502 | memcpy(packet_buf + off, iov[i].iov_base, iov[i].iov_len); | |||
| 503 | off += iov[i].iov_len; | |||
| 504 | } | |||
| 505 | ||||
| 506 | bzero(&hdr, sizeof hdr); | |||
| 507 | bzero(&udp, sizeof udp); | |||
| 508 | ||||
| 509 | /* isakmp - turn off the encryption bit in the isakmp hdr */ | |||
| 510 | isakmphdr = (struct isakmp_hdr *) packet_buf; | |||
| 511 | isakmphdr->flags &= ~(ISAKMP_FLAGS_ENC1); | |||
| 512 | ||||
| 513 | /* udp */ | |||
| 514 | udp.uh_sport = sockaddr_port(src); | |||
| 515 | udp.uh_dport = sockaddr_port(dst); | |||
| 516 | datalen += sizeof udp; | |||
| 517 | if (ntohs(udp.uh_sport)(__uint16_t)(__builtin_constant_p(udp.uh_sport) ? (__uint16_t )(((__uint16_t)(udp.uh_sport) & 0xffU) << 8 | ((__uint16_t )(udp.uh_sport) & 0xff00U) >> 8) : __swap16md(udp.uh_sport )) == 4500 || | |||
| 518 | ntohs(udp.uh_dport)(__uint16_t)(__builtin_constant_p(udp.uh_dport) ? (__uint16_t )(((__uint16_t)(udp.uh_dport) & 0xffU) << 8 | ((__uint16_t )(udp.uh_dport) & 0xff00U) >> 8) : __swap16md(udp.uh_dport )) == 4500) { /* XXX Quick and dirty */ | |||
| 519 | add_espmarker = 1; | |||
| 520 | datalen += sizeof espmarker; | |||
| 521 | } | |||
| 522 | udp.uh_ulen = htons(datalen)(__uint16_t)(__builtin_constant_p(datalen) ? (__uint16_t)(((__uint16_t )(datalen) & 0xffU) << 8 | ((__uint16_t)(datalen) & 0xff00U) >> 8) : __swap16md(datalen)); | |||
| 523 | ||||
| 524 | /* ip */ | |||
| 525 | hdr.sa_family = htonl(src->sa_family)(__uint32_t)(__builtin_constant_p(src->sa_family) ? (__uint32_t )(((__uint32_t)(src->sa_family) & 0xff) << 24 | ( (__uint32_t)(src->sa_family) & 0xff00) << 8 | (( __uint32_t)(src->sa_family) & 0xff0000) >> 8 | ( (__uint32_t)(src->sa_family) & 0xff000000) >> 24 ) : __swap32md(src->sa_family)); | |||
| 526 | switch (src->sa_family) { | |||
| 527 | default: | |||
| 528 | /* Assume IPv4. XXX Can 'default' ever happen here? */ | |||
| 529 | hdr.sa_family = htonl(AF_INET)(__uint32_t)(__builtin_constant_p(2) ? (__uint32_t)(((__uint32_t )(2) & 0xff) << 24 | ((__uint32_t)(2) & 0xff00) << 8 | ((__uint32_t)(2) & 0xff0000) >> 8 | ( (__uint32_t)(2) & 0xff000000) >> 24) : __swap32md(2 )); | |||
| 530 | hdr.ip.ip4.ip_src.s_addr = 0x02020202; | |||
| 531 | hdr.ip.ip4.ip_dst.s_addr = 0x01010101; | |||
| 532 | /* The rest of the setup is common to AF_INET. */ | |||
| 533 | goto setup_ip4; | |||
| 534 | ||||
| 535 | case AF_INET2: | |||
| 536 | hdr.ip.ip4.ip_src.s_addr = | |||
| 537 | ((struct sockaddr_in *)src)->sin_addr.s_addr; | |||
| 538 | hdr.ip.ip4.ip_dst.s_addr = | |||
| 539 | ((struct sockaddr_in *)dst)->sin_addr.s_addr; | |||
| 540 | ||||
| 541 | setup_ip4: | |||
| 542 | hdrlen = sizeof hdr.ip.ip4; | |||
| 543 | hdr.ip.ip4.ip_v = 0x4; | |||
| 544 | hdr.ip.ip4.ip_hl = 0x5; | |||
| 545 | hdr.ip.ip4.ip_p = IPPROTO_UDP17; | |||
| 546 | hdr.ip.ip4.ip_len = htons(datalen + hdrlen)(__uint16_t)(__builtin_constant_p(datalen + hdrlen) ? (__uint16_t )(((__uint16_t)(datalen + hdrlen) & 0xffU) << 8 | ( (__uint16_t)(datalen + hdrlen) & 0xff00U) >> 8) : __swap16md (datalen + hdrlen)); | |||
| 547 | /* Let's use the IP ID as a "packet counter". */ | |||
| 548 | i = ntohs(hdr.ip.ip4.ip_id)(__uint16_t)(__builtin_constant_p(hdr.ip.ip4.ip_id) ? (__uint16_t )(((__uint16_t)(hdr.ip.ip4.ip_id) & 0xffU) << 8 | ( (__uint16_t)(hdr.ip.ip4.ip_id) & 0xff00U) >> 8) : __swap16md (hdr.ip.ip4.ip_id)) + 1; | |||
| 549 | hdr.ip.ip4.ip_id = htons(i)(__uint16_t)(__builtin_constant_p(i) ? (__uint16_t)(((__uint16_t )(i) & 0xffU) << 8 | ((__uint16_t)(i) & 0xff00U ) >> 8) : __swap16md(i)); | |||
| 550 | /* Calculate IP header checksum. */ | |||
| 551 | hdr.ip.ip4.ip_sum = in_cksum((u_int16_t *) & hdr.ip.ip4, | |||
| 552 | hdr.ip.ip4.ip_hl << 2); | |||
| 553 | break; | |||
| 554 | ||||
| 555 | case AF_INET624: | |||
| 556 | hdrlen = sizeof(hdr.ip.ip6); | |||
| 557 | hdr.ip.ip6.ip6_vfcip6_ctlun.ip6_un2_vfc = IPV6_VERSION0x60; | |||
| 558 | hdr.ip.ip6.ip6_nxtip6_ctlun.ip6_un1.ip6_un1_nxt = IPPROTO_UDP17; | |||
| 559 | hdr.ip.ip6.ip6_plenip6_ctlun.ip6_un1.ip6_un1_plen = udp.uh_ulen; | |||
| 560 | memcpy(&hdr.ip.ip6.ip6_src, | |||
| 561 | &((struct sockaddr_in6 *)src)->sin6_addr, | |||
| 562 | sizeof hdr.ip.ip6.ip6_src); | |||
| 563 | memcpy(&hdr.ip.ip6.ip6_dst, | |||
| 564 | &((struct sockaddr_in6 *)dst)->sin6_addr, | |||
| 565 | sizeof hdr.ip.ip6.ip6_dst); | |||
| 566 | break; | |||
| 567 | } | |||
| 568 | ||||
| 569 | /* Calculate UDP checksum. */ | |||
| 570 | udp.uh_sum = udp_cksum(&hdr, &udp, (u_int16_t *) packet_buf); | |||
| 571 | hdrlen += sizeof hdr.sa_family; | |||
| 572 | ||||
| 573 | /* pcap file packet header */ | |||
| 574 | gettimeofday(&tv, 0); | |||
| 575 | hdr.pcap.ts.tv_sec = tv.tv_sec; | |||
| 576 | hdr.pcap.ts.tv_usec = tv.tv_usec; | |||
| 577 | hdr.pcap.caplen = datalen + hdrlen; | |||
| 578 | hdr.pcap.len = datalen + hdrlen; | |||
| 579 | ||||
| 580 | hdrlen += sizeof(struct pcap_pkthdr); | |||
| 581 | datalen -= sizeof(struct udphdr); | |||
| 582 | ||||
| 583 | /* Write to pcap file. */ | |||
| 584 | fwrite(&hdr, hdrlen, 1, packet_log); /* pcap + IP */ | |||
| 585 | fwrite(&udp, sizeof(struct udphdr), 1, packet_log); /* UDP */ | |||
| 586 | if (add_espmarker) { | |||
| 587 | fwrite(&espmarker, sizeof espmarker, 1, packet_log); | |||
| 588 | datalen -= sizeof espmarker; | |||
| 589 | } | |||
| 590 | fwrite(packet_buf, datalen, 1, packet_log); /* IKE-data */ | |||
| 591 | fflush(packet_log); | |||
| 592 | } | |||
| 593 | ||||
| 594 | /* Copied from tcpdump/print-udp.c, mostly rewritten. */ | |||
| 595 | static int | |||
| 596 | udp_cksum(struct packhdr *hdr, const struct udphdr *u, u_int16_t *d) | |||
| 597 | { | |||
| 598 | struct ip *ip4; | |||
| 599 | struct ip6_hdr *ip6; | |||
| 600 | int i, hdrlen, tlen = ntohs(u->uh_ulen)(__uint16_t)(__builtin_constant_p(u->uh_ulen) ? (__uint16_t )(((__uint16_t)(u->uh_ulen) & 0xffU) << 8 | ((__uint16_t )(u->uh_ulen) & 0xff00U) >> 8) : __swap16md(u-> uh_ulen)) - sizeof(struct udphdr); | |||
| 601 | ||||
| 602 | union phu { | |||
| 603 | struct ip4pseudo { | |||
| 604 | struct in_addr src; | |||
| 605 | struct in_addr dst; | |||
| 606 | u_int8_t z; | |||
| 607 | u_int8_t proto; | |||
| 608 | u_int16_t len; | |||
| 609 | } ip4p; | |||
| 610 | struct ip6pseudo { | |||
| 611 | struct in6_addr src; | |||
| 612 | struct in6_addr dst; | |||
| 613 | u_int32_t plen; | |||
| 614 | u_int16_t z0; | |||
| 615 | u_int8_t z1; | |||
| 616 | u_int8_t nxt; | |||
| 617 | } ip6p; | |||
| 618 | u_int16_t pa[20]; | |||
| 619 | } phu; | |||
| 620 | const u_int16_t *sp; | |||
| 621 | u_int32_t sum; | |||
| 622 | ||||
| 623 | /* Setup pseudoheader. */ | |||
| 624 | bzero(phu.pa, sizeof phu); | |||
| 625 | switch (ntohl(hdr->sa_family)(__uint32_t)(__builtin_constant_p(hdr->sa_family) ? (__uint32_t )(((__uint32_t)(hdr->sa_family) & 0xff) << 24 | ( (__uint32_t)(hdr->sa_family) & 0xff00) << 8 | (( __uint32_t)(hdr->sa_family) & 0xff0000) >> 8 | ( (__uint32_t)(hdr->sa_family) & 0xff000000) >> 24 ) : __swap32md(hdr->sa_family))) { | |||
| 626 | case AF_INET2: | |||
| 627 | ip4 = &hdr->ip.ip4; | |||
| 628 | memcpy(&phu.ip4p.src, &ip4->ip_src, sizeof(struct in_addr)); | |||
| 629 | memcpy(&phu.ip4p.dst, &ip4->ip_dst, sizeof(struct in_addr)); | |||
| 630 | phu.ip4p.proto = ip4->ip_p; | |||
| 631 | phu.ip4p.len = u->uh_ulen; | |||
| 632 | hdrlen = sizeof phu.ip4p; | |||
| 633 | break; | |||
| 634 | ||||
| 635 | case AF_INET624: | |||
| 636 | ip6 = &hdr->ip.ip6; | |||
| 637 | memcpy(&phu.ip6p.src, &ip6->ip6_src, sizeof(phu.ip6p.src)); | |||
| 638 | memcpy(&phu.ip6p.dst, &ip6->ip6_dst, sizeof(phu.ip6p.dst)); | |||
| 639 | phu.ip6p.plen = u->uh_ulen; | |||
| 640 | phu.ip6p.nxt = ip6->ip6_nxtip6_ctlun.ip6_un1.ip6_un1_nxt; | |||
| 641 | hdrlen = sizeof phu.ip6p; | |||
| 642 | break; | |||
| 643 | ||||
| 644 | default: | |||
| 645 | return 0; | |||
| 646 | } | |||
| 647 | ||||
| 648 | /* IPv6 wants a 0xFFFF checksum "on error", not 0x0. */ | |||
| 649 | if (tlen < 0) | |||
| 650 | return (ntohl(hdr->sa_family)(__uint32_t)(__builtin_constant_p(hdr->sa_family) ? (__uint32_t )(((__uint32_t)(hdr->sa_family) & 0xff) << 24 | ( (__uint32_t)(hdr->sa_family) & 0xff00) << 8 | (( __uint32_t)(hdr->sa_family) & 0xff0000) >> 8 | ( (__uint32_t)(hdr->sa_family) & 0xff000000) >> 24 ) : __swap32md(hdr->sa_family)) == AF_INET2 ? 0 : 0xFFFF); | |||
| 651 | ||||
| 652 | sum = 0; | |||
| 653 | for (i = 0; i < hdrlen; i += 2) | |||
| 654 | sum += phu.pa[i / 2]; | |||
| 655 | ||||
| 656 | sp = (const u_int16_t *)u; | |||
| 657 | for (i = 0; i < (int)sizeof(struct udphdr); i += 2) | |||
| 658 | sum += *sp++; | |||
| 659 | ||||
| 660 | sp = d; | |||
| 661 | for (i = 0; i < (tlen & ~1); i += 2) | |||
| 662 | sum += *sp++; | |||
| 663 | ||||
| 664 | if (tlen & 1) | |||
| 665 | sum += htons((*(const char *)sp) << 8)(__uint16_t)(__builtin_constant_p((*(const char *)sp) << 8) ? (__uint16_t)(((__uint16_t)((*(const char *)sp) << 8) & 0xffU) << 8 | ((__uint16_t)((*(const char *)sp ) << 8) & 0xff00U) >> 8) : __swap16md((*(const char *)sp) << 8)); | |||
| 666 | ||||
| 667 | while (sum > 0xffff) | |||
| 668 | sum = (sum & 0xffff) + (sum >> 16); | |||
| 669 | sum = ~sum & 0xffff; | |||
| 670 | ||||
| 671 | return sum; | |||
| 672 | } | |||
| 673 | ||||
| 674 | /* Copied from tcpdump/print-ip.c, modified. */ | |||
| 675 | static u_int16_t | |||
| 676 | in_cksum(const u_int16_t *w, int len) | |||
| 677 | { | |||
| 678 | int nleft = len, sum = 0; | |||
| 679 | u_int16_t answer; | |||
| 680 | ||||
| 681 | while (nleft > 1) { | |||
| 682 | sum += *w++; | |||
| 683 | nleft -= 2; | |||
| 684 | } | |||
| 685 | if (nleft == 1) | |||
| 686 | sum += htons(*(const u_char *)w << 8)(__uint16_t)(__builtin_constant_p(*(const u_char *)w << 8) ? (__uint16_t)(((__uint16_t)(*(const u_char *)w << 8 ) & 0xffU) << 8 | ((__uint16_t)(*(const u_char *)w << 8) & 0xff00U) >> 8) : __swap16md(*(const u_char *) w << 8)); | |||
| 687 | ||||
| 688 | sum = (sum >> 16) + (sum & 0xffff); /* add hi 16 to low 16 */ | |||
| 689 | sum += (sum >> 16); /* add carry */ | |||
| 690 | answer = ~sum; /* truncate to 16 bits */ | |||
| 691 | return answer; | |||
| 692 | } |