unrealircd- supernets unrealircd source & configuration |
git clone git://git.acid.vegas/unrealircd.git |
Log | Files | Refs | Archive | README | LICENSE |
geoip_base.c (8183B)
1 /* 2 * GEOIP Base module, needed for all geoip functions 3 * as this stores the geo information in ModData. 4 * (C) Copyright 2021-.. Syzop and The UnrealIRCd Team 5 * License: GPLv2 or later 6 */ 7 8 #include "unrealircd.h" 9 10 ModuleHeader MOD_HEADER 11 = { 12 "geoip_base", 13 "5.0", 14 "Base module for geoip", 15 "UnrealIRCd Team", 16 "unrealircd-6", 17 }; 18 19 struct geoip_base_config_s { 20 int check_on_load; 21 }; 22 23 /* Forward declarations */ 24 void geoip_base_free(ModData *m); 25 const char *geoip_base_serialize(ModData *m); 26 void geoip_base_unserialize(const char *str, ModData *m); 27 int geoip_base_handshake(Client *client); 28 int geoip_base_ip_change(Client *client, const char *oldip); 29 int geoip_base_whois(Client *client, Client *target, NameValuePrioList **list); 30 int geoip_connect_extinfo(Client *client, NameValuePrioList **list); 31 int geoip_json_expand_client(Client *client, int detail, json_t *j); 32 int geoip_base_configtest(ConfigFile *cf, ConfigEntry *ce, int type, int *errs); 33 int geoip_base_configrun(ConfigFile *cf, ConfigEntry *ce, int type); 34 EVENT(geoip_base_set_existing_users_evt); 35 CMD_FUNC(cmd_geoip); 36 37 ModDataInfo *geoip_md; /* Module Data structure which we acquire */ 38 struct geoip_base_config_s geoip_base_config; 39 40 /* We can use GEOIPDATA() and GEOIPDATARAW() for fast access. 41 * People wanting to get this information from outside this module 42 * should use geoip_client(client) ! 43 */ 44 45 #define GEOIPDATARAW(x) (moddata_client((x), geoip_md).ptr) 46 #define GEOIPDATA(x) ((GeoIPResult *)moddata_client((x), geoip_md).ptr) 47 48 int geoip_base_configtest(ConfigFile *cf, ConfigEntry *ce, int type, int *errs) 49 { 50 ConfigEntry *cep; 51 int errors = 0; 52 int i; 53 54 if (type != CONFIG_SET) 55 return 0; 56 57 if (!ce || !ce->name) 58 return 0; 59 60 if (strcmp(ce->name, "geoip")) 61 return 0; 62 63 for (cep = ce->items; cep; cep = cep->next) 64 { 65 if (!strcmp(cep->name, "check-on-load")) 66 { 67 CheckNull(cep); 68 continue; 69 } 70 config_warn("%s:%i: unknown item geoip::%s", cep->file->filename, cep->line_number, cep->name); 71 } 72 73 *errs = errors; 74 return errors ? -1 : 1; 75 } 76 77 int geoip_base_configrun(ConfigFile *cf, ConfigEntry *ce, int type) 78 { 79 ConfigEntry *cep; 80 81 if (type != CONFIG_SET) 82 return 0; 83 84 if (!ce || !ce->name) 85 return 0; 86 87 if (strcmp(ce->name, "geoip")) 88 return 0; 89 90 for (cep = ce->items; cep; cep = cep->next) 91 { 92 if (!strcmp(cep->name, "check-on-load")) 93 geoip_base_config.check_on_load = config_checkval(cep->value, CFG_YESNO); 94 } 95 return 1; 96 } 97 98 MOD_TEST() 99 { 100 MARK_AS_OFFICIAL_MODULE(modinfo); 101 HookAdd(modinfo->handle, HOOKTYPE_CONFIGTEST, 0, geoip_base_configtest); 102 return MOD_SUCCESS; 103 } 104 105 MOD_INIT() 106 { 107 ModDataInfo mreq; 108 109 MARK_AS_OFFICIAL_MODULE(modinfo); 110 111 memset(&mreq, 0, sizeof(mreq)); 112 mreq.name = "geoip"; 113 mreq.free = geoip_base_free; 114 mreq.serialize = geoip_base_serialize; 115 mreq.unserialize = geoip_base_unserialize; 116 mreq.sync = MODDATA_SYNC_EARLY; 117 mreq.type = MODDATATYPE_CLIENT; 118 geoip_md = ModDataAdd(modinfo->handle, mreq); 119 if (!geoip_md) 120 abort(); 121 122 HookAdd(modinfo->handle, HOOKTYPE_CONFIGRUN, 0, geoip_base_configrun); 123 HookAdd(modinfo->handle, HOOKTYPE_HANDSHAKE, 0, geoip_base_handshake); 124 HookAdd(modinfo->handle, HOOKTYPE_IP_CHANGE, 0, geoip_base_ip_change); 125 HookAdd(modinfo->handle, HOOKTYPE_SERVER_HANDSHAKE_OUT, 0, geoip_base_handshake); 126 HookAdd(modinfo->handle, HOOKTYPE_CONNECT_EXTINFO, 1, geoip_connect_extinfo); /* (prio: near-first) */ 127 HookAdd(modinfo->handle, HOOKTYPE_PRE_LOCAL_CONNECT, 0,geoip_base_handshake); /* in case the IP changed in registration phase (WEBIRC, HTTP Forwarded) */ 128 HookAdd(modinfo->handle, HOOKTYPE_WHOIS, 0, geoip_base_whois); 129 HookAdd(modinfo->handle, HOOKTYPE_JSON_EXPAND_CLIENT, 0, geoip_json_expand_client); 130 131 CommandAdd(modinfo->handle, "GEOIP", cmd_geoip, MAXPARA, CMD_USER); 132 133 /* set defaults */ 134 geoip_base_config.check_on_load = 1; 135 136 return MOD_SUCCESS; 137 } 138 139 MOD_LOAD() 140 { 141 /* add info for all users upon module loading if enabled, but delay it a bit for data provider module to load */ 142 if (geoip_base_config.check_on_load) 143 { 144 EventAdd(modinfo->handle, "geoip_base_set_existing_users", geoip_base_set_existing_users_evt, NULL, 1000, 1); 145 } 146 return MOD_SUCCESS; 147 } 148 149 150 MOD_UNLOAD() 151 { 152 return MOD_SUCCESS; 153 } 154 155 int geoip_base_handshake(Client *client) 156 { 157 if (!client->ip) 158 return 0; 159 GeoIPResult *res = geoip_lookup(client->ip); 160 161 if (!res) 162 return 0; 163 164 if (GEOIPDATA(client)) 165 { 166 free_geoip_result(GEOIPDATA(client)); 167 GEOIPDATARAW(client) = NULL; 168 } 169 GEOIPDATARAW(client) = res; 170 return 0; 171 } 172 173 int geoip_base_ip_change(Client *client, const char *oldip) 174 { 175 geoip_base_handshake(client); 176 return 0; 177 } 178 179 void geoip_base_free(ModData *m) 180 { 181 if (m->ptr) 182 { 183 free_geoip_result((GeoIPResult *)m->ptr); 184 m->ptr = NULL; 185 } 186 } 187 188 const char *geoip_base_serialize(ModData *m) 189 { 190 static char buf[512]; 191 GeoIPResult *geo; 192 193 if (!m->ptr) 194 return NULL; 195 196 geo = m->ptr; 197 snprintf(buf, sizeof(buf), "cc=%s|cd=%s", 198 geo->country_code, 199 geo->country_name); 200 201 return buf; 202 } 203 204 void geoip_base_unserialize(const char *str, ModData *m) 205 { 206 char buf[512], *p=NULL, *varname, *value; 207 char *country_name = NULL; 208 char *country_code = NULL; 209 GeoIPResult *res; 210 211 if (m->ptr) 212 { 213 free_geoip_result((GeoIPResult *)m->ptr); 214 m->ptr = NULL; 215 } 216 if (str == NULL) 217 return; 218 219 strlcpy(buf, str, sizeof(buf)); 220 for (varname = strtoken(&p, buf, "|"); varname; varname = strtoken(&p, NULL, "|")) 221 { 222 value = strchr(varname, '='); 223 if (!value) 224 continue; 225 *value++ = '\0'; 226 if (!strcmp(varname, "cc")) 227 country_code = value; 228 else if (!strcmp(varname, "cd")) 229 country_name = value; 230 } 231 232 if (!country_code || !country_name) 233 return; /* does not meet minimum criteria */ 234 235 res = safe_alloc(sizeof(GeoIPResult)); 236 safe_strdup(res->country_name, country_name); 237 safe_strdup(res->country_code, country_code); 238 m->ptr = res; 239 } 240 241 EVENT(geoip_base_set_existing_users_evt) 242 { 243 Client *client; 244 list_for_each_entry(client, &client_list, client_node) 245 { 246 if (MyUser(client)) 247 geoip_base_handshake(client); 248 } 249 } 250 251 int geoip_connect_extinfo(Client *client, NameValuePrioList **list) 252 { 253 GeoIPResult *geo = GEOIPDATA(client); 254 if (geo) 255 add_nvplist(list, 0, "country", geo->country_code); 256 return 0; 257 } 258 259 int geoip_json_expand_client(Client *client, int detail, json_t *j) 260 { 261 GeoIPResult *geo = GEOIPDATA(client); 262 json_t *geoip; 263 264 if (!geo) 265 return 0; 266 267 geoip = json_object(); 268 json_object_set_new(j, "geoip", geoip); 269 json_object_set_new(geoip, "country_code", json_string_unreal(geo->country_code)); 270 271 return 0; 272 } 273 274 int geoip_base_whois(Client *client, Client *target, NameValuePrioList **list) 275 { 276 GeoIPResult *geo; 277 char buf[512]; 278 int policy = whois_get_policy(client, target, "geo"); 279 280 if (policy == WHOIS_CONFIG_DETAILS_NONE) 281 return 0; 282 283 geo = GEOIPDATA(target); 284 if (!geo) 285 return 0; 286 287 // we only have country atm, but if we add city then city goes in 'full' and 288 // country goes in 'limited' 289 // if policy == WHOIS_CONFIG_DETAILS_LIMITED ... 290 add_nvplist_numeric_fmt(list, 0, "geo", client, RPL_WHOISCOUNTRY, 291 "%s %s :is connecting from %s", 292 target->name, 293 geo->country_code, 294 geo->country_name); 295 return 0; 296 } 297 298 CMD_FUNC(cmd_geoip) 299 { 300 const char *ip = NULL; 301 Client *target; 302 GeoIPResult *res; 303 304 if (!IsOper(client)) 305 { 306 sendnumeric(client, ERR_NOPRIVILEGES); 307 return; 308 } 309 310 if ((parc < 2) || BadPtr(parv[1])) 311 { 312 /* Maybe some report */ 313 return; 314 } 315 316 if (strchr(parv[1], '.') || strchr(parv[1], ':')) 317 { 318 ip = parv[1]; 319 } else { 320 target = find_user(parv[1], NULL); 321 if (!target) 322 { 323 sendnumeric(client, ERR_NOSUCHNICK, parv[1]); 324 return; 325 } 326 ip = target->ip; 327 if (!ip) 328 { 329 sendnotice(client, "User %s has no known IP address", client->name); // (eg: services bot) 330 return; 331 } 332 } 333 334 res = geoip_lookup(ip); 335 336 sendnotice(client, "*** GEOIP information for IP %s ***", ip); 337 if (!res) 338 { 339 sendnotice(client, "- No information available"); 340 return; 341 } else { 342 if (res->country_code) 343 sendnotice(client, "- Country code: %s", res->country_code); 344 if (res->country_name) 345 sendnotice(client, "- Country name: %s", res->country_name); 346 } 347 348 free_geoip_result(res); 349 350 sendnotice(client, "*** End of information ***"); 351 }