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