安全

目 录

  1. 安全
    1. passwd的管理
    2. /etc/dialups和/etc/d_passwd文件
    3. 日志管理
    4. UUCP的安全问题
      1. USERFILE文件
      2. L.cmds文件
      3. uucp登录
      4. uucp使用的文件和目录
    5. /etc/group
    6. 管理脚本范例
      1. Mail Server脚本
      2. Web server脚本
    7. 系统检查
    8. 系统泄密处理
    9. 限制用户
    10. 路由功能
      1. ADSL
      2. IPChains
    11. 防火墙
      1. netfilter
      2. ip/tables
      3. 防火墙技术分析讲义
    12. 编程安全
      1. 系统调用
        1. I/O
        2. 进程控制
        3. 文件属性
        4. UID和GID的处理
      2. 标准C库
        1. I/O
        2. /etc/passwd的处理
        3. /etc/group的处理
        4. 加密子程序
        5. 运行shell


安全

[目录]


passwd的管理

发信人: cloudsky (晓舟·轩辕明月), 信区: Linux
标  题: passwd的管理
发信站: 武汉白云黄鹤站 (Fri Feb  5 22:06:25 1999) , 站内信件

    所有用户都可以用passwd -s看自己口令属性,超级用户可以看别人。

    显示格式如下:

name status mm/dd/yy min max warn
status  PS有口令,LK锁定,NP无口令
mm/dd/yy 口令最后一次被改变的时间
min     单位为天。下次更改的口令的最短时限。
        /etc/default/passwd中定义了MINWEEKS
max     口令有效的最长时限。
        MAXWEEKS is found in /etc/default/passwd and is set to NULL.
warn  在口令过期前多少天开始提醒用户
passwd -e jhli Change the login shell.
passwd -g jhli Change the gecos (finger) information.
passwd -h jhli Change the home directory.
passwd -f jhli 强迫用户下次更改口令
passwd -l jhli 锁定用户
passwd -d jhli 删除口令后不会给出password:提示,而口令为空的时候依旧会出现这个提示,还需要按一次回车。
-n min 如果min比max大,则用户无法自己修改口令。
-w warn
-x max 把max设置成-1,则用户口令永不过期。若设置成0,则强迫用户下次登录时更改口令,然后该用户口令过期功能被关闭。
passwd -a -s 显示所有用户口令属性
/etc/default/passwd文件是个配置文件,
MAXWEEKS=
MINWEEKS=
PASSLENGTH=
WARNWEEKS=

    PASSLENGTH=6表明口令至少6个字符,口令超过8个字符的时候只有前8个字符有意义。值得注意的是,su和rlogin的时候,只要安全检查通过并不理会LK状态。所以如果发现这些LK用户拥有过shell进程,那就要好好检查安全问题了。


[目录]


/etc/dialups和/etc/d_passwd文件

发信人: cloudsky (晓舟·轩辕明月), 信区: Linux
标  题: /etc/dialups和/etc/d_passwd文件
发信站: 武汉白云黄鹤站 (Fri Feb  5 22:07:30 1999) , 站内信件

/etc/dialups列出了需要额外的拨号口令的终端设备全称路径名。
该文件应该是root属主,并且chmod 600
/etc/d_passwd格式如下login-shell:password:

/dev/pts/4
/dev/pts/5
/dev/pts/6
/dev/pts/7

/usr/bin/sh:[email protected]#$%^&*:
/usr/bin/csh:[email protected]#$%^&*:
/sbin/sh:[email protected]#$%^&*:

效果如下,jhli使用/usr/bin/csh。
登录成功后可以用tty命令确认自己使用哪个终端。
login: jhli
Password:
Dialup Password:

各个操作系统可能有细微差别,请man dialups、man d_passwd。
同时提醒大家的是,man可能是没有得到更新的早期的man,实践出来的效果才是真的。

[目录]


日志管理

    日志对于安全来说,非常重要,他记录了系统每天发生的各种各样的事情,你可以通过他来检查错误发生的原因,或者受到攻击时攻击者留下的痕迹。日志主要的功能有:审计和监测。他还可以实时的监测系统状态,监测和追踪侵入者等等。

  在Linux系统中,有三个主要的日志子系统:

  连接时间日志--由多个程序执行,把纪录写入到/var/log/wtmp和/var/run/utmp,login等程序更新wtmp和utmp文件,使系统管理员能够跟踪谁在何时登录到系统。

  进程统计--由系统内核执行。当一个进程终止时,为每个进程往进程统计文件(pacct或acct)中写一个纪录。进程统计的目的是为系统中的基本服务提供命令使用统计。

  错误日志--由syslogd(8)执行。各种系统守护进程、用户程序和内核通过syslog(3)向文件/var/log/messages报告值得注意的事件。另外有许多UNIX程序创建日志。像HTTP和FTP这样提供网络服务的服务器也保持详细的日志。

  常用的日志文件如下:

    access-log   纪录HTTP/web的传输
    acct/pacct   纪录用户命令
    aculog     纪录MODEM的活动
    btmp      纪录失败的纪录
    lastlog     纪录最近几次成功登录的事件和最后一次不成功的登录
    messages    从syslog中记录信息(有的链接到syslog文件)
    sudolog     纪录使用sudo发出的命令
    sulog      纪录使用su命令的使用
    syslog     从syslog中记录信息(通常链接到messages文件)
    utmp      纪录当前登录的每个用户
    wtmp      一个用户每次登录进入和退出时间的永久纪录
    xferlog     纪录FTP会话

  utmp、wtmp和lastlog日志文件是多数重用UNIX日志子系统的关键--保持用户登录进入和退出的纪录。有关当前登录用户的信息记录在文件utmp中;登录进入和退出纪录在文件wtmp中;最后一次登录文件可以用lastlog命令察看。数据交换、关机和重起也记录在wtmp文件中。所有的纪录都包含时间戳。这些文件(lastlog通常不大)在具有大量用户的系统中增长十分迅速。例如wtmp文件可以无限增长,除非定期截取。许多系统以一天或者一周为单位把wtmp配置成循环使用。它通常由cron运行的脚本来修改。这些脚本重新命名并循环使用wtmp文件。通常,wtmp在第一天结束后命名为wtmp.1;第二天后wtmp.1变为wtmp.2等等,直到wtmp.7。

  每次有一个用户登录时,login程序在文件lastlog中察看用户的UID。如果找到了,则把用户上次登录、退出时间和主机名写到标准输出中,然后login程序在lastlog中纪录新的登录时间。在新的lastlog纪录写入后,utmp文件打开并插入用户的utmp纪录。该纪录一直用到用户登录退出时删除。utmp文件被各种命令文件使用,包括who、w、users和finger。

  下一步,login程序打开文件wtmp附加用户的utmp纪录。当用户登录退出时,具有更新时间戳的同一utmp纪录附加到文件中。wtmp文件被程序last和ac使用。

  具体命令

  wtmp和utmp文件都是二进制文件,他们不能被诸如tail命令剪贴或合并(使用cat命令)。用户需要使用who、w、users、last和ac来使用这两个文件包含的信息。

  who:who命令查询utmp文件并报告当前登录的每个用户。Who的缺省输出包括用户名、终端类型、登录日期及远程主机。例如:who(回车)显示

  chyang    pts/0 Aug     18 15:06
  ynguo     pts/2 Aug     18 15:32
  ynguo     pts/3 Aug     18 13:55
  lewis     pts/4 Aug     18 13:35
  ynguo     pts/7 Aug     18 14:12
  ylou     pts/8 Aug     18 14:15

  如果指明了wtmp文件名,则who命令查询所有以前的纪录。命令who /var/log/wtmp将报告自从wtmp文件创建或删改以来的每一次登录。

  w:w命令查询utmp文件并显示当前系统中每个用户和它所运行的进程信息。例如:w(回车)显示:3:36pm up 1 day, 22:34, 6 users, load average: 0.23, 0.29, 0.27。

USER TTY FROM [email protected] IDLE JCPU PCPU WHAT
chyang pts/0 202.38.68.242 3:06pm 2:04 0.08s 0.04s -bash
ynguo  pts/2 202.38.79.47 3:32pm 0.00s 0.14s 0.05  w
lewis  pts/3 202.38.64.233 1:55pm 30:39 0.27s 0.22s -bash
lewis pts/4 202.38.64.233 1:35pm 6.00s 4.03s 0.01s sh /home/users/
ynguo pts/7 simba.nic.ustc.e 2:12pm 0.00s 0.47s 0.24s telnet mail
ylou pts/8 202.38.64.235 2:15pm 1:09m 0.10s 0.04s -bash

  users:users用单独的一行打印出当前登录的用户,每个显示的用户名对应一个登录会话。如果一个用户有不止一个登录会话,那他的用户名将显示相同的次数。例如:users(回车)显示:chyang lewis lewis ylou ynguo ynguo

  last:last命令往回搜索wtmp来显示自从文件第一次创建以来登录过的用户。例如:

  chyang pts/9  202.38.68.242 Tue Aug 1 08:34 - 11:23 (02:49)
  cfan  pts/6  202.38.64.224 Tue Aug 1 08:33 - 08:48 (00:14)
  chyang pts/4  202.38.68.242 Tue Aug 1 08:32 - 12:13 (03:40)
  lewis  pts/3   202.38.64.233 Tue Aug 1 08:06 - 11:09 (03:03)
  lewis  pts/2   202.38.64.233 Tue Aug 1 07:56 - 11:09 (03:12

如果指明了用户,那么last只报告该用户的近期活动,例如:last ynguo(回车)显示:

  ynguo  pts/4 simba.nic.ustc.e Fri Aug 4 16:50 - 08:20 (15:30)
  ynguo  pts/4 simba.nic.ustc.e Thu Aug 3 23:55 - 04:40 (04:44)
  ynguo  pts/11 simba.nic.ustc.e Thu Aug 3 20:45 - 22:02 (01:16)
  ynguo  pts/0 simba.nic.ustc.e Thu Aug 3 03:17 - 05:42 (02:25)
  ynguo  pts/0 simba.nic.ustc.e Wed Aug 2 01:04 - 03:16 1+02:12)
  ynguo  pts/0 simba.nic.ustc.e Wed Aug 2 00:43 - 00:54 (00:11)
  ynguo  pts/9 simba.nic.ustc.e Thu Aug 1 20:30 - 21:26 (00:55)

  ac:ac命令根据当前的/var/log/wtmp文件中的登录进入和退出来报告用户连结的时间(小时),如果不使用标志,则报告总的时间。例如:ac(回车)显示:total 5177.47

    ac -d(回车)显示每天的总的连结时间
    Aug 12 total 261.87
    Aug 13 total 351.39
    Aug 14 total 396.09
    Aug 15 total 462.63
    Aug 16 total 270.45
    Aug 17 total 104.29
    Today total 179.02
    ac -p (回车)显示每个用户的总的连接时间
    ynguo 193.23
    yucao 3.35
    rong 133.40
    hdai 10.52
    zjzhu 52.87
    zqzhou 13.14
    liangliu 24.34
    total 5178.24

  lastlog:lastlog文件在每次有用户登录时被查询。可以使用lastlog命令来检查某特定用户上次登录的时间,并格式化输出上次登录日志/var/log/lastlog的内容。它根据UID排序显示登录名、端口号(tty)和上次登录时间。如果一个用户从未登录过,lastlog显示\"**Never logged**。注意需要以root运行该命令,例如:

  rong    5   202.38.64.187   Fri Aug 18 15:57:01 +0800 2000
  dbb  **Never logged in**
  xinchen **Never logged in**
  pb9511   **Never logged in**
  xchen   0  202.38.64.190 Sun Aug 13 10:01:22 +0800 2000

  另外,可一加一些参数,例如,last -u 102将报告UID为102的用户;last -t 7表示限制上一周的报告。

  进程统计

  UNIX可以跟踪每个用户运行的每条命令,如果想知道昨晚弄乱了哪些重要的文件,进程统计子系统可以告诉你。它对还跟踪一个侵入者有帮助。与连接时间日志不同,进程统计子系统缺省不激活,它必须启动。在Linux系统中启动进程统计使用accton命令,必须用root身份来运行。Accton命令的形式accton file,file必须先存在。先使用touch命令来创建pacct文件:touch /var/log/pacct,然后运行accton: accton /var/log/pacct。一旦accton被激活,就可以使用lastcomm命令监测系统中任何时候执行的命令。若要关闭统计,可以使用不带任何参数的accton命令。

lastcomm命令报告以前执行的文件。不带参数时,lastcomm命令显示当前统计文件生命周期内纪录的所有命令的有关信息。包括命令名、用户、tty、命令花费的CPU时间和一个时间戳。如果系统有许多用户,输入则可能很长。下面的例子:

  crond      F  root   ??   0.00 secs Sun Aug 20 00:16
  promisc_check.s S  root   ??   0.04 secs Sun Aug 20 00:16
  promisc_check    root   ??   0.01 secs Sun Aug 20 00:16
  grep        root   ??   0.02 secs Sun Aug 20 00:16
  tail        root   ??   0.01 secs Sun Aug 20 00:16
  sh         root   ??   0.01 secs Sun Aug 20 00:15
  ping      S  root   ??   0.01 secs Sun Aug 20 00:15
  ping6.pl    F root   ??   0.01 secs Sun Aug 20 00:15
  sh      root   ??   0.01 secs Sun Aug 20 00:15
  ping      S  root   ??   0.02 secs Sun Aug 20 00:15
  ping6.pl    F  root   ??   0.02 secs Sun Aug 20 00:15
  sh         root   ??   0.02 secs Sun Aug 20 00:15
  ping  S  root   ??  0.00 secs Sun Aug 20 00:15
  ping6.pl  F  root   ??  0.01 secs Sun Aug 20 00:15
  sh root   ??  0.01 secs Sun Aug 20 00:15
  ping  S  root   ??  0.01 secs Sun Aug 20 00:15
  sh  root   ??  0.02 secs Sun Aug 20 00:15
  ping  S  root   ??  1.34 secs Sun Aug 20 00:15
  locate  root   ttyp0  1.34 secs Sun Aug 20 00:15
  accton  S  root   ttyp0  0.00 secs Sun Aug 20 00:15

  进程统计的一个问题是pacct文件可能增长的十分迅速。这时需要交互式的或经过cron机制运行sa命令来保持日志数据在系统控制内。sa命令报告、清理并维护进程统计文件。它能把/var/log/pacct中的信息压缩到摘要文件/var/log/savacct和/var/log/usracct中。这些摘要包含按命令名和用户名分类的系统统计数据。sa缺省情况下先读它们,然后读pacct文件,使报告能包含所有的可用信息。sa的输出有下面一些标记项:

    avio--每次执行的平均I/O操作次数
    cp--用户和系统时间总和,以分钟计
    cpu--和cp一样
    k--内核使用的平均CPU时间,以1k为单位
    k*sec--CPU存储完整性,以1k-core秒
    re--实时时间,以分钟计
    s--系统时间,以分钟计
    tio--I/O操作的总数
    u--用户时间,以分钟计
    例如:
    842   173.26re    4.30cp 0avio 358k
    2    10.98re     4.06cp 0avio 299k find
    9    24.80re     0.05cp 0avio 291k ***other
    105   30.44re     0.03cp 0avio 302k ping
    104   30.55re     0.03cp 0avio 394k sh
    162   0.11re      0.03cp 0avio 413k security.sh*
    154   0.03re      0.02cp 0avio 273k ls
    56    31.61re     0.02cp 0avio 823k ping6.pl*
    2    3.23re      0.02cp 0avio 822k ping6.pl
    35    0.02re      0.01cp 0avio 257k md5sum
    97    0.02re      0.01cp 0avio 263k initlog
    12  0.19re  0.01cp 0avio 399k promisc_check.s
    15  0.09re  0.00cp 0avio 288k grep
    11  0.08re  0.00cp 0avio 332k awk

