python urllib2 详解

urllib2是Python的一个获取URLs(Uniform Resource Locators)的组件。他以urlopen函数的形式提供了一个非常简单的接口,
这是具有利用不同协议获取URLs的能力,他同样提供了一个比较复杂的接口来处理一般情况,例如:基础验证,cookies,代理和其他。
它们通过handlers和openers的对象提供。
urllib2支持获取不同格式的URLs(在URL的”:”前定义的字串,例如:”ftp”是”ftp:python.ort/”的前缀),它们利用它们相关网络协议(例如FTP,HTTP)
进行获取。这篇教程关注最广泛的应用–HTTP。
对于简单的应用,urlopen是非常容易使用的。但当你在打开HTTP的URLs时遇到错误或异常,你将需要一些超文本传输协议(HTTP)的理解。
最权威的HTTP文档当然是RFC 2616(http://rfc.net/rfc2616.html)。这是一个技术文档,所以并不易于阅读。这篇HOWTO教程的目的是展现如何使用urllib2,
并提供足够的HTTP细节来帮助你理解。他并不是urllib2的文档说明,而是起一个辅助作用。
获取 URLs
最简单的使用urllib2将如下所示
[codesyntax lang=”python”]

import urllib2 
response = urllib2.urlopen('http://python.org/') 
html = response.read()

[/codesyntax]
urllib2的很多应用就是那么简单(记住,除了”http:”,URL同样可以使用”ftp:”,”file:”等等来替代)。但这篇文章是教授HTTP的更复杂的应用。
HTTP是基于请求和应答机制的–客户端提出请求,服务端提供应答。urllib2用一个Request对象来映射你提出的HTTP请求,在它最简单的使用形式中你将用你要请求的
地址创建一个Request对象,通过调用urlopen并传入Request对象,将返回一个相关请求response对象,这个应答对象如同一个文件对象,所以你可以在Response中调用.read()。
[python]
import urllib2
req = urllib2.Request(‘http://www.voidspace.org.uk’)
response = urllib2.urlopen(req)
the_page = response.read()

[/codesyntax]
记得urllib2使用相同的接口处理所有的URL头。例如你可以像下面那样创建一个ftp请求。
req = urllib2.Request(‘ftp://example.com/’)
在HTTP请求时,允许你做额外的两件事。首先是你能够发送data表单数据,其次你能够传送额外的关于数据或发送本身的信息(“metadata”)到服务器,此数据作为HTTP的”headers”来发送。
接下来让我们看看这些如何发送的吧。
Data数据
有时候你希望发送一些数据到URL(通常URL与CGI[通用网关接口]脚本,或其他WEB应用程序挂接)。在HTTP中,这个经常使用熟知的POST请求发送。这个通常在你提交一个HTML表单时由你的浏览器来做。
并不是所有的POSTs都来源于表单,你能够使用POST提交任意的数据到你自己的程序。一般的HTML表单,data需要编码成标准形式。然后做为data参数传到Request对象。编码工作使用urllib的函数而非
urllib2。
[codesyntax lang=”python”]

import urllib 
import urllib2 
url = 'http://www.someserver.com/cgi-bin/register.cgi' 
values = {'name' : 'Michael Foord', 
          'location' : 'Northampton', 
          'language' : 'Python' } 
data = urllib.urlencode(values) 
req = urllib2.Request(url, data) 
response = urllib2.urlopen(req) 
the_page = response.read()

[/codesyntax]
记住有时需要别的编码(例如从HTML上传文件–看http://www.w3.org/TR/REC-html40/interact/forms.html#h-17.13 HTML Specification, Form Submission的详细说明)。
如ugoni没有传送data参数,urllib2使用GET方式的请求。GET和POST请求的不同之处是POST请求通常有”副作用”,它们会由于某种途径改变系统状态(例如提交成堆垃圾到你的门口)。
尽管HTTP标准说的很清楚POSTs通常会产生副作用,GET请求不会产生副作用,但没有什么可以阻止GET请求产生副作用,同样POST请求也可能不产生副作用。Data同样可以通过在Get请求
的URL本身上面编码来传送。
可看如下例子
[python:nogutter]
>>> import urllib2
>>> import urllib
>>> data = {}
>>> data[‘name’] = ‘Somebody Here’
>>> data[‘location’] = ‘Northampton’
>>> data[‘language’] = ‘Python’
>>> url_values = urllib.urlencode(data)
>>> print url_values
name=Somebody+Here&language=Python&location=Northampton
>>> url = ‘http://www.example.com/example.cgi’
>>> full_url = url + ‘?’ + url_values
>>> data = urllib2.open(full_url)

[/codesyntax]
Headers
我们将在这里讨论特定的HTTP头,来说明怎样添加headers到你的HTTP请求。
有一些站点不喜欢被程序(非人为访问)访问,或者发送不同版本的内容到不同的浏览器。默认的urllib2把自己作为“Python-urllib/x.y”(x和y是Python主版本和次版本号,例如Python-urllib/2.5),
这个身份可能会让站点迷惑,或者干脆不工作。浏览器确认自己身份是通过User-Agent头,当你创建了一个请求对象,你可以给他一个包含头数据的字典。下面的例子发送跟上面一样的内容,但把自身
模拟成Internet Explorer。
[codesyntax lang=”python”]

import urllib 
import urllib2 
url = 'http://www.someserver.com/cgi-bin/register.cgi' 
user_agent = 'Mozilla/4.0 (compatible; MSIE 5.5; Windows NT)' 
values = {'name' : 'Michael Foord', 
          'location' : 'Northampton', 
          'language' : 'Python' } 
headers = { 'User-Agent' : user_agent } 
data = urllib.urlencode(values) 
req = urllib2.Request(url, data, headers) 
response = urllib2.urlopen(req) 
the_page = response.read()

[/codesyntax]
response应答对象同样有两个很有用的方法。看下面的节info and geturl,我们将看到当发生错误时会发生什么。
Handle Exceptions处理异常
当urlopen不能够处理一个response时,产生urlError(不过通常的Python APIs异常如ValueError,TypeError等也会同时产生)。
HTTPError是urlError的子类,通常在特定HTTP URLs中产生。
URLError
通常,URLError在没有网络连接(没有路由到特定服务器),或者服务器不存在的情况下产生。这种情况下,异常同样会带有”reason”属性,它是一个tuple,包含了一个错误号和一个错误信息。
例如
[codesyntax lang=”python”]

>>> req = urllib2.Request('http://www.pretend_server.org') 
>>> try: urllib2.urlopen(req) 
>>> except URLError, e: 
>>>    print e.reason 
>>> 
(4, 'getaddrinfo failed')

[/codesyntax]
HTTPError
服务器上每一个HTTP 应答对象response包含一个数字”状态码”。有时状态码指出服务器无法完成请求。默认的处理器会为你处理一部分这种应答(例如:假如response是一个”重定向”,需要客户端从别的地址获取文档
,urllib2将为你处理)。其他不能处理的,urlopen会产生一个HTTPError。典型的错误包含”404″(页面无法找到),”403″(请求禁止),和”401″(带验证请求)。
请看RFC 2616 第十节有所有的HTTP错误码
HTTPError实例产生后会有一个整型’code’属性,是服务器发送的相关错误号。
Error Codes错误码
因为默认的处理器处理了重定向(300以外号码),并且100-299范围的号码指示成功,所以你只能看到400-599的错误号码。
BaseHTTPServer.BaseHTTPRequestHandler.response是一个很有用的应答号码字典,显示了RFC 2616使用的所有的应答号。这里为了方便重新展示该字典。(译者略)
当一个错误号产生后,服务器返回一个HTTP错误号,和一个错误页面。你可以使用HTTPError实例作为页面返回的应答对象response。这表示和错误属性一样,它同样包含了read,geturl,和info方法。
[codesyntax lang=”python”]

>>> req = urllib2.Request('http://www.python.org/fish.html') 
>>> try: 
>>>     urllib2.urlopen(req) 
>>> except URLError, e: 
>>>     print e.code 
>>>     print e.read() 
>>> 
404 

Error 404: File Not Found 
...... etc...

[/codesyntax]
Wrapping it Up包装
所以如果你想为HTTPError或URLError做准备,将有两个基本的办法。我则比较喜欢第二种。
第一个:
[codesyntax lang=”python”]

from urllib2 import Request, urlopen, URLError, HTTPError 
req = Request(someurl) 
try: 
    response = urlopen(req) 
except HTTPError, e: 
    print 'The server couldn/'t fulfill the request.' 
    print 'Error code: ', e.code 
except URLError, e: 
    print 'We failed to reach a server.' 
    print 'Reason: ', e.reason 
else: 
    # everything is fine

[/codesyntax]
注意:except HTTPError 必须在第一个,否则except URLError将同样接受到HTTPError。
第二个:
[codesyntax lang=”python”]

from urllib2 import Request, urlopen, URLError 
req = Request(someurl) 
try: 
    response = urlopen(req) 
except URLError, e: 
    if hasattr(e, 'reason'): 
        print 'We failed to reach a server.' 
        print 'Reason: ', e.reason 
    elif hasattr(e, 'code'): 
        print 'The server couldn/'t fulfill the request.' 
        print 'Error code: ', e.code 
else: 
    # everything is fine

[/codesyntax]
info and geturl
urlopen返回的应答对象response(或者HTTPError实例)有两个很有用的方法info()和geturl()
geturl — 这个返回获取的真实的URL,这个很有用,因为urlopen(或者opener对象使用的)或许
会有重定向。获取的URL或许跟请求URL不同。
info — 这个返回对象的字典对象,该字典描述了获取的页面情况。通常是服务器发送的特定头headers。目前是httplib.HTTPMessage 实例。
经典的headers包含”Content-length”,”Content-type”,和其他。查看Quick Reference to HTTP Headers(http://www.cs.tut.fi/~jkorpela/http.html)
获取有用的HTTP头列表,以及它们的解释意义。
Openers和Handlers
当你获取一个URL你使用一个opener(一个urllib2.OpenerDirector的实例,urllib2.OpenerDirector可能名字可能有点让人混淆。)正常情况下,我们
使用默认opener — 通过urlopen,但你能够创建个性的openers,Openers使用处理器handlers,所有的“繁重”工作由handlers处理。每个handlers知道
如何通过特定协议打开URLs,或者如何处理URL打开时的各个方面,例如HTTP重定向或者HTTP cookies。
如果你希望用特定处理器获取URLs你会想创建一个openers,例如获取一个能处理cookie的opener,或者获取一个不重定向的opener。
要创建一个 opener,实例化一个OpenerDirector,然后调用不断调用.add_handler(some_handler_instance).
同样,可以使用build_opener,这是一个更加方便的函数,用来创建opener对象,他只需要一次函数调用。
build_opener默认添加几个处理器,但提供快捷的方法来添加或更新默认处理器。
其他的处理器handlers你或许会希望处理代理,验证,和其他常用但有点特殊的情况。
install_opener 用来创建(全局)默认opener。这个表示调用urlopen将使用你安装的opener。
Opener对象有一个open方法,该方法可以像urlopen函数那样直接用来获取urls:通常不必调用install_opener,除了为了方便。
Basic Authentication 基本验证
为了展示创建和安装一个handler,我们将使用HTTPBasicAuthHandler,为了更加细节的描述本主题–包含一个基础验证的工作原理。
请看Basic Authentication Tutorial(http://www.voidspace.org.uk/python/articles/authentication.shtml)
当需要基础验证时,服务器发送一个header(401错误码) 请求验证。这个指定了scheme 和一个‘realm’,看起来像这样:Www-authenticate: SCHEME realm=”REALM”.
例如
Www-authenticate: Basic realm=”cPanel Users”
客户端必须使用新的请求,并在请求头里包含正确的姓名和密码。这是“基础验证”,为了简化这个过程,我们可以创建一个HTTPBasicAuthHandler的实例,并让opener使用这个
handler。
HTTPBasicAuthHandler使用一个密码管理的对象来处理URLs和realms来映射用户名和密码。如果你知道realm(从服务器发送来的头里)是什么,你就能使用HTTPPasswordMgr。
通常人们不关心realm是什么。那样的话,就能用方便的HTTPPasswordMgrWithDefaultRealm。这个将在你为URL指定一个默认的用户名和密码。这将在你为特定realm提供一个其他组合时
得到提供。我们通过给realm参数指定None提供给add_password来指示这种情况。
最高层次的URL是第一个要求验证的URL。你传给.add_password()更深层次的URLs将同样合适。
[codesyntax lang=”python”]

# 创建一个密码管理者 
password_mgr = urllib2.HTTPPasswordMgrWithDefaultRealm() 
# 添加用户名和密码 
# 如果知道 realm, 我们可以使用他代替 ``None``. 
top_level_url = "http://example.com/foo/" 
password_mgr.add_password(None, top_level_url, username, password) 
handler = urllib2.HTTPBasicAuthHandler(password_mgr) 
# 创建 "opener" (OpenerDirector 实例) 
opener = urllib2.build_opener(handler) 
# 使用 opener 获取一个URL 
opener.open(a_url) 
# 安装 opener. 
# 现在所有调用 urllib2.urlopen 将用我们的 opener.

[/codesyntax]
urllib2.install_opener(opener)
注意:以上的例子我们仅仅提供我们的HHTPBasicAuthHandler给build_opener。默认的openers有正常状况的handlers–ProxyHandler,UnknownHandler,HTTPHandler,HTTPDefaultErrorHandler, HTTPRedirectHandler, FTPHandler, FileHandler, HTTPErrorProcessor。
top_level_url 实际上可以是完整URL(包含”http:”,以及主机名及可选的端口号)例如:http://example.com/,也可以是一个“authority”(即主机名和可选的
包含端口号)例如:“example.com” or “example.com:8080”(后者包含了端口号)。权限验证,如果递交的话不能包含”用户信息”部分,例如:
“joe@password:example.com”是错误的。
Proxies代理urllib 将自动监测你的代理设置并使用他们。这个通过ProxyHandler这个在正常处理器链中的对象来处理。通常,那工作的很好。但有时不起作用
。其中一个方法便是安装我们自己的代理处理器ProxyHandler,并不定义代理。这个跟使用Basic Authentication 处理器很相似。
[codesyntax lang=”python”]

>>> proxy_support = urllib.request.ProxyHandler({}) 
>>> opener = urllib.request.build_opener(proxy_support) 
>>> urllib.request.install_opener(opener)

[/codesyntax]
注意:
此时urllib.request不支持通过代理获取https地址。但,这个可以通过扩展urllib.request达到目的。
Sockets and Layers
Python支持获取网络资源是分层结构。urllib 使用http.client库,再调用socket库实现。
在Python2.3你可以指定socket的等待回应超时时间。这个在需要获取网页的应用程序里很有用。默认的socket模型没有超时和挂起。现在,socket超时没有暴露 www.2cto.com
给http.client或者urllib.request层。但你可以给所有的sockets设置全局的超时。

DDNS实现 (DHCP+DNS)

在网络管理中,维护DNS服务器是一项很基本的工作。但是,随着网络规模的不断扩大,频繁的去修改DNS区域数据文件,那也将会是一件很麻烦的事情。因此,动态DNS就应运而生。

动态DNS(DDNS)需要DNS和DHCP来协同工作。Linux下也可以实现DDNS,不过DNS需要Bind8以上的版本,DHCP需要3.0以上的版本。

本文用RedHat9来实现DDNS,Bind版本是bind-9.2.1-16,DHCP版本是dhcp-3.0pl1-23。DNS和DHCP使用一台服务器。

后记讲使用Cent OS 5.1实现DDNS。

1. DDNS试验拓扑

DDNS试验拓扑

2. 安装DNS和DHCP软件包

挂载系统盘,进入RPM包目录,使用rpm –ivh来安装bind包和dhcp包。其中caching-nameserver包是用来安装name.ca、name.local等区域文件的,如果不安装此包,那么就要手写或者从别的地方down这些文件了。

rpm

3. 配置DNS服务

① 编辑DNS服务主配置文件named.conf,默认在/etc/目录下。 [codesyntax lang=”text”]

vi /etc/named.conf
options {
             directory "/var/named";
};
zone "." IN {
            type hint;
             file "named.ca";
};
zone "localhost" IN {
             type master;
             file "localhost.zone";
             allow-update { none; };
};
zone "0.0.127.in-addr.arpa" IN {
             type master;
             file "named.local";
             allow-update { none; };
};
zone "bob.com" IN {
             type master;
            file "bob.com.dns";
             allow-update { none; };
};
zone "1.168.192.in-addr.arpa" IN {
             type master;
             file "bob.com.rev";
             allow-update { none; };
};
include "/etc/rndc.key";

[/codesyntax]

② 建立区域数据文件

因为安装了caching-nameserver这个包,所以像named.ca、named.local和localhost.zone这三个区域数据文件都有了。现在来创建bob.com域的正向和反向区域数据文件。 [codesyntax lang=”text”]

vi /var/named/bob.com.dns
$TTL 86400
$ORIGIN bob.com.
@    IN   SOA   bob.com.   root.bob.com. (
                                                    20081103 ;     serial
                                                    120 ;          refresh
                                                    14400 ;      retry
                                                    3600000 ;  expiry
                                                    86400 ) ;    minimum
                      IN   NS     bob.com.
dns                IN    A      192.168.1.251
www             IN    A      192.168.1.250

[/codesyntax] [codesyntax lang=”text”]

i /var/named/bob.com.rev
$TTL 86400
@    IN    SOA   bob.com.   root.bob.com. (
                                                    20081103 ;     Serial
                                                    120 ;          Refresh
                                                    14400 ;      Retry
                                                    3600000 ;  Expire
                                                    86400 ) ;    Minimum
                     IN   NS      bob.com.
251               IN  PTR     dns.bob.com.
250               IN  PTR     [url]www.bob.com[/url].

[/codesyntax] [codesyntax lang=”bash”]

chown named.named /var/named/bob.com.*

[/codesyntax]

③ 测试DNS服务

使用service named start命令启动DNS服务。

named

在防火墙中将UDP和TCP的53端口开放。

然后使用service iptables restart命令重启防火墙。

Windows PC测试:

在Windows PC上将DNS指向192.168.1.251。

windos

在Windows PC上使用nslookup命令来解析DNS服务器中的域名。

windows

Linux  PC测试:

在Linux PC上将DNS指向192.168.1.251。

resolv

在Linux PC上使用host命令和nslookup命令来解析DNS服务器中的域名。

linuxpc

4. 配置DHCP服务

① 编辑DHCP服务主配置文件dhcpd.conf,默认在/etc/目录下。 [codesyntax lang=”text”]

vi /etc/dhcpd.conf
ddns-update-style interim;
ignore client-updates;
default-lease-time 604800;
max-lease-time 864000;
option domain-name “bob.com”;
option domain-name-servers 192.168.1.251;
option time-offset -18000;
subnet 192.168.1.0 netmask 255.255.255.0 {
        range 192.168.1.100 192.168.1.200;
        option broadcast-address 192.168.1.255;
        option routers 192.168.1.1;
        }

[/codesyntax]

② 测试DHCP+DNS服务

使用service dhcpd start命令启动DHCP服务。

dhcpd

Windows PC测试:

在Windows PC上设置动态获取IP和DNS。

dhcp

在Windows PC上使用nslookup命令来解析DNS服务器中的域名。

windows

Linux PC测试:

在Linux PC上使用动态获取IP和DNS。

linuxpc

使用service network restart命令重启网卡。

service

使用ifconfig命令查看Linux PC获取到的IP地址。

linux

使用cat /etc/resolv.conf查看Linux PC获取到的DNS地址。

dhcp

在Linux PC上使用host命令和nslookup命令来解析DNS服务器中的域名。

linuxpc

5. 配置安全的DDNS

① 创建密钥

在DDNS服务器中以root身份进行:

使用dnssec–keygen –a HMAC-MD5 –b 128 –n USER bobddns命令来生成密钥。

dnssec-keygen用来生成更新密钥。

-a HMAC-MD5采用HMAC-MD5加密算法。

-b 128生成的密钥长度为128位。

-n USER bobddns密钥的用户名为bobddns。

dnssec

密钥生成后,会在当前目录下自动生成两个密钥文件Kbobddns.+157+xxx.key和Kbobddns.+157+xxx.private。

ls两个密钥文件

查看两个密钥文件的内容:

cat Kbobddns.+157+50923.key

cat Kbobddns.+157+50923.private

cat密钥文件

两个密钥文件中的128位密钥是一致的。需记住这一串密钥字符串,后面将会用到。

② 添加密钥信息到DNS主配置文件中 [codesyntax lang=”text”]

vi /etc/named.conf
添加:
key bobddns {
algorithm hmac-md5;
secret J+mC6Q29xiOtNEBySR4O1g==;
};

[/codesyntax] algorithm:指明生成密钥的算法。 secret:指明密钥串。 将bob.com区域中的allow-update { none; }中的“none”改成“key bobddns”; 将1.168.192.in-addr.arpa区域中的allow-update { none; }中的“none”也改成“key bobddns”。将“none”改成“key bobddns”的意思是指明采用“key bobddns”作为密钥的用户可以动态更新“bob.com”区域。

编辑named.conf

③ 添加密钥信息到DHCP主配置文件中 [codesyntax lang=”text”]

vi /etc/dhcpd.conf
添加:
key bobddns {
            algorithm hmac-md5;
            secret J+mC6Q29xiOtNEBySR4O1g==;
}
zone bob.com. {
            primary 192.168.1.251;
            key bobddns;
}
zone 1.168.192.in-addr.arpa. {
            primary 192.168.1.251;
            key bobddns;
}

[/codesyntax]

编辑dhcpd.conf

注意:域名后面的“.”千万不能少了,还有在每个“}”后面都没有“;”,这两点和named是不一样的,请注意。

④ 重启DHCP和DNS服务

service dhcpd restart

service named restart

重启DHCP和DNS服务

⑤ 测试DDNS

Windows PC测试:

使用hostname命令查看主机名。

windowspc

使用ipconfig/releaseipconfig/renew命令重新向DHCP服务器获取IP。

使用nslookup命令测试。使用ls bob.com命令,发现PC1已经被添加到了bob.com这个域中了。然后使用pc1.bob.com能解析到自己的IP地址了。

windows

Linux PC测试:

使用hostname命令查看主机名。

Linuxpc

在Linux PC上的/etc目录下新建一个DHCP客户端文件,文件名为dhclient.conf。 [codesyntax lang=”text”]

vi /etc/dhclient.conf
加入:
send fqdn.fqdn "Linux";
send fqdn.encoded on;
send fqdn.server-update off;

[/codesyntax]

dhclient.conf

使用dhclient命令立即启动DHCP客户端。

使用nslookup命令测试。使用linux.bob.com能解析到自己的IP地址了,使用pc1.bob.com也能解析到Windows PC的IP地址了。

linux

DDNS服务器测试:

在重启完DHCP和DNS服务后,如果正常,会在/var/named/目录下生成两个.jnl二进制格式区域文件。这两个文件是当前正在工作的区域文件的运行时文件,所有动态更新的记录首先会反应到这两个文件中,然后经过大约15分钟的时间才会将更新内容添加到区域数据文件中。在本文的例子中,区域数据文件就是“bob.com.dns”和“bob.com.rev”。

jnl

查看更新后的区域数据文件,系统会将手写的区域数据文件格式更改成它自己的格式。

bob.com.dns

说明:以上区域文件的书写格式与更新前相比变化较大,说明该文件已经被更新过了。Windows PC和Linux PC的主机记录已经在区域数据文件中自动添加进来了。这里还要说明的是,在动态更新的客户端PC1和Linux的A纪录下多了一条同名的TXT类型的纪录。TXT类型纪录是BIND-DNS和DHCP专门用来实现DDNS的辅助性资源纪录,它的值是哈希标示符字符串,该字符串的值还可以在DHCP租约文件/var/lib/dhcp/dhcpd.leases中找到。

dhcpd.lease

bob.com.rev

后记:Cent OS 5.1实验DDNS成功。

刚开始我使用Cent OS 5.1做这个实验,但是没有成功。named和dhcpd这两个服务都能够正常的启动,但是两个区域数据文件的.jnl文件死活不出现,这样就没有达到动态更新的目的。因为以前我使用Red Hat 9将这个实验做了出来,所以,现在我就先使用Red Hat 9来做这个实验,成功了。

接下来,我又重新使用Cent OS 5.1来做这个DDNS实验,但是结果还是一样。我以为是chroot搞的鬼,就将bind-chroot-9.3.3-10.el5这个包卸载了,但是结果还是不成功。那问题就不在chroot上了,我又重装上了bind-chroot-9.3.3-10.el5。

后来,我比对了一下Red Hat 9和Cent OS 5的区域数据文件的属主(Red Hat 9 的区域数据文件默认在/var/named/目录下;Cent OS 5的区域数据文件默认在/var/named/chroot/var/named/目录下。),发现Red Hat 9的named目录的属主和属组都是named,而Cent OS 5的named目录的属主是root,属组是named,并且named目录下的区域数据文件的属主和属组与named目录一样。因此,我将named目录的属主和属组都改成了named后,并且重启named服务,使用updatedb命令重刷系统数据库后,在/var/named/chroot/var/named/目录下两个.jnl文件出现了。此时使用Windows PC和Linux PC测试都成功了。真的很高兴,做了几遍终于搞定了。原来是文件及目录的权限搞怪,使用ps aux可以看到named服务的管理者是named。

如果使用Cent OS或者Red Hat 企业版做这个实验,其他步骤和上面一样,只要将name目录的属主改成named即可搞定。 [codesyntax lang=”bash”]

chown -R named.named /var/named/chroot/var/named/

[/codesyntax]

NAT路由详解

由于Internet的快速发展 IPV4地址不够用,不能每个主机分到一个公网IP 所以使用NAT地址转换。

下面是我在网上找到的一副图

一般来说都是由私网内主机(例如上图中“电脑A-01”)主动发起连接,数据包经过NAT地址转换后送给公网上的服务器(例如上图中的“Server”),连接建立以后可双向传送数据,NAT设备允许私网内主机主动向公网内主机发送数据,但却禁止反方向的主动传递,但在一些特殊的场合需要不同私网内的主机进行互联(例如P2P软件、网络会议、视频传输等),TCP穿越NAT的问题必须解决。

下面是NAT的几种类型

NAT设备的类型对于TCP穿越NAT,有着十分重要的影响,根据端口映射方式,NAT可分为如下4类,前3种NAT类型可统称为cone类型。
(1)全克隆( Full Cone) : NAT把所有来自相同内部IP地址和端口的请求映射到相同的外部IP地址和端口。任何一个外部主机均可通过该映射发送IP包到该内部主机。
(2)限制性克隆(Restricted Cone) : NAT把所有来自相同内部IP地址和端口的请求映射到相同的外部IP地址和端口。但是,只有当内部主机先给IP地址为X的外部主机发送IP包,该外部主机才能向该内部主机发送IP包。
(3)端口限制性克隆( Port Restricted Cone) :端口限制性克隆与限制性克隆类似,只是多了端口号的限制,即只有内部主机先向IP地址为X,端口号为P的外部主机发送1个IP包,该外部主机才能够把源端口号为P的IP包发送给该内部主机。
(4)对称式NAT ( Symmetric NAT): 对称式NAT与端口限制性克隆类似,唯一不同的是当同一内部主机使用相同的端口与不同IP地址或端口的外部主机进行通信时, NAT对该内部主机的端口映射会有所不同,这种情况下NAT会针对不同IP地址或端口的外部主机为内部主机的相同端口分配新的外部端口号。对称式NAT不保证所有会话中的私有地址端口和公开地址端口之间绑定的一致性。相反,它为每个新的会话分配一个新的端口号。这种情况下内部主机的“内网IP地址和端口”与“NAT IP地址和端口”之间会形成一对多关系。

这是我在网上找到的另一份关于NAT四种类型的解释,我觉得这个叙述更加清楚明了,这里写下来作为补充,请按照顺序和上面叙述的四种NAT类型进行对照理解:

从内网主机发出报文访问外网目标时,可用四元组[源IP,源端口,目标IP,目标端口]来表示会话:
[私有源地址,私有源端口,全局目标地址,全局目标端口]
     ↓NAT
[全局源地址,全局源端口,全局目标地址,全局目标端口]
   NAT在对不同的私有源地址进行转换的时候,可能转换成同一全局源地址,也可能转换成不同的全局源地址(如果NAT地址池配置有多个全局地址)。
   而对于同一私有源地址和端口的转换情况则分为以下几种:
(1)完全Cone NAT 无论目标地址和端口怎样,每次都把该私有源IP地址/端口映射到同一个全局源地址/端口;外网的任何主机都可以发送报文到该映射的全局地址而访问到该内部主机。路由器的静态地址映射就是属于这种。
(2)限制Cone NAT 地址/端口映射的情况同完全Cone NAT的,但外网的主机要访问内网主机,该内网主机必须先发送过报文给该外网主机的地址。
(3)端口限制Cone NAT 地址/端口映射情况同完全Cone NAT的,但外网主机要访问内网主机,该内网主机必须先发送过报文给该外网主机的地址和端口。大多数路由器的NAPT就是属于这种情况。本文后面论及的Cone NAT也是指这种情况。

(4)Symmetric NAT 对不同的目标地址/端口,源私有地址映射到源全局地址不变,但是映射的全局端口会改变。外网主机必须先收到过内网主机的报文,才能访问到该内网主机。一些路由器和防火墙产品的NAT就是属于这种情况。

    Symmetric NAT并不对新会话进行端口绑定,而是分配一个全新的NAT端口给每一个新的会话.
     Server S1                                     Server S2
        18.181.0.31:1235                              138.76.29.7:1235
               |                                             |
               |                                             |
               +———————-+———————-+
                                      |
          ^  Session 1 (A-S1)  ^      |      ^  Session 2 (A-S2)  ^
          |  18.181.0.31:1235  |      |      |  138.76.29.7:1235  |
          v 155.99.25.11:62000 v      |      v 155.99.25.11:62001 v
                                      |
                                 Symmetric NAT
                                 155.99.25.11
                                      |
          ^  Session 1 (A-S1)  ^      |      ^  Session 2 (A-S2)  ^
          |  18.181.0.31:1235  |      |      |  138.76.29.7:1235  |
          v   10.0.0.1:1234    v      |      v   10.0.0.1:1234    v
                                      |
                                   Client A
                                10.0.0.1:1234
    如上图,如果Client A同时发起两个会话到S1和S2,对称NAT会分配NAT地址155.99.25.11:62000给Session1,然后分配另一个不同的NAT地址155.99.25.11:62001给Session2.对称NAT能够区别两个不同的会话并进行地址转换,应用程序每发出一个会话都会使用一个新的端口.

下面我们接着来看看对NAT进行打洞的流程与原理

先假设:有一个服务器S在公网上有一个IP,两个私网分别由NAT-A和NAT-B连接到公网,NAT-A后面有一台客户端A,NAT-B后面有一台客户端B,现在,我们需要借助S将A和B建立直接的TCP连接,即由B向A打一个洞,让A可以沿这个洞直接连接到B主机,就好像NAT-B不存在一样。

实现过程如下:
1、 S启动两个网络侦听,一个叫【主连接】侦听,一个叫【协助打洞】的侦听。
2、 A和B分别与S的【主连接】保持联系。
3、 当A需要和B建立直接的TCP连接时,首先连接S的【协助打洞】端口,并发送协助连接申请。同时在该端口号上启动侦听。注意由于要在相同的网络终端上绑定到不同的套接字上,所以必须为这些套接字设置 SO_REUSEADDR 属性(即允许重用),否则侦听会失败。
4、 S的【协助打洞】连接收到A的申请后通过【主连接】通知B,并将A经过NAT-A转换后的公网IP地址和端口等信息告诉B。
5、 B收到S的连接通知后首先与S的【协助打洞】端口连接,随便发送一些数据后立即断开,这样做的目的是让S能知道B经过NAT-B转换后的公网IP和端口号。
6、 B尝试与A的经过NAT-A转换后的公网IP地址和端口进行connect,根据不同的路由器会有不同的结果,有些路由器在这个操作就能建立连接,大多数路由器对于不请自到的SYN请求包直接丢弃而导致connect失败,但NAT-B会纪录此次连接的目标地址和端口号(即A经过NAT-A转换后的公网IP和端口号),为接下来真正的连接做好了准备,这就是所谓的打洞,即B向A打了一个洞,下次A就能直接连接到B刚才使用的端口号了。
7、 客户端B打洞的同时在相同的端口上启动侦听。B在一切准备就绪以后通过与S的【主连接】回复消息“我已经准备好”,S在收到以后将B经过NAT-B转换后的公网IP和端口号告诉给A。
8、 A收到S回复的B的公网IP和端口号等信息以后,开始连接到B公网IP和端口号(此时NAT-A也会纪录此次连接的目标地址和端口号(即B经过NAT-B转换后的公网IP和端口号),即A也向B打了一个洞,之后B也能直接连接到A的公网IP和端口号了),由于在步骤6中B曾经尝试连接过A的公网IP地址和端口,NAT-B纪录了此次连接的信息,所以当A主动连接B时,NAT-B会认为是合法的SYN数据,并允许通过,从而直接的TCP连接建立起来了。

有了一定的知识补充,接下来开始实现UDP和TCP打洞。因为没干过这个 可能要花一定的时间

NAT技术实现

NAT的基本原理是仅在私网主机需要访问Internet时才会分配到合法的公网地址,而在内部互联时则使用私网地址。当访问Internet的报文经过NAT网关时,NAT网关会用一个合法的公网地址替换原报文中的源IP地址,并对这种转换进行记录;之后,当报文从Internet侧返回时,NAT网关查找原有的记录,将报文的目的地址再替换回原来的私网地址,并送回发出请求的主机。这样,在私网侧或公网侧设备看来,这个过程与普通的网络访问并没有任何的区别。

1  NAT实现方式

1.1  Basic NAT方式

Basic NAT方式属于一对一的地址转换,在这种方式下只转换IP地址,而对TCP/UDP协议的端口号不处理,一个公网IP地址不能同时被多个用户使用。

图1 Basic NAT方式原理图

如图1所示,Basic NAT方式的处理过程如下:

(1) NAT设备收到私网侧主机发送的访问公网侧服务器的报文。

(2) NAT设备从地址池中选取一个空闲的公网IP地址,建立与私网侧报文源IP地址间的NAT转换表项(正反向),并依据查找正向NAT表项的结果将报文转换后向公网侧发送。

(3) NAT设备收到公网侧的回应报文后,根据其目的IP地址查找反向NAT表项,并依据查表结果将报文转换后向私网侧发送。

& 说明:

由于Basic NAT这种一对一的转换方式并未实现公网地址的复用,不能有效解决IP地址短缺的问题,因此在实际应用中并不常用。

1.2  NAPT方式

由于Basic NAT方式并未实现地址复用,因此并不能解决公网地址短缺的问题,而NAPT方式则可以解决这个问题。

NAPT方式属于多对一的地址转换,它通过使用“IP地址+端口号”的形式进行转换,使多个私网用户可共用一个公网IP地址访问外网,因此是地址转换实现的主要形式。

图2 NAPT方式原理图

如图2所示,NAPT方式的处理过程如下:

(1) NAT设备收到私网侧主机发送的访问公网侧服务器的报文。

(2) NAT设备从地址池中选取一对空闲的“公网IP地址+端口号”,建立与私网侧报文“源IP地址+源端口号”间的NAPT转换表项(正反向),并依据查找正向NAPT表项的结果将报文转换后向公网侧发送。

(3) NAT设备收到公网侧的回应报文后,根据其“目的IP地址+目的端口号”查找反向NAPT表项,并依据查表结果将报文转换后向私网侧发送。

1.3  NAT Server方式

出于安全考虑,大部分私网主机通常并不希望被公网用户访问。但在某些实际应用中,需要给公网用户提供一个访问私网服务器的机会。而在Basic NAT或NAPT方式下,由于由公网用户发起的访问无法动态建立NAT表项,因此公网用户无法访问私网主机。NAT Server(NAT内部服务器)方式就可以解决这个问题——通过静态配置“公网IP地址+端口号”与“私网IP地址+端口号”间的映射关系,NAT设备可以将公网地址“反向”转换成私网地址。

图3 NAT Server方式原理图

如图3所示,NAT Server方式的处理过程如下:

(1) 在NAT设备上手工配置静态NAT转换表项(正反向)。

(2) NAT设备收到公网侧主机发送的访问私网侧服务器的报文。

(3) NAT设备根据公网侧报文的“目的IP地址+目的端口号”查找反向静态NAT表项,并依据查表结果将报文转换后向私网侧发送。

(4) NAT设备收到私网侧的回应报文后,根据其“源IP地址+源端口号”查找正向静态NAT表项,并依据查表结果将报文转换后向公网侧发送。

1.4  EASY IP方式

EASY IP方式是指直接使用接口的公网IP地址作为转换后的源地址进行地址转换,它可以动态获取出接口地址,从而有效支持出接口通过拨号或DHCP方式获取公网IP地址的应用场景。同时,EASY IP方式也可以利用访问控制列表来控制哪些内部地址可以进行地址转换。

EASY IP方式特别适合小型局域网访问Internet的情况。这里的小型局域网主要指中小型网吧、小型办公室等环境,一般具有以下特点:内部主机较少、出接口通过拨号方式获得临时公网IP地址以供内部主机访问Internet。对于这种情况,可以使用EASY IP方式使局域网用户都通过这个IP地址接入Internet。

图4 EASY IP方式原理图

如图4所示,EASY IP方式的处理过程如下:

(1) NAT设备收到私网侧主机发送的访问公网侧服务器的报文。

(2) NAT设备利用公网侧接口的“公网IP地址+端口号”,建立与私网侧报文“源IP地址+源端口号”间的EASY IP转换表项(正反向),并依据查找正向EASY IP表项的结果将报文转换后向公网侧发送。

(3) NAT设备收到公网侧的回应报文后,根据其“目的IP地址+目的端口号”查找反向EASY IP表项,并依据查表结果将报文转换后向私网侧发送。

1.1.2  DNS Mapping方式

在某些应用中,私网用户希望通过域名访问位于同一私网的内部服务器,而DNS服务器却位于公网。由于通常DNS响应报文中携带的是内部服务器的公网IP地址,因此若不在NAT设备上进行处理,私网用户将无法通过域名访问到内部服务器。

这个问题可以使用DNS Mapping方式来解决,通过配置“域名—公网IP地址—公网端口—协议类型”映射表,建立内部服务器的域名与其公网信息间的对应关系。

图5 DNS Mapping方式原理图

如图5所示,私网用户Host希望通过域名方式访问Web服务器。当NAT设备收到DNS响应报文后,先根据其中携带的域名查找DNS Mapping映射表,再根据“公网IP地址—公网端口—协议类型”查找Web服务器,然后将DNS响应报文中的公网IP地址替换成Web服务器的私网IP地址。这样,Host收到的DNS响应报文中就携带了Web服务器的私网IP地址,从而可以通过域名来访问Web服务器。

2  ALG机制

2.1  ALG机制简介

通常情况下,NAT只改变IP报文头部地址信息,而不对报文载荷进行分析,这对于普通的应用层协议(如Telnet)来说,并不会影响其业务的开展;然而有一些应用层协议,其报文载荷中可能也携带有地址或端口信息,若这些信息不能被有效转换,就可能导致问题。譬如,某些应用层协议会在客户端与服务器之间协商端口号,然后服务器使用协商出的端口号向客户端发起连接。如果NAT设备对二者的协商过程一无所知,那么当服务器向客户端发起连接时,就会因为在NAT设备上找不到内部与外部的IP地址/端口号对应关系而造成连接失败。

这个问题可以通过应用级网关(ALG)机制来解决。ALG是特定应用协议的转换代理,它通过对IP报文的载荷进行解析,改变封装在其中的地址和端口信息,并完成其它必要的工作以使应用协议可以穿越NAT。ALG机制可处理的应用层协议包括DNS、FTP、H.323、ILS和SIP等,下面以FTP协议为例介绍ALG处理的过程。

2.2  FTP协议的ALG处理

在FTP工作过程中,客户端与服务器之间将建立两条TCP连接:一条为控制连接,负责传输诸如用户指令和参数等控制信息,其中包括发起数据连接时要用到的端口信息;另一条为数据连接,负责在服务器与客户端之间建立数据通道以传送文件。FTP可分为主动和被动两种模式,根据所采用的模式以及服务器/客户端的位置来决定是否需要进行ALG处理:

1. 主动模式

在主动模式下,在由客户端发起控制连接中,客户端将指定的端口通过PORT指令发送给服务器,然后由服务器向该端口发起数据连接,因此:

l 当客户端位于公网而服务器位于私网时,由于客户端向服务器通告的是公网地址和端口,服务器可直接向其发起数据连接,因此无需在控制连接中进行ALG处理;

l 当客户端位于私网而服务器位于公网时,由于客户端向服务器通告的是私网地址和端口,因此需在控制连接中通过ALG处理将其转换为公网地址和端口,以供服务器发起数据连接所用,其过程如图6所示。

图6 主动模式下的ALG处理

(1) 首先,由客户端向服务器发送PORT指令,以向服务器通知发起数据连接所应使用的地址和端口(IP 1,Port 1);

(2) NAT设备收到该指令后,将其中所携带的私网地址和端口(IP 1,Port 1)替换为公网地址和端口(IP 2,Port 2),并据此创建相应的NAPT表项——此过程即为ALG处理;

(3) 服务器收到该指令后,主动向公网地址和端口(IP 2,Port 2)发起数据连接,并在通过NAT设备时被转化为私网地址和端口(IP 1,Port 1)。

2. 被动模式

在被动模式下,在由客户端发起控制连接中,客户端向服务器发送PASV请求来通知服务器它将发起被动模式,服务器再将指定的端口通过PASV响应发送给客户端,然后由客户端向该端口发起数据连接,因此:

l 当服务器位于公网而客户端位于私网时,由于服务器向客户端通告的是公网地址和端口,客户端可直接向其发起数据连接,因此无需在控制连接中进行ALG处理;

l 当服务器位于私网而客户端位于公网时,由于服务器向客户端通告的是私网地址和端口,因此需在控制连接中通过ALG处理将其转换为公网地址和端口,以供客户端发起数据连接所用,其过程如图7所示。

图7 被动模式下的ALG处理

(1) 首先,由客户端向服务器发送PASV请求;

(2) 服务器收到该请求后,选择并打开服务器端数据通道的地址和端口(IP 1,Port 1),并通过PASV响应向客户端返回该地址和端口;

(3) NAT设备收到该响应后,将其中所携带的私网地址和端口(IP 1,Port 1)替换为公网地址和端口(IP 2,Port 2),并据此创建相应的NAPT表项——此过程即为ALG处理;

(4) 客户端收到该响应后,向公网地址和端口(IP 2,Port 2)发起数据连接,并在通过NAT设备时被转换为私网地址和端口(IP 1,Port 1)。

3  NAT多实例的实现

NAT多实例主要针对MPLS L3VPN用户访问公网或为公网提供服务而提出,可实现不同VPN内、使用相同私网地址的用户同时访问外部网络。NAT多实例在转换过程中增加了对VPN的识别和处理,把VPN作为区分会话的参数之一,以此实现了多实例同时访问公网的功能。

1. 多实例Basic NAT

与单实例一样,多实例的Basic NAT只对私网的IP地址进行转换,但不同的是多实例Basic NAT在原有私网IP地址转换的基础上增加了对VPN的识别和处理,即在NAT转换表项中增加了VPN信息,并将其作为转换依据之一,以确保将不同VPN内相同的私网IP地址转换成不同的公网IP地址。

多实例NAPT

与单实例相比,多实例的NAPT在原有私网IP地址和端口号转换的基础上,增加了对VPN的识别和处理,即在NAPT转换表项中增加了VPN信息,并将其作为转换依据之一,以确保将不同VPN内相同的“私网IP地址+端口号”转换成不同的“公网IP地址+端口号”。

3. 多实例NAT Server

与单实例相比,多实例的NAT Server增加了私网侧对VPN的支持,即在所配置的静态NAT转换表项中增加了VPN信息,并将其作为转换依据之一,以确保将访问不同VPN的报文送达正确的VPN,其处理流程与单实例相同。

4. 多实例EASY IP

与单实例相比,多实例的EASY IP在原有私网IP地址和端口号转换的基础上,增加了对VPN的识别和处理,即在EASY IP转换表项中增加了VPN信息,并将其作为转换依据之一,以确保将不同VPN内相同的“私网IP地址+端口号”转换成不同的“公网IP地址+端口号”。

5. 多实例DNS Mapping

与单实例相比,多实例的DNS Mapping增加了私网侧对VPN的支持,即在所配置的DNS Mapping映射表项中增加了VPN信息,并将其作为转换依据之一,以确保将访问不同VPN的报文送达正确的VPN,其处理流程与单实例相同。

6. 多实例ALG处理

多实例的ALG处理流程与单实例基本相同,不同的是NAT设备在创建公网与私网的地址端口映射表项时,NAT多实例在私网侧地址和端口基础上增加了对VPN的识别与处理,即在映射表项中增加了VPN信息,譬如将私网侧的(VPN A,IP 1,Port 1)与公网侧的(IP 2,Port 2)进行映射。

Wifiin免费接入运营商wifi热点

很多90后学生用户往往有这样烦恼:还没到月底,手机的流量用完了。因为没有收入来源,也没有白领们常常可以享受到的话费补助,自从有了微信后,学生们对电话和短信的需求越来越少,互联网应用成了他们最主要的手机应用,流量成了最最关键的刚需。如果不想再额外支出费用,又想解决上网的问题,怎么办?
其实,在90%以上的高校,以及大约50%以上的中小学校园,运营商已经布设了WLAN网络,但资费却不便宜,而且每个运营商的网络都限定给自己的在网用户使用,也把很多人挡在了网络的外面。
如今有一款叫wifiin的软件,也叫WiFi一号通,可以支持自动连接运营商wifi热点,发现热点一点就能用。而且不跟手机的SIM卡关联,即使没卡的手机或者只有wifi的ipad也能用。非常神奇。说白了就是把所有的运营商的认证接口做了聚合,并且直接给用户即时开户即时使用。157892942

原来这个软件内聚合了很多免费的任务,可以通过做任务的方式,实现免费上网的目的。在最新的2.4版本里,用户可以有以下途径获得wifiin的虚拟银币那它是怎么实现免费上网的呢?
· 每天签到和分享
· 推荐wifiin给其他朋友
· 下载应用内推荐的其他app并试用。
· 消费返利,目前最新的Android版本支持大众点评的团购订单,其他平台还需要等待一段时间。

157892943

157892944

目前这个软件支持中国移动CMCC、CMCC-EDU、中国电信ChinaNet以及中国联通ChinaUnicom等WLAN热点,是同类软件中唯一一家支持3个运营商的app。支持的范围最广。157892945

在智能手机操作平台方面,wifiin支持Android、iOS和WP,从覆盖的操作系统平台上来讲,也是比较完整的,没有盲区。157892946

此外,wifiin最大的一个特点是支持Pad和没有sim卡的手机,因为同类软件都需要先跟服务器通信获取权限,所以都需要手机的数据流量支持,而wifiin经过特殊处理流程,可以避开这一步,是AppStore同类软件中的唯一一款支持iPad的App。
wifiin的特点是简单并且可以免费上网。你不需要在每个运营商都开通对应的账号,也不用繁琐的账号输入过程,它自动完成上网所需要的步骤。

官网:http://www.wifiin.com

网络流量捕捉:Wireshark

Wireshark简介

Wireshark(前称Ethereal)是一个网络封包分析软件。网络封包分析软件的功能是撷取网络封包,并尽可能显示出最为详细的网络封包资料。网络封包分析软件的功能可想像成 “电工技师使用电表来量测电流、电压、电阻” 的工作 – 只是将场景移植到网络上,并将电线替换成网络线。
网络管理员使用Wireshark来检测网络问题,网络安全工程师使用Wireshark来检查资讯安全相关问题,开发者使用Wireshark来为新的通讯协定除错,普通使用者使用Wireshark来学习网络协定的相关知识当然,有的人也会“居心叵测”的用它来寻找一些敏感信息。
Wireshark不是入侵侦测软件(Intrusion DetectionSoftware,IDS)。对于网络上的异常流量行为,Wireshark不会产生警示或是任何提示。然而,仔细分析Wireshark撷取的封包能够帮助使用者对于网络行为有更清楚的了解。Wireshark不会对网络封包产生内容的修改,它只会反映出目前流通的封包资讯。 Wireshark本身也不会送出封包至网络上。
Linux网络流量分析系统首先依赖于一套捕捉网络数据包的函数库。这套函数库工作在在网络分析系统模块的最底层。作用是从网卡取得数据包或者根据过滤规则取出数据包的子集,再转交给上层分析模块。从协议上说,这套函数库将一个数据包从链路层接收,至少将其还原至传输层以上,以供上层分析。
在Linux系统中,1992年Lawrence Berkeley Lab的Steven McCanne和Van Jacobson提出了包过滤器的一种的实现,BPF(BSD Packet Filter)。Libpcap是一个基于BPF的开放源码的捕包函数库。现有的大部分Linux捕包系统都是基于这套函数库或者是在它基础上做一些针对性的改进。在window系统中,意大利人Fulvio Risso和Loris Degioanni提出并实现了Winpcap函数库,作者称之为NPF。由于NPF的主要思想就是来源于BPF,它的设计目标就是为windows系统提供一个功能强大的开发式数据包捕获平台,希望在Linux系统中的网络分析工具经过简单编译以后也可以移植到windows中,因此这两种捕包架构是非常现实的。就实现来说提供的函数调用接口也是一致的。Ethereal网络分析系统也需要一个底层的抓包平台,在Linux中是采用Libpcap函数库抓包,在windows系统中采用winpcap函数库抓包。

层次化的数据包协议分析方法

取得捕包函数捕回的数据包后就需要进行协议分析和协议还原工作了。由于OSI的7层协议模型,协议数据是从上到下封装后发送的。对于协议分析需要从下至上进行。首先对网络层的协议识别后进行组包还原然后脱去网络层协议头。将里面的数据交给传输层分析,这样一直进行下去直到应用层。由于网络协议种类很多,就Ethereal所识别的500多种协议来说,为了使协议和协议间层次关系明显。从而对数据流里的各个层次的协议能够逐层处理。Ethereal系统采用了协议树的方式。
如果协议A的所有数据都是封装在协议B里的,那么这个协议A就是协议B是另外一个协议的儿子节点(比如图中的TCP和UDP协议就是IP协议的儿子节点)。我们将最低层的无结构数据流作为根接点。那么具有相同父节点的协议成为兄弟节点。那么这些拥有同样父协议兄弟节点协议如何互相区分了?Ethereal系统采用协议的特征字来识别。每个协议会注册自己的特征字。这些特征字给自己的子节点协议提供可以互相区分开来的标识。比如tcp协议的port字段注册后。Tcp.port=21就可以认为是ftp协议,特征字可以是协议规范定义的任何一个字段。比如ip协议就可以定义proto字段为一个特征字。
在Ethereal中注册一个协议解析器首先要指出它的父协议是什么。另外还要指出自己区别于父节点下的兄弟接点协议的特征。比如ftp协议。在Ethereal中他的父接点是tcp协议,它的特征就是tcp协议的port字段为21。这样当一个端口为21的tcp数据流来到时。首先由tcp协议注册的解析模块处理,处理完之后通过查找协议树找到自己协议下面的子协议,判断应该由那个子协议来执行,找到正确的子协议后,就转交给ftp注册的解析模块处理。这样由根节点开始一层层解析下去。
由于采用了协议树加特征字的设计,这个系统在协议解析上由了很强的扩展性,增加一个协议解析器只需要将解析函数挂到协议树的相应节点上即可。

基于插件技术的协议分析器

所谓插件技术,就是在程序的设计开发过程中,把整个应用程序分成宿主程序和插件两个部分,宿主程序与插件能够相互通信,并且,在宿主程序不变的情况下,可以通过增减插件或修改插件来调整应用程序的功能。运用插件技术可以开发出伸缩性良好、便于维护的应用程序。它着名的应用实例有:媒体播放器winamp、微软的网络浏览器IE等。
由于现在网络协议种类繁多,为了可以随时增加新的协议分析器,一般的协议分析器都采用插件技术,这样如果需要对一个新的协议分析只需要开发编写这个协议分析器并调用注册函数在系统注册就可以使用了。通过增加插件使程序有很强的可扩展性,各个功能模块内聚。

安装Wireshark

该软件有极其方便和友好的图形用户界面,并且能够使得用户通过图形界面的配置和选择,针对多块网卡、多个协议进行显示,效果非常好。目前最新版本为:Wireshark 1.0.3。安装该软件请按照如下步骤进行:
1. 将下载的最新版本软件拷贝到临时文件夹
[codesyntax lang=”bash”]

cp wireshark-1.0.3.tar.gz /usr/local/src/

[/codesyntax]
2. 切换到临时文件夹目录
[codesyntax lang=”bash”]

cd /usr/local/src/

[/codesyntax]
3. 解压缩文件
[codesyntax lang=”bash”]

tar -xvf wireshark-1.0.3.tar.gz

[/codesyntax]
另外,同Tcpdump一样,在编译Ethereal之前应先确定已经安装pcap库(libpcap),这是编译Wireshark时所必需的。如果该库已经安装,就可以执行下面的命令来编译并安装Wireshark:
[codesyntax lang=”bash”]

cd wireshark-1.0.3
 ./configure
 make
 make install

[/codesyntax]
当编译并安装好Wireshark后,就可以执行“wireshark”命令来启动Wireshark

网络爬虫(二):利用urllib2通过指定的URL抓取网页内容

版本号:Python2.7.5,Python3改动较大,各位另寻教程。
所谓网页抓取,就是把URL地址中指定的网络资源从网络流中读取出来,保存到本地。
类似于使用程序模拟IE浏览器的功能,把URL作为HTTP请求的内容发送到服务器端, 然后读取服务器端的响应资源。
继续阅读网络爬虫(二):利用urllib2通过指定的URL抓取网页内容

网络爬虫(一):抓取网页的含义和URL基本构成

一、网络爬虫的定义

网络爬虫,即Web Spider,是一个很形象的名字。
把互联网比喻成一个蜘蛛网,那么Spider就是在网上爬来爬去的蜘蛛。
网络蜘蛛是通过网页的链接地址来寻找网页的。
从网站某一个页面(通常是首页)开始,读取网页的内容,找到在网页中的其它链接地址,
然后通过这些链接地址寻找下一个网页,这样一直循环下去,直到把这个网站所有的网页都抓取完为止。
如果把整个互联网当成一个网站,那么网络蜘蛛就可以用这个原理把互联网上所有的网页都抓取下来。
这样看来,网络爬虫就是一个爬行程序,一个抓取网页的程序。
网络爬虫的基本操作是抓取网页。
那么如何才能随心所欲地获得自己想要的页面?
我们先从URL开始。

二、浏览网页的过程

抓取网页的过程其实和读者平时使用IE浏览器浏览网页的道理是一样的。
比如说你在浏览器的地址栏中输入 www.baidu.com 这个地址。
打开网页的过程其实就是浏览器作为一个浏览的“客户端”,向服务器端发送了 一次请求,把服务器端的文件“抓”到本地,再进行解释、展现。
HTML是一种标记语言,用标签标记内容并加以解析和区分。
浏览器的功能是将获取到的HTML代码进行解析,然后将原始的代码转变成我们直接看到的网站页面。

三、URI和URL的概念和举例

简单的来讲,URL就是在浏览器端输入的 http://www.baidu.com 这个字符串。
在理解URL之前,首先要理解URI的概念。
什么是URI?
Web上每种可用的资源,如 HTML文档、图像、视频片段、程序等都由一个通用资源标志符(Universal Resource Identifier, URI)进行定位。
URI通常由三部分组成:
①访问资源的命名机制;
②存放资源的主机名;
③资源自身 的名称,由路径表示。
如下面的URI:
http://www.why.com.cn/myhtml/html1223/
我们可以这样解释它:
①这是一个可以通过HTTP协议访问的资源,
②位于主机 www.webmonkey.com.cn上,
③通过路径“/html/html40”访问。

四、URL的理解和举例

URL是URI的一个子集。它是Uniform Resource Locator的缩写,译为“统一资源定位 符”。
通俗地说,URL是Internet上描述信息资源的字符串,主要用在各种WWW客户程序和服务器程序上。
采用URL可以用一种统一的格式来描述各种信息资源,包括文件、服务器的地址和目录等。
URL的一般格式为(带方括号[]的为可选项):
protocol :// hostname[:port] / path / [;parameters][?query]#fragment

URL的格式由三部分组成:

①第一部分是协议(或称为服务方式)。
②第二部分是存有该资源的主机IP地址(有时也包括端口号)。
③第三部分是主机资源的具体地址,如目录和文件名等。

第一部分和第二部分用“://”符号隔开,
第二部分和第三部分用“/”符号隔开。
第一部分和第二部分是不可缺少的,第三部分有时可以省略。

五、URL和URI简单比较

URI属于URL更低层次的抽象,一种字符串文本标准。
换句话说,URI属于父类,而URL属于URI的子类。URL是URI的一个子集。
URI的定义是:统一资源标识符;
URL的定义是:统一资源定位符。
二者的区别在于,URI表示请求服务器的路径,定义这么一个资源。
而URL同时说明要如何访问这个资源(http://)。

下面来看看两个URL的小例子。

1.HTTP协议的URL示例:
使用超级文本传输协议HTTP,提供超级文本信息服务的资源。

例:http://www.peopledaily.com.cn/channel/welcome.htm
其计算机域名为www.peopledaily.com.cn。
超级文本文件(文件类型为.html)是在目录 /channel下的welcome.htm。
这是中国人民日报的一台计算机。

例:http://www.rol.cn.net/talk/talk1.htm
其计算机域名为www.rol.cn.net。
超级文本文件(文件类型为.html)是在目录/talk下的talk1.htm。
这是瑞得聊天室的地址,可由此进入瑞得聊天室的第1室。

2.文件的URL
用URL表示文件时,服务器方式用file表示,后面要有主机IP地址、文件的存取路 径(即目录)和文件名等信息。
有时可以省略目录和文件名,但“/”符号不能省略。

例:file://ftp.yoyodyne.com/pub/files/foobar.txt
上面这个URL代表存放在主机ftp.yoyodyne.com上的pub/files/目录下的一个文件,文件名是foobar.txt。

例:file://ftp.yoyodyne.com/pub
代表主机ftp.yoyodyne.com上的目录/pub。

例:file://ftp.yoyodyne.com/
代表主机ftp.yoyodyne.com的根目录。

爬虫最主要的处理对象就是URL,它根据URL地址取得所需要的文件内容,然后对它 进行进一步的处理。
因此,准确地理解URL对理解网络爬虫至关重要。

本文节选至:请叫我汪海