Ah! Thanks, Rob!

Not all that easy to edit winsock.inc, since it un-tars as readonly, so had to chmod +w first. I didn't put it back to readonly - probably should have so it doesn't get modified accidentally...

Then, my "fakeapi" no longer works - apparently because "new NASMX" uses a different linker than "old NASMX". I solved it by "%define"ing the "true names" back to the "short names". Would have been easier if I'd done it that way in the first place! That finally got it to work (in Linux).

But this is merely a distraction from the project at hand - getting my IP from http://www.whatismyip.com . Going back to my "plain" version, if I deliberately butcher the "request", I get back "400 bad request". This indicates that my socket/connect/write/read are all working (doesn't it?). Yet if I write a "correct" (as nearly as I can determine) request, I get nothing at all back - the "read" just hangs...

At the moment, I'm stumped!

Best,
Frank

Posted on 2011-10-08 08:56:40 by fbkotler

Ah! Thanks, Rob!

Not all that easy to edit winsock.inc, since it un-tars as readonly, so had to chmod +w first. I didn't put it back to readonly - probably should have so it doesn't get modified accidentally...

Then, my "fakeapi" no longer works - apparently because "new NASMX" uses a different linker than "old NASMX". I solved it by "%define"ing the "true names" back to the "short names". Would have been easier if I'd done it that way in the first place! That finally got it to work (in Linux).


hmmm...GoLink has been in use for quite some time ( ie: even before my involvement ).  This may be another issue altogether.


But this is merely a distraction from the project at hand - getting my IP from http://www.whatismyip.com . Going back to my "plain" version, if I deliberately butcher the "request", I get back "400 bad request". This indicates that my socket/connect/write/read are all working (doesn't it?).


Yes, at least as far as initial connection and request transmission.


Yet if I write a "correct" (as nearly as I can determine) request, I get nothing at all back - the "read" just hangs...

At the moment, I'm stumped!

Best,
Frank


In the request header you are specifying:

    db "Host: clax.inspiretomorrow.net" ,13 ,10


This returns 96.9.162.227 as the IP address when I ping it.
However, you are specifying 75.126.1.55 for your connection which appears to be resolving to some host at softlayer.com.
This appears to be a simple mismatch, thus the server is possibly dropping the request for the unknown host.
Posted on 2011-10-08 20:34:05 by p1ranha
Ah ha! That's a good clue. In the "plain" version, I'm using www.whatismyip.com for the host, or sometimes automation.whatismyip.com - which appears to be the same IP, but "reversed" 72.233.89.198 vs 198.89.233.72. I may well be butchering the conversion of the "dotted quad" to a big-endian dword, as well.

I distinctly remember writting some code that converted something in the form "72.233.89.198" to a big-endian dword ("long" in Gas), but I can't find it. As I remember, I wasn't too happy with it anyway...

Lemme rework some of that from "square one" (or "square zero" in assembly :) ), and see if that provides any enlightenment...

Best,
Frank

Posted on 2011-10-08 21:02:42 by fbkotler
Well, Here I am again.
I could create the socket, connect it and send the http request.
Now the problem is in receive all the information

this is my code

.section .data
Errorsocket: .asciz"socket() failed \n"
Econnect: .asciz"error connecting socket \n"
request: .ascii  "GET /index.html HTTP/1.1 Host: www.whatismyip.com User-Agent: assembly language Connection: close"

.equ length, request
.section .bss
buffer: .space 100
.section .text

.globl _start
_start:
      #Creating a reliable, stream socket  TCP
              movl $2, (%esp) #af_inet
        movl $1, 4(%esp) #sock-stream
        movl $0, 8(%esp) #ipprotocp

        movl $102,%eax #socketcall
        movl $1,%ebx  #socketcall_socket
        movl %esp,%ecx #
          int  $0x80
        cmpl $0, %eax
        jl error

        #Establish a connection to the server
        # connect (int fd, struct sockaddr *uservaddr, int addrlen)       
        #parameters sent to esp
movl %eax, (%esp) #fd
        #struct sockaddrr *uservaddr
        movw $2, 12(%esp) #af_inet
        movw $0x5000, 14(%esp) #port
        movl $0xc559e948, 16(%esp) # ip

        #connect()
        leal 12(%esp), %ebx #loading sockaddr *uservaddr pointer.
        movl %ebx, 4(%esp) #we move the pointer after fd, that is to say 4
        movl $16, 8(%esp)  #size 
        movl    $102,%eax    #socketcall
        movl    $3, %ebx    #connect
        movl %esp, %ecx
        int    $0x80
        cmpl $0, %eax
        jne error2
         
          #send()
        leal request, %eax
        movl %eax, 8(%esp)         
        movl $length, 12(%esp)
        movl $0, 16(%esp)
        movl $102, %eax
        movl $9, %ebx  #send system call 
        movl %esp, %ecx
        int $0x80
                 
   
        #receive()
        movl $buffer, 8(%esp)
        movl $99, 12(%esp)
        movl $0, 16(%esp)
        movl $102, %eax
        movl $10, %ebx
        movl %esp, %ecx
        int $0x80
            jmp endprogram
