1 #include "hostsutils.h"
2 #include "dnsgenerator.h"
3 #include "mmgr.h"
4 #include "goodiplist.h"
5 
HostsUtils_GetCName_Callback(int Number,HostsRecordType Type,const char * Data,char * Buffer)6 static int HostsUtils_GetCName_Callback(int Number,
7                                         HostsRecordType Type,
8                                         const char *Data,
9                                         char *Buffer
10                                         )
11 {
12     strcpy(Buffer, Data);
13     return 0;
14 }
15 
HostsUtils_GetCName(const char * Domain,char * Buffer,HostsContainer * Container)16 int HostsUtils_GetCName(const char *Domain,
17                         char *Buffer,
18                         HostsContainer *Container
19                         )
20 {
21     return Container->Find(Container,
22                            Domain,
23                            HOSTS_TYPE_CNAME,
24                            (HostsFindFunc)HostsUtils_GetCName_Callback,
25                            Buffer
26                            )
27             == NULL;
28 }
29 
HostsUtils_TypeExisting(HostsContainer * Container,const char * Domain,HostsRecordType Type)30 BOOL HostsUtils_TypeExisting(HostsContainer *Container,
31                              const char *Domain,
32                              HostsRecordType Type
33                              )
34 {
35     return Container->Find(Container,
36                            Domain,
37                            Type,
38                            NULL,
39                            NULL
40                            )
41             != NULL;
42 }
43 
HostsUtils_Generate(int Number,HostsRecordType Type,const void * Data,DnsGenerator * g)44 static int HostsUtils_Generate(int              Number,
45                                HostsRecordType  Type,
46                                const void       *Data,
47                                DnsGenerator     *g /* Inited */
48                                )
49 {
50     switch( Type )
51     {
52     case HOSTS_TYPE_CNAME:
53         if( g->CName(g, "a", Data, 60) != 0 )
54         {
55             return -26;
56         }
57         break;
58 
59     case HOSTS_TYPE_A:
60         if( g->RawData(g,
61                        "a",
62                        DNS_TYPE_A,
63                        DNS_CLASS_IN,
64                        Data,
65                        4,
66                        60
67                        )
68             != 0 )
69         {
70             return -41;
71         }
72         break;
73 
74     case HOSTS_TYPE_AAAA:
75         if( g->RawData(g,
76                        "a",
77                        DNS_TYPE_AAAA,
78                        DNS_CLASS_IN,
79                        Data,
80                        16,
81                        60
82                        )
83             != 0 )
84         {
85             return -56;
86         }
87         break;
88 
89     case HOSTS_TYPE_GOOD_IP_LIST:
90         {
91             const char *ActuallData;
92 
93             ActuallData = GoodIpList_Get(Data);
94             if( ActuallData == NULL )
95             {
96                 return -96;
97             }
98 
99             if( g->RawData(g,
100                            "a",
101                            DNS_TYPE_A,
102                            DNS_CLASS_IN,
103                            ActuallData,
104                            4,
105                            60
106                            )
107                 != 0 )
108             {
109                 return -109;
110             }
111         }
112         break;
113 
114     default:
115         return -61;
116         break;
117     }
118 
119     return 0;
120 }
121 
HostsUtils_Try(IHeader * Header,int BufferLength,HostsContainer * Container)122 HostsUtilsTryResult HostsUtils_Try(IHeader *Header,
123                                    int BufferLength,
124                                    HostsContainer *Container
125                                    )
126 {
127 	char *RequestEntity = (char *)(Header + 1);
128 	const char	*MatchState;
129 	HostsRecordType Type;
130 
131     if( Header->Type != DNS_TYPE_CNAME &&
132         HostsUtils_TypeExisting(Container, Header->Domain, HOSTS_TYPE_CNAME)
133         )
134     {
135         return HOSTSUTILS_TRY_RECURSED;
136     }
137 
138     switch( Header->Type )
139     {
140     case DNS_TYPE_CNAME:
141         Type = HOSTS_TYPE_CNAME;
142         MatchState = Container->Find(Container,
143                                      Header->Domain,
144                                      HOSTS_TYPE_CNAME,
145                                      NULL,
146                                      NULL
147                                      );
148         break;
149 
150     case DNS_TYPE_A:
151         MatchState = Container->Find(Container,
152                                      Header->Domain,
153                                      HOSTS_TYPE_A,
154                                      NULL,
155                                      NULL
156                                      );
157         if( MatchState != NULL )
158         {
159             Type = HOSTS_TYPE_A;
160         } else {
161             Type = HOSTS_TYPE_GOOD_IP_LIST;
162             MatchState = Container->Find(Container,
163                                          Header->Domain,
164                                          HOSTS_TYPE_GOOD_IP_LIST,
165                                          NULL,
166                                          NULL
167                                          );
168         }
169         break;
170 
171     case DNS_TYPE_AAAA:
172         Type = HOSTS_TYPE_AAAA;
173         MatchState = Container->Find(Container,
174                                      Header->Domain,
175                                      HOSTS_TYPE_AAAA,
176                                      NULL,
177                                      NULL
178                                      );
179         break;
180 
181     default:
182         return HOSTSUTILS_TRY_NONE;
183         break;
184     }
185 
186 	if( MatchState != NULL )
187 	{
188         DnsGenerator g;
189 
190         char *HereToGenerate = RequestEntity + Header->EntityLength;
191         int LeftBufferLength =
192                           BufferLength - sizeof(IHeader) - Header->EntityLength;
193 
194         int ResultLength;
195 
196         if( DnsGenerator_Init(&g,
197                               HereToGenerate,
198                               LeftBufferLength,
199                               RequestEntity,
200                               Header->EntityLength,
201                               TRUE
202                               )
203            != 0)
204         {
205             return HOSTSUTILS_TRY_NONE;
206         }
207 
208         g.Header->Flags.Direction = 1;
209         g.Header->Flags.AuthoritativeAnswer = 0;
210         g.Header->Flags.RecursionAvailable = 1;
211         g.Header->Flags.ResponseCode = 0;
212         g.Header->Flags.Type = 0;
213 
214         if( g.NextPurpose(&g) != DNS_RECORD_PURPOSE_ANSWER )
215         {
216             return HOSTSUTILS_TRY_NONE;
217         }
218 
219         if( Container->Find(Container,
220                             Header->Domain,
221                             Type,
222                             (HostsFindFunc)HostsUtils_Generate,
223                             &g
224                             )
225             == NULL )
226         {
227             return HOSTSUTILS_TRY_NONE;
228         }
229 
230         if( Header->EDNSEnabled )
231         {
232             while( g.NextPurpose(&g) != DNS_RECORD_PURPOSE_ADDITIONAL );
233             if( g.EDns(&g, 1280) != 0 )
234             {
235                 return HOSTSUTILS_TRY_NONE;
236             }
237         }
238 
239         /* g will no longer be needed, and can be crapped */
240         ResultLength = DNSCompress(HereToGenerate, g.Length(&g));
241         if( ResultLength < 0 )
242         {
243             return HOSTSUTILS_TRY_NONE;
244         }
245 
246         Header->EntityLength = ResultLength;
247         memmove(RequestEntity, HereToGenerate, ResultLength);
248 
249         IHeader_SendBack(Header);
250 
251         return HOSTSUTILS_TRY_OK;
252 	} else {
253 	    return HOSTSUTILS_TRY_NONE;
254 	}
255 }
256 
HostsUtils_Query(SOCKET Socket,Address_Type * BackAddress,int Identifier,const char * Name,DNSRecordType Type)257 int HostsUtils_Query(SOCKET Socket, /* Both for sending and receiving */
258                      Address_Type *BackAddress,
259                      int Identifier,
260                      const char *Name,
261                      DNSRecordType Type
262                      )
263 {
264     static const char DNSHeader[DNS_HEADER_LENGTH] = {
265         00, 00, /* QueryIdentifier */
266         01, 00, /* Flags */
267         00, 00, /* QuestionCount */
268         00, 00, /* AnswerCount */
269         00, 00, /* NameServerCount */
270         00, 00, /* AdditionalCount */
271     };
272 
273     char RequestBuffer[2048];
274     IHeader *Header = (IHeader *)RequestBuffer;
275     char *RequestEntity = RequestBuffer + sizeof(IHeader);
276 
277 	DnsGenerator g;
278 
279 	if( DnsGenerator_Init(&g,
280                           RequestEntity,
281                           sizeof(RequestBuffer) - sizeof(IHeader),
282                           DNSHeader,
283                           DNS_HEADER_LENGTH,
284                           FALSE
285                           )
286         != 0 )
287     {
288         return -323;
289     }
290 
291     g.CopyIdentifier(&g, Identifier);
292 
293     if( g.Question(&g, Name, Type, DNS_CLASS_IN) != 0 )
294     {
295         return -328;
296     }
297 
298     if( IHeader_Fill(Header,
299                      TRUE,
300                      RequestEntity,
301                      g.Length(&g),
302                      (struct sockaddr *)&(BackAddress->Addr),
303                      Socket,
304                      BackAddress->family,
305                      "CNameRedirect"
306                      )
307         != 0 )
308     {
309         return -309;
310     }
311 
312     return MMgr_Send(Header, sizeof(RequestBuffer));
313 }
314 
315 /* Error code returned */
HostsUtils_CombineRecursedResponse(void * Buffer,int Bufferlength,char * RecursedEntity,int EntityLength,const char * RecursedDomain)316 int HostsUtils_CombineRecursedResponse(void       *Buffer, /* Include IHeader */
317                                        int          Bufferlength,
318                                        char         *RecursedEntity,
319                                        int          EntityLength,
320                                        const char   *RecursedDomain
321                                        )
322 {
323     IHeader *NewHeader = (IHeader *)Buffer;
324     char *NewEntity = Buffer + sizeof(IHeader);
325 
326     DnsSimpleParser p;
327     DnsSimpleParserIterator i;
328     DnsGenerator g;
329 
330     uint16_t OriginalIdentifier = *(uint16_t *)NewEntity;
331 
332     int CompressedLength;
333 
334     if( DnsSimpleParser_Init(&p,
335                              RecursedEntity,
336                              EntityLength,
337                              FALSE
338                              ) != 0
339         )
340     {
341         return -268;
342     }
343 
344     if( DnsSimpleParserIterator_Init(&i, &p) != 0 )
345     {
346         return -273;
347     }
348 
349     if( DnsGenerator_Init(&g,
350                           NewEntity,
351                           Bufferlength - sizeof(IHeader),
352                           NULL,
353                           0,
354                           FALSE
355                           )
356        != 0 )
357     {
358         return -285;
359     }
360 
361     g.CopyHeader(&g, RecursedEntity, FALSE);
362     g.CopyIdentifier(&g, OriginalIdentifier);
363 
364     if( g.Question(&g,
365                    NewHeader->Domain,
366                    NewHeader->Type,
367                    DNS_CLASS_IN
368                    )
369        != 0 )
370     {
371         return -298;
372     }
373 
374     if( g.NextPurpose(&g) != DNS_RECORD_PURPOSE_ANSWER )
375     {
376         return -303;
377     }
378 
379     if( g.CName(&g, NewHeader->Domain, RecursedDomain, 60) != 0 )
380     {
381         return -309;
382     }
383 
384     i.GotoAnswers(&i);
385 
386     while( i.Next(&i) != NULL && i.Purpose == DNS_RECORD_PURPOSE_ANSWER )
387     {
388         switch( i.Type )
389         {
390         case DNS_TYPE_CNAME:
391             if( g.CopyCName(&g, &i) != 0 )
392             {
393                 return -321;
394             }
395             break;
396 
397         case DNS_TYPE_A:
398             if( g.CopyA(&g, &i) != 0 )
399             {
400                 return -328;
401             }
402             break;
403 
404         case DNS_TYPE_AAAA:
405             if( g.CopyAAAA(&g, &i) != 0 )
406             {
407                 return -335;
408             }
409             break;
410 
411         default:
412             break;
413         }
414     }
415 
416     if( NewHeader->EDNSEnabled )
417     {
418         while( g.NextPurpose(&g) != DNS_RECORD_PURPOSE_ADDITIONAL );
419 
420         if( g.EDns(&g, 1280) != 0 )
421         {
422             return -351;
423         }
424     }
425 
426     CompressedLength = DNSCompress(g.Buffer, g.Length(&g));
427     if( CompressedLength < 0 )
428     {
429         return -343;
430     }
431 
432     NewHeader->EntityLength = CompressedLength;
433 
434     return 0;
435 }
436