00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032
00033 #include "dhcpd.h"
00034 #include <omapip/omapip_p.h>
00035 #include <errno.h>
00036
00037 #if defined (TRACING)
00038 void (*trace_set_time_hook) (TIME);
00039 static int tracing_stopped;
00040 static int traceoutfile;
00041 static int traceindex;
00042 static trace_type_t **trace_types;
00043 static int trace_type_count;
00044 static int trace_type_max;
00045 static trace_type_t *new_trace_types;
00046 static FILE *traceinfile;
00047 static tracefile_header_t tracefile_header;
00048 static int trace_playback_flag;
00049 trace_type_t trace_time_marker;
00050
00051 #if defined (DEBUG_MEMORY_LEAKAGE) || defined (DEBUG_MEMORY_LEAKAGE_ON_EXIT)
00052 extern omapi_array_t *trace_listeners;
00053 extern omapi_array_t *omapi_connections;
00054
00055 extern int errno;
00056
00057 void trace_free_all ()
00058 {
00059 trace_type_t *tp;
00060 int i;
00061 tp = new_trace_types;
00062 while (tp) {
00063 new_trace_types = tp -> next;
00064 if (tp -> name) {
00065 dfree (tp -> name, MDL);
00066 tp -> name = (char *)0;
00067 }
00068 dfree (tp, MDL);
00069 tp = new_trace_types;
00070 }
00071 for (i = 0; i < trace_type_count; i++) {
00072 if (trace_types [i]) {
00073 if (trace_types [i] -> name)
00074 dfree (trace_types [i] -> name, MDL);
00075 dfree (trace_types [i], MDL);
00076 }
00077 }
00078 dfree (trace_types, MDL);
00079 trace_types = (trace_type_t **)0;
00080 trace_type_count = trace_type_max = 0;
00081
00082 omapi_array_free (&trace_listeners, MDL);
00083 omapi_array_free (&omapi_connections, MDL);
00084 }
00085 #endif
00086
00087 static isc_result_t trace_type_record (trace_type_t *,
00088 unsigned, const char *, int);
00089
00090 int trace_playback ()
00091 {
00092 return trace_playback_flag;
00093 }
00094
00095 int trace_record ()
00096 {
00097 if (traceoutfile && !tracing_stopped)
00098 return 1;
00099 return 0;
00100 }
00101
00102 isc_result_t trace_init (void (*set_time) (TIME),
00103 const char *file, int line)
00104 {
00105 trace_type_t *root_type;
00106 static int root_setup = 0;
00107
00108 if (root_setup)
00109 return ISC_R_SUCCESS;
00110
00111 trace_set_time_hook = set_time;
00112
00113 root_type = trace_type_register ("trace-index-mapping",
00114 (void *)0, trace_index_map_input,
00115 trace_index_stop_tracing, file, line);
00116 if (!root_type)
00117 return ISC_R_UNEXPECTED;
00118 if (new_trace_types == root_type)
00119 new_trace_types = new_trace_types -> next;
00120 root_type -> index = 0;
00121 trace_type_stash (root_type);
00122
00123 root_setup = 1;
00124 return ISC_R_SUCCESS;
00125 }
00126
00127 isc_result_t trace_begin (const char *filename,
00128 const char *file, int line)
00129 {
00130 tracefile_header_t tfh;
00131 int status;
00132 trace_type_t *tptr, *next;
00133 isc_result_t result;
00134
00135 if (traceoutfile) {
00136 log_error ("%s(%d): trace_begin called twice",
00137 file, line);
00138 return DHCP_R_INVALIDARG;
00139 }
00140
00141 traceoutfile = open (filename, O_CREAT | O_WRONLY | O_EXCL | O_CLOEXEC, 0600);
00142 if (traceoutfile < 0 && errno == EEXIST) {
00143 log_error ("WARNING: Overwriting trace file \"%s\"", filename);
00144 traceoutfile = open (filename, O_WRONLY | O_EXCL | O_TRUNC | O_CLOEXEC,
00145 0600);
00146 }
00147
00148 if (traceoutfile < 0) {
00149 log_error ("%s(%d): trace_begin: %s: %m",
00150 file, line, filename);
00151 return ISC_R_UNEXPECTED;
00152 }
00153 #if defined (HAVE_SETFD)
00154 if (fcntl (traceoutfile, F_SETFD, 1) < 0)
00155 log_error ("Can't set close-on-exec on %s: %m", filename);
00156 #endif
00157
00158 tfh.magic = htonl (TRACEFILE_MAGIC);
00159 tfh.version = htonl (TRACEFILE_VERSION);
00160 tfh.hlen = htonl (sizeof (tracefile_header_t));
00161 tfh.phlen = htonl (sizeof (tracepacket_t));
00162
00163 status = write (traceoutfile, &tfh, sizeof tfh);
00164 if (status < 0) {
00165 log_error ("%s(%d): trace_begin write failed: %m", file, line);
00166 return ISC_R_UNEXPECTED;
00167 } else if (status != sizeof tfh) {
00168 log_error ("%s(%d): trace_begin: short write (%d:%ld)",
00169 file, line, status, (long)(sizeof tfh));
00170 trace_stop ();
00171 return ISC_R_UNEXPECTED;
00172 }
00173
00174
00175 if (new_trace_types) {
00176 next = new_trace_types;
00177 new_trace_types = (trace_type_t *)0;
00178 for (tptr = next; tptr; tptr = next) {
00179 next = tptr -> next;
00180 if (tptr -> index != 0) {
00181 result = (trace_type_record
00182 (tptr,
00183 strlen (tptr -> name), file, line));
00184 if (result != ISC_R_SUCCESS)
00185 return status;
00186 }
00187 }
00188 }
00189
00190 return ISC_R_SUCCESS;
00191 }
00192
00193 isc_result_t trace_write_packet (trace_type_t *ttype, unsigned length,
00194 const char *buf, const char *file, int line)
00195 {
00196 trace_iov_t iov;
00197
00198 iov.buf = buf;
00199 iov.len = length;
00200 return trace_write_packet_iov (ttype, 1, &iov, file, line);
00201 }
00202
00203 isc_result_t trace_write_packet_iov (trace_type_t *ttype,
00204 int count, trace_iov_t *iov,
00205 const char *file, int line)
00206 {
00207 tracepacket_t tmp;
00208 int status;
00209 int i;
00210 int length;
00211
00212
00213
00214 if (tracing_stopped)
00215 return 0;
00216
00217 if (!ttype) {
00218 log_error ("%s(%d): trace_write_packet with null trace type",
00219 file ? file : "<unknown file>", line);
00220 return DHCP_R_INVALIDARG;
00221 }
00222 if (!traceoutfile) {
00223 log_error ("%s(%d): trace_write_packet with no tracefile.",
00224 file ? file : "<unknown file>", line);
00225 return DHCP_R_INVALIDARG;
00226 }
00227
00228
00229 length = 0;
00230 for (i = 0; i < count; i++)
00231 length += iov [i].len;
00232
00233
00234
00235 memset(&tmp, 0, sizeof(tmp));
00236 tmp.type_index = htonl (ttype -> index);
00237 tmp.when = htonl (time ((time_t *)0));
00238 tmp.length = htonl (length);
00239
00240 status = write (traceoutfile, &tmp, sizeof tmp);
00241 if (status < 0) {
00242 log_error ("%s(%d): trace_write_packet write failed: %m",
00243 file, line);
00244 return ISC_R_UNEXPECTED;
00245 } else if (status != sizeof tmp) {
00246 log_error ("%s(%d): trace_write_packet: short write (%d:%ld)",
00247 file, line, status, (long)(sizeof tmp));
00248 trace_stop ();
00249 }
00250
00251 for (i = 0; i < count; i++) {
00252 status = write (traceoutfile, iov [i].buf, iov [i].len);
00253 if (status < 0) {
00254 log_error ("%s(%d): %s write failed: %m",
00255 file, line, "trace_write_packet");
00256 return ISC_R_UNEXPECTED;
00257 } else if (status != iov [i].len) {
00258 log_error ("%s(%d): %s: short write (%d:%d)",
00259 file, line,
00260 "trace_write_packet", status, length);
00261 trace_stop ();
00262 }
00263 }
00264
00265
00266
00267
00268 if (length % 8) {
00269 static char zero [] = { 0, 0, 0, 0, 0, 0, 0 };
00270 unsigned padl = 8 - (length % 8);
00271
00272 status = write (traceoutfile, zero, padl);
00273 if (status < 0) {
00274 log_error ("%s(%d): trace_write_packet write failed: %m",
00275 file, line);
00276 return ISC_R_UNEXPECTED;
00277 } else if (status != padl) {
00278 log_error ("%s(%d): trace_write_packet: short write (%d:%d)",
00279 file, line, status, padl);
00280 trace_stop ();
00281 }
00282 }
00283
00284 return ISC_R_SUCCESS;
00285 }
00286
00287 void trace_type_stash (trace_type_t *tptr)
00288 {
00289 trace_type_t **vec;
00290 int delta;
00291 if (trace_type_max <= tptr -> index) {
00292 delta = tptr -> index - trace_type_max + 10;
00293 vec = dmalloc (((trace_type_max + delta) *
00294 sizeof (trace_type_t *)), MDL);
00295 if (!vec)
00296 return;
00297 memset (&vec [trace_type_max], 0,
00298 (sizeof (trace_type_t *)) * delta);
00299 trace_type_max += delta;
00300 if (trace_types) {
00301 memcpy (vec, trace_types,
00302 trace_type_count * sizeof (trace_type_t *));
00303 dfree (trace_types, MDL);
00304 }
00305 trace_types = vec;
00306 }
00307 trace_types [tptr -> index] = tptr;
00308 if (tptr -> index >= trace_type_count)
00309 trace_type_count = tptr -> index + 1;
00310 }
00311
00312 trace_type_t *trace_type_register (const char *name,
00313 void *baggage,
00314 void (*have_packet) (trace_type_t *,
00315 unsigned, char *),
00316 void (*stop_tracing) (trace_type_t *),
00317 const char *file, int line)
00318 {
00319 trace_type_t *ttmp;
00320 unsigned slen = strlen (name);
00321 isc_result_t status;
00322
00323 ttmp = dmalloc (sizeof *ttmp, file, line);
00324 if (!ttmp)
00325 return ttmp;
00326 ttmp -> index = -1;
00327 ttmp -> name = dmalloc (slen + 1, file, line);
00328 if (!ttmp -> name) {
00329 dfree (ttmp, file, line);
00330 return (trace_type_t *)0;
00331 }
00332 strcpy (ttmp -> name, name);
00333 ttmp -> have_packet = have_packet;
00334 ttmp -> stop_tracing = stop_tracing;
00335
00336 if (traceoutfile) {
00337 status = trace_type_record (ttmp, slen, file, line);
00338 if (status != ISC_R_SUCCESS) {
00339 dfree (ttmp -> name, file, line);
00340 dfree (ttmp, file, line);
00341 return (trace_type_t *)0;
00342 }
00343 } else {
00344 ttmp -> next = new_trace_types;
00345 new_trace_types = ttmp;
00346 }
00347
00348 return ttmp;
00349 }
00350
00351 static isc_result_t trace_type_record (trace_type_t *ttmp, unsigned slen,
00352 const char *file, int line)
00353 {
00354 trace_index_mapping_t *tim;
00355 isc_result_t status;
00356
00357 tim = dmalloc (slen + TRACE_INDEX_MAPPING_SIZE, file, line);
00358 if (!tim)
00359 return ISC_R_NOMEMORY;
00360 ttmp -> index = ++traceindex;
00361 trace_type_stash (ttmp);
00362 tim -> index = htonl (ttmp -> index);
00363 memcpy (tim -> name, ttmp -> name, slen);
00364 status = trace_write_packet (trace_types [0],
00365 slen + TRACE_INDEX_MAPPING_SIZE,
00366 (char *)tim, file, line);
00367 dfree (tim, file, line);
00368 return status;
00369 }
00370
00371
00372
00373 void trace_stop (void)
00374 {
00375 int i;
00376
00377 for (i = 0; i < trace_type_count; i++)
00378 if (trace_types [i] -> stop_tracing)
00379 (*(trace_types [i] -> stop_tracing))
00380 (trace_types [i]);
00381 tracing_stopped = 1;
00382 }
00383
00384 void trace_index_map_input (trace_type_t *ttype, unsigned length, char *buf)
00385 {
00386 trace_index_mapping_t *tmap;
00387 unsigned len;
00388 trace_type_t *tptr, **prev;
00389
00390 if (length < TRACE_INDEX_MAPPING_SIZE) {
00391 log_error ("short trace index mapping");
00392 return;
00393 }
00394 tmap = (trace_index_mapping_t *)buf;
00395
00396 prev = &new_trace_types;
00397 for (tptr = new_trace_types; tptr; tptr = tptr -> next) {
00398 len = strlen (tptr -> name);
00399 if (len == length - TRACE_INDEX_MAPPING_SIZE &&
00400 !memcmp (tptr -> name, tmap -> name, len)) {
00401 tptr -> index = ntohl (tmap -> index);
00402 trace_type_stash (tptr);
00403 *prev = tptr -> next;
00404 return;
00405 }
00406 prev = &tptr -> next;
00407 }
00408
00409 log_error ("No registered trace type for type name %.*s",
00410 (int)length - TRACE_INDEX_MAPPING_SIZE, tmap -> name);
00411 return;
00412 }
00413
00414 void trace_index_stop_tracing (trace_type_t *ttype) { }
00415
00416 void trace_replay_init (void)
00417 {
00418 trace_playback_flag = 1;
00419 }
00420
00421 void trace_file_replay (const char *filename)
00422 {
00423 tracepacket_t *tpkt = NULL;
00424 int status;
00425 char *buf = NULL;
00426 unsigned buflen;
00427 unsigned bufmax = 0;
00428 trace_type_t *ttype = NULL;
00429 isc_result_t result;
00430 int len;
00431
00432 traceinfile = fopen (filename, "re");
00433 if (!traceinfile) {
00434 log_error("Can't open tracefile %s: %m", filename);
00435 return;
00436 }
00437 #if defined (HAVE_SETFD)
00438 if (fcntl (fileno(traceinfile), F_SETFD, 1) < 0)
00439 log_error("Can't set close-on-exec on %s: %m", filename);
00440 #endif
00441 status = fread(&tracefile_header, 1,
00442 sizeof tracefile_header, traceinfile);
00443 if (status < sizeof tracefile_header) {
00444 if (ferror(traceinfile))
00445 log_error("Error reading trace file header: %m");
00446 else
00447 log_error("Short read on trace file header: %d %ld.",
00448 status, (long)(sizeof tracefile_header));
00449 goto out;
00450 }
00451 tracefile_header.magic = ntohl(tracefile_header.magic);
00452 tracefile_header.version = ntohl(tracefile_header.version);
00453 tracefile_header.hlen = ntohl(tracefile_header.hlen);
00454 tracefile_header.phlen = ntohl(tracefile_header.phlen);
00455
00456 if (tracefile_header.magic != TRACEFILE_MAGIC) {
00457 log_error("%s: not a dhcp trace file.", filename);
00458 goto out;
00459 }
00460 if (tracefile_header.version > TRACEFILE_VERSION) {
00461 log_error ("tracefile version %ld > current %ld.",
00462 (long int)tracefile_header.version,
00463 (long int)TRACEFILE_VERSION);
00464 goto out;
00465 }
00466 if (tracefile_header.phlen < sizeof *tpkt) {
00467 log_error("tracefile packet size too small - %ld < %ld",
00468 (long int)tracefile_header.phlen,
00469 (long int)sizeof *tpkt);
00470 goto out;
00471 }
00472 len = (sizeof tracefile_header) - tracefile_header.hlen;
00473 if (len < 0) {
00474 log_error("tracefile header size too small - %ld < %ld",
00475 (long int)tracefile_header.hlen,
00476 (long int)sizeof tracefile_header);
00477 goto out;
00478 }
00479 if (len > 0) {
00480 status = fseek(traceinfile, (long)len, SEEK_CUR);
00481 if (status < 0) {
00482 log_error("can't seek past header: %m");
00483 goto out;
00484 }
00485 }
00486
00487 tpkt = dmalloc((unsigned)tracefile_header.phlen, MDL);
00488 if (tpkt == NULL) {
00489 log_error ("can't allocate trace packet header.");
00490 goto out;
00491 }
00492
00493 while ((result = trace_get_next_packet(&ttype, tpkt, &buf, &buflen,
00494 &bufmax)) == ISC_R_SUCCESS) {
00495 (*ttype->have_packet)(ttype, tpkt->length, buf);
00496 ttype = NULL;
00497 }
00498 out:
00499 fclose(traceinfile);
00500 if (buf != NULL)
00501 dfree(buf, MDL);
00502 if (tpkt != NULL)
00503 dfree(tpkt, MDL);
00504 }
00505
00506
00507
00508
00509
00510 isc_result_t trace_get_next_packet (trace_type_t **ttp,
00511 tracepacket_t *tpkt,
00512 char **buf, unsigned *buflen,
00513 unsigned *bufmax)
00514 {
00515 trace_type_t *ttype;
00516 unsigned paylen;
00517 int status, curposok = 0;
00518 fpos_t curpos;
00519
00520 while(1) {
00521 curposok = 0;
00522 status = fgetpos(traceinfile, &curpos);
00523 if (status < 0) {
00524 log_error("Can't save tracefile position: %m");
00525 } else {
00526 curposok = 1;
00527 }
00528
00529 status = fread(tpkt, 1, (size_t)tracefile_header.phlen,
00530 traceinfile);
00531 if (status < tracefile_header.phlen) {
00532 if (ferror(traceinfile))
00533 log_error("Error reading trace packet header: "
00534 "%m");
00535 else if (status == 0)
00536 return ISC_R_EOF;
00537 else
00538 log_error ("Short read on trace packet header:"
00539 " %ld %ld.",
00540 (long int)status,
00541 (long int)tracefile_header.phlen);
00542 return DHCP_R_PROTOCOLERROR;
00543 }
00544
00545
00546 tpkt->type_index = ntohl(tpkt -> type_index);
00547 tpkt->length = ntohl(tpkt -> length);
00548 tpkt->when = ntohl(tpkt -> when);
00549
00550
00551 if (tpkt->type_index < trace_type_count &&
00552 trace_types[tpkt->type_index])
00553 ttype = trace_types[tpkt->type_index];
00554 else {
00555 log_error ("Trace packet with unknown index %ld",
00556 (long int)tpkt->type_index);
00557 return DHCP_R_PROTOCOLERROR;
00558 }
00559
00560
00561
00562
00563
00564
00565
00566
00567
00568
00569
00570
00571
00572 if ((ttp != NULL) && (*ttp == NULL) &&
00573 (tpkt->when != cur_tv.tv_sec) &&
00574 (trace_set_time_hook != NULL)) {
00575 if (curposok == 0) {
00576 log_error("no curpos for fsetpos in "
00577 "tracefile");
00578 return DHCP_R_PROTOCOLERROR;
00579 }
00580
00581 status = fsetpos(traceinfile, &curpos);
00582 if (status < 0) {
00583 log_error("fsetpos in tracefile failed: %m");
00584 return DHCP_R_PROTOCOLERROR;
00585 }
00586
00587 (*trace_set_time_hook) (tpkt->when);
00588 continue;
00589 }
00590 break;
00591 }
00592
00593
00594
00595 if (ttp && *ttp && ttype != *ttp) {
00596 log_error ("Read packet type %s when expecting %s",
00597 ttype -> name, (*ttp) -> name);
00598 status = fsetpos (traceinfile, &curpos);
00599 if (status < 0) {
00600 log_error ("fsetpos in tracefile failed: %m");
00601 return DHCP_R_PROTOCOLERROR;
00602 }
00603 return ISC_R_UNEXPECTEDTOKEN;
00604 }
00605
00606 paylen = tpkt -> length;
00607 if (paylen % 8)
00608 paylen += 8 - (tpkt -> length % 8);
00609 if (paylen > (*bufmax)) {
00610 if ((*buf))
00611 dfree ((*buf), MDL);
00612 (*bufmax) = ((paylen + 1023) & ~1023U);
00613 (*buf) = dmalloc ((*bufmax), MDL);
00614 if (!(*buf)) {
00615 log_error ("Can't allocate input buffer sized %d",
00616 (*bufmax));
00617 return ISC_R_NOMEMORY;
00618 }
00619 }
00620
00621 status = fread ((*buf), 1, paylen, traceinfile);
00622 if (status < paylen) {
00623 if (ferror (traceinfile))
00624 log_error ("Error reading trace payload: %m");
00625 else
00626 log_error ("Short read on trace payload: %d %d.",
00627 status, paylen);
00628 return DHCP_R_PROTOCOLERROR;
00629 }
00630
00631
00632 *buflen = tpkt -> length;
00633
00634 if (ttp)
00635 *ttp = ttype;
00636 return ISC_R_SUCCESS;
00637 }
00638
00639 isc_result_t trace_get_packet (trace_type_t **ttp,
00640 unsigned *buflen, char **buf)
00641 {
00642 tracepacket_t *tpkt;
00643 unsigned bufmax = 0;
00644 isc_result_t status;
00645
00646 if (!buf || *buf)
00647 return DHCP_R_INVALIDARG;
00648
00649 tpkt = dmalloc ((unsigned)tracefile_header.phlen, MDL);
00650 if (!tpkt) {
00651 log_error ("can't allocate trace packet header.");
00652 return ISC_R_NOMEMORY;
00653 }
00654
00655 status = trace_get_next_packet (ttp, tpkt, buf, buflen, &bufmax);
00656
00657 dfree (tpkt, MDL);
00658 return status;
00659 }
00660
00661
00662
00663
00664
00665
00666 isc_result_t trace_get_file (trace_type_t *ttype,
00667 const char *filename, unsigned *len, char **buf)
00668 {
00669 fpos_t curpos;
00670 unsigned max = 0;
00671 tracepacket_t *tpkt;
00672 int status;
00673 isc_result_t result;
00674
00675
00676 if (!buf || !len || *buf)
00677 return DHCP_R_INVALIDARG;
00678
00679
00680 status = fgetpos (traceinfile, &curpos);
00681 if (status < 0)
00682 log_error ("Can't save tracefile position: %m");
00683
00684 tpkt = dmalloc ((unsigned)tracefile_header.phlen, MDL);
00685 if (!tpkt) {
00686 log_error ("can't allocate trace packet header.");
00687 return ISC_R_NOMEMORY;
00688 }
00689
00690 result = trace_get_next_packet (&ttype, tpkt, buf, len, &max);
00691
00692 dfree (tpkt, MDL);
00693 if (result != ISC_R_SUCCESS) {
00694 if (*buf) {
00695 dfree (*buf, MDL);
00696 *buf = NULL;
00697 }
00698 return result;
00699 }
00700
00701
00702 if (strcmp (filename, *buf)) {
00703 log_error ("Read file %s when expecting %s", *buf, filename);
00704 dfree (*buf, MDL);
00705 *buf = NULL;
00706
00707 status = fsetpos (traceinfile, &curpos);
00708 if (status < 0) {
00709 log_error ("fsetpos in tracefile failed: %m");
00710 return DHCP_R_PROTOCOLERROR;
00711 }
00712 return ISC_R_UNEXPECTEDTOKEN;
00713 }
00714
00715 return ISC_R_SUCCESS;
00716 }
00717 #endif