用户还可以根据用户而不是命令来提供一个摘要报告。例如sa -m显示如下:

        885   173.28re    4.31cp 0avk
    root  879   173.23re    4.31cp 0avk
    alias 3   0.05re     0.00cp 0avk
    qmailp 3   0.01re     0.00cp 0avk

  Syslog设备

  Syslog已被许多日志函数采纳,它用在许多保护措施中--任何程序都可以通过syslog 纪录事件。Syslog可以纪录系统事件,可以写到一个文件或设备中,或给用户发送一个信息。它能纪录本地事件或通过网络纪录另一个主机上的事件。

  Syslog设备依据两个重要的文件:/etc/syslogd(守护进程)和/etc/syslog.conf配置文件,习惯上,多数syslog信息被写到/var/adm或/var/log目录下的信息文件中(messages.*)。一个典型的syslog纪录包括生成程序的名字和一个文本信息。它还包括一个设备和一个优先级范围(但不在日之中出现)。

  每个syslog消息被赋予下面的主要设备之一:

    LOG_AUTH--认证系统:login、su、getty等
    LOG_AUTHPRIV--同LOG_AUTH,但只登录到所选择的单个用户可读的文件中
    LOG_CRON--cron守护进程
    LOG_DAEMON--其他系统守护进程,如routed
    LOG_FTP--文件传输协议:ftpd、tftpd
    LOG_KERN--内核产生的消息
    LOG_LPR--系统打印机缓冲池:lpr、lpd
    LOG_MAIL--电子邮件系统
    LOG_NEWS--网络新闻系统
    LOG_SYSLOG--由syslogd(8)产生的内部消息
    LOG_USER--随机用户进程产生的消息
    LOG_UUCP--UUCP子系统
    LOG_LOCAL0~LOG_LOCAL7--为本地使用保留
    Syslog为每个事件赋予几个不同的优先级:
    LOG_EMERG--紧急情况
    LOG_ALERT--应该被立即改正的问题,如系统数据库破坏
    LOG_CRIT--重要情况,如硬盘错误
    LOG_ERR--错误
    LOG_WARNING--警告信息
    LOG_NOTICE--不是错误情况,但是可能需要处理
    LOG_INFO--情报信息
    LOG_DEBUG--包含情报的信息,通常旨在调试一个程序时使用

  syslog.conf文件指明syslogd程序纪录日志的行为,该程序在启动时查询配置文件。该文件由不同程序或消息分类的单个条目组成,每个占一行。对每类消息提供一个选择域和一个动作域。这些域由tab隔开:选择域指明消息的类型和优先级;动作域指明syslogd接收到一个与选择标准相匹配的消息时所执行的动作。每个选项是由设备和优先级组成。当指明一个优先级时,syslogd将纪录一个拥有相同或更高优先级的消息。所以如果指明\"crit\",那所有标为crit、alert和emerg的消息将被纪录。每行的行动域指明当选择域选择了一个给定消息后应该把他发送到哪儿。例如,如果想把所有邮件消息纪录到一个文件中,如下:

  #Log all the mail messages in one place
    mail.* /var/log/maillog


  其他设备也有自己的日志。UUCP和news设备能产生许多外部消息。它把这些消息存到自己的日志(/var/log/spooler)中并把级别限为\"err\"或更高。例如:

    # Save mail and news errors of level err and higher in aspecial file.
    uucp,news.crit /var/log/spooler

  当一个紧急消息到来时,可能想让所有的用户都得到。也可能想让自己的日志接收并保存。

    #Everybody gets emergency messages, plus log them on anther machine
    *.emerg *
    *.emerg @linuxaid.com.cn

  alert消息应该写到root和tiger的个人账号中:

    #Root and Tiger get alert and higher messages
    *.alert root,tiger

  有时syslogd将产生大量的消息。例如内核(\"kern\"设备)可能很冗长。用户可能想把内核消息纪录到/dev/console中。下面的例子表明内核日志纪录被注释掉了:

    #Log all kernel messages to the console
    #Logging much else clutters up the screen
    #kern.* /dev/console

  用户可以在一行中指明所有的设备。下面的例子把info或更高级别的消息送到/var/log/messages,除了mail以外。级别\"none\"禁止一个设备:

    #Log anything(except mail)of level info or higher
    #Don\'t log private authentication messages!
    *.info:mail.none;autHPriv.none /var/log/messages

  在有些情况下,可以把日志送到打印机(或者通过网络送到root的邮箱、日志服务器、每天更换的磁带机甚至光盘刻录机),这样网络入侵者怎么修改日志都没有用了。通常要广泛纪录日志。Syslog设备是一个攻击者的显著目标。一个为其他主机维护日志的系统对于防范服务器攻击特别脆弱,因此要特别注意。

  有个小命令logger为syslog(3)系统日志文件提供一个shell命令接口,使用户能创建日志文件中的条目。用法:logger 例如:logger This is a test!

它将产生一个如下的syslog纪录:Aug 19 22:22:34 tiger: This is a test!

  注意不要完全相信日志,因为攻击者很容易修改它的。

  程序日志

  许多程序通过维护日志来反映系统的安全状态。su命令允许用户获得另一个用户的权限,所以它的安全很重要,它的文件为sulog。同样的还有sudolog。另外,想Apache有两个日志:access_log和error_log。

  其他日志工具

    chklastlog
    ftp://coast.cs.purdue.edu/pub/tools/unix/chklastlog/
    chkwtmp
    ftp://coast.cs.purdue.edu/pub/tools/unix/chkwtmp/
    dump_lastlog
    ftp://coast.cs.purdue.edu/pub/tools/unix/dump_lastlog.Z
    spar
    ftp://coast.cs.purdue.edu/pub/tools/unix/TAMU/
    Swatch
    http://www.lomar.org/komar/alek/pres/swatch/cover.html
    Zap
    ftp://caost.cs.purdue.edu/pub/tools/unix/zap.tar.gz

  日志分类方法

    http://csrc.nist.gov/nissc/1998/proceedings/paperD1.pdf


[目录]


UUCP的安全问题

    UUCP系统未设置限制,允许任何本系统外的用户执行任何命令和拷贝进/出uucp用户可读/写的任何文件。在具体的uucp应用环境中应了解这点,根据需要设置保护。在UUCP中,有两个程序处理安全问题。第一个是uucico程序,该程序在其他系统调用本系统时启动。这个程序是本系统uucp安全的关键,完成本系统文件传输的传进和传出。第二个程序是uuxqt,该程序为所有的远程命令执行服务。


[目录]


USERFILE文件

    uucico用文件/usr/lib/uucp/USERFILE确定远程系统发送或接收什么文件,其格式为:
        login,sys[c]path_name[path_name.]
    其中login是本系统的登录名,sys是远程系统名,c是可选的call_back标志,path_name是目录名。

    uucico作为登录外壳启动时,将得到远程系统名和所在系统的登录名,并在USERFILE文件中找到匹配login和sys的行。如果该行含有call_back标志c,uucico将不传送文件,连接断开,调用远程系统(即,任何系统可以告诉本系统它的名是xyz,于是本系统挂起,调用实际的xyz执行文件传输),若无c,uucico将执行远程系统请求的文件传送,被传送的文件名被假定为以path_name开头的。

用户需要了解以下几点:
    ·如果远程系统使用的登录名未列于USERFILE的登录域中,uucico将拒绝允许其他系统做任何事,并挂起。
    ·如果系统名未列于sys域中,uucico将使用USERFILE中有匹配的登录名和空系统名的第一行,如:nuucp,/usr/spool/uucppublic应用到作为nuucp登录的所有系统。cbuucp,c将迫使作为cbuucp登录的所有系统自己执行文件传输的请求。若调用系统名不匹配sys系统中的任何一个,并且无空入口项,uucico也将拒绝做任何事。
    ·若两个机器都设置了call_back标志,传送文件的请求决不会被执行,两个系统会一直互相调用,直到两个系统中的一个取消call_back时,才能进行文件传送。
    ·如果一个用户的登录名列于USERFILE文件的login域中,则当调用本系统的uucico为该用户传送文件时,uucico只传送至path_name指定的目录中的文件。空登录名用于所有未明确列于USERFILE文件中的用户进行登录。所以pat,/usr/pat只允许pat传送/usr/pat目录结构中的文件。/usr/spool/uucppublic/tmp其他用户仅允许传送目录/usr/spool/uucppublic和/tmp中的文件。不要允许uucico将文件拷进/出到除了/usr/spool/uucppublic目录以外的其他任何目录,否则可能会有人用下面的命令拷贝走本系统的重要信息:
uucpyoursys!/etc/passwdto-creep


[目录]


L.cmds文件

    uuxqt利用/usr/lib/uucp/L.cmds文件确定要执行的远程执行请求命令。该文件的格式是每行一条命令。如果只需uuxqt处理电子邮件,该文件中就只须一行命令:
        rmail

    系统管理员可允许登录用户执行netnews(rnews)的命令或远程打印命令(lp),但决不允许用户执行拷贝文件到标准输出的命令,如cat命令或网络命令uucp,否则这些人只需在他们自己的系统上敲入:
    uux"yoursys!uucpyoursys!/etc/passwd(outside!~/passwd)"
然后就可等待本系统发送出命令文件。


[目录]


uucp登录

    UUCP系统需要两个登录帐户,一个是其他系统登录的帐户,另一个是系统管理使用的帐户。例如,数据传输登录帐户是nuucp,管理登录帐户是uucp,则在/etc/passwd文件中应当有两行。

    UID和GID的5号通常留给uucp,由于uucico具有管理登录的SUID许可,因此nuucp帐户的UID和GID应当用其他值。


[目录]


uucp使用的文件和目录

    /usr/lib/uucp用于存放不能由用户直接运行的各种uucp,如uuxqt和uucico。该目录还含有若干个确定uucp如何操作的文件,如L.cmds和USERFILE。这些文件只能对uucp管理帐户可写(系统管理员一定不愿让用户更改远程可执行命令表)。根据安全的观点,该目录中另一个系统管理员必须清楚的文件是L.sys。该文件中含有uucico能调用的每个系统的入口项。入口项数据包括uucico所调用系统的电话号码、登录名、未加密的口令。不用说,L.sys应当属于uucp管理帐户所有,且应当具有400或600存取许可。

    uucp用/usr/spool/uucp目录存放工作文件。文件名以C.开头的文件是送到其他系统的命令文件,含有在其他系统上拷入(/出)数据和执行命令的请求。文件名以D.开头的文件用作C.文件的数据文件。文件名以X.开头的文件是来自其他系统的远程执行请求,由uuxqt解释。文件名以TM.开始的文件是从其他系统传送数据到本系统过程中uucp所使用的暂存文件。

    XQTDIR是uuxqt用于执行X.文件的目录。LOGFILE可有助于管理uucp的安全,它含有执行uucp请求成功与否的信息。系统管理员可时常查看该文件,了解有哪些系统正登录本系统执行uucp请求,是什么请求,特别要检查这些请求是否试图做不允许的操作。


[目录]


/etc/group

    /etc/group文件含有关于小组的信息,/etc/passwd中的每个GID在本文件中应当有相应的入口项,入口项中列出了小组名和小组中的用户。这样可方便地了解每个小组的用户,否则必须根据GID在/etc/passwd文件中从头至尾地寻找同组用户。
/etc/group文件对小组的许可权限的控制并不是必要的,因为系统用UID和GID(取自/etc/passwd)决定文件存取权限,即使/etc/group文件不存在于系统中,具有相同的GID用户也可以小组的存取许可权限共享文件。

    小组就像登录用户一样可以有口令。如果/etc/group文件入口项的第二个域为非空,则将被认为是加密口令,newgrp命令将要求用户给出口令,然后将口令加密,再与该域的加密口令比较。给小组建立口令一般不是个好方法。第一,如果小组内共享文件,而某人猜中小组口令,则该组的所有用户的文件就可能泄密:其次,管理小组口令很费事,因为对于小组没有类似的passwd命令。可用/usr/lib/makekey生成一个口令写入/etc/group。

    以下情况必须建立新组:
        ·可能要增加新用户,该用户不属于任何一个现有的小组。
        ·有的用户可能时常需要独自为一个小组。
        ·有的用户可能有一个SGID程序,需要独自为一个小组。
        ·有时可能要安装运行SGID的软件系统,该软件系统需要建立一个新组。

    要增加一个新组,必须编辑该文件,为新组加一个入口项。由于用户登录时,系统从/etc/passwd文件中取GID,而不是从/etc/group中取GID,所以group文件和口令文件应当具有一致性。对于一个用户的小组,UID和GID应当是相同的。多用户小组的GID应当不同于任何用户的UID,一般为5位数,这样在查看/etc/passwd文件时,就可根据5位数据的GID识别多用户小组,这将减少增加新组和新用户时可能产生的混淆。


[目录]


管理脚本范例

[目录]


Mail Server脚本

      This is the configuration script file for our Mail Server. This is configured to allows unlimited traffic on the Loopback interface, ICMP, DNS Server and Client (53), SSH Server (22), SMTP Server and Client (25), IMAP server (143), and OUTGOING TRACEROUTE requests by default.
      If you don't want some services listed in the firewall rules files for the Mail Server that I make ON by default, comment them out with a "#" at the beginning of the line. If you want some other
      services that I commented out with a "#", then remove the "#" at the beginning of their lines.
      Create the firewall script file, touch /etc/rc.d/init.d/firewall on your Mail Server and add:

            #!/bin/sh
            #
            # ----------------------------------------------------------------------------
            # Last modified by Gerhard Mourani:  04-25-2000
            # ----------------------------------------------------------------------------
            # Copyright (C) 1997, 1998, 1999  Robert L. Ziegler
            #
            # Permission to use, copy, modify, and distribute this software and its
            # documentation for educational, research, private and non-profit purposes,
            # without fee, and without a written agreement is hereby granted.
            # This software is provided as an example and basis for individual firewall
            # development.  This software is provided without warranty.
            #
            # Any material furnished by Robert L. Ziegler is furnished on an
            # "as is" basis.  He makes no warranties of any kind, either expressed
            # or implied as to any matter including, but not limited to, warranty
            # of fitness for a particular purpose, exclusivity or results obtained
            # from use of the material.
            # ----------------------------------------------------------------------------
            #
            # Invoked from /etc/rc.d/init.d/firewall.
            # chkconfig: - 60 95
            # description: Starts and stops the IPCHAINS Firewall \
            #              used to provide Firewall network services.

            # Source function library.
            . /etc/rc.d/init.d/functions

            # Source networking configuration.
            . /etc/sysconfig/network

            # Check that networking is up.
            if [ ${NETWORKING} = "no" ]
            then
            exit 0
            fi

            if [ ! -x /sbin/ipchains ]; then
            exit 0
            fi

            # See how we were called.
            case "$1" in
            start)
            echo -n "Starting Firewalling Services: "

            # Some definitions for easy maintenance.

            # ----------------------------------------------------------------------------
            #  EDIT THESE TO SUIT YOUR SYSTEM AND ISP.

            EXTERNAL_INTERFACE="eth0"                               # Internet connected interface
            LOOPBACK_INTERFACE="lo"                                 # Your local naming convention
            IPADDR="my.ip.address"                                  # Your IP address
            ANYWHERE="any/0"                                        # Match any IP address
            NAMESERVER_1="my.name.server.1"                         # Everyone must have at least one
            NAMESERVER_2="my.name.server.2"                         # Your secondary name server
            MY_ISP="my.isp.address.range/24"                        # ISP  NOC address range

            SMTP_SERVER="my.smtp.server"                            # Your Mail Hub Server.
            SYSLOG_SERVER="syslog.internal.server"                  # Your syslog internal server
            SYSLOG_CLIENT="sys.int.client.range/24"                 # Your syslog internal client range

            LOOPBACK="127.0.0.0/8"                                  # Reserved loopback address range
            CLASS_A="10.0.0.0/8"                                    # Class A private networks
            CLASS_B="172.16.0.0/12"                                 # Class B private networks
            CLASS_C="192.168.0.0/16"                                # Class C private networks
            CLASS_D_MULTICAST="224.0.0.0/4"                         # Class D multicast addresses
            CLASS_E_RESERVED_NET="240.0.0.0/5"                  # Class E reserved addresses
            BROADCAST_SRC="0.0.0.0"                                 # Broadcast source address
            BROADCAST_DEST="255.255.255.255"                       # Broadcast destination address
            PRIVPORTS="0:1023"                                      # Well known, privileged port range
            UNPRIVPORTS="1024:65535"                                # Unprivileged port range

            # ----------------------------------------------------------------------------

            # SSH starts at 1023 and works down to 513 for
            # each additional simultaneous incoming connection.
            SSH_PORTS="1022:1023"                                  # range for SSH privileged ports

            # traceroute usually uses -S 32769:65535 -D 33434:33523
            TRACEROUTE_SRC_PORTS="32769:65535"
            TRACEROUTE_DEST_PORTS="33434:33523"

            # ----------------------------------------------------------------------------
            # Default policy is DENY
            # Explicitly accept desired INCOMING  OUTGOING connections

            # Remove all existing rules belonging to this filter
            ipchains -F

            # Clearing all current rules and user defined chains
            ipchains -X

            # Set the default policy of the filter to deny.
            # Don't even bother sending an error message back.
            ipchains -P input  DENY
            ipchains -P output DENY
            ipchains -P forward DENY

            # ----------------------------------------------------------------------------
            # LOOPBACK

            # Unlimited traffic on the loopback interface.
            ipchains -A input  -i $LOOPBACK_INTERFACE -j ACCEPT
            ipchains -A output -i $LOOPBACK_INTERFACE -j ACCEPT

            # ----------------------------------------------------------------------------
            # Network Ghouls
            # Deny access to jerks

            # /etc/rc.d/rc.firewall.blocked contains a list of
            # ipchains -A input  -i $EXTERNAL_INTERFACE -s address -j DENY
            # rules to block from any access.

            # Refuse any connection from problem sites
            #if [ -f /etc/rc.d/rc.firewall.blocked ]; then
            #    . /etc/rc.d/rc.firewall.blocked
            #fi

            # ----------------------------------------------------------------------------
            # SPOOFING  BAD ADDRESSES
            # Refuse spoofed packets.
            # Ignore blatantly illegal source addresses.
            # Protect yourself from sending to bad addresses.

            # Refuse spoofed packets pretending to be from the external address.
            ipchains -A input  -i $EXTERNAL_INTERFACE -s $IPADDR -j DENY -l

            # Refuse packets claiming to be to or from a Class A private network
            ipchains -A input  -i $EXTERNAL_INTERFACE -s $CLASS_A -j DENY -l
            ipchains -A input  -i $EXTERNAL_INTERFACE -d $CLASS_A -j DENY -l
            ipchains -A output -i $EXTERNAL_INTERFACE -s $CLASS_A -j REJECT -l
            ipchains -A output -i $EXTERNAL_INTERFACE -d $CLASS_A -j REJECT -l

            # Refuse packets claiming to be to or from a Class B private network
            ipchains -A input  -i $EXTERNAL_INTERFACE -s $CLASS_B -j DENY -l
            ipchains -A input  -i $EXTERNAL_INTERFACE -d $CLASS_B -j DENY -l
            ipchains -A output -i $EXTERNAL_INTERFACE -s $CLASS_B -j REJECT -l
            ipchains -A output -i $EXTERNAL_INTERFACE -d $CLASS_B -j REJECT -l

            # Refuse packets claiming to be to or from a Class C private network
            #    ipchains -A input  -i $EXTERNAL_INTERFACE -s $CLASS_C -j DENY -l
            #    ipchains -A input  -i $EXTERNAL_INTERFACE -d $CLASS_C -j DENY -l
            #    ipchains -A output -i $EXTERNAL_INTERFACE -s $CLASS_C -j REJECT -l
            #    ipchains -A output -i $EXTERNAL_INTERFACE -d $CLASS_C -j REJECT -l

            # Refuse packets claiming to be from the loopback interface
            ipchains -A input  -i $EXTERNAL_INTERFACE -s $LOOPBACK -j DENY -l
            ipchains -A output -i $EXTERNAL_INTERFACE -s $LOOPBACK -j REJECT -l

            # Refuse broadcast address SOURCE packets
            ipchains -A input  -i $EXTERNAL_INTERFACE -s $BROADCAST_DEST -j DENY -l
            ipchains -A input  -i $EXTERNAL_INTERFACE -d $BROADCAST_SRC -j DENY -l

            # Refuse Class D multicast addresses (in.h) (NET-3-HOWTO)
            # Multicast is illegal as a source address.
            # Multicast uses UDP.
            ipchains -A input  -i $EXTERNAL_INTERFACE -s $CLASS_D_MULTICAST -j DENY -l

            # Refuse Class E reserved IP  addresses
            ipchains -A input  -i $EXTERNAL_INTERFACE -s $CLASS_E_RESERVED_NET -j DENY -l

            # refuse addresses defined as reserved by the IANA
            # 0.*.*.*, 1.*.*.*, 2.*.*.*, 5.*.*.*, 7.*.*.*, 23.*.*.*, 27.*.*.*
            # 31.*.*.*, 37.*.*.*, 39.*.*.*, 41.*.*.*, 42.*.*.*, 58-60.*.*.*
            # 65-95.*.*.*, 96-126.*.*.*, 197.*.*.*, 201.*.*.* (?), 217-223.*.*.*
            ipchains -A input  -i $EXTERNAL_INTERFACE -s 1.0.0.0/8 -j DENY -l
            ipchains -A input  -i $EXTERNAL_INTERFACE -s 2.0.0.0/8 -j DENY -l
            ipchains -A input  -i $EXTERNAL_INTERFACE -s 5.0.0.0/8 -j DENY -l
            ipchains -A input  -i $EXTERNAL_INTERFACE -s 7.0.0.0/8 -j DENY -l
            ipchains -A input  -i $EXTERNAL_INTERFACE -s 23.0.0.0/8 -j DENY -l
            ipchains -A input  -i $EXTERNAL_INTERFACE -s 27.0.0.0/8 -j DENY -l
            ipchains -A input  -i $EXTERNAL_INTERFACE -s 31.0.0.0/8 -j DENY -l
            ipchains -A input  -i $EXTERNAL_INTERFACE -s 37.0.0.0/8 -j DENY -l
            ipchains -A input  -i $EXTERNAL_INTERFACE -s 39.0.0.0/8 -j DENY -l
            ipchains -A input  -i $EXTERNAL_INTERFACE -s 41.0.0.0/8 -j DENY -l
            ipchains -A input  -i $EXTERNAL_INTERFACE -s 42.0.0.0/8 -j DENY -l
            ipchains -A input  -i $EXTERNAL_INTERFACE -s 58.0.0.0/7 -j DENY -l
            ipchains -A input  -i $EXTERNAL_INTERFACE -s 60.0.0.0/8 -j DENY -l

            #65: 01000001    - /3 includes 64 - need 65-79 spelled out
            ipchains -A input  -i $EXTERNAL_INTERFACE -s 65.0.0.0/8 -j DENY -l
            ipchains -A input  -i $EXTERNAL_INTERFACE -s 66.0.0.0/8 -j DENY -l
            ipchains -A input  -i $EXTERNAL_INTERFACE -s 67.0.0.0/8 -j DENY -l
            ipchains -A input  -i $EXTERNAL_INTERFACE -s 68.0.0.0/8 -j DENY -l
            ipchains -A input  -i $EXTERNAL_INTERFACE -s 69.0.0.0/8 -j DENY -l
            ipchains -A input  -i $EXTERNAL_INTERFACE -s 70.0.0.0/8 -j DENY -l
            ipchains -A input  -i $EXTERNAL_INTERFACE -s 71.0.0.0/8 -j DENY -l
            ipchains -A input  -i $EXTERNAL_INTERFACE -s 72.0.0.0/8 -j DENY -l
            ipchains -A input  -i $EXTERNAL_INTERFACE -s 73.0.0.0/8 -j DENY -l
            ipchains -A input  -i $EXTERNAL_INTERFACE -s 74.0.0.0/8 -j DENY -l
            ipchains -A input  -i $EXTERNAL_INTERFACE -s 75.0.0.0/8 -j DENY -l
            ipchains -A input  -i $EXTERNAL_INTERFACE -s 76.0.0.0/8 -j DENY -l
            ipchains -A input  -i $EXTERNAL_INTERFACE -s 77.0.0.0/8 -j DENY -l
            ipchains -A input  -i $EXTERNAL_INTERFACE -s 78.0.0.0/8 -j DENY -l
            ipchains -A input  -i $EXTERNAL_INTERFACE -s 79.0.0.0/8 -j DENY -l

            #80: 01010000   - /4 masks 80-95
            ipchains -A input  -i $EXTERNAL_INTERFACE -s 80.0.0.0/4 -j DENY -l

            # 96: 01100000    - /4 makses 96-111
            ipchains -A input  -i $EXTERNAL_INTERFACE -s 96.0.0.0/4 -j DENY -l

            #126: 01111110    - /3 includes 127 - need 112-126 spelled out
            ipchains -A input  -i $EXTERNAL_INTERFACE -s 112.0.0.0/8 -j DENY -l
            ipchains -A input  -i $EXTERNAL_INTERFACE -s 113.0.0.0/8 -j DENY -l
            ipchains -A input  -i $EXTERNAL_INTERFACE -s 114.0.0.0/8 -j DENY -l
            ipchains -A input  -i $EXTERNAL_INTERFACE -s 115.0.0.0/8 -j DENY -l
            ipchains -A input  -i $EXTERNAL_INTERFACE -s 116.0.0.0/8 -j DENY -l
            ipchains -A input  -i $EXTERNAL_INTERFACE -s 117.0.0.0/8 -j DENY -l
            ipchains -A input  -i $EXTERNAL_INTERFACE -s 118.0.0.0/8 -j DENY -l
            ipchains -A input  -i $EXTERNAL_INTERFACE -s 119.0.0.0/8 -j DENY -l
            ipchains -A input  -i $EXTERNAL_INTERFACE -s 120.0.0.0/8 -j DENY -l
            ipchains -A input  -i $EXTERNAL_INTERFACE -s 121.0.0.0/8 -j DENY -l
            ipchains -A input  -i $EXTERNAL_INTERFACE -s 122.0.0.0/8 -j DENY -l
            ipchains -A input  -i $EXTERNAL_INTERFACE -s 123.0.0.0/8 -j DENY -l
            ipchains -A input  -i $EXTERNAL_INTERFACE -s 124.0.0.0/8 -j DENY -l
            ipchains -A input  -i $EXTERNAL_INTERFACE -s 125.0.0.0/8 -j DENY -l
            ipchains -A input  -i $EXTERNAL_INTERFACE -s 126.0.0.0/8 -j DENY -l

            #217: 11011001    - /5 includes 216 - need 217-219 spelled out
            ipchains -A input  -i $EXTERNAL_INTERFACE -s 217.0.0.0/8 -j DENY -l
            ipchains -A input  -i $EXTERNAL_INTERFACE -s 218.0.0.0/8 -j DENY -l
            ipchains -A input  -i $EXTERNAL_INTERFACE -s 219.0.0.0/8 -j DENY -l

            #223: 11011111    - /6 masks 220-223
            ipchains -A input  -i $EXTERNAL_INTERFACE -s 220.0.0.0/6 -j DENY -l

            # ----------------------------------------------------------------------------
            # ICMP

            #    To prevent denial of service attacks based on ICMP bombs, filter
            #    incoming Redirect (5) and outgoing Destination Unreachable (3).
            #    Note, however, disabling Destination Unreachable (3) is not
            #    advisable, as it is used to negotiate packet fragment size.

            # For bi-directional ping.
            #     Message Types:  Echo_Reply (0),  Echo_Request (8)
            #     To prevent attacks, limit the src addresses to your ISP range.
            #
            # For outgoing traceroute.
            #     Message Types:  INCOMING Dest_Unreachable (3), Time_Exceeded (11)
            #     default UDP base: 33434 to base+nhops-1
            #
            # For incoming traceroute.
            #     Message Types:  OUTGOING Dest_Unreachable (3), Time_Exceeded (11)
            #     To block this, deny OUTGOING 3 and 11

            #  0: echo-reply (pong)
            #  3: destination-unreachable, port-unreachable, fragmentation-needed, etc.
            #  4: source-quench
            #  5: redirect
            #  8: echo-request (ping)
            # 11: time-exceeded
            # 12: parameter-problem

            ipchains -A input  -i $EXTERNAL_INTERFACE -p icmp \
            -s $ANYWHERE 0 -d $IPADDR -j ACCEPT
            ipchains -A input  -i $EXTERNAL_INTERFACE -p icmp \
            -s $ANYWHERE 3 -d $IPADDR -j ACCEPT
            ipchains -A input  -i $EXTERNAL_INTERFACE -p icmp \
            -s $ANYWHERE 4 -d $IPADDR -j ACCEPT
            ipchains -A input  -i $EXTERNAL_INTERFACE -p icmp \
            -s $ANYWHERE 11 -d $IPADDR -j ACCEPT
            ipchains -A input  -i $EXTERNAL_INTERFACE -p icmp \
            -s $ANYWHERE 12 -d $IPADDR -j ACCEPT
            ipchains -A input  -i $EXTERNAL_INTERFACE -p icmp \
            -s $MY_ISP 8 -d $IPADDR -j ACCEPT

            ipchains -A output -i $EXTERNAL_INTERFACE -p icmp \
            -s $IPADDR 0 -d $MY_ISP -j ACCEPT
            ipchains -A output -i $EXTERNAL_INTERFACE -p icmp \
            -s $IPADDR 3 -d $MY_ISP -j ACCEPT
            ipchains -A output -i $EXTERNAL_INTERFACE -p icmp \
            -s $IPADDR 4 -d $ANYWHERE -j ACCEPT
            ipchains -A output -i $EXTERNAL_INTERFACE -p icmp \
            -s $IPADDR 8 -d $ANYWHERE -j ACCEPT
            ipchains -A output -i $EXTERNAL_INTERFACE -p icmp \
            -s $IPADDR 12 -d $ANYWHERE -j ACCEPT
            ipchains -A output -i $EXTERNAL_INTERFACE -p icmp \
            -s $IPADDR 11 -d $MY_ISP -j ACCEPT

            # ----------------------------------------------------------------------------
            # UDP INCOMING TRACEROUTE
            # traceroute usually uses -S 32769:65535 -D 33434:33523

            ipchains -A input  -i $EXTERNAL_INTERFACE -p udp \
            -s $MY_ISP $TRACEROUTE_SRC_PORTS \
            -d $IPADDR $TRACEROUTE_DEST_PORTS -j ACCEPT -l

            ipchains -A input  -i $EXTERNAL_INTERFACE -p udp \
            -s $ANYWHERE $TRACEROUTE_SRC_PORTS \
            -d $IPADDR $TRACEROUTE_DEST_PORTS -j DENY -l

            # ----------------------------------------------------------------------------
            # DNS server
            # ----------

            # DNS: full server
            # server/client to server query or response

            ipchains -A input  -i $EXTERNAL_INTERFACE -p udp \
            -s $ANYWHERE $UNPRIVPORTS \
            -d $IPADDR 53 -j ACCEPT

            ipchains -A output -i $EXTERNAL_INTERFACE -p udp \
            -s $IPADDR 53 \
            -d $ANYWHERE $UNPRIVPORTS -j ACCEPT

            # DNS client  Zone Transfers (53)
            # ---------------
            ipchains -A input  -i $EXTERNAL_INTERFACE -p udp \
            -s $NAMESERVER_1 53 \
            -d $IPADDR $UNPRIVPORTS -j ACCEPT

            ipchains -A output -i $EXTERNAL_INTERFACE -p udp \
            -s $IPADDR $UNPRIVPORTS \
            -d $NAMESERVER_1 53 -j ACCEPT

            ipchains -A input  -i $EXTERNAL_INTERFACE -p tcp ! -y \
            -s $NAMESERVER_1 53 \
            -d $IPADDR $UNPRIVPORTS -j ACCEPT

            ipchains -A output -i $EXTERNAL_INTERFACE -p tcp \
            -s $IPADDR $UNPRIVPORTS \
            -d $NAMESERVER_1 53 -j ACCEPT

            # ----------------------------------------------------------------------------
            # TCP accept only on selected ports
            # ---------------------------------
            # ------------------------------------------------------------------

            # SSH server (22)
            # ---------------

            ipchains -A input  -i $EXTERNAL_INTERFACE -p tcp \
            -s $ANYWHERE $UNPRIVPORTS \
            -d $IPADDR 22 -j ACCEPT

            ipchains -A output -i $EXTERNAL_INTERFACE -p tcp ! -y \
            -s $IPADDR 22 \
            -d $ANYWHERE $UNPRIVPORTS -j ACCEPT

            ipchains -A input  -i $EXTERNAL_INTERFACE -p tcp \
            -s $ANYWHERE $SSH_PORTS \
            -d $IPADDR 22 -j ACCEPT

            ipchains -A output -i $EXTERNAL_INTERFACE -p tcp ! -y \
            -s $IPADDR 22 \
            -d $ANYWHERE $SSH_PORTS -j ACCEPT

            # ------------------------------------------------------------------

            # AUTH server (113)
            # -----------------

            # Reject, rather than deny, the incoming auth port. (NET-3-HOWTO)

            ipchains -A input  -i $EXTERNAL_INTERFACE -p tcp \
            -s $ANYWHERE \
            -d $IPADDR 113 -j REJECT

            # ------------------------------------------------------------------

            # SYSLOG server (514)
            # -----------------

            # Provides full remote logging. Using  this feature you're able to
            # control all syslog messages on one host.

            #    ipchains -A input  -i $EXTERNAL_INTERFACE -p udp \
            #             -s $SYSLOG_CLIENT \
            #             -d $IPADDR 514 -j ACCEPT

            # SYSLOG client (514)
            # -----------------

            #    ipchains -A output -i $EXTERNAL_INTERFACE -p udp \
            #             -s $IPADDR 514 \
            #             -d $SYSLOG_SERVER 514 -j ACCEPT

            # ------------------------------------------------------------------

            # SMTP server (25)
            # ----------------

            ipchains -A input  -i $EXTERNAL_INTERFACE -p tcp \
            -s $ANYWHERE $UNPRIVPORTS \
            -d $IPADDR 25 -j ACCEPT

            ipchains -A output -i $EXTERNAL_INTERFACE -p tcp ! -y \
            -s $IPADDR 25 \
            -d $ANYWHERE $UNPRIVPORTS -j ACCEPT

            # SMTP client (25)
            # ----------------
            ipchains -A input  -i $EXTERNAL_INTERFACE -p tcp ! -y \
            -s $ANYWHERE 25 \
            -d $IPADDR $UNPRIVPORTS -j ACCEPT

            ipchains -A output -i $EXTERNAL_INTERFACE -p tcp \
            -s $IPADDR $UNPRIVPORTS \
            -d $ANYWHERE 25 -j ACCEPT

            # ------------------------------------------------------------------

            # IMAP server (143)
            # -----------------

            ipchains -A input  -i $EXTERNAL_INTERFACE -p tcp \
            -s $ANYWHERE $UNPRIVPORTS \
            -d $IPADDR 143 -j ACCEPT

            ipchains -A output -i $EXTERNAL_INTERFACE -p tcp ! -y \
            -s $IPADDR 143 \
            -d $ANYWHERE $UNPRIVPORTS -j ACCEPT

            # POP server (110)
            # -----------------
            #    ipchains -A input  -i $EXTERNAL_INTERFACE -p tcp \
            #             -s $ANYWHERE $UNPRIVPORTS \
            #             -d $IPADDR 110 -j ACCEPT

            #    ipchains -A output -i $EXTERNAL_INTERFACE -p tcp ! -y \
            #             -s $IPADDR 110 \
            #             -d $ANYWHERE $UNPRIVPORTS -j ACCEPT

            # ------------------------------------------------------------------

            # OUTGOING TRACEROUTE
            # -------------------
            ipchains -A output -i $EXTERNAL_INTERFACE -p udp \
            -s $IPADDR $TRACEROUTE_SRC_PORTS \
            -d $ANYWHERE $TRACEROUTE_DEST_PORTS -j ACCEPT

            # ----------------------------------------------------------------------------
            # Enable logging for selected denied packets

            ipchains -A input  -i $EXTERNAL_INTERFACE -p tcp \
            -d $IPADDR -j DENY -l

            ipchains -A input  -i $EXTERNAL_INTERFACE -p udp \
            -d $IPADDR $PRIVPORTS -j DENY -l

            ipchains -A input  -i $EXTERNAL_INTERFACE -p udp \
            -d $IPADDR $UNPRIVPORTS -j DENY -l

            ipchains -A input  -i $EXTERNAL_INTERFACE -p icmp \
            -s $ANYWHERE 5 -d $IPADDR -j DENY -l

            ipchains -A input  -i $EXTERNAL_INTERFACE -p icmp \
            -s $ANYWHERE 13:255 -d $IPADDR -j DENY -l

            # ----------------------------------------------------------------------------

            ;;
            stop)
            echo -n "Shutting Firewalling Services: "

            # Remove all existing rules belonging to this filter
            ipchains -F

            # Delete all user-defined chain to this filter
            ipchains -X

            # Reset the default policy of the filter to accept.
            ipchains -P input  ACCEPT
            ipchains -P output ACCEPT
            ipchains -P forward ACCEPT

            ;;
            status)
            status firewall
            ;;
            restart|reload)
            $0 stop
            $0 start
            ;;
            *)
            echo "Usage: firewall {start|stop|status|restart|reload}"
            exit 1
            esac

            exit 0


          Now, make this script executable and change its default permissions:


          [[email protected]] /#chmod 700 /etc/rc.d/init.d/firewall
          [[email protected]] /#chown 0.0 /etc/rc.d/init.d/firewall


          Create the symbolic rc.d links for your Firewall with the command:


          [[email protected]] /#chkconfig --add firewall
          [[email protected]] /#chkconfig --level 345 firewall on


          Now, your firewall rules are configured to use System V init (System V init is in charge of starting all the normal processes that need to run at boot time) and it will be automatically started each time if your server reboot.


          To manually stop the firewall on your system, use the following command:


          [[email protected]] /# /etc/rc.d/init.d/firewall stop


          Shutting Firewalling Services:                        [  OK  ]


          To manually start the firewall on your system, use the following command:


          [[email protected]] /# /etc/rc.d/init.d/firewall start


          Starting Firewalling Services:                        [  OK  ]

