我试图通过使用原始套接字添加新的Hop by Hop选项。由于内核不处理无法识别的选项类型,因此会发送无法识别的参数的ICMP错误。
我尝试通过添加新选项作为已知选项来更改内核中的一些内容,因此内核不会向我发送错误。到目前为止这是成功的...但问题是,接收器没有收到数据包。使用Wireshark,它显示数据包在接口处被截获,但不会显示在用户空间中。
我的代码如下,
在发件人处,它会在最后打印"已发送的数据" ,但接收者不会打印任何内容。
server.c
#include <sys/socket.h>
#include <errno.h>
#include <sys/types.h>
#include <netinet/ip6.h>
#include <arpa/inet.h>
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
#include <netdb.h>
#include <netinet/in.h>
#include <time.h>
#define DEST "::1"
#define IPV6_TLV_OPTX 0xEE
#define IPV6_TLV_ROUTERALERT 5
short unsigned sequence_number();
short unsigned number;
int main(void)
{
int j=0, pton_fd;
int i=0;
struct ip6_hbh hbh_hdr;
struct msghdr msg = {};
struct cmsghdr *cmsg;
int cmsglen;
char src_ip[INET6_ADDRSTRLEN], dst_ip[INET6_ADDRSTRLEN];
int s,status;
struct sockaddr_in6 daddr;
char packet[40];
//-----members for ancillary data-----------
struct iovec iov[2];
void *extbuf;
socklen_t extlen;
int currentlen;
void *databuf;
int offset;
uint8_t value;
uint8_t value1;
uint8_t value2;
/* point the iphdr to the beginning of the packet */
struct ip6_hdr *ip = (struct ip6_hdr *)packet;
if ((s = socket(AF_INET6, SOCK_RAW, IPPROTO_RAW)) < 0) {
perror("error:");
exit(EXIT_FAILURE);
}
int setsock_offset = 2;
if(setsockopt(s, IPPROTO_IPV6, IPV6_CHECKSUM, &setsock_offset, sizeof(setsock_offset) < 0))
{
perror("setsockopt");
exit(EXIT_FAILURE);
}
daddr.sin6_family = AF_INET6;
daddr.sin6_port = 0; /* not needed in SOCK_RAW */
daddr.sin6_scope_id = if_nametoindex("eth0");
pton_fd = inet_pton(AF_INET6, "fe80::a00:27ff:fe30:9ae9", (struct in6_addr *)&daddr.sin6_addr.s6_addr);
if (pton_fd == 0)
{
printf("Does not contain a character string representing a network address");
exit(EXIT_FAILURE);
}
else if (pton_fd < 0)
{
perror("pton()");
exit(EXIT_FAILURE);
}
ip->ip6_flow = htonl ((6<<28) | (0<<20) | 0);
ip->ip6_plen = htons (8);
ip->ip6_nxt = 0;
ip->ip6_hops = 64;
if ((status = inet_pton(AF_INET6, "fe80::921b:eff:fe03:637d", &(ip->ip6_src))) != 1)
{
fprintf(stderr,"inet_pton() failed.\nError message: %s",strerror(status)); exit(EXIT_FAILURE);
}
if ((status = inet_pton(AF_INET6, "fe80::a00:27ff:fe30:9ae9", &(ip->ip6_dst))) != 1)
{
fprintf(stderr,"inet_pton() failed.\nError message: %s",strerror(status)); exit(EXIT_FAILURE);
}
// Specifying the ancillary data for Hop-by-Hop headers
currentlen = inet6_opt_init(NULL,0);
if (currentlen == -1){
perror("1st opt_init");
exit(EXIT_FAILURE);
}
printf("Hop by Hop length: %d\n", currentlen);
// Setting Hop by Hop extension header next field
//hbh_hdr.ip6h_nxt = 59;
//hbh_hdr.ip6h_len = 0;
currentlen = inet6_opt_append(NULL, 0, currentlen, IPV6_TLV_ROUTERALERT, 2, 1, NULL);
if (currentlen == -1) {
printf("ERROR NO: %d\n",errno);
//perror("1st opt_append");
fprintf(stderr, "append error %s, %s\n",strerror(errno),strerror(currentlen));
exit(EXIT_FAILURE);
}
currentlen = inet6_opt_finish(NULL, 0, currentlen);
if (currentlen == -1) {
perror("1st opt_finish");
exit(EXIT_FAILURE);
}
printf("currentlen: %d\n",currentlen);
extlen = currentlen;
cmsglen = CMSG_SPACE(extlen);
cmsg = malloc(sizeof(cmsglen));
if (cmsg == NULL) {
perror("msg malloc");
exit(EXIT_FAILURE);
}
cmsg->cmsg_len = CMSG_LEN(extlen);
cmsg->cmsg_level = IPPROTO_IPV6;
cmsg->cmsg_type = IPV6_HOPOPTS;
extbuf = CMSG_DATA(cmsg);
extbuf = malloc(extlen);
printf("Size of extbuf: %ld",sizeof(extbuf));
if (extbuf == NULL) {
perror("malloc");
exit(EXIT_FAILURE);
}
printf("Extenlen: %d\n",extlen);
//hbh_hdr.ip6h_nxt = 59;
currentlen = inet6_opt_init(extbuf, extlen);
if (currentlen == -1) {
perror("2nd opt_init");
exit(EXIT_FAILURE);
}
//extbuf = (unsigned char*)extbuf;
//char ip6hop_nexth_value = 59;
*(unsigned char*)(extbuf) = 59;
unsigned char* temp = extbuf;
//for(i=0; i<extlen;i++) {
// printf("Ext buffer is: %d\n",*temp);
// temp++;
//}
currentlen = inet6_opt_append(extbuf, extlen, currentlen, IPV6_TLV_ROUTERALERT, 2, 1, &databuf);
if (currentlen == -1) {
perror("append() error");
exit(EXIT_FAILURE);
}
printf("len after append:%d\n", currentlen);
//insert value for the version and flags
offset = 0;
value = 0x11;
offset = inet6_opt_set_val(databuf, offset, &value, sizeof(value));
//value1 = 0x01;
//printf("Data buffer is: %x\n",databuf);
//offset = inet6_opt_set_val(databuf, offset, &value1, sizeof(value1));
value2 = 0x01;
offset = inet6_opt_set_val(databuf, offset, &value2, sizeof(value2));
currentlen = inet6_opt_finish(extbuf, extlen, currentlen);
if (currentlen == -1)
perror("opt_finish");
//*(uint8_t)(extbuf) = 59;
printf("Data buffer is: %x\n",*(unsigned char*)(databuf));
printf("Extlen is: %d\n",extlen);
printf("Currentlen is: %d\n", currentlen);
unsigned char* temp1 = databuf;
for(j=0; j<3;j++) {
printf("Data buffer is: %d\n",*temp1);
temp1++;
}
for(i=0;i<extlen;i++) {
printf("exbuf is:%d\n",*temp);
temp++;
}
/*
cmsglen = CMSG_SPACE(extlen);
cmsg = malloc(cmsglen);
if (cmsg == NULL) {
perror("msg malloc");
exit(EXIT_FAILURE);
}
cmsg->cmsg_len = CMSG_LEN(extlen);
cmsg->cmsg_level = IPPROTO_IPV6;
cmsg->cmsg_type = IPV6_HOPOPTS;
extbuf = CMSG_DATA(cmsg);
*/
iov[0].iov_base = packet;
iov[0].iov_len = sizeof(packet);
iov[1].iov_base = extbuf;
iov[1].iov_len = sizeof(extbuf);
//iov[2].iov_base = databuf;
//iov[2].iov_len = sizeof(databuf);
msg.msg_control = cmsg;
msg.msg_controllen = cmsglen;
msg.msg_name = (struct sockaddr*)&daddr;
msg.msg_namelen = sizeof(daddr);
msg.msg_iov = &iov;
msg.msg_iovlen = 2;
msg.msg_flags = 0;
while(1) {
sleep(1);
/*if (sendto(s, (char *)packet, sizeof(packet), 0,
(struct sockaddr *)&daddr, (socklen_t)sizeof(daddr)) < 0)
perror("packet send error:");
}*/
if (sendmsg(s, &msg, 2) < 0) {
perror("sendmsg()");
}
else
printf("data sent\n");
}
exit(EXIT_SUCCESS);
}
short unsigned sequence_number()
{
number = rand();
return number;
}
RECEIVER.C
#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>
#include <string.h>
#include <netinet/ip6.h>
#include <errno.h>
#include <netdb.h>
#define IP_TLV_ROUTERALERT 5
int print_options(void *, socklen_t);
int main(void)
{
int s,i;
struct sockaddr_in6 saddr;
char packet[80];
int setsock_offset = 1;
//-----for ancillary data
int currentlen;
void *extptr;
struct sockaddr_in6 addr;
struct msghdr msg;
struct cmsghdr *cmsgptr;
struct iovec iov;
void *extbuf;
socklen_t extension_len;
socklen_t extlen;
socklen_t cmsgspace;
char databuf[80];
char sender_ip[40];
//sender_ip = (char*)malloc(sizeof(char));
printf("size :%d\n",sizeof(sender_ip));
strcpy(sender_ip, "fe80::921b:eff:fe03:637d");
printf("Sender ip: %s\n", sender_ip);
addr.sin6_family = AF_INET6;
addr.sin6_port = 0;
inet_pton(AF_INET6, sender_ip, (struct in6_addr *)&addr.sin6_addr.s6_addr);
if ((s = socket(AF_INET6, SOCK_RAW, IPPROTO_RAW)) < 0) {
perror("error:");
exit(EXIT_FAILURE);
}
if (setsockopt(s, IPPROTO_IPV6, IPV6_RECVHOPOPTS, &setsock_offset, sizeof(setsock_offset)) < 0)
{
perror("setsockopt");
exit(EXIT_FAILURE);
}
currentlen = inet6_opt_init(NULL,0);
if (currentlen == -1)
{
perror("1st opt_init");
exit(EXIT_FAILURE);
}
currentlen = inet6_opt_append(NULL,0,currentlen, IPV6_TLV_ROUTERALERT, 2, 1, NULL);
if (currentlen == -1)
{
perror("1st append");
exit(EXIT_FAILURE);
}
currentlen = inet6_opt_finish(NULL, 0, currentlen);
if (currentlen == -1)
{
perror("1st finish");
exit(EXIT_FAILURE);
}
extension_len = currentlen;
cmsgspace = CMSG_SPACE(extension_len);
cmsgptr = malloc(cmsgspace);
if (cmsgptr == NULL)
{
perror("malloc");
exit(EXIT_FAILURE);
}
extptr = CMSG_DATA(cmsgptr);
msg.msg_control = cmsgptr;
msg.msg_controllen = cmsgspace;
iov.iov_base = databuf;
iov.iov_len = 1;
msg.msg_iov = &iov;
msg.msg_iovlen = 1;
msg.msg_flags = 0;
msg.msg_name = (struct sockaddr *)&addr;
msg.msg_namelen = sizeof(addr);
memset(packet, 0, sizeof(packet));
socklen_t *len = (socklen_t *)sizeof(saddr);
int fromlen = sizeof(saddr);
while(1)
{
printf("Waiting for packets...\n");
if (recvmsg(s, &msg, 0) == -1)
{
perror("packet receive error:");
return;
}
if (msg.msg_controllen != 0 &&
cmsgptr->cmsg_level == IPPROTO_IPV6 &&
cmsgptr->cmsg_type == IPV6_HOPOPTS ) {
print_options(extptr, extension_len);
}
}
}
int print_options(void *extbuf, socklen_t extlen)
{
struct ip6_hbh *ext;
int currentlen;
uint8_t type;
socklen_t len;
void *databuf;
int offset;
uint8_t value;
uint8_t value1;
ext = (struct ip6_hbh *)extbuf;
printf("nxt header %u, len: %u (bytes%d)\n", ext->ip6h_nxt, ext->ip6h_len, (ext->ip6h_len + 1)*8);
currentlen = 0;
while(1)
{
currentlen = inet6_opt_next(extbuf, extlen, currentlen, &type, &databuf);
if(currentlen == -1)
break;
printf("Received opt %u len %u\n", type, len);
switch(type)
{
case IPV6_TLV_ROUTERALERT:
offset = 0;
offset = inet6_opt_get_val(databuf, offset, &value, sizeof(value) );
printf("1 byte field %x\n", value);
offset = inet6_opt_get_val(databuf, offset, &value1, sizeof(value1) );
printf("2 byte field %x\n", value1);
break;
default:
printf("unknown option :%x\n", type);
break;
}
}
return(0);
}
我一直在使用的参考文献来自RFC 3542。
如果您能够提供一些参考资料,我可以在哪里获得更多信息,或者唯一的方法是创建ethernet_level原始套接字并获取用户的所有信息 - space。(我认为这是不合理的,因为必须有一种方法对用户空间进行一些测试)
答案 0 :(得分:1)
在您的receiver.c中,使用以下命令创建一个rawip套接字:
(s = socket(AF_INET6, SOCK_RAW, IPPROTO_RAW))
问题在于IPPROTO_RAW,您可以在以下网址获取其描述:
http://manpages.ubuntu.com/manpages/hardy/man7/raw.7.html
“IPPROTO_RAW协议意味着启用了IP_HDRINCL,并且能够发送传递头中指定的任何IP协议。使用原始套接字无法通过IPPROTO_RAW接收所有IP协议。”
您可以使用NEXTHDR_HOP而不是IPPROTO_RAW创建套接字。
我自己没有尝试过,只需从doc / code获取。