error:  pushl $Errorsocket
        call printf
        jmp  endprogram

error2:  pushl %eax
        pushl $Econnect
        call printf
        jmp endprogram
endprogram: 
        movl $1, %eax
movl $0, %ebx
int $0x80

It returns me in %eax: -22. So, it is clear that there is a problem.
Before that, I would like to clear up some doubts that I have.
In send() function, it returns me: 2736. The number of bytes sent if successful. So, it sent 2736 bytes...  how I realised that the quantity bytes sent are correct?
Then, according to
recv(int s, void *buf, size_t len, int flags);
I have to send the buffer pointer. My question is: how many bytes do I have to set to the buffer var? I set up 100 but because I had no idea what i had to write there.

And finally, why it returned me this error?

thanks!!!




Posted on 2011-10-13 15:46:30 by massem

Well, Here I am again.
I could create the socket, connect it and send the http request.
Now the problem is in receive all the information


No, your initial problem is still in the send().  There may be more but I don't have the time to debug it.

The HTTP protocol uses CR/LF delimited headers in the request with a separate CR/LF at the end.

You originally wrote:



request: .ascii  "GET /index.html HTTP/1.1 Host: www.whatismyip.com User-Agent: assembly language Connection: close"



But you need this (note that this is Nasm syntax):


msg db "GET /index.html HTTP/1.1", 13, 10
    db "Host: www.whatismyip.com" ,13 ,10
    db "User-Agent: assembly language", 13, 10
    db "Connection: close", 13, 10
    db 13, 10
msg_len equ $ - msg


The 13,10 characters are the Carraige Return and Line Feed characters (CR/LF) you are missing.
You need to understand the protocol first in order to properly submit requests and receive replys.
Posted on 2011-10-13 17:39:05 by p1ranha
Well, I tried p1ranha's advice regarding the "correct" IP for "Nathan's server". Getting "Network Unreachable"! I haven't gotten back to that one...

Trying this minor tweak to Marce's code, I get 404! That's the closest I've come yet!


.section .data
Errorsocket: .asciz"socket() failed \n"
Econnect: .asciz"error connecting socket \n"
request: .ascii  "GET /index.html HTTP/1.1\r\nHost: www.whatismyip.com\r\nUser-Agent: assembly language\r\nConnection: close\r\n\r\n"

.equ length, . - request
.section .bss
buffer: .space 100
sockdesc: .long 0
.section .text

.globl _start
_start:
      #Creating a reliable, stream socket  TCP
              movl $2, (%esp) #af_inet
        movl $1, 4(%esp) #sock-stream
        movl $0, 8(%esp) #ipprotocp

        movl $102,%eax #socketcall
        movl $1,%ebx  #socketcall_socket
        movl %esp,%ecx #
          int  $0x80
        cmpl $0, %eax
        jl error

        #Establish a connection to the server
        # connect (int fd, struct sockaddr *uservaddr, int addrlen)       
        #parameters sent to esp
movl %eax, (%esp) #fd
        #struct sockaddrr *uservaddr
        movw $2, 12(%esp) #af_inet
        movw $0x5000, 14(%esp) #port
        movl $0xc559e948, 16(%esp) # ip

        #connect()
        leal 12(%esp), %ebx #loading sockaddr *uservaddr pointer.
        movl %ebx, 4(%esp) #we move the pointer after fd, that is to say 4
        movl $16, 8(%esp)  #size 
        movl    $102,%eax    #socketcall
        movl    $3, %ebx    #connect
        movl %esp, %ecx
        int    $0x80
        cmpl $0, %eax
        jne error2
         
          #send()
        leal request, %eax
        movl %eax, 4(%esp) # buf
        movl $length, 8(%esp) #length
        movl $0, 12(%esp) #flags
        movl $102, %eax
        movl $9, %ebx  #send system call 
        movl %esp, %ecx
        int $0x80

testl %eax, %eax
jns goodsend
call report_error
        jmp  endprogram
goodsend:
                 
   
        #receive()
        movl $buffer, 4(%esp)
        movl $99, 8(%esp)
        movl $0, 12(%esp)
        movl $102, %eax
        movl $10, %ebx
        movl %esp, %ecx
        int $0x80
testl %eax, %eax
jns goodrecv
call report_error
        jmp  endprogram
goodrecv:
pushl $buffer
call printf

            jmp endprogram
error:  pushl $Errorsocket
        call printf
        jmp  endprogram

error2:  pushl %eax
        pushl $Econnect
        call printf
        jmp endprogram
endprogram: 
        movl $1, %eax
movl $0, %ebx
int $0x80


As you see, I call my "report_error", so you'll have to link against "rpterror.o"... or dump that...

Best,
Frank

Posted on 2011-10-13 21:01:08 by fbkotler
Bingo!


.section .data
Errorsocket: .asciz"socket() failed \n"
Econnect: .asciz"error connecting socket \n"
request: .ascii  "GET / HTTP/1.1\r\nHost: www.whatismyip.com\r\nUser-Agent: assembly language\r\nConnection: close\r\n\r\n"

.equ length, . - request

.section .bss
buffer: .space 0x1000

.section .text

.globl _start
_start:
      #Creating a reliable, stream socket  TCP
              movl $2, (%esp) #af_inet
        movl $1, 4(%esp) #sock-stream
        movl $0, 8(%esp) #ipprotocp

        movl $102,%eax #socketcall
        movl $1,%ebx  #socketcall_socket
        movl %esp,%ecx #
          int  $0x80
        cmpl $0, %eax
        jl error

        #Establish a connection to the server
        # connect (int fd, struct sockaddr *uservaddr, int addrlen)       
        #parameters sent to esp
movl %eax, (%esp) #fd
        #struct sockaddrr *uservaddr
        movw $2, 12(%esp) #af_inet
        movw $0x5000, 14(%esp) #port
        movl $0xc559e948, 16(%esp) # ip

        #connect()
        leal 12(%esp), %ebx #loading sockaddr *uservaddr pointer.
        movl %ebx, 4(%esp) #we move the pointer after fd, that is to say 4
        movl $16, 8(%esp)  #size 
        movl    $102,%eax    #socketcall
        movl    $3, %ebx    #connect
        movl %esp, %ecx
        int    $0x80
        cmpl $0, %eax
        jne error2
         
          #send()
        leal request, %eax
        movl %eax, 4(%esp) # buf
        movl $length, 8(%esp) #length
        movl $0, 12(%esp) #flags
        movl $102, %eax
        movl $9, %ebx  #send system call 
        movl %esp, %ecx
        int $0x80

testl %eax, %eax
jns goodsend
call report_error
        jmp  endprogram
goodsend:
                 
   
        #receive()
        movl $buffer, 4(%esp)
        movl $0x1000, 8(%esp)
        movl $0, 12(%esp)
        movl $102, %eax
        movl $10, %ebx
        movl %esp, %ecx
        int $0x80
testl %eax, %eax
jns goodrecv
call report_error
        jmp  endprogram
goodrecv:
pushl $buffer
call printf

            jmp endprogram
error:  pushl $Errorsocket
        call printf
        jmp  endprogram

error2:  pushl %eax
        pushl $Econnect
        call printf
        jmp endprogram
endprogram: 
        movl $1, %eax
movl $0, %ebx
int $0x80


P1ranha's tips were especially helpful! That "extra CRLF" at the end helped my version, too.

Making a request for just "/" rather than "/index.html" got rid of the 404!
I made your buffer a little bigger, and re-arranged some of the parameters - at first, I didn't "get" that you were putting the file descriptor at (%esp) and leaving it there. Okay, but then you were putting remaining parameters at 8(%esp) and up - should have been at 4(%esp) and up (I think). Anyway, this "seems to work".

Best,
Frank
Posted on 2011-10-14 00:33:00 by fbkotler
Mmmm... well, that doesn't get quite the whole page. There's quite a lot of it - almost 19k. What I've done in my Nasm version is to make the buffer bigger still, at which point I ran into a problem I know can occur with sockets: you don't always get the whole thing in one read. I'm using sys_read/sys_write instead of send/recv. So I put the read in a loop, until it returned zero. I think now I'm getting the whole "index.html" (although it apparently isn't named that). The "relevant  portion", I think, goes like this:

Your IP Address Is: <span id="184">&#55;</span><label id="125">
2</label><label id="237">&#46;</label>&#55;&#49;&#46;
<!--Do not scrape your IP from here, go to
www.whatismyip.com/faq/automation.asp for more information
on our automation rules.-->&#50;<label class="116">1</label>
<span id="125">&#50;</span><span class="73">&#46;</span>&#56;<br />


I don't see how to parse my IP out of that mess, and they seem to be asking us not to do it. I guess that leaves us with their automation page. Can we just "GET" an .asp file? I don't even know what an .asp file is!

Best,
Frank

Posted on 2011-10-14 02:47:54 by fbkotler
well as p1ranha adviced me, I am reading http protocol to understand it.

Anyway, I'm happy for you Frank, you are so close!
In regarding your doubts:
I didn't "get" that you were putting the file descriptor at (%esp) and leaving it there

I left the fd at (%esp) which is saved there from its creation .. isn't it?

you were putting remaining parameters at 8(%esp) and up - should have been at 4(%esp) and up (I think).

mmm I started putting parameters at 4(%esp), look this:

leal request, %eax  #Loading the request address in %eax
movl %eax, 4(%esp) # Loading the mention address in 4(%esp) 
movl $length, 8(%esp) #Loading its length
movl $0, 12(%esp) #flags


Maybe we have to specify this address GET /n09230945.asp  HTTP/1.1
instead of www.whatismyip.com at GET

What do u think, guys?
Posted on 2011-10-14 08:28:39 by massem
The request GET / HTTP/1.1 returns the default page of the site being visited.  For most web sites this is the file index.html.  Note that Windows servers ( and oddly configured Linux servers ) may expect default.htm or some other named file.  Thus specifically requesting the file index.html from those servers may fail or will return a code to redirect the "browser" to the site's true home page.
Posted on 2011-10-14 09:17:14 by p1ranha
what about this?
GET /automation/n09230945.asp HTTP/1.0
Host: www.whatismyip.com
Posted on 2011-10-14 10:19:49 by massem
That gets me a page telling me that the automation file has moved. Going where it says gets me the "rules" file (they don't want us to hit it more often than every five minutes). The actual n09230945.asp file is apparently at automation.whatismyip.com rather than www.whatismyip.com. I dunno...

Best,
Frank

Posted on 2011-10-14 11:33:58 by fbkotler
HTTP/1.1 200 OK !!!!!!!!!!!

I made it.
Check this out:
request:  .ascii "GET /n09230945.asp HTTP/1.1\r\nHost: automation.whatismyip.com\r\nUser-Agent: assembly language\r\nConnection: close\r\n\r\n"

but I got
HTTP/1.1 200 OK
Connection: close
Date: Fri, 14 Oct 2011 19:12:06 GMT
Server: Microsoft-IIS/6.0
X-Powered-By: ASP.NET
Content-Length: 14
Content-Type: text/html
Set-Cookie: ASPSESSIONIDCQQTRQCA=IIHPGABANHDNNAAIKJJGMJML; path=/
Cache-control: private

I guess due to the fact that it could be possible that the bytes sent by a call to send() on one
end of a connection may not all be returned by a single call to recv() on the other end. I need to repeatedly receive bytes until I have received as many as we sent.

Is it ok ?






Posted on 2011-10-14 13:51:21 by massem
I think you've found the combination! I don't know how I missed that in all the things I've tried, but I did.

Your posted output ends at "Cache-control: private". Right after that is the text we're looking for: "my" IP. I don't think you need to read "as many as sent", but you need to read until "sys_recv" returns zero. At least, I read until "sys_read" returns zero. I haven't actually implemented it with "sys_recv" so it'll be a little bit different, but...

if %eax is negative, quit with an error
if %eax is positive
  subtract %eax from "bytes to read"
      if negative, quit - out of buffer space
  add %eax to buffer position
  read/recv more
if %eax is zero, all done - print it or whatever...

It may be a regular thing to read/recv once, up to "Cache-control: private", and the second read/recv is the "text we want"... or maybe that's coincidence? I haven't tested it much. Since they ask you to not hit it more often than every five minutes, I don't want to pound on it too much. Have a cup of that good Italian coffee between trials, or something. I think you've got it! Congratulations!

Best,
Frank

Posted on 2011-10-14 16:32:45 by fbkotler
The Cache-Control reply header is used by both Proxy servers and your browser to determine the length of time that a page is valid.  It helps reduce network congestion by having the Proxy maintain a local copy of the page which it can subsequently serve up to the specified length of time.  It may also be used by a browser to reduce the number of server requests such that the browser does not have to resend the request for that particular resource again.
FYI: If not evident by my prior posts, then yes, I've spent many years writing commercial http and https apps, mostly in C/C++ but assembly is so underground that it appeals to me! :)
Posted on 2011-10-14 19:44:31 by p1ranha
Also, just a quick note:  The User-Agent request header may be used by the server to determine the capabilities of the browser, and thus the returned response code and content based upon it may vary.  For example, not specifying a Windows Internet Exporer or Mozilla compatible browser may not give you the identical results.  This is something to consider when attempting various requests...
Most developers I know capture the request/reply communications ( using WireShark or tcpdump for example ) and emulate the browser of choice...
Posted on 2011-10-14 20:01:14 by p1ranha