/* doscan - Denial Of Service Capable Auditing of Networks * Copyright (C) 2003 Florian Weimer * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #include "config.h" #include "opt.h" #include "results.h" #include #include #include #include #include #include #include #include typedef struct { ticks_t timestamp; ipv4_t host; int error; const char *banner; } result_t; result_t *results = 0; unsigned allocated; unsigned used; typedef struct format_t { void (*printer) (const struct format_t *, const result_t *); char *data; } format_t; format_t *format_list; static void format_host (const format_t *, const result_t *); static void format_host_name (const format_t *, const result_t *); static void format_banner (const format_t *, const result_t *); static void format_error (const format_t *, const result_t *); static void format_errno (const format_t *, const result_t *); static void format_time_relative (const format_t *, const result_t *); static void format_time_local (const format_t *, const result_t *); static void format_time_utc (const format_t *, const result_t *); static void format_print_data (const format_t *, const result_t *); static void grow_results (void); static const char *quote (const char *, size_t); static int result_cmp (const void *, const void *); static void results_print_one (const result_t *); static const char *error_as_string (int error); static enum output_style { SORT_BY_HOST, UNSORTED } output_style = SORT_BY_HOST; void results_style (const char *style) { if (strcasecmp (style, "sort-by-host") == 0) { output_style = SORT_BY_HOST; return; } if (strcasecmp (style, "unsorted") == 0) { output_style = UNSORTED; return; } fprintf (stderr, "%s: unknown output style '%s'\n", opt_program, style); exit (EXIT_FAILURE); } void results_format (const char *format) { const char *p; format_t *f; /* Allocate the formatting descriptor array. */ format_list = new format_t[strlen (format) + 1]; p = format; f = format_list; while (*p) { if (*p == '%') { p++; switch (*p) { case '\0': fprintf (stderr, "%s: trailing '%%' in --output argument", opt_program); exit (EXIT_FAILURE); break; case 'a': f->printer = format_host; f->data = 0; f++; break; case 'b': f->printer = format_banner; f->data = 0; f++; break; case 'e': f->printer = format_error; f->data = 0; f++; break; case 'E': f->printer = format_errno; f->data = 0; f++; break; case 'n': f->printer = format_host_name; f->data = 0; f++; break; case 'N': f->printer = format_print_data; f->data = strdup("\n"); f++; break; case 'r': f->printer = format_time_relative; f->data = 0; f++; break; case 't': f->printer = format_time_local; f->data = 0; f++; break; case 'T': f->printer = format_time_utc; f->data = 0; f++; break; case '%': f->printer = format_print_data; f->data = strdup("%"); f++; break; default: fprintf (stderr, "%s: illegal pattern '%%%c' in --output argument", opt_program, *p); exit (EXIT_FAILURE); } p++; } else { /* Not a pattern, but a string. */ const char *end = p; while ((*end != '\0') && (*end != '%')) { end++; } f->printer = format_print_data; f->data = new char[end - p + 1]; memcpy (f->data, p, end - p); f->data[end - p] = '\0'; f++; p = end; } } f->printer = format_print_data; f->data = "\n"; f++; f->printer = 0; f->data = 0; } void results_add (ticks_t timestamp, ipv4_t host, int error, const char *data, size_t length) { grow_results(); results[used].timestamp = timestamp; results[used].host = host; results[used].error = error; if (data) { results[used].banner = quote (data, length); } else { results[used].banner = ""; } if (output_style == UNSORTED) { results_print_one (results + used); } used++; } void results_add (ipv4_t host, int error, const std::string& data) { results_add (ticks_get_cached(), host, error, data.data(), data.size()); } void results_add (ipv4_t host, const std::string& data) { results_add (ticks_get_cached(), host, 0, data.data(), data.size()); } void results_add_unquoted (ipv4_t host, int error, const std::string& msg) { grow_results(); results[used].timestamp = ticks_get_cached(); results[used].host = host; results[used].error = error; results[used].banner = strdup(msg.c_str()); if (output_style == UNSORTED) { results_print_one (results + used); } used++; } void results_add_unquoted (ipv4_t host, const std::string& msg) { results_add_unquoted(host, 0, msg); } void results_print () { unsigned j; if (output_style == UNSORTED) { return; /* already printed */ } qsort (results, used, sizeof (result_t), result_cmp); for (j = 0; j < used; j++) { results_print_one (results + j); } } unsigned results_count (void) { return used; } static int result_cmp (const void *a, const void *b) { result_t *left = (result_t *)a; result_t *right = (result_t *)b; if (left->host < right->host) { return -1; } if (left->host > right->host) { return 1; } return 0; } static void grow_results (void) { if (results == 0) { allocated = 256; } else { if (used < allocated) { /* Nothing to do, enough space. */ return; } allocated *= 2; } results = static_cast(realloc (results, allocated * sizeof (result_t))); } static const char * quote (const char *data, size_t length) { const char *source; char *target, *result; char buffer[length * 4 + 1]; unsigned ch; source = data; target = buffer; while (source < (data + length)) { ch = (unsigned char)*source; switch (ch) { case '\t': *(target++) = '\\'; *(target++) = 't'; break; case '\r': *(target++) = '\\'; *(target++) = 'r'; break; case '\n': *(target++) = '\\'; *(target++) = 'n'; break; case '\\': *(target++) = '\\'; *(target++) = '\\'; break; default: if ((ch < ' ') || (ch > '~')) { /* This assumes ASCII. */ *(target++) = '\\'; *(target++) = '0' + ((ch >> 6) & 7); *(target++) = '0' + ((ch >> 3) & 7); *(target++) = '0' + (ch & 7); } else { *(target++) = *source; } } source++; } *(target++) = 0; result = new char[target - buffer]; memcpy (result, buffer, target - buffer); return result; } static void results_print_one (const result_t *result) { const format_t *f = format_list; while (f->printer) { f->printer (f, result); f++; } } static const char * error_as_string (int error) { switch (error) { case 0: return ""; #define X(e) case e: return #e X(EACCES); X(ECONNREFUSED); X(ECONNRESET); X(EHOSTUNREACH); X(ENETUNREACH); X(EPERM); X(EPIPE); X(ETIMEDOUT); #undef X case RESULTS_ERROR_NOMATCH: return "no match"; case RESULTS_ERROR_NODATA: return "no data"; default: return "unknown"; } } static void format_host (const format_t *format, const result_t *result) { ipv4_string_t a; ipv4_address_to_string (result->host, a); printf ("%s", a); } static void format_host_name (const format_t *format, const result_t *result) { struct in_addr in; struct hostent *he; in.s_addr = htonl (result->host); #ifdef GETHOSTBYADDR_ACCEPTS_IN_ADDR he = gethostbyaddr (&in, sizeof (in), AF_INET); #else #ifdef GETHOSTBYADDR_ACCEPTS_CHAR he = gethostbyaddr (reinterpret_cast(&in), sizeof (in), AF_INET); #else #error Type of first argument to gethostbyaddr() is not known. #endif #endif if (he) { printf ("%s", he->h_name); } else { /* No address. */ format_host (format, result); } } static void format_banner (const format_t *format, const result_t *result) { printf ("%s", result->banner); } static void format_error (const format_t *format, const result_t *result) { printf ("%s", error_as_string (result->error)); } static void format_errno (const format_t *format, const result_t *result) { printf ("%d", result->error); } static void format_time_relative (const format_t *format, const result_t *result) { printf ("%u.%03u", result->timestamp / 1000, result->timestamp % 1000); } static void format_time_local (const format_t *format, const result_t *result) { ticks_string_t t; ticks_to_string_local (result->timestamp, t); printf ("%s", t); } static void format_time_utc (const format_t *format, const result_t *result) { ticks_string_t t; ticks_to_string_utc (result->timestamp, t); printf ("%s", t); } static void format_print_data (const format_t *format, const result_t *result) { printf ("%s", format->data); } /* arch-tag: 6748223c-f7aa-4098-b436-4628c61fe74f */