免费注册 查看新帖 |

Chinaunix

  平台 论坛 博客 文库
最近访问板块 发新帖
查看: 5258 | 回复: 8
打印 上一主题 下一主题

网络编程中,指定ifindex发送无效的问题 [复制链接]

论坛徽章:
0
跳转到指定楼层
1 [收藏(0)] [报告]
发表于 2010-02-02 11:10 |只看该作者 |倒序浏览
sockfd是IPv6下的原始套接口,IPPROTO_CN是自己定义的数。如下:
sockfd = socket(AF_INET6, SOCK_RAW, IPPROTO_CN);

发送数据时使用sendmsg函数,我想指定用哪个网卡发送数据,但是指定无效。
比如eth0的ifindex是2,lo的ifindex是1。
当我指定ifindex是2时,对方能收到数据,正常。可是指定ifindex是1时,按理说对方应该收不到,可是却收到了。

请教问题出在什么地方?

(问题更详细的描述在 http://bbs.chinaunix.net/thread-1626203-1-1.html 的前两楼)

论坛徽章:
0
2 [报告]
发表于 2010-02-03 11:24 |只看该作者
设置的返回值你判断了吗?确定设置成功了?

论坛徽章:
0
3 [报告]
发表于 2010-02-03 12:25 |只看该作者
判断了,成功。而且对方也成功收到数据了。

论坛徽章:
0
4 [报告]
发表于 2010-02-04 12:59 |只看该作者
本帖最后由 migney 于 2010-02-04 13:17 编辑

三台主机A、B、C。A与B相连,B与C相连。

B有2个网卡:与A相连的网卡为eth0,接口索引为2,IPv6地址为1::2。与C相连的网卡为eth1,接口索引为3,IPv6地址为2::1。
A有1个网卡:eth0,接口索引为2,IPv6地址为1::1。
C有1个网卡:eth0,接口索引为2,IPv6地址为2::2。

即:
[A eth0,2,1::1]-------[eth0,2,1::2  B  eth1,3,2::1]----------[eth0,2,2::2  C]

  1. //省略各种include
  2. int main ()
  3. {
  4.         int sockfd = socket (AF_INET6, SOCK_RAW, 88);
  5.         if (sockfd < 0) {
  6.                 perror ("socket");
  7.                 return -1;
  8.         }

  9.         int hop = 1; /* 设置为1跳,即只有邻居才能收到 */
  10.         if (setsockopt (sockfd, IPPROTO_IPV6, IPV6_MULTICAST_HOPS, &hop, sizeof (hop)) < 0) {
  11.                 perror ("setsockopt");
  12.                 return -1;
  13.         }

  14.         char dst_addr[] = "ff02::1"; /* 组播地址 */
  15.         char src_addr[] = "1::2"; /* IPv6数据报源地址 */
  16.         int ifindex = 3; /* 设置从哪个接口发送数据 */
  17.         char data[] = "\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f\x00";

  18.         struct iovec iovector[2];
  19.         iovector[0].iov_base = (void *)data;
  20.         iovector[0].iov_len = 16;
  21.         iovector[1].iov_base = NULL;
  22.         iovector[1].iov_len = 0;

  23.         struct sockaddr_in6 sa6_dst;
  24.         memset (&sa6_dst, 0, sizeof (sa6_dst));
  25.         sa6_dst.sin6_family = AF_INET6;
  26. #ifdef SIN6_LEN
  27.         sa6_dst.sin6_len = sizeof (struct sockaddr_in6);
  28. #endif
  29.         if (inet_pton (AF_INET6, dst_addr, &sa6_dst.sin6_addr) != 1) {
  30.                 perror ("inet_pton");
  31.                 return -1;
  32.         }
  33. #ifdef HAVE_SIN6_SCOPE_ID
  34.         sa6_dst.sin6_scope_id = ifindex;
  35. #endif

  36.         u_char cmsgbuf[CMSG_SPACE(sizeof (struct in6_pktinfo))];
  37.         struct cmsghdr *scmsgp;
  38.         scmsgp = (struct cmsghdr *)cmsgbuf;
  39.         struct in6_pktinfo *pktinfo;
  40.         pktinfo = (struct in6_pktinfo *)(CMSG_DATA(scmsgp));

  41.         scmsgp->cmsg_len = CMSG_LEN (sizeof (struct in6_pktinfo));
  42.         scmsgp->cmsg_level = IPPROTO_IPV6;
  43.         scmsgp->cmsg_type = IPV6_PKTINFO;
  44.         if (inet_pton (AF_INET6, src_addr, &pktinfo->ipi6_addr) != 1) {
  45.                 perror ("inet_pton");
  46.                 return -1;
  47.         }
  48.         pktinfo->ipi6_ifindex = ifindex;

  49.         struct msghdr smsghdr;
  50.         memset (&smsghdr, 0, sizeof (struct msghdr));
  51.         smsghdr.msg_name = (void *)&sa6_dst;
  52.         smsghdr.msg_namelen = sizeof (struct sockaddr_in6);
  53.         smsghdr.msg_iov = iovector;
  54.         smsghdr.msg_iovlen = 1;
  55.         smsghdr.msg_control = NULL;
  56.         smsghdr.msg_controllen = 0;
  57.         smsghdr.msg_flags = 0;

  58.         int n;
  59.         if ((n = sendmsg (sockfd, &smsghdr, 0)) < 0)
  60.         {
  61.                 perror("sendmsg");
  62.                 return -1;
  63.         }

  64.         printf ("send %d bytes\n", n);

  65.         return 0;
  66. }
复制代码
看代码中17、18两行,无论源地址改为什么,发送接口索引改为什么,都只有主机A能收到数据,且源地址为 fe80 :: xxxx : xxxx : xxxx : xxxx 形的地址。
由此可见,这两行设置没有起作用。

论坛徽章:
0
5 [报告]
发表于 2010-02-04 15:04 |只看该作者
如果目的地址不写链路组播地址,直接写B的地址。看看B能收到吗。

我最近也在研究ipv6,正好讨论讨论。

论坛徽章:
0
6 [报告]
发表于 2010-02-04 16:40 |只看该作者
本帖最后由 migney 于 2010-02-04 16:42 编辑

我忘了说了,上面发送程序是在B上运行的。

如果目的地址写A的地址1::1,A能收到,且源地址为1::2,正常。
C也一样。
我想B是看目的地址的网段,与哪个网卡相同,就从哪个网卡发送。如果都不相同,就用默认的网卡发送。

但是问题在于,设置的源地址和发送接口无论怎么写都没有效果。

论坛徽章:
0
7 [报告]
发表于 2010-02-04 21:37 |只看该作者
A B C的地址是不是有问题阿。
链路地址都是FE02开头的。

你把A,B,C的地址都设置为FE02开头的试试。

还有你最好用tcpdump在B上抓包看看,看这个包从哪个网卡发送出去了。也许是两个都发送了。

还有再试一下,目的地址直接写成C的,看C能否收到。

ipv6的应用层程序我没写过,我一直是做内核协议栈开发的。

论坛徽章:
0
8 [报告]
发表于 2010-02-05 12:43 |只看该作者
你指的链路地址都是FE02开头的,是不是ifconfig结果中Scope:Link那个地址?
我这里的地址都是以FE80开头的。

在B上抓包结果说明,只是从eth0发送了,没有从eth1发送。

目的地址写成C的,C能收到。

问一下,内核协议栈开发,会不会遇到使数据从指定接口发送出去的情况?是怎么做的呢?

感谢一直以来的关注

论坛徽章:
0
9 [报告]
发表于 2010-02-06 00:03 |只看该作者
在内核发送的话,直接指定目的dev。很简单。但是应用层就比较麻烦,毕竟中间经过了太多的代码。那一个环节出错都可能错误。

我觉得这个问题有可能是这样。你B节点上两个地址都是同一个网段的。
对于ipv4来说,相当于你两个网卡一个地址是192.168.1.10 另一个是192.168.1.20

所以协议栈就分辨不出来用哪个发送。

既然直接写C的地址,C能收到,说明程序和协议栈基本上正常。肯定是有了小问题忽略了。
你把前缀修改一下试试。
您需要登录后才可以回帖 登录 | 注册

本版积分规则 发表回复

  

北京盛拓优讯信息技术有限公司. 版权所有 京ICP备16024965号-6 北京市公安局海淀分局网监中心备案编号:11010802020122 niuxiaotong@pcpop.com 17352615567
未成年举报专区
中国互联网协会会员  联系我们:huangweiwei@itpub.net
感谢所有关心和支持过ChinaUnix的朋友们 转载本站内容请注明原作者名及出处

清除 Cookies - ChinaUnix - Archiver - WAP - TOP