我们正试图通过原始套接字与侦听
Linux环回接口的服务器通信,似乎服务器没有从我们那里获得单个数据包.我们发送的数据包在Wireshark中可见.
是否可以在环回上使用原始套接字? (请不要问我们为什么需要它:这里解释起来太复杂了)
编辑:这是我们打开它的方式
_I_RawSocket = socket( PF_PACKET,SOCK_RAW,htons(ETH_P_ALL))) memset( &ifr,sizeof( ifr ) ); strcpy( ifr.ifr_ifrn.ifrn_name,_InterfaceName); ioctl( _I_RawSocket,SIOCGIFINDEX,&ifr ) memset( &sll,sizeof( sll ) ); sll.sll_family = AF_PACKET; sll.sll_ifindex = ifr.ifr_ifindex; sll.sll_protocol = htons( ETH_P_ALL ); bind( _I_RawSocket,(struct sockaddr *) &sll,sizeof( sll ))
服务器是lighttpd,可通过localhost上的普通套接字访问.
netstat –raw打印空表但我绝对相信我们在普通eth设备上有两个功能原始套接字.
解决方法
原始套接字使用bind()和connect()表现得特别不稳定,但我无法确认您的问题在于它们.我建议你遵循一个更简单的方法:
寄件人
#include <sys/socket.h> #include <sys/types.h> #include <netinet/ip.h> #include <arpa/inet.h> #include <string.h> #include <stdio.h> #include <stdlib.h> #define DEST "127.0.0.1" int main(int argc,char **argv) { int s; struct sockaddr_in dst_addr; char packet[50]; struct iphdr *ip = (struct iphdr *)packet; if((s = socket(AF_INET,IPPROTO_RAW)) < 0) { perror("error:"); exit(EXIT_FAILURE); } dst_addr.sin_family = AF_INET; dst_addr.sin_port = 0; /* not needed in SOCK_RAW */ inet_pton(AF_INET,DEST,(struct in_addr *)&dst_addr.sin_addr.s_addr); memset(dst_addr.sin_zero,sizeof(dst_addr.sin_zero)); memset(packet,'A',sizeof(packet)); /* payload will be all As */ ip->ihl = 5; ip->version = 4; ip->tos = 0; ip->tot_len = htons(40); ip->frag_off = 0; /* NF */ ip->ttl = 64; ip->protocol = IPPROTO_RAW; /* this has to be IPPROTO_RAW */ ip->check = 0; ip->saddr = dst_addr.sin_addr.s_addr; ip->daddr = dst_addr.sin_addr.s_addr; while(42) { sleep(5); if (sendto(s,packet,sizeof(packet),(struct sockaddr *)&dst_addr,(socklen_t)sizeof(dst_addr)) < 0) perror("uh oh:"); } return(0); }
接收器
#include <sys/socket.h> #include <sys/types.h> #include <netinet/ip.h> #include <arpa/inet.h> #include <string.h> #include <stdio.h> #include <stdlib.h> int main(int argc,char **argv) { int s; struct sockaddr_in src_addr; char packet[50]; if ((s = socket(AF_INET,IPPROTO_RAW)) < 0) { perror("error:"); exit(EXIT_FAILURE); } memset(packet,sizeof(packet)); socklen_t *len = (socklen_t *)sizeof(src_addr); int fromlen = sizeof(src_addr); while(42) { if (recvfrom(s,&packet,(struct sockaddr *)&src_addr,&fromlen) < 0) perror("uh oh:"); int i = sizeof(struct iphdr); /* print the payload */ for(; i < sizeof(packet); i++) { printf("%c",packet[i]); } printf("\n"); } return(0); }
我希望这些行为完全像你想要的那样.阅读man 7 raw,了解为什么这有效的血腥细节,更重要的是man 7数据包,如果你想扩展它.另外,请注意IPPROTO_RAW意味着IP_HDRINCL套接字选项,这就是我们自己构建ip头的原因 – 尽管IP校验和和总长度仍由内核计算和填充.
编辑:此外,如果您想要一个原始套接字用于将有效数据发送到像lighttpd这样的应用程序,您必须将协议参数与socket()匹配,并为IP头字段提供有效值.正确的以太网头不是必需的 – 内核堆栈将为您填充唯一重要的字段.