Network Programming Notes reading _python 3 (4)

4. Sockets and DNS name

讨论网络地址,描述将主机名解析为原始IP地址的分布式服务

4.1. Hostname and socket

浏览器汇总一般键入域名。有些域名标识整个机构。如,python.org,而另一些指定了主机/服务。如,www.google.com/asaph.rhodesmill.org。访问一些站点时,可以使用主机名的缩写。如,asaph,站点会自动填充主机名剩余部分。无论已经在本地进行了任何自定义设置,使用包含了顶级域名及其他所有部分的完全限定域名(fully qualified domain name)总是正确无误的。

4.1.0 top-level domain (TLD):. Either a .com, .net, .org, .gov, .mil, or it is an internationally recognized two-letter country code. Now there with more top-level domains, such as .beer, distinguishing it difficult.

4.1.0.1. Each TLD has its own server, run by the agency responsible for all domain authorization for the TLD. When registering a domain name, a corresponding entry will increase the organization's domain name in Serv. When the world is running on any one Cli hope to resolve belong to the domain name, top-Serv will go to the agency to request Cli own domain Serv. Institutions can create a variety of host name, return address corresponding. This name will be the name of the agency's top Serv maintain their name together. Around the world use the system query to the appropriate set of names Serv provides domain name service (DNS, Domain Name Service)

. 4.1.0.2 all need to provide some form of socket name as a parameter of the main socket methods:

4.1.0.2.1 mysocket.accept ():. Called by listening socket TCP stream. When ready to send a connection request to the program, the method is called. It returns a tuple, the second is connected to the remote address (the first term is the new connection to the remote address of socket)
4.1.0.2.2 mysocket.bind (address):. A ​​specific local address (a data packet to be sent source address) assigned to the socket. The other machine is to initiate a connection request, the address may be used as the address to be connected.
4.1.0.2.3 mysocket.connect (address):. Data transmitted through the socket will be transmitted to the specified remote address. For UDP, it just sets a default address. Such as the caller does not have to use sendto () and recvfrom () method, but the use of send () and recv (), it will use the default address. The process itself does not make any network communication operations immediately. For TCP, which will be with another machine via three-way handshake to establish a new stream, and throws an exception if the establishment fails Py.
4.1.0.2.4 mysocket.getpeername ():. Returns a connection to a remote socket address
4.1.0.2.5 mysocket.getsockname ():. Returned socket own local endpoint address
The source address for the UDP, returns a tuple comprises data string and returns the data:. 4.1.0.2.6 mysocket.recvfrom (...)
4.1.0.2.7 mysocket.sendto (data, address):. UDP-port is not connected to a particular remote address to send the wanted data.

4.1.1. 5 coordinates the socket

创建和部署每个socket对象,总共需要作出5个主要的决定,hostname和ip只是其中最后两个,创建及部署socket步骤如下:
import socket
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.bind(('127.0.0.1', 1060))
指定了4个值: 两个用来对socket做配置,另外两个提供bind()调用需要的ip。还有第5个坐标

4.1.1.1. Address family (address family) choice is the most important decision. A particular machine may be connected to a plurality of different types of networks. To choose the address family want to specify the type of network communication. Popular in the POSIX AF_UNIX address family, provides direct connection between programs running on the same machine, the connection is the file name, not the address of the host name and port number is.

4.1.1.2 socket type (socket type):. Want to use a particular communication technology is given on the network that has been selected. Although the UDP and TCP protocol suite AF_INET indeed unique, but the socket to create a more generic name SOCK_DGRAM based datagram socket, providing reliable data transfer and flow control flow is represented by SOCK_STREAM, just use two symbols is enough many agreements covering a large number of different protocol suite.

4.1.1.3. The third parameter is the protocol (Protocol), this parameter is seldom used, often do not specify this parameter, or set it to 0, it indicates the protocol is automatically selected. If you want to use the stream at the IP layer, select TCP. Want to use the datagram, select UDP. Practical applications, almost no.

4.1.1.4. IP

4.1.1.5. port

4.1.1.6. Socket were the reason why the hostname and port of two parts, because the specified coordinates socket of the first three, five coordinates, in fact, the new socket is necessary for three fixed coordinate, followed by the use of a specific address family any number of network connections needed to coordinate

4.1.2. IPv6

4.1.2.1. Another address family other than AF_INET, future mainstream address family -IPv6.32 bit addresses can only provide 4 billion IP, are not enough for everyone to provide IP, Py another program compatible IPv6, needs to be done very simple.

