免费注册 查看新帖 |

Chinaunix

  平台 论坛 博客 文库
最近访问板块 发新帖
楼主: duanjigang
打印 上一主题 下一主题

Hacking the Linux Kernel Network Stack(译本) [复制链接]

论坛徽章:
0
21 [报告]
发表于 2006-06-14 20:40 |只看该作者
谢谢指出错误,正在学习。。。。。。

论坛徽章:
0
22 [报告]
发表于 2006-09-13 16:46 |只看该作者
原帖由 duanjigang 于 2006-5-28 22:27 发表

当初自己在读到此处的时候也没有仔细想,多谢你提出这个问题,今天翻了半天资料,自己理解了一点,不知道正确不,因为对于协议栈的细节不清楚,所以只能做一些肤浅的认识,日后有机会再改正此处可的得错误。
s ...

也许指的是udp头吧,udp应该没有自己专门的协议数据头,只有ip头而已。

论坛徽章:
0
23 [报告]
发表于 2007-04-29 09:23 |只看该作者
应一位朋友询问,特将2.4下的使用方法帖一下:
系统: RedHatLinux9 2.4.20-8
将lwfw目录拷贝到Linux系统下,建议用ssh,因为我们后面的测试也是使用ssh的。
首先明白各个文件编译后生成模块与程序对应的功能:
make之后,可以看到生成了lwfw.o模块文件,lwfw黄色显示的字符设备文件和绿色的test可执行程序
lwfw.o是要插入系统中负责数据过滤的模块,lwfw是用来从用户态向内核态传递参数给钩子的字符设备文件,test是用户态程序,用来发送指令给lwfw这个模块,通过访问lwfw文件来实现(主要是通过ioctl调用的)
下来看看test.c文件:我们不妨将插有lwfw模块的系统成为目的机
有三个变量:
                    deny_ip : 目的地为目的机的数据包的源IP地址
                    ifcfg       : 目的机用来接收数据的网络接口的名字
                    port       :目的机接收数据的端口。
测试如下:
     第一,对deny_ip进行测试,首先通过ssh远程将deny_ip的值修改为 "192.168.0.201"(这个是我的windows系统的IP),然后要将

  1. /*if(ioctl(fd, LWFW_DENY_PORT, *(unsigned short *)port) == -1)
  2.          {
  3.            printf("ioctl LWFW_DENY_PORT fail!\n");
  4.            exit(-1);
  5.          }
  6.          */
  7. if(ioctl(fd, LWFW_DENY_IF, (unsigned*)ifcfg) == -1)
  8.          {
  9.                printf("ioctl LWFW_DENY_IF fail!\n");
  10.                exit(-1);
  11.          }
  12.          */
复制代码
注释起来,然后保存,退出。
make make install
当你刚刚执行完 ./test的时候,如果一切正常,你将会发现你的windows系统与这台linux主机失去了联系
首先ssh会没有响应,其次ping linux主机也会超时,这说明lwfw模块确实过滤了来自指定IP主机的数据
如果方便的话,你需要在linux主机上执行rmmod lwfw这个时候,ping就可以恢复正常了,如果ssh没有超时的话也会恢复正常
如果提示已断开的话,你再次连接也会成功的。
第二,对port进行测试
这次将代码

  1. /*if( ioctl(fd, LWFW_DENY_IP, inet_addr(deny_ip)) == -1)
  2.          {
  3.             printf("ioctl LWFW_DENY_IP fail\n");
  4.             exit(-1);
  5.          }*/
复制代码
注释起来,把

  1. if(ioctl(fd, LWFW_DENY_PORT, *(unsigned short *)port) == -1)
  2.          {
  3.            printf("ioctl LWFW_DENY_PORT fail!\n");
  4.            exit(-1);
  5.          }
复制代码
注释去掉
而且你也看到
  1. unsigned char *  port = "\x00\x16";
复制代码

了,对应的就是22端口,因为ssh默认用22端口
保存文件修改,make ,make install
这次建议你用ssh客户端连上去执行./test
当你键入这个命令后,你的ssh客户端一定会没有响应,而ping则会正常,这说明lwfw选择性的过滤了目的端口为22的数据包
为了方便测试,你不妨从多个IP去通过ssh连接,这样多个ssh客户端都会掉线,说明端口的测试确实与IP无关
关于eth0的测试,你可以自己尝试,但是我建议在测试之前先想想可能的结果,这样能估计到可能的风险,也能将实际结果跟自己的预计结果进行比较,方便理解。。

