/* Distributed Checksum Clearinghouse checksum inverter * * --C-LICENSE-- * $Revision: 1.20 $ */ #include "dcc_ck.h" #include "dcc_xhdr.h" #include static DCC_EMSG dcc_emsg; static int verbose; #define LOOP_LIM_V 0x100000 /* progress report every /8 */ #define LOOP_LIM (LOOP_LIM_V*32) static u_char have_sum; static DCC_SUM sum; static in_addr_t begin, end; static const char *cachedir; #define LOG_NUM_FILES 12 #define NUM_FILES (1<b[0])<<4) + ((s)->b[1]>>4)) typedef struct { char magic[64]; # define CACHE_MAGIC "ck2ip cache file version 1" char name[8]; } CACHE_HDR; static int save_cksum(DCC_EMSG *, WF *, DCC_CK_TYPES, DCC_SUM *, DCC_TGTS); static void direct(void); static void build_cache(void); static void search_cache(void); static void DCC_NORET usage(void) { fprintf(stderr, "usage: [-vN] [-D cachedir]" " [-B IPv4-begin] [-E IPv4-end] [-C 'h1 h2 h3 h4']\n"); exit(1); } int main(int argc, char **argv) { u_char have_range, new_cache; int error, i; dcc_syslog_init(0, argv[0], 0); dup2(1, 2); /* put error messages in context */ have_range = 0; new_cache = 0; begin = 0; end = -1; while ((i = getopt(argc, argv, "vND:B:E:C:")) != -1) { switch (i) { case 'v': ++verbose; break; case 'N': new_cache = 1; break; case 'D': cachedir = optarg; break; case 'B': have_range = 1; dcc_host_lock(); if (!dcc_get_host(optarg, DCC_GETH_V4, &error)) { fprintf(stderr, "\"-B %s\": %s\n", optarg, H_ERROR_STR1(error)); exit(1); } begin = ntohl(dcc_hostaddrs[0].ipv4.sin_addr.s_addr); if (begin > end) { fprintf(stderr, "beginning after end\n"); exit(1); } dcc_host_unlock(); break; case 'E': have_range = 1; dcc_host_lock(); if (!dcc_get_host(optarg, DCC_GETH_V4, &error)) { fprintf(stderr, "\"-E %s\": %s\n", optarg, H_ERROR_STR1(error)); exit(1); } end = ntohl(dcc_hostaddrs[0].ipv4.sin_addr.s_addr); if (begin > end) { fprintf(stderr, "end before beginning\n"); exit(1); } dcc_host_unlock(); break; case 'C': if (0 >= dcc_parse_hex_ck(&dcc_emsg, 0, DCC_XHDR_TYPE_IP, DCC_CK_IP, optarg, 0, &save_cksum)) { fprintf(stderr, "%s\n", dcc_emsg.c); exit(1); } have_sum = 1; break; default: usage(); } } argc -= optind; argv += optind; if (argc != 0) usage(); if (new_cache) { if (!cachedir) { fprintf(stderr, "-N (new cache) requires -D\n"); if (!have_sum) exit(1); new_cache = 0; } } if (!have_sum && !new_cache) { fprintf(stderr, "-C required except with -N (new cache)\n"); usage(); } if (cachedir && have_range) fprintf(stderr, "-D is incompatible with -B and -E\n"); dcc_clnt_unthread_init(); if (!cachedir || have_range) { direct(); } else if (new_cache) { build_cache(); } else { search_cache(); } exit(EX_OK); } static int save_cksum(DCC_EMSG *emsg DCC_UNUSED, WF *wf DCC_UNUSED, DCC_CK_TYPES type DCC_UNUSED, DCC_SUM *new_sum, DCC_TGTS tgts DCC_UNUSED) { sum = *new_sum; return 1; } /* immediate brute force search */ static void direct(void) { struct in_addr addr4; struct in6_addr addr6; DCC_SUM test_sum; char abuf[64]; time_t now; char tbuf[12]; addr4.s_addr = htonl(0); dcc_ipv4toipv6(&addr6, addr4); do { addr6.s6_addr32[3] = htonl(begin); ipv6tock(&test_sum, &addr6); if (!memcmp(&test_sum, &sum, sizeof(test_sum))) { printf("found %s\n", dcc_trim_ffff(dcc_ipv6tostr(abuf, sizeof(abuf), &addr6))); return; } if (verbose ? (begin % (256*256) == 0xffff) : (begin % (256*256*256) == 0xffffff)) { now = time(0); strftime(tbuf, sizeof(tbuf), "%X", localtime(&now)); printf(" %s\t%s\n", dcc_trim_ffff(dcc_ipv6tostr(abuf, sizeof(abuf), &addr6)), tbuf); } } while (begin++ != end); printf("not found\n"); } static void cache_write(int fd, const void *buf, int buf_len, int cnum, const char *msg) { char cname[CNAME_LEN+1]; int serrno, i; i = write(fd, buf, buf_len); if (i == buf_len) return; serrno = errno; if (i < 0) fprintf(stderr, "write(%s %s/"CNAME_PAT"): %s\n", msg, cachedir, cnum, strerror(errno)); else fprintf(stderr, "write(%s %s/%s)=%d\n", msg, cachedir, cname, i); /* do not leave the file system overflowing */ if (i >= 0 || serrno == ENOSPC) { for (i = 0; i <= cnum; ++i) { snprintf(cname, sizeof(cname), CNAME_PAT, i); unlink(cname); } rmdir(cachedir); } exit(1); } /* build a directory of cache files */ static void build_cache(void) { char cname[CNAME_LEN+1]; in_addr_t a; struct in_addr addr4; struct in6_addr addr6; DCC_SUM test_sum; CACHE_HDR hdr; void *zeros; u_int64_t avg_file_size; int zero_len; typedef struct { int fd; u_int len; u_int total; # define BUF_ADDRS (1024*32) in_addr_t addrs[BUF_ADDRS]; } BUF; BUF *b, *bufs; char abuf[64]; time_t now; char tbuf[12]; int cnum; if (0 == chdir(cachedir)) { fprintf(stderr, "%s already exists\n", cachedir); exit(1); } if (0 > mkdir(cachedir, 0777)) { fprintf(stderr, "mkdir(%s): %s\n", cachedir, strerror(errno)); exit(1); } if (0 > chdir(cachedir)) { fprintf(stderr, "%s: %s\n", cachedir, strerror(errno)); exit(1); } /* create the files empty and generally contiguous */ bufs = malloc(sizeof(BUF)*NUM_FILES); memset(bufs, 0, sizeof(BUF)*NUM_FILES); avg_file_size = 1; avg_file_size <<= 32; avg_file_size /= NUM_FILES; /* average file size */ zero_len = ((u_int)avg_file_size) * sizeof(in_addr_t); zeros = malloc(zero_len); memset(zeros, 0, zero_len); for (cnum = 0, b = bufs; cnum < NUM_FILES; ++cnum, ++b) { snprintf(cname, sizeof(cname), CNAME_PAT, cnum); b->fd = open(cname, O_WRONLY | O_CREAT, 0666); if (b->fd < 0) { fprintf(stderr, "open(%s/%s): %s\n", cachedir, cname, strerror(errno)); exit(1); } cache_write(b->fd, zeros, zero_len, cnum, "zeros"); if (sizeof(hdr) != lseek(b->fd, sizeof(hdr), SEEK_SET)) { fprintf(stderr, "lseek(%d %s/%s): %s", ISZ(hdr), cachedir, cname, strerror(errno)); exit(1); } b->total = sizeof(hdr); } free(zeros); printf("empty files created in %s\n", cachedir); /* generate the data consisting of lists of IPv4 addresses */ addr4.s_addr = htonl(0); dcc_ipv4toipv6(&addr6, addr4); a = 0; do { addr6.s6_addr32[3] = htonl(a); ipv6tock(&test_sum, &addr6); cnum = SUM2CNUM(&test_sum); b = &bufs[cnum]; b->addrs[b->len] = addr6.s6_addr32[3]; if (++b->len == BUF_ADDRS) { cache_write(b->fd, b->addrs, sizeof(b->addrs), cnum, "addresses"); b->total += sizeof(b->addrs); b->len = 0; } /* announce the completion of some addresses */ if (verbose ? (a % (256*256*16) == 0xfffff) : (a % (256*256*256) == 0xffffff)) { now = time(0); strftime(tbuf, sizeof(tbuf), "%X", localtime(&now)); printf(" %s\t%s\n", dcc_trim_ffff(dcc_ipv6tostr(abuf, sizeof(abuf), &addr6)), tbuf); } } while (a++ != 0xffffffff); /* flush the buffers and write the magic string in each file */ memset(&hdr, 0, sizeof(hdr)); BUFCPY(hdr.magic, CACHE_MAGIC); for (cnum = 0, b = bufs; cnum < NUM_FILES; ++cnum, ++b) { snprintf(hdr.name, sizeof(hdr.name), CNAME_PAT, cnum); if (b->len != 0) { cache_write(b->fd, b->addrs, b->len*sizeof(b->addrs[0]), cnum, "addresses"); b->total += b->len*sizeof(b->addrs[0]); b->len = 0; } if (0 > ftruncate(b->fd, b->total)) { fprintf(stderr, "ftruncate(%s/%s): %s", cachedir, hdr.name, strerror(errno)); exit(1); } if (0 != lseek(b->fd, 0, SEEK_SET)) { fprintf(stderr, "lseek(0 %s/%s): %s", cachedir, hdr.name, strerror(errno)); exit(1); } cache_write(b->fd, &hdr, sizeof(hdr), cnum, "header"); if (0 > fsync(b->fd)) { fprintf(stderr, "fsync(%s/%s): %s", cachedir, hdr.name, strerror(errno)); exit(1); } if (0 > close(b->fd)) { fprintf(stderr, "close(%s/%s): %s", cachedir, hdr.name, strerror(errno)); exit(1); } } } static void search_cache(void) { char cname[CNAME_LEN+1]; int fd; CACHE_HDR hdr; in_addr_t fbuf[1024*(1024*12/10)]; struct in_addr addr4; struct in6_addr addr6; DCC_SUM test_sum; char abuf[80]; int total, len, i; if (0 > chdir(cachedir)) { fprintf(stderr, "%s: %s\n", cachedir, strerror(errno)); exit(1); } snprintf(cname, sizeof(cname), CNAME_PAT, SUM2CNUM(&sum)); fd = open(cname, O_RDONLY, 0); if (fd < 0) { fprintf(stderr, "%s/%s: %s\n", cachedir, cname, strerror(errno)); exit(1); } i = read(fd, &hdr, sizeof(hdr)); if (i != sizeof(hdr)) { if (i < 0) fprintf(stderr, "read(header %s/%s): %s\n", cachedir, cname, strerror(errno)); else fprintf(stderr, "read(header %s/%s)=%d\n", cachedir, cname, i); exit(1); } if (strncmp(hdr.magic, CACHE_MAGIC, sizeof(hdr.magic))) { fprintf(stderr, "unrecognized magic in %s/%s\n", cachedir, cname); exit(1); } if (strncmp(hdr.name, cname, sizeof(hdr.name))) { fprintf(stderr, "wrong name in %s/%s\n", cachedir, cname); exit(1); } total = 0; for (;;) { len = read(fd, fbuf, sizeof(fbuf)); if (len < 0) { fprintf(stderr, "read(data %s/%s): %s\n", cachedir, cname, strerror(errno)); exit(1); } if (total+len == 0 || len % (sizeof fbuf[0]) != 0) { fprintf(stderr, "%s/%s truncated at %d bytes\n", cachedir, cname, total+len); exit(1); } if (len == 0) { fprintf(stderr, "checksum not found in %s/%s\n", cachedir, cname); exit(1); } total += len; addr4.s_addr = 0; dcc_ipv4toipv6(&addr6, addr4); i = 0; do { addr6.s6_addr32[3] = fbuf[i]; ipv6tock(&test_sum, &addr6); if (!memcmp(&test_sum, &sum, sizeof(test_sum))) { printf("found %s\n", dcc_trim_ffff(dcc_ipv6tostr(abuf, sizeof(abuf), &addr6))); return; } } while (++i, (len -= sizeof(fbuf[0])) >0); } }