Py, you can be tested directly by checking the built-in socket has_ipv6 current platform supports IPv6, IPv6 does not represent actual configuration is complete and has been running, can be used to transmit data packets, and only indicate whether the OS to achieve IPv6 support, and whether IPv6 has been used has nothing to do.

In[63]: import socket
In[64]: socket.has_ipv6
Out[64]: True

. 4.1.2.2 IPv6 impact on Py code:

4.1.2.2.1. Use AF_INET6 to create a socket
4.1.2.2.2. Socket name not only IP and port composition, further comprising providing an additional coordinate "flow" of information and "scope" logo
Expressions 4.1.2.2.3. IPv6 contains a large number of colon, hexadecimal value

Compared to IPv4 achieve, IPv6 protocol link layer security for many features to provide a more complete support

4.2. Modern Address Resolution

Py-socket用户工具集最强大的工具之一---getaddrinfo():socket模块中涉及地址的众多操作之一,可能是将username和port转换为可供socket方法使用的地址时,所需的唯一方法。该方法能指明要创建的连接所需的一切已知信息,将返回全部坐标,这些坐标是创建并将socket连接至指定目标地址所必须的。
>>> import socket
>>> from pprint import pprint
>>> infolist = socket.getaddrinfo('gatech.edu', 'www')
>>> pprint(infolist)
[(2, 1, 6,'',('130.207.244.244', 80)),(2, 1, 17,'',('130.207.244.244', 80))]
>>> info = infolist[0]
>>> info[0:3]
(2, 1, 6)
>>> s = socket.socket(*info[0:3])
>>> info[4]
('130.207.244.244', 80)
>>> s.connect(info[4])

info variable contains a socket to create and use the socket to initiate a connection all the information needed. It provides the address family, type, protocol, canonical name, address information.
To provide getaddrinfo () the parameters of what?
Request is connected to the possible methods needed to provide HTTP service host gatech.edu, the return value is a list containing two elements. Return value that the two methods may be used to initiate the connection. May be used to create a IPPROTO_TCP go (code-named 6) SOCK_STREAM-socket (socket type 1), may also be used to create a IPPROTO_UDP (code 17) is SOCK_DGRAM (socket type 2) of the socket.

In 4.2.0. 3-2 to use such a real symbol AF_INET, clearly the underlying mechanism of the socket while the production environment of code unless Py To getaddrinfo () indicates that the row ah To address type, otherwise it will not be referenced socket any symbol module. The use getaddrinfo () returns the value 3 as a front socket () arguments to the constructor, the return value of 5 as an incoming address, the need for any call to socket address, such as connect ()

4.2.0.1. Getaddrinfo () provided in addition to allowing hostname, but also allows the provision WWW (not int) as the port name. If you want to use such a symbol www / smtp as the port, without the use of 80/25, we no longer need additional call before Py code.

如何使用getaddrinfo()来支持3种基本网络操作(绑定、连接、识别已经向我们发送信息的远程主机)

4.2.1. Use getaddrinfo () to bind to port Serv

想要得到一个地址,将其作为参数提供给bind(),原因可能是正在创建一个Serv-socket,也可能是希望Cli从一个可预计的地址连接至其他主机,此时可调用getaddrinfo(),将主机名设为None,但提供port与socket类型,如果某个字段为数字,可用0来表示通配符。
>>> from socket import getaddrinfo
>>> getaddrinfo(None, 'smtp', 0, socket.SOCK_STREAM, 0, socket.AI_PASSIVE)
[(2,1,6, '', ('0.0.0.0', 25)), (10, 1, 6, '', ('::', 25, 0, 0))]
>>> getaddrinfo(None, 53, 0, socket.SOCK_DGRAM, 0, socket.AI_PASSIVE)
[(10, 2, 17, '', ('::', 53, 0, 0)), (2, 2, 17, '', ('0.0.0.0', 53))]

We made two queries:
1) Use string as the port identifier -> wondering if SMTP uses TCP to support data transmission, should bind () to the address, if you want by bind () on the unit to a specific IP, should by bind () which address the socket is bound to, the query returns the answer is right wildcard address, that can be bound to any IPv4 and IPv6 interfaces on this machine. The need to provide the correct socket address family, socket type and protocol.
Conversely, if () is bound to a specific IP by native bind, and the configuration address, should be omitted AI_PASSIVE into, and to develop hostname.
2) using the original port number
or less of two ways can be used to try to bind to the localhost socket:

>>> getaddrinfo('127.0.0.1', 'smtp', 0, socket.SOCK_STREAM, 0)
[(<AddressFamily.AF_INET: 2>, <SocketKind.SOCK_STREAM: 1>, 0, '
', ('127.0.0.1', 25))]
>>> getaddrinfo('localhost', 'smtp', 0, socket.SOCK_STREAM, 0)
[(<AddressFamily.AF_INET6: 23>, <SocketKind.SOCK_STREAM: 1>,
0, '', ('::1', 25, 0, 0)), (<AddressFamily.AF_INET: 2>, <Sock
etKind.SOCK_STREAM: 1>, 0, '', ('127.0.0.1', 25))]

If the local host using the IPv4 address, IPv4 only initiated connection by receiving; If localhost, local name IPv4 / 6 on this machine can be used.

4.2.2. Use getaddrinfo () connected Serv

除了绑定本地IP自行提供服务外,还可使用getaddrinfo()获取连接到其他服务所需的信息。查询服务时,可使用一个空字符串表示要通过自环接口连接回本机,也可提供一个包含IPv4/6/主机名的字符串来指定目标地址

4.2.2.1. Call connect () / sendto () connected Serv / send data to Serv, call getaddrinfo (), and set AI_ADDRCONFIG mark, the computer will not connect all IP are filtered out.

1) For example, an organization might have both IP IPv4, but also the IP IPv6. If a particular host only supports IPv4, hope will result in a non-IPv4 filtered out.
2) Native IPv6 only, but only support IPv4 Serv connection, also need to specify AI_V4MAPPED, after specifying the tag, will be re-encoded as an IPv4 address IPv6 is actually used
to put together the above, obtained before the socket connector, using getaddrinfo () methods common

>>> getaddrinfo('ftp.kernel.org', 'ftp', 0, socket.SOCK_STREAM, 0, socket.AI_ADDRCONFIG | socket.AI_V4MAPPED)
[(2, 1, 5, '', ('204.152.191.37', 21)), (2, 1, 6, '', ('149.20.29.133', 21))]

Required information is obtained from the return value getaddrinfo () of: This is a list containing all the way through the TCP connection ftp.kernel.org FTP host port. The return value is included in the plurality of IP. For load balancing, the Serv deployed on a number of different IP. When a plurality of return addresses, a first IP should be used normally returned. Only the connection fails, just try the rest of the IP.

4.2.2.2. Another query, I want to know how to connect to the IANA HTTP interface by the query.

getaddrinfo('iana.org', 'www', 0, socket.SOCK_STREAM, 0, socket.AI_ADDRCONFIG | socket.AI_V4MAPPED)
[(<AddressFamily.AF_INET: 2>, <SocketKind.SOCK_STREAM: 1>, 0, '', ('192.0.43.8', 80))]

4.2.3. Use getaddrinfo () request canonical hostname

4.2.3.1. Need to know the other part of the official name of the host Ip, possibly because we are building a new link may be due to a Serv-socket just accepted a connection request. -> would pose a threat: to find the machine from the IP host name of the query, IP owners can make DNS queries return any value as a result, as google.com/python.org. When a request belonging to a certain IP hostname, IP owners want full control of the returned string

4.2.3.2. Because the query for canonical host name, IP will be mapped to a hostname, rather than to map the hostname to IP, so called discovery DNS queries. After obtaining hostname returned, must first review and confirm that it can be resolved to the original IP, in order to trust the result is returned.

The canonical host name of the query time-consuming, resulting in an extra round of global DNS queries, so when the log is often skipped. If a reverse lookup service will each host name with the corresponding IP, will make the connection response becomes extremely slow. Common practices OS-MA is the only IP logging, if an IP raises the question, can be found in the IP, corresponding hostname queries manually start the log file

4.2.3.2. Reverse lookup, set AI_CANONNAME as long as the run getaddrinfo (). Item 4 returns the tuple will contain canonical hostname.

>>> getaddrinfo('iana.org', 'www', 0, socket.SOCK_STREAM, 0, socket.AI_ADDRCONFIG | socket.AI_V4MAPPED | socket.AI_CANONNAME)
[(<AddressFamily.AF_INET: 2>, <SocketKind.SOCK_STREAM: 1>, 0, 'iana.org', ('192.0.43.8', 80))]

