﻿<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:trackback="http://madskills.com/public/xml/rss/module/trackback/" xmlns:wfw="http://wellformedweb.org/CommentAPI/" xmlns:slash="http://purl.org/rss/1.0/modules/slash/"><channel><title>IT博客-darkstax-文章分类-linux技术</title><link>http://www.cnitblog.com/darkstax/category/2495.html</link><description>slackware linux</description><language>zh-cn</language><lastBuildDate>Tue, 27 Sep 2011 06:46:26 GMT</lastBuildDate><pubDate>Tue, 27 Sep 2011 06:46:26 GMT</pubDate><ttl>60</ttl><item><title>xorg.conf man page</title><link>http://www.cnitblog.com/darkstax/articles/19140.html</link><dc:creator>darkstax</dc:creator><author>darkstax</author><pubDate>Mon, 13 Nov 2006 14:39:00 GMT</pubDate><guid>http://www.cnitblog.com/darkstax/articles/19140.html</guid><wfw:comment>http://www.cnitblog.com/darkstax/comments/19140.html</wfw:comment><comments>http://www.cnitblog.com/darkstax/articles/19140.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cnitblog.com/darkstax/comments/commentRss/19140.html</wfw:commentRss><trackback:ping>http://www.cnitblog.com/darkstax/services/trackbacks/19140.html</trackback:ping><description><![CDATA[&nbsp;&nbsp;&nbsp;&nbsp; 摘要: Table of Contents										Name		xorg.conf - Configuration File for Xorg IntroductionXorg supports several mechanisms for supplying/obtaining configuration and run-time parameters: command...&nbsp;&nbsp;<a href='http://www.cnitblog.com/darkstax/articles/19140.html'>阅读全文</a><img src ="http://www.cnitblog.com/darkstax/aggbug/19140.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cnitblog.com/darkstax/" target="_blank">darkstax</a> 2006-11-13 22:39 <a href="http://www.cnitblog.com/darkstax/articles/19140.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>Linux Network Performance</title><link>http://www.cnitblog.com/darkstax/articles/18247.html</link><dc:creator>darkstax</dc:creator><author>darkstax</author><pubDate>Sat, 21 Oct 2006 17:58:00 GMT</pubDate><guid>http://www.cnitblog.com/darkstax/articles/18247.html</guid><wfw:comment>http://www.cnitblog.com/darkstax/comments/18247.html</wfw:comment><comments>http://www.cnitblog.com/darkstax/articles/18247.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cnitblog.com/darkstax/comments/commentRss/18247.html</wfw:commentRss><trackback:ping>http://www.cnitblog.com/darkstax/services/trackbacks/18247.html</trackback:ping><description><![CDATA[
		<div class="book">
				<div class="titlepage">
						<div>
								<h1 class="title">
										<a name="id2760322">
										</a>Linux Network Performance</h1>
						</div>
						<div>
								<h2 class="subtitle">RAW ethernet vs. UDP</h2>
						</div>
						<div>
								<div class="authorgroup">
										<div class="author">
												<h3 class="author">Andreas Schaufler</h3>
										</div>
								</div>
						</div>
						<div>
								<div class="abstract">
										<p class="title">
												<b>Abstract</b>
										</p>
										<p>This document describes how to do RAW ethernet programming on Linux and gives a comparison of Linux' networking performance on UDP and ethernet layer. <br /><br /><b>A visitor of my website has pointed out to me that there is a mistake in the performance measuring code. This means the figures presented are very likely wrong. Currently I do not have the time to rerun the tests. The value of this article is therefore reduced to that it is a tutorial for RAW Ethernet programming on Linux but nothing more. </b></p>
								</div>
						</div>
						<hr />
				</div>
				<div class="toc">
						<p>
								<b>Table of Contents</b>
						</p>
						<dl>
								<dt>1. <a href="http://www.landshut.org/members/Faustus/fh/linux/udp_vs_raw/ch01.html">RAW ethernet programming</a></dt>
								<dd>
										<dl>
												<dt>
														<a href="http://www.landshut.org/members/Faustus/fh/linux/udp_vs_raw/ch01.html#id2766085">Networking layers</a>
												</dt>
												<dt>
														<a href="http://www.landshut.org/members/Faustus/fh/linux/udp_vs_raw/ch01s02.html">UDP</a>
												</dt>
												<dt>
														<a href="http://www.landshut.org/members/Faustus/fh/linux/udp_vs_raw/ch01s03.html">RAW ethernet</a>
												</dt>
												<dd>
														<dl>
																<dt>
																		<a href="http://www.landshut.org/members/Faustus/fh/linux/udp_vs_raw/ch01s03.html#id2766238">ethernet Frame Spec (IEEE 802.3)</a>
																</dt>
																<dt>
																		<a href="http://www.landshut.org/members/Faustus/fh/linux/udp_vs_raw/ch01s03.html#id2766267">Example Code</a>
																</dt>
														</dl>
												</dd>
										</dl>
								</dd>
								<dt>2. <a href="http://www.landshut.org/members/Faustus/fh/linux/udp_vs_raw/ch02.html">Testing Environment</a></dt>
								<dd>
										<dl>
												<dt>
														<a href="http://www.landshut.org/members/Faustus/fh/linux/udp_vs_raw/ch02.html#id2766728">Equipment</a>
												</dt>
												<dt>
														<a href="http://www.landshut.org/members/Faustus/fh/linux/udp_vs_raw/ch02s02.html">What was measured ?</a>
												</dt>
										</dl>
								</dd>
								<dt>3. <a href="http://www.landshut.org/members/Faustus/fh/linux/udp_vs_raw/ch03.html">Testing Results</a></dt>
								<dd>
										<dl>
												<dt>
														<a href="http://www.landshut.org/members/Faustus/fh/linux/udp_vs_raw/ch03.html#id2767034">Results in numbers</a>
												</dt>
												<dt>
														<a href="http://www.landshut.org/members/Faustus/fh/linux/udp_vs_raw/ch03s02.html">Comparison of UDP results</a>
												</dt>
												<dt>
														<a href="http://www.landshut.org/members/Faustus/fh/linux/udp_vs_raw/ch03s03.html">Comparison of RAW results</a>
												</dt>
												<dt>
														<a href="http://www.landshut.org/members/Faustus/fh/linux/udp_vs_raw/ch03s04.html">Comparison of UDP and RAW ethernet results</a>
												</dt>
										</dl>
								</dd>
								<dt>A. <a href="http://www.landshut.org/members/Faustus/fh/linux/udp_vs_raw/apa.html"></a></dt>
								<dd>
										<dl>
												<dt>
														<a href="http://www.landshut.org/members/Faustus/fh/linux/udp_vs_raw/apa.html#id2768459">Contact</a>
												</dt>
										</dl>
								</dd>
								<dt>B. <a href="http://www.landshut.org/members/Faustus/fh/linux/udp_vs_raw/apb.html"></a></dt>
								<dd>
										<dl>
												<dt>
														<a href="http://www.landshut.org/members/Faustus/fh/linux/udp_vs_raw/apb.html#id2768498">Source Code</a>
												</dt>
										</dl>
								</dd>
						</dl>
				</div>
				<div class="list-of-tables">
						<p>
								<b>List of Tables</b>
						</p>
						<dl>
								<dt>3.1. <a href="http://www.landshut.org/members/Faustus/fh/linux/udp_vs_raw/ch03.html#id2767042">Results</a></dt>
						</dl>
				</div>
				<p class="list-of-examples">
						<b>List of Examples</b>
				</p>
				<div class="list-of-examples">
						<dl>
								<dt>1.1. <a href="http://www.landshut.org/members/Faustus/fh/linux/udp_vs_raw/ch01s02.html#id2766342">Create a UDP socket</a></dt>
								<dt>1.2. <a href="http://www.landshut.org/members/Faustus/fh/linux/udp_vs_raw/ch01s02.html#id2766354">Use a UDP socket to send a message</a></dt>
								<dt>1.3. <a href="http://www.landshut.org/members/Faustus/fh/linux/udp_vs_raw/ch01s02.html#id2766367">Use a UDP socket to receive a message</a></dt>
								<dt>1.4. <a href="http://www.landshut.org/members/Faustus/fh/linux/udp_vs_raw/ch01s03.html#id2766273">Create a RAW ethernet socket</a></dt>
								<dt>1.5. <a href="http://www.landshut.org/members/Faustus/fh/linux/udp_vs_raw/ch01s03.html#id2766286">Send a RAW ethernet frame</a></dt>
								<dt>1.6. <a href="http://www.landshut.org/members/Faustus/fh/linux/udp_vs_raw/ch01s03.html#id2766304">Receive a RAW ethernet frame</a></dt>
						</dl>
				</div>
				<div class="chapter">
						<div class="titlepage">
								<div>
										<h2 class="title">
												<a name="raw_ethernet_howto">
												</a>Chapter 1. RAW ethernet programming</h2>
								</div>
						</div>
						<div class="toc">
								<p>
										<b>Table of Contents</b>
								</p>
								<dl>
										<dt>
												<a href="http://www.landshut.org/members/Faustus/fh/linux/udp_vs_raw/ch01.html#id2766085">Networking layers</a>
										</dt>
										<dt>
												<a href="http://www.landshut.org/members/Faustus/fh/linux/udp_vs_raw/ch01s02.html">UDP</a>
										</dt>
										<dt>
												<a href="http://www.landshut.org/members/Faustus/fh/linux/udp_vs_raw/ch01s03.html">RAW ethernet</a>
										</dt>
										<dd>
												<dl>
														<dt>
																<a href="http://www.landshut.org/members/Faustus/fh/linux/udp_vs_raw/ch01s03.html#id2766238">ethernet Frame Spec (IEEE 802.3)</a>
														</dt>
														<dt>
																<a href="http://www.landshut.org/members/Faustus/fh/linux/udp_vs_raw/ch01s03.html#id2766267">Example Code</a>
														</dt>
												</dl>
										</dd>
								</dl>
						</div>
						<p>The first chapter gives a short overview of how to establish a RAW ethernet communication between two Linux hosts. </p>
						<div class="sect1">
								<div class="titlepage">
										<div>
												<h2 class="title" style="CLEAR: both">
														<a name="id2766085">
														</a>Networking layers</h2>
										</div>
								</div>
								<p>IP networking is using <span class="emphasis"><em>four</em></span> layers: </p>
								<div class="mediaobject">
										<img src="http://www.landshut.org/members/Faustus/fh/linux/udp_vs_raw/layers.png" />
								</div>
								<p>
								</p>
								<p>Normaly applications are placed above the <span class="emphasis"><em>TCP/UDP</em></span> layer. Thus, communication between two programs is going two times through all the layers. On the sender side from TCP/ UDP down to the physical layer, on the receiver side from the physical layer up to the TCP/ UDP layer. The actual data transmission is carried out by the physical layer. </p>
								<div class="mediaobject">
										<img src="http://www.landshut.org/members/Faustus/fh/linux/udp_vs_raw/layers_mit_pfeil.png" />
								</div>
								<p>
								</p>
								<p>However, it is also possible for two programs to communicate on the ethernet layer. In this case the IP and the TCP/UDP layer are not used and as a result an increased data transmission rate is to be expected. It is one purpose of this document to show exact performance figures. </p>
						</div>
				</div>
				<div class="navfooter">
						<hr />
				</div>
		</div>
		<div class="sect1">
				<div class="titlepage">
						<div>
								<h2 class="title" style="CLEAR: both">
										<a name="id2766329">
										</a>UDP</h2>
						</div>
				</div>
				<p>First of all let us take a look at UDP. It is necessary to create a socket. This socket can later be used to send or receive a UDP message. </p>
				<div class="example">
						<p class="title">
								<b>Example 1.1. Create a UDP socket</b>
						</p>
						<pre class="programlisting">#include&lt;string.h&gt;
#include&lt;sys/socket.h&gt;
#include&lt;netinet/in.h&gt;
						
int create_udp_socket(int port) {
	/*socketdescriptor*/
	int    s;				
	/*struct used for binding the socket to a local address*/
	struct sockaddr_in host_address;	
	
	/*create the socket*/
	s=socket(PF_INET, SOCK_DGRAM, IPPROTO_UDP);
	if (s &lt; 0) { /*errorhandling ....*/}
	
	/*init the host_address the socket is beeing bound to*/
	memset((void*)&amp;host_address, 0, sizeof(host_address));
	/*set address family*/
	host_address.sin_family=PF_INET;
	/*accept any incoming messages:*/
	host_address.sin_addr.s_addr=INADDR_ANY;
	/*the port the socket i to be bound to:*/
	host_address.sin_port=htons(port);
	
	/*bind it...*/
	if (
	   bind(s, (struct sockaddr*)&amp;host_address, sizeof(host_address)) &lt; 0
	   ) {
		/*errorhandling...*/
	}
	return s;
}</pre>
				</div>
				<p>
				</p>
				<div class="example">
						<p class="title">
								<b>Example 1.2. Use a UDP socket to send a message</b>
						</p>
						<pre class="programlisting">#define BUF_SIZE 1000
#define LOCAL_PORT 5000
#define REMOTE_PORT 5000

...

int s; /*the socket descriptor*/
char buffer[BUF_SIZE]; 			/*the message to send*/
struct sockaddr_in target_host_address;	/*the receiver's address*/
unsigned char* target_address_holder;	/*a pointer to the ip address*/

...

/*create the socket*/
s = create_udp_socket(LOCAL_PORT);
if (s == -1) {errorhandling.....}

/*init target address structure*/
target_host_address.sin_family=PF_INET;
target_host_address.sin_port=htons(REMOTE_PORT);
target_address_holder=(unsigned char*)&amp;target_host_address.sin_addr.s_addr;
target_address_holder[0]=10;
target_address_holder[1]=0;
target_address_holder[2]=0;
target_address_holder[3]=1;

/*fill message with random data....*/
for (j = 0; j &lt; BUF_SIZE; j++) {
	buffer[j] = (unsigned char)((int) (255.0*rand()/(RAND_MAX+1.0)));
}

/*send it*/
sendto(s, buffer, BUF_SIZE, 0, 
	(struct sockaddr*)&amp;target_host_address, sizeof(struct sockaddr));</pre>
				</div>
				<p>
				</p>
				<div class="example">
						<p class="title">
								<b>Example 1.3. Use a UDP socket to receive a message</b>
						</p>
						<pre class="programlisting">#define BUF_SIZE 1000
#define LOCAL_PORT 5000

...

char buffer[BUF_SIZE];

/*address of the sender will be stored here*/
struct sockaddr_in host_address;
int hst_addr_size = sizeof(host_address);

/*length of the incoming packet*/
int length = 0;					
/*socketdescriptor*/
int s;						

...

/*create the socket*/
s = create_udp_socket(LOCAL_PORT); 
if (s == -1) {errorhandling.....}

/*wait for incoming message*/
length = recvfrom(s, buffer, BUF_SIZE, 0, 
	(struct sockaddr*)&amp;host_address, &amp;hst_addr_size);</pre>
				</div>
				<p>
				</p>
		</div>
		<div class="navfooter">
				<hr />
		</div>
		<div class="sect1">
				<div class="titlepage">
						<div>
								<h2 class="title" style="CLEAR: both">
										<a name="id2766376">
										</a>RAW ethernet</h2>
						</div>
				</div>
				<p>Now let us look at RAW ethernet communication. From the programmers' point of view it is quite similar to UDP. The differences are: </p>
				<div class="itemizedlist">
						<ul type="disc">
								<li>
										<p>the parameters for the function used to create a socket</p>
								</li>
								<li>
										<p>instead of IP addresses MAC addresses are used</p>
								</li>
								<li>
										<p>an ethernet frame needs to be created manually</p>
								</li>
						</ul>
				</div>
				<p>
				</p>
				<div class="sect2">
						<div class="titlepage">
								<div>
										<h3 class="title">
												<a name="id2766238">
												</a>ethernet Frame Spec (IEEE 802.3)</h3>
								</div>
						</div>
						<p>
						</p>
						<div class="mediaobject">
								<img src="http://www.landshut.org/members/Faustus/fh/linux/udp_vs_raw/ethernet_frame.png" />
						</div>
						<p>
						</p>
				</div>
				<div class="sect2">
						<div class="titlepage">
								<div>
										<h3 class="title">
												<a name="id2766267">
												</a>Example Code</h3>
								</div>
						</div>
						<div class="example">
								<p class="title">
										<b>Example 1.4. Create a RAW ethernet socket</b>
								</p>
								<pre class="programlisting">#include &lt;sys/socket.h&gt;
#include &lt;linux/if_packet.h&gt;
#include &lt;linux/if_ether.h&gt;
#include &lt;linux/if_arp.h&gt;

...

int s; /*socketdescriptor*/

s = socket(AF_PACKET, SOCK_RAW, htons(ETH_P_ALL));
if (s == -1) { errorhandling ... }</pre>
						</div>
						<div class="example">
								<p class="title">
										<b>Example 1.5. Send a RAW ethernet frame</b>
								</p>
								<pre class="programlisting">#define ETH_FRAME_LEN 1518

...

/*target address*/
struct sockaddr_ll socket_address;

/*buffer for ethernet frame*/
void* buffer = (void*)malloc(ETH_FRAME_LEN);
 
/*pointer to ethenet header*/
unsigned char* etherhead = buffer;
	
/*userdata in ethernet frame*/
unsigned char* data = buffer + 14;
	
/*another pointer to ethernet header*/
struct ethhdr *eh = (struct ethhdr *)etherhead;
 
int send_result = 0;

/*our MAC address*/
unsigned char src_mac[6] = {0x00, 0x01, 0x02, 0xFA, 0x70, 0xAA};

/*other host MAC address*/
unsigned char dest_mac[6] = {0x00, 0x04, 0x75, 0xC8, 0x28, 0xE5};

/*prepare sockaddr_ll*/

/*RAW communication*/
socket_address.sll_family   = PF_PACKET;	
/*we don't use a protocoll above ethernet layer
  -&gt;just use anything here*/
socket_address.sll_protocol = htons(ETH_P_IP);	

/*index of the network device
see full code later how to retrieve it*/
socket_address.sll_ifindex  = 2;

/*ARP hardware identifier is ethernet*/
socket_address.sll_hatype   = ARPHRD_ETHER;
	
/*target is another host*/
socket_address.sll_pkttype  = PACKET_OTHERHOST;

