I wrote a tcp server which I want to update to support IPv6, so I need to replace the sockaddr_in structure with sockaddr_in6.
Unfortunately sockaddr_in6 is not defined in windows.inc. Can anyone tell me what's needed to add it?
Also, if anyone has example code for an IPv6 tcp server it would be very helpful. Ideally I want to accept both IPv4 and IPv6 connections using dual stack by creating an IPv6 socket and turning off the socket option IPV6_V6ONLY, (which is not defined in MASM32 either, but it is 027h), and then invoke bind and listen to allow inbound connections.
It appears that other then changing sockaddr_in to sockaddr_in6 and changing AF_INET to AF_INET6 (or AF_UNSPEC for dual stack), I will just need to adapt to using getaddrinfo and getnameinfo in place of the IPv4-only functions.
Its handy in MSDN.
https://msdn.microsoft.com/en-us/library/windows/hardware/ff570824(v=vs.85).aspx
typedef struct sockaddr_in {
ADDRESS_FAMILY sin6_family;
USHORT sin6_port;
ULONG sin6_flowinfo;
IN6_ADDR sin6_addr;
union {
ULONG sin6_scope_id;
SCOPE_ID sin6_scope_struct;
};
} SOCKADDR_IN6, *PSOCKADDR_IN6;
Thanks Hutch, but how would I create the same structure in MASM?
Is ADDRESS_FAMILY 8 bytes?
What does UNION do?
It appears that sin6_scope_struct is not defined in WINDOWS.INC either.
Pick what you need:
ADDRINFOA STRUCT
ai_flags DWORD ? ; AI_PASSIVE, AI_CANONNAME, AI_NUMERICHOST
ai_family DWORD ? ; PF_xxx
ai_socktype DWORD ? ; SOCK_xxx
ai_protocol DWORD ? ; 0 or IPPROTO_xxx for IPv4 and IPv6
ai_addrlen dd ? ; Length of ai_addr
ai_canonname LPVOID ? ; Canonical name for nodename
ai_addr dd ? ; Binary address
ai_next dd ? ; Next structure in linked list
ADDRINFOA ENDS
SOCKADDR_IN6 STRUCT
sin6_family DWORD ?
sin6_port USHORT ?
sin6_flowinfo ULONG ?
sin6_addr DWORD ?
UNION
sin6_scope_id ULONG ?
sin6_scope_struct SCOPE_ID <>
ENDS
SOCKADDR_IN6 ENDS
PSOCKADDR_IN6 typedef ptr SOCKADDR_IN6
For the definition of SCOPE_ID, see here (https://msdn.microsoft.com/en-us/library/windows/hardware/ff570824%28v=vs.85%29.aspx). Looks like a RECORD.
Thanks JJ, that was exactly what I needed.
The structure is more likely something like this:
SOCKADDR_IN6 STRUCT
sin6_family WORD ?
sin6_port WORD ?
sin6_flowinfo DWORD ?
sin6_addr BYTE 16 DUP (?)
;UNION
sin6_scope_id DWORD ?
;sin6_scope_struct SCOPE_ID <>
;ENDS
SOCKADDR_IN6 ENDS
scopeid is usually zero, probably you don't need to complicate things, unless you wish.
José is right, the family is a short. Here is the GCC ws2tcpip.h, much cleaner than the obfuscated M$ crap:
struct sockaddr_in6 {
short sin6_family; /* AF_INET6 */
u_short sin6_port; /* transport layer port # */
u_long sin6_flowinfo; /* IPv6 traffic class & flow info */
struct in6_addr sin6_addr; /* IPv6 address */
u_long sin6_scope_id; /* set of interfaces for a scope */
};
The sin6_addr member is a "struct" that can be one byte, word or dword:struct in6_addr {
union {
u_char _S6_u8[16];
u_short _S6_u16[8];
u_long _S6_u32[4];
} _S6_un;
};
And of course, it is a DWORD in practice, what else?
Quote from: jj2007 on November 15, 2017, 07:35:09 PM
and of course, it is a DWORD in practice, what else?
It is never a DWORD, JJ. :icon_eek:
Have you ever seen a IPv6 address?
Yeah, it's four DWORDs, right, thank you so much and have a nice day.
Quote from: jj2007 on November 15, 2017, 08:00:55 PM
Yeah, it's four DWORDs, right, thank you so much and have a nice day.
No, it is 16 bytes. No function deals with it as an array of dwords.
Now, you can rest in peace. :t
Quote from: aw27 on November 15, 2017, 08:10:07 PMNo function deals with it as an array of dwords.
Then why does GCC provide
u_long _S6_u32[4]; in the header file?
Quote from: jj2007 on November 15, 2017, 09:10:03 PM
Quote from: aw27 on November 15, 2017, 08:10:07 PMNo function deals with it as an array of dwords.
Then why does GCC provide u_long _S6_u32[4]; in the header file?
Does not make much sense, but VS does the same.
On top of that values are in network byte order.
actually, it's 8 words, divided into 3 groups of different sizes :biggrin:
... and normative it is:
Quote from: RFC4291IPv6 addresses are 128-bit identifiers for interfaces and sets of interfaces
RFC4291 (https://tools.ietf.org/html/rfc4291#section-2)
struct in6_addr {
union {
u_char _S6_u8[16];
u_short _S6_u16[8];
u_long _S6_u32[4];
GUID _S6_uxxl;
} _S6_un;
};
;)
I said, no function uses array of dwords. All that matters is the array of BYTES.
Following code connects to my IPv6 enabled website with IPv6 address 2a02:c205:2004:9655::4
You need IPv6 (Actually you can do it with a tunnel broker like https://tunnelbroker.net/ , as I am doing).
include \masm32\include\masm32rt.inc
include \masm32\include\ws2_32.inc
;includelib \masm32\lib\ws2_32.lib ; too old
includelib "C:\Program Files (x86)\Windows Kits\10\Lib\10.0.15063.0\um\x86\ws2_32.lib"
includelib \masm32\lib\msvcrt.lib
memset proto C :ptr, :dword, :dword
inet_pton PROTO :SDWORD, :PTR, :PTR
SOCKADDR_IN6 STRUCT
sin6_family WORD ?
sin6_port WORD ?
sin6_flowinfo DWORD ?
sin6_addr BYTE 16 DUP (?)
sin6_scope_id DWORD ?
SOCKADDR_IN6 ENDS
.Data
atelierweb db "2a02:c205:2004:9655::4",0
request db "GET / HTTP/1.1",13,10,"Host: www.atelierweb.com",13,10,"Connection: close",13,10,13,10,0;
.Code
main proc
LOCAL wsadata:WSADATA
LOCAL _addr : SOCKADDR_IN6
LOCAL sock : dword
LOCAL buffer[256] : byte
invoke memset, addr buffer,0,sizeof buffer
Invoke WSAStartup, 202h, Addr wsadata
.if eax!=0
jmp @exit2
.endif
INVOKE socket, AF_INET6, SOCK_STREAM, IPPROTO_TCP
.if eax==INVALID_SOCKET
jmp @exit1
.endif
mov sock, eax
invoke memset, addr _addr,0,sizeof _addr
mov _addr.sin6_family, AF_INET6
INVOKE htons, 80
mov _addr.sin6_port, ax
INVOKE inet_pton, AF_INET6, addr atelierweb, addr _addr.sin6_addr
INVOKE connect, sock, ADDR _addr, sizeof _addr
INVOKE send, sock, addr request, SIZEOF request, 0
INVOKE recv, sock, addr buffer, sizeof buffer,0
INVOKE crt_printf, addr buffer
INVOKE closesocket, sock
@exit1:
invoke WSACleanup
@exit2:
Invoke ExitProcess, 0
main endp
End main
HTTP/1.1 200 OK
Cache-Control: no-store, no-cache, must-revalidate
Pragma: no-cache
Content-Type: text/html; charset=UTF-8
Expires: Thu, 19 Nov 1981 08:52:00 GMT
Server: Microsoft-IIS/7.5
X-Powered-By: PHP/7.0.22
Set-Cookie: PHPSESSID=mbpa5ug5qip3in|
Quote from: jj2007 on November 15, 2017, 07:35:09 PM
the obfuscated M$ crap:
:lol:
Sorry for taking out of context, but it's too funny for me.... :greenclp:
:lol:
Jose, Thanks for the IPv6 client example!
I see that you had to use a newer version of ws2_32.lib and defined inet_pton to make it work.
Do you have any MASM32 example code for an IPv6 server?
Instead of using getaddrinfo (which can automatically fill in the addrinfo data with all the interface's network addresses to bind to), I decided it would be simpler to
fill in the addrinfo data manually using "in6addr_any" but MASM says this symbol is undefined. Do you know the value?
Hi Mike,
in6addr_any, is externally defined.
extern in6addr_any:oword
or
simply :: (i.e 16 zero bytes)
Quote
Do you have any MASM32 example code for an IPv6 server?
No, I am waiting for yours. :biggrin:
After some research I found the "in6addr_any" value is 6173083. However, I'm still not able to get the server to bind to the listening port using IPv6.
When using IPv4, I can set the address to INADDR_ANY to allow all local interface addresses to be bound to the selected TCP port.
IPv6 allows this by setting the address to in6addr_any, but I can't make it work.
Quote
If an application does not care what local address is assigned, specify the constant value INADDR_ANY for an IPv4 local address or the constant value in6addr_any for an IPv6 local address in the sa_data member of the name parameter. This allows the underlying service provider to use any appropriate network address, potentially simplifying application programming in the presence of multihomed hosts (that is, hosts that have more than one network interface and address).
Source: https://msdn.microsoft.com/en-us/library/windows/desktop/ms737550(v=vs.85).aspx
The problem appears to be related to the "sin6_addr" element of the SOCKADDR_IN6 structure, which apparently has a "sa_data" member within it's 16 bytes which is where the "in6addr_any" value belongs, according to the above MSDN quote.
Here is a minimalistic program demonstrating the issue. It will conditionally assemble for either an IPv4 or IPv6 socket, by setting the "IPv4" value TRUE or FALSE.
In IPv4 mode, it binds fine using INADDR_ANY, but in IPv6 mode it fails to bind, resulting in WSAError 10049 (WSAEADDRNOTAVAIL - Cannot assign requested address).
Quote
include \masm32\include\masm32rt.inc
include \masm32\include\ws2_32.inc
includelib \masm32\lib\ws2_32.lib
includelib \masm32\lib\msvcrt.lib
;-------------------------------------
IPv4 equ FALSE ; Set to false for IPv6!
;-------------------------------------
in6addr_any equ 61730832 ; This was not defined in Windows.inc
SOCKADDR_IN6 STRUCT
sin6_family WORD ?
sin6_port WORD ?
sin6_flowinfo DWORD ?
sin6_addr DWORD ?,?in
sin6_scope_id DWORD ?
SOCKADDR_IN6 ENDS
.Data
Port dd 23 ; Inbound TCP port
goodbye db "goodbye" ; Msg to send client
_addr4_size dd SIZEOF _addr4
_addr6_size dd SIZEOF _addr6
_addr4 sockaddr_in <?> ; IPv4
_addr6 sockaddr_in6 <?> ; IPv6
.Code
main proc
LOCAL wsadata:WSADATA
LOCAL sock : dword
LOCAL sock2 : dword
Invoke WSAStartup, 202h, Addr wsadata
if (IPv4)
INVOKE socket, AF_INET, SOCK_STREAM, IPPROTO_TCP ;
mov _addr4.sin_family, AF_INET
mov _addr4.sin_addr, INADDR_ANY ; IPv4: use all network interfaces available
else ;IPv6:
invoke socket, AF_INET6, SOCK_STREAM, IPPROTO_TCP
mov _addr6.sin6_family, AF_INET6
mov dword ptr _addr6.sin6_addr, in6addr_any ; IPv6: use all network interfaces available
mov _addr6.sin6_flowinfo,0 ; flowinfo must be 0
mov _addr6.sin6_scope_id,0 ; scope_id must be 0
endif
mov sock,eax ; save socket descriptor handle
; TCP Server functions:
; "Socket" to get socket Descriptor.
; "htons" to convert TCP port from decimal to network bytes.
; "Bind" to own a TCP port.
; "Setsockopt" to set socket options.
; "Listen" for incoming connections on port.
; "Accept" allow an incoming connection.
invoke htons,Port ; Convert port values host/network bytes
if (IPv4)
mov _addr4.sin_port, ax ; IPv4: store sin_port to bind
invoke bind,sock,addr _addr4 , sizeof _addr4 ; "Bind" to port socket
else
mov _addr6.sin6_port,ax ; IPv6: store sin_port to bind
invoke bind,sock,addr _addr6 , sizeof _addr6 ; "Bind" to port socket
endif
.if eax!=NULL
print "Bind Failed",13,10
jmp @exit
.endif
invoke listen,sock,3 ; "Listen" for incoming connection (maximum=3) SOMAXCONN
.if eax!=NULL ; Check for error
print "Listen Failed",10,13
jmp @exit
.endif
print "Listening for incoming connections",13,10
Accept_loop:
if (IPv4)
invoke accept, sock, addr _addr4, addr _addr4_size ; IPv4: Accept Connection
else
invoke accept, sock, addr _addr6, addr _addr6_size ; IPv6: Accept Connection
endif
.if eax!=INVALID_SOCKET
mov sock2,eax ; If socket is good, handle connection.
print "Connection Accepted!",13,10
invoke send,sock2,addr goodbye,sizeof goodbye,0 ; Send message to client
invoke Sleep,500
invoke closesocket, sock2
.endif
jmp Accept_loop
@exit:
print "WSAGetLastError="
invoke WSAGetLastError
.if eax==WSAEADDRNOTAVAIL
push eax
print "WSAEADDRNOTAVAIL - Cannot assign requested address - "
pop eax
.endif
print ustr$(eax),13,10
print "exiting",13,10
Invoke ExitProcess, 0
main endp
End main
Quote
After some research I found the "in6addr_any" value is 6173083.
So, I have been preaching to the fishes. :dazzled:
Jose - I just read your post after I posted mine. I changed the code to zero out all 16 bytes of the sin6_addr, and now it's binding and accepting connections! :-)
:biggrin:
Anyway, SOCKADDR_IN6 STRUCT looks wrong and will make the program crash anytime.
Oh yes there was a typo there with the "sin6_addr dword ?,?in", I'm not sure how the "in" got there but I've already changed it back to "sin6_addr db 16 dup (?)".
I added some features such as IP and hostname output for incoming connections. Since MASM32's ws_32.lib is missing inet_ntop you will need to use a newer one from MS SDK.
Quote
; Example IPv4 and/or IPv6 Socket Server
include \masm32\include\masm32rt.inc
include \masm32\include\ws2_32.inc
;includelib \masm32\lib\ws2_32.lib ; too old for IPv6 functions
includelib "C:\Program Files\Windows Kits\10\Lib\10.0.16299.0\um\x86\ws2_32.lib"
;--------------------------------------
IPv4 equ FALSE ; Set to FALSE for IPv6!
;--------------------------------------
;define IPV6_V6ONLY 27 // Treat IPv6 wildcard bind as AF_INET6-only - Disable this for Dual-Stack
;define in6addr_any 0 // Requires all 16 bytes of sin6_addr to be zero
inet_pton PROTO :SDWORD,:PTR,:PTR ; Convert IPv4 or IPv6 address in text form to binary form
inet_ntop PROTO :SDWORD,:PTR,:PTR,:DWORD ; Convert IPv4 or IPv6 address in binary form to text form (replaces inet_ntoa)
KeyThread PROTO
SOCKADDR_IN6 STRUCT
sin6_family WORD ?
sin6_port WORD ?
sin6_flowinfo DWORD ?
sin6_addr db 16 dup (?)
sin6_scope_id DWORD ?
SOCKADDR_IN6 ENDS
.Data
Port dd 23 ; Inbound TCP port (23=Telnet)
goodbye db "goodbye" ; Msg to send client
_addr4_size dd SIZEOF _addr4 ; IPv4 size
_addr6_size dd SIZEOF _addr6 ; IPv6 size
zero dd 0 ; used to set TCPv6Only option off
_addr4 sockaddr_in <?> ; IPv4
_addr6 sockaddr_in6 <?> ; IPv6
hostname db 1024 dup (?)
servicename db 32 dup (?) ; service name (or number)
buffer db 46 dup (?) ; buffer to print Ansi text IP address
bufsize dd ?
ThreadID dd ?
.Code
Start:
main proc
LOCAL wsadata:WSADATA
LOCAL sock : dword
LOCAL sock2 : dword
cls ; clear screen
xor eax,eax
invoke CreateThread,eax,eax,addr KeyThread,eax,eax,eax ; Keyboard thread
Invoke WSAStartup, 202h, Addr wsadata
; TCP Server functions:
; "Socket" to get socket Descriptor.
; "htons" to convert TCP port from decimal to network bytes.
; "Bind" to own a TCP port.
; "Setsockopt" to set socket options.
; "Listen" for incoming connections on port.
; "Accept" allow an incoming connection.
if (IPv4)
invoke socket, AF_INET, SOCK_STREAM, IPPROTO_TCP
mov _addr4.sin_family, AF_INET
mov _addr4.sin_addr, INADDR_ANY ; IPv4: use all network interfaces available
else ;IPv6:
invoke socket, AF_INET6, SOCK_STREAM, IPPROTO_TCP
mov _addr6.sin6_family, AF_INET6
xor ebx,ebx
mov dword ptr _addr6.sin6_addr, ebx ;IPv6: Zero 16 byte .sin6_addr to use in6addr_any
mov dword ptr _addr6.sin6_addr+4, ebx
mov _addr6.sin6_flowinfo,ebx ; flowinfo must be 0
mov _addr6.sin6_scope_id,ebx ; scope_id must be 0
endif
mov sock,eax ; save socket descriptor handle
invoke htons,Port ; Convert port value to host/network bytes
if (IPv4)
mov _addr4.sin_port, ax ; IPv4: store sin_port to bind
invoke bind,sock,addr _addr4, sizeof _addr4 ; "Bind" to port socket
else ;IPv6
push eax
; Disable the IPV6_V6ONLY mode, so that IPv4 connections are also accepted.
IPV6_V6ONLY equ 27 ; value missing from windows.inc
invoke setsockopt, sock, IPPROTO_IPV6, IPV6_V6ONLY, addr zero, sizeof zero
.if eax!=NULL
print "setsockopt disable IP6_V6ONLY Failed",13,10
jmp @exit
.endif
pop eax
mov _addr6.sin6_port,ax ; IPv6: store sin_port to bind
invoke bind,sock,addr _addr6, sizeof _addr6 ; "Bind" to port socket
endif
.if eax!=NULL
print "Bind Failed",13,10
jmp @exit
.endif
invoke listen,sock,3 ; "Listen" for incoming connection (maximum=3) SOMAXCONN
.if eax!=NULL ; Check for error
print "Listen Failed",10,13
jmp @exit
.endif
print "Listening for incoming connections - Press ESC to exit.",13,10
Accept_loop:
if (IPv4)
invoke accept, sock, addr _addr4, addr _addr4_size ; IPv4: Accept Connection
else;IPv6
invoke accept, sock, addr _addr6, addr _addr6_size ; IPv6: Accept Connection
endif
.if eax!=INVALID_SOCKET
mov sock2,eax ; If socket is good, handle connection.
print "Connection Accepted!",13,10
if (IPv4)
print "IPv4 address hex: "
mov eax,dword ptr _addr4.sin_addr
else ;IPv6
print "IPv6 address hex: "
mov eax,dword ptr _addr6.sin6_addr
bswap eax
print uhex$(eax),32
mov eax,dword ptr _addr6.sin6_addr+4
bswap eax
print uhex$(eax),32
mov eax,dword ptr _addr6.sin6_addr+8
bswap eax
print uhex$(eax),32
mov eax,dword ptr _addr6.sin6_addr+12
endif
bswap eax
print uhex$(eax),13,10
if (IPv4)
print "IPv4 address txt: "
invoke inet_ntop,AF_INET, addr _addr4.sin_addr, addr buffer, addr bufsize ; Create Ansi text IP Address
invoke StdOut,addr buffer
print chr$(13),10
else ;IPv6
print "IPv6 address txt: "
invoke inet_ntop,AF_INET6, addr _addr6.sin6_addr, addr buffer, addr bufsize ; Create Ansi text IP Address
invoke StdOut,addr buffer
print chr$(13),10
; Check if it's really an IPv4 address (00000000 00000000 0000FFFF xxxxxxxx)
mov eax, dword ptr _addr6.sin6_addr
or eax, dword ptr _addr6.sin6_addr+4
jnz notipv4
cmp dword ptr _addr6.sin6_addr+8,0FFFF0000h
jne notipv4
print "IPv4 correct txt: "
lea eax,buffer+7 ; skip first 7 characters "::ffff:"
Invoke StdOut,eax
print chr$(13),10
notipv4:
endif
; getnameinfo - creates hostname and servicename from address
;
; The flags parameter can be used to customize processing of the getnameinfo function.
; The following flags are available:
; NI_NOFQDN - When set, local hosts only get their Relative Distinguished Name (RDN) returned.
; NI_NUMERICHOST - returns the numeric form of the hostname instead of its name.
; ; The numeric form is also returned if the hostname wont resolve by DNS.
; NI_NAMEREQD - When set, a host name that cannot be resolved by DNS results in an error.
; NI_NUMERICSERV - When set, The service port number is returned instead of its name.
; Also, if no hostname is found, the hostname is returned as the IP address.
; NI_DGRAM - Indicates the service is a datagram service. (providing different port numbers).
if (IPv4)
invoke getnameinfo, addr _addr4, sizeof _addr4,\
addr hostname,sizeof hostname,\
addr servicename,sizeof servicename,0
else ; IPv6
invoke getnameinfo, addr _addr6, sizeof _addr6,\
addr hostname,sizeof hostname,\
addr servicename,sizeof servicename,0
endif
.if eax !=NULL
print "getnameinfo Failed!",13,10
jmp @exit
.endif
print "hostname: "
invoke StdOut,addr hostname
print chr$(13),10
print "servicename: "
invoke StdOut,addr servicename
print chr$(13),10
invoke send,sock2,addr goodbye,sizeof goodbye,0 ; Send message to client
invoke Sleep,500
invoke closesocket, sock2 ; Disconnect client
.endif
jmp Accept_loop
@exit:
print "WSAGetLastError="
invoke WSAGetLastError
.if eax==WSAEADDRNOTAVAIL
push eax
print "WSAEADDRNOTAVAIL - Cannot assign requested address - "
pop eax
.endif
print ustr$(eax),13,10
Invoke ExitProcess, 0
main endp
KeyThread proc near
getkey
cmp al,01Bh ; Exit if ESC pressed
jne KeyThread
Invoke ExitProcess, 0
KeyThread endp
End Start
I tried to run my server under Windows XP, but I get the message:
Quote
Title: Server.exe Entry Point Not Found:
Dialog: The procedure entry point inet_ntop could not be found in the dynamic link library ws_32.dll.
Is it possible to only load the inet_ntop from the ws_32.dll if GetVersionEx shows Windows Vista or later?
Nevermind, I was able to call the function directly using GetModuleHandle/GetProcAddress. :-)
Or you can make your own inet_ntop from WSAAddressToString. In this case, you have to watch for a "%" in the result and remove everything after it.
I considered doing that, but I decided not so support IPv6 under XP (at least for now) because the dual-stack approach to having one socket answer both IPv6 and IPv4 connections is not available in Windows XP, and it would require a listening socket for each one.
1. the netdatas can't be crossed the CISCO switch,so the server and client must be in localnet.
2. you must set the server addr into your ipv6.
3. The server displays the information of the client that is connected
client:
include \masm32\include\masm32rt.inc
include \masm32\include\ws2_32.inc
includelib \masm32\lib\ws2_32.lib
include \masm32\include\debug.inc
includelib \masm32\lib\debug.lib
includelib \masm32\lib\msvcrt.lib
memset proto C :ptr, :dword, :dword
;inet_pton PROTO :SDWORD, :PTR, :PTR
proto_Pinet_pton typedef proto stdcall :SDWORD,:PTR,:PTR
Pinet_pton typedef ptr proto_Pinet_pton
SOCKADDR_IN6 STRUCT
sin6_family WORD ?
sin6_port WORD ?
sin6_flowinfo DWORD ?
sin6_addr BYTE 16 DUP (?)
sin6_scope_id DWORD ?
SOCKADDR_IN6 ENDS
.Data
svr_ipv6 db "fe80::cdff:9f34:d69:7323%11",0
.data?
_inet_pton Pinet_pton ?
.Code
ErrorMessage Proc lpCaption:dword,nFlag:BOOL
Local lpErrorMessage:DWORD
.if nFlag==TRUE
call WSAGetLastError
.else
call GetLastError
.endif
lea ecx,lpErrorMessage
invoke FormatMessage, FORMAT_MESSAGE_ALLOCATE_BUFFER or FORMAT_MESSAGE_FROM_SYSTEM, NULL, EAX, LANG_NEUTRAL,ecx,0,NULL
invoke MessageBox, 0, lpErrorMessage, lpCaption, MB_OK
invoke LocalFree, lpErrorMessage
ret
ErrorMessage EndP
GetApiAdd proc dllname:DWORD,procname:DWORD
Local hdll:HWND
invoke LoadLibrary,dllname
.if eax!=0
mov hdll,eax
invoke GetProcAddress,hdll,procname
push eax
invoke FreeLibrary,hdll
pop eax
.else
invoke ErrorMessage,CTXT("LoadLibrary"),FALSE
.endif
ret
GetApiAdd endp
start proc
LOCAL wsadata:WSADATA
LOCAL _addr : SOCKADDR_IN6
LOCAL sock : dword
LOCAL buffer[128]:byte
invoke GetApiAdd,CTXT("ws2_32.dll"),CTXT("inet_pton")
.if eax==0
invoke ErrorMessage,CTXT("GetApiAdd"),FALSE
jmp @exit2
.else
mov _inet_pton,eax
.endif
invoke memset, addr buffer,0,sizeof buffer
invoke memset, addr _addr,0,sizeof _addr
Invoke WSAStartup, 202h, Addr wsadata
.if eax!=0
invoke ErrorMessage,CTXT("WSAStartup"),TRUE
jmp @exit2
.endif
INVOKE socket, AF_INET6, SOCK_STREAM, IPPROTO_TCP
.if eax==INVALID_SOCKET
invoke ErrorMessage,CTXT("socket"),TRUE
jmp @exit1
.endif
mov sock, eax
mov _addr.sin6_family, AF_INET6
INVOKE htons, 9023
mov _addr.sin6_port, ax
INVOKE _inet_pton, AF_INET6, offset svr_ipv6, addr _addr.sin6_addr
INVOKE connect, sock, ADDR _addr, sizeof _addr
.if eax==SOCKET_ERROR
invoke ErrorMessage,CTXT("connect"),TRUE
.else
INVOKE recv, sock, addr buffer, 100,0
INVOKE crt_printf, addr buffer
.endif
INVOKE closesocket, sock
@exit1:
invoke WSACleanup
@exit2:
print chr$(13),10
inkey
Invoke ExitProcess, 0
start endp
end start
server:
include \masm32\include\masm32rt.inc
include \masm32\include\ws2_32.inc
includelib \masm32\lib\ws2_32.lib ;
include \masm32\include\debug.inc
includelib \masm32\lib\debug.lib
;--------------------------------------
IPv4 equ FALSE ; Set to FALSE for IPv6!
;--------------------------------------
proto_Pinet_ntop typedef proto stdcall :SDWORD,:PTR,:PTR,:DWORD
Pinet_ntop typedef ptr proto_Pinet_ntop
;define IPV6_V6ONLY 27 // Treat IPv6 wildcard bind as AF_INET6-only - Disable this for Dual-Stack
;define in6addr_any 0 // Requires all 16 bytes of sin6_addr to be zero
;inet_pton PROTO :SDWORD,:PTR,:PTR ; Convert IPv4 or IPv6 address in text form to binary form
;inet_ntop PROTO :SDWORD,:PTR,:PTR,:DWORD ; Convert IPv4 or IPv6 address in binary form to text form (replaces inet_ntoa)
;KeyThread PROTO
sockaddr_in6 STRUCT
sin6_family WORD ?
sin6_port WORD ?
sin6_flowinfo DWORD ?
sin6_addr db 16 dup (?);sin6_addr
sin6_scope_id DWORD ?
sockaddr_in6 ENDS
.Data
Port dd 9023 ; Inbound TCP port (23=Telnet)
goodbye db "...goodbye!..." ; Msg to send client
_addr4_size dd SIZEOF _addr4 ; IPv4 size
_addr6_size dd SIZEOF _addr6 ; IPv6 size
zero dd 0 ; used to set TCPv6Only option off
_addr4 sockaddr_in <?> ; IPv4
_addr6 sockaddr_in6 <?> ; IPv6
hostname db 1024 dup (?)
servicename db 32 dup (?) ; service name (or number)
buffer db 46 dup (?) ; buffer to print Ansi text IP address
bufsize dd ?
ThreadID dd ?
_inet_ntop Pinet_ntop ?
.Code
ErrorMessage Proc lpCaption:dword,nFlag:BOOL
Local lpErrorMessage:DWORD
.if nFlag==TRUE
call WSAGetLastError
.else
call GetLastError
.endif
lea ecx,lpErrorMessage
invoke FormatMessage, FORMAT_MESSAGE_ALLOCATE_BUFFER or FORMAT_MESSAGE_FROM_SYSTEM, NULL, EAX, LANG_NEUTRAL,ecx,0,NULL
invoke MessageBox, 0, lpErrorMessage, lpCaption, MB_OK
invoke LocalFree, lpErrorMessage
ret
ErrorMessage EndP
GetApiAdd proc dllname:DWORD,procname:DWORD
Local hdll:HWND
invoke LoadLibrary,dllname
.if eax!=0
mov hdll,eax
invoke GetProcAddress,hdll,procname
push eax
invoke FreeLibrary,hdll
pop eax
.else
invoke ErrorMessage,CTXT("LoadLibrary"),FALSE
.endif
ret
GetApiAdd endp
KeyThread proc near
getkey
cmp al,01Bh ; Exit if ESC pressed
jne KeyThread
invoke WSACleanup
Invoke ExitProcess, 0
KeyThread endp
start proc
LOCAL wsadata:WSADATA
LOCAL sock : dword
LOCAL sock2 : dword
invoke GetApiAdd,CTXT("ws2_32.dll"),CTXT("inet_ntop")
.if eax==0
invoke ErrorMessage,CTXT("GetApiAdd"),FALSE
jmp @exit
.else
mov _inet_ntop,eax
.endif
;PrintHex eax
cls ; clear screen
xor eax,eax
invoke CreateThread,eax,eax,addr KeyThread,eax,eax,eax ; Keyboard thread
Invoke WSAStartup, 202h, Addr wsadata
; TCP Server functions:
; "Socket" to get socket Descriptor.
; "htons" to convert TCP port from decimal to network bytes.
; "Bind" to own a TCP port.
; "Setsockopt" to set socket options.
; "Listen" for incoming connections on port.
; "Accept" allow an incoming connection.
if (IPv4)
invoke socket, AF_INET, SOCK_STREAM, IPPROTO_TCP
mov _addr4.sin_family, AF_INET
mov _addr4.sin_addr, INADDR_ANY ; IPv4: use all network interfaces available
else ;IPv6:
invoke socket, AF_INET6, SOCK_STREAM, IPPROTO_TCP
mov _addr6.sin6_family, AF_INET6
xor ebx,ebx
mov dword ptr _addr6.sin6_addr, ebx ;IPv6: Zero 16 byte .sin6_addr to use in6addr_any
mov dword ptr _addr6.sin6_addr+4, ebx
mov _addr6.sin6_flowinfo,ebx ; flowinfo must be 0
mov _addr6.sin6_scope_id,ebx ; scope_id must be 0
endif
mov sock,eax ; save socket descriptor handle
invoke htons,Port ; Convert port value to host/network bytes
if (IPv4)
mov _addr4.sin_port, ax ; IPv4: store sin_port to bind
invoke bind,sock,addr _addr4, sizeof _addr4 ; "Bind" to port socket
else ;IPv6
push eax
; Disable the IPV6_V6ONLY mode, so that IPv4 connections are also accepted.
IPV6_V6ONLY equ 27 ; value missing from windows.inc
invoke setsockopt, sock, IPPROTO_IPV6, IPV6_V6ONLY, addr zero, sizeof zero
.if eax!=NULL
invoke ErrorMessage,CTXT("setsockopt"),TRUE
jmp @exit
.endif
pop eax
mov _addr6.sin6_port,ax ; IPv6: store sin_port to bind
invoke bind,sock,addr _addr6, sizeof _addr6 ; "Bind" to port socket
endif
.if eax!=NULL
invoke ErrorMessage,CTXT("bind"),TRUE
jmp @exit
.endif
invoke listen,sock,3 ; "Listen" for incoming connection (maximum=3) SOMAXCONN
.if eax!=NULL ; Check for error
invoke ErrorMessage,CTXT("listen"),TRUE
jmp @exit
.endif
print "Listening for incoming connections - Press ESC to exit.",13,10
Accept_loop:
if (IPv4)
invoke accept, sock, addr _addr4, addr _addr4_size ; IPv4: Accept Connection
else;IPv6
invoke accept, sock, addr _addr6, addr _addr6_size ; IPv6: Accept Connection
endif
.if eax!=INVALID_SOCKET
mov sock2,eax ; If socket is good, handle connection.
print "Connection Accepted!",13,10
if (IPv4)
print "IPv4 address hex: "
mov eax,dword ptr _addr4.sin_addr
else ;IPv6
print "IPv6 address hex: "
mov eax,dword ptr _addr6.sin6_addr
bswap eax
print uhex$(eax),32
mov eax,dword ptr _addr6.sin6_addr+4
bswap eax
print uhex$(eax),32
mov eax,dword ptr _addr6.sin6_addr+8
bswap eax
print uhex$(eax),32
mov eax,dword ptr _addr6.sin6_addr+12
endif
bswap eax
print uhex$(eax),13,10
if (IPv4)
print "IPv4 address txt: "
invoke _inet_ntop,AF_INET, addr _addr4.sin_addr, addr buffer, addr bufsize ; Create Ansi text IP Address
invoke StdOut,addr buffer
print chr$(13),10
else ;IPv6
print "IPv6 address txt: "
invoke _inet_ntop,AF_INET6, addr _addr6.sin6_addr, addr buffer, addr bufsize ; Create Ansi text IP Address
invoke StdOut,addr buffer
print chr$(13),10
; Check if it's really an IPv4 address (00000000 00000000 0000FFFF xxxxxxxx)
mov eax, dword ptr _addr6.sin6_addr
or eax, dword ptr _addr6.sin6_addr+4
jnz notipv4
cmp dword ptr _addr6.sin6_addr+8,0FFFF0000h
jne notipv4
print "IPv4 correct txt: "
lea eax,buffer+7 ; skip first 7 characters "::ffff:"
Invoke StdOut,eax
print chr$(13),10
notipv4:
endif
; getnameinfo - creates hostname and servicename from address
;
; The flags parameter can be used to customize processing of the getnameinfo function.
; The following flags are available:
; NI_NOFQDN - When set, local hosts only get their Relative Distinguished Name (RDN) returned.
; NI_NUMERICHOST - returns the numeric form of the hostname instead of its name.
; ; The numeric form is also returned if the hostname wont resolve by DNS.
; NI_NAMEREQD - When set, a host name that cannot be resolved by DNS results in an error.
; NI_NUMERICSERV - When set, The service port number is returned instead of its name.
; Also, if no hostname is found, the hostname is returned as the IP address.
; NI_DGRAM - Indicates the service is a datagram service. (providing different port numbers).
if (IPv4)
invoke getnameinfo, addr _addr4, sizeof _addr4,addr hostname,sizeof hostname,addr servicename,sizeof servicename,0
else ; IPv6
invoke getnameinfo, addr _addr6, sizeof _addr6,addr hostname,sizeof hostname,addr servicename,sizeof servicename,0
endif
.if eax !=NULL
print "getnameinfo Failed!",13,10
jmp @exit
.endif
print "hostname: "
invoke StdOut,addr hostname
print chr$(13),10
print "servicename: "
invoke StdOut,addr servicename
print chr$(13),10
invoke send,sock2,addr goodbye,sizeof goodbye,0 ; Send message to client
invoke Sleep,500
invoke closesocket, sock2 ; Disconnect client
.endif
jmp Accept_loop
@exit:
print "WSAGetLastError="
invoke WSAGetLastError
.if eax==WSAEADDRNOTAVAIL
push eax
print "WSAEADDRNOTAVAIL - Cannot assign requested address - "
pop eax
.endif
print ustr$(eax),13,10
invoke WSACleanup
Invoke ExitProcess, 0
start endp
end start
Hi six_L,
Your code builds fine, and the server is listening, but the client is stuck at
INVOKE connect, sock, ADDR _addr, sizeof _addr
After a while, a MsgBox "can't establish a connection" appears. Is that expected behaviour?
svr_ipv6 db "fe80::cdff:9f34:d69:7323%11",0
modify your ipv6.
It will be valid until next reboot because these are not static.
The best will be to use a name and resolve it.