4.2.4. Other getaddrinfo () mark

4.2.4.1 AI_ALL:. If you want to see all pupil, the marker may be labeled with AI_V4MAPPED combine the returned list contains all known addresses corresponding to the target host on a host connected via IPv6

4.2.4.2 AI_NUMERICHOST:. Ban on the hostname parameter to cern.ch text parsing, only the hostname as IPv4 / 6 to resolve, such as 74.207.234.78/fe80::fcfd:4aff:fecf:ea4e. After setting faster, not DNS round-trip, the OS is untrusted user input control can prevent, avoid forcing query the name of the other party control of Serv

4.2.4.3 AI_NUMERICSERV:. Disabled www symbol in the form of port name, stick with the "80" port. On POSIX-OS, resolve a symbolic form of port, just a quick scan / etc / services file (need to check the service option /etc/nsswitch.conf file for confirmation)

4.2.4.4. Py detects string requires special coding mode, automatic conversion, Py contains a 'idna' codec, the conversion can be completed between the IDN

4.2.5 The original name of the service program

getaddrinfo()流行前,程序员通过OS支持的更简单的名称服务程序来进行socket的编程,多数是硬编码,只支持IPv4,应该避免使用这些程序。
1)socket模块的标准库页面找到相关的文档,有两个调用能返回当前机器的hostname
socket.gethostname()
'DESKTOP-S1A6RSJ'
socket.getfqdn()
'DESKTOP-S1A6RSJ'
2)还有两个能够对IPv4-hostname和IP进行相互转换
socket.gethostbyname('cern.ch')
'188.184.9.234'
socket.gethostbyaddr('188.184.9.234')
('webrlb01.cern.ch', [], ['188.184.9.234'])
3)有三个程序可以通过OS已知的符号名查询协议号及port
socket.getprotobyname('UDP')
17
socket.getservbyname('www')
80
socket.getservbyport(80)
'http'
4)想要获取Py的机器的主IP,可以将完全限定主机名传各gethostbyname()调用。
socket.gethostbyname(socket.getfqdn())
'192.168.137.1'

4.2.6. Tag used getsockaddr ()

# 4-1 www_ping.py
import argparse, socket, sys

def connect_to(hostname_or_ip):
    try:
        infolist = socket.getaddrinfo(
            hostname_or_ip, 'www', 0, socket.SOCK_STREAM, 0,
            socket.AI_ADDRCONFIG | socket.AI_V4MAPPED | socket.AI_CANONNAME,
        )
    except socket.gaierror as e:
        print('Name service failure:', e.args[1])
        sys.exit(1)

    info = infolist[0] # per standard recommendation, try the first one
    # print('info_{}'.format(info)) # info_(<AddressFamily.AF_INET: 2>, <SocketKind.SOCK_STREAM: 1>, 0, 'mit.edu', ('23.213.151.198', 80))
    socket_args = info[0:3]
    # print('socket_args_{}'.format(socket_args)) # socket_args_(<AddressFamily.AF_INET: 2>, <SocketKind.SOCK_STREAM: 1>, 0)
    address = info[4]
    # print('address_{}'.format(address)) # address_('23.213.151.198', 80)
    s = socket.socket(*socket_args)
    try:
        s.connect(address)
    except socket.error as e:
        print('Network failure:', e.args[1])
    else:
        print('Success: host', info[3], 'is listening on port 80')

if __name__ == '__main__':
    parser = argparse.ArgumentParser(description='Try connecting to port 80')
    parser.add_argument('hostname', help='hostname that you want to contact')
    connect_to(parser.parse_args().hostname)
>python www_ping.py mit.edu
Success: host mit.edu is listening on port 80
>python www_ping.py smtp.google.com
Name service failure: getaddrinfo failed
>python www_ping.py no-such-host.com
Name service failure: getaddrinfo failed
该脚本有3点值得注意:

4.2.6.1. The script is completely generic, no mention of using the IP protocol / TCP as a transport mode, if you enter a hostname is connected via AppleTalk, then getaddrinfo () will return the AppleTalk socket family, and protocol type, and ultimately create and connect the socket is the type of

4.2.6.2. Getaddrinfo () call will cause the failure of a particular name service error gaierror, rather than a socket error in the general network failure detection end of the script, resulting.

4.2.6.3. There are no incoming constructor socket three separate parameters, * passed in the parameter list, the list socket_args three elements are used as three separate parameters passed to the constructor. The return address is used as a separate unit, it passed all the required socket program.

