c++ - 由于 sin6_port 值,sendto 在 Linux 中的 UDP 原始套接字 ipv6 上返回无效参数?

标签 c++ linux sockets udp ipv6

#include <stdio.h>
#include <stdlib.h>
#include <sys/socket.h>
#include <netinet/ip6.h>
#include <netinet/udp.h>
#include <netinet/in.h>
#include <netdb.h>
#include <arpa/inet.h>
#include <errno.h>
#include <string.h>
#include <sys/types.h>

struct ip6_hdr;
struct udphdr;

int main(){
  int clientSocket, portNum, nBytes;
  char buffer[1024];
  struct sockaddr_in serverAddr;
  struct sockaddr_in6 serverAddr6;
  socklen_t addr_size;
  struct hostent *hp;
  struct msghdr m;
  struct in_addr **addr_list;
  /*Create UDP socket*/
 clientSocket = socket(PF_INET6, SOCK_RAW, IPPROTO_RAW);

  /*Configure settings in address struct*/
  hp = gethostbyname2("2001:0db8:0:f101::2", PF_INET6);
  memset((char *)&serverAddr6, 0, sizeof(serverAddr6));
  memcpy((char *)&serverAddr6.sin6_addr, hp->h_addr, hp->h_length);
  serverAddr6.sin6_family = hp->h_addrtype;
  // serverAddr6.sin6_port   = htons(7891);
  serverAddr6.sin6_port   = 0;//htons(IPPROTO_RAW);

  /*Initialize size variable to be used later on*/
  const size_t IPV6_HEADER_LEN = 40;
  const size_t UDP_HEADER_LEN  = 8;
  addr_size = sizeof serverAddr6;
  size_t data_len = sizeof(serverAddr6) - IPV6_HEADER_LEN;

  /*Populate ip header*/
  struct ip6_hdr *iphdr = (struct ip6_hdr *)buffer;
  iphdr->ip6_flow = htonl ((6 << 28) | (0 << 20) | 0); // IPv6 version (4 bits), Traffic class (8 bits), Flow label (20 bits)
  iphdr->ip6_plen = data_len;

  iphdr->ip6_nxt = IPPROTO_UDP;
  iphdr->ip6_hops = 64;

  //supposing src_addr and dst_addr pointers are never NULL
  memcpy(&iphdr->ip6_src, (const in6_addr*)&serverAddr6.sin6_addr, sizeof(in6_addr));
  memcpy(&iphdr->ip6_dst, (const in6_addr*)&serverAddr6.sin6_addr, sizeof(in6_addr));

  /*Populate UDP header*/
  udphdr * udp_header = reinterpret_cast<udphdr *>(buffer + IPV6_HEADER_LEN);
  udp_header->source = htons(0);
  udp_header->dest   = htons(7891);

  int len = sizeof(serverAddr6);
  uint32_t data_length = (len - (IPV6_HEADER_LEN + UDP_HEADER_LEN));
  udp_header->len      = htons(data_length + sizeof(udphdr));
  udp_header->check    = htons(0);

  for (int i=0; i<10; ++i)
  {
      sprintf(buffer, "%d", i);
      nBytes = strlen(buffer) + 1;

      /*Send message to server*/
      if(sendto(clientSocket,buffer,nBytes,0,(struct sockaddr *)&serverAddr6,addr_size) == -1 )
      {
          printf("sendto(): %s\n", strerror(errno));
          exit(0);
      }

      /*Receive message from server*/
      // nBytes = recvfrom(clientSocket,buffer,1024,0,NULL, NULL);
      // nBytes = recvmsg(clientSocket,&m,0);
    if((nBytes = recvmsg(clientSocket,&m, 0)) == -1)
    {
      printf("recvmsg(): %s\n", strerror(errno));
      // exit(0);
    }
      printf("Received from server: %s\n",buffer);
  }

  return 0;
}

我对套接字编程还很陌生。我有以下代码。它返回 sendto(): 无效参数 经过调查,我发现该行包含: serverAddr6.sin6_port = htons(7891); *在代码片段中注释掉 在谷歌的帮助下,我找到了解决方案 http://osdir.com/ml/linux.ipv6.usagi.users/2003-03/msg00004.html :

From the kernel source code, it seems that when you use raw ipv6 socket, you have to set

dest.sin6_port = htons(IPPROTO_RAW);

http://osdir.com/ml/linux.ipv6.usagi.users/2003-03/msg00005.html 中:

dest.sin6_port=0;

另一方面,我不能采用这个提议的解决方案,因为我必须将端口指定为 0 以外的其他值。

有什么建议或解释吗?

最佳答案

我正在使用 Python 3,并且在发送 IPv6 包时也遇到了 OSError: [Errno 22] Invalid argument。但是,当我将sendto参数的端口号设置为0时,数据包发送成功,脚本生成的数据包中指定的端口( buffer 在你的程序中)仍然被使用。

您应该使用不同的端口号来生成数据包和调用sendto。使用所需的端口号生成并使用端口号 0 调用。

下面是我的代码

s = socket.socket(AF_INET6, SOCK_RAW, IPPROTO_RAW)
s.setsockopt(IPPROTO_IPV6, IP_HDRINCL, 1)
s.sendto(GenerateIPv6Packet('::1', 53, '::1', 53), ('::1', 0))
    # generate the packet with port 53 and call sendto with port 0

很抱歉用不同的编程语言回答。

关于c++ - 由于 sin6_port 值,sendto 在 Linux 中的 UDP 原始套接字 ipv6 上返回无效参数?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/32514818/

相关文章:

c++ - 为什么在一个类中使用 uint64_t 需要比 2 个 uint32_t 更多的内存?以及如何防止这种情况?

c++ - 错误 C2535 : 'void NumberList::appendNode(double)' : member function already defined or declared Line 35

c++ - Qt Release DLL错误

c++ - 将指针作为类模板参数传递给任何成员函数

java - 重新启动游戏服务器后的 Ghost Java 进程

arrays - Bash:awk 输出到数组

linux - 有没有办法使用 IAM 来管理开发人员对 EC2 实例的访问? (ssh 不是 ec2 api)

java - 使用 DataOutputStream 发送 0 字节?

c++ - 在没有atm开关的情况下模拟atm通信

c - 单线程在 WinSock recv() 处阻塞所有其他线程