1 #include <string.h>
2 #include "dynamichosts.h"
3 #include "common.h"
4 #include "downloader.h"
5 #include "readline.h"
6 #include "goodiplist.h"
7 #include "timedtask.h"
8 #include "rwlock.h"
9 #include "logs.h"
10 
11 static const char   *File = NULL;
12 static RWLock		HostsLock;
13 static volatile HostsContainer	*MainDynamicContainer = NULL;
14 
DynamicHosts_Load(void)15 static int DynamicHosts_Load(void)
16 {
17 	FILE			*fp;
18 	char			Buffer[320];
19 	ReadLineStatus	Status;
20 
21 	HostsContainer *TempContainer;
22 
23 	fp = fopen(File, "r");
24 	if( fp == NULL )
25 	{
26 		return -1;
27 	}
28 
29 	TempContainer = (HostsContainer *)SafeMalloc(sizeof(HostsContainer));
30 	if( TempContainer == NULL )
31 	{
32 		fclose(fp);
33 		return -1;
34 	}
35 
36 	if( HostsContainer_Init(TempContainer) != 0 )
37 	{
38 		fclose(fp);
39 
40 		SafeFree(TempContainer);
41 		return -1;
42 	}
43 
44 	while( TRUE )
45 	{
46 		Status = ReadLine(fp, Buffer, sizeof(Buffer));
47 		if( Status == READ_FAILED_OR_END )
48         {
49             break;
50         }
51 
52 		if( Status == READ_TRUNCATED )
53 		{
54 			ERRORMSG("Hosts is too long : %s\n", Buffer);
55 			ReadLine_GoToNextLine(fp);
56 			continue;
57 		}
58 
59         TempContainer->Load(TempContainer, Buffer);
60 	}
61 
62 	RWLock_WrLock(HostsLock);
63 	if( MainDynamicContainer != NULL )
64 	{
65 	    MainDynamicContainer->Free((HostsContainer *)MainDynamicContainer);
66 		SafeFree((void *)MainDynamicContainer);
67 	}
68 	MainDynamicContainer = TempContainer;
69 
70 	RWLock_UnWLock(HostsLock);
71 
72 	INFO("Loading hosts completed.\n");
73 
74 	fclose(fp);
75 	return 0;
76 }
77 
78 /* Arguments for updating  */
79 static int          HostsRetryInterval;
80 static char         *Script = NULL; /* malloced */
81 static const char	**HostsURLs = NULL; /* malloced */
82 
GetHostsFromInternet_Failed(int ErrorCode,const char * URL,const char * File1)83 static void GetHostsFromInternet_Failed(int ErrorCode, const char *URL, const char *File1)
84 {
85 	ERRORMSG("Getting Hosts %s failed. Waiting %d second(s) to try again.\n",
86              URL,
87              HostsRetryInterval
88              );
89 }
90 
GetHostsFromInternet_Succeed(const char * URL,const char * File1)91 static void GetHostsFromInternet_Succeed(const char *URL, const char *File1)
92 {
93 	INFO("Hosts %s saved.\n", URL);
94 }
95 
GetHostsFromInternet_Thread(void * Unused1,void * Unused2)96 static void GetHostsFromInternet_Thread(void *Unused1, void *Unused2)
97 {
98 	int			DownloadState;
99 
100     if( HostsURLs[1] == NULL )
101     {
102         INFO("Getting hosts from %s ...\n", HostsURLs[0]);
103     } else {
104         INFO("Getting hosts from various places ...\n");
105     }
106 
107     DownloadState = GetFromInternet_MultiFiles(HostsURLs,
108                                                File,
109                                                HostsRetryInterval,
110                                                -1,
111                                                GetHostsFromInternet_Failed,
112                                                GetHostsFromInternet_Succeed
113                                                );
114 
115     if( DownloadState == 0 )
116     {
117         INFO("Hosts saved at %s.\n", File);
118 
119         if( Script != NULL )
120         {
121             INFO("Running hosts script \"%s\"...\n", Script);
122 
123             if( Execute(Script) < 0 )
124             {
125                 ERRORMSG("Hosts script running failed.\n");
126             }
127         }
128 
129         DynamicHosts_Load();
130     } else {
131         ERRORMSG("Getting hosts file(s) failed.\n");
132     }
133 }
134 
DynamicHosts_Init(ConfigFileInfo * ConfigInfo)135 int DynamicHosts_Init(ConfigFileInfo *ConfigInfo)
136 {
137 	StringList  *Hosts;
138 	int          UpdateInterval;
139 	const char  *RawScript;
140 
141 	Hosts = ConfigGetStringList(ConfigInfo, "Hosts");
142 	if( Hosts == NULL )
143 	{
144 		File = NULL;
145 		return -151;
146 	}
147 
148 	Hosts->TrimAll(Hosts, "\"\t ");
149 
150     HostsURLs = Hosts->ToCharPtrArray(Hosts);
151 	UpdateInterval = ConfigGetInt32(ConfigInfo, "HostsUpdateInterval");
152 	HostsRetryInterval = ConfigGetInt32(ConfigInfo, "HostsRetryInterval");
153 
154 	RawScript = ConfigGetRawString(ConfigInfo, "HostsScript");
155 	if( RawScript != NULL )
156     {
157         static const int SIZE_OF_PATH_BUFFER = 1024;
158 
159         Script = SafeMalloc(SIZE_OF_PATH_BUFFER);
160         if( Script == NULL )
161         {
162             ERRORMSG("No enough memory.\n");
163             return -160;
164         }
165 
166         strcpy(Script, RawScript);
167 
168         if( ExpandPath(Script, SIZE_OF_PATH_BUFFER) != 0 )
169         {
170             ERRORMSG("Path is too long : .\n", Script);
171             return -170;
172         }
173     } else {
174         Script = NULL;
175     }
176 
177 	RWLock_Init(HostsLock);
178 
179 	File = ConfigGetRawString(ConfigInfo, "HostsDownloadPath");
180 
181 	if( HostsRetryInterval < 0 )
182 	{
183 		ERRORMSG("`HostsRetryInterval' is too small (< 0).\n");
184 		File = NULL;
185 		return -167;
186 	}
187 
188 	INFO("Local hosts file : \"%s\"\n", File);
189 
190 	if( FileIsReadable(File) )
191 	{
192 		INFO("Loading the existing hosts file ...\n");
193 		DynamicHosts_Load();
194 	} else {
195 		INFO("Hosts file is unreadable, this may cause some failures.\n");
196 	}
197 
198 	if( UpdateInterval <= 0 )
199     {
200         TimedTask_Add(FALSE,
201                       TRUE,
202                       0,
203                       (TaskFunc)GetHostsFromInternet_Thread,
204                       NULL,
205                       NULL,
206                       TRUE);
207     } else {
208         TimedTask_Add(TRUE,
209                       TRUE,
210                       UpdateInterval * 1000,
211                       (TaskFunc)GetHostsFromInternet_Thread,
212                       NULL,
213                       NULL,
214                       TRUE);
215     }
216 
217 	return 0;
218 }
219 
DynamicHosts_GetCName(const char * Domain,char * Buffer)220 int DynamicHosts_GetCName(const char *Domain, char *Buffer)
221 {
222     int ret;
223 
224     if( MainDynamicContainer == NULL )
225     {
226         return -198;
227     }
228 
229     RWLock_RdLock(HostsLock);
230 
231     ret = HostsUtils_GetCName(Domain,
232                               Buffer,
233                               (HostsContainer *)MainDynamicContainer
234                               );
235 
236     RWLock_UnRLock(HostsLock);
237 
238     return ret;
239 }
240 
DynamicHosts_TypeExisting(const char * Domain,HostsRecordType Type)241 BOOL DynamicHosts_TypeExisting(const char *Domain, HostsRecordType Type)
242 {
243     BOOL ret;
244 
245     if( MainDynamicContainer == NULL )
246     {
247         return FALSE;
248     }
249 
250     RWLock_RdLock(HostsLock);
251 
252     ret = HostsUtils_TypeExisting((HostsContainer *)MainDynamicContainer,
253                                   Domain,
254                                   Type
255                                   );
256 
257     RWLock_UnRLock(HostsLock);
258 
259     return ret;
260 }
261 
DynamicHosts_Try(IHeader * Header,int BufferLength)262 HostsUtilsTryResult DynamicHosts_Try(IHeader *Header, int BufferLength)
263 {
264     HostsUtilsTryResult ret;
265 
266     if( MainDynamicContainer == NULL )
267     {
268         return HOSTSUTILS_TRY_NONE;
269     }
270 
271     RWLock_RdLock(HostsLock);
272 
273     ret = HostsUtils_Try(Header,
274                          BufferLength,
275                          (HostsContainer *)MainDynamicContainer
276                          );
277 
278     RWLock_UnRLock(HostsLock);
279 
280     return ret;
281 }
282