4.3 DNS protocol: Domain Name System (DNS, Domain Name System) is an Internet hosts thousands of mutual cooperation, hostname and IP mapping to relational queries to make a mechanism for the response. Instead of remembering all this mechanism IP address 82.xx.xx.xx, DNS is behind the support.

DNS协议
目的: 解析hostname,返回IP地址
标准: RFC 1034与RFC 1035(1987)
传输层协议: UDP/IP与TCP/IP
端口号: 53
库: 第三方,包括dnspython3

To complete analytical information sent by the PC will traverse the hierarchy Serv composition. PC and Serv name may not resolve hostname. The reason is that neither the local hostname, and never visit in the near future and is still in the name of Serv cache. In this case, the need to query the name of a top-Serv in the world, responsible for obtaining DNS domain name queries, once returned to the DNS IP, can in turn access the IP, complete domain name queries
on how to start this operation

4.3.0. Www.python.org to this domain name, for example. If the browser needs to resolve the address, it will run a similar getaddrinfo () call, request the OS domain name resolution. OS itself know whether to run their own name Serv, whether the connected network will provide the name Serv.

4.3.0.1 PC is usually linked to the network via the DHCP, automatic configuration name Serv information is available through the company office LAN, it can also be through a wireless network / DSL connection to the network. OS-MA will manually configure the IP address of the DNS when setting up the machine. Whether the above that case, you must specify the DNS original IP, because the former can be connected to the DNS by other means, can not make any DNS queries.

4.3.0.2 again, DNS and performance provided by your ISP is not satisfied, it will configure itself a tripartite DNS, such as Google's 8.8.8.8 and 8.8.4.4, however, to name resolution, you must specify the DNS-Sevr

4.3.0.3 if not query the domain, PC also know that some of the hostname corresponding IP. When calling getaddrinfo (), in fact, the first thing to do is not think OS DNS query hostname, DNS query time-consuming, often the last option. OS before the hostname queries to DNS, queries from elsewhere.

4.3.0.4. Use POSIX-OS, depending on the file you want to query hosts entry in /etc/nsswitch.conf. Such as, Ubuntu, first check the / etc / hosts, will use a proprietary protocol multicast DNS as much as possible, only the operation fails / is not available, will enable full hostname DNS query to obtain the corresponding IP.

4.3.0.5. For Windows, depending on the control panel options.

4.3.0.6. Without www.python.org this domain on the local machine, not accessed within a sufficiently short time through the domain, the local cache of the browser is not the IP corresponding to the domain, in this case , PC will query the local DNS, UDP sends a DNS query packet-based real problem on to the DNS server

1) We will check the DNS domain name of their recent query cache to see whether the recent www.python.org want within minutes or hours by other machines through DNS queries, if there is an entry, not expired, you can immediately return to IP If today we are the first attempt to access www.python.org person, then you need to start from scratch query DNS IP address corresponding to the hostname.
2) our DNS servers will start from the top-level DNS hierarchy in the world, recursive queries www.python.org. Serv able to identify the root of the name of all top-level domain (TLD), such as .com, .org, .net, and group information is stored Serv responsible for responding to top-level domain. To find the domain name Serv before connecting to the Domain Name System (DNS), the name of the software is usually built Serv Serv top of IP, UDP, after a round-trip, we will be able to get the DNS domain name .org preserved the index Serv.
3) sends a second DNS request, the server sends to a .org, Xuwen responsible for keeping Serv python.org, use the whois Serv access to information stored on top of a domain name.

$ whois python.org
Domain Name: PYTHON.ORG
...
Registrar URL: http://www.gandi.net
Updated Date: 2019-02-25T03:01:59Z
Creation Date: 1995-03-27T05:00:00Z
Registry Expiry Date: 2020-03-28T05:00:00Z
Registrar Registration Expiration Date:
...
Name Server: NS3.P11.DYNECT.NET
Name Server: NS1.P11.DYNECT.NET
Name Server: NS2.P11.DYNECT.NET
Name Server: NS4.P11.DYNECT.NET
DNSSEC: unsigned

No matter where in the world, any DNS hostname python.org belonging to a request, will be sent to a DNS four listed above. Now that we have completed the DNS to communicate with the DNS root and top .org DNS, you can query directly to the NS3.P11.DYNECT.NET the python.org, according to its name Serv python.org different configurations, the DNS also the number of inquiries to be carried out will be different. One of four Serv above can return query results www.python.org, our DNS servers also can return a UDP packet to the browser (includes corresponding IP).

