Rev 3601 | Rev 5545 | 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) ;; |
||
3545 | hidnplayr | 282 | ;> third parameter (optional) = hints for socketnum 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 | lea eax, [esp+4] ; pointer to (1) |
||
315 | jz .timeout |
||
1155 | clevermous | 316 | ; 3. Got packet. Call processing function. |
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 |
||
3545 | hidnplayr | 332 | push eax |
333 | call getaddrinfo_abort |
||
334 | and dword [edi], 0 |
||
335 | push EAI_AGAIN |
||
336 | pop eax |
||
1155 | clevermous | 337 | .ret.restore: |
338 | ; 6. Restore event mask. |
||
3545 | hidnplayr | 339 | pop ebx ; get event mask (2) |
340 | push eax ; save return code (3) |
||
341 | mcall 40 |
||
342 | pop eax ; restore return code (3) |
||
1155 | clevermous | 343 | .ret: |
344 | ; 7. Restore stack pointer, used registers and return. |
||
3545 | hidnplayr | 345 | add esp, sizeof.__gai_reqdata ; undo (1) |
346 | pop edi esi ebx |
||
347 | ret 16 |
||
1155 | clevermous | 348 | |
349 | ;;===========================================================================;; |
||
350 | ;; int __stdcall getaddrinfo_start(__in const char* hostname, ;; |
||
351 | ;; __in const char* servname, ;; |
||
352 | ;; __in const struct addrinfo* hints, ;; |
||
353 | ;; __out struct addrinfo **res, ;; |
||
354 | ;; __out struct __gai_reqdata* reqdata); ;; |
||
355 | getaddrinfo_start: ;; |
||
356 | ;;---------------------------------------------------------------------------;; |
||
357 | ;? Initiator for getaddrinfo, sends DNS request ;; |
||
358 | ;;---------------------------------------------------------------------------;; |
||
359 | ;> first 4 parameters same as for getaddrinfo ;; |
||
360 | ;> last parameter = pointer to buffer for __gai_reqdata, must be passed to ;; |
||
361 | ;> getaddrinfo_process as is ;; |
||
362 | ;;---------------------------------------------------------------------------;; |
||
363 | ;< eax = <0 if wait loop must be entered / 0 on success / EAI_* on error ;; |
||
364 | ;;===========================================================================;; |
||
365 | ;; Known limitations: ;; |
||
366 | ;; 1. No support for TCP connections => ;; |
||
367 | ;; 1a. Long replies will be truncated, and not all IP addresses will be got. ;; |
||
368 | ;; 2. No support for iterative resolving => ;; |
||
369 | ;; 2a. In theory may fail with some servers. ;; |
||
370 | ;; 3. Assumes that domain for relative names is always root, ".". ;; |
||
371 | ;; 4. Does not support lookup of services by name, ;; |
||
372 | ;; only decimal representation is supported. ;; |
||
373 | ;; 5. Assumes that IPv4 is always configured, so AI_ADDRCONFIG has no effect.;; |
||
374 | ;;===========================================================================;; |
||
375 | ; 0. Create stack frame and save used registers for __stdcall. |
||
3545 | hidnplayr | 376 | push ebx esi edi |
377 | push ebp |
||
378 | mov ebp, esp |
||
1155 | clevermous | 379 | virtual at ebp-8 |
3545 | hidnplayr | 380 | .recent_restsize dd ? ; this is for memory alloc in ._.generate_data |
381 | .recent_page dd ? ; this is for memory alloc in ._.generate_data |
||
382 | rd 5 ; saved regs and return address |
||
383 | .hostname dd ? |
||
384 | .servname dd ? |
||
385 | .hints dd ? |
||
386 | .res dd ? |
||
387 | .reqdata dd ? |
||
1155 | clevermous | 388 | end virtual |
3545 | hidnplayr | 389 | xor edi, edi |
390 | push edi ; init .recent_page |
||
391 | push edi ; init .recent_restsize |
||
1155 | clevermous | 392 | ; 1. Check that parameters are correct and can be handled by this implementation. |
393 | ; 1a. If 'res' pointer is given, set result to zero. |
||
3545 | hidnplayr | 394 | mov eax, [.res] |
395 | test eax, eax |
||
396 | jz @f |
||
397 | mov [eax], edi |
||
1155 | clevermous | 398 | @@: |
399 | ; 1b. Only AI_SUPPORTED flags are supported for hints->ai_flags. |
||
3545 | hidnplayr | 400 | mov ecx, [.hints] |
401 | xor edx, edx |
||
402 | jecxz .nohints |
||
403 | mov edx, [ecx+addrinfo.ai_flags] |
||
1155 | clevermous | 404 | .nohints: |
3545 | hidnplayr | 405 | mov ebx, [.reqdata] |
406 | mov [ebx+__gai_reqdata.flags], edx |
||
407 | push EAI_BADFLAGS |
||
408 | pop eax |
||
409 | test edx, not AI_SUPPORTED |
||
410 | jnz .ret |
||
1155 | clevermous | 411 | ; 1c. Either hostname or servname must be given. If AI_CANONNAME is set, |
412 | ; hostname must also be set. |
||
3545 | hidnplayr | 413 | cmp [.hostname], edi |
414 | jnz @f |
||
415 | test dl, AI_CANONNAME |
||
416 | jnz .ret |
||
417 | push EAI_NONAME |
||
418 | pop eax |
||
419 | cmp [.servname], edi |
||
420 | jz .ret |
||
1155 | clevermous | 421 | @@: |
422 | ; 1d. Only IPv4 is supported, so hints->ai_family must be either PF_UNSPEC or PF_INET. |
||
3545 | hidnplayr | 423 | push EAI_FAMILY |
424 | pop eax |
||
425 | jecxz @f |
||
426 | cmp [ecx+addrinfo.ai_family], edi |
||
427 | jz @f |
||
428 | cmp [ecx+addrinfo.ai_family], AF_INET4 |
||
429 | jnz .ret |
||
1155 | clevermous | 430 | @@: |
431 | ; 1e. Valid combinations for ai_socktype/ai_protocol: 0/0 for any or |
||
3545 | hidnplayr | 432 | ; SOCK_STREAM/IPPROTO_TCP, SOCK_DGRAM/IPPROTO_UDP |
433 | ; (raw socketnums are not yet supported by the kernel) |
||
434 | xor edx, edx ; assume 0=any if no hints |
||
435 | jecxz .socketnum_type_ok |
||
436 | mov edx, [ecx+addrinfo.ai_socktype] |
||
437 | mov esi, [ecx+addrinfo.ai_protocol] |
||
1155 | clevermous | 438 | ; 1f. Test for ai_socktype=0 and ai_protocol=0. |
3545 | hidnplayr | 439 | test edx, edx |
440 | jnz .check_socktype |
||
441 | test esi, esi |
||
442 | jz .socketnum_type_ok |
||
1155 | clevermous | 443 | ; 1g. ai_socktype=0, ai_protocol is nonzero. |
3545 | hidnplayr | 444 | push EAI_SERVICE |
445 | pop eax |
||
446 | inc edx ; edx = SOCK_STREAM |
||
447 | cmp esi, IPPROTO_TCP |
||
448 | jz .socketnum_type_ok |
||
449 | inc edx ; edx = SOCK_DGRAM |
||
450 | cmp esi, IPPROTO_UDP |
||
451 | jz .socketnum_type_ok |
||
1155 | clevermous | 452 | .ret: |
453 | ; Restore saved registers, destroy stack frame and return. |
||
3545 | hidnplayr | 454 | mov esp, ebp |
455 | pop ebp |
||
456 | pop edi esi ebx |
||
457 | ret 20 |
||
1155 | clevermous | 458 | ; 1h. ai_socktype is nonzero. |
459 | .check_socktype: |
||
3545 | hidnplayr | 460 | push EAI_SOCKTYPE |
461 | pop eax |
||
462 | cmp edx, SOCK_STREAM |
||
463 | jz .check_tcp |
||
464 | cmp edx, SOCK_DGRAM |
||
465 | jnz .ret |
||
466 | test esi, esi |
||
467 | jz .socketnum_type_ok |
||
468 | cmp esi, IPPROTO_UDP |
||
469 | jz .socketnum_type_ok |
||
470 | jmp .ret |
||
1155 | clevermous | 471 | .check_tcp: |
3545 | hidnplayr | 472 | test esi, esi |
473 | jz .socketnum_type_ok |
||
474 | cmp esi, IPPROTO_TCP |
||
475 | jnz .ret |
||
476 | .socketnum_type_ok: |
||
477 | mov [ebx+__gai_reqdata.socktype], dl |
||
1155 | clevermous | 478 | ; 2. Resolve service. |
479 | ; 2a. If no name is given, remember value -1. |
||
3545 | hidnplayr | 480 | push -1 |
481 | pop edx |
||
482 | mov esi, [.servname] |
||
483 | test esi, esi |
||
484 | jz .service_resolved |
||
1155 | clevermous | 485 | ; 2b. Loop for characters of string while digits are encountered. |
3545 | hidnplayr | 486 | xor edx, edx |
487 | xor eax, eax |
||
1155 | clevermous | 488 | .serv_to_number: |
3545 | hidnplayr | 489 | lodsb |
490 | sub al, '0' |
||
491 | cmp al, 9 |
||
492 | ja .serv_to_number_done |
||
1155 | clevermous | 493 | ; for each digit, set edx = edx*10 + |
3545 | hidnplayr | 494 | lea edx, [edx*5] |
495 | lea edx, [edx*2+eax] |
||
1155 | clevermous | 496 | ; check for correctness: service port must fit in word |
3545 | hidnplayr | 497 | cmp edx, 0x10000 |
498 | jae .service_not_number |
||
499 | jmp .serv_to_number |
||
1155 | clevermous | 500 | .serv_to_number_done: |
3545 | hidnplayr | 501 | and edx, 0xFFFF ; make sure that port fits |
1155 | clevermous | 502 | ; 2c. If zero character reached, name is resolved; |
503 | ; otherwise, return error (no support for symbolic names yet) |
||
3545 | hidnplayr | 504 | cmp al, -'0' |
505 | jz .service_resolved |
||
1155 | clevermous | 506 | .service_not_number: |
3545 | hidnplayr | 507 | push EAI_NONAME |
508 | pop eax |
||
509 | jmp .ret |
||
1155 | clevermous | 510 | .service_resolved: |
511 | ; 2d. Save result to reqdata. |
||
3545 | hidnplayr | 512 | mov [ebx+__gai_reqdata.service], edx |
1155 | clevermous | 513 | ; 3. Process host name. |
3545 | hidnplayr | 514 | mov esi, [.hostname] |
1155 | clevermous | 515 | ; 3a. If hostname is not given, |
3545 | hidnplayr | 516 | ; use localhost for active socketnums and INADDR_ANY for passive socketnums. |
517 | mov eax, 0x0100007F ; 127.0.0.1 in network byte order |
||
518 | test byte [ebx+__gai_reqdata.flags], AI_PASSIVE |
||
519 | jz @f |
||
520 | xor eax, eax |
||
1155 | clevermous | 521 | @@: |
3545 | hidnplayr | 522 | test esi, esi |
523 | jz .hostname_is_ip |
||
1155 | clevermous | 524 | ; 3b. Check for dotted IPv4 name. |
3545 | hidnplayr | 525 | push esi |
526 | call inet_addr |
||
527 | cmp eax, -1 |
||
528 | jz .resolve_hostname |
||
1155 | clevermous | 529 | .hostname_is_ip: |
530 | ; 3c. hostname is valid representation of IP address, and we have resolved it. |
||
531 | ; Generate result, if .res pointer is not NULL. |
||
3545 | hidnplayr | 532 | mov ebx, [.reqdata] |
533 | mov esi, [.res] |
||
534 | test esi, esi |
||
535 | jz .no_result |
||
536 | call getaddrinfo._.generate_data |
||
1155 | clevermous | 537 | ; 3d. Check for memory allocation error. |
538 | .3d: |
||
3545 | hidnplayr | 539 | push EAI_MEMORY |
540 | pop eax |
||
541 | test esi, esi |
||
542 | jz .ret |
||
1155 | clevermous | 543 | ; 3e. If AI_CANONNAME is set, copy input name. |
3545 | hidnplayr | 544 | test byte [ebx+__gai_reqdata.flags], AI_CANONNAME |
545 | jz .no_result |
||
1155 | clevermous | 546 | ; 3f. Calculate length of name. |
3545 | hidnplayr | 547 | push -1 |
548 | pop ecx |
||
549 | mov edi, [.hostname] |
||
550 | xor eax, eax |
||
551 | repnz scasb |
||
552 | not ecx |
||
1155 | clevermous | 553 | ; 3g. Check whether it fits on one page with main data. |
3545 | hidnplayr | 554 | cmp ecx, [.recent_restsize] |
555 | jbe .name_fits |
||
1155 | clevermous | 556 | ; 3h. If not, allocate new page. |
3545 | hidnplayr | 557 | push ecx |
558 | add ecx, 4 ; first dword contains number of objects on the page |
||
559 | mcall 68, 12 |
||
560 | pop ecx |
||
1155 | clevermous | 561 | ; 3i. If allocation has failed, free addrinfo and return error. |
3545 | hidnplayr | 562 | test eax, eax |
563 | jnz .name_allocated |
||
564 | push [.res] |
||
565 | call freeaddrinfo |
||
566 | push EAI_MEMORY |
||
567 | pop eax |
||
568 | jmp .ret |
||
1155 | clevermous | 569 | .name_allocated: |
570 | ; 3j. Otherwise, set edi to allocated memory and continue to 3l. |
||
3545 | hidnplayr | 571 | xchg edi, eax ; put result to edi |
572 | push 1 |
||
573 | pop eax |
||
574 | stosd ; number of objects on the page = 1 |
||
575 | jmp .copy_name |
||
1155 | clevermous | 576 | .name_fits: |
577 | ; 3k. Get pointer to free memory in allocated page. |
||
3545 | hidnplayr | 578 | mov edi, [.recent_page] |
579 | mov eax, edi |
||
580 | and eax, not 0xFFF |
||
581 | inc dword [eax] ; increase number of objects |
||
1155 | clevermous | 582 | .copy_name: |
583 | ; 3l. Put pointer to struct addrinfo. |
||
3545 | hidnplayr | 584 | mov eax, [.res] |
585 | mov eax, [eax] |
||
586 | mov [eax+addrinfo.ai_canonname], edi |
||
1155 | clevermous | 587 | ; 3m. Copy name. |
3545 | hidnplayr | 588 | rep movsb |
1155 | clevermous | 589 | .no_result: |
590 | ; 3n. Return success. |
||
3545 | hidnplayr | 591 | xor eax, eax |
592 | jmp .ret |
||
1155 | clevermous | 593 | ; 4. Host address is not dotted IP. Test whether we are allowed to contact DNS. |
594 | ; Return error if no. |
||
595 | .resolve_hostname: |
||
3545 | hidnplayr | 596 | push EAI_NONAME |
597 | pop eax |
||
598 | mov ebx, [.reqdata] |
||
599 | test byte [ebx+__gai_reqdata.flags], AI_NUMERICHOST |
||
600 | jnz .ret |
||
1155 | clevermous | 601 | ; Host address is domain name. Contact DNS server. |
3545 | hidnplayr | 602 | mov esi, [.hostname] |
1155 | clevermous | 603 | ; 5. Reserve stack place for UDP packet. |
604 | ; According to RFC1035, maximum UDP packet size in DNS is 512 bytes. |
||
3545 | hidnplayr | 605 | sub esp, 512 |
1155 | clevermous | 606 | ; 6. Create DNS request packet. |
607 | ; 6a. Set pointer to start of buffer. |
||
3545 | hidnplayr | 608 | mov edi, esp |
1155 | clevermous | 609 | ; 6b. Get request ID, write it to buffer. |
3545 | hidnplayr | 610 | push 1 |
611 | pop eax |
||
612 | lock xadd [DNSrequestID], eax ; atomically increment ID, get old value |
||
613 | stosw |
||
614 | mov [ebx+__gai_reqdata.reqid], ax |
||
1155 | clevermous | 615 | ; 6c. Packed field: QR=0 (query), Opcode=0000 (standard query), |
3545 | hidnplayr | 616 | ; AA=0 (ignored in requests), TC=0 (no truncation), |
617 | ; RD=1 (recursion desired) |
||
618 | mov al, 00000001b |
||
619 | stosb |
||
1155 | clevermous | 620 | ; 6d. Packed field: ignored in requests |
3545 | hidnplayr | 621 | mov al, 0 |
622 | stosb |
||
1155 | clevermous | 623 | ; 6e. Write questions count = 1 and answers count = 0 |
624 | ; Note that network byte order is big-endian. |
||
3545 | hidnplayr | 625 | mov eax, 0x00000100 |
626 | stosd |
||
1155 | clevermous | 627 | ; 6f. Write nameservers count = 0 and additional records count = 0 |
3545 | hidnplayr | 628 | xor eax, eax |
629 | stosd |
||
1155 | clevermous | 630 | ; 6g. Write request data: name |
631 | ; According to RFC1035, maximum length of name is 255 bytes. |
||
632 | ; For correct names, buffer cannot overflow. |
||
3545 | hidnplayr | 633 | lea ebx, [esi+256] ; ebx = limit for name (including terminating zero) |
1155 | clevermous | 634 | ; translate string "www.yandex.ru" {00} to byte data {03} "www" {06} "yandex" {02} "ru" {00} |
3545 | hidnplayr | 635 | .nameloop: ; here we go in the start of each label: before "www", before "yandex", before "ru" |
636 | xor ecx, ecx ; ecx = length of current label |
||
637 | inc edi ; skip length, it will be filled later |
||
638 | .labelloop: ; here we go for each symbol of name |
||
639 | lodsb ; get next character |
||
640 | test al, al ; terminating zero? |
||
641 | jz .endname |
||
642 | cmp esi, ebx ; limit exceeded? |
||
643 | jae .wrongname |
||
644 | cmp al, '.' ; end of label? |
||
645 | jz .labelend |
||
646 | stosb ; put next character |
||
647 | inc ecx ; increment label length |
||
648 | jmp .labelloop |
||
1155 | clevermous | 649 | .wrongname: |
3545 | hidnplayr | 650 | push EAI_NONAME |
651 | pop eax |
||
652 | jmp .ret |
||
1155 | clevermous | 653 | .labelend: |
3545 | hidnplayr | 654 | test ecx, ecx ; null label can be only in the end of name |
655 | jz .wrongname |
||
1155 | clevermous | 656 | .endname: |
3545 | hidnplayr | 657 | cmp ecx, 63 |
658 | ja .wrongname |
||
1155 | clevermous | 659 | ; write length to byte [edi-ecx-1] |
3545 | hidnplayr | 660 | mov eax, ecx |
661 | neg eax |
||
662 | mov byte [edi+eax-1], cl |
||
663 | cmp byte [esi-1], 0 ; that was last label in the name? |
||
664 | jnz .nameloop |
||
1155 | clevermous | 665 | ; write terminating zero if not yet |
3545 | hidnplayr | 666 | mov al, 0 |
667 | cmp byte [edi-1], al |
||
668 | jz @f |
||
669 | stosb |
||
1155 | clevermous | 670 | @@: |
671 | ; 6h. Write request data: |
||
3545 | hidnplayr | 672 | ; query type = A (host address) = 1, |
673 | ; query class = IN (internet IPv4 address) = 1 |
||
1155 | clevermous | 674 | ; Note that network byte order is big-endian. |
3545 | hidnplayr | 675 | mov eax, 0x01000100 |
676 | stosd |
||
1155 | clevermous | 677 | ; 7. Get DNS server address. |
3601 | hidnplayr | 678 | mcall 76, API_IPv4 + (1 shl 8) + 4 ; protocol IP=0, device number=0, function=get DNS address |
3545 | hidnplayr | 679 | cmp eax, -1 |
680 | je .ret.dnserr |
||
681 | mov esi, eax ; put server address to esi |
||
682 | ; 8. Open UDP socketnum to DNS server, port 53. |
||
683 | ; 8a. Create new socketnum. |
||
684 | mcall 75, 0, AF_INET4, SOCK_DGRAM |
||
685 | cmp eax, -1 ; error? |
||
686 | jz .ret.dnserr |
||
687 | mov ecx, eax ; put socketnum handle to ecx |
||
688 | ; 8b. Create sockaddr structure on the stack. |
||
689 | push 0 |
||
690 | push 0 ; sin_zero |
||
691 | push esi ; sin_addr |
||
692 | push AF_INET4 + (53 shl 24) |
||
693 | ; sin_family and sin_port in network byte order |
||
694 | ; 8c. Connect. |
||
695 | mcall 75, 4, , esp, sizeof.sockaddr_in |
||
696 | ; 8d. Restore the stack, undo 8b. |
||
697 | add esp, esi |
||
698 | ; 8e. Check result. |
||
699 | cmp eax, -1 |
||
700 | jz .ret.close |
||
1155 | clevermous | 701 | ; 9. Send DNS request packet. |
3545 | hidnplayr | 702 | sub edi, esp ; get packet length |
703 | mov esi, edi |
||
704 | xor edi, edi |
||
705 | mcall 75, 6, , esp |
||
706 | cmp eax, -1 |
||
707 | jz .ret.close |
||
708 | mov eax, [.reqdata] |
||
709 | mov [eax+__gai_reqdata.socketnum], ecx |
||
710 | push -1 |
||
711 | pop eax ; return status: more processing required |
||
712 | jmp .ret.dns |
||
1155 | clevermous | 713 | .ret.close: |
3545 | hidnplayr | 714 | mcall 75, 1 |
1155 | clevermous | 715 | .ret.dnserr: |
3545 | hidnplayr | 716 | push EAI_AGAIN |
717 | pop eax |
||
1155 | clevermous | 718 | .ret.dns: |
719 | ; 6. Restore stack pointer and return. |
||
3545 | hidnplayr | 720 | jmp .ret |
1155 | clevermous | 721 | |
722 | ;;===========================================================================;; |
||
723 | ;; int __stdcall getaddrinfo_process(__in struct __gai_reqdata* reqdata, ;; |
||
724 | ;; __out struct addrinfo** res); ;; |
||
725 | getaddrinfo_process: ;; |
||
726 | ;;---------------------------------------------------------------------------;; |
||
727 | ;? Processes network events from DNS reply ;; |
||
728 | ;;---------------------------------------------------------------------------;; |
||
729 | ;> first parameter = pointer to struct __gai_reqdata filled by ..._start ;; |
||
730 | ;> second parameter = same as for getaddrinfo ;; |
||
731 | ;;---------------------------------------------------------------------------;; |
||
732 | ;< eax = -1 if more processing required / 0 on success / >0 = error code ;; |
||
733 | ;;===========================================================================;; |
||
734 | ; 0. Create stack frame. |
||
3545 | hidnplayr | 735 | push ebp |
736 | mov ebp, esp |
||
1155 | clevermous | 737 | virtual at ebp-.locals_size |
738 | .locals_start: |
||
3545 | hidnplayr | 739 | .datagram rb 512 |
740 | .addrname dd ? |
||
741 | .name dd ? |
||
742 | .res_list_tail dd ? |
||
743 | .cname dd ? |
||
744 | .recent_restsize dd ? ; this is for memory alloc in ._.generate_data |
||
745 | .recent_page dd ? ; this is for memory alloc in ._.generate_data |
||
1155 | clevermous | 746 | .locals_size = $ - .locals_start |
3545 | hidnplayr | 747 | rd 2 |
748 | .reqdata dd ? |
||
749 | .res dd ? |
||
1155 | clevermous | 750 | end virtual |
3545 | hidnplayr | 751 | xor eax, eax |
752 | push eax ; initialize .recent_page |
||
753 | push eax ; initialize .recent_restsize |
||
754 | push eax ; initialize .cname |
||
755 | push [.res] ; initialize .res_list_tail |
||
756 | sub esp, .locals_size-16 ; reserve place for other vars |
||
757 | mov edx, esp ; edx -> buffer for datagram |
||
1155 | clevermous | 758 | ; 1. Save used registers for __stdcall. |
3545 | hidnplayr | 759 | push ebx esi edi |
760 | mov edi, [.reqdata] |
||
1155 | clevermous | 761 | ; 2. Read UDP datagram. |
3545 | hidnplayr | 762 | mov ecx, [edi+__gai_reqdata.socketnum] |
763 | push edi |
||
3704 | hidnplayr | 764 | mcall 75, 7, , , 512, MSG_DONTWAIT |
3545 | hidnplayr | 765 | pop edi |
766 | ; 3. Ignore events for other socketnums (return if no data read) |
||
767 | test eax, eax |
||
768 | jz .ret.more_processing_required |
||
1155 | clevermous | 769 | ; 4. Sanity check: discard too short packets. |
3545 | hidnplayr | 770 | xchg ecx, eax ; save packet length in ecx |
771 | cmp ecx, 12 |
||
772 | jb .ret.more_processing_required |
||
1155 | clevermous | 773 | ; 5. Discard packets with ID != request ID. |
3545 | hidnplayr | 774 | mov eax, dword [edi+__gai_reqdata.reqid] |
775 | cmp ax, [edx] |
||
776 | jnz .ret.more_processing_required |
||
1155 | clevermous | 777 | ; 6. Sanity check: discard query packets. |
3545 | hidnplayr | 778 | test byte [edx+2], 80h |
779 | jz .ret.more_processing_required |
||
1155 | clevermous | 780 | ; 7. Sanity check: must be exactly one query (our). |
3545 | hidnplayr | 781 | cmp word [edx+4], 0x0100 ; note network byte order |
782 | jnz .ret.more_processing_required |
||
1155 | clevermous | 783 | ; 8. Check for errors. Return EAI_NONAME for error code 3 and EAI_FAIL for other. |
3545 | hidnplayr | 784 | mov al, [edx+3] |
785 | and al, 0xF |
||
786 | jz @f |
||
787 | cmp al, 3 |
||
788 | jnz .ret.no_recovery |
||
789 | jmp .ret.no_name |
||
1155 | clevermous | 790 | @@: |
791 | ; 9. Locate answers section. Exactly 1 query is present in this packet. |
||
3545 | hidnplayr | 792 | add ecx, edx ; ecx = limit |
793 | lea esi, [edx+12] |
||
794 | call .skip_name |
||
795 | lodsd ; skip QTYPE and QCLASS field |
||
796 | cmp esi, ecx |
||
797 | ja .ret.no_recovery |
||
1155 | clevermous | 798 | ; 10. Loop through all answers. |
3545 | hidnplayr | 799 | movzx ebx, word [edx+6] ; get answers count |
800 | xchg bl, bh ; network -> Intel byte order |
||
1155 | clevermous | 801 | .answers_loop: |
3545 | hidnplayr | 802 | dec ebx |
803 | js .answers_done |
||
1155 | clevermous | 804 | ; 10a. Process each record. |
3545 | hidnplayr | 805 | mov [.name], esi |
1155 | clevermous | 806 | ; 10b. Skip name field. |
3545 | hidnplayr | 807 | call .skip_name |
1155 | clevermous | 808 | ; 10c. Get record information, handle two types for class IN (internet). |
3545 | hidnplayr | 809 | lodsd ; get type and class |
810 | cmp esi, ecx |
||
811 | ja .ret.no_recovery |
||
812 | cmp eax, 0x01000500 ; type=5, class=1? |
||
813 | jz .got_cname |
||
814 | cmp eax, 0x01000100 ; type=1, class=1? |
||
815 | jnz .answers_loop.next |
||
1155 | clevermous | 816 | .got_addr: |
817 | ; 10d. Process record A, host address. |
||
3545 | hidnplayr | 818 | add esi, 10 |
819 | cmp esi, ecx |
||
820 | ja .ret.no_recovery |
||
821 | cmp word [esi-6], 0x0400 ; RDATA for A records must be 4 bytes long |
||
822 | jnz .ret.no_recovery |
||
823 | mov eax, [.name] |
||
824 | mov [.addrname], eax |
||
1155 | clevermous | 825 | ; 10e. Create corresponding record in the answer. |
3545 | hidnplayr | 826 | push ebx ecx esi |
827 | mov eax, [esi-4] ; IP address |
||
828 | mov esi, [.res_list_tail] ; pointer to result |
||
829 | test esi, esi |
||
830 | jz .no_result ; do not save if .res is NULL |
||
831 | mov ebx, [.reqdata] ; request data |
||
832 | call getaddrinfo._.generate_data |
||
833 | mov [.res_list_tail], esi |
||
834 | pop esi ecx ebx |
||
835 | cmp [.res_list_tail], 0 |
||
836 | jnz .answers_loop |
||
1155 | clevermous | 837 | ; 10f. If generate_data failed (this means memory allocation failure), abort |
3545 | hidnplayr | 838 | jmp .ret.no_memory |
1155 | clevermous | 839 | .no_result: |
3545 | hidnplayr | 840 | pop esi ecx ebx |
841 | jmp .answers_loop |
||
1155 | clevermous | 842 | .got_cname: |
843 | ; 10g. Process record CNAME, main host name. |
||
3545 | hidnplayr | 844 | lea eax, [esi+6] |
845 | mov [.cname], eax |
||
1155 | clevermous | 846 | .answers_loop.next: |
847 | ; 10h. Skip other record fields, advance to next record. |
||
3545 | hidnplayr | 848 | lodsd ; skip TTL |
849 | xor eax, eax |
||
850 | lodsw ; get length of RDATA field |
||
851 | xchg al, ah ; network -> Intel byte order |
||
852 | add esi, eax |
||
853 | cmp esi, ecx |
||
854 | ja .ret.no_recovery |
||
855 | jmp .answers_loop |
||
1155 | clevermous | 856 | .answers_done: |
857 | ; 11. Check that there is at least 1 answer. |
||
3545 | hidnplayr | 858 | mov eax, [.res_list_tail] |
859 | cmp [.res], eax |
||
860 | jz .ret.no_data |
||
1155 | clevermous | 861 | ; 12. If canonical name was required, add it now. |
3545 | hidnplayr | 862 | mov eax, [.reqdata] |
863 | test byte [eax+__gai_reqdata.flags], AI_CANONNAME |
||
864 | jz .no_canon_name |
||
1155 | clevermous | 865 | ; 12a. If at least one CNAME record is present, use name from last such record. |
866 | ; Otherwise, use name from one of A records. |
||
3545 | hidnplayr | 867 | mov esi, [.cname] |
868 | test esi, esi |
||
869 | jnz .has_cname |
||
870 | mov esi, [.addrname] |
||
1155 | clevermous | 871 | .has_cname: |
872 | ; 12b. Calculate name length. |
||
3545 | hidnplayr | 873 | call .get_name_length |
874 | jc .ret.no_recovery |
||
1155 | clevermous | 875 | ; 12c. Check that the caller really want to get data. |
3545 | hidnplayr | 876 | cmp [.res], 0 |
877 | jz .no_canon_name |
||
1155 | clevermous | 878 | ; 12d. Allocate memory for name. |
3545 | hidnplayr | 879 | call getaddrinfo._.memalloc |
880 | test edi, edi |
||
881 | jz .ret.no_memory |
||
1155 | clevermous | 882 | ; 12e. Make first entry in .res list point to canonical name. |
3545 | hidnplayr | 883 | mov eax, [.res] |
884 | mov eax, [eax] |
||
885 | mov [eax+addrinfo.ai_canonname], edi |
||
1155 | clevermous | 886 | ; 12f. Decode name. |
3545 | hidnplayr | 887 | call .decode_name |
1155 | clevermous | 888 | .no_canon_name: |
889 | ; 13. Set status to success. |
||
3545 | hidnplayr | 890 | xor eax, eax |
891 | jmp .ret.close |
||
1155 | clevermous | 892 | ; Handle errors. |
893 | .ret.more_processing_required: |
||
3545 | hidnplayr | 894 | push -1 |
895 | pop eax |
||
896 | jmp .ret |
||
1155 | clevermous | 897 | .ret.no_recovery: |
3545 | hidnplayr | 898 | push EAI_FAIL |
899 | pop eax |
||
900 | jmp .ret.destroy |
||
1155 | clevermous | 901 | .ret.no_memory: |
3545 | hidnplayr | 902 | push EAI_MEMORY |
903 | pop eax |
||
904 | jmp .ret.destroy |
||
1155 | clevermous | 905 | .ret.no_name: |
906 | .ret.no_data: |
||
3545 | hidnplayr | 907 | push EAI_NONAME |
908 | pop eax |
||
1155 | clevermous | 909 | .ret.destroy: |
910 | ; 14. If an error occured, free memory acquired so far. |
||
3545 | hidnplayr | 911 | push eax |
912 | mov esi, [.res] |
||
913 | test esi, esi |
||
914 | jz @f |
||
915 | pushd [esi] |
||
916 | call freeaddrinfo |
||
917 | and dword [esi], 0 |
||
1155 | clevermous | 918 | @@: |
3545 | hidnplayr | 919 | pop eax |
1155 | clevermous | 920 | .ret.close: |
3545 | hidnplayr | 921 | ; 15. Close socketnum. |
922 | push eax |
||
923 | mov ecx, [.reqdata] |
||
924 | mov ecx, [ecx+__gai_reqdata.socketnum] |
||
925 | mcall 75, 1 |
||
926 | pop eax |
||
1155 | clevermous | 927 | ; 16. Restore used registers, destroy stack frame and return. |
928 | .ret: |
||
3545 | hidnplayr | 929 | pop edi esi ebx |
930 | mov esp, ebp |
||
931 | pop ebp |
||
932 | ret 8 |
||
1155 | clevermous | 933 | |
934 | ;;===========================================================================;; |
||
935 | ;; Internal auxiliary function for skipping names in DNS packet. ;; |
||
936 | .skip_name: ;; |
||
937 | ;;---------------------------------------------------------------------------;; |
||
938 | ;? Skips name in DNS packet. ;; |
||
939 | ;;---------------------------------------------------------------------------;; |
||
940 | ;> esi -> name ;; |
||
941 | ;> ecx = end of packet ;; |
||
942 | ;;---------------------------------------------------------------------------;; |
||
943 | ;< esi -> end of name ;; |
||
944 | ;;===========================================================================;; |
||
3545 | hidnplayr | 945 | xor eax, eax |
946 | cmp esi, ecx |
||
947 | jae .skip_name.done |
||
948 | lodsb |
||
949 | test al, al |
||
950 | jz .skip_name.done |
||
951 | test al, 0xC0 |
||
952 | jnz .skip_name.pointer |
||
953 | add esi, eax |
||
954 | jmp .skip_name |
||
1155 | clevermous | 955 | .skip_name.pointer: |
3545 | hidnplayr | 956 | inc esi |
1155 | clevermous | 957 | .skip_name.done: |
3545 | hidnplayr | 958 | ret |
1155 | clevermous | 959 | |
960 | ;;===========================================================================;; |
||
961 | ;; Internal auxiliary function for calculating length of name in DNS packet. ;; |
||
962 | .get_name_length: ;; |
||
963 | ;;---------------------------------------------------------------------------;; |
||
964 | ;? Calculate length of name (including terminating zero) in DNS packet. ;; |
||
965 | ;;---------------------------------------------------------------------------;; |
||
966 | ;> edx = start of packet ;; |
||
967 | ;> esi -> name ;; |
||
968 | ;> ecx = end of packet ;; |
||
969 | ;;---------------------------------------------------------------------------;; |
||
970 | ;< eax = length of name ;; |
||
971 | ;< CF set on error / cleared on success ;; |
||
972 | ;;===========================================================================;; |
||
3545 | hidnplayr | 973 | xor ebx, ebx ; ebx will hold data length |
1155 | clevermous | 974 | .get_name_length.zero: |
3545 | hidnplayr | 975 | xor eax, eax |
1155 | clevermous | 976 | .get_name_length.loop: |
3545 | hidnplayr | 977 | cmp esi, ecx |
978 | jae .get_name_length.fail |
||
979 | lodsb |
||
980 | test al, al |
||
981 | jz .get_name_length.done |
||
982 | test al, 0xC0 |
||
983 | jnz .get_name_length.pointer |
||
984 | add esi, eax |
||
985 | inc ebx |
||
986 | add ebx, eax |
||
987 | cmp ebx, 256 |
||
988 | jbe .get_name_length.loop |
||
1155 | clevermous | 989 | .get_name_length.fail: |
3545 | hidnplayr | 990 | stc |
991 | ret |
||
1155 | clevermous | 992 | .get_name_length.pointer: |
3545 | hidnplayr | 993 | and al, 0x3F |
994 | mov ah, al |
||
995 | lodsb |
||
996 | lea esi, [edx+eax] |
||
997 | jmp .get_name_length.zero |
||
1155 | clevermous | 998 | .get_name_length.done: |
3545 | hidnplayr | 999 | test ebx, ebx |
1000 | jz .get_name_length.fail |
||
1001 | xchg eax, ebx |
||
1002 | clc |
||
1003 | ret |
||
1155 | clevermous | 1004 | |
1005 | ;;===========================================================================;; |
||
1006 | ;; Internal auxiliary function for decoding DNS name. ;; |
||
1007 | .decode_name: ;; |
||
1008 | ;;---------------------------------------------------------------------------;; |
||
1009 | ;? Decode name in DNS packet. ;; |
||
1010 | ;;---------------------------------------------------------------------------;; |
||
1011 | ;> edx = start of packet ;; |
||
1012 | ;> esi -> name in packet ;; |
||
1013 | ;> edi -> buffer for decoded name ;; |
||
1014 | ;;===========================================================================;; |
||
3545 | hidnplayr | 1015 | xor eax, eax |
1016 | lodsb |
||
1017 | test al, al |
||
1018 | jz .decode_name.done |
||
1019 | test al, 0xC0 |
||
1020 | jnz .decode_name.pointer |
||
1021 | mov ecx, eax |
||
1022 | rep movsb |
||
1023 | mov al, '.' |
||
1024 | stosb |
||
1025 | jmp .decode_name |
||
1155 | clevermous | 1026 | .decode_name.pointer: |
3545 | hidnplayr | 1027 | and al, 0x3F |
1028 | mov ah, al |
||
1029 | lodsb |
||
1030 | lea esi, [edx+eax] |
||
1031 | jmp .decode_name |
||
1155 | clevermous | 1032 | .decode_name.done: |
3545 | hidnplayr | 1033 | mov byte [edi-1], 0 |
1034 | ret |
||
1155 | clevermous | 1035 | |
1036 | ;;===========================================================================;; |
||
1037 | ;; Internal auxiliary function for allocating memory for getaddrinfo. ;; |
||
1038 | getaddrinfo._.memalloc: ;; |
||
1039 | ;;---------------------------------------------------------------------------;; |
||
1040 | ;? Memory allocation. ;; |
||
1041 | ;;---------------------------------------------------------------------------;; |
||
1042 | ;> eax = size in bytes, must be less than page size. ;; |
||
1043 | ;> [ebp-4] = .recent_page = last allocated page ;; |
||
1044 | ;> [ebp-8] = .recent_restsize = bytes rest in last allocated page ;; |
||
1045 | ;;---------------------------------------------------------------------------;; |
||
1046 | ;< edi -> allocated memory / NULL on error ;; |
||
1047 | ;;===========================================================================;; |
||
1048 | ; 1. Set edi to result of function. |
||
3545 | hidnplayr | 1049 | mov edi, [ebp-4] |
1155 | clevermous | 1050 | ; 2. Check whether we need to allocate a new page. |
3545 | hidnplayr | 1051 | cmp eax, [ebp-8] |
1052 | jbe .no_new_page |
||
1155 | clevermous | 1053 | ; 2. Allocate new page if need. Reset edi to new result. |
3545 | hidnplayr | 1054 | push eax ebx |
1055 | mcall 68, 12, 0x1000 |
||
1056 | xchg edi, eax ; put result to edi |
||
1057 | pop ebx eax |
||
1155 | clevermous | 1058 | ; 3. Check returned value of allocator. Fail if it failed. |
3545 | hidnplayr | 1059 | test edi, edi |
1060 | jz .ret |
||
1155 | clevermous | 1061 | ; 4. Update .recent_page and .recent_restsize. |
3545 | hidnplayr | 1062 | add edi, 4 |
1063 | sub ecx, 4 |
||
1064 | mov [ebp-4], edi |
||
1065 | mov [ebp-8], ecx |
||
1155 | clevermous | 1066 | .no_new_page: |
1067 | ; 5. Increase number of objects on this page. |
||
3545 | hidnplayr | 1068 | push eax |
1069 | mov eax, edi |
||
1070 | and eax, not 0xFFF |
||
1071 | inc dword [eax] |
||
1072 | pop eax |
||
1155 | clevermous | 1073 | ; 6. Advance last allocated pointer, decrease memory size. |
3545 | hidnplayr | 1074 | add [ebp-4], eax |
1075 | sub [ebp-8], eax |
||
1155 | clevermous | 1076 | ; 7. Return. |
1077 | .ret: |
||
3545 | hidnplayr | 1078 | ret |
1155 | clevermous | 1079 | |
1080 | ;;===========================================================================;; |
||
1081 | ;; Internal auxiliary function for freeing memory for freeaddrinfo. ;; |
||
1082 | getaddrinfo._.memfree: ;; |
||
1083 | ;;---------------------------------------------------------------------------;; |
||
1084 | ;? Free memory. ;; |
||
1085 | ;;---------------------------------------------------------------------------;; |
||
1086 | ;> eax = pointer ;; |
||
1087 | ;;===========================================================================;; |
||
1088 | ; 1. Get start of page. |
||
3545 | hidnplayr | 1089 | mov ecx, eax |
1090 | and ecx, not 0xFFF |
||
1155 | clevermous | 1091 | ; 2. Decrease number of objects. |
3545 | hidnplayr | 1092 | dec dword [ecx] |
1155 | clevermous | 1093 | ; 3. If it goes to zero, free the page. |
3545 | hidnplayr | 1094 | jnz @f |
1095 | push ebx |
||
1096 | mcall 68, 13 |
||
1097 | pop ebx |
||
1155 | clevermous | 1098 | @@: |
1099 | ; 4. Done. |
||
3545 | hidnplayr | 1100 | ret |
1155 | clevermous | 1101 | |
1102 | ;;===========================================================================;; |
||
1103 | getaddrinfo._.generate_data: ;; |
||
1104 | ;;---------------------------------------------------------------------------;; |
||
1105 | ;? Generate item(s) of getaddrinfo result list by one IP address. ;; |
||
1106 | ;;---------------------------------------------------------------------------;; |
||
1107 | ;> eax = IP address ;; |
||
1108 | ;> ebx = request data ;; |
||
1109 | ;> esi = pointer to result ;; |
||
1110 | ;> [ebp-4] = .recent_page = last allocated page ;; |
||
1111 | ;> [ebp-8] = .recent_restsize = bytes rest in last allocated page ;; |
||
1112 | ;;---------------------------------------------------------------------------;; |
||
1113 | ;< esi = pointer to next list item for result / NULL on error ;; |
||
1114 | ;;===========================================================================;; |
||
1115 | ; 1. If no service is given, append one item with zero port. |
||
1116 | ; append one item with zero socktype/protocol/port. |
||
3545 | hidnplayr | 1117 | cmp [ebx+__gai_reqdata.service], -1 |
1118 | jnz .has_service |
||
1119 | call .append_item |
||
1155 | clevermous | 1120 | ; 1a. If neither protocol nor socktype were specified, |
3545 | hidnplayr | 1121 | ; leave zeroes in socktype and protocol. |
1122 | mov cl, [ebx+__gai_reqdata.socktype] |
||
1123 | test cl, cl |
||
1124 | jz .no_socktype |
||
1155 | clevermous | 1125 | ; 1b. Otherwise, set socktype and protocol to desired. |
3545 | hidnplayr | 1126 | call .set_socktype |
1155 | clevermous | 1127 | .no_socktype: |
3545 | hidnplayr | 1128 | ret |
1155 | clevermous | 1129 | .has_service: |
1130 | ; 2. If TCP is allowed, append item for TCP. |
||
3545 | hidnplayr | 1131 | cmp [ebx+__gai_reqdata.socktype], 0 |
1132 | jz .tcp_ok |
||
1133 | cmp [ebx+__gai_reqdata.socktype], SOCK_STREAM |
||
1134 | jnz .tcp_disallowed |
||
1155 | clevermous | 1135 | .tcp_ok: |
3545 | hidnplayr | 1136 | call .append_item |
1137 | mov cl, SOCK_STREAM |
||
1138 | call .set_socktype |
||
1139 | call .set_port |
||
1155 | clevermous | 1140 | .tcp_disallowed: |
1141 | ; 3. If UDP is allowed, append item for UDP. |
||
3545 | hidnplayr | 1142 | cmp [ebx+__gai_reqdata.socktype], 0 |
1143 | jz .udp_ok |
||
1144 | cmp [ebx+__gai_reqdata.socktype], SOCK_DGRAM |
||
1145 | jnz .udp_disallowed |
||
1155 | clevermous | 1146 | .udp_ok: |
3545 | hidnplayr | 1147 | call .append_item |
1148 | mov cl, SOCK_DGRAM |
||
1149 | call .set_socktype |
||
1150 | call .set_port |
||
1155 | clevermous | 1151 | .udp_disallowed: |
3545 | hidnplayr | 1152 | ret |
1155 | clevermous | 1153 | |
1154 | .append_item: |
||
1155 | ; 1. Allocate memory for struct sockaddr_in and struct addrinfo. |
||
3545 | hidnplayr | 1156 | push eax |
1157 | push sizeof.addrinfo + sizeof.sockaddr_in |
||
1158 | pop eax |
||
1159 | call getaddrinfo._.memalloc |
||
1155 | clevermous | 1160 | ; 2. Check for memory allocation fail. |
3545 | hidnplayr | 1161 | test edi, edi |
1162 | jz .no_memory |
||
1155 | clevermous | 1163 | ; 3. Zero allocated memory. |
3545 | hidnplayr | 1164 | push (sizeof.addrinfo + sizeof.sockaddr_in) / 4 |
1165 | pop ecx |
||
1166 | xor eax, eax |
||
1167 | push edi |
||
1168 | rep stosd |
||
1169 | pop edi |
||
1155 | clevermous | 1170 | ; 4. Fill struct addrinfo. |
3545 | hidnplayr | 1171 | mov eax, [ebx+__gai_reqdata.flags] |
1172 | mov [edi+addrinfo.ai_flags], eax |
||
1173 | mov byte [edi+addrinfo.ai_family], AF_INET4 |
||
1174 | mov byte [edi+addrinfo.ai_addrlen], sizeof.sockaddr_in |
||
1175 | lea ecx, [edi+sizeof.addrinfo] |
||
1176 | mov [edi+addrinfo.ai_addr], ecx |
||
1155 | clevermous | 1177 | ; 5. Fill struct sockaddr_in. |
3545 | hidnplayr | 1178 | mov byte [ecx+sockaddr_in.sin_family], AF_INET4 |
1179 | pop eax |
||
1180 | mov [ecx+sockaddr_in.sin_addr], eax |
||
1155 | clevermous | 1181 | ; 6. Append new item to the list. |
3545 | hidnplayr | 1182 | mov [esi], edi |
1183 | lea esi, [edi+addrinfo.ai_next] |
||
1155 | clevermous | 1184 | ; 7. Return. |
3545 | hidnplayr | 1185 | ret |
1155 | clevermous | 1186 | .no_memory: |
3545 | hidnplayr | 1187 | pop eax |
1188 | xor esi, esi |
||
1189 | ret |
||
1155 | clevermous | 1190 | |
1191 | .set_socktype: |
||
3545 | hidnplayr | 1192 | ; Set ai_socktype and ai_protocol fields by given socketnum type. |
1193 | mov byte [edi+addrinfo.ai_socktype], cl |
||
1194 | dec cl |
||
1195 | jnz .set_udp |
||
1155 | clevermous | 1196 | .set_tcp: |
3545 | hidnplayr | 1197 | mov byte [edi+addrinfo.ai_protocol], IPPROTO_TCP |
1198 | ret |
||
1155 | clevermous | 1199 | .set_udp: |
3545 | hidnplayr | 1200 | mov byte [edi+addrinfo.ai_protocol], IPPROTO_UDP |
1201 | ret |
||
1155 | clevermous | 1202 | |
1203 | .set_port: |
||
1204 | ; Just copy port from input __gai_reqdata to output addrinfo. |
||
3545 | hidnplayr | 1205 | push edx |
1206 | mov edx, [ebx+__gai_reqdata.service] |
||
1207 | xchg dl, dh ; convert to network byte order ;;;;; CHECKME |
||
1208 | mov [edi+sizeof.addrinfo+sockaddr_in.sin_port], dx |
||
1209 | pop edx |
||
1210 | ret |
||
1155 | clevermous | 1211 | |
1212 | ;;===========================================================================;; |
||
1213 | ;; void __stdcall getaddrinfo_abort(__in struct __gai_reqdata* reqdata); ;; |
||
1214 | getaddrinfo_abort: ;; |
||
1215 | ;;---------------------------------------------------------------------------;; |
||
1216 | ;? Abort process started by getaddrinfo_start, free all resources. ;; |
||
1217 | ;;---------------------------------------------------------------------------;; |
||
1218 | ;> first parameter = pointer to struct __gai_reqdata filled by ..._start ;; |
||
1219 | ;;===========================================================================;; |
||
1220 | ; 0. Save used registers for __stdcall. |
||
3545 | hidnplayr | 1221 | push ebx |
1222 | ; 1. Allocated resources: only socketnum, so close it and return. |
||
1223 | mov eax, [esp+8] |
||
1224 | mov ecx, [eax+__gai_reqdata.socketnum] |
||
1225 | mcall 75, 1 |
||
1155 | clevermous | 1226 | ; 2. Restore used registers and return. |
3545 | hidnplayr | 1227 | pop ebx |
1228 | ret 4 |
||
1155 | clevermous | 1229 | |
1230 | ;;===========================================================================;; |
||
1231 | ;; void __stdcall freeaddrinfo(__in struct addrinfo* ai); ;; |
||
1232 | freeaddrinfo: ;; |
||
1233 | ;;---------------------------------------------------------------------------;; |
||
1234 | ;? Free one or more addrinfo structures returned by getaddrinfo. ;; |
||
1235 | ;;---------------------------------------------------------------------------;; |
||
1236 | ;> first parameter = head of list of structures ;; |
||
1237 | ; (may be arbitrary sublist of original) ;; |
||
1238 | ;;===========================================================================;; |
||
1239 | ; 1. Loop for all items in the list. |
||
3545 | hidnplayr | 1240 | mov edx, [esp+4] ; eax = ai |
1155 | clevermous | 1241 | .loop: |
3545 | hidnplayr | 1242 | test edx, edx |
1243 | jz .done |
||
1155 | clevermous | 1244 | ; 2. Free each item. |
1245 | ; 2a. Free ai_canonname, if allocated. |
||
3545 | hidnplayr | 1246 | mov eax, [edx+addrinfo.ai_canonname] |
1247 | test eax, eax |
||
1248 | jz .no_canon_name |
||
1249 | call getaddrinfo._.memfree |
||
1155 | clevermous | 1250 | .no_canon_name: |
1251 | ; 2b. Remember next item |
||
3545 | hidnplayr | 1252 | ; (after freeing the field ai_next can became unavailable). |
1253 | pushd [edx+addrinfo.ai_next] |
||
1155 | clevermous | 1254 | ; 2c. Free item itself. |
3545 | hidnplayr | 1255 | xchg eax, edx |
1256 | call getaddrinfo._.memfree |
||
1155 | clevermous | 1257 | ; 2d. Restore pointer to next item and continue loop. |
3545 | hidnplayr | 1258 | pop edx |
1259 | jmp .loop |
||
1155 | clevermous | 1260 | .done: |
1261 | ; 3. Done. |
||
3545 | hidnplayr | 1262 | ret 4 |
1155 | clevermous | 1263 | |
1264 | ;;===========================================================================;; |
||
1265 | ;;///////////////////////////////////////////////////////////////////////////;; |
||
1266 | ;;===========================================================================;; |
||
1267 | ;! Exported functions section ;; |
||
1268 | ;;===========================================================================;; |
||
1269 | ;;///////////////////////////////////////////////////////////////////////////;; |
||
1270 | ;;===========================================================================;; |
||
1271 | |||
1272 | |||
1273 | align 4 |
||
1274 | @EXPORT: |
||
3545 | hidnplayr | 1275 | export \ |
1276 | lib_init , 'lib_init' , \ |
||
1277 | 0x00010001 , 'version' , \ |
||
1278 | inet_addr , 'inet_addr' , \ |
||
1279 | inet_ntoa , 'inet_ntoa' , \ |
||
1280 | getaddrinfo , 'getaddrinfo' , \ |
||
1281 | getaddrinfo_start , 'getaddrinfo_start' , \ |
||
1282 | getaddrinfo_process , 'getaddrinfo_process' , \ |
||
1283 | getaddrinfo_abort , 'getaddrinfo_abort' , \ |
||
1284 | freeaddrinfo , 'freeaddrinfo' |
||
1155 | clevermous | 1285 | |
1286 | section '.data' data readable writable align 16 |
||
1287 | ; uninitialized data |
||
1288 | mem.alloc dd ? |
||
1289 | mem.free dd ? |
||
1290 | mem.realloc dd ? |
||
1291 | dll.load dd ? |
||
1292 | |||
3545 | hidnplayr | 1293 | DNSrequestID dd ? |
1155 | clevermous | 1294 | |
3545 | hidnplayr | 1295 | inet_ntoa.buffer rb 16 ; static buffer for inet_ntoa>>>>>>0>>>>>>>>> |