]> jfr.im git - irc/quakenet/newserv.git/blame - rbl/rbl_zonefile.c
LUA: port luadb to dbapi2 to drop postgres dependency
[irc/quakenet/newserv.git] / rbl / rbl_zonefile.c
CommitLineData
67af3857
GB
1#include <string.h>
2#include <stdio.h>
3#include "../core/hooks.h"
4#include "../control/control.h"
5#include "../irc/irc.h"
6#include "../lib/irc_string.h"
7#include "../lib/version.h"
8#include "../core/config.h"
9#include "rbl_zonefile.h"
10
11MODULE_VERSION("");
12
13static int rbl_zf_cmpip(const struct irc_in_addr *a, const struct irc_in_addr *b) {
14 for (int i = 0; i < 8; i++) {
15 if (ntohs(a->in6_16[i]) < ntohs(b->in6_16[i]))
16 return -1;
17 else if (ntohs(a->in6_16[i]) > ntohs(b->in6_16[i]))
18 return 1;
19 }
20
21 return 0;
22}
23
24static int rbl_zf_bsearch(array *entries, struct irc_in_addr *ip, char *message, size_t msglen) {
25 int first, last, mid;
26
27 first = 0;
28 last = entries->cursi - 1;
29 mid = (first + last) / 2;
30
31 while (first <= last) {
32 rbl_zf_entry *ze = &((rbl_zf_entry *)entries->content)[mid];
33
34 if (rbl_zf_cmpip(&ze->ipaddress, ip) < 0 && !ipmask_check(&ze->ipaddress, ip, ze->bits))
35 first = mid + 1;
36 else if (ipmask_check(&ze->ipaddress, ip, ze->bits)) {
37 if (message) {
38 if (ze->message)
39 strncpy(message, ze->message->content, msglen);
40 else
41 message[0] = '\0';
42 }
43
44 return 1;
45 } else
46 last = mid - 1;
47
48 mid = (first + last) / 2;
49 }
50
51 return -1;
52}
53
54static int rbl_zf_lookup(rbl_instance *rbl, struct irc_in_addr *ip, char *message, size_t msglen) {
55 rbl_zf_udata *udata = rbl->udata;
56
57 if (rbl_zf_bsearch(&udata->whitelist, ip, NULL, 0) > 0)
58 return -1;
59
60 return rbl_zf_bsearch(&udata->blacklist, ip, message, msglen);
61}
62
63static void rbl_zf_freeentries(array *entries) {
64 rbl_zf_entry *ze;
65 int i;
66
67 for (i = 0; i < entries->cursi; i++) {
68 ze = &((rbl_zf_entry *)entries->content)[i];
69 freesstring(ze->message);
70 }
71 array_free(entries);
72}
73
74static int rbl_zf_parseentry(rbl_instance *rbl, const char *line) {
75 rbl_zf_udata *udata = rbl->udata;
76 int slot, exempt = 0;
77 char mask[255], message[255];
78 struct irc_in_addr ip;
79 unsigned char bits;
80 rbl_zf_entry *ze;
81
82 if (line[0] == '$' || line[0] == ':')
83 return 0; /* Ignore option lines */
84
85 if (line[0] == '!') {
86 exempt = 1;
87 line++;
88 }
89
90 message[0] = '\0';
91
92 if (sscanf(line, "%s %[^\n]", mask, message) < 1)
93 return -1;
94
95 if (!ipmask_parse(mask, &ip, &bits))
96 return -1;
97
98 if (exempt) {
99 slot = array_getfreeslot(&udata->whitelist);
100 ze = &((rbl_zf_entry *)udata->whitelist.content)[slot];
101 } else {
102 slot = array_getfreeslot(&udata->blacklist);
103 ze = &((rbl_zf_entry *)udata->blacklist.content)[slot];
104 }
105
106 memcpy(&ze->ipaddress, &ip, sizeof(ip));
107 ze->bits = bits;
108 ze->exempt = exempt;
109 ze->message = getsstring(message, 255);
110
111 return 0;
112}
113
114static int rbl_zf_cmpentry(const void *a, const void *b) {
115 const rbl_zf_entry *za = a;
116 const rbl_zf_entry *zb = b;
117
118 return rbl_zf_cmpip(&za->ipaddress, &zb->ipaddress);
119}
120
121static int rbl_zf_refresh(rbl_instance *rbl) {
122 char line[512];
123 rbl_zf_udata *udata = rbl->udata;
124 FILE *fp = fopen(udata->file->content, "r");
125
126 if (!fp)
127 return -1;
128
129 rbl_zf_freeentries(&udata->whitelist);
130 array_init(&udata->whitelist, sizeof(rbl_zf_entry));
131
132 rbl_zf_freeentries(&udata->blacklist);
133 array_init(&udata->blacklist, sizeof(rbl_zf_entry));
134
135 while (!feof(fp)) {
136 if (fgets(line, sizeof(line), fp) == NULL)
137 break;
138
139 if (line[strlen(line) - 1] == '\n')
140 line[strlen(line) - 1] = '\0';
141
142 if (line[strlen(line) - 1] == '\r')
143 line[strlen(line) - 1] = '\0';
144
145 if (line[0] != '\0')
146 rbl_zf_parseentry(rbl, line);
147 }
148
149 fclose(fp);
150
151 qsort(udata->whitelist.content, udata->whitelist.cursi, sizeof(rbl_zf_entry), rbl_zf_cmpentry);
152 qsort(udata->blacklist.content, udata->blacklist.cursi, sizeof(rbl_zf_entry), rbl_zf_cmpentry);
153
154 return 0;
155}
156
157static void rbl_zf_dtor(rbl_instance *rbl) {
158 rbl_zf_udata *udata = rbl->udata;
159 freesstring(udata->file);
160 rbl_zf_freeentries(&udata->whitelist);
161 rbl_zf_freeentries(&udata->blacklist);
162}
163
164static rbl_ops rbl_zonefile_ops = {
165 .lookup = rbl_zf_lookup,
166 .refresh = rbl_zf_refresh,
167 .dtor = rbl_zf_dtor
168};
169
170int rbl_zf_load(const char *name, const char *file) {
171 rbl_zf_udata *udata = malloc(sizeof(*udata));
172 udata->file = getsstring(file, 512);
173 array_init(&udata->whitelist, sizeof(rbl_zf_entry));
174 array_init(&udata->blacklist, sizeof(rbl_zf_entry));
175 return registerrbl(name, &rbl_zonefile_ops, udata);
176}
177
178void _init(void) {
179 array *zfiles;
180
181 zfiles = getconfigitems("rbl_zonefile", "zone");
182 if (!zfiles) {
183 Error("rbl_zonefile", ERR_INFO, "No zonefiles added.");
184 } else {
185 sstring **files = (sstring **)(zfiles->content);
186 int i;
187 for(i=0;i<zfiles->cursi;i++) {
188 char line[512];
189 char *pos;
190
191 strncpy(line, files[i]->content, sizeof(line));
192
193 pos = strchr(line, ',');
194
195 if(!pos) {
196 Error("rbl_zonefile", ERR_INFO, "RBL zonefile line is missing zone path: %s", line);
197 continue;
198 }
199
200 *pos = '\0';
201
202 if (rbl_zf_load(line, pos + 1) < 0)
203 Error("rbl_zonefile", ERR_WARNING, "Failed to load zonefile: %s", pos + 1);
204 }
205 }
206}
207
208void _fini(void) {
209 deregisterrblbyops(&rbl_zonefile_ops);
210}
211