AmendHub

Download

jcs

/

subtext

/

ipdb.c

 

(View History)

jcs   ipdb: Add IP geolocation database lookup module Latest amendment: 509 on 2023-06-15

1 /*
2 * Copyright (c) 2023 joshua stein <jcs@jcs.org>
3 *
4 * Permission to use, copy, modify, and distribute this software for any
5 * purpose with or without fee is hereby granted, provided that the above
6 * copyright notice and this permission notice appear in all copies.
7 *
8 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
9 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
10 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
11 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
12 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
13 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
14 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
15 */
16
17 #include <stdio.h>
18 #include <stdlib.h>
19 #include <string.h>
20 #include "ipdb.h"
21 #include "logger.h"
22 #include "tcp.h" /* for long2ip/ip2long */
23 #include "util.h"
24
25 struct ipdb_file *
26 ipdb_open(char *filename)
27 {
28 struct ipdb_file *ipdb;
29 size_t size;
30 short error, fh;
31
32 CtoPstr(filename);
33 error = FSOpen(filename, 0, &fh);
34 PtoCstr(filename);
35 if (error) {
36 logger_printf("[ipdb] Failed opening database %s: %d", filename,
37 err);
38 return NULL;
39 }
40
41 ipdb = xmalloc(sizeof(struct ipdb_file));
42 if (ipdb == NULL) {
43 logger_printf("[ipdb] Failed malloc");
44 goto bail;
45 }
46
47 ipdb->fh = fh;
48 SetFPos(ipdb->fh, fsFromLEOF, 0);
49 GetFPos(ipdb->fh, &ipdb->fsize);
50 SetFPos(ipdb->fh, fsFromStart, 0);
51
52 if (ipdb->fsize == 0) {
53 logger_printf("[ipdb] Empty database file %s", filename);
54 goto bail;
55 }
56
57 size = sizeof(ipdb->starts);
58 error = FSRead(ipdb->fh, &size, &ipdb->starts);
59 if (error) {
60 logger_printf("[ipdb] Error reading network table from %s: %d",
61 filename, error);
62 goto bail;
63 }
64
65 return ipdb;
66
67 bail:
68 FSClose(ipdb->fh);
69 if (ipdb != NULL)
70 xfree(&ipdb);
71 return NULL;
72 }
73
74 void
75 ipdb_close(struct ipdb_file **ipdbp)
76 {
77 struct ipdb_file *ipdb = (struct ipdb_file *)&ipdbp;
78
79 FSClose(ipdb->fh);
80 xfree(ipdbp);
81 }
82
83 char *
84 ipdb_lookup(struct ipdb_file *ipdb, u_int32_t ip)
85 {
86 size_t size;
87 u_int32_t range[3], net_start, net_end, start, end, mid, last_mid, pos;
88 short error;
89 unsigned char ip_o[4], locsize, *tmp;
90 char *loc;
91
92 tmp = (unsigned char *)&ip;
93 ip_o[0] = tmp[0];
94 ip_o[1] = tmp[1];
95 ip_o[2] = tmp[2];
96 ip_o[3] = tmp[3];
97
98 net_start = ipdb->starts[ip_o[0]];
99 if (net_start == 0)
100 return NULL;
101
102 net_end = 0;
103 if (ip_o[0] != 255)
104 net_end = ipdb->starts[ip_o[0] + 1];
105 if (net_end == 0)
106 net_end = ipdb->fsize;
107
108 start = net_start;
109 end = net_end;
110 pos = 0;
111 last_mid = 0;
112
113 for (;;) {
114 mid = start + ((end - start) / 2);
115 /* align */
116 mid -= ((mid - net_start) % (sizeof(u_int32_t) * 3));
117 if (mid == last_mid)
118 break;
119 last_mid = mid;
120
121 SetFPos(ipdb->fh, fsFromStart, mid);
122 size = sizeof(range);
123 error = FSRead(ipdb->fh, &size, &range);
124 if (error) {
125 logger_printf("[ipdb] Error reading from database: %d", error);
126 return NULL;
127 }
128
129 if (ip >= range[0] && ip <= range[1]) {
130 pos = range[2];
131 break;
132 }
133
134 if (ip < range[0])
135 /* too high, clamp to [start, mid] */
136 end = mid;
137 else if (ip > range[1])
138 /* too low, clamp to [mid, end] */
139 start = mid;
140
141 if (mid < net_start || mid > net_end)
142 break;
143 }
144
145 if (!pos)
146 return NULL;
147
148 SetFPos(ipdb->fh, fsFromStart, pos);
149 size = 1;
150 error = FSRead(ipdb->fh, &size, &locsize);
151 if (error) {
152 logger_printf("[ipdb] Error reading from database: %d", error);
153 return NULL;
154 }
155
156 loc = xmalloc(locsize + 1);
157 if (loc == NULL) {
158 logger_printf("[ipdb] Out of memory");
159 return NULL;
160 }
161 size = locsize;
162 error = FSRead(ipdb->fh, &size, loc);
163 if (error) {
164 logger_printf("[ipdb] Error reading from database: %d", error);
165 xfree(&loc);
166 return NULL;
167 }
168 loc[locsize] = '\0';
169
170 return loc;
171 }