通行证│用户名: 密码: 验证码: 验证码,看不清楚?请点击刷新验证码 电信网通铁通移动   在线
资源搜索:
热门搜索:Linux VB C语言 PhotoShop Flash TCP/IP
   首页 | 文章 | 软件 | 动画 | 资源 | 励志 | 骗术 | 论坛 | 邮箱 | 会员中心 | 军事 | 科技 | 博客 | 图片 | 商城 | 最新更新 | 800g资源 | 爱心黑客
您现在的位置: 爱国者黑客 >> 资源 >> 操作系统 >> FreeBSD >> 原理与内核 >> 文章正文
网桥原理及源代码详解
责任编辑:admin   更新日期:2005-8-6
f, 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 1

SY(_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");
#endif

SYSCTL_STRUCT(_net_link_ether, PF_BDG, bdgstats,
CTLFLAG_RD, &bdg_stats , bdg_stats, "bridge statistics");

static int bdg_loops ;


static void
bdg_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 __inline
struct 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 ;/*返回该指针*/
   else
return 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 << 8); \
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_t
bridge_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);
else
   BDG_STAT(ifp, BDG_FORWARD);
break ;
   }

   if ( dropit ) {/*不转发为真吗?*/
if (dst == BDG_BCAST || dst == BDG_MCAST || dst == BDG_LOCAL)
dst = BDG_LOCAL ;/*如果是发送给本机的包,即上面那些条件成立,返回该标志由ether_input函数处理*/
else
  dst = BDG_DROP ;/*该标志返回给ether_input后,该函数会把包抛弃*/
   } else {
if (dst == ifp)/*如果包来自该接口,又要发送到该接口,当然应该丢弃该包*/
   dst = BDG_DROP;
   }
   DEB(printf("bridge_in %6D ->%6D ty 0x%04x dst %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 {   \

上一页  [1] [2] [3] [4] [5] 下一页

  • 上一篇文章:
  • 下一篇文章:
  • 热门文章
    Olldbg常见问题
    汇编语言的艺术(组合语言的艺术)--观
    汇编语言的艺术(组合语言的艺术)--准
    汇编语言的艺术(组合语言的艺术)--基
    汇编语言的艺术(组合语言的艺术)--基
    汇编语言---程式设计 (4)
    虚拟8086模式
    SYS命令使用说明
    javascript + CSS 实现动态菜单显
    推荐文章
    自制Windows XP SP2自动安装光盘
    SQLServer注入工具改进版 v1.02
    使用photoshop CS进行自然美肤
    Photoshop绘制诺基亚手机
    PHOTOSHOP制作秋日之梦
    PHOTOSHOP鼠绘名模王爱萍
    Photoshop制作晶莹飞溅的水珠
    教你用PHOTOSHOP做放大镜
    鼠绘美女及服装修画全过程