/*address length*/
socket_address.sll_halen    = ETH_ALEN;		
/*MAC - begin*/
socket_address.sll_addr[0]  = 0x00;		
socket_address.sll_addr[1]  = 0x04;		
socket_address.sll_addr[2]  = 0x75;
socket_address.sll_addr[3]  = 0xC8;
socket_address.sll_addr[4]  = 0x28;
socket_address.sll_addr[5]  = 0xE5;
/*MAC - end*/
socket_address.sll_addr[6]  = 0x00;/*not used*/
socket_address.sll_addr[7]  = 0x00;/*not used*/


/*set the frame header*/
memcpy((void*)buffer, (void*)dest_mac, ETH_ALEN);
memcpy((void*)(buffer+ETH_ALEN), (void*)src_mac, ETH_ALEN);
eh-&gt;h_proto = 0x00;
/*fill the frame with some data*/
for (j = 0; j &lt; 1500; j++) {
	data[j] = (unsigned char)((int) (255.0*rand()/(RAND_MAX+1.0)));
}

/*send the packet*/
send_result = sendto(s, buffer, ETH_FRAME_LEN, 0, 
	      (struct sockaddr*)&amp;socket_address, sizeof(socket_address));
if (send_result == -1) { errorhandling... }</pre>
						</div>
						<div class="example">
								<p class="title">
										<b>Example 1.6. Receive a RAW ethernet frame</b>
								</p>
								<pre class="programlisting">void* buffer = (void*)malloc(ETH_FRAME_LEN); /*Buffer for ethernet frame*/
int length = 0; /*length of the received frame*/ 
...
length = recvfrom(s, buffer, ETH_FRAME_LEN, 0, NULL, NULL);
if (length == -1) { errorhandling .... }</pre>
						</div>
				</div>
		</div>
		<div class="navfooter">
				<hr />
		</div>
		<div class="chapter">
				<div class="titlepage">
						<div>
								<h2 class="title">
										<a name="testing_environment">
										</a>Chapter 2. Testing Environment</h2>
						</div>
				</div>
				<div class="toc">
						<p>
								<b>Table of Contents</b>
						</p>
						<dl>
								<dt>
										<a href="http://www.landshut.org/members/Faustus/fh/linux/udp_vs_raw/ch02.html#id2766728">Equipment</a>
								</dt>
								<dt>
										<a href="http://www.landshut.org/members/Faustus/fh/linux/udp_vs_raw/ch02s02.html">What was measured ?</a>
								</dt>
						</dl>
				</div>
				<p>In this chapter the testing environment is described. </p>
				<div class="sect1">
						<div class="titlepage">
								<div>
										<h2 class="title" style="CLEAR: both">
												<a name="id2766728">
												</a>Equipment</h2>
								</div>
						</div>
						<p>The following hardware equipment was used: </p>
						<div class="itemizedlist">
								<ul type="disc">
										<li>
												<p>Netgear Fast ethernet Switch FS516 16-Port</p>
										</li>
										<li>
												<p>Host 1: </p>
												<div class="itemizedlist">
														<ul type="round">
																<li>
																		<p>Intel Pentium IV 2.0 GHz</p>
																</li>
																<li>
																		<p>Intel Corp. 82801BD PRO/100 VE (LOM)</p>
																</li>
																<li>
																		<p>Linux 2.4.18</p>
																</li>
														</ul>
												</div>
												<p>
												</p>
										</li>
										<li>
												<p>Host 2: </p>
												<div class="itemizedlist">
														<ul type="round">
																<li>
																		<p>Intel Celeron 533 MHz</p>
																</li>
																<li>
																		<p>3Com Corporation 3c905C-TX [Fast Etherlink]</p>
																</li>
																<li>
																		<p>Linux 2.4.20</p>
																</li>
														</ul>
												</div>
												<p>
												</p>
										</li>
										<li>
												<p>Host 3: </p>
												<div class="itemizedlist">
														<ul type="round">
																<li>
																		<p>Intel Pentium III M 500 MHz</p>
																</li>
																<li>
																		<p>SMC8035TX CardBus 10M/100M (PCMCIA)</p>
																</li>
																<li>
																		<p>Linux 2.4.20</p>
																</li>
														</ul>
												</div>
												<p>
												</p>
										</li>
										<li>
												<p>Host 4: </p>
												<div class="itemizedlist">
														<ul type="round">
																<li>
																		<p>AMD Athlon 1200 MHz</p>
																</li>
																<li>
																		<p>3Com Corporation 3c905C-TX/TX-M [Tornado]</p>
																</li>
																<li>
																		<p>Linux 2.4.18</p>
																</li>
														</ul>
												</div>
												<p>
												</p>
										</li>
								</ul>
						</div>
						<p>
						</p>
				</div>
		</div>
		<div class="navfooter">
				<hr />
		</div>
		<div class="sect1">
				<div class="titlepage">
						<div>
								<h2 class="title" style="CLEAR: both">
										<a name="id2766941">
										</a>What was measured ?</h2>
						</div>
				</div>
				<p>
				</p>
				<div class="itemizedlist">
						<ul type="disc">
								<li>
										<p>two hosts were communicating with each other</p>
								</li>
								<li>
										<p>amount of user data in the packets was varying from 50 octets up to 1500 octets. (step: 50 octets)</p>
								</li>
								<li>
										<p>each measurement was carried out for UDP and RAW ethernet</p>
								</li>
								<li>
										<p>the value taken as result is the average of 100.000 measurements for one roundtrip (back and forth both hosts, as shown below)</p>
								</li>
						</ul>
				</div>
				<p>
				</p>
				<div class="mediaobject">
						<img src="http://www.landshut.org/members/Faustus/fh/linux/udp_vs_raw/2way_packet.png" />
						<div class="caption">way of a packet</div>
				</div>
				<p>
				</p>
		</div>
		<div class="navfooter">
				<hr />
		</div>
		<div class="chapter">
				<div class="titlepage">
						<div>
								<h2 class="title">
										<a name="testing_results">
										</a>Chapter 3. Testing Results</h2>
						</div>
				</div>
				<div class="toc">
						<p>
								<b>Table of Contents</b>
						</p>
						<dl>
								<dt>
										<a href="http://www.landshut.org/members/Faustus/fh/linux/udp_vs_raw/ch03.html#id2767034">Results in numbers</a>
								</dt>
								<dt>
										<a href="http://www.landshut.org/members/Faustus/fh/linux/udp_vs_raw/ch03s02.html">Comparison of UDP results</a>
								</dt>
								<dt>
										<a href="http://www.landshut.org/members/Faustus/fh/linux/udp_vs_raw/ch03s03.html">Comparison of RAW results</a>
								</dt>
								<dt>
										<a href="http://www.landshut.org/members/Faustus/fh/linux/udp_vs_raw/ch03s04.html">Comparison of UDP and RAW ethernet results</a>
								</dt>
						</dl>
				</div>
				<p>This chapter shows the testing results. </p>
				<div class="sect1">
						<div class="titlepage">
								<div>
										<h2 class="title" style="CLEAR: both">
												<a name="id2767034">
												</a>Results in numbers</h2>
								</div>
						</div>
						<div class="table">
								<p class="title">
										<b>Table 3.1. Results</b>
								</p>
								<table summary="Results" border="1">
										<colgroup>
												<col />
												<col />
												<col />
												<col />
												<col />
												<col />
												<col />
										</colgroup>
										<thead>
												<tr>
														<th>*</th>
														<th colspan="2">Host3 / Host 4 (SMC/ 3Com)</th>
														<th colspan="2">Host1 / Host 4 (Intel/ 3Com)</th>
														<th colspan="2">Host2 / Host 4 (3Com/ 3Com)</th>
												</tr>
												<tr>
														<th>#octets</th>
														<th>RAW (us)</th>
														<th>UDP (us)</th>
														<th>RAW (us)</th>
														<th>UDP (us)</th>
														<th>RAW (us)</th>
														<th>UDP (us)</th>
												</tr>
										</thead>
										<tfoot>
												<tr>
														<th> </th>
														<th> </th>
														<th> </th>
														<th> </th>
														<th> </th>
														<th> </th>
														<th> </th>
												</tr>
										</tfoot>
										<tbody>
												<tr>
														<td>50</td>
														<td>29</td>
														<td>227</td>
														<td>116</td>
														<td>100</td>
														<td>14</td>
														<td>208</td>
												</tr>
												<tr>
														<td>100</td>
														<td>19</td>
														<td>290</td>
														<td>104</td>
														<td>119</td>
														<td>13</td>
														<td>227</td>
												</tr>
												<tr>
														<td>150</td>
														<td>13</td>
														<td>296</td>
														<td>124</td>
														<td>137</td>
														<td>14</td>
														<td>232</td>
												</tr>
												<tr>
														<td>200</td>
														<td>21</td>
														<td>360</td>
														<td>142</td>
														<td>154</td>
														<td>26</td>
														<td>285</td>
												</tr>
												<tr>
														<td>250</td>
														<td>22</td>
														<td>361</td>
														<td>159</td>
														<td>173</td>
														<td>27</td>
														<td>300</td>
												</tr>
												<tr>
														<td>300</td>
														<td>22</td>
														<td>418</td>
														<td>177</td>
														<td>192</td>
														<td>27</td>
														<td>306</td>
												</tr>
												<tr>
														<td>350</td>
														<td>20</td>
														<td>442</td>
														<td>196</td>
														<td>209</td>
														<td>28</td>
														<td>355</td>
												</tr>
												<tr>
														<td>400</td>
														<td>18</td>
														<td>478</td>
														<td>214</td>
														<td>226</td>
														<td>30</td>
														<td>366</td>
												</tr>
												<tr>
														<td>450</td>
														<td>23</td>
														<td>511</td>
														<td>232</td>
														<td>244</td>
														<td>30</td>
														<td>371</td>
												</tr>
												<tr>
														<td>500</td>
														<td>17</td>
														<td>523</td>
														<td>251</td>
														<td>263</td>
														<td>31</td>
														<td>384</td>
												</tr>
												<tr>
														<td>550</td>
														<td>19</td>
														<td>590</td>
														<td>116</td>
														<td>263</td>
														<td>32</td>
														<td>426</td>
												</tr>
												<tr>
														<td>600</td>
														<td>18</td>
														<td>601</td>
														<td>124</td>
														<td>330</td>
														<td>33</td>
														<td>447</td>
												</tr>
												<tr>
														<td>650</td>
														<td>18</td>
														<td>651</td>
														<td>50</td>
														<td>317</td>
														<td>34</td>
														<td>453</td>
												</tr>
												<tr>
														<td>700</td>
														<td>17</td>
														<td>682</td>
														<td>10</td>
														<td>335</td>
														<td>35</td>
														<td>467</td>
												</tr>
												<tr>
														<td>750</td>
														<td>17</td>
														<td>708</td>
														<td>10</td>
														<td>394</td>
														<td>35</td>
														<td>505</td>
												</tr>
												<tr>
														<td>800</td>
														<td>17</td>
														<td>751</td>
														<td>10</td>
														<td>372</td>
														<td>36</td>
														<td>520</td>
												</tr>
												<tr>
														<td>850</td>
														<td>17</td>
														<td>765</td>
														<td>10</td>
														<td>388</td>
														<td>36</td>
														<td>524</td>
												</tr>
												<tr>
														<td>900</td>
														<td>17</td>
														<td>816</td>
														<td>10</td>
														<td>406</td>
														<td>37</td>
														<td>557</td>
												</tr>
												<tr>
														<td>950</td>
														<td>17</td>
														<td>823</td>
														<td>10</td>
														<td>424</td>
														<td>38</td>
														<td>593</td>
												</tr>
												<tr>
														<td>1000</td>
														<td>17</td>
														<td>874</td>
														<td>10</td>
														<td>443</td>
														<td>38</td>
														<td>595</td>
												</tr>
												<tr>
														<td>1050</td>
														<td>17</td>
														<td>906</td>
														<td>10</td>
														<td>461</td>
														<td>39</td>
														<td>611</td>
												</tr>
												<tr>
														<td>1100</td>
														<td>18</td>
														<td>901</td>
														<td>10</td>
														<td>478</td>
														<td>40</td>
														<td>641</td>
												</tr>
												<tr>
														<td>1150</td>
														<td>21</td>
														<td>915</td>
														<td>11</td>
														<td>496</td>
														<td>41</td>
														<td>664</td>
												</tr>
												<tr>
														<td>1200</td>
														<td>21</td>
														<td>952</td>
														<td>11</td>
														<td>558</td>
														<td>41</td>
														<td>671</td>
												</tr>
												<tr>
														<td>1250</td>
														<td>21</td>
														<td>965</td>
														<td>11</td>
														<td>532</td>
														<td>42</td>
														<td>697</td>
												</tr>
												<tr>
														<td>1300</td>
														<td>19</td>
														<td>973</td>
														<td>11</td>
														<td>550</td>
														<td>43</td>
														<td>742</td>
												</tr>
												<tr>
														<td>1350</td>
														<td>17</td>
														<td>976</td>
														<td>11</td>
														<td>568</td>
														<td>44</td>
														<td>739</td>
												</tr>
												<tr>
														<td>1400</td>
														<td>17</td>
														<td>1000</td>
														<td>11</td>
														<td>586</td>
														<td>44</td>
														<td>745</td>
												</tr>
												<tr>
														<td>1450</td>
														<td>22</td>
														<td>1142</td>
														<td>12</td>
														<td>605</td>
														<td>45</td>
														<td>781</td>
												</tr>
												<tr>
														<td>1500</td>
														<td>19</td>
														<td>1155</td>
														<td>12</td>
														<td>633</td>
														<td>46</td>
														<td>767</td>
												</tr>
										</tbody>
								</table>
						</div>
						<p>. </p>
				</div>
		</div>
		<div class="navfooter">
				<hr />
		</div>
		<div class="sect1">
				<div class="titlepage">
						<div>
								<h2 class="title" style="CLEAR: both">
										<a name="id2768204">
										</a>Comparison of UDP results</h2>
						</div>
				</div>
				<p>The following graph is showing the results of the UDP measurements for each of the different hardware configurations. </p>
				<p>
				</p>
				<div class="mediaobject">
						<img src="http://www.landshut.org/members/Faustus/fh/linux/udp_vs_raw/udp.png" />
						<div class="caption">comparison of UDP performance</div>
				</div>
				<p>
				</p>
				<p>These results are not surprising. The more user data a packet contains the more time is taken for one roundtrip (linear growing). It is also possible to see that the performance is different for different hardware configurations. </p>
		</div>
		<div class="navfooter">
				<hr />
		</div>
		<div class="sect1">
				<div class="titlepage">
						<div>
								<h2 class="title" style="CLEAR: both">
										<a name="id2768254">
										</a>Comparison of RAW results</h2>
						</div>
				</div>
				<p>The following graph is showing the results of the RAW ethernet measurements for each of the different hardware configurations. </p>
				<p>
				</p>
				<div class="mediaobject">
						<img src="http://www.landshut.org/members/Faustus/fh/linux/udp_vs_raw/raw.png" />
						<div class="caption">comparison of RAW ethernet performance</div>
				</div>
				<p>
				</p>
				<p>Looking at SMC/ 3com and 3com/ 3com performance the results are as expected. The time required for one roundtrip is increasing almost linearly, when the amount of user data is increasing. However, the results which were produced by the Intel NIC were unexpected. Although the Intel NIC was very slow when it came to sending packets containing 50 up tp 600 octets of user data, it was outperforming the other two, when the amount of data in a packet is increasing. A possible explanation might be that the driver or the hardware is somehow optimized for larger packages. However this behaviour is not reflected in the UDP comparison graph above. </p>
		</div>
		<div class="navfooter">
				<hr />
		</div>
		<div class="sect1">
				<div class="titlepage">
						<div>
								<h2 class="title" style="CLEAR: both">
										<a name="id2768324">
										</a>Comparison of UDP and RAW ethernet results</h2>
						</div>
				</div>
				<p>Finally both graphs are merged into one diagram, in order to compare the performance of UDP and RAW ethernet. </p>
				<p>
				</p>
				<div class="mediaobject">
						<img src="http://www.landshut.org/members/Faustus/fh/linux/udp_vs_raw/SMC_3com.png" />
				</div>
				<p>
				</p>
				<p>
				</p>
				<div class="mediaobject">
						<img src="http://www.landshut.org/members/Faustus/fh/linux/udp_vs_raw/Intel_3com.png" />
				</div>
				<p>
				</p>
				<p>
				</p>
				<div class="mediaobject">
						<img src="http://www.landshut.org/members/Faustus/fh/linux/udp_vs_raw/3com_3com.png" />
				</div>
				<p>
				</p>
				<p>
				</p>
				<div class="mediaobject">
						<img src="http://www.landshut.org/members/Faustus/fh/linux/udp_vs_raw/all.png" />
				</div>
				<p>
				</p>
				<p>The results show that RAW ethernet in general is much faster than UDP. Looking at the features that are offered by UDP and RAW ethernet it becomes visible that those two are quite similiar. Both are not connection oriented, both are packet based and both do not give any guarantee for success of transmission. Thus, in the view of real world systems which are currently using UDP running over ethernet or systems which require very high network performance, RAW ethernet could offer a very good solution. </p>
		</div>
		<div class="navfooter">
				<hr />
		</div>
		<div class="appendix">
				<div class="titlepage">
				</div>
				<div class="toc">
						<p>
								<b>Table of Contents</b>
						</p>
						<dl>
								<dt>
										<a href="http://www.landshut.org/members/Faustus/fh/linux/udp_vs_raw/apa.html#id2768459">Contact</a>
								</dt>
						</dl>
				</div>
				<div class="sect1">
						<div class="titlepage">
								<div>
										<h2 class="title" style="CLEAR: both">
												<a name="id2768459">
												</a>Contact</h2>
								</div>
						</div>
						<p>Email address: <a href="mailto:andreas.schaufler@gmx.de" target="_top">andreas.schaufler@gmx.de</a></p>
						<p>WWW: <a href="http://www.landshut.org/bnla01/members/Faustus" target="_top">http://www.landshut.org/bnla01/members/Faustus</a></p>
				</div>
		</div>
		<div class="navfooter">
				<hr />
		</div>
