.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.
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