AmendHub

Download:

jcs

/

subtext

/

amendments

/

509

ipdb: Add IP geolocation database lookup module


jcs made amendment 509 about 1 year ago
--- ipdb.c Thu Jun 15 09:14:37 2023 +++ ipdb.c Thu Jun 15 09:14:37 2023 @@ -0,0 +1,171 @@ +/* + * Copyright (c) 2023 joshua stein <jcs@jcs.org> + * + * 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 <stdio.h> +#include <stdlib.h> +#include <string.h> +#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; + } + + 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; +} --- ipdb.h Wed Jun 14 21:02:27 2023 +++ ipdb.h Wed Jun 14 21:02:27 2023 @@ -0,0 +1,58 @@ +/* + * Copyright (c) 2023 joshua stein <jcs@jcs.org> + * + * 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. + */ + +/* ipdb database format: + + [uint32_t][0] file offset of network "0.0.0.0/8" + [uint32_t][1] file offset of network "1.0.0.0/8" + ... + [uint32_t][255] file offset of network "255.0.0.0/8" + [uint8_t] location 0 length + [char][length] location 0 + [uint8_t] location 1 length + [char][length] location 1 + ... + [uint32_t] network 0 start (1.0.0.0) + [uint32_t] network 0 end (1.0.0.255) + [uint32_t] network 0 location pointer + [uint32_t] network 1 start (1.0.1.0) + [uint32_t] network 1 end (1.0.1.255) + [uint32_t] network 1 location pointer + ... + + For an ip "5.6.7.8", look up table[5] and seek there, then do a binary + search between that location and that of table[6] (or end of file if + 255). + + If the table location points to 0, that network is not in the file. +*/ + +#ifndef __IPDB_H__ +#define __IPDB_H__ + +#include "util.h" + +struct ipdb_file { + short fh; + size_t fsize; + u_int32_t starts[256]; +}; + +struct ipdb_file * ipdb_open(char *filename); +void ipdb_close(struct ipdb_file **ipdbp); +char * ipdb_lookup(struct ipdb_file *ipdb, u_int32_t ip); + +#endif