FreeBSD下dummynet控制网络
关于FreeBSD4.4网络源代码接口层数据结构ifnet分析说明Unix系统-电脑资料
关于FreeBSD4.4网络源代码接口层数据结构ifnet分析说明Unix系统-电脑资料关于FreeBSD4.4 网络源代码接口层数据结构ifnet分析说明作者:xie_minix 在FreeBSD4.4版的NET/3底部的接口层中包含了一些重要的数据结构,其中ifnet数据结构是有关网络接口设备通用部分的最重要的数据结构,他的源代码部分在文件/usr/src/sys/net/if.h中.要分关于FreeBSD4.4网络源代码接口层数据结构ifnet分析说明作者: xie_minix在FreeBSD4.4版的NET/3底部的接口层中包含了一些重要的数据结构,其中ifnet数据结构是有关网络接口设备通用部分的最重要的数据结构,他的源代码部分在文件/usr/src/sys/net/if.h中.要分析链路层(网卡驱动程序)源代码,必须要理解该结构.Ifnet数据结构非常大,但是比较容易理解,一个网络接口有一个ifnet结构,每一个ifnet结构都链接起来了,形成一个单向链表.按他的功能来分一共有五个部分:1.实现信息: 包括一些网络适配器名,唯一标示等.2.硬件信息: 包括网络适配器的一些属性,如以太网,PPP等3.接口统计: 主要被用于SNMP4.函数指针: 包括标准的对设备文件操作的函数指针,如OPEN,IOCTL等5.输出队列: mbuf的管理等以下是ifnet的成员结构说明:struct ifnet *if_next: 因为ifnet结构是一个单向链表,所以在结构头一般都是链表的指针,既指向下一ifnet(即下一网络适配器的ifnet).struct ifaddr *if_addrlist: ifaddr数据结构是描述该接口的地址,每一个ifnet都有一个ifaddr结构链表,因为我们知道,一个网卡他可以支持各种各样的协议,如TCP/IP,NETBEUI,APPLETALK等,所以对ifaddr 结构来说,他也应该是一个单向链表,他的结构如下:struct ifaddr *ifa_next: 一样,链表的头一般是下一该结构的指针.struct ifnet *ifa_ifp:回指针,即指到用该结构的ifnet结构.struct sockaddr *ifa_addr: 指向协议的接口地址,搞网络研究的读者应该很熟悉struct sockaddr *ifa_dstaddr:对方的地址(PPP是对方,以太网是广播地址)struct sockaddr *ifa_netmask:这不用我说void (*ifa_rtrequest) ( ): 路由使用u_short ifa_flags: 路由使用short ifa_refcnt: 该结构的引用记数int ifa_matric: 路由使用char *if_name: 设备的名称,如:ne2000为”ne”,LANCE(AMD公司)为leshort if_unit: 接口号,该类型的卡第一块为0,第二块为1等.u_short if_index: 在内核中该设备的索引号(唯一值).short if_flags: 该网卡的状态和属性,读网卡的状态时使用,如网卡是否正忙?设置混杂模式,是否使用ARP,支持PPP或BROADCAST等.short if_timer: 用于定时接受统计数据int if_pcount: 用于混杂模式侦听者的数量caddr_t if_bpf: 用于BPF(包过滤):struct if_data{ :此结构是通用的接口信息u_char ifi_type: 硬件类型,如IFT_ETHER代表以太网,IFT_FDDI代表光纤网络.u_charifi_physical;以太网的类型(如10base-T,AUI,等等)u_char ifi_addrlen: 数据链路地址的长度,以太网是6u_char ifi_hdrlen: 硬件首部长度,以太网的首部是14u_long ifi_mtu: 最大传输单元,以太网是1500u_long ifi_metric:一般是0,路由使用u_longifi_baudrate;连接速度u_longifi_ipackets;接口上接收的包数u_longifi_ierrors;接收错误包数u_longifi_opackets;在接口上发送的包数u_longifi_oerrors;在接口上发送包错的数u_longifi_collisions;载波帧听的冲突数u_longifi_ibytes;总共接收的字节数u_longifi_obytes;发送的字节数u_longifi_imcasts;接受的多播包数u_longifi_omcasts;发送的多播包数u_longifi_iqdrops;本接口接收失败的包数u_longifi_noproto;不被支持协议的包数u_longifi_h was sist;/* 半波卸载性能*/u_longifi_unused;没被使用structtimeval ifi_lastchange;最后一次更改的时间}neowredhat 回复于:2003-06-11 16:12:07厉害!simonzhan 回复于:2004-05-19 11:59:20强!。
freeBSD 安装 组建家庭网络
第一章:安装FreeBSD首先你最好要有FreeBSD的安装光盘,你可以从软件商店里面花10块钱买到,也可以从 上免费下载三张安装光盘的第一张ISO镜像文件然后再将它刻录成光盘。
FreeBSD还支持很多安装介质,比如Ftp、NFS等,但都不如光盘保险。
接着可以从别的台式机上借过来光驱、键盘、显示器给该主机装上,把主板BIOS设置为从光驱引导,如果是486电脑,主板可能不支持光驱启动这个时候你可以用光盘上floppies目录里面的boot.flp和kern.flp这两个软盘镜像文件制作两张启动软盘,制作过程请参考光盘上的readme.txt文本,启动时候先插boot盘再按提示插kern盘引导。
正常引导之后我们可以看到图1的画面。
图1为了简单起见直接选择第一项―skip kernel configuration and continue with installation‖忽略内核配置继续安装,如果选择第二项系统将进入一个简单内核的配置界面,在那里可以去除一些你电脑里面没有的设备,比如SCSI设备、USB设备等等,这样的好处就是精简了系统,减少了内核的大小也能缩短系统的启动检测硬件的时间。
接下来的图2为选择安装方式,我们选择―Express‖模式进行安装,这和―Standard‖模式的主要区别在于在拷贝完文件之后不会要求你立刻设置网络、用户等信息,所以是给没有耐心的人的选项,此处选择这个模式的目的是不让安装系统设置网卡,因为网卡要到后面通过单独设置―/etc/rc.conf‖来实现。
图2图3图4图3显示的是FreeBSD自带的Fdisk硬盘分区编辑器,由于我的硬盘是个空盘,只显示了一个名为―unused‖的未使用分区,如果硬盘上还有DOS或NTFS分区的话在这里均能看到,如果硬盘已经没有空余空间,请先用Pqmagic软件等分区工具事先划分出来一块未使用的空间。
有了一定大小的―unused‖分区后就可以选中这个―unused‖的分区然后按―C‖键在该分区上创建FreeBSD分区,FreeBSD称之为―Slice‖,接着我们看到图4的画面,按―Q‖键保存并进入下一步。
运用FreeBSD替代路由器实现网络地址转换
第28卷 第6期桂林电子科技大学学报Vo l.28,N o.6 2008年12月Journal of G uilin University of Electronic Technology Dec.2008 运用FreeBSD替代路由器实现网络地址转换韦程馨,潘家英(广西中医学院信息网络中心,广西南宁 530001)摘 要:校园网事实上就是校园内部的Intr anet,一般通过交换设备组网,再通过路由器接入CERN ET主干线路。
对校园网使用效果影响较大的因素就是网络出口问题。
校园网的特殊性要求必须使用NA T(网络地址转换),这就需要出口的核心设备应具有较强的地址转换能力,通常这是由路由器来完成的,然而路由器有限的CPU处理能力限制了处理的效率。
利用Fr eeBSD的高性能和高可靠性,通过对内核的编译,启用基本系统内建网络服务功能k I P-FI REWA L L,配合当今廉价而高速的P C硬件,进行网络地址转换(N AT)和数据包过滤,替代路由器实现高效、稳定、安全的网络传输。
关键词:Fr eeBSD;IP FIR EW A L L;N AT;内核;路由器中图分类号:T P393.06 文献标识码:A 文章编号:1673-808X(2008)06-0511-05Using freeBSD to replace router to make network address translationW EI Cheng-x in,P A N J ia-y ing(Informat ion Net work Center,Guangx i T ra ditional Chi nese Medical University,Nanning530001,China)Abstract:A campus netw or k is a n intr anet on cam pus connected to the CERN ET by Sw it ch Net wo rking and theRo uter.A significant impacting facto r of the campus netw or k effect is net wo rk o ut put pro blem.Ca mpus net wo rkmust use N AT(net wo rk addr ess tra nslatio n)and r equires t he cor e equipm ent o f output to switch the Netw o rk Ad-dr ess po wer fully.T his par t of w or k is usually car ried o ut by the Ro uter.Ho wev er,the Ro uter is inefficient han-dling with CPU and thus limits the efficiency o f Net wo rk A ddr ess Co nv ersio n.In v iew of the efficiency and r elia-bility of Fr eeBSD,com piling the ker nel,using the netw or k serv ice functio n in the basic sy stem——I PF IRE-WA L L,and coo per ating the cheap but hig h speed PC har dw ar e,o ne can achieve the netw o rk addr ess conver sio n(NA T)and packet filter ing,then finally r eplace the R outer t o make efficient,st able and secur e netw or k t ransmis-sion.Key words:Fr eeBSD;IP FI REWA L L;N A T;kernel;r outer 随着校园网的高速发展,学校上网用户也随之增多,校园网用户数量的增加使核心路由器负担也随之加重。
FreeBSD常用命令大全
FreeBSD常用命令大全1.禁止ping/etc/rc.d/rc.localecho 1 > /proc/sys/net/ipv4/icmp_echo_ignore_all2.对用户和口令文件进行权限控制chmod 600 /etc/passwdchmod 600 /etc/shadowchmod 600 /etc/groupchmod 600 /etc/gshadow3.给下面文件加上不可更改属性chattr +i /etc/passwdchattr +i /etc/shadowchattr +i /etc/groupchattr +i /etc/gshadow4.对vsftp进行访问控制vi hosts.denyvsftpd: all --先禁止所有vsftp的请求vi hosts.allowvsftpd: 192.168.2.1 --再允许内网的vsftd请求5.关闭无用端口,只开启常规端口(21、22、80、443)service portmap stopchkconfig --level 35 portmap off --关闭111端口netstat -nap |grep 32768killall rpc.statd --关闭32768端口netstat -nap |grep 631killall cupsd --关闭631端口service sendmail stopchkconfig --level 12345 sendmail off --关闭25端口6.apache安全设置(先备份httpd.conf配置文件)vi /etc/httpd/httpd.confServerSignature OffServerTokens Prod ---隐藏Apache的版本号及其它敏感信息<Directory>Options -ExecCGI -FollowSymLinks -Indexes --关闭CGI执行程序、includes、目录浏览</Directory>将UserDir public_html改为UserDir disabled#ScriptAlias /cgi-bin "/usr/local/apache/cgi-bin/"注释掉manual7.vi /etc/profileHISTFILESIZE=30HISTSIZE=30 --这表示每个用户的“.bash_history”文件只可以保存30条旧命令tmout=600 --用户将在10分钟无操作后自动注销vi /etc/skel/.bash_logoutrm -f $HOME/.bash_history --当用户每次注销时,“.bash_history”文件都会被删除。
网桥原理及源代码
网桥原理及源代码详解信息来源:邪恶八进制中国复制内容到剪贴板代码:/* 概述:* 该代码在FB中提供桥接功能,不过他只是在以太网接口上工作,能提供多个逻辑桥* ,我们称为组,组是由一组有相同组ID的接口组成,组ID的范围在1到2^16-1之间.* 打开桥的功能是通过sysctl net.link.ether.bridge=1来启动的.* 而sysctl net.link.ether.bridge_cfg是把以太网接口进行分组的命令,如: * sysctl net.link.ether.bridge_cfg="vr0:1,vr1:1,fxp0:2,fxp1:2" 该命令的结果* 为网卡vr0和vr1可以进行相互通信,fxp0和fxp1之间可以互相转发,等于是分为俩组了.* 但目前的该项设置还不能进行多组成员和单向控制,即一块卡可以为多个组的成员和某卡* 与另外卡的数据单向流动.在本文中,我将结合代码来讲解如何实现以上的功能.* 在本代码中,重要的数据结构是cluster_softc,他主要是记录一个组的接口所连接的机器* 的硬件地址,该地址数组存储采用HASH算法,据我所知,4.4版和OpenBSD版的HASH函数算法根本不同,* 我们在下面的代码分析过程中将看到,我也将讲解两个版本的不同之处,说实话,该算法我根本看* 不懂(OpenBSD),估计该算法应该有相关的论文描述.* 代码的学习顺序:* 由于在if_ethersubr.c中的ether_input函数接到一数据包后,先查看bridge功能是否打开,* 即判断全局变量do_bridge是否为1(该变量是由上面讲的sysctl来控制的),为真的话就调用* 本文中的函数bridge_in(详细可看我写的"ethernet网络驱动代码详解"),所以在本文中的* bridge_in函数是第一个被调用的.该函数的作用是在上面讲的哪个重要的数据结构中查找* 目标地址要通过本机的哪块卡发送,当然其中还涉及到多播,广播和是否将网卡进行分组以* 及是否发送方,目的方经过的本机网卡是否被分在同组中等,在完成后,如果成功找到了发送* 到目的地机器和本机直接相连的网卡就返回该网卡的ifnet结构指针(该结构可连接所描述的卡* 的所有信息,见我所写的"关于FreeBSD4.4网络源代码接口层数据结构ifnet 分析说明"),然后* if_ethersubr.c中的ether_input函数还要查看是否是发给本机的包,如果不是则调用本文的* bridge_forward函数进行数据的转发,这就是本文的主要功能.和交换机的原理有点类似.* 性能分析:* 由于在进行桥转发的过程中,是一定要使网卡工作在混杂模式的,所以进行网桥工作的卡要选购* 性能好的网卡,我个人觉得intel,3com等比较适合,其他的如rtl8139卡最好只用来做实验,不要* 用于实际的工作中(如果要我说明原因,请看看他的驱动程序你就知道了,但单机上网没关系),另* 外,PCI漕内不要其他的卡(如声卡等),我们知道,网卡驱动程序目前在BSD中工作于中断驱动模式,* 也就是说,进来一个包就能产生一个中断,而中断的系统开销有多达大家可以查看内核代码,总之* 是非常大,如果你是四块卡,而且担任网桥及一些过滤功能的话,肯定数据包通过量会比较大,那么* 中断产生的频率是平常一块卡的十几甚至是几十倍(平常的卡一个是数据量不大,另一个是不在混* 杂模式下).要想桥工作的效率提高,建议去除本机处理针对本机的高层协议处理,如IP协议等,或改* 写驱动程序为半轮询模式(使用timeout读卡的数据是否到达),OpenBSD中的bridge是真正的把bridge做* 为一个设备来编写的,配备了标准的设备驱动程序,不过我还没有完全分析过,大概的看了看,觉得* 比FreeBSD中的桥功能要强很多啊!* 如何驱动一个网桥:* 首先在内核配置文件中加入以下一行:* option BRIDGE* 注:我所使用的4.4版本是必须的,当前版本不需要这样,可以kld动态加载. * 重新编译核心后重启,使用 sysctl net.link.ether.bridge=1启动桥功能. * 如果想把网卡编组,使用 sysctl net.link.ether.bridge_cfg="设备:组号,设备:组号,..."即完成.*/[/color]/** 此处略去BSD版权申明*/#include <sys/param.h>#include <sys/mbuf.h>#include <sys/malloc.h>#include <sys/protosw.h>#include <sys/systm.h>#include <sys/socket.h>#include <sys/ctype.h>#include <sys/kernel.h>#include <sys/sysctl.h>#include <net/pfil.h>#include <net/if.h>#include <net/if_types.h>#include <net/if_var.h>#include <netinet/in.h>#include <netinet/in_systm.h>#include <netinet/in_var.h>#include <netinet/ip.h>#include <netinet/if_ether.h>#include <net/route.h>#include <netinet/ip_fw.h>#include <netinet/ip_dummynet.h>#include <net/bridge.h>/*--------------------*/#define HASH_SIZE 8192 /* HASH表的大小,必须是2的权数 *//*hash表,该表存放与本机各块卡相连机器的硬件地址*/typedef struct hash_table {struct ifnet * name; /*与某机器相连的本机网卡的ifnet结构指针*/u_char etheraddr[6]; /*某台机器的硬件地址*/u_int16_t used; /*这是一个是否在用(某机器是否活动)的标志*/} bdg_hash_table ;/**哈稀函数,我不理解他的算法,难道这样就不会产生同义字了吗?*/#define HASH_FN(addr) ( \ntohs( ((u_int16_t *)addr)[1] ^ ((u_int16_t *)addr)[2] & (HASH_SIZE -1))/** 下面的结构存储了本机的各卡的硬件地址.*/struct bdg_addr {u_char etheraddr[6] ;/*本机卡的硬件地址*/u_int16_t _padding ;/*这个成员还象没看到他用过*/};/** 这就是我们上面说的组,每块卡都有一个cluster_softc结构*/struct cluster_softc {u_int16_t cluster_id; /*组的ID号*/u_int16_t ports;/*顺序号*/bdg_hash_table *ht;/*和该卡所连接的机器MAC地址哈稀表首指针*/struct bdg_addr *my_macs; /* 本卡的硬件地址 */};extern struct protosw inetsw[]; /* 在netinet/ip_input.c中 */extern u_char ip_protox[]; /* 在netinet/ip_input.c中 */static int n_clusters; /* 组的数量*/static struct cluster_softc *clusters; /*定义一个组的全局初始指针*/#define BDG_MUTED(ifp) (ifp2sc[ifp->if_index].flags & IFF_MUTE) /*检查本机某卡是否桥启用*/#define BDG_MUTE(ifp) ifp2sc[ifp->if_index].flags |= IFF_MUTE /*禁止本机的该卡桥功能*/#define BDG_CLUSTER(ifp) (ifp2sc[ifp->if_index].cluster)/*根据卡在核心的唯一序号定位他的cluster_softc结构指针*/#define BDG_SAMECLUSTER(ifp,src) \(src == NULL || BDG_CLUSTER(ifp) == BDG_CLUSTER(src) /*俩卡是否在同一组里?*//*src==NULL代表数据包来自ether_output函数.*/#ifdef __i386__/*比较两个地址是否相同,硬件地址是6个字节,所以他先比较后面的长字(4个字节),再比较前一个字(2个字节)*/#define BDG_MATCH(a,b) ( \((u_int16_t *)(a))[2] == ((u_int16_t *)(b))[2] && \*((u_int32_t *)(a)) == *((u_int32_t *)(b))/*以下是比较广播地址*/#define IS_ETHER_BROADCAST(a) ( \*((u_int32_t *)(a)) == 0xffffffff && \((u_int16_t *)(a))[2] == 0xffff#else/* 非i386的机器不一定按长字或字对齐,所以按字节的方式比较. */#define BDG_MATCH(a,b) (!bcmp(a, b, ETHER_ADDR_LEN)#define IS_ETHER_BROADCAST(a) (!bcmp(a, "\377\377\377\377\377\377", 6)) #endif/**以下两句是调试用的.*/#define DDB(x) x#define DEB(x)static int bdginit(void);/*申明bridge初始化函数*/static void parse_bdg_cfg(void);/*申明sysctl的字符参数分解函数*/static int bdg_ipf; /* bridge中的IPFilter */static int bdg_ipfw;#if 0 /* 调试用的打印信息 */static char *bdg_dst_names[] = {"BDG_NULL ","BDG_BCAST ","BDG_MCAST ","BDG_LOCAL ","BDG_DROP ","BDG_UNKNOWN ","BDG_IN ","BDG_OUT ","BDG_FORWARD " };#endif/** 以下系统初始化几个结构*/static struct bdg_stats bdg_stats ;/*该结构用于统计信息*/static struct callout_handle bdg_timeout_h ;/*用于保存timeout函数返回值*//* 把一网络接口加到组中,当然如果定义的组不存在的话,就建立一个该组.*/static struct cluster_softc *add_cluster(u_int16_t cluster_id, struct arpcom *ac){struct cluster_softc *c = NULL;/*这是准备用于返回的加入(没有该组就是建立的)组结构*/int i;for (i = 0; i < n_clusters ; i++) /*遍历所有组,n_clusters在加入后或建立后会++*/if (clusters[i].cluster_id == cluster_id)/*有该组号吗?*/ goto found;/*有,跳过建立一个新的,直接到加入该组,此时i+全局变量clusters的内容是发现该组的cluster_softc指针*//* 我们要在此建立一个新的组*/c = malloc((1+n_clusters) * sizeof (*c), M_IFADDR, M_NOWAIT |M_ZERO);/*分配这么多干吗,错了吗?没有,看后面就知道了,他进行了举家搬迁,把前面的都搬过来了*/if (c == NULL) {/* 分配失败 */printf("-- bridge: cannot add new cluster\n");/*应该加上,no memory说明*/return NULL;}/*分配一个HASH表给该卡,要用掉蛮多内存的,即12*8K*/c[n_clusters].ht = (struct hash_table *)malloc(HASH_SIZE * sizeof(struct hash_table),M_IFADDR, M_WAITOK | M_ZERO);if (c[n_clusters].ht == NULL) {/*没内存了,很少出现此情况*/ printf("-- bridge: cannot allocate hash table for new cluster\n"); free(c, M_IFADDR);/*HASH表没分配到,当然前面分配到的cluster_softc结构要释放掉*/return NULL;}/*分配一存放本机网卡硬件地址的表*/c[n_clusters].my_macs=(struct bdg_addr *)malloc(BDG_MAX_PORTS * sizeof(struct bdg_addr),M_IFADDR, M_WAITOK | M_ZERO);if (c[n_clusters].my_macs == NULL) { /*内存分配不成功*/ printf("-- bridge: cannot allocate mac addr table for new cluster\n");free(c[n_clusters].ht, M_IFADDR);/*上面跟这个结构有关的已分配结构都要释放*/free(c, M_IFADDR);return NULL;}c[n_clusters].cluster_id = cluster_id;/*新组的ID号*/c[n_clusters].ports = 0;/*在新组中加入的卡*//** 在这个地方就开始了前面说是否错了的处理的地方,意思是把原来分配的组的指针数组拷贝到新的组中.*/if (n_clusters > 0) {for (i=0; i < n_clusters; i++)/*因为n_clusters在上面已经设置完了,不需要i=<*/c[i] = clusters[i]; /*搬家了*//***/for (i = 0 ; i < if_index && i < BDG_MAX_PORTS; i++)/*if_index是系统内的所有网卡数*/if (ifp2sc[i].cluster != NULL)ifp2sc[i].cluster = c + (ifp2sc[i].cluster - clusters);free(clusters, M_IFADDR);/*释放掉老的cluster_softc*/}clusters = c;/*重新定位全局变量指针,新的cluster_softc指针数组的头指针为新分配的C*/i = n_clusters;n_clusters++;found:c = clusters + i; /* 刚申请的组指针 */bcopy(ac->ac_enaddr, &(c->my_macs[c->ports]), 6); /*把本网卡的硬件地址存入刚申请的组中*/c->ports++;/*该组的网卡数加一块*/return c;}/** 关闭桥转发, 并在接口卡上去掉混杂模式,HASH表和网卡的分组也去除*/static voidbridge_off(void){struct ifnet *ifp ;int i, s;DEB(printf("bridge_off: n_clusters %d\n", n_clusters)IFNET_RLOCK();/*新加的,老版本中没有,其定义为mtx_lock(&ifnet_lock),好象是互斥锁,我没有研究过.关于ifnet_lock,是定义在if.c中,mtx结构,应该是互斥体结构,之所以加上他,应该是和SMP有关系.*/TAILQ_FOREACH(ifp, &ifnet, if_link) {/*if_link是ifnet链表中的下一个ifnet*/struct bdg_softc *b;if (ifp->if_index >= BDG_MAX_PORTS)/*一般不会出现这种情况*/ continue; /* */b = &(ifp2sc[ifp->if_index]);if ( b->flags & IFF_BDG_PROMISC {/*如果网卡在混杂模式就做下面的工作*/s = splimp();/*关网络中断*/ifpromisc(ifp, 0);/*去掉混杂模式,ifp是要去掉该模式的网卡的ifnet 结构指针.*/splx(s);/*开网络中断*/b->flags &= ~(IFF_BDG_PROMISC|IFF_MUTE) ;DEB(printf(">> now %s%d promisc OFF if_flags 0x%x bdg_flags 0x%x\n", ifp->if_name, ifp->if_unit,ifp->if_flags, b->flags)}b->flags &= ~(IFF_USED) ;/*去掉IFF_USED标志,既不再桥转发了.*/b->cluster = NULL;/*该卡所在的组的指针也置空.*/bdg_stats.s[ifp->if_index].name[0] = '\0';/*当然统计信息也要改了.*/}IFNET_RUNLOCK();/*解互斥锁,看到这应该明白了,互斥锁是在修改ifnet结构和bdg_stats结构时进行保护的.*/s = splimp();for (i=0; i < n_clusters; i++) {/*所有组*/free(clusters[i].ht, M_IFADDR);/*把HASH表释放掉*/free(clusters[i].my_macs, M_IFADDR);/*把在组中记录本机网卡硬件地址的空间释放掉*/}if (clusters != NULL)free(clusters, M_IFADDR);/*释放组占用的空间*/clusters = NULL;/*置组的头的指针为空*/n_clusters =0;/*卡分组的数量也重新置0*/splx(s);}/** 把所有卡都置为混杂模式.*/static voidbridge_on(void){struct ifnet *ifp ;int s ;IFNET_RLOCK();/*看前面bridge_off函数有说明*/TAILQ_FOREACH(ifp, &ifnet, if_link) {/*遍历整个ifnet结构*/ struct bdg_softc *b = &ifp2sc[ifp->if_index];if ( !(b->flags & IFF_USED) /*如果没有在使用*/continue ;if ( !( ifp->if_flags & IFF_UP) {/*如果接口关闭*/s = splimp();if_up(ifp);/*打开接口,在if.c中,调用if_route函数,比较复杂,到讲route.c和radix.c的时候再讲*/splx(s);}if ( !(b->flags & IFF_BDG_PROMISC) {/*是否在混杂模式?*/ int ret ;s = splimp();ret = ifpromisc(ifp, 1);/*设置混杂模式,1是加上混杂模式,0是取消混杂模式*/splx(s);b->flags |= IFF_BDG_PROMISC ;/*在该卡的bdg_softc结构中也加上混杂模式*/DEB(printf(">> now %s%d promisc ON if_flags 0x%x bdg_flags 0x%x\n", ifp->if_name, ifp->if_unit,ifp->if_flags, b->flags)}if (b->flags & IFF_MUTE) {/*去掉阻塞*/DEB(printf(">> unmuting %s%d\n", ifp->if_name, ifp->if_unit)b->flags &= ~IFF_MUTE;}}IFNET_RUNLOCK();}/***该函数在执行系统命令 sysctl net.link.ether.bridge 和sysctlnet.link.ether.bdg_cfg后*/static voidreconfigure_bridge(void){bridge_off();/*先关闭所有卡的桥转发,该函数在上面*/if (do_bridge) {/*如果桥转发打开了,就执行分析bdg_cfg设置的字符串*/if (if_index >= BDG_MAX_PORTS) {printf("-- sorry too many interfaces (%d, max is %d),"" disabling bridging\n", if_index, BDG_MAX_PORTS);do_bridge=0;return;}parse_bdg_cfg();/*分析字符串,该函数在下面*/bridge_on();/*打开所有卡的桥转发,该函数的描述在上面*/}}static char bridge_cfg[1024]; /* in BSS so initialized to all NULs *//**分析字符串函数,如:...bdg_cfg=vr0:1,vr1:1,fxp0:2,fxp1:2 也就是说对卡进行分组时,要把卡的名称,设备号,及组号*分解出来,该函数不和内核有太多牵连,纯粹是字符串分解函数,按照目前的这种分解情况,每块卡只能存在于一个组中,*如果我们希望他能在多个组中应该怎么办?而且一卡多组的情况是非常有用的,如: *..........................................| *..........................................| ...Internet 入口*................................._____________________ *.................................|.......卡1 ........| *.................................|.卡2...........卡3.| 透明网桥A *.................................|___________________| *...................................|..............| *...................................|..............| *................................主机B...........主机C*说明:网桥A是一个有三块卡的FreeBSD主机,其中卡1通向Internet* 主机B是认证服务器,主机C是数据库服务器.* 要求从Internet进入的数据包只能到主机B进行认证,认证后该机IP地址存入主机A的缓冲,才能和C通讯* 也就是说卡1和卡2是同组,卡1同卡3在认证后将是同组,关于A记录已认证IP地址的方法,我认为最好使用* patricia树,但在树中只存储主机路由及认证信息.*/static voidparse_bdg_cfg(){char *p, *beg ;int l, cluster;static char *sep = ", \t";for (p = bridge_cfg; *p ; p++) {struct ifnet *ifp;int found = 0;char c;/*该函数在libc库中,index.c中.如下:*//*index(p, ch)register const char *p, ch;{for (;; ++p) {if (*p == ch)return((char *)p);if (!*p)return((char *)NULL);}}*/if (index(sep, *p)) /* 由上面的解释可知道,跳过',号' 和'TAB键 ' */continue ;/* 卡名是由小写字母和数字组成,如:vr0,fxp0,等 */for ( beg = p ; islower(*p) || isdigit(*p) ; p++ /*循环开始,是小写或数字时继续*/;l = p - beg ; /* 得到了名字的长度*/if (l == 0) /* 长度是0当然是不行的 */break ;if ( *p != ':' /* 紧接的后面的字符如果不是":",那么就假定默认为组1 */cluster = 1 ;elsecluster = strtoul( p+1, &p, 10);/*字符转换为无符号整数*/c = *p; /*暂时把p指针中的东西保存到C中,因为要把0(字符串结尾)放到*p 中,以后再换回*/*p = '\0';/** 开始在接口列表中查找该网卡名*/IFNET_RLOCK(); /* 互斥锁 */TAILQ_FOREACH(ifp, &ifnet, if_link) {/*遍历整个ifnet结构*/ char buf[IFNAMSIZ];snprintf(buf, sizeof(buf), "%s%d", ifp->if_name, ifp->if_unit);/*把卡名字和子设备号合并放到buf中,如:名字=vr,子设备号=0,合并后为vr0*/ if (!strncmp(beg, buf, max(l, strlen(buf)))) {/*比较我们参数的设备名和buf中的相等吗?*/struct bdg_softc *b = &ifp2sc[ifp->if_index];if (ifp->if_type != IFT_ETHER && ifp->if_type != IFT_L2VLAN) {/*不是以太网卡*/printf("%s is not an ethernet, continue\n", buf);continue;}if (b->flags & IFF_USED) {/*如果接口卡中有该标志,那他已经用于bridge 了.*/printf("%s already used, skipping\n", buf);break;}b->cluster = add_cluster(htons(cluster), (struct arpcom *)ifp);/*调用前面的函数,把卡加入到组中.*/b->flags |= IFF_USED ;/*加上bridge开始使用标志*/sprintf(bdg_stats.s[ifp->if_index].name, /*打印信息到屏幕*/"%s%d:%d", ifp->if_name, ifp->if_unit, cluster);DEB(printf("--++ found %s next c %d\n",bdg_stats.s[ifp->if_index].name, c)found = 1;/*置发现标志*/break ;}}IFNET_RUNLOCK();/*解互斥锁*/if (!found)/*没找到接口,可能是你参数输入错误*/printf("interface %s Not found in bridge\n", beg);*p = c;/*换回来*/if (c == '\0')break; /* 到了字符串结尾 */}}/** 如果使用的是SYSCTL_PROC来定义一个控制节点,那么第7个参数是一个处理函数指针,以下这两个函数都是处理函数*/static intsysctl_bdg(SYSCTL_HANDLER_ARGS) /*以下是在sysctl.h中关于SYSCTL_HANDLER_ARGS的说明*//*#define SYSCTL_HANDLER_ARGS struct sysctl_oid *oidp, void *arg1, int arg2, struct sysctl_req *req */{int error, oldval = do_bridge ;/*把do_bridge放到oldval中暂时保存*/error = sysctl_handle_int(oidp, oidp->oid_arg1, oidp->oid_arg2, req);/*该函数把数据放到全局结构变量oidp中*//*由于oidp中有指向do_bridge的指针,所以*//*sysctl中的=xxx的值将放到do_bridge中*/DEB( printf("called sysctl for bridge name %s arg2 %d val %d->%d\n", oidp->oid_name, oidp->oid_arg2, oldval, do_bridge);if (oldval != do_bridge)/*如果和原来的值不同,就重新设置bridge*/ reconfigure_bridge();return error ;}/** 和上面是一样的,这里就不多解释了.他们不同之处是一个是整数型,一个是字符串型*/static intsysctl_bdg_cfg(SYSCTL_HANDLER_ARGS){int error = 0 ;char old_cfg[1024] ;/*不同的地方,即是字符串*/strcpy(old_cfg, bridge_cfg) ;/*字符串拷贝,已经检查过,没有溢出产生.如有兴趣,可查LIBC库*/error = sysctl_handle_string(oidp, bridge_cfg, oidp->oid_arg2, req);DEB(printf("called sysctl for bridge name %s arg2 %d err %d val %s->%s\n", oidp->oid_name, oidp->oid_arg2,error,old_cfg, bridge_cfg);)if (strcmp(old_cfg, bridge_cfg))reconfigure_bridge();return error ;}static intsysctl_refresh(SYSCTL_HANDLER_ARGS){if (req->newptr)reconfigure_bridge();/*该函数在上面*/return 0;}SYSCTL_DECL(_net_link_ether);/*申明一节点,表示下面的SYSCTL将继承该节点*/SYSCTL_PROC(_net_link_ether, OID_AUTO, bridge_cfg,CTLTYPE_STRING|CTLFLAG_RW,&bridge_cfg, sizeof(bridge_cfg), &sysctl_bdg_cfg, "A","Bridge configuration");/*网卡的分组,"A"代表参数是字符串,sysctl_bdg_cfg是处理的函数的名称*/SYSCTL_PROC(_net_link_ether, OID_AUTO, bridge, CTLTYPE_INT|CTLFLAG_RW, &do_bridge, 0, &sysctl_bdg, "I", "Bridging");/*对桥转发开关的控制,sysctl_bdf是控制函数,"I"代表参数是整数型*/SYSCTL_INT(_net_link_ether, OID_AUTO, bridge_ipfw, CTLFLAG_RW, &bdg_ipfw,0,"Pass bridged pkts through firewall");/*对桥的防火墙的开关*/SYSCTL_INT(_net_link_ether, OID_AUTO, bridge_ipf, CTLFLAG_RW, &bdg_ipf, 0,"Pass bridged pkts through IPFilter");/*包过滤的开关*//*因为下面都是控制整数型变量,所以做一个宏*/#define SY(parent, var, comment) \static int var ; \SYSCTL_INT(parent, OID_AUTO, var, CTLFLAG_RW, &(var), 0, comment);/*以下的SYSCTL大都用于防火墙控制*/int bdg_ipfw_drops;SYSCTL_INT(_net_link_ether, OID_AUTO, bridge_ipfw_drop,CTLFLAG_RW, &bdg_ipfw_drops,0,"");int bdg_ipfw_colls;SYSCTL_INT(_net_link_ether, OID_AUTO, bridge_ipfw_collisions, CTLFLAG_RW, &bdg_ipfw_colls,0,"");SYSCTL_PROC(_net_link_ether, OID_AUTO, bridge_refresh,CTLTYPE_INT|CTLFLAG_WR,NULL, 0, &sysctl_refresh, "I", "iface refresh");#if 1SY(_net_link_ether, verbose, "Be verbose");SY(_net_link_ether, bdg_split_pkts, "Packets split in bdg_forward"); SY(_net_link_ether, bdg_thru, "Packets through bridge");SY(_net_link_ether, bdg_copied, "Packets copied in bdg_forward");SY(_net_link_ether, bdg_dropped, "Packets dropped in bdg_forward");SY(_net_link_ether, bdg_copy, "Force copy in bdg_forward");SY(_net_link_ether, bdg_predict, "Correctly predicted header location");SY(_net_link_ether, bdg_fw_avg, "Cycle counter avg");SY(_net_link_ether, bdg_fw_ticks, "Cycle counter item");SY(_net_link_ether, bdg_fw_count, "Cycle counter count");#endifSYSCTL_STRUCT(_net_link_ether, PF_BDG, bdgstats,CTLFLAG_RD, &bdg_stats , bdg_stats, "bridge statistics");static int bdg_loops ;static voidbdg_timeout(void *dummy){static int slowtimer; /*会初始化为0*/if (do_bridge) {/*桥转发打开了就执行下面的*/static int age_index = 0 ;int l = age_index + HASH_SIZE/4 ;/*l=2048,因为HASH表内放的是指针,每个指针占用4字节,所以/4表示有多少个指针*/int i;/**/if (l > HASH_SIZE)/*这时候l=2048,怎么可能>HASH_SIZE(9182)*/l = HASH_SIZE ;for (i=0; i<n_clusters; i++) {/*遍历每个组*/bdg_hash_table *bdg_table = clusters[i].ht;/*该网卡的HASH表*/for (; age_index < l ; age_index++)/*遍历整个HASH表*/if (bdg_table[age_index].used) /*如果该成员被使用了*/bdg_table[age_index].used = 0 ;/*清除掉,但我不清楚为什么不同时清除成员name,如果在此时bridge_in正接收*//*到包,会把name保存到old变量中,会不会出问题呢?(可看看下面的bridge_in)*/else if (bdg_table[age_index].name) {bdg_table[age_index].name = NULL ;}}if (age_index >= HASH_SIZE)age_index = 0 ;if (--slowtimer <= 0 {/*经过5次的bdg_timeout后,才为0*/ slowtimer = 5 ;/*由于在初始化时,slowtimer被置为0,所以在函数第一次被调用时,次处总会被执行*/bridge_on() ; /* 打开桥的一些设置,看上面的该函数说明.*/bdg_loops = 0 ;}}bdg_timeout_h = timeout(bdg_timeout, NULL, 2*hz ;/*启动监视器*/ }/** 查找包的目的地,返回值如下:* BDG_BCAST 广播包,这种包是要发送到每一个接口的* BDG_MCAST 多播包* BDG_LOCAL 该包是发送给本机的一个包,如果该机做为透明网桥放火墙,应该拦截该包,并做特殊处理* BDG_DROP 该包必须抛弃* other 其他类型的包**/static __inlinestruct ifnet *bridge_dst_lookup(struct ether_header *eh, struct cluster_softc *c) {/*eh是以太网包的头部*/struct ifnet *dst ;int index ;struct bdg_addr *p ;bdg_hash_table *bt; /*HASH表入口指针 */if (IS_ETHER_BROADCAST(eh->ether_dhost))/*是广播地址吗?*/return BDG_BCAST ;/*是的就返回广播地址标志*/if (eh->ether_dhost[0] & 1)/*硬件地址的最后一位是1吗?即是多播地址吗*/return BDG_MCAST ;/*是的就返回多播地址标志*//** 以下循环是查看本机的所有网卡的硬件地址是否和eh中的目的地址相同,相同就是发送到本机的.*/for (index = c->ports, p = c->my_macs; index ; index--, p++ /*在cluster_softc结构中遍历本机所有网卡*/if (BDG_MATCH(p->etheraddr, eh->ether_dhost) /*和这块卡的硬件地址相同吗?*/return BDG_LOCAL ;/*相同就返回本地的标志*//** 如果以上都不是,那么在HASH表中查找一下,目的地和本机的那块卡相连.*/index= HASH_FN( eh->ether_dhost ;/*HASH查找,精华部分,查到该地址在HASH表的第index个偏移*/bt = &(c->ht[index]);/*定位该HASH条目的入口*/dst = bt->name;/*得到与目的地机器相连的本机某网卡的ifnet结构指针*/if ( dst && BDG_MATCH( bt->etheraddr, eh->ether_dhost)return dst ;/*返回该指针*/elsereturn BDG_UNKNOWN ;/*否则没查到,我不知道什么时候将出现该情况.*/}/*** bridge_in() 函数由if_ethersubr.c中的ether_input函数调用,在该函数中会判断bridge功能是否打开,如果打开* 既调用该函数.ether_input函数会根据返回值决定是否调用我们即将讲的下一个函数bridge_forward.* 函数入口:* eh 进入以太网包的以太网包头.* ifp ifnet结构,即该包是从哪块卡进来的.(ifnet包含了卡的所有信息) ** 函数返回: 目的地要进过本机哪块网卡发送,即那块卡的ifnet结构指针.说明如下* BDG_BCAST 广播地址* BDG_MCAST 多播地址* BDG_LOCAL 不需要转发,该包是发给本机的.* BDG_DROP 该包要丢弃* ifp 即将发送的网卡的ifnet指针.**/static struct ifnet *bridge_in(struct ifnet *ifp, struct ether_header *eh){int index;struct ifnet *dst , *old ;bdg_hash_table *bt; /* 将用来放置当前HASH表中该地址的HASH指针的位置 */int dropit = BDG_MUTED(ifp) ;/** HASH_FN宏在上面的函数中已经有描述.不过在这里是查看对方的MAC 地址是否以前有记录(即在HASH表中查找)*/index= HASH_FN(eh->ether_shost);/*这中HASH的查找方法是否有问题,是否会产生同义词?他的算法是MAC地址的*//*[1]和[2]两字节互补后在和HASH长度-1相与,那他认为是唯一值,这是不可靠的.*//*我们可以利用该情况生成同义词,进行HASH覆盖,带着次问题我又查看了OpenBSD*//*的源代码,他的算法又是另外一种,请看OpenBSD的Alley算法(Bob Jenkins):*//*#define mix(a,b,c) \ 本人因能力有限,看不懂OpenBSD的算法do { \a -= b; a -= c; a ^= (c >> 13); \b -= c; b -= a; b ^= (a << ; \c -= a; c -= b; c ^= (b >> 13); \a -= b; a -= c; a ^= (c >> 12); \b -= c; b -= a; b ^= (a << 16); \c -= a; c -= b; c ^= (b >> 5); \a -= b; a -= c; a ^= (c >> 3); \b -= c; b -= a; b ^= (a << 10); \c -= a; c -= b; c ^= (b >> 15); \} while (0)u_int32_tbridge_hash(struct bridge_softc *sc, struct ether_addr *addr) 下面的更看不懂了,OpenBSD的哈稀函数{u_int32_t a = 0x9e3779b9, b = 0x9e3779b9, c = sc->sc_hashkey;b += addr->ether_addr_octet[5] << 8;b += addr->ether_addr_octet[4];a += addr->ether_addr_octet[3] << 24;a += addr->ether_addr_octet[2] << 16;a += addr->ether_addr_octet[1] << 8;a += addr->ether_addr_octet[0];mix(a, b, c);return (c & BRIDGE_RTABLE_MASK);}如果你不懂得以上的算法,那么桥的技术应该说还没精通.本人就是这样,不是谦虚.计算机搞到后面基本上就是拼算法的先进与合理性.*/bt = &(ifp2sc[ifp->if_index].cluster->ht[index]);/*当然假定index 没有同义词,那么就/*可以找到该MAC地址在HASH表的入口了*/bt->used = 1 ;/*该MAC的HASH指针开始启用.*/old = bt->name ;/*暂时存放到old中,记住,大家看看timeout中对bt->name的清除是多么的重要啊*/if ( old { /* 为真就是以前就填充过,说明该机器以前发过包通过本机. */if (!BDG_MATCH( eh->ether_shost, bt->etheraddr) {/*看看上次对方机器的包的源硬件地址和本次的地址相同吗?*/bdg_ipfw_colls++ ;/*不同,有问题,其实这里的操作有点类似ARP中的.*/bt->name = NULL ;} else if (old != ifp) {/*源地址是对的,但本机接收网卡发生了更换(重新设置了网卡)或源机器移动了.环回也有可能*/bt->name = ifp ; /* 指向新的正确的接收网卡的ifnet结构 */ printf("-- loop (%d) %6D to %s%d from %s%d (%s)\n",bdg_loops, eh->ether_shost, ".",ifp->if_name, ifp->if_unit,old->if_name, old->if_unit,BDG_MUTED(old) ? "muted":"active");/*打印信息到屏幕*/dropit = 1 ;/*在本次转发中是否转发,1是不转发,就是说在发现上面的那种情况后,不转发该包*/if ( !BDG_MUTED(old) {if (++bdg_loops > 10)BDG_MUTE(old) ;}}}/** 把发送方的地址写到HASH表中.*/if (bt->name == NULL) {/*因为发送方是第一次发送包.*/DEB(printf("new addr %6D at %d for %s%d\n",eh->ether_shost, ".", index, ifp->if_name, ifp->if_unit)bcopy(eh->ether_shost, bt->etheraddr, 6);/*把发送方的以太网硬件地址放到HASH表中该发送方HASH索引的地方.*/bt->name = ifp ;}dst = bridge_dst_lookup(eh, ifp2sc[ifp->if_index].cluster);/*调用上面说明的函数来查找目的地要经过的本机网卡.*//** BDG_STAT是对bdg_port_stat结构进行操作,统计各种包的in的数量(做++操作)*/BDG_STAT(ifp, BDG_IN);switch ((uintptr_t)dst) {case (uintptr_t)BDG_BCAST:case (uintptr_t)BDG_MCAST:case (uintptr_t)BDG_LOCAL:case (uintptr_t)BDG_UNKNOWN:case (uintptr_t)BDG_DROP:BDG_STAT(ifp, dst);break ;default :if (dst == ifp || dropit)BDG_STAT(ifp, BDG_DROP);elseBDG_STAT(ifp, BDG_FORWARD);break ;}if ( dropit {/*不转发为真吗?*/if (dst == BDG_BCAST || dst == BDG_MCAST || dst == BDG_LOCAL)dst = BDG_LOCAL ;/*如果是发送给本机的包,即上面那些条件成立,返回该标志由ether_input函数处理*/elsedst = BDG_DROP ;/*该标志返回给ether_input后,该函数会把包抛弃*/ } else {if (dst == ifp)/*如果包来自该接口,又要发送到该接口,当然应该丢弃该包*/ dst = BDG_DROP;}DEB(printf("bridge_in %6D ->%6D ty 0x%04xdst %s%d\n",eh->ether_shost, ".",eh->ether_dhost,".",ntohs(eh->ether_type),(dst <= BDG_FORWARD) ? bdg_dst_names[(int)dst] :dst->if_name,(dst <= BDG_FORWARD) ? 0 : dst->if_unit);return dst ;/*返回的值是给ether_input函数的*/}/* 该函数由ether_input函数(if_ethersubr.c中)调用,作用是把包转发到相应的网络接口* 参数dst是将要被转发的接口,当然,他可以是一个接口,也有可能是一组或所有接口.* 该函数内是作为放火墙代码的放置地的理想地方.非同组接口过滤,以太层包过滤,IP层包过滤* 或自己编写的钩子都可以在此实现.*/static struct mbuf *bdg_forward(struct mbuf *m0, struct ifnet *dst){/*该宏的作用是把先前保存的以太网包头部恢复到mbuf中.*/#define EH_RESTORE(_m) do { \/*关于M_PREPEND宏我在以前的文章中讲过,该宏是对mbuf进行操作,在此处是在mbuf前申请以太网头部长度的空间*/M_PREPEND((_m), ETHER_HDR_LEN, M_DONTWAIT); \if ((_m) == NULL) { \bdg_dropped++; \return NULL; \} \if (eh != mtod((_m), struct ether_header *)) \bcopy(&save_eh, mtod((_m), struct ether_header *), ETHER_HDR_LEN); \ else \bdg_predict++; \} while (0);struct ether_header *eh; /*暂时存放以太网头部*/struct ifnet *src; /*该包是本机的哪块网卡接收的*/struct ifnet *ifp, *last; /*转发包时要用到的一些临时存放ifnet 结构的指针*/int shared = bdg_copy ; /* 看前面的sysctl宏 */int once = 0; /* 代表只发送一次 */struct ifnet *real_dst = dst ;struct ip_fw_args args;#ifdef PFIL_HOOKS /* PFIL_HOOKS 即包过滤钩子*/struct packet_filter_hook *pfh;/* 包过滤钩子结构*/int rv;#endif /* PFIL_HOOKS 即包过滤钩子*/struct ether_header save_eh;DEB(quad_t ticks; ticks = rdtsc()args.rule = NULL; /*放火墙规则*//* 关于这一些放火墙及DUMMYNET,我没有研究过,有兴趣的可以自己扩展研究 */for (;m0->m_type == MT_TAG; m0 = m0->m_next)if (m0->_m_tag_id == PACKET_TAG_DUMMYNET) {args.rule = ((struct dn_pkt *)m0)->rule;shared = 0;}if (args.rule == NULL)bdg_thru++;eh = mtod(m0, struct ether_header *);/*eh指向了m0中的以太网头部*/src = m0->m_pkthdr.rcvif; /*接收该包的本机的网卡接口的ifnet 结构指针*/if (src == NULL) /* 代表包是从ether_output函数输出,即从本机的上层协议输出 */dst = bridge_dst_lookup(eh, ifp2sc[real_dst->if_index].cluster);if (dst == BDG_DROP) { /* 这种情况不会发生,因为在ether_input函数中已经对BDG_DROP进行了过滤 */printf("xx bdg_forward for BDG_DROP\n");m_freem(m0);bdg_dropped++;/*统计丢弃的包数量*/return NULL;}if (dst == BDG_LOCAL) { /* 这种情况不会发生,因为在ether_input函数中已经对BDG_DROP进行了过滤 */printf("xx ouch, bdg_forward for local pkt\n");return m0;}if (dst == BDG_BCAST || dst == BDG_MCAST) {/* need a copy for the local stack */shared = 1 ;}/* 在这是做了一个和ip_output中类似的过滤器,当放火墙已经打开,并且包不是从ether_output输出的时候(* 会过滤两次).当然在此处还可以限制一些非IP包,其他链路层的包.*/if (src != NULL && (#ifdef PFIL_HOOKS((pfh = pfil_hook_get(PFIL_IN,&inetsw[ip_protox[IPPROTO_IP]].pr_pfh)) != NULL && bdg_ipf !=0) || #endif(IPFW_LOADED && bdg_ipfw != 0))){int i;if (args.rule != NULL && fw_one_pass)goto forward; /* 包已经处理过了,直接到forward转发 */i = min(m0->m_pkthdr.len, max_protohdr) ;if ( shared || m0->m_len < i) {m0 = m_pullup(m0, i) ;if (m0 == NULL) {printf("-- bdg: pullup failed.\n") ;bdg_dropped++;return NULL ;}eh = mtod(m0, struct ether_header *);}bcopy(eh, &save_eh, ETHER_HDR_LEN); /*保存以太网头部,以后用EH_RESTORE 恢复 */m_adj(m0, ETHER_HDR_LEN); /* 剥掉头部 */#ifdef PFIL_HOOKS/** NetBSD风格的过滤器*/if (pfh != NULL && m0->m_pkthdr.len >= sizeof(struct ip) &&ntohs(save_eh.ether_type) == ETHERTYPE_IP) {/** 调用放火墙前,要确定是IP包.*/struct ip *ip = mtod(m0, struct ip *);/*指向IP头部*/ip->ip_len = ntohs(ip->ip_len);ip->ip_off = ntohs(ip->ip_off);do {if (pfh->pfil_func) {。
FreeBSD--常用命令
FreeBSD--常⽤命令FreeBSD常⽤命令查看⽹络流量a.systat -if 1 (1表⽰1s刷新屏幕⼀次)stat 1# Traffic 流量 peak 峰值 average 平均值查看进程ps -ef |grep xxx查看硬盘详细分区信息&读写状况gstatsysctl sysctl -a 查看所有变量(/etc/sysctl.conf)sysctl kern.maxproc 查看特定变量sysctl kern.maxfiles=5000 设置变量查看磁盘空间使⽤情形 df 和 du指令df⽤来查看整个档案系统的使⽤情形,如果您需要知道某个⽬录的使⽤情形⽤指令du。
df -hdu -h /etcdu -sh /etc-s 参数来省略指定⽬录下的⼦⽬录-h 表⽰使⽤GB、MB等易读的格式shutdown now 切换到单⽤户模式shutdown -p now shutdown -hp now 关闭电源shutdown -r now reboot 重新启动机器shutdown -p +90 (90分钟后关机)shutdown 020*******(020*******表⽰2002年3⽉12⽇23:59,格式是yymmddhhmm)挂载ntfs,fat32分区和u盘ntfs: mount_ntfs -C eucCN /dev/ad0s5 /mnt/dfat32:mount_msdos -L zh_CN.eucCN /dev/ad0s6 /mnt/eu盘(scsi盘): mount_msdos -L zh_CN.eucCN /dev/da0s1 /mnt/ucdrom: #mount_cd9660 /dev/acd0 /mnt/cdromNTFS在FreeBSD中只能只读⽽⽆法写⼊卸载分区umount /dev/ad0s5umount -f /dev/ad0s5 (强制卸载)如何在FreeBSD5.X以上加载,卸载ISO⽂件mount iso⽂件:mdconfig -a -t vnode -f myisofile.iso (屏幕输出md0或者类似的设备名)mount -t cd9660 /dev/md0 /cdromumount:umount /cdrommdconfig -d -u 0 (上⾯的-u后⾯的数字和前⾯的md?中的数字⼀致)mdconfig -l 命令可以列出关于配置 md(4) 设备的信息检视软件间的关联cd /usr/ports/sysutils/pkg_treemake install clean之后我们就可以使⽤ pkg_tree | more 来看各个软件之间的关系了使⽤ portupgrade 更新软件cd /usr/ports/sysutils/portupgrademake install clean配置⽂件:/usr/local/etc/pkgtools.conf如果您只想要升级某⼀个软件本⾝,⽽⾮所有相依的软件,只要使⽤portupgrade "pkgname" 即可。
基于FreeBSD实现校园网上网带宽控制
2017年第2期信息与电脑China Computer&Communication网络与通信技术基于FreeBSD 实现校园网上网带宽控制邱得斌(广东省新闻出版高级技工学校,广东 广州 510650)摘 要:校园网络的出口带宽有限,需要对每个用户的带宽进行控制。
笔者基于广东省新闻出版高级技工学校校园网的实际情况,分析校内用户上网带宽需求的特点,制定了流量控制策略,将开源操作系统+防火墙(FreeBSD+IPFW)作为流量控制的技术解决方案,讲述了IPFW 的带宽控制配置方法和运行管理。
总结了FreeBSD+IPFW 是一个稳定、高性能、低成本的,特别适合应用于中小型校园网、小区带宽控制的解决方案。
关键词:FreeBSD;IPFW;校园网;带宽控制中图分类号:TP393.18 文献标识码:A 文章编号:1003-9767(2017)02-0208-03Implementation of Campus Network Bandwidth Control based on FreeBSDQiu Debin(Guangdong Press and Publication Technician College, Guangzhou Guangdong 510650, China)Abstract: Campus network bandwidth is limited, the need to control the bandwidth of each user. In this paper, the actualsituation of Guangdong Press and Publication Technician College network based on the analysis of characteristics of Campus Internet users bandwidth requirements, developed a flow control strategy, using open-source operating system + firewall (FreeBSD+IPFW) as a flow control scheme, describes the IPFW bandwidth control allocation method and operation management. It is concluded thatFreeBSD+IPFW is a stable, high performance and low cost, especially suitable for small and medium sized campus network and cellas the solution of bandwidth control.Key words: FreeBSD; IPFW; campus network; bandwidth control信息网络普及,学校的教学和学习都离不开网络,网络给大家带来了便捷,而工作学习之余,难免会有教工或学生有些娱乐活动,如下载高清电影,玩玩大的在线游戏,电脑也会中毒产生大量网络流量等,占用了大量的网络出口带宽。
IPFW中文手册
IPFW中文手册ipfw是FreeBSD下的一个用户界面,它用来控制ipfw防火墙和流量整形。
ipfw的配置,也叫做规则集,它是由一系列的规则组成的,这些规则的编号是从1到65535。
通过ipfw的数据包可以来自协议栈的许多各个的地方(这主要依赖于数据包的来源和目的,某些数据包很可多次经过防火墙)。
数据包在通过防火墙的时候,要和防火墙规则集逐条对比。
如果发现匹配的规则,则执行相应规则的动作。
在特定的规则动作和系统设置下,数据包在匹配完一个规则后,可能在某些规则之后重新进入防火墙。
一个ipfw规则集总是包含一个默认的规则(编号为65535),这个默认规则匹配所有的数据包,不能修改或删除。
根据内核配置的不同,这个默认规则或者是拒绝所以数据包通过,或者是允许所有数据包通过。
如果规则集中存在一个或多个包含有keep-state(状态保持)或limit(限制)的规则,那么ipfw就表现为状态保持。
例如:当这种规则匹配了一个数据包时,ipfw将创建一个动态规则,让后来的,同这个数据包的地址和端口参数严格一致的数据包,与这个动态规则相匹配。
这些动态规则,都有一个有限的生存期。
生存期在第一次遇到check-state、keep-state或者是limit规则时被检查。
这些动态规则的典型应用,是用来保证合法的数据包在通过时开启防火墙。
查看下面的“状态防火墙”和“示例”章节,获取更多关于状态保持的信息。
包括动态规则在内的所有规则,都有几个相关的计数器:一个包计数器,一个字节计数器,一个记录计数器和一个用来提示最后匹配时间的时间戳。
这些计数器都可以被ipfw命令显示和清零。
可以用add命令来添加规则;可以用delete命令来删除单个或一组规则;可以用flush命令来删除所有的规则(set 31除外);可以用show和list命令来显示包括计数器在内的信息。
最后,计数器可以被zero和resetlog命令清零。
并且,每个规则隶属于32个不同的规则集中的一个。
网络模拟工具Netem
⽹络模拟⼯具Netem⽹络模拟⼯具Netem可以模拟时延,丢包,重复包,乱序等功能。
Netem是⽤过命令⾏‘tc’来设置规则的,tc命令是IProute2命令中的⼀部分!1. 设置固定delay 100ms (所有经过eth0的包都被延时了100ms):# tc qdisc add dev eth0 root netem delay 100ms修改# tc qdisc change dev eth0 root netem delay 100ms删除#tc qdisc del dev eth0 root netem delay 100ms2. 设置delay 100ms Jitter 10ms:# tc qdisc change dev eth0 root netem delay 100ms 10ms3. Jitter其实是有相关性的,如果要设置Jitter的相关性25%:# tc qdisc change dev eth0 root netem delay 100ms 10ms 25%4. 设置Jitter为正态分布。
# tc qdisc change dev eth0 root netem delay 100ms 20ms distribution normal5. 设置丢包率10%# tc qdisc change dev eth0 root netem loss 10%6. 丢包率也有相关性。
如设置10%的丢包率,但是丢包率之间的相关性为25%# tc qdisc change dev eth0 root netem loss 0.3% 25%7. 包的duplication。
# tc qdisc change dev eth0 root netem duplicate 3%8. 包的corruption。
# tc qdisc change dev eth0 root netem corrupt 0.1%9. 乱序,每第5个包马上发送,其他的包间隔10ms发送。
FreeBSD安装与配置之概述
FreeBSD安装与配置之概述作者:佚名来源:站长之家更新时间:2008-9-13 11:16:04【字体:缩小字体放大字体】FreeBSD是一种运行在Intel平台上、可以自由使用的Unix系统,它可以从In ternet上免费获得。
而它又具备极其优异的性能,使它得到了计算机研究人员和网络专业人士的认可。
因此,不但专业人员把它用作个人使用的Unix工作站,很多企业,特别是ISP (Internet服务提供商)都使用运行FreeBSD的服务器来为他们的众多用户提供网络服务。
BSD Unix使用一个神话中的精灵形象作为其吉祥物,这个吉祥物标志被各BSD发行版本沿用。
1993年12月FreeBSD 1.0版本正式发布。
任何人都可以通过购买光盘或者通过I nternet下载的方法,自由获得FreeBSD系统,使得FreeBSD取得了很大成功。
由于Unix商标属于X/Open组织,而FreeBSD只是一个自由操作系统,从法律角度上看FreeBSD 不能被叫作Unix(不能使用Unix做商标)。
但是基于Unix本身的历史,FreeBS D可以算最原汁原味的Unix。
由于FreeBSD十分关心系统的性能和稳定性,同时FreeBSD的开发又非常活跃并十分开放。
因此在系统开发中支持几个版本的FreeBSD系统并行发展,一些版本用于提供一个最具稳定性的操作系统,另一些版本逐渐融合进各种新特性,使FreeBSD不断发展。
目前Fr eeBSD最新版本是5.3。
那么FreeBSD与Linux有什么区别呢,我想大家也许对这个问题很感兴趣。
FreeBSD是一个自由的,源自AT&T UNIX的操作系统。
目前已经不包含任何AT&T的代码。
可以说它是正统的UNIX后代。
而Linux是由一个芬兰Helsinki大学的学生Linus Torvalds开发的UNIX的克隆。
事实上,FreeBSD和Linux严格意义上不能叫做UNIX,因为UNIX是The Open Group的注册商标。
FreeBSD在校园网络管理中的典型应用
本栏目责任编辑:冯蕾网络通讯与安全FreeBSD是一种运行在Intel平台上、可以自由使用的Unix操作系统,它可以从Internet上免费获得。
由于其具备极其优异的网络性能和极高的可靠性,得到了广大计算机研究人员和网络专业人士的认可[1]。
在校园网络管理中,为了实现一些典型的应用,往往需要购置各种不同的专用设备,不仅价格昂贵,而且难以实现功能的集中统一,但由于FreeBSD本身就是一个非常完善的网络操作系统,它所带有的ipfw/natd和ipfilter都能够实现基于包过滤和网络地址转换的防火墙应用,并且绝大多数在Unix平台下的软件可以很容易移植到FreeBSD中,其PortsCollections包括了上千个可以立即使用的应用程序,所以使用FreeBSD搭建一个可用的、满足需要的网络环境非常方便。
有关FreeBSD的详尽资料参见[2]。
本文试图通过使用FreeBSD系统来解决在当前高校校园网的管理过程中所遇到的一些典型问题。
1双链路接入Internet的实现目前很多高校除了接入教育科研网外,还同时租用了当地某个ISP的线路接入Internet,以解决访问公众网的速度存在瓶颈的问题。
一般有两种方法实现这种接入。
一是使用代理服务器,配两块网卡,一块接入校园网,一块直接接入ISP,用户访问公众网时,设置代理服务器上网。
这种方式对代理服务器的性能要求较高,用户在访问教育网或非教育网时,需要修改浏览器的代理服务器设置,才能达到较好的访问速度,并且只能代理某些特定的网络服务。
另外一种方法就是把两个出口都接在边缘路由器上,通过在路由器上配置策略路由,对教育网的访问走教育网出口,对其他网站的访问通过NAT地址翻译后走ISP提供的出口。
使用这种方式,由于对路由器的系统开销很大,而一般的路由器处理NAT操作效率较低,在网络流量较大时很不理想。
我们在使用过这两种接入方式后,都觉得效果不太满意,最终选择了使用一台安装FreeBSD操作系统的带三块网卡的PC机来实现了较为完美的接入方式。
FreeBSD下防火墙的简单设置
FreeBSD下防火墙的简单设置FreeBSD下防火墙的简单设置IPFW 的无状态规则语法,是由一种提供复杂的选择能力的技术支持的,这种技术远远超出了一般的防火墙安装人员的知识水平。
IPFW 是为满足专业用户,以及掌握先进技术的电脑爱好者们对于高级的包选择需求而设计的。
要完全释放IPFW 的规则所拥有的强大能力,需要对不同的协议的细节有深入的了解,并根据它们独特的包头信息来编写规则。
这一级别的详细阐述超出了这本手册的范围。
IPFW 由七个部分组成,其主要组件是内核的防火墙过滤规则处理器,及其集成的数据包记帐工具、日志工具、用以触发NAT 工具的'divert' (转发) 规则、高级特殊用途工具、dummynet 流量整形机制,'fwd rule' 转发工具,桥接工具,以及ipstealth 工具。
IPFW 支持IPv4 和IPv6。
以上为Freebsd手册上的说法。
之所以选择Freebsd作为实验小学的网站服务器,其中一个关键原因就是IPFW的强大功能。
windows和linux的一些防火墙基本上没有它严厉。
不用担心系统被人家拿下的危险了。
废话不说了。
一、开机启动IPFW防火墙ee /etc/rc.conf加入以下代码:firewall_type="open"firewall_script="/etc/ipfw.rules"//ipfw.rules 是防火墙规则文件二、建立防火墙规则ee /etc/ipfw.rules################ Start of IPFW rules file################################ Flush out the list before we begin.ipfw -q -f flush# Set rules command prefixcmd="ipfw -q add"pif="bge0"# public interface name of NIC//bge0是我的网卡的系统名称。
FreeBSD下dummynet控制网络
Dummynet安装配置DummyNet是FreeBSD的内部系统工具,需要在安装FreeBSD系统后重新安装编译内核。
该工具是内核级别的IP包处理工具。
该工具可以模拟包的丢失、包的延时……(仓促间仅试验了drop & delay,但相信功能远多于此)。
该工具是配合FreeBSD自带的防火墙ipfw 使用的。
第一部分:简单的介绍安装1、FreeBSD系统的安装:(1,2,3,……,系统的安装过程省略)2、dummynet安装:我在FreeBSD8.1下面的安装最简单的方法是通过以root 身份运行sysinstall,选择Configure,然后是Distributions、src,选中其中的base 和sys3、接下来配置内核(因为要编译内核,过程比较慢very very )内核文件默认路径/usr/src/sys/i386/confE、reboot重启系统,让新内核生效第二部分:简单举例(本处需要使用ipfw规则,偶也不熟,找手册吧)本例通过ping网关看到网络基本正常,丢包率0.0%,平均延迟3.257ms (进、出来回,单向就是1.6ms)2、设置延迟和丢包设置所有上行icmp协议的ip包延迟100ms丢包率40%通过ping网关看丢包率在46.5%,平均延迟106.581ms(单向out,如果双向则在210ms 所有)3、设置延迟让所有通过网卡的ip包都延迟500ms(包含进、出)通过ping网关看,丢包率在0.5%,平均延时1002.87ms(进、出双向,单向则为500ms左右)第三部分:结论通过以上实验看,在有线网络环境下dummynet基本上可以模拟丢包、延时等,需要结合ipfw使用,但是是否能够作为第三方去控制别的IP地址间的带宽或者控制无线网络,结果未知。
在FreeBSD操作系统中通过VirtualBox安装Windows虚拟机
在FreeBSD 操作系统中通过VirtualBox 安装Windows 虚拟机作为学校的网络管理员,经常需要通过远程来管理学校的网络。
虽然很多网络设备都支持SSH或Telnet的管理方式,也就是命令行界面的管理方式。
但很多网管工具是基于Windows 的。
因此需要远程登录到学校的Windows 操作系统来进行管理。
带有公网IP的Windows系统虽然可以通过远程桌面的方式进行远程访问。
但通过多年使用Windows 操作系统的经验。
Windows 系统的漏洞频出,被攻击、被入侵的可能性很大。
因此,我想通过常年开机一种安全、健壮的操作系统,经过选择,我选择了FreeBSD操作系统。
FreeBSD操作系统是一种UNIX 操作系统,出的漏洞极少,很多大网站都采用它,比如雅虎、百度等公司。
在FreeBSD系统中安装虚拟机软件,然后在虚拟机软件中安装Windows 操作系统。
需要需要管理学校网络时,通过SSH 远程登录FreeBSD 操作系统,然后在FreeBSD 中通过虚拟机软件开启Windows 系统,接着通过远程桌面登录Windows 系统,在其中管理学校的网络。
管理完毕,关闭Windows 系统,防止外部攻击。
这样就保证了基本系统认为FreeBSD系统,安全性很高。
通过实践解决问题主要通过以下四个步骤解决上述问题:1、通过升级方式安装FreeBSD10.1操作系统。
FreeBSD10.1为最新的FreeBSD 版本。
2、安装xorg。
xorg为FreeBSD下图形界面的基础组件。
3、在xorg 下进行VirtualBox 虚拟机的安装。
4、在VirtualBox 中安装windows2003。
详细的解决方案如下:1、通过升级方式安装FreeBSD10.1 操作系统硬件:IBM X3650服务器。
CPU为至强1.86G 8核内存4G查看CPU 和内存的命令如下:CPU: cat /var/run/dmesg.boot | grep CPUMEM: cat /var/run/dmesg.boot | grep mem现有的操作系统:FreeBSD10.0IP1:111.42.224.148公网)ip2: 10.0.0.148(内网)当前最新的FreeBSD 操作系统为10.1,为了安全性和软件的安装方便,需要将FreeBSD10.0升级到FreeBSD10.1.过程如下:1)通过root用户登录FreeBSD10.0服务器,运行freebsd-update upgrade - 10.1-RELEASE 进行版本升级,然后运行freebsd-update install 进行FreeBSD10.1 的安装。
FreeBSD系统优化部分内核参数调优中文注释
reeBSD系统优化部分内核参数调优中文注释#最大的接受TCP缓冲区空间net.inet.tcp.recvspace=65536#最大的接受UDP缓冲区大小net.inet.udp.sendspace=65535#最大的发送UDP数据缓冲区大小net.inet.udp.maxdgram=65535#本地套接字连接的数据发送空间net.local.stream.sendspace=65535#加快网络性能的协议net.inet.tcp.rfc1323=1net.inet.tcp.rfc1644=1net.inet.tcp.rfc3042=1net.inet.tcp.rfc3390=1#最大的套接字缓冲区kern.ipc.maxsockbuf=2097152#系统中允许的最多文件数量kern.maxfiles=65536#每个进程能够同时打开的最大文件数量kern.maxfilesperproc=32768#当一台计算机发起TCP连接请求时,系统会回应ACK应答数据包。
#该选项设置是否延迟ACK应答数据包,把它和包含数据的数据包一起发送,#在高速网络和低负载的情况下会略微提高性能,但在网络连接较差的时候,#对方计算机得不到应答会持续发起连接请求,反而会降低性能。
net.inet.tcp.delayed_ack=0#屏蔽ICMP重定向功能net.inet.icmp.drop_redirect=1net.inet.icmp.log_redirect=1net.inet.ip.redirect=0net.inet6.ip6.redirect=0#防止ICMP广播风暴net.inet.icmp.bmcastecho=0net.inet.icmp.maskrepl=0#限制系统发送ICMP速率net.inet.icmp.icmplim=100#安全参数,编译内核的时候加了options TCP_DROP_SYNFIN才可以用net.inet.icmp.icmplim_output=0net.inet.tcp.drop_synfin=1#设置为1会帮助系统清除没有正常断开的TCP连接,这增加了一些网络带宽的使用,但是一些死掉的连接最终能被识别并清除。
基于freebsd流控系统.doc
基于FreeBSD系统搭建流量监控系统本文为实战过程,分三步走,非常适合新手操作。
●FreeBSD系统的安装(FreeBSD6.2)●Panabit流控引擎的安装(本人使用的是Panabit0905.tar.gz )●Panabit系统配置手册●FreeBSD系统的安装Panabit系统目前仅运行在FreeBSD4.11版本之上,因为Panabit开发依赖FreeBSD 4.11很多优化特性,有利于系统性能。
但本人选用的是FreeBSD6.2版本。
安装过程参考/showthread.php?t=3831,虽然上面是7.1的安装但同样适用于6.2,安装系统吗大同小异啦,呵呵!1、启动计算机后,经过一些加载过程后,将载入FreeBSD 引导画面,直接回车。
2、经过一些加载过程后,开始进入安装向导。
进入向导前,首先会要求你选择所在国家。
这个决定着键盘布局,不过我们一般都用标准的101 美国qwerty键盘,所以直接选默认的232美国,回车键确定。
3、正式进入了安装向导,FreeBSD 7.0 的安装程序名叫Sysinstall。
现在你看到的就是Sysinstall 的主菜单,其中有各种安装选项。
使用方向键选择S tandard(即标准安装)项目,回车确认,进入标准安装。
4、首先会看到一个安装提示消息框,提示你进入Fdisk 分区程序。
确认即可5、现在看到的是分区向导,这里会列出你的硬盘信息。
一般情况下,我们使用自动分区功能,把整个硬盘创建成FreeBSD分区。
如果硬盘已经有其他操作系统存在,比如以前装过XP,会有Fat32或NTFS分区,则按上下光标键选中,按D删除以前的分区。
这里我们按A键,自动分区完毕。
再按键盘Q键,退出分区程序。
反正不是很熟悉分区操作的就依样画葫芦操作吧,以前接触过fdisk所以还有点点明白它的操作,呵呵!上次培训时,还有点记得怎么操作的,现在都忘了。
6、这里是询问你安装何种硬盘引导程序。
freebsd4.x内核网络模块编译要点Unix系统-电脑资料
freebsd4.x内核网络模块编译要点Unix系统-电脑资料1. 目录 net -- 链路层驱动 netinet -- tcp/ip堆栈 module -- 模块家目录xxx -- 单独建立一个目录,从其他目录拷贝一个Makefile就可以了,修改里面的文件 3. 修改/sys/i386/files文件,模块定义对应核配置文件中的pseudo-device xxxxx 3. opt_xxx.h 的定1. 目录net -- 链路层驱动netinet -- tcp/ip堆栈module -- 模块家目录xxx -- 单独建立一个目录,从其他目录拷贝一个Makefile就可以了,修改里面的文件3. 修改/sys/i386/files文件,模块定义对应核配置文件中的pseudo-device xxxxx3. "opt_xxx.h" 的定义,开关宏定义, 对应核配置文件中的OPTIONS XXX修改/sys/i386/options文件4. config -d 目录 kern.conf,到指定目录下编译内核5. 初始调试时,不要将模块编译到内核中,稳定后再编译到内核中,,电脑资料《freebsd 4.x 内核网络模块编译要点Unix系统》(https://www.)。
修改/sys/modules/Makefile6. 模块源文件中尽量使用static定义全局变量,避免冲突对于多源文件共享变量,不要使用static定义7. 钩子函数挂接位置链路层: if_ethersubr.ctcp/ip层: ip_output.c ip_input.c tcp_output.c tcp_input.c8. 钩子定义#ifdef _KERNELtypedef int myfunc_t(args...);extern myfunc_t *myfunc_ptr;#endif /* _KERNEL */附值:myfunc_ptr = myfunc;使用:myfunc_ptr(args...)9. 头文件的引用顺序很多头文件必须顺序引用,否则报错。
- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
Dummynet安装配置
DummyNet是FreeBSD的内部系统工具,需要在安装FreeBSD系统后重新安装编译内核。
该工具是内核级别的IP包处理工具。
该工具可以模拟包的丢失、包的延时……(仓促间仅试验了drop & delay,但相信功能远多于此)。
该工具是配合FreeBSD自带的防火墙ipfw 使用的。
第一部分:简单的介绍安装
1、FreeBSD系统的安装:
(1,2,3,……,系统的安装过程省略)
2、dummynet安装:
我在FreeBSD8.1下面的安装最简单的方法是通过以root 身份运行sysinstall,选择Configure,然后是Distributions、src,选中其中的base 和sys
3、接下来配置内核(因为要编译内核,过程比较慢very very )
内核文件默认路径/usr/src/sys/i386/conf
E、reboot重启系统,让新内核生效
第二部分:简单举例(本处需要使用ipfw规则,偶也不熟,找手册吧)
本例通过ping网关看到网络基本正常,丢包率0.0%,平均延迟3.257ms (进、出来回,单向就是1.6ms)
2、设置延迟和丢包
设置所有上行icmp协议的ip包延迟100ms丢包率40%
通过ping网关看丢包率在46.5%,平均延迟106.581ms(单向out,如果双向则在210ms 所有)
3、设置延迟
让所有通过网卡的ip包都延迟500ms(包含进、出)
通过ping网关看,丢包率在0.5%,平均延时1002.87ms(进、出双向,单向则为500ms左右)
第三部分:结论
通过以上实验看,在有线网络环境下dummynet基本上可以模拟丢包、延时等,需要结合ipfw使用,但是是否能够作为第三方去控制别的IP地址间的带宽或者控制无线网络,结果
未知。