. 4.3.0.7 The process requires four separate network round: PC we want to send a DNS request to obtain a response. To get results, our DNS recursive query that contains three different round trips between other Serv. Therefore, when you first enter a domain name in the browser, the wait time

4.3.1. Why not use the original DNS

推荐做法是,除非由于特殊原因必须进行DNS查询,否则永远都通过getaddrinfo()/其他系统支持的机制来解析hostname,通过OS来查询hostname会带来如下好处:

1) DNS is usually not the only way to get OS name information. If, as the first choice, PC name suddenly becomes unavailable in the application, and the browser, file sharing, path, etc. may be used, since there is no OS that by analogy with WINS, / etc / hosts mechanism to query domain name that their programs can not use these names.
2) PC cache holds recently queried domain name may already contain the required IP domain name, if you try to do DNS queries on their own, it means repeating the work already done
3) run Py script systems may already have information Serv local domain name, the reason may be OS-MA made a manual configuration, using a similar protocol DHCP network installation. If your DNS queries Py program start, you need to know how to get information about a specific OS.
4) If you do not use local DNS, it can not use its own local DNS cache that prevents the program and other programs running on the same network, frequently used for local hostname query.
5) DNS in the world will do some adjustments, OS libraries and daemons will be gradually updated to accommodate the latest changes. If the original DNS calls directly in the program, so you need to track these changes to ensure that changes IP, DNS itself and international conventions on the code TLD synchronization.
6) Py not put any DNS tools built into the standard library, to be used for DNS Py, you must select third-party libraries dnspython3

4.3.2. DNS lookup using Py

Reasons for using Py has a DNS call. If you write a message Serv / without local mail relay on Cli try to send mail directly to the recipient, would like to get a domain name associated with the MX records, you can find the right Serv-mail friends @ example.com of the

. 4.3.2.1 dnspython3 Py3 support may be one of the best libraries installed:

$ pip install dnspython3

The library uses its own method to get the domain name Serv Win / POSIX-OS is being used, a request on behalf of these Serv recursive queries. Therefore, OS-MA / Serv network configuration is properly configured to run the name Serv

# 4-2 dns_basic.py

import argparse, dns.resolver

def lookup(name):
    for qtype in 'A', 'AAAA', 'CNAME', 'MX', 'NS':
        answer = dns.resolver.query(name, qtype, raise_on_no_answer=False)
        if answer.rrset is not None:
            print(answer.rrset)
    
    if __name__ == '__main__':
        parser = argparse.ArgumentParser(description='Resolve a name using DNS')
        parser.add_argument('name', help='name that you want to look up in DNS')
        lookup(parser.parse_args().name)

You can only try a DNS query, the script on the command line summary provides a hostname as an argument and then loop query different types of records belonging to the hostname to python.org run as a parameter, you can get the following DNS information.

$ python dns_basic.py pythonorg
python.org. 42945 IN A 140.211.10.69
python.org. 86140 IN MX 50 mail.python.org
python.org. 86146 IN NS ns4.p11.dynect.net
...

Can be seen that each have returned response is represented by a sequence of objects, in order, each line printing key is as follows:
1) name of the query
2) the name is stored in the cache valid time, s is the unit
3) " class ", as represented returns web address in response to the iN
. 4) recorded in" type ", a common representation of IPv4 a, AAAA IPv6, the name Serv record NS, messages Serv domain using the MX
. 5)," data "to provide to connect or communicate with the information needed Serv.

. 4.3.2.2 learned about 3:00 python.org domain information:

1) A record tells us that if you want to connect to the real python.org machine (initiating a HTTP connection, start an SSH session, etc.), it should send packets to 140.211.10.69-IP,
2) NS record tells us, want any query belongs python.org hostname, the request should be resolved ns1.p11.dynect.net to ns4.p11.dynect.net (in the order given, not in numerical order) four servers.
3) want to send an email to the email address of the user in the domain @ python.org, need to consult hostname-mail.python.org
the DNS query page may return the CNAME record type, hostname represents the hostname query is actually just another alias It requires a separate query the original hostname, because this process requires two round-trip, so this record type out of fashion, but sometimes encounter

4.3.3. Resolve your mailbox domain