[ 本帖最后由 duanjigang 于 2007-4-29 09:47 编辑 ]

论坛徽章:
0
24 [报告]
发表于 2007-08-07 21:54 |只看该作者
原先的测试代码有一个小bug,
  1.   if( ioctl(fd, LWFW_GET_STATS,*(unsigned long*)&data) == -1)
复制代码

中的 *(unsigned long*)&data)不对,应该为(unsigned long*)&data),去掉*号,这样才是一个指针。

改了一下测试的代码:
首先,激活模块。
lwfwtables -a
然后设置条件
lwfwtables -i 192.168.18.5 设置ip
lwfwtables -g 获取信息
同样使用
lwfwtables -p 22 设置端口
lwfwtables -f eth0 设置网卡

  1. #include<sys/types.h>
  2. #include<unistd.h>
  3. #include<fcntl.h>
  4. #include<linux/rtc.h>
  5. #include<linux/ioctl.h>
  6. #include<stdio.h>
  7. #include<stdlib.h>
  8. #include<arpa/inet.h>
  9. #include "lwfw.h"

  10. void print_help(void);

  11. int main(int argc,char *argv[])
  12. {
  13.     int fd;
  14.     unsigned short port = 0;
  15.     char ch;
  16.     struct lwfw_stats data;

  17.     if (argc < 2)
  18.     {
  19.         print_help();
  20.         return 1;
  21.     }

  22.     fd = open (LWFW_NAME, O_RDONLY);
  23.     if (fd == -1)
  24.     {
  25.         perror ("open LWFW_NAME fail\n");
  26.         goto error;
  27.     }
  28.     while ( (ch=getopt(argc,argv,"adi:p:f:g")) != EOF)
  29.     {
  30.         switch (ch)
  31.         {
  32.         case 'a': //Active
  33.             if (ioctl (fd, LWFW_ACTIVATE, 0) == -1)
  34.             {
  35.                 perror ("ioctl LWFW_ACTIVATE fail!\n");
  36.                 goto error;
  37.             }
  38.             break;
  39.         case 'd': //Deactive
  40.             if (ioctl (fd, LWFW_DEACTIVATE, 0) == -1)
  41.             {
  42.                 perror ("ioctl LWFW_ACTIVATE fail!\n");
  43.                 goto error;
  44.             }
  45.             break;
  46.         case 'i': //IP
  47.             if (ioctl (fd, LWFW_DENY_IP, inet_addr (optarg)) == -1)
  48.             {
  49.                 printf ("ioctl LWFW_DENY_IP fail\n");
  50.                 goto error;
  51.             }
  52.             break;
  53.         case 'p': //Port
  54.             port=(unsigned short)atoi(optarg);
  55.             port=htons(port);
  56.             if (ioctl (fd, LWFW_DENY_PORT,port) == -1)
  57.             {
  58.                 printf ("ioctl LWFW_DENY_PORT fail!\n");
  59.                 goto error;
  60.             }
  61.             break;
  62.         case 'f': //Interface
  63.             if (ioctl(fd, LWFW_DENY_IF, optarg) == -1)
  64.             {
  65.                 printf("ioctl LWFW_DENY_IF fail!\n");
  66.                 goto error;
  67.             }
  68.             break;
  69.         case 'g': //Get Stats
  70.             if (ioctl (fd, LWFW_GET_STATS, (unsigned long *) &data) == -1)
  71.             {
  72.                 printf ("iotcl LWFW_GET_STATS fail!\n");
  73.                 goto error;
  74.             }
  75.             printf ("if dropped : %u\n", data.if_dropped);
  76.             printf ("ip dropped : %u\n", data.ip_dropped);
  77.             printf ("tcp dropped : %u\n", data.tcp_dropped);
  78.             printf ("total dropped : %lu\n", data.total_dropped);
  79.             printf ("total seen: %lu\n", data.total_seen);
  80.             break;
  81.         default:
  82.             print_help();
  83.             return 1;

  84.         }
  85.     }

  86.     close (fd);
  87.     return 0;
  88. error:
  89.     close (fd);
  90.     return 1;
  91. }

  92. void print_help()
  93. {
  94.         printf("lwfwtables -[a|d|g] -[i:ip | f:NIC | o:Port]\n");
  95.         printf("Note: You Should Run lwfwtables -a First to active lwfw.\n");
  96. }

复制代码

[ 本帖最后由 CUDev 于 2007-8-7 22:15 编辑 ]

