From 0fa5507faf00bbc6b1311685dca6cb3974a762ab Mon Sep 17 00:00:00 2001 From: Ralph Ronnquist Date: Thu, 10 Nov 2022 23:27:46 +1100 Subject: [PATCH] fixed sendmsg flagging and source address --- rrqnet.c | 91 ++++++++++++++++++++++++++++---------------------------- 1 file changed, 46 insertions(+), 45 deletions(-) diff --git a/rrqnet.c b/rrqnet.c index 2711039..2bf5e39 100644 --- a/rrqnet.c +++ b/rrqnet.c @@ -66,9 +66,9 @@ struct Allowed { // Details of actualized connections. struct Remote { struct SockAddr uaddr; // The remote IP address - struct SockAddr laddr; // The local IP address struct Allowed *spec; // Rule being instantiated struct timeval rec_when; // Last received packet time, in seconds + struct SockAddr laddr; // The local IP address }; // Details of an interface at a remote. @@ -923,8 +923,9 @@ static void write_remote(unsigned char *buf, int n,struct Remote *r) { if ( n < 12 ) { VERBOSE2OUT( "SENDing %d bytes to %s\n", n, inet_stoa( &r->uaddr ) ); } else { - VERBOSE2OUT( "SENDing %d bytes %s -> %s to %s\n", n, + VERBOSE2OUT( "SENDing %d bytes %s -> %s from %s to %s\n", n, inet_mtoa( buf+6 ), inet_mtoa( buf ), + inet_stoa( &r->laddr ), inet_stoa( &r->uaddr ) ); } memcpy( output, buf, n ); // Use the private buffer for delivery @@ -950,7 +951,7 @@ static void write_remote(unsigned char *buf, int n,struct Remote *r) { } else if ( r->spec->psk.keyfile ) { encrypt( output, n, &r->spec->psk ); } - // Setup the packet addressing + // Reserve for packet addressing struct in_pktinfo pkt4info = { .ipi_ifindex = 0, /* Interface index */ .ipi_spec_dst.s_addr = 0, /* Local address */ @@ -966,6 +967,7 @@ static void write_remote(unsigned char *buf, int n,struct Remote *r) { struct sockaddr_in6 *sock6 = &r->uaddr.in6; void *sock; size_t size; + int flags = 0; if ( udp6 ) { // Note that the size of +struct sockaddr_in6+ is actually // larger than the size of +struct sockaddr+ (due to the @@ -973,23 +975,33 @@ static void write_remote(unsigned char *buf, int n,struct Remote *r) { // following cuteness for passing arguments to +sendto+. sock = sock6; size = sizeof( struct sockaddr_in6 ); - VERBOSE2OUT( "IPv6 UDP %d %s\n", - udp_fd, inet_stoa( &r->laddr ) ); - if ( r->laddr.in.sa_family ) { + VERBOSE2OUT( "IPv6 UDP %d %s %s\n", udp_fd, + inet_stoa( &r->laddr ), + inet_stoa( &r->uaddr ) ); + switch ( r->laddr.in.sa_family ) { + case AF_INET6: memcpy( &pkt6info.ipi6_addr, &sock6->sin6_addr, 16 ); pktinfo = &pkt6info; pktinfosize = sizeof( pkt6info ); - } - } else { - sock = sock4; - size = sizeof( struct sockaddr_in ); - VERBOSE2OUT( "IPv4 UDP %d %s\n", - udp_fd, inet_stoa( &r->laddr ) ); - if ( r->laddr.in.sa_family ) { + flags = IPV6_PKTINFO; + break; + case AF_INET: memcpy( &pkt4info.ipi_spec_dst, &sock4->sin_addr, 4 ); pktinfo = &pkt4info; pktinfosize = sizeof( pkt4info ); + flags = IP_PKTINFO; + break; } + } else { + sock = sock4; + size = sizeof( struct sockaddr_in ); + VERBOSE2OUT( "IPv4 UDP %d %s %s\n", udp_fd, + inet_stoa( &r->laddr ), + inet_stoa( &r->uaddr ) ); + memcpy( &pkt4info.ipi_spec_dst, &sock4->sin_addr, 4 ); + pktinfo = &pkt4info; + pktinfosize = sizeof( pkt4info ); + flags = IP_PKTINFO; } VERBOSE2OUT( "SEND %d bytes from %s to %s [%s -> %s]\n", n, @@ -1000,18 +1012,16 @@ static void write_remote(unsigned char *buf, int n,struct Remote *r) { ); // IS sendmsg thread safe?? struct iovec data[1] = {{ output, n }}; - (void)pktinfo; - (void)pktinfosize; struct msghdr msg = { .msg_name = sock, .msg_namelen = size, .msg_iov = data, .msg_iovlen = 1, - .msg_control = 0, //pktinfo, - .msg_controllen = 0, //pktinfosize, + .msg_control = pktinfo, + .msg_controllen = pktinfosize, .msg_flags = 0 // unused }; - if ( sendmsg( udp_fd, &msg, 0 ) < n ) { + if ( sendmsg( udp_fd, &msg, flags ) < n ) { perror( "Writing socket" ); // Invalidate remote temporarily instead? But if it's an // "uplink" it should be retried eventually... @@ -1207,11 +1217,11 @@ static void route_packet(PacketItem *pi) { Interface_DEL( y ); // Need to see this interface again return; } - VERBOSE2OUT( "RECV route %s -> %s to %s\n", - inet_mtoa( buf+6 ), inet_mtoa( buf ), - inet_stoa( &y->remote->uaddr ) ); // Set the local address for the remote - memcpy( &y->remote->laddr, &pi->dst, sizeof( pi->dst ) ); + memcpy( &x->remote->laddr, &pi->dst, sizeof( pi->dst ) ); + VERBOSE2OUT( "RECV route %s -> %s using %s\n", + inet_mtoa( buf+6 ), inet_mtoa( buf ), + inet_stoa( &x->remote->laddr ) ); write_remote( buf, len, y->remote ); return; } @@ -1275,9 +1285,12 @@ static void *packet_handler(void *data) { } else { if ( udp6 ) { unmap_if_mapped( &todo->src ); + unmap_if_mapped( &todo->dst ); } route_packet( todo ); } + memset( &todo->src, 0, sizeof( struct SockAddr ) ); + memset( &todo->dst, 0, sizeof( struct SockAddr ) ); Queue_addItem( &todolist.free, (QueueItem*) todo ); } return 0; @@ -1305,43 +1318,34 @@ void todolist_initialize(int nbuf,int nthr) { } } -static ssize_t recvpacket(int fd,PacketItem *p) { - int flags = 0; - socklen_t addrlen = - udp6? sizeof( p->src.in6 ) : sizeof( p->src.in4 ); - struct iovec buffer = { - .iov_base = p->buffer, - .iov_len = BUFSIZE - }; - char data[1000]; +// Reads a UDP packet on the given file descriptor and captures the +// source and destination addresses of the UDP message. +inline static ssize_t recvpacket(int fd,PacketItem *p) { + char data[100]; // Data area for "pktinfo" + struct iovec buffer[1] = {{ p->buffer, BUFSIZE }}; struct msghdr msg = { .msg_name = &p->src.in, - .msg_namelen = addrlen, - .msg_iov = &buffer, + .msg_namelen = udp6? sizeof( p->src.in6 ) : sizeof( p->src.in4 ), + .msg_iov = buffer, .msg_iovlen = 1, .msg_control = data, .msg_controllen = sizeof( data ), .msg_flags = 0 // Return value }; - p->len = recvmsg( fd, &msg, flags ); + p->len = recvmsg( fd, &msg, udp6? 0 : IP_PKTINFO ); struct cmsghdr *cmsg = CMSG_FIRSTHDR( &msg ); - VERBOSE3OUT( "anc %p %ld\n", cmsg, p->len ); - for ( ; cmsg; cmsg = CMSG_NXTHDR( &msg, cmsg ) ) { - VERBOSE3OUT( "anc type = %d\n", cmsg->cmsg_type ); - } - cmsg = CMSG_FIRSTHDR( &msg ); if ( cmsg ) { if ( udp6 ) { struct in6_pktinfo *pinf = (struct in6_pktinfo*) CMSG_DATA( cmsg ); p->dst.in6.sin6_family = AF_INET6; memcpy( &p->dst.in6.sin6_addr, &pinf->ipi6_addr, 16 ); - VERBOSE3OUT( "DEST= udp6 %d %s\n", + VERBOSE2OUT( "DEST= udp6 %d %s\n", pinf->ipi6_ifindex, inet_stoa( &p->dst ) ); } else { struct in_pktinfo *pinf = (struct in_pktinfo*) CMSG_DATA( cmsg ); p->dst.in4.sin_family = AF_INET; p->dst.in4.sin_addr = pinf->ipi_addr; - VERBOSE3OUT( "DEST= %d %s\n", + VERBOSE2OUT( "DEST= %d %s\n", pinf->ipi_ifindex, inet_stoa( &p->dst ) ); } } @@ -1361,10 +1365,7 @@ static void *doreadUDP(void *data) { while ( 1 ) { PacketItem *todo = (PacketItem *) Queue_getItem( &todolist.free ); todo->fd = fd; - memset( &todo->src, 0, sizeof( struct SockAddr ) ); - memset( &todo->dst, 0, sizeof( struct SockAddr ) ); - todo->len = 0; - VERBOSE3OUT( "Reading packet\n" ); + VERBOSE3OUT( "Reading packet on %d\n", fd ); ssize_t len = recvpacket( fd, todo ); if ( len == -1) { perror( "Receiving UDP" ); -- 2.39.2