4.3.3.1. Resolve mail domain is a reasonable application program Py most original DNS query. The rule is that if the MX record exists, must attempt to communicate with these SMTP-Serv. If no message receiving SMTP-Serv, must return an error (or placed in the retry queue summary message) to the user.

4.3.3.2. If the priority is different according to the priority number, from small to large try these SMTP-Serv, If the MX record does not exist, but the domain name of A / AAAA, may attempt to A / AAAA initiate connection corresponding IP . If a domain does not provide any record, the CNAME are given, using the same rules should search for the CNAME records corresponding to domain MX or A records

4-3 shows a possible implementation of the algorithm, through a series of DNS queries to obtain a possible target IP, and print out its decisions, like constantly adjusting tactics and return address, instead of printing it, you can achieve Py a mail distribution tool to send messages to a remote address.

# 4-3 解析电子邮件域名 dns_mx.py
import argparse, dns.resolver

def resolve_hostname(hostname, indent=''):
    'Print an A or AAAA record for hostname; follow CNAMEs if necessary.'
    indent = indent + '   '
    answer = dns.resolver.query(hostname, 'A')
    if answer.rrset is not None:
        for record in answer:
            print(indent, hostname, 'has A address', record.address)
        return
    answer = dns.resolver.query(hostname, 'AAAA')
    if answer.rrset is not None:
        for record in answer:
            print(indent, hostname, 'has AAAA address', record.address)
        return
    answer = dns.resolver.query(hostname, 'CNAME')
    if answer.rrset is not None:
        record = answer[0]
        cname = record.address
        print(indent, hostname, 'is a CNAME alias for', cname)
        resolve_hostname(cname, indent)
        return
    print(indent, 'ERROR: no A, AAAA, or CNAME records for', hostname)

def resolve_email_domain(domain):
    "For an email address name@domain find its mail server IP addresses."
    try:
        answer = dns.resolver.query(domain, 'MX', raise_on_no_answer=False)
    except dns.resolver.NXDOMAIN:
        print('Error: No such domain', domain)
        return 
    if answer.rrset is not None:
        records = sorted(answer, key=lambda record: record.preference)
        for record in records:
            name = record.exchange.to_text(omit_final_dot=True)
            print('Priority', record.preference)
            resolve_hostname(name)
    else:
        print('This domain has no explicit MX records')
        print('Attempting to resolve it as an A, AAAA, or CNAME')
        resolve_hostname(domain)

if __name__ == '__main__':
    parser = argparse.ArgumentParser(description='Find mailserver IP address')
    parser.add_argument('domain', help='domain that you want to send mail to')
    resolve_email_domain(parser.parse_args().domain)

1) resolve_hostname () based on the current host connected to an IPv4 or IPv6 for dynamic selection of the A and AAAA, it does not show robust. At this point, you should use getsockaddr (), instead of trying to resolve its own hostname of the mail Serv, 4-3 display works only for DNS to understand how the query is parsed
2) real-mail messages Serv Serv does not speak of prints it out, send mail to these addresses. As long as there once sent successfully, we continue to send stop. (After sending successfully continue the walk Serv list, generate multiple copies of email correspondence sent to each successful there will be a copy of Serv), python.org only a message of IP Serv

$ python dns_mx.py python.org
This domain has 1 MX records
Priority 50
    mail.python.org has A address 82.94.164.166

Whether the IP is part of a machine or shared by a host cluster, simply can not see it from the outside. IANA has no less than six email Serv.

$ python dns_mx.py iana.org
...

By attempting to run on many different domain names this script, you can see mail routing large / small organization is how to receive to a different IP

4.4. Summary

4.4.1. Py programs typically need to address hostname can be converted to the actual socket connection

4.4.2. Most hostname queries through the socket module getsockaddr () to complete, because the function of intelligence is provided by the OS, not only know how to use all mechanisms available to query the domain name, but also know the local IP stack configuration support address type (IPv4 / 6)

4.4.3. Traditional IPv4 is still the most popular, but IPv6 is becoming increasingly common. Use getsockaddr () were hostname and port queries, Py can address as a single string without a single line and explain how to resolve the address.

4.4.4. DNS name resolution method is the principle behind the most. Is a distributed database in the world for domain name queries directly with the appropriate domain name to point Serv institutions. The original DNS queries directly Py the frequency is not high, but when you send e-mail directly based on the domain name after the @ symbol in e-mail address, or helpful

Guess you like

Origin www.cnblogs.com/wangxue533/p/11992990.html