オルタナティブ・ブログ > プログラマー社長のブログ >

プログラミングでメシが食えるか!?

sendmsg(),recvmsg()を使ったUDP送受信プログラム:IPv6

»

連載中(?)のsendmsg(),recvmsg()を使ったUDP送受信プログラムですが、いよいよIPv6です。IPv6ではIPV6_PKTINFOがどの処理系でも使えるので簡単、と思ったのですが、やってみると意外と苦労しました。。

まず、setsockopt()で指定するのは、IPV6_PKTINFOではなく、IPV6_RECVPKTINFOでないと駄目、というのが、SolarisとLinuxで、そもそもIPV6_RECVPKTINFOが無いのがBSD(MacOSX)というところで苦労しました。RECVPKTINFOと言っているのにsendmsg()にも効果があるのでなぜ?と思ったら、送信するときにはsetsockopt()しなくても、指定すれば有効になるみたいです。同じソケットで送信も受信もするならセットすることになるので、まあ、しておくことにしておけばいい感じです。

つづいて、struct msghdrのmsg_name,msg_namelenに指定する、あるいは取得するものが、struct sockaddr_storageだろうと思っていたら、struct sockaddr_in6みたいで、まあどちらでも同じように使えるのですが、取得したものをgetnameinfo()するときに、第二引数をsizeof(struct sockaddr_storage)にしてしまうと、Solarisだとエラーになってしまうと言うのも悩みました。取得したmsg_namelenの値にするか、sizeof(struct sockaddr_in6)を指定しないと駄目です。

ということで、いろいろ仕事の予定が入ってしまい、実行結果はあまり綺麗にまとまっていないので、ソースを紹介してしまいましょう。いちおうLinux、BSD(MacOSX)、Solarisで動作確認してあります。

受信プログラム

#ifdef __SunOS
#define _XPG4_2
#define __EXTENSIONS__
#endif

#include        <stdio.h>
#include        <unistd.h>
#include        <stdlib.h>
#include        <string.h>
#include        <errno.h>
#include        <sys/socket.h>
#include        <arpa/inet.h>
#include        <netdb.h>
#include        <poll.h>
#include        <net/if.h>

#define SOCK_NO 16
#define BUF_LEN 512

int recvFunc(int soc,int ifno)
{
char    hbuf[NI_MAXHOST],sbuf[NI_MAXSERV];
unsigned char buf[BUF_LEN];
struct msghdr   msg;
struct iovec    iov[1];
struct cmsghdr  *cmsg;
char    cbuf[512],addr[256];
struct sockaddr_storage sin;
struct in6_pktinfo      *pktinfo=NULL;
int     rc;
int     error;

        iov[0].iov_base=buf;
        iov[0].iov_len=BUF_LEN;

        memset(&sin,0,sizeof(sin));
        memset(&msg,0,sizeof(msg));
        msg.msg_name=&sin;
        msg.msg_namelen=sizeof(sin);
        msg.msg_iov=iov;
        msg.msg_iovlen=1;
        msg.msg_control=cbuf;
        msg.msg_controllen=512;

        rc=recvmsg(soc,&msg,0);
        if(rc<0){
                perror("recvmsg");
                return(-1);
        }

        for(cmsg=CMSG_FIRSTHDR(&msg);cmsg!=NULL;
                cmsg=CMSG_NXTHDR(&msg,cmsg)){
                if(cmsg->cmsg_level==IPPROTO_IPV6&& cmsg->cmsg_type==IPV6_PKTINFO){
                        pktinfo=(struct in6_pktinfo *)CMSG_DATA(cmsg);
                }
        }

        printf("*************************\n");
        printf("buf=[%s]\n",buf);
        if((error=getnameinfo((struct sockaddr *)&sin,msg.msg_namelen,hbuf,sizeof(hbuf),sbuf,sizeof(sbuf),NI_NUMERICHOST|NI_NUMERICSERV))){
                fprintf(stderr,"getnameinfo:%s\n",gai_strerror(error));
        }
        else{
                fprintf(stderr,"from(%d):%s:%s\n",ifno,hbuf,sbuf);
        }

        if(pktinfo!=NULL){
                inet_ntop(AF_INET6,&pktinfo->ipi6_addr,addr,sizeof(addr));
                printf("pktinfo->ipi6_addr=%s\n",addr);
                printf("pktinfo->ipi6_ifindex=%d\n",pktinfo->ipi6_ifindex);
        }
        else{
                printf("no pktinfo\n");
        }

        printf("*************************\n");

        return(0);
}

