pizarro
asked on
VB or C++ -How to find out country of origin?
hello,
I need to write a CGI script that determines what country the user comes from. For example, If a user in Germany runs the CGI script, the CGI script would be able to tell that that person comes from Germany. I know that the IP address of the user is passed as an environmental variable, but how to make the jump to the actual domain name and/or country?
The CGI script can be in any language, but preferably in VB, C/C++, and/or Pearl.
Please help!!!
I need to write a CGI script that determines what country the user comes from. For example, If a user in Germany runs the CGI script, the CGI script would be able to tell that that person comes from Germany. I know that the IP address of the user is passed as an environmental variable, but how to make the jump to the actual domain name and/or country?
The CGI script can be in any language, but preferably in VB, C/C++, and/or Pearl.
Please help!!!
ASKER
This might get the domain name but some domain names don't indicate what the country actually is. Also, I could not find any reference for the gethostbyaddress function and the h_name structure.
The domain is the only easy way to guess the country, and even then often you can't tell or the information is unreliable. The information as to what country the user is in simply isn't sent to the web server, and there's no master database anywhere where you can look it up. You can often manually tell by doing a traceroute to look at the name of routers are upsteam of the final IP address, but there's no fixed naming convention so this can't be done automatically.
Domain isn't completely reliable, but it's the best you have.
Domain isn't completely reliable, but it's the best you have.
ASKER
I now agree that the domain will be the only information I will be able to use. But I still could not get the API functions above to work.
I have some code for VB5 that uses GetHostByName, I think I could modify it to use GetHostByAddr. It's pretty tricky because you need to initialize the winsock properly. I would be willing to make the changes and post the full code if you'll agree to accept the answer if it works.
Or perl would be much easier, actually, when I posted that I reread the question and saw perl would be Ok. It's much easier in perl because perl does the setup for you. Take your pick.
ASKER
If it works I will accept it for sure. Even if it quite doesn't work but I feel it gave me a good lead I will accept it.
ASKER CERTIFIED SOLUTION
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
And of course, since you asked about country, from the top level domain:
($TopLevelDomain) = $hostname =~/\.(.*?)$/;
print "Top level domain: $TopLevelDomain\n";
($TopLevelDomain) = $hostname =~/\.(.*?)$/;
print "Top level domain: $TopLevelDomain\n";
oops, ignore my last comment, the regexp is bad, I don't know what I was thinking. Here's a full script (since you originally asked for a script):
use Socket;
print "Content-type: text/plain\n\n";
$ipnum = inet_aton($ENV{REMOTE_ADDR });
$hostname = gethostbyaddr($ipnum, AF_INET);
print "Your IP address is $ENV{REMOTE_ADDR}\n";
print "You are at $hostname\n";
($TopLevelDomain) = $hostname =~/\.([^.]+)$/;
print "Your top level domain is $TopLevelDomain\n";
use Socket;
print "Content-type: text/plain\n\n";
$ipnum = inet_aton($ENV{REMOTE_ADDR
$hostname = gethostbyaddr($ipnum, AF_INET);
print "Your IP address is $ENV{REMOTE_ADDR}\n";
print "You are at $hostname\n";
($TopLevelDomain) = $hostname =~/\.([^.]+)$/;
print "Your top level domain is $TopLevelDomain\n";
ASKER
Can you post the VB code? I don't like using perl on Windows NT servers...
I went ahead and wrote the program in VB to turn an IP address into a hostname, you can figure out how to make it into a CGI:
Private Const WS_VERSION_REQD = &H101
Private Const WS_VERSION_MAJOR = WS_VERSION_REQD \ &H100 And &HFF&
Private Const WS_VERSION_MINOR = WS_VERSION_REQD And &HFF&
Private Const MIN_SOCKETS_REQD = 1
Private Const SOCKET_ERROR = -1
Private Const WSADescription_Len = 256
Private Const WSASYS_Status_Len = 128
Private Const AF_INET = 2
Private Type HOSTENT
hName As Long
hAliases As Long
hAddrType As Integer
hLength As Integer
hAddrList As Long
End Type
Private Type WSADATA
wversion As Integer
wHighVersion As Integer
szDescription(0 To WSADescription_Len) As Byte
szSystemStatus(0 To WSASYS_Status_Len) As Byte
iMaxSockets As Integer
iMaxUdpDg As Integer
lpszVendorInfo As Long
End Type
Private Declare Function WSAGetLastError Lib "WSOCK32.DLL" () As Long
Private Declare Function WSAStartup Lib "WSOCK32.DLL" (ByVal wVersionRequired&, lpWSAData As WSADATA) As Long
Private Declare Function WSACleanup Lib "WSOCK32.DLL" () As Long
Private Declare Sub RtlMoveMemory Lib "KERNEL32" (hpvDest As Any, ByVal hpvSource&, ByVal cbCopy&)
Private Declare Function inet_addr Lib "WSOCK32.DLL" (ByVal ipnum As String) As Long
Private Declare Function gethostbyaddr Lib "WSOCK32.DLL" (ipnum As Long, ByVal iplen As Long, ByVal iptype As Long) As Long
Private Sub Command1_Click()
host$ = GetHostByAddress("207.114. 128.129")
Debug.Print host$
End Sub
Public Function GetHostByAddress(ipnum As String) As String
Dim hostname As String
Dim host As HOSTENT
Dim hostip_addr As Long
Dim hostent_addr As Long
SocketsInitialize
hostip_addr = inet_addr(ipnum)
hostent_addr = gethostbyaddr(hostip_addr, 4, AF_INET)
If hostent_addr = 0 Then
MsgBox "Winsock.dll is not responding."
Exit Function
End If
RtlMoveMemory host, hostent_addr, LenB(host)
hostname = Space$(256)
RtlMoveMemory ByVal hostname, host.hName, LenB(hostname)
If InStr(hostname, Chr$(0)) Then hostname = Left$(hostname, InStr(hostname, Chr$(0)) - 1)
SocketsCleanup
GetHostByAddress = hostname
End Function
Function hibyte(ByVal wParam As Integer)
hibyte = wParam \ &H100 And &HFF&
End Function
Function lobyte(ByVal wParam As Integer)
lobyte = wParam And &HFF&
End Function
Sub SocketsInitialize()
Dim WSAD As WSADATA
Dim iReturn As Integer
Dim sLowByte As String, sHighByte As String, sMsg As String
iReturn = WSAStartup(WS_VERSION_REQD , WSAD)
If iReturn <> 0 Then
MsgBox "Winsock.dll is not responding."
End
End If
If lobyte(WSAD.wversion) < WS_VERSION_MAJOR Or (lobyte(WSAD.wversion) = WS_VERSION_MAJOR And hibyte(WSAD.wversion) < WS_VERSION_MINOR) Then
sHighByte = Trim$(Str$(hibyte(WSAD.wve rsion)))
sLowByte = Trim$(Str$(lobyte(WSAD.wve rsion)))
sMsg = "Windows Sockets version " & sLowByte & "." & sHighByte
sMsg = sMsg & " is not supported by winsock.dll "
MsgBox sMsg
End
End If
If WSAD.iMaxSockets < MIN_SOCKETS_REQD Then
sMsg = "This application requires a minimum of "
sMsg = sMsg & Trim$(Str$(MIN_SOCKETS_REQ D)) & " supported sockets."
MsgBox sMsg
End
End If
End Sub
Sub SocketsCleanup()
Dim lReturn As Long
lReturn = WSACleanup()
If lReturn <> 0 Then
MsgBox "Socket error " & Trim$(Str$(lReturn)) & " occurred in Cleanup "
End
End If
End Sub
Private Const WS_VERSION_REQD = &H101
Private Const WS_VERSION_MAJOR = WS_VERSION_REQD \ &H100 And &HFF&
Private Const WS_VERSION_MINOR = WS_VERSION_REQD And &HFF&
Private Const MIN_SOCKETS_REQD = 1
Private Const SOCKET_ERROR = -1
Private Const WSADescription_Len = 256
Private Const WSASYS_Status_Len = 128
Private Const AF_INET = 2
Private Type HOSTENT
hName As Long
hAliases As Long
hAddrType As Integer
hLength As Integer
hAddrList As Long
End Type
Private Type WSADATA
wversion As Integer
wHighVersion As Integer
szDescription(0 To WSADescription_Len) As Byte
szSystemStatus(0 To WSASYS_Status_Len) As Byte
iMaxSockets As Integer
iMaxUdpDg As Integer
lpszVendorInfo As Long
End Type
Private Declare Function WSAGetLastError Lib "WSOCK32.DLL" () As Long
Private Declare Function WSAStartup Lib "WSOCK32.DLL" (ByVal wVersionRequired&, lpWSAData As WSADATA) As Long
Private Declare Function WSACleanup Lib "WSOCK32.DLL" () As Long
Private Declare Sub RtlMoveMemory Lib "KERNEL32" (hpvDest As Any, ByVal hpvSource&, ByVal cbCopy&)
Private Declare Function inet_addr Lib "WSOCK32.DLL" (ByVal ipnum As String) As Long
Private Declare Function gethostbyaddr Lib "WSOCK32.DLL" (ipnum As Long, ByVal iplen As Long, ByVal iptype As Long) As Long
Private Sub Command1_Click()
host$ = GetHostByAddress("207.114.
Debug.Print host$
End Sub
Public Function GetHostByAddress(ipnum As String) As String
Dim hostname As String
Dim host As HOSTENT
Dim hostip_addr As Long
Dim hostent_addr As Long
SocketsInitialize
hostip_addr = inet_addr(ipnum)
hostent_addr = gethostbyaddr(hostip_addr,
If hostent_addr = 0 Then
MsgBox "Winsock.dll is not responding."
Exit Function
End If
RtlMoveMemory host, hostent_addr, LenB(host)
hostname = Space$(256)
RtlMoveMemory ByVal hostname, host.hName, LenB(hostname)
If InStr(hostname, Chr$(0)) Then hostname = Left$(hostname, InStr(hostname, Chr$(0)) - 1)
SocketsCleanup
GetHostByAddress = hostname
End Function
Function hibyte(ByVal wParam As Integer)
hibyte = wParam \ &H100 And &HFF&
End Function
Function lobyte(ByVal wParam As Integer)
lobyte = wParam And &HFF&
End Function
Sub SocketsInitialize()
Dim WSAD As WSADATA
Dim iReturn As Integer
Dim sLowByte As String, sHighByte As String, sMsg As String
iReturn = WSAStartup(WS_VERSION_REQD
If iReturn <> 0 Then
MsgBox "Winsock.dll is not responding."
End
End If
If lobyte(WSAD.wversion) < WS_VERSION_MAJOR Or (lobyte(WSAD.wversion) = WS_VERSION_MAJOR And hibyte(WSAD.wversion) < WS_VERSION_MINOR) Then
sHighByte = Trim$(Str$(hibyte(WSAD.wve
sLowByte = Trim$(Str$(lobyte(WSAD.wve
sMsg = "Windows Sockets version " & sLowByte & "." & sHighByte
sMsg = sMsg & " is not supported by winsock.dll "
MsgBox sMsg
End
End If
If WSAD.iMaxSockets < MIN_SOCKETS_REQD Then
sMsg = "This application requires a minimum of "
sMsg = sMsg & Trim$(Str$(MIN_SOCKETS_REQ
MsgBox sMsg
End
End If
End Sub
Sub SocketsCleanup()
Dim lReturn As Long
lReturn = WSACleanup()
If lReturn <> 0 Then
MsgBox "Socket error " & Trim$(Str$(lReturn)) & " occurred in Cleanup "
End
End If
End Sub
ASKER
thanks.
Check win32 help for detail about these APIs (winsock API).