Resolve Ipv6 or Ipv4 URL to IP addresses and hosts

Share your advanced PureBasic knowledge/code with the community.
SFSxOI
Addict
Addict
Posts: 2970
Joined: Sat Dec 31, 2005 5:24 pm
Location: Where ya would never look.....

Resolve Ipv6 or Ipv4 URL to IP addresses and hosts

Post by SFSxOI »

The old tried and true API's like the 'gethostbyname' and 'gethostbyaddr' functions are now depreciated in favor of newer API's available in Vista and above, a lot of older IPv4 only API functions will probably vanish completly in a near furture version of Windows (some will go away in Windows 9). Ipv6 is a reality, operating systems are changing, time to get that older code using older API and based upon IPv4 (which is what the current version of Purebasic is based upon for some of its network or internet related functions) updated.

The below is a basic short example that resolves an IPv6 or IPv4 URL address to an IP address and also provides the host for that resolved IP address. If URL entered is an IPv4 address the familiar dotted-decimal IP address is given, for a IPv6 URL the IPv6 hexidecimal Ip address is given, along with the hosts (reverse DNS) for the resolved IP address. For Windows Vista and up (winsock version 2.2), tested mostly with and originally intended for Windows 7 and Windows 8.

Code: Select all

Prototype PGetAddrInfoEx(pName, pServiceName, dwNameSpace, lpNspId, pHints, ppResult, timeout, lpOverlapped, lpCompletionRoutine, lpNameHandle)
Prototype PWSAStartup(wVersionRequested, lpWSAData)
Prototype PWSACleanup()
Prototype PFreeAddrInfoEx(ai)
Prototype PRtlZeroMemory(mem, sze)
Prototype Pgetnameinfo(sa, salen, host, hostlen, serv, servlen, flags)
Prototype PInetNtop(Family, pAddr, pStringBuf, StringBufSize)

Global GetAddrInfoEx.PGetAddrInfoEx
Global WSAStartup.PWSAStartup
Global WSACleanup.PWSACleanup
Global FreeAddrInfoEx.PFreeAddrInfoEx
Global ZeroMemory.PRtlZeroMemory
Global getnameinfo.Pgetnameinfo
Global InetNtop.PInetNtop

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 ADDRINFOEX ;->Structure ADDRINFOEX
  ai_flags.i
  ai_family.i
  ai_socktype.i
  ai_protocol.i
  ai_addrlen.i
  *ai_canonname 
  *ai_addr.SOCKET_ADDRESS
  *ai_blob
  ai_bloblen.i
  ai_provider.l
  *ai_next.ADDRINFOEX
EndStructure

#AF_INET6 = 23
#INET6_ADDRSTRLEN = 65
#INET_ADDRSTRLEN = 22
#NS_DNS = 12
#NI_MAXHOST = 1025

Procedure LoadLibraries()
  Global Lib_Winsock.l, Lib_Kernel32.l
    
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")
  CompilerIf #PB_Compiler_Unicode ; if compiled in unicode use this
    FreeAddrInfoEx.PFreeAddrInfoEx=GetFunction(Lib_Winsock,"FreeAddrInfoExW")
    GetAddrInfoEx.PGetAddrInfoEx=GetFunction(Lib_Winsock,"GetAddrInfoExW")
    getnameinfo.Pgetnameinfo=GetFunction(Lib_Winsock,"GetNameInfoW")
    InetNtop.PInetNtop=GetFunction(Lib_Winsock,"InetNtopW")
  CompilerElse ; if not compiled in unicode use this
    FreeAddrInfoEx.PFreeAddrInfoEx=GetFunction(Lib_Winsock,"FreeAddrInfoEx")
    GetAddrInfoEx.PGetAddrInfoEx=GetFunction(Lib_Winsock,"GetAddrInfoExA")
    getnameinfo.Pgetnameinfo=GetFunction(Lib_Winsock,"getnameinfo")
    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
EndProcedure

Macro MAKEWORD(a, b)
  (a & $FF)|((b & $FF)<<8)
EndMacro

