ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

IPv6组播接口选择

2019-11-09 05:50:51  阅读:338  来源: 互联网

标签:sockets ipv6 c-3 linux multicast


用于为具有IPv4的传出流量选择接口的setsockopt方法是IP_MULTICAST_IF,它接受两个参数.在ip(4)手册页中:

Set the local device for a multicast socket. The argument for
setsockopt(2) is an ip_mreqn or (since Linux 3.5) ip_mreq
structure similar to IP_ADD_MEMBERSHIP, or an in_addr structure.

尝试对IPv6流量执行类似操作时,该选项将更改为接口索引.从ipv6(4)手册页:

Set the device for outgoing multicast packets on the socket.
This is allowed only for SOCK_DGRAM and SOCK_RAW socket. The
argument is a pointer to an interface index (see netdevice(7))
in an integer.

在网络接口(例如eth0)分配了多个地址的情况下会发生什么情况? IPv6套接字接口是否消除了单独使用每个地址的可能性?

解决方法:

如果您的接口只有一个本地链接地址(fe80 :: / 10)和一个公共可路由地址,则传出数据包的源地址取决于您要发送到的多播地址的范围.

IPv6多播地址的格式为ffxy :: / 16,其中x是标志字段,y是作用域.如果范围是1(本地接口)或2(本地链接),则源地址将是本地链接地址.如果范围是3或更大,则源地址将是可公开路由的地址.

另一方面,如果接口具有多个可公共路由的地址,则在发送数据报时需要使用sendmsg,以便可以使用IPV6_PKTINFO控制标头设置源地址.

以下是如何执行此操作的完整示例,假设您将2001 :: 1:2:3和2002 :: 1:2:3作为一个接口上的IPv6地址,而ff03 :: 1:2:3是多播您发送到的地址.

#define _GNU_SOURCE   // needed for some IPv6 datatypes to be visible

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

// multicast address to send to
const char *maddr = "ff03::1:2:3";

// uncomment the line for the source address you want to use
const char *srcaddr = "2001::1:2:3";
//const char *srcaddr = "2002::1:2:3";

int main()
{
    int sock;
    struct sockaddr_in6 dstaddr;

    struct iovec iovec[1];
    struct msghdr msg;
    struct cmsghdr* cmsg;
    char msg_control[1024];
    char udp_packet[] = "this is a test";
    int cmsg_space;
    struct in6_pktinfo *pktinfo;

    dstaddr.sin6_family = AF_INET6;
    inet_pton(AF_INET6, maddr, &dstaddr.sin6_addr);
    dstaddr.sin6_port = htons(5555);
    dstaddr.sin6_flowinfo = 0;
    dstaddr.sin6_scope_id = 0;

    if ((sock=socket(AF_INET6, SOCK_DGRAM, 0)) == -1) {
        perror("socket failed");
        exit(1);
    }

    // set up the msghdr structure with the destination address, 
    // buffer to send, and control info buffer
    iovec[0].iov_base = udp_packet;
    iovec[0].iov_len = strlen(udp_packet);
    msg.msg_name = &dstaddr;
    msg.msg_namelen = sizeof(dstaddr);
    msg.msg_iov = iovec;
    msg.msg_iovlen = sizeof(iovec) / sizeof(*iovec);
    msg.msg_control = msg_control;
    msg.msg_controllen = sizeof(msg_control);
    msg.msg_flags = 0;

    // add IPV6_PKTINFO control message to specify source address
    cmsg_space = 0;
    cmsg = CMSG_FIRSTHDR(&msg);
    cmsg->cmsg_level = IPPROTO_IPV6;
    cmsg->cmsg_type = IPV6_PKTINFO;
    cmsg->cmsg_len = CMSG_LEN(sizeof(*pktinfo));
    pktinfo = (struct in6_pktinfo*) CMSG_DATA(cmsg);
    pktinfo->ipi6_ifindex = 0;
    inet_pton(AF_INET6, srcaddr, &pktinfo->ipi6_addr);
    cmsg_space += CMSG_SPACE(sizeof(*pktinfo));
    msg.msg_controllen = cmsg_space;

    // send packet
    if (sendmsg(sock, &msg, 0) == -1) {
        perror("send failed");
    }

    return 0;
}

标签:sockets,ipv6,c-3,linux,multicast
来源: https://codeday.me/bug/20191109/2012075.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有