unrealircd- supernets unrealircd source & configuration |
git clone git://git.acid.vegas/unrealircd.git |
Log | Files | Refs | Archive | README | LICENSE |
geoip_classic.c (8024B)
1 /* GEOIP Classic module 2 * (C) Copyright 2021 Bram Matthys and the UnrealIRCd team 3 * License: GPLv2 or later 4 */ 5 6 #include "unrealircd.h" 7 #include <GeoIP.h> 8 9 ModuleHeader MOD_HEADER 10 = { 11 "geoip_classic", 12 "5.0", 13 "GEOIP using classic databases", 14 "UnrealIRCd Team", 15 "unrealircd-6", 16 }; 17 18 struct geoip_classic_config_s { 19 char *v4_db_file; 20 char *v6_db_file; 21 /* for config reading only */ 22 int have_config; 23 int have_ipv4_database; 24 int have_ipv6_database; 25 }; 26 27 /* Variables */ 28 29 struct geoip_classic_config_s geoip_classic_config; 30 GeoIP *gi4 = NULL; 31 GeoIP *gi6 = NULL; 32 33 /* Forward declarations */ 34 int geoip_classic_configtest(ConfigFile *cf, ConfigEntry *ce, int type, int *errs); 35 int geoip_classic_configposttest(int *errs); 36 int geoip_classic_configrun(ConfigFile *cf, ConfigEntry *ce, int type); 37 void geoip_classic_free(void); 38 GeoIPResult *geoip_lookup_classic(char *ip); 39 40 int geoip_classic_configtest(ConfigFile *cf, ConfigEntry *ce, int type, int *errs) 41 { 42 ConfigEntry *cep; 43 int errors = 0; 44 int i; 45 46 if (type != CONFIG_SET) 47 return 0; 48 49 if (!ce || !ce->name) 50 return 0; 51 52 if (strcmp(ce->name, "geoip-classic")) 53 return 0; 54 55 geoip_classic_config.have_config = 1; 56 57 for (cep = ce->items; cep; cep = cep->next) 58 { 59 if (!strcmp(cep->name, "ipv4-database")) 60 { 61 if (geoip_classic_config.have_ipv4_database) 62 { 63 config_error("%s:%i: duplicate item set::geoip-classic::%s", cep->file->filename, cep->line_number, cep->name); 64 continue; 65 } 66 if (!is_file_readable(cep->value, PERMDATADIR)) 67 { 68 config_error("%s:%i: set::geoip-classic::%s: cannot open file \"%s/%s\" for reading (%s)", cep->file->filename, cep->line_number, cep->name, PERMDATADIR, cep->value, strerror(errno)); 69 errors++; 70 continue; 71 } 72 geoip_classic_config.have_ipv4_database = 1; 73 continue; 74 } 75 if (!strcmp(cep->name, "ipv6-database")) 76 { 77 if (geoip_classic_config.have_ipv6_database) 78 { 79 config_error("%s:%i: duplicate item set::geoip-classic::%s", cep->file->filename, cep->line_number, cep->name); 80 continue; 81 } 82 if (!is_file_readable(cep->value, PERMDATADIR)) 83 { 84 config_error("%s:%i: set::geoip-classic::%s: cannot open file \"%s/%s\" for reading (%s)", cep->file->filename, cep->line_number, cep->name, PERMDATADIR, cep->value, strerror(errno)); 85 errors++; 86 continue; 87 } 88 geoip_classic_config.have_ipv6_database = 1; 89 continue; 90 } 91 config_warn("%s:%i: unknown item set::geoip-classic::%s", cep->file->filename, cep->line_number, cep->name); 92 } 93 94 *errs = errors; 95 return errors ? -1 : 1; 96 } 97 98 int geoip_classic_configposttest(int *errs) 99 { 100 int errors = 0; 101 if (geoip_classic_config.have_config) 102 { 103 if (!geoip_classic_config.have_ipv4_database && !geoip_classic_config.have_ipv6_database) 104 { 105 config_error("geoip_classic: no database files specified! Remove set::geoip-classic to use defaults"); 106 errors++; 107 } 108 } else 109 { 110 safe_strdup(geoip_classic_config.v4_db_file, "GeoIP.dat"); 111 safe_strdup(geoip_classic_config.v6_db_file, "GeoIPv6.dat"); 112 113 if (is_file_readable(geoip_classic_config.v4_db_file, PERMDATADIR)) 114 { 115 geoip_classic_config.have_ipv4_database = 1; 116 } else 117 { 118 config_warn("[geoip_classic] cannot open IPv4 database file \"%s/%s\" for reading (%s)", PERMDATADIR, geoip_classic_config.v4_db_file, strerror(errno)); 119 safe_free(geoip_classic_config.v4_db_file); 120 } 121 if (is_file_readable(geoip_classic_config.v6_db_file, PERMDATADIR)) 122 { 123 geoip_classic_config.have_ipv6_database = 1; 124 } else 125 { 126 config_warn("[geoip_classic] cannot open IPv6 database file \"%s/%s\" for reading (%s)", PERMDATADIR, geoip_classic_config.v6_db_file, strerror(errno)); 127 safe_free(geoip_classic_config.v6_db_file); 128 } 129 if (!geoip_classic_config.have_ipv4_database && !geoip_classic_config.have_ipv6_database) 130 { 131 config_error("[geoip_classic] couldn't read any database! Either put these in %s location " 132 "or specify another in set::geoip-classic config block", PERMDATADIR); 133 errors++; 134 } 135 } 136 137 *errs = errors; 138 return errors ? -1 : 1; 139 } 140 141 int geoip_classic_configrun(ConfigFile *cf, ConfigEntry *ce, int type) 142 { 143 ConfigEntry *cep; 144 145 if (type != CONFIG_SET) 146 return 0; 147 148 if (!ce || !ce->name) 149 return 0; 150 151 if (strcmp(ce->name, "geoip-classic")) 152 return 0; 153 154 for (cep = ce->items; cep; cep = cep->next) 155 { 156 if (!strcmp(cep->name, "ipv4-database") && geoip_classic_config.have_ipv4_database) 157 safe_strdup(geoip_classic_config.v4_db_file, cep->value); 158 if (!strcmp(cep->name, "ipv6-database") && geoip_classic_config.have_ipv6_database) 159 safe_strdup(geoip_classic_config.v6_db_file, cep->value); 160 } 161 return 1; 162 } 163 164 MOD_TEST() 165 { 166 MARK_AS_OFFICIAL_MODULE(modinfo); 167 if (!CallbackAddPVoid(modinfo->handle, CALLBACKTYPE_GEOIP_LOOKUP, TO_PVOIDFUNC(geoip_lookup_classic))) 168 { 169 unreal_log(ULOG_ERROR, "geoip_classic", "GEOIP_ADD_CALLBACK_FAILED", NULL, 170 "geoip_classic: Could not install GEOIP_LOOKUP callback. " 171 "Most likely another geoip module is already loaded. " 172 "You can only load one!"); 173 return MOD_FAILED; 174 } 175 176 geoip_classic_config.have_config = 0; 177 geoip_classic_config.have_ipv4_database = 0; 178 geoip_classic_config.have_ipv6_database = 0; 179 HookAdd(modinfo->handle, HOOKTYPE_CONFIGTEST, 0, geoip_classic_configtest); 180 HookAdd(modinfo->handle, HOOKTYPE_CONFIGPOSTTEST, 0, geoip_classic_configposttest); 181 return MOD_SUCCESS; 182 } 183 184 MOD_INIT() 185 { 186 MARK_AS_OFFICIAL_MODULE(modinfo); 187 geoip_classic_free(); 188 HookAdd(modinfo->handle, HOOKTYPE_CONFIGRUN, 0, geoip_classic_configrun); 189 return MOD_SUCCESS; 190 } 191 192 MOD_LOAD() 193 { 194 int found_good_file = 0; 195 196 if (geoip_classic_config.v4_db_file) 197 { 198 convert_to_absolute_path(&geoip_classic_config.v4_db_file, PERMDATADIR); 199 gi4 = GeoIP_open(geoip_classic_config.v4_db_file, GEOIP_STANDARD | GEOIP_CHECK_CACHE | GEOIP_SILENCE); 200 if (gi4) 201 { 202 found_good_file = 1; 203 } else 204 { 205 int save_err = errno; 206 unreal_log(ULOG_WARNING, "geoip_classic", "GEOIP_CANNOT_OPEN_DB", NULL, 207 "[IPv4] Could not open '$filename': $system_error", 208 log_data_string("filename", geoip_classic_config.v4_db_file), 209 log_data_string("system_error", strerror(save_err))); 210 } 211 } 212 if (geoip_classic_config.v6_db_file) 213 { 214 convert_to_absolute_path(&geoip_classic_config.v6_db_file, PERMDATADIR); 215 gi6 = GeoIP_open(geoip_classic_config.v6_db_file, GEOIP_STANDARD | GEOIP_CHECK_CACHE | GEOIP_SILENCE); 216 if (gi6) 217 { 218 found_good_file = 1; 219 } else 220 { 221 int save_err = errno; 222 unreal_log(ULOG_WARNING, "geoip_classic", "GEOIP_CANNOT_OPEN_DB", NULL, 223 "[IPv6] Could not open '$filename': $system_error", 224 log_data_string("filename", geoip_classic_config.v6_db_file), 225 log_data_string("system_error", strerror(save_err))); 226 } 227 convert_to_absolute_path(&geoip_classic_config.v6_db_file, PERMDATADIR); 228 } 229 230 if (!found_good_file) 231 { 232 unreal_log(ULOG_ERROR, "geoip_classic", "GEOIP_CANNOT_OPEN_DB", NULL, 233 "could not open any database!"); 234 return MOD_FAILED; 235 } 236 return MOD_SUCCESS; 237 } 238 239 MOD_UNLOAD() 240 { 241 geoip_classic_free(); 242 return MOD_SUCCESS; 243 } 244 245 void geoip_classic_free(void) 246 { 247 if (gi4) 248 GeoIP_delete(gi4); 249 if (gi6) 250 GeoIP_delete(gi6); 251 gi4 = NULL; 252 gi6 = NULL; 253 safe_free(geoip_classic_config.v4_db_file); 254 safe_free(geoip_classic_config.v6_db_file); 255 } 256 257 GeoIPResult *geoip_lookup_classic(char *ip) 258 { 259 static char buf[256]; 260 const char *country_code, *country_name; 261 GeoIPLookup gl; 262 GeoIP *gi; 263 int geoid; 264 GeoIPResult *r; 265 266 if (!ip) 267 return NULL; 268 269 if (strchr(ip, ':')) 270 { 271 if (!gi6) 272 return NULL; 273 geoid = GeoIP_id_by_addr_v6_gl(gi6, ip, &gl); 274 gi = gi6; 275 } else 276 { 277 if (!gi4 || !strcmp(ip, "255.255.255.255")) 278 return NULL; 279 geoid = GeoIP_id_by_addr_gl(gi4, ip, &gl); 280 gi = gi4; 281 } 282 283 if (geoid == 0) 284 return NULL; 285 286 country_code = GeoIP_code_by_id(geoid); 287 country_name = GeoIP_country_name_by_id(gi, geoid); 288 289 if (!country_code || !country_name) 290 return NULL; 291 292 r = safe_alloc(sizeof(GeoIPResult)); 293 safe_strdup(r->country_code, country_code); 294 safe_strdup(r->country_name, country_name); 295 return r; 296 } 297