Procedure.s GetIPFromURL(ip$)
  Protected hints.ADDRINFOEX, *res.ADDRINFOEX, *p.ADDRINFOEX
  Protected ipstr.s, inurl$ = ip$
  
  ZeroMemory(@hints, SizeOf(hints))
  hints\ai_family = #AF_UNSPEC 
  hints\ai_socktype = #SOCK_STREAM
  status.i = GetAddrInfoEx(@inurl$, #Null, #NS_DNS, #Null, @hints, @*res, #Null, #Null, #Null, #Null)
  If status > #NO_ERROR
    FreeAddrInfoEx(*res)
    ProcedureReturn Str(0)
  EndIf
  *p=*res
  If *p\ai_family = #AF_INET
    *ipv4.sockaddr_in = *p\ai_addr
    *addr = @*ipv4\sin_addr
    ipstr_spc.i = #INET_ADDRSTRLEN
    host_name.s = Space(#NI_MAXHOST)
    getnameinfo(*p\ai_addr, SizeOf(sockaddr_in), @host_name, #NI_MAXHOST, #Null, #Null, 0)
    ipver$ = "IPv4"
  ElseIf *p\ai_family = #AF_INET6
    *ipv6.sockaddr_in6  = *p\ai_addr
    *addr = *ipv6\sin6_addr
    ipstr_spc.i = #INET6_ADDRSTRLEN
    host_name.s = Space(#NI_MAXHOST)
    getnameinfo(*p\ai_addr, SizeOf(sockaddr_in6), @host_name, #NI_MAXHOST, #Null, #Null, 0)
    ipver$ = "IPv6"
  EndIf
  ipstr.s = Space(ipstr_spc)
  InetNtop(*p\ai_family, *addr, @ipstr, Len(ipstr))
  FreeAddrInfoEx(*res)
  ProcedureReturn "Address entered was : " + inurl$ + " - The " + ipver$ + " address is : " + ipstr + " - which resolves to host name : " + host_name
  
EndProcedure

LoadLibraries()
wVersionRequested.w = MAKEWORD(2,2)
WSAStart.i = WSAStartup(wVersionRequested,@wsaData.WSADATA)

Debug GetIPFromURL("www.v6.facebook.com")
Debug GetIPFromURL("ipv6.google.com")
Debug GetIPFromURL("www.google.com")
Debug GetIPFromURL("www.purebasic.com")
Debug GetIPFromURL("2620:0:1cfe:face:b00c::3")
Debug GetIPFromURL("74.125.130.106")

WSACleanup()
If Lib_Winsock : CloseLibrary(Lib_Winsock) : EndIf
If Lib_Kernel32 : CloseLibrary(Lib_Kernel32) : EndIf
The advantage of a 64 bit operating system over a 32 bit operating system comes down to only being twice the headache.
rsts
Addict
Addict
Posts: 2736
Joined: Wed Aug 24, 2005 8:39 am
Location: Southwest OH - USA

Re: Resolve Ipv6 or Ipv4 URL to IP addresses and hosts

Post by rsts »

Needed something like this and here it is :)

Thanks for sharing.
User avatar
Zebuddi123
Enthusiast
Enthusiast
Posts: 794
Joined: Wed Feb 01, 2012 3:30 pm
Location: Nottinghamshire UK
Contact:

Re: Resolve Ipv6 or Ipv4 URL to IP addresses and hosts

Post by Zebuddi123 »

Hi SFSxOI Great work thanks for sharing :D

I have converted it for my use as a pb lib with some error checking, loading libraries returns -1 if fails. not sure if ive done enough but still a beginner and learning (the best part) so i`ll post the .res & .lib section case anyone wants it. only tested on w7 ult and works fine :shock: :lol:

ResolveIP_res.pb

Code: Select all

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 ADDRINFOEX ;->Structure ADDRINFOEX
	ai_flags.i
	ai_family.i
	ai_socktype.i
	ai_protocol.i
	ai_addrlen.i
	*ai_canonname 
	*ai_addr.SOCKET_ADDRESS
	*ai_blob
	ai_bloblen.i
	ai_provider.l
	*ai_next.ADDRINFOEX
EndStructure

#AF_INET6 = 23
#INET6_ADDRSTRLEN = 65
#INET_ADDRSTRLEN = 22
#NS_DNS = 12
#NI_MAXHOST = 1025

Macro MAKEWORD(a, b)
	(a & $FF)|((b & $FF)<<8)
EndMacro


ResolveIP_lib.pb

Code: Select all

Prototype PGetAddrInfoEx(pName, pServiceName, dwNameSpace, lpNspId, pHints, ppResult, timeout, lpOverlapped, lpCompletionRoutine, lpNameHandle)
Prototype PWSAStartup(wVersionRequested, lpWSAData)
Prototype PWSACleanup()
Prototype PFreeAddrInfoEx(ai)
Prototype PRtlZeroMemory(mem, sze)
Prototype Pgetnameinfo(sa, salen, host, hostlen, serv, servlen, flags)
Prototype PInetNtop(Family, pAddr, pStringBuf, StringBufSize)

Global GetAddrInfoEx.PGetAddrInfoEx
Global WSAStartup.PWSAStartup
Global WSACleanup.PWSACleanup
Global FreeAddrInfoEx.PFreeAddrInfoEx
Global ZeroMemory.PRtlZeroMemory
Global getnameinfo.Pgetnameinfo
Global InetNtop.PInetNtop


Procedure.i LoadLibraries()
	Global Lib_Winsock.l, Lib_Kernel32.l
	
	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")
		CompilerIf #PB_Compiler_Unicode ; if compiled in unicode use this
			FreeAddrInfoEx.PFreeAddrInfoEx=GetFunction(Lib_Winsock,"FreeAddrInfoExW")
			GetAddrInfoEx.PGetAddrInfoEx=GetFunction(Lib_Winsock,"GetAddrInfoExW")
			getnameinfo.Pgetnameinfo=GetFunction(Lib_Winsock,"GetNameInfoW")
			InetNtop.PInetNtop=GetFunction(Lib_Winsock,"InetNtopW")
		CompilerElse ; if not compiled in unicode use this
			FreeAddrInfoEx.PFreeAddrInfoEx=GetFunction(Lib_Winsock,"FreeAddrInfoEx")
			GetAddrInfoEx.PGetAddrInfoEx=GetFunction(Lib_Winsock,"GetAddrInfoExA")
			getnameinfo.Pgetnameinfo=GetFunction(Lib_Winsock,"getnameinfo")
			InetNtop.PInetNtop=GetFunction(Lib_Winsock,"inet_ntop")
		CompilerEndIf
	Else
		ProcedureReturn -1
	EndIf
	
	Lib_Kernel32 = OpenLibrary(#PB_Any,"Kernel32.dll")
	If IsLibrary(Lib_Kernel32)<> 0
		ZeroMemory.PRtlZeroMemory=GetFunction(Lib_Kernel32,"RtlZeroMemory")
	Else
		ProcedureReturn  -1
	EndIf
	ProcedureReturn 1
EndProcedure

Procedure.b Init_GetIP()
	If LoadLibraries()
		wVersionRequested.w = MAKEWORD(2,2)
		WSAStart.i = WSAStartup(wVersionRequested,@wsaData.WSADATA)
	Else
		ProcedureReturn  -1
	EndIf
	ProcedureReturn 1
EndProcedure


Procedure GetIP_CleanUP()
	WSACleanup()
	
	If Lib_Winsock 
		CloseLibrary(Lib_Winsock) 
	EndIf 
	
	If Lib_Kernel32
		CloseLibrary(Lib_Kernel32) 
	EndIf
	
EndProcedure


ProcedureDLL.s GetIPFromURL(ip$) ;Returns Resolved IP$ else returns -1 as a string if library load error
	If Init_GetIP()
		Debug "searching for ip address "+ip$
		Protected hints.ADDRINFOEX, *res.ADDRINFOEX, *p.ADDRINFOEX
		Protected ipstr.s, inurl$ = ip$
		
		ZeroMemory(@hints, SizeOf(hints))
		hints\ai_family = #AF_UNSPEC 
		hints\ai_socktype = #SOCK_STREAM
		status.i = GetAddrInfoEx(@inurl$, #Null, #NS_DNS, #Null, @hints, @*res, #Null, #Null, #Null, #Null)
		If status > #NO_ERROR
			FreeAddrInfoEx(*res)
			ProcedureReturn Str(0)
		EndIf
		*p=*res
		If *p\ai_family = #AF_INET
			*ipv4.sockaddr_in = *p\ai_addr
			*addr = @*ipv4\sin_addr
			ipstr_spc.i = #INET_ADDRSTRLEN
			host_name.s = Space(#NI_MAXHOST)
			getnameinfo(*p\ai_addr, SizeOf(sockaddr_in), @host_name, #NI_MAXHOST, #Null, #Null, 0)
			ipver$ = "IPv4"
		ElseIf *p\ai_family = #AF_INET6
			*ipv6.sockaddr_in6  = *p\ai_addr
			*addr = *ipv6\sin6_addr
			ipstr_spc.i = #INET6_ADDRSTRLEN
			host_name.s = Space(#NI_MAXHOST)
			getnameinfo(*p\ai_addr, SizeOf(sockaddr_in6), @host_name, #NI_MAXHOST, #Null, #Null, 0)
			ipver$ = "IPv6"
		EndIf
		ipstr.s = Space(ipstr_spc)
		InetNtop(*p\ai_family, *addr, @ipstr, Len(ipstr))
		FreeAddrInfoEx(*res)
		GetIP_CleanUP()
		ProcedureReturn "Address entered was : " + inurl$ + " - The " + ipver$ + " address is : " + ipstr + " - which resolves to host name : " + host_name
	Else
		ProcedureReturn  Str(-1)
	EndIf
EndProcedure
Example

Code: Select all

Restore tot : Read.i x 
Dim url.s(x)

Restore urls

For i=1 To x
	Read.s url(i)
	Debug GetIPFromURL(url(i))	
Next

DataSection
	tot:
	Data.i 5
	endtot:
	
	urls:
	Data.s "www.purebasic.com" , "www.google.com" , "www.popsci.com" , "176.234.12.34" , "74.125.130.106"
	endurls:
EndDataSection


Zebuddi. :)
malleo, caput, bang. Ego, comprehendunt in tempore
SFSxOI
Addict
Addict
Posts: 2970
Joined: Sat Dec 31, 2005 5:24 pm
Location: Where ya would never look.....

Re: Resolve Ipv6 or Ipv4 URL to IP addresses and hosts

Post by SFSxOI »

yes, the post is old, I know, but after getting an email from someone who was interested in this and saying it did not work when compiled 64 bit I realized i should have updated this post a longggg time ago.

The code I originally posted worked for 32 bit only. To make this work for both x64 and x86 purebasic compiles, change the ADDRINFOEX to this:

Code: Select all

Structure ADDRINFOEX ;->Structure ADDRINFOEX - works on both 64 and 32bit
  ai_flags.l
  ai_family.l
  ai_socktype.l
  ai_protocol.i
  ai_addrlen.l
  *ai_canonname
  *ai_addr.SOCKET_ADDRESS ; or use the SOCKADDR_STORAGE structure here, your choice, works with either one, SOCKADDR_STORAGE is the new recommended way to go.
  *ai_blob
  ai_bloblen.i
  ai_provider.i
  *ai_next.ADDRINFOEX
EndStructure

;;; if you need the SOCKADDR_STORAGE structure here it is:

Structure SOCKADDR_STORAGE
  ss_family.i
  __ss_pad1.c[6]
  __ss_align.q
  __ss_pad2.c[112]
EndStructure

The advantage of a 64 bit operating system over a 32 bit operating system comes down to only being twice the headache.
Armoured
Enthusiast
Enthusiast
Posts: 348
Joined: Mon Jan 26, 2004 11:39 am
Location: ITALY
Contact:

Re: Resolve Ipv6 or Ipv4 URL to IP addresses and hosts

Post by Armoured »

SFSxOI this code work to get the hostname of IP's in a LAN?
Post Reply