<img src ="http://www.cnitblog.com/darkstax/aggbug/18247.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cnitblog.com/darkstax/" target="_blank">darkstax</a> 2006-10-22 01:58 <a href="http://www.cnitblog.com/darkstax/articles/18247.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>Packet Sniffer Construction </title><link>http://www.cnitblog.com/darkstax/articles/18219.html</link><dc:creator>darkstax</dc:creator><author>darkstax</author><pubDate>Sat, 21 Oct 2006 02:47:00 GMT</pubDate><guid>http://www.cnitblog.com/darkstax/articles/18219.html</guid><wfw:comment>http://www.cnitblog.com/darkstax/comments/18219.html</wfw:comment><comments>http://www.cnitblog.com/darkstax/articles/18219.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cnitblog.com/darkstax/comments/commentRss/18219.html</wfw:commentRss><trackback:ping>http://www.cnitblog.com/darkstax/services/trackbacks/18219.html</trackback:ping><description><![CDATA[
		<pre>                     Packet Sniffer Construction 

                               Part II

                                 by

                             Chad Renfro
                           raw_sock@usa.net

   In the previous paper we discussed the use of the SOCK_RAW device 
for accessing packets  from the network layer, and how to interpret 
packets in a logical manor. This will serve as the basis for the 
next set of topics for constructing a more complete packet sniffer. 
The first topic will be error checking the socket function calls. 
Error checking will become invaluable as the code evolves into a more 
complete application. The second topic that this paper will concentrate 
on is the use of the  "ioctl" function for selecting and manipulating the
network interface. 

By looking at the code below you will notice that it has grown 
substantially since the last issue.  First the use of functions to has been
implemented to modularize the code, due to the fact that one of the main 
topics of this issue error checking. Modular coding is very helpful in 
quickly tracking down the problem in evolving code. This also helps the 
growing pains of adding new functions without backtracking and debugging 
the code base. Second all of the socket call have been "wrapped". Also 
remember in the first article the code was not really a true packet sniffer. 
This was due to the fact that the sniffer did not set the interface into 
promiscuous "PROMISC" mode. Promiscuous mode on a network interface 
enables an interface that is intended to look at traffic addressed only to its 6 
byte mac address to look at ALL traffic on the broadcast medium. This sniffer 
will utilize the Set_Promisc function to set the promiscuous flag on the 
network interface. In the original sniffer,the sniffer would get packets from 
the first non-loopback interface. All of the manipulation to the interface in 
this project will be done via the ioctl function call. The ioctl function call is 
"used to manipulate the underlying device parameters for special files", as 
stated by the BSD man pages. These special file are usually terminals, sockets 
and interfaces. Our concern is using ioctl to manipulate socket and the network 
interface. The interface in this project will be chosen by hard coding 
it in the "headers.h" file.

The ioctl function is the all in one function for ansii c when it comes to 
gathering and manipulating interface attributes. Although the following 
example shows how to retrieve and set certain flags on a given interface 
ioctl has many other uses that should be looked at as well. For a better
understanding of ioctl other features look at the ioctls.h and 
ioctl-types.h files.

<div style="BORDER-RIGHT: #cccccc 1px solid; PADDING-RIGHT: 5px; BORDER-TOP: #cccccc 1px solid; PADDING-LEFT: 4px; FONT-SIZE: 13px; PADDING-BOTTOM: 4px; BORDER-LEFT: #cccccc 1px solid; WIDTH: 98%; WORD-BREAK: break-all; PADDING-TOP: 4px; BORDER-BOTTOM: #cccccc 1px solid; BACKGROUND-COLOR: #eeeeee"><span style="COLOR: #008000">/*</span><span style="COLOR: #008000">***********************Tcp_sniff_2.c*******************</span><span style="COLOR: #008000">*/</span><span style="COLOR: #000000"><br /></span><span style="COLOR: #000000">1</span><span style="COLOR: #000000">.#include </span><span style="COLOR: #000000">&lt;</span><span style="COLOR: #000000">stdio.h</span><span style="COLOR: #000000">&gt;</span><span style="COLOR: #000000"><br /></span><span style="COLOR: #000000">2</span><span style="COLOR: #000000">.#include </span><span style="COLOR: #000000">&lt;</span><span style="COLOR: #000000">sys</span><span style="COLOR: #000000">/</span><span style="COLOR: #000000">socket.h</span><span style="COLOR: #000000">&gt;</span><span style="COLOR: #000000"><br /></span><span style="COLOR: #000000">3</span><span style="COLOR: #000000">.#include </span><span style="COLOR: #000000">&lt;</span><span style="COLOR: #000000">socketbits.h</span><span style="COLOR: #000000">&gt;</span><span style="COLOR: #000000"><br /></span><span style="COLOR: #000000">4</span><span style="COLOR: #000000">.#include </span><span style="COLOR: #000000">&lt;</span><span style="COLOR: #000000">sys</span><span style="COLOR: #000000">/</span><span style="COLOR: #000000">ioctl.h</span><span style="COLOR: #000000">&gt;</span><span style="COLOR: #000000"><br /></span><span style="COLOR: #000000">5</span><span style="COLOR: #000000">.#include </span><span style="COLOR: #000000">&lt;</span><span style="COLOR: #000000">net</span><span style="COLOR: #000000">/</span><span style="COLOR: #0000ff">if</span><span style="COLOR: #000000">.h</span><span style="COLOR: #000000">&gt;</span><span style="COLOR: #000000"><br /></span><span style="COLOR: #000000">6</span><span style="COLOR: #000000">.#include </span><span style="COLOR: #000000">&lt;</span><span style="COLOR: #000000">netinet</span><span style="COLOR: #000000">/</span><span style="COLOR: #0000ff">in</span><span style="COLOR: #000000">.h</span><span style="COLOR: #000000">&gt;</span><span style="COLOR: #000000"><br /></span><span style="COLOR: #000000">7</span><span style="COLOR: #000000">.#include </span><span style="COLOR: #000000">&lt;</span><span style="COLOR: #000000">arpa</span><span style="COLOR: #000000">/</span><span style="COLOR: #000000">inet.h</span><span style="COLOR: #000000">&gt;</span><span style="COLOR: #000000"><br /></span><span style="COLOR: #000000">8</span><span style="COLOR: #000000">.#include </span><span style="COLOR: #000000">&lt;</span><span style="COLOR: #000000">unistd.h</span><span style="COLOR: #000000">&gt;</span><span style="COLOR: #000000"><br /></span><span style="COLOR: #000000">9</span><span style="COLOR: #000000">.#include </span><span style="COLOR: #000000">"</span><span style="COLOR: #000000">headers.h</span><span style="COLOR: #000000">"</span><span style="COLOR: #000000"><br /><br /></span><span style="COLOR: #008000">/*</span><span style="COLOR: #008000">Prototype area</span><span style="COLOR: #008000">*/</span><span style="COLOR: #000000"><br /><br /></span><span style="COLOR: #000000">10</span><span style="COLOR: #000000">.</span><span style="COLOR: #0000ff">int</span><span style="COLOR: #000000"> Open_Raw_Socket(</span><span style="COLOR: #0000ff">void</span><span style="COLOR: #000000">);<br /></span><span style="COLOR: #000000">11</span><span style="COLOR: #000000">.</span><span style="COLOR: #0000ff">int</span><span style="COLOR: #000000"> Set_Promisc(</span><span style="COLOR: #0000ff">char</span><span style="COLOR: #000000"> </span><span style="COLOR: #000000">*</span><span style="COLOR: #0000ff">interface</span><span style="COLOR: #000000">, </span><span style="COLOR: #0000ff">int</span><span style="COLOR: #000000"> sock);<br /><br /></span><span style="COLOR: #000000">12</span><span style="COLOR: #000000">.</span><span style="COLOR: #0000ff">int</span><span style="COLOR: #000000"> main() {<br /></span><span style="COLOR: #000000">13</span><span style="COLOR: #000000">.    </span><span style="COLOR: #0000ff">int</span><span style="COLOR: #000000"> sock, bytes_recieved, fromlen;<br /></span><span style="COLOR: #000000">14</span><span style="COLOR: #000000">.    </span><span style="COLOR: #0000ff">char</span><span style="COLOR: #000000"> buffer[</span><span style="COLOR: #000000">65535</span><span style="COLOR: #000000">];<br /></span><span style="COLOR: #000000">15</span><span style="COLOR: #000000">.    </span><span style="COLOR: #0000ff">struct</span><span style="COLOR: #000000"> sockaddr_in from;<br /></span><span style="COLOR: #000000">16</span><span style="COLOR: #000000">.    </span><span style="COLOR: #0000ff">struct</span><span style="COLOR: #000000"> ip  </span><span style="COLOR: #000000">*</span><span style="COLOR: #000000">ip;<br /></span><span style="COLOR: #000000">17</span><span style="COLOR: #000000">.    </span><span style="COLOR: #0000ff">struct</span><span style="COLOR: #000000"> tcp </span><span style="COLOR: #000000">*</span><span style="COLOR: #000000">tcp;<br /><br /></span><span style="COLOR: #000000">18</span><span style="COLOR: #000000">.  sock </span><span style="COLOR: #000000">=</span><span style="COLOR: #000000"> Open_Raw_Socket();<br /><br />    </span><span style="COLOR: #008000">/*</span><span style="COLOR: #008000">now since the socket has been created,<br />      set the interface into promiscuous mode</span><span style="COLOR: #008000">*/</span><span style="COLOR: #000000"><br /><br /></span><span style="COLOR: #000000">19</span><span style="COLOR: #000000">.  Set_Promisc(INTERFACE, sock);<br /><br /><br /></span><span style="COLOR: #000000">20</span><span style="COLOR: #000000">.        </span><span style="COLOR: #0000ff">while</span><span style="COLOR: #000000">(</span><span style="COLOR: #000000">1</span><span style="COLOR: #000000">)<br /></span><span style="COLOR: #000000">22</span><span style="COLOR: #000000">.        {<br /></span><span style="COLOR: #000000">23</span><span style="COLOR: #000000">.               fromlen </span><span style="COLOR: #000000">=</span><span style="COLOR: #000000"> </span><span style="COLOR: #0000ff">sizeof</span><span style="COLOR: #000000"> from;<br /></span><span style="COLOR: #000000">24</span><span style="COLOR: #000000">.               bytes_recieved </span><span style="COLOR: #000000">=</span><span style="COLOR: #000000"> recvfrom(sock, buffer, </span><span style="COLOR: #0000ff">sizeof</span><span style="COLOR: #000000"> buffer,<br />                                 </span><span style="COLOR: #000000">0</span><span style="COLOR: #000000">, (</span><span style="COLOR: #0000ff">struct</span><span style="COLOR: #000000"> sockaddr </span><span style="COLOR: #000000">*</span><span style="COLOR: #000000">)</span><span style="COLOR: #000000">&amp;</span><span style="COLOR: #000000">from, </span><span style="COLOR: #000000">&amp;</span><span style="COLOR: #000000">fromlen);<br /></span><span style="COLOR: #000000">25</span><span style="COLOR: #000000">.               printf(</span><span style="COLOR: #000000">"</span><span style="COLOR: #000000">\nBytes received ::: %5d\n</span><span style="COLOR: #000000">"</span><span style="COLOR: #000000">,bytes_recieved);<br /></span><span style="COLOR: #000000">26</span><span style="COLOR: #000000">.               printf(</span><span style="COLOR: #000000">"</span><span style="COLOR: #000000">Source address ::: %s\n</span><span style="COLOR: #000000">"</span><span style="COLOR: #000000">,inet_ntoa(from.sin_addr));<br /></span><span style="COLOR: #000000">27</span><span style="COLOR: #000000">.               ip </span><span style="COLOR: #000000">=</span><span style="COLOR: #000000"> (</span><span style="COLOR: #0000ff">struct</span><span style="COLOR: #000000"> ip </span><span style="COLOR: #000000">*</span><span style="COLOR: #000000">)buffer;<br />                </span><span style="COLOR: #008000">/*</span><span style="COLOR: #008000">See if this is a TCP packet</span><span style="COLOR: #008000">*/</span><span style="COLOR: #000000"><br /></span><span style="COLOR: #000000">28</span><span style="COLOR: #000000">.               </span><span style="COLOR: #0000ff">if</span><span style="COLOR: #000000">(ip</span><span style="COLOR: #000000">-&gt;</span><span style="COLOR: #000000">ip_protocol </span><span style="COLOR: #000000">==</span><span style="COLOR: #000000"> </span><span style="COLOR: #000000">6</span><span style="COLOR: #000000">) {<br />                    </span><span style="COLOR: #008000">/*</span><span style="COLOR: #008000">This is a TCP packet</span><span style="COLOR: #008000">*/</span><span style="COLOR: #000000"><br /></span><span style="COLOR: #000000">29</span><span style="COLOR: #000000">.                     printf(</span><span style="COLOR: #000000">"</span><span style="COLOR: #000000">IP header length ::: %d\n</span><span style="COLOR: #000000">"</span><span style="COLOR: #000000">,ip</span><span style="COLOR: #000000">-&gt;</span><span style="COLOR: #000000">ip_length);<br /></span><span style="COLOR: #000000">30</span><span style="COLOR: #000000">.                     printf(</span><span style="COLOR: #000000">"</span><span style="COLOR: #000000">Protocol ::: %d\n</span><span style="COLOR: #000000">"</span><span style="COLOR: #000000">,ip</span><span style="COLOR: #000000">-&gt;</span><span style="COLOR: #000000">ip_protocol);<br /></span><span style="COLOR: #000000">31</span><span style="COLOR: #000000">.                     tcp </span><span style="COLOR: #000000">=</span><span style="COLOR: #000000"> (</span><span style="COLOR: #0000ff">struct</span><span style="COLOR: #000000"> tcp </span><span style="COLOR: #000000">*</span><span style="COLOR: #000000">)(buffer </span><span style="COLOR: #000000">+</span><span style="COLOR: #000000"> (</span><span style="COLOR: #000000">4</span><span style="COLOR: #000000">*</span><span style="COLOR: #000000">ip</span><span style="COLOR: #000000">-&gt;</span><span style="COLOR: #000000">ip_length));<br /></span><span style="COLOR: #000000">32</span><span style="COLOR: #000000">.                     printf(</span><span style="COLOR: #000000">"</span><span style="COLOR: #000000">Source port ::: %d\n</span><span style="COLOR: #000000">"</span><span style="COLOR: #000000">,ntohs(tcp</span><span style="COLOR: #000000">-&gt;</span><span style="COLOR: #000000">tcp_source_port));<br /></span><span style="COLOR: #000000">33</span><span style="COLOR: #000000">.                     printf(</span><span style="COLOR: #000000">"</span><span style="COLOR: #000000">Dest port  ::: %d\n</span><span style="COLOR: #000000">"</span><span style="COLOR: #000000">,ntohs(tcp</span><span style="COLOR: #000000">-&gt;</span><span style="COLOR: #000000">tcp_dest_port));<br /></span><span style="COLOR: #000000">34</span><span style="COLOR: #000000">.               }<br /><br /></span><span style="COLOR: #000000">35</span><span style="COLOR: #000000">.        }<br /></span><span style="COLOR: #000000">36</span><span style="COLOR: #000000">.}<br /><br /></span><span style="COLOR: #000000">37</span><span style="COLOR: #000000">.</span><span style="COLOR: #0000ff">int</span><span style="COLOR: #000000"> Open_Raw_Socket() {<br /></span><span style="COLOR: #000000">38</span><span style="COLOR: #000000">. </span><span style="COLOR: #0000ff">int</span><span style="COLOR: #000000"> sock;<br /></span><span style="COLOR: #000000">39</span><span style="COLOR: #000000">.   </span><span style="COLOR: #0000ff">if</span><span style="COLOR: #000000">((sock </span><span style="COLOR: #000000">=</span><span style="COLOR: #000000"> socket(AF_INET, SOCK_RAW, IPPROTO_TCP)) </span><span style="COLOR: #000000">&lt;</span><span style="COLOR: #000000"> </span><span style="COLOR: #000000">0</span><span style="COLOR: #000000">) {<br />        </span><span style="COLOR: #008000">/*</span><span style="COLOR: #008000">Then the socket was not created properly and must die</span><span style="COLOR: #008000">*/</span><span style="COLOR: #000000"><br /></span><span style="COLOR: #000000">40</span><span style="COLOR: #000000">.        perror(</span><span style="COLOR: #000000">"</span><span style="COLOR: #000000">The raw socket was not created</span><span style="COLOR: #000000">"</span><span style="COLOR: #000000">);<br /></span><span style="COLOR: #000000">41</span><span style="COLOR: #000000">.        exit(</span><span style="COLOR: #000000">0</span><span style="COLOR: #000000">);<br /></span><span style="COLOR: #000000">42</span><span style="COLOR: #000000">.   };<br /></span><span style="COLOR: #000000">43</span><span style="COLOR: #000000">.       </span><span style="COLOR: #0000ff">return</span><span style="COLOR: #000000">(sock);<br /></span><span style="COLOR: #000000">44</span><span style="COLOR: #000000">. }<br /><br /></span><span style="COLOR: #000000">45</span><span style="COLOR: #000000">.</span><span style="COLOR: #0000ff">int</span><span style="COLOR: #000000"> Set_Promisc(</span><span style="COLOR: #0000ff">char</span><span style="COLOR: #000000"> </span><span style="COLOR: #000000">*</span><span style="COLOR: #0000ff">interface</span><span style="COLOR: #000000">, </span><span style="COLOR: #0000ff">int</span><span style="COLOR: #000000"> sock ) {<br /></span><span style="COLOR: #000000">46</span><span style="COLOR: #000000">.       </span><span style="COLOR: #0000ff">struct</span><span style="COLOR: #000000"> ifreq ifr;<br /></span><span style="COLOR: #000000">47</span><span style="COLOR: #000000">.       strncpy(ifr.ifr_name, </span><span style="COLOR: #0000ff">interface</span><span style="COLOR: #000000">,strnlen(</span><span style="COLOR: #0000ff">interface</span><span style="COLOR: #000000">)</span><span style="COLOR: #000000">+</span><span style="COLOR: #000000">1</span><span style="COLOR: #000000">);<br /></span><span style="COLOR: #000000">48</span><span style="COLOR: #000000">.       </span><span style="COLOR: #0000ff">if</span><span style="COLOR: #000000">((ioctl(sock, SIOCGIFFLAGS, </span><span style="COLOR: #000000">&amp;</span><span style="COLOR: #000000">ifr) </span><span style="COLOR: #000000">==</span><span style="COLOR: #000000"> </span><span style="COLOR: #000000">-</span><span style="COLOR: #000000">1</span><span style="COLOR: #000000">)) {<br />                </span><span style="COLOR: #008000">/*</span><span style="COLOR: #008000">Could not retrieve flags for the interface</span><span style="COLOR: #008000">*/</span><span style="COLOR: #000000"><br /></span><span style="COLOR: #000000">49</span><span style="COLOR: #000000">.               perror(</span><span style="COLOR: #000000">"</span><span style="COLOR: #000000">Could not retrive flags for the interface</span><span style="COLOR: #000000">"</span><span style="COLOR: #000000">);<br /></span><span style="COLOR: #000000">50</span><span style="COLOR: #000000">.               exit(</span><span style="COLOR: #000000">0</span><span style="COLOR: #000000">);<br /></span><span style="COLOR: #000000">51</span><span style="COLOR: #000000">.       }<br /></span><span style="COLOR: #000000">52</span><span style="COLOR: #000000">.       printf(</span><span style="COLOR: #000000">"</span><span style="COLOR: #000000">The interface is ::: %s\n</span><span style="COLOR: #000000">"</span><span style="COLOR: #000000">, </span><span style="COLOR: #0000ff">interface</span><span style="COLOR: #000000">);<br /></span><span style="COLOR: #000000">53</span><span style="COLOR: #000000">.       perror(</span><span style="COLOR: #000000">"</span><span style="COLOR: #000000">Retrieved flags from interface successfully</span><span style="COLOR: #000000">"</span><span style="COLOR: #000000">);<br /><br />        </span><span style="COLOR: #008000">/*</span><span style="COLOR: #008000">now that the flags have been retrieved</span><span style="COLOR: #008000">*/</span><span style="COLOR: #000000"><br />        </span><span style="COLOR: #008000">/*</span><span style="COLOR: #008000"> set the flags to PROMISC </span><span style="COLOR: #008000">*/</span><span style="COLOR: #000000"><br /></span><span style="COLOR: #000000">54</span><span style="COLOR: #000000">.       ifr.ifr_flags </span><span style="COLOR: #000000">|=</span><span style="COLOR: #000000"> IFF_PROMISC;<br /></span><span style="COLOR: #000000">55</span><span style="COLOR: #000000">.       </span><span style="COLOR: #0000ff">if</span><span style="COLOR: #000000"> (ioctl (sock, SIOCSIFFLAGS, </span><span style="COLOR: #000000">&amp;</span><span style="COLOR: #000000">ifr) </span><span style="COLOR: #000000">==</span><span style="COLOR: #000000"> </span><span style="COLOR: #000000">-</span><span style="COLOR: #000000">1</span><span style="COLOR: #000000"> ) {<br />                </span><span style="COLOR: #008000">/*</span><span style="COLOR: #008000">Could not set the flags on the interface </span><span style="COLOR: #008000">*/</span><span style="COLOR: #000000"><br /></span><span style="COLOR: #000000">56</span><span style="COLOR: #000000">.               perror(</span><span style="COLOR: #000000">"</span><span style="COLOR: #000000">Could not set the PROMISC flag:</span><span style="COLOR: #000000">"</span><span style="COLOR: #000000">);<br /></span><span style="COLOR: #000000">57</span><span style="COLOR: #000000">.               exit(</span><span style="COLOR: #000000">0</span><span style="COLOR: #000000">);<br /></span><span style="COLOR: #000000">58</span><span style="COLOR: #000000">.       }<br /></span><span style="COLOR: #000000">59</span><span style="COLOR: #000000">.       printf(</span><span style="COLOR: #000000">"</span><span style="COLOR: #000000">Setting interface ::: %s ::: to promisc</span><span style="COLOR: #000000">"</span><span style="COLOR: #000000">, </span><span style="COLOR: #0000ff">interface</span><span style="COLOR: #000000">);<br /><br /></span><span style="COLOR: #000000">60</span><span style="COLOR: #000000">.       </span><span style="COLOR: #0000ff">return</span><span style="COLOR: #000000">(</span><span style="COLOR: #000000">0</span><span style="COLOR: #000000">);<br /></span><span style="COLOR: #000000">61</span><span style="COLOR: #000000">. }<br /><br /><br /></span><span style="COLOR: #008000">/*</span><span style="COLOR: #008000">**********************EOF*********************************</span><span style="COLOR: #008000">*/</span><span style="COLOR: #000000"><br /></span></div>
Now we will examine the code line by line. Most of the code base
has not changed and therefore we will not spend time going over the 
original code. Lets get started.



