2007年10月22日星期一

套接字选项(三)

如果不在套接字级别上设置选项,即setsockopt系统调用的参数level不设为SOL_SOCKET,那么sys_setsockopt的实现会 直接调用sock->ops->setsockopt。对MY_PF_INET域的RAW协议来讲,sock->ops = myinet_sockraw_ops,而myinet_sockraw_ops.setsockopt = sock_common_setsockopt。
而sock_common_setsockopt直接调用sock->sk->sk_prot->setsockopt。对于RAW协议来讲,即myraw_setsockopt。
下面关注myraw_setsockopt的实现。对于RAW协议来讲,level还可以有两种取值:SOL_IP和SOL_RAW。 myraw_setsockopt首先检查level是否为SOL_IP,如果是,调用myip_setsockopt函数,该函数实现IP级别上的选 项,否则,为SOL_RAW级别上的选项,SOL_RAW级别上只有一个选项,即ICMP_FILTER,在MY_IPPROTO_ICMP协议下有效。 它激活绑定到MY_IPPROTO_ICMP协议的一个用于myraw socket特殊的过滤器。该值对每种ICMP消息都有一个位(掩码),可以把那种ICMP消息过滤掉,缺省时是不过滤ICMP消息。
对于ICMP_FILTER选项,myraw_setsockopt调用myraw_seticmpfilter函数,它把option_value赋给 sock->sk->filter,option_value是一个结构体:
struct icmp_filter {
__u32 data;
};
它是一个32位的位掩码。
关于该位掩码,我们目前知道的是最低位为回显应答的位掩码,由于目前我们的MY_PF_INET域代码还没完善,我们在PF_INET域上进行测试,把下面的代码添加到一个ping程序中,ping程序就收不到来自服务器的回应包了:
#include
#include
#include

#include
#include
int main()
{
struct icmp_filter filter;
socklen_t size = sizeof( struct icmp_filter );
int fd = socket( PF_INET, SOCK_RAW, IPPROTO_ICMP );
if( fd < 0 )
perror("error: ");

getsockopt( fd, SOL_RAW, ICMP_FILTER, &filter, &size );
printf("the filter: %x\n", filter.data );

filter.data = 1;
int err = setsockopt( fd, SOL_RAW, ICMP_FILTER, &filter, sizeof(struct icmp_filter) );
if( err < 0 )
perror("error: ");

memset( &filter, 0, sizeof( struct icmp_filter ) );
getsockopt( fd, SOL_RAW, ICMP_FILTER, &filter, &size );
printf("new filter: %x\n", filter.data);

close(fd);
return 0;
}

没有评论: