added ipv6 sending
[rrq/rrqnet.git] / rrqnet.c
index 8f09381d8c4e071c7a4c3061f68fd4e8eb4f6d78..7c702208d5b6e6bf290e4680dfd50384511f0a84 100644 (file)
--- a/rrqnet.c
+++ b/rrqnet.c
@@ -946,35 +946,63 @@ static void sendpacket4(unsigned char *buf, int n,struct Remote *r) {
        .msg_controllen = CMSG_SPACE( sizeof( struct in_pktinfo ) ),
        .msg_flags = 0 // unused
     };
-    if ( r->laddr.in.sa_family && 0 ) {
-       msg.msg_control = &control;
-       msg.msg_controllen = CMSG_SPACE( sizeof( struct in_pktinfo ) );
-    }
-    VERBOSE2OUT( "sendmsg %lu from %s to %s\n",
+    VERBOSE2OUT( "sendmsg ipv4 %lu from %s to %s\n",
                 msg.msg_controllen,
                 inet_stoa( &r->laddr ),
                 inet_stoa( &r->uaddr ) );
     if ( sendmsg( udp_fd, &msg, 0 ) < n ) {
        perror( "Writing socket" );
     }
-#if 0 // ILLUSTRATION
-    struct cmsghdr *cmsg = CMSG_FIRSTHDR(&msg);
-    cmsg->cmsg_level = IPPROTO_IP;
-    cmsg->cmsg_type = IP_PKTINFO;
-    cmsg->cmsg_len = CMSG_LEN(sizeof(struct in_pktinfo));
-    struct in_pktinfo *pktinfo = (struct in_pktinfo*) CMSG_DATA(cmsg);
-    pktinfo->ipi_ifindex = src_interface_index;
-    pktinfo->ipi_spec_dst = src_addr;
-    msg.msg_controllen = 
-       return sendmsg( fd, &msg, IP_PKTINFO );
-#endif
 }
 
 static void sendpacket6(unsigned char *buf, int n,struct Remote *r) {
-    //NYI
-    (void)buf;
-    (void)n;
-    (void)r;
+    // The UDP socket is ipv6, possibly with mapped ipv4 address(es)
+    struct iovec data[1] = {{ .iov_base = buf, .iov_len = n }};
+    struct {
+       struct cmsghdr hdr;
+       union {
+           struct in_pktinfo in4;
+           struct in6_pktinfo in6;
+       } data;
+    } control;
+    struct msghdr msg = {
+       .msg_name = &r->uaddr.in6,
+       .msg_namelen = sizeof( struct sockaddr_in6 ),
+       .msg_iov = data,
+       .msg_iovlen = 1,
+       .msg_control = 0,
+       .msg_controllen = 0,
+       .msg_flags = 0 // unused
+    };
+    if ( r->ifindex ) {
+       switch ( r->laddr.in.sa_family ) {
+       case AF_INET6:
+           control.hdr.cmsg_len = CMSG_LEN(sizeof(struct in6_pktinfo));
+           control.hdr.cmsg_level = IPPROTO_IPV6;
+           control.hdr.cmsg_type = IPV6_PKTINFO;
+           control.data.in6.ipi6_ifindex = r->ifindex;
+           memcpy( &control.data.in6.ipi6_addr, &r->laddr.in6.sin6_addr, 16 );
+           msg.msg_control = &control;
+           msg.msg_controllen = CMSG_SPACE( sizeof( struct in6_pktinfo ) );
+           break;
+       case AF_INET:
+           control.hdr.cmsg_len = CMSG_LEN(sizeof(struct in_pktinfo));
+           control.hdr.cmsg_level = IPPROTO_IP;
+           control.hdr.cmsg_type = IP_PKTINFO;
+           control.data.in4.ipi_ifindex = r->ifindex;
+           control.data.in4.ipi_spec_dst = r->laddr.in4.sin_addr;
+           msg.msg_control = &control;
+           msg.msg_controllen = CMSG_SPACE( sizeof( struct in_pktinfo ) );
+           break;
+       }
+    }
+    VERBOSE2OUT( "sendmsg ipv6 %d from %s to %s\n",
+                r->ifindex,
+                inet_stoa( &r->laddr ),
+                inet_stoa( &r->uaddr ) );
+    if ( sendmsg( udp_fd, &msg, 0 ) < n ) {
+       perror( "Writing socket" );
+    }
 }
 
 // Write a packet via the given Interface with encryption as specified.
@@ -1188,21 +1216,24 @@ static void route_packet(PacketItem *pi) {
        VERBOSE2OUT( "not a nice packet\n" );
        return; // not a nice packet
     }
-    // Set the local addressing for the remote
-    if ( udp6 ) {
-       x->remote->ifindex = pi->dstinfo.in6.ipi6_ifindex;
-       x->remote->laddr.in6.sin6_family = AF_INET6;
-       x->remote->laddr.in6.sin6_port = htons( udp_port );
-       memcpy( &x->remote->laddr.in6.sin6_addr,
-               &pi->dstinfo.in6.ipi6_addr,
-               16 );
-    } else {
-       x->remote->ifindex = pi->dstinfo.in4.ipi_ifindex;
-       x->remote->laddr.in4.sin_family = AF_INET;
-       x->remote->laddr.in4.sin_port = htons( udp_port );
-       memcpy( &x->remote->laddr.in4.sin_addr,
-               &pi->dstinfo.in4.ipi_spec_dst,
-               4 );
+    // Set the local addressing for the remote, unless set already
+    if ( x->remote->ifindex == 0 ) {
+       if ( udp6 ) {
+           x->remote->ifindex = pi->dstinfo.in6.ipi6_ifindex;
+           x->remote->laddr.in6.sin6_family = AF_INET6;
+           x->remote->laddr.in6.sin6_port = htons( udp_port );
+           memcpy( &x->remote->laddr.in6.sin6_addr,
+                   &pi->dstinfo.in6.ipi6_addr,
+                   16 );
+           unmap_if_mapped( &x->remote->laddr );
+       } else {
+           x->remote->ifindex = pi->dstinfo.in4.ipi_ifindex;
+           x->remote->laddr.in4.sin_family = AF_INET;
+           x->remote->laddr.in4.sin_port = htons( udp_port );
+           memcpy( &x->remote->laddr.in4.sin_addr,
+                   &pi->dstinfo.in4.ipi_spec_dst,
+                   4 );
+       }
     }
     if ( ( *buf & 1 ) == 0 ) {
        // unicast