利用Java编写简单IIS日志清理工具(一)

2014-11-23 23:38:11 · 作者: · 浏览: 0

文/图 海啸天鸣(Ansty)[华南农业大学 李海鸣]

拿下XXX网站,提权得到管理员权限以后,大家是不是就一走了之呢?是不是忘了什么很重要的事情呢?没错,清理日志!勤快点的管理员会定时分析系统日志,看看系统什么时候发生过什么事情;细心的管理员则可以从日志里面看出我们跑进他们系统的脚印哦。
现在网上提供的日志清理工具好多都是直接删除整个日志文件的,管理员在查日志文件时发现日志没了,不用说也知道服务器被黑,这样做是比较傻瓜的。因此,我们就需要可以清理我们指定IP的日志这个功能。网上找了一下,发现iisantidote这个小工具可以实现,但没提供源码。我就本着开源的思想,用Java写了这么一个小工具。本文没有做太复杂的功能,实现清理指定IIS文件的日志就OK了,即在IIS日志文件里面找到我们指定IP的记录,然后删除。
在开始写程序前,我们引入下面三个包。

import java.io.*; //封装了java对文件的一些操作
import java.util.ArrayList; //java封装好了链表,我们无需再自己重新写,方便了很多
import java.util.ListIterator; //对链表的一些操作,非常方便

读IIS日志

public void readLog() {
try {
BufferedReader bFile = new BufferedReader(new InputStreamReader(new FileInputStream(fileName)));
String data;
while ((data = bFile.readLine()) != null) {//判断是否读到空数据,空则停止
logArray.add(data);//保存数据
}
bFile.close();//处理完文件以后一定要关闭文件读取流
} catch (FileNotFoundException e) {//处理文件异常
System.out.println("文件无法找到");
} catch (IOException e) {//处理输入输出异常
e.printStackTrace();
}
}

我们先一下BufferedReader的构造方法。
BufferedReader(Reader in)用于创建一个使用默认大小输入缓冲区的缓冲字符输入流。为什么我们要选择这个类来操作文件呢?对于IIS的日志文件,如果访问量很大,那么产生的日志就会非常庞大。如果使用一个未带缓冲区的方法来读一个大文件,会费很多的时间,程序也很容易假死,而且效率也很低下。因为这个类里面的参数是Reader,所以我们就要用“new InputStreamReader(new FileInputStream(fileName))”来获得一个Reader类的对象。fileName就是我们输入的IIS日志文件的路径。
bFile通过readLine()每次读入一行日志记录,然后将这些记录全部存储到一个logArray的数组里面,logArray的类型是Array。我们前面说过了,Array封装了很多链表操作方法,add()就能直接将我们的数据添加进链表里。

处理IIS日志记录,删除存在指定IP的记录

public void execLog() {
ListIterator li = logArray.listIterator();
String temp;
while (li.hasNext()) {//判断是否到了链表尾部
temp = li.next().toString();//将链表数据转换成String类型
try {
if (temp.split(" ")[1].toString().equals(ip)) {//与指定的IP进行比较
} else //过滤指定IP的记录
newLogArray.add(temp); //添加到新的日志链表
} catch (Exception e) {//处理异常
e.printStackTrace();
}
}
}

ListIterator是一个接口,允许程序员按任一方向遍历列表、迭代期间修改列表,并获得迭代器在列表中的当前位置。在这里我们只用到了hasNext()和next()方法。顾名思义,第一个是判断是否还有后续元素,第二个就是获得后续元素,我们通过循环判断所有的元素即可。temp是一个String类型的变量,每次只存储一条日志记录,记录的格式是“时间 客户IP 访问类型 标志”,对于我们来说,我们只关心客户IP,此时调用String类的spilt()方法来获得就可以了。
temp.split(" ")能将一个String类型的变量temp按空格分成一组数组,从上面的记录格式我们可以看出,客户IP是在第二个位置的,所以我们就可以通过temp.split(“ “)[1]来得到客户IP。equal()方法就是比较了。整个IF-ELSE里面是将与IP匹配的记录略去,然后存到新的newLogArray里面,这样得到的newLogArray链表就是没有我们自己IP的日志列表了。

修改IIS日志文件

public void writeLog(ArrayList temp) {
ListIterator li = temp.listIterator();
//temp就是我们要写到日志文件的日志记录链表
try {
BufferedWriter bw = new BufferedWriter(new FileWriter(fileName));
while (li.hasNext()) {
bw.write(li.next().toString() + " ");//逐行写入,后面再加个换行
}
bw.flush();//关闭文件之前,一定要先flush()
bw.close();
} catch (IOException e) {
e.printStackTrace();
}
}

写文件同样要用到带缓冲的方法,就是BufferedWriter,这里的理论跟读文件一样,就不再细说了。我们依然利用循环来将链表中的记录写进文件,最后那个换行一定要加上去,如果不加的话,写进去的时候是没有换行的。
之后,最重要的工作就是把我们上面写的代码连接在一起了。在我们修改IIS日志文件的时候,如果只是修改过往日志,那还好,直接修改就行了。但是如果修改的是当天日志,那可就不同了,因为IIS仍在运行,正在操作那个日志文件,我们就只有看着的份,写是写不了的了。所以,我们在修改之前,一定要把IIS先给停了。

public void exec() {
try {
Process p = null;
p = Runtime.getRuntime().exec("cmd /c iisreset /stop");
execResult(p);//打印DOS命令执行返回的数据
p = Runtime.getRuntime().exec("cmd /c net stop w3svc");
execResult(p);
readLog();//读日志,前面已经介绍
execLog();//处理日志
writeLog(newLogArray);//修改日志
p = Runtime.getRuntime().exec("cmd /c iisreset /enable");
execResult(p);
p = Runtime.getRuntime().exec("cmd /c iisreset /start");
execRe