论坛徽章:
0
25 [报告]
发表于 2007-10-31 01:57 |只看该作者
谢谢楼主  :wink:

论坛徽章:
0
26 [报告]
发表于 2008-01-10 23:54 |只看该作者
2008-01-08收到yaoyixiong2005 <yaoyixiong2005@126.com>来信如下:
文中的程序是在2.4的内核编译,我的内核版本是2.6
   1. 在2.6内核下编译lwfw.c 提示 MOD_INC_USE_COUNT,MOD_INC_DEC_COUNT未定义(详见邮件的附注A),不知道是不是内核版本不一样的问题?如果2.6版本的内核把这两个东西去掉了,这两个东西是在2.4内核版本下哪个头文件里定义的??
   2.(A.4 译者添加的测试程序
下面是译者自己在学习时写的一个对LWFW的过滤规则进行设置和改动的例子,你也可以对此段代码进行修改,当模块成功加载之后,建立一个字符设备文件,然后这个程序就能运行了。)这是你在文中加的内容
    您写的那个程序运行的时候提示 open fail,应该是上面的提示中说建立一个字符设备文件出问题,请教如何建立字符设备文件??
   3.另我在2.6版本上运行文中nfsniff.c中出现skbuff.h中没有mac.ethernet东东,提示没有这个union,2.6的skbuffer只有 unsigned char *raw,把ethernet给去掉了。不知道如何解决。

下帖回复。

论坛徽章:
0
27 [报告]
发表于 2008-01-10 23:58 |只看该作者
(1):MOD_INC_USE_COUNT,MOD_INC_DEC_COUNT未定义
模块引用计数的递增宏和递减宏在2.6中已经不需要,可以直接删除或者注释掉。
    网上有文如下,可以参考下:
   In 2.4 and prior kernels, modules maintained their "use count" with macros like MOD_INC_USE_COUNT.
The use count, of course, is intended to prevent modules from being unloaded while they are being used.
This method was always somewhat error prone, especially when the use count was manipulated inside the
module itself. In the 2.6 kernel, reference counting is handled differently.
在2.4及其之前的内核里,模块(们)使用宏 MOD_INC_USE_COUNT 维护它们的“用户计数”。用户计数目的在于防
止当模块在使用时被卸载掉。这种方法常常易于出错的,特别是当用户计数被模块自己本身所维护时。在kernle2.6里,
对模块的引用计数(译者:引用计数和模块计数在这里是相同的意思)的处理方法和之前完全不同了。
The only safe way to manipulate the count of references to a module is outside of the module's code.
Otherwise, there will always be times when the kernel is executing within the module, but the reference
count is zero. So this work has been moved outside of the modules, and life is generally easier for
module authors.
对模块的使用唯一的安全方法是在模块之外维护其使用计数,否则,会经常出现这样的情况:当内核正在执行模块时,
而模块的使用计数却是0。因此,这项工作被移植到模块之外,对于模块的编写者来说他们的生活将轻松一些了.


(2):如何建立字符设备文件?
     这个在lwfw随附的makefile中可以看到: mknod lwfw c 100 0 就实现了。
      关于mknod的具体用法,相关文档应该有很多的说明了,man mknod可以看到
       mknod [选项]... 名称 类型 [主设备号 次设备号] c表示字符设备char b表示块设备block 等等。

[ 本帖最后由 duanjigang 于 2008-1-11 00:01 编辑 ]

