blob: 0207b7feda103c020379c76b0b27b6a0db6b57c8 [file] [log] [blame]
MG Mud User88f12472016-06-24 23:31:02 +02001/*
2 * Mudlibseite des iplookup systems, mit dem aus numerischen IP Adressen
3 * der Hostname und der Ort, an dem sich der Rechner befinden berechnet wird.
4 * Ergebnisse werden gecachet.
5 *
6 * (c)2010 rumata @ morgengrauen
7 */
8
9#pragma strict_types,save_types
10#pragma no_clone,no_shadow
11
12// Format der ipmap:
13// Key: numerische ip als string (ohne fuehrende nullen)
14// Data:
15// [ip,0] Hostname, der vom externen Server geliefert wurde.
16// [ip,1] Locationinformation, die vom externen Server kommt.
17// dieser sollte den Ort, oder falls es nicht besser geht, das Land
18// im Klartext liefern.
19// [ip,2] Zeitstempel, bei dessen erreichen der Wert geloescht werden
20// soll.
21// [ip,3] Status der Anfrage
22
23private mapping ipmap;
24#define IPMAP_HOST 0
25#define IPMAP_CITY 1
26#define IPMAP_EXPIRE 2
27#define IPMAP_STATUS 3
28
29// externer server, der der lokationdaten berechnet
30#define IPLOOKUP_HOST "127.0.0.1"
31#define IPLOOKUP_PORT 8711
32#define IPLOOKUP_SAVE "/p/daemon/save/iplookup"
33
34// moegliche statuswerte (platz zum zaehlen der anfragen gelassen)
35#define STATUS_QUERYING 1
36#define STATUS_AUTHORITATIVE 128
37
38// so lange werden die daten im cache gehalten
39#define CACHE_TIME 86400 /* 1 day */
40
41// Ab dieser Groesse betrache ich den cache als "gross genug",
42// um einen cache update in etappen zu rechtfertigen.
43#define LARGE_CACHE_LIMIT 2000
44
45// so lange sind wir bereit auf die antwort einer anfrage beim server zu warten
46#define QUERY_TIME 60 /* 1 min */
47
48#include <config.h>
49#if MUDNAME == "MorgenGrauen"
50#define LOG(x) log_file("rumata/iplookup.log",strftime("%Y-%m-%d %H:%M:%S: ")+(x)+"\n")
51#else
52#define LOG(x)
53#endif
54
55// PROTOTYPES
MG Mud User88f12472016-06-24 23:31:02 +020056static void expire_cache_small();
57static void expire_cache_large( string* keys );
MG Mud User88f12472016-06-24 23:31:02 +020058
59// IMPLEMENTATION
60
Zesstra2bffcd42020-02-04 22:17:55 +010061protected void create() {
MG Mud User88f12472016-06-24 23:31:02 +020062 seteuid(getuid());
63 restore_object( IPLOOKUP_SAVE );
64
65 if( !mappingp(ipmap) || widthof(ipmap)!=4 ) {
66 ipmap = m_allocate( 0, 4 );
67 LOG("restore failed, creating new ipmap");
68 } else {
69 LOG(sprintf("created (%d entries)",sizeof(ipmap)));
70 }
71}
72
73public void reset() {
74 if( sizeof(ipmap) < LARGE_CACHE_LIMIT ) {
75 expire_cache_small();
76 } else {
77 LOG(sprintf("reset %d ->",sizeof(ipmap)));
78 expire_cache_large( m_indices(ipmap) );
79 }
80 set_next_reset(10800);
81}
82
83static int active_entry( string key, mixed* data ) {
84 return time() < data[IPMAP_EXPIRE];
85}
86
87// Den cache auf einfache weise aufraeumen.
88static void expire_cache_small() {
89 int s = sizeof(ipmap);
90 ipmap = filter( ipmap, #'active_entry );
91 save_object( IPLOOKUP_SAVE );
92 LOG(sprintf("reset (%d -> %d)",s,sizeof(ipmap)));
93}
94
95// Kompliziertere routine, die den cache etappenweise abarbeitet.
96static void expire_cache_large( string* keys ) {
97 if( !pointerp(keys) ) return;
98 int next=0;
99 foreach( string key: keys ) {
100 if( get_eval_cost() < 100000 ) break;
101 if( ipmap[key,IPMAP_EXPIRE] < time() ) {
102 m_delete( ipmap, key );
103 }
104 next++;
105 }
106 LOG(sprintf("checking %d of %d",next,sizeof(keys)));
107 if( next<sizeof(keys) ) {
108 call_out( #'expire_cache_large, 6, keys[next..] );
109 } else {
110 save_object( IPLOOKUP_SAVE );
111 LOG(sprintf("reset -> %d (done)",sizeof(ipmap)));
112 }
113}
114
115#define SEARCHING "<auf der Suche...>"
116
117/* Erzeugt einen temporaeren Eintrag, der fuer eine Suche steht.
118 * Wenn die Antwort kommt, wird der Eintrag mit den entgueltigen
119 * Daten ueberschrieben.
120 */
121static void make_request( string ipnum ) {
Zesstra5ce91172019-11-05 23:57:34 +0100122 send_udp( IPLOOKUP_HOST, IPLOOKUP_PORT, to_bytes(ipnum, "ASCII") );
MG Mud User88f12472016-06-24 23:31:02 +0200123 ipmap += ([ ipnum : ipnum ; SEARCHING ;
124 time()+QUERY_TIME ; STATUS_QUERYING
125 ]);
126}
127
128/* Liefert zu einer gegebenen ipnum den Ort.
129 * diese Funktion wird von simul_efun aufgerufen.
130 * @param ipnum eine numerische ip-adresse oder ein interactive
131 * @return den Ort (oder das Land) in dem sich die ip-adresse
132 * laut externem Server befindet.
133 */
Zesstra2bffcd42020-02-04 22:17:55 +0100134public string country( string|object ipnum ) {
MG Mud User88f12472016-06-24 23:31:02 +0200135 string host,city;
136 int expire,state;
137
138 if( objectp(ipnum) ) {
139 ipnum = query_ip_number(ipnum);
140 }
141 if( !stringp(ipnum) ) {
142 return "<undefined>";
143 }
144 if( !m_contains( &host, &city, &expire, &state, ipmap, ipnum ) ) {
145 make_request( ipnum );
146 return SEARCHING;
147 }
148
149 return city;
150}
151
152/* Liefert zu einer gegebenen ipnum den Hostnamen.
153 * diese Funktion wird von simul_efun aufgerufen.
154 * @param ipnum eine numerische ip-adresse oder ein interactive
155 * @return den Hostnamen der zu der angegebenen ip-adresse gehoert.
156 * wenn der hostname nicht bekannt ist, wird die ipadresse zurueckgegeben.
157 */
Zesstra2bffcd42020-02-04 22:17:55 +0100158public string host( string|object ipnum ) {
MG Mud User88f12472016-06-24 23:31:02 +0200159 string host,city;
160 int expire,state;
161
162 if( objectp(ipnum) ) {
163 ipnum = query_ip_number(ipnum);
164 }
165 if( !stringp(ipnum) ) {
166 return "<undefined>";
167 }
168 if( !m_contains( &host, &city, &expire, &state, ipmap, ipnum ) ) {
169 make_request( ipnum );
170 return ipnum;
171 }
172
173 return host;
174}
175
176/* wird vom master aufgerufen, wenn eine antwort vom externen
177 * iplookup dienst eintrudelt.
178 */
179public void update( string udp_reply ) {
180 string* reply;
181 if( previous_object()!=master() ) return;
182 reply = explode(udp_reply,"\n");
183 if( sizeof(reply)<4 ) return;
184
185 if( reply[3] == "<unknown>" ) reply[3] = reply[1];
186 if( reply[2] == "<unknown>" ) reply[2] = "irgendwoher";
187 ipmap += ([ reply[1] : reply[3] ; reply[2] ; time()+CACHE_TIME ;
188 STATUS_AUTHORITATIVE ]);
189 //save_object( IPLOOKUP_SAVE );
190}
191
192int remove(int silent) {
193 save_object( IPLOOKUP_SAVE );
194 destruct(this_object());
195 return 1;
196}
197
198// DEBUGGING CODE
199
200#if 0
201public void dump( string key, mixed* data ) {
202 printf( "%s: %s (%s) s=%d bis %d\n", key, data[0], data[1],
203 data[3], data[2] );
204}
205
206public void load(string s) {
207 restore_object(s);
208 if( !mappingp(ipmap) || widthof(ipmap)!=4 ) {
209 ipmap = m_allocate( 0, 4 );
210 LOG("restore failed, creating new ipmap");
211 } else {
212 LOG(sprintf("created (%d entries)",sizeof(ipmap)));
213 }
214}
215
216public void debug() {
217 map( ipmap, #'dump );
218 printf( "= %d Eintraege\n", sizeof(ipmap) );
219}
220#endif