int main(int argc,char *argv[])
{
char    *portnm;
int     s[SOCK_NO];
struct addrinfo hints,*res,*res0;
int     error;
int     smax;
const int       on=1;
char    hbuf[NI_MAXHOST],sbuf[NI_MAXSERV];
struct pollfd   targets[SOCK_NO];
int     nready,i;
int     end;
int     rc;
struct if_nameindex     *nindex,*iptr;
struct ipv6_mreq mreq;
struct in6_addr sin6_addr;

        if(argc<2){
                fprintf(stderr,"%s port\n",argv[0]);
                return(1);
        }
        portnm=argv[1];

        /* for debug */
        nindex=if_nameindex();
        for(iptr=nindex;iptr->if_index!=0;iptr++){
                printf("%d:%s\n",iptr->if_index,iptr->if_name);
        }
        if_freenameindex(nindex);
        /* for debug */

        memset(&hints,0,sizeof(hints));
        hints.ai_socktype=SOCK_DGRAM;
        hints.ai_flags=AI_PASSIVE;
        error=getaddrinfo(NULL,portnm,&hints,&res0);
        if(error){
                fprintf(stderr,"getaddrinfo():%s:%s\n",portnm,gai_strerror(error));
                return(-1);
        }

        smax=0;
        for(res=res0;res&&smax<SOCK_NO;res=res->ai_next){
                if(res->ai_family!=AF_INET6){
                        s[smax]=-1;
                        continue;
                }
                s[smax]=socket(res->ai_family,res->ai_socktype,res->ai_protocol);
                if(s[smax]<0){
                        continue;
                }
#ifdef  IPV6_V6ONLY
                rc=setsockopt(s[smax],IPPROTO_IPV6,IPV6_V6ONLY,&on,sizeof(on));
                if(rc<0){
                        perror("setsockopt(IPV6_V6ONLY)");
                }
#endif
#ifdef IPV6_RECVPKTINFO
                printf("use IPV6_RECVPKTINFO\n");
                rc=setsockopt(s[smax],IPPROTO_IPV6,IPV6_RECVPKTINFO,&on,sizeof(on));
                if(rc<0){
                        perror("setsockopt(IPV6_RECVPKTINFO)");
                }
#else
                printf("use IPV6_PKTINFO\n");
                rc=setsockopt(s[smax],IPPROTO_IPV6,IPV6_PKTINFO,&on,sizeof(on));
                if(rc<0){
                        perror("setsockopt(IPV6_PKTINFO)");
                }
#endif

                inet_pton(AF_INET6, "ff02::1", &sin6_addr);
                mreq.ipv6mr_multiaddr = sin6_addr;
                mreq.ipv6mr_interface = 0;
                rc=setsockopt(s[smax], IPPROTO_IPV6, IPV6_JOIN_GROUP, &mreq, sizeof(mreq));
                if(rc<0){
                        perror("setsockopt(IPV6_JOIN_GROUP)");
                }

                if(bind(s[smax],res->ai_addr,res->ai_addrlen)<0){
                        close(s[smax]);
                        s[smax]=-1;
                        continue;
                }
                error=getnameinfo(res->ai_addr,res->ai_addrlen,hbuf,sizeof(hbuf),sbuf,sizeof(sbuf),NI_NUMERICHOST|NI_NUMERICSERV);
                if(error){
                        fprintf(stderr,"getnameinfo():%s\n",gai_strerror(error));
                        freeaddrinfo(res0);
                        return(-1);
                }
                fprintf(stderr,"bind to %s %s\n",hbuf,sbuf);
                smax++;
        }

        freeaddrinfo(res0);

        if(smax==0){
                fprintf(stderr,"no socket to bind to\n");
                return(-1);
        }

        for(i=0;i<smax;i++){
                if(s[i]==-1){
                        continue;
                }
                targets[i].fd=s[i];
                targets[i].events=POLLIN|POLLERR;
        }

        end=0;
        do{
                switch((nready=poll(targets,smax,-1))){
                        case    -1:
                                if(errno!=EINTR){
                                        perror("poll");
                                        end=1;
                                }
                                break;
                        case    0:
                                fprintf(stderr,"Timeout\n");
                                break;
                        default:
                                for(i=0;i<smax;i++){
                                        if(targets[i].revents&(POLLIN|POLLERR)){
                                                recvFunc(s[i],i);
                                        }
                                }
                                break;
                }
        }while(end!=1);

        for(i=0;i<smax;i++){
                close(s[i]);
        }

        return(0);
}

