安全 |
所有用户都可以用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列出了需要额外的拨号口令的终端设备全称路径名。
该文件应该是root属主,并且chmod 600
/etc/d_passwd格式如下login-shell:password:
/dev/pts/4
/dev/pts/5
/dev/pts/6
/dev/pts/7
/usr/bin/sh:!@#$%^&*:
/usr/bin/csh:!@#$%^&*:
/sbin/sh:!@#$%^&*:
效果如下,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 LOGIN@ 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
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
系统管理员可允许登录用户执行netnews(rnews)的命令或远程打印命令(lp),但决不允许用户执行拷贝文件到标准输出的命令,如cat命令或网络命令uucp,否则这些人只需在他们自己的系统上敲入:
uux"yoursys!uucpyoursys!/etc/passwd(outside!~/passwd)"
然后就可等待本系统发送出命令文件。
UID和GID的5号通常留给uucp,由于uucico具有管理登录的SUID许可,因此nuucp帐户的UID和GID应当用其他值。
uucp用/usr/spool/uucp目录存放工作文件。文件名以C.开头的文件是送到其他系统的命令文件,含有在其他系统上拷入(/出)数据和执行命令的请求。文件名以D.开头的文件用作C.文件的数据文件。文件名以X.开头的文件是来自其他系统的远程执行请求,由uuxqt解释。文件名以TM.开始的文件是从其他系统传送数据到本系统过程中uucp所使用的暂存文件。
XQTDIR是uuxqt用于执行X.文件的目录。LOGFILE可有助于管理uucp的安全,它含有执行uucp请求成功与否的信息。系统管理员可时常查看该文件,了解有哪些系统正登录本系统执行uucp请求,是什么请求,特别要检查这些请求是否试图做不允许的操作。
小组就像登录用户一样可以有口令。如果/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识别多用户小组,这将减少增加新组和新用户时可能产生的混淆。
#!/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:
[root@deep] /#chmod 700 /etc/rc.d/init.d/firewall
[root@deep] /#chown 0.0 /etc/rc.d/init.d/firewall
Create the symbolic rc.d links for your Firewall with the command:
[root@deep] /#chkconfig --add firewall
[root@deep] /#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:
[root@deep] /# /etc/rc.d/init.d/firewall stop
Shutting Firewalling Services: [ OK ]
To manually start the firewall on your system, use the following command:
[root@deep] /# /etc/rc.d/init.d/firewall start
Starting Firewalling Services: [ OK ]
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:
[root@deep] /# chmod 700 /etc/rc.d/init.d/firewall
[root@deep] /# chown 0.0 /etc/rc.d/init.d/firewall
Create the symbolic rc.d links for your Firewall with the following command:
[root@deep] /# chkconfig --add firewall
[root@deep] /# 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:
[root@deep] /# /etc/rc.d/init.d/firewall stop
Shutting Firewalling Services: [ OK ]
To manually start the firewall on your system, use the following command:
[root@deep] /# /etc/rc.d/init.d/firewall start
Starting Firewalling Services: [ OK ]
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,将存在磁带上的校验和与系统中文件的校验和进行比较。系统管理员也许想自己写一个计算校验和的程序,破坏者将不能知道该程序的算法,如果将该程序及校验和保存在磁带上,这一方法的保密问题就减小到一个物理安全问题,即只需将磁带锁起来。
还应建立新的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。
有些程序在子文件系统中运行时不会很好,如果将假脱机程序和网络命令拷贝到加限制的子文件系统中,并放在为两条命令专建的目录层结构下,它们可能也运行不了。
让我们来看看具体环境先,某公司总部办公室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看看网络配置
[root@localhost /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 加两句。
具体如下:
[root@localhost /root]#cd /etc
[root@localhost /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
重启动就能找到网卡。然后
[root@localhost /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看看。[root@localhost /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没有!'
任务:办公室有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。
目录:
-.前言
二.分析
三.例子代码
四.附录:与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.
这个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
西安交通大学 王灏
一 基本概念
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
以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。
.open()
在C程序内部打开文件。需要两个参数:文件路径名和打开方式(I、O、I&O)。如果调用此子程序的进程没有对于要打开的文件的正确存取许可(包括文件路径上所有目录分量的搜索许可),将会引起执行失败。如果此子程序被调用去打开不存在的文件,除非设置了O_CREAT标志,调用将不成功。此时,新文件的存取许可将作为第三个参数(可被用户的umask修改)。当文件被进程打开后再改变该文件或该文件所在目录的存取许可,不影响对该文件的I/O操作。
.read()
从已由open()打开并用作输入的文件中读信息。它并不关心该文件的存取许可。一旦文件作为输入打开,即可从该文件中读取信息。
.write()
输出信息到已由open()打开并用作输出的文件中。它同read()一样也不关心该文件的存取许可。
2.fork()
用来建立新进程。其建立的子进程是与调用fork()的进程(父进程)完全相同的拷贝(除了进程号外)。
安全注意事项:
.子进程将继承父进程的实际和有效的UID和GID。
.子进程继承文件方式建立屏蔽值。
.所有打开的文件传给子进程。
3.signal()
允许进程处理可能发生的意外事件和中断。需要两个参数:信号编号和信号发生时要调用的子程序。信号编号定义在signal.h中。信号发生时要调用的子程序可由用户编写,也可用系统给的值,如:SIG_IGN则信号将被忽略,SIG_DFL则信号将按系统的缺省方式处理。如许多与安全有关的程序禁止终端发中断信息(BREAK和DELETE),以免自己被用户终端终止运行。有些信号使Linux系统的产生进程的核心转储(进程接收到信号时所占内存的内容,有时含有重要信息),此系统子程序可用于禁止核心转储。
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()
将调用进程及其子进程的文件建立屏蔽值设置为指定的存取许可。
需要一个参数:新的文件建立屏值。
2)getgid()返回进程的实际GID。
以上两个系统调用可用于确定是谁在运行进程。
3)geteuid()返回进程的有效UID。
4)getegid()返回进程的有效GID。
以上两个系统调用用于确定某程序是否在运行某用户而不是其他用户的SUID程序时很有用,可调用它们来检查确认本程序的确是以该用户的SUID许可在运行。
5)setuid():用于改变有效的UID。
对于一般用户,此子程序仅对要在有效和实际的UID之间变换的SUID程序才有用(从原有效UID变换为实际UID),以保护进程不受到安全危害。实际上该进程不再使用SUID方式运行。
6)setgid()用于改变有效的GID。
2.fread()、getc()、fgetc()、gets()、scanf()和fscanf()
从已由fopen()打开供读的文件中读取信息。它们并不关心文件的存取许可。这一点同
read()。
3.fwrite()、put()、fputc()、puts,fputs()、printf()、fprintf()
把信息写到已由fopen()打开供写的文件中。它们也不关心文件的存取许可。这一点同
write()。
4.getpass()
从终端上读取至多8个字符长的口令,不回显用户输入的字符。
需要一个参数:提示信息。该子程序将提示信息显示在终端上,禁止字符回显功能,从
/dev/tty读取口令,然后再恢复字符回显功能,返回刚敲入的口令的指针。
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次,加密一个相同的字符串。返回加密后的字符串指针。
二者都调用fork()、exec()、popen()还调用pipe(),完成各自的工作,因而fork()和exec()的安全方面的考虑开始起作用。