Chinaunix首页 | 论坛 | 博客
  • 博客访问: 334339
  • 博文数量: 214
  • 博客积分: 4258
  • 博客等级: 上校
  • 技术积分: 2021
  • 用 户 组: 普通用户
  • 注册时间: 2010-12-02 09:16
个人简介

http://blog.csdn.net/ly21st http://ly21st.blog.chinaunix.net

文章分类

全部博文(214)

文章存档

2018年(16)

2015年(1)

2014年(2)

2012年(22)

2011年(173)

分类: LINUX

2011-09-24 23:15:58

12.1 概述

       启动守护进程的集中方法:

1)由系统初始化脚本启动。这些脚本一般在/etc目录或以/etc/rc开头的目录下,它们的位置和内容依赖于具体的实现。由这些脚本启动的守护进程在开始时都拥有超级用户权限。

2)许多网络服务器是由inetd超级服务器启动的,inetd自己是由上一步上的某个脚本启动的。

3)cron守护进程按规则定期执行一些程序;

4)可用at命令指定在将来的某一时刻执行进程;

5)不管是在前台还是在后台,守护进程也可以在用户终端上启动,这在测试守护进程或守护进程因某些原因终止而要重启时经常使用。

 

syslog函数是输出守护进程消息的标准方式,它将消息发往syslogd守护进程。

12.2 syslogd守护进程

       源自Berkeleysyslogd的实现在启动时执行以下操作:

1)读入配置文件,通产是/etc/syslog.conf, 它设定守护进程对接受每次键入的各种登记消息(log message)怎样处理。

2)创建一个Unix域套接口,给它绑定路径名/var/run/log(在某些系统上是/dev/log);

3)创建一个UDP套接口,给它绑定端口514syslog服务使用的端口号);

4)打开路径名/dev/klog,内核中的所有出错消息作为这个设备的输入出现。

12.3 syslog函数

       因为守护进程没有控制终端,所以它不能fprintfstderr上,守护进程为登记消息通常调用syslog函数。

void syslog( int  priority,  const  char * message,…);

messageprintf所用的格式化字符串类似,还增加了%m,它将由对当前errno值的出错消息所取代。在消息的结尾可以加换行符,但这不是必需的。

12.4 daemon_init函数

#include  "unp.h"

#include 

 

#define MAXFD   64

 

extern int daemon_proc; /* defined in error.c */

 

int

daemon_init(const char *pname, int facility)

{

   int     i;

   pid_t   pid;

 

   if ( (pid = Fork()) < 0)

     return (-1);

   else if (pid)

     _exit(0);      /* parent terminates */

 

   /* child 1 continues... */

 

   if (setsid() < 0)      /* become session leader */

     return (-1);

 

   Signal(SIGHUP, SIG_IGN);

   if ( (pid = Fork()) < 0)

     return (-1);

   else if (pid)

     _exit(0);      /* child 1 terminates */

 

   /* child 2 continues... */

 

   daemon_proc = 1;       /* for err_XXX() functions */

 

   chdir("/");         /* change working directory */

   umask(0);

 

   /* close off file descriptors */

   for (i = 0; i < MAXFD; i++)

     close(i);

 

   /* redirect stdin, stdout, and stderr to /dev/null */

   open("/dev/null", O_RDONLY);

   open("/dev/null", O_RDWR);

   open("/dev/null", O_RDWR);

 

   openlog(pname, LOG_PID, facility);

 

   return (0);         /* success */

}

       守护进程运行时没有控制终端,所以它不会受到来自内核的SIGHUP信号。因此很多守护进程将该信号作为管理员通知其他配置文件已修改之用,守护进程收到SIGHUP信号后应重新读入配置文件。另外两个守护进程不应收到的信号是SIGINTSIGWINCH,这些信号也可用作通知守护进程一些其他事项。

 

