The better way to do the same thing for just checking IPv6 connections is to use an IPv6 ping. Below is some simple code using API to do this. For windows Vista and above with winsock version 2.2 - tested Windows 7 x86 & Windows 8 x86.
(note: Yes i'm aware some of these API's have equals with the PureBasic underscore designation, e.g. "FunctionName_(x,x,x....)" and there would be no need to load up a library and call from the .dll directly)
Code: Select all
Prototype Pgetaddrinfo(pNodeName, pServiceName, pHints, ppResult)
Prototype PGetAddrInfoEx(pName, pServiceName, dwNameSpace, lpNspId, pHints, ppResult, timeout, lpOverlapped, lpCompletionRoutine, lpNameHandle)
Prototype PWSAStartup(wVersionRequested, lpWSAData)
Prototype PWSACleanup()
Prototype PInetNtop(Family, pAddr, pStringBuf, StringBufSize)
Prototype PRtlZeroMemory(mem, sze)
Prototype PFreeAddrInfo(ai)
Prototype PFreeAddrInfoEx(ai)
Prototype PIcmp6SendEcho2(IcmpHandle, Event, ApcRoutine, ApcContext, SourceAddress, DestinationAddress, RequestData, RequestSize, RequestOptions, ReplyBuffer, ReplySize, Timeout)
Prototype PIcmp6ParseReplies(ReplyBuffer, ReplySize)
Prototype PIcmp6CreateFile()
Prototype PInetPton(Family, pszAddrString, pAddrBuf)
Prototype Pgetnameinfo(sa, salen, host, hostlen, serv, servlen, flags)
Prototype PNetWkstaGetInfo(servername, level, bufptr)
Prototype PNetApiBufferFree(Buffer_in)
Prototype PWSAGetLastError()
Global getaddrinfo.Pgetaddrinfo
Global GetAddrInfoEx.PGetAddrInfoEx
Global WSAStartup.PWSAStartup
Global WSACleanup.PWSACleanup
Global InetNtop.PInetNtop
Global ZeroMemory.PRtlZeroMemory
Global FreeAddrInfo.PFreeAddrInfo
Global FreeAddrInfoEx.PFreeAddrInfoEx
Global Icmp6SendEcho2.PIcmp6SendEcho2
Global Icmp6CreateFile.PIcmp6CreateFile
Global Icmp6ParseReplies.PIcmp6ParseReplies
Global InetPton.PInetPton
Global getnameinfo.Pgetnameinfo
Global NetWkstaGetInfo.PNetWkstaGetInfo
Global NetApiBufferFree.PNetApiBufferFree
Global WSAGetLastError.PWSAGetLastError
Structure IN6_ADDR ;->Structure in6_addr
StructureUnion
Byte.b[16]
Word.w[8]
EndStructureUnion
EndStructure
Structure sockaddr_in6 ;->Structure sockaddr_in6
sin6_family.w
sin6_port.w
sin6_flowinfo.l
sin6_addr.IN6_ADDR
sin6_scope_id.l
EndStructure
Structure IPV6_ADDRESS_EX ;->Structure IPV6_ADDRESS_EX
sin6_port.w
sin6_flowinfo.l
sin6_addr.w[8]
sin6_scope_id.l
EndStructure
Structure ICMPV6_ECHO_REPLY ;->Structure ICMPV6_ECHO_REPLY
Address.IPV6_ADDRESS_EX
Status.l
RoundTripTime.i
EndStructure
Structure ADDRINFOEX ;->Structure ADDRINFOEX
ai_flags.l
ai_family.l
ai_socktype.l
ai_protocol.l
ai_addrlen.i
*ai_canonname.c
*ai_addr.sockaddr_in6
*ai_blob
ai_bloblen.i
ai_provider.l
*ai_next.ADDRINFOEX
EndStructure
Structure WKSTA_INFO_100 ;->Structure WKSTA_INFO_100
wki100_platform_id.l
wki100_computername.l
wki100_langroup.l
wki100_ver_major.l
wki100_ver_minor.l
EndStructure
Structure IO_STATUS_BLOCK
StructureUnion
Status.i
Pointer.i
EndStructureUnion
Information.i
EndStructure
#DEFAULT_SEND_SIZE = 32
; added the IO_STATUS_BLOCK structure because the size of the structure will change between 32 and 64 bit when the .i become 8 bytes on 64 bit
#IO_STATUS_BLOCK_SIZE = SizeOf(IO_STATUS_BLOCK)
#ICMPV6_ECHO_REPLY_SIZE = SizeOf(ICMPV6_ECHO_REPLY)
#ICMP_ERROR_MESSAGE_SIZE = 8
#REQUEST_DATA_SIZE = 32
; #DEFAULT_RECEIVE_SIZE is used for the reply buffer size. Per MS > http://msdn.microsoft.com/en-us/library/windows/desktop/aa366041(v=vs.85).aspx
;"The buffer must be large enough to hold at least one ICMPV6_ECHO_REPLY structure plus the number of bytes of data specified in the RequestSize parameter."
;"This buffer should also be large enough to also hold 8 more bytes of data (the size of an ICMP error message) plus space for an IO_STATUS_BLOCK structure."
#DEFAULT_RECEIVE_SIZE = #ICMPV6_ECHO_REPLY_SIZE + #REQUEST_DATA_SIZE + #ICMP_ERROR_MESSAGE_SIZE + #IO_STATUS_BLOCK_SIZE
#DEFAULT_BUFFER_SIZE = 8184
#DEFAULT_TIMEOUT = 1000
#AF_INET6 = 23
#NS_DNS = 12
#NERR_Success = 0
#INET6_ADDRSTRLEN = 65
#NI_MAXHOST = 1025 ;Max size of a fully-qualified domain name
#NI_MAXSERV = 32 ;Max size of a service name
#MAX_OPT_SIZE = 40 ; Maximum length of IP options in bytes
#MAX_BUFFER_SIZE = SizeOf(ICMP_ECHO_REPLY) + $fff7 + #MAX_OPT_SIZE
Macro MAKEWORD(a, b)
(a & $FF)|((b & $FF)<<8)
EndMacro
Procedure LoadLibraries()
Global Lib_iphlpapi.l, Lib_Winsock.l, Lib_Lib_Kernel32.l, Lib_Netapi32.l
Lib_iphlpapi = OpenLibrary(#PB_Any,"iphlpapi.dll")
If IsLibrary(Lib_iphlpapi)<> 0
Icmp6SendEcho2.PIcmp6SendEcho2=GetFunction(Lib_iphlpapi,"Icmp6SendEcho2")
Icmp6CreateFile.PIcmp6CreateFile=GetFunction(Lib_iphlpapi,"Icmp6CreateFile")
Icmp6ParseReplies.PIcmp6ParseReplies=GetFunction(Lib_iphlpapi,"Icmp6ParseReplies")
EndIf
Lib_Winsock = OpenLibrary(#PB_Any,"ws2_32.dll")
If IsLibrary(Lib_Winsock)<> 0
WSAStartup.PWSAStartup=GetFunction(Lib_Winsock,"WSAStartup")
WSACleanup.PWSACleanup=GetFunction(Lib_Winsock,"WSACleanup")
WSAGetLastError.PWSAGetLastError=GetFunction(Lib_Winsock,"WSAGetLastError")
CompilerIf #PB_Compiler_Unicode ; if compiled in unicode use this
FreeAddrInfo.PFreeAddrInfo=GetFunction(Lib_Winsock,"FreeAddrInfoW")
FreeAddrInfoEx.PFreeAddrInfoEx=GetFunction(Lib_Winsock,"FreeAddrInfoExW")
getaddrinfo.Pgetaddrinfo=GetFunction(Lib_Winsock,"GetAddrInfoW")
getnameinfo.Pgetnameinfo=GetFunction(Lib_Winsock,"GetNameInfoW")
GetAddrInfoEx.PGetAddrInfoEx=GetFunction(Lib_Winsock,"GetAddrInfoExW")
InetPton.PInetPton=GetFunction(Lib_Winsock,"InetPtonW")
InetNtop.PInetNtop=GetFunction(Lib_Winsock,"InetNtopW")
CompilerElse ; if not compiled in unicode use this
FreeAddrInfo.PFreeAddrInfo=GetFunction(Lib_Winsock,"freeaddrinfo")
FreeAddrInfoEx.PFreeAddrInfoEx=GetFunction(Lib_Winsock,"FreeAddrInfoEx")
getaddrinfo.Pgetaddrinfo=GetFunction(Lib_Winsock,"getaddrinfo")
getnameinfo.Pgetnameinfo=GetFunction(Lib_Winsock,"getnameinfo")
GetAddrInfoEx.PGetAddrInfoEx=GetFunction(Lib_Winsock,"GetAddrInfoExA")
InetPton.PInetPton=GetFunction(Lib_Winsock,"inet_pton")
InetNtop.PInetNtop=GetFunction(Lib_Winsock,"inet_ntop")
CompilerEndIf
EndIf
Lib_Kernel32 = OpenLibrary(#PB_Any,"Kernel32.dll")
If IsLibrary(Lib_Kernel32)<> 0
ZeroMemory.PRtlZeroMemory=GetFunction(Lib_Kernel32,"RtlZeroMemory")
EndIf
Lib_Netapi32 = OpenLibrary(#PB_Any,"Netapi32.dll")
If IsLibrary(Lib_Netapi32)<> 0
NetApiBufferFree.PNetApiBufferFree=GetFunction(Lib_Netapi32,"NetApiBufferFree")
NetWkstaGetInfo.PNetWkstaGetInfo=GetFunction(Lib_Netapi32,"NetWkstaGetInfo")
EndIf
EndProcedure
Procedure.s GetCompName()
Level.l = 100
*WkstaBuf.WKSTA_INFO_100 = #Null
If NetWkstaGetInfo(#Null, Level, @*WkstaBuf) = #NERR_Success
comp$ = PeekS(*WkstaBuf\wki100_computername, -1, #PB_Unicode)
Else
comp$ = "Could not get local computer name due to error"
EndIf
NetApiBufferFree(*WkstaBuf)
ProcedureReturn comp$
EndProcedure
Procedure Ipv6PingConnectTest(DestinationIPAddress$)
Protected ICMPV6Sucess.b
Protected senddatastrng$, compname$, resolvestr$, addrbuf.s, host_name.s, errmsg$
Protected send_data_size.i, replySize.i, try_timeout.i
*LocalComp.sockaddr_in6 = #Null
*Destination.sockaddr_in6 = #Null
*Resolve.sockaddr_in6 = #Null
*LocalComp.sockaddr_in6 = AllocateMemory(SizeOf(sockaddr_in6))
*Destination.sockaddr_in6 = AllocateMemory(SizeOf(sockaddr_in6))
*Resolve.sockaddr_in6 = AllocateMemory(SizeOf(sockaddr_in6))
*Resolve\sin6_family = #AF_INET6
senddatastrng$ = "HELLO"
*requestData.c = AllocateMemory(#REQUEST_DATA_SIZE)
*prequestData = *requestData
CopyMemoryString(@senddatastrng$, @*prequestData)
CompilerIf #PB_Compiler_Unicode
send_data_size = StringByteLength(PeekS(*requestData)) + 2
CompilerElse
send_data_size = StringByteLength(PeekS(*requestData)) + 1
CompilerEndIf
If send_data_size <= #DEFAULT_SEND_SIZE
replySize = #DEFAULT_BUFFER_SIZE
Else
replySize = #MAX_BUFFER_SIZE
EndIf
*ReplyBuffer.c = AllocateMemory(replySize)
*icmpEcho.ICMPV6_ECHO_REPLY = *ReplyBuffer
try_timeout = 5000;#DEFAULT_TIMEOUT ; in milliseconds
;; ; the destination address *************************
*dest_result.ADDRINFOEX = #Null
hints.ADDRINFOEX
ZeroMemory(@hints, SizeOf(hints))
hints\ai_family = #AF_INET6
hints\ai_socktype = #SOCK_STREAM
; if using GetAddrInfoEx then must use FreeAddrInfoEx to free
res_getaddrinfo = GetAddrInfoEx(@DestinationIPAddress$, #Null, #NS_DNS, #Null, @hints, @*dest_result, #Null, #Null, #Null, #Null)
; can also use > getaddrinfo(@DestinationIPAddress$, #Null, @hints, @*dest_result)
; if using getaddrinfo then must use FreeAddrInfo to free
If res_getaddrinfo > #NO_ERROR
FreeAddrInfoEx(*dest_result)
FreeMemory(*LocalComp)
FreeMemory(*Destination)
FreeMemory(*Resolve)
ProcedureReturn -2
EndIf
*Destination\sin6_family = #AF_INET6
*Destination\sin6_port = 0
*Destination\sin6_addr = *dest_result\ai_addr\sin6_addr
;**************************************************************
Icmp6File = Icmp6CreateFile()
If Icmp6File = #INVALID_HANDLE_VALUE
FreeAddrInfoEx(*dest_result)
FreeMemory(*LocalComp)
FreeMemory(*Destination)
FreeMemory(*Resolve)
ProcedureReturn #INVALID_HANDLE_VALUE
EndIf
numberOfReplies = Icmp6SendEcho2(Icmp6File, #Null, #Null, #Null, *LocalComp, *Destination, *requestData, send_data_size, #Null, *ReplyBuffer, replySize, try_timeout)
icmp6parse = Icmp6ParseReplies(*ReplyBuffer, SizeOf(*ReplyBuffer))
If numberOfReplies > 0 And icmp6parse = 1
ICMPV6Sucess = #True
Else
ICMPV6Sucess = #False
EndIf
Select WSAGetLastError()
Case 0
errmsg$ = "Success"
Case 1231
errmsg$ = "The network location cannot be reached"
Case 11001
errmsg$ = "Buffer Too Small"
Case 11002
errmsg$ = "Destination Net Unreachable"
Case 11003
errmsg$ = "Destination Host Unreachable"
Case 11004
errmsg$ = "Destination Protocol Unreachable"
Case 11005
errmsg$ = "Destination Port Unreachable"
Case 11006
errmsg$ = "No Resources"
Case 11007
errmsg$ = "Bad Option"
Case 11008
errmsg$ = "Hardware Error"
Case 11009
errmsg$ = "Packet Too Big"
Case 11010
errmsg$ = "Request Timed Out"
Case 11011
errmsg$ = "Bad Request"
Case 11012
errmsg$ = "Bad Route"
Case 11013
errmsg$ = "TimeToLive Expired Transit"
Case 11014
errmsg$ = "TimeToLive Expired Reassembly"
Case 11015
errmsg$ = "Parameter Problem"
Case 11016
errmsg$ = "Source Quench"
Case 11017
errmsg$ = "Option Too Big"
Case 11018
errmsg$ = "Negotiating IPSEC"
Case 11050
errmsg$ = "General Failure"
Default
errmsg$ = "Unknown Status or Failure"
EndSelect
Debug "IPv6 address ping tested = " + DestinationIPAddress$
addrbuf = Space(#INET6_ADDRSTRLEN)
InetNtop(#AF_INET6, @*icmpEcho\Address\sin6_addr, @addrbuf, #INET6_ADDRSTRLEN)
compname$ = GetCompName()
Debug "IPv6 responding address = " + addrbuf
InetPton(#AF_INET6, @addrbuf, *Resolve\sin6_addr) ; put addrbuf text address representation of address that responded to ping in *Resolve structure
host_name = Space(#NI_MAXHOST)
getresolveinfo = getnameinfo(*Resolve, SizeOf(sockaddr_in6), @host_name, #NI_MAXHOST, #Null, #Null, 0) ; get the host name
If getresolveinfo = 0
resolvestr$ = "IPv6 responding resolves to = "
Else
resolvestr$ = "IPv6 responding address could not be resolved = "
EndIf
If FindString(host_name, compname$, 1) = 1
host_name = host_name + " (local computer)"
EndIf
Debug resolvestr$ + host_name
Debug "Ping Status = " + errmsg$
addrbuf = ""
host_name = ""
; **********************************************************************
IcmpCloseHandle_(Icmp6File)
FreeAddrInfoEx(*dest_result)
FreeMemory(*LocalComp)
FreeMemory(*Destination)
FreeMemory(*Resolve)
ProcedureReturn ICMPV6Sucess
EndProcedure
LoadLibraries()
wVersionRequested.w = MAKEWORD(2,2)
WSAStart.i = WSAStartup(wVersionRequested,@wsaData.WSADATA)
Debug "**********************************************************"
Debug Ipv6PingConnectTest("2620:0:1cfe:face:b00c::3") ; facebook ipv6 hex address
Debug "**********************************************************"
Debug Ipv6PingConnectTest("www.v6.facebook.com") ; facebook named Ipv6 address
Debug "**********************************************************"
Debug Ipv6PingConnectTest("www.facebook.com") ; set up for both Ipv6 and Ipv4
Debug "**********************************************************"
Debug Ipv6PingConnectTest("www.google.com") ; set up for both Ipv6 and Ipv4
Debug "**********************************************************"
Debug Ipv6PingConnectTest("::1") ; test to local loopback IPv6 address
Debug "**********************************************************"
Debug Ipv6PingConnectTest("::3") ; intentional test to failure
Debug "**********************************************************"
WSACleanup()
If Lib_iphlpapi : CloseLibrary(Lib_iphlpapi) : EndIf
If Lib_Kernel32 : CloseLibrary(Lib_Kernel32) : EndIf
If Lib_Winsock : CloseLibrary(Lib_Winsock) : EndIf
If Lib_Netapi32 : CloseLibrary(Lib_Netapi32) : EndIf
Edit note: Updated the code from previous post