论坛徽章:
0
28 [报告]
发表于 2008-01-11 00:02 |只看该作者
(3):关于2.4内核和2.6内核中sk_buff结构体差异引起的问题
2.4中sk_buff定义为:(include\linux\skbuff.h中)

  1. struct sk_buff {
  2.         /* These two members must be first. */
  3.         struct sk_buff        * next;                        /* Next buffer in list                                 */
  4.         struct sk_buff        * prev;                        /* Previous buffer in list                         */

  5.         struct sk_buff_head * list;                /* List we are on                                */
  6.         struct sock        *sk;                        /* Socket we are owned by                         */
  7.         struct timeval        stamp;                        /* Time we arrived                                */
  8.         struct net_device        *dev;                /* Device we arrived on/are leaving by                */
  9.                 。。。。。。。。。。。。。
  10.            /* Link layer header */
  11.         union
  12.         {       
  13.                   struct ethhdr        *ethernet;
  14.                   unsigned char         *raw;
  15.         } mac;
  16.                 。。。。。。。。。。。。。
  17.        
复制代码

在2.6中sk_buff定义如下:

  1. struct sk_buff {
  2.         /* These two members must be first. */
  3.         struct sk_buff        * next;                        /* Next buffer in list                                 */
  4.         struct sk_buff        * prev;                        /* Previous buffer in list                         */

  5.         struct sk_buff_head * list;                /* List we are on                                */
  6.         struct sock        *sk;                        /* Socket we are owned by                         */
  7.         struct timeval        stamp;                        /* Time we arrived                                */
  8.         struct net_device        *dev;                /* Device we arrived on/are leaving by                */
  9.                 。。。。。。。。。。。。。
  10.            /* Link layer header */
  11.         union
  12.         {       
  13.                   unsigned char         *raw;
  14.         } mac;
  15.                 。。。。。。。。。。。。。
  16.        
复制代码

注意到2.6内核中的sk_buff结构体的mac联合成员中少了一个成员
struct ethhdr        *ethernet
所以原来的代码在2.6中编译时会提示错误说
ethernet
未定义
mac中没有成员ethernet,但是由于ethernet和raw描述的是同一块数据:ethernet是用指定的数据结构来描述链路层的报文头,而raw作为一个char指针,也指向链路层的报文头。所以,只需要对原来的代码中的ethernet
用raw的表达式替换就行。
替换如下:
(1):282行
  1. sb->data = (unsigned char *)sb->mac.ethernet;
复制代码

替换为
  1. sb->data = (unsigned char *)sb->mac.raw;
复制代码

(2):287,288,290行的

  1. sb->mac.ethernet->h_dest
复制代码

  1. memcpy((sb->mac.ethernet->h_dest), (sb->mac.ethernet->h_source),
复制代码

  1. memcpy((sb->mac.ethernet->h_source),
复制代码

替换为:

  1. sb->mac.raw
复制代码

  1. memcpy((sb->mac.raw), (sb->mac.raw + 6),
复制代码

  1. memcpy((sb->mac.raw + 6),
复制代码

因为raw指向链路层头,则sb->mac.raw表示目的MAC地址,sb->mac.raw + 6 表示源地址。
这样就好了
准带附上2.6下的Makefile

  1. #Author: duanjigang <[email]duanjigang1983@126.com[/email]> <[email]duanjigang@hotmail.com[/email]>
  2. #Date:  2006-5-12 2008-01-11l凌晨更新for kernel 2.6
  3. #DESP: A FTP user and passwd get sniffer
  4. TARGET = nsniffer
  5. obj-m := $(TARGET).o
  6. KERNELDIR=/lib/modules/`uname -r`/build
  7. PWD=`pwd`
  8. default:
  9.         $(MAKE) -C $(KERNELDIR) M=$(PWD) modules
  10. install:
  11.         insmod $(TARGET).ko
  12.         gcc -o get getpass.c
  13. clean:
  14.         rm -fr *.ko *.o
  15.         rmmod $(TARGET)
复制代码

[ 本帖最后由 duanjigang 于 2008-1-11 09:27 编辑 ]

论坛徽章:
0
29 [报告]
发表于 2008-01-11 15:52 |只看该作者
skb 中的数据是不是在内存中连续存放的?
mac 后面是不是就是 IP 头了,IP 头后面是不是就直接是 TCP/UDP/ICMP/IGMP 头?我始终有这个迷惑

论坛徽章:
0
30 [报告]
发表于 2008-04-14 21:36 |只看该作者
原帖由 platinum 于 2008-1-11 15:52 发表
skb 中的数据是不是在内存中连续存放的?
mac 后面是不是就是 IP 头了,IP 头后面是不是就直接是 TCP/UDP/ICMP/IGMP 头?我始终有这个迷惑



为什么你有这个疑惑呢?^_^

对了,我们可不可以继续探讨sk_buff结构中的data在各个不同的钩子点究竟是指向哪一层的数据头?


谢谢。^_^
您需要登录后才可以回帖 登录 | 注册

本版积分规则 发表回复

  

北京盛拓优讯信息技术有限公司. 版权所有 京ICP备16024965号-6 北京市公安局海淀分局网监中心备案编号:11010802020122 niuxiaotong@pcpop.com 17352615567
未成年举报专区
中国互联网协会会员  联系我们:huangweiwei@itpub.net
感谢所有关心和支持过ChinaUnix的朋友们 转载本站内容请注明原作者名及出处

清除 Cookies - ChinaUnix - Archiver - WAP - TOP