Linux就这个范儿 第12章 一个网络一个世界
与Linux有缘相识还得从一项开发任务说起。十八年前,我在Nucleus OS上开发无线网桥AP,需要加入STP生成树协议(SpanningTreeProtocol)。当时我对STP不太了解,只知道它是由一个名字叫man却不是man的,并有“互联网之母”称号的牛人发明的。于是就上网査找资料。那时参考资料很少,很幸运Linux上有STP的源码可以借鉴,从而顺利的在Nucleus上实现了STP,也因此与Linux结下了不解之缘。从那时起我就下决心不断学习和掌握它,同时很荣幸地享受着Linux提供的各种各样的网络服务。
Nucleus0S是当时与VxWorks、QNX等实时操作系统齐名的专门为嵌入式应用而设计的一个抢先式多任务操作系统。MTK很多时候用的就是它。
STP能够提供路径冗余。使用STP可以使两个终端中只有一条有效路径。
RadiaPerlman在1983年发明了SpanningTreeAlgorithms(STA)生成树算法并研制出了用网桥(交换机)设备的SpanningTreeProtocol(STP)生成树协议。
12.1 You've Got a Mail
你是否还记得多年以前放映的那部电影you have got a mail(中译名《电子情书》)?电影里讲述的那浪漫温馨的爱情故事至今回荡在我心田。那么我们就以这个故亊作为讲述Linux邮件服务的开始,在Linux上架设邮件服务器,让Email搭起乔与凯瑟琳爱情的桥……
12.1.1 Email服务模式
Email是Internet应用中最广泛的应用之一。Linux邮件服务在这个方面发展得非常快,尤其是邮件服务器软件。几年前只有Sendmail,现在己经有很多种选择,如Qmail、Postfix、exim以及Zmailer等,绝对让你挑花眼。
Email地址通常使用“账号@主机名称”的方式来表示。假设乔在xyz.com上的邮件服务器注册,取得了一个合法的电子邮件使用权限,他的邮箱账号为joe,那他的Email地址就是:[email protected]。这时候他就能收发邮件了。当他要给凯瑟琳写电子邮件的,假设凯瑟琳的Email地址是[email protected],那他的电脑是否能够将这封信直接通过网络传到abc。com那个主机上呢?哈哈,当然不行啦!乔要寄出一封邮件时需要很多系统帮忙的,我们结合传送过程讲讲电子邮件服务及其组成,你就会明白了。
电子邮件服务基于客户/服务器模式,对于一个完整的邮件系统来说,它由三部分组成。
如果要将它们对应到现实世界中的邮政系统就是:邮局、邮递员和邮政法。
1.邮局
也就是邮件服务器,它起着传统邮局的作用,是邮件系统的核心,由MTA、MDA、存储和MRA四个部门组成。
(1)MTA(MailTransfcrAgent),中译名是邮件传送代理。它的职能是将邮递员收上来的信件转发到目标邮局,属于邮政系统的分拣运输部门。它将来自用户端或者其他MTA的来信收下来,如果该邮件的目的地并不是本身的用户,那么本地的MTA就会将该封信再传送到下一部主机。乔利用[email protected]发给凯瑟琳的邮件被xyz.com上的邮件服务器先收下来再做后面的处理。我们一般提到的邮件服务器就是MTA,主流的有Sendmail、Postfix、Qmail等。实际上MDA是挂在MTA底下的一个部门。
(2)MDA(Mail Delivey Agent),中译名是邮件投递代理。它的主要职能是接过MTA转过来的邮件并分析由MTA所收到的新建表头或内容以决定这封邮件的去向。上面提到的MTA的信件转发功能其实是由MDA实现的。如果MTA所收到的邮件目标是自己,那么MDA就将邮件转到用户的邮箱(Mailbox)里。当发现收到的乔给凯瑟琳的邮件不是发给本地的,那就准备转发出去。为什么说是准备呢?因为MDA还有分析与过滤功能。它可以根据邮件的表头或者特定的邮件内容来分析过滤,例如过滤一些垃圾广告邮件。为什么说MDA是附属部门呢?其实各主要的MTA软件,例如postfix,都有自己的MDA功能,不过有的外挂的软件功能更强大,例如procmail就是过滤好手。,
(3)邮件存储,属于邮政系统的仓储部门。我们的Linux系统预设的邮箱放在/var/spool/mail/[用户账号]中。如果MTA收到的邮件是给本地用户的,MDA会将邮件塞到mailbox里。例如凯瑟琳注册的abc。com邮件服务器收到转发过来的给凯瑟琳的邮件,abc。com邮件服务器发现是本机的用户,MDA就会将邮件放在凯瑟琳拥有的mailbox当中。
(4)MRA(Mail Retrieval Agent),中译名邮件收取代理。它主要的职能是向邮递员发放要投递的信件,属于邮政系统的对外营业部门。例如,凯瑟琳PC上的MUA与MRA连接,凯瑟琳输入账号与密码获取认证和授权。MRA确认用户账号和密码没有问题了,就把在/var/spool/mail/kathleen下的邮件传给凯瑟琳的MUA,当所有邮件传送结束后,凯瑟琳的mailbox下的内容就会被删除。
2.邮递员
也就足邮件客户端,正式称谓是邮件用户代理(Mail User Agent),简称MUA。其接受用户输入的各种指令,将用户的邮件通过SMTP协议发送至MTA或者通过POP3、IMAP协议将邮件从MTA取到本机。例如在Linux上的Evolution和Mozilla推出的Thunderbird(雷鸟)等就是干这个用的,它们收发邮件主机的电子邮件,以及提供用户浏览与编写邮件的功能。
3.邮政法
俗话说:“没有规矩不成方圆。”为了保证邮政系统的正常运作,国家制定了邮政法。为了保证电子邮件的顺利收发,人们也制定了一套相关的“法律”,就是收发邮件的各种通信协议。
发送电子邮件使用的协议是简单邮件传输协议(SMTP),它规定了邮件的发送和转发规则。MUA到MTA,MTA到MTA之间使用的就是SMTP协议。
接收电子邮件的大多使用的是POP3协议,它规定了人们在收取邮件时要遵守的一些格式规范。POP3是Internet电子邮件的第一个离线协议标准,允许从服务器上把电子邮件存贮到本地主机,同时删除保存在邮件服务器上的邮件。现在还有一个POP3的替代协议叫IMAP(Internet Message Access Protocol),它提供了一些新颖的功能。
还有出于安全考虑防止垃圾邮件的简单认证安全层(SASL),它提供一种认证机制来验证用户名和密码,从而提高了安全性。
图12.1清晰的展示了邮件服务的基本工作原理。在整个邮件传送过程中,乔发给凯瑟琳的邮件通过乔所属的邮件服务器发送到凯瑟琳所属的邮件服务器上,然后停留在凯瑟琳在服务器上的mailbox里,而不是为凯瑟琳服务的邮递员MUA手上,理解这点很关键,为了简明起见,图中故意省略了所属远程邮局的邮递员投递邮件环节。
12.1.2架设Postfix服务器
当你理解上面的概念后,就不难架设一个邮件服务器了。Sendmail出道很早,是一款比较出名的MTA软件。
不过配置Sendmail没那么简单,会让许多人望而却步。Postfix的出现使我们架设Mail Server有了一个更好的选择。
Postfix有两个主要的软件包,postfix(SMTP Server)和qpopper(POP3Server)。我们把SMTP及POP3Server都架设在同一主机上,这样在实际操作上比较方便。
1.配置SMTP服务器
Main.cf是Postfix的主要配置文件,常规情况下应该保存在/etc/poslfix目录下。它的大致内容如代码1所示。为了让大家能够理解每一个配置项的含义,我做了一些中文注释。
代码1:
#邮件存放的目录。 queue_directory= /var/spool/postfix #postXXX命令(如postfix、postalias、postconf等)所在目求。 command_directory = /usr/sbin #指定所有Postfix相关的daemon所在目录。目录必须拥有root权限。 daemon_directory = /usr/lib/postfix #指定MailServer在Internet上的完整主机名称。 myhostname = mta.taobao.com #指定本地端的域名。 mydomain = taobao.com #在Postfix主机上发送邮件时,对方接收后显示的发件人的邮件地址 #xx@[$myorigin],由于mydomain在前面设置的是taobao.com。所以 #对方接收后显示发件人为[email protected]。 myorigin = $mydomain #默认值为127.0.0.1,会造成外部MUA,MTA无法跟Postfix交互, #建议改为all。 inet_interfaces = all #Postfix默认使用此参数来判断收到的信件是否为本地信件, #其默认值应该包含$myhostname。 #有多个域名时。各名称之间可使用空格键或逗号“,”隔开。 mydestination = $mydomain #邮件服务器允许转发是指接收并同意传递一个目的地址不属于本地域名的邮件 #允许转发邮件的具体方式默认值为:subnet,主要有3种方式: #class:根据服务器设置的IP地址属于A/B/C中的哪一类地址决定 # 允许转发的服务器: #subnet:根据mailserver的IP及netmask计算, # 只允许同一个网段的主机利用你的mailserver来relay邮件; #host:只允许localhost可以relay邮件 mynetworks_style = subnet #指定可以使用此mailserver来转发邮件的IP/netmask。 #如果mynetwoks跟mynetworks_style同时设置。 #则myneworks覆盖mynetworks_style的值。 mynetworks=192.168.1.0/24,127.0.0.0/8 #设定每封信件大小不得超过10MB。 message_size_limit=10240000
设置mynetworks_style时,最好不要使用class方式。因为如果你的邮件服务器地址为119.167.235.251,就会使得所有119.x.x.x这样的IP都能利用你的服务器来为他们做邮件转发,这时你的服务器就很容易成为垃圾邮件的载体了。
设置完这些参数后,就可以启动postfix了。执行命令:
# postfix start
乔要给凯瑟琳写情书,就可以通过这个邮件服务器发送给她了。
2.配置POP3服务器
目前这台服务器还只能提供寄信功能,还不能收信。要想收信,还得配罝POP3服务器。POP3服务是通过xinetd来启动的,常规情况下配置文件是/etc/xinetd.d/qpopper,它的大致内容如代码2所示。
代码2:
servicepop3 { disable = yes socket_type = stream protocol = tcp wait = no user = root server = /usr/sbin/popper server_args = -s flags = IPv4 }
将“disable”的值改成“no”保存。然后执行命令:
# rcxinetd restart
你的POP3服务器就能用了。这时,凯瑟琳就能够通过这个服务器收到乔发给她的邮件了。
3.邮件服务器维护
虽然乔和凯瑟琳可以通过这套服务器相互收发邮件了,但是也不能确保一切都万无一失,因为邮件服务器有可能会发生故障。认真负责的你这时不要慌,出了问题咱们解决问题就行,乔和凯瑟琳是不会怪你的。
查看日志是确认系统故障的一个便捷途径。Postfix的日志放在/var/log/mail下,除了包含邮件收发记录外,还会记录邮件系统的错误信息。如果你哪天发现邮件服务器工作不正常了,就可以通过这个文件查看相关信息,作为排错的依据。
此外,你可能还有一个更大的疑问,那就是用户的邮件都放在哪里了?这个无需担心,服务器提供了很多个“大柜子”来放它们。用户的邮件暂存在/var/spool/mail目录下。例如乔的邮件都放在/var/spool/mail/joe文件中;凯瑟琳的在/var/spool/mail/kathleen文件中。其实不只是用户正常收发的邮件会被这样妥帖地保存着,那些无法正常发送的邮件也会暂存在/var/spool/postfix目录下,还能使用mailq査看它们。
那么为什么会有邮件无法正常发送呢?原因有很多,比较常见的是:DNS有问题,另一端MTA离线或信箱容量已满等。在这种情况下Postfix会把邮件打上时间戳,暂时存放在deferred queue里。驻留太多邮件会给邮件主机带来额外的负担,需要根据实际情况调整这些参数。驻留邮件的参数设置可以通过postconf命令查看和配置。postconf是一个能帮助你配置Postfix的工具。例如我们使用命令:
# postcon£ -d maximal_queue_lifetime
查看邮件驻留最长时间的设定值。如果返回结果为:
maximal_queuc_lifetime = 3d
则表示邮件驻留的最长时间为3天。超过这个时间,退信给发件人。还可以使用命令:
Postconf -d | grep backoff
获得deferred queue邮件的最短和最长时间minimal_backoff_time和maximal_backoff_time。有时候已经过时的邮件是没必要再发送了。就比如凯瑟琳已经嫁人,乔给她的情书写得再情真意切也是没啥用的,弄不好还要挨揍。若是真发生这个悲剧,我们得帮乔一把:
Postsuper -d ALL
删除所有驻留的邮件。这也叫“挥剑斩情丝”!
4.配置Postfix认证功能
前面我们己经使用mynetworks和mynetworks_stylc来指定邮件服务器转发信任源。当一个邮件服务器不符邮件接收者和邮件发送者是谁,而是对所有邮件进行转发(relay),则该邮件服务器被称为开放转发(open relay)的邮件服务器。为了避免沦为open relay被外人利用,我们设定mynetworks_style为subnet,但是当你每次出差从外网通过公司的邮件系统给客户发信时,因为你笔记本的IP地址不在转发范围,就需要告诉管理员把它设定在mynetworks里,多麻烦呀!所以我们要启用SMTP的认证功能,识别发件人的邮件账号和密码,通过认证后就不受信任源的限制。
SMTP认证方式采用SASL(Simple Authenticationand Security Layer)。SASL是一种用来扩充C/S模式验证能力的机制。支持SASL的服务器端监听网络连接。客户端连接应用并发起认证过程:客户端选择个SMTP AUTH的机制,并根据这个机制准备相应的凭证,然后把它选择的机制和相应的凭证发给服务器。服务器方保存客户端的验证机制和相应的凭证,并把它交给一个真正完成这种密码验证的后台服务,比如saslauthd来验证服务。验证服务根据客户的凭证和验证的后端数据(比如/etc/shadow文件)来确定是否通过验证,并把验证结果返回给邮件发送服务,Postfix通过返回结果来判断用户是否有权使用转发服务,或是辨认谁在使用你的服务器。
Cyrus SASL是SASL的一个实现。安装完cyrus-sasl这个软件包后,只需要简单地修改一下main.cf文件即可。下面我们就在main.cf中配置认证功能,添加的内容如下:
#启用Postfix的SASL认证功能。
smtpd_sasl_auth_enable = yes
#设定Postfix收发信件的规则(保持下列为一行,没有断行):
smtpd_recipient_restrictions = permit_mynetworks,permit_sasl_authenticated,
reject_unauth_destination
这里我们给Postfix设定了三条收发信件的规则,其实这种规则还有很多,表12-1列出了一些较为常用的规则。
还得说一下saslauthd。Saslauthd是一个独立运行的daemon,它是基于系统密码来验证的,可以读取很多种后端的认证数据,包括:getpwent(/etc/passwd)、kerberos、pam、rimap(remoteIMAPserver)、shadow和Idap,其中一些操作是需要root权限才能执行,而saslauthd就是以root身份来运行的,它可以帮助postfix来验证密码,因为postfix本身在设计的时候避开了特权身份。我们使用rcsaslauthdstart命令启动saslauthd服务,使用chkconfigsaslauthd35命令在下次开机时自动启动saslauthd服务。
12.1.3 Email故事的结局
邮件造情缘,在那首抒情的Some where Over the rain bow的歌曲中,乔和凯瑟琳终于通过我们搭建的邮件服务器在公园里约会成功了。他们拥抱着……我们的Linux邮件服务就是那幕后的真英雄。世界界上最珍贵的是人与人之间的情感,记得和家人朋友多多联系,哪怕,只是个邮件!
12.2联接世界的Web应用
Linux网络,Web是重中之重。因为几乎所有的Web服务器都能够运行在Linux系统之上,这使得Linux逐渐成为互联网的核心,奠定了广泛且忠实的群众基础。最常见的形式是将Linux与Apache+Mysql+Perl/PHP/Python捆绑,从而构成了大家耳熟能详的LAMP。现在又出现了一个长尾巴的P兄弟——Ruby。它们共同组成了一个强大的Web应用程序平台,与J2EE和.Net这两个商业软件形成了三足鼎立之势。
当前有很多著名的网站采用了LAMP架构,如新浪、YouTube等。但随着时间的推进,这个曾经不可一世的Apache越发显得老态龙钟,渐渐地已经跟不上技术发展的脚步了。现如今。一个高性能的Web和反向代理服务器——Nginx,就像Apache的克星一样杀将过来,所到之处是打得Apache片甲不留。尤其是在高并发连接的情况下,Nginx的效率几乎是Apache的数十上百倍,这个时候Apache哪有不死的道理?
当然,不管技术如何的变化,在Linux上利用Web服务器、数据库和脚本语言来建设web应用的思路一直没有变。接下来我们就去认识一下这些东西。
12.2.1 Web服务器
讲述Web之前,让我们先来膜拜一下“互联网之父”伯纳斯·李。他在CERN(欧洲粒子物理研究所)工作时,编写了一个名为“Enquire”的信息处理工具,算得上是WWW的最初概念吧。
1989年,那是一个夏天的午后,伯纳斯·李端着咖啡,在被紫丁香花簇拥着的实验室走廊里悠闲地散步。馥郁香浓的咖啡味夹杂着恬淡幽雅的花香,阵阵飘入伯纳斯·李鼻子里,刺激着他的嗅觉神经。若是把你我这等凡人置身到那个环境下,估计也就是感叹一下:今儿是个好天儿!可是伯纳斯李却陷入了思考:各种好闻的气味夹在一起可以让人心旷神怡,那么是不是各种类型信息拼接在一起也会让人耳目一新呢?于是放下咖啡回到实验室,继续鼓捣他的“Enquire”。经过一番努力,伯纳斯·李使得“Enquire”能够同时处理多种类型的信息,且能够将它们一同展现出来。这是一种新颖的信息类型,应该取个好名字,很快就有了Hypertext(超文本)这个改变世界的新名词。
紧接着在第二年,就是1990年,伯纳斯·李在NeXTStep网络系统上又开发出了世界上第一Web服务器——Httpd和第一个客户端浏览器程序——Word Wide Web(WWW)。同年12月,CERN首次启动了万维网并成立了全球第一个WWW网站info.cern.ch(至今仍是CERN的官方网站)从此以后,万维网开始得到了广泛的应用。我们必须要膜拜伯纳斯·李的原因就是他并没有因此自满,而是继续推动着万维网的前进方向。相继制定了互联网的URIs、HTTP、HTML等技术规范,并在美国麻省理工学院成立了非营利性互联网组织W3C,使得Web技术和应用能够长期地蓬勃发展。
伯纳斯·李永远都是我最最敬仰的大科学家之一。他并没有因为创造了万维网而获得丰呼的物质回报。恰恰相反的是他放弃了所有权,使得万维网成为了一个完全开放式的系统。对人无所求,给人的却是极好的东西。这就是大家风范!
大神膜拜完了,我们还是要回到正题上来,看看Web服务器是个什么玩意儿吧。
Web服务器用来存储超文本文件HTML(网页),并基于客户端网页浏览器的需求,将网页传输并分配给用户的计算机。所有工作的执行都依赖于超文本传输协议(HTTP)。用户运行客户端浏览器,以此给网站服务器发送访问请求并浏览其存储的超文本文件。除此之外,用户还可利用网页向Web服务器发送信息,要求Web服务器进行处理并返回结果。因此,Web服务器不仅能够存储超文本文件(网页),还拥有处理数据等其他功能。
在上述处理过程中涉及了路径翻译,我们有必要首先搞清楚这个概念。Web服务器会把统一资源定位符(URL)[ 统一资源定位符(Uniform Resourcc Locator)简称URL.
是用于完整地描述Internet上网页和其他资源的地址(该地址以“http://”开始)的一种标识方法。]的路径分量映射到一个本地文件系统资源(如果是静态请求)或者一个内部或外部程序名(如果是动态请求)。
统一资源定位符(Uniform Resourcc Locator)简称URL.是用于完整地描述Internet上网页和其他资源的地址(该地址以“http://”开始)的一种标识方法。
对于静态请求,客户端指定的URL路径是服务器根目录的相对路径。假设客户端发来了这样的URL:
http://www.example.com/path/file.html
客户端的用户代理(useragent)会把它翻译连接到www.example.com服务器上的一个HTTP1.1请求:
GET /path/file.html HTTP/1.1 Host: www.example.com
在www.example.com上的Web服务器将把给定路径附加到根目录上。如果Web服务器的根目录设置为/home/public/web,那么结果应该是本地文件系统资源/home/public/web/path/file.html。知道本地路径及文件名后,Web服务器读取文件,如果文件存在就把响应结果发给客户端浏览器,否则返回错误信息。所以响应结果可能是文件内容的描述以及文件内容本身或者表示文件不存在等错误信息。
然后再看看Web服务器有哪几个功能。一般来讲,有以下六个基本功能:
(1)支持HTTP通信协议。
(2)支持通用网关接口。
(3)支持基于IP、域名、端口的虚拟主机。
(4)支持服务器端包含指令(SSI)。
(5)支持FastCGI。
(6)支持URL重写。
虽然其功能很强大,但是它的工作原理并不复杂。一般可分成如下4个步骤:连接、请求、应答以及关闭连接。下面对这4个步骤做一简单的介绍。
连接过程就是Web服务器和其浏览器之间所建立起来的一种连接。如果要查看连接过程是否实现,用户可以找到和打开socket这个虚拟文件,这个文件的建立意味着连接过程这一步骤已经成功建立。
请求过程就是Web的浏览器运用socket这个文件向其服务器提出各种请求。
应答过程就是运用HTTP协议把在请求过程中所提出来的请求传输到Web的服务器,进而实施任务处理,然后运用HTTP协议把任务处理的结果传输到Web的浏览器,同时在Web的浏览器上面展示上述所请求之界面。
关闭连接就是当上一个步骤——应答过程完成以后,Web服务器和其浏览器之间断开连接之过程。上述4个步骤环环相扣、紧密相联,逻辑性比较强,可以支持多个进程、多个线程以及多个进程与多个线程相混合的技术应用。
在Windows、Linux与Unix这3个操作系统上都可以架设Web服务器,可以理直气壮地说Linux的性能价格比在这3个操作系统中最高,它支持多个硬件平台,网络功能超群。当然有了条件优越的马场(Linux),又有了性能卓越的快马(高性能Web服务器,例如nginx),之后就要靠我们驯马师根据服务器系统的特点与用途做进一步的优化与处现,让快马发挥出神奇的功能。例如从系统层面进行内核参数调节,提高服务器性能[ 衡量服务器性能有两个重要指标:QPS和RT。QPS(Query-per-second)指的是1秒钟内完成的请求数量。RT( Response-time)指的是1个请求完成的时间。QPS增加意味者单台服务器的利用率提高.所需的服务器的数量减少.RT的缩短意味着用户访问页面的响应时间就少,QPS也会增加。推荐三款Linux系统上的Web服务性能测试工具,它们足http_load、webbench和ab。];从编写Web应用方面注意尽量减少Web服务器的数据传输量以及降低数据传输的频率,从而提高网络客户端的网页加载的速度。
12.2.2数据库
数据库是Linux应用中的重要部分,顾名思义就是存放数据的仓库。不过在计算机上存放数据时不像存放粮食那么简单,要按照数据结构来组织、存储和管理数据。数据库技术产生于六十年代末,随着信息技术和市场的发展,特别是在二十世纪九十年代以后,数据管理不再仅仅是存储和管理数据,而转变成用户所需要的各种数据管理的方式。数据库无论从最简单的存储数据表格到进行海量数据存储的大型数据库系统,在各个方面都得到了广泛应用。
首先我们谈谈关系型数据库。Linux上的商业数据库包括:Oracle、Sybase、DB2、lnformix;自由软件数据库包括:MySQL、PostgreSQL、Msql、Gadfly、BeaglcSQL等。在它们当中,MySQL的性价比最好。它是瑞典的TcX公司(已经被Oracle收购)负责开发和维护的一个真正的多用户和多线程的SQL数据库服务器,在Linux平台上的使用案例多如牛毛。它以客户机/服务器结构实现其功能的,由一个服务器守护程序mysqld和很多不同的客户程序和库组成。
尽管MySQL足免费的,但是它从来没有停止进步。从5.0开始支持存储过程和trigger,功能变得越来越强大。正是由于这个原因,淘宝和支付宝在大刀阔斧开展去O工作(O这里指的是Oracle),极力推广MySQL。MySQL语法上虽然和PL/SQL有差别,不过搞过编程的人都知道,语法不是问题,关键是思想。了解MySQL语法后,就可以从变量定义、循环、判断、游标、异常处理这个几个方面开始深入学习了。
衡量服务器性能有两个重要指标:QPS和RT。QPS(Query-per-second)指的是1秒钟内完成的请求数量。RT( Response-time)指的是1个请求完成的时间。QPS增加意味者单台服务器的利用率提高.所需的服务器的数量减少.RT的缩短意味着用户访问页面的响应时间就少,QPS也会增加。
推荐三款Linux系统上的Web服务性能测试工具,它们是http_load、webbench和ab
在设计关系型数据库的读写应用时,要考虑快速读取、读写分离和避免单点故障。先通过数据库分片来解决数据库写扩展的问题。数据库分片主要是按照业务来分,尽可能的拆分业务。把数据库分片,部署到不同的服务器上,避免单点故障以及写操作成为瓶颈。另外利用MySQL复制(master-slave)来解决读的问题。首先MySQL数据库通过master-slave实现读写分离,通过多个slave来应对应用程序读的操作。
然而随着互联网Web2.0网站的兴起,非关系型数据库成了一个极其热门的新领域。传统的关系数据库在应付Web2.0网站,特别是超大规模和高并发的SNS类型的Web2.0纯动态网站的已经显得力不从心。暴露了很多难以克服的问题。于是在对数据库要求“三高”(高并发、高扩展和高可用)的背景下产生了NoSQL数据库。它以键值对存储,结构不固定,每个元组可以有不一样的字段,每个元组可以根据需要增加一些自己的键值对,这样就不会局限于固定的结构,可以减少些时间和空间的开销。正是由于这个特点,它们可以处理超大量的数据,运行在便宜的PC服务器集群上。
需要声明的是NoSQL可不是指没有SQL,而是Not Only SQL的意思。现在有些人鼓吹要一场革命运动铲除关系型数据库,这完全是天方夜谭。固然NoSQL发展势头强劲,利用哈希表的API访问给出确切的键值(key)返回响应的值(value)的方法,可伸缩性和性能结构可以掌握在开发人员手上,风险可控。但是这种自由是双刃剑,非规范化模型缺乏统一的接口和互操性,系统设计的差异化很大,降低了开发的敏捷性。而SQL数据模型的工作方式呢,它强调建立数据的完整性、简洁性、数据标准化和抽象,这对所有的大型复杂应用极为重要。因此,建立在NoSQL的基础架构上的SQL数据库,双方融合互补,才是一个最好的解决方案。举个简单的例子,memcached与MySQL并肩作战应付读的问题更靠谱。Memcached是一套分布式的快取系统。memcached的API使用三十二位元的循环冗余校验(CRC-32)计算键值后,将资料分散在不同的机器上。当表格满了以后,接下来新增的资料会以LRU机制杆换掉。应用程序萏先从memcached中获取数据,获取不到再从数据库中获得并保存在memcached中。好的应用95%的数据从memcache中获得,3%的数据从MySQL的querycache中获得,剩下2%才去查表。这就应验了CacheisKing[ 缓存为王。在计算机和网络的世界里,缓存无处不在。
]这句话。
说起运行在Linux上的NoSQL数据库,还真不少,例如有Memcache、Riak、Cassandra、HBASE、Redis和MongoDB等。Memcache是老牌产品,稳定性力面有一定的口碑,应用较为广泛。Redis是后起之秀,查询速度比较快,支持List和Set等不少的数据类型。关于Redis,有一个细节,我禁不住要夸一夸它。编译Redis之前并不需要执行./configure。编译完后在当前目录下产生四个执行文件,清晰明了,分别是redis-server、redis-cli、redis-benchmark、redis-stat尽管只是四个文件,但是从服务daemon程序、命令行操作工具、性能测试工具和状态检测工具一应俱全。当然如果是企业级应用,选用Cassandra或HBase更合适一些。
缓存为王。在计算机和网络的世界里,缓存无处不在。
12.2.3解释型语言
古老的LAMP包的脚木组件中包括了CGIweb接口,它在90年代初期开始流行起来。通用网关接口(CommonGatewayInterface/CGI)描述了客户端和服务器程序之间传输数据的一种标准,是一种很重要的互联网技术。它允许网页浏览器的用户在服务器上执行一个程序,和接受静态的内容一样接受动态的内容。程序员使用脚本语言来创建这些小程序,因为它们能很容易地操作文本流,甚至当这些文本流并非源自程序自身的。
除了有Java平台和.NET平台这两种重装骑兵提供Web动态技术外,还有如PHP、Perl、Python和Ruby等轻骑兵,它们也能快速有效地提供相应的轻量级解决方案。当然PHP、Perl、Python和Ruby不仅是后台脚本语言,它们还都能作为前台语言来开发命令行或图形界面的应用。Linux系统对这四种语言的支持都非常好,好多杀手级的应用都源于此,例如新浪微博就是用PHP开发的。所以我迫不及待地想向你介绍一下它们各自的特点。
首先是PHP,它简单和专一,在HTML代码中外以单纯地插入PHP代码。它好像是专门为网络应用量身打造的,处理套接字流(socket stream)的情况比较多。而Perl、Python和Ruby是通用语言,正好与PHP相反,做法一般是往这类语言的代码中嵌入HTML代码,
其次是Perl,它吸取了C、sed、awk、shell scripting以及很多其他程序语言的特性。其中最重要的特性是它内部集成了正则表达式的功能。以及巨大的第三方代码库CPAN。Perl既强大又好用,所以它被广泛地用日常生活的方方面面,例如在Perl社区里有这么一个笑话,内容大致是:下次股市大崩盘产生的原因极可能是由于某个Perl程序员的脚本里面的臭虫引起的。当然Perl也不是十全十美的。它的程序代码令人难以阅读。写好一段优雅的Perl程序还真需要一定的功力。
至于Python,它的开发者哲学是“用一种方法、最好是只有一种方法来做一件事”。它是完全面向对象的语言,比Perl具备更好的可读性,并且能够支撑大规模的软件开发。很多项目是这样安排的,在性能要求极高的部分叫C++编写,然后用Python调用相应的模组。我尝试过Python开发,这里不得不提一下让人既爱又恨的那个限制性很强的缩进规则。例如if语句的下一行如果不向右缩进,不能通过编译,这种苛刻的规则是个双刃剑。它使得代码具有较好的可读性,但是也给初学者带来了不少困扰。
接下来再来说说后起之秀Ruby,它兼具Perl的表现力和Python的可读性。Ruby更注重编程人的感受,而不是语言本身的功能。这个观点有点意思,编程的过程也讲究人性化。所以Ruby语言通常非常直观,按照编程人认为它应该的运行方式运行。由于它借用了很多Perl的东西,所以Perl6的开发者唐风(Audrey Tang)戏称,“Ruby是没有到处打广告的Perl6”。
不得不承认上而讲的这些编程语言都是好东西。但是面对出现的越来越多的编程语言,有些程序员会感到无所适从。在实际工作中,我的体会是:在互联网开发中没有一种语言是万能的,只会一种语言是万万不能的。淘宝有位牛人曾经干过前端工程师、Java工程师、DBA和SQA。淘宝总裁三丰曾经说过:“今天我们很多功能切分过度,让人家掌握的领域太窄,我后面强制要求P7①以上必须是全能选手,从前端到Java,再到搞数据,再到搞无线,从Android到iPhone,都要会。”博览众家之长,做到人器合一,确实是我们追求的目标。
淘宝职级。P7为专家级。
12.2.4架设Web服务器
又到了实战的时刻。首先声明我准备采用LNMP“组合拳”来完成Web服务器的架设。为什么呢?这年头,Apache除了慢没打别的缺点了。Nginx是后起之秀,高并发和负载均衡能力均受到青睐,很多公司改弦易张使用Nginx替代Apache做整个网站的前端服务。另一方面Nginx采用的是2-clause BSD-like协议,在尊重代码作者的著作权的情况下鼓励代码共享,可以免费使用,并且可用于商业用途。因为BSD协议限制比较少,允许代码使用者修改代码或二次开发,所以很多公司在选用开源产品时会把遵从BSD协议的软件作为首选。
首先谈谈Nginx的工作方式。它通过异步IO来解决主线程阻塞的问题。运行模式是Master-Worker模式。至于究竟采用多少个Nginxworker子进程呢?我们可以根据CPU数量和实际业务量来决定,其次,Nginx通过配置支持PHP、JSP、ASP.NET和Perl实现动态页面生成,在本例中我们就用PHP作为组合中的“P”成员。
由于Nginx有自己的数据类型、内存、进程和线程管理等方法,研究透nginx非一时之功,这里介绍的只是皮毛而己。
从http://www.nginx.net网站下载源码包安装后,我们就要根据我们的实际需求对nginx.conf做配置。Nginx配S文件主要分为4部分:main(全局配置),server(虚拟主机配置),upstream(主要为反向代理)和localion(目录匹配配置),每部分包含若干个指令:
●main部分指令的影响力是整个所有部分;
●server部分指令的影响力范围没有那么大,主要用于指定虚拟主机域名、IP和端口,这
些会被location继承,同时server部分继承了main部分的指令;
●location部分用于匹配网页位置(例如,根目录“/”和“/images”等等),它继承了server
部分的指令;
●upstream的指令用于设置反向代理及后端服务器的负载均衡,不会继承也不会影响其
他部分。
有了配置的整体概念后,我们再来看看nginx.conf文件里主要选项的含义。
#用户组
user www www;
#工作进程,可根据CPU数量设置。例如4核CPU采用4个工作进程
worker_processes 4;
#错误日志
error_log logs/error.log;
#pid文件位置
pid logs/nflinx.pid;
events{
#工作进程(每个worker)的最大连接数量,根据硬件调整,和前面工作进程配合起来用。worker_connections 1024;
}
http{
include mime.types;
default_type application/octet-stream;
sendfile on;
keepalive_timeout 65;
server{
#默认端口是80
listen 80 default;
server_name localhost;
location /
root html;
index index.html index.htm;
}
#重定向服务器错误页到静态页 /50x.html
error_page 500 502 503 504 /50x.html;
location = /50x.html {
root html;
}
}
}
进程的文件描述符 打开数量
在初次启动Nginx时,文件描述符短缺是较普遍的问题。因为所有线程共享相同的资源,包括内存和文件描述符,所以建议你使用ulimit命令改变系统的进程文件描述符限制。ulimit是一种Linux系统上帮助我们改变进程文件描述符限制的内建功能。
在上一章中我们谈到优化内核参数可以提高服务器负载能力。为了增强nginx运行的性能,我们在/etc/sysct1.conf末尾加入以下内容:
/etc/sysct1.conf #表示SYN队列的长度 net.ipv4.tcp_max_syn_backlog=65536 #进入包的最大设备队列 net.core.netdev_max_ backlog=32768 #listen()的默认参数,挂起请求的最大数量 net.core.somaxconn=32768 #指定了发送套接字缓冲区大小的缺省值 net.core.wmem_default=8388608 #指定了接收套接字缓冲区大小的缺省值 net.core.rmem_default=8388608 #指定最大TCP接收缓冲区大小,可使用setsockopt()设置接收缓冲区大小 net.core.rmem_max=16777216 #指定最大TCP发送缓冲区大小。可使用setsockopt()设置发送缓冲区大小 net.core.wmem_max=16777216 #可以防范那些伪造的sequence号码,关掉可以提高性能 net.ipv4.tcp_timestamps=0 #为了打开对端的连接,内核需要发送一个SYN并附带 #一个回应前面一个SYN的ACK。这个设置决定了 #内核放弃连接之前发送SYN+ACK包的数量。 net.ipv4.tcp_synack_retries=2 #新连接,内核要发送多少个SYN边接请求才决定放弃 net.ipv4.tcp_syn_retries=2 #开启TCP连接中TIME-WAIT sockets的快速回收 net.ipv4.tcp_tw_recycle=1 #允许将TIME-WAIT sockets重新用于新的TCP连接 net.ipv4.tcp_tw_reuse=1 #将系统对本地端口范围限制在5000~65535 net.ipv4.ip_local_port_range=5000 65535
在上面的系统控制配置文件修改完成之后,敲入/sbin/sysctl -p命令使配置生效。总的来说,有如下两种手段提高服务器的响应速度和并发:一种是异步I/O epoll方式,另一种是多线程或多进程方式。利用线程池和增加线程数量能很大程度地提高系统的响应速度。在连接数不算很多的时候,多线程威力不小。但是如果要维护上万以上的用户长连接,线程本身的开销不容忽视。Linux操作系统线程本身是一种资源。数量是有限制的,不可能无节制地使用。所以线程越多消耗内存越多,系统的内存也有可能被线程耗尽。基于此,在确定自己使用的线程数量时,还需结合CPU、内存以及实际应用场景综合考虑,对症下药。例如计算型应用消耗CPU,线程数最一般就是CPU的数量;搜索索引服务器,代理应用消耗I/O,线程越多越好。但是达到一定程度时,线程本身资源就成为一种瓶颈。这种情况下,Nginx使用异步I/O的方法实现高并发的效果最好。
Nginx的安装和配置的讲解告一段落后,我们再进行MySQL的安装和配置工作。MySQL的配置文件为/etc/my.cnf,所包含的选项众多,涉及了目录、语言、存储引擎、网络、信息安全、内存管理、日志、镜像和表空间文件等方面的设置。在丰富而复杂的MySQL配置选项中,我强调一下字符集的设置,建议使用utf8编码格式避免中文乱码的问题。这里举一个简单的my.cnf配置,内容如下所示:
my.cnf [mysqld] datadir=/var/lib/mysql socket=/var/lib/mysql/mysql.sock user=mysql #Default to using old password format forcompatibility with mysql 3.x #clients(those using the mysqlclient10 compatibility package). Old_passwords = 1 #default-character-sets=utf8 [mysqld-safe] log-error=/var/log/mysqld.log pid-file=/var/run/mysqld/mysqld.pid de£ault-characterset=utf8
另外从系统安全性考虑,建议为mysql服务添加一个非root用户组和用户,例如:
Groupadd mysql
useradd mysql –g mysql -M[ 添加mysql到mysql组,M指的是不要自动建立用户的登入记录。]
然后以非root用户的方式启动mysqld。
接下来,我们说说在LNMP组合中的P成员。这里我们挑选的P成员是PHP。Linux系统一般默认带Perl。PHP还需自己安装。一般来说,你不需要改变PHP设置,根据默认的配置PHP通常就能工作了。但PHP设计者们本着精益求精的精神,为用户提供更加周到和全面的服务。他们考虑到用户可能需要针对特定应用程序对PHP语言的一些功能进行调整。因此,将一些PHP变量通过/etc/php.ini的配置文件给出来。此配置文件包括设置文件路径、改变会话以及数据库参数和激活扩展选项(activating extensions)等。就拿错误信息选项为例,PHP缺省是打开错误信息显示的,此时display_errors=On,我们把它改为:display_errors=Off关闭错误显示。这样做的话PHP函数执行错误的信息将不会再显示给用户,在一定程度上防止攻击者从错误信息得知脚本的物理位置以及一些其他有用的信息,起码给攻击名的黑箱检测造成一定的障碍。但是这些错误信总对我们自己还是有用的,把它们写到指定文件中为好,所以配置指令log_errors=Off修改为log_errors=On以及指定日志文件的位置,我们就能看到错误日志帮助我们找到运行问题。好,现在我们把php.ini中的配置指令做如下修改:
error_reporting = E_ALL ;将会向PHP报告发生的每个错误 display_errors = Off ;关闭错误显示 log_errors = On ;开启错误日志文件功能 log_errors_max_len = 1024 ;设置每个错误日志项的最大长度 error_log = /usr/local/error.log ;指定错误日志文件位置 expose_php = false
另外PHP默认expose_php=On,当PHP启动的时候,Web服务器标准头信息中会添加PHP版本号信息,为了防范潜在的黑客攻击,还是用expose_php=false或Off关闭此功能为好。
PHP配置完成后,咱别忘了在Nginx配置文件的server部分中再加入定义支持PHP,配置内容如下所示:
Location ~ .*\. (php|php5) ?$ { £astcgi_pass 127.0.0.1:9000; fastcgi_index index.php; include fastcgi.conf; }
OK! Nginx、Mysql以及PHP都搞定了,我们使用如下命令:
/usr/local/bin/php-cgi –b 127.0.0.1:9000
启动php-cgi,然后写个PHP测试页info.php,内容如下:
php
phpin£o();
?>;
如果工作正常的话,访问网页时你应该能看到PHP的信息。如果看到了,恭喜你,Nginx+Mysql+PHP安装运行成功,在此基础上你就可以提供丰富多彩的Web服务了。
在这次小试牛刀成功之后,你应该会有点成就感吧。为什么会有?你可知道在Nginx和lighttpd等高性能Web服务器横空出世前,部署一个中大型网站,成本和部署的代价可是相当可观的。随着Nginx和lighttpd等高性能服务器日趋成熟,成为替代Apache最有力的竞争者,使得网站部署越来越简单,成本越来越低。现在为一个中大型网站架Web服务器也是采用类似的这种架构,自然而然地你己经成功地迈出了通往互联网金光大道的第一步。
12.3铜墙铁壁真功夫——Linux内核集成的IP信息包过滤系统
首先声明这不是讲述防火墙的专业书籍。Linux系统上实现的防火墙相当强大,我们这里只能是浮光掠影地瞧瞧。
当我第一次接触大名鼎鼎的netfitler/iptables时,还是公司指派我做WLAN计费路由器,我头疼得要命,不知道从哪里入手,但是因为工作需要,必须得掌握,只好硬着头皮看下去。为伊消得人憔悴,好久时间才迎来了获知它的那种兴奋,为了不让你再有如我般痛苦的经历,所以我尽量用图画的形式深入浅出地让大家理解netfilter/iptables的原理和作用。
既然不容易理解为什么要这么费力地学习呢?要知道Linux的路由、过滤和分类代码,从功能和性能上都不弱于现有的那些专业的路山器、防火墙和流量整形产品,掌握这门功夫,你的网络编程思想和开发就到达了另一个境界。
netfilter/iptables是Linux内核集成的IP信息包过滤系统。虽然把netfilter/iptables IP信息包过滤系统作为一个整体看待,但是其实它们是该过滤系统的两个组件。Netfilter是内核的模块实现,iptables是上层操作的工具。
首先看看netfilter组件,它是内核的一部分,由一些信息包过滤表组成,这些表包含内核用来控制信息包过滤处理的规则集。Netfilter是 Linux内核的一个通用架构(框架,为什麽加通过框架,因为你可以根据框架规范加模块 加表),它提供一系列的表(tables),每个表由若干链(chains)组成,而每条链中可以有一条或数条规则(rule)。netfilter功能强大,支持L2、L3、L4W的包过滤、数据包修改、NAT、转发策略和拦截策略等。而且你还可以自己写模块(module)实现很多其他的功能,比如xt_limit module能够实现简单的流量控制功能。好东西啊!
接下来我们再来看看iptables组件,它是一种管理内核包的过滤工具,在用户空间(userspace)运行,它使插入、修改和除去信息包过滤表中的规则变得很容易。实际上真正来执行这些过滤规则的还是netfilter。它不仅仅实现了包过滤功能,而且通过netfilter实现了一整套框架,在这个框架之上实现包过滤、NAT等功能,从而提供更好的可扩展性和灵活性。此外,ipfwadm、ipchains、iptables是不同时代的三个包过滤防火墙工具,作用都是对内核的防火墙模块进行操作。如表12-2所示。
讲到这里,看到你己面无表情地点头了,我不得不喊一声“醒醒,别睡了”,洗个脸,泡杯茶,等会儿我们再来接着看。
12.3.1 iptables 5链4表
iptables通过socket接口对netfilter进行操作,创建socket的方法如下:
socket(TC_AF,SOCK_RAW,IPPROTO_RAW);
此中TC_AF就是AF_INET,然后通过getsockopt()和setsockopt()系统调用来读取和更改netfilter的设置。
netfilters/iptables就好像是一个网络包裹传送和转发中心,如图12.2所示。它预先配好了五条传送带,它们是PREROUTING、INPUT、FORWARD、OUTPUT和POSTROUTING,并且配备了4个非常先进的包裹过滤处理规范(表),它们是filter、nat、mangle和raw。4个表的优先级由高到低的顺序为:raw>mangle>nat>filter。举例来说:如果在PRROUTING链上,既有mangle表,也有nat表,那么先由mangle表处理,然后两由nat表处理。raw表只在PREROUTING链和OUTPUT链上使用,因为优先级最高,从而拥有对收到的数据包在连接跟踪前进行处理的特权。一但用户在某个链上使用了raw表,处理方式就很简单粗暴。当raw表处理完后,会跳过nat表和ip_conntrack的处理。直接拍拍屁股离开这条链,即不再做地址转换和数据包的链接跟踪处理了。raw表可以应用在那些不需要做nat的情况以提高性能。例如在大量访问的Web服务器上设置一下规则。实行从80端口来的数据包不麻烦iptables做链接跟踪处理的策略。采用这种策略会提高用户的访问速度。
理解了iptables的工作原理后,我们再来看看它的命令格式:
Iptables [-t table] command [match] [target/jump]
在iptables命令里:
(1)选项-t用来指定使用哪个表,他可以是任何一个表,默认是filter表,关于iptables过滤表说明如表12-3所示
英文含义是乱砍、撕裂的意思。iptables利用mangle表对数据包做TOS和TTL等项的修改。其实动作幅度没那么强烈。
DROP,LOG、ACCEPT和RFJECT分别对应的英文含义是丢弃、记日志、接受和拒绝。
上面介绍了四个表的最基本的内容。你不仅要清楚它们的使用目的,还要清楚每一条链的使用方法才能更好地实现你所要达到的目的。如果你不了解的话,就可能会在防火墙上留下学习漏洞,给不法之徒以可乘之机。
(2)command指定iptables对我们提交的规则要做什么样的操作。这些操作可能是在某个表里增加或删除一些东西,或做点儿其他什么有意义的事情。
(3)match提供/判断数据包的匹配条件。iptables的匹配条件繁多,提供了从协议、ip地址、网络接口、MAC地址、最大匹配速度和状态方面的通用及其扩展匹配选项。由于篇幅有限,各种匹配项目的说明还有劳各位自己査找参考手册。
(4)target/jump 决定符合条件的包到何处去,语法是--jump target 或-j target。target和jump唯一区别是jump的目标是具体的操作。例如ACCEPT和DROP是两个基本的target。
12.3.2 netfilter
netfilter拥有一整套完善的数据包裹处理的标准流程,以及好几套数据包裹过滤规范(表)。当然,用户也可以根据自己的需要,定制新属性并在netfilter的基础上扩展自己的数据包裹检查模块。图12.3表述了netfilter的实现框架,明白这张图中的函数和变量,对你认识和了解netfilter大有好处。我们先看看图中的变量和结构定义:
skb指的就是承载数据的包裹,nf_hook_ops结构对应了一套过滤规范(表)。nf_sockopt_opS指的是数据包裹过滤操作规则属性,例如匹配等属性。protocol指的是协议,相当于数据包裹运输类型,包括“EMS类”的TCP,“普通类”的UDP。hook链号指的是数据包裹检查链代号,有以下五条:NF_INET_PRE_ROUTING、NF_INET_LOCAL_IN、NF_INET_FORWARD、NF_INET_LOCAL_OUT和NF_NET_POST_ROUTING,此了五条传送链在nelfilter中的位置如图12.4所示。NF_INET5条链上的数据包流向有如下规则:
(1)发往本机的包流过NF_INET_PRE_ROUTING和NF_INET_LOCAL_lN
(2)本机发出的包流过NF_INET_LOCAL_OUT和NF_INET POST_ ROUTING
(3)本机转发的包流过NF_ INET _PRE _ROUTING、NF_INET_ FORWARD和NF _INET_
POST _ROUTING
(4)第一个ROUTE的作用是将包分流成发向本机的包和本机需要转发的包(一个简单
的分类)
(5)第二个ROUTE的作用是为本机发出的包寻找发送设备
表-注册-》链
接下来我们再来看看函数定义。nf_register_hook函数的作用是将nf_hook_ops一套检查过滤规范,类似nat表等,添加到相应的hook链上。在注册成功后。就可以在数据skb经过的某个函数里添加对该hook所在链进行的nf_hook_slow函数调用。当数据包裹到达时,netfilter就按照调用检测过滤规范中的这个hook指定的规则要求进行相应的操作。
那么nf_hook_slow函数是什么东东呢?在讲nf_hook_Slow调用之前,我们来看看强悍的NF_HOOK宏,其定义如下:
#de£ine NF_HOOK(pf,hook,skb,indev,outdev,ok£n)\
(list_empty(&nf_hooks[(pf)][(hook)]\
? (okfn) (skb)\
: nf_hook_slow((pf),(hook),(skb),(indev),(outdev),(okfn)))
这是包裹过滤检测中心的一个检查过滤方法,用它来控制网络包裹的去留。如果根据规则发现包裹是违禁包裹,就把包裹截下来不让它继续往下走。检查步骤和方法如图12.5所示:
skb数据包见P391
理解了上面的宏定义,我们的底气就多了一些。这时候我们再来者看看nf_hook_slow函数。它依次调用本过滤链上操作规范(表)对应的包裹过滤规则。执行过程如下,首先遍历检查点上的nf_hook_ops结构调用相应的nf_hookfn函数。如果检査点上没有钩子函数,直接调用(okfh) (skb);如来有钩子函数,则先遍历检査点上的钩子函数,并根据钩子函数的返回值来确定下一步的动作:如果钩子函数能够完全遍历,最后同样需要调用(okfh)(skb),需要说明的是钩子函数中是不能设置跳转的。如果在钩子函数中扣留了包裹,后面的钩子函数就没有机会检査这个数据包裹了,所以过滤链上钩子函数的执行顺序很重要,它们安排得是否合理决定了数据过滤转发功能实现得是否合理。执行钩子函数后的返回结果有如下类型:
(1)NF_DROP:包裹被扣留
(2)NF_ACCEPT:包裹可以通过
(3)NF_STOLEN:包裹被缓存(缓存量够大)
(4)NF_QUEUE:把包裹送到其他地方
(5)NF_REPEAT:再次调用当前的检查方法
nf_register_sockopt函数是用来注册新规则信息的,允许在新的扩展模块上注册新特性。它的作用是将nf_sockopt_ops添加到sockopt链表中,如图12.3所示。与之配套的函数有nf_getsockopt和nf_setsockopt。nf_getsockopt函数是用来查看过滤规则信息。nf_setsockopt函数是用来设置过滤规则信息。它们调用nf_sockopt中对应的nf_hook_ops的set、get函数。
顺便提一下,这里我们讲的是三层防火墙的检测规范(表),二层的检查规范(表)和这个不完全一样。对于二层检测规范(表),Linux内核使用br_netfilters和ebtables两个组件。ebtables的功能和语法和iptables的语法类似,只是iptables是在IP层对数据包进行过滤和NAT的,而ebtables则是在MAC层实现类似的功能。我们这里就不谈了,有兴趣的话你可以用类似的思路去研究bridge防火墙。
bridge桥接
br_netfilters 内核态组件
ebtables 用户态组件
Linux 内核 ebtables bridge netfilter源代码分析求助 [问题点数:40分,结帖人Windeal] http://bbs.csdn.net/topics/390955966 在linux内核代码net/bridge/中发现文件夹netfilter,里面有如下文件。最近发现一个项目修改了其内容,谁能帮忙解释下这个目录有什么功能,最好能给些参考资料~~ ebt_802_3.c ebtable_nat.c ebt_arp.c ebt_ip6.c ebt_log.c ebt_nflog.c ebt_snat.c ebt_vlan.c ebtable_broute.c ebtables.c ebt_arpreply.c ebt_ip.c ebt_mark.c ebt_pkttype.c ebt_stp.c Kconfig ebtable_filter.c ebt_among.c ebt_dnat.c ebt_limit.c ebt_mark_m.c ebt_redirect.c ebt_ulog.c Makefile 1.数据帧进入数据链路层,首先经过BROURING链的Broute处理,决定是直接路由该数据帧还是让它进入到PREROUTING链 2.如果数据帧的目的地址和源地址在同一个网段,网桥会屏蔽它;如果数据帧是多播帧或广播帧,则要在同一网段中除了接收端口以外的其他端口发送这个数据帧。 3..接下来,数据帧到达PREROUTING链后可以改变目的MAC地址(DNAT);当数据帧通过PREROUTING链后,Ebtables将会根据该数据帧的目的MAC地址决定是否转发该帧,如果这个帧的目的MAC是本机的,就会进入到INPUT链,在这个链中,可以过滤进入本机的数据帧,通过INPUT链后,就到达网络层,数据帧变成数据包;如果数据帧的目的MAC不是本机的,它进入FORWARD链,FORWARD链将过滤 数据帧;然后这个数据帧就会到达POSTROUTING链,在这里可以改变数据帧的源MAC地址(SNAT)。由本机产生的帧,首先判断是否需要Bridging,如果不需要则进行直接路由;如果需要就会进入到OUTPUT链中,以对数据帧改变目的MAC地址(DNAT)和过滤,接下来这个帧到达POSTROUTING链,这个链可以改变数据帧的源MAC地址(SNAT);最后,这个帧就到达了NIC。 4.桥接方式的处理流程 当数据帧进入Linux网桥后,先通过Ebtables的BROUTING链和PREROUTING链;接下来,经过Iptables的PREROUTING链,这时还是在数据链路层,而不是在Iptables通常起作用的网络层,这就是br_nf帮助数据帧在数据链路层可以经过Iptables链的作用;然后,经过Ebtables的FORWARD链和Iptables的FORWARD链;最后,先后经过Ebtables和Iptables的POSTROUTING链。 这些链接讲iptables的比较多,挑netfilter的部分看就好了,ebtables是基于链路mac地址的包处理,iptables是基于ip和端口号协议等信息进行的包处理,netfilter是内核的一个框架,将两者结合在一起,使用注册的钩子函数,结合起来对包进行过滤,丢包,修改,转发等处理 讲个实例... 路由器lan口eth0跟无线虚拟接口ath0都在桥br0下,想实现在br0之上通过netfilter区分ath0与eth0流量,并对ath0接口的http请求做一个hijack动作,并redirect到某个网站上去.... 实现方法多种多样了..就讲一种用到ebtables跟iptables的. 先用ebtables对ath0上面的所有skb都打一个mark(broute表上,具体命令google下).这里就主要用到了ebt_mark.c等文件了。 然后再加一条iptables规则,match部份过滤ath0上所有http请求并且skb->mark跟ebtables上面设置一致的包,target部份就是做具体的redirect部份动作了..... 至于kernel里面对skb打mark的入口点自然就是handle_bridge函数了. 其实这个是为了实现一个facebook wifi功能....
12.3.3实践出真知
我曾经在加拿大NeesusDatacom工作了五年,我的主要任务是给Intersil等知名公司编写有关WLAN芯片的驱动程序。但由于家庭原因,在2003年那个夏天,我来到了中国,在中国遇到了几个“臭味相投”的大海龟。壮志在我心,我们试图打造中国第一个能无线上网并支持多媒体播放的列车(厚积薄发,终于把大招儿憋出来了),如阁12.6所示。当时的方案是在每个列车上有一台服务器,带2块GPRS和2块CDMA上网卡支持外网访问。服务器的RJ45网口连接我们自己定制的无线路出器,支持多用户同时上网及认证。经过两个多月不分白天和黑夜的奋战。2004年,那个激动的夜晚,整列车厢的网络己经安装部署完毕。列车启动了,餐车里有个英俊的英格兰小伙子,正在拿笔记本电脑写文件。我和他交谈了一会儿,让他试试访问一下Yahoo和CNN等网页。他很惊讶,好奇地输入www.yahoo.com,很快yahoo网页出现在他笔记本电脑的浏览器上了。他简直不敢相信,居然在中国的列车能访问国外的网站,他用了一连串“unbelievable”来表达自己的兴奋的心情。
在列车上访问网页不是那么容易,运动中的列车外网环境十分恶劣,不断地切换IP,实时地从外网获取网页信息不太现实。在这种情况下,我们想到了用squid做为上网代理缓存毋庸置疑(⊙o⊙)……,squid是一款非常优秀的高性能的代理缓存服务软件,配置简单灵活,支持缓存和多种协议,可以加快内部网浏览Internet的速度。在这种应用场合下,需要squid和iptables搭档实现代理缓存的网络转发。代理服务器在网络拓扑中的位置至关重要,它位于网关或防火墙上。我们需要iptables帮助我们完成重定向功能,现在请看列车服务器上rc.local文件中相关功能的脚本命令:
$IFACE=br0 #允许IP转发 echo"1”> /proc/sys/net/ipv4/ip_forward #消除防火墙规则 iptables -F iptables -t nat -F #内网用户使用MASQUERADE动态NAT转换访问外网 iptables -t nat -A POSTROUTING -O ppp0 -j MASQUERADE #从用户非本地来的端口为80的TCP包重定向到squid的监听端口3128 iptables –t nat –A PREROUTING -i $IFACE -p tcp-d ! 192.168.20.1—dport 80 -j REDIRECT --to-ports3128 #以nobody的身份启动squid su nobody -c"/usr/local/sguid/bin/RunCache &”
12.3.4小盒子的秘密
现在我们再来看看本节开篇提到的那个WLAN计费路由器。别看它体积小,功能却不差。我们用iptables实现了防火墙功能,内置了一个小型的数据库,管理用户的登录和使用情况。
在前面我们谈到了Linux预先提供了5条规则链。这5条规则链与多个真正意义上的检测过滤规范(表)对应。我们可以使用iptables -N添加自己的新检测规范(表).但是这已是虚拟意义上的规范(表)。在小盒子系统中我们增加四个自己的链,也就是四个虚拟链表,我给它们哥儿四个起了四个名字,分别叫mac_filter、ip_filter_lantowan、ip_filter_wantolan和aaa _filter。 aaa 3A 授权 认证 审计
第一条链是mac_filter,它提供了根据数据包里的源MAC地址米判断决定是否接收或丢掉数据包的策略。
第二条链是ip_filter_lantowan,它控制从LAN接口到WAN接口的数据包的动作,可以根据数据包的源IP地址、目的IP地址、协议类型和目的端口来决定是接收还是丢掉这个数据包。如果我们的WLAN无线路由器只允许无线接入的用户访问外网,不允许WLAN的用户访问本地局域网,这个链表就派上用场了。
第三条链是ip_filter_wantolan,它控制从WAN接口到LAN接口的数据包的动作,可以
根据数据包的源IP地址、目的IP地址、协议类型和目的端口来决定是接收还是丢掉这个数据包。
第四条链是aaa_filter.它为通过认证的用户提供上网服务,没有认证的用户不能访问外网。运维人员可以根据实际情况,启动和关闭aaa_filter。2001年的那个春天,为了加大推广热点的力度,为用户提供免费上网服务,我们关闭aaa_filter。随着在网吧、茶餐厅和机场等地越来越多的用户有了无线上网的需求,我们也就开始要求只有认证以后的用户才能使用我们的小盒子上网,更好地为已认证的用户服务.
现在我们就来看看隐藏在小盒子中的代码。这些代码有助于你理解Linux iptables的火墙功能。说明一下:IPTABLES定义为“/sbin/iptables”。
代码3:
Int iptables_prepare (void) { …… // 删除所有规则 /sbin/iptables -F snprintf( str, CMD_STR_LEN.”%s -F”,IPTABLES); iptables_exec_cmd( str); //删除所有规则链/sbin/iptables -X snprintf(str, CMD_STR_LEN,”%s -x”,IPTABLES); iptables_exec_cmd(str); //新增虚拟链mac_filter /sbin/iptables -N mac_filter snprintf(str, CMD_STR_LEN, ”%s -N %s”,IPTABLES,MAC_FILTER); iptables_exec_cmd(str), //新增虚拟链ip_filter_lantowan /sbin/iptables -N ip_filter_ lantowan snprintf ( str, CMD_STR_LEN , “%s -N %s”, IPTABLES,IP _FILTER_ lantowan) ; iptables_exec_cmd (str); 新增虚拟链ip_filter_wantolan /sbin/iptables -N ip_filter_wantalan snprintf ( str, CMD_STR_LEN , “%s -N %s”, IPTABLES, IP FILTER_WANTOLAN) ; iptables_exec_cmd (str); //新增虚拟链aaa_filter /sbin/iptables -N aaa_filtar snprintfI( str, CMD_STR_LEN. “%s -N ts”,IPTABLES. AAA_FILTER); iptables_exec_cmd (str); …… //在INPUT链中,禁止来自未认证的用户的80端口的TCP数据包(HTTP) //命令类似:/sbin/iptables -A INPUT -p tcp –I ! br0 -- dport 80 -j DROP snprintf( str,CMD_STR_LEN, “%s -A INPUT -p tcp -i ! br0 --dport 80 -j DROP”, IPTABLES ) ; iptables_exec_cmd ( str) ; //INPUT链中,禁止来自未认证的用户的443端口的TCP数据包(HTTPS) //命令类似:/sbin/iptables -A INPUT -p tcp -i ! br0 -dport 443 -j DROP snprintf(str, CMD_STR_LEN. “%s -A INPUT -p tcp –I ! br0 --dport 443 -j DROP”, IPTABLES), iptables_exec_cmd(str); …… //开启aaa_ filter.其中包括在FORWARD链上增加aaa_filter, //命令类似:/sbin/iptables -R FORWARDl-i ath0 -j aaa_filter iptables_aaa_enable(); iptables_exec_cmd( str); //FORWARD链表,添加开启防火墙命令 //命令类似:/sbin/iptables -R FORWARD 2-s 0.0.0.0/32 -j ACCEPT snprintf (str, CMD_STR_LEN.”%s -R FORWARD %d -s 0.0.0.0/32 -j %s”, IPTABLES,POS_FW_STATUS,”ACCEPT”); iptables_exec_cmd (str); //FORWARD链表,允许所有已建立和相关的连接. //命令类似:/sbin/iptables -A FORWARD //-m state --state ESTABLISHED, RELATED -j ACCEPT snprintf(str, CMD_STR_LEN, “%s -A %s -m state --state ESTABLISHED,RELATED –j %s”, IPTABLES,“FORWARD”, “ACCEPT”); iptables_exec_cmd ( str); …… //允许未认证的用户的端口53的UDP数据包(DNS), //使无线上网用户可以通过主机名得到本地服务器的IP地址 snprintf(str,CMD_STR_LEN,“%s -A %s -p udp --dpart 53 -j RETURN” , IPTABLES,AAA._FILTER); iptables_exec_cmd (str); //初始化阶段,丢弃经过aaa_filter的其他数据包 snprintf(str, CMD_STR_LEN,“%s -A %s -j DROP", IPTABLES, AAA_FILTER); iptables_exec_cmd ( str ) ; …… }
初始化链表后启动aaa_filter,见代码4:
代码4:
int iptables_aaa_enable (void) { …… // 在FORWARD链上增加aaa_filter,命令类似: // /sbin/iptables -R FORWARD 1-i ath0[ 无线路由器设备中的无线芯片用是Atheros公司的WLAN芯片。] -j aaa_filter snprintf (str,CMD_STR_LEN, “%s -R FORWARD %d –I %s -j%s”, IPTABLES,POS_AAA_FILTER,pLanName,AAA_FILTER) ; iptables_exec_cmd(str) ; // 在PREROUTING的NAT链上增加aaa_filter,命令类似: // /sbin/iptables -t nat -R PREROUTING 1-i ath0 -j aaa_filter #替换/修改第几条规则 这里修改第一条规则 snprintf (str,CMD_STR_LEN, “%s -t nat -R PREROTJTING %d -i %s -j %s” , IPTABLES,1,pLanName, AAA_FILTER) ; iptables_exec_cmd(str) ; …… }
提供了关闭aaa_filter的功能,使用户能够不需要认证免费上网。见代码5:
代码5:
int iptables_aaa_disable (void) { …… //在FORWARD链上.-s 0. 0. 0.0/32的含义是没有policy路由, //所以起到禁止aaa_filter的功能 //命令类似: /sbin/iptables -R FORWARD 1-S 0.0.0.0/32 -j aaa_filter snprintf (str, CMD_STR_LEN. “%s -R FORWARD %d -s 0.0.0.0/32 -j %s” , IPTABLES,PO S_AAA_FILTER, “ACCEPT”); iptables_exec_cmd(str); //在PREROUTING的NAT链上,-s 0.0.0.0/32的含义是没有policy路由, //所以起到禁止aaa_filter的功能 //命令类似: /sbin/iptables -t nat -R PREROUTING 1 -s 0.0.0.0/32 -j aaa_filter snprintf ( str, CMD_STR_LEN, “%s -t nat -R PREROUTING %d -s 0.0.0.0/32 -j %s” , IPTABLES,POS_AAA_FILTER. “ACCE PT”) ; iptables_exec_cmd( str) ; …… }
在aaa_filter中加入通过认证的用户的IP地址,这样能做就允许认证用户上网,而未认证用户无法上网,见代码6:
代码6:
int iptables_aaa_add_ip (char *pIpAddr) { …… //在INPUT链的aaa_filter上, //加入规则:凡是从pIpAddr来的数据包都通过. snprintf(str,CMD_STR_LEN. ”%s -I %s 1-s %s -j %s” , IPTABLES,AAA_FILTER,plpAddr. “RETURN”) ; iptables_exec_cmd(str) ; //在FORWARD链NAT的aaa_filter上, //加入规则:凡是从pIpAddr来的数据包都通过. snprintf(str,CMD_STR_LEN, “%s -t nat -I %s 1-s %s -j %s”, IPTABLES,AAA_FILTER, plpAddr,“RETURN”) ; iptables_exec_cmd (str) ; …… }
如果认证用户退出登录或长时间未有网络流量,在aaa_filter中删除其IP地址并断开连接,见代码7:
代码7:
int iptables_aaa_delete_ip (char *pIpAddr) { …… //删除在INPUT链的aaa_ filter中pIpAddr对应的规则 If (index>0) { snprintf(str, CMD_STR_LEN, “ %S -D %s %d”, IPTABLES,AAA_FILTER,index) ; iptables_exec_cmd (str) ; is_exist = 1; } …… //删除在FORWARD链NAT的aaa_ filter中pIpAddr对应的规则 If (index>0) { snprintf(str, CMD_STR_LEN, “ %S –t nat -D %s %d”, IPTABLES,AAA_FILTER,index) ; iptables_exec_cmd (str) ; is_exist = 1; } //利用ip_ct_selective_cleanup()方法从内核中删除已经建立的连接 if (is_exist) { if (del_established_conn(pIpAddr) == FAILURE) return FAILURE; } …… }
ip_conntrack是Linux NAT 一个跟踪连接条目的模块,记录着允许的跟踪连接条目。ip_conntrack模块记录TCP通信协议的established connection记录。当时我们做WLAN计费AP时,把超时的用户从connectian中踢出去。除了从iptables中限制外,还要把他从ip_conntrack删除,否则他不会离线,要等到ip_conntrack的超时才行,这个时间很长。当时写了一个module,通过module把connection立刻断开,见代码8:
代码8:
…… /* Returns true when finished. */ int conn_remove(const struct ip_conntrack *i, void* data) { u_int32_t uip; struct ip_conntrack_tuple tuple; if (i ==NULL) { printk(“KERN_INFO in func %s, parameter error\n”, _FUNCTION_) ; return0 ; } uip = (u_int32_t) data, tuple = I ->tuplehash [IP_CT_DIR_ORIGINAL] . tuple; if ((tuple.sre . ip == uip )││ ( tuple.dst. ip == uip)) { return1; } return0 } static int write_proc (struct file *file, const char* buffer, unsigned long count, void* data) { u_int32_t ip; //检查输入数据长度是否为ip地址长度 if(count !=4) { return 0: } If(copy_from_user (&ip, buffer, count)) { return -EFAULT; ip_ct_selective_cleanup ( conn_remove , (void*) ip ) : return count; } ……
设置ip_conntrack参数有三种方法,例如我想把ip_conntrack的时间改成2小时(7200s)。
netfilter里面的模块 ip_conntracck
方法一:echo”7200”>/proc/sys/net/ipv4/netfilter/ip_conntrack_tcp_timeout_established
方法二:sysctl -w net.ipv4.ip_tcp_timeout established=7200
方法三:vi/etc/sysctl.conf后加入:net.ipv4.ip_tcp_timeout_established= 7200
不过前两种方法有个问题,在系统重启后新设置的数值都会消失恢复原状。如果要想重启后还有效的话,请使用第三种方法。
在本节即将结束时,你一定体会到了iptables的强大威力了吧。我们还把上面讲述的小盒子应用到了列车无线上网的方案中。圈12.7为列车网络示意图.你能说出这个小盒子在
图12.7中的什么位置吗?
12.4分享文件的乐趣
文件是一种数据的表现形式,数据是比黄金还珍贵的资源。在工作中我们经常会碰到有个文件或者文件夹需要与小伙伴们分享。如果是十年前,我会很自豪地拿出64M U盘,然后把文件拷贝给他。那时候拥有自己的U盘一定会让周围的同事羡慕不已。然而随着网络的迅速发展,这种方法已经过时,利用网络来解决文件分享的问题已经相当普及。通过NFS/Samba或者FTP等方法你可以很轻松地搞定文件传输。
现在主流需求
1、无主被动模式
2、密文传输
3、无额外的交互次数
sshd(openssh-server Linux)服务器端 -》winscp(Windows) 客户端
-》scp(openssh-clients Linux)客户端
发展趋势:FTP->SCP->RSYNC(断点续传,加密,压缩,流量控制)
首先说说FTP。FTP是传输文件的土方法,由于出生的时候,网络江湖还没那么险恶,所以协议设计得不是那么周到,遭到了很多人的批评。有人说它的工作方式设计不合理,主动模式和被动模式哪个模式都不灵,都需要额外的交互次数;有人说它密码安全策略不完善,没有对密码安全作出规定,数据竟敢以明文的形式传输,黑客通过嗅探就可获取密码和数据;有人说它不能配合防火墙工作,FTP客户端IP地址不可路由,位于防火墙之后只能使用被动传输模式进行数据传输……
说句心里话,虽然FTP有这样那样的缺点,但是它的历史功绩是不能抹杀的。在早期的网络世界中,大多数人是用FTP在不同主机之间传输文件的。自FTP发布以来,安全的数据传输经历了长足发展,才有了SCP逐步取代FTP进行文件传输的趋势。FTP协议现在
看起来效率并不是很高,需要比较多的交换握手步骤,但是它的文件传输思想被HTTP发扬光大。如今HTTP传输文件的步骤非常简单,性能也好。客户端向HTTP服务器端发送GET命令,可以一次性包含URL、HTTP协议版本、虚拟主机名等等字段,HTTP服务器端收到请求后处理,返回的响应包含了客户端想要的所有数据,在相同的TCP连接中就可以搞定文件传输。
关于如何架设FTP服务器,相对比较简单,我就不再赘述。除此之外,Linux系统还提供了丰富的数据传输命令和工具,例如rcp、scp、rsync、ftp、sftp、lftp、wget和curl等命令进行文件传输。
scp命令用来进行远程文件拷贝。数据传输使用ssh,并且和ssh使用相同的认证方式,是SSH中最方便有用的命令。
curl主要是用于获取网页,是对libcurl库的一个命令行工具的包装。Libcurl库中提供了相应功能的API,可以在程序中调用。它非常适合来进行自动的文件传输或操作序列,是一个很好的模拟用户在网页浏览器上行为的工具。
这里我们简单介绍一下比较常用的rsync。
rsync分别安装于服务端和客户端,服务端和客户端使用同一个rsync软件包来实现远程镜像和定期同步更新。一个rsync服务端可同时备份多个客户端的数据;多个服务端也可以备份一个客户端的数据。rsync默认端口为873,服务器在该端口接收客户的匿名或者认证方式的备份请求。Linux系统一般默认安装了rsync。
在运行rsync前,你还需要告诉rsync服务端你对认证、访问、日志记录等方面的要求是什么,把必要的配置写入配置文件/etc/rsyncd.conf中。配置文件包括全局参数、模块参数的设置。下面是其配置文件的一个例子:
uid = nobody gid = nobody use chroot = no max connectians = 5 pid file = /var/run/rsyncd.pid lock file = /var/run/rsyrcd .lock log file = /var/log/rsyncd. log hosts allow = 10.232.0.0/16 , 10.235.0.0/16 hosts deny = 0.0.0.0/0 [2nd] path = /home/admin comment = 2nd ignore errors read only = true list = false uid = root gid = root auth users=2nd secrets file = /root/.2nd.crt [backup] path=/home/admin comment=backup ignore errors read only=false list=false uid=root gid=root auth users=backup secrets file = /root/.backup. crt
读完配置文件后,我简单讲讲配置文件中配置选项的含义。
在服务器配好之后,我们就可以通过rsync命令实现本地与rsync服务器的连接和通信。rsync命令既可以满足从本地拷贝文件到远程服务器的需求,也可以满足从远程服务器到本地的需求。
将远程机器的内容拷贝到本地机器的基本语法如下:
rsync [OPTION] [USER@] HOST: SRC DEST
其中SRC地址路径以单个冒号“:”进行分隔。
将本地机器的内容拷贝到远程机器的基本语法如下:
rsync [OPTION] SRC [USER@]HOST: DEST
DEST地址路径以单个冒号“:”进行分隔。这里我举个简单的例子:
rsyne -avz --delete fangru@192.168.10.66:/home/work /backup1/
将服务器上的/home/work模块备份到本地/backup1/目录中,同时进行目录同步,删除本地目录中多余的文件。
在实际工作中,我们经常会遇到要保持两个Linux服务器之问的某个文件夹同步的需求。当服务器A中的文件发生变化了,服务器B上的文件也要随之改变。这时候rsync就派上用场了.如果要完成上述要求,我们需要在服务器A上安装rsync,配置成一台rsync服务器。在服务器B上建立脚本sync_ab:
#!/bin/bash /usr/loca/rsync/bin/rsync -vazu -progress --delete --password-file=/etc/ rsyne . secret fangru@192.168.10.66 : /home/fangru /home
在这个脚本中的/etc/rsync.secret指的是一个存放密码的文件,其内容如下:
fangru:981026
为了安全起见,我们利用命令修改文件属性为只有root可读可写:
chmod 600 /etc/rsync. secret
然后在刚才的sync_ab脚本加上可执行权限:
chmod 755 sync_ab
使用crontab设定,让sync_ab脚本每30分钟运行一次。执行如下命令:
0,30 * * * * /root/sync_ab
太酷了!服务器在整点和30分间隔的时候都会自动运行一次sync_ab,以此来保持文件的同步更新。
当然Linux上传输文件的方法确实不少,一般情况我喜欢用scp。但要做服务器之间的备份或海量文件同步的操作的话,rsync是首选。如果把它配成无人会话模式,就可以实现傻瓜式地操作,同步文件既方便又快速。当然你可以根据自己的喜好选择使用其他工具,黑猫和白猫抓到耗子就是好猫。另外,Windows系统主机与Linux系统主机进行文件传输的工具也不少。你可以在Windows上安装SecureCRT、putty和SSH client等工具,它们会帮你简单方便地完成传输文件的任务。
scp、rsync、ftp的功能总结
客户端:scp ,rsync,lftp
服务端:vsftp,sshd,rsync
断点续传:winscp、lftp、rsync
加密传输:rsync、scp、FTP(需要服务器端支持)
压缩传输:scp、rsync
流量控制:scp、rsync、lftp
通过比较,Linux下能取代FTP协议的服务器端和客户端软件只有rsync
http://www.cnblogs.com/MYSQLZOUQI/articles/4911707.html
12.4.1 NFS
通过FTP或HTTP等方法传送文件有个问题,就是你无法直接修改主机上的文件。当你想更改Linux主机上的某个文件时,你必须从服务器上把文件下载下来进行修改,修改完后还要记得传上去。如果哪天你忘了上传文件,事情就不好办了,你不知道服务器和本地文件夹中的哪个文件是最新的,应该保留哪个版本。
NFS (Network File System)就不同了。它是一种分布式文件系统。你可以直接访问服务器上的文件,就像操作本地硬盘一样,只要你有权限,还可以随你痛快地使用cp、cd、mv和rm……命令。通过NFS不但能共享文件,我们还可以在不同操作系统的计算机间共享外设,例如打印机等。通信协议的设计与主机及作业系统无关,程序不必了解支持通信的网络协议的情况,这样就提高了程序的互操作性(例如smb协议),如图12.8所示.
由于NFS支持多种功能,每一种都要启动一个端口来传输资料。这些端口是从小于1024中随机抽取的,所以客户端无法知道提供服务的端口。这就需要RPC来帮忙。这里说的RPC可不是指人品差(Ren Pin Cha),它是指远程过程调用RPC(Remote Procedure Call)服务,充当红娘的角色。RPC接受NFS各项功能的注册,并在111端口监听请求。例如客户端向服务器的端口111发出NFS文件存取功能的查询要求,服务器找到对应的已注册的NFSdaemon返回给客户端后,RPC牵线搭桥的任务才算告一段落。
安装rpcbind服务
NFS服务器的配置相对比较简单,只需要在相应的配置文件中进行设置,然后启动NFS服务器即可。exports配置文件在目录“/etc”下,用于配置NFS服务器所提供的目录共享。exports的最初设置为空,没有输出任何的目录共享,这也是出于安全考虑,这样即使启动了NFS服务也不会提供任何的共享。在exports文件中每行提供一个共享的目录,格式如下所示:
要输出的共享目录客户端主机的地址(设置选项)
在共享设置行中,共享目录和主机地址间用空格分隔,主机地址之后紧随设置选项,设
置选项放在括号中。如果有多个设置,选项间用逗号分隔。下面是exports配置文件的一个
实例:
/www/magiclinux *.magiclinux. com (sync ,rw) /home/ftp 192.168.0.66(sync , ro)
在配置文件中对客户端主机的指定非常灵活,如下表所示:
设置选择也比较多,但经常用的有以下3个
对于实际的应用系统,每次启动Linux系统后都要手工启动NFS服务器是不现实的,需要设置系统在指定的运行级别自动启动portmap/rpcbind和nfs服务.
我们用chkconfig命令设置portmap和nfs服务在系统的运行级别为3和5时实现自动启动。
centos5叫portmap
centos6叫rpcbind(portmap改名为rpcbind)
[root@localhost ~] # chkconfig --level 35 portmap on [root@localhost ~] # chkconfig --level 35 nfs on [root@localhost ~] # chkconfig --list portmap nfs 0:off 1: off 2 :off 3 :on 4:off 5 : on 6:off [root@localhost ~] #chkconfig --list nfs nfs 0:off 1:off 2:off 3:on 4:off 5:on 6:off
在正确设置了NFS共享目录后并正确启动NFS服务器后,可以用showmount命令查询NFS服务器的共享状态,用exportfs命令维护分享资源和重新输出共享目录,
例如利用exportfs -rv命令使NFS服务器重新读取exports文件中的设置,该命令在改变exports文件设置后,使设置在当前服务器中生效,而不需要重新启动NFS服务器。
在介绍完NFS服务器后,我们再来看看如何在客户端上完成显示、挂载和卸载NFS服务器的共享目录。要实现这些任务主要靠我们熟悉的mount命令.先说显示共享目录,在使用mount挂载NFS服务器的共享目录之前,最好先查询NFS服务器中是否允许本机连接相应的目录共享,命令如下:
showmount -e 服务器地址
而mount│grep nfs命令用来显示当前主机挂载的NFS目录。
然后再讲挂载,命令格式如下:
mount NFS服务器地址:共享目录本地挂载点目录
例如:mount 192.168.10.66:/home/fangru/mnt/fangru,其中/mnt/fangru是已建立的空目录。如果要实现开机时挂载nfs文件系统,那么在客户端/etc/fstab中做如下设置:
192.168.10.66: /home/fangru /mnt/fangru nfs defaults 0 0
最后讲一下卸载,命令如下:
umount /mnt/fangru
客户端访问操作比较简单,但是服务器还需要考虑保证访问的安全性。虽然“我家大门常打开,开放怀抱等你”这句话没有错,但是共享目录的大门可不能毫无保留地开放怀抱,完全敞开是相当危险的。出于安全的考虑,对共享的目录需要做一些限定.举个例子说明一下。
首先在NFS Server上建立一分享目录/home/fangru,设定存取的来源为192.168.10.88;新增一个UID为5000的使用者admin.并让admin对此目录拥有最大权限;新增一个GID为5000的群组permitgrp:让该群组成员(jagen和joy)对共享目录具有只读权限-
在服务端我们需要做如下的工作:
服务端
1.建立分享目录: # mkdir /home/fangru 2.建立文件: # vi /home/fangru/permission Access is permitted. 3. 新增账号: # useradd -u 5000 -m admin #passwd admin Changing password for admin. New password: Re-enter new password: Password changed. 4. 新增群组: # graupadd -g 5000 perrnitgrp 5. 修改文件目录相关属性 # chown -R admin: permitgrp /home/fangru # chmad 750 /home/fangru # chmod 640 /home/fangru/permission # Is -ld /home/fangru /home/fangru/permission drwxr-x--- 2 admin permitgrp 4096 Jul 19 04:43 /home/fangru -rw-r----- 1 admin permitgrp 21 Jul 19 04:43 /home/fangru/permission 6. 设置/etc/exports : # vi /etc/exports /home/fangru 192.168.10 . 88 ( rw, root, squash, sync) # exportfs -rv
在客户端我们做如下工作:
客户端
1. 新增id皆为5000的使用者及群组 # useradd -u 5000 –m admin # passwd admin Changing password for admin. New password: Re-enter new password: Passward changed. # groupadd –g 5000 permitgrp 2. 将jagen和joy加入permitgrp群组: # vi /etc/group permitgrp :!: 5000: jagen,joy 3. 使用jagen账号挂载: # sudo mount 192.168.10.66:/home/fangru nfs # cd nfs 4. 访问/home/fangru下的文件 # cat permission Access is permitted. 5. 写入/home/fangru下的文件,但是很遗憾没有权限不可以写入 # touch jagenfile touch: cannot touch ’jagenfile’:Permission denied
从上面的例子,我们发现对群组及其成员设置的权限控制起作用了。
固定NFS启动端口便于iptables设置
http://www.haiyun.me/archives/centos-nfs-port.html
NFS启动时会随机启动多个端口并向RPC注册,这样如果使用iptables对NFS端口进行限制就会有点麻烦,可以更改配置文件固定NFS服务相关端口。
portmap /rpcbind默认监听111端口
先上张图看看NFS启动后的端口:
nfs-port.png
分配端口,编辑配置文件:
vi /etc/sysconfig/nfs
添加:
#http://www.haiyun.me
RQUOTAD_PORT=30001
LOCKD_TCPPORT=30002
LOCKD_UDPPORT=30002
MOUNTD_PORT=30003
STATD_PORT=30004
重启portmap和nfs:
/etc/init.d/portmap restart
/etc/init.d/nfs restart
现在看看启动的端口:
rpcinfo -p localhost
iptables设置:
iptables -A INPUT -s 192.168.1.1 -p tcp --dport 111 -j ACCEPT
iptables -A INPUT -s 192.168.1.1 -p udp --dport 111 -j ACCEPT
iptables -A INPUT -s 192.168.1.1 -p tcp --dport 2049 -j ACCEPT
iptables -A INPUT -s 192.168.1.1 -p udp --dport 2049 -j ACCEPT
iptables -A INPUT -s 192.168.1.1 -p tcp --dport 30001:30004 -j ACCEPT
iptables -A INPUT -s 192.168.1.1 -p udp --dport 30001:30004 -j ACCEPT
12.4.2 Samba
“一起桑巴舞,不再孤独,投入忘情的舞步……”这节我们所谈的Samba不是舞蹈。它是一个能让Linux系统应用Microsoft网络通信协议的软件,实现Windows与Linux文件共享的功能。Samba将SMB通信协议应用到了Linux系统上,就形成了现在的Samba软件。SMB是Server Message Block的缩写,即为服务器消息块,主要是作为Microsoft的网络通信协议。后来微软加入了许多新的功能,决定将SMB改名叫CIFS (Common Internet FileSystem).即公共Internet文件系统。CIFS已经被作为Internet应用程序标准被提交到IETF。
注意:微软将SMB改名后,与NETBISO脱离,试图使它成为Internet上的一个标准协议。(Windows和Linux都可以用)
Samba最大的功能就是可以用于Linux与Windows系统间直接的文件共享和打印共享,Samba既可以用于Windows与Linux之间的文件共享,也可以用于Linux与Linux之间的资源共享,由于NFS(网络文件系统)可以很好地完成Linux与Linux之间的数据共享,因而Samba较多地用在Linux与Windows之间的数据共享上面。
SMB是基于客户机/服务器型的协议,一台Samba服务器既可以充当文件共享服务器,也可以充当一个Samba的客户端,例如,一台在Linux下已经架设好的Samba服务器,Windows客户端就可以通过SMB协议共享Samba服务器上的资源文件,同时,Samba服务器也可以访问网络中其他Windows系统或者Linux系统共享出来的文件。
SMB的核心配置文件是smb.conf.默认的smb.conf有很多个选项和内容,比较繁琐,文件布局有点像Windows的ini文件。主要包括以下3部分:
(1) global:全局参数
(2) directory shares:目录共享部分,包括标准的[home]部分
(3) print shares:打印共享部分
我们就来看看设置文件中这三部分的具体内容,如下:
#全局参数配置是针对所有的资源 [global] #工作组的名称 workgroup=xiaolong #设置可访问SMB服务器的主机(可为IP、主机名、域名) hosts allow = 192.168.10.0/24 127.0.0.1 #指定SMB服务器使用的安全等级. #1. share:任何用户都不需要密码,直接可以访问 #2.user 要提供用户名和密码才能访问 #3.server将用户和密码提交到另一服务器验证. #如果递交失败,就退到user安全级. #要求网络上存在一台Windows的主域控制器, #samba把用户名和密码递交给它去验证。 security=user #用来设定用户密码是否加密,yes表示需要加密,否则不加密. #由于现在的Windows系统都以加密形式发送SMB/CIFS口令,因此这里选择yes。 encrypt passwords = yes #用来指定samba的密码文件. smb passwd file=/etc/samba/smbpasswd #共享资源参数配置 [homes] #用户以账号和密码访问,是否允许进入自己的宿主文件夹 comment = Home Directories browseable = no writable = yes valid users = %S create mode=0664 directory mode=0775 #打印机配置 [printers] comment = All Printers path = /var/spool/samba browseable = no #允许guest账户使用打印服务 public = yes guest ok = no writable = no printable = yes #“[fangru]”用来设定在Windows中显示出来的共享目录的名称. #“path”用来指定共享的目录,必选项. #“writeable”用来设置是否可写,yes为可写.no为不可写。 # “browseable”用来定义是否可以在Windows工作组下看到共享文件夹, # 如果需要隐藏共享文件夹,选择no即可. #“guest ok”用来定义匿名用户是否可以登录, # 如果security设置为user,此选项默认值为no. #“comment”是对共享目录的说明文件,自己可以定义说明信息. #“valid users”用来定义可以访问该Samba服务器的用户。 # “create mask”用来定义客户端用户创建文件的默认权限, # 664表示对用户可读可写,对用户组可读可写,对其他用户仅仅有只读权限。 #“directory mask”用米定义客户端用户创建目录的默认权限, # 755表示对用户可读可写可执行,对用户组和其他用户可读可执行。 [ fangru] comment = fangru files path = /xiaolong/fangru valid users = fangru create mask = 664 directory mask = 775 writeable = yes browseable = yes guest ok= yes
Samba核心配置的工作告一段落。用户在访问Samba服务器时需要输入用户名和密码.下面就介绍如何配置Samba服务器的权限控制。
首先添加fangru系统级用户,指定工作目录为/xiaolong/fangru,操作如下:
# useradd -d /xiaolong/fangru -s /sbin/nologin fangru
useradd是创建系统用户的命令,参数“-d”是指定fangru用户的工作目录,而fangru就是创建用户的名称,“-s”是指定用户使用的默认shell,/sbin/nologin表示fangru是个虚拟用户,也就是fangru不能通过shell登录系统。用户的最终权限分配为目录权限和Samba权限的最小交集。每当创建一个用户,Linux系统都会在/etc/passwd文件中添加一行对应的用户名信息,在这里我们仅仅用到的是/etc/passwd文件中的用户名信息,不必对用户设置登录系统的密码。
然后创建Samba登录用户。系统用户是Linux对应的用户,而Samba用户是客户端连接Samba服务器时需要使用的用户。创建Samba用户使用的命令是smbpasswd,而smbpasswd的原理是通过读取/etc/passwd文件中存在的用户名,进而设置密码。对于系统用户,可以设置密码,也可以不设置密码,如果设置密码,可以和其对应的Samba用户密码相同,也可以不同。为fangru设置Samba服务器的登录密码,操作如下:
# smbpasswd -a fangru
New SMB password:
Retype new SMB password
Added user fangru.
这样设置完毕,就可以用fangru在客户端登录Samba服务器了。
因为Samba不能做到每个人只能删除自己的文件而不能删除别人的文件这个功能,因此需要通过Linux设置目录Sticky bit权限协助完成此种功能。目录设定了Sticky的权限,在这个目录下的文件只有root与文件的所有者才能删除,别的用户通过设置才能查看此用户目录下的所有文件,但不能删除,只有本用户才能删除。关于目录和文件权限问题请参考本书第2章的内容。
访问权限设置好后,开始启动文件共享服务。在Linux上我们可以使用smbclient工具访问Samba服务器共享文件,操作非常方便。Smbclient常见用法如下:
smbclient //Samba服务器的IP地址-U Samba用户名
例如:
# smbclient //192.168.10.66/xiaolong -U fangru Password: …… smb:\>
有点眼熟呀。没错,与登录FTP服务器后的情景很相似,登录Samba服务器后,就可以进行文件的上传与下载,如果你有足够的权限,还可以进行修改文件的操作。除此之外,还支持lcd、dir、del和md等smb命令行操作。
Samba服务器共享出来的文件还可以在Linux客户端用mount命令进行挂载。如下所示:
#mount -t cifs -1 //192.168.10 . 66/xiaolong /samba #-l label
Password : [root@web /]# df -Th|grep /samba cifs 15G 2.7G 11G 20% /samba
顺便提一下,除了上面讲的几种文件共享方式,互联网上的文件共享还可以使用P2P模式.文件本身存在用户本人的个人电脑上。大多数参加文件共享的人也同时下载其他用户提供的共享文件。上传和下载的这两个动作经常是连在一起的。Linux常用的P2P软件有qBitTorrent、kTorrent、rTorrent、Azureus和Deluge等。Windows很普及的BitTorrent和Flashget(快车)软件已有Linux版。随着“云存储[ 云存储借助于云计算理念和技术提供存储服务。例如Hadoop,它不仅仅是一个用于存储的分布式文件系统,还是由通用计算设备组成的大型集群上执行分布式应用的框架。]”概念火热,老牌P2P文件共享技术也在改进,文件通过客户端设置可自动上传到网络服务器上,即使在我们不在线的情况下,好友仍能共享我们的文件。
smb->进化为->cifs(samba软件实现)
云存储借助于云计算理念和技术提供存储服务。例如Hadoop,它不仅仅是一个用于存储的分布式文件系统,还是由通用计算设备组成的大型集群上执行分布式应用的框架。
12.5在虚拟与现实之间穿梭——实现安全的连接
当你问某个移动用户:“我在咖啡馆想边喝着咖啡边接收公司的电子邮件和访问公司内网办公。如何能保证安全地访问互联网?”知识渊博的他会回答:“用VPN呀!”是的,用VPN! VPN是一种通过互联网把公司的私有网络和远程网络安全地连接起来的虚拟逻辑网络技术。任何人如果想从VPN中获取数据,都是无法读懂的,因为数据进行了加密。VPN不是进行远程连接中出现的第一个技术。二十世纪末,最普遍的做法是使用专线,例如用ISDN把多个不同办公地区的计算机连接起来。但是互联网发展得非常快,ISP还提供了快速安全的VPN方案,它比专线便宜多了。公司利用这种方法建立起只允许员工使用的虚拟内部网络,使在远程办公区或家中的内部员工通过桌面共享技术就可以在一起工作。
更有意思的是我们可以DIY自己的VPN服务器。曾经听说过这么一个项目是用CentOS的OpenVPN服务器实现的。一个阿拉斯加的公司老板是一个狂热的天文爱好者。他在新墨西哥州购买了一个度假村,在村中建了一个小型的天文观测台。该观测站内有一台电脑能控制伸缩圆顶、望远镜以及室外视频监控摄像头。VPN帮他实现了强大的远程控制功能。由于望远镜系统是在互联网上运行的,具有远程访问权限,因此在阿拉斯加的他不仅可以控制在墨西哥州的望远镜,还可以远程监控天文台和度假屋,并且能够远程重启和管理天文台内外分布在LAN上的所有设备。
在天文台中他安装了一台微型PC (Mini-ITX规格)系统,运行CentOS的LinuxOpenVPN,通过sshd访问互联网。第二台微型PC在他的阿拉斯加家中。在两台电脑之间建立一个持久的VPN连接。新墨西哥州的家和天文台建筑物之间用8端口或16端口以太网交换机以及6类线缆把所用设备连接起来,交换机通过光纤与互联网相连。6类电缆作为连接房内基础电源管理开关和天文台的客户端电源管理开关之间的线路。通过移动电话按键他就可以控制连接在8口交换机上的电源管理开关,开启或关闭每个设备,6类线缆还把这种控制能力扩展到天文台的客户端的管理上。虽然这个项目听起来不算小,但是只要一台CentOSOpenVPN服务器就能完全胜任此项工作。在企业环境中,一台这种服务器可以为200多个客户提供VPN服务。另外用于承载VPN和SSH远程访问的企业及软件也是免费的,这个方案难道不划算吗?
12.5.1 VPN实现方式
虽然VPN种类不少,但可以明确划分为以下两类:站到站接入和远程接入。站到站接入包含IPSEC、MPLS VPN和GRE,是由传统广域网接入演变过来的,成对管理.扩展配置相对复杂。远程接入包含IPSEC、SSL VPN、L2TP、L2TP/IPSEC和PPTP,由拨号演变过来,按用户管理,扩展性比较好。我们先通过表格分别列出各种VPN技术的实现方式及其特点,然后再进一步讲述。
IPSec是目前应用最为广泛的VPN技术。IPSec可在IP层提供保护,并且IPScc可同时支持站到站模式及远程访问模式。IPSec采用DES、AES、3DES算法,可以保证数据的完整性及安全性.IPSec在Linux上得到支持的主要有两类,一类为FreeS/WAN,现在已经停止开发,其分裂为两个项目,Openswan与Strongswan。
SSL是近年来兴起的VPN技术。SSL属于远程接入协议,可以存在3种部署模式。第一种是无客户端模式( clientless),这种模式提供对电子邮件及部分资源的远程访问,且不需安装任何程序或者客户端。第二种是瘦客户端模式,这种模式通过在客户端安装Java程序或插件,提供基于TCP的访问。第三种是全隧道模式,这种模式通过SSL客户端,使客户端与企业内部建立一条隧道,使得访问者逻辑连接在企业网。SSL-Based VPN其主要代表有OpenVPN。
L2TP本质上是一种隧道传输协议,它使用两种类型的消息:控制消息和数据隧道消息。控制消息负责创建、维护及终止L2TP隧道,而数据隧道消息则负责用户数据的真正传输。L2TP支持标准的安全特性CHAP和PAP(2种身份验证协议),可以进行用户身份认证。在安全性考虑上,L2TP仅定义了控制消息的加密传输方式,对传输中的数据并不加密。因为安全性不高,企业较少部署使用。
如果不得已使用L2TP VPN,为了弥补其安全性的缺陷,需要使用三层加密,即IPSec.这种VPN被称为基于IPSec的L2TP。首先用户会建立IPSec会话,然后在IPSec加密通道内建立L2TP会话。这样可以确保数据在Internet上的安全性和可靠性.
PPTP提供PPTP客户机和PPTP服务器之间的保密通信。通过PPTP.客户可以采用拨号方式接入公共的口网。拨号客户首先按常规方式拨号到ISP的接入服务器,建立PPP连接。在此基础上客户进行二次拨号建立到PPTP服务器的连接,该连接称为PPTP隧道。PPTP把建立隧道的主动权交给了客户,但客户需要在其PC机上配置PPTP,这样做既会增加用户的工作量,又会造成网络的安全隐患。另外,PPTP仅工作于IP,不具有隧道终点的验证功能,需要依赖用户的验证.PoPTop可以说是PPTP在Linux下的实现。不过,IPScc上跑L2TP更安全。
12.5.2 IPSec VPN
对几种VPN方式进行比较之后,我们发现IPSec和SSL VPN方式应用最广泛。我们就先了解一下IPSec标准,然后在Linux服务器上配置符合IPSec协议标准的OpenSwan软件以加深理解它的工作机制。应该说IPsec协议不是一个人在作战,它是应用于口层上网络数据安全的一整套体系结构,包括网络认证头AH(Authentication Header)协议、封装安全载荷ESP( Encapsulating Security Payload)协议、因特网密钥交换IKE (lnternet Key Exchange)协议和用于网络认证及加密的一些算法等。AH协议提供数据源认证、数据完整性校验和防报文重放功能,它能保护通信免受篡改,但不能防止窃听,适合用于传输非机密数据。ESP协议提供加密、数据源认证、数据完整性校验和防报文重放功能。ESP的工作原理是在每一个数据包的标准P包头后面添加一个ESP报文头,并在数据包后面追加一个ESP尾。
在实际进行IP通信时,可以根据实际安全需求同时使用AH和ESP两种协议或选择使用其中的一种。IPsec有传输和隧道两种工作模式。传输模式只是传输层数据被用来计算AH或ESP头,AH或ESP头以及ESP加密的用户数据被放置在原IP包头后面。隧道模式更常用一些,在两个安全网关之间一般采用隧道模式进行通信,如图12.9所示。隧道技术就是利用封包和解包技术,在公用网络上建立一条安全的数据通道(隧道).让数据包通过这条隧道传输。用户的整个IP数据包被用米计算AH或ESP头,ESP加密的用户数据被封装在一个新的口数据包中。
从公众的角度来看,IPSec在整个数据包之外又加了一个保护层,保证了数据在一个虚拟的隧道中移动。这层我们叫封装( encapsulation),在隧道两端的计算机或网络设备我们叫隧道接口( tunnel interfaces)。这种技术在网络数据处理上很常用。为了更好地理解隧道协议,我举个形象的比喻来说明这个问题。想象一下,有个供应商通过快递公司给你运送一个很重要的包裹。供应商把包裹(用户协议)放在一个盒子(隧道协议)里,快递员把盒子放在卡车(传输协议)里送到仓库(隧道接口)。卡车(传输协议)在高速公路(互联网)上行驶送到你家(另一个隧道接口)。你打开盒子(隧道协议)取出包裹(用户协议)。这样你应该明白了吧。
在理解IPSec工作原理后,我们介绍一个IPSec VPN中最著名的人物Openswan。它自带有IPsec内核堆栈KLIPS,更方便的是可以使用2.6内核中的堆栈代码。如果使用2.6及以上内核,不用打NAT补丁就能起作用。Openswan已经内建对x.509和NAT Traversal的支持,使用起来非常的方便。下载openswan软件包后只要make programs install就可以搞定,然后用ipsec verify命令来检验安装是否成功。
Openswan支持net-to-net和RoadWarrior两种模式。net to net模式是网关对网关的通信。所在的Linux主机为通信的网关,作为其子网的出口,对于子网的用户来说是透明的,远程的子网在通信后可以像自己的局域网一样的访问。RoadWarrior模式是客户端对网关的连接方式,例如公司员工带着笔记本电脑出差或在家,需要用IPSec连接到公司的内部网络。
为了讲述方便,假设我们现在有四台Linux主机。你也可以用VMWare架设虚拟主机的方法来实现。网络拓扑示意图如图12.10所示:
网络服务器Left的内网接eth0接口,地址是192.168.1.2.外网接eth1接口,地址是192.168.0.2,子网客户机PCA属于192.168.1.0/24这个局域网.IP地址为192.168.1.3。网络服务器Right的内网接eth0接口,地址是192.168.2.2,外网接eth1接口,地址是192.168.0.3,子网客户机PCB属于192.168.2.0/24这个局域网,口地址为192.168.2.3。
一般来讲我们主要从认证、密钥和加密这三个方面考虑安全机制。使用者与设备身份认证最常用的是用户名与密码或令牌认证等方式。通过VPN接入设备与AAA服务器、LDAP服务器或者动态密码服务器集成提高认证的准确性与安全性。密钥管理主要有SKIP和ISAKMP两种技术,他们的主要任务是保证在公用数据网上安全地传递密钥而不被第三方窃取。在SKIP中,工作密钥是通过种子密钥和随机数经过Diffie-Hellman算法计算而来,真正加密数据的密钥是不在网络上明文传输的,而且在一个新的连接中工作密钥也是不一样的。在JSAKMP中,双方都有公钥和私钥两把密钥,通过双钥加密的技术发送给对方。加解密技术是数据通信中一项较成熟的技术,分为对称式加密和非对称式加密。对称式加密算法用的比较广泛的有DES、3DES和AES等.AES比DES支持更长的密钥,比DES具有更强的安全性和更高的效率。非对称加密算法中加密和解密使用不同的一对key.一个叫公钥,一个叫私钥,公钥与私钥是有关系的。用公钥加密的数据包需要用其对应的私钥解密才能得到明文。非对称加密算法例如RSA、DSA,它比对称加密要慢100到1000倍。非对称加密更安全
很幸运VPN可直接利用上述现有的加解密技术。接下来我们再来看看Openswan是如何实现认证和加解密的。Openswan支持许多不同的安全认证方式,包括RSA keys、pre-sharedkeys或x.509证书方式,主要在ipsec.conf和ipsec.secrets两个配置文件中。
我们首先看看RSA密钥方式,在Left和Right服务器里,分别执行以下命令目的是生成一个新的RSA密钥对。
ipsecnewhostkey -output /etc/ipsec.secrets
然后:
Left: ipsecshowhostkey --lef t>> /etc/ipsec.conf Right: ipsecshowhostkey --right >rightrsasigkey.tmp scprightrsasigkey.tmproot@left : /etc/rightrsasigkey.tmp Left: cat /etc/rightrsasigkey.tmp>> /etc/ipsec . conf scp /etc/ ipsec.conf root@right : /etc/ipsec.conf
你可能会感到有些奇怪。我们使用上面的命令来来回回地拷贝,究竟是为什么?其实这样做的主要目的就是要在left服务器的ipsec.conf文件上有right服务器的rsasigkey值,反之亦然。配置文件类似是这样的:
conn %default authby=rsasig compress=yes #关掉 Opportunistic Encryption include /etc/ipsec.d/examples/no_oe.conf conn net-to-net …… left=192.168.0.2 leftsubnet = 192.168.1.0/24 …… right=192.168.0.3 rightsubnet=192.168.2.0/24 …… leftrsasigkey=0sAQ… rightrsasigkey=0sAQ… …… auto= add
接下来我们再来看看x.509数字证书方式。基于PKI(Public Key Infrastructure,公钥基础设施)构架的x.509数字证书方式更灵活,不必要一个一个地都记住长长的rsasig。在ipsec.conf中需要填入以下信息:
leftrsasigkey=%cert rightrsasigkey=%cert letcert=xxx.pem rightcert=xxxx.pem
虽然填入证书文件名就行,但是前期是你要做很多功课的。在Left服务器上使用openssl生成根证书、Left和Right服务器证书,把文件拷贝到ipsec.d下相应的目录下,并通过安全渠道(scp、软盘或ftp等方式)把证书等文件拷贝到Right服务器上。在完成了ipsec所属的两个配置文件的配置工作之后,我们就可以在两个服务器上用
“ipsec auto --upnetwork-to-network”
命令启动VPN。
VPN的隧道建立过程是这样的,首先VPN A向VPN B发起连接请求.B收到后初始化ipsec隧道的建立;然后IKEO第一阶段认证对等体,并为ipsec协商建立一条安全隧道;接下来是IKE第二阶段,用来完成ipsec协商,并建立ipsec隧道。一旦隧道被建立,就可以开始被用来保护VPN通信,当没有流量使用ipsec的时候VPN就会废弃隧道。有两种废弃隧道的方法,一种是明确地废弃隧道,另一种是通过SA的生存周期超时来废弃隧道。我们可以使用ipseceroute或ipsec look命令检查隧道建立情况。如果我们发现命令返回信息里面包含了tun信息,说明隧道已经建立了,我们就在192.168.1.0/24和192.168.2.0/24这两个局域网内的两个主机之间互相ping 一下。嗯,如果没有ping通,我们还得用iptables检查一下防火墙的配置。如果服务器开了iptables来做lP伪装(MASQUERADE)或NAT,就不能让MASQUERADE或NAT替你转发到Right服务器下的子网数据包,使用下面的命令防止nat竞争转发:
iptables -t nat -A POSTROUTING -o eth0 -s 192.168.1.0/24 -d ! 192.168.2.0/24 -j MASQERADE
上面我们实现了net-to-net模式的VPN。VPN还支持RoadWarrior模式,那么这种模式的工作情况又如何呢?其实它与Net-to-Net模式的认证和配置方法很类似,只是配置内容项有所区别。因为通信的主机处于固定的位置上.net-to-net模式中Left和Right是相同的,而在RoadWarrior配置中,Left就是自己(LocaL),Right就是远程主机(Remote)。所以在我们看上去,两个配置文件的Left和Right值是相反的。这点是RoadWarrior配置的关键。
另外,使用Windows系统的人很多,让Windows客户端通过Linux的IPSec VPN网关进行网络访问是非常有用的。在Windows上,下载ipsec工具,例如Marcus Maller的ipsec.exe和Linsys IPSec Tool的lsipsectool.exe等,然后生成和导入证书,配置完后就可以运行IPSec服务,但要记住密钥需要转化成Windows可以识别的p12格式哦。
12.5.3 SSL VPN
SL VPN是指应用层的VPN。用户利用浏览器内建的Secure Socket Layer(SSL)封包处理功能,用浏览器访问公司内部的SSL VPN服务器,然后透过网络封包转发的方式,让用户可以在远程计算机执行应用程序,读取公司内部服务器数据。它采用标准的安全套接层(SSL)对传输中的数据包进行加密,从而在应用层保护了数据的安全性。
随着移动互联网的流行,SSL VPN发展非常迅速。3G手机通过SSL VPN方式就可以访问企业资源。采用SSL VPN接入方式,具有极强的用户认证授权保护,同时数据的传输是强加密的,密钥是经过动态协商的,能够防止信息传输被恶意篡改。但是还是有人担心东西保存在手机上不保险。不用担心,因为有了云计算和云存储提供远程服务后,终端上只是桌面级的操作,不含任何企业的应用和数据,这样具有更高的安全保障。
还有另外一个应用场景,使用SSL VPN手段穿越GFW国家防火墙。OpenVPN是一位善于伪装的情报员,在你自己的国外主机上安装上一个OpenVPN.网站的操作例如FTP文件服务、POP3&SMTP邮件收发以及在Google查技术资料就畅通无阻了。下面我们就来看看OpenVPN是如何伪装的。
OpenVPN是一个开放源码的基于SSL的VPN系统,使用UDP协议,同时TCP也被支持,在选择协议时候,需要注意2个加密隧道之间的网络状况,如有高延迟或者丢包较多的情况下,请选择TCP协议作为底层协议,UDP协议由于存在无连接和重传机制,导致要隧道上层的协议进行重传,效率非常低下。,支持从NAT设备后的连接。在Linux上运行的OpenVPN需要tun、OpenSSL和LZO几个软件的支持。软件套件齐备后,我们还要做一些配置工作。
OpenVPN与生俱来便具备了许多安全特性:它在用户空间运行,无须对内核及网络协议栈作修改;初始完毕后以chroot方式运行,放弃root权限;使用mlockall以防止敏感数据交换到磁盘。
该软件最早由James Yonan编写。OpenVPN允许参与建立VPN的单点使用预设的私钥,第三方证书,或者用户名/密码来进行身份验证。它大量使用了OpenSSL加密库,以及SSLv3/TLSv1协议。
OpenVPN能在Linux、xBSD、Mac OS X与Windows2000/XP上运行。它并不是一个基于Web的VPN软件,也不与IPsec及其他VPN软件包兼容。
来自百度百科:http://baike.baidu.com/link?url=C8173TRd7H53ScXvWOvbqiwS2I3j4mKYUyrrfpYCGc8DFK2974ypOq-u6yTYpHFshj_jr78-wCmuU3vNbfYP1oA6Hohboi6zfoJ9Z2LSf5q
首先使用OpenVPN的clean-all和build-ca命令初始化PKI,然后使用build-key-serverserver生成服务器密钥,使用build-key clientl生成某个客户端的密钥,使用build-dh生成Diffie Hellman参数。在制造了一堆钥匙之后,我们把在easy-rsa目录下生成的密钥(例如:ca.crt、ca.key、clientl.crt、clientl.csr、clientl .key、dh1024.pem、server.crt、server.csr和server.kcy等)打包后通过SCP或FTP等手段搞到本地。
另外要想使OpenVPN服务器工作,还得根据实际情况配置好OpenVPN拥有的server.conf,包括本地IP,根证书、服务器证书、服务器私钥和Diffiehellman参数的存放路径和文件名以及VPN服务器子网等。如果你在中国需要访问一些域名被封掉的网站,可以通过在国外搭建的OpenVPN服务器把DNS push到你的客户机上。假设服务器的IP地址为10.8.0.1,那么在server.conf中加入:
server.conf push “dhcp-option DNS 10.8.0.1” push “dhcp-option DNS 8.8.8.8”
并在服务器/etc/resolv.conf文件中加入:
/etc/resolv.conf nameserver 8.8.8.8
Linux系统一般都带有私有的DNS服务器,使用/etc/init.d/named start开启DNS服务。除了配合好OpenVPN自身带的配置,还需要设置路由。例如使用如下命令,才能透过VPN访问Intemet。
iptables -t nat -A POSTROUTING -s 10.8.0.0/24 -o eth0 –j SNAT --to-source a.b.c.d
同时需要记住把ip forward选项打开,可使用如下命令实现:
sysctl -w net.ipv4.ip_forward=1
下面我们再谈谈用户权限的配置。SSL VPN比IPSec VPN访问控制粒度要细。由于IPSec VPN部署在网络层,因此内部网络对于IPSec VPN的使用者来说是透明的,只要是通过了IPSec VPN网关,就可以任意访问内网中的资源。SSL VPN重点在于保护具体的敏感数据,针对不同的客户端指定不同的等级和权限。我们对OpenVPN服务端进行用户权限配置,而不需要修改客户端配置文件。例如在server.conf增加:
server.conf
#10.8.0.0是给所有VPN客户端的IP段: server 10.8.0.0 255.255.255.0 #10.8.1.0是给管理员分配的IP段, server 10.8.1.0 255.255.255.0 #10.8.2.0就是给特定用户组分配的IP段; server 10.8.2.0 255.255.255.0 #下面是定义服务器读取特殊客户端配置文件的目录为ccd; client-config-dir ccd
有上面的基础,在ccd目录下就可以对指定的客户进行特殊的定义,例如:
sysadmin1: ifconfig-push 10.8.1.1 10.8.1.2 contractor1: ifconfig-push 10.8.2.1 10.8.2.2 contractor2: ifconfig-push 10.8.2.5 10.8.2.6
配置工作做完后,万事具备只欠东风,启动OpenVPN就可以支持SSL VPN访问了。参考命令如下:
open --config /usr/local/etc/server.conf
在Windows和Mac OS X上都可以装OpenVPN客户端,下载安装后配置client.o文件,并将打包的key文件(ca.crt、ca.key、clientl.crt、clientl.csr和clientl.key)解压到open文件夹下。启动OpenVPN客户端点击connect即可享受VPN服务了。打开QQ、IE、MSN等网络应用玩一玩,还可以尝试访问一些被GFW禁掉的网站,有点小激动。
f