Useful socket methods
So far, you have gained knowledge of socket and client-server architecture. At this level, you can make a small program of networks. However, the aim of this book is to test the network and gather information. Python offers very beautiful as well as useful methods to gather information. First, import the socket and then use these methods:
- socket.gethostbyname(hostname): This method converts a hostname to the IPv4 address format. The IPv4 address is returned in the form of a string. Here is an example:
>>> import socket>>>
socket.gethostbyname('thapar.edu')'220.227.15.55'>>>>>>
socket.gethostbyname('google.com')'173.194.126.64'>>>
I know you are thinking about the nslookup command. Later, you will see more magic.
- socket.gethostbyname_ex(name): This method converts a hostname to the IPv4 address pattern. However, the advantage over the previous method is that it gives all the IP addresses of the domain name. It returns a tuple (hostname, canonical name, and IP_addrlist) where the hostname is given by us, the canonical name is a (possibly empty) list of canonical hostnames of the server for the same address, and IP_addrlist is a list of all of the available IP addresses of the same hostname. Often, one domain name is hosted on many IP addresses to balance the load of the server. Unfortunately, this method does not work for IPv6. I hope you are well-acquainted with tuples, lists, and dictionaries. Let's look at an example:
>>> socket.gethostbyname_ex('thapar.edu')('thapar.edu', [],
['14.139.242.100', '220.227.15.55'])>>>
socket.gethostbyname_ex('google.com')>>>('google.com', [],
['173.194.36.64', '173.194.36.71', '173.194.36.73',
'173.194.36.70',
'173.194.36.78', '173.194.36.66', '173.194.36.65',
'173.194.36.68',
'173.194.36.69', '173.194.36.72', '173.194.36.67'])>>>
It returns many IP addresses for a single domain name. This means that one domain such as thapar.edu or google.com runs on multiple IPs.
- socket.gethostname(): This returns the hostname of the system where the Python interpreter is currently running:
>>> socket.gethostname()'eXtreme'
To glean the current machine's IP address by using the socket module, you can use the following trick using gethostbyname(gethostname()):
>>> socket.gethostbyname(socket.gethostname())'192.168.10.1'>>>
You know that our computer has many interfaces. If you want to know the IP address of all of the interfaces, use the extended interface:.
>>> socket.gethostbyname_ex(socket.gethostname())('eXtreme', [],
['10.0.0.10', '192.168.10.1', '192.168.0.1'])>>>
It returns one tuple containing three elements, the first is the machine name, the second is a list of aliases for the hostname (empty, in this case,) and the third is the list of the IP addresses of interfaces.
- socket.getfqdn([name]): This is used to find the fully qualified domain name if it's available. The fully qualified domain name consists of a host and domain name; for example, beta might be the hostname, and example.com might be the domain name. The fully qualified domain name (FQDN) becomes beta.example.com:
>>> socket.getfqdn('facebook.com')'edge-star-shv-12-
frc3.facebook.com'
In the preceding example, edge-star-shv-12-frc3 is the hostname, and facebook.com is the domain name. In the following example, FQDN is not available for thapar.edu:
>>> socket.getfqdn('thapar.edu')'thapar.edu'
If the name argument is blank, it returns the current machine name:
>>> socket.getfqdn()'eXtreme'>>>
- socket.gethostbyaddr(ip_address): This is like a reverse lookup for the name. It returns a tuple (hostname, canonical name, and IP_addrlist) where hostname is the hostname that responds to the given ip_address, the canonical name is a (possibly empty) list of canonical names of the same address, and IP_addrlist is a list of IP addresses for the same network interface on the same host:
>>> socket.gethostbyaddr('173.194.36.71')('del01s06-in-
f7.1e100.net', [], ['173.194.36.71'])>>>
socket.gethostbyaddr('119.18.50.66')Traceback (most recent call
last): File "<pyshell#9>", line 1, in <module>
socket.gethostbyaddr('119.18.50.66')herror: [Errno 11004] host
not found
It shows an error in the last query because reverse DNS lookup is not present.
- socket.getservbyname(servicename[, protocol_name]): This converts any protocol name to the corresponding port number. The Protocol name is optional, either TCP or UDP. For example, the DNS service uses TCP as well as UDP connections. If the protocol name is not given, any protocol could match:
>>> import socket>>> socket.getservbyname('http')80>>>
socket.getservbyname('smtp','tcp')25>>>
- socket.getservbyport(port[, protocol_name]): This converts an internet port number to the corresponding service name. The protocol name is optional, either TCP or UDP:
>>> socket.getservbyport(80)'http'>>>
socket.getservbyport(23)'telnet'>>>
socket.getservbyport(445)'microsoft-ds'>>>
- socket.connect_ex(address): This method returns an error indicator. If successful, it returns 0; otherwise, it returns the errno variable. You can take advantage of this function to scan the ports. Run the connect_ex.py program:
import socket rmip ='127.0.0.1' portlist = [22,23,80,912,135,445,20] for port in portlist: sock= socket.socket(socket.AF_INET,socket.SOCK_STREAM) result = sock.connect_ex((rmip,port)) print port,":", result sock.close()
The output is shown in the following screenshot:
The preceding program output shows that ports 80 ,912 ,135 , and 445 are open. This is a rudimentary port scanner. The program is using the IP address 127.0.0.1; this is a loopback address, so it is impossible to have any connectivity issues. However, when you have issues, perform this on another device with a large port list. This time, you will have to use socket.settimeout(value):
socket.getaddrinfo(host, port[, family[, socktype[, proto[, flags]]]])
This socket method converts the host and port arguments into a sequence of five tuples.
Let's take a look at the following example:
>>> import socket >>> socket.getaddrinfo('www.thapar.edu', 'http') [(2, 1, 0, '', ('220.227.15.47', 80)), (2, 1, 0, '',
('14.139.242.100', 80))] >>>
Output 2 represents the family, 1 represents the socket type, 0 represents the protocol, '' represents the canonical name, and ('220.227.15.47', 80) represents the 2 socket address. However, this number is difficult to comprehend. Open the directory of the socket.
Use the following code to find the result in a readable form:
import socket def get_protnumber(prefix): return dict( (getattr(socket, a), a) for a in dir(socket) if a.startswith(prefix)) proto_fam = get_protnumber('AF_') types = get_protnumber('SOCK_') protocols = get_protnumber('IPPROTO_') for res in socket.getaddrinfo('www.thapar.edu', 'http'): family, socktype, proto, canonname, sockaddr = res print 'Family :', proto_fam[family] print 'Type :', types[socktype] print 'Protocol :', protocols[proto] print 'Canonical name:', canonname print 'Socket address:', sockaddr
The output of the code is shown in the following screenshot:
The upper part makes a dictionary using the AF_, SOCK_, and IPPROTO_ prefixes that map the protocol number to their names. This dictionary is formed by the list comprehension technique.
The upper part of the code might be confusing sometimes, but we can execute the code separately as follows:
>>> dict(( getattr(socket,n),n) for n in dir(socket) if
n.startswith('AF_')) {0: 'AF_UNSPEC', 2: 'AF_INET', 6: 'AF_IPX', 11: 'AF_SNA', 12:
'AF_DECnet', 16: 'AF_APPLETALK', 23: 'AF_INET6', 26: 'AF_IRDA'}
Now, this is easy to understand. This code is usually used to get the protocol number:
for res in socket.getaddrinfo('www.thapar.edu', 'http'):
The preceding line of code returns the five values, as discussed in the definition. These values are then matched with their corresponding dictionary.