实时监控所有端口的连接情况、及时对异常连接发出警告并提示用户删除异常连接,就可以有效地达到防黑目的。
使用微软的IP助手库函数(iphlpapi.dll)是一个捷径。其中的 GetTcpTable函数能返回当前系统中全部有效的 TCP连接。其定义为:
Declare Function GetTcpTable Lib "iphlpapi.dll" (ByRef pTcpTable As MIB_TCPTABLE, ByRef pdwSize As Long, ByVal bOrder As Long) As Long
其中参数一是 TCP连接表缓冲区的指针,参数二是缓冲区大小(当缓冲区不够大时,该参数返回实际需要的大小),参数三指示连接表是否需要按“Local IP”、“Localport”、“Remote IP”、“Remote port”依次进行排序。
对于监控 UDP连接表,可使用 GetUdpTable函数完成。由于在使用上完全类似,这里略去讨论。
二、异常警告及删除连接
通过定时比较前后两个 TCP连接表,我们可以立即发现异常并发出警告。收到警告信号后,我们应首先将可疑连接删除掉,然后再仔细查找系统中是否有安全漏洞或有可疑进程在工作。IP助手库函数中的 SetTcpEntry函数可以帮助我们删除可疑连接。其定义为:
Public Declare Function SetTcpEntry Lib "IPhlpAPI" (pTcpRow As MIB_TCPROW) As Long 'This is used to close an open port.
在调用此函数之前,应将欲删连接的状态置为 MIB_TCP_STATE_DELETE_TCB(删除)。MIB_TCP_STATE_DELETE_TCB也是目前唯一可在运行时设置的状态。
好了,有了这些,一个放火墙的基本原理以及方法已经知道了,哈哈,我们想将这些函数,API封装起来。建立一个类模块,名称为modNetstat,代码如下
Public MIBICMPSTATS As MIBICMPSTATS
Public Type MIBICMPSTATS
dwEchos As Long
dwEchoReps As Long
End Type
Public MIBICMPINFO As MIBICMPINFO
Public Type MIBICMPINFO
icmpOutStats As MIBICMPSTATS
End Type
Public MIB_ICMP As MIB_ICMP
Public Type MIB_ICMP
stats As MIBICMPINFO
End Type
'GetIcmpStatistics函数能够让你查看当前ICMP数据报的流量
Public Declare Function GetIcmpStatistics Lib "iphlpapi.dll" (pStats As MIBICMPINFO) As Long
Public Last_ICMP_Cnt As Integer
Type MIB_TCPROW
dwState As Long
dwLocalAddr As Long
dwLocalPort As Long
dwRemoteAddr As Long
dwRemotePort As Long
End Type
Type MIB_TCPTABLE
dwNumEntries As Long
table(100) As MIB_TCPROW
End Type
Public MIB_TCPTABLE As MIB_TCPTABLE
'GetTcpTable函数能返回当前系统中全部有效的 TCP连接
Declare Function GetTcpTable Lib "iphlpapi.dll" (ByRef pTcpTable As MIB_TCPTABLE, ByRef pdwSize As Long, ByVal bOrder As Long) As Long
'SetTcpEntry函数可以帮助我们删除可疑连接
Public Declare Function SetTcpEntry Lib "IPhlpAPI" (pTcpRow As MIB_TCPROW) As Long 'This is used to close an open port.
'定义连接状态为13个
Public IP_States(13) As String
Private Last_Tcp_Cnt As Integer
Private Const AF_INET = 2
Private Const IP_SUCCESS As Long = 0
Private Const MAX_WSADescription = 256
Private Const MAX_WSASYSStatus = 128
Private Const SOCKET_ERROR As Long = -1
Private Const WS_VERSION_REQD As Long = &H101
Type HOSTENT
h_name As Long ' official name of host
h_aliases As Long ' alias list
h_addrtype As Integer ' host address type
h_length As Integer ' length of address
h_addr_list As Long ' list of addresses
End Type
Type servent
s_name As Long ' (pointer to string) official service name
s_aliases As Long ' (pointer to string) alias list (might be null-seperated with 2null terminated)
s_port As Long ' port #
s_proto As Long ' (pointer to) protocol to use
End Type
Private Type WSADATA
wVersion As Integer
wHighVersion As Integer
szDescription(0 To MAX_WSADescription) As Byte
szSystemStatus(0 To MAX_WSASYSStatus) As Byte
wMaxSockets As Long
wMaxUDPDG As Long
dwVendorInfo As Long
End Type
Public Declare Function ntohs Lib "WSOCK32.DLL" (ByVal netshort As Long) As Long
'inet_addr将IP地址从 点数格式转换成无符号长整型
Private Declare Function inet_addr Lib "WSOCK32.DLL" (ByVal CP As String) As Long
'inet_ntoa将IP地址从 点数格式转换成ascii
Private Declare Function inet_ntoa Lib "WSOCK32.DLL" (ByVal inn As Long) As Long
Private Declare Function gethostbyaddr Lib "WSOCK32.DLL" (Addr As Long, ByVal addr_len As Long, ByVal addr_type As Long) As Long
Private Declare Function gethostbyname Lib "WSOCK32.DLL" (ByVal host_name As String) As Long
Private Declare Function WSAStartup Lib "WSOCK32.DLL" (ByVal wVersionRequired As Long, lpWSADATA As WSADATA) As Long
Private Declare Function WSACleanup Lib "WSOCK32.DLL" () As Long
'若该函数的返回值非0,则为存储器的地址。由于VB不能直接操作地址,所以还必须调用RtlMoveMemory函数将数据写入地址中
Private Declare Sub RtlMoveMemory Lib "kernel32" (hpvDest As Any, ByVal hpvSource As Long, ByVal cbCopy As Long)
'将数据转换为内存二进制形式字符串
Declare Sub CopyMemory Lib "kernel32" Alias "RtlMoveMemory" (Dest As Any, Src As Any, ByVal cb&)
Declare Function lstrlen Lib "kernel32" (ByVal lpString As Any) As Integer
Private Blocked As Boolean
'定义网络状态
Sub InitStates()
IP_States(0) = "未知"
IP_States(1) = "已经关闭"
IP_States(2) = "监听"
IP_States(3) = "发送同步空闲字符"
IP_States(4) = "接收同步空闲字符"
IP_States(5) = "数据交换中"
IP_States(6) = "结束等待1"
IP_States(7) = "结束等待2"
IP_States(8) = "关闭等待"
IP_States(9) = "关闭中"
IP_States(10) = "命令正确应答"
IP_States(11) = "连接等待"
IP_States(12) = "删除TCP连接"
End Sub
Public Function GetAscIP(ByVal inn As Long) As String
Dim nStr&
Dim lpStr As Long
Dim retString As String
retString = String(32, 0)
lpStr = inet_ntoa(inn)
If lpStr Then
nStr = lstrlen(lpStr)
If nStr > 32 Then nStr = 32
CopyMemory ByVal retString, ByVal lpStr, nStr
retString = Left(retString, nStr)
GetAscIP = retString
Else
GetAscIP = "无法取得IP"
End If
End Function
好了,日志是建立一个LOG文件,所以我们将所需要的函数封装一个类模块里。建立一个public模块。代码如下
'对日志的定义
Public Function Log(RemA As String, RemP As String, LocP As String, Txt As String)
Dim ff As Long
ff = FreeFile
'打开log文件
Open App.Path & "\log.log" For Append As #ff
'向log文件写入数据
Write #ff, Time & "-" & Date, RemA, RemP, LocP, Txt
'将数据在日志窗口中显示出来
Frmlog.lstLog.ListItems.Add , , Time & "-" & Date
Frmlog.lstLog.ListItems(Frmlog.lstLog.ListItems.Count).SubItems(1) = RemA
Frmlog.lstLog.ListItems(Frmlog.lstLog.ListItems.Count).SubItems(2) = RemP
Frmlog.lstLog.ListItems(Frmlog.lstLog.ListItems.Count).SubItems(3) = LocP
Frmlog.lstLog.ListItems(Frmlog.lstLog.ListItems.Count).SubItems(4) = Txt
'结束日志操作
Close #ff
End Function
好了,封装好了函数以及API数据库,下面是设计界面,以及功能结合了:)
先建立主窗体,这里将名称改为frmMain,我不想抹杀你们的创意,但是为了代码的最后测试成功,请你不要改变:)
点工程——部件,插入microsoft windows common controls 6.0 (sp4)前面点上小钩,确定:)
回到桌面,双点击Toolbar,加入后,在上面右键属性。
依次插入按钮,如下:
Private Sub Form_Load()
'调用网络状态函数
modNetstat.InitStates
'一开始就刷新网络状态列表
RefreshTable
End Sub
Private Sub ListView1_MouseUp(Button As Integer, Shift As Integer, x As Single, y As Single)
'判断是否为鼠标右键按下
If Button = 2 And ListView1.ListItems.Count > 0 Then
'调用控制按钮,在下面将说到
frmMain.PopupMenu frmMenu.mnuConn
End If
End Sub
Private Sub tmrRefresh_Timer()
'定时刷新网络状态列表
RefreshTable
End Sub
Public Sub Toolbar1_ButtonClick(ByVal Button As MSComctlLib.Button)
Select Case Button.Index