Download
jcs
/subtext
/ipdb.c
(View History)
jcs ipdb: Log when the database has been loaded | Latest amendment: 555 on 2023-11-21 |
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 | logger_printf("[ipdb] Loaded database %s of size %lu", filename, |
66 | ipdb->fsize); |
67 | |
68 | return ipdb; |
69 | |
70 | bail: |
71 | FSClose(ipdb->fh); |
72 | if (ipdb != NULL) |
73 | xfree(&ipdb); |
74 | return NULL; |
75 | } |
76 | |
77 | void |
78 | ipdb_close(struct ipdb_file **ipdbp) |
79 | { |
80 | struct ipdb_file *ipdb = (struct ipdb_file *)*ipdbp; |
81 | |
82 | FSClose(ipdb->fh); |
83 | xfree(ipdbp); |
84 | } |
85 | |
86 | char * |
87 | ipdb_lookup(struct ipdb_file *ipdb, u_int32_t ip) |
88 | { |
89 | size_t size; |
90 | u_int32_t range[3], net_start, net_end, start, end, mid, last_mid, pos; |
91 | short error; |
92 | unsigned char ip_o[4], locsize, *tmp; |
93 | char *loc; |
94 | |
95 | tmp = (unsigned char *)&ip; |
96 | ip_o[0] = tmp[0]; |
97 | ip_o[1] = tmp[1]; |
98 | ip_o[2] = tmp[2]; |
99 | ip_o[3] = tmp[3]; |
100 | |
101 | net_start = ipdb->starts[ip_o[0]]; |
102 | if (net_start == 0) |
103 | return NULL; |
104 | |
105 | net_end = 0; |
106 | if (ip_o[0] != 255) |
107 | net_end = ipdb->starts[ip_o[0] + 1]; |
108 | if (net_end == 0) |
109 | net_end = ipdb->fsize; |
110 | |
111 | start = net_start; |
112 | end = net_end; |
113 | pos = 0; |
114 | last_mid = 0; |
115 | |
116 | for (;;) { |
117 | mid = start + ((end - start) / 2); |
118 | /* align */ |
119 | mid -= ((mid - net_start) % (sizeof(u_int32_t) * 3)); |
120 | if (mid == last_mid) |
121 | break; |
122 | last_mid = mid; |
123 | |
124 | SetFPos(ipdb->fh, fsFromStart, mid); |
125 | size = sizeof(range); |
126 | error = FSRead(ipdb->fh, &size, &range); |
127 | if (error) { |
128 | logger_printf("[ipdb] Error reading from database: %d", error); |
129 | return NULL; |
130 | } |
131 | |
132 | if (ip >= range[0] && ip <= range[1]) { |
133 | pos = range[2]; |
134 | break; |
135 | } |
136 | |
137 | if (ip < range[0]) |
138 | /* too high, clamp to [start, mid] */ |
139 | end = mid; |
140 | else if (ip > range[1]) |
141 | /* too low, clamp to [mid, end] */ |
142 | start = mid; |
143 | |
144 | if (mid < net_start || mid > net_end) |
145 | break; |
146 | } |
147 | |
148 | if (!pos) |
149 | return NULL; |
150 | |
151 | SetFPos(ipdb->fh, fsFromStart, pos); |
152 | size = 1; |
153 | error = FSRead(ipdb->fh, &size, &locsize); |
154 | if (error) { |
155 | logger_printf("[ipdb] Error reading from database: %d", error); |
156 | return NULL; |
157 | } |
158 | |
159 | loc = xmalloc(locsize + 1); |
160 | if (loc == NULL) { |
161 | logger_printf("[ipdb] Out of memory"); |
162 | return NULL; |
163 | } |
164 | size = locsize; |
165 | error = FSRead(ipdb->fh, &size, loc); |
166 | if (error) { |
167 | logger_printf("[ipdb] Error reading from database: %d", error); |
168 | xfree(&loc); |
169 | return NULL; |
170 | } |
171 | loc[locsize] = '\0'; |
172 | |
173 | return loc; |
174 | } |