From: Ralph Ronnquist <ralph.ronnquist@gmail.com>
Date: Fri, 11 Nov 2022 09:33:28 +0000 (+1100)
Subject: added ipv6 sending
X-Git-Tag: 1.6.1~3
X-Git-Url: https://git.rrq.au/?a=commitdiff_plain;h=f861a198150c18d51ae736f1ce0ccca56cae72b4;p=rrq%2Frrqnet.git

added ipv6 sending
---

diff --git a/rrqnet.c b/rrqnet.c
index 8f09381..7c70220 100644
--- 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