I would really like to be able to send an IPv6 with a arbitrary IP out a specific interface for a setup/probe type situation. So there is no route setup yet, and it will be sent out a Point-to-Point type interface. With IPv4 I was able to do this just fine with a sendmsg with the IP_PKTINFO data. But with SOL_IPV6/IPV6_PKTINFO, I am not able to do the same thing. The IPv4 code comments in route.c at line 2240, seem to be the reason it works for IPv4. Should IPv6 work the same way? Or is there a bug in my test app? http://git.kernel.org/?p=linux/kernel/git/stable/linux-2.6.24.y.git;a=blob;f=net/ipv4/route.c;h=28484f396b048e1dd49210e5caffc24e29148f2b;hb=HEAD Here is a test app and the results I get on 2.6.24. ============== acmay@mud:~$ ip -6 addr 1: lo: <LOOPBACK,UP,LOWER_UP> mtu 16436 inet6 ::1/128 scope host valid_lft forever preferred_lft forever 2: eth1: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qlen 1000 inet6 2001::1/64 scope global valid_lft forever preferred_lft forever inet6 fe80::217:31ff:fec4:4cd9/64 scope link valid_lft forever preferred_lft forever acmay@mud:~$ ip -6 route 2001::/64 dev eth1 metric 256 expires 21333753sec mtu 1500 advmss 1440 hoplimit 4294967295 fe80::/64 dev eth1 metric 256 expires 21035002sec mtu 1500 advmss 1440 hoplimit 4294967295 ff00::/8 dev eth1 metric 256 expires 21035002sec mtu 1500 advmss 1440 hoplimit 4294967295 acmay@mud:~$ ./a.out eth1 2001::1 2002::1 eth1 ifindex = 2 sendmsg failed : Network is unreachable
#include <stdio.h> #include <string.h> #include <sys/types.h> #include <sys/ioctl.h> #include <sys/socket.h> #include <net/if.h> #include <netinet/in.h> #include <netinet/ip6.h> #define UDP_PORT 7856 void print_usage () { printf ("sendmsg6 <if_index> <source ip> <destination ip>\n"); } int main(int argc, char *argv[]) { int sock6; struct sockaddr_in6 saddr6; struct msghdr msg; int result; int data = 0; int if_index; struct iovec iov = { &data, 4 }; struct { struct cmsghdr cm; struct in6_pktinfo ipi6; } cmsg = { { sizeof( struct cmsghdr ) + sizeof( struct in6_pktinfo ), SOL_IPV6, IPV6_PKTINFO}, { 0,}}; struct ifreq my_ifreq; if (! (argv[1] && argv[2] )){ print_usage(); return -1; } sock6 = socket(PF_INET6, SOCK_DGRAM, IPPROTO_UDP); if (sock6 == -1) { perror("socket failed"); return -1; } strcpy(my_ifreq.ifr_name, argv[1]); if (ioctl(sock6, SIOCGIFINDEX, &my_ifreq) == -1) { perror("ioctl failed"); return -1; } if ( (if_index = if_nametoindex (argv[1])) == 0) { printf("Could not get interface index for %s\n", argv[1]); return -1; } printf("%s ifindex = %d\n", argv[1], if_index); memset(&saddr6, 0, sizeof(struct sockaddr_in6)); saddr6.sin6_family = AF_INET6; saddr6.sin6_port = htons(UDP_PORT); result = inet_pton(AF_INET6, argv[3], &saddr6.sin6_addr); if (result <= 0) { perror("inet_pton failed for destination ip\n"); return -1; } cmsg.ipi6.ipi6_ifindex = if_index; result = inet_pton(AF_INET6, argv[2], &cmsg.ipi6.ipi6_addr); if (result <= 0) { perror("inet_pton failed for source ip\n"); return -1; } msg.msg_name = &saddr6; msg.msg_namelen = sizeof(struct sockaddr_in6); msg.msg_iov = &iov; msg.msg_iovlen = 1; msg.msg_control = &cmsg; msg.msg_controllen = sizeof(cmsg); msg.msg_flags = 0; result = sendmsg(sock6, &msg, 0 ); if (result == -1) { perror("sendmsg failed\n"); } else { printf("sendmsg returned %d\n", result); } close(sock6); return 0; }