12.5 inetd守护进程

       典型的Unix系统中都有很多服务器在运行,等待客户的请求。这些进程都是在系统启动时从/etc/rc文件里启动,它们启动时所做的工作差不多一样:创建套接口,给它绑定服务器的众所周知端口,等待连接(如果是tcp)或数据报(如果是udp),然后fork,子进程为客户服务,父进程继续等待下一个客户请求。该模型有两个问题:

1)这些守护进程都有几乎相同的启动代码,首先是创建套接口,还要考虑变成守护进程;

2)每个守护进程在进程表中要占有一项,但它们在大部分时间里处于睡眠状态。

 

4.3BSD版本通过提供一个因特网超级服务器:inetd守护进程使这些问题得到简化。该守护进程解决了刚才提到的两个问题:

1)因为大部分启动时要做的工作由inetd处理了,所以守护进程的编写得到简化。这避免了每个服务器程序都要调用daemon_init函数;

2)单个进程(inetd)能为多个服务等待客户的请求,取代了每个服务一个进程的方式,这样减少了系统中的进程总数。

       inetd进程使用daemon_init函数中的技术将自己变成一个守护进程,然后读入并处理它的配置文件,通常为/etc/inetd.conf。下面是一些实例:

呵呵!如上面的設定,我們可以將 telnet 的啟動項目進行更多的限制!如此一來,將有助於我們的安全防護呢!尤其如果可以針對不同的介面來設定,嘿嘿!就更加的棒囉!不過,請注意喔!如果照上面的設定,那麼您的主機上面將會開了兩個 23 port 的介面,分別是給兩個介面來使用的呢!嗯!真好玩?同樣的, 你也可以針對自己的喜好來設定你的其他 daemon 使他掛在 xinetd 底下呢!

xinetd.conf配置详解
先來看一看預設的 /etc/xinetd.conf 這個檔案的內容是什麼吧!

[root@linux ~]# vi /etc/xinetd.conf
#
# Simple configuration file for xinetd
#
# Some defaults, and include /etc/xinetd.d/
defaults
{
instances = 60 <==
同一服務的同時連線數最多可達 60
log_type = SYSLOG authpriv <==
登錄後,會被紀錄到登錄檔的資訊
log_on_success = HOST PID <==
若成功的登入時,記錄的資訊有哪些?
log_on_failure = HOST <==
若登入失敗,則記錄的資訊又是如何?
cps = 25 30 <==
同一秒鐘內最大連線數量為 25 個,若超過 25 個,
則該服務會暫時停止 30 秒!
}
 
includedir /etc/xinetd.d <==
更多的設定值在 /etc/xinetd.d 那個目錄內

基本上,這個預設參數檔的意義是:『當某個使用 super daemon 管理的服務啟動時,除非該服務已經設定好管理的項目,否則將以上述 xinetd.conf 內的預設參數帶入。』的意思,也就是說,這僅是預設值, 但我們可以自行指定新的設定值來取代 xinetd.conf 內的預設值啦! 也就是說,這個檔案設定成,在預設的狀態下『:一個服務最多可達 60 個連線,且同一秒內連接上的連線不可超過 25 個。而若登入的成功與否時,會分別記錄不同的資訊到登錄檔當中。』這樣說,可以比較清楚了吧? ^_^ 至於更多的參數說明,我們會在底下再強調的!

既然這只是個預設參數檔,那麼自然有更多的服務參數檔案囉~沒錯~而所有的服務參數檔都在 /etc/xinetd.d 裡面,這是因為上表當中的最後一行啊!這樣瞭了吧! ^_^ 那麼每個參數檔案的內容是怎樣呢?一般來說,他是這樣的:

service
{
...
.............
}
 

第一行一定都有個 service ,至於那個 裡面的內容, 則與 /etc/services 有關,因為他可以對照著 /etc/services 內的名稱與 port number 來決定所要啟用的 port 是那個啊!然後相關的參數就在兩個大刮號中間。 attribute 是一些 xinetd 的管理參數, assign_op 則是參數的設定方法。 assign_op 的主要設定形式為:

 = :表示後面的設定參數就是這樣啦!