18.  sock = Open_Raw_Socket();
	Here is the call to open the raw socket. Now 
	jump down and look at the Open_Raw_Socket 
	function.

	37.int Open_Raw_Socket() {
	38. int sock;
	39.   if((sock = socket(AF_INET, SOCK_RAW, IPPROTO_TCP)) &lt; 0) {
	        /*Then the socket was not created properly and must die*/
	40.        perror("The raw socket was not created");
	41.        exit(0);
	42.   };
	43.       return(sock);
	44. }

	
	Allot of this function should look familiar from the first paper.
	The socket call is the same only this time the socket function
	is wrapped in an if statement to test for an error return. Remember
	all the socket call does is create an endpoint for communication
	if successful it will return a socket descriptor ( an integer )
	and if the call fails it will return a "-1". This is what line
	39 is testing for, if the socket returns a value less
	than 0 it must have failed. If it fails two other tasks must
	take place. First report the error using perror, this will 
	print the error to std_out and will also print the "errno" 
	value that will describe where the last call failed. Second the 
	exit call is used to halt the execution of the program. Now
	most good programs will also close any open file/socket descriptors
	before the exit is called. This is not really necessary due to
	the fact that the exit call will close all open descriptors 
	before it closes. 
	
	Hopefully the socket will succeed and return an open descriptor
	If it does the function will perform the return(sock) call and send
	back an open descriptor to the call on line 18 and store the 
	descriptor in "sock". If the socket call fails this could be caused
	by a defective interface or the user running the program not having
	the correct permissions. Remember to open a socket the user must
	have root access.
	

19.  Set_Promisc(INTERFACE, sock);
	Now that the socket has been successfully created the interface 
	can be chosen and manipulated. For this example the interface has
	been preselected and hard coded into "headers.h" it reads,
			
		#define INTERFACE "eth0"

	This is not the optimal way to choose an interface due to the 
	fact that there are calls to query for all network interfaces
	using ioctl. Given that this is our first exercise using ioctl
	the emphasis will be placed on the use of ioctl to manipulate
	the flags for a predefined interface. 
	
	45.int Set_Promisc(char *interface, int sock ) {
	46.       struct ifreq ifr;
	47.       strncpy(ifr.ifr_name, interface,strnlen(interface)+1);
	48.       if((ioctl(sock, SIOCGIFFLAGS, &amp;ifr) == -1)) {
	                /*Could not retrieve flags for the interface*/
	49.               perror("Could not retrive flags for the interface");
	50.               exit(0);
	51.       }
	52.       printf("The interface is ::: %s\n", interface);
	53.       perror("Retrieved flags from interface successfully");
	          /*now that the flags have been retrieved*/
	          /* set the flags to PROMISC */
	54.       ifr.ifr_flags |= IFF_PROMISC;
	55.       if (ioctl (sock, SIOCSIFFLAGS, &amp;ifr) == -1 ) {
	                /*Could not set the flags on the interface */
	56.               perror("Could not set the PROMISC flag:");
	57.               exit(0);
	58.       }
	59.       printf("Setting interface ::: %s ::: to promisc", interface);
	60.       return(0);
	61. } 
	
  Starting at line 45, look at the beginning of the Set_Promisc function. As the 
  name implies the sole purpose of this function is to set a network
  interface into promiscuous mode. The function takes two parameters, the
  a char pointer to the interface and the integer that references the 
  open raw socket. Now starting with line 46 we will introduce ioctl.

46.       struct ifreq ifr;
	This is an interface request structure used for socket ioctl.
	The ifreq structure is a rather large structure the main members
	that will be used in this structure are the members that hold the 
	interface name and the interface flags.

47.       strncpy(ifr.ifr_name, interface,strnlen(interface)+1);
	     	Earlier we addressed the fact that we had the interface
		predetermined and hard coded in "headers.h". Here the 
		value held in interface must be copied into the ifr structure
		into the ifr.ifr_name member. This is due to the fact that
		the ioctl call will require an address to a interface request
		structure with the name of the interface in the structure.

48.       if((ioctl(sock, SIOCGIFFLAGS, &amp;ifr) == -1))
		Here is the first ioctl call that will get the flags of
		the interface name that was placed in the ifr struct earlier
		look at the internal ioctl call :

		  ioctl(sock, SIOCGIFFLAGS, &amp;ifr)
		
		the first parameter is an open socket descriptor "sock"
		the second is the request that is to be performed. In 
		this case the call is requesting "SOCGIFFLAGS" which 
		will get the flags of the "eth0" interface. The third
		parameter is an address of an interface request structure
		ifr which hold the name of the interface that will be 
		queried.   This step must be performed before the promisc 
                flag can be set. Now look at the entire line, the ioctl 
                call is all being tested for its return. On success the 
                call will return "0" and if the call fails a "-1" will 
                be returned.

54.       ifr.ifr_flags |= IFF_PROMISC;
		This is where the interface flags are changed. Here
		the promiscuous flag is being applied to the interface
		structure ifr. Notice the notation "|=" this is what 
		applies the promiscuous flag to the ifr structure. 
		Although the promisc flag is applied here this is not 
		the final step there is still one final call to set 
		the new flags into place. This is what is called bit 
		testing, to see if a certain bit is set. There is a 
		very special notation for altering and testing bits.
			To set a specific bit use a binary "or"  "|" to combine
			the bit var with the needed bit mask:
			  x = x|mask;
			
			To unset a specific bit use the binary "and" "&amp;" with
			the complement sign "~" of the mask :
			  x= x &amp; ~mask;

			To just test if a bit is on, use the "&amp;" sign and 
			evaluate the result for a non zero value : 
			
			 result=x &amp; mask; 
 

55.       if (ioctl (sock, SIOCSIFFLAGS, &amp;ifr) == -1 )
		This is the final ioctl call to put the device into
		promiscuous mode. Just as the first call retrieved the 
		flags of the interface, this call sets the new revised
		flags that were set in the ifr struct to the physical 
		interface. Also notice that just as in the first ioctl
		call that the return value here is being tested for 
		success.

59.       printf("Setting interface ::: %s ::: to promisc", interface);
		If all goes well this message should be sent to 
		std_out letting the end_user know that the socket 
		was created and that the interface was set into    
		promiscuous mode properly.

60.       return(0);
		Finally the value of "0" is sent back to the original
		call to signify that the function completed successfully.



There is still allot of functionally that could be added to the 
sniffer to make it more complete but most of that is parsing the raw packets
into some desired output form. 

The next step in constructing a more complete sniffer would be to be able to
capture not just a single protocol but all packets. This is the major drawback
to this project is the fact that only Tcp based packets can be viewed. To work
around that the SOCK_RAW device should be replaced with SOCK_PACKET.

However this is only for linux based operating systems. A better solution 
wouldbe to use a preconstructed API like libpcap written by Lawrence 
Berkeley National Laboratory. The use of libpcap was designed to make the 
sniffer code more portable across different operating systems. Now guess 
what the next issue will deal with.
 