OSによるのですが、リンクローカルマルチキャスト宛のパケットを、なにもしなくても受信できるものと、ちゃんと参加表明しないと受信できないものがありましたので、一応「ff02::1」に参加するコードも入れておきました。

送信プログラム

#ifdef __SunOS
#define _XPG4_2
#define __EXTENSIONS__
#endif

#include        <stdio.h>
#include        <unistd.h>
#include        <stdlib.h>
#include        <string.h>
#include        <errno.h>
#include        <sys/types.h>
#include        <sys/socket.h>
#include        <arpa/inet.h>
#include        <net/if.h>
#include        <netdb.h>
#include        <poll.h>

#define BUF_LEN 512
#define SOCK_NO 16

int main(int argc,char *argv[])
{
char    *hostnm,*portnm;
struct addrinfo hints,*res,*res0;
int     s[SOCK_NO];
int     smax,i;
struct sockaddr_storage to[SOCK_NO];
int     tolen[SOCK_NO];
char    hbuf[NI_MAXHOST],sbuf[NI_MAXSERV];
int     error;
unsigned char   buf[BUF_LEN];
char    buf2[BUF_LEN],*ptr;
struct in6_addr myaddr;
char    *if_name;
const int       on=1;
struct if_nameindex     *nindex,*iptr;
int     rc;

        if(argc<=2){
                fprintf(stderr,"%s if-name my-ipaddress\n",argv[0]);
                return(-1);
        }
        if_name=argv[1];
        if(!inet_pton(AF_INET6,argv[2],&myaddr)){
                perror("inet_pton");
                return(-1);
        }

        /* for debug */
        nindex=if_nameindex();
        for(iptr=nindex;iptr->if_index!=0;iptr++){
                printf("%d:%s\n",iptr->if_index,iptr->if_name);
        }
        if_freenameindex(nindex);
        /* for debug */

        printf("input \"host port\"\n");
        while(1){
                if(fgets((char *)buf,sizeof(buf),stdin)==NULL){
                        perror("fgets");
                        break;
                }
                if((ptr=strchr((char *)buf,'\n'))!=NULL){
                        *ptr='\0';
                }
                strcpy(buf2,(char *)buf);
                if((hostnm=strtok(buf2," "))==NULL){
                        fprintf(stderr,"Input-error\n");
                        fprintf(stderr,"host:port:nic\n");
                        continue;
                }
                if((portnm=strtok(NULL,"\r\n"))==NULL){
                        fprintf(stderr,"Input-error\n");
                        fprintf(stderr,"host:port:nic\n");
                        continue;
                }

                memset(&hints,0,sizeof(hints));
                hints.ai_socktype=SOCK_DGRAM;
                error=getaddrinfo(hostnm,portnm,&hints,&res0);
                if(error){
                        fprintf(stderr,"getaddrinfo:%s %s:%s\n",hostnm,portnm,gai_strerror(error));
                        return(-1);
                }

                smax=0;
                for(res=res0;res&&smax<SOCK_NO;res=res->ai_next){
                        error=getnameinfo(res->ai_addr,res->ai_addrlen,hbuf,sizeof(hbuf),sbuf,sizeof(sbuf),NI_NUMERICHOST|NI_NUMERICSERV);
                        if(error){
                                fprintf(stderr,"getnameinfo:%s %s:%s\n",hostnm,portnm,gai_strerror(error));
                                continue;
                        }
                        s[smax]=socket(res->ai_family,res->ai_socktype,res->ai_protocol);
                        if(s[smax]<0){
                                perror("socket");
                                continue;
                        }

#ifdef  IPV6_RECVPKTINFO
                        printf("use IPV6_RECVPKTINFO\n");
                        rc=setsockopt(s[smax],IPPROTO_IPV6,IPV6_RECVPKTINFO,&on,sizeof(on));
                        if(rc<0){
                                perror("setsockopt(IPV6_RECVPKTINFO)");
                        }
#else
                        printf("use IPV6_PKTINFO\n");
                        rc=setsockopt(s[smax],IPPROTO_IPV6,IPV6_PKTINFO,&on,sizeof(on));
                        if(rc<0){
                                perror("setsockopt(IPV6_PKTINFO)");
                        }
#endif

                        memcpy(&to[smax],res->ai_addr,res->ai_addrlen);
                        tolen[smax]=res->ai_addrlen;
                        fprintf(stderr,"target %d : %s port %s\n",smax,hbuf,sbuf);
                        smax++;
                }

                freeaddrinfo(res0);

                if(smax==0){
                        fprintf(stderr,"no destination to send\n");
                        continue;
                }

                for(i=0;i<smax;i++){
                        struct msghdr   msg;
                        struct iovec    iov[1];
                        struct cmsghdr  *cmsg;
                        char    cbuf[512];
                        struct in6_pktinfo       pktinfo;
                        int     rc;

                        iov[0].iov_base=buf;
                        iov[0].iov_len=BUF_LEN;

                        memset(&msg,0,sizeof(msg));
                        msg.msg_name=&to[i];
                        msg.msg_namelen=tolen[i];
                        msg.msg_iov=iov;
                        msg.msg_iovlen=1;
                        msg.msg_control=cbuf;
                        msg.msg_controllen=512;

                        memset(&pktinfo,0,sizeof(pktinfo));
                        pktinfo.ipi6_ifindex=if_nametoindex(if_name);
                        fprintf(stderr,"ifindex=%d\n",pktinfo.ipi6_ifindex);
                        memcpy(&pktinfo.ipi6_addr,&myaddr,sizeof(struct in6_addr));

                        cmsg=CMSG_FIRSTHDR(&msg);
                        cmsg->cmsg_level=IPPROTO_IPV6;
                        cmsg->cmsg_type=IPV6_PKTINFO;
                        cmsg->cmsg_len=CMSG_LEN(sizeof(struct in6_pktinfo));
                        memcpy(CMSG_DATA(cmsg),&pktinfo,sizeof(pktinfo));
                        msg.msg_controllen=cmsg->cmsg_len;

                        rc=sendmsg(s[i],&msg,0);
                        if(rc<0){
                                perror("send");
                        }
                }

                for(i=0;i<smax;i++){
                        close(s[i]);
                }
        }

        return(0);
}

