使用setsockopt()系统绑定设备的原始套接字在Fedora core 6(2.6.18-1.2798.fc6)中不工作
请在这个问题上任何人都能帮忙。请 在下面的示例代码中,我们使用eth0绑定了raw sock。但是在运行程序时 原始sock的recvfrom正在同一台机器(xx_86)上接收来自eth0和eth1的数据包。 我不清楚为什么,我可以在这个问题上帮助一个人。 我希望setsockopt不能正常工作 操作系统:Fedora core 6(2.6.18-1.2798.fc6) Sampe代码:使用setsockopt()系统绑定设备的原始套接字在Fedora core 6(2.6.18-1.2798.fc6)中不工作,c,raw-sockets,C,Raw Sockets,请在这个问题上任何人都能帮忙。请 在下面的示例代码中,我们使用eth0绑定了raw sock。但是在运行程序时 原始sock的recvfrom正在同一台机器(xx_86)上接收来自eth0和eth1的数据包。 我不清楚为什么,我可以在这个问题上帮助一个人。 我希望setsockopt不能正常工作 操作系统:Fedora core 6(2.6.18-1.2798.fc6) Sampe代码: #include <stdio.h> #include <stdlib.h> #in
#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <unistd.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <linux/if_ether.h>
#include <net/if.h>
#include <linux/filter.h>
#include <sys/ioctl.h>
#include <string.h>
#include <arpa/inet.h>
int main(int argc, char **argv) {
int sock, i;
unsigned char buffer[2048];
unsigned char tbuff[2048];
unsigned char *iphead, *ethhead,*phead;
struct ifreq ethreq;
// NOTE: use TCPDUMP to build the filter array.
// set filter to sniff only port 443
// $ sudo tcpdump -dd port 443
// raw for recvfrom eth0
if ((sock = socket(PF_PACKET, SOCK_RAW, htons(ETH_P_IP))) == -1) {
perror("socket");
exit(1);
}
// set network card to promiscuos
strncpy(ethreq.ifr_name, "eth0", IFNAMSIZ);
if (ioctl(sock,SIOCGIFFLAGS, ðreq) == -1) {
perror("ioctl");
close(sock);
exit(1);
}
ethreq.ifr_flags |= IFF_PROMISC;
if (ioctl(sock, SIOCSIFFLAGS, ðreq) == -1) {
perror("ioctl");
close(sock);
exit(1);
}
//bind to sock with eth0
struct ifreq Interface;
memset(&Interface, 0, sizeof(Interface));
strncpy(Interface.ifr_ifrn.ifrn_name, "eth0", IFNAMSIZ);
if (setsockopt(sock, SOL_SOCKET, SO_BINDTODEVICE, &Interface, sizeof(Interface)) < 0) { close(sock); }
//open the RAW socket for sendto
int s = socket (PF_INET, SOCK_RAW, IPPROTO_RAW);
struct sockaddr_in sin;
memset(&sin,0,sizeof(sin));
sin.sin_family = AF_INET;
sin.sin_port = htons(0);
sin.sin_addr.s_addr = inet_addr ("10.3.161.104");
// inform kernal don't fill IP and Transport header
int one = 1;
const int *val = &one;
if (setsockopt (s, IPPROTO_IP, IP_HDRINCL, val, sizeof (one)) < 0)
printf ("Warning: Cannot set HDRINCL!\n");
//bind the sock descriptor with eth0
struct ifreq Interface1;
memset(&Interface1, 0, sizeof(Interface1));
strncpy(Interface1.ifr_ifrn.ifrn_name, "eth0", IFNAMSIZ);
if (setsockopt(s, SOL_SOCKET, SO_BINDTODEVICE, &Interface1, sizeof(Interface1)) < 0) { close(s); }
while (1) {
printf("----------------------\n");
i = recvfrom(sock, buffer, sizeof(buffer), 0, NULL, NULL);
printf("%d bytes read\n", i);
// check header size: Ethernet = 14, IP = 20, TCP = 8 (sum = 42)
if (i < 42) {
perror("recvfrom():");
printf("Incomplete packet (errno is %d)\n", errno);
close(sock);
exit(0);
}
phead = buffer + 14; // (skip ethernet header)
memcpy(tbuff,phead,i-14);
iphead=tbuff;
if (*iphead == 0x45) {
int ptrindex= iphead[9];
switch(ptrindex){
case 1:
printf("The transport protocl is:ICMP\n");
break;
case 2:
printf("The transport protol is:IGMP\n");
break;
case 6:
printf("The transport protocol is:TCP\n");
break;
case 17:
printf("The transport protocol is:UDP\n");
break;
case 103:
printf("The transport protocol is:PIM\n");
break;
default:
printf("The transport protocol is:%d\n",iphead[9]);
}
//printf("%d",*ptrindex);
// printf("\n The transport protocol is :%u\n",iphead[9]);
printf("Source Address: %d.%d.%d.%d, Port: %d\n",
iphead[12], iphead[13], iphead[14], iphead[15], (iphead[20] << 8) + iphead[21]);
printf("Dest Address: %d.%d.%d.%d, Port: %d\n",
iphead[16], iphead[17], iphead[18], iphead[19], (iphead[22] << 8) + iphead[23]);
if(sendto(s,tbuff,i-14,0,(struct sockaddr *)&sin,sizeof(sin))<0)
printf("error\n");
else{printf("\nThe received packet is send\n");}
memset(buffer,0,sizeof(buffer));
memset(tbuff,0,sizeof(tbuff));
}
else{ printf("The non ip had received");}
}
close(sock);
}
#包括
#包括
#包括
#包括
#包括
#包括
#包括
#包括
#包括
#包括
#包括
#包括
int main(int argc,字符**argv){
int sock,i;
无符号字符缓冲区[2048];
无符号字符tbuff[2048];
未签名字符*iphead、*ethhead、*phead;
结构ifreq-ethreq;
//注意:使用TCPDUMP构建过滤器阵列。
//将过滤器设置为仅嗅探端口443
//$sudo tcpdump-dd端口443
//来自eth0的recvfrom的原始数据
if((sock=socket(PF_数据包,sock_原始,htons(ETH_P_IP)))=-1){
佩罗(“插座”);
出口(1);
}
//将网卡设置为promiscuos
strncpy(ethreq.ifr_名称,“eth0”,IFNAMSIZ);
if(ioctl(sock、SIOCGIFFLAGS和ethreq)=-1){
perror(“ioctl”);
关闭(袜子);
出口(1);
}
ethreq.ifr_flags |=IFF_PROMISC;
if(ioctl(sock、SIOCSIFFLAGS和ethreq)=-1){
perror(“ioctl”);
关闭(袜子);
出口(1);
}
//用eth0绑定到sock
结构ifreq接口;
memset(&Interface,0,sizeof(Interface));
strncpy(Interface.ifr_ifrn.ifrn_name,“eth0”,IFNAMSIZ);
if(setsockopt(sock,SOL_SOCKET,SO_BINDTODEVICE,&Interface,sizeof(Interface))<0){close(sock);}
//打开sendto的原始套接字
int s=插座(PF_INET、SOCK_RAW、IPPROTO_RAW);
sin中的结构sockaddr_;
memset(&sin,0,sizeof(sin));
sin.sin_family=AF_INET;
sin.sin_端口=htons(0);
sin.sin_addr.s_addr=inet_addr(“10.3.161.104”);
//通知内核不要填充IP和传输头
int-one=1;
常量int*val=&one;
如果(设置锁定选项(s、IPPROTO_IP、IP_HDRINCL、val、尺寸(一个))<0)
printf(“警告:无法设置HDRINCL!\n”);
//用eth0绑定sock描述符
结构ifreq接口1;
memset(&Interface1,0,sizeof(Interface1));
strncpy(interface 1.ifr_ifrn.ifrn_name,“eth0”,IFNAMSIZ);
if(setsockopt(s,SOL_SOCKET,SO_BINDTODEVICE,&Interface1,sizeof(Interface1))<0{close(s);}
而(1){
printf(“-------------------------\n”);
i=recvfrom(sock,buffer,sizeof(buffer),0,NULL,NULL);
printf(“%d字节读取\n”,i);
//检查报头大小:以太网=14,IP=20,TCP=8(总和=42)
如果(i<42){
perror(“recvfrom():”);
printf(“不完整的数据包(错误号为%d)\n”,错误号);
关闭(袜子);
出口(0);
}
phead=缓冲区+14;//(跳过以太网报头)
memcpy(tbuff、phead、i-14);
iphead=tbuff;
如果(*iphead==0x45){
int ptrindex=iphead[9];
开关(ptrindex){
案例1:
printf(“传输协议为:ICMP\n”);
打破
案例2:
printf(“传输协议为:IGMP\n”);
打破
案例6:
printf(“传输协议为:TCP\n”);
打破
案例17:
printf(“传输协议为:UDP\n”);
打破
案例103:
printf(“传输协议为:PIM\n”);
打破
违约:
printf(“传输协议为:%d\n”,iphead[9]);
}
//printf(“%d”,*ptrindex);
//printf(“\n传输协议为:%u\n”,iphead[9]);
printf(“源地址:%d.%d.%d.%d,端口:%d\n”,
iphead[12]、iphead[13]、iphead[14]、iphead[15]、(linux手册页中的iphead[20](http://linux.die.net/man/7/socket):
SO\u BINDTODEVICE
将此套接字绑定到特定设备,如“eth0”,如传递的接口名称中所指定。如果名称为空字符串或选项长度为零,则将删除套接字设备绑定。传递的选项是以null结尾的可变长度接口名称字符串,最大大小为IFNAMSIZ。如果套接字绑定到接口,则仅从该特定接口接收数据包e由套接字处理。请注意,这仅适用于某些套接字类型,尤其是AF_INET sockets。数据包套接字不支持此操作(在那里使用普通绑定(2))
所以,还是试试绑定吧。谢谢大家,非常感谢你们宝贵的时间。它是用绑定方法工作的
代码段帮助了我
setsockopt()
是fedora 2.6.18中的一个bug
替代方法如下所示
void BindToInterface(int raw , char *device , int protocol) {
struct sockaddr_ll sll;
struct ifreq ifr; bzero(&sll , sizeof(sll));
bzero(&ifr , sizeof(ifr));
strncpy((char *)ifr.ifr_name ,device , IFNAMSIZ);
//copy device name to ifr
if((ioctl(raw , SIOCGIFINDEX , &ifr)) == -1)
{
perror("Unable to find interface index");
exit(-1);
}
sll.sll_family = AF_PACKET;
sll.sll_ifindex = ifr.ifr_ifindex;
sll.sll_protocol = htons(protocol);
if((bind(raw , (struct sockaddr *)&sll , sizeof(sll))) ==-1)
{
perror("bind: ");
exit(-1);
}
return 0;
}
好的,为什么不在setsockopt()
错误上设置一个perror()
?谢谢大家,非常感谢你们花了这么多时间。它是用绑定方法工作的