]>
Commit | Line | Data |
---|---|---|
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 | ||
11 | MODULE_VERSION(""); | |
12 | ||
13 | static 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 | ||
24 | static 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 | ||
54 | static 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 | ||
63 | static 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 | ||
74 | static 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 | ||
114 | static 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 | ||
121 | static 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 | ||
157 | static 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 | ||
164 | static rbl_ops rbl_zonefile_ops = { | |
165 | .lookup = rbl_zf_lookup, | |
166 | .refresh = rbl_zf_refresh, | |
167 | .dtor = rbl_zf_dtor | |
168 | }; | |
169 | ||
170 | int 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 | ||
178 | void _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 | ||
208 | void _fini(void) { | |
209 | deregisterrblbyops(&rbl_zonefile_ops); | |
210 | } | |
211 |