671 lines
14 KiB
PHP
671 lines
14 KiB
PHP
|
;
|
||
|
; ETH.INC
|
||
|
;
|
||
|
; made by hidnplayr (hidnplayr@gmail.com) for KolibriOS and DEX4U
|
||
|
;
|
||
|
; The given code before every macro is only a simple example
|
||
|
;
|
||
|
; Change the OS value to DEX4U or MEOS
|
||
|
;
|
||
|
; HISTORY
|
||
|
;
|
||
|
; v1.0: 18 august 2006
|
||
|
;
|
||
|
|
||
|
MEOS equ 1 ; Dont change these !
|
||
|
DEX4U equ 2 ;
|
||
|
|
||
|
OS equ MEOS ; Change these instead ;)
|
||
|
TIMEOUT equ 60 ; timeout for DNS request
|
||
|
BUFFER equ 512 ; Buffer size for DNS
|
||
|
|
||
|
macro int1 {
|
||
|
if OS eq MEOS
|
||
|
mcall
|
||
|
else if OS eq DEX4U
|
||
|
int 0x52
|
||
|
end if
|
||
|
}
|
||
|
|
||
|
macro int2 {
|
||
|
if OS eq MEOS
|
||
|
mcall
|
||
|
else if OS eq DEX4U
|
||
|
int 0x53
|
||
|
end if
|
||
|
}
|
||
|
|
||
|
macro mov arg1,arg2 {
|
||
|
|
||
|
if arg1 eq arg2
|
||
|
else
|
||
|
mov arg1,arg2
|
||
|
end if
|
||
|
|
||
|
}
|
||
|
|
||
|
; eth.get_IP eax
|
||
|
;
|
||
|
; gets the current IP that is defined in Stack (return in eax in this example)
|
||
|
macro eth.get_IP IP {
|
||
|
if OS eq MEOS
|
||
|
mov eax,52
|
||
|
end if
|
||
|
mov ebx,1
|
||
|
int1
|
||
|
|
||
|
mov IP ,eax
|
||
|
}
|
||
|
|
||
|
; eth.get_GATEWAY eax
|
||
|
;
|
||
|
; gets the current GATEWAY that is defined in Stack (return in eax in this example)
|
||
|
macro eth.get_GATEWAY GATEWAY {
|
||
|
if OS eq MEOS
|
||
|
mov eax,52
|
||
|
end if
|
||
|
mov ebx,9
|
||
|
int1
|
||
|
move GATEWAY ,eax
|
||
|
}
|
||
|
|
||
|
; eth.get_SUBNET eax
|
||
|
;
|
||
|
; gets the current SUBNET that is defined in Stack (return in eax in this example)
|
||
|
macro eth.get_SUBNET SUBNET {
|
||
|
if OS eq MEOS
|
||
|
mov eax,52
|
||
|
end if
|
||
|
mov ebx,10
|
||
|
int1
|
||
|
mov SUBNET ,eax
|
||
|
}
|
||
|
|
||
|
; eth.get_DNS eax
|
||
|
;
|
||
|
; gets the current DNS that is defined in Stack (return in eax in this example)
|
||
|
macro eth.get_DNS DNS {
|
||
|
if OS eq MEOS
|
||
|
mov eax,52
|
||
|
end if
|
||
|
mov ebx,13
|
||
|
int1
|
||
|
mov DNS ,eax
|
||
|
}
|
||
|
|
||
|
; eth.set_IP eax
|
||
|
;
|
||
|
; set a new IP in stack (input in eax in this example)
|
||
|
macro eth.set_IP IP {
|
||
|
mov ecx,IP
|
||
|
if OS eq MEOS
|
||
|
mov eax,52
|
||
|
end if
|
||
|
mov ebx,3
|
||
|
int1
|
||
|
}
|
||
|
|
||
|
; eth.set_GATEWAY eax
|
||
|
;
|
||
|
; set a new GATEWAY in stack (input in eax in this example)
|
||
|
macro eth.set_GATEWAY GATEWAY {
|
||
|
mov ecx,GATEWAY
|
||
|
if OS eq MEOS
|
||
|
mov eax,52
|
||
|
end if
|
||
|
mov ebx,11
|
||
|
int1
|
||
|
}
|
||
|
|
||
|
; eth.set_SUBNET eax
|
||
|
;
|
||
|
; set a new SUBNET in stack (input in eax in this example)
|
||
|
macro eth.set_SUBNET SUBNET {
|
||
|
mov ecx,SUBNET
|
||
|
if OS eq MEOS
|
||
|
mov eax,52
|
||
|
end if
|
||
|
mov ebx,12
|
||
|
int1
|
||
|
}
|
||
|
|
||
|
; eth.set_DNS eax
|
||
|
;
|
||
|
; set a new DNS in stack (input in eax in this example)
|
||
|
macro eth.set_DNS DNS {
|
||
|
mov ecx,DNS
|
||
|
if OS eq MEOS
|
||
|
mov eax,52
|
||
|
end if
|
||
|
mov ebx,14
|
||
|
int1
|
||
|
}
|
||
|
|
||
|
; eth.open eax,80,ebx,[socket]
|
||
|
;
|
||
|
; open a socket on local port in eax to port 80 on server on ebx
|
||
|
; the socketnumber will be returned in [socket] (dword)
|
||
|
macro eth.open local,remote,ip,socket {
|
||
|
mov ecx, local
|
||
|
mov edx, remote
|
||
|
mov esi, ip
|
||
|
if OS eq MEOS
|
||
|
mov eax,53
|
||
|
end if
|
||
|
mov ebx, 0
|
||
|
int2
|
||
|
|
||
|
mov socket,eax
|
||
|
}
|
||
|
|
||
|
; eth.close [socket]
|
||
|
;
|
||
|
; closes socket on socketnumber [socket]
|
||
|
macro eth.close socket {
|
||
|
mov ecx, socket
|
||
|
if OS eq MEOS
|
||
|
mov eax,53
|
||
|
end if
|
||
|
mov ebx, 1
|
||
|
int2
|
||
|
}
|
||
|
|
||
|
; eth.poll [socket],eax
|
||
|
;
|
||
|
; polls [socket] for data
|
||
|
; eax = 0 when there is data
|
||
|
macro eth.poll socket,result {
|
||
|
mov ecx, socket
|
||
|
if OS eq MEOS
|
||
|
mov eax,53
|
||
|
end if
|
||
|
mov ebx, 2
|
||
|
int2
|
||
|
|
||
|
mov result, eax
|
||
|
}
|
||
|
|
||
|
; eth.read_byte [socket], bl
|
||
|
;
|
||
|
; reads a byte from the socket and returns in bl
|
||
|
macro eth.read_byte socket, result {
|
||
|
mov ecx, socket
|
||
|
if OS eq MEOS
|
||
|
mov eax,53
|
||
|
end if
|
||
|
mov ebx, 3
|
||
|
int2
|
||
|
|
||
|
mov result,bl
|
||
|
}
|
||
|
|
||
|
; eth.write [socket],12,msg
|
||
|
; msg db 'hello world!'
|
||
|
;
|
||
|
; send message msg to socket
|
||
|
macro eth.write socket,length,msg {
|
||
|
mov ecx, socket
|
||
|
mov edx, length
|
||
|
mov esi, msg
|
||
|
if OS eq MEOS
|
||
|
mov eax,53
|
||
|
end if
|
||
|
mov ebx, 4
|
||
|
int2
|
||
|
}
|
||
|
|
||
|
; eth.open_tcp 80,80,eax,0,[socket]
|
||
|
;
|
||
|
; opens a tcp socket on port 80 to port 80 on IP eax with passive open
|
||
|
; returns socket number in eax
|
||
|
macro eth.open_tcp local,remote,ip,passive,socket {
|
||
|
|
||
|
pusha
|
||
|
mov ecx, local
|
||
|
mov edx, remote
|
||
|
mov esi, ip
|
||
|
mov edi, passive ; 0 = PASSIVE open
|
||
|
if OS eq MEOS
|
||
|
mov eax,53
|
||
|
end if
|
||
|
mov ebx, 5
|
||
|
int2
|
||
|
popa
|
||
|
|
||
|
mov socket,eax
|
||
|
}
|
||
|
|
||
|
; eth.socket_status [socket],eax
|
||
|
;
|
||
|
; returns socket status in eax
|
||
|
macro eth.socket_status socket,result {
|
||
|
mov ecx, socket
|
||
|
if OS eq MEOS
|
||
|
mov eax,53
|
||
|
end if
|
||
|
mov ebx, 6
|
||
|
int2
|
||
|
|
||
|
mov result,eax
|
||
|
}
|
||
|
|
||
|
; eth.write_tcp [socket],12,msg
|
||
|
;
|
||
|
; msg db 'hello world!'
|
||
|
;
|
||
|
; send message to TCP socket
|
||
|
macro eth.write_tcp socket,length,msg {
|
||
|
mov ecx, socket
|
||
|
mov edx, length
|
||
|
mov esi, msg
|
||
|
if OS eq MEOS
|
||
|
mov eax,53
|
||
|
end if
|
||
|
mov ebx, 7
|
||
|
int2
|
||
|
}
|
||
|
|
||
|
; eth.close_tcp [socket]
|
||
|
;
|
||
|
; closes tcp socket [socket]
|
||
|
macro eth.close_tcp socket {
|
||
|
mov ecx, socket
|
||
|
if OS eq MEOS
|
||
|
mov eax,53
|
||
|
end if
|
||
|
mov ebx, 8
|
||
|
int2
|
||
|
}
|
||
|
|
||
|
; eth.check_port 165,eax
|
||
|
;
|
||
|
; checks if port 165 is used
|
||
|
; return is 0 when port is free
|
||
|
macro eth.check_port port,result {
|
||
|
if OS eq MEOS
|
||
|
mov eax,53
|
||
|
end if
|
||
|
mov ebx, 9
|
||
|
mov ecx, port
|
||
|
int2
|
||
|
|
||
|
mov result,eax
|
||
|
}
|
||
|
|
||
|
; eth.status eax
|
||
|
;
|
||
|
; returns socket status in eax
|
||
|
macro eth.status status {
|
||
|
if OS eq MEOS
|
||
|
mov eax,53
|
||
|
end if
|
||
|
mov ebx, 255
|
||
|
mov ecx, 6
|
||
|
int2
|
||
|
|
||
|
mov status,eax
|
||
|
}
|
||
|
|
||
|
; eth.search 165,edx
|
||
|
;
|
||
|
; searches a free local port starting from 166 (165 + 1 !)
|
||
|
; returns in edx
|
||
|
macro eth.search_port port,result {
|
||
|
mov edx,port
|
||
|
@@:
|
||
|
inc edx
|
||
|
eth.check_port edx,eax
|
||
|
cmp eax,0
|
||
|
je @r
|
||
|
mov result,edx
|
||
|
}
|
||
|
|
||
|
; eth.read_data [socket],buffer,512
|
||
|
; buffer rb 512
|
||
|
; socket dd ?
|
||
|
;
|
||
|
; reads data from socket into a buffer, stops when there is no more data or buffer is full.
|
||
|
macro eth.read_data socket,dest,endptr,bufferl {
|
||
|
|
||
|
mov eax, dest
|
||
|
mov endptr, eax
|
||
|
|
||
|
; we have data - this will be the response
|
||
|
@@:
|
||
|
mov eax,endptr
|
||
|
cmp eax,bufferl
|
||
|
jg @f
|
||
|
|
||
|
mov eax, 53
|
||
|
mov ebx, 3
|
||
|
mov ecx, socket
|
||
|
mcall ; read byte - block (high byte)
|
||
|
|
||
|
; Store the data in the response buffer
|
||
|
mov eax, endptr
|
||
|
mov [eax], bl
|
||
|
inc dword endptr
|
||
|
|
||
|
mov eax, 53
|
||
|
mov ebx, 2
|
||
|
mov ecx, socket
|
||
|
mcall ; any more data?
|
||
|
|
||
|
cmp eax, 0
|
||
|
jne @r ; yes, so get it
|
||
|
@@:
|
||
|
|
||
|
}
|
||
|
|
||
|
; eth.wait_for_data [socket],60,abort
|
||
|
; eth.read_data ....
|
||
|
; abort:
|
||
|
;
|
||
|
; Waits for data with timeout
|
||
|
|
||
|
macro eth.wait_for_data socket,TIMEOUT,abort {
|
||
|
|
||
|
mov edx,TIMEOUT
|
||
|
|
||
|
@@:
|
||
|
eth.poll socket,eax
|
||
|
|
||
|
cmp eax,0
|
||
|
jne @f
|
||
|
|
||
|
dec edx
|
||
|
jz abort
|
||
|
|
||
|
if OS eq MEOS
|
||
|
mov eax,5 ; wait here for event
|
||
|
mov ebx,100
|
||
|
mcall
|
||
|
else if OS eq DEX4U
|
||
|
mov ax,18
|
||
|
call [SetDelay]
|
||
|
call dword[stack_handler]
|
||
|
end if
|
||
|
|
||
|
jmp @r
|
||
|
@@:
|
||
|
|
||
|
}
|
||
|
|
||
|
|
||
|
; The function 'resolve' resolves the address in edx and puts the resulting IP in eax.
|
||
|
; When the input is an IP-adress, the function will output this IP in eax.
|
||
|
; If something goes wrong, the result in eax should be 0
|
||
|
;
|
||
|
; example:
|
||
|
;
|
||
|
; resolve query1,IP
|
||
|
; resolve '192.168.0.1',IP
|
||
|
; resolve query2,IP
|
||
|
;
|
||
|
; query1 db 'www.google.com',0
|
||
|
; query2 db '49.78.84.45',0
|
||
|
; IP dd ?
|
||
|
|
||
|
macro resolve query,result {
|
||
|
|
||
|
if query eqtype 0
|
||
|
mov edx,query
|
||
|
else
|
||
|
local ..string, ..label
|
||
|
jmp ..label
|
||
|
..string db query,0
|
||
|
..label:
|
||
|
mov edx,..string
|
||
|
end if
|
||
|
|
||
|
call __resolve
|
||
|
|
||
|
mov result,eax
|
||
|
|
||
|
}
|
||
|
|
||
|
if used __resolve
|
||
|
|
||
|
__resolve:
|
||
|
|
||
|
;DEBUGF 1,'Resolving started\n'
|
||
|
|
||
|
|
||
|
; This code validates if the query is an IP containing 4 numbers and 3 dots
|
||
|
|
||
|
|
||
|
push edx ; push edx (query address) onto stack
|
||
|
xor al, al ; make al (dot count) zero
|
||
|
|
||
|
@@:
|
||
|
cmp byte[edx],'0' ; check if this byte is a number, if not jump to no_IP
|
||
|
jl no_IP ;
|
||
|
cmp byte[edx],'9' ;
|
||
|
jg no_IP ;
|
||
|
|
||
|
inc edx ; the byte was a number, so lets check the next byte
|
||
|
|
||
|
cmp byte[edx],0 ; is this byte zero? (have we reached end of query?)
|
||
|
jz @f ; jump to next @@ then
|
||
|
|
||
|
cmp byte[edx],'.' ; is this byte a dot?
|
||
|
jne @r ; if not, jump to previous @@
|
||
|
|
||
|
inc al ; the byte was a dot so increment al(dot count)
|
||
|
inc edx ; next byte
|
||
|
jmp @r ; lets check for numbers again (jump to previous @@)
|
||
|
|
||
|
@@: ; we reach this when end of query reached
|
||
|
cmp al,3 ; check if there where 3 dots
|
||
|
jnz no_IP ; if not, jump to no_IP (this is where the DNS will take over)
|
||
|
|
||
|
; The following code should convert this IP into a dword and output it in eax
|
||
|
|
||
|
pop esi ; edx (query address) was pushed onto stack and is now popped in esi
|
||
|
|
||
|
xor edx, edx ; result
|
||
|
xor eax, eax ; current character
|
||
|
xor ebx, ebx ; current byte
|
||
|
|
||
|
.outer_loop:
|
||
|
shl edx, 8
|
||
|
add edx, ebx
|
||
|
xor ebx, ebx
|
||
|
.inner_loop:
|
||
|
lodsb
|
||
|
test eax, eax
|
||
|
jz .finish
|
||
|
cmp al, '.'
|
||
|
jz .outer_loop
|
||
|
sub eax, '0'
|
||
|
imul ebx, 10
|
||
|
add ebx, eax
|
||
|
jmp .inner_loop
|
||
|
.finish:
|
||
|
shl edx, 8
|
||
|
add edx, ebx
|
||
|
|
||
|
bswap edx
|
||
|
mov eax, edx
|
||
|
|
||
|
;DEBUGF 1,'The query was an IP: %x.%x.%x.%x\n',dh,dl,al,ah
|
||
|
|
||
|
ret
|
||
|
|
||
|
|
||
|
no_IP:
|
||
|
|
||
|
pop edx
|
||
|
|
||
|
; The query is not an IP address, we will send the query to a DNS server and hope for answer ;)
|
||
|
|
||
|
;DEBUGF 1,'The query is no ip, Building request string from:%u\n',edx
|
||
|
|
||
|
; Build the request string
|
||
|
mov eax, 0x00010100
|
||
|
mov [dnsMsg], eax
|
||
|
mov eax, 0x00000100
|
||
|
mov [dnsMsg+4], eax
|
||
|
mov eax, 0x00000000
|
||
|
mov [dnsMsg+8], eax
|
||
|
|
||
|
; domain name goes in at dnsMsg+12
|
||
|
mov esi, dnsMsg + 12 ; location of label length
|
||
|
mov edi, dnsMsg + 13 ; label start
|
||
|
mov ecx, 12 ; total string length so far
|
||
|
|
||
|
td002:
|
||
|
mov [esi], byte 0
|
||
|
inc ecx
|
||
|
|
||
|
td0021:
|
||
|
mov al, [edx]
|
||
|
|
||
|
cmp al, 0
|
||
|
je td001 ; we have finished the string translation
|
||
|
|
||
|
cmp al, '.'
|
||
|
je td004 ; we have finished the label
|
||
|
|
||
|
inc byte [esi]
|
||
|
inc ecx
|
||
|
mov [edi], al
|
||
|
inc edi
|
||
|
inc edx
|
||
|
jmp td0021
|
||
|
|
||
|
td004:
|
||
|
mov esi, edi
|
||
|
inc edi
|
||
|
inc edx
|
||
|
jmp td002
|
||
|
|
||
|
; write label len + label text
|
||
|
td001:
|
||
|
mov [edi], byte 0
|
||
|
inc ecx
|
||
|
inc edi
|
||
|
mov [edi], dword 0x01000100
|
||
|
add ecx, 4
|
||
|
|
||
|
mov [dnsMsgLen], ecx ; We'll need the length of the message when we send it
|
||
|
; Now, lets send this and wait for an answer
|
||
|
|
||
|
eth.search_port 1024,edx ; Find a free port starting from 1025 and store in edx
|
||
|
eth.get_DNS esi ; Read DNS IP from stack into esi
|
||
|
eth.open edx,53,esi,[socketNum] ; First, open socket
|
||
|
; DEBUGF 1,'Socket opened: %u (port %u)\n',[socketNum],ecx
|
||
|
eth.write [socketNum],[dnsMsgLen],dnsMsg ; Write to socket ( request DNS lookup )
|
||
|
; DEBUGF 1,'Data written, length:%u offset:%u\n',[dnsMsgLen],dnsMsg
|
||
|
; DEBUGF 1,'Waiting for data: (timeout is %us)\n',TIMEOUT
|
||
|
eth.wait_for_data [socketNum],TIMEOUT,no_data; Now, we wait for data from remote
|
||
|
eth.read_data [socketNum],dnsMsg,[dnsMsgLen],dnsMsg+BUFFER ; Read the data into the buffer
|
||
|
; DEBUGF 1,'Data received, offset:%u buffer size:%u length:%u\n',dnsMsg,BUFFER,esi-dnsMsg
|
||
|
eth.close [socketNum] ; We're done, close the socket
|
||
|
; DEBUGF 1,'Closed Socket\n'
|
||
|
|
||
|
; Now parse the message to get the host IP. Man, this is complicated. It's described in RFC 1035
|
||
|
; 1) Validate that we have an answer with > 0 responses
|
||
|
; 2) Find the answer record with TYPE 0001 ( host IP )
|
||
|
; 3) Finally, copy the IP address to the display
|
||
|
; Note: The response is in dnsMsg, the end of the buffer is pointed to by [dnsMsgLen]
|
||
|
|
||
|
mov esi, dnsMsg
|
||
|
|
||
|
mov al, [esi+2] ; Is this a response to my question?
|
||
|
and al, 0x80
|
||
|
cmp al, 0x80
|
||
|
jne abort
|
||
|
|
||
|
;DEBUGF 1,'It was a response to my question\n'
|
||
|
|
||
|
mov al, [esi+3] ; Were there any errors?
|
||
|
and al, 0x0F
|
||
|
cmp al, 0x00
|
||
|
jne abort
|
||
|
|
||
|
;DEBUGF 1,'There were no errorst\n'
|
||
|
|
||
|
mov ax, [esi+6] ; Is there ( at least 1 ) answer?
|
||
|
cmp ax, 0x00
|
||
|
je abort
|
||
|
|
||
|
; Header validated. Scan through and get my answer
|
||
|
add esi, 12 ; Skip to the question field
|
||
|
call skipName ; Skip through the question field
|
||
|
add esi, 4 ; skip past the questions qtype, qclass
|
||
|
|
||
|
ctr002z:
|
||
|
; Now at the answer. There may be several answers, find the right one ( TYPE = 0x0001 )
|
||
|
call skipName
|
||
|
mov ax, [esi]
|
||
|
cmp ax, 0x0100 ; Is this the IP address answer?
|
||
|
jne ctr002c
|
||
|
add esi, 10 ; Yes! Point eax to the first byte of the IP address
|
||
|
mov eax,[esi]
|
||
|
|
||
|
;DEBUGF 1,'Found First Byte of IP\n'
|
||
|
|
||
|
ret
|
||
|
|
||
|
|
||
|
ctr002c: ; Skip through the answer, move to the next
|
||
|
add esi, 8
|
||
|
movzx eax, byte [esi+1]
|
||
|
mov ah, [esi]
|
||
|
add esi, eax
|
||
|
add esi, 2
|
||
|
|
||
|
cmp esi, [dnsMsgLen] ; Have we reached the end of the msg? This is an error condition, should not happen
|
||
|
jl ctr002z ; Check next answer
|
||
|
|
||
|
abort:
|
||
|
;DEBUGF 1,'Something went wrong, aborting\n'
|
||
|
xor eax,eax
|
||
|
|
||
|
ret
|
||
|
|
||
|
|
||
|
skipName:
|
||
|
; Increment esi to the first byte past the name field
|
||
|
; Names may use compressed labels. Normally do.
|
||
|
; RFC 1035 page 30 gives details
|
||
|
mov al, [esi]
|
||
|
cmp al, 0
|
||
|
je sn_exit
|
||
|
and al, 0xc0
|
||
|
cmp al, 0xc0
|
||
|
je sn001
|
||
|
|
||
|
movzx eax, byte [esi]
|
||
|
inc eax
|
||
|
add esi, eax
|
||
|
jmp skipName
|
||
|
|
||
|
sn001:
|
||
|
add esi, 2 ; A pointer is always at the end
|
||
|
ret
|
||
|
|
||
|
sn_exit:
|
||
|
inc esi
|
||
|
ret
|
||
|
|
||
|
no_data:
|
||
|
eth.close [socketNum]
|
||
|
xor eax,eax
|
||
|
|
||
|
ret
|
||
|
|
||
|
dnsMsgLen: dd 0
|
||
|
socketNum: dd 0xFFFF
|
||
|
|
||
|
if ~defined dnsMsg
|
||
|
dnsMsg: rb BUFFER
|
||
|
end if
|
||
|
|
||
|
end if
|
||
|
|
||
|
|
||
|
|
||
|
|