Rev 1514 | Go to most recent revision | Details | Compare with Previous | Last modification | View Log | RSS feed
Rev | Author | Line No. | Line |
---|---|---|---|
1155 | clevermous | 1 | format MS COFF |
2 | |||
3 | public @EXPORT as 'EXPORTS' |
||
4 | |||
1200 | hidnplayr | 5 | include '../struct.inc' |
6 | include '../proc32.inc' |
||
7 | include '../macros.inc' |
||
1155 | clevermous | 8 | purge section,mov,add,sub |
9 | |||
1542 | hidnplayr | 10 | include '../network.inc' |
1155 | clevermous | 11 | |
12 | section '.flat' code readable align 16 |
||
13 | |||
14 | ;;===========================================================================;; |
||
15 | lib_init: ;//////////////////////////////////////////////////////////////////;; |
||
16 | ;;---------------------------------------------------------------------------;; |
||
17 | ;? Library entry point (called after library load) ;; |
||
18 | ;;---------------------------------------------------------------------------;; |
||
19 | ;> eax = pointer to memory allocation routine ;; |
||
20 | ;> ebx = pointer to memory freeing routine ;; |
||
21 | ;> ecx = pointer to memory reallocation routine ;; |
||
22 | ;> edx = pointer to library loading routine ;; |
||
23 | ;;---------------------------------------------------------------------------;; |
||
24 | ;< eax = 1 (fail) / 0 (ok) (library initialization result) ;; |
||
25 | ;;===========================================================================;; |
||
26 | mov [mem.alloc], eax |
||
27 | mov [mem.free], ebx |
||
28 | mov [mem.realloc], ecx |
||
29 | mov [dll.load], edx |
||
30 | mov [DNSrequestID], 1 |
||
1200 | hidnplayr | 31 | stdcall edx, @IMPORT |
1542 | hidnplayr | 32 | xor eax, eax |
33 | ret |
||
1155 | clevermous | 34 | |
35 | ;;===========================================================================;; |
||
36 | ;; in_addr_t __stdcall inet_addr(__in const char* hostname); ;; |
||
1200 | hidnplayr | 37 | inet_addr: ;; |
1155 | clevermous | 38 | ;;---------------------------------------------------------------------------;; |
39 | ;? Convert the string from standard IPv4 dotted notation to integer IP addr. ;; |
||
40 | ;;---------------------------------------------------------------------------;; |
||
41 | ;> first parameter = host name ;; |
||
42 | ;;---------------------------------------------------------------------------;; |
||
43 | ;< eax = IP address on success / -1 on error ;; |
||
44 | ;;===========================================================================;; |
||
45 | ; 0. Save used registers for __stdcall. |
||
46 | push ebx esi edi |
||
47 | mov esi, [esp+16] ; esi = hostname |
||
48 | ; 1. Check that only allowed symbols are present. |
||
49 | ; (hex digits, possibly letters 'x'/'X' and up to 3 dots) |
||
50 | push esi |
||
51 | xor ecx, ecx |
||
52 | .calcdots_loop: |
||
53 | ; loop for all characters in string |
||
54 | lodsb |
||
55 | ; check for end of string |
||
56 | cmp al, 0 |
||
57 | jz .calcdots_loop_done |
||
58 | ; check for dot |
||
59 | cmp al, '.' |
||
60 | jz .dot |
||
61 | ; check for digit |
||
62 | sub al, '0' |
||
63 | cmp al, 9 |
||
64 | jbe .calcdots_loop |
||
65 | ; check for hex letter |
||
66 | sub al, 'A' - '0' ; 'A'-'F' -> 0-5, 'a'-'f' -> 20h-25h |
||
67 | and al, not 20h |
||
68 | cmp al, 'F' - 'A' |
||
69 | jbe .calcdots_loop |
||
70 | ; check for 'x'/'X' |
||
71 | cmp al, 'X' - 'A' |
||
72 | jz .calcdots_loop |
||
73 | jmp .fail.pop |
||
74 | .dot: |
||
75 | inc ecx |
||
76 | jmp .calcdots_loop |
||
77 | .calcdots_loop_done: |
||
78 | cmp ecx, 4 |
||
79 | jae .fail.pop |
||
80 | ; 2. The name can be valid dotted name; try to convert, checking limit |
||
81 | pop esi |
||
82 | xor edi, edi ; edi = address |
||
83 | push 0xFFFFFFFF |
||
84 | pop edx ; edx = mask for rest of address |
||
85 | ; 2a. Convert name except for last group. |
||
86 | jecxz .ip_convert_2b |
||
87 | .ip_convert_2a: |
||
88 | push ecx |
||
89 | mov ecx, 0xFF ; limit for all groups except for last |
||
90 | call .get_number |
||
91 | pop ecx |
||
92 | jc .fail |
||
93 | cmp byte [esi-1], '.' |
||
94 | jnz .fail |
||
95 | shl edi, 8 |
||
96 | shr edx, 8 |
||
97 | add edi, eax |
||
98 | loop .ip_convert_2a |
||
99 | ; 2b. Convert last group. |
||
100 | .ip_convert_2b: |
||
101 | mov ecx, edx |
||
102 | call .get_number |
||
103 | jc .fail |
||
104 | cmp byte [esi-1], 0 |
||
105 | jnz .fail |
||
106 | @@: |
||
107 | shl edi, 8 |
||
108 | shr edx, 8 |
||
109 | jnz @b |
||
110 | add edi, eax |
||
111 | ; 2c. Convert to network byte order. |
||
112 | bswap edi |
||
113 | ; 3. Set return value, restore used registers and return. |
||
114 | xchg eax, edi |
||
115 | .ret: |
||
116 | pop edi esi ebx |
||
117 | ret 4 |
||
118 | ; 4. On error, return -1. |
||
119 | .fail.pop: |
||
120 | pop esi |
||
121 | .fail: |
||
122 | push -1 |
||
123 | pop eax |
||
124 | jmp .ret |
||
125 | |||
126 | ;;===========================================================================;; |
||
127 | ;; Internal auxiliary function for IP parsing. ;; |
||
1200 | hidnplayr | 128 | .get_number: ;; |
1155 | clevermous | 129 | ;;---------------------------------------------------------------------------;; |
130 | ;? Converts string to number. ;; |
||
131 | ;;---------------------------------------------------------------------------;; |
||
132 | ;> esi -> string ;; |
||
133 | ;> ecx = limit for number ;; |
||
134 | ;;---------------------------------------------------------------------------;; |
||
135 | ;< eax = number ;; |
||
136 | ;< CF set on error (too big number) / cleared on success ;; |
||
137 | ;< esi -> end of number representation ;; |
||
138 | ;;===========================================================================;; |
||
139 | ; 0. Save edx, which is used in caller. |
||
140 | push edx |
||
141 | ; 1. Initialize number, zero eax so that lodsb gets full dword. |
||
142 | xor eax, eax |
||
143 | xor edx, edx |
||
144 | ; 2. Get used numeral system: 0x = hex, otherwise 0 = octal, otherwise decimal |
||
145 | push 10 |
||
146 | pop ebx |
||
147 | lodsb |
||
148 | cmp al, '0' |
||
149 | jnz .convert |
||
150 | push 8 |
||
151 | pop ebx |
||
152 | lodsb |
||
153 | cmp al, 'x' |
||
154 | jnz .convert |
||
155 | add ebx, ebx |
||
156 | ; 3. Loop while digits are encountered. |
||
157 | .convert: |
||
158 | ; 4. Convert digit from text representation to binary value. |
||
1200 | hidnplayr | 159 | or al, 20h ; '0'-'9' -> '0'-'9', 'A'-'F' -> 'a'-'f' |
1155 | clevermous | 160 | sub al, '0' |
161 | cmp al, 9 |
||
162 | jbe .digit |
||
163 | sub al, 'a' - '0' |
||
164 | cmp al, 'f' - 'a' |
||
165 | ja .convert_done |
||
166 | add al, 10 |
||
167 | .digit: |
||
168 | ; 5. Digit must be less than base of numeral system. |
||
169 | cmp eax, ebx |
||
170 | jae .convert_done |
||
171 | ; 6. Advance the number. |
||
172 | imul edx, ebx |
||
173 | add edx, eax |
||
174 | cmp edx, ecx |
||
175 | ja .gn_error |
||
176 | ; 3b. Continue loop. |
||
177 | lodsb |
||
178 | jmp .convert |
||
179 | .convert_done: |
||
180 | ; 7. Invalid character, number converted, return success. |
||
181 | xchg eax, edx |
||
182 | pop edx |
||
183 | clc |
||
184 | ret |
||
185 | .gn_error: |
||
186 | ; 8. Too big number, return error. |
||
187 | pop edx |
||
188 | stc |
||
189 | ret |
||
190 | |||
191 | ;;===========================================================================;; |
||
192 | ;; char* __stdcall inet_ntoa(struct in_addr in); ;; |
||
1200 | hidnplayr | 193 | inet_ntoa: ;; |
1155 | clevermous | 194 | ;;---------------------------------------------------------------------------;; |
195 | ;? Convert the Internet host address to standard IPv4 dotted notation. ;; |
||
196 | ;;---------------------------------------------------------------------------;; |
||
197 | ;> first parameter = host address ;; |
||
198 | ;;---------------------------------------------------------------------------;; |
||
199 | ;< eax = pointer to resulting string (in static buffer) ;; |
||
200 | ;;===========================================================================;; |
||
201 | ; 0. Save used registers for __stdcall. |
||
202 | push ebx esi edi |
||
203 | mov bl, 0xCD ; constant for div 10 |
||
204 | ; 1. Write octet 4 times. |
||
205 | mov edi, .buffer |
||
206 | mov edx, [esp+16] ; eax = in |
||
207 | mov al, dl |
||
208 | call .write |
||
209 | mov al, dh |
||
210 | shr edx, 16 |
||
211 | call .write |
||
212 | mov al, dl |
||
213 | call .write |
||
214 | mov al, dh |
||
215 | call .write |
||
216 | ; 2. Replace final dot with terminating zero. |
||
217 | mov byte [edi-1], 0 |
||
218 | ; 3. Restore used registers, set result value and return. |
||
219 | pop edi esi ebx |
||
220 | mov eax, .buffer |
||
221 | ret 4 |
||
222 | |||
223 | .write: |
||
224 | movzx esi, al |
||
225 | mul bl |
||
226 | add esi, ('.' shl 8) + '0' |
||
227 | shr ah, 3 ; ah = al / 10 |
||
228 | movzx ecx, ah |
||
229 | add ecx, ecx |
||
230 | lea ecx, [ecx*5] |
||
231 | sub esi, ecx ; lobyte(esi) = al % 10, hibyte(esi) = '.' |
||
232 | test ah, ah |
||
233 | jz .1digit |
||
234 | cmp ah, 10 |
||
235 | jb .2digit |
||
236 | cmp ah, 20 |
||
237 | sbb cl, cl |
||
238 | add cl, '2' |
||
239 | mov byte [edi], cl |
||
240 | movzx ecx, cl |
||
241 | lea ecx, [ecx*5] |
||
242 | sub ah, cl |
||
243 | sub ah, cl |
||
244 | add ah, ('0'*11) and 255 |
||
245 | mov byte [edi+1], ah |
||
246 | mov word [edi+2], si |
||
247 | add edi, 4 |
||
248 | ret |
||
249 | .2digit: |
||
250 | add ah, '0' |
||
251 | mov byte [edi], ah |
||
252 | mov word [edi+1], si |
||
253 | add edi, 3 |
||
254 | ret |
||
255 | .1digit: |
||
256 | mov word [edi], si |
||
257 | add edi, 2 |
||
258 | ret |
||
259 | |||
260 | struct __gai_reqdata |
||
1542 | hidnplayr | 261 | socketnum dd ? |
1155 | clevermous | 262 | ; external code should not look on rest of this structure, |
263 | ; it is internal for getaddrinfo_start/process/abort |
||
264 | reqid dw ? ; DNS request ID |
||
265 | socktype db ? ; SOCK_* or 0 for any |
||
266 | db ? |
||
1200 | hidnplayr | 267 | service dd ? |
1155 | clevermous | 268 | flags dd ? |
269 | reserved rb 16 |
||
270 | ends |
||
271 | |||
272 | ;;===========================================================================;; |
||
273 | ;; int __stdcall getaddrinfo(__in const char* hostname, ;; |
||
274 | ;; __in const char* servname, ;; |
||
275 | ;; __in const struct addrinfo* hints, ;; |
||
276 | ;; __out struct addrinfo **res); ;; |
||
1200 | hidnplayr | 277 | getaddrinfo: ;; |
1155 | clevermous | 278 | ;;---------------------------------------------------------------------------;; |
279 | ;? Get a list of IP addresses and port numbers for given host and service ;; |
||
280 | ;;---------------------------------------------------------------------------;; |
||
281 | ;> first parameter (optional) = host name ;; |
||
282 | ;> second parameter (optional) = service name (decimal number for now) ;; |
||
1542 | hidnplayr | 283 | ;> third parameter (optional) = hints for socketnum type ;; |
1155 | clevermous | 284 | ;> fourth parameter = pointer to result (head of L1-list) ;; |
285 | ;;---------------------------------------------------------------------------;; |
||
286 | ;< eax = 0 on success / one of EAI_ codes on error ;; |
||
287 | ;;===========================================================================;; |
||
288 | ; 0. Save used registers for __stdcall. |
||
289 | push ebx esi edi |
||
290 | mov edi, [esp+28] ; edi = res |
||
291 | ; 1. Create and send DNS packet. |
||
292 | sub esp, sizeof.__gai_reqdata ; reserve stack place (1) |
||
293 | push esp ; fifth parameter = pointer to (1) |
||
294 | push edi ; fourth parameter = res |
||
295 | push dword [esp+32+sizeof.__gai_reqdata] ; third parameter = hints |
||
296 | push dword [esp+32+sizeof.__gai_reqdata] ; second parameter = servname |
||
297 | push dword [esp+32+sizeof.__gai_reqdata] ; first parameter = hostname |
||
298 | call getaddrinfo_start |
||
299 | test eax, eax |
||
300 | jns .ret ; if name resolved without network activity, return |
||
301 | ; 2. Wait for DNS reply. |
||
302 | ; 2a. Ignore all events except network stack. |
||
303 | mcall 40, EVM_STACK |
||
304 | push eax ; save previous event mask (2) |
||
305 | ; 2b. Get upper limit for wait time. Use timeout = 5 seconds. |
||
306 | mcall 26, 9 ; get time stamp |
||
307 | xchg esi, eax ; save time stamp to esi |
||
308 | mov ebx, 500 ; start value for timeout |
||
309 | add esi, ebx |
||
310 | .wait: |
||
311 | ; 2c. Wait for event with timeout. |
||
312 | mcall 23 ; wait for event - must be stack event |
||
313 | ; 2d. Check for timeout. |
||
314 | test eax, eax |
||
315 | lea eax, [esp+4] ; pointer to (1) |
||
316 | jz .timeout |
||
317 | ; 3. Got packet. Call processing function. |
||
318 | push edi ; second parameter: pointer to result |
||
319 | push eax ; first parameter: pointer to reqdata |
||
320 | call getaddrinfo_process |
||
321 | ; 4. Test whether wait loop must be continued. |
||
322 | test eax, eax |
||
323 | jns .ret.restore |
||
324 | ; 2e. Recalculate timeout value. |
||
325 | mcall 26, 9 |
||
326 | mov ebx, esi |
||
327 | sub ebx, eax |
||
328 | ; 2f. Check that time is not over; if not, continue wait loop |
||
329 | cmp ebx, 500 |
||
330 | jbe .wait |
||
331 | .timeout: |
||
332 | ; 5. Timeout: abort and return error |
||
333 | push eax |
||
334 | call getaddrinfo_abort |
||
335 | and dword [edi], 0 |
||
336 | push EAI_AGAIN |
||
337 | pop eax |
||
338 | .ret.restore: |
||
339 | ; 6. Restore event mask. |
||
340 | pop ebx ; get event mask (2) |
||
341 | push eax ; save return code (3) |
||
342 | mcall 40 |
||
343 | pop eax ; restore return code (3) |
||
344 | .ret: |
||
345 | ; 7. Restore stack pointer, used registers and return. |
||
346 | add esp, sizeof.__gai_reqdata ; undo (1) |
||
347 | pop edi esi ebx |
||
348 | ret 16 |
||
349 | |||
350 | ;;===========================================================================;; |
||
351 | ;; int __stdcall getaddrinfo_start(__in const char* hostname, ;; |
||
352 | ;; __in const char* servname, ;; |
||
353 | ;; __in const struct addrinfo* hints, ;; |
||
354 | ;; __out struct addrinfo **res, ;; |
||
355 | ;; __out struct __gai_reqdata* reqdata); ;; |
||
1200 | hidnplayr | 356 | getaddrinfo_start: ;; |
1155 | clevermous | 357 | ;;---------------------------------------------------------------------------;; |
358 | ;? Initiator for getaddrinfo, sends DNS request ;; |
||
359 | ;;---------------------------------------------------------------------------;; |
||
360 | ;> first 4 parameters same as for getaddrinfo ;; |
||
361 | ;> last parameter = pointer to buffer for __gai_reqdata, must be passed to ;; |
||
362 | ;> getaddrinfo_process as is ;; |
||
363 | ;;---------------------------------------------------------------------------;; |
||
364 | ;< eax = <0 if wait loop must be entered / 0 on success / EAI_* on error ;; |
||
365 | ;;===========================================================================;; |
||
366 | ;; Known limitations: ;; |
||
367 | ;; 1. No support for TCP connections => ;; |
||
368 | ;; 1a. Long replies will be truncated, and not all IP addresses will be got. ;; |
||
369 | ;; 2. No support for iterative resolving => ;; |
||
370 | ;; 2a. In theory may fail with some servers. ;; |
||
371 | ;; 3. Assumes that domain for relative names is always root, ".". ;; |
||
372 | ;; 4. Does not support lookup of services by name, ;; |
||
373 | ;; only decimal representation is supported. ;; |
||
374 | ;; 5. Assumes that IPv4 is always configured, so AI_ADDRCONFIG has no effect.;; |
||
375 | ;;===========================================================================;; |
||
376 | ; 0. Create stack frame and save used registers for __stdcall. |
||
377 | push ebx esi edi |
||
378 | push ebp |
||
379 | mov ebp, esp |
||
380 | virtual at ebp-8 |
||
381 | .recent_restsize dd ? ; this is for memory alloc in ._.generate_data |
||
382 | .recent_page dd ? ; this is for memory alloc in ._.generate_data |
||
383 | rd 5 ; saved regs and return address |
||
384 | .hostname dd ? |
||
385 | .servname dd ? |
||
386 | .hints dd ? |
||
387 | .res dd ? |
||
388 | .reqdata dd ? |
||
389 | end virtual |
||
390 | xor edi, edi |
||
391 | push edi ; init .recent_page |
||
392 | push edi ; init .recent_restsize |
||
393 | ; 1. Check that parameters are correct and can be handled by this implementation. |
||
394 | ; 1a. If 'res' pointer is given, set result to zero. |
||
395 | mov eax, [.res] |
||
396 | test eax, eax |
||
397 | jz @f |
||
398 | mov [eax], edi |
||
399 | @@: |
||
400 | ; 1b. Only AI_SUPPORTED flags are supported for hints->ai_flags. |
||
401 | mov ecx, [.hints] |
||
402 | xor edx, edx |
||
403 | jecxz .nohints |
||
404 | mov edx, [ecx+addrinfo.ai_flags] |
||
405 | .nohints: |
||
406 | mov ebx, [.reqdata] |
||
407 | mov [ebx+__gai_reqdata.flags], edx |
||
408 | push EAI_BADFLAGS |
||
409 | pop eax |
||
410 | test edx, not AI_SUPPORTED |
||
411 | jnz .ret |
||
412 | ; 1c. Either hostname or servname must be given. If AI_CANONNAME is set, |
||
413 | ; hostname must also be set. |
||
414 | cmp [.hostname], edi |
||
415 | jnz @f |
||
416 | test dl, AI_CANONNAME |
||
417 | jnz .ret |
||
418 | push EAI_NONAME |
||
419 | pop eax |
||
420 | cmp [.servname], edi |
||
421 | jz .ret |
||
422 | @@: |
||
423 | ; 1d. Only IPv4 is supported, so hints->ai_family must be either PF_UNSPEC or PF_INET. |
||
424 | push EAI_FAMILY |
||
425 | pop eax |
||
426 | jecxz @f |
||
427 | cmp [ecx+addrinfo.ai_family], edi |
||
428 | jz @f |
||
1542 | hidnplayr | 429 | cmp [ecx+addrinfo.ai_family], AF_INET4 |
1155 | clevermous | 430 | jnz .ret |
431 | @@: |
||
432 | ; 1e. Valid combinations for ai_socktype/ai_protocol: 0/0 for any or |
||
1200 | hidnplayr | 433 | ; SOCK_STREAM/IPPROTO_TCP, SOCK_DGRAM/IPPROTO_UDP |
1542 | hidnplayr | 434 | ; (raw socketnums are not yet supported by the kernel) |
1155 | clevermous | 435 | xor edx, edx ; assume 0=any if no hints |
1542 | hidnplayr | 436 | jecxz .socketnum_type_ok |
1155 | clevermous | 437 | mov edx, [ecx+addrinfo.ai_socktype] |
438 | mov esi, [ecx+addrinfo.ai_protocol] |
||
439 | ; 1f. Test for ai_socktype=0 and ai_protocol=0. |
||
440 | test edx, edx |
||
441 | jnz .check_socktype |
||
442 | test esi, esi |
||
1542 | hidnplayr | 443 | jz .socketnum_type_ok |
1155 | clevermous | 444 | ; 1g. ai_socktype=0, ai_protocol is nonzero. |
445 | push EAI_SERVICE |
||
446 | pop eax |
||
447 | inc edx ; edx = SOCK_STREAM |
||
448 | cmp esi, IPPROTO_TCP |
||
1542 | hidnplayr | 449 | jz .socketnum_type_ok |
1155 | clevermous | 450 | inc edx ; edx = SOCK_DGRAM |
451 | cmp esi, IPPROTO_UDP |
||
1542 | hidnplayr | 452 | jz .socketnum_type_ok |
1155 | clevermous | 453 | .ret: |
454 | ; Restore saved registers, destroy stack frame and return. |
||
455 | mov esp, ebp |
||
456 | pop ebp |
||
457 | pop edi esi ebx |
||
458 | ret 20 |
||
459 | ; 1h. ai_socktype is nonzero. |
||
460 | .check_socktype: |
||
461 | push EAI_SOCKTYPE |
||
462 | pop eax |
||
463 | cmp edx, SOCK_STREAM |
||
464 | jz .check_tcp |
||
465 | cmp edx, SOCK_DGRAM |
||
466 | jnz .ret |
||
467 | test esi, esi |
||
1542 | hidnplayr | 468 | jz .socketnum_type_ok |
1155 | clevermous | 469 | cmp esi, IPPROTO_UDP |
1542 | hidnplayr | 470 | jz .socketnum_type_ok |
1155 | clevermous | 471 | jmp .ret |
472 | .check_tcp: |
||
473 | test esi, esi |
||
1542 | hidnplayr | 474 | jz .socketnum_type_ok |
1155 | clevermous | 475 | cmp esi, IPPROTO_TCP |
476 | jnz .ret |
||
1542 | hidnplayr | 477 | .socketnum_type_ok: |
1155 | clevermous | 478 | mov [ebx+__gai_reqdata.socktype], dl |
479 | ; 2. Resolve service. |
||
480 | ; 2a. If no name is given, remember value -1. |
||
481 | push -1 |
||
482 | pop edx |
||
483 | mov esi, [.servname] |
||
484 | test esi, esi |
||
485 | jz .service_resolved |
||
486 | ; 2b. Loop for characters of string while digits are encountered. |
||
487 | xor edx, edx |
||
488 | xor eax, eax |
||
489 | .serv_to_number: |
||
490 | lodsb |
||
491 | sub al, '0' |
||
492 | cmp al, 9 |
||
493 | ja .serv_to_number_done |
||
494 | ; for each digit, set edx = edx*10 + |
||
495 | lea edx, [edx*5] |
||
496 | lea edx, [edx*2+eax] |
||
497 | ; check for correctness: service port must fit in word |
||
498 | cmp edx, 0x10000 |
||
499 | jae .service_not_number |
||
500 | jmp .serv_to_number |
||
501 | .serv_to_number_done: |
||
502 | and edx, 0xFFFF ; make sure that port fits |
||
503 | ; 2c. If zero character reached, name is resolved; |
||
504 | ; otherwise, return error (no support for symbolic names yet) |
||
505 | cmp al, -'0' |
||
506 | jz .service_resolved |
||
507 | .service_not_number: |
||
508 | push EAI_NONAME |
||
509 | pop eax |
||
510 | jmp .ret |
||
511 | .service_resolved: |
||
512 | ; 2d. Save result to reqdata. |
||
513 | mov [ebx+__gai_reqdata.service], edx |
||
514 | ; 3. Process host name. |
||
515 | mov esi, [.hostname] |
||
516 | ; 3a. If hostname is not given, |
||
1542 | hidnplayr | 517 | ; use localhost for active socketnums and INADDR_ANY for passive socketnums. |
1200 | hidnplayr | 518 | mov eax, 0x0100007F ; 127.0.0.1 in network byte order |
1155 | clevermous | 519 | test byte [ebx+__gai_reqdata.flags], AI_PASSIVE |
520 | jz @f |
||
521 | xor eax, eax |
||
522 | @@: |
||
523 | test esi, esi |
||
524 | jz .hostname_is_ip |
||
525 | ; 3b. Check for dotted IPv4 name. |
||
526 | push esi |
||
527 | call inet_addr |
||
528 | cmp eax, -1 |
||
529 | jz .resolve_hostname |
||
530 | .hostname_is_ip: |
||
531 | ; 3c. hostname is valid representation of IP address, and we have resolved it. |
||
532 | ; Generate result, if .res pointer is not NULL. |
||
533 | mov ebx, [.reqdata] |
||
534 | mov esi, [.res] |
||
535 | test esi, esi |
||
536 | jz .no_result |
||
537 | call getaddrinfo._.generate_data |
||
538 | ; 3d. Check for memory allocation error. |
||
539 | .3d: |
||
540 | push EAI_MEMORY |
||
541 | pop eax |
||
542 | test esi, esi |
||
543 | jz .ret |
||
544 | ; 3e. If AI_CANONNAME is set, copy input name. |
||
545 | test byte [ebx+__gai_reqdata.flags], AI_CANONNAME |
||
546 | jz .no_result |
||
547 | ; 3f. Calculate length of name. |
||
548 | push -1 |
||
549 | pop ecx |
||
550 | mov edi, [.hostname] |
||
551 | xor eax, eax |
||
552 | repnz scasb |
||
553 | not ecx |
||
554 | ; 3g. Check whether it fits on one page with main data. |
||
555 | cmp ecx, [.recent_restsize] |
||
556 | jbe .name_fits |
||
557 | ; 3h. If not, allocate new page. |
||
558 | push ecx |
||
559 | add ecx, 4 ; first dword contains number of objects on the page |
||
560 | mcall 68, 12 |
||
561 | pop ecx |
||
562 | ; 3i. If allocation has failed, free addrinfo and return error. |
||
563 | test eax, eax |
||
564 | jnz .name_allocated |
||
565 | push [.res] |
||
566 | call freeaddrinfo |
||
567 | push EAI_MEMORY |
||
568 | pop eax |
||
569 | jmp .ret |
||
570 | .name_allocated: |
||
571 | ; 3j. Otherwise, set edi to allocated memory and continue to 3l. |
||
572 | xchg edi, eax ; put result to edi |
||
573 | push 1 |
||
574 | pop eax |
||
575 | stosd ; number of objects on the page = 1 |
||
576 | jmp .copy_name |
||
577 | .name_fits: |
||
578 | ; 3k. Get pointer to free memory in allocated page. |
||
579 | mov edi, [.recent_page] |
||
580 | mov eax, edi |
||
581 | and eax, not 0xFFF |
||
582 | inc dword [eax] ; increase number of objects |
||
583 | .copy_name: |
||
584 | ; 3l. Put pointer to struct addrinfo. |
||
585 | mov eax, [.res] |
||
586 | mov eax, [eax] |
||
587 | mov [eax+addrinfo.ai_canonname], edi |
||
588 | ; 3m. Copy name. |
||
589 | rep movsb |
||
590 | .no_result: |
||
591 | ; 3n. Return success. |
||
592 | xor eax, eax |
||
593 | jmp .ret |
||
594 | ; 4. Host address is not dotted IP. Test whether we are allowed to contact DNS. |
||
595 | ; Return error if no. |
||
596 | .resolve_hostname: |
||
597 | push EAI_NONAME |
||
598 | pop eax |
||
599 | mov ebx, [.reqdata] |
||
600 | test byte [ebx+__gai_reqdata.flags], AI_NUMERICHOST |
||
601 | jnz .ret |
||
602 | ; Host address is domain name. Contact DNS server. |
||
603 | mov esi, [.hostname] |
||
604 | ; 5. Reserve stack place for UDP packet. |
||
605 | ; According to RFC1035, maximum UDP packet size in DNS is 512 bytes. |
||
606 | sub esp, 512 |
||
607 | ; 6. Create DNS request packet. |
||
608 | ; 6a. Set pointer to start of buffer. |
||
609 | mov edi, esp |
||
610 | ; 6b. Get request ID, write it to buffer. |
||
611 | push 1 |
||
612 | pop eax |
||
613 | lock xadd [DNSrequestID], eax ; atomically increment ID, get old value |
||
614 | stosw |
||
615 | mov [ebx+__gai_reqdata.reqid], ax |
||
616 | ; 6c. Packed field: QR=0 (query), Opcode=0000 (standard query), |
||
1200 | hidnplayr | 617 | ; AA=0 (ignored in requests), TC=0 (no truncation), |
618 | ; RD=1 (recursion desired) |
||
1155 | clevermous | 619 | mov al, 00000001b |
620 | stosb |
||
621 | ; 6d. Packed field: ignored in requests |
||
622 | mov al, 0 |
||
623 | stosb |
||
624 | ; 6e. Write questions count = 1 and answers count = 0 |
||
625 | ; Note that network byte order is big-endian. |
||
626 | mov eax, 0x00000100 |
||
627 | stosd |
||
628 | ; 6f. Write nameservers count = 0 and additional records count = 0 |
||
629 | xor eax, eax |
||
630 | stosd |
||
631 | ; 6g. Write request data: name |
||
632 | ; According to RFC1035, maximum length of name is 255 bytes. |
||
633 | ; For correct names, buffer cannot overflow. |
||
634 | lea ebx, [esi+256] ; ebx = limit for name (including terminating zero) |
||
635 | ; translate string "www.yandex.ru" {00} to byte data {03} "www" {06} "yandex" {02} "ru" {00} |
||
636 | .nameloop: ; here we go in the start of each label: before "www", before "yandex", before "ru" |
||
637 | xor ecx, ecx ; ecx = length of current label |
||
638 | inc edi ; skip length, it will be filled later |
||
639 | .labelloop: ; here we go for each symbol of name |
||
640 | lodsb ; get next character |
||
641 | test al, al ; terminating zero? |
||
642 | jz .endname |
||
643 | cmp esi, ebx ; limit exceeded? |
||
644 | jae .wrongname |
||
1200 | hidnplayr | 645 | cmp al, '.' ; end of label? |
1155 | clevermous | 646 | jz .labelend |
647 | stosb ; put next character |
||
648 | inc ecx ; increment label length |
||
649 | jmp .labelloop |
||
650 | .wrongname: |
||
651 | push EAI_NONAME |
||
652 | pop eax |
||
653 | jmp .ret |
||
654 | .labelend: |
||
655 | test ecx, ecx ; null label can be only in the end of name |
||
656 | jz .wrongname |
||
657 | .endname: |
||
658 | cmp ecx, 63 |
||
659 | ja .wrongname |
||
660 | ; write length to byte [edi-ecx-1] |
||
661 | mov eax, ecx |
||
662 | neg eax |
||
663 | mov byte [edi+eax-1], cl |
||
1200 | hidnplayr | 664 | cmp byte [esi-1], 0 ; that was last label in the name? |
1155 | clevermous | 665 | jnz .nameloop |
666 | ; write terminating zero if not yet |
||
667 | mov al, 0 |
||
668 | cmp byte [edi-1], al |
||
669 | jz @f |
||
670 | stosb |
||
671 | @@: |
||
672 | ; 6h. Write request data: |
||
1200 | hidnplayr | 673 | ; query type = A (host address) = 1, |
674 | ; query class = IN (internet IPv4 address) = 1 |
||
1155 | clevermous | 675 | ; Note that network byte order is big-endian. |
676 | mov eax, 0x01000100 |
||
677 | stosd |
||
678 | ; 7. Get DNS server address. |
||
1208 | hidnplayr | 679 | mcall 75, 0x00000004 ; protocol IP=0, device number=0, function=get DNS address |
1197 | clevermous | 680 | cmp eax, -1 |
1208 | hidnplayr | 681 | je .ret.dnserr |
682 | mov esi, eax ; put server address to esi |
||
1542 | hidnplayr | 683 | ; 8. Open UDP socketnum to DNS server, port 53. |
684 | ; 8a. Create new socketnum. |
||
685 | mcall 74, 0, AF_INET4, SOCK_DGRAM |
||
1200 | hidnplayr | 686 | cmp eax, -1 ; error? |
1155 | clevermous | 687 | jz .ret.dnserr |
1542 | hidnplayr | 688 | mov ecx, eax ; put socketnum handle to ecx |
1197 | clevermous | 689 | ; 8b. Create sockaddr structure on the stack. |
690 | push 0 |
||
691 | push 0 ; sin_zero |
||
692 | push esi ; sin_addr |
||
1542 | hidnplayr | 693 | push AF_INET4 + (53 shl 16) |
1197 | clevermous | 694 | ; sin_family and sin_port in network byte order |
1208 | hidnplayr | 695 | ; 8c. Connect. |
1197 | clevermous | 696 | mcall 74, 4, , esp, sizeof.sockaddr_in |
697 | ; 8d. Restore the stack, undo 8b. |
||
698 | add esp, esi |
||
699 | ; 8e. Check result. |
||
700 | cmp eax, -1 |
||
701 | jz .ret.close |
||
1155 | clevermous | 702 | ; 9. Send DNS request packet. |
703 | sub edi, esp ; get packet length |
||
1197 | clevermous | 704 | mov esi, edi |
705 | xor edi, edi |
||
706 | mcall 74, 6, , esp |
||
1155 | clevermous | 707 | cmp eax, -1 |
708 | jz .ret.close |
||
709 | mov eax, [.reqdata] |
||
1542 | hidnplayr | 710 | mov [eax+__gai_reqdata.socketnum], ecx |
1155 | clevermous | 711 | push -1 |
712 | pop eax ; return status: more processing required |
||
713 | jmp .ret.dns |
||
714 | .ret.close: |
||
1197 | clevermous | 715 | mcall 74, 1 |
1155 | clevermous | 716 | .ret.dnserr: |
717 | push EAI_AGAIN |
||
718 | pop eax |
||
719 | .ret.dns: |
||
720 | ; 6. Restore stack pointer and return. |
||
721 | jmp .ret |
||
722 | |||
723 | ;;===========================================================================;; |
||
724 | ;; int __stdcall getaddrinfo_process(__in struct __gai_reqdata* reqdata, ;; |
||
725 | ;; __out struct addrinfo** res); ;; |
||
1200 | hidnplayr | 726 | getaddrinfo_process: ;; |
1155 | clevermous | 727 | ;;---------------------------------------------------------------------------;; |
728 | ;? Processes network events from DNS reply ;; |
||
729 | ;;---------------------------------------------------------------------------;; |
||
730 | ;> first parameter = pointer to struct __gai_reqdata filled by ..._start ;; |
||
731 | ;> second parameter = same as for getaddrinfo ;; |
||
732 | ;;---------------------------------------------------------------------------;; |
||
733 | ;< eax = -1 if more processing required / 0 on success / >0 = error code ;; |
||
734 | ;;===========================================================================;; |
||
735 | ; 0. Create stack frame. |
||
736 | push ebp |
||
737 | mov ebp, esp |
||
738 | virtual at ebp-.locals_size |
||
739 | .locals_start: |
||
740 | .datagram rb 512 |
||
741 | .addrname dd ? |
||
742 | .name dd ? |
||
743 | .res_list_tail dd ? |
||
744 | .cname dd ? |
||
745 | .recent_restsize dd ? ; this is for memory alloc in ._.generate_data |
||
746 | .recent_page dd ? ; this is for memory alloc in ._.generate_data |
||
747 | .locals_size = $ - .locals_start |
||
748 | rd 2 |
||
749 | .reqdata dd ? |
||
750 | .res dd ? |
||
751 | end virtual |
||
752 | xor eax, eax |
||
753 | push eax ; initialize .recent_page |
||
754 | push eax ; initialize .recent_restsize |
||
755 | push eax ; initialize .cname |
||
756 | push [.res] ; initialize .res_list_tail |
||
757 | sub esp, .locals_size-16 ; reserve place for other vars |
||
758 | mov edx, esp ; edx -> buffer for datagram |
||
759 | ; 1. Save used registers for __stdcall. |
||
760 | push ebx esi edi |
||
761 | mov edi, [.reqdata] |
||
762 | ; 2. Read UDP datagram. |
||
1542 | hidnplayr | 763 | mov ecx, [edi+__gai_reqdata.socketnum] |
1197 | clevermous | 764 | push edi |
1208 | hidnplayr | 765 | mcall 74, 7, , , 512, 0 |
1197 | clevermous | 766 | pop edi |
1542 | hidnplayr | 767 | ; 3. Ignore events for other socketnums (return if no data read) |
1155 | clevermous | 768 | test eax, eax |
769 | jz .ret.more_processing_required |
||
770 | ; 4. Sanity check: discard too short packets. |
||
771 | xchg ecx, eax ; save packet length in ecx |
||
772 | cmp ecx, 12 |
||
773 | jb .ret.more_processing_required |
||
774 | ; 5. Discard packets with ID != request ID. |
||
775 | mov eax, dword [edi+__gai_reqdata.reqid] |
||
776 | cmp ax, [edx] |
||
777 | jnz .ret.more_processing_required |
||
778 | ; 6. Sanity check: discard query packets. |
||
779 | test byte [edx+2], 80h |
||
780 | jz .ret.more_processing_required |
||
781 | ; 7. Sanity check: must be exactly one query (our). |
||
782 | cmp word [edx+4], 0x0100 ; note network byte order |
||
783 | jnz .ret.more_processing_required |
||
784 | ; 8. Check for errors. Return EAI_NONAME for error code 3 and EAI_FAIL for other. |
||
785 | mov al, [edx+3] |
||
786 | and al, 0xF |
||
787 | jz @f |
||
788 | cmp al, 3 |
||
789 | jnz .ret.no_recovery |
||
790 | jmp .ret.no_name |
||
791 | @@: |
||
792 | ; 9. Locate answers section. Exactly 1 query is present in this packet. |
||
793 | add ecx, edx ; ecx = limit |
||
794 | lea esi, [edx+12] |
||
795 | call .skip_name |
||
796 | lodsd ; skip QTYPE and QCLASS field |
||
797 | cmp esi, ecx |
||
798 | ja .ret.no_recovery |
||
799 | ; 10. Loop through all answers. |
||
800 | movzx ebx, word [edx+6] ; get answers count |
||
801 | xchg bl, bh ; network -> Intel byte order |
||
802 | .answers_loop: |
||
803 | dec ebx |
||
804 | js .answers_done |
||
805 | ; 10a. Process each record. |
||
806 | mov [.name], esi |
||
807 | ; 10b. Skip name field. |
||
808 | call .skip_name |
||
809 | ; 10c. Get record information, handle two types for class IN (internet). |
||
810 | lodsd ; get type and class |
||
811 | cmp esi, ecx |
||
812 | ja .ret.no_recovery |
||
1200 | hidnplayr | 813 | cmp eax, 0x01000500 ; type=5, class=1? |
1155 | clevermous | 814 | jz .got_cname |
1200 | hidnplayr | 815 | cmp eax, 0x01000100 ; type=1, class=1? |
1155 | clevermous | 816 | jnz .answers_loop.next |
817 | .got_addr: |
||
818 | ; 10d. Process record A, host address. |
||
819 | add esi, 10 |
||
820 | cmp esi, ecx |
||
821 | ja .ret.no_recovery |
||
822 | cmp word [esi-6], 0x0400 ; RDATA for A records must be 4 bytes long |
||
823 | jnz .ret.no_recovery |
||
824 | mov eax, [.name] |
||
825 | mov [.addrname], eax |
||
826 | ; 10e. Create corresponding record in the answer. |
||
827 | push ebx ecx esi |
||
828 | mov eax, [esi-4] ; IP address |
||
829 | mov esi, [.res_list_tail] ; pointer to result |
||
830 | test esi, esi |
||
831 | jz .no_result ; do not save if .res is NULL |
||
1200 | hidnplayr | 832 | mov ebx, [.reqdata] ; request data |
1155 | clevermous | 833 | call getaddrinfo._.generate_data |
834 | mov [.res_list_tail], esi |
||
835 | pop esi ecx ebx |
||
836 | cmp [.res_list_tail], 0 |
||
837 | jnz .answers_loop |
||
838 | ; 10f. If generate_data failed (this means memory allocation failure), abort |
||
839 | jmp .ret.no_memory |
||
840 | .no_result: |
||
841 | pop esi ecx ebx |
||
842 | jmp .answers_loop |
||
843 | .got_cname: |
||
844 | ; 10g. Process record CNAME, main host name. |
||
845 | lea eax, [esi+6] |
||
846 | mov [.cname], eax |
||
847 | .answers_loop.next: |
||
848 | ; 10h. Skip other record fields, advance to next record. |
||
849 | lodsd ; skip TTL |
||
850 | xor eax, eax |
||
851 | lodsw ; get length of RDATA field |
||
852 | xchg al, ah ; network -> Intel byte order |
||
853 | add esi, eax |
||
854 | cmp esi, ecx |
||
855 | ja .ret.no_recovery |
||
856 | jmp .answers_loop |
||
857 | .answers_done: |
||
858 | ; 11. Check that there is at least 1 answer. |
||
859 | mov eax, [.res_list_tail] |
||
860 | cmp [.res], eax |
||
861 | jz .ret.no_data |
||
862 | ; 12. If canonical name was required, add it now. |
||
863 | mov eax, [.reqdata] |
||
864 | test byte [eax+__gai_reqdata.flags], AI_CANONNAME |
||
865 | jz .no_canon_name |
||
866 | ; 12a. If at least one CNAME record is present, use name from last such record. |
||
867 | ; Otherwise, use name from one of A records. |
||
868 | mov esi, [.cname] |
||
869 | test esi, esi |
||
870 | jnz .has_cname |
||
871 | mov esi, [.addrname] |
||
872 | .has_cname: |
||
873 | ; 12b. Calculate name length. |
||
874 | call .get_name_length |
||
875 | jc .ret.no_recovery |
||
876 | ; 12c. Check that the caller really want to get data. |
||
877 | cmp [.res], 0 |
||
878 | jz .no_canon_name |
||
879 | ; 12d. Allocate memory for name. |
||
880 | call getaddrinfo._.memalloc |
||
881 | test edi, edi |
||
882 | jz .ret.no_memory |
||
883 | ; 12e. Make first entry in .res list point to canonical name. |
||
884 | mov eax, [.res] |
||
885 | mov eax, [eax] |
||
886 | mov [eax+addrinfo.ai_canonname], edi |
||
887 | ; 12f. Decode name. |
||
888 | call .decode_name |
||
889 | .no_canon_name: |
||
890 | ; 13. Set status to success. |
||
891 | xor eax, eax |
||
892 | jmp .ret.close |
||
893 | ; Handle errors. |
||
894 | .ret.more_processing_required: |
||
895 | push -1 |
||
896 | pop eax |
||
897 | jmp .ret |
||
898 | .ret.no_recovery: |
||
899 | push EAI_FAIL |
||
900 | pop eax |
||
901 | jmp .ret.destroy |
||
902 | .ret.no_memory: |
||
903 | push EAI_MEMORY |
||
904 | pop eax |
||
905 | jmp .ret.destroy |
||
906 | .ret.no_name: |
||
907 | .ret.no_data: |
||
908 | push EAI_NONAME |
||
909 | pop eax |
||
910 | .ret.destroy: |
||
911 | ; 14. If an error occured, free memory acquired so far. |
||
912 | push eax |
||
913 | mov esi, [.res] |
||
914 | test esi, esi |
||
915 | jz @f |
||
916 | pushd [esi] |
||
917 | call freeaddrinfo |
||
918 | and dword [esi], 0 |
||
919 | @@: |
||
920 | pop eax |
||
921 | .ret.close: |
||
1542 | hidnplayr | 922 | ; 15. Close socketnum. |
1155 | clevermous | 923 | push eax |
924 | mov ecx, [.reqdata] |
||
1542 | hidnplayr | 925 | mov ecx, [ecx+__gai_reqdata.socketnum] |
1197 | clevermous | 926 | mcall 74, 1 |
1155 | clevermous | 927 | pop eax |
928 | ; 16. Restore used registers, destroy stack frame and return. |
||
929 | .ret: |
||
930 | pop edi esi ebx |
||
931 | mov esp, ebp |
||
932 | pop ebp |
||
933 | ret 8 |
||
934 | |||
935 | ;;===========================================================================;; |
||
936 | ;; Internal auxiliary function for skipping names in DNS packet. ;; |
||
1200 | hidnplayr | 937 | .skip_name: ;; |
1155 | clevermous | 938 | ;;---------------------------------------------------------------------------;; |
939 | ;? Skips name in DNS packet. ;; |
||
940 | ;;---------------------------------------------------------------------------;; |
||
941 | ;> esi -> name ;; |
||
942 | ;> ecx = end of packet ;; |
||
943 | ;;---------------------------------------------------------------------------;; |
||
944 | ;< esi -> end of name ;; |
||
945 | ;;===========================================================================;; |
||
946 | xor eax, eax |
||
947 | cmp esi, ecx |
||
948 | jae .skip_name.done |
||
949 | lodsb |
||
950 | test al, al |
||
951 | jz .skip_name.done |
||
952 | test al, 0xC0 |
||
953 | jnz .skip_name.pointer |
||
954 | add esi, eax |
||
955 | jmp .skip_name |
||
956 | .skip_name.pointer: |
||
957 | inc esi |
||
958 | .skip_name.done: |
||
959 | ret |
||
960 | |||
961 | ;;===========================================================================;; |
||
962 | ;; Internal auxiliary function for calculating length of name in DNS packet. ;; |
||
1200 | hidnplayr | 963 | .get_name_length: ;; |
1155 | clevermous | 964 | ;;---------------------------------------------------------------------------;; |
965 | ;? Calculate length of name (including terminating zero) in DNS packet. ;; |
||
966 | ;;---------------------------------------------------------------------------;; |
||
967 | ;> edx = start of packet ;; |
||
968 | ;> esi -> name ;; |
||
969 | ;> ecx = end of packet ;; |
||
970 | ;;---------------------------------------------------------------------------;; |
||
971 | ;< eax = length of name ;; |
||
972 | ;< CF set on error / cleared on success ;; |
||
973 | ;;===========================================================================;; |
||
974 | xor ebx, ebx ; ebx will hold data length |
||
975 | .get_name_length.zero: |
||
976 | xor eax, eax |
||
977 | .get_name_length.loop: |
||
978 | cmp esi, ecx |
||
979 | jae .get_name_length.fail |
||
980 | lodsb |
||
981 | test al, al |
||
982 | jz .get_name_length.done |
||
983 | test al, 0xC0 |
||
984 | jnz .get_name_length.pointer |
||
985 | add esi, eax |
||
986 | inc ebx |
||
987 | add ebx, eax |
||
988 | cmp ebx, 256 |
||
989 | jbe .get_name_length.loop |
||
990 | .get_name_length.fail: |
||
991 | stc |
||
992 | ret |
||
993 | .get_name_length.pointer: |
||
994 | and al, 0x3F |
||
995 | mov ah, al |
||
996 | lodsb |
||
997 | lea esi, [edx+eax] |
||
998 | jmp .get_name_length.zero |
||
999 | .get_name_length.done: |
||
1000 | test ebx, ebx |
||
1001 | jz .get_name_length.fail |
||
1002 | xchg eax, ebx |
||
1003 | clc |
||
1004 | ret |
||
1005 | |||
1006 | ;;===========================================================================;; |
||
1007 | ;; Internal auxiliary function for decoding DNS name. ;; |
||
1200 | hidnplayr | 1008 | .decode_name: ;; |
1155 | clevermous | 1009 | ;;---------------------------------------------------------------------------;; |
1010 | ;? Decode name in DNS packet. ;; |
||
1011 | ;;---------------------------------------------------------------------------;; |
||
1012 | ;> edx = start of packet ;; |
||
1013 | ;> esi -> name in packet ;; |
||
1014 | ;> edi -> buffer for decoded name ;; |
||
1015 | ;;===========================================================================;; |
||
1016 | xor eax, eax |
||
1017 | lodsb |
||
1018 | test al, al |
||
1019 | jz .decode_name.done |
||
1020 | test al, 0xC0 |
||
1021 | jnz .decode_name.pointer |
||
1022 | mov ecx, eax |
||
1023 | rep movsb |
||
1024 | mov al, '.' |
||
1025 | stosb |
||
1026 | jmp .decode_name |
||
1027 | .decode_name.pointer: |
||
1028 | and al, 0x3F |
||
1029 | mov ah, al |
||
1030 | lodsb |
||
1031 | lea esi, [edx+eax] |
||
1032 | jmp .decode_name |
||
1033 | .decode_name.done: |
||
1034 | mov byte [edi-1], 0 |
||
1035 | ret |
||
1036 | |||
1037 | ;;===========================================================================;; |
||
1038 | ;; Internal auxiliary function for allocating memory for getaddrinfo. ;; |
||
1200 | hidnplayr | 1039 | getaddrinfo._.memalloc: ;; |
1155 | clevermous | 1040 | ;;---------------------------------------------------------------------------;; |
1041 | ;? Memory allocation. ;; |
||
1042 | ;;---------------------------------------------------------------------------;; |
||
1043 | ;> eax = size in bytes, must be less than page size. ;; |
||
1044 | ;> [ebp-4] = .recent_page = last allocated page ;; |
||
1045 | ;> [ebp-8] = .recent_restsize = bytes rest in last allocated page ;; |
||
1046 | ;;---------------------------------------------------------------------------;; |
||
1047 | ;< edi -> allocated memory / NULL on error ;; |
||
1048 | ;;===========================================================================;; |
||
1049 | ; 1. Set edi to result of function. |
||
1050 | mov edi, [ebp-4] |
||
1051 | ; 2. Check whether we need to allocate a new page. |
||
1052 | cmp eax, [ebp-8] |
||
1053 | jbe .no_new_page |
||
1054 | ; 2. Allocate new page if need. Reset edi to new result. |
||
1055 | push eax ebx |
||
1056 | mcall 68, 12, 0x1000 |
||
1057 | xchg edi, eax ; put result to edi |
||
1058 | pop ebx eax |
||
1059 | ; 3. Check returned value of allocator. Fail if it failed. |
||
1060 | test edi, edi |
||
1061 | jz .ret |
||
1062 | ; 4. Update .recent_page and .recent_restsize. |
||
1063 | add edi, 4 |
||
1064 | sub ecx, 4 |
||
1065 | mov [ebp-4], edi |
||
1066 | mov [ebp-8], ecx |
||
1067 | .no_new_page: |
||
1068 | ; 5. Increase number of objects on this page. |
||
1069 | push eax |
||
1070 | mov eax, edi |
||
1071 | and eax, not 0xFFF |
||
1072 | inc dword [eax] |
||
1073 | pop eax |
||
1074 | ; 6. Advance last allocated pointer, decrease memory size. |
||
1075 | add [ebp-4], eax |
||
1076 | sub [ebp-8], eax |
||
1077 | ; 7. Return. |
||
1078 | .ret: |
||
1079 | ret |
||
1080 | |||
1081 | ;;===========================================================================;; |
||
1082 | ;; Internal auxiliary function for freeing memory for freeaddrinfo. ;; |
||
1200 | hidnplayr | 1083 | getaddrinfo._.memfree: ;; |
1155 | clevermous | 1084 | ;;---------------------------------------------------------------------------;; |
1085 | ;? Free memory. ;; |
||
1086 | ;;---------------------------------------------------------------------------;; |
||
1087 | ;> eax = pointer ;; |
||
1088 | ;;===========================================================================;; |
||
1089 | ; 1. Get start of page. |
||
1090 | mov ecx, eax |
||
1091 | and ecx, not 0xFFF |
||
1092 | ; 2. Decrease number of objects. |
||
1093 | dec dword [ecx] |
||
1094 | ; 3. If it goes to zero, free the page. |
||
1095 | jnz @f |
||
1096 | push ebx |
||
1097 | mcall 68, 13 |
||
1098 | pop ebx |
||
1099 | @@: |
||
1100 | ; 4. Done. |
||
1101 | ret |
||
1102 | |||
1103 | ;;===========================================================================;; |
||
1200 | hidnplayr | 1104 | getaddrinfo._.generate_data: ;; |
1155 | clevermous | 1105 | ;;---------------------------------------------------------------------------;; |
1106 | ;? Generate item(s) of getaddrinfo result list by one IP address. ;; |
||
1107 | ;;---------------------------------------------------------------------------;; |
||
1108 | ;> eax = IP address ;; |
||
1109 | ;> ebx = request data ;; |
||
1110 | ;> esi = pointer to result ;; |
||
1111 | ;> [ebp-4] = .recent_page = last allocated page ;; |
||
1112 | ;> [ebp-8] = .recent_restsize = bytes rest in last allocated page ;; |
||
1113 | ;;---------------------------------------------------------------------------;; |
||
1114 | ;< esi = pointer to next list item for result / NULL on error ;; |
||
1115 | ;;===========================================================================;; |
||
1116 | ; 1. If no service is given, append one item with zero port. |
||
1117 | ; append one item with zero socktype/protocol/port. |
||
1118 | cmp [ebx+__gai_reqdata.service], -1 |
||
1119 | jnz .has_service |
||
1120 | call .append_item |
||
1121 | ; 1a. If neither protocol nor socktype were specified, |
||
1200 | hidnplayr | 1122 | ; leave zeroes in socktype and protocol. |
1155 | clevermous | 1123 | mov cl, [ebx+__gai_reqdata.socktype] |
1124 | test cl, cl |
||
1125 | jz .no_socktype |
||
1126 | ; 1b. Otherwise, set socktype and protocol to desired. |
||
1127 | call .set_socktype |
||
1128 | .no_socktype: |
||
1129 | ret |
||
1130 | .has_service: |
||
1131 | ; 2. If TCP is allowed, append item for TCP. |
||
1132 | cmp [ebx+__gai_reqdata.socktype], 0 |
||
1133 | jz .tcp_ok |
||
1134 | cmp [ebx+__gai_reqdata.socktype], SOCK_STREAM |
||
1135 | jnz .tcp_disallowed |
||
1136 | .tcp_ok: |
||
1137 | call .append_item |
||
1138 | mov cl, SOCK_STREAM |
||
1139 | call .set_socktype |
||
1140 | call .set_port |
||
1141 | .tcp_disallowed: |
||
1142 | ; 3. If UDP is allowed, append item for UDP. |
||
1143 | cmp [ebx+__gai_reqdata.socktype], 0 |
||
1144 | jz .udp_ok |
||
1145 | cmp [ebx+__gai_reqdata.socktype], SOCK_DGRAM |
||
1146 | jnz .udp_disallowed |
||
1147 | .udp_ok: |
||
1148 | call .append_item |
||
1149 | mov cl, SOCK_DGRAM |
||
1150 | call .set_socktype |
||
1151 | call .set_port |
||
1152 | .udp_disallowed: |
||
1153 | ret |
||
1154 | |||
1155 | .append_item: |
||
1156 | ; 1. Allocate memory for struct sockaddr_in and struct addrinfo. |
||
1157 | push eax |
||
1158 | push sizeof.addrinfo + sizeof.sockaddr_in |
||
1159 | pop eax |
||
1160 | call getaddrinfo._.memalloc |
||
1161 | ; 2. Check for memory allocation fail. |
||
1162 | test edi, edi |
||
1163 | jz .no_memory |
||
1164 | ; 3. Zero allocated memory. |
||
1165 | push (sizeof.addrinfo + sizeof.sockaddr_in) / 4 |
||
1166 | pop ecx |
||
1167 | xor eax, eax |
||
1168 | push edi |
||
1169 | rep stosd |
||
1170 | pop edi |
||
1171 | ; 4. Fill struct addrinfo. |
||
1172 | mov eax, [ebx+__gai_reqdata.flags] |
||
1173 | mov [edi+addrinfo.ai_flags], eax |
||
1542 | hidnplayr | 1174 | mov byte [edi+addrinfo.ai_family], AF_INET4 |
1155 | clevermous | 1175 | mov byte [edi+addrinfo.ai_addrlen], sizeof.sockaddr_in |
1176 | lea ecx, [edi+sizeof.addrinfo] |
||
1177 | mov [edi+addrinfo.ai_addr], ecx |
||
1178 | ; 5. Fill struct sockaddr_in. |
||
1542 | hidnplayr | 1179 | mov byte [ecx+sockaddr_in.sin_family], AF_INET4 |
1155 | clevermous | 1180 | pop eax |
1181 | mov [ecx+sockaddr_in.sin_addr], eax |
||
1182 | ; 6. Append new item to the list. |
||
1183 | mov [esi], edi |
||
1184 | lea esi, [edi+addrinfo.ai_next] |
||
1185 | ; 7. Return. |
||
1186 | ret |
||
1187 | .no_memory: |
||
1188 | pop eax |
||
1189 | xor esi, esi |
||
1190 | ret |
||
1191 | |||
1192 | .set_socktype: |
||
1542 | hidnplayr | 1193 | ; Set ai_socktype and ai_protocol fields by given socketnum type. |
1155 | clevermous | 1194 | mov byte [edi+addrinfo.ai_socktype], cl |
1195 | dec cl |
||
1196 | jnz .set_udp |
||
1197 | .set_tcp: |
||
1198 | mov byte [edi+addrinfo.ai_protocol], IPPROTO_TCP |
||
1199 | ret |
||
1200 | .set_udp: |
||
1201 | mov byte [edi+addrinfo.ai_protocol], IPPROTO_UDP |
||
1202 | ret |
||
1203 | |||
1204 | .set_port: |
||
1205 | ; Just copy port from input __gai_reqdata to output addrinfo. |
||
1206 | push edx |
||
1207 | mov edx, [ebx+__gai_reqdata.service] |
||
1208 | xchg dl, dh ; convert to network byte order |
||
1209 | mov [edi+sizeof.addrinfo+sockaddr_in.sin_port], dx |
||
1210 | pop edx |
||
1211 | ret |
||
1212 | |||
1213 | ;;===========================================================================;; |
||
1214 | ;; void __stdcall getaddrinfo_abort(__in struct __gai_reqdata* reqdata); ;; |
||
1200 | hidnplayr | 1215 | getaddrinfo_abort: ;; |
1155 | clevermous | 1216 | ;;---------------------------------------------------------------------------;; |
1217 | ;? Abort process started by getaddrinfo_start, free all resources. ;; |
||
1218 | ;;---------------------------------------------------------------------------;; |
||
1219 | ;> first parameter = pointer to struct __gai_reqdata filled by ..._start ;; |
||
1220 | ;;===========================================================================;; |
||
1221 | ; 0. Save used registers for __stdcall. |
||
1222 | push ebx |
||
1542 | hidnplayr | 1223 | ; 1. Allocated resources: only socketnum, so close it and return. |
1155 | clevermous | 1224 | mov eax, [esp+8] |
1542 | hidnplayr | 1225 | mov ecx, [eax+__gai_reqdata.socketnum] |
1197 | clevermous | 1226 | mcall 74, 1 |
1155 | clevermous | 1227 | ; 2. Restore used registers and return. |
1228 | pop ebx |
||
1229 | ret 4 |
||
1230 | |||
1231 | ;;===========================================================================;; |
||
1232 | ;; void __stdcall freeaddrinfo(__in struct addrinfo* ai); ;; |
||
1200 | hidnplayr | 1233 | freeaddrinfo: ;; |
1155 | clevermous | 1234 | ;;---------------------------------------------------------------------------;; |
1235 | ;? Free one or more addrinfo structures returned by getaddrinfo. ;; |
||
1236 | ;;---------------------------------------------------------------------------;; |
||
1237 | ;> first parameter = head of list of structures ;; |
||
1238 | ; (may be arbitrary sublist of original) ;; |
||
1239 | ;;===========================================================================;; |
||
1240 | ; 1. Loop for all items in the list. |
||
1241 | mov edx, [esp+4] ; eax = ai |
||
1242 | .loop: |
||
1243 | test edx, edx |
||
1244 | jz .done |
||
1245 | ; 2. Free each item. |
||
1246 | ; 2a. Free ai_canonname, if allocated. |
||
1247 | mov eax, [edx+addrinfo.ai_canonname] |
||
1248 | test eax, eax |
||
1249 | jz .no_canon_name |
||
1250 | call getaddrinfo._.memfree |
||
1251 | .no_canon_name: |
||
1252 | ; 2b. Remember next item |
||
1200 | hidnplayr | 1253 | ; (after freeing the field ai_next can became unavailable). |
1155 | clevermous | 1254 | pushd [edx+addrinfo.ai_next] |
1255 | ; 2c. Free item itself. |
||
1256 | xchg eax, edx |
||
1257 | call getaddrinfo._.memfree |
||
1258 | ; 2d. Restore pointer to next item and continue loop. |
||
1259 | pop edx |
||
1260 | jmp .loop |
||
1261 | .done: |
||
1262 | ; 3. Done. |
||
1263 | ret 4 |
||
1264 | |||
1265 | ;;===========================================================================;; |
||
1266 | ;;///////////////////////////////////////////////////////////////////////////;; |
||
1267 | ;;===========================================================================;; |
||
1268 | ;! Exported functions section ;; |
||
1269 | ;;===========================================================================;; |
||
1270 | ;;///////////////////////////////////////////////////////////////////////////;; |
||
1271 | ;;===========================================================================;; |
||
1272 | |||
1273 | |||
1274 | align 4 |
||
1275 | @EXPORT: |
||
1276 | export \ |
||
1277 | lib_init , 'lib_init' , \ |
||
1278 | 0x00010001 , 'version' , \ |
||
1279 | inet_addr , 'inet_addr' , \ |
||
1280 | inet_ntoa , 'inet_ntoa' , \ |
||
1200 | hidnplayr | 1281 | getaddrinfo , 'getaddrinfo' , \ |
1155 | clevermous | 1282 | getaddrinfo_start , 'getaddrinfo_start' , \ |
1200 | hidnplayr | 1283 | getaddrinfo_process , 'getaddrinfo_process' , \ |
1155 | clevermous | 1284 | getaddrinfo_abort , 'getaddrinfo_abort' , \ |
1285 | freeaddrinfo , 'freeaddrinfo' |
||
1286 | |||
1287 | ; import from libini |
||
1288 | align 4 |
||
1289 | @IMPORT: |
||
1290 | |||
1200 | hidnplayr | 1291 | library libini, 'libini.obj' |
1155 | clevermous | 1292 | import libini, \ |
1293 | ini.get_str, 'ini_get_str', \ |
||
1294 | ini.get_int, 'ini_get_int' |
||
1295 | |||
1296 | |||
1297 | section '.data' data readable writable align 16 |
||
1298 | ; uninitialized data |
||
1299 | mem.alloc dd ? |
||
1300 | mem.free dd ? |
||
1301 | mem.realloc dd ? |
||
1302 | dll.load dd ? |
||
1303 | |||
1304 | DNSrequestID dd ? |
||
1305 | |||
1306 | inet_ntoa.buffer rb 16 ; static buffer for inet_ntoa>>>>>>0>>>>>>>>> |