前回までは、送信するデータを「IPアドレス:ポート番号」で指定していましたが、IPv6では":"をアドレス表記に使うので、「IPアドレス ポート番号」とスペース区切りで指定するようにしてありますので、実行して実験してみる人は気をつけてください。

ここまでくれば、実はIPv4、IPv6を一緒に扱うこともできますが、サンプルにしてはソースが長くなってしまうので、IPv6専用にしておきました。

===追記===

実行結果を載せておきます。

Linuxでの受信


eth0: fe80::221:5eff:fe46:3040/64
eth1: fe80::21b:21ff:fe35:61d0/64

1:lo
2:eth1
3:eth0
4:sit0
use IPV6_RECVPKTINFO
bind to :: 44444
*************************
buf=[fe80::221:5eff:fe46:3040 44444]    <- eth0宛
from(0):fe80::21e:c2ff:feb8:9058%eth0:49382
pktinfo->ipi6_addr=fe80::221:5eff:fe46:3040
pktinfo->ipi6_ifindex=3
*************************
*************************
buf=[fe80::21b:21ff:fe35:61d0 44444]    <- eth1宛
from(0):fe80::21e:c2ff:feb8:9058%eth1:55254
pktinfo->ipi6_addr=fe80::21b:21ff:fe35:61d0
pktinfo->ipi6_ifindex=2
*************************
*************************
buf=[ff02::1 44444]                     <- マルチキャスト宛
from(0):fe80::21e:c2ff:feb8:9058%eth0:55255
pktinfo->ipi6_addr=ff02::1
pktinfo->ipi6_ifindex=3
*************************
*************************
buf=[ff02::1 44444]                     <- マルチキャスト宛
from(0):fe80::21e:c2ff:feb8:9058%eth1:55255
pktinfo->ipi6_addr=ff02::1
pktinfo->ipi6_ifindex=2
*************************

Solarisでの受信


bge0: fe80::209:3dff:fe13:3e3b/10
bge1: fe80::209:3dff:fe13:3e3c/10

1:lo0
2:bge0
3:bge1
use IPV6_RECVPKTINFO
bind to :: 44444
*************************
buf=[fe80::209:3dff:fe13:3e3b 44444]    <- bge0宛
from(0):fe80::21e:c2ff:feb8:9058%bge0:53065
pktinfo->ipi6_addr=fe80::209:3dff:fe13:3e3b
pktinfo->ipi6_ifindex=2
*************************
*************************
buf=[fe80::209:3dff:fe13:3e3c 44444]    <- bge1宛
from(0):fe80::21e:c2ff:feb8:9058%bge1:53066
pktinfo->ipi6_addr=fe80::209:3dff:fe13:3e3c
pktinfo->ipi6_ifindex=3
*************************
*************************
buf=[ff02::1 44444]                     <- マルチキャスト宛
from(0):fe80::21e:c2ff:feb8:9058%bge0:53067
pktinfo->ipi6_addr=ff02::1
pktinfo->ipi6_ifindex=2
*************************

BSD(MacOSX)での受信


en0: fe80::21e:c2ff:feb8:9058
en5: fe80::21d:73ff:fe68:4f3e

1:lo0
2:gif0
3:stf0
4:en0
6:en3
7:en2
5:en5
use IPV6_PKTINFO
bind to :: 44444
*************************
buf=[fe80::21e:c2ff:feb8:9058 44444]    <- en0宛
from(0):fe80::221:5eff:fe46:3040%en0:54100
pktinfo->ipi6_addr=fe80::21e:c2ff:feb8:9058
pktinfo->ipi6_ifindex=4
*************************
*************************
buf=[fe80::21d:73ff:fe68:4f3e 44444]    <- en5宛
from(0):fe80::221:5eff:fe46:3040%en5:37547
pktinfo->ipi6_addr=fe80::21d:73ff:fe68:4f3e
pktinfo->ipi6_ifindex=5
*************************
*************************
buf=[ff02::1 44444]                     <- マルチキャスト宛
from(0):fe80::221:5eff:fe46:3040%en5:47019
pktinfo->ipi6_addr=ff02::1
pktinfo->ipi6_ifindex=5
*************************
*************************
buf=[ff02::1 44444]                     <- マルチキャスト宛
from(0):fe80::221:5eff:fe46:3040%en0:47019
pktinfo->ipi6_addr=ff02::1
pktinfo->ipi6_ifindex=4
*************************

送信の動き


en0: fe80::21e:c2ff:feb8:9058
en5: fe80::21d:73ff:fe68:4f3e

1:lo0
2:gif0
3:stf0
4:en0
6:en3
7:en2
5:en5
use IPV6_PKTINFO
bind to :: 44444
*************************
buf=[fe80::21e:c2ff:feb8:9058 44444]    <- en0宛
from(0):fe80::221:5eff:fe46:3040%en0:54100
pktinfo->ipi6_addr=fe80::21e:c2ff:feb8:9058
pktinfo->ipi6_ifindex=4
*************************
*************************
buf=[fe80::21d:73ff:fe68:4f3e 44444]    <- en5宛
from(0):fe80::221:5eff:fe46:3040%en5:37547
pktinfo->ipi6_addr=fe80::21d:73ff:fe68:4f3e
pktinfo->ipi6_ifindex=5
*************************
*************************
buf=[ff02::1 44444]                     <- マルチキャスト宛
from(0):fe80::221:5eff:fe46:3040%en5:47019
pktinfo->ipi6_addr=ff02::1
pktinfo->ipi6_ifindex=5
*************************
*************************
buf=[ff02::1 44444]                     <- マルチキャスト宛
from(0):fe80::221:5eff:fe46:3040%en0:47019
pktinfo->ipi6_addr=ff02::1
pktinfo->ipi6_ifindex=4
*************************
komata-MacBook-Air:SendRecvMsgTest komata$ send6.txt
-bash: send6.txt: command not found
komata-MacBook-Air:SendRecvMsgTest komata$ cat send6.txt
/// from linux ///
//// ./send6 eth0 fe80::221:5eff:fe46:3040
*************************
buf=[fe80::21e:c2ff:feb8:9058 44444]
from(0):fe80::221:5eff:fe46:3040%en0:52108      <- eth0からen0宛に届いている
pktinfo->ipi6_addr=fe80::21e:c2ff:feb8:9058
pktinfo->ipi6_ifindex=4
*************************
*************************
buf=[ff02::1 44444]                             <- マルチキャスト宛
from(0):fe80::221:5eff:fe46:3040%en5:35483      <- eth0からen5宛に届いている
pktinfo->ipi6_addr=ff02::1
pktinfo->ipi6_ifindex=5
*************************
*************************
buf=[ff02::1 44444]
from(0):fe80::221:5eff:fe46:3040%en0:35483      <- 同時にen0宛にも届いている
pktinfo->ipi6_addr=ff02::1
pktinfo->ipi6_ifindex=4
*************************
//// ./send6 eth1 fe80::21b:21ff:fe35:61d0
*************************
buf=[fe80::21e:c2ff:feb8:9058 44444]
from(0):fe80::21b:21ff:fe35:61d0%en0:56278      <- eth1からen0宛に届いている
pktinfo->ipi6_addr=fe80::21e:c2ff:feb8:9058
pktinfo->ipi6_ifindex=4
*************************
*************************
buf=[ff02::1 44444]                             <- マルチキャスト宛
from(0):fe80::21b:21ff:fe35:61d0%en5:51383      <- eth1からen5宛に届いている
pktinfo->ipi6_addr=ff02::1
pktinfo->ipi6_ifindex=5
*************************
*************************
buf=[ff02::1 44444]
from(0):fe80::21b:21ff:fe35:61d0%en0:51383      <- 同時にen0宛にも届いている
pktinfo->ipi6_addr=ff02::1
pktinfo->ipi6_ifindex=4
*************************
/// from solaris ///
//// ./send6 bge0 fe80::209:3dff:fe13:3e3b
*************************
buf=[fe80::21e:c2ff:feb8:9058 44444]
from(0):fe80::209:3dff:fe13:3e3b%en0:42806      <- bge0からen0宛に届いている
pktinfo->ipi6_addr=fe80::21e:c2ff:feb8:9058
pktinfo->ipi6_ifindex=4
*************************
*************************
buf=[ff02::1 44444]                             <- マルチキャスト宛
from(0):fe80::209:3dff:fe13:3e3b%en5:42841      <- bge0からen5宛に届いている
pktinfo->ipi6_addr=ff02::1
pktinfo->ipi6_ifindex=5
*************************
*************************
buf=[ff02::1 44444]
from(0):fe80::209:3dff:fe13:3e3b%en0:42841      <- 同時にen0宛にも届いている
pktinfo->ipi6_addr=ff02::1
pktinfo->ipi6_ifindex=4
*************************
//// ./send6 bge1 fe80::209:3dff:fe13:3e3c
*************************
buf=[fe80::21e:c2ff:feb8:9058 44444]
from(0):fe80::209:3dff:fe13:3e3c%en0:42809      <- bge1からen0宛に届いている
pktinfo->ipi6_addr=fe80::21e:c2ff:feb8:9058
pktinfo->ipi6_ifindex=4
*************************
*************************
buf=[ff02::1 44444]                             <- マルチキャスト宛
from(0):fe80::209:3dff:fe13:3e3c%en5:42842      <- bge1からen5宛に届いている
pktinfo->ipi6_addr=ff02::1
pktinfo->ipi6_ifindex=5
*************************
*************************
buf=[ff02::1 44444]
from(0):fe80::209:3dff:fe13:3e3c%en0:42842      <- 同時にen0宛にも届いている
pktinfo->ipi6_addr=ff02::1
pktinfo->ipi6_ifindex=4
*************************
/// BSD ///
//// ./send6 en0 fe80::21e:c2ff:feb8:9058
*************************
buf=[fe80::21e:c2ff:feb8:9058 44444]
from(0):fe80::21e:c2ff:feb8:9058%en0:51278      <- en0からen0宛に届いている
pktinfo->ipi6_addr=fe80::21e:c2ff:feb8:9058
pktinfo->ipi6_ifindex=4
*************************
bind to :: 44444
*************************
buf=[ff02::1 44444]                             <- マルチキャスト宛
from(0):fe80::21e:c2ff:feb8:9058%en0:62491      <- en0からen0宛に届いている
pktinfo->ipi6_addr=ff02::1
pktinfo->ipi6_ifindex=4
*************************
*************************
buf=[ff02::1 44444]
from(0):fe80::21e:c2ff:feb8:9058%en5:62491      <- 同時にen5宛にも届いている
pktinfo->ipi6_addr=ff02::1
pktinfo->ipi6_ifindex=5
*************************
//// ./send6 en5 fe80::21d:73ff:fe68:4f3e
*************************
buf=[fe80::21e:c2ff:feb8:9058 44444]
from(0):fe80::21d:73ff:fe68:4f3e%en0:51279      <- en5からen0宛に届いている
pktinfo->ipi6_addr=fe80::21e:c2ff:feb8:9058
pktinfo->ipi6_ifindex=4
*************************
*************************
buf=[ff02::1 44444]                             <- マルチキャスト宛
from(0):fe80::21d:73ff:fe68:4f3e%en5:62492      <- en5からen5宛に届いている
pktinfo->ipi6_addr=ff02::1
pktinfo->ipi6_ifindex=5
*************************
*************************
buf=[ff02::1 44444]
from(0):fe80::21d:73ff:fe68:4f3e%en0:62492      <- 同時にen0宛にも届いている
pktinfo->ipi6_addr=ff02::1
pktinfo->ipi6_ifindex=4
*************************

IPv4に比べるとOSによる違いは少ない感じです。Solarisでの受信でマルチキャスト宛が一つしか届かないのはIPMPにしているからかも知れません。

Comment(0)