+=
: 表示後面的設定為『在原來的設定裡頭加入新的參數
-+
:表示後面的設定為『在原來的參數捨棄這裡輸入的參數!』

用途不太相同,敬請留意呦!好了!底下再來說一說那些 attribute value

attribute
(
功能)

assing_op
(
允許的動作)

說明與範例

一般設定項目:

disable

yes
no

允許該 server 可以執行或者是不能執行!當設定為 yes 表示該服務不能執行!這個設定是一定要的啦。如果我想要啟動某個服務,那麼這裡就要設定成為:

disable = no

socket_type

stream
dgram
raw

stream 為連線機制較為可靠的 TCP 封包,若為 UDP 封包則使用 dgram 機制。 raw 代表 server 需要與 IP 直接對談!例如 telnet 使用 TCP ,所以:

socket_type = stream

protocol

tcp
udp
....

這個東西說的是,連線的狀態使用的是哪一種協定!?各個協定的代號可以參考 /etc/protocols 內容!此外,除非是你自己設定的服務,否則這個可以不用設定啦!

wait

yes
no

這就是我們剛剛提到的 Multi-threaded  single-threaded 的方式啦!一般來說,我們希望大家的要求都可以同時被啟用,所以可以設定

wait = no

user

UID
root

還記得我們在  那一篇提到的 UID 概念嗎?對啦!這個 UID 就是那個 UID 啦!要注意的是,假如你的服務啟動者不要以 root 為主的話,那麼這個地方就可以改變其他的使用者,例如 nobody !這個咚咚也會有安全防護的機制存在!此外,需要注意這個 UID 必須存在於 /etc/passwd

group

GID

user 的意思相同!只是這個 GID 的使用者也必須存在於 /etc/group 當中!

instances

number
UNLIMITED

這個是『在同一時間之內,同一個服務可以允許的連線數目』的意思, 你可以寫入一個『數字』來控制連線數目,也可以使用 UNLIMITED 來告訴系統『沒有上限』囉!例如你在同時段之內僅允許 ftp 連線有 30 個,那麼這裡就可以輸入 30 啦!

nice

-19 ~ 19

還記得我們在  裡面談到的那個 nice 指令嗎?!對啦!這裡就是這個東西囉!數字越小( 負值 )代表該程序越優先被執行!

server

program
完整檔名

這個就是指出這個服務的啟動程式!例如要啟動 telnet 的話,其實就是 in.telnetd 這支程式啦!所以這個時候在這裡輸入

server = /usr/sbin/in.telnetd

server_args

program
一些參數

這裡應該輸入的就是你的 server 那裡需要輸入的一些參數啦!例如 in.telnetd 當中,我們還可以加入某些參數!

log_on_success

PID
HOST
USERID
EXIT
DURATION

在『成功登入』之後,需要記錄的項目:PID 為紀錄該 server 啟動時候的 process ID HOST 為遠端主機的 IPUSERID 為登入者的帳號、EXTI 為離開的時候記錄的項目、 DURATION 為該使用者使用此服務多久?

log_on_failure

HOST
USERID
ATTEMPT
RECORD

當登入失敗之後被 syslog 登入的項目:HOST為遠端主機的 IPUSERID為登入者帳號、 ATTEMPT為記錄登入失敗者企圖的意圖為何、RECORD為記錄遠端主機的資訊!以及為何本機 server 不能啟動的原因!主要有 login, shell, exec, finger 等指令可以使用在這裡!( 基本上,可以在 /etc/hosts.allow /etc/hosts.deny 書寫內容 )

進階設定項目:

env

'name=value'

這一個項目可以讓你設定環境變數,環境變數的設定規則可以參考 

port

number

這裡可以設定不同的服務與對應的 port ,但是請記住你的 port 與服務名稱必須與 /etc/services 內記載的相同才行!

redirect

IP_Address port

client 端對我們 server 的要求,轉到另一部主機上去!呵呵!這個好玩呦! 例如當有人要使用你的 ftp 時,你可以將他轉到另一部機器上面去!那個 IP_Address 就代表另一部遠端主機的 IP 囉!

includedir

directory

表示將某個目錄底下的所有檔案都給他塞進來 xinetd.conf 這個設定裡頭!這東西有用多了,如此一來我們可以一個一個設定不同的項目!而不需要將所有的服務都寫在 xinetd.conf 當中!你可以在 /etc/xinetd.conf 發現這個設定呦!

安全控管項目:

bind

IP_Address

這個是設定『允許使用此一服務的介面卡』的意思!舉個例子來說,你的 Linux 主機上面有兩個 IP ,而你只想要讓 IP1 可以使用此一服務,但 IP2 不能使用此服務,這裡就可以將 IP1 寫入即可!那麼 IP2 就不可以使用此一 server

interface

IP_Address

bind 相同

only_from

0.0.0.0
192.168.1.0/24
host_name
domain_name

這東西用在安全機制上面,也就是管制『只有這裡面規定的 IP 或者是主機名稱可以登入!』如果是 0.0.0.0 表示所有的 PC 皆可登入,如果是 192.168.1.0/24 則表示為 C class 的網域!亦即由 192.168.1.1 ~ 192.168.1.255 皆可登入!另外,也可以選擇 domain name ,例如 .ev.ncku.edu.tw 就可以允許成大環工系的網域 IP 登入你的主機使用該 server

no_access

0.0.0.0
192.168.1.0/24
host_name
domain_name

only_from 差不多啦!就是用來管理可否進入你的 Linux 主機啟用你的 server 服務的管理項目! no_access 表示『不可登入』的 PC 囉!

access_times

00:00-12:00
HH:MM-HH:MM

這個項目在設定『該服務 server 啟動的時間』,使用的是 24 小時的設定!例如你的 ftp 要在 8 點到 16 點開放的話,就是: 08:00-16:00

umask

000
777
022

還記得在  裡面約略提過的 umask 這個東西嗎?呵呵!沒錯!就是那個鬼玩意兒囉! 可以設定使用者建立目錄或者是檔案時候的屬性!系統建議值是 022


OK
!我們就利用上面這些參數來架構出我們所需要的一些服務的設定吧! 參考看看底下的設定方法囉! ^_^

一個簡單的 telnet 範例設定

我們說過,使用 super daemon 來管理主機,最大的優點就是多了一道管理的手續,所以,可以進行比較多的監控動作,像上一個小節我們提到的相關參數當中, 就能夠發現到一些端倪了。在這裡,我們舉個簡單的例子來說明一下整個 super daemon 的管理吧!但是要設定 telnet 的話,就得要安裝 telnet 才行。 FC4 的版本上,我們安裝的是 telnet-server-0.17-35 這個套件資料,請您先以  來安裝喔! ^_^

在預設的 /etc/xinetd.d/telnet 內容是這樣的:

[root@linux ~]# vi /etc/xinetd.d/telnet
service telnet
{
flags = REUSE <==
額外的參數使用 REUSE
socket_type = stream <==
使用 TCP 的封包格式

wait = no <==
可以有多個連線同時連進來
user = root <==
啟動者預設為 root
server = /usr/sbin/in.telnetd <==
使用的是這支程式!

log_on_failure += USERID <==
若登入錯誤,『加計』記錄使用者 ID
disable = yes <==
此服務預設關閉!

}
 

其實,主要的參數可以參考上一小節的表格,也可以直接利用『 man xinetd.conf 』來查閱!不過,如果你對於這樣的設定並不滿意的話,其實還可以手動來修改呢! 因為我們知道, telnet 並不是個十分安全的服務,詳細機制可以參考    來查閱,所以,如果你想要更多的安全機制,舉例來說,你想要讓 telnet 在區域網路內與 Internet 上面的連線機制有差異時,例如這樣:

