Rev 260 | Go to most recent revision | Only display areas with differences | Regard whitespace | Details | Blame | Last modification | View Log | RSS feed
Rev 260 | Rev 485 | ||
---|---|---|---|
1 | ; |
1 | ; |
2 | ; ETH.INC |
2 | ; ETH.INC |
3 | ; |
3 | ; |
4 | ; made by hidnplayr (hidnplayr@gmail.com) for KolibriOS |
4 | ; made by hidnplayr (hidnplayr@gmail.com) for KolibriOS |
5 | ; |
5 | ; |
6 | ; The given code before every macro is only a simple example |
6 | ; The given code before every macro is only a simple example |
7 | ; |
7 | ; |
8 | ; |
8 | ; |
9 | ; HISTORY |
9 | ; HISTORY |
10 | ; |
10 | ; |
11 | ; v1.0: 18 august 2006 original release |
11 | ; v1.0: 18 august 2006 original release |
12 | ; v1.1: december 2006 bugfixes and improvements |
12 | ; v1.1: december 2006 bugfixes and improvements |
13 | ; |
13 | ; |
14 | - | ||
15 | 14 | ||
16 | macro mov arg1,arg2 { |
15 | macro mov arg1,arg2 { |
17 | if arg1 eq arg2 |
16 | if arg1 eq arg2 |
18 | else |
17 | else |
19 | mov arg1,arg2 |
18 | mov arg1,arg2 |
20 | end if |
19 | end if |
21 | } |
20 | } |
22 | 21 | ||
23 | TCB_LISTEN = 1 |
22 | TCB_LISTEN = 1 |
24 | TCB_SYN_SENT = 2 |
23 | TCB_SYN_SENT = 2 |
25 | TCB_SYN_RECEIVED = 3 |
24 | TCB_SYN_RECEIVED = 3 |
26 | TCB_ESTABLISHED = 4 |
25 | TCB_ESTABLISHED = 4 |
27 | TCB_FIN_WAIT_1 = 5 |
26 | TCB_FIN_WAIT_1 = 5 |
28 | TCB_FIN_WAIT_2 = 6 |
27 | TCB_FIN_WAIT_2 = 6 |
29 | TCB_CLOSE_WAIT = 7 |
28 | TCB_CLOSE_WAIT = 7 |
30 | TCB_CLOSING = 8 |
29 | TCB_CLOSING = 8 |
31 | TCB_LAST_ASK = 9 |
30 | TCB_LAST_ASK = 9 |
32 | TCB_TIME_WAIT = 10 |
31 | TCB_TIME_WAIT = 10 |
33 | TCB_CLOSED = 11 |
32 | TCB_CLOSED = 11 |
34 | 33 | ||
35 | PASSIVE = 0 |
34 | PASSIVE = 0 |
36 | ACTIVE = 1 |
35 | ACTIVE = 1 |
37 | 36 | ||
38 | ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; |
37 | ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; |
39 | 38 | ||
40 | ; eth.get_IP eax |
39 | ; eth.get_IP eax |
41 | ; |
40 | ; |
42 | ; gets the current IP that is defined in Stack (return in eax in this example) |
41 | ; gets the current IP that is defined in Stack (return in eax in this example) |
43 | macro eth.get_IP IP { |
42 | macro eth.get_IP IP { |
44 | mov ebx,1 |
43 | mov ebx,1 |
45 | mov eax,52 |
44 | mov eax,52 |
46 | int 0x40 |
45 | mcall |
47 | 46 | ||
48 | mov IP ,eax |
47 | mov IP ,eax |
49 | } |
48 | } |
50 | 49 | ||
51 | ; eth.get_GATEWAY eax |
50 | ; eth.get_GATEWAY eax |
52 | ; |
51 | ; |
53 | ; gets the current GATEWAY that is defined in Stack (return in eax in this example) |
52 | ; gets the current GATEWAY that is defined in Stack (return in eax in this example) |
54 | macro eth.get_GATEWAY GATEWAY { |
53 | macro eth.get_GATEWAY GATEWAY { |
55 | mov ebx,9 |
54 | mov ebx,9 |
56 | mov eax,52 |
55 | mov eax,52 |
57 | int 0x40 |
56 | mcall |
58 | move GATEWAY ,eax |
57 | move GATEWAY ,eax |
59 | } |
58 | } |
60 | 59 | ||
61 | ; eth.get_SUBNET eax |
60 | ; eth.get_SUBNET eax |
62 | ; |
61 | ; |
63 | ; gets the current SUBNET that is defined in Stack (return in eax in this example) |
62 | ; gets the current SUBNET that is defined in Stack (return in eax in this example) |
64 | macro eth.get_SUBNET SUBNET { |
63 | macro eth.get_SUBNET SUBNET { |
65 | mov ebx,10 |
64 | mov ebx,10 |
66 | mov eax,52 |
65 | mov eax,52 |
67 | int 0x40 |
66 | mcall |
68 | mov SUBNET ,eax |
67 | mov SUBNET ,eax |
69 | } |
68 | } |
70 | 69 | ||
71 | ; eth.get_DNS eax |
70 | ; eth.get_DNS eax |
72 | ; |
71 | ; |
73 | ; gets the current DNS that is defined in Stack (return in eax in this example) |
72 | ; gets the current DNS that is defined in Stack (return in eax in this example) |
74 | macro eth.get_DNS DNS { |
73 | macro eth.get_DNS DNS { |
75 | mov ebx,13 |
74 | mov ebx,13 |
76 | mov eax,52 |
75 | mov eax,52 |
77 | int 0x40 |
76 | mcall |
78 | mov DNS ,eax |
77 | mov DNS ,eax |
79 | } |
78 | } |
80 | 79 | ||
81 | ; eth.set_IP eax |
80 | ; eth.set_IP eax |
82 | ; |
81 | ; |
83 | ; set a new IP in stack (input in eax in this example) |
82 | ; set a new IP in stack (input in eax in this example) |
84 | macro eth.set_IP IP { |
83 | macro eth.set_IP IP { |
85 | mov ecx,IP |
84 | mov ecx,IP |
86 | mov ebx,3 |
85 | mov ebx,3 |
87 | mov eax,52 |
86 | mov eax,52 |
88 | int 0x40 |
87 | mcall |
89 | } |
88 | } |
90 | 89 | ||
91 | ; eth.set_GATEWAY eax |
90 | ; eth.set_GATEWAY eax |
92 | ; |
91 | ; |
93 | ; set a new GATEWAY in stack (input in eax in this example) |
92 | ; set a new GATEWAY in stack (input in eax in this example) |
94 | macro eth.set_GATEWAY GATEWAY { |
93 | macro eth.set_GATEWAY GATEWAY { |
95 | mov ecx,GATEWAY |
94 | mov ecx,GATEWAY |
96 | mov ebx,11 |
95 | mov ebx,11 |
97 | mov eax,52 |
96 | mov eax,52 |
98 | int 0x40 |
97 | mcall |
99 | } |
98 | } |
100 | 99 | ||
101 | ; eth.set_SUBNET eax |
100 | ; eth.set_SUBNET eax |
102 | ; |
101 | ; |
103 | ; set a new SUBNET in stack (input in eax in this example) |
102 | ; set a new SUBNET in stack (input in eax in this example) |
104 | macro eth.set_SUBNET SUBNET { |
103 | macro eth.set_SUBNET SUBNET { |
105 | mov ecx,SUBNET |
104 | mov ecx,SUBNET |
106 | mov ebx,12 |
105 | mov ebx,12 |
107 | mov eax,52 |
106 | mov eax,52 |
108 | int 0x40 |
107 | mcall |
109 | } |
108 | } |
110 | 109 | ||
111 | ; eth.set_DNS eax |
110 | ; eth.set_DNS eax |
112 | ; |
111 | ; |
113 | ; set a new DNS in stack (input in eax in this example) |
112 | ; set a new DNS in stack (input in eax in this example) |
114 | macro eth.set_DNS DNS { |
113 | macro eth.set_DNS DNS { |
115 | mov ecx,DNS |
114 | mov ecx,DNS |
116 | mov ebx,14 |
115 | mov ebx,14 |
117 | mov eax,52 |
116 | mov eax,52 |
118 | int 0x40 |
117 | mcall |
119 | } |
118 | } |
120 | 119 | ||
121 | ; eth.open eax,80,ebx,[socket] |
120 | ; eth.open eax,80,ebx,[socket] |
122 | ; |
121 | ; |
123 | ; open a socket on local port in eax to port 80 on server on ebx |
122 | ; open a socket on local port in eax to port 80 on server on ebx |
124 | ; the socketnumber will be returned in [socket] (dword) |
123 | ; the socketnumber will be returned in [socket] (dword) |
125 | macro eth.open_udp local,remote,ip,socket { |
124 | macro eth.open_udp local,remote,ip,socket { |
126 | mov ecx, local |
125 | mov ecx, local |
127 | mov edx, remote |
126 | mov edx, remote |
128 | mov esi, ip |
127 | mov esi, ip |
129 | mov ebx, 0 |
128 | mov ebx, 0 |
130 | mov eax, 53 |
129 | mov eax, 53 |
131 | int 0x40 |
130 | mcall |
132 | 131 | ||
133 | mov socket,eax |
132 | mov socket,eax |
134 | } |
133 | } |
135 | 134 | ||
136 | ; eth.close [socket] |
135 | ; eth.close [socket] |
137 | ; |
136 | ; |
138 | ; closes socket on socketnumber [socket] |
137 | ; closes socket on socketnumber [socket] |
139 | macro eth.close_udp socket { |
138 | macro eth.close_udp socket { |
140 | mov ecx, socket |
139 | mov ecx, socket |
141 | mov ebx, 1 |
140 | mov ebx, 1 |
142 | mov eax, 53 |
141 | mov eax, 53 |
143 | int 0x40 |
142 | mcall |
144 | } |
143 | } |
145 | 144 | ||
146 | ; eth.poll [socket],eax |
145 | ; eth.poll [socket],eax |
147 | ; |
146 | ; |
148 | ; polls [socket] for data |
147 | ; polls [socket] for data |
149 | ; eax = 0 when there is data |
148 | ; eax = 0 when there is data |
150 | macro eth.poll socket { |
149 | macro eth.poll socket { |
151 | mov ecx, socket |
150 | mov ecx, socket |
152 | mov ebx, 2 |
151 | mov ebx, 2 |
153 | mov eax, 53 |
152 | mov eax, 53 |
154 | int 0x40 |
153 | mcall |
155 | } |
154 | } |
156 | 155 | ||
157 | ; eth.read_byte [socket], bl |
156 | ; eth.read_byte [socket], bl |
158 | ; |
157 | ; |
159 | ; reads a byte from the socket and returns in bl |
158 | ; reads a byte from the socket and returns in bl |
160 | macro eth.read_byte socket, result { |
159 | macro eth.read_byte socket, result { |
161 | mov ecx, socket |
160 | mov ecx, socket |
162 | mov ebx, 3 |
161 | mov ebx, 3 |
163 | mov eax, 53 |
162 | mov eax, 53 |
164 | int 0x40 |
163 | mcall |
165 | 164 | ||
166 | mov result,bl |
165 | mov result,bl |
167 | } |
166 | } |
168 | 167 | ||
169 | ; eth.read_byte [socket], bl |
168 | ; eth.read_byte [socket], bl |
170 | ; |
169 | ; |
171 | ; reads a byte from the socket and returns in bl |
170 | ; reads a byte from the socket and returns in bl |
172 | macro eth.read_packet socket, result { |
171 | macro eth.read_packet socket, result { |
173 | mov edx, result |
172 | mov edx, result |
174 | mov ecx, socket |
173 | mov ecx, socket |
175 | mov ebx, 10 |
174 | mov ebx, 10 |
176 | mov eax, 53 |
175 | mov eax, 53 |
177 | int 0x40 |
176 | mcall |
178 | } |
177 | } |
179 | 178 | ||
180 | ; eth.write [socket],12,msg |
179 | ; eth.write [socket],12,msg |
181 | ; msg db 'hello world!' |
180 | ; msg db 'hello world!' |
182 | ; |
181 | ; |
183 | ; send message msg to socket |
182 | ; send message msg to socket |
184 | macro eth.write_udp socket,length,msg,verify { |
183 | macro eth.write_udp socket,length,msg,verify { |
185 | mov ecx, socket |
184 | mov ecx, socket |
186 | mov edx, length |
185 | mov edx, length |
187 | mov esi, msg |
186 | mov esi, msg |
188 | mov ebx, 4 |
187 | mov ebx, 4 |
189 | mov eax, 53 |
188 | mov eax, 53 |
190 | int 0x40 |
189 | mcall |
191 | 190 | ||
192 | if verify eq 1 |
191 | if verify eq 1 |
193 | call verifysend |
192 | call verifysend |
194 | end if |
193 | end if |
195 | 194 | ||
196 | } |
195 | } |
197 | 196 | ||
198 | verifysend: |
197 | verifysend: |
199 | test eax,eax |
198 | test eax,eax |
200 | jnz @f |
199 | jnz @f |
201 | ret |
200 | ret |
202 | @@: |
201 | @@: |
203 | pusha |
202 | pusha |
204 | mov eax,5 |
203 | mov eax,5 |
205 | mov ebx,100 |
204 | mov ebx,100 |
206 | int 0x40 |
205 | mcall |
- | 206 | ||
207 | popa |
207 | popa |
208 | int 0x40 |
208 | mcall |
209 | ret |
209 | ret |
210 | 210 | ||
211 | ; eth.open_tcp 80,80,eax,0,[socket] |
211 | ; eth.open_tcp 80,80,eax,0,[socket] |
212 | ; |
212 | ; |
213 | ; opens a tcp socket on port 80 to port 80 on IP eax with passive open |
213 | ; opens a tcp socket on port 80 to port 80 on IP eax with passive open |
214 | ; returns socket number in eax |
214 | ; returns socket number in eax |
215 | macro eth.open_tcp local,remote,ip,passive,socket { |
215 | macro eth.open_tcp local,remote,ip,passive,socket { |
216 | 216 | ||
217 | mov ecx, local |
217 | mov ecx, local |
218 | mov edx, remote |
218 | mov edx, remote |
219 | mov esi, ip |
219 | mov esi, ip |
220 | mov edi, passive ; 0 = PASSIVE open |
220 | mov edi, passive ; 0 = PASSIVE open |
221 | mov ebx, 5 |
221 | mov ebx, 5 |
222 | mov eax, 53 |
222 | mov eax, 53 |
223 | int 0x40 |
223 | mcall |
224 | 224 | ||
225 | mov socket,eax |
225 | mov socket,eax |
226 | } |
226 | } |
227 | 227 | ||
228 | ; eth.socket_status [socket],eax |
228 | ; eth.socket_status [socket],eax |
229 | ; |
229 | ; |
230 | ; returns socket status in eax |
230 | ; returns socket status in eax |
231 | macro eth.socket_status socket,result { |
231 | macro eth.socket_status socket,result { |
232 | mov ecx, socket |
232 | mov ecx, socket |
233 | mov ebx, 6 |
233 | mov ebx, 6 |
234 | mov eax, 53 |
234 | mov eax, 53 |
235 | int 0x40 |
235 | mcall |
236 | 236 | ||
237 | mov result,eax |
237 | mov result,eax |
238 | } |
238 | } |
239 | 239 | ||
240 | ; eth.write_tcp [socket],12,msg |
240 | ; eth.write_tcp [socket],12,msg |
241 | ; |
241 | ; |
242 | ; msg db 'hello world!' |
242 | ; msg db 'hello world!' |
243 | ; |
243 | ; |
244 | ; send message to TCP socket |
244 | ; send message to TCP socket |
245 | macro eth.write_tcp socket,length,msg,verify { |
245 | macro eth.write_tcp socket,length,msg,verify { |
246 | mov ecx, socket |
246 | mov ecx, socket |
247 | mov edx, length |
247 | mov edx, length |
248 | mov esi, msg |
248 | mov esi, msg |
249 | mov ebx, 7 |
249 | mov ebx, 7 |
250 | mov eax, 53 |
250 | mov eax, 53 |
251 | int 0x40 |
251 | mcall |
252 | 252 | ||
253 | if verify eq 1 |
253 | if verify eq 1 |
254 | call verifysend |
254 | call verifysend |
255 | end if |
255 | end if |
256 | } |
256 | } |
257 | 257 | ||
258 | ; eth.close_tcp [socket] |
258 | ; eth.close_tcp [socket] |
259 | ; |
259 | ; |
260 | ; closes tcp socket [socket] |
260 | ; closes tcp socket [socket] |
261 | macro eth.close_tcp socket { |
261 | macro eth.close_tcp socket { |
262 | mov ecx, socket |
262 | mov ecx, socket |
263 | mov ebx, 8 |
263 | mov ebx, 8 |
264 | mov eax, 53 |
264 | mov eax, 53 |
265 | int 0x40 |
265 | mcall |
266 | } |
266 | } |
267 | 267 | ||
268 | ; eth.check_port 165,eax |
268 | ; eth.check_port 165,eax |
269 | ; |
269 | ; |
270 | ; checks if port 165 is used |
270 | ; checks if port 165 is used |
271 | ; return is 0 when port is free |
271 | ; return is 0 when port is free |
272 | macro eth.check_port port,result { |
272 | macro eth.check_port port,result { |
273 | mov ecx, port |
273 | mov ecx, port |
274 | mov ebx, 9 |
274 | mov ebx, 9 |
275 | mov eax, 53 |
275 | mov eax, 53 |
276 | int 0x40 |
276 | mcall |
277 | 277 | ||
278 | mov result,eax |
278 | mov result,eax |
279 | } |
279 | } |
280 | 280 | ||
281 | ; eth.status eax |
281 | ; eth.status eax |
282 | ; |
282 | ; |
283 | ; returns socket status in eax |
283 | ; returns socket status in eax |
284 | macro eth.status status { |
284 | macro eth.status status { |
285 | mov ebx, 255 |
285 | mov ebx, 255 |
286 | mov ecx, 6 |
286 | mov ecx, 6 |
287 | mov eax, 53 |
287 | mov eax, 53 |
288 | int 0x40 |
288 | mcall |
289 | 289 | ||
290 | mov status,eax |
290 | mov status,eax |
291 | } |
291 | } |
292 | 292 | ||
293 | ; eth.search 165,edx |
293 | ; eth.search 165,edx |
294 | ; |
294 | ; |
295 | ; searches a free local port starting from 166 (165 + 1 !) |
295 | ; searches a free local port starting from 166 (165 + 1 !) |
296 | ; returns in edx |
296 | ; returns in edx |
297 | macro eth.search_port port,result { |
297 | macro eth.search_port port,result { |
298 | mov edx,port |
298 | mov edx,port |
299 | @@: |
299 | @@: |
300 | inc edx |
300 | inc edx |
301 | eth.check_port edx,eax |
301 | eth.check_port edx,eax |
302 | cmp eax,0 |
302 | cmp eax,0 |
303 | je @r |
303 | je @r |
304 | mov result,edx |
304 | mov result,edx |
305 | } |
305 | } |
306 | 306 | ||
307 | 307 | ||
308 | 308 | ||
309 | ; eth.read_data [socket],buffer,512 |
309 | ; eth.read_data [socket],buffer,512 |
310 | ; buffer rb 512 |
310 | ; buffer rb 512 |
311 | ; socket dd ? |
311 | ; socket dd ? |
312 | ; |
312 | ; |
313 | ; reads data from socket into a buffer, stops when there is no more data or buffer is full. |
313 | ; reads data from socket into a buffer, stops when there is no more data or buffer is full. |
314 | macro eth.read_data socket,dest,endptr,bufferl { |
314 | macro eth.read_data socket,dest,endptr,bufferl { |
315 | local .getdata,.loop,.end |
315 | local .getdata,.loop,.end |
316 | mov eax, dest |
316 | mov eax, dest |
317 | mov endptr, eax |
317 | mov endptr, eax |
318 | 318 | ||
319 | ; we have data - this will be the response |
319 | ; we have data - this will be the response |
320 | .getdata: |
320 | .getdata: |
321 | mov eax,endptr |
321 | mov eax,endptr |
322 | cmp eax,bufferl |
322 | cmp eax,bufferl |
323 | jg .end |
323 | jg .end |
324 | 324 | ||
325 | eth.read_byte socket,bl |
325 | eth.read_byte socket,bl |
326 | 326 | ||
327 | ; Store the data in the response buffer |
327 | ; Store the data in the response buffer |
328 | mov eax, endptr |
328 | mov eax, endptr |
329 | mov [eax], bl |
329 | mov [eax], bl |
330 | inc dword endptr |
330 | inc dword endptr |
331 | 331 | ||
332 | eth.poll socket |
332 | eth.poll socket |
333 | 333 | ||
334 | cmp eax,0 |
334 | cmp eax,0 |
335 | jne .getdata ; yes, so get it |
335 | jne .getdata ; yes, so get it |
336 | 336 | ||
337 | ; now we are going to wait 30 times 10 ms (300ms) |
337 | ; now we are going to wait 30 times 10 ms (300ms) |
338 | 338 | ||
339 | mov edx,0 |
339 | mov edx,0 |
340 | .loop: |
340 | .loop: |
341 | mov eax,5 |
341 | mov eax,5 |
342 | mov ebx,1 |
342 | mov ebx,1 |
343 | int 0x40 |
343 | mcall |
344 | 344 | ||
345 | eth.poll socket |
345 | eth.poll socket |
346 | 346 | ||
347 | cmp eax, 0 |
347 | cmp eax, 0 |
348 | jne .getdata ; yes, so get it |
348 | jne .getdata ; yes, so get it |
349 | 349 | ||
350 | inc edx |
350 | inc edx |
351 | cmp edx,100 |
351 | cmp edx,100 |
352 | jl .loop |
352 | jl .loop |
353 | 353 | ||
354 | .end: |
354 | .end: |
355 | 355 | ||
356 | } |
356 | } |
357 | 357 | ||
358 | ; eth.wait_for_data [socket],60,abort |
358 | ; eth.wait_for_data [socket],60,abort |
359 | ; eth.read_data .... |
359 | ; eth.read_data .... |
360 | ; abort: |
360 | ; abort: |
361 | ; |
361 | ; |
362 | ; Waits for data with timeout |
362 | ; Waits for data with timeout |
363 | 363 | ||
364 | macro eth.wait_for_data socket,TIMEOUT,abort { |
364 | macro eth.wait_for_data socket,TIMEOUT,abort { |
365 | 365 | ||
366 | mov edx,TIMEOUT |
366 | mov edx,TIMEOUT |
367 | 367 | ||
368 | @@: |
368 | @@: |
369 | eth.poll socket |
369 | eth.poll socket |
370 | 370 | ||
371 | cmp eax,0 |
371 | cmp eax,0 |
372 | jne @f |
372 | jne @f |
373 | 373 | ||
374 | dec edx |
374 | dec edx |
375 | jz abort |
375 | jz abort |
376 | 376 | ||
377 | mov eax,5 ; wait here for event |
377 | mov eax,5 ; wait here for event |
378 | mov ebx,10 |
378 | mov ebx,10 |
379 | int 0x40 |
379 | mcall |
380 | 380 | ||
381 | jmp @r |
381 | jmp @r |
382 | @@: |
382 | @@: |
383 | 383 | ||
384 | } |
384 | } |
385 | 385 | ||
386 | 386 | ||
387 | ; The function 'resolve' resolves the address in edx and puts the resulting IP in eax. |
387 | ; The function 'resolve' resolves the address in edx and puts the resulting IP in eax. |
388 | ; When the input is an IP-adress, the function will output this IP in eax. |
388 | ; When the input is an IP-adress, the function will output this IP in eax. |
389 | ; If something goes wrong, the result in eax should be 0 |
389 | ; If something goes wrong, the result in eax should be 0 |
390 | ; |
390 | ; |
391 | ; example: |
391 | ; example: |
392 | ; |
392 | ; |
393 | ; resolve query1,IP,PORT |
393 | ; resolve query1,IP,PORT |
394 | ; resolve '192.168.0.1',IP,PORT |
394 | ; resolve '192.168.0.1',IP,PORT |
395 | ; resolve query2,IP,PORT |
395 | ; resolve query2,IP,PORT |
396 | ; |
396 | ; |
397 | ; query1 db 'www.google.com',0 |
397 | ; query1 db 'www.google.com',0 |
398 | ; query2 db '49.78.84.45',0 |
398 | ; query2 db '49.78.84.45',0 |
399 | ; IP dd ? |
399 | ; IP dd ? |
400 | ; PORT dd ? |
400 | ; PORT dd ? |
401 | 401 | ||
402 | macro resolve query,result { |
402 | macro resolve query,result { |
403 | 403 | ||
404 | if query eqtype 0 |
404 | if query eqtype 0 |
405 | mov edx,query |
405 | mov edx,query |
406 | else |
406 | else |
407 | local ..string, ..label |
407 | local ..string, ..label |
408 | jmp ..label |
408 | jmp ..label |
409 | ..string db query,0 |
409 | ..string db query,0 |
410 | ..label: |
410 | ..label: |
411 | mov edx,..string |
411 | mov edx,..string |
412 | end if |
412 | end if |
413 | 413 | ||
414 | call __resolve |
414 | call __resolve |
415 | 415 | ||
416 | mov result,eax |
416 | mov result,eax |
417 | 417 | ||
418 | } |
418 | } |
419 | 419 | ||
420 | if used __resolve |
420 | if used __resolve |
421 | 421 | ||
422 | __resolve: |
422 | __resolve: |
423 | 423 | ||
424 | if __DEBUG__ eq 1 |
424 | if __DEBUG__ eq 1 |
425 | DEBUGF 1,'Resolving started\n' |
425 | DEBUGF 1,'Resolving started\n' |
426 | end if |
426 | end if |
427 | 427 | ||
428 | ; This code validates if the query is an IP containing 4 numbers and 3 dots |
428 | ; This code validates if the query is an IP containing 4 numbers and 3 dots |
429 | 429 | ||
430 | 430 | ||
431 | push edx ; push edx (query address) onto stack |
431 | push edx ; push edx (query address) onto stack |
432 | xor al, al ; make al (dot count) zero |
432 | xor al, al ; make al (dot count) zero |
433 | 433 | ||
434 | @@: |
434 | @@: |
435 | cmp byte[edx],'0' ; check if this byte is a number, if not jump to no_IP |
435 | cmp byte[edx],'0' ; check if this byte is a number, if not jump to no_IP |
436 | jl no_IP ; |
436 | jl no_IP ; |
437 | cmp byte[edx],'9' ; |
437 | cmp byte[edx],'9' ; |
438 | jg no_IP ; |
438 | jg no_IP ; |
439 | 439 | ||
440 | inc edx ; the byte was a number, so lets check the next byte |
440 | inc edx ; the byte was a number, so lets check the next byte |
441 | 441 | ||
442 | cmp byte[edx],0 ; is this byte zero? (have we reached end of query?) |
442 | cmp byte[edx],0 ; is this byte zero? (have we reached end of query?) |
443 | jz @f ; jump to next @@ then |
443 | jz @f ; jump to next @@ then |
444 | cmp byte[edx],':' |
444 | cmp byte[edx],':' |
445 | jz @f |
445 | jz @f |
446 | 446 | ||
447 | cmp byte[edx],'.' ; is this byte a dot? |
447 | cmp byte[edx],'.' ; is this byte a dot? |
448 | jne @r ; if not, jump to previous @@ |
448 | jne @r ; if not, jump to previous @@ |
449 | 449 | ||
450 | inc al ; the byte was a dot so increment al(dot count) |
450 | inc al ; the byte was a dot so increment al(dot count) |
451 | inc edx ; next byte |
451 | inc edx ; next byte |
452 | jmp @r ; lets check for numbers again (jump to previous @@) |
452 | jmp @r ; lets check for numbers again (jump to previous @@) |
453 | 453 | ||
454 | @@: ; we reach this when end of query reached |
454 | @@: ; we reach this when end of query reached |
455 | cmp al,3 ; check if there where 3 dots |
455 | cmp al,3 ; check if there where 3 dots |
456 | jnz no_IP ; if not, jump to no_IP (this is where the DNS will take over) |
456 | jnz no_IP ; if not, jump to no_IP (this is where the DNS will take over) |
457 | 457 | ||
458 | ; The following code will convert this IP into a dword and output it in eax |
458 | ; The following code will convert this IP into a dword and output it in eax |
459 | ; If there is also a port number specified, this will be returned in ebx, otherwise ebx is -1 |
459 | ; If there is also a port number specified, this will be returned in ebx, otherwise ebx is -1 |
460 | 460 | ||
461 | pop esi ; edx (query address) was pushed onto stack and is now popped in esi |
461 | pop esi ; edx (query address) was pushed onto stack and is now popped in esi |
462 | 462 | ||
463 | xor edx, edx ; result |
463 | xor edx, edx ; result |
464 | xor eax, eax ; current character |
464 | xor eax, eax ; current character |
465 | xor ebx, ebx ; current byte |
465 | xor ebx, ebx ; current byte |
466 | 466 | ||
467 | .outer_loop: |
467 | .outer_loop: |
468 | shl edx, 8 |
468 | shl edx, 8 |
469 | add edx, ebx |
469 | add edx, ebx |
470 | xor ebx, ebx |
470 | xor ebx, ebx |
471 | .inner_loop: |
471 | .inner_loop: |
472 | lodsb |
472 | lodsb |
473 | test eax, eax |
473 | test eax, eax |
474 | jz .finish |
474 | jz .finish |
475 | cmp al, '.' |
475 | cmp al, '.' |
476 | jz .outer_loop |
476 | jz .outer_loop |
477 | sub eax, '0' |
477 | sub eax, '0' |
478 | imul ebx, 10 |
478 | imul ebx, 10 |
479 | add ebx, eax |
479 | add ebx, eax |
480 | jmp .inner_loop |
480 | jmp .inner_loop |
481 | .finish: |
481 | .finish: |
482 | shl edx, 8 |
482 | shl edx, 8 |
483 | add edx, ebx |
483 | add edx, ebx |
484 | 484 | ||
485 | bswap edx ; we want little endian order |
485 | bswap edx ; we want little endian order |
486 | mov eax, edx |
486 | mov eax, edx |
487 | 487 | ||
488 | ret |
488 | ret |
489 | 489 | ||
490 | 490 | ||
491 | no_IP: |
491 | no_IP: |
492 | 492 | ||
493 | pop edx |
493 | pop edx |
494 | 494 | ||
495 | ; The query is not an IP address, we will send the query to a DNS server and hope for answer ;) |
495 | ; The query is not an IP address, we will send the query to a DNS server and hope for answer ;) |
496 | if __DEBUG__ eq 1 |
496 | if __DEBUG__ eq 1 |
497 | DEBUGF 1,'The query is no ip, Building request string from:%u\n',edx |
497 | DEBUGF 1,'The query is no ip, Building request string from:%u\n',edx |
498 | end if |
498 | end if |
499 | 499 | ||
500 | ; Build the request string |
500 | ; Build the request string |
501 | mov eax, 0x00010100 |
501 | mov eax, 0x00010100 |
502 | mov [dnsMsg], eax |
502 | mov [dnsMsg], eax |
503 | mov eax, 0x00000100 |
503 | mov eax, 0x00000100 |
504 | mov [dnsMsg+4], eax |
504 | mov [dnsMsg+4], eax |
505 | mov eax, 0x00000000 |
505 | mov eax, 0x00000000 |
506 | mov [dnsMsg+8], eax |
506 | mov [dnsMsg+8], eax |
507 | 507 | ||
508 | ; domain name goes in at dnsMsg+12 |
508 | ; domain name goes in at dnsMsg+12 |
509 | mov esi, dnsMsg + 12 ; location of label length |
509 | mov esi, dnsMsg + 12 ; location of label length |
510 | mov edi, dnsMsg + 13 ; label start |
510 | mov edi, dnsMsg + 13 ; label start |
511 | mov ecx, 12 ; total string length so far |
511 | mov ecx, 12 ; total string length so far |
512 | 512 | ||
513 | td002: |
513 | td002: |
514 | mov [esi], byte 0 |
514 | mov [esi], byte 0 |
515 | inc ecx |
515 | inc ecx |
516 | 516 | ||
517 | td0021: |
517 | td0021: |
518 | mov al, [edx] |
518 | mov al, [edx] |
519 | 519 | ||
520 | cmp al, 0 |
520 | cmp al, 0 |
521 | je td001 ; we have finished the string translation |
521 | je td001 ; we have finished the string translation |
522 | 522 | ||
523 | cmp al, '.' |
523 | cmp al, '.' |
524 | je td004 ; we have finished the label |
524 | je td004 ; we have finished the label |
525 | 525 | ||
526 | inc byte [esi] |
526 | inc byte [esi] |
527 | inc ecx |
527 | inc ecx |
528 | mov [edi], al |
528 | mov [edi], al |
529 | inc edi |
529 | inc edi |
530 | inc edx |
530 | inc edx |
531 | jmp td0021 |
531 | jmp td0021 |
532 | 532 | ||
533 | td004: |
533 | td004: |
534 | mov esi, edi |
534 | mov esi, edi |
535 | inc edi |
535 | inc edi |
536 | inc edx |
536 | inc edx |
537 | jmp td002 |
537 | jmp td002 |
538 | 538 | ||
539 | ; write label len + label text |
539 | ; write label len + label text |
540 | td001: |
540 | td001: |
541 | mov [edi], byte 0 |
541 | mov [edi], byte 0 |
542 | inc ecx |
542 | inc ecx |
543 | inc edi |
543 | inc edi |
544 | mov [edi], dword 0x01000100 |
544 | mov [edi], dword 0x01000100 |
545 | add ecx, 4 |
545 | add ecx, 4 |
546 | 546 | ||
547 | mov [dnsMsgLen], ecx ; We'll need the length of the message when we send it |
547 | mov [dnsMsgLen], ecx ; We'll need the length of the message when we send it |
548 | ; Now, lets send this and wait for an answer |
548 | ; Now, lets send this and wait for an answer |
549 | 549 | ||
550 | eth.search_port 1024,edx ; Find a free port starting from 1025 and store in edx |
550 | eth.search_port 1024,edx ; Find a free port starting from 1025 and store in edx |
551 | eth.get_DNS esi ; Read DNS IP from stack into esi |
551 | eth.get_DNS esi ; Read DNS IP from stack into esi |
552 | eth.open_udp edx,53,esi,[socketNum] ; First, open socket |
552 | eth.open_udp edx,53,esi,[socketNum] ; First, open socket |
553 | if __DEBUG__ eq 1 |
553 | if __DEBUG__ eq 1 |
554 | DEBUGF 1,'Socket opened: %u (port %u)\n',[socketNum],ecx |
554 | DEBUGF 1,'Socket opened: %u (port %u)\n',[socketNum],ecx |
555 | end if |
555 | end if |
556 | eth.write_udp [socketNum],[dnsMsgLen],dnsMsg ; Write to socket ( request DNS lookup ) |
556 | eth.write_udp [socketNum],[dnsMsgLen],dnsMsg ; Write to socket ( request DNS lookup ) |
557 | if __DEBUG__ eq 1 |
557 | if __DEBUG__ eq 1 |
558 | DEBUGF 1,'Data written, length:%u offset:%u\n',[dnsMsgLen],dnsMsg |
558 | DEBUGF 1,'Data written, length:%u offset:%u\n',[dnsMsgLen],dnsMsg |
559 | DEBUGF 1,'Waiting for data: (timeout is %us)\n',TIMEOUT |
559 | DEBUGF 1,'Waiting for data: (timeout is %us)\n',TIMEOUT |
560 | end if |
560 | end if |
561 | eth.wait_for_data [socketNum],TIMEOUT,abort ; Now, we wait for data from remote |
561 | eth.wait_for_data [socketNum],TIMEOUT,abort ; Now, we wait for data from remote |
562 | eth.read_data [socketNum],dnsMsg,[dnsMsgLen],dnsMsg+BUFFER ; Read the data into the buffer |
562 | eth.read_data [socketNum],dnsMsg,[dnsMsgLen],dnsMsg+BUFFER ; Read the data into the buffer |
563 | if __DEBUG__ eq 1 |
563 | if __DEBUG__ eq 1 |
564 | DEBUGF 1,'Data received, offset:%u buffer size:%u length:%u\n',dnsMsg,BUFFER,esi-dnsMsg |
564 | DEBUGF 1,'Data received, offset:%u buffer size:%u length:%u\n',dnsMsg,BUFFER,esi-dnsMsg |
565 | end if |
565 | end if |
566 | eth.close_udp [socketNum] ; We're done, close the socket |
566 | eth.close_udp [socketNum] ; We're done, close the socket |
567 | if __DEBUG__ eq 1 |
567 | if __DEBUG__ eq 1 |
568 | DEBUGF 1,'Closed Socket\n' |
568 | DEBUGF 1,'Closed Socket\n' |
569 | end if |
569 | end if |
570 | 570 | ||
571 | ; Now parse the message to get the host IP. Man, this is complicated. It's described in RFC 1035 |
571 | ; Now parse the message to get the host IP. Man, this is complicated. It's described in RFC 1035 |
572 | ; 1) Validate that we have an answer with > 0 responses |
572 | ; 1) Validate that we have an answer with > 0 responses |
573 | ; 2) Find the answer record with TYPE 0001 ( host IP ) |
573 | ; 2) Find the answer record with TYPE 0001 ( host IP ) |
574 | ; 3) Finally, copy the IP address to the display |
574 | ; 3) Finally, copy the IP address to the display |
575 | ; Note: The response is in dnsMsg, the end of the buffer is pointed to by [dnsMsgLen] |
575 | ; Note: The response is in dnsMsg, the end of the buffer is pointed to by [dnsMsgLen] |
576 | 576 | ||
577 | mov esi, dnsMsg |
577 | mov esi, dnsMsg |
578 | 578 | ||
579 | mov al, [esi+2] ; Is this a response to my question? |
579 | mov al, [esi+2] ; Is this a response to my question? |
580 | and al, 0x80 |
580 | and al, 0x80 |
581 | cmp al, 0x80 |
581 | cmp al, 0x80 |
582 | jne abort |
582 | jne abort |
583 | if __DEBUG__ eq 1 |
583 | if __DEBUG__ eq 1 |
584 | DEBUGF 1,'It was a response to my question\n' |
584 | DEBUGF 1,'It was a response to my question\n' |
585 | end if |
585 | end if |
586 | 586 | ||
587 | mov al, [esi+3] ; Were there any errors? |
587 | mov al, [esi+3] ; Were there any errors? |
588 | and al, 0x0F |
588 | and al, 0x0F |
589 | cmp al, 0x00 |
589 | cmp al, 0x00 |
590 | jne abort |
590 | jne abort |
591 | 591 | ||
592 | if __DEBUG__ eq 1 |
592 | if __DEBUG__ eq 1 |
593 | DEBUGF 1,'There were no errors\n' |
593 | DEBUGF 1,'There were no errors\n' |
594 | end if |
594 | end if |
595 | 595 | ||
596 | mov ax, [esi+6] ; Is there ( at least 1 ) answer? |
596 | mov ax, [esi+6] ; Is there ( at least 1 ) answer? |
597 | cmp ax, 0x00 |
597 | cmp ax, 0x00 |
598 | je abort |
598 | je abort |
599 | 599 | ||
600 | ; Header validated. Scan through and get my answer |
600 | ; Header validated. Scan through and get my answer |
601 | add esi, 12 ; Skip to the question field |
601 | add esi, 12 ; Skip to the question field |
602 | call skipName ; Skip through the question field |
602 | call skipName ; Skip through the question field |
603 | add esi, 4 ; skip past the questions qtype, qclass |
603 | add esi, 4 ; skip past the questions qtype, qclass |
604 | 604 | ||
605 | ctr002z: |
605 | ctr002z: |
606 | ; Now at the answer. There may be several answers, find the right one ( TYPE = 0x0001 ) |
606 | ; Now at the answer. There may be several answers, find the right one ( TYPE = 0x0001 ) |
607 | call skipName |
607 | call skipName |
608 | mov ax, [esi] |
608 | mov ax, [esi] |
609 | cmp ax, 0x0100 ; Is this the IP address answer? |
609 | cmp ax, 0x0100 ; Is this the IP address answer? |
610 | jne ctr002c |
610 | jne ctr002c |
611 | add esi, 10 ; Yes! Point eax to the first byte of the IP address |
611 | add esi, 10 ; Yes! Point eax to the first byte of the IP address |
612 | mov eax,[esi] |
612 | mov eax,[esi] |
613 | 613 | ||
614 | ret |
614 | ret |
615 | 615 | ||
616 | 616 | ||
617 | ctr002c: ; Skip through the answer, move to the next |
617 | ctr002c: ; Skip through the answer, move to the next |
618 | add esi, 8 |
618 | add esi, 8 |
619 | movzx eax, byte [esi+1] |
619 | movzx eax, byte [esi+1] |
620 | mov ah, [esi] |
620 | mov ah, [esi] |
621 | add esi, eax |
621 | add esi, eax |
622 | add esi, 2 |
622 | add esi, 2 |
623 | 623 | ||
624 | cmp esi, [dnsMsgLen] ; Have we reached the end of the msg? This is an error condition, should not happen |
624 | cmp esi, [dnsMsgLen] ; Have we reached the end of the msg? This is an error condition, should not happen |
625 | jl ctr002z ; Check next answer |
625 | jl ctr002z ; Check next answer |
626 | 626 | ||
627 | abort: |
627 | abort: |
628 | if __DEBUG__ eq 1 |
628 | if __DEBUG__ eq 1 |
629 | DEBUGF 1,'Something went wrong, aborting\n' |
629 | DEBUGF 1,'Something went wrong, aborting\n' |
630 | end if |
630 | end if |
631 | xor eax,eax |
631 | xor eax,eax |
632 | 632 | ||
633 | ret |
633 | ret |
634 | 634 | ||
635 | 635 | ||
636 | skipName: |
636 | skipName: |
637 | ; Increment esi to the first byte past the name field |
637 | ; Increment esi to the first byte past the name field |
638 | ; Names may use compressed labels. Normally do. |
638 | ; Names may use compressed labels. Normally do. |
639 | ; RFC 1035 page 30 gives details |
639 | ; RFC 1035 page 30 gives details |
640 | mov al, [esi] |
640 | mov al, [esi] |
641 | cmp al, 0 |
641 | cmp al, 0 |
642 | je sn_exit |
642 | je sn_exit |
643 | and al, 0xc0 |
643 | and al, 0xc0 |
644 | cmp al, 0xc0 |
644 | cmp al, 0xc0 |
645 | je sn001 |
645 | je sn001 |
646 | 646 | ||
647 | movzx eax, byte [esi] |
647 | movzx eax, byte [esi] |
648 | inc eax |
648 | inc eax |
649 | add esi, eax |
649 | add esi, eax |
650 | jmp skipName |
650 | jmp skipName |
651 | 651 | ||
652 | sn001: |
652 | sn001: |
653 | add esi, 2 ; A pointer is always at the end |
653 | add esi, 2 ; A pointer is always at the end |
654 | ret |
654 | ret |
655 | 655 | ||
656 | sn_exit: |
656 | sn_exit: |
657 | inc esi |
657 | inc esi |
658 | ret |
658 | ret |
659 | 659 | ||
660 | dnsMsgLen: dd 0 |
660 | dnsMsgLen: dd 0 |
661 | socketNum: dd 0xFFFF |
661 | socketNum: dd 0xFFFF |
662 | 662 | ||
663 | if ~defined dnsMsg |
663 | if ~defined dnsMsg |
664 | dnsMsg: rb BUFFER |
664 | dnsMsg: rb BUFFER |
665 | end if |
665 | end if |
666 | 666 | ||
667 | end if |
667 | end if |