/* * Copyright (c) 2023 joshua stein * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ #include #include #include #include "ipdb.h" #include "logger.h" #include "tcp.h" /* for long2ip/ip2long */ #include "util.h" struct ipdb_file * ipdb_open(char *filename) { struct ipdb_file *ipdb; size_t size; short error, fh; CtoPstr(filename); error = FSOpen(filename, 0, &fh); PtoCstr(filename); if (error) { logger_printf("[ipdb] Failed opening database %s: %d", filename, err); return NULL; } ipdb = xmalloc(sizeof(struct ipdb_file)); if (ipdb == NULL) { logger_printf("[ipdb] Failed malloc"); goto bail; } ipdb->fh = fh; SetFPos(ipdb->fh, fsFromLEOF, 0); GetFPos(ipdb->fh, &ipdb->fsize); SetFPos(ipdb->fh, fsFromStart, 0); if (ipdb->fsize == 0) { logger_printf("[ipdb] Empty database file %s", filename); goto bail; } size = sizeof(ipdb->starts); error = FSRead(ipdb->fh, &size, &ipdb->starts); if (error) { logger_printf("[ipdb] Error reading network table from %s: %d", filename, error); goto bail; } logger_printf("[ipdb] Loaded database %s of size %lu", filename, ipdb->fsize); return ipdb; bail: FSClose(ipdb->fh); if (ipdb != NULL) xfree(&ipdb); return NULL; } void ipdb_close(struct ipdb_file **ipdbp) { struct ipdb_file *ipdb = (struct ipdb_file *)*ipdbp; FSClose(ipdb->fh); xfree(ipdbp); } char * ipdb_lookup(struct ipdb_file *ipdb, u_int32_t ip) { size_t size; u_int32_t range[3], net_start, net_end, start, end, mid, last_mid, pos; short error; unsigned char ip_o[4], locsize, *tmp; char *loc; tmp = (unsigned char *)&ip; ip_o[0] = tmp[0]; ip_o[1] = tmp[1]; ip_o[2] = tmp[2]; ip_o[3] = tmp[3]; net_start = ipdb->starts[ip_o[0]]; if (net_start == 0) return NULL; net_end = 0; if (ip_o[0] != 255) net_end = ipdb->starts[ip_o[0] + 1]; if (net_end == 0) net_end = ipdb->fsize; start = net_start; end = net_end; pos = 0; last_mid = 0; for (;;) { mid = start + ((end - start) / 2); /* align */ mid -= ((mid - net_start) % (sizeof(u_int32_t) * 3)); if (mid == last_mid) break; last_mid = mid; SetFPos(ipdb->fh, fsFromStart, mid); size = sizeof(range); error = FSRead(ipdb->fh, &size, &range); if (error) { logger_printf("[ipdb] Error reading from database: %d", error); return NULL; } if (ip >= range[0] && ip <= range[1]) { pos = range[2]; break; } if (ip < range[0]) /* too high, clamp to [start, mid] */ end = mid; else if (ip > range[1]) /* too low, clamp to [mid, end] */ start = mid; if (mid < net_start || mid > net_end) break; } if (!pos) return NULL; SetFPos(ipdb->fh, fsFromStart, pos); size = 1; error = FSRead(ipdb->fh, &size, &locsize); if (error) { logger_printf("[ipdb] Error reading from database: %d", error); return NULL; } loc = xmalloc(locsize + 1); if (loc == NULL) { logger_printf("[ipdb] Out of memory"); return NULL; } size = locsize; error = FSRead(ipdb->fh, &size, loc); if (error) { logger_printf("[ipdb] Error reading from database: %d", error); xfree(&loc); return NULL; } loc[locsize] = '\0'; return loc; }