Tcpdump is the premier network analysis tool for information security professionals. Having a solid grasp of this user-space appalication is mandatory for anyone desiring a thorough understanding of TCP/IP.
tcpdump -D
yubo@debian:~/login$ sudo tcpdump -D
[sudo] password for yubo:
1.eth0
2.wlan0
3.nflog (Linux netfilter log (NFLOG) interface)
4.any (Pseudo-device that captures on all interfaces)
5.lo
tcpdump -i eth0
tcpdump -c 2 -i event0
root@yubo-2:~# tcpdump -c 2 -i venet0
tcpdump: verbose output suppressed, use -v or -vv for full protocol decode
listening on venet0, link-type LINUX_SLL (Linux cooked), capture size 65535 bytes
00:06:39.197531 IP yubo-2.ssh > 112.250.100.205.46493: Flags [P.], seq 1776389372:1776389580, ack 2267257061, win 292, options [nop,nop,TS val 1163336703 ecr 2017454], length 208
00:06:39.197997 IP yubo-2.40698 > 181.41.222.18.domain: 14384+ PTR? 205.100.250.112.in-addr.arpa. (46)
2 packets captured
5 packets received by filter
0 packets dropped by kernel
root@yubo-2:~# tcpdump -c 2 -A -i venet0
tcpdump: verbose output suppressed, use -v or -vv for full protocol decode
listening on venet0, link-type LINUX_SLL (Linux cooked), capture size 65535 bytes
00:09:50.581560 IP yubo-2.ssh > 112.250.100.205.46493: Flags [P.], seq 1776393404:1776393612, ack 2267259285, win 292, options [nop,nop,TS val 1163528086 ecr 2065321], length 208
E.....@.@..".e .p.d.....i....#.....$.......
EZ......H.x.5.^i"[email protected]*..>...#6.!:.B...Zz.}.0.M..5..S!...1.y..~...M......5..n..{..zO.2..u..5.FX..b$iJ[email protected]..=E~R.....9...,x?..<...!..>.....x..HU/...>XzK.....A.Z.<.]...%.........1ax...a.U..&P.
00:09:50.581992 IP yubo-2.50899 > 181.41.222.18.domain: 32128+ PTR? 205.100.250.112.in-addr.arpa. (46)
E..J..@[email protected] ..).....5.6v.}............205.100.250.112.in-addr.arpa.....
2 packets captured
6 packets received by filter
0 packets dropped by kernel
The tcpdump generate a .pcap file, then you can read it with tcpdump command
这篇文章解析了misc和char的不同,但是思路都是一样的,主要可能是在归类的时候会有一些不同的。
先说一下,misc的主设备号已经被内核给固定死了,为10,只能修改次设备号(minor).
通常情况下,一个字符设备都不得不在初始化的过程中进行下面的步骤:
通过alloc_chrdev_region()分配主次设备号。
使用cdev_init()和cdev_add()来以一个字符设备注册自己。
这个就不用具体讲了,系统的调用就是寻找这个值。
echo $PATH
/usr/local/bin:/usr/bin:/bin:/usr/local/games:/usr/games
这个是我的值,具体添加路径是,我找找看哈:
# set PATH so it includes user s private bin if it exists
if [ -d "$HOME/bin" ] ; then
PATH="$HOME/bin:$PATH"
fi
EDITOR=vim; export EDITOR
你想使用或者需要改变这个值,就仿照上面的代码去改动,最后别忘了
source .profile
我安装python的各种软件就放在这里了, 如果在安装时不指定目录时默认安装在这里。 所有的可执行文件都放在这里,
但是,如果我在./configure --prefix=/usr
时,这样产生的可执行文件位于/usr/bin.看来默认就是–prefix=/xx/bin中。
除了在配置编译的时候指定/usr目录,通过系统包管理器产生的文件如apt(debian) 安装的文件也会位于这个目录。(有一点很奇怪,就是./configure是默认也会在此目录下) 在我的印象中,使用源码安装的程序应该位于/usr/local/bin中。
这个s就是systemd的意思,这个是系统管理程序。
这篇文章介绍wait和exit的知识。
系统调用wait做两件事,首先,wait暂停调用它的进程,直到子进程结束,然后,wait取得子进程结束时传递给exit的值。
#include <stdio.h>
#include <stdlib.h>
#define DELAY 2
void child_code(int), parent_code(int);
int main()
{
int newpid;
printf("Before: mypid is %d\n", getpid());
if ((newpid = fork()) == -1)
perror("fork");
else if (newpid == 0)
child_code(DELAY);
else
parent_code(newpid);
}
void child_code(int delay)
{
printf("child %d here, will sleep for %d seconds\n", getpid(), delay);
sleep(delay);
printf("child done ,about to exit\n");
exit(17);
}
void parent_code(int childpid)
{
int wait_rec; /* return value from wait() */
wait_rec = wait(NULL);
printf("done waiting for %d. Wait returned: %d\n", childpid, wait_rec);
}
注意这个wait,返回了子进程的某个值。
yubo@debian:~/test/tmp/unix$ ./test
Before: mypid is 21708
child 21709 here, will sleep for 2 seconds
child done ,about to exit
done waiting for 21709. Wait returned: 21709
yubo@debian:~/test/tmp/unix$
wait的目的之一就是通知父进程子进程结束运行了,第二个目的是告诉父进程子进程是如何结束的。
一个进程以(成功、失败或死亡)之一来结束运行了。通常情况下,成功的程序调用exit(0)退出或者从main函数中return 0。
一个进程有可能内存不足导致执行失败,这个时候,unix的编程标准是给exit一个非0 的值,这样你就告诉程序员这个程序是由于何种的原因导致失败的。
最后一种就是进程有可能被被别的信号杀死。
wait返回结束的子进程的pid给父进程,父进程是如何知道子进程是以何种的方式退出的呢?
答案是传递给wait的参数之中。这个整型变量的地址传递给函数,由3部分构成–8位记录退出值,7位记录信号序号,还有一位是标识位:产生了内核镜像(code dump).
#include <stdio.h>
#include <stdlib.h>
#define DELAY 5
void child_code(int );
void parent_code(int);
int main()
{
int newpid;
printf("Before, mypid is %d\n", getpid());
if ((newpid = fork()) == -1)
perror("fork");
else if (newpid == 0)
child_code(DELAY);
else
parent_code(newpid);
}
void child_code(int delay)
{
printf("child %d here,will sleep for %d seconds\n",getpid(), delay);
sleep(delay);
printf("child done, about to exit\n");
exit(17);
}
void parent_code(int childpid)
{
int wait_rv;
int child_status;
int high_8, low_7, bit_7;
wait_rv = wait(&child_status);
printf("done waiting for %d,Wait returned: %d\n", childpid, wait_rv);
high_8 = child_status >> 8; /** 1111 1111 0000 0000 */
low_7 = child_status & 0x7f; /* 0000 0000 0111 1111 */
bit_7 = child_status & 0x80; /* 0000 0000 1000 0000 */
printf("status: exit = %d, sig = %d, core = %d\n",high_8, low_7, bit_7);
}
第一次运行可以有以下结果:
yubo@debian:~/test/tmp/unix$ ./test
Before, mypid is 7711
child 7712 here,will sleep for 5 seconds
child done, about to exit
done waiting for 7712,Wait returned: 7712
status: exit = 17, sig = 0, core = 0
这里大约会停顿5秒中的时间用来等待子进程。
第二次运行时要注意,另开一个后台,当运行这个程序时,看到子进程的pid时,立即回到另一个终端,kill child-pid,这时候你再看看返回的结果。
yubo@debian:~/test/tmp/unix$ ./test
Before, mypid is 7768
child 7769 here,will sleep for 5 seconds
done waiting for 7769,Wait returned: 7769
status: exit = 0, sig = 15, core = 0
你可以将程序中的DELAY的值设置的大一些。
上文介绍了udev的编写,这篇文章就结合一个usb键盘,亲自测试udev的应用。
编写一个内核模块,当任何一个usb键盘插入时自动加载相应的模块并打印出相关的日志。
这个实验的目的,就是让你熟悉udev对硬件的控制,我们知道,安装内核的模块后,才能利用硬件。传统的insmod module-name已经熟悉,现在就是udev的表现时刻了(用户空间工具,取决于你的发行版)
先写一个模块,关于usb键盘的。
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/usb.h>
#include <linux/usb/input.h>
#include <linux/hid.h>
MODULE_AUTHOR("Bo YU<[email protected]>");
MODULE_DESCRIPTION("probe usb keyboard\n");
MODULE_LICENSE("GPL");
static struct usb_device_id hello_id_table [] = {
{
USB_INTERFACE_INFO(USB_INTERFACE_CLASS_HID,
USB_INTERFACE_SUBCLASS_BOOT,
USB_INTERFACE_PROTOCOL_KEYBOARD)
},
{ }, /* Here are entry */
};
/* 向内核注册 */
MODULE_DEVICE_TABLE(usb, hello_id_table);
static int hello_probe(struct usb_interface *interface,
const struct usb_device_id *id)
{
pr_info("Hello, Module, Task 05: USB keyboard function called\n");
return 0;
}
static void hello_disconnect(struct usb_interface *interface)
{
pr_info("Hello, Module, Task 05: USB keyboard disconnect function is called\n");
}
static struct usb_driver hello_driver = {
.name = "hello_driver",
.probe = hello_probe,
.disconnect = hello_disconnect,
.id_table = hello_id_table,
};
static int __init hello_init(void)
{
int retval = 0;
pr_info("Hello, module Task 05, hello, world!\n");
retval = usb_register(&hello_driver);
if (retval)
pr_info("Hello, module task 05 .Register failed, Error number %d", retval);
return 0;
}
static void __exit hello_exit(void)
{
usb_deregister(&hello_driver);
pr_info("Hello, Module task 05: Exit\n");
}
module_init(hello_init);
module_exit(hello_exit);
相应的Makefile,在链接的这篇文章,用Ctrl+f搜寻一下201702即可。
为了使用udev,前提你的模块写的得正确,可以make && insmod x.ko我这里是没有问题的。
接下来,就是编写udev了。
首先使用命令:
sudo udevadm info --name=/dev/input/by-id/usb-Chicony_HP_Elite_USB_Keyboard-event-kbd --attribute-walk
这是我的usb键盘的名字,费了很大的劲才找到,by-id目录后才是键盘名字,–attribute–walk是参数。如果你也找不到你要插入的设备,就先dmesg一下,然后插入你的硬件,再dmesg一下,你就会发现你的硬件信息。
这是我的信息:
这个系统信息很全,将这个设备的所有相关的硬件表示出来了。KERNEL、SUBSYSTEM等需要的字眼已经全出来了。接下来就是编写udev的规则了。
你可以将规则文件放在/lib/udev/rules.d/目录下也可以放在/etc/udev/rules.d/目录下,为了方便自己的管理,放在/etc目录下比较方便。
怎么写呢,这样的:
SUBSYSTEM=="input", SYMLINK+="task05", RUN+="/usr/bin/install.sh"
规则文件的命名也是有规律的:摘自
iles should be named xx-descriptive-name.rules, the xx should be chosen first according to the following sequence points:
< 60 most user rules; if you want to prevent an assignment being overriden by default rules, use the := operator.
these cannot access persistent information such as that from vol_id
< 70 rules that run helpers such as vol_id to populate the udev db
< 90 rules that run other programs (often using information in the udev db)
>=90 rules that should run last
现在的问题就是我的脚本运行问题,我测试了好几次,好像udev的执行脚本必须放在/bin的目录下,其他的则不行。
/usr/bin/install.sh 的文件内容如下:
#!/usr/bin/sh
insmod /home/yubo/little/test/task05.ko
那么,在确认没有安装这个模块的前提下,依次这么做:
插入键盘,dmesg如下:
然后,拔掉键盘,
然后确保/test下的目录已经make生成可task05.ko这个文件,接着执行
sudo /etc/init.d/udev restart
那么,插入文件后,dmesg后显示:
也就是说,将task05这个模块插入了内核,但是,有不完善的地方,如果重复安装,则不行的。
这篇文章在分类的时候让我犹豫了一下,我想还是归到kernel的类别下。
在linux kernel 2.6中,内核引入了一种新的机制,该机制可以动态的监控/dev目录下 的设备,原来的实现/dev的监控功能的 devfs被抛弃了。这篇文章也就是简单的记录下,详细的情况请参考这篇文章 udev
在linux系统中,/dev目录是存储设备节点的,每一个设备节点都指向了一个设备,用户空间的应用程序可以使用这些设备节点来交互硬件设备,例如,X server 就是监听 /dev/input/mice来反映鼠标的运动的。
devfs只是可以展示这些信息,无法提供一个合适的方法去修改这些问题,/udev的引入,就是解决这类问题的。解决的方法是根据用户向/sysfs提供的规则(rules),udev在 /dev目录下产生对应的设备节点。
sysfs被内核使用,导出插入内核最基本的设备信息。udev就是根据这些信息来创造设备节点,sysfs被悬挂在/sys目录下。
重新命名一个设备节点
提供一个可代替或者不变的名字对于一个设备
由一个程序的输出结果就可以命名一个设备节点
改变一个设备节点的权限
启动一个脚本当一个设备节点被创造或者删除时
重命名一个网络接口
提供一种不因设备变换、设备节点而变化的机制,具有很重要的作用。具体来讲,就是让用户可以辨认出自己需要的设备。下面是我的笔记本中存储设备的节点(没有插U盘),注意我使用的命令:
下面这幅图片是我插入一个U盘的显示:注意中间的usb-genereic-
由此可以看出,同一个设备有两个不同的名称?我的u盘正好是两个分区,ata-st500是我的硬盘。
决定如何命名一个设备并且如何表现,这些就是规则文件的任务了。在udev中,这些文件保存在/etc/udev/rules.d/目录下,并且所有的文件以.rules后缀结尾。
在这个目录下的文件,udev以一定的规则解析规则文件,所以,如果你想使你的规则文件代替默认的规则文件,则最好使你的规则文件置于前面。
规则文件只能一行写一个,不能一条规则写多行,以#进行注释。
一个设备可以被不止一个规则文件控制,
就是简单的键值配对,每条规则至少一个键值,总的来说,就是匹配和赋值。例子:
KERNEL=="hdb", NAME="my_spare_disk"
”==”就是匹配符号,”=”就是赋值符号。
为了更精确的匹配硬件,udev提供了几个不同的匹配关键词,详细的,请参阅man udev
KERNEL 设备在内核的名字
SUBSYSTEM 匹配设备子系统
DRIVER 匹配设备的驱动
通过这几种匹配条件,你可以使用以下赋值字段进行控制。
NAME 设备节点的名字
SYMLINK 一个对应设备的符号链接
最后一种实际上会形成设备名的链表,如果你是有意这么做的,请使用 “+=”进行操作。
KERNEL=="hdb", NAME="my_spare_disk"
这条规则是说,匹配一个被kernel称为hdb的设备,并且命名为“my_spare_disk”,而不是叫做hdb。
KERNEL=="hdb",DRIVER=="ide-disk" SYMLINK+="sparedisk"
这条规则是说,匹配一个kernel成为“hdb”&&驱动为“ide-disk”的设备,并且在保留默认设备名称的情况下,创造一个新的符号链接叫做”sparedisk”.
为了保持/dev目录下的文件组织是系统默认的,你最好使用符号链接,建立自己的设备名称。`
KERNEL=="hdc", SYMLINK+="cdrom cdrom0"
如果你写上面这条规则,则会导致/dev/cdrom和/dev/cdrom0,且都指向名为hdc的设备