·              對內部網域開放較多權限的部分:
假設 Linux 主機有兩張網路卡,對內的這一張 IP 192.168.1.100 ,且僅針對 192.168.1.0/24 這個網段提供登入。然後開放所有與 telnet 有關的權限, 包含總連線數量與連線時間等。但是, 192.168.1.120 192.168.1.130 兩個 IP 不允許登入;

·              對外部網域較多限制的設定:
對外的 IP 假設為 140.116.44.125 ,且僅允許台南的校園網路 (140.116.0.0/16) 以及教育界的主機名稱 (.edu.tw),另外,僅開放早上 1~9 點及 20~24 兩個時段登入而已。 此外,最多容許十個連線進入。

在這樣的規劃情況下,我可以將剛剛上頭的 /etc/xinetd.d/telnet 這個檔案修改成為:

[root@linux ~]# vi /etc/xinetd.d/telnet
 #
先針對對內的較為鬆散的限制來設定:
 service telnet
{
disable = no <==
預設就是啟動 telnet 服務
bind = 192.168.1.100 <==
只允許經由這個介面卡的封包進來
only_from = 192.168.1.0/24 <==
只允許 192.168.0.0/24 這個網段
的主機連線進來使用 telnet 的服務
no_access = 192.168.1.{120,130} <==
不許這些 PC 登入
instances = UNLIMITED <==
同時允許連線不限制!
nice = 0 <==
使用的優先順序較高
flags = REUSE <==
額外使用的參數
socket_type = stream <==
使用 tcp 封包常用的連線型態
wait = no <==
不需等待,可以同時允許多個連線
user = root <==
啟動程序的使用者身份
server = /usr/sbin/in.telnetd<==
服務啟動的程式
server_args = -a none <==
上面那個程式的參數
log_on_failure += USERID <==
錯誤登入時,要記錄下來的內容
}
 
 #
再針對外部的連線來進行限制呢!
service telnet
{
disable = no <==
預設就是啟動 telnet 服務
bind = 140.116.44.125 <==
只允許經由這個介面卡的封包進來
only_from = 140.116.0.0/16 <==
只允許 140.116.0.0 ~ 140.116.255.255
這個網段連線進來使用 telnet 的服務

only_from = .edu.tw <==
重複設定,只有教務界才能連線!
access_times = 1:00-9:00 20:00-23:59
 <==
每天只有這兩個時段開放服務
umask = 022 <==
建立檔案時的預設屬性設定
instances = 10 <==
同時只允許 10 個連線
nice = 10 <==
使用的優先順序較低
flags = REUSE <==
額外使用的參數
socket_type = stream <==
使用 tcp 封包常用的連線型態
wait = no <==
不需等待,可以同時允許多個連線
user = root <==
啟動程序的使用者身份
server = /usr/sbin/in.telnetd<==
服務啟動的程式
server_args = -a none <==
上面那個程式的參數
log_on_failure += USERID <==
錯誤登入時,要記錄下來的內容
}

在上面這個範例當中,我們用了很多的網路 IP 顯示方式,包括 192.168.1.0/24 以及 140.116.0.0/16 ,這代表『 192.168.1.0~192.168.1.255 的所有 IP 』以及 140.116.0.0 ~140.116.255.255 所有的 IP 』更詳細的說明,我們會在伺服器篇內詳談的。 用了這個設定值之後,你會發現你的 telnet 針對兩個網段來設計了! 設計完成之後,由於這是 xinetd 的設定檔,所以啟動的方式與觀察的方式為:

# 如果您的 telnet 本來就有啟動的話,那麼會發現有一個連線存在你的系統中
[root@linux ~]# netstat -tulnp
Active Internet connections (only servers)
Proto Recv-Q Send-Q Local Address Foreign Address State PID/Program name
tcp 0 0 0.0.0.0:23 0.0.0.0:* LISTEN 19255/xinetd
 #
