fixed sendmsg flagging and source address
authorRalph Ronnquist <ralph.ronnquist@gmail.com>
Thu, 10 Nov 2022 12:27:46 +0000 (23:27 +1100)
committerRalph Ronnquist <ralph.ronnquist@gmail.com>
Thu, 10 Nov 2022 12:27:46 +0000 (23:27 +1100)
rrqnet.c

index 2711039cfddaccd81fc4fcd0bda51bdffda3f6ff..2bf5e39a13c8b9e0a207cd9207fdae3c5023627a 100644 (file)
--- 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" );