This is the end of part two 

	1. Beej's Guide to Network Programming
	     This is an awesome paper that really helps 
	     clear up any misconceptions about network programming.
                             [http://www.ecst.csuchico.edu/~beej/guide/net

       2. TCP/IP Illustrated Vol 1,2,3, Unix Network Programing
          W.Richard Stevens


/*************************headers.h**************************/
/*structure of an ip header*/
struct ip {
	unsigned int        ip_length:4;    /*little-endian*/
	unsigned int         ip_version:4;
	unsigned char       ip_tos;
	unsigned short      ip_total_length;
	unsigned short      ip_id;
	unsigned short      ip_flags;
	unsigned char       ip_ttl;
	unsigned char       ip_protocol;
	unsigned short      ip_cksum;
	unsigned int          ip_source;
	unsigned int          ip_dest;
};

/* Structure of a TCP header */
struct tcp {
	unsigned short      tcp_source_port;
	unsigned short      tcp_dest_port;
	unsigned int         tcp_seqno;
	unsigned int         tcp_ackno;
	unsigned int         tcp_res1:4,     /*little-endian*/
	tcp_hlen:4,
	tcp_fin:1,
 	tcp_syn:1,
	tcp_rst:1,
	tcp_psh:1,
	tcp_ack:1,
	tcp_urg:1,
	tcp_res2:2;
	unsigned short      tcp_winsize;
	unsigned short      tcp_cksum;
	unsigned short      tcp_urgent;
};
/*********************EOF***********************************/
</pre>
<img src ="http://www.cnitblog.com/darkstax/aggbug/18219.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cnitblog.com/darkstax/" target="_blank">darkstax</a> 2006-10-21 10:47 <a href="http://www.cnitblog.com/darkstax/articles/18219.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>Basic Packet-Sniffer Construction from the Ground Up</title><link>http://www.cnitblog.com/darkstax/articles/18194.html</link><dc:creator>darkstax</dc:creator><author>darkstax</author><pubDate>Fri, 20 Oct 2006 10:01:00 GMT</pubDate><guid>http://www.cnitblog.com/darkstax/articles/18194.html</guid><wfw:comment>http://www.cnitblog.com/darkstax/comments/18194.html</wfw:comment><comments>http://www.cnitblog.com/darkstax/articles/18194.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cnitblog.com/darkstax/comments/commentRss/18194.html</wfw:commentRss><trackback:ping>http://www.cnitblog.com/darkstax/services/trackbacks/18194.html</trackback:ping><description><![CDATA[
		<pre>                           Basic Packet-Sniffer Construction
			          from the Ground Up

                                       Part 1
                                         by

                                     Chad Renfro
				 raw_sock@hotmail.com


   Packet sniffers are applications used by network administrators to monitor and
validate network traffic. Sniffers are programs used to read packets that travel across 
the network at various levels of the OSI layer. And like most security tools sniffers too
can be used for both good and destructive purposes. On the light-side of network
administration sniffers help quickly track down problems such as bottlenecks and
misplaced filters. However on the dark-side sniffers can be used to reap tremendous
amounts of havoc by gathering legitimate user names and passwords so that other
machines can be quickly compromised. Hopefully this paper will be used to help
administrators gain control of their networks by being able to analyze network traffic 
not only by using preconstructed  sniffers but by being able to create their own. This
paper will look at the packet sniffer from the bottem up, looking in depth at the sniffer
core and then gradualy adding functionality to the application. The example included
here will help illustrate some rather cumbersome issues when dealing with network
programing. In no way will this single paper teach a person to write a complete sniffing
application like tcpdump or sniffit. It will however teach some very fundamental issues
that are inherent to all packet sniffers. Like how the packets are accessed on the network
and how to work with the packets at different layers.








The most basic sniffer...

Sniffer #1.

   This sniffer will illustrate the use of the  SOCK_RAW device and show how to gather
packets from the network and print out some simple header  information to std_out.
Although the basic premise is that packet sniffers operate  in a promiscuous mode which
listens to all packets weather or not the packet is destined  for the machines mac address,
this example will collect packets in a non-promiscuous mode . This will let usconcentrate
on the SOCK_RAW device for the first example. To operate this same  code  in a
promiscous mode  the network card may be put in a promiscous mode manually. To do
this type this in after the log in :


   &gt; su -
   Password : ********
   # ifconfig eth0 promisc

   This will now set the network interface eth0 in promiscous mode. 

<div style="BORDER-RIGHT: #cccccc 1px solid; PADDING-RIGHT: 5px; BORDER-TOP: #cccccc 1px solid; PADDING-LEFT: 4px; FONT-SIZE: 13px; PADDING-BOTTOM: 4px; BORDER-LEFT: #cccccc 1px solid; WIDTH: 98%; WORD-BREAK: break-all; PADDING-TOP: 4px; BORDER-BOTTOM: #cccccc 1px solid; BACKGROUND-COLOR: #eeeeee"><span style="COLOR: #000000"><br /></span><span style="COLOR: #008000">/*</span><span style="COLOR: #008000">***********************simple_Tcp_sniff.c*******************</span><span style="COLOR: #008000">*/</span><span style="COLOR: #000000"><br /><br /></span><span style="COLOR: #000000">1</span><span style="COLOR: #000000">.    #include </span><span style="COLOR: #000000">&lt;</span><span style="COLOR: #000000">stdio.h</span><span style="COLOR: #000000">&gt;</span><span style="COLOR: #000000"><br /></span><span style="COLOR: #000000">2</span><span style="COLOR: #000000">.    #include </span><span style="COLOR: #000000">&lt;</span><span style="COLOR: #000000">sys</span><span style="COLOR: #000000">/</span><span style="COLOR: #000000">socket.h</span><span style="COLOR: #000000">&gt;</span><span style="COLOR: #000000"><br /></span><span style="COLOR: #000000">3</span><span style="COLOR: #000000">.    #include </span><span style="COLOR: #000000">&lt;</span><span style="COLOR: #000000">netinet</span><span style="COLOR: #000000">/</span><span style="COLOR: #0000ff">in</span><span style="COLOR: #000000">.h</span><span style="COLOR: #000000">&gt;</span><span style="COLOR: #000000"><br /></span><span style="COLOR: #000000">4</span><span style="COLOR: #000000">.    #include </span><span style="COLOR: #000000">&lt;</span><span style="COLOR: #000000">arpa</span><span style="COLOR: #000000">/</span><span style="COLOR: #000000">inet.h</span><span style="COLOR: #000000">&gt;</span><span style="COLOR: #000000"><br /><br /></span><span style="COLOR: #000000">5</span><span style="COLOR: #000000">.    #include </span><span style="COLOR: #000000">"</span><span style="COLOR: #000000">headers.h</span><span style="COLOR: #000000">"</span><span style="COLOR: #000000"><br /><br /></span><span style="COLOR: #000000">6</span><span style="COLOR: #000000">.    </span><span style="COLOR: #0000ff">int</span><span style="COLOR: #000000"> main()<br /></span><span style="COLOR: #000000">7</span><span style="COLOR: #000000">.    {<br /></span><span style="COLOR: #000000">8</span><span style="COLOR: #000000">.        </span><span style="COLOR: #0000ff">int</span><span style="COLOR: #000000"> sock, bytes_recieved, fromlen;<br /></span><span style="COLOR: #000000">9</span><span style="COLOR: #000000">.        </span><span style="COLOR: #0000ff">char</span><span style="COLOR: #000000"> buffer[</span><span style="COLOR: #000000">65535</span><span style="COLOR: #000000">];<br /></span><span style="COLOR: #000000">10</span><span style="COLOR: #000000">.        </span><span style="COLOR: #0000ff">struct</span><span style="COLOR: #000000"> sockaddr_in from;<br /></span><span style="COLOR: #000000">11</span><span style="COLOR: #000000">.        </span><span style="COLOR: #0000ff">struct</span><span style="COLOR: #000000"> ip  </span><span style="COLOR: #000000">*</span><span style="COLOR: #000000">ip;<br /></span><span style="COLOR: #000000">12</span><span style="COLOR: #000000">.        </span><span style="COLOR: #0000ff">struct</span><span style="COLOR: #000000"> tcp </span><span style="COLOR: #000000">*</span><span style="COLOR: #000000">tcp;<br /></span><span style="COLOR: #000000">13</span><span style="COLOR: #000000">.<br /><br /></span><span style="COLOR: #000000">14</span><span style="COLOR: #000000">.        sock </span><span style="COLOR: #000000">=</span><span style="COLOR: #000000"> socket(AF_INET, SOCK_RAW, IPPROTO_TCP);<br /><br /></span><span style="COLOR: #000000">15</span><span style="COLOR: #000000">.    </span><span style="COLOR: #0000ff">while</span><span style="COLOR: #000000">(</span><span style="COLOR: #000000">1</span><span style="COLOR: #000000">)<br /></span><span style="COLOR: #000000">16</span><span style="COLOR: #000000">.     {<br /></span><span style="COLOR: #000000">17</span><span style="COLOR: #000000">.        fromlen </span><span style="COLOR: #000000">=</span><span style="COLOR: #000000"> </span><span style="COLOR: #0000ff">sizeof</span><span style="COLOR: #000000"> from;<br /></span><span style="COLOR: #000000">18</span><span style="COLOR: #000000">.        bytes_recieved </span><span style="COLOR: #000000">=</span><span style="COLOR: #000000"> recvfrom(sock, buffer, </span><span style="COLOR: #0000ff">sizeof</span><span style="COLOR: #000000"> buffer, </span><span style="COLOR: #000000">0</span><span style="COLOR: #000000">,<br />                                             (</span><span style="COLOR: #0000ff">struct</span><span style="COLOR: #000000"> sockaddr </span><span style="COLOR: #000000">*</span><span style="COLOR: #000000">)</span><span style="COLOR: #000000">&amp;</span><span style="COLOR: #000000">from, </span><span style="COLOR: #000000">&amp;</span><span style="COLOR: #000000">fromlen);<br /></span><span style="COLOR: #000000">19</span><span style="COLOR: #000000">.        printf(</span><span style="COLOR: #000000">"</span><span style="COLOR: #000000">\nBytes received ::: %5d\n</span><span style="COLOR: #000000">"</span><span style="COLOR: #000000">,bytes_recieved);<br /></span><span style="COLOR: #000000">20</span><span style="COLOR: #000000">.        printf(</span><span style="COLOR: #000000">"</span><span style="COLOR: #000000">Source address ::: %s\n</span><span style="COLOR: #000000">"</span><span style="COLOR: #000000">,inet_ntoa(from.sin_addr));<br /></span><span style="COLOR: #000000">21</span><span style="COLOR: #000000">.        ip </span><span style="COLOR: #000000">=</span><span style="COLOR: #000000"> (</span><span style="COLOR: #0000ff">struct</span><span style="COLOR: #000000"> ip </span><span style="COLOR: #000000">*</span><span style="COLOR: #000000">)buffer;<br /></span><span style="COLOR: #000000">22</span><span style="COLOR: #000000">.        printf(</span><span style="COLOR: #000000">"</span><span style="COLOR: #000000">IP header length ::: %d\n</span><span style="COLOR: #000000">"</span><span style="COLOR: #000000">,ip</span><span style="COLOR: #000000">-&gt;</span><span style="COLOR: #000000">ip_length);<br /></span><span style="COLOR: #000000">23</span><span style="COLOR: #000000">.        printf(</span><span style="COLOR: #000000">"</span><span style="COLOR: #000000">Protocol ::: %d\n</span><span style="COLOR: #000000">"</span><span style="COLOR: #000000">,ip</span><span style="COLOR: #000000">-&gt;</span><span style="COLOR: #000000">ip_protocol);<br /></span><span style="COLOR: #000000">24</span><span style="COLOR: #000000">.        tcp </span><span style="COLOR: #000000">=</span><span style="COLOR: #000000"> (</span><span style="COLOR: #0000ff">struct</span><span style="COLOR: #000000"> tcp </span><span style="COLOR: #000000">*</span><span style="COLOR: #000000">)(buffer </span><span style="COLOR: #000000">+</span><span style="COLOR: #000000"> (</span><span style="COLOR: #000000">4</span><span style="COLOR: #000000">*</span><span style="COLOR: #000000">ip</span><span style="COLOR: #000000">-&gt;</span><span style="COLOR: #000000">ip_length));<br /></span><span style="COLOR: #000000">25</span><span style="COLOR: #000000">.        printf(</span><span style="COLOR: #000000">"</span><span style="COLOR: #000000">Source port ::: %d\n</span><span style="COLOR: #000000">"</span><span style="COLOR: #000000">,ntohs(tcp</span><span style="COLOR: #000000">-&gt;</span><span style="COLOR: #000000">tcp_source_port);<br /></span><span style="COLOR: #000000">26</span><span style="COLOR: #000000">.        printf(</span><span style="COLOR: #000000">"</span><span style="COLOR: #000000">Dest port  ::: %d\n</span><span style="COLOR: #000000">"</span><span style="COLOR: #000000">,ntohs(tcp</span><span style="COLOR: #000000">-&gt;</span><span style="COLOR: #000000">tcp_dest_port));<br /><br /></span><span style="COLOR: #000000">27</span><span style="COLOR: #000000">.             }<br /></span><span style="COLOR: #000000">28</span><span style="COLOR: #000000">. }<br /></span><span style="COLOR: #008000">/*</span><span style="COLOR: #008000">**********************EOF*********************************</span><span style="COLOR: #008000">*/</span><span style="COLOR: #000000"><br /></span></div>
What this means :

Line 1-4 :
   These are the header files required to use some needed c functions we will use later

	&lt;stdio.h&gt;      =     functions like printf and std_out
	&lt;sys/socket.h&gt; =     this will give access to the SOCK_RAW and the 
	                     IPPROTO_TCP defines 	
	&lt;netinet/in.h&gt; =     structs like the sockaddr_in 
	&lt;arpa/inet.h&gt;  =     lets us use the functions to do network to host byte 
	                     order conversions
line 5 :
   This is the header file headers.h that is also included with this program to give standard
   structures to access the ip and tcp fields. The structures identify each field in the ip and
   tcp header for instance :
 
	struct ip {
	       unsigned int        ip_length:4;         /* length of ip-header in 32-bit
                                                           words*/
 	       unsigned int        ip_version:4;        /* set to "4", for Ipv4 */
	       unsigned char       ip_tos;              /* type of service*/
	       unsigned short      ip_total_length;     /* Total length of ip datagram in
                                                           bytes */
	       unsigned short      ip_id;               /*identification field*/
	       unsigned short      ip_flags;
	       unsigned char       ip_ttl;              /*time-to-live, sets upper limit
                                                          for max number of routers to 
                                                          go through before the packet is
                                                          discarded*/

	       unsigned char       ip_protocol;         /*identifies the correct transport
			                                  protocol */
	       unsigned short      ip_cksum;            /*calculated for the ip header ONLY*/
               unsigned int        ip_source;           /*source ip */
               unsigned int        ip_dest;             /*dest ip*/
	};



	struct tcp {
                 unsigned short     tcp_source_port; /*tcp source port*/
	         unsigned short     tcp_dest_port;   /*tcp dest port*/
	         unsigned int       tcp_seqno;       /*tcp sequence number,
                                                       identifies the byte in the 
                                                       stream of data*/
	         unsigned int       tcp_ackno;       /*contains the next seq num that
                                                       the sender expects to recieve*/
	         unsigned int       tcp_res1:4,      /*little-endian*/
                                    tcp_hlen:4,      /*length of tcp header in 32-bit
                                                       words*/ 
	                            tcp_fin:1,       /*Finish flag "fin"*/
                                    tcp_syn:1,       /*Synchronize sequence
                                                       numbers to start a connection
		                    tcp_rst:1,       /*Reset flag */
                                    tcp_psh:1,       /*Push, sends data to the
                                                       application*/
                                    tcp_ack:1,       /*acknowledge*/
                                    tcp_urg:1,       /*urgent pointer*/
                                    tcp_res2:2;
                 unsigned short     tcp_winsize;     /*maxinum number of bytes able
		                                       to recieve*/
	         unsigned short     tcp_cksum;       /*checksum to cover the tcp
                                                       header and data portion of the
                                                       packet*/

	         unsigned short     tcp_urgent;     /*vaild only if the urgent flag is
			                              set, used to transmit
                                                      emergency data */
	};


line 8-13 :
   This is the variable declaration section
      
	integers :
	     sock                 = socket file descriptor 
	     bytes_recieved       = bytes read from the open socket "sock" 
	     fromlen              = the size of the from structure char :
             buffer               = where the ip packet that is read off the 
		                    wire will be held buffer will hold a datagram 
		                    of 65535 bytes which is the maximum length 
		                    of an ip datagram.

       Struct sockaddr_in :

	   struct sockaddr_in {
		short int          sin_family;  /* Address family   */
		unsigned short int sin_port;    /* Port number      */
		struct in_addr     sin_addr;    /* Internet address */
		unsigned char      sin_zero[8]; /* Same size as struct sockaddr */
	    };

      Before we go any further two topics should be covered,byte-ordering and sockaddr
   structures.  Byte-ordering,is the way that the operating system stores bytes in memory.
   There are two ways that this is done first with the low-order byte at the starting address
   this is known as "little-endian" or host-byte order. Next bytes can be stored with the
   high order byte at the starting address, this is called "big-endian" or network byte order.
   The Internet protocol uses &gt;&gt;&gt;&gt;&gt;&gt; network byte order.
    
       This is important because if you are working on an intel based linux box you will be
   programming on a little-endian machine and to send data via ip you must convert the
   bytes to network-byte order. For examle lets say we are going to store a 2-byte number
   in memory say the value is (in hex) 0x0203


   First this is how the value is stored on a big-endian machine:

                    ___________
                   | 02  | 03  |
                   |_____|_____| 
        address:    0       1


   And here is the same value on a little-endian machine:

                   ___________
                  |03   | 02  |
                  |_____|_____|
       address:    1       0



   The same value is being represented in both examples it is just how we order the bytes
   that changes.

   The next topic that you must understand is the sockaddr vs. the sockaddr_in structures.
   The struct sockaddr is used to hold information about the socket such as the family type
   and other address information it looks like :

	struct sockaddr {
	          unsigned short sa_family;         /*address family*/ 
                  char           sa_data[14];       /*address data*/
	};
	 
	
      The first element in the structure "sa_family" will be used to reference what the family
   type is for the socket, in our sniffer it will be AF_INET. Next the "sa_data" element
   holds the destination port and address for the socket. To make it easier to deal with the
   sockaddr struct the use of the sockaddr_in structure is commonly used. Sockaddr_in 
   makes it easier to reference all of the elements that are contained by sockaddr.


   Sockaddr_in looks like:



   struct sockaddr_in {
             short int          sin_family;    /* Address family               */
             unsigned short int sin_port;      /* Port number                  */
             struct in_addr     sin_addr;      /* Internet address             */
             unsigned char      sin_zero[8];   /* Same size as struct sockaddr */
   };







      We will use this struct and declare a variable "from" which will give us the information
   on the packet that we will collect from the raw socket. For instance the var
   "from.sin_addr" will give access to the packets source address (in 
   network byte order). The thing to mention here is that all items in the sockaddr_in
   structure must be in network-byte order. When we receive the data in the sockaddr_in
   struct we must then convert it back to Host-byte order. To do this we can use some
   predefined functions to convert back and forth between  host and network byteorder.

   Here are the functions we will use:

	ntohs       : this function converts  network byte order to host byte order
                      for a 16-bit short

	ntohl       : same as above but for a 32-bit long

	inet_ntoa   : this function converts a 32-bit network binary value to a
                      dotted decimal ip address

	inet_aton   : converts a character string  address to the 32-bit network
                      binary value

	inet_addr   : takes a char string dotted decimal addr and returns a 32-bit
                      network binary value

   To further illustrate ,say I want to know the port number that this packet originated from:

	int packet_port; packet_port	=ntohs(from.sin_port);
		                         ^^^^^	

   If I want the source IP address of the packet we will use a special function to get it to the
   123.123.123.123 format:

	char *ip_addr; ip_addr	=inet_ntoa(from.sin_addr)
		                 ^^^^^^^^^

line 11-12:

   struct ip *ip :
   struct tcp *tcp :
	
      This is a structure that we defined in our header file "headers.h". This structure is
   declared so that we can access individual fields of the ip/tcp header. The structure is like
   a transparent slide with predefined fields drawn on it. When a packet is taken off 
   the wire it is a stream of bits, to make sense of it the "transparency" (or cast) is laid on
   top of or over the bits so the individual fields can be referenced.

Line 14 :

   sock = socket(AF_INET, SOCK_RAW, IPPROTO_TCP);

   This is the most important line in the entire program. Socket() takes three arguments in
   this form:

	sockfd = socket(int family, int type, int protocol);



	
    The first argument is the family. This could be either AF_UNIX which is used so a process
   can communicate with another process on the same host or AF_INET which is used for
   internet communication between remote hosts. In this case it will be  AF_INET . Next  
   is the type, the type is usually between 1 of 4 choices (there are others that we will not
   discuss here) the main four are :

   1.	SOCK_DRAM      : used for udp datagrams
   2.	SOCK_STREAM    : used for tcp packets
   3.	SOCK_RAW       : used to bypass the transport layer
	                 and directly access the IP layer

   4.	SOCK_PACKET    : this is linux specific, it is similuar to
                         SOCK_RAW except it accesses the DATA LINK Layer

      For our needs we will use the SOCK_RAW type. You must have root acces to open a
    raw socket. The last parameter  is the protocol,the protocol value specifies what type of
    traffic the socket should receive , for normal sockets this value is usally set to "0"
    because the socket can figure out if for instance the "type" of SOCK_DGRAM is
    specified then the protocol should be UDP.In our case we just want to look at tcp 
    traffic so we will specify IPPROTO_TCP.

	
line 15 :
   while (1)

  The while (1) puts the program into an infinite loop this is necessary so that after the
 first packet is processed we will loop around and grab the next. 


Line 18:
   bytes_recieved = recvfrom(sock, buffer, sizeof buffer, 0, (struct sockaddr *)&amp;from, &amp;fromlen);
	
   Now here is where we are actually reading data from the open socket "sock".The from
   struct is also filled in but notice that we are casting "from" from a "sockaddr_in" struct
   to a "sockaddr" struct. We do this because the recvfrom() requires a sockaddr type but
   to access the separate fields we will continue to use the sockaddr_in structure. The 
   length of the "from" struct must also be present and passed by address. The recvfrom()
   call will return the number of bytes on success and a -1 on error and fill the global var
   errno.

   This is what we call "blocking-I/O" the recvfrom() will wait here forever until a
   datagram on the open socket is ready to be processed. This is opposed to 
   Non-blocking I/O which is like running a process in the background and move on to
   other tasks.


Line 20:
   printf("Source address ::: %s\n",inet_ntoa(from.sin_addr));

   This printf uses the special function inet_ntoa() to take the value of "from.sin_addr"
   which is stored in Network-byte order and outputs a value in a readable ip form such
   as 192.168.1.XXX.

Line 21:
   ip = (struct ip *)buffer;

   This is where we will overlay a predefined structure that will help us to individually
   identify the fields in the packet that we pick up from the open socket.


Line 22:
   printf("IP header length ::: %d\n",ip-&gt;ip_length);

   The thing to notice on this line is the "ip-&gt;ip_length" this will access a pointer in
   memory to the ip header length the important thing to remember is that the length 
   will be represented in 4-byte words this will be more important later when trying to
   access items past the ip header such as the tcp header or the data portion of the packet.



Line 23:
   printf("Protocol ::: %d\n",ip-&gt;ip_protocol);
	
   This gives access to the type of protocol such as 6 for tcp or 17 for udp.

Line 24:
   tcp = (struct tcp *)(buffer + (4*ip-&gt;ip_length));

       Remember earlier it was mentioned that the ip header length is stored in 4 byte words,
   this is where that bit of information becomes important. Here we are trying to get access
   to the tcp header fields, to do this we must overlay a structure that has the fields
   predefined just as we did with ip. There is one key difference here the ip header fields
   were easy to access due to the fact that the beginning of the buffer was also the beginning
   of the ip header as so :

	
	|----------------- buffer ----------------|
	 _________________________________________
	| ip header          |                    |
       	|____________________|____________________|
                             ^
                             *ip
                             ^
                             *buffer

      So to get access to the ip header we just set a pointer casted as an ip structure to the
   beginning of the buffer like "ip = (struct ip *)buffer;". To get access to the tcp header 
   is a little more difficult due to the fact that we must set a pointer and cast it as a tcp
   structure at the beginning of the tcp header which follows the ip header in the buffer 
   as so :

	
	 |----------------- buffer ---------------|
          ________________________________________
         | ip header | tcp header |               |
         |___________|____________|_______________|
                     ^
                     *tcp
                    	
This is why we use 4*ip-&gt;ip_length to find the start of the tcp header.

Line 25-26:
    printf("Source port ::: %d\n",ntohs(tcp-&gt;tcp_source_port);
    printf("Dest port  ::: %d\n",ntohs(tcp-&gt;tcp_dest_port));

   We can now access the source and dest ports which are located in the tcp header via 
   the structure as defined above.




     This will conclude  our  first very simple tcp sniffer. This was a very basic application
   that should help define how  to access packets passing on the network and how  to use
   sockets to access the packets. Hopefully this will be the first of many papers to come,
   which each proceeding paper we will add a new or more complex feature to the sniffer. I
   should also mention that there a number of great resources on the net that should aid you
   in further research in this area :

	1. Beej's Guide to Network Programming
	     This is an awesome paper that really helps 
	     clear up any misconceptions about network programming.
                [http://www.ecst.csuchico.edu/~beej/guide/net]

        2. TCP/IP Illustrated Vol 1,2,3
           W.Richard Stevens

To use the above program, cut out the above code and strip off all 
of the line numbers. Save the edited file as sniff.c. Next cut 
out the header file headers.h (below) and save it to a file headers.h
in the same directory. Now just compile: gcc -o sniff sniff.c
You should now have the executable "sniff", to run it type
#./sniff

/*************************headers.h**************************/
/*structure of an ip header             */
struct ip {
	unsigned int        ip_length:4;    /*little-endian*/
	unsigned int        ip_version:4;
	unsigned char       ip_tos;
	unsigned short      ip_total_length;
	unsigned short      ip_id;
	unsigned short      ip_flags;
	unsigned char       ip_ttl;
	unsigned char       ip_protocol;
	unsigned short      ip_cksum;
	unsigned int        ip_source;
	unsigned int        ip_dest;
};

/* Structure of a TCP header */
struct tcp {
	unsigned short      tcp_source_port;
	unsigned short      tcp_dest_port;
	unsigned int        tcp_seqno;
	unsigned int        tcp_ackno;
	unsigned int        tcp_res1:4,     /*little-endian*/
	tcp_hlen:4,
	tcp_fin:1,
 	tcp_syn:1,
	tcp_rst:1,
	tcp_psh:1,
	tcp_ack:1,
	tcp_urg:1,
	tcp_res2:2;
	unsigned short      tcp_winsize;
	unsigned short      tcp_cksum;
	unsigned short      tcp_urgent;
};
/*********************EOF***********************************/

</pre>
<img src ="http://www.cnitblog.com/darkstax/aggbug/18194.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cnitblog.com/darkstax/" target="_blank">darkstax</a> 2006-10-20 18:01 <a href="http://www.cnitblog.com/darkstax/articles/18194.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>md5校验</title><link>http://www.cnitblog.com/darkstax/articles/17738.html</link><dc:creator>darkstax</dc:creator><author>darkstax</author><pubDate>Sun, 08 Oct 2006 13:13:00 GMT</pubDate><guid>http://www.cnitblog.com/darkstax/articles/17738.html</guid><wfw:comment>http://www.cnitblog.com/darkstax/comments/17738.html</wfw:comment><comments>http://www.cnitblog.com/darkstax/articles/17738.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cnitblog.com/darkstax/comments/commentRss/17738.html</wfw:commentRss><trackback:ping>http://www.cnitblog.com/darkstax/services/trackbacks/17738.html</trackback:ping><description><![CDATA[
		<p>Verify md5sum using linux<br /><strong>md5sum -c linux.iso.md5</strong></p>
		<p>Create an md5sum using linux<br /><strong>md5sum linux.iso &gt; linux.iso.md5<br /><br /></strong><br /><br /></p>
		<h2>NAME</h2>md5sum - compute and check MD5 message digest <a name="lbAC"><font color="#236eb5"> </font></a><h2>SYNOPSIS</h2><b>md5sum</b> [<i>OPTION</i>] [<i>FILE</i>]... <br /><b>md5sum</b> [<i>OPTION</i>] <i>--check </i>[<i>FILE</i>] <a name="lbAD"><font color="#236eb5"> </font></a><h2>DESCRIPTION</h2><p>Print or check MD5 (128-bit) checksums. With no FILE, or when FILE is -, read standard input. </p><dl compact=""><dt><b>-b</b>, <b>--binary</b></dt><dd>read files in binary mode (default on DOS/Windows) 
</dd><dt><b>-c</b>, <b>--check</b></dt><dd>check MD5 sums against given list 
</dd><dt><b>-t</b>, <b>--text</b></dt><dd>read files in text mode (default) </dd></dl><a name="lbAE"><font color="#236eb5"> </font></a><h3>The following two options are useful only when verifying checksums:</h3><dl compact=""><dt><b>--status</b></dt><dd>don't output anything, status code shows success 
</dd><dt><b>-w</b>, <b>--warn</b></dt><dd>warn about improperly formated checksum lines 
</dd><dt><b>--help</b></dt><dd>display this help and exit 
</dd><dt><b>--version</b></dt><dd>output version information and exit </dd></dl><p>The sums are computed as described in RFC 1321. When checking, the input should be a former output of this program. The default mode is to print a line with checksum, a character indicating type (`*' for binary, ` ' for text), and name for each FILE. <a name="lbAF"><font color="#236eb5"> </font></a></p><h2>SEE ALSO</h2>The full documentation for <b>md5sum</b> is maintained as a Texinfo manual. If the <b>info</b> and <b>md5sum</b> programs are properly installed at your site, the command 
<dl compact=""><dt></dt><dd><b>info md5sum</b></dd></dl><p>should give you access to the complete manual. </p><img src ="http://www.cnitblog.com/darkstax/aggbug/17738.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cnitblog.com/darkstax/" target="_blank">darkstax</a> 2006-10-08 21:13 <a href="http://www.cnitblog.com/darkstax/articles/17738.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>Iptables Tutorial 1.2.1</title><link>http://www.cnitblog.com/darkstax/articles/17737.html</link><dc:creator>darkstax</dc:creator><author>darkstax</author><pubDate>Sun, 08 Oct 2006 13:00:00 GMT</pubDate><guid>http://www.cnitblog.com/darkstax/articles/17737.html</guid><wfw:comment>http://www.cnitblog.com/darkstax/comments/17737.html</wfw:comment><comments>http://www.cnitblog.com/darkstax/articles/17737.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cnitblog.com/darkstax/comments/commentRss/17737.html</wfw:commentRss><trackback:ping>http://www.cnitblog.com/darkstax/services/trackbacks/17737.html</trackback:ping><description><![CDATA[&nbsp;&nbsp;&nbsp;&nbsp; 摘要: Iptables Tutorial 1.2.1																												Oskar Andreasson																								     &lt;oan@frozentux.net&gt;    																				Copyright © 2001-2006 Oskar Andreas...&nbsp;&nbsp;<a href='http://www.cnitblog.com/darkstax/articles/17737.html'>阅读全文</a><img src ="http://www.cnitblog.com/darkstax/aggbug/17737.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cnitblog.com/darkstax/" target="_blank">darkstax</a> 2006-10-08 21:00 <a href="http://www.cnitblog.com/darkstax/articles/17737.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>Iptables 指南</title><link>http://www.cnitblog.com/darkstax/articles/17733.html</link><dc:creator>darkstax</dc:creator><author>darkstax</author><pubDate>Sun, 08 Oct 2006 12:45:00 GMT</pubDate><guid>http://www.cnitblog.com/darkstax/articles/17733.html</guid><wfw:comment>http://www.cnitblog.com/darkstax/comments/17733.html</wfw:comment><comments>http://www.cnitblog.com/darkstax/articles/17733.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cnitblog.com/darkstax/comments/commentRss/17733.html</wfw:commentRss><trackback:ping>http://www.cnitblog.com/darkstax/services/trackbacks/17733.html</trackback:ping><description><![CDATA[&nbsp;&nbsp;&nbsp;&nbsp; 摘要: Iptables 指南 1.1.19																				Oskar Andreasson																														     oan@frozentux.net     																				Copyright © 2001-2003 by Oskar Andreasson						...&nbsp;&nbsp;<a href='http://www.cnitblog.com/darkstax/articles/17733.html'>阅读全文</a><img src ="http://www.cnitblog.com/darkstax/aggbug/17733.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cnitblog.com/darkstax/" target="_blank">darkstax</a> 2006-10-08 20:45 <a href="http://www.cnitblog.com/darkstax/articles/17733.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>Slackware的启动(init)过程</title><link>http://www.cnitblog.com/darkstax/articles/14939.html</link><dc:creator>darkstax</dc:creator><author>darkstax</author><pubDate>Tue, 08 Aug 2006 08:20:00 GMT</pubDate><guid>http://www.cnitblog.com/darkstax/articles/14939.html</guid><wfw:comment>http://www.cnitblog.com/darkstax/comments/14939.html</wfw:comment><comments>http://www.cnitblog.com/darkstax/articles/14939.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cnitblog.com/darkstax/comments/commentRss/14939.html</wfw:commentRss><trackback:ping>http://www.cnitblog.com/darkstax/services/trackbacks/14939.html</trackback:ping><description><![CDATA[
		<p>
				<b>作者：</b>Peter Kaagman<br /><b>原文：</b><a href="http://www.slackfiles.org/documentation/en/articles/init.html">http://www.slackfiles.org/documentation/en/articles/init.html</a><br /><b>翻译</b>：windrose</p>
		<div class="book">
				<div class="tree">
						<div class="menu">
								<ul>
										<li class="leaf">
												<a href="http://slack.linuxsir.org/main/?q=node/30">导言</a>
										</li>
										<li class="leaf">
												<a href="http://slack.linuxsir.org/main/?q=node/31">运行级(runlevel)</a>
										</li>
										<li class="leaf">
												<a href="http://slack.linuxsir.org/main/?q=node/32">Init</a>
										</li>
										<li class="leaf">
												<a href="http://slack.linuxsir.org/main/?q=node/33">inittab</a>
										</li>
										<li class="leaf">
												<a href="http://slack.linuxsir.org/main/?q=node/34">结论</a>
										</li>
								</ul>
						</div>
						<h2>导言</h2>
						<!-- begin content -->
						<div class="node">
								<div class="content">
										<p>在一次IBM于阿姆斯特丹举办的Linux研讨会上，一位老师提出以下说法：“启动是Linux最难的部分。但是，一旦内核已经载入，并由init接管之后，你就畅行无阻了。从那个时刻起，所有发生的事情你都可以在脚本和文档(man page)里面读到。”</p>
										<p>他当然是对的。在启动Linux机器的过程中没有什么秘密。你能在ASCII文件中读到所有东西。但是，在跟踪这些脚本的过程中也很容易迷路。Slackware与别的发行版不同之处在于它坚持用BSD风格的启动过程，而不是像它们那样用Sys V的启动过程。</p>
										<p>在Sys V的启动系统中，所有起动/停止的脚本都放在 /etc/rc.d目录中。在每一个运行级(runlevel)都有一个目录(即 /etc/rc.1, /etc/rc.2 等等)，其中全是该运行级所需运行脚本的链接。当进入一个运行级时，有一个大的脚本来处理这些链接以起动(或停止)该运行级的服务。</p>
										<p>Sys V启动过程用在Redhat、Suse中，我将把解释它的事留给用这类系统的人。没有实际使用它的机器，我恐怕很快会在细节上晕头转向。</p>
										<p>Slackware的用户(Slackers)多数认为Sys V启动过程既复杂又难于维护。老实说，Redhat和Suse用户的想法正好相反。不过，先跟着我，然后你自己作出判断。</p>
										<p>在本文档中，我将试着证明IBM的老师是正确的。我将循着Slackware(8.1)的启动过程，用脚本和man page作为指导。会引用很多，而较少(我自己的)文字。</p>
										<p>又及：你可能注意到，英语不是我的母语。我会尽量经常地用拼写检查程序，但它在语法方面的用处不大。无论在内容或语法方面的错误，请不吝赐教。此外，我非常喜欢大家对我写的东西提出看法。<br /><br /></p>
										<h2>运行级(runlevel)</h2>
										<!-- begin content -->
										<div class="node">
												<p class="content">我们会很多次谈到运行级，所以现在是个好机会来解释一下运行级。运行级是决定某机器的服务等级的*nix方式。在每个运行级中，人们可以定义哪些服务要激活、哪些不用。原则上，可以有很多运行级。实际上，只有5个：</p>
												<div class="content">
														<ul>
																<li>单用户运行级，只有最少的服务在运行。这个运行级经常用于系统维护。 
</li>
																<li>多用户运行级，所有提供的服务都在运行。这些服务可能是诸如HTTP服务器、电子邮件服务器、SQL服务器之类。正是系统管理员(你)所需要的。 
</li>
																<li>多用户运行级，和前面一样，但这次有个图形界面的登陆管理器。<br />多用户运行级之一就是机器正常的运行状态。你可以决定另外的运行级。例如，用于远程维护的有网络支持的单用户运行级。 </li>
														</ul>
												</div>
												<p>上述运行级之外，还有两个特殊的运行级：</p>
												<ul>
														<li>停止系统(halt)的运行级。 
</li>
														<li>重新启动(reboot)的运行级。 </li>
												</ul>
												<h2>Init</h2>
												<!-- begin content -->
												<div class="node">
														<div class="content">
																<p>假如我想用树状图表示我机器上所有的进程，我可能会得到这样的结果：<br /></p>
																<div class="codeblock">
																		<code>&lt;pre&gt;<br />bilbo@bilbo:~$ pstree<br />init-+-4*[agetty]<br />     |-atd<br />     |-bash<br />     |-bash---startx---xinit-+-X<br />     | `-xinitrc-+-bbmail<br />     | `-blackbox-+-mozilla-bin---mozilla-bin---4+<br />     | `-rxvt---bash---pstree<br />     |-crond<br />     |-dhcpcd<br />     |-fetchmail<br />     |-gpm<br />     |-gvim<br />     |-httpd---7*[httpd]<br />     |-inetd---in.identd---in.identd---5*[in.identd]<br />     |-keventd<br />     |-khubd<br />     |-klogd<br />     |-kreiserfsd<br />     |-loop0<br />     |-loop1<br />     |-lpd<br />     |-mdrecoveryd<br />     |-named<br />     |-2*[sendmail]<br />     `-syslogd<br />bilbo@bilbo:~$<br />&lt;/pre&gt;</code>
																</div>
																<br />pstree命令显示我机器上运行的进程的树状图，看起来有点像目录结构。最引人注目(至少在我看来)的是，树状图的“根”是“init”。从init派生出所有其他进程。这并非偶然。 
<p></p><p>来自manpage文档：<br /></p><div class="codeblock"><code>&lt;pre&gt;<br />INIT(8) Linux System Administrator's Manual INIT(8)<br />NAME<br />       init, telinit - process control initialization<br />SYNOPSIS<br />       /sbin/init [ -a ] [ -s ] [ -b ] [ -z xxx ] [ 0123456Ss ]<br />       /sbin/telinit [ -t sec ] [ 0123456sSQqabcUu ]<br />DESCRIPTION<br />   Init<br />       Init is the parent of all processes. Its primary role is<br />       to create processes from a script stored in the file<br />       /etc/inittab (see inittab(5)). This file usually has<br />       entries which cause init to spawn gettys on each line that<br />       users can log in. It also controls autonomous processes<br />       required by any particular system.<br />&lt;/pre&gt;</code></div><br />有几个值得注意的要点： 
<p></p><ul><li>init派生所有进程(Init is the parent of all processes.) 
</li><li>init从文件 /etc/inittab中启动进程 
</li><li>init控制所有独立的进程 </li></ul><p>在上面的树状图中，你能看到那些独立的进程。它们都是init的直系后代，举几个例子：agetty(4个)、sendmail(2个)、lpd和syslogd。</p><p>但为什么init是“所有进程之母”，看看manpage：<br /></p><div class="codeblock"><code>&lt;pre&gt;<br />BOOTING<br />       After init is invoked as the last step of the kernel boot<br />       sequence, it looks for the file /etc/inittab to see if there is an<br />       entry of the type initdefault (see inittab(5)). The initdefault<br />       entry determines the initial runlevel of the system. If there is<br />       no such entry (or no /etc/inittab at all), a runlevel must be<br />       entered at the system console.<br />&lt;/pre&gt;</code></div><br />可见内核(kernel)启动时所做的最后一件事就是启动init。init接着按 /etc/inittab的规定做事。 
<p></p><p>init的manpage给出了更多的信息，但对我们来说也许该看看/etc/inittab了。它似乎是个非常重要的文件。<br />来自manpage：<br /></p><div class="codeblock"><code>&lt;pre&gt;<br />INITTAB(5) Linux System Administrator's Manual INITTAB(5)<br />NAME<br />       inittab - format of the inittab file used by the sysv-compatible<br />       init process<br />DESCRIPTION<br />       The inittab file describes which processes are started at bootup<br />       and during normal operation (e.g. /etc/init.d/boot,<br />       /etc/init.d/rc, gettys...). Init(8) distinguishes multiple run-<br />       levels, each of which can have its own set of processes that are<br />       started. Valid runlevels are 0-6 plus A, B, and C for ondemand<br />       entries. An entry in the inittab file has the following format:<br />              id:runlevels:action:process<br />&lt;/pre&gt;</code></div><br />啊哈，令人吃惊！它说：“用于与sysv兼容的init进程”。这是Slackware吗？没错，Slackware确实是用Sys V的init。纯粹为了开心，我们看看Slackware的软件包说明：<br /><div class="codeblock"><code>&lt;pre&gt;<br />bilbo@bilbo:~$ head -n 14 /var/log/packages/sysvinit-2.84-i386-18<br />PACKAGE NAME: sysvinit-2.84-i386-18<br />COMPRESSED PACKAGE SIZE: 232 K<br />UNCOMPRESSED PACKAGE SIZE: 560 K<br />PACKAGE LOCATION: /var/log/mount/slackware/a/sysvinit-2.84-i386-18.tgz<br />PACKAGE DESCRIPTION:<br />sysvinit: sysvinit (init, the parent of all processes)<br />sysvinit:<br />sysvinit: System V style init programs by Miquel van Smoorenburg that control<br />sysvinit: the booting and shutdown of your system. These support a number of<br />sysvinit: system runlevels, each with a specific set of utilities spawned.<br />sysvinit: For example, the normal system runlevel is 3, which starts agetty<br />sysvinit: on virtual consoles tty1 - tty6. Runlevel 4 starts xdm.<br />sysvinit: Runlevel 0 shuts the system down.<br />sysvinit:<br />bilbo@bilbo:~$<br />&lt;/pre&gt;</code></div><br />所以不要听信别人说Slackware不用Sys V的init，不过它是按BSD风格来用。<br /><br /><h2>inittab</h2><!-- begin content --><div class="node"><p class="content">玩够了......让我们看看 /etc/inittab 的格式。同样来自manpage：<br /></p><div class="codeblock"><code>&lt;pre&gt;<br />              id:runlevels:action:process<br />Lines beginning with `#' are ignored.<br />id is a unique sequence of 1-4 characters which iden-<br />tifies an entry in inittab (for versions of<br />sysvinit compiled with libraries &lt; 5.2.18 or a.out<br />libraries the limit is 2 characters).<br />Note: For gettys or other login processes, the id<br />field should be the tty suffix of the corresponding<br />tty, e.g. 1 for tty1. Otherwise, the login<br />accounting might not work correctly.<br />runlevels<br />lists the runlevels for which the specified action<br />should be taken.<br />action describes which action should be taken.<br />process<br />specifies the process to be executed. If the pro-<br />cess field starts with a `+' character, init will<br />not do utmp and wtmp accounting for that process.<br />This is needed for gettys that insist on doing<br />their own utmp/wtmp housekeeping. This is also a<br />historic bug.<br />&lt;/pre&gt;</code></div><div class="content"><br />组成这个文件的每行都有4个部分，用“:”分隔开 </div><p class="content"></p><div class="content"><ul><li>id - 该行的标识 
</li><li>runlevels - 该行为应该发生的运行级的列表 
</li><li>action - 应发生的行为，你能在inittab的manpage里面发现对它们的概述。我将在适当的时候引用。 
</li><li>process - 应由init启动的进程。 </li></ul></div><p>复杂吗？还不是那么坏吧，这是我的 /etc/inittab：<br /></p><div class="codeblock"><code>&lt;pre&gt;<br />bilbo@bilbo:~$ cat /etc/inittab<br />#<br /># inittab This file describes how the INIT process should set up<br /># the system in a certain run-level.<br />#<br /># Version: @(#)inittab 2.04 17/05/93 MvS<br /># 2.10 02/10/95 PV<br /># 3.00 02/06/1999 PV<br /># 4.00 04/10/2002 PV<br />#<br /># Author: Miquel van Smoorenburg, &lt;miquels@drinkel.nl.mugnet.org&gt;<br /># Modified by: Patrick J. Volkerding, &lt;volkerdi@slackware.com&gt;<br />#<br /># These are the default runlevels in Slackware:<br /># 0 = halt<br /># 1 = single user mode<br /># 2 = unused (but configured the same as runlevel 3)<br /># 3 = multiuser mode (default Slackware runlevel)<br /># 4 = X11 with KDM/GDM/XDM (session managers)<br /># 5 = unused (but configured the same as runlevel 3)<br /># 6 = reboot<br /># Default runlevel. (Do not set to 0 or 6)<br />id:3:initdefault:<br /># System initialization (runs when system boots).<br />si:S:sysinit:/etc/rc.d/rc.S<br /># Script to run when going single user (runlevel 1).<br />su:1S:wait:/etc/rc.d/rc.K<br /># Script to run when going multi user.<br />rc:2345:wait:/etc/rc.d/rc.M<br /># What to do at the "Three Finger Salute".<br />ca::ctrlaltdel:/sbin/shutdown -t5 -r now<br /># Runlevel 0 halts the system.<br />l0:0:wait:/etc/rc.d/rc.0<br /># Runlevel 6 reboots the system.<br />l6:6:wait:/etc/rc.d/rc.6<br /># What to do when power fails.<br />pf::powerfail:/sbin/genpowerfail start<br /># If power is back, cancel the running shutdown.<br />pg::powerokwait:/sbin/genpowerfail stop<br /># These are the standard console login getties in multiuser mode:<br />c1:1235:respawn:/sbin/agetty 38400 tty1 linux<br />c2:1235:respawn:/sbin/agetty 38400 tty2 linux<br />c3:1235:respawn:/sbin/agetty 38400 tty3 linux<br />c4:1235:respawn:/sbin/agetty 38400 tty4 linux<br />c5:1235:respawn:/sbin/agetty 38400 tty5 linux<br />c6:12345:respawn:/sbin/agetty 38400 tty6 linux<br /># Local serial lines:<br />#s1:12345:respawn:/sbin/agetty -L ttyS0 9600 vt100<br />#s2:12345:respawn:/sbin/agetty -L ttyS1 9600 vt100<br /># Dialup lines:<br />#d1:12345:respawn:/sbin/agetty -mt60 38400,19200,9600,2400,1200 ttyS0 vt100<br />#d2:12345:respawn:/sbin/agetty -mt60 38400,19200,9600,2400,1200 ttyS1 vt100<br /># Runlevel 4 used to be for an X window only system, until we discovered<br /># that it throws init into a loop that keeps your load avg at least 1 all<br /># the time. Thus, there is now one getty opened on tty6. Hopefully no one<br /># will notice. ;^)<br /># It might not be bad to have one text console anyway, in case something<br /># happens to X.<br />x1:4:wait:/etc/rc.d/rc.4<br /># End of /etc/inittab<br />bilbo@bilbo:~$<br />&lt;/pre&gt;</code></div><br />只有74行文字(仅约一张A4纸的篇幅)，如果你把那些注释去掉，将只剩下16行。但你将学到那些注释很值得读一读。<br />让我们开始把/etc/inittab拆开：<br /><div class="codeblock"><code>&lt;pre&gt;<br /># Author: Miquel van Smoorenburg, &lt;miquels@drinkel.nl.mugnet.org&gt;<br /># Modified by: Patrick J. Volkerding, &lt;volkerdi@slackware.com&gt;<br />&lt;/pre&gt;</code></div><br />这个文件的最后版本是由Miquel van Smoorenburg(听起来像德国人)制作的，然后由Patrick J. Volkerding(Slackware的维护者，对，Slackware是一个人的工作)为了用于Slackware而作了修改。这个注释没有太大作用，但它确实在那里。我们把它当作GPL的实例好了。<br /><div class="codeblock"><code>&lt;pre&gt;<br /># These are the default runlevels in Slackware:<br /># 0 = halt<br /># 1 = single user mode<br /># 2 = unused (but configured the same as runlevel 3)<br /># 3 = multiuser mode (default Slackware runlevel)<br /># 4 = X11 with KDM/GDM/XDM (session managers)<br /># 5 = unused (but configured the same as runlevel 3)<br /># 6 = reboot<br />&lt;/pre&gt;</code></div><br />又是一些注释，当然它什么事都不做，但它让接下来的事情清晰了很多。你看到的是对Slackware用到的7个运行级的描述。运行级2和5都没有用到，往后你会看到它们和运行级3用同样的脚本。<br /><div class="codeblock"><code>&lt;pre&gt;<br /># Default runlevel. (Do not set to 0 or 6)<br />id:3:initdefault:<br />&lt;/pre&gt;</code></div><br />终于要做些事情了。它是一个正常的inittab行，4个部分用“:”隔开。在这里的行为是“initdefault”，按照manpage的说法：<br /><div class="codeblock"><code>&lt;pre&gt;<br />       initdefault<br />              An initdefault entry specifies the runlevel which should<br />be entered after system boot.<br />If none exists, init will ask for a runlevel on the console.<br />The process field is ignored.<br />&lt;/pre&gt;</code></div><br />在这里定义了缺省的运行级，当然注释就是这么说的。因此，Slackware缺省的运行级是3，用控制台/文本登录的多用户运行级。 
<p></p><p>假如系统启动时，Slackware没有接到进入其他运行级的信号(例如"telinit 1"这类命令)，它就会进入这个运行级。<br /></p><div class="codeblock"><code>&lt;pre&gt;<br /># System initialization (runs when system boots).<br />si:S:sysinit:/etc/rc.d/rc.S<br />&lt;/pre&gt;</code></div><br />这里的行为是“sysinit”(系统初始化)，意思很明显，但我们还是看看manpage：<br /><div class="codeblock"><code>&lt;pre&gt;<br />       sysinit<br />             The process will be executed during system boot.<br />It will be executed before any boot or bootwait<br />entries. The runlevels field is ignored.<br />&lt;/pre&gt;</code></div><br />虽然这里指明了运行级S，但实际上被忽略了。将执行的程序是/etc/rc.d/rc.S，是个脚本。你会看到Slackware所有的启动脚本都在/etc/rc.d。在/etc/rc.d/rc.S里，系统将被初始化，我们接下来讨论这个脚本时就会看到。<br /><div class="codeblock"><code>&lt;pre&gt;<br /># Script to run when going single user (runlevel 1).<br />su:1S:wait:/etc/rc.d/rc.K<br />&lt;/pre&gt;</code></div><br />这里的行为是wait：<br /><div class="codeblock"><code>&lt;pre&gt;<br />       wait The process will be started once when the specified<br />                runlevel is entered and init will wait for its<br />                termination.<br />&lt;/pre&gt;</code></div><br />其中定义的脚本将在进入运行级1和S(意思是single)时被调用。“wait”行为将使init保留所有其他的动作直至/etc/rc.d/rc.K执行完毕。/etc/rc.d/rc.K启动了单用户运行级所需的服务，迟一点你会看到那不算很多。<br /><div class="codeblock"><code>&lt;pre&gt;<br /># Script to run when going multi user.<br />rc:2345:wait:/etc/rc.d/rc.M<br />&lt;/pre&gt;</code></div><br />在这里的行为还是wait。这里定义了运行级2、3、4、5都调用/etc/rc.d/rc.M，基本上是除了运行级1之外的所有“常规”的运行级。一会儿我们会看到那是个怎样的脚本。 
<p></p><p>目前为止我们所看到的行是用来定义系统启动之后所发生的事。在所有情况下，init都会等到它启动的进程(脚本)终止。下面的几行是init在特殊情况下应做的事，而且不属于任何特定的运行级。<br /></p><div class="codeblock"><code>&lt;pre&gt;<br /># What to do at the "Three Finger Salute".<br />ca::ctrlaltdel:/sbin/shutdown -t5 -r now<br />&lt;/pre&gt;</code></div><br />不单微软知道所谓的“三指礼”(译注：ctrl-alt-del)，在Linux中你也能决定它出现时该做什么。下面是init的manpage中关于这个行为的条目：<br /><div class="codeblock"><code>&lt;pre&gt;<br />       ctrlaltdel<br />              The process will be executed when init receives the SIGINT<br />signal. This means that someone on the system console has<br />pressed the CTRL-ALT-DEL key combination. Typically one wants<br />to execute some sort of shutdown either to get into<br />single-user level or to reboot the machine.<br />&lt;/pre&gt;</code></div><br />在Slackware的系统上，将会执行 /sbin/shutdown -t5 -r now 。<br /><div class="codeblock"><code>&lt;pre&gt;<br />SHUTDOWN(8) Linux System Administrator's Manual SHUTDOWN(8)<br />NAME<br />       shutdown - bring the system down<br />SYNOPSIS<br />       /sbin/shutdown [-t sec] [-arkhncfF] time [warning-message]<br />DESCRIPTION<br />       shutdown brings the system down in a secure way. All<br />       logged-in users are notified that the system is going<br />       down, and login(1) is blocked. It is possible to shut the<br />       system down immediately or after a specified delay. All<br />       processes are first notified that the system is going down<br />       by the signal SIGTERM. This gives programs like vi(1) the<br />       time to save the file being edited, mail and news process-<br />       ing programs a chance to exit cleanly, etc. shutdown does<br />       its job by signalling the init process, asking it to<br />       change the runlevel. Runlevel 0 is used to halt the sys-<br />       tem, runlevel 6 is used to reboot the system, and runlevel<br />       1 is used to put to system into a state where administra-<br />       tive tasks can be performed; this is the default if nei-<br />       ther the -h or -r flag is given to shutdown. To see which<br />       actions are taken on halt or reboot see the appropriate<br />       entries for these runlevels in the file /etc/inittab.<br />&lt;/pre&gt;</code></div><br />参数 -r 的意思是重新启动(reboot)，做法是给init进入运行级6的信号。延迟时间是从现在开始5秒。如果你有保持运行时间的癖好(uptime junkie)，你可以让“三指礼”做完全不同的事情，并有效地迫使用户明确给出shutdown命令。(假如你有个NT类系统和Linux共存的服务器群，取消ctrl-alt-del的功能并不是一件坏事。) 
<p></p><p>当然第2部分(译注：指定运行级)就不必要了，init是对外界信号作出反应。<br /></p><div class="codeblock"><code>&lt;pre&gt;<br /># Runlevel 0 halts the system.<br />l0:0:wait:/etc/rc.d/rc.0<br />&lt;/pre&gt;</code></div><br />这里的行为又是wait，因此init又会等待脚本执行完毕。进入运行级0后，init将执行 /etc/rc.d/rc.0 (最后是零)。这个脚本所做的是让所有启动了的进程安全地停止。不是所有的程序都喜欢你直接拔出插头的。作为最后的行动，它将调用poweroff来关闭系统或通知用户可以拔插头了。<br /><div class="codeblock"><code>&lt;pre&gt;<br /># Runlevel 6 reboots the system.<br />l6:6:wait:/etc/rc.d/rc.6<br />&lt;/pre&gt;</code></div><br />这一行与上面那行非常像，事实上 /etc/rc.d/rc.0 是指向 /etc/rc.d/rc.6的符号链接，两个脚本其实是同一个。脚本的调用方式决定了最后一步会怎么做。在运行级6中，最后的命令将是reboot。<br /><div class="codeblock"><code>&lt;pre&gt;<br /># What to do when power fails.<br />pf::powerfail:/sbin/genpowerfail start<br /># If power is back, cancel the running shutdown.<br />pg::powerokwait:/sbin/genpowerfail stop<br />&lt;/pre&gt;</code></div><br />这两行的命令要合在一起说，因为它们有很多相关性。它们的行为是：<br /><div class="codeblock"><code>&lt;pre&gt;<br />       powerwait<br />                     The process will be executed when the power goes<br />down. Init is usually informed about this by a pro-<br />cess talking to a UPS connected to the computer.<br />Init will wait for the process to finish before<br />continuing.<br />       powerfail<br />                     As for powerwait, except that init does not wait<br />for the process's completion.<br />       powerokwait<br />                     This process will be executed as soon as init is<br />                     informormed that the power has been restored.<br />&lt;/pre&gt;</code></div><br />这两行都是电力中断(或实际上是UPS电量耗尽)时该做的事情。 
<p></p><p>/sbin/genpowerfail start由关闭系统开始，/sbin/genpowerfail stop则试图在电力恢复时中断关机的行为。你可能注意到用start参数时并不会等脚本执行完毕，假如等了，就不可能中断关机的过程。 /sbin/genpowerfail是个使用shutdown命令的脚本，假如你有UPS你应该读一读这个脚本。</p><p>我们现在已经到了系统将要运行的关头。系统初始化的脚本已经执行了，缺省运行级的脚本也已经执行了- 单用户运行级是/etc/rc.d/rc.K，多用户运行级2、3、4、5执行的是/etc/rc.d/rc.M；所有需要的后台服务也在运行。在多用户运行级中，假如在/etc/rc.d/rc.M中启动了telnet和ssh服务，用户已经可以用这些方式登录系统了。假如你的系统是一个没有显示器和键盘的服务器，你让它这么待着就行了。</p><p>目前还不可能做到的是从控制台登录，有时能从控制台登录是会很方便的。init的下一个任务就是控制台登录。<br /></p><div class="codeblock"><code>&lt;pre&gt;<br /># These are the standard console login getties in multiuser mode:<br />c1:1235:respawn:/sbin/agetty 38400 tty1 linux<br />c2:1235:respawn:/sbin/agetty 38400 tty2 linux<br />c3:1235:respawn:/sbin/agetty 38400 tty3 linux<br />c4:1235:respawn:/sbin/agetty 38400 tty4 linux<br />c5:1235:respawn:/sbin/agetty 38400 tty5 linux<br />c6:12345:respawn:/sbin/agetty 38400 tty6 linux<br />&lt;/pre&gt;</code></div><br />马上我们有了个新的行为，在inittab的manpage里：<br /><div class="codeblock"><code>&lt;pre&gt;<br />       respawn<br />                     The process will be restarted whenever it termi-<br />nates (e.g. getty).<br />&lt;/pre&gt;</code></div><br />因此，已经启动的进程/sbin/agetty若被终止了，会重新运行。很明显，为运行级1、2、3和5启动了tty1至tty6的虚拟控制台。这些都是没有X的运行级。例外的是tty6上运行的agetty也将在运行级4(有X的运行级)启动。 
<p></p><p>agetty的manpage让我们了解到agetty的实际行为：<br /></p><div class="codeblock"><code>&lt;pre&gt;<br />AGETTY(8) AGETTY(8)<br />NAME<br />       agetty - alternative Linux getty<br />       SYNOPSIS<br />              agetty [-ihLmnw] [-f issue_file] [-l login_program] [-I<br />init] [-t timeout] [-H login_host] port baud_rate,...<br />[term]<br />agetty [-ihLmnw] [-f issue_file] [-l login_program] [-I<br />init] [-t timeout] [-H login_host] baud_rate,... port<br />[term]<br />       DESCRIPTION<br />              agetty opens a tty port, prompts for a login name and<br />              invokes the /bin/login command. It is normally invoked by<br />              init(8).<br />&lt;/pre&gt;</code></div><br />可见，agetty在一个tty的端口等待用户登录，然后将运行/bin/login。<br /><div class="codeblock"><code>&lt;pre&gt;<br />LOGIN(1) LOGIN(1)<br />NAME<br />       login - begin session on the system<br />       SYNOPSIS<br />              login [-p] [username] [ENV=VAR ...]<br />login [-p] [-h host] [-f username]<br />login [-p] -r host<br />       DESCRIPTION<br />              login is used to establish a new session with the system.<br />              It is normally invoked automatically by responding to the<br />              login: prompt on the user's terminal. login may be spe-<br />              cial to the shell and may not be invoked as a sub-process.<br />              Typically, login is treated by the shell as exec login<br />              which causes the user to exit from the current shell.<br />              Attempting to execute login from any shell but the login<br />              shell will produce an error message.<br />&lt;/pre&gt;</code></div><br />login在系统上启动了一个新的会话。让我们回头看看pstree的输出：<br /><div class="codeblock"><code>&lt;pre&gt;<br />bilbo@bilbo:~$ pstree<br />init-+-4*[agetty]<br />     |-atd<br />     |-bash<br />     |-bash---startx---xinit-+-X<br />     | `-xinitrc-+-bbmail<br />     | `-blackbox-+-mozilla-bin---mozilla-bin---4+<br />     | `-rxvt---bash---pstree<br />&lt;/pre&gt;</code></div><br />该死！不是应该有6个agetty吗？呃，对，曾经确实是有6个。但很显然，我从虚拟控制台登录了两次，有一次没有运行其他的程序，另一次运行了startx，变成了X会话。 
<p></p><p>当我logout的时候agetty会重新运行，还记得respawn吗？有趣的是，假如agetty启动得更早，会不会多个用户通过同一个虚拟控制台登录呢？</p><p>*nix总是提供了与系统联系的多种途径，我们已经知道了其中的2种：</p><ul><li>通过网络，用telnet、ssh之类工具 
</li><li>通过直接连接到系统的键盘、显示器和鼠标 </li></ul><p>但是，*nix还有其他途径与系统联系：<br /></p><div class="codeblock"><code>&lt;pre&gt;<br /># Local serial lines:<br />#s1:12345:respawn:/sbin/agetty -L ttyS0 9600 vt100<br />#s2:12345:respawn:/sbin/agetty -L ttyS1 9600 vt100<br /># Dialup lines:<br />#d1:12345:respawn:/sbin/agetty -mt60 38400,19200,9600,2400,1200 ttyS0 vt100<br />#d2:12345:respawn:/sbin/agetty -mt60 38400,19200,9600,2400,1200 ttyS1 vt100<br />&lt;/pre&gt;</code></div><br />上面两段为串行线路启动agetty，用于串口连接的终端或者用modem拨号进入。 
<p></p><p>你可以看到，它们缺省情况是被注释掉的。但一旦你需要使用古老的VT类终端或拨号进入系统，你就要用到这些代码。</p><p>在最后，要由X来给我们提供一个图形界面的运行级：<br /></p><div class="codeblock"><code>&lt;pre&gt;<br /># Runlevel 4 used to be for an X window only system, until we discovered<br /># that it throws init into a loop that keeps your load avg at least 1 all<br /># the time. Thus, there is now one getty opened on tty6. Hopefully no one<br /># will notice. ;^)<br /># It might not be bad to have one text console anyway, in case something<br /># happens to X.<br />x1:4:wait:/etc/rc.d/rc.4<br />&lt;/pre&gt;</code></div><br />注释首先解释了为运行级4在tty6留下一个getty的原因。行为是wait，执行/etc/rc.d/rc.4。这个脚本将依次搜索kdm(kde的登录管理器)、gdm(gnome的登录管理器)，最后是xdm(缺省的X登录管理器)。它会运行它所找到的第一个。这些登录管理器可以和agetty类比，它们会等着用户登录，当用户退出后自己重新运行。<br /><div class="codeblock"><code>&lt;pre&gt;<br />bilbo@bilbo:~$ man kdm<br />No manual entry for kdm<br />bilbo@bilbo:~$<br />&lt;/pre&gt;</code></div><br />显然，目前为止没有kdm的manpage。<br /><div class="codeblock"><code>&lt;pre&gt;<br />bilbo@bilbo:~$ man gdm<br />No manual entry for gdm<br />bilbo@bilbo:~$<br />&lt;/pre&gt;</code></div><br />目前为止，gnome的用户也不关心gdm的manpage。(译注：Slackware 9.1中已经有了)<br /><div class="codeblock"><code>&lt;pre&gt;<br />XDM(1) XDM(1)<br />NAME<br />       xdm - X Display Manager with support for XDMCP, host<br />       chooser<br /> SYNOPSIS<br />       xdm [ -config configuration_file ] [ -nodaemon ] [ -debug<br />       debug_level ] [ -error error_log_file ] [ -resources<br />       resource_file ] [ -server server_entry ] [ -session ses-<br />       sion_program ]<br />DESCRIPTION<br />       Xdm manages a collection of X displays, which may be on<br />       the local host or remote servers. The design of xdm was<br />       guided by the needs of X terminals as well as The Open<br />       Group standard XDMCP, the X Display Manager Control Proto-<br />       col. Xdm provides services similar to those provided by<br />       init, getty and login on character terminals: prompting<br />       for login name and password, authenticating the user, and<br />       running a ``session.''<br />&lt;/pre&gt;</code></div><br />最后我们终于找到了，这是xdm的manpage的片段。由于我总是在运行级3，我没法告诉你很多有关它的事。 
<p></p><p>我们已经看到，init - 所有进程之母 - 从内核那里接管了系统，然后init将处理/etc/inittab文件，根据inittab的输入，init将依次：</p><ul><li>设置缺省的运行级 
</li><li>运行系统初始化脚本 /etc/rc.d/rc.S 并等待它结束 
</li><li>运行指定运行级的脚本并等待它结束 
<ul><li>运行级1是/etc/rc.d/rc.K 
</li><li>运行级2、3、4、5是/etc/rc.d/rc.M 
</li><li>运行级0(关机)是/etc/rc.d/rc.0 
</li><li>运行级6(重新启动)是/etc/rc.d/rc.6 </li></ul></li><li>决定在特殊情况，例如ctrl-alt-del或停电时应采取的行动 
</li><li>为运行级1、2、3和5启动agetty(还有运行级4时启动6号终端，但有其特殊原因) 
</li><li>为串口连接启动终端，尽管这不是缺省的行为 
</li><li>为运行级4启动图形界面的登录管理器 </li></ul><h2>结论</h2><!-- begin content --><div class="node"><div class="content"><p>事实上这些就是init做的全部事情。剩下的“只不过是脚本”了。但是，仔细读它们也是很有趣的，否则你不会知道在哪里加载模块以及启动网络。</p></div></div></div></div>
												</div>
										</div>
								</div>
						</div>
				</div>
		</div>
<img src ="http://www.cnitblog.com/darkstax/aggbug/14939.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cnitblog.com/darkstax/" target="_blank">darkstax</a> 2006-08-08 16:20 <a href="http://www.cnitblog.com/darkstax/articles/14939.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>Linux的启动过程</title><link>http://www.cnitblog.com/darkstax/articles/14932.html</link><dc:creator>darkstax</dc:creator><author>darkstax</author><pubDate>Tue, 08 Aug 2006 07:45:00 GMT</pubDate><guid>http://www.cnitblog.com/darkstax/articles/14932.html</guid><wfw:comment>http://www.cnitblog.com/darkstax/comments/14932.html</wfw:comment><comments>http://www.cnitblog.com/darkstax/articles/14932.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cnitblog.com/darkstax/comments/commentRss/14932.html</wfw:commentRss><trackback:ping>http://www.cnitblog.com/darkstax/services/trackbacks/14932.html</trackback:ping><description><![CDATA[
		<h3 class="post-title">Linux's boot process explained </h3>
		<span style="FONT-SIZE: 130%">Short history of the UNIX operating system</span>
		<br />
		<br />Linux is an implementation of the UNIX operating system concept. UNIX was derived from AT&amp;T's "Sys V" (System 5). The initialization process is meant to control the starting and ending of services and/or daemons in a system, and permits different start-up configurations on different execution levels ("run levels").<br />Some Linux distribution, like <a href="http://www.slackware.com/">SlackWare</a>, use the BSD init system, developed at the University of California, Berkeley.<br />Sys V uses a much more complex set of command files and directives to determine which services are available at different levels of execution, than the BSD's do.<br /><br /><span style="FONT-SIZE: 130%">Booting the Linux operating system</span><br /><br />The first thing a computer does on start-up is a primer test (POST - Power On Self Test). This way several devices are tested, including the processor, memory, graphics card and the keyboard. Here is tested the <i>boot medium</i> (hard disk, floppy unit, CD-ROMs). After POST, the loader from a ROM loads the <i>boot sector</i>, which in turn loads the operating system from the active partition.<br />The boot blocks is always at the same place: track 0, cylinder 0, head 0 of the device from which we're booting. This block contains a program called <i>loader</i>, which in Linux's case is <a href="http://www.acm.uiuc.edu/workshops/linux_install/lilo.html">LiLo</a> (Linux Loader), or <a href="http://www.gnu.org/software/grub/">Grub</a> (GNU Grub Unified Boot Loader), which actually boots the operating system. These loaders in Linux , in case of a multi-boot configuration (more operating systems on a computer), permit the selection of the operating system to be booted. Lilo and Grub are installed or at the <a href="http://www.webopedia.com/TERM/M/MBR.html">MBR (Master Boot Record)</a>, or at the first sector of the active partition.<br />In the following we will refer to <b>LiLO</b> as boot loader. This is usually installed in the boot sector, also known as MBR. If the user decides to boot <i>Linux</i>, LiLo will try to load the kernel. Now I will present step-by-step LiLo's attempt to load the operating system.<br /><br />1. In case of a multi-boot config, LiLo permits the user two choose an operating system from the menu. The LiLo settings are stored at <i>/etc/lilo.conf</i>. System administrators use this file for a very detailed finement of the loader. Here can be manually set what operating systems are installed, as well as the method for loading any of them. If on the computer there is only Linux, LiLo can be set to load directly the kernel, and skip the selection menu.<br /><br />2. The Linux kernel is compressed, and contains a small bit, which will decompress it. Immediately after the first step begins the decompression and the loading of the kernel.<br /><br />3. If the kernel detects that your graphics card supports more complex text modes, Linux allows the usage of them - this can be specified or during the recompilation of the kernel, or right inside Lilo, or other program, like <i>rdev</i>.<br /><br />4. The kernel verifies hardware configuration (floppy drive, hard disk, network adapters, etc) and configures the drivers for the system. During this operation, several informative messages are shown to the user.<br /><br />5. The kernel tries to mount the <i>file system</i> and the system files. The location of system files is configurable during recompilation, or with other programs - LiLo and rdev. The file system type is automatically detected. The most used file systems on Linux are <a href="http://en.wikipedia.org/wiki/Ext2">ext2</a> and <a href="http://en.wikipedia.org/wiki/Ext3">ext3</a>. If the mount fails, a so-called <i>kernel panic</i> will occur, and the system will "freeze".<br />System files are usually mounted in <i>read-only</i> mode, to permit a verification of them during the mount. This verification isn't indicated if the files were mounted in <i>read-write</i> mode.<br /><br />6. After these steps, the kernel will start <i>init</i>, which will become process number 1, and will start the rest of the system.<br /><br /><span style="FONT-SIZE: 130%">The init process</span><br /><br />It's Linux's first process, and parent of all the other processes. This process is the first running process on any Linux/UNIX system, and is started directly by the kernel. It is what loads the rest of the system, and always has a <i>PID</i> of 1.<br /><br /><span style="FONT-SIZE: 130%">The initialization files in /etc/inittab</span><br /><br />First time the initialization process (<i>init</i>) examines the file /etc/inittab to determine what processes have to be launched after. This file provides <i>init</i> information on runlevels, and on what process should be launched on each runlevel.<br />After that, <i>init</i> looks up the first line with a <i>sysinit</i> (system initialization) action and executes the specified command file, in this case /etc/rc.d/rc.sysinit. After the execution of the scripts in /etc/rc.d/rc.sysinit, <i>init</i> starts to launch the processes associated with the initial runlevel.<br />The next few lines in /etc/inittab are specific to the different execution (run-) levels. Every line runs as a single script (/etc/rc.d/rc), which has a number from 1 to 6 as argument to specify the runlevel.<br />The most used action in /etc/inittab is <i>wait</i>, which means <i>init</i> executes the command file for a specified runlevel, and then waits until that level is terminated.<br /><br /><span style="FONT-SIZE: 130%">The files in /etc/rc.d/rc.sysinit</span><br /><br />The commands defined in /etc/inittab are executed only once, by the <i>init</i> process, every time when the operating system boots. Usually these scripts are running as a succession of commands, and usually realise the following:<br /><br />1. Determine whether the system takes part of a network, depending on the content of /etc/sysconfig/network<br /><br />2. Mount /proc, the file system used in Linux to determine the state of the diverse processes.<br /><br />3. Set the system time in fuction to the BIOS settings, as well as realises other settings (setting of time zone, etc), stabilized and configured during the installation of the system.<br /><br />4. Enables virtual memory, activating and mounting the swap partition, specified in /etc/fstab (<i>File System Table</i>)<br /><br />5. Sets the host name for the network and system wide authentication, like NIS (<i>Network Information Service</i>), NIS+ (an improved version of NIS), and so on.<br /><br />6. Verifies the root fily system, and if no problems, mounts it.<br /><br />7. Verifies the other file systems specified in /etc/fstab.<br /><br />8. Identifies, if case of, special routines used by the operating system to recognize installed hardware to configure Plug'n'Play devices, and to activate other prime devices, like the sound card, for example.<br /><br />9. Verifies the state of special disk devices, like RAID (<i>Redundant Array of Inexpensive Disks</i>)<br /><br />10. Mounts all the specified file systems in /etc/fstab.<br /><br />11. Executes other system-specific tasks.<br /><br /><span style="FONT-SIZE: 130%">The /etc/rc.d/init.d directory</span><br /><br />The directory /etc/rc.d/init.d contains all the commands which start or stop services which are associated with all the execution levels.<br />All the files in /etc/rc.d/init.d have a short name which describes the services to which they're associated. For example, /etc/rc.d/init.d/amd starts and stops the <i>a</i>uto <i>m</i>ount <i>d</i>aemon, which mounts the NFS host and devices anytime when needed.<br /><br /><span style="FONT-SIZE: 130%">The login process</span><br /><br />After the <i>init</i> process executes all the commands, files and scripts, the last few processes are the /sbin/mingetty ones, which shows the banner and log-in message of the distribution you have installed. The system is loaded and prepared so the user could log in.<br /><br /><span style="FONT-SIZE: 130%">Linux's execution levels</span><br /><br />The execution levels represent the mode in which the computer operates. They are defined by a set of available services at any time they are started. The execution levels represent different ways Linux uses to be available to you, the user, or eventually the administrator.<br />As daily user you don't have to bother with the execution levels, although the multi-user level makes the services which you need while using Linux in a network (though in a transparent mode) available.<br />In the next few sentences I'll present the execution levels, one by one:<br /><br />0: Halt (stops all running processes and executes <i>shutdown</i>)<br /><br />1: Known under the name "<i>Single-user mode</i>". In this case the system runs with a reduced set of services and daemons. The root file system is mounted <i>read-only</i>. This runlevel is used when the others fail while booting.<br /><br />2: On this level run the most of the services, with the exception of network services (<i>httpd</i>, <i>named</i>, <i>nfs</i>, etc). This execution level is ideal for the debug of network services, keeping the file system shared.<br /><br />3: Complete multi-user mode, with network support enabled.<br /><br />4: Unused, in most of the distributions. In Slackware this level is equivalent with 3, the only difference is that this has graphic login enabled.<br /><br />5: Complete multi-user mode, with network and graphic subsystem support enabled.<br /><br />6: Reboot. Stops all running processes and reboots the system to the initial execution level.<br /><br /><span style="FONT-SIZE: 130%">Modification of execution levels</span><br /><br />The most used facility of <i>init</i>, and maybe the most confusing one, is the ability to move from an execution level to an other.<br />The system boots into a runlevel specified in /etc/inittab, or to a level specified at the LiLo prompt. To change the execution level, use the command <i>init</i>. For example, to change the execution level to 3, type<br /><br /><blockquote>init 3</blockquote><br />This stops most of the processes and takes the system into a multi-user mode with networking enabled. Attention, changing the init level might force several daemons used at the moment to stop!<br /><br /><span style="FONT-SIZE: 130%">The directories of execution levels</span><br /><br />Every execution level has a directory with a symbolic links (<i>symlinks</i>) pointing to the corresponding scripts in /etc/rc.d/init.d. These directories are:<br /><br />/etc/rc.d/rc0.d<br />/etc/rc.d/rc1.d<br />/etc/rc.d/rc2.d<br />/etc/rc.d/rc3.d<br />/etc/rc.d/rc4.d<br />/etc/rc.d/rc5.d<br />/etc/rc.d/rc6.d<br /><br />The name of the symlinks are semnificative. It specifies which service has to be stopped, started and when. The links starting with an "S" are programmed to start in various execution levels. The links also have a number in their name (01-99). Now some examples of symlinks in the directory /etc/rc.d/rc2.d:<br /><br />K20nfs -&gt; ../init.d/nfs<br />K50inet -&gt; ../init.d/inet<br />S60lpd -&gt; ../init.d/lpd<br />S80sendmail -&gt; ../init.d/sendmail<br /><br />When operating systems change the execution level, init compares the list of the terminated processes (links which start with "K") from the directory of the current execution level with the list of processes which have to be started (starting with "S"), found in the destination directory.<br /><br /><i>Example:</i><br /><br />When the system boots into runlevel 3, will execute all the corresponding links starting with "S", in an order accorind to their number:<br /><br />/etc/rc.d/rc3.d/S60lpd start<br />/etc/rc.d/rc3.d/S80sendmail start<br />(and so on)<br /><br />If the system now changes to runlevel 1, will execute:<br /><br />/etc/rc.d/rc3.d/K20nfs stop<br />/etc/rc.d/rc3.d/K50inet stop<br />(presuming that <i>nfs</i> and <i>inet</i> are NOT in /etc/rc.d/rc1.d)<br /><br />After that it will start all the processes mentioned in /etc/rc.d/rc1.d except which are already running. In this example there's a single one only:<br /><br />/etc/rc.d/rc1.d/S00single<br /><br /><span style="FONT-SIZE: 130%">Changing the current execution level</span><br /><br />To change the current execution level for example to level 3, edit /etc/inittab in a text editor, and edit the following line:<br /><br /><i>id:3:initdefault:</i><br /><br />(<u>do <i>not</i> change the initial runlevel to 0 or 6!</u>)<br /><br /><span style="FONT-SIZE: 130%">Booting into an alternative execution level</span><br /><br />At the LiLo prompt you have to write the number of the wanted execution level, before booting the operating system. This way to boot into the third level, type for example:<br /><br /><br /><blockquote>linux 3</blockquote><br /><br /><span style="FONT-SIZE: 130%">Eliminating a service from an execution level</span><br /><br />To disable a service from a runlevel, you might simply delete or modify the corresponding symlink.<br />For example, to disable <i>pcmcia</i>, and don't start in the future, type:<br /><br /><br /><blockquote>rm /etc/rc.d/rc3.d/S45pcmcia</blockquote><br /><br /><span style="FONT-SIZE: 130%">Adding a service to an execution level</span><br /><br />To add a service, it is needed to create a symlink pointing to the corresponding scripts in /etc/rc.d/init.d. After the symlink is created, be sure to assign it a number, so it would be started in the right time:<br /><br />To add "lpd" to runlevel 3, type:<br /><br /><br /><blockquote>ln -s /etc/rc.d/init.d/lpd /etc/rc.d/rc3.d/S64lpd</blockquote><br /><br /><img src ="http://www.cnitblog.com/darkstax/aggbug/14932.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cnitblog.com/darkstax/" target="_blank">darkstax</a> 2006-08-08 15:45 <a href="http://www.cnitblog.com/darkstax/articles/14932.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item></channel></rss>