看到喔!是 xinetd program name 呢!
 
 #
重新修改 /etc/xinetd.d/telnet 之後,重新啟動的方式與觀察為:
[root@linux ~]# /etc/init.d/xinetd restart
[root@linux ~]# netstat -tulnp
Active Internet connections (only servers)
Proto Recv-Q Send-Q Local Address Foreign Address State PID/Program name
tcp 0 0 140.116.44.125:23 0.0.0.0:* LISTEN 19281/xinetd
tcp 0 0 192.168.1.100:23 0.0.0.0:* LISTEN 19281/xinetd
 #
有沒有看到兩個介面啊~而且, PID 會是同一個呢!

呵呵!如上面的設定,我們可以將 telnet 的啟動項目進行更多的限制!如此一來,將有助於我們的安全防護呢!尤其如果可以針對不同的介面來設定,嘿嘿!就更加的棒囉!不過,請注意喔!如果照上面的設定,那麼您的主機上面將會開了兩個 23 port 的介面,分別是給兩個介面來使用的呢!嗯!真好玩?同樣的, 你也可以針對自己的喜好來設定你的其他 daemon 使他掛在 xinetd 底下呢!

 

 

root的身份在/etc/xinetd.d/目录中编辑文本文件proftpd,内容如下:

#   default:   on
#   description:   The   proftpd   server   serves   proftpd   sessions;
  service   proftpd
  {
    disable   =   no
    port   =   21
    socket_type   =   stream
    protocol   =   tcp
    user   =   root
    server   =   /usr/local/sbin/in.proftpd
    type   =   UNLISTED
    wait   =   no
  }

第一和第二行是注释行,不用管它。第三行是定义服务的名称为proftpd
第五行disable的意思是禁用,disable=yes是禁用,disable=no就是启动。如果你想每次启动就使用服务的话,肯定要disable=no啦。
第六行是指定该服务的端口,ftp的端口是21。如果你不用21端口,可以根据proftpd.conf文件作相应的改变。呵呵,这个就根据你的服务设置端口咯。
第七行是socket的类型,这里我们设为stream(流)。
第八行是指定协议,这里我们设为tcp协议。
第九行是启动该服务的用户,我们设为root
第十行是指定运行文件的路径。
第十二行是不等待到启动完成。

文件编好后,运行:
  killall   -HUP   xinetd
或:
/etc/rc.d/init.d/xinetd   restart


之后这个服务便可以使用了。

12.6 daemon_inetd函数

#include  "unp.h"

#include 

 

extern int daemon_proc; /* defined in error.c */

 

void

daemon_inetd(const char *pname, int facility)

{

   daemon_proc = 1;    /* for our err_XXX() functions */

   openlog(pname, LOG_PID, facility);

}

inetd启动的时间/日期服务器程序

#include  "unp.h"

#include 

 

int

main(int argc, char **argv)

{

   int listenfd, connfd;

   socklen_t addrlen, len;

   struct sockaddr *cliaddr;

   char buff[MAXLINE];

   time_t ticks;

 

   if (argc < 2 || argc > 3)

     err_quit("usage: daytimetcpsrv2 [ ] ");

 

   daemon_init(argv[0], 0);

 

   if (argc == 2)

     listenfd = Tcp_listen(NULL, argv[1], &addrlen);

   else

     listenfd = Tcp_listen(argv[1], argv[2], &addrlen);

 

   cliaddr = Malloc(addrlen);

 

   for ( ; ; ) {

     len = addrlen;

     connfd = Accept(listenfd, cliaddr, &len);

     err_msg("connection from %s", Sock_ntop(cliaddr, len));

 

     ticks = time(NULL);

     snprintf(buff, sizeof(buff), "%.24s\r\n", ctime(&ticks));

     Write(connfd, buff, strlen(buff));

 

     Close(connfd);

   }

}

 

阅读(449) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~