Net_py Chapter 4. net_py Domains Top-level Domains:.edu,.com.,.ca, etc Domain Name: newpaltz.edu,...
-
Upload
arthur-watson -
Category
Documents
-
view
224 -
download
2
Transcript of Net_py Chapter 4. net_py Domains Top-level Domains:.edu,.com.,.ca, etc Domain Name: newpaltz.edu,...
net_py
Chapter 4
net_py
Domains
Top-level Domains: .edu, .com., .ca, etc
Domain Name: newpaltz.edu, etc
Fully Qualified Domain Name: wyvern.cs.newpaltz.edu. Owning a domain name gives you the right to create FQDNs with your Domain Name at the end. Technically any name that ends with a '.' is also considered fully qualified.
Hostname: wyvern.
net_py
/etc/resolv.conf
How domain name searches start:
If your search name is not fully qualified search begins by searching for using the name servers specified.
<your search name> <your search name>.cs.newpaltz.edu <your search name>.acsl.newpaltz.edu <your search name>.newpaltz.edu
(GeoIP)[pletcha@archimedes pypcap-1.1]$ cat /etc/resolv.conf # Generated by NetworkManagerdomain newpaltz.edusearch cs.newpaltz.edu acsl.newpaltz.edu newpaltz.edunameserver 137.140.1.98nameserver 137.140.1.102
net_py
Example:
Searching for my.website.cam will search for
my.website.cam my.website.cam.cs.newpaltz.edu my.website.cam.acsl.newpaltz.edu my.website.cam.newpaltz.edu
But searching for my.website.cam. will search for
my.website.cam
only.
net_py
Example 2:
Searching for argos searches for:
argos.cs.newpaltz.edu # fails argos.acsl.newpaltz.edu # fails argos.newpaltz.edu # succeeds
This is why you can use host names only on campus.
net_py
Socket Names Used By:
mysocket.accept(): returns a tuple whose 2nd entry is a remote address
mysocket.bind(address): binds to a local address so outgoing packets have this source address.
mysocket.connect(address): indicates the remote address that packets using this connection must either go to or come from.
mysocket.getpeername(): Returns the remote address the socket is connected to
mysocket.getsocketname(): returns the address of this socket
mysocket.recvfrom(): UDP: returns data and the address of the sender
mysocket.sendto(data,address): UDP, indicates the receiver address.
net_py
Five Socket Properties:
socket.AF_INET: Internet Address Family => kind of network and transport – UDP or TCP.
socket.AF_UNIX: like the internet but between processes on the same host
socket.SOCK_DGRAM: packet service (UDP for AF_INET)
socket.SOCK_STREAM: stream service (TCP for AF_INET)
3rd argument, not used n this book
socket.IPPROTO_TCP: use TCP for SOCK_STREAM.
socket.IPPROTO_UDP: use TCP for SOCK_DGRAM
net_py
IPv6:
Will replace IPv4 when we run our ot IPv4 IP addresses.
IPv6 has more services than IPv4.
>>> import socket>>> print socket.has_ipv6()# tells you if your machine is capable of ipv6; not # if it is enabled.
net_py
Address Resolution:
One way of avoiding specifying destination IP addresses, etc, is to let the socket module tell you what you need to know.
We are asking, “How can we connect to the web server on host gatech.edu?”
>>> import socket>>> infolist = socket.getaddrinfo('gatech.edu','www')>>> pprint infolist[(1,2,6,'',('130.207.244.244','80'), (1,2,17,'',('130.207.244.244','80')# all the interfaces on .244.244 associated with 'www'>>> ftpca = infolist[0] # == (1,2,6,'',('130.207.244.244','80')>>> ftp = ftpca[0:3] # == (2,1,6)>>> s = socket.socket(*ftp) # unpack a list with *# s = socket.socket(ftp[0],ftp[1]) would do just as well>>> s.connect(ftpca[4]) # ('130.207.244.244','80')
net_py
NOTE:
HTTPD officially supports TCP (6) and UDP (17).
gatech.edu is an alias for this host. It also has a “cannonical” name. but we didn't ask for this so it wasn't returned.
Calling socket.getaddrinfo() we don't need to use socket.AF_INET, etc, in our code.
net_py
Asking socket.getaddrinfo() for help in binding.
Problem: Provide an address for bind() without deciding this yourself.
Example: Suppose you want to open a server (passive) using port 1060
>>> from socket import getaddrinfo>>> import socket>>> getaddrinfo(None,1060,0,socket.SOCK_STREAM,0,socket.AI_PASSIVE)[(2, 1, 6, '', ('0.0.0.0', 1060)), (10, 1, 6, '', ('::', 1060, 0, 0))]>>> getaddrinfo(None,1060,0,socket.SOCK_DGRAM,0,socket.AI_PASSIVE)[(2, 2, 17, '', ('0.0.0.0', 1060)), (10, 2, 17, '', ('::', 1060, 0, 0))]
# we are asking here, where to bind to. We get an IPv4 and an IPv6 answer# in both cases, TCP and UDP.
net_py
Asking socket.getaddrinfo() for help in binding.
Problem: Want a particular address for bind().
Example: Suppose you want to open a server (passive) using port 1060 and a known local IP address.
>>> from socket import getaddrinfo>>> import socket>>> getaddrinfo('127.0.0.1',1060,0,socket.SOCK_STREAM,0)[(2, 1, 6, '', ('127.0.0.1', 1060))]>>> getaddrinfo(localhost,1060,0,socket.SOCK_STREAM,0)[(2, 1, 6, '', ('::1', 1060,0,0)), (2, 1,6, '', ('127.0.0.1', 1060))]
# we are asking here, where to bind to. We get an IPv4 and an IPv6 answer
net_py
Asking getaddrinfo() about services
The rest of the uses of getaddrinfo() are outward looking.
socket.AI_ADDRCONFIG: filter out things you can't use
socket.AI_AI_V4MAPPED: get IPV4 only
If you don't specify certain address types you get multiple addresses
>>> getaddrinfo('ftp.kernel.org','ftp',0,socket.SOCK_STREAM,0,... socket.AI_ADDRCONFIG | socket.AI_V4MAPPED)[(2, 1, 6, '', ('149.20.4.69', 21))]
>>> getaddrinfo('iana.org','www',0,socket.SOCK_STREAM,0)[(2, 1, 6, '', ('192.0.43.8', 80)), (10, 1, 6, '', ('2001:500:88:200::8', 80, 0, 0))]
net_py
Asking getaddrinfo() about services
The rest of the uses of getaddrinfo() are outward looking.
socket.AI_ADDRCONFIG: filter out things you can't use
socket.AI_AI_V4MAPPED: get IPV4 only
If you don't specify certain address types you get multiple addresses
>>> getaddrinfo('ftp.kernel.org','ftp',0,socket.SOCK_STREAM,0,... socket.AI_ADDRCONFIG | socket.AI_V4MAPPED)[(2, 1, 6, '', ('149.20.4.69', 21))]
>>> getaddrinfo('iana.org','www',0,socket.SOCK_STREAM,0)[(2, 1, 6, '', ('192.0.43.8', 80)), (10, 1, 6, '', ('2001:500:88:200::8', 80, 0, 0))]
net_py
Alternative Methods:
Older methods are hard-wired for IPv4 so should be avoided.
gethostbyname()getfqdn()gethostnbyaddr()getprotobyname(0getservbyname()getservbyport()
socket.gethostbyname(socket.getfqdn())# gives you the primary IP address of this machine
net_py
Using getaddrinfo() and getsockaddr():
#!/usr/bin/env python# Foundations of Python Network Programming - Chapter 4 - www_ping.py# Find the WWW service of an arbitrary host using getaddrinfo().
import socket, sys
if len(sys.argv) != 2: print >>sys.stderr, 'usage: www_ping.py <hostname_or_ip>' sys.exit(2)
hostname_or_ip = sys.argv[1]
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, e: print 'Name service failure:', e.args[1] sys.exit(1)
net_py
Using getaddrinfo() and getsockaddr():
info = infolist[0] # per standard recommendation, try the first onesocket_args = info[0:3]address = info[4]s = socket.socket(*socket_args)try: s.connect(address)except socket.error, e: print 'Network failure:', e.args[1]else: print 'Success: host', info[3], 'is listening on port 80'
net_py
Just to be sure 1:
#!/usr/bin/env python# Foundations of Python Network Programming - Chapter 4 - forward_reverse.pyimport socket, sys
if len(sys.argv) != 2: print >>sys.stderr, 'usage: forward_reverse.py <hostname>' sys.exit(2)hostname = sys.argv[1]try: infolist = socket.getaddrinfo( hostname, 0, 0, socket.SOCK_STREAM, 0, socket.AI_ADDRCONFIG | socket.AI_V4MAPPED | socket.AI_CANONNAME )except socket.gaierror, e: print 'Forward name service failure:', e.args[1] sys.exit(1)
info = infolist[0] # choose the first, if there are several addressescanonical = info[3]socketname = info[4]ip = socketname[0]
net_py
Just to be sure 2:
if not canonical: print 'WARNING! The IP address', ip, 'has no reverse name' sys.exit(1)
print hostname, 'has IP address', ipprint ip, 'has the canonical hostname', canonical
# Lowercase for case-insensitive comparison, and chop off hostnames.
forward = hostname.lower().split('.')reverse = canonical.lower().split('.')
if forward == reverse: print 'Wow, the names agree completely!' sys.exit(0)
net_py
Just to be sure 3:
# Truncate the domain names, which now look like ['www', mit', 'edu'],# to the same length and compare. Failing that, be willing to try a# compare with the first element (the hostname?) lopped off if both of# they are the same length.
length = min(len(forward), len(reverse))if (forward[-length:] == reverse[-length:] or (len(forward) == len(reverse) and forward[-length+1:] == reverse[-length+1:] and len(forward[-2]) > 2)): # avoid thinking '.co.uk' means a match! print 'The forward and reverse names have a lot in common'else: print 'WARNING! The reverse name belongs to a different organization'
net_py
DNSDomain Name:List of labels in path of nodes
used for reverse(addr->name) lookup
net_py
Reverse lookup
[pletcha@archimedes 04]$ host 137.140.1.4848.1.140.137.in-addr.arpa domain name pointer www.newpaltz.edu.
net_py
DNS Packet
net_py
DNS Packet
Q/R: 0/1Opcode: Name or pointerAA: Answer is authoritative(1)TC: truncatedRD: Recursion desired (1)RA: Recursion available (1)rcode: ) - ok, 3 – invalid name from AA
net_py
DNS Query
net_py
Wireshark look
net_py
DNS Query Response
net_py
Wireshark look:
net_py
How to Interpret Previous Slide:
Blue area is the entire response packet.
Bytes 2D-35 are the number of Questions (1), Answers (1), Authoritative Answers (2), Additional Answers(2).
Byte 36 is the length of the first label in the string
Query Type: 00 0C
Query Class: 00 01 (ends on byte 54)
And so on ...
48.1.140.137.in-addr.arpa
net_py
Handling Repeated Strings:
Bytes 55 and 56 ought to be the beginning of the same IP address string repeated. Instead there are two bytes – C0 0C.
When you see most significant four bits of a byte as C this indicates that the next 12 bits are a pointer into the response packet.
In our case the pointer is 0C. So count C bytes into the packet and guess where this gets you – right to the beginning of the original version of
namely, 02 34 38 01 31 03 31 34 30 03 ...
And so on ...
48.1.140.137.in-addr.arpa
net_py
When to use DNS directly:
The authors of our text suggest we stick to getaddrinfo() for all our addressing needs except one – find the mail server for a remote email address.
Suppose you want to send an email to someone but your own mail server is down. Since you normally use your own email server to route the email to the destination mail server, your email can't be sent unless you can by-pass your own email server.
net_py
Email Servers: What protocols are involved in email.
SMTP
SMTP
POP3 orIMAP
“your” mail server “their” mail server
your client:browser,thunderbird
their client:perhaps not running rightnow
net_py
Email Servers: How to by-pass your local mail server.
SMTP
SMTP
POP3 orIMAP
“your” mail server “their” mail server
your client:a python program that knows how tosend an email to aremote mail server(Chapter 13)
their client:perhaps not running rightnow
SMTP
net_py
How to send an email without your local email server:
Ask the DNS server for a remote domain name for the MX resource.
The reply should come back with the domain name and/or IP address of the mail server for that domain.
Build up your email message with the necessary header fields and send it off to the remote email server (port numbers: 25 and 465).
net_py
How to find a remote Mail Server:
Ask the DNS server for a remote domain name for the MX resource.
[pletcha@archimedes 04]$ cat dns_mx.py#!/usr/bin/env python# Foundations of Python Network Programming - Chapter 4 - dns_mx.py# Looking up a mail domain - the part of an email address after the `@`
import sys, DNS
if len(sys.argv) != 2: print >>sys.stderr, 'usage: dns_basic.py <hostname>' sys.exit(2)
net_py
def resolve_hostname(hostname, indent=0): """Print an A or AAAA record for `hostname`; follow CNAMEs if necessary.""" indent = indent + 4 istr = ' ' * indent request = DNS.Request() reply = request.req(name=sys.argv[1], qtype=DNS.Type.A) if reply.answers: for answer in reply.answers: print istr, 'Hostname', hostname, '= A', answer['data'] return reply = request.req(name=sys.argv[1], qtype=DNS.Type.AAAA) if reply.answers: for answer in reply.answers: print istr, 'Hostname', hostname, '= AAAA', answer['data'] return reply = request.req(name=sys.argv[1], qtype=DNS.Type.CNAME) if reply.answers: cname = reply.answers[0]['data'] print istr, 'Hostname', hostname, 'is an alias for', cname resolve_hostname(cname, indent) return print istr, 'ERROR: no records for', hostname
net_py
def resolve_email_domain(domain): """Print mail server IP addresses for an email address @ `domain`.""" request = DNS.Request() reply = request.req(name=sys.argv[1], qtype=DNS.Type.MX) if reply.answers: print 'The domain %r has explicit MX records!' % (domain,) print 'Try the servers in this order:' datalist = [ answer['data'] for answer in reply.answers ] datalist.sort() # lower-priority integers go first for data in datalist: priority = data[0] hostname = data[1] print 'Priority:', priority, ' Hostname:', hostname resolve_hostname(hostname) else: print 'Drat, this domain has no explicit MX records' print 'We will have to try resolving it as an A, AAAA, or CNAME' resolve_hostname(domain)
DNS.DiscoverNameServers()resolve_email_domain(sys.argv[1])
net_py
Send a simple email:
Following slide, from Chapter 13, sends a simple email directly to the remote email server.
Exercise: Combine the previous two programs.
net_py
Sending a simple email message:
[pletcha@archimedes 13]$ cat simple.py #!/usr/bin/env python# Basic SMTP transmission - Chapter 13 - simple.pyimport sys, smtplibif len(sys.argv) < 4: print "usage: %s server fromaddr toaddr [toaddr...]" % sys.argv[0] sys.exit(2)server, fromaddr, toaddrs = sys.argv[1], sys.argv[2], sys.argv[3:]message = """To: %sFrom: %sSubject: Test Message from simple.py
Hello,
This is a test message sent to you from the simple.py programin Foundations of Python Network Programming.""" % (', '.join(toaddrs), fromaddr)
s = smtplib.SMTP(server)s.sendmail(fromaddr, toaddrs, message)print "Message successfully sent to %d recipient(s)" % len(toaddrs)