说实在的,对於 tcpdump这个软体来说,你甚至可以说这个软体其实就是个骇客软体,因为他不但可以分析封包的流向,连封包的内容也可以进行『监听』,如果你使用的传输资料是明码的话,不得了,在 router 上面就可能被人家监听走了! 很可怕呐!所以,我们也要来了解一下这个软体啊!(注:这个tcpdump 必须使用 root 的身份执行)
[root@linux ~]# tcpdump [-nn] [-i 介面] [-w 储存档名] [-c 次数] [-Ae]
[-qX] [-r 档案] [所欲撷取的资料内容]
参数:
-nn:直接以 IP 及 port number 显示,而非主机名与服务名称
-i :后面接要『监听』的网路介面,例如 eth0, lo, ppp0 等等的介面;
-w :如果你要将监听所得的封包资料储存下来,用这个参数就对了!后面接档名
-c :监听的封包数,如果没有这个参数, tcpdump 会持续不断的监听,
直到使用者输入 [ctrl]-c 为止。
-A :封包的内容以 ASCII 显示,通常用来捉取 WWW 的网页封包资料。
-e :使用资料连接层 (OSI 第二层) 的 MAC 封包资料来显示;
-q :仅列出较为简短的封包资讯,每一行的内容比较精简
-X :可以列出十六进位 (hex) 以及 ASCII 的封包内容,对於监听封包内容很有用
-r :从后面接的档案将封包资料读出来。那个『档案』是已经存在的档案,
并且这个『档案』是由 -w 所制作出来的。
所欲撷取的资料内容:我们可以专门针对某些通讯协定或者是 IP 来源进行封包撷取,
那就可以简化输出的结果,并取得最有用的资讯。常见的表示方法有:
'host foo', 'host 127.0.0.1' :针对单部主机来进行封包撷取
'net 192.168' :针对某个网域来进行封包的撷取;
'src host 127.0.0.1' 'dst net 192.168':同时加上来源(src)或目标(dst)限制
'tcp port 21':还可以针对通讯协定侦测,如 tcp, udp, arp, ether 等
还可以利用 and 与 or 来进行封包资料的整合显示呢!
范例一:以 IP 与 port number 捉下 eth0 这个网路卡上的封包,持续 3 秒
[root@linux ~]# tcpdump -i eth0 -nn
tcpdump: verbose output suppressed, use -v or -vv for full protocol decode
listening on eth0, link-type EN10MB (Ethernet), capture size 96 bytes
01:33:40.41 IP 192.168.1.100.22 > 192.168.1.11.1190: P 116:232(116) ack 1 win 9648
01:33:40.41 IP 192.168.1.100.22 > 192.168.1.11.1190: P 232:364(132) ack 1 win 9648
<==按下 [ctrl]-c 之后结束
6680 packets captured <==捉下来的封包数量
14250 packets received by filter <==由过滤所得的总封包数量
7512 packets dropped by kernel <==被核心所丢弃的封包
如果你是第一次看 tcpdump 的 man page 时,肯定一个头两个大,因为 tcpdump几乎都是分析封包的表头资料,使用者如果没有简易的网路封包基础,要看懂粉难呐! 所以,至少您得要回到网路基础里面去将 TCP封包的表头资料理解理解才好啊! ^_^!至於那个范例一所产生的输出范例中,我们可以约略区分为数个栏位,我们以范例一当中那个特殊字体行来说明一下:
* 01:33:40.41:这个是此封包被撷取的时间,『时:分:秒』的单位;
* IP:透过的通讯协定是 IP ;
* 192.168.1.100.22 > :传送端是 192.168.1.100 这个 IP,而传送的 port number 为 22,您必须要了解的是,那个大於 (>) 的符号指的是封包的传输方向喔!
* 192.168.1.11.1190:接收端的 IP 是 192.168.1.11, 且该主机开启 port 1190 来接收;
* P 116:232(116):这个封包带有 PUSH 的资料传输标志, 且传输的资料为整体资料的 116~232 byte,所以这个封包带有 116 bytes 的资料量;
* ack 1 win 9648:ACK与 Window size 的相关资料。
最简单的说法,就是该封包是由 192.168.1.100 传到 192.168.1.11,透过的 port 是由 22 到 1190 ,且带有116 bytes 的资料量,使用的是 PUSH 的旗标,而不是 SYN 之类的主动连线标志。呵呵!不容易看的懂吧!所以说,上头才讲请务必到TCP 表头资料的部分去瞧一瞧的啊!
再来,一个网路状态很忙的主机上面,你想要取得某部主机对你连线的封包资料而已时, 使用tcpdump 配合管线命令与正规表示法也可以,不过,毕竟不好捉取! 我们可以透过 tcpdump的表示法功能,就能够轻易的将所需要的资料独立的取出来。在上面的范例一当中,我们仅针对 eth0 做监听,所以整个 eth0介面上面的资料都会被显示到萤幕上,不好分析啊!那麼我们可以简化吗?例如只取出 port 21 的连线封包,可以这样做:
[root@linux ~]# tcpdump -i eth0 -nn port 21
tcpdump: verbose output suppressed, use -v or -vv for full protocol decode
listening on eth0, link-type EN10MB (Ethernet), capture size 96 bytes
01:54:37.96 IP 192.168.1.11.1240 > 192.168.1.100.21: . ack 1 win 65535
01:54:37.96 IP 192.168.1.100.21 > 192.168.1.11.1240: P 1:21(20) ack 1 win 5840
01:54:38.12 IP 192.168.1.11.1240 > 192.168.1.100.21: . ack 21 win 65515
01:54:42.79 IP 192.168.1.11.1240 > 192.168.1.100.21: P 1:17(16) ack 21 win 65515
01:54:42.79 IP 192.168.1.100.21 > 192.168.1.11.1240: . ack 17 win 5840
01:54:42.79 IP 192.168.1.100.21 > 192.168.1.11.1240: P 21:55(34) ack 17 win 5840
瞧!这样就仅提出 port 21 的资讯而已,且仔细看的话,你会发现封包的传递都是双向的, client 端发出『要求』而 server 端则予以『回应』,所以,当然是有去有回啊! 而我们也就可以经过这个封包的流向来了解到封包运作的过程。 举例来说:
1. 我们先在一个终端机视窗输入『 tcpdump -i lo -nn 』 的监听,
2. 再另开一个终端机视窗来对本机 (127.0.0.1) 登入『ssh localhost』
那麼输出的结果会是如何?
[root@linux ~]# tcpdump -i lo -nn
1 tcpdump: verbose output suppressed, use -v or -vv for full protocol decode
2 listening on lo, link-type EN10MB (Ethernet), capture size 96 bytes
3 11:02:54.253777 IP 127.0.0.1.32936 > 127.0.0.1.22: S 933696132:933696132(0)
win 32767 <mss 16396,sackOK,timestamp 236681316 0,nop,wscale 2>
4 11:02:54.253831 IP 127.0.0.1.22 > 127.0.0.1.32936: S 920046702:920046702(0)
ack 933696133 win 32767 <mss 16396,sackOK,timestamp 236681316 236681316,nop,
wscale 2>
5 11:02:54.253871 IP 127.0.0.1.32936 > 127.0.0.1.22: . ack 1 win 8192 <nop,
nop,timestamp 236681316 236681316>
6 11:02:54.272124 IP 127.0.0.1.22 > 127.0.0.1.32936: P 1:23(22) ack 1 win 8192
<nop,nop,timestamp 236681334 236681316>
7 11:02:54.272375 IP 127.0.0.1.32936 > 127.0.0.1.22: . ack 23 win 8192 <nop,
nop,timestamp 236681334 236681334>
上表显示的头两行是 tcpdump 的基本说明,然后:
* 第 3 行显示的是『来自 client 端,带有 SYN 主动连线的封包』,
* 第 4 行显示的是『来自 server 端,除了回应 client 端之外(ACK),还带有 SYN 主动连线的标志;
* 第 5 行则显示 client 端回应 server 确定连线建立 (ACK)
* 第 6 行以后则开始进入资料传输的步骤。
从第 3-5 行的流程来看,熟不熟悉啊?没错!那就是 三向交握 的基础流程啦!够有趣吧! 不过 tcpdump之所以被称为骇客软体之一可不止上头介绍的功能呐! 上面介绍的功能可以用来作为我们主机的封包连线与传输的流程分析,这将有助於我们了解到封包的运作,同时了解到主机的防火墙设定规则是否有需要修订的地方。
更神奇的使用要来啦!如果我们使用tcpdump 在 router 上面监听『明码』的传输资料时, 例如 FTP 传输协定,你觉得会发生什麼问题呢? 我们先在主机端下达『tcpdump -i lo port 21 -nn -X 』然后再以 ftp 登入本机,并输入帐号与密码, 结果你就可以发现如下的状况:
[root@linux ~]# tcpdump -i lo -nn -X 'port 21'
0x0000: 4500 0048 2a28 4000 4006 1286 7f00 0001 E..H*(@.@.......
0x0010: 7f00 0001 0015 80ab 8355 2149 835c d825 .........U!I.\.%
0x0020: 8018 2000 fe3c 0000 0101 080a 0e2e 0b67 .....<.........g
0x0030: 0e2e 0b61 3232 3020 2876 7346 5450 6420 ...a220.(vsFTPd.
0x0040: 322e 302e 3129 0d0a 2.0.1)..
0x0000: 4510 0041 d34b 4000 4006 6959 7f00 0001 E..A.K@
[email protected]....
0x0010: 7f00 0001 80ab 0015 835c d825 8355 215d .........\.%.U!]
0x0020: 8018 2000 fe35 0000 0101 080a 0e2e 1b37 .....5.........7
0x0030: 0e2e 0b67 5553 4552 2064 6d74 7361 690d ...gUSER.dmtsai.
0x0040: 0a .
0x0000: 4510 004a d34f 4000 4006 694c 7f00 0001 E..J.O@
[email protected]....
0x0010: 7f00 0001 80ab 0015 835c d832 8355 217f .........\.2.U!.
0x0020: 8018 2000 fe3e 0000 0101 080a 0e2e 3227 .....>........2'
0x0030: 0e2e 1b38 5041 5353 206d 7970 6173 7377 ...8PASS.mypassw
0x0040: 6f72 6469 7379 6f75 0d0a ordisyou..
上面的输出结果已经被简化过了,你必须要自行在你的输出结果当中搜寻相关的字串才行。 从上面输出结果的特殊字体中,我们可以发现『该 FTP软体使用的是 vsftpd ,并且使用者输入 dmtsai 这个帐号名称,且密码是 mypasswordisyou』嘿嘿!你说可不可怕啊!如果使用的是明码的方式来传输你的网路资料? 所以我们才常常在讲啊,网路是很不安全低!
另外你得了解,为了让网路介面可以让 tcpdump 监听,所以执行 tcpdump 时网路介面会启动在 『错乱模式 (promiscuous)』,所以你会在/var/log/messages 里面看到很多的警告讯息,通知你说你的网路卡被设定成为错乱模式!别担心,那是正常的。 至於更多的应用,请参考man tcpdump 罗!
查找算法:
1. 无序表的顺序查找*******\n"
2. 有序表的折半查找*******\n"
3. 二叉顺序树的查找*
#include<iostream.h>
#include<iomanip.h>
#include<malloc.h>
#define N 100
typedef int elemtype;
typedef elemtype elem[N];
typedef struct node
{
elemtype data;
struct node*left,*right;
}BTree;
int search(elemtype elem[],int key,int length)//顺序查找
{
int i=0;
while(i<length&&elem[i]!=key)
i++;
if(i>=length)
return -1;
else return i;
}
int search_bin(elemtype elem[],int low,int high,int key)//折半查找
{
int mid;
if(low>high)
return -1;//not find return -1
else
{
mid=(low+high)/2;
if(key<elem[mid])
return (search_bin(elem,low,mid-1,key));
else if(key==elem[mid])
return mid;//find!
else
return (search_bin(elem,mid+1,high,key));
}
}
BTree*tree(BTree*&r,elemtype x)
{
if(r==NULL)
{
r=new BTree;
r->data=x;
r->left=r->right=NULL;
}
else
{
if(x<r->data)
tree(r->left,x);
else
tree(r->right,x);
}
return r;
}
void incorder(BTree*t)
{
if(t!=NULL)
{
incorder(t->left);
cout<<setw(3)<<t->data;
incorder(t->right);
}
}
int remove(BTree*&b,int x)//查找并删除
{
BTree*p,*q,*r,*t;
p=b; //p指向待比较的接点
q=NULL; //q指向p的前驱接点
while(p!=NULL&&p->data!=x)
if(x<p->data)
{
q=p;
p=p->left;
}
else
{
q=p;
p=p->right;
}
if(p==NULL)
return 0;
else if(p->left==NULL)//被删接点无左子树
{
if(q==NULL)
t=p->right;
else if(q->left==p)
q->left=p->right;
else
q->right=p->right;
}
else//有左子树
{
r=p->left;
while(r->right!=NULL)
r=r->right;
r->right=p->right;
if(q==NULL)
t=p->left;//被删接点是根接点
else if(q->left==p)
q->left=p->left;
else
q->right=p->left;
}
return 1;
}
void printree(BTree*b)
{
if(b!=NULL)
{
cout<<b->data;
if(b->left!=NULL||b->right!=NULL)
{
cout<<"(";
printree(b->left);
if(b->right!=NULL)
cout<<",";
printree(b->right);
cout<<")";
}
}
}
void main()
{
BTree *root=NULL;
elemtype elem[N];
int ch,key,length,n1,i,flag;
cout<<"##A simple find example!!##\n";
cout<<"**********************************\n"
<<"********1. 无序表的顺序查找*******\n"
<<"********2. 有序表的折半查找*******\n"
<<"********3. 二叉顺序树的查找*******\n"
<<"********4. 退出!! *******\n";
cout<<"put in the excel's length(<=100):\n";
cin>>length;
cout<<"put in your "<<length<<" nums elem:\n";
for(i=0;i<length;i++)
cin>>elem[i];
cout<<"elem数组"<<endl<<"下标";
for(i=0;i<length;i++)
cout<<setw(3)<<i;
cout<<endl<<" 值:";
for(i=0;i<length;i++)
cout<<setw(3)<<elem[i];
cout<<endl;
while(flag)
{
cout<<"put in your choose(1~4):";
cin>>ch;
if(ch==1)
{
cout<<"put in the elem you want to find:";
cin>>key;
n1=search(elem,key,length);
if(n1>=0)
cout<<"elem["<<n1<<"]="<<key<<endl;
else
cout<<key<<" is not find!!\n";
flag=1;
}
else if(ch==2)
{
for(i=0;i<length;i++)
{
for(int j=0;j<length;j++)
{
if(elem[i]<elem[j])
{
int text;
text=elem[i];
elem[i]=elem[j];
elem[j]=text;
}
}
}
cout<<"排序后:\n";
cout<<"elem数组"<<endl<<"下标";
for(i=0;i<length;i++)
cout<<setw(3)<<i;
cout<<endl<<" 值:";
for(i=0;i<length;i++)
cout<<setw(3)<<elem[i];
cout<<endl;
cout<<"put in the elem you want to find:";
cin>>key;
n1=search_bin(elem,0,length-1,key);
if(n1>=0)
cout<<"elem["<<n1<<"]="<<key<<endl;
else
cout<<key<<" is not find!!\n";
flag=1;
}
else if(ch==3)
{
for(i=0;i<length;i++)
root=tree(root,elem[i]);
cout<<"二叉排序树:\n";
printree(root);cout<<endl;
cout<<"递增序列:\n";
incorder(root);
cout<<endl;
cout<<"put in the elem you want to delete:";
cin>>key;
remove(root,key);
cout<<"删除后的二叉排序树:\n";
printree(root);
cout<<endl;
flag=1;
}
else if(ch==4)
{flag=0;cout<<"退出!!!\n";}
else cout<<"算法完成,谢谢使用再见!!\n";
}
}