[目录]


Web server脚本

      This is the configuration script file for our Web Server. This configuration allows unlimited traffic on the Loopback interface, ICMP, DNS Caching and Client Server (53), SSH Server (22), HTTP Server (80),HTTPS Server (443), SMTP Client (25), FTP Server (20, 21), and  OUTGOING TRACEROUTE requests by default.

    If you don't want some services listed in the firewall rules files for the Web Server that I make ON by default, comment them out with a "#" at the beginning of the line. If you want some other services that I commented out with a "#", then remove the "#" at the beginning of those  lines.
          Create the firewall script file, touch /etc/rc.d/init.d/firewall on your Web Server and add:

          #!/bin/sh
          #
          # ----------------------------------------------------------------------------
          # Last modified by Gerhard Mourani:  04-25-2000
          # ----------------------------------------------------------------------------
          # Copyright (C) 1997, 1998, 1999  Robert L. Ziegler
          #
          # Permission to use, copy, modify, and distribute this software and its
          # documentation for educational, research, private and non-profit purposes,
          # without fee, and without a written agreement is hereby granted.
          # This software is provided as an example and basis for individual firewall
          # development.  This software is provided without warranty.
          #
          # Any material furnished by Robert L. Ziegler is furnished on an
          # "as is" basis.  He makes no warranties of any kind, either expressed
          # or implied as to any matter including, but not limited to, warranty
          # of fitness for a particular purpose, exclusivity or results obtained
          # from use of the material.
          # ----------------------------------------------------------------------------
          #
          # Invoked from /etc/rc.d/init.d/firewall.
          # chkconfig: - 60 95
          # description: Starts and stops the IPCHAINS Firewall \
          #              used to provide Firewall network services.

          # Source function library.
          . /etc/rc.d/init.d/functions

          # Source networking configuration.
          . /etc/sysconfig/network

          # Check that networking is up.
          if [ ${NETWORKING} = "no" ]
          then
          exit 0
          fi

          if [ ! -x /sbin/ipchains ]; then
          exit 0
          fi

          # See how we were called.
          case "$1" in
          start)
          echo -n "Starting Firewalling Services: "

          # Some definitions for easy maintenance.

          # ----------------------------------------------------------------------------
          #  EDIT THESE TO SUIT YOUR SYSTEM AND ISP.

          EXTERNAL_INTERFACE="eth0"                       # Internet connected interface
          LOOPBACK_INTERFACE="lo"                        # Your local naming convention
          IPADDR="my.ip.address"                        # Your IP address
          ANYWHERE="any/0"                                # Match any IP address
          NAMESERVER_1="my.name.server.1"                # Everyone must have at least one
          NAMESERVER_2="my.name.server.2"                # Your secondary name server
          MY_ISP="my.isp.address.range/24"               # ISP  NOC address range

          SMTP_SERVER="my.smtp.server"                         # Your Mail Hub Server.
          SYSLOG_SERVER="syslog.internal.server"          # Your syslog internal server
          SYSLOG_CLIENT="sys.int.client.range/24"         # Your syslog internal client range

          LOOPBACK="127.0.0.0/8"                        # Reserved loopback address range
          CLASS_A="10.0.0.0/8"                                # Class A private networks
          CLASS_B="172.16.0.0/12"                        # Class B private networks
          CLASS_C="192.168.0.0/16"                        # Class C private networks
          CLASS_D_MULTICAST="224.0.0.0/4"                # Class D multicast addresses
          CLASS_E_RESERVED_NET="240.0.0.0/5"                # Class E reserved addresses
          BROADCAST_SRC="0.0.0.0"                        # Broadcast source address
          BROADCAST_DEST="255.255.255.255"                # Broadcast destination address
          PRIVPORTS="0:1023"                                # Well known, privileged port range
          UNPRIVPORTS="1024:65535"                        # Unprivileged port range

          # ----------------------------------------------------------------------------

          # SSH starts at 1023 and works down to 513 for
          # each additional simultaneous incoming connection.
          SSH_PORTS="1022:1023"                                   # range for SSH privileged ports

          # traceroute usually uses -S 32769:65535 -D 33434:33523
          TRACEROUTE_SRC_PORTS="32769:65535"
          TRACEROUTE_DEST_PORTS="33434:33523"

          # ----------------------------------------------------------------------------
          # Default policy is DENY
          # Explicitly accept desired INCOMING  OUTGOING connections

          # Remove all existing rules belonging to this filter
          ipchains -F

          # Clearing all current rules and user defined chains
          ipchains -X

          # Set the default policy of the filter to deny.
          # Don't even bother sending an error message back.
          ipchains -P input   DENY
          ipchains -P output  DENY
          ipchains -P forward DENY

          # ----------------------------------------------------------------------------
          # LOOPBACK

          # Unlimited traffic on the loopback interface.
          ipchains -A input  -i $LOOPBACK_INTERFACE -j ACCEPT
          ipchains -A output -i $LOOPBACK_INTERFACE -j ACCEPT

          # ----------------------------------------------------------------------------
          # Network Ghouls
          # Deny access to jerks

          # /etc/rc.d/rc.firewall.blocked contains a list of
          # ipchains -A input  -i $EXTERNAL_INTERFACE -s address -j DENY
          # rules to block from any access.

          # Refuse any connection from problem sites
          #if [ -f /etc/rc.d/rc.firewall.blocked ]; then
          #    . /etc/rc.d/rc.firewall.blocked
          #fi

          # ----------------------------------------------------------------------------
          # SPOOFING  BAD ADDRESSES
          # Refuse spoofed packets.
          # Ignore blatantly illegal source addresses.
          # Protect yourself from sending to bad addresses.

          # Refuse spoofed packets pretending to be from the external address.
          ipchains -A input  -i $EXTERNAL_INTERFACE -s $IPADDR -j DENY -l

          # Refuse packets claiming to be to or from a Class A private network
          ipchains -A input  -i $EXTERNAL_INTERFACE -s $CLASS_A -j DENY -l
          ipchains -A input  -i $EXTERNAL_INTERFACE -d $CLASS_A -j DENY -l
          ipchains -A output -i $EXTERNAL_INTERFACE -s $CLASS_A -j REJECT -l
          ipchains -A output -i $EXTERNAL_INTERFACE -d $CLASS_A -j REJECT -l

          # Refuse packets claiming to be to or from a Class B private network
          ipchains -A input  -i $EXTERNAL_INTERFACE -s $CLASS_B -j DENY -l
          ipchains -A input  -i $EXTERNAL_INTERFACE -d $CLASS_B -j DENY -l
          ipchains -A output -i $EXTERNAL_INTERFACE -s $CLASS_B -j REJECT -l
          ipchains -A output -i $EXTERNAL_INTERFACE -d $CLASS_B -j REJECT -l

          # Refuse packets claiming to be to or from a Class C private network
          #    ipchains -A input  -i $EXTERNAL_INTERFACE -s $CLASS_C -j DENY -l
          #    ipchains -A input  -i $EXTERNAL_INTERFACE -d $CLASS_C -j DENY -l
          #    ipchains -A output -i $EXTERNAL_INTERFACE -s $CLASS_C -j REJECT -l
          #    ipchains -A output -i $EXTERNAL_INTERFACE -d $CLASS_C -j REJECT -l

          # Refuse packets claiming to be from the loopback interface
          ipchains -A input  -i $EXTERNAL_INTERFACE -s $LOOPBACK -j DENY -l
          ipchains -A output -i $EXTERNAL_INTERFACE -s $LOOPBACK -j REJECT -l

          # Refuse broadcast address SOURCE packets
          ipchains -A input  -i $EXTERNAL_INTERFACE -s $BROADCAST_DEST -j DENY -l
          ipchains -A input  -i $EXTERNAL_INTERFACE -d $BROADCAST_SRC -j DENY -l

          # Refuse Class D multicast addresses (in.h) (NET-3-HOWTO)
          # Multicast is illegal as a source address.
          # Multicast uses UDP.
          ipchains -A input  -i $EXTERNAL_INTERFACE -s $CLASS_D_MULTICAST -j DENY -l

          # Refuse Class E reserved IP  addresses
          ipchains -A input  -i $EXTERNAL_INTERFACE -s $CLASS_E_RESERVED_NET -j DENY -l

          # refuse addresses defined as reserved by the IANA
          # 0.*.*.*, 1.*.*.*, 2.*.*.*, 5.*.*.*, 7.*.*.*, 23.*.*.*, 27.*.*.*
          # 31.*.*.*, 37.*.*.*, 39.*.*.*, 41.*.*.*, 42.*.*.*, 58-60.*.*.*
          # 65-95.*.*.*, 96-126.*.*.*, 197.*.*.*, 201.*.*.* (?), 217-223.*.*.*
          ipchains -A input  -i $EXTERNAL_INTERFACE -s 1.0.0.0/8  -j DENY -l
          ipchains -A input  -i $EXTERNAL_INTERFACE -s 2.0.0.0/8  -j DENY -l
          ipchains -A input  -i $EXTERNAL_INTERFACE -s 5.0.0.0/8  -j DENY -l
          ipchains -A input  -i $EXTERNAL_INTERFACE -s 7.0.0.0/8  -j DENY -l
          ipchains -A input  -i $EXTERNAL_INTERFACE -s 23.0.0.0/8 -j DENY -l
          ipchains -A input  -i $EXTERNAL_INTERFACE -s 27.0.0.0/8 -j DENY -l
          ipchains -A input  -i $EXTERNAL_INTERFACE -s 31.0.0.0/8 -j DENY -l
          ipchains -A input  -i $EXTERNAL_INTERFACE -s 37.0.0.0/8 -j DENY -l
          ipchains -A input  -i $EXTERNAL_INTERFACE -s 39.0.0.0/8 -j DENY -l
          ipchains -A input  -i $EXTERNAL_INTERFACE -s 41.0.0.0/8 -j DENY -l
          ipchains -A input  -i $EXTERNAL_INTERFACE -s 42.0.0.0/8 -j DENY -l
          ipchains -A input  -i $EXTERNAL_INTERFACE -s 58.0.0.0/7 -j DENY -l
          ipchains -A input  -i $EXTERNAL_INTERFACE -s 60.0.0.0/8 -j DENY -l

          #65: 01000001    - /3 includes 64 - need 65-79 spelled out
          ipchains -A input  -i $EXTERNAL_INTERFACE -s 65.0.0.0/8 -j DENY -l
          ipchains -A input  -i $EXTERNAL_INTERFACE -s 66.0.0.0/8 -j DENY -l
          ipchains -A input  -i $EXTERNAL_INTERFACE -s 67.0.0.0/8 -j DENY -l
          ipchains -A input  -i $EXTERNAL_INTERFACE -s 68.0.0.0/8 -j DENY -l
          ipchains -A input  -i $EXTERNAL_INTERFACE -s 69.0.0.0/8 -j DENY -l
          ipchains -A input  -i $EXTERNAL_INTERFACE -s 70.0.0.0/8 -j DENY -l
          ipchains -A input  -i $EXTERNAL_INTERFACE -s 71.0.0.0/8 -j DENY -l
          ipchains -A input  -i $EXTERNAL_INTERFACE -s 72.0.0.0/8 -j DENY -l
          ipchains -A input  -i $EXTERNAL_INTERFACE -s 73.0.0.0/8 -j DENY -l
          ipchains -A input  -i $EXTERNAL_INTERFACE -s 74.0.0.0/8 -j DENY -l
          ipchains -A input  -i $EXTERNAL_INTERFACE -s 75.0.0.0/8 -j DENY -l
          ipchains -A input  -i $EXTERNAL_INTERFACE -s 76.0.0.0/8 -j DENY -l
          ipchains -A input  -i $EXTERNAL_INTERFACE -s 77.0.0.0/8 -j DENY -l
          ipchains -A input  -i $EXTERNAL_INTERFACE -s 78.0.0.0/8 -j DENY -l
          ipchains -A input  -i $EXTERNAL_INTERFACE -s 79.0.0.0/8 -j DENY -l

          #80: 01010000   - /4 masks 80-95
          ipchains -A input  -i $EXTERNAL_INTERFACE -s 80.0.0.0/4 -j DENY -l

          # 96: 01100000    - /4 makses 96-111
          ipchains -A input  -i $EXTERNAL_INTERFACE -s 96.0.0.0/4 -j DENY -l

          #126: 01111110    - /3 includes 127 - need 112-126 spelled out
          ipchains -A input  -i $EXTERNAL_INTERFACE -s 112.0.0.0/8 -j DENY -l
          ipchains -A input  -i $EXTERNAL_INTERFACE -s 113.0.0.0/8 -j DENY -l
          ipchains -A input  -i $EXTERNAL_INTERFACE -s 114.0.0.0/8 -j DENY -l
          ipchains -A input  -i $EXTERNAL_INTERFACE -s 115.0.0.0/8 -j DENY -l
          ipchains -A input  -i $EXTERNAL_INTERFACE -s 116.0.0.0/8 -j DENY -l
          ipchains -A input  -i $EXTERNAL_INTERFACE -s 117.0.0.0/8 -j DENY -l
          ipchains -A input  -i $EXTERNAL_INTERFACE -s 118.0.0.0/8 -j DENY -l
          ipchains -A input  -i $EXTERNAL_INTERFACE -s 119.0.0.0/8 -j DENY -l
          ipchains -A input  -i $EXTERNAL_INTERFACE -s 120.0.0.0/8 -j DENY -l
          ipchains -A input  -i $EXTERNAL_INTERFACE -s 121.0.0.0/8 -j DENY -l
          ipchains -A input  -i $EXTERNAL_INTERFACE -s 122.0.0.0/8 -j DENY -l
          ipchains -A input  -i $EXTERNAL_INTERFACE -s 123.0.0.0/8 -j DENY -l
          ipchains -A input  -i $EXTERNAL_INTERFACE -s 124.0.0.0/8 -j DENY -l
          ipchains -A input  -i $EXTERNAL_INTERFACE -s 125.0.0.0/8 -j DENY -l
          ipchains -A input  -i $EXTERNAL_INTERFACE -s 126.0.0.0/8 -j DENY -l

          #217: 11011001    - /5 includes 216 - need 217-219 spelled out
          ipchains -A input  -i $EXTERNAL_INTERFACE -s 217.0.0.0/8 -j DENY -l
          ipchains -A input  -i $EXTERNAL_INTERFACE -s 218.0.0.0/8 -j DENY -l
          ipchains -A input  -i $EXTERNAL_INTERFACE -s 219.0.0.0/8 -j DENY -l

          #223: 11011111    - /6 masks 220-223
          ipchains -A input  -i $EXTERNAL_INTERFACE -s 220.0.0.0/6 -j DENY -l

          # ----------------------------------------------------------------------------
          # ICMP

          #    To prevent denial of service attacks based on ICMP bombs, filter
          #    incoming Redirect (5) and outgoing Destination Unreachable (3).
          #    Note, however, disabling Destination Unreachable (3) is not
          #    advisable, as it is used to negotiate packet fragment size.

          # For bi-directional ping.
          #     Message Types:  Echo_Reply (0),  Echo_Request (8)
          #     To prevent attacks, limit the src addresses to your ISP range.
          #
          # For outgoing traceroute.
          #     Message Types:  INCOMING Dest_Unreachable (3), Time_Exceeded (11)
          #     default UDP base: 33434 to base+nhops-1
          #
          # For incoming traceroute.
          #     Message Types:  OUTGOING Dest_Unreachable (3), Time_Exceeded (11)
          #     To block this, deny OUTGOING 3 and 11

          #  0: echo-reply (pong)
          #  3: destination-unreachable, port-unreachable, fragmentation-needed, etc.
          #  4: source-quench
          #  5: redirect
          #  8: echo-request (ping)
          # 11: time-exceeded
          # 12: parameter-problem

          ipchains -A input  -i $EXTERNAL_INTERFACE -p icmp \
          -s $ANYWHERE 0 -d $IPADDR -j ACCEPT
          ipchains -A input  -i $EXTERNAL_INTERFACE -p icmp \
          -s $ANYWHERE 3 -d $IPADDR -j ACCEPT
          ipchains -A input  -i $EXTERNAL_INTERFACE -p icmp \
          -s $ANYWHERE 4 -d $IPADDR -j ACCEPT
          ipchains -A input  -i $EXTERNAL_INTERFACE -p icmp \
          -s $ANYWHERE 11 -d $IPADDR -j ACCEPT
          ipchains -A input  -i $EXTERNAL_INTERFACE -p icmp \
          -s $ANYWHERE 12 -d $IPADDR -j ACCEPT
          ipchains -A input  -i $EXTERNAL_INTERFACE -p icmp \
          -s $MY_ISP 8 -d $IPADDR -j ACCEPT

          ipchains -A output -i $EXTERNAL_INTERFACE -p icmp \
          -s $IPADDR 0 -d $MY_ISP -j ACCEPT
          ipchains -A output -i $EXTERNAL_INTERFACE -p icmp \
          -s $IPADDR 3 -d $MY_ISP -j ACCEPT
          ipchains -A output -i $EXTERNAL_INTERFACE -p icmp \
          -s $IPADDR 4 -d $ANYWHERE -j ACCEPT
          ipchains -A output -i $EXTERNAL_INTERFACE -p icmp \
          -s $IPADDR 8 -d $ANYWHERE -j ACCEPT
          ipchains -A output -i $EXTERNAL_INTERFACE -p icmp \
          -s $IPADDR 12 -d $ANYWHERE -j ACCEPT
          ipchains -A output -i $EXTERNAL_INTERFACE -p icmp \
          -s $IPADDR 11 -d $MY_ISP -j ACCEPT

          # ----------------------------------------------------------------------------
          # UDP INCOMING TRACEROUTE
          # traceroute usually uses -S 32769:65535 -D 33434:33523

          ipchains -A input  -i $EXTERNAL_INTERFACE -p udp \
          -s $MY_ISP $TRACEROUTE_SRC_PORTS \
          -d $IPADDR $TRACEROUTE_DEST_PORTS -j ACCEPT -l

          ipchains -A input  -i $EXTERNAL_INTERFACE -p udp \
          -s $ANYWHERE $TRACEROUTE_SRC_PORTS \
          -d $IPADDR $TRACEROUTE_DEST_PORTS -j DENY -l

          # ----------------------------------------------------------------------------
          # DNS forwarding, caching only nameserver (53)
          # --------------------------------------------

          # server to server query or response
          # Caching only name server only requires UDP, not TCP

          ipchains -A input  -i $EXTERNAL_INTERFACE -p udp \
          -s $NAMESERVER_1 53 \
          -d $IPADDR 53 -j ACCEPT

          ipchains -A output -i $EXTERNAL_INTERFACE -p udp \
          -s $IPADDR 53 \
          -d $NAMESERVER_1 53 -j ACCEPT

          ipchains -A input  -i $EXTERNAL_INTERFACE -p udp \
          -s $NAMESERVER_2 53 \
          -d $IPADDR 53 -j ACCEPT

          ipchains -A output -i $EXTERNAL_INTERFACE -p udp \
          -s $IPADDR 53 \
          -d $NAMESERVER_2 53 -j ACCEPT

          # DNS client (53)
          # ---------------
          ipchains -A input  -i $EXTERNAL_INTERFACE -p udp \
          -s $NAMESERVER_1 53 \
          -d $IPADDR $UNPRIVPORTS -j ACCEPT

          ipchains -A output -i $EXTERNAL_INTERFACE -p udp \
          -s $IPADDR $UNPRIVPORTS \
          -d $NAMESERVER_1 53 -j ACCEPT

          ipchains -A input  -i $EXTERNAL_INTERFACE -p udp \
          -s $NAMESERVER_2 53 \
          -d $IPADDR $UNPRIVPORTS -j ACCEPT

          ipchains -A output -i $EXTERNAL_INTERFACE -p udp \
          -s $IPADDR $UNPRIVPORTS \
          -d $NAMESERVER_2 53 -j ACCEPT

          # TCP client to server requests are allowed by the protocol
          # if UDP requests fail. This is rarely seen. Usually, clients
          # use TCP as a secondary nameserver for zone transfers from
          # their primary nameservers, and as hackers.

          ipchains -A input  -i $EXTERNAL_INTERFACE -p tcp ! -y \
          -s $NAMESERVER_1 53 \
          -d $IPADDR $UNPRIVPORTS -j ACCEPT

          ipchains -A output -i $EXTERNAL_INTERFACE -p tcp \
          -s $IPADDR $UNPRIVPORTS \
          -d $NAMESERVER_1 53 -j ACCEPT

          ipchains -A input  -i $EXTERNAL_INTERFACE -p tcp ! -y \
          -s $NAMESERVER_2 53 \
          -d $IPADDR $UNPRIVPORTS -j ACCEPT

          ipchains -A output -i $EXTERNAL_INTERFACE -p tcp \
          -s $IPADDR $UNPRIVPORTS \
          -d $NAMESERVER_2 53 -j ACCEPT

          # ----------------------------------------------------------------------------
          # TCP accept only on selected ports
          # ---------------------------------
          # ------------------------------------------------------------------

          # SSH server (22)
          # ---------------

          ipchains -A input  -i $EXTERNAL_INTERFACE -p tcp \
          -s $ANYWHERE $UNPRIVPORTS \
          -d $IPADDR 22 -j ACCEPT

          ipchains -A output -i $EXTERNAL_INTERFACE -p tcp ! -y \
          -s $IPADDR 22 \
          -d $ANYWHERE $UNPRIVPORTS -j ACCEPT

          ipchains -A input  -i $EXTERNAL_INTERFACE -p tcp \
          -s $ANYWHERE $SSH_PORTS \
          -d $IPADDR 22 -j ACCEPT

          ipchains -A output -i $EXTERNAL_INTERFACE -p tcp ! -y \
          -s $IPADDR 22 \
          -d $ANYWHERE $SSH_PORTS -j ACCEPT


          # ------------------------------------------------------------------

          # HTTP server (80)
          # ----------------

          ipchains -A input  -i $EXTERNAL_INTERFACE -p tcp \
          -s $ANYWHERE $UNPRIVPORTS \
          -d $IPADDR 80 -j ACCEPT

          ipchains -A output -i $EXTERNAL_INTERFACE -p tcp ! -y \
          -s $IPADDR 80 \
          -d $ANYWHERE $UNPRIVPORTS -j ACCEPT

          # ------------------------------------------------------------------

          # HTTPS server (443)
          # ------------------

          ipchains -A input  -i $EXTERNAL_INTERFACE -p tcp \
          -s $ANYWHERE $UNPRIVPORTS \
          -d $IPADDR 443 -j ACCEPT

          ipchains -A output -i $EXTERNAL_INTERFACE -p tcp ! -y \
          -s $IPADDR 443 \
          -d $ANYWHERE $UNPRIVPORTS -j ACCEPT

          # ------------------------------------------------------------------

          # SYSLOG server (514)
          # -----------------

          # Provides full remote logging. Using  this feature you're able to
          # control all syslog messages on one host.

          #    ipchains -A input  -i $EXTERNAL_INTERFACE -p udp \
          #             -s $SYSLOG_CLIENT \
          #             -d $IPADDR 514 -j ACCEPT

          # SYSLOG client (514)
          # -----------------

          #    ipchains -A output -i $EXTERNAL_INTERFACE -p udp \
          #             -s $IPADDR 514 \
          #             -d $SYSLOG_SERVER 514 -j ACCEPT

          # ------------------------------------------------------------------

          # AUTH server (113)
          # -----------------

          # Reject, rather than deny, the incoming auth port. (NET-3-HOWTO)

          ipchains -A input  -i $EXTERNAL_INTERFACE -p tcp \
          -s $ANYWHERE \
          -d $IPADDR 113 -j REJECT

          # ------------------------------------------------------------------

          # SMTP client (25)
          # ----------------
          ipchains -A input  -i $EXTERNAL_INTERFACE -p tcp ! -y \
          -s $SMTP_SERVER 25 \
          -d $IPADDR $UNPRIVPORTS -j ACCEPT

          ipchains -A output -i $EXTERNAL_INTERFACE -p tcp \
          -s $IPADDR $UNPRIVPORTS \
          -d $SMTP_SERVER 25 -j ACCEPT

          # ------------------------------------------------------------------

          # FTP server (20, 21)
          # -------------------

          # incoming request

          ipchains -A input  -i $EXTERNAL_INTERFACE -p tcp \
          -s $ANYWHERE $UNPRIVPORTS \
          -d $IPADDR 21 -j ACCEPT

          ipchains -A output -i $EXTERNAL_INTERFACE -p tcp ! -y \
          -s $IPADDR 21 \
          -d $ANYWHERE $UNPRIVPORTS -j ACCEPT

          # PORT MODE data channel responses
          #
          ipchains -A input  -i $EXTERNAL_INTERFACE -p tcp ! -y \
          -s $ANYWHERE $UNPRIVPORTS \
          -d $IPADDR 20 -j ACCEPT

          ipchains -A output -i $EXTERNAL_INTERFACE -p tcp \
          -s $IPADDR 20 \
          -d $ANYWHERE $UNPRIVPORTS -j ACCEPT

          # PASSIVE MODE data channel responses

          ipchains -A input  -i $EXTERNAL_INTERFACE -p tcp \
          -s $ANYWHERE $UNPRIVPORTS \
          -d $IPADDR $UNPRIVPORTS -j ACCEPT

          ipchains -A output -i $EXTERNAL_INTERFACE -p tcp ! -y \
          -s $IPADDR $UNPRIVPORTS \
          -d $ANYWHERE $UNPRIVPORTS -j ACCEPT

          # ------------------------------------------------------------------
          # OUTGOING TRACEROUTE
          # -------------------
          ipchains -A output -i $EXTERNAL_INTERFACE -p udp \
          -s $IPADDR $TRACEROUTE_SRC_PORTS \
          -d $ANYWHERE $TRACEROUTE_DEST_PORTS -j ACCEPT

          # ----------------------------------------------------------------------------
          # Enable logging for selected denied packets

          ipchains -A input  -i $EXTERNAL_INTERFACE -p tcp \
          -d $IPADDR -j DENY -l

          ipchains -A input  -i $EXTERNAL_INTERFACE -p udp \
          -d $IPADDR $PRIVPORTS -j DENY -l

          ipchains -A input  -i $EXTERNAL_INTERFACE -p udp \
          -d $IPADDR $UNPRIVPORTS -j DENY -l

          ipchains -A input  -i $EXTERNAL_INTERFACE -p icmp \
          -s $ANYWHERE 5 -d $IPADDR -j DENY -l

          ipchains -A input  -i $EXTERNAL_INTERFACE -p icmp \
          -s $ANYWHERE 13:255 -d $IPADDR -j DENY -l

          # ----------------------------------------------------------------------------

          ;;
          stop)
          echo -n "Shutting Firewalling Services: "

          # Remove all existing rules belonging to this filter
          ipchains -F

          # Delete all user-defined chain to this filter
          ipchains -X

          # Reset the default policy of the filter to accept.
          ipchains -P input  ACCEPT
          ipchains -P output ACCEPT
          ipchains -P forward ACCEPT

          ;;
          status)
          status firewall
          ;;
          restart|reload)
          $0 stop
          $0 start
          ;;
          *)
          echo "Usage: firewall {start|stop|status|restart|reload}"
          exit 1
          esac

          exit 0


          Now, make this script executable and change its default permissions:


          [[email protected]] /# chmod 700 /etc/rc.d/init.d/firewall
          [[email protected]] /# chown 0.0 /etc/rc.d/init.d/firewall


          Create the symbolic rc.d links for your Firewall with the following command:


          [[email protected]] /# chkconfig --add firewall
          [[email protected]] /# chkconfig --level 345 firewall on


          Now, your firewall rules are configured to use System V init (System V init is in charge of starting all the normal processes that need to run at boot time) and it will be automatically started each time your server reboots.

          To manually stop the firewall on your system, use the following command:


          [[email protected]] /# /etc/rc.d/init.d/firewall stop


          Shutting Firewalling Services:                        [  OK  ]


          To manually start the firewall on your system, use the following command:


          [[email protected]] /# /etc/rc.d/init.d/firewall start


          Starting Firewalling Services:                        [  OK  ]

[目录]


系统检查

    像find和secure这样的程序称为检查程序,它们搜索文件系统,寻找出SUID/SGID文件、设备文件、任何人可写的系统文件、设有口令的登录用户、具有相同UID/GID的用户等等。

    Linux记帐软件包可用作安全检查工具,除最后登录时间的记录外,记帐系统还能保存全天运行的所有进程的完整记录,对于一个进程所存贮的信息包括UID、命令名、进程开始执行与结束的时间、CPU时间和实际消耗的时间、该进程是否是root进程,这将有助于系统管理员了解系统中的用户在干什么。acctcom命令可以列出一天的帐目表。标明系统中有多个记帐数据文件,记帐信息保存在文件/usr/adm/pacct*中,/usr/adm/pacct是当前记录文件,/usr/adm/pacctn是以前的记帐文件(n为整型数)。若有若干个记帐文件要查看,可在acctcom命令中指定文件名:acctcom/usr/adm/pacct?/usr/adm/pacct要检查的一个问题是:在acctcom的输出中查找一个用户过多的登录过程,若有,则说明可能有人一遍遍地尝试登录,猜测口令,企图非法进入系统。

    此外,还应查看root进程,除了系统管理员用su命令从终端进入root,系统启动,系统停止时间,以及由init(通常init只启动getty,login,登录外壳),cron启动的进程和具有rootSUID许可的命令外,不应当有任何root进程。由记帐系统也可获得有关每个用户的CPU利用率,运行的进程数等统计数据。

需要研究以下常用命令

su命令
    可不必注销帐户而将另一用户又登录进入系统,作为另一用户工作。它将启动一新的外壳并将有效和实际的UID和GID设置给另一用户。因此必须严格将root口令保密。
    通常系统管理员不会直接使用root账号通过网络远程登陆(很多系统默认配置也不允许这样做),而是使用一个“一般”的账号登陆,然后su,把自己变成root。但是请注意,黑客一旦知道root密码,同样可以这样做,而且很多黑客正是利用su的漏洞,在系统装入木马,等系统管理员su的时候,得到root账号,所以应该尽量小心。

newgrp命令
    与su相似,用于修改当前所处的组名。

其他检查命令
    1)du报告在层次目录结构(当前工作目录或指定目录起)中各目录占用的磁盘块数。可用于检查用户对文件系统的使用情况。
    2)df报告整个文件系统当前的空间使用情况。可用于合理调整磁盘空间的使用和管理。
    3)ps检查当前系统中正在运行的所有进程。对于用了大量CPU时间的进程、同时运行了许多进程的用户、运行了很长时间但用了很少CPU时间的用户进程应当深入检查。还可以查出运行了一个无限循环的后台进程的用户,未注销帐户就关闭终端的用户(一般发生在直接连线的终端)。
    4)who可以告诉系统管理员系统中工作的进展情况等等许多信息,检查用户的登录时间,登录终端。
    5)su每当用户试图使用su命令进入系统用户时,命令将在/usr/adm/sulog文件中写一条信息,若该文件记录了大量试图用su进入root的无效操作信息,则表明可能有人企图破译root口令。
    6)login在一些系统中,login程序记录了无效的登录企图(若本系统的login程序不做这项工作而系统中有login源程序,则应修改login)。每天总有少量的无效登录,若无效登录的次数突然增加了两倍,则表明可能有人企图通过猜测登录名和口令,非法进入系统。

    这里最重要的一点是:系统管理员越熟悉自己的用户和用户的工作习惯,就越能快速发现系统中任何不寻常的事件,而不寻常的事件意味着系统已被人窃密。

[目录]


系统泄密处理

    如果发现有人已经破坏了系统安全,这时系统管理员首先应做的是面对肇事用户。如果该用户所做的事不是蓄意的,而且公司没有关于“破坏安全”的规章,也未造成损失,则系统管理员只需清理系统,并留心该用户一段时间。如果该用户造成了某些损失,则应当报告有关人员,并且应尽可能地将系统恢复到原来的状态。

    如果肇事者是非授权用户,那就得做最坏的假设了:肇事者已设法成为root且本系统的文件和程序已经泄密了。系统管理员应当想法查出谁是肇事者,他造成了什么损坏,还应当对整个文件做一次全面的检查,并不只是检查SUID和SGID,设备文件。如果系统安全被一个敌对的用户破坏了,应当采用下面的步骤:

    ·关闭系统,然后重新引导,不要进入多用户方式,进入单用户方式。
    ·安装含有本系统原始Linux版本的带和软盘。
    ·将/bin、/usr/bin、/etc、/usr/lib中的文件拷贝到一个暂存目录中。
    ·将暂存目录中所有文件的校验和(用原始版本的sum程序拷贝做校验和,不要用/bin中的sum程序做)与系统中所有对旧的文件的校验和进行比较,如果有任何差别,要查清差别产生的原因。如果两个校验和不同,是由于安装了新版本的程序,确认是否的确安装了新版本程序。如果不能找出校验和不同的原因,用暂存目录中的命令替换系统中的原有命令。
    ·在确认系统中的命令还未被篡改之前,不要用系统中原命令。用暂存目录中的外壳,并将PATH设置为仅在暂存目录中搜索命令。
    ·根据暂存目录中所有系统命令的存取许可,检查系统中所有命令的存取许可。
    ·检查所有系统目录的存取许可,如果用了perms,检查permlist文件是否被篡改过。
    ·如果系统Linux(/Linux)的校验和不同于原版的校验和,并且系统管理员从未修改过核心,则应当认为,一个非法者“很能干”,从暂存缓冲区重新装入系统。系统管理员可以从逐步增加的文件系统备份中恢复用户的文件,但是在检查备份中的“有趣”文件之前,不能做文件恢复。
    ·改变系统中的所有口令,通知用户他们的口令已改变,应找系统管理员得到新口令。
    ·当用户来要新口令时,告诉用户发生了一次安全事故,让他们查看自己的文件和目录是否潜伏着危害(如SUID文件、特洛依木马、任何人可写的目录),并报告系统管理员任何异乎寻常的情况。
    ·设法查清安全破坏是如何发生的。如果没有肇事者说明,这也许是不可能弄清的。如果能发现肇事者如何进入系统,设法堵住这个安全漏洞。

    第一次安装Linux系统时,可以将外壳、sum命令、所有文件的校验和存放在安全的介质上(磁带、软盘、硬盘和任何可以卸下并锁起来的介质)。这样不必再从原版系统带上重新装入文件,可以安装备份介质,装入外壳和sum,将存在磁带上的校验和与系统中文件的校验和进行比较。系统管理员也许想自己写一个计算校验和的程序,破坏者将不能知道该程序的算法,如果将该程序及校验和保存在磁带上,这一方法的保密问题就减小到一个物理安全问题,即只需将磁带锁起来。


[目录]


限制用户

    如果的确想限制一个用户,可用chroot()子程序为用户建立一个完全隔离的环境。这个子程序改变了进程对根目录的概念,因此可用于将一个用户封在整个文件系统的某一层目录结构中,使用户无法用cd命令转出该层目录结构,不能存取文件系统中其他部分的任何文件。这种限制方式比加限制的外壳好得多。用户使用的命令应由系统管理员在新的root目录中建立一个bin目录,并建立用户可用命令的链到系统的/bin目录中相应命令文件上(若在不同的文件系统则应拷贝命令文件)。

    还应建立新的passwd文件,保留系统登录帐户(为了使ls-l正确地报告与受限制的子文件系统中的文件相关的正确登录名)和用户帐户,但系统帐户的口令改为NOLOGIN以使受限制的用户不能取得系统登录的真实口令,使“破密”程序的任何企图成为泡影。utmp文件是who所需要的,该文件含有系统中已登录用户的列表。

    新的/etc/profile文件也不是建链文件,以便受限制的用户可以执行不同的启动命令。/dev目录中的终端设备文件被链接到新的/dev目录下,因为命令who产生输出时要查看这些文件。在系统V及以后的Linux版本中,login命令有chroot()的功能。如果口令文件中用户入口项的登录外壳域(最后一个域)是*,login将调用chroot()把用户的根目录设置成为口令文件中用户入口项登录目录域指定的目录。然后再调用exec()执行login,新的login将在新子系统文件中执行该用户的登录。

    chroot()并不是把root封锁在一个子文件系统中,所以给受限制用户用的命令时应加以考虑,具有root的SUID许可的程序可能会给予用户root的能力。应当将这种可能减低到最小程度,交给用户使用的命令应当取自清除了SUID陷井的系统命令。链接文件可减少磁盘占用区,但要记住,当与敌对用户打交道时,链接到chroot目录结构(尤其是命令)的系统文件是很危险的。如果建立一个像这样的限制环境,应确保对安装到新的/bin的每条命令都做过测试,有些程序可能有系统管理员未曾想到的出乎意料的执行结果。为了使这些命令能运行,还得在加限制的子文件系统中加服务目录或文件,如:/tmp、/etc/termcap、/dev/swap、/dev/mem、/usr/lib/terminfo、/dev/kmem,用户所登录的/dev中的tty文件以及/Linux。

    有些程序在子文件系统中运行时不会很好,如果将假脱机程序和网络命令拷贝到加限制的子文件系统中,并放在为两条命令专建的目录层结构下,它们可能也运行不了。

[目录]


路由功能

[目录]


ADSL

    本解决方案主要针对公司、学校、网吧等需用一条ADSL将整个局网连上INTERNET,适合于10 -50台计算机的中小型网络用户。对于10台以下计算机的用WINAGTE、SYGATE就蛮好用。

    让我们来看看具体环境先,某公司总部办公室21间、计算机30台。组成10-100MB对等局域网,用一条ADSL宽带线路跑,以前用WINGATE将局域网连上INTERNET,后来觉得不爽我又用WINDOWS2000双网卡做了个NAT地址转换,使用网关和透明协议拖。这下下感觉舒服些了。呵呵,用了不久又发现些不大不小的毛病:比如内部互发OICQ慢啊,访问SINA.COM.CN等个别网站有问题啊等等。MS的东东看似简单但是当你想微调一下系统的时候,你就会突然发现原来人生多么无奈啊。痛定思痛!:(我毅然决定放弃WINDOWS2000,改用LINUX!!

    要用LINUX得搞台机器吧,东拼西凑好不容易搞了一台。各位看官请看: INTEL FX主板+PENTIUM 75芯片+16MB内存+540MB硬盘+512K显卡+DE220 10MB网卡。软件嘛随便找个LINUX发行版,我手头有REDHAT 6.2 核心是2.2.14,按SERVER的安装方式,经过长达48分钟左右的安装,可爱的#提示符出现在大家面前!各位看客也可以根据自己的具体情况安装。

  硬件、软件都装好了,下面开始具体配置。(加了#提示符号表示输入命令)

1、用ifconfig看看网络配置
[[email protected] /root]#ifconfig
lo   Link encap:Local Loopback
inet addr:127.0.0.1 Mask:255.0.0.0
UP LOOPBACK RUNNING MTU:3924 Metric:1
RX packets:23 errors:0 dropped:0 overruns:0 frame:0
TX packets:23 errors:0 dropped:0 overruns:0 carrier:0

 只有lo没找到网卡。不急,自己配。我是DLINK的DE220 IRQ=3 IO=300,兼容NE2000。在/etc/conf.modules 加两句。
具体如下:

[[email protected] /root]#cd /etc
[[email protected] /root]#vi conf.modules
alias eth0 ne
options eth0 io=0x300 irq=3

    IO和IRQ可以根据你自己的网卡设置如果不能插入就按INSERT,加完就按ESC。再按: ,再输入w 存盘,再q 退出。如果不放心就 #more conf.modules 看看写进去没有。
    一般市面上ISA的便宜网卡都兼容NE2000。如果是新手在LINUX下安装网卡的可能会遇到这样那样的问题,多在网上找找看看,一般都能解决。要提醒大家最好别用PNP即插即用模式,在LINUX出了问题不好解决,简直是场噩梦。

2、下面配置网卡IP地址, 在/etc/sysconfig/network-scripts下有个文件ifcfg-eth0 写成如下:

DEVICE=eth0
IPADDR=192.168.0.254
这是网卡的IP地址,以后客户机的网关就是这个地址。
NETMASK=255.255.255.0
NETWORK=192.168.0.0
BROADCAST=192.168.0.255
ONBOOT=yes
BOOTPROTO=none

    重启动就能找到网卡。然后

[[email protected] /root]#ifconfig
eth0  Link encap:Ethernet HWaddr 00:40:05:64:11:28
   inet addr:192.168.0.254 Bcast:192.168.0.255 Mask:255.255.255.0
     UP BROADCAST RUNNING MULTICAST MTU:1500 Metric:1
     RX packets:347573 errors:0 dropped:0 overruns:0 frame:0
     TX packets:40194 errors:0 dropped:0 overruns:0 carrier:0
     collisions:35 txqueuelen:100
     Interrupt:3 Base address:0x300
lo    Link encap:Local Loopback
     inet addr:127.0.0.1 Mask:255.0.0.0
     UP LOOPBACK RUNNING MTU:3924 Metric:1
     RX packets:23 errors:0 dropped:0 overruns:0 frame:0
     TX packets:23 errors:0 dropped:0 overruns:0 carrier:0
     collisions:0 txqueuelen:0
    哈哈,eth0找到网卡了,配置也正确,恭喜恭喜!进行下一步。

3、下一步做ADSL的驱动。
    去http://www.roaringpenguin.com/pppoe/rp-pppoe-2.6.tar.gz下个驱动程序先,大概85K大小。copy到/root去。然后

#tar xvfz rp-pppoe-2.6.tar.gz
#cd rp-pppoe-2.6
#./go

    开始安装,装好就#make一下下,开始配置ADSL。

Welcome to the Roaring Penguin ADSL client setup. First, I will run some checks on your system to make sure the PPPoE client is installed properly... Looks good! Now, please enter some information:
USER NAME
>>> Enter your PPPoE user name (default):

    这里输入在电信局申请的adsl的帐号

INTERFACE
>>> Enter the Ethernet interface connected to the ADSL modem For Solaris,this is likely to be something like /dev/hme0. For Linux, it will be ethn,where 'n' is a number.(default eth0):

    问你用哪片网卡拨号,默认是第一片eth0就可以了

4、最后一步:配置ipchains伪装IP。
    在 /etc/sysconfig的network文件里保证要有这句: FORWARD_IPV4=true
    然后改/etc/rc.d/rc.local这个文件,加入以下内容

<SPAN la
Do you want the link to come up on demand, or stay up continuously? If you want it to come up on demand, enter the idle time in seconds after which the link should be dropped. If you want the link to stay up permanently, enter 'no' (two letters, lower-case.)
NOTE: Demand-activated links do not interact well with dynamic IP addresses.You may have some problems with demand-activated links.
>>> Enter the demand value (default no):

    用缺省的no就可以了。

Please enter the IP address of your ISP's primary DNS server. If your ISP claims that 'the server will provide DNS addresses', enter 'server' (all lower-case) here. If you just press enter, I will assume you know what you are doing and not modify your DNS set up.
>>> Enter the DNS information here:

    这里填你ISP的DNS地址,成都用61.139.2.69,辅助DNS成都可用202.98.127.32

PASSWORD
>>> Please enter your PPPoE password:
    ADSL拨号密码这个东东。

    搞定!爽爽,用#adsl-start 就可以开始拨号。如果连接成功系统会提示你:
…….connect
    用ifconfig看看。[[email protected] /root]# ifconfig

eth0   Link encap:Ethernet HWaddr 00:40:05:64:11:28
     inet addr:192.168.0.254 Bcast:192.168.0.255 Mask:255.255.255.0
     UP BROADCAST RUNNING MULTICAST MTU:1500 Metric:1
     RX packets:347573 errors:0 dropped:0 overruns:0 frame:0
     TX packets:40194 errors:0 dropped:0 overruns:0 carrier:0
     collisions:35 txqueuelen:100
     Interrupt:3 Base address:0x300
lo    Link encap:Local Loopback
     inet addr:127.0.0.1 Mask:255.0.0.0
     UP LOOPBACK RUNNING MTU:3924 Metric:1
     RX packets:23 errors:0 dropped:0 overruns:0 frame:0
     TX packets:23 errors:0 dropped:0 overruns:0 carrier:0
     collisions:0 txqueuelen:0
ppp0   Link encap:Point-to-Point Protocol
     UP POINTOPOINT RUNNING NOARP MULTICAST MTU:1492 Metric:1
     RX packets:20498 errors:0 dropped:0 overruns:0 frame:0
     TX packets:19187 errors:0 dropped:0 overruns:0 carrier:0
     collisions:0 txqueuelen:10

看见ppp0没有!'

[目录]


IPChains

用Linux+IPChains代替Windows+WinGate
蓝森林 http://www.lslnet.com 张中华

    任务:办公室有10台电脑,组成局域网,其中1台名为gate的机器配有ISDN卡,可拨号上网,另外9台机器也要上网,由gate机器做代理或网关,共享其ISDN设备。原来的方案是:gate机器上的操作系统是Win98,使用的代理软件是WinGate。现在,gate机器的操作系统换成了Linux,怎么让其它9台机器也能上网?
    经过尝试,我使用IPChains的IP伪装转发功能成功地做到了这一点。我的配置为:蓝点Linux 2.0,Kernel-2.2.16,isdn4linux v3.1pre1,上海贝尔生产的ISDN内置卡,型号为SBT6021。
    下面介绍具体做法。介绍顺序为:内核->ipchains的配置->其它机器的配置。

0、 前提条件

    前提条件当然就是这台配有ISDN卡,安装了Linux的名为gate的机器,本身必须能够顺利拨号上网。我已做到了,具体操作过程写在我的另一篇文章《在Linux下使用ISDN拨号上网》中。

1、 内核

    这个方案的原理是:由于这台gate机器建立拨号连接后,具有真正的IP地址,能够正常地访问Internet,而局域网内其它机器却没有真正的IP地址,不能象gate机器那样正常
    地访问Internet,解决办法就是由gate机器代劳其它机器的Internet访问请求,假装是它自己的。把这台gate机器作为局域网的网关,当它收到来自局域网内其它机器的请求数据包时,进行伪装,然后再转发出去;相应地,当伪装后发出去的数据包得到响应返回时,先对该响应数据包进行还原,再转交给回局域网内真正发出请求的那台机器。这种做法叫做IP Masquerade(IP伪装)。
要Linux内核支持IP伪装这种功能,在编译内核时,必须选中下列选项:

Network firewalls
IP: firewalling
IP: masquerading
IP: ipportfw masq support
IP: ipautofw masquerade support
IP: ip fwmark masq-forwarding support
IP: ICMP masquerading

    但我不必急于编译内核,如果现有的内核已经包含这些选项了,我又何必重复一遍呢。
那我怎么知道现有内核是否已经包含这些选项了呢?看内核编译配置文件/usr/src/linux/.config(注意:文件名以"."开头的文件是隐藏文件,要用ls -a才可看到。)我看到其中有下面这7行内容,对应于刚才的7个选项:

CONFIG_FIREWALL=y
CONFIG_IP_FIREWALL=y
CONFIG_IP_MASQUERADE=y
CONFIG_IP_MASQUERADE_ICMP=y
CONFIG_IP_MASQUERADE_IPAUTOFW=m
CONFIG_IP_MASQUERADE_IPPORTFW=m
CONFIG_IP_MASQUERADE_MFW=m

    "=y"表示内核直接支持(代码已链入内核中),"=m"表示模块支持(代码在另外的内核中,可由内核载入)。于是这就表明,蓝点Linux 2.0的原有内核已包含这些选项了,我就不用重新编译内核啦。
    但仍然得做点事情,首先必须命令内核,启动IP转发功能:
        echo 1 > /proc/sys/net/ipv4/ip_forward
    往/proc/sys/net/ipv4/ip_forward里写入"1"就行了。
    有些功能如ftp, irc等的伪装,需要相应的模块支持,这些模块放在/lib/modules/2.2.16/ipv4目录中,装入它们:
        depmod -a
        modprobe ip_masq_ftp
        modprobe ip_masq_irc
        modprobe ip_masq_raudio

2、 ipchains的配置
    蓝点Linux 2.0包含的ipchains软件已经足够满足我的要求了,我就不必安装新的,只需配置一下即可。Ipchains是一个包过滤器,功能强大,设置也复杂,但我只想使用其IP伪装转发功能而已,设置得以简化。我这台Linux机器在一个局域网上,局域网的域名为thalia.com,地址为210.96.100.0,这台机器的主机名为gate,地址为210.96.100.10。

    对ipchains过滤器进行设置,就是设置各种链及规则。先看看目前情况如何:

        ipchains -L
    得到类似下面的信息:

        Chain input (policy ACCEPT):
        Chain forward (policy ACCEPT):
        Chain output (policy ACCEPT):

    没什么规则,3条链的策略都是接受。
    由于只是使用伪装转发功能,所以只对forward链进行操作。
    ipchains -P forward DENY把forward链的策略设为DENY,拒绝通过。此后增加可通过的规则,逐渐允许更多的数据包通过,这是一种先紧后松的做法。

        ipchains -A forward -s 210.96.100.0/255.255.255.0 -j MASQ

    增加1条规则,这条规则说明:对来自210.96.100.0局域网内(网络掩码为255.255.255.0)的数据包(-s 210.96.100.0/255.255.255.0),进行伪装处理(-j MASQ)。
    这时候再看一下情况如何:
        ipchains -L
    得到类似下面的信息:
        Chain input (policy ACCEPT):
        Chain forward (policy DENY):
        target prot opt source destination ports
        MASQ all ------ 210.96.100.0/24 anywhere n/a
        Chain output (policy ACCEPT):
        forward链中多了1条MASQ规则。
    要简单地实现共享ISDN上网,这已经足够了。

3、 其它机器的配置
    配置局域网上的其它Win98, Win2000机器,要点是把缺省网关设为那台Linux gate机器,DNS域名服务器也设为那台Linux gate机器。应用软件如IE,OutlookExpress等不用做任何设置,想象成ISDN装在本机上就行。
    我现在就去设置1台Win98机器试试看。
    (1)在“控制面板 | 网络 | 配置”下,选中“TCP/IP->3Com PCI Ethernet Adapter”(这台机器配的是3Com网卡),点击“属性”按钮,弹出TCP/IP属性对话框。
    (2)到“IP地址”页中,指定IP地址,IP地址为210.96.100.14,子网掩码为255.255.255.0;到“网关”页中,添加新网关210.96.100.10。
    (3)机器重启。
    (4)打开IE,浏览http://168.160.224.103(即新浪网sina.com.cn),看到了新浪的首页;但是浏览http://www.sina.com.cn,却不行。这是域名解析的问题。
    (5)重复(1)步骤,弹出TCP/IP属性对话框,到“DNS配置”页中,启用DNS,主机名写zzh,添加DNS服务器搜索顺序210.96.100.10。机器重启。打开IE,再次浏览http://www.sina.com.cn,这次好啦。

4、 形成shell文件
    上面对内核和ipchains的配置是逐条命令进行的,已经全部成功通过,现在把它们写成shell文件。
/etc/ppp/ip-masq-start文件内容如下:
# IP masq
echo 1 > /proc/sys/net/ipv4/ip_forward
depmod -a


modprobe ip_masq_irc
modprobe ip_masq_raudio
ipchains -P forward DENY
ipchains -A forward -s 210.96.100.0/255.255.255.0 -j MASQ

    让它成为可执行文件:
        chmod a+x /etc/ppp/ip-masq-start
    以后事情就简单了。要开启IP伪装转发功能,下命令/etc/ppp/ip-masq-start。

[目录]


防火墙

[目录]


netfilter

标题: A new place to LKM:netfilter
作者: yawl <[email protected]>
时间: 2000-10

目录:
-.前言
二.分析
三.例子代码
四.附录:与2.2在应用方面的区别简介
五.后记


-.前言

  在linux2.2内核中的防火墙ipchains已经被用户广泛认可,它提供了完整的防火墙功能(包过滤,地址伪装,透明代理),又避免了商业防火墙那高的惊人的价格。如果你用的是某款国产防火墙,那么十有八九你实际在受到ipchains(有些甚至是2.0系列中ipfwadm)的保护:-).在未来的2.4内核中,被称为netfilter(http://netfilter.kernelnotes.org/)的防火墙以更好的结构重新构造,并实现了许多新功能,如完整的动态NAT(2.2内核实际是多对一的"地址伪装"),基于MAC及用户的过滤,真正的基于状态的过滤(不再是简单的查看tcp的标志位等),包速率限制等。
  在原有的网络部分的LKM中,如果对网络部分进行处理,一般是先生成struct packet_type结构,在用dev_add_pack将其插入网络层(注意此时的packet_type实际相当于一个的三层的协议,如ip_packet_type,ipx_8023_packet_type等),具体的例子可参见phrack 55期<Building into the linux network layer>和本月小四写的月刊文章<利用LLKM处理网络通信----对抗IDS、Firewall>。
  而netfilter本身在IP层内提供了另外的5个插入点(其文档中称为HOOK):NF_IP_PRE_ROUTING,NF_IP_LOCAL_IN,NF_IP_FORWARD,NF_IP_LOCAL_OUT,NF_IP_POST_ROUTING,分别对应IP层的五个不同位置,这样理论上在写lkm时便可以选择更适合的切入点,再辅以netfilter内置的新功能(如connect tracking),应该会帮助写出功能更强的lkm。
  本来准备写出一个完整的例子(限制IP连接数),但计划总赶不上变化:-(,只好先贴出个简单的例子来,权且自我安慰成抛砖引玉了。
  本文的参考配置是linux2.4.0-test4和iptable-1.1.1,好,开始抛砖,闪人喽!


二.分析
  通俗的说,netfilter的架构就是在整个网络流程的若干位置放置了一些检测点(HOOK),而在每个检测点上上登记了一些处理函数进行处理(如包过滤,NAT等,甚至可以是用户自定义的功能)。
  IP层的五个HOOK点的位置如下图所示(copy from <packet filter howto>) :

          --->[1]--->[ROUTE]--->[3]--->[5]--->
                        |            ^
                        |            |
                        |         [ROUTE]
                        v            |
                       [2]          [4]
                        |            ^
                        |            |
                        v            |
                       [local process]

[1]:NF_IP_PRE_ROUTING:刚刚进入网络层的数据包通过此点(刚刚进行完版本号,校验和等检测),源地址转换在此点
进行;
[2]:NF_IP_LOCAL_IN:经路由查找后,送往本机的通过此检查点,INPUT包过滤在此点进行;
[3]:NF_IP_FORWARD:要转发的包通过此检测点,FORWORD包过滤在此点进行;
[4]:NF_IP_LOCAL_OUT:本机进程发出的包通过此检测点,OUTPUT包过滤在此点进行;
[5]:NF_IP_POST_ROUTING:所有马上便要通过网络设备出去的包通过此检测点,内置的目的地址转换功能(包括地址伪
装)在此点进行。

  在IP层代码中,有一些带有NF_HOOK宏的语句,如IP的转发函数中有:

<-ipforward.c ip_forward()->
NF_HOOK(PF_INET, NF_IP_FORWARD, skb, skb->dev, dev2,
                       ip_forward_finish);

  其中NF_HOOK宏的定义提炼如下:

<-/include/linux/netfilter.h->
#ifdef CONFIG_NETFILTER
#define NF_HOOK(pf, hook, skb, indev, outdev, okfn)                        \
(list_empty(&nf_hooks[(pf)][(hook)])                                        \
? (okfn)(skb)                                                                \
: nf_hook_slow((pf), (hook), (skb), (indev), (outdev), (okfn)))
#else /* !CONFIG_NETFILTER */
#define NF_HOOK(pf, hook, skb, indev, outdev, okfn) (okfn)(skb)
#endif /*CONFIG_NETFILTER*/

  如果在编译内核时没有配置netfilter时,就相当于调用最后一个参数,此例中即执行ip_forward_finish函数;否则进入HOOK点,执行通过nf_register_hook()登记的功能(这句话表达的可能比较含糊,实际是进入
nf_hook_slow()函数,再由它执行登记的函数)。

  NF_HOOK宏的参数分别为:
1.pf:协议族名,netfilter架构同样可以用于IP层之外,因此这个变量还可以有诸如PF_INET6,PF_DECnet等名字。
2.hook:HOOK点的名字,对于IP层,就是取上面的五个值;
3.skb:不用多解释了吧;
4.indev:进来的设备,以struct net_device结构表示;
5.outdev:出去的设备,以struct net_device结构表示;
(后面可以看到,以上五个参数将传到用nf_register_hook登记的处理函数中。)
6.okfn:是个函数指针,当所有的该HOOK点的所有登记函数调用完后,转而走此流程。

  这些点是已经在内核中定义好的,除非你是这部分内核代码的维护者,否则无权增加或修改,而在此检测点进行的处理,则可由用户指定。像packet filter,NAT,connection track这些功能,也是以这种方式提供的。正如netfilter的当初的设计目标--提供一个完善灵活的框架,为扩展功能提供方便。

  如果我们想加入自己的代码,便要用nf_register_hook函数,其函数原型为:
  int nf_register_hook(struct nf_hook_ops *reg)
  我们考察一下struct nf_hook_ops结构:

struct nf_hook_ops
{
        struct list_head list;

        /* User fills in from here down. */
        nf_hookfn *hook;
        int pf;
        int hooknum;
        /* Hooks are ordered in ascending priority. */
        int priority;
};

  我们的工作便是生成一个struct nf_hook_ops结构的实例,并用nf_register_hook将其HOOK上。其中list项我们总要初始化为{NULL,NULL};由于一般在IP层工作,pf总是PF_INET;hooknum就是我们选择的HOOK点;一个HOOK点可能挂多个处理函数,谁先谁后,便要看优先级,即priority的指定了。netfilter_ipv4.h中用一个枚举类型指定了内置的处理函数的优先级:

enum nf_ip_hook_priorities {
        NF_IP_PRI_FIRST = INT_MIN,
        NF_IP_PRI_CONNTRACK = -200,
        NF_IP_PRI_MANGLE = -150,
        NF_IP_PRI_NAT_DST = -100,
        NF_IP_PRI_FILTER = 0,
        NF_IP_PRI_NAT_SRC = 100,
        NF_IP_PRI_LAST = INT_MAX,
};

  hook是提供的处理函数,也就是我们的主要工作,其原型为:

unsigned int nf_hookfn(unsigned int hooknum,
                               struct sk_buff **skb,
                               const struct net_device *in,
                               const struct net_device *out,
                               int (*okfn)(struct sk_buff *));

  它的五个参数将由NFHOOK宏传进去。
  了解了这些,基本上便可以可以写一个lkm出来了。

三.例子代码

这段代码是一个例子,其功能实现了一个IDS,检测几个简单攻击(land,winnuke)和特殊扫描(nmap),当然,不会有人真把
它当严肃的IDS使用吧:-)。可以利用类似结构干点别的。。。

<-example.c begin->

/*
*  netfilter module example: it`s a kernel IDS(be quie,donot laugh, my friend)
[email protected]
*  Compile:gcc -O -c -Wall sample.c ,under linux2.4 kernel,netfilter is needed.
*/

#define __KERNEL__
#define MODULE

#include <linux/module.h>
#include <linux/skbuff.h>
#include <linux/netdevice.h>
#include <linux/config.h>
#include <linux/ip.h>
#include <linux/tcp.h>
#include <linux/udp.h>
#include <linux/netfilter_ipv4.h>

#define ALERT(fmt,args...) printk("nsfocus: " fmt, ##args)
/*message will be print to screen(too many~),and logged to /var/log/message*/

static unsigned int sample(unsigned int hooknum,struct sk_buff **skb,
                                const struct net_device *in,
                                const struct net_device *out,int (*okfn)(struct sk_buff *))
{
        struct iphdr *iph;
        struct tcphdr *tcph;
        struct udphdr *udph;

        __u32        sip;
        __u32        dip;
        __u16        sport;
        __u16        dport;

        iph=(*skb)->nh.iph;
        sip=iph->saddr;
        dip=iph->daddr;

        /*play ip packet here
        (note:checksum has been checked,if connection track is enabled,defrag have been done )*/
        if(iph->ihl!=5){
                ALERT("IP packet with packet from %d.%d.%d.%d to %d.%d.%d.%d\n",NIPQUAD(sip),NIPQUAD(dip));
        }

        if(iph->protocol==6){
                tcph=(struct tcphdr*)((__u32 *)iph+iph->ihl);
                sport=tcph->source;
                dport=tcph->dest;
                /*play tcp packet here*/
                if((tcph->syn)&&(sport==dport)&&(sip==dip)){
                        ALERT("maybe land attack\n");
                }
                if(ntohs(tcph->dest)==139&&tcph->urg){
                        ALERT("maybe winnuke a from %d.%d.%d.%d to %d.%d.%d.%d\n",NIPQUAD(sip),NIPQUAD(dip));
                }
                if(tcph->ece&&tcph->cwr){
                        ALERT("queso from %d.%d.%d.%d to %d.%d.%d.%d\n",NIPQUAD(sip),NIPQUAD(dip));
                }
                   if((tcph->fin)&&(tcph->syn)&&(!tcph->rst)&&(!tcph->psh)&&(!tcph->ack)&&(!tcph->urg)){
                        ALERT("SF_scan from %d.%d.%d.%d to %d.%d.%d.%d\n",NIPQUAD(sip),NIPQUAD(dip));
                }
                   if((!tcph->fin)&&(!tcph->syn)&&(!tcph->rst)&&(!tcph->psh)&&(!tcph->ack)&&(!tcph->urg)){
                        ALERT("NULL_scan from %d.%d.%d.%d to %d.%d.%d.%d\n",NIPQUAD(sip),NIPQUAD(dip));
                }
                   if(tcph->fin&&tcph->syn&&tcph->rst&&tcph->psh&&tcph->ack&&tcph->urg){
                        ALERT("FULL_Xmas_scan from %d.%d.%d.%d to %d.%d.%d.%d\n",NIPQUAD(sip),NIPQUAD(dip));
                }
                   if((tcph->fin)&&(!tcph->syn)&&(!tcph->rst)&&(tcph->psh)&&(!tcph->ack)&&(tcph->urg)){
                        ALERT("XMAS_Scan(FPU)from %d.%d.%d.%d to %d.%d.%d.%d\n",NIPQUAD(sip),NIPQUAD(dip));
                }
        }

        else if(iph->protocol==17){
                udph=(struct udphdr *)((__u32 *)iph+iph->ihl);
                sport=udph->source;
                dport=udph->dest;
                /*play udp packet here*/
        }

        else if(iph->protocol==1){
                /*play icmp packet here*/
        }

        else if(iph->protocol==2){
                ALERT("igmp packet from %d.%d.%d.%d to %d.%d.%d.%d\n",NIPQUAD(sip),NIPQUAD(dip));
                /*play igmp packet here*/
        }

        else{
                ALERT("unknown protocol%d packet from %d.%d.%d.%d to %d.%d.%d.%d\n",iph->protocol,NIPQUAD(sip),NIPQUAD(dip));
        }
        return NF_ACCEPT;
        /*for it is IDS,we just accept all packet,
        if you really want to drop this skb,just return NF_DROP*/

}

static struct nf_hook_ops iplimitfilter
={ {NULL,NULL} ,sample,PF_INET,NF_IP_PRE_ROUTING,NF_IP_PRI_FILTER-1};

int init_module(void)
{
        return nf_register_hook(&iplimitfilter);
}

void cleanup_module(void)
{
        nf_unregister_hook(&iplimitfilter);
}

<-example.c end->

四.附录:与2.2在应用方面的区别简介

  本来还想详细介绍一下iptables的用法,但如果说的太详细的话,还不如索性将HOWTO翻译一下,于是干脆了却了这个念头,只顺便简介一下与以前版本的变化(而且是我认为最重要的)。如果ipchains本来便没有在你的脑子中扎根,其实便没有必要看这部分。
  netfilter,又可称为iptables.开发初期准备将packet filter和NAT的配置工具完全分开,一个称为iptables,另一个称为ipnatctl,而将整个项目成为netfilter.但后来可能是还是习惯2.2内核中用ipchians一个工具干两件事的用法,又改为全部用iptables配置了。
  理论上还可以用2.2系列的ipchains和2.0系列的ipfwadm作配置工具,但只是做兼容或过渡的考虑了。通过源码看到他们也是通过现有的结构HOOK上去的(主要是net/ipv4/netfilter目录下的ip_fw_compat.c,ip_fw_compat_masq.c,
ip_fw_compat_redir.c,ipchains_core.c,ipfwadm_core.c这几个文件)。
  一个重要的变化是原有的INPUT,OUTPUT(原来是小写的input,ouput)链(现在应称为表?)的位置变了,原来的input,output的位置相当于现在的NF_IP_PRE_ROUTING,NF_IP_POST_ROUTING 。原有的结构确实不太合理,转发的包要经过三条链,现在INPUT专指去往本机的,OUPUT专指从本机发出的,而FOWARD仍旧是转发的包。
  举两个简单的例子:
  1.作地址伪装(场景:对外通过拨号连接internet)注意原来的MASQ变成好长的MASQUERATE,而伪装相当于SNAT,因此位置是在POSTROUTING:

  iptables -t nat -A POSTROUTING -o ppp0 -j MASQUERATE

  2.还有一个限制包速率的功能比较好玩,例如如下规则:

  iptables -A FORWARD -p tcp --syn -m limit --limit 1/s -j ACCEPT

  简单的说就是在转发时(-A FORWARD:因为是防火墙嘛),如果是tcp协议,且有syn标记(-p tcp --syn),可以限制为每秒一个(-m limit --limit 1/s ),行动项是ACCEPT。最后连起来意义就是每秒只允许转发一个tcp连接请求。


五.后记
  netfilter还提供了许多新功能,如可以将包转发到应用层,由应用程序进行处理等,可目前我还没有分析多少,慢慢抽出点时间看吧。唉,尽管以前看过ipchains的代码,但netfilter实在变动太大了,一切都要从头看起:-(
  最后,当然要感谢Rusty Russell,netfilter项目的负责人,不仅为我们提供了这个强大好用的工具,还写了大量非常优秀的文档。


参考文献:

[1.] Linux 2.4 Packet Filtering HOWTO
        Rusty Russell, mailing list [email protected]
          v1.0.1 Mon May  1 18:09:31 CST 2000
[2.] Linux IPCHAINS-HOWTO
          Paul Russell, [email protected]
          v1.0.7, Fri Mar 12 13:46:20 CST 1999
[3.] Linux 2.4 NAT HOWTO
          Rusty Russell, mailing list [email protected]
          v1.0.1 Mon May  1 18:38:22 CST 2000
[4.] Linux netfilter Hacking HOWTO
          Rusty Russell, mailing list [email protected]
          v1.0.1 Sat Jul  1 18:24:41 EST 2000
[5.] Writing a Module for netfilter
        by Paul "Rusty" Russell
        Linux Magazine June 2000 http://www.linux-mag.com/2000-06/gear_01.html
[6.] Salvatore Sanfilippo<[email protected]>写的一份netfilter sample,但可惜我找不到出处了,只剩下手头一份打印稿,But anyway,thanks to Salvatore.

[目录]


ip/tables

  1 /*
  2  * 25-Jul-1998 Major changes to allow for ip chain table
  3  *
  4  * 3-Jan-2000 Named tables to allow packet selection for different uses.
  5  */
  6
  7 /*
  8  *      Format of an IP firewall descriptor
  9  *
注意这里的说明:IP地址和掩码是按照网络字节存储(大端存储)标志字节和端口号是按照主机字节序存储(依主机硬件结构而定)
10  *      src, dst, src_mask, dst_mask are always stored in network byte order.
11  *      flags are stored in host byte order (of course).
12  *      Port numbers are stored in HOST byte order.
13  */
14
15 #ifndef _IPTABLES_H
16 #define _IPTABLES_H
17
18 #ifdef __KERNEL__
19 #include linux/if.h
20 #include linux/types.h
21 #include linux/in.h
22 #include linux/ip.h
23 #include linux/skbuff.h
24 #endif
25 #include linux/netfilter_ipv4.h
26
27 #define IPT_FUNCTION_MAXNAMELEN 30
28 #define IPT_TABLE_MAXNAMELEN 32
29
这个结构存储与IP头部有关的防火墙规则信息。这里的注释说“这个结构无须填充零字节”,就是说这个结构的大小正好是4的倍数。这里由于IFNAMSIZ等于16,所以整个结构大小确实是4的倍数。
30 /* Yes, Virginia, you have to zero the padding. */
31 struct ipt_ip {
32         /* Source and destination IP addr */
33         struct in_addr src, dst;
34         /* Mask for src and dest IP addr */
35         struct in_addr smsk, dmsk;
36         char iniface[IFNAMSIZ], outiface[IFNAMSIZ];
37         unsigned char iniface_mask[IFNAMSIZ], outiface_mask[IFNAMSIZ];
38
39         /* Protocol, 0 = ANY */
40         u_int16_t proto;
41
42         /* Flags word */
43         u_int8_t flags;
44         /* Inverse flags */
45         u_int8_t invflags;
46 };
47这个结构存储match的信息,这里的匹配主要是指与IP无关的防火墙规则信息。由系统缺省设置的匹配主要有三个“tcp”、“udp”,“icmp”,我在分析ip_tables.c时将详细描述。
48 struct ipt_entry_match
49 {
50         union {
51                 struct {
52                         u_int16_t match_size;
53
54                         /* Used by userspace */
55                         char name[IPT_FUNCTION_MAXNAMELEN];
56                 } user;
57                 struct {
58                         u_int16_t match_size;
59
60                         /* Used inside the kernel */
61                         struct ipt_match *match;
62                 } kernel;
63
64                 /* Total length */
65                 u_int16_t match_size;
66         } u;
67
68         unsigned char data[0];
69 };
70 target结构信息,是决定一个分组命运的信息。也可以理解为action信息,其意义是指当一个分组与rule和match信息匹配后,如何处置该分组。处置方法一般有三种:一,命令常数,比如DROP ACCEPT等等;二 系统预定义的模块处理函数,比如”SNAT DNAT"等等;第三种是用户自己写模块函数。
71 struct ipt_entry_target
72 {
73         union {
74                 struct {
75                         u_int16_t target_size;
76
77                         /* Used by userspace */
78                         char name[IPT_FUNCTION_MAXNAMELEN];
79                 } user;
80                 struct {
81                         u_int16_t target_size;
82
83                         /* Used inside the kernel */
84                         struct ipt_target *target;
85                 } kernel;
86
87                 /* Total length */
88                 u_int16_t target_size;
89         } u;
90
91         unsigned char data[0];
92 };
93这个结构已经很明显给出了target的形式:命令常数、或者模块函数。
94 struct ipt_standard_target
95 {
96         struct ipt_entry_target target;
97         int verdict;
98 };
99
计数器结构,每一个rule都有一个计数器结构用来统计匹配该条规则的分组数目和字节数目。为基于统计的安全工具提供分析基础。
100 struct ipt_counters
101 {
102         u_int64_t pcnt, bcnt;                   /* Packet and byte counters */
103 };
104
标志字段,各个常数后面的注释已经给出了明确的解释,这里不再赘述。
105 /* Values for "flag" field in struct ipt_ip (general ip structure). */
106 #define IPT_F_FRAG              0x01    /* Set if rule is a fragment rule */
107 #define IPT_F_MASK              0x01    /* All possible flag bits mask. */
108
109 /* Values for "inv" field in struct ipt_ip. */
110 #define IPT_INV_VIA_IN          0x01    /* Invert the sense of IN IFACE. */
111 #define IPT_INV_VIA_OUT         0x02    /* Invert the sense of OUT IFACE */
112 #define IPT_INV_TOS             0x04    /* Invert the sense of TOS. */
113 #define IPT_INV_SRCIP           0x08    /* Invert the sense of SRC IP. */
114 #define IPT_INV_DSTIP           0x10    /* Invert the sense of DST OP. */
115 #define IPT_INV_FRAG            0x20    /* Invert the sense of FRAG. */
116 #define IPT_INV_PROTO           0x40    /* Invert the sense of PROTO. */
掩码标志。用法是当出现超出掩码范围的标志时,确认是非法标志。
117 #define IPT_INV_MASK            0x7F    /* All possible flag bits mask. */
118
其实这个结构的构成这里的注释已经说的很清楚,但是从论坛上有人问"关于netfilter的问题“时,可以看出很多人还是不理解。与前面ipchains版本防火墙不同的是iptables的防火墙规则构成发生了变化。ipchains的构成是rule+target,而iptables的构成是ip匹配信息+match+target。同时iptables构成的每一个部分都是可变大小的,由于经常出现”char XXX[0]“就可以看出。但是我个人认为规则的组织有点不好理解,它经常是先分配一段空间,然后将规则一条一条放入。如同文件系统存放变长记录的文件时,总要在记录中放入记录长度,以便以后取出记录,这里iptables正是使用这种方法,在每个规则中都放入长度字段,这样方便提取各个组成部分和计算下一条规则的位置。
119 /* This structure defines each of the firewall rules.  Consists of 3
120    parts which are 1) general IP header stuff 2) match specific
121    stuff 3) the target to perform if the rule matches */
122 struct ipt_entry
123 {
124         struct ipt_ip ip;
125
126         /* Mark with fields that we care about. */
127         unsigned int nfcache;
128下面两个字段用来计算target的位置和下一条规则的位置。
129         /* Size of ipt_entry + matches */
130         u_int16_t target_offset;
131         /* Size of ipt_entry + matches + target */
132         u_int16_t next_offset;
133
这个字段的存在,为发现规则中存在”环路“提供手段。
134         /* Back pointer */
135         unsigned int comefrom;
136
137         /* Packet and byte counters. */
138         struct ipt_counters counters;
139
140         /* The matches (if any), then the target. */
141         unsigned char elems[0];
142 };
143
144 /*
145  * New IP firewall options for [gs]etsockopt at the RAW IP level.
146  * Unlike BSD Linux inherits IP options so you don't have to use a raw
147  * socket for this. Instead we check rights in the calls. */
定义提供给set/getsockopt系统调用的命令常数的基常数。
148 #define IPT_BASE_CTL            64      /* base for firewall socket options */
149
150 #define IPT_SO_SET_REPLACE      (IPT_BASE_CTL)
151 #define IPT_SO_SET_ADD_COUNTERS (IPT_BASE_CTL + 1)
152 #define IPT_SO_SET_MAX          IPT_SO_SET_ADD_COUNTERS
153
154 #define IPT_SO_GET_INFO         (IPT_BASE_CTL)
155 #define IPT_SO_GET_ENTRIES      (IPT_BASE_CTL + 1)
156 #define IPT_SO_GET_MAX          IPT_SO_GET_ENTRIES
157
158 /* CONTINUE verdict for targets */
159 #define IPT_CONTINUE 0xFFFFFFFF
160
161 /* For standard target */
162 #define IPT_RETURN (-NF_MAX_VERDICT - 1)
163
Tcp匹配规则信息。
164 /* TCP matching stuff */
165 struct ipt_tcp
166 {
167         u_int16_t spts[2];                      /* Source port range. */
168         u_int16_t dpts[2];                      /* Destination port range. */
169         u_int8_t option;                        /* TCP Option iff non-zero*/
170         u_int8_t flg_mask;                      /* TCP flags mask byte */
171         u_int8_t flg_cmp;                       /* TCP flags compare byte */
172         u_int8_t invflags;                      /* Inverse flags */
173 };
174
tcp的取反标志值。
175 /* Values for "inv" field in struct ipt_tcp. */
176 #define IPT_TCP_INV_SRCPT       0x01    /* Invert the sense of source ports. */
177 #define IPT_TCP_INV_DSTPT       0x02    /* Invert the sense of dest ports. */
178 #define IPT_TCP_INV_FLAGS       0x04    /* Invert the sense of TCP flags. */
179 #define IPT_TCP_INV_OPTION      0x08    /* Invert the sense of option test. */
180 #define IPT_TCP_INV_MASK        0x0F    /* All possible flags. */
181
udp匹配规则信息
182 /* UDP matching stuff */
183 struct ipt_udp
184 {
185         u_int16_t spts[2];                      /* Source port range. */
186         u_int16_t dpts[2];                      /* Destination port range. */
187         u_int8_t invflags;                      /* Inverse flags */
188 };
189
190 /* Values for "invflags" field in struct ipt_udp. */
191 #define IPT_UDP_INV_SRCPT       0x01    /* Invert the sense of source ports. */
192 #define IPT_UDP_INV_DSTPT       0x02    /* Invert the sense of dest ports. */
193 #define IPT_UDP_INV_MASK        0x03    /* All possible flags. */
194
195 /* ICMP matching stuff */
ICMP匹配规则信息
196 struct ipt_icmp
197 {
198         u_int8_t type;                          /* type to match */
199         u_int8_t code[2];                       /* range of code */
200         u_int8_t invflags;                      /* Inverse flags */
201 };
202
203 /* Values for "inv" field for struct ipt_icmp. */
204 #define IPT_ICMP_INV    0x01    /* Invert the sense of type/code test */
205
这个结构实质上用户通过getsockopt系统调用获取table信息时所传递参数的类型。
206 /* The argument to IPT_SO_GET_INFO */
207 struct ipt_getinfo
208 {
209         /* Which table: caller fills this in. */
210         char name[IPT_TABLE_MAXNAMELEN];
211
212         /* Kernel fills these in. */
213         /* Which hook entry points are valid: bitmask */
214         unsigned int valid_hooks;
215
216         /* Hook entry points: one per netfilter hook. */
217         unsigned int hook_entry[NF_IP_NUMHOOKS];
218
219         /* Underflow points. */
220         unsigned int underflow[NF_IP_NUMHOOKS];
221
222         /* Number of entries */
223         unsigned int num_entries;
224
225         /* Size of entries. */
226         unsigned int size;
227 };
228
这个结构是用户通过系统调用更换table是所传递的参数类型。
229 /* The argument to IPT_SO_SET_REPLACE. */
230 struct ipt_replace
231 {
232         /* Which table. */
233         char name[IPT_TABLE_MAXNAMELEN];
234
235         /* Which hook entry points are valid: bitmask.  You can't
236            change this. */
237         unsigned int valid_hooks;
238
239         /* Number of entries */
240         unsigned int num_entries;
241
242         /* Total size of new entries */
243         unsigned int size;
244
245         /* Hook entry points. */
246         unsigned int hook_entry[NF_IP_NUMHOOKS];
247
248         /* Underflow points. */
249         unsigned int underflow[NF_IP_NUMHOOKS];
250
251         /* Information about old entries: */
252         /* Number of counters (must be equal to current number of entries). */
253         unsigned int num_counters;
254         /* The old entries' counters. */
255         struct ipt_counters *counters;
256
257         /* The entries (hang off end: not really an array). */
258         struct ipt_entry entries[0];
259 };
260
这个更改计数器时传递的参数类型。
261 /* The argument to IPT_SO_ADD_COUNTERS. */
262 struct ipt_counters_info
263 {
264         /* Which table. */
265         char name[IPT_TABLE_MAXNAMELEN];
266
267         unsigned int num_counters;
268
269         /* The counters (actually `number' of these). */
270         struct ipt_counters counters[0];
271 };
272
这个是想获取防火墙规则时,传递给系统调用的参数类型。
273 /* The argument to IPT_SO_GET_ENTRIES. */
274 struct ipt_get_entries
275 {
276         /* Which table: user fills this in. */
277         char name[IPT_TABLE_MAXNAMELEN];
278
279         /* User fills this in: total entry size. */
280         unsigned int size;
281
282         /* The entries. */
283         struct ipt_entry entrytable[0];
284 };
285
286 /* Standard return verdict, or do jump. */
287 #define IPT_STANDARD_TARGET ""
288 /* Error verdict. */
289 #define IPT_ERROR_TARGET "ERROR"
290
现面定义了一些使用例程
291 /* Helper functions */
获取一条防火墙规则的target位置
292 extern __inline__ struct ipt_entry_target *
293 ipt_get_target(struct ipt_entry *e)
294 {
295         return (void *)e + e->target_offset;
296 }
297
下面的宏遍历处理一条防火墙规则的所有匹配。我已经说过每一条防火墙规则在iptables中分为三部分,而且每一部分的大小都是可变的。比如match部分,它本身可以有多个match项。
298 /* fn returns 0 to continue iteration */
299 #define IPT_MATCH_ITERATE(e, fn, args...)       \
300 ({                                              \
301         unsigned int __i;                       \
302         int __ret = 0;                          \
303         struct ipt_entry_match *__m;            \

这个for语句我来解释一下:首先__i取值为ipt_entry结构的大小,实质上就是match匹配的开始处的偏移地址,将其与e相加就得到了match匹配的地址,然后调用fn处理这个匹配。如果函数返回值为零,当前匹配的偏移地址加上当前匹配的大小,如果不超过target的偏移地址,则继续处理下一条匹配。
304                                                 \
305         for (__i = sizeof(struct ipt_entry);    \
306              __i target_offset;          \
307              __i += __m->u.match_size) {        \
308                 __m = (void *)(e) + __i;        \
309                                                 \
310                 __ret = fn(__m , ## args);      \
311                 if (__ret != 0)                 \
312                         break;                  \
313         }                                       \
314         __ret;                                  \
315 })
316
这个宏处理一个table中的所有防火墙规则。对比对上一个宏的理解,这里我就不解释了。
317 /* fn returns 0 to continue iteration */
318 #define IPT_ENTRY_ITERATE(entries, size, fn, args...)           \
319 ({                                                              \
320         unsigned int __i;                                       \
321         int __ret = 0;                                          \
322         struct ipt_entry *__e;                                  \
323                                                                 \
324         for (__i = 0; __i next_offset) {  \
325                 __e = (void *)(entries) + __i;                  \
326                                                                 \
327                 __ret = fn(__e , ## args);                      \
328                 if (__ret != 0)                                 \
329                         break;                                  \
330         }                                                       \
331         __ret;                                                  \
332 })
333
334 /*
335  *      Main firewall chains definitions and global var's definitions.
336  */
337 #ifdef __KERNEL__
338
339 #include ·
340 extern void ipt_init(void) __init;
341
所有的匹配处理都注册到一个match处理链表中,链表结点的类型就是这里的结构类型。当处理匹配时都是调用这里注册的处理函数。每个结点实质上由三个函数构成,一个匹配处理函数,一个合法性检查函数,一个析构函数。最后一个是反身指针,指针的作用如注释所示。
342 struct ipt_match
343 {
344         struct list_head list;
345
346         const char name[IPT_FUNCTION_MAXNAMELEN];
347
348         /* Return true or false: return FALSE and set *hotdrop = 1 to
349            force immediate packet drop. */
350         int (*match)(const struct sk_buff *skb,
351                      const struct net_device *in,
352                      const struct net_device *out,
353                      const void *matchinfo,
354                      int offset,
355                      const void *hdr,
356                      u_int16_t datalen,
357                      int *hotdrop);
358
359         /* Called when user tries to insert an entry of this type. */
360         /* Should return true or false. */
361         int (*checkentry)(const char *tablename,
362                           const struct ipt_ip *ip,
363                           void *matchinfo,
364                           unsigned int matchinfosize,
365                           unsigned int hook_mask);
366
367         /* Called when entry of this type deleted. */
368         void (*destroy)(void *matchinfo, unsigned int matchinfosize);
369
370         /* Set this to THIS_MODULE if you are a module, otherwise NULL */
371         struct module *me;
372 };
373
和match一样,所有的target都注册到这个结构类型的全局链表中,每个target的处理函数都是这里注册的函数。和上面的解释一样,这里也主要包含三个函数指针。
374 /* Registration hooks for targets. */
375 struct ipt_target
376 {
377         struct list_head list;
378
379         const char name[IPT_FUNCTION_MAXNAMELEN];
380
381         /* Returns verdict. */
382         unsigned int (*target)(struct sk_buff **pskb,
383                                unsigned int hooknum,
384                                const struct net_device *in,
385                                const struct net_device *out,
386                                const void *targinfo,
387                                void *userdata);
388
389         /* Called when user tries to insert an entry of this type:
390            hook_mask is a bitmask of hooks from which it can be
391            called. */
392         /* Should return true or false. */
393         int (*checkentry)(const char *tablename,
394                           const struct ipt_entry *e,
395                           void *targinfo,
396                           unsigned int targinfosize,
397                           unsigned int hook_mask);
398
399         /* Called when entry of this type deleted. */
400         void (*destroy)(void *targinfo, unsigned int targinfosize);
401
402         /* Set this to THIS_MODULE if you are a module, otherwise NULL */
403         struct module *me;
404 };
405
注册函数
406 extern int ipt_register_target(struct ipt_target *target);
407 extern void ipt_unregister_target(struct ipt_target *target);
408
409 extern int ipt_register_match(struct ipt_match *match);
410 extern void ipt_unregister_match(struct ipt_match *match);
411
table结构
412 /* Furniture shopping... */
413 struct ipt_table
414 {
415         struct list_head list;
416
417         /* A unique name... */
418         char name[IPT_TABLE_MAXNAMELEN];
419
420         /* Seed table: copied in register_table */
421         struct ipt_replace *table;
422
423         /* What hooks you will enter on */
424         unsigned int valid_hooks;
425
426         /* Lock for the curtain */
427         rwlock_t lock;
428
429         /* Man behind the curtain... */
430         struct ipt_table_info *private;
431 };
432
小结iptables的防火墙组织结构:

现在我们可以给出iptables防火墙规则的组织结构了。第一级是table级,每一个防火墙可以有多个table;第二级是hook级,每一个table都有一个hook集合,每个hook都有一个防火墙规则链;第三级基本规则级,基本规则级的规则包括三部分,IP规则信息、匹配规则信息和target。而这三个组成部分的每一个都可以包括同类型的多个部分规则。
433 extern int ipt_register_table(struct ipt_table *table);
434 extern void ipt_unregister_table(struct ipt_table *table);
435 extern unsigned int ipt_do_table(struct sk_buff **pskb,
436                                  unsigned int hook,
437                                  const struct net_device *in,
438                                  const struct net_device *out,
439                                  struct ipt_table *table,
440                                  void *userdata);
441
有关table结构对齐的宏。

442 #define IPT_ALIGN(s) (((s) + (__alignof__(struct ipt_entry)-1))  ~(__alignof__(struct ipt_entry)-1))
443 #endif /*__KERNEL__*/
444 #endif /* _IPTABLES_H */
445


西安交通大学  王灏

[目录]


防火墙技术分析讲义

防火墙技术分析讲义
                                        [email protected]

一 基本概念

1.1 防火墙分类:
        包过滤
        代理(应用层网关)

1.2 代理:

        两个连接(browser与proxy之间,proxy与web server之间)。
        工作在应用层。

        直接发往服务器的包:
        GET / HTTP/1.1
        Accept:        */*
        Accept-Language: zh-cn
        Accept-Encoding: gzip, deflate
        User-Agent: Mozilla/4.0 (compatible; MSIE 5.01; Windows NT 5.0)
        Host: www.lisoleg.net
        Connection: Keep-Alive

        往代理发出的包:
        GET http://www.lisoleg.net/ HTTP/1.1
        Accept: image/gif, image/x-xbitmap, image/jpeg, image/pjpeg, application/vnd.ms-powerpoint, application/msword, */*
        Accept-Language: zh-cn
        Accept-Encoding: gzip, deflate
        If-Modified-Since: Thu, 14 Dec 2000 07:24:52 GMT
        If-None-Match: "8026-185-3a3875c4"
        User-Agent: Mozilla/4.0 (compatible; MSIE 5.01; Windows NT 5.0)
        Host: www.lisoleg.net
        Proxy-Connection: Keep-Alive

        增强:
        cache

1.3 包过滤
        单IP包检测
        缺陷:无状态

1.4 增强1-状态检测(Stateful Inspection),又称动态包过滤(dynamic packet filtering)
        1.4.1 规则表和动态状态表

        1.4.2 ftp的例子:
        A 4847->B 21 PORT 192,168,7,60,18,241
        B 21->A 4847 PORT command successful.

        B 20->A 4849 syn
        > A classic example is transferring files using FTP. The firewall remembers the details of the
        > incoming request to get a file from an FTP server. The firewall then tracks the back-channel
        > request (the FTP Port command) by the server for transferring information back to the client.
        > As long as the information agrees (same IP addresses, no changes in port numbers, and no
        > non-FTP requests), the firewall allows the traffic. After the transfer is complete, the
        > firewall closes the ports involved.

        1.4.3 两种实现方法:
        1.4.3.1 checkpoint FW1,netfilter
        1.4.3.2 动态添加规则(ipchains patch)
        > I believe it does exactly what I want: Installing a temporary
               > "backward"-rule to let packets in as a response to an
               > outgoing request.


1.5 增强2-地址转换:
        1.5.1 静态NAT
        1.5.2 动态NAT
        1.5.3 地址伪装


1.6 增强3-VPN:
        位置的优越性

二 Linux下防火墙的实现之一(2.2内核):

2.1 截获位置:
        网络层

                  ----------------------------------------------------------------
                  |            ACCEPT/                              lo interface |
                  v           REDIRECT                  _______                  |
          --> C --> S --> ______ --> D --> ~~~~~~~~ -->|forward|----> _______ -->
              h     a    |input |    e    {Routing }   |Chain  |     |output |ACCEPT
              e     n    |Chain |    m    {Decision}   |_______| --->|Chain  |
              c     i    |______|    a     ~~~~~~~~        |     | ->|_______|
              k     t       |        s       |             |     | |     |
              s     y       |        q       |             v     | |     |
              u     |       v        e       v            DENY/  | |     v
              m     |     DENY/      r   Local Process   REJECT  | |   DENY/
              |     v    REJECT      a       |                   | |  REJECT
              |   DENY               d       --------------------- |
              v                      e -----------------------------
             DENY


2.2 提炼出的代码:

输入检测:
        /*
        *         Main IP Receive routine.
        */
        int ip_rcv(struct sk_buff *skb, struct device *dev, struct packet_type *pt)
        {
        #ifdef        CONFIG_FIREWALL
                int fwres;
                u16 rport;
        #endif /* CONFIG_FIREWALL */

        ......

        #ifdef CONFIG_FIREWALL
                /*
                *        See if the firewall wants to dispose of the packet.
                *
                * We can't do ICMP reply or local delivery before routing,
                * so we delay those decisions until after route. --RR
                */
                fwres = call_in_firewall(PF_INET, dev, iph, &rport, &skb);
                if (fwres < FW_ACCEPT && fwres != FW_REJECT)
                        goto drop;
                iph = skb->nh.iph;
        #endif /* CONFIG_FIREWALL */

        ......

        #ifdef CONFIG_FIREWALL
                if (fwres == FW_REJECT) {
                        icmp_send(skb, ICMP_DEST_UNREACH, ICMP_PORT_UNREACH, 0);
                        goto drop;
                }
        #endif /* CONFIG_FIREWALL */

                return skb->dst->input(skb); //根据路由查找的结果决定是转发(ip_forward)还是发往上层(ip_local_deliver)
        drop:
                kfree_skb(skb);        //如果规则匹配的结果是FW_REJECT,FW_BLOCK,丢弃此包
                return(0);

        }

转发检测:
        int ip_forward(struct sk_buff *skb)
        {
        ...
        #ifdef CONFIG_FIREWALL
                        fw_res=call_fw_firewall(PF_INET, dev2, iph, NULL, &skb);
                        switch (fw_res) {
                        case FW_ACCEPT:
                        case FW_MASQUERADE:
                                break;
                        case FW_REJECT:
                                icmp_send(skb, ICMP_DEST_UNREACH, ICMP_HOST_UNREACH, 0);
                                /* fall thru */
                        default:
                                kfree_skb(skb);
                                return -1;
                        }
        #endif
        ...
        }

输出检测:(不同的上层协议走不同的流程,因此检测点较多)
        UDP/RAW/ICMP报文:ip_build_xmit
        TCP报文:ip_queue_xmit
        转发的包:ip_forward
        其他:ip_build_and_send_pkt


实际的匹配:
        /*
        *        Returns one of the generic firewall policies, like FW_ACCEPT.
        *
        *        The testing is either false for normal firewall mode or true for
        *        user checking mode (counters are not updated, TOS & mark not done).
        */
        static int
        ip_fw_check(struct iphdr *ip,                 //IP头位置
                    const char *rif,                //出口网卡的名字
                    __u16 *redirport,                //端口转发时用到
                    struct ip_chain *chain,        //规则链的名字
                    struct sk_buff *skb,        //要检测的数据包
                    unsigned int slot,
                    int testing)                //见函数本身的注释

调用举例:
        call_in_firewall实际调用ipfw_input_check,而ipfw_input_check中有:
        int ipfw_input_check(struct firewall_ops *this, int pf, struct device *dev,
                             void *phdr, void *arg, struct sk_buff **pskb)
        {
                return ip_fw_check(phdr, dev->name,
                                   arg, IP_FW_INPUT_CHAIN, *pskb, SLOT_NUMBER(), 0);
        }

实际流程:

        ip_fw_check
        {
                从传入的skb参数中提取源地址src,目的地址dst,源端口src_port,目的端口dst_port,
                TCP发起连接标志tcpsyn,分片包位移offset,IP包TOS消息oldtos;

                ......

                f = chain->chain;        //取出规则链的的一条规则,规则链由chain参数传入
                count = 0;
                do {
                        for (; f; f = f->next) {        //遍历规则链中的规则,直到匹配(ip_rule_match返回1)
                                count++;
                                if (ip_rule_match(f,rif,ip,
                                                  tcpsyn,src_port,dst_port,offset)) {
                                        if (!testing
                                            && !ip_fw_domatch(f, ip, rif, chain->label,//作些标记,一般返回1
                                                              skb, slot,
                                                              src_port, dst_port,
                                                              count, tcpsyn)) {
                                                ret = FW_BLOCK;
                                                goto out;
                                        }
                                        break;
                                }
                        }
                        if(f) { //找到匹配规则

                                ......

                        }else { //这次遍历根本没找到
                                是从别的地方跳转过来的,则转回去,然后继续遍历;
                                否则应用这条链的缺省规则;
                        }

                } while (ret == FW_SKIP+2);
        out:

                ......

                return ret;
        }


碎片:
        根据第一个片的消息进行过滤,其他分片则允许通过。如果规则是丢弃的话,虽然后面的分片都可到达主机,
        但由于第一片被滤掉了,无法重组成功,因此从效果上也相当于整个IP包被丢弃。

        存在的漏洞等.

2.3 规则:

        from 192.168.7.0/24 to 192.168.6.32/32 tcp 80 BLOCK

规则的数据结构表示:


        规则链
        struct ip_chain
        {
                ip_chainlabel label;            /* Defines the label for each block */
                struct ip_chain *next;            /* Pointer to next block */
                struct ip_fwkernel *chain;  /* Pointer to first rule in block */
                __u32 refcount;             /* Number of refernces to block */
                int policy;                    /* Default rule for chain.  Only *
                                             * used in built in chains */
                struct ip_reent reent[0];   /* Actually several of these */
        };

        规则
        struct ip_fwkernel
        {
                struct ip_fw ipfw;
                struct ip_fwkernel *next;        /* where to go next if current
                                                * rule doesn't match */
                struct ip_chain *branch;        /* which branch to jump to if
                                                * current rule matches */
                int simplebranch;                /* Use this if branch == NULL */
                struct ip_counters counters[0]; /* Actually several of these */
        };

        待匹配的数据包消息
        struct ip_fw
        {
                struct in_addr fw_src, fw_dst;                /* Source and destination IP addr */
                struct in_addr fw_smsk, fw_dmsk;        /* Mask for src and dest IP addr */
                __u32 fw_mark;                          /* ID to stamp on packet */
                __u16 fw_proto;                         /* Protocol, 0 = ANY */
                __u16 fw_flg;                                /* Flags word */
                __u16 fw_invflg;                        /* Inverse flags */
                __u16 fw_spts[2];                       /* Source port range. */
                __u16 fw_dpts[2];                       /* Destination port range. */
                __u16 fw_redirpt;                       /* Port to redirect to. */
                __u16 fw_outputsize;                    /* Max amount to output to
                                                           NETLINK */
                char           fw_vianame[IFNAMSIZ];        /* name of interface "via" */
                __u8           fw_tosand, fw_tosxor;        /* Revised packet priority */
        };


2.4 地址转换
        ip_fw_demasquerade
        ip_fw_masquerade


三 Linux下防火墙的实现之二(2.4内核):
3.1
        A Packet Traversing the Netfilter System:

        --->PRE------>[ROUTE]--->FWD---------->POST------>
               Conntrack    |       Filter   ^    NAT (Src)
               Mangle       |                |    Conntrack
               NAT (Dst)    |             [ROUTE]
               (QDisc)      v                |
                            IN Filter       OUT Conntrack
                            |  Conntrack     ^  Mangle
                            |                |  NAT (Dst)
                            v                |  Filter


3.2 例子

## Insert connection-tracking modules (not needed if built into kernel).
# insmod ip_conntrack
# insmod ip_conntrack_ftp

## Create chain which blocks new connections, except if coming from inside.
# iptables -N block
# iptables -A block -m state --state ESTABLISHED,RELATED -j ACCEPT
# iptables -A block -m state --state NEW -i ! ppp0 -j ACCEPT
# iptables -A block -j DROP

## Jump to that chain from INPUT and FORWARD chains.
# iptables -A INPUT -j block
# iptables -A FORWARD -j block

3.3 规则的描述
        一条规则分为三部分:
        struct ipt_entry        //主要用来匹配IP头
        struct ip_match        //额外的匹配(tcp头,mac地址等)
        struct ip_target        //除缺省的动作外(如ACCEPT,DROP),可以增加新的(如REJECT)。

3.4 代码提炼

ip_input.c:
        /*
        *         Main IP Receive routine.
        */
        int ip_rcv(struct sk_buff *skb, struct net_device *dev, struct packet_type *pt)
        {
        ...
        return NF_HOOK(PF_INET, NF_IP_PRE_ROUTING, skb, dev, NULL,
                               ip_rcv_finish);
        ...
        }

netfilter.h:
        #ifdef CONFIG_NETFILTER
        #define NF_HOOK(pf, hook, skb, indev, outdev, okfn)                        \
        (list_empty(&nf_hooks[(pf)][(hook)])                                        \
        ? (okfn)(skb)                                                                \
        : nf_hook_slow((pf), (hook), (skb), (indev), (outdev), (okfn)))
        #else /* !CONFIG_NETFILTER */
        #define NF_HOOK(pf, hook, skb, indev, outdev, okfn) (okfn)(skb)
        #endif /*CONFIG_NETFILTER*/

大的框架:"HOOK表":
        struct list_head nf_hooks[NPROTO][NF_MAX_HOOKS];        //netfilter.c
        通过nf_register_hook和nf_unregister_hook完成添加删除工作,nf_iterate负责执行hook上的函数。

        增加用户自定义的HOOK,参见【8】,【10】:

重要流程(建议结合netfilter hacking howto 4.1.3来看):
/* Returns one of the generic firewall policies, like NF_ACCEPT. */
unsigned int
ipt_do_table(struct sk_buff **pskb,
             unsigned int hook,
             const struct net_device *in,
             const struct net_device *out,
             struct ipt_table *table,
             void *userdata)
{
        struct ipt_entry *e;
        struct ipt_entry_target *t;
        unsigned int verdict = NF_DROP;

        table_base = (void *)table->private->entries
                + TABLE_OFFSET(table->private,
                               cpu_number_map(smp_processor_id()));
        e = get_entry(table_base, table->private->hook_entry[hook]);

        ...
        ip_packet_match(ip, indev, outdev, &e->ip, offset);

        ...
        IPT_MATCH_ITERATE(e, do_match, *pskb, in, out, offset, protohdr, datalen, &hotdrop)

        ...
        t = ipt_get_target(e);

        ...
        verdict = t->u.kernel.target->target(pskb, hook, in, out, t->data, userdata);//非标准的target走这一步

        ...
        return verdict;
}

要加强对这段话的理解(netfilter hacking howto 4.1节) :
>iptables does not register with any netfilter hooks: it relies on
>other modules to do that and feed it the packets as appropriate; a
>module must register the netfilter hooks and ip_tables separately, and
>provide the mechanism to call ip_tables when the hook is reached.

四 Linux下防火墙的实现之三(checkpoint FW1)

让我们看看checkpoint的在linux上的防火墙是如何实现的,最终我们会发现,竟然和lkm使用的手段差不多:)

fw1通过dev_add_pack的办法加载输入过滤函数,但是在net_bh()中,传往网络层的skbuff是克隆的,即
skb2=skb_clone(skb, GFP_ATOMIC);
if(skb2)
        pt_prev->func(skb2, skb->dev, pt_prev);
而fw1是怎么解决这个问题的呢?见下面的代码:

输入一:

        ; 哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪?
                        align 4

        ; 圹圹圹圹圹圹圹?S U B        R O U T        I N E 圹圹圹圹圹圹圹圹圹圹圹圹圹圹圹圹圹圹圹?

        ; Attributes: bp-based frame

                        public fwinstallin
        fwinstallin        proc near                ; CODE XREF: fwinstall+E9p
                                                ; fwinstall+149p

        var_18                = byte ptr -18h
        arg_0                = dword        ptr  8

                        push        ebp
                        mov        ebp, esp
                        sub        esp, 10h
                        push        esi
                        push        ebx
                        mov        esi, ds:dev_base
                        cmp        [ebp+arg_0], 0
                        jz        short loc_0_802CBD0
                        add        esp, 0FFFFFFF4h
                        push        offset fw_ip_packet_type
                        call        dev_add_pack
                        mov        ebx, fw_ip_packet_type+10h        ;如果考虑字节对齐问题的话fw_ip_packet_type+10h这时应该是ip_packet_type
                        mov        dword ptr ds:fw_type_list, ebx
                        jmp        short loc_0_802CB9C
        ; 哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪?
                        align 4

        loc_0_802CB90:                                ; CODE XREF: fwinstallin+41j
                        add        esp, 0FFFFFFF4h
                        push        ebx
                        call        dev_remove_pack                ;fw1把ip_packet_type歇载掉了,然后自己在自己的处理函数(fw_filterin)中调ip_recv
                        mov        ebx, [ebx+10h]

        loc_0_802CB9C:                                ; CODE XREF: fwinstallin+2Dj
                        add        esp, 10h
                        test        ebx, ebx
                        jnz        short loc_0_802CB90
                        test        esi, esi
                        jz        short loc_0_802CC14

        loc_0_802CBA7:                                ; CODE XREF: fwinstallin+68j
                        test        byte ptr fwdebug, 81h
                        jz        short loc_0_802CBC3
                        add        esp, 0FFFFFFF8h
                        mov        eax, [esi]
                        push        eax
                        push        offset aFwinstallinS ; "fwinstallin: %s\n"
                        call        fwkdebug_printf
                        add        esp, 10h

        loc_0_802CBC3:                                ; CODE XREF: fwinstallin+4Ej
                        mov        esi, [esi+28h]
                        test        esi, esi
                        jnz        short loc_0_802CBA7
                        jmp        short loc_0_802CC14
        ; 哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪?
                        align 8

        loc_0_802CBD0:                                ; CODE XREF: fwinstallin+12j
                        cmp        dword ptr ds:fw_type_list, 0
                        jz        short loc_0_802CC14
                        add        esp, 0FFFFFFF4h
                        push        offset fw_ip_packet_type
                        call        dev_remove_pack
                        add        esp, 10h
                        cmp        dword ptr ds:fw_type_list, 0
                        jz        short loc_0_802CC14

        loc_0_802CBF2:                                ; CODE XREF: fwinstallin+B2j
                        add        esp, 0FFFFFFF4h
                        mov        eax, dword ptr ds:fw_type_list
                        push        eax
                        call        dev_add_pack
                        mov        eax, dword ptr ds:fw_type_list
                        add        esp, 10h
                        mov        eax, [eax+10h]
                        mov        dword ptr ds:fw_type_list, eax
                        test        eax, eax
                        jnz        short loc_0_802CBF2

        loc_0_802CC14:                                ; CODE XREF: fwinstallin+45j
                                                ; fwinstallin+6Aj ...
                        lea        esp, [ebp+var_18]
                        xor        eax, eax
                        pop        ebx
                        pop        esi
                        mov        esp, ebp
                        pop        ebp
                        retn
        fwinstallin        endp

输入二:
        public fw_ip_packet_type
        fw_ip_packet_type dd 8,        0, offset fw_filterin, 2 dup(0)        ; DATA XREF: fwinstallin+17o


输出的挂载和lkm的手法一样,更改dev->hard_start_xmit。dev结构在2.2版本的发展过程中变了一次,
为了兼容fw1对这点也做了处理。


输出一:
        ; 哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪?
                        align 4

        ; 圹圹圹圹圹圹圹?S U B        R O U T        I N E 圹圹圹圹圹圹圹圹圹圹圹圹圹圹圹圹圹圹圹?

        ; Attributes: bp-based frame

                        public fwinstallout
        fwinstallout        proc near                ; CODE XREF: fwinstall+FBp
                                                ; fwinstall+153p

        var_18                = byte ptr -18h
        arg_0                = dword        ptr  8

                        push        ebp
                        mov        ebp, esp
                        sub        esp, 0Ch
                        push        edi
                        push        esi
                        push        ebx
                        mov        edi, [ebp+arg_0]
                        xor        esi, esi
                        mov        ebx, ds:dev_base
                        jmp        short loc_0_802D0A8
        ; 哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪?

        loc_0_802D096:                                ; CODE XREF: fwinstallout+50j
                        add        esp, 0FFFFFFFCh
                        push        edi
                        push        esi
                        push        ebx
                        call        installout_on_device
                        add        esp, 10h
                        mov        ebx, [ebx+28h]
                        inc        esi

        loc_0_802D0A8:                                ; CODE XREF: fwinstallout+14j
                        test        ebx, ebx
                        jz        short loc_0_802D0F8
                        test        byte ptr fwdebug, 81h
                        jz        short loc_0_802D0CD
                        xor        eax, eax
                        mov        ax, [ebx+50h]
                        push        eax
                        mov        eax, [ebx]
                        push        eax
                        push        esi
                        push        offset aFwinstalloutIn ; "fwinstallout:        interface %d: name=%s, fl"...
                        call        fwkdebug_printf
                        add        esp, 10h

        loc_0_802D0CD:                                ; CODE XREF: fwinstallout+33j
                        cmp        esi, 3Fh
                        jle        short loc_0_802D096
                        add        esp, 0FFFFFFF8h
                        push        40h
                        push        offset aFw1CanOnlyHand ; "FW-1:        Can only handle        %d interfaces\n"
                        call        fwkdebug_printf
                        add        esp, 10h
                        test        edi, edi
                        jz        short loc_0_802D0F8
                        add        esp, 0FFFFFFF4h
                        push        offset aFw1NotAllInter ; "FW-1:        Not all        interfaces installed\n"
                        call        fwkdebug_printf
                        add        esp, 10h

        loc_0_802D0F8:                                ; CODE XREF: fwinstallout+2Aj
                                                ; fwinstallout+66j
                        mov        fw_nif,        esi
                        test        byte ptr fwdebug, 81h
                        jz        short loc_0_802D124
                        add        esp, 0FFFFFFFCh
                        mov        eax, offset aUn        ; "un"
                        test        edi, edi
                        jz        short loc_0_802D118
                        mov        eax, offset unk_0_80687E4

        loc_0_802D118:                                ; CODE XREF: fwinstallout+91j
                        push        eax
                        push        esi
                        push        offset aFw1DInterfaces ; "FW-1:        %d interfaces %sinstalled\n"
                        call        fwkdebug_printf

        loc_0_802D124:                                ; CODE XREF: fwinstallout+85j
                        lea        esp, [ebp+var_18]
                        xor        eax, eax
                        pop        ebx
                        pop        esi
                        pop        edi
                        mov        esp, ebp
                        pop        ebp
                        retn
        fwinstallout        endp

输出二:

        ; 哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪?
                        align 10h

        ; 圹圹圹圹圹圹圹?S U B        R O U T        I N E 圹圹圹圹圹圹圹圹圹圹圹圹圹圹圹圹圹圹圹?

        ; Attributes: bp-based frame

                        public installout_on_device
        installout_on_device proc near                ; CODE XREF: fwinstallout+1Cp

        var_18                = byte ptr -18h
        var_4                = dword        ptr -4
        arg_0                = dword        ptr  8
        arg_4                = dword        ptr  0Ch
        arg_8                = dword        ptr  10h

                        push        ebp
                        mov        ebp, esp
                        sub        esp, 0Ch
                        push        edi
                        push        esi
                        push        ebx
                        mov        edi, [ebp+arg_0]
                        mov        esi, [ebp+arg_4]
                        mov        ebx, [ebp+arg_8]
                        add        esp, 0FFFFFFF4h
                        push        edi
                        call        xmit_func_addr
                        mov        [ebp+var_4], eax
                        add        esp, 10h
                        test        ebx, ebx
                        jz        short loc_0_802CFD4
                        mov        ebx, esi
                        shl        ebx, 4
                        cmp        (oftab+4)[ebx],        0
                        jz        short loc_0_802CF90
                        add        esp, 0FFFFFFF4h
                        push        offset aFw1OutputFilte ; "FW-1:        Output filter already installed\n"
                        call        fwkdebug_printf
                        mov        eax, 6Ah
                        jmp        loc_0_802D074

输出三:

        ; 哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪?
                        align 8

        ; 圹圹圹圹圹圹圹?S U B        R O U T        I N E 圹圹圹圹圹圹圹圹圹圹圹圹圹圹圹圹圹圹圹?

        ; Attributes: bp-based frame

                        public xmit_func_addr
        xmit_func_addr        proc near                ; CODE XREF: installout_on_device+16p

        arg_0                = dword        ptr  8

                        push        ebp
                        mov        ebp, esp
                        mov        edx, [ebp+arg_0]
                        lea        eax, [edx+0ACh]
                        cmp        kver, 0Dh
                        jle        short loc_0_802CB5B
                        lea        eax, [edx+0B0h]

        loc_0_802CB5B:                                ; CODE XREF: xmit_func_addr+13j
                        mov        esp, ebp
                        pop        ebp
                        retn
        xmit_func_addr        endp

FW1与linux的一些比较,可以参看参考文献【11】


五 参考文献
        【1】了解Check Point FW-1状态表
                http://magazine.nsfocus.com/detail.asp?id=538
        【2】A Stateful Inspection of FireWall-1
                http://www.dataprotect.com/bh2000/
        【3】Linux IPCHAINS-HOWTO
                http://www.linuxdoc.org
        【4】防火墙新生代:Stateful-inspection
                http://www.liuxuan.com/safe/anquan/html/firewall/04.htm
        【5】netfilter站点上的文档
                http://netfilter.kernelnotes.org
        【6】Application Gateways and Stateful Inspection:A Brief Note Comparing and Contrasting
                http://www.avolio.com/apgw+spf.html
        【7】Internet Firewalls:Frequently Asked Questions
                http://www.interhack.net/pubs/fwfaq
        【8】Writing a Module for netfilter
                http://www.linux-mag.com/2000-06/gear_01.html
        【9】ipchains的源代码分析
                http://www.lisoleg.net/lisoleg/network/ipchains.zip
        【10】内核防火墙netfilter入门
                http://magazine.nsfocus.com/detail.asp?id=637
        【11】Check Point Firewall-1 on Linux, Part Two
                http://www.securityfocus.com/frames/?focus=linux&content=/focus/linux/articles/checkpoint2.html

[目录]


编程安全

    Linux系统为程序员提供了许多系统调用和C程序库,这些系统调用可存取各种安全属性。有些是信息调用,返回文件属性,实际的和有效的UID、GID等信息。有些可改变文件属性。UID、GID等有些处理口令文件和小组文件,还有些完成加密和解密。

    以root权限运行的程序可以做很多事,很明显,系统安全不仅仅是系统管理员的责任,程序员也需要注意有关系统调用,标准C库子程序的安全,写出安全的C程序很重要。

    一般有两方面的安全问题,在写程序时必须考虑:

A>确保自己建立的任何临时文件不含有机密数据,如果有机密数据,设置临时文件仅对自己可读/写。确保建立临时文件的目录仅对自己可写。
B>确保自己要运行的任何命令(通过system()、popen()、execlp()、execvp()运行的命令)的确是自己要运行的命令,而不是其他什么命令,尤其是自己的程序为SUID或SGID许可时要小心。

    第一方面比较简单,在程序开始前调用umask(077)。若要使文件对其他人可读,可再调
chmod(),也可用下述语名建立一个“不可见”的临时文件。
creat("/tmp/xxx",0);
file=open("/tmp/xxx",O_RDWR);
unlink("/tmp/xxx");

    文件/tmp/xxx建立后,打开,然后断开链,但是分配给该文件的存储器并未删除,直到最终指向该文件的文件通道被关闭时才被删除。打开该文件的进程和它的任何子进程都可存取这个临时文件,而其他进程不能存取该文件,因为它在/tmp中的目录项已被unlink()删除。

    第二方面比较复杂而微妙,由于system()、popen()、execlp()、execvp()执行时,若不给出执行命令的全路径,就能“骗”用户的程序去执行不同的命令。因为系统子程序是根据PATH变量确定哪种顺序搜索哪些目录,以寻找指定的命令,这称为SUID陷井。最安全的办法是在调用system()前将有效UID改变成实际UID,另一种比较好的方法是以全路径名命令作为参数。execl()、execv()、execle()、execve()都要求全路径名作为参数。对付SUID陷井的另一方式是在程序中设置PATH,由于system()和popen()都启动外壳,故可使用外壳句法。如:system("PATH=/bin:/usr/bincd");这样允许用户运行系统命令而不必知道要执行的命令在哪个目录中,但这种方法不能用于execlp()和execvp()中,因为它们不能启动外壳执行调用序列传递的命令字符串。关于外壳解释传递给system()和popen()的命令行的方式,有两个其他的问题:.外壳使用IFS外壳变量中的字符,将命令行分解成单词(通常这个外壳变量中是空格、tab、换行),如IFS中是/,字符串/bin/ed被解释成单词bin,接下来是单词ed,从而引起命令行的曲解。

    再强调一次:在通过自己的程序运行另一个程序前,应将有效UID改为实际的UID,等另一个程序退出后,再将有效UID改回原来的有效UID。

[目录]


系统调用

[目录]


I/O

.creat()
建立一个新文件或重写一个暂存文件。需要两个参数:文件名和存取许可值(8进制方式)。如:creat(“/usr/pat/read_write”,0666)/*建立存取许可方式为0666的文件*/调用此子程序的进程必须要有建立的文件的所在目录的写和执行许可,置给creat()的许可方式变量将被umask()设置的文件建立屏蔽值所修改,新文件的所有者和小组由有效的UID和GID决定。返回值为新建文件的文件描述符。
.
fstat()
见后面的stat()。

.open()
在C程序内部打开文件。需要两个参数:文件路径名和打开方式(I、O、I&O)。如果调用此子程序的进程没有对于要打开的文件的正确存取许可(包括文件路径上所有目录分量的搜索许可),将会引起执行失败。如果此子程序被调用去打开不存在的文件,除非设置了O_CREAT标志,调用将不成功。此时,新文件的存取许可将作为第三个参数(可被用户的umask修改)。当文件被进程打开后再改变该文件或该文件所在目录的存取许可,不影响对该文件的I/O操作。

.read()
从已由open()打开并用作输入的文件中读信息。它并不关心该文件的存取许可。一旦文件作为输入打开,即可从该文件中读取信息。

.write()
输出信息到已由open()打开并用作输出的文件中。它同read()一样也不关心该文件的存取许可。

[目录]


进程控制

1.exec()族
包括execl()、execv()、execle()、execve()、execlp()和execvp(),可将一可执行模快拷贝到调用进程占有的存贮空间。正被调用进程执行的程序将不复存在,新程序取代其位置。这是Linux系统中一个程序被执行的唯一方式:用将执行的程序复盖原有的程序。
安全注意事项:
.实际的和有效的UID和GID传递给由exec()调入的不具有SUID和SGID许可的程序。
.如果由exec()调入的程序有SUID和SGID许可,则有效的UID和GID将设置给该程序的
所有者或小组。
.文件建立屏蔽值将传递给新程序。
.除设了对exec()关闭标志的文件外,所有打开的文件都传递给新程序。用fcntl()子
程序可设置对exec()的关闭标志。

2.fork()
用来建立新进程。其建立的子进程是与调用fork()的进程(父进程)完全相同的拷贝(除了进程号外)。
安全注意事项:
.子进程将继承父进程的实际和有效的UID和GID。
.子进程继承文件方式建立屏蔽值。
.所有打开的文件传给子进程。

3.signal()
允许进程处理可能发生的意外事件和中断。需要两个参数:信号编号和信号发生时要调用的子程序。信号编号定义在signal.h中。信号发生时要调用的子程序可由用户编写,也可用系统给的值,如:SIG_IGN则信号将被忽略,SIG_DFL则信号将按系统的缺省方式处理。如许多与安全有关的程序禁止终端发中断信息(BREAK和DELETE),以免自己被用户终端终止运行。有些信号使Linux系统的产生进程的核心转储(进程接收到信号时所占内存的内容,有时含有重要信息),此系统子程序可用于禁止核心转储。


[目录]


文件属性

1.access()
检测指定文件的存取能力是否符合指定的存取类型。需要两个参数:文件名和要检测的存
取类型(整数)。
存取类型定义如下:
0:检查文件是否存在。
1:检查是否可执行(搜索)。
2:检查是否可写。
3:检查是否可写和执行。
4:检查是否可读。
5:检查是否可读和执行。
6:检查是否可读可写可执行。
这些数字的意义和chmod命令中规定许可方式的数字意义相同。此子程序使用实际的UID
和GID检测文件的存取能力(一般有效的UID和GID用于检查文件存取能力)。
返回值:0:许可-1:不许可。

2.chmod()
将指定文件或目录的存取许可方式改成新的许可方式。
需要两个参数:文件名和新的存取许可方式。

3.chown()
同时改变指定文件的所有者和小组的UID和GID。(与chown命令不同。)
由于此子程序同时改变文件的所有者和小组,故必须取消所操作文件的SUID和SGID许可,
以防止用户建立SUID和SGID程序,然后运行chown()去获得别人的权限。

4.stat()
返回文件的状态(属性)。需要两个参数:文件路径名和一个结构指针,指向状态信息的
存放的位置。
结构定义如下:
st_mode:文件类型和存取许可方式。
st_ino:I节点号。
st_dev:文件所在设备的ID。
st_rdev:特别文件的ID。
st_nlink:文件链接数。
st_uid:文件所有者的UID。
st_gid:文件小组的GID。
st_size:按字节计数的文件大小。
st_atime:最后存取时间(读)。
st_mtime:最后修改时间(写)和最后状态的改变。
st_ctime:最后的状态修改时间。
返回值:0:成功1:失败。

5.umask()
将调用进程及其子进程的文件建立屏蔽值设置为指定的存取许可。
需要一个参数:新的文件建立屏值。


[目录]


UID和GID的处理

1)getuid()返回进程的实际UID。

2)getgid()返回进程的实际GID。

以上两个系统调用可用于确定是谁在运行进程。

3)geteuid()返回进程的有效UID。

4)getegid()返回进程的有效GID。

以上两个系统调用用于确定某程序是否在运行某用户而不是其他用户的SUID程序时很有用,可调用它们来检查确认本程序的确是以该用户的SUID许可在运行。

5)setuid():用于改变有效的UID。

对于一般用户,此子程序仅对要在有效和实际的UID之间变换的SUID程序才有用(从原有效UID变换为实际UID),以保护进程不受到安全危害。实际上该进程不再使用SUID方式运行。

6)setgid()用于改变有效的GID。


[目录]


标准C库

[目录]


I/O

1.fopen()
打开一个文件供读或写,安全方面的考虑同open()一样。

2.fread()、getc()、fgetc()、gets()、scanf()和fscanf()
从已由fopen()打开供读的文件中读取信息。它们并不关心文件的存取许可。这一点同
read()。

3.fwrite()、put()、fputc()、puts,fputs()、printf()、fprintf()
把信息写到已由fopen()打开供写的文件中。它们也不关心文件的存取许可。这一点同
write()。

4.getpass()
从终端上读取至多8个字符长的口令,不回显用户输入的字符。
需要一个参数:提示信息。该子程序将提示信息显示在终端上,禁止字符回显功能,从
/dev/tty读取口令,然后再恢复字符回显功能,返回刚敲入的口令的指针。

[目录]


/etc/passwd的处理

有一组子程序可对/etc/passwd文件进行方便地存取,可在入口项对文件读取、写入或更新
等等。
1.getpwuid()
从/etc/passwd文件中获取指定的UID的入口项。
2.getpwnam()
对于指定的登录名,在/etc/passwd文件检索入口项。以上两个子程序返回一个指向passwd
结构的指针,该结构定义在/usr/include/pwd.h中,定义如下:
structpasswd{
char*pw_name;/*登录名*/
char*pw_passwd;/*加密后的口令*/
uid_tpw_uid;/*UID*/
gid_tpw_gid;/*GID*/
char*pw_age;/*代理信息*/
char*pw_comment;/*注释*/
char*pw_gecos;
char*pw_dir;/*主目录*/
char*pw_shell;/*使用的外壳*/
};
3.getpwent()、setpwent()、endpwent()
对口令文件作后续处理。
首次调用getpwent(),打开/etc/passwd并返回指向文件中第一个入口项的指针,保持调用
之间文件的打开状态。再调用getpwent()可顺序地返回口令文件中的各入口项。调用
setpwent()把口令文件的指针重新置为文件的开始处。使用完口令文件后调用endpwent()
关闭口令文件。
4.putpwent()
修改或增加/etc/passwd文件中的入口项。
此子程序将入口项写到一个指定的文件中,一般是一个临时文件,直接写口令文件是很危
险的。最好在执行前做文件封锁,使两个程序不能同时写一个文件。算法如下:
.建立一个独立的临时文件,即/etc/passnnn,nnn是PID号。
建立新产生的临时文件和标准临时文件/etc/ptmp的链,若建链失败,则为有人正在使用
/etc/ptmp,等待,直到/etc/ptmp可用为止或退出。
.将/etc/passwd拷贝到/etc/ptmp,可对此文件做修改。
.将/etc/passwd移到备份文件/etc/opasswd。
.建立/etc/ptmp和/etc/passwd的链。
.断开/etc/passnnn与/etc/ptmp的链。
注意临时文件应建立在/etc目录,才能保证文件处于同一文件系统中,建链才能成功,
且临时文件不会不安全。此外,若新文件已存在,即便建链的是root用户,也将失败,
从而保证了一旦临时文件成功地建链后没有人能再插进来干扰。当然,使用临时文件
的程序应确保清除所有临时文件,正确地捕捉信号。

[目录]


/etc/group的处理

有一组类似于前面的子程序处理/etc/group的信息,使用时必须用include语句将/usr/include/grp.h文件加入到自己的程序中。该文件定义了group结构,将由getgrnam()、
getgrgid()、getgrent()返回group结构指针。
1.getgrnam()
在/etc/group文件中搜索指定的小组名,然后返回指向小组入口项的指针。
2.getgrgid()
类似于前一子程序,不同的是搜索指定的GID。
3.getgrent()
返回group文件中的下一个入口项。
4.setgrent()
将group文件的文件指针恢复到文件的起点。
5.endgrent()
用于完成工作后,关闭group文件。
6.getuid()
返回调用进程的实际UID。
7.getpruid()
以getuid()返回的实际UID为参数,确定与实际UID相应的登录名,或指定一个UID为参
8.getlogin()
返回在终端上登录的用户的指针。
系统依次检查STDIN、STDOUT、STDERR是否与终端相联,与终端相联的标准输入用于
确定终端名,终端名用于查找列于/etc/utmp文件中的用户,该文件由login维护,由who程序用
来确认用户。
9.cuserid()
首先调用getlogin(),若getlogin()返回NULL指针,再调用getpwuid(getuid())。
10.logname
列出登录进终端的用户名。
11. whoamI
显示出运行这条命令的用户的登录名。
12. id
显示实际的U I D和G I D(若有效的U I D和G I D和实际的不同时也显示有效的U I D和G I D)和
相应的登录名。


[目录]


加密子程序

1977年1月,NBS宣布一个用于美国联邦政府ADP系统的网络的标准加密法:数据加密标准即DES用于非机密应用方面。DES一次处理64BITS的块,56位的加密键。

1.setkey()和encrypt()
提供用户对DES的存取。
这两个子程序都取64bits长的字符数组,数组中的每个元素代表一个位,为0或1。
setkey()设置将按DES处理的加密键,忽略每第8位构成一个56位的加密键。
encrypt()然后加密或解密给定的64bits长的一块,加密或解密取决于该子程序的第二个变元,0:加密1:解密。

2.crypt()
是Linux系统中的口令加密程序,也被/usr/lib/makekey命令调用。
crypt()子程序与crypt命令无关,它与/usr/lib/makekey一样取8个字符长的关键词,2个salt字符。关键词送给setkey(),salt字符用于混合encrypt()中的DES算法,最终调用encrypt()重复25次,加密一个相同的字符串。返回加密后的字符串指针。


[目录]


运行shell

1.system()
运行/bin/sh执行其参数指定的命令,当指定命令完成时返回。
2.popen()
类似于system(),不同的是命令运行时,其标准输入或输出联到由popen()返回的文件指针。

二者都调用fork()、exec()、popen()还调用pipe(),完成各自的工作,因而fork()和exec()的安全方面的考虑开始起作用。


[目录]


[ 本文件由良友·收藏家自动生成 ]