ch18_02.htm

来自「By Tom Christiansen and Nathan Torkingto」· HTM 代码 · 共 659 行

HTM
659
字号
<HTML><HEAD><TITLE>Recipe 18.1. Simple DNS Lookups (Perl Cookbook)</TITLE><METANAME="DC.title"CONTENT="Perl Cookbook"><METANAME="DC.creator"CONTENT="Tom Christiansen &amp; Nathan Torkington"><METANAME="DC.publisher"CONTENT="O'Reilly &amp; Associates, Inc."><METANAME="DC.date"CONTENT="1999-07-02T01:44:58Z"><METANAME="DC.type"CONTENT="Text.Monograph"><METANAME="DC.format"CONTENT="text/html"SCHEME="MIME"><METANAME="DC.source"CONTENT="1-56592-243-3"SCHEME="ISBN"><METANAME="DC.language"CONTENT="en-US"><METANAME="generator"CONTENT="Jade 1.1/O'Reilly DocBook 3.0 to HTML 4.0"><LINKREV="made"HREF="mailto:online-books@oreilly.com"TITLE="Online Books Comments"><LINKREL="up"HREF="ch18_01.htm"TITLE="18. Internet Services"><LINKREL="prev"HREF="ch18_01.htm"TITLE="18.0. Introduction"><LINKREL="next"HREF="ch18_03.htm"TITLE="18.2. Being an FTP Client"></HEAD><BODYBGCOLOR="#FFFFFF"><img alt="Book Home" border="0" src="gifs/smbanner.gif" usemap="#banner-map" /><map name="banner-map"><area shape="rect" coords="1,-2,616,66" href="index.htm" alt="Perl Cookbook"><area shape="rect" coords="629,-11,726,25" href="jobjects/fsearch.htm" alt="Search this book" /></map><div class="navbar"><p><TABLEWIDTH="684"BORDER="0"CELLSPACING="0"CELLPADDING="0"><TR><TDALIGN="LEFT"VALIGN="TOP"WIDTH="228"><ACLASS="sect1"HREF="ch18_01.htm"TITLE="18.0. Introduction"><IMGSRC="../gifs/txtpreva.gif"ALT="Previous: 18.0. Introduction"BORDER="0"></A></TD><TDALIGN="CENTER"VALIGN="TOP"WIDTH="228"><B><FONTFACE="ARIEL,HELVETICA,HELV,SANSERIF"SIZE="-1"><ACLASS="chapter"REL="up"HREF="ch18_01.htm"TITLE="18. Internet Services"></A></FONT></B></TD><TDALIGN="RIGHT"VALIGN="TOP"WIDTH="228"><ACLASS="sect1"HREF="ch18_03.htm"TITLE="18.2. Being an FTP Client"><IMGSRC="../gifs/txtnexta.gif"ALT="Next: 18.2. Being an FTP Client"BORDER="0"></A></TD></TR></TABLE></DIV><DIVCLASS="sect1"><H2CLASS="sect1"><ACLASS="title"NAME="ch18-chap18_simple_0">18.1. Simple DNS Lookups</A></H2><DIVCLASS="sect2"><H3CLASS="sect2"><ACLASS="title"NAME="ch18-pgfId-79">Problem<ACLASS="indexterm"NAME="ch18-idx-1000004277-0"></A><ACLASS="indexterm"NAME="ch18-idx-1000004277-1"></A><ACLASS="indexterm"NAME="ch18-idx-1000004277-2"></A></A></H3><PCLASS="para">You want to find the IP address of a host or turn an IP address into a name. Network servers do this to authenticate their clients, and clients do it when the user gives them a hostname but Perl's socket library requires an IP address. Furthermore, many servers produce log files containing IP addresses, but hostnames are more useful to analysis software and humans.</P></DIV><DIVCLASS="sect2"><H3CLASS="sect2"><ACLASS="title"NAME="ch18-pgfId-85">Solution</A></H3><PCLASS="para">If you have a name like <CODECLASS="literal">www.perl.com</CODE>, use <CODECLASS="literal">gethostbyname</CODE> if you want all the addresses:</P><PRECLASS="programlisting">use Socket;@addresses = gethostbyname($name)   or die &quot;Can't resolve $name: $!\n&quot;;@addresses = map { inet_ntoa($_) } @addresses[4 .. $#addresses];# @addresses is a list of IP addresses (&quot;208.201.239.48&quot;, &quot;208.201.239.49&quot;)</PRE><PCLASS="para">Or, use <CODECLASS="literal">inet_aton</CODE> if you only need the first:</P><PRECLASS="programlisting">use Socket;$address = inet_ntoa(inet_aton($name));# $address is a single IP address &quot;208.201.239.48&quot;</PRE><PCLASS="para">If you have an IP address like <CODECLASS="literal">&quot;208.201.239.48&quot;</CODE>, use:</P><PRECLASS="programlisting">use Socket;$name = gethostbyaddr(inet_aton($address), AF_INET)            or die &quot;Can't resolve $address: $!\n&quot;;# $name is the hostname (&quot;www.perl.com&quot;)</PRE></DIV><DIVCLASS="sect2"><H3CLASS="sect2"><ACLASS="title"NAME="ch18-pgfId-123">Discussion</A></H3><PCLASS="para">This process is complicated because the functions are mere wrappers for the C system calls, so this means you have to convert IP addresses from ASCII strings (<CODECLASS="literal">&quot;208.146.240.1&quot;</CODE>) into their C structures. The standard Socket module gives you <CODECLASS="literal">inet_aton</CODE> to convert from ASCII to the packed numeric format and <CODECLASS="literal">inet_ntoa</CODE> to convert back:</P><PRECLASS="programlisting">use Socket;$packed_address = inet_aton(&quot;208.146.140.1&quot;);$ascii_address  = inet_ntoa($packed_address);</PRE><PCLASS="para">The <CODECLASS="literal">gethostbyname</CODE> function takes a string containing the hostname (or IP address). In scalar context, it returns the IP address of the remote host suitable for passing to <CODECLASS="literal">inet_ntoa</CODE> (or <CODECLASS="literal">undef</CODE> on error). In list context, it returns a list of at least five elements (or an empty list in case of error). The returned list is:</P><TABLECLASS="informaltable"BORDER="1"CELLPADDING="3"><THEADCLASS="thead"><TRCLASS="row"VALIGN="TOP"><THCLASS="entry"ALIGN="LEFT"ROWSPAN="1"COLSPAN="1"><PCLASS="para">Index</P></TH><THCLASS="entry"ALIGN="LEFT"ROWSPAN="1"COLSPAN="1"><PCLASS="para">Meaning</P></TH></TR></THEAD><TBODYCLASS="tbody"><TRCLASS="row"VALIGN="TOP"><TDCLASS="entry"ROWSPAN="1"COLSPAN="1"><PCLASS="para"><CODECLASS="literal">0</CODE></P></TD><TDCLASS="entry"ROWSPAN="1"COLSPAN="1"><PCLASS="para">Official name of host</P></TD></TR><TRCLASS="row"VALIGN="TOP"><TDCLASS="entry"ROWSPAN="1"COLSPAN="1"><PCLASS="para"><CODECLASS="literal">1</CODE></P></TD><TDCLASS="entry"ROWSPAN="1"COLSPAN="1"><PCLASS="para">Aliases (space-separated string)</P></TD></TR><TRCLASS="row"VALIGN="TOP"><TDCLASS="entry"ROWSPAN="1"COLSPAN="1"><PCLASS="para"><CODECLASS="literal">2</CODE></P></TD><TDCLASS="entry"ROWSPAN="1"COLSPAN="1"><PCLASS="para">Address Type (normally AF_INET)</P></TD></TR><TRCLASS="row"VALIGN="TOP"><TDCLASS="entry"ROWSPAN="1"COLSPAN="1"><PCLASS="para"><CODECLASS="literal">3</CODE></P></TD><TDCLASS="entry"ROWSPAN="1"COLSPAN="1"><PCLASS="para">Length of Address Structure (irrelevant)</P></TD></TR><TRCLASS="row"VALIGN="TOP"><TDCLASS="entry"ROWSPAN="1"COLSPAN="1"><PCLASS="para"><CODECLASS="literal">4,5, ...</CODE></P></TD><TDCLASS="entry"ROWSPAN="1"COLSPAN="1"><PCLASS="para">Address Structures</P></TD></TR></TBODY></TABLE><PCLASS="para">A hostname may have more than one address, particularly busy web sites, where many machines serve identical web pages to share the load. In such situations, the DNS server that provides you the addresses rotates them to balance the load. If you need to pick an IP address to connect to, it is sufficient to always select the first (but if it doesn't work, try the rest as well):</P><PRECLASS="programlisting">$packed = gethostbyname($hostname)            or die &quot;Couldn't resolve address for $hostname: $!\n&quot;;$address = inet_ntoa($packed);print &quot;I will use $address as the address for $hostname\n&quot;;</PRE><PCLASS="para">If you're using hostnames to permit or refuse access to a service, be careful. Anyone can set their DNS server to identify their machine as <CODECLASS="literal">www.whitehouse.gov</CODE>, <CODECLASS="literal">www.yahoo.com </CODE>, or <CODECLASS="literal">this.is.not.funny</CODE>. You can't know whether the machine really has the name it claims to have until you use <CODECLASS="literal">gethostbyname</CODE> and check that the original address is in the address list for the name.</P><PRECLASS="programlisting"># $address is the IP address I'm checking, like &quot;128.138.243.20&quot;use Socket;$name    = gethostbyaddr(inet_aton($address), AF_INET)                or die &quot;Can't look up $address : $!\n&quot;;@addr    = gethostbyname($name)                or die &quot;Can't look up $name : $!\n&quot;;$found   = grep { $address eq inet_ntoa($_) } @addr[4..$#addr];</PRE><PCLASS="para">It turns out that even with this algorithm, you can't be absolutely sure of the name due to a variety of methods that can be used to circumvent even this technique. Even the IP address from which the packets appear to be coming can be spoofed, so you shouldn't ever rely on the network layer for authentication. Always do authentication yourself (with passwords, or cryptographic challenges) when it really matters, because the IPv4 network was not designed to provide security.</P><PCLASS="para">More information is kept about a host than just addresses and aliases. To fully access this information, use the Net::DNS module from CPAN. For instance, <ACLASS="xref"HREF="ch18_02.htm#ch18-15726"TITLE="mxhost">Example 18.1</A> shows how to retrieve the MX (mail exchange) records for an arbitrary host.</P><DIVCLASS="example"><H4CLASS="example"><ACLASS="title"NAME="ch18-15726">Example 18.1: mxhost</A></H4><PRECLASS="programlisting"> #!/usr/bin/perl # mxhost - find mx exchangers for a host use Net::DNS; $host = shift; $res = Net::DNS::Resolver-&gt;<CODECLASS="literal">new</CODE><CODECLASS="replaceable"><I>()</I></CODE>; @mx = mx($res, $host)    or die &quot;Can't find MX records for $host (&quot;.$res-&gt;errorstring.&quot;)\n&quot;; foreach $record (@mx) {     print $record-&gt;preference, &quot; &quot;, $record-&gt;exchange, &quot;\n&quot;; }</PRE></DIV><PCLASS="para">Here's some output:</P><PRECLASS="programlisting">% mxhost cnn.com<CODECLASS="userinput"><B><CODECLASS="replaceable"><I>10 mail.turner.com</I></CODE></B></CODE><CODECLASS="userinput"><B><CODECLASS="replaceable"><I>30 alfw2.turner.com</I></CODE></B></CODE></PRE><PCLASS="para">The <CODECLASS="literal">inet_aton</CODE> function takes a string containing a hostname or IP address, as does <CODECLASS="literal">gethostbyname</CODE>, but it only returns the first IP address for the host. If you want to find them all, you'll need to add some more code. The Net::hostent provides for by-name access that will let you do that. <ACLASS="xref"HREF="ch18_02.htm#ch18-18854"TITLE="hostaddrs">Example 18.2</A> shows an example of its use.</P><DIVCLASS="example"><H4CLASS="example"><ACLASS="title"NAME="ch18-18854">Example 18.2: hostaddrs</A></H4><PRECLASS="programlisting">#!/usr/bin/perl# hostaddrs - canonize name and show addressesuse Socket;use Net::hostent;$name = shift;if ($hent = gethostbyname($name)) {    $name      = $hent-&gt;name;                # in case different    $addr_ref  = $hent-&gt;addr_list;    @addresses = map { inet_ntoa($_) } @$addr_ref;}print &quot;$name =&gt; @addresses\n&quot;;</PRE></DIV><PCLASS="para">Here's the output:</P><PRECLASS="programlisting">% hostaddrs www.ora.com<CODECLASS="userinput"><B>helio.ora.com =&gt; 204.148.40.9</B></CODE>% hostaddrs www.whitehouse.gov<CODECLASS="userinput"><B>www.whitehouse.gov =&gt; 198.137.240.91 198.137.240.92</B></CODE><ACLASS="indexterm"NAME="ch18-idx-1000004279-0"></A><ACLASS="indexterm"NAME="ch18-idx-1000004279-1"></A><ACLASS="indexterm"NAME="ch18-idx-1000004279-2"></A></PRE></DIV><DIVCLASS="sect2"><H3CLASS="sect2"><ACLASS="title"NAME="ch18-pgfId-245">See Also</A></H3><PCLASS="para">The <CODECLASS="literal">gethostbyname</CODE> and <CODECLASS="literal">gethostbyaddr</CODE> functions in <ACLASS="olink"HREF="../prog/ch03_01.htm">Chapter 3</A> of <ACLASS="citetitle"HREF="../prog/index.htm"TITLE="Programming Perl"><CITECLASS="citetitle">Programming Perl</CITE></A> and in <ICLASS="filename">perlfunc </I>(1); the documentation for the Net::DNS module from CPAN; the documentation for the standard Socket and Net::hostent modules</P></DIV></DIV><DIVCLASS="htmlnav"><P></P><HRALIGN="LEFT"WIDTH="684"TITLE="footer"><TABLEWIDTH="684"BORDER="0"CELLSPACING="0"CELLPADDING="0"><TR><TDALIGN="LEFT"VALIGN="TOP"WIDTH="228"><ACLASS="sect1"HREF="ch18_01.htm"TITLE="18.0. Introduction"><IMGSRC="../gifs/txtpreva.gif"ALT="Previous: 18.0. Introduction"BORDER="0"></A></TD><TDALIGN="CENTER"VALIGN="TOP"WIDTH="228"><ACLASS="book"HREF="index.htm"TITLE="Perl Cookbook"><IMGSRC="../gifs/txthome.gif"ALT="Perl Cookbook"BORDER="0"></A></TD><TDALIGN="RIGHT"VALIGN="TOP"WIDTH="228"><ACLASS="sect1"HREF="ch18_03.htm"TITLE="18.2. Being an FTP Client"><IMGSRC="../gifs/txtnexta.gif"ALT="Next: 18.2. Being an FTP Client"BORDER="0"></A></TD></TR><TR><TDALIGN="LEFT"VALIGN="TOP"WIDTH="228">18.0. Introduction</TD><TDALIGN="CENTER"VALIGN="TOP"WIDTH="228"><ACLASS="index"HREF="index/index.htm"TITLE="Book Index"><IMGSRC="../gifs/index.gif"ALT="Book Index"BORDER="0"></A></TD><TDALIGN="RIGHT"VALIGN="TOP"WIDTH="228">18.2. Being an FTP Client</TD></TR></TABLE><HRALIGN="LEFT"WIDTH="684"TITLE="footer"><FONTSIZE="-1"></DIV<!-- LIBRARY NAV BAR --> <img src="../gifs/smnavbar.gif" usemap="#library-map" border="0" alt="Library Navigation Links"><p> <a href="copyrght.htm">Copyright &copy; 2002</a> O'Reilly &amp; Associates. All rights reserved.</font> </p> <map name="library-map"> <area shape="rect" coords="1,0,85,94" href="../index.htm"><area shape="rect" coords="86,1,178,103" href="../lwp/index.htm"><area shape="rect" coords="180,0,265,103" href="../lperl/index.htm"><area shape="rect" coords="267,0,353,105" href="../perlnut/index.htm"><area shape="rect" coords="354,1,446,115" href="../prog/index.htm"><area shape="rect" coords="448,0,526,132" href="../tk/index.htm"><area shape="rect" coords="528,1,615,119" href="../cookbook/index.htm"><area shape="rect" coords="617,0,690,135" href="../pxml/index.htm"></map> </BODY></HTML>

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?