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