1 #include <string.h>
2 #include "mmgr.h"
3 #include "stringchunk.h"
4 #include "utils.h"
5 #include "filter.h"
6 #include "hosts.h"
7 #include "dnscache.h"
8 #include "logs.h"
9 #include "ipmisc.h"
10 #include "readline.h"
11 
12 typedef int (*SendFunc)(void *Module,
13                         IHeader *h, /* Entity followed */
14                         int BufferLength
15                         );
16 
17 typedef struct _ModuleInterface {
18     union {
19         UdpM    Udp;
20         TcpM    Tcp;
21     } ModuleUnion;
22 
23     SendFunc    Send;
24 
25     const char *ModuleName;
26 
27 } ModuleInterface;
28 
29 static StableBuffer Modules; /* Storing ModuleInterfaces */
30 static Array        ModuleArray; /* ModuleInterfaces' references */
31 static StringChunk  Distributor; /* Domain-to-ModuleInterface mapping */
32 
MappingAModule(ModuleInterface * Stored,StringList * DomainList)33 static int MappingAModule(ModuleInterface *Stored, StringList *DomainList)
34 {
35     StringListIterator  i;
36     const char *OneDomain;
37 
38     DomainList->TrimAll(DomainList, "\t .");
39     DomainList->LowercaseAll(DomainList);
40 
41     if( StringListIterator_Init(&i, DomainList) != 0 )
42     {
43         return -46;
44     }
45 
46     while( (OneDomain = i.Next(&i)) != NULL )
47     {
48         StringChunk_Add_Domain(&Distributor,
49                                OneDomain,
50                                &Stored,
51                                sizeof(ModuleInterface *)
52                                );
53     }
54 
55     return 0;
56 }
57 
StoreAModule(void)58 static ModuleInterface *StoreAModule(void)
59 {
60     ModuleInterface *Added;
61 
62     Added = Modules.Add(&Modules, NULL, sizeof(ModuleInterface), TRUE);
63     if( Added == NULL )
64     {
65         return NULL;
66     }
67 
68     if( Array_PushBack(&ModuleArray, &Added, NULL) < 0 )
69     {
70         return NULL;
71     }
72 
73     Added->ModuleName = "Unknown";
74 
75     return Added;
76 }
77 
Udp_Init_Core(const char * Services,StringList * DomainList,const char * Parallel)78 static int Udp_Init_Core(const char *Services,
79                          StringList *DomainList,
80                          const char *Parallel
81                          )
82 {
83     ModuleInterface *NewM;
84 
85     char ParallelOnOff[8];
86     BOOL ParallelQuery;
87 
88     if( Services == NULL || DomainList == NULL || Parallel == NULL )
89     {
90         return -99;
91     }
92 
93     NewM = StoreAModule();
94     if( NewM == NULL )
95     {
96         return -101;
97     }
98 
99     NewM->ModuleName = "UDP";
100 
101     strncpy(ParallelOnOff, Parallel, sizeof(ParallelOnOff));
102     ParallelOnOff[sizeof(ParallelOnOff) - 1] = '\0';
103     StrToLower(ParallelOnOff);
104 
105     if( strcmp(ParallelOnOff, "on") == 0 )
106     {
107         ParallelQuery = TRUE;
108     } else {
109         ParallelQuery = FALSE;
110     }
111 
112     /* Initializing module */
113     if( UdpM_Init(&(NewM->ModuleUnion.Udp), Services, ParallelQuery) != 0 )
114     {
115         return -128;
116     }
117 
118     NewM->Send = (SendFunc)(NewM->ModuleUnion.Udp.Send);
119 
120     if( MappingAModule(NewM, DomainList) != 0 )
121     {
122         ERRORMSG("Mapping UDP module of %s failed.\n", Services);
123     }
124 
125     return 0;
126 }
127 
Udp_Init(StringListIterator * i)128 static int Udp_Init(StringListIterator  *i)
129 {
130     const char *Services;
131     const char *Domains;
132     const char *Parallel;
133 
134     StringList DomainList;
135 
136     /* Initializing parameters */
137     Services = i->Next(i);
138     Domains = i->Next(i);
139     Parallel = i->Next(i);
140 
141     if( Domains == NULL )
142     {
143         return -143;
144     }
145 
146     if( StringList_Init(&DomainList, Domains, ",") != 0 )
147     {
148         return -148;
149     }
150 
151     if( Udp_Init_Core(Services, &DomainList, Parallel) != 0 )
152     {
153         return -153;
154     }
155 
156     DomainList.Free(&DomainList);
157 
158     return 0;
159 }
160 
Tcp_Init_Core(const char * Services,StringList * DomainList,const char * Proxies)161 static int Tcp_Init_Core(const char *Services,
162                          StringList *DomainList,
163                          const char *Proxies
164                          )
165 {
166     ModuleInterface *NewM;
167 
168     char ProxyString[8];
169 
170     if( Services == NULL || DomainList == NULL || Proxies == NULL )
171     {
172         return -157;
173     }
174 
175     NewM = StoreAModule();
176     if( NewM == NULL )
177     {
178         return -192;
179     }
180 
181     NewM->ModuleName = "TCP";
182 
183     strncpy(ProxyString, Proxies, sizeof(ProxyString));
184     ProxyString[sizeof(ProxyString) - 1] = '\0';
185     StrToLower(ProxyString);
186 
187     if( strcmp(ProxyString, "no") == 0 )
188     {
189         Proxies = NULL;
190     }
191 
192     /* Initializing module */
193     if( TcpM_Init(&(NewM->ModuleUnion.Tcp), Services, Proxies) != 0 )
194     {
195         return -180;
196     }
197 
198     NewM->Send = (SendFunc)(NewM->ModuleUnion.Tcp.Send);
199 
200     if( MappingAModule(NewM, DomainList) != 0 )
201     {
202         ERRORMSG("Mapping TCP module of %s failed.\n", Services);
203     }
204 
205     return 0;
206 }
207 
Tcp_Init(StringListIterator * i)208 static int Tcp_Init(StringListIterator  *i)
209 {
210     const char *Services;
211     const char *Domains;
212     const char *Proxies;
213 
214     StringList DomainList;
215 
216     /* Initializing parameters */
217     Services = i->Next(i);
218     Domains = i->Next(i);
219     Proxies = i->Next(i);
220 
221     if( Domains == NULL )
222     {
223         return -143;
224     }
225 
226     if( StringList_Init(&DomainList, Domains, ",") != 0 )
227     {
228         return -148;
229     }
230 
231     if( Tcp_Init_Core(Services, &DomainList, Proxies) != 0 )
232     {
233         return -233;
234     }
235 
236     DomainList.Free(&DomainList);
237 
238     return 0;
239 }
240 
241 /*
242 # UDP
243 PROTOCOL UDP
244 SERVER 1.2.4.8,127.0.0.1
245 PARALLEL ON
246 
247 example.com
248 
249 #############################
250 # TCP
251 PROTOCOL TCP
252 SERVER 1.2.4.8,127.0.0.1
253 PROXY NO
254 
255 example.com
256 
257 #############################
258 # TCP
259 PROTOCOL TCP
260 SERVER 1.2.4.8,127.0.0.1
261 PROXY 192.168.1.1:8080,192.168.1.1:8081
262 
263 example.com
264 
265 */
Modules_InitFromFile(StringListIterator * i)266 static int Modules_InitFromFile(StringListIterator  *i)
267 {
268     #define MAX_PATH_BUFFER     384
269 
270     StringChunk Args;
271     StringList  Domains;
272 
273     const char *FileOri;
274     char File[MAX_PATH_BUFFER];
275     FILE *fp;
276 
277     ReadLineStatus  Status;
278 
279     const char *Protocol = NULL;
280 
281     FileOri = i->Next(i);
282 
283     if( FileOri == NULL )
284     {
285         return -201;
286     }
287 
288     strncpy(File, FileOri, sizeof(File));
289     File[sizeof(File) - 1] = '\0';
290 
291     ReplaceStr(File, "\"", "");
292 
293     ExpandPath(File, sizeof(File));
294 
295     fp = fopen(File, "r");
296     if( fp == NULL )
297     {
298         WARNING("Cannot open group file \"%s\".\n", File);
299         return 0;
300     }
301 
302     if( StringChunk_Init(&Args, NULL) != 0 )
303     {
304         return -230;
305     }
306 
307     if( StringList_Init(&Domains, NULL, NULL) != 0 )
308     {
309         return -235;
310     }
311 
312     do {
313         char Buffer[384];
314         const char *Value;
315 
316         Status = ReadLine(fp, Buffer, sizeof(Buffer));
317 
318         if( Status == READ_TRUNCATED )
319         {
320             WARNING("Line is too long %s, file \"%s\".\n", Buffer, File);
321             Status = ReadLine_GoToNextLine(fp);
322             continue;
323         }
324 
325         if( Status == READ_FAILED_OR_END )
326         {
327             break;
328         }
329 
330         StrToLower(Buffer);
331 
332         Value = SplitNameAndValue(Buffer, " \t=");
333         if( Value != NULL )
334         {
335             StringChunk_Add(&Args, Buffer, Value, strlen(Value) + 1);
336         } else {
337             Domains.Add(&Domains, Buffer, NULL);
338         }
339 
340     } while( TRUE );
341 
342     fclose(fp);
343 
344     if( !StringChunk_Match_NoWildCard(&Args,
345                                       "protocol",
346                                       NULL,
347                                       (void **)&Protocol
348                                       ) ||
349         Protocol == NULL
350         )
351     {
352         ERRORMSG("No protocol specified, file \"%s\".\n", File);
353         return -270;
354     }
355 
356     if( strcmp(Protocol, "udp") == 0 )
357     {
358         const char *Services = NULL;
359         const char *Parallel = "on";
360 
361         StringChunk_Match_NoWildCard(&Args, "server", NULL, (void **)&Services);
362         StringChunk_Match_NoWildCard(&Args,
363                                      "parallel",
364                                      NULL,
365                                      (void **)&Parallel
366                                      );
367 
368         if( Udp_Init_Core(Services, &Domains, Parallel) != 0 )
369         {
370             ERRORMSG("Loading group file \"%s\" failed.\n", File);
371             return -337;
372         }
373 
374     } else if( strcmp(Protocol, "tcp") == 0 )
375     {
376         const char *Services = NULL;
377         const char *Proxies = "no";
378 
379         StringChunk_Match_NoWildCard(&Args, "server", NULL, (void **)&Services);
380         StringChunk_Match_NoWildCard(&Args, "proxy", NULL, (void **)&Proxies);
381 
382         if( Tcp_Init_Core(Services, &Domains, Proxies) != 0 )
383         {
384             ERRORMSG("Loading group file \"%s\" failed.\n", File);
385             return -233;
386         }
387 
388     } else {
389         ERRORMSG("Unknown protocol %s, file \"%s\".\n", Protocol, File);
390         return -281;
391     }
392 
393     StringChunk_Free(&Args, TRUE);
394     Domains.Free(&Domains);
395 
396     return 0;
397 }
398 
Modules_Init(ConfigFileInfo * ConfigInfo)399 static int Modules_Init(ConfigFileInfo *ConfigInfo)
400 {
401     StringList  *ServerGroups;
402     StringListIterator  i;
403 
404     const char *Type;
405 
406     ServerGroups = ConfigGetStringList(ConfigInfo, "ServerGroup");
407     if( ServerGroups == NULL )
408     {
409         ERRORMSG("Please set at least one server group.\n");
410         return -202;
411     }
412 
413     if( StringListIterator_Init(&i, ServerGroups) != 0 )
414     {
415         return -207;
416     }
417 
418     while( (Type = i.Next(&i)) != NULL )
419     {
420         if( strcmp(Type, "UDP") == 0 )
421         {
422             if( Udp_Init(&i) != 0 )
423             {
424                 ERRORMSG("Initializing UDPGroups failed.\n");
425                 return -218;
426             }
427         } else if( strcmp(Type, "TCP") == 0 )
428         {
429             if( Tcp_Init(&i) != 0 )
430             {
431                 ERRORMSG("Initializing TCPGroups failed.\n");
432                 return -226;
433             }
434         } else if( strcmp(Type, "FILE") == 0 )
435         {
436             if( Modules_InitFromFile(&i) != 0 )
437             {
438                 ERRORMSG("Initializing group files failed.\n");
439                 return -318;
440             }
441         } else {
442             ERRORMSG("Initializing server groups failed, near %s.\n", Type);
443             return -230;
444         }
445     }
446 
447     INFO("Server groups initialized.\n", Type);
448     return 0;
449 }
450 
MMgr_Init(ConfigFileInfo * ConfigInfo)451 int MMgr_Init(ConfigFileInfo *ConfigInfo)
452 {
453     if( Filter_Init(ConfigInfo) != 0 )
454     {
455         return -159;
456     }
457 
458     /* Hosts & Cache */
459     if( Hosts_Init(ConfigInfo) != 0 )
460     {
461         return -165;
462     }
463 
464     if( DNSCache_Init(ConfigInfo) != 0 )
465     {
466         return -164;
467     }
468 
469     if( IpMiscSingleton_Init(ConfigInfo) != 0 )
470     {
471         return -176;
472     }
473 
474     /* Ordinary modeles */
475     if( StringChunk_Init(&Distributor, NULL) != 0 )
476     {
477         return -10;
478     }
479 
480     if( StableBuffer_Init(&Modules) != 0 )
481     {
482         return -27;
483     }
484 
485     if( Array_Init(&ModuleArray,
486                    sizeof(ModuleInterface *),
487                    0,
488                    FALSE,
489                    NULL
490                    )
491        != 0 )
492     {
493         return -98;
494     }
495 
496     return Modules_Init(ConfigInfo);
497 }
498 
MMgr_Send(IHeader * h,int BufferLength)499 int MMgr_Send(IHeader *h, int BufferLength)
500 {
501     ModuleInterface **i;
502     ModuleInterface *TheModule;
503 
504     /* Determine whether to discard the query */
505     if( Filter_Out(h) )
506     {
507         return 0;
508     }
509 
510     /* Hosts & Cache */
511     if( Hosts_Get(h, BufferLength) == 0 )
512     {
513         return 0;
514     }
515 
516     if( DNSCache_FetchFromCache(h, BufferLength) == 0 )
517     {
518         return 0;
519     }
520 
521     /* Ordinary modeles */
522     if( StringChunk_Domain_Match(&Distributor,
523                                  h->Domain,
524                                  &(h->HashValue),
525                                  (void **)&i
526                                  )
527        )
528     {
529     } else if( Array_GetUsed(&ModuleArray) > 0 ){
530         i = Array_GetBySubscript(&ModuleArray,
531                                  (int)(*(uint16_t *)IHEADER_TAIL(h)) %
532                                      Array_GetUsed(&ModuleArray)
533                                  );
534     } else {
535         i = NULL;
536     }
537 
538     if( i == NULL || *i == NULL )
539     {
540         return -190;
541     }
542 
543     TheModule = *i;
544 
545     return TheModule->Send(&(TheModule->ModuleUnion), h, BufferLength);
546 }
547