]> git.ipfire.org Git - thirdparty/freeradius-server.git/commitdiff
Swap src/dst before we call udp_send
authorArran Cudbard-Bell <a.cudbardb@freeradius.org>
Fri, 6 Nov 2020 17:52:23 +0000 (11:52 -0600)
committerArran Cudbard-Bell <a.cudbardb@freeradius.org>
Fri, 6 Nov 2020 17:52:30 +0000 (11:52 -0600)
src/modules/proto_dhcpv4/proto_dhcpv4_udp.c
src/modules/proto_dhcpv6/proto_dhcpv6_udp.c
src/modules/proto_radius/proto_radius_udp.c
src/modules/proto_vmps/proto_vmps_udp.c
src/protocols/radius/packet.c

index e6d5ac99bcadee369e15933900c2ab366a5eda68..0f15e000e48e4d2a90da2b135233aa71f4675b0d 100644 (file)
@@ -213,7 +213,7 @@ static ssize_t mod_write(fr_listen_t *li, void *packet_ctx, UNUSED fr_time_t req
 
        fr_io_track_t                   *track = talloc_get_type_abort(packet_ctx, fr_io_track_t);
        proto_dhcpv4_track_t            *request = talloc_get_type_abort(track->packet, proto_dhcpv4_track_t);
-       fr_io_address_t                 address = {};
+       fr_socket_t                     socket;
 
        int                             flags;
        ssize_t                         data_size;
@@ -230,7 +230,7 @@ static ssize_t mod_write(fr_listen_t *li, void *packet_ctx, UNUSED fr_time_t req
        /*
         *      Swap src/dst IP/port
         */
-       fr_socket_addr_swap(&address.socket, &track->address->socket);
+       fr_socket_addr_swap(&socket, &track->address->socket);
 
        /*
         *      Figure out which kind of packet we're sending.
@@ -258,22 +258,22 @@ static ssize_t mod_write(fr_listen_t *li, void *packet_ctx, UNUSED fr_time_t req
                 *      - else if socket wasn't bound to *, then use that
                 *      - else if we have ifindex, get main IP from that interface and use that.
                 *      - else for offer/ack, look at option 54, for Server Identification and use that
-                *      - else leave source IP as whatever is already in "address.socket.inet.src_ipaddr".
+                *      - else leave source IP as whatever is already in "socket.inet.src_ipaddr".
                 */
                if (!fr_ipaddr_is_inaddr_any(&inst->src_ipaddr)) {
-                       address.socket.inet.src_ipaddr = inst->src_ipaddr;
+                       socket.inet.src_ipaddr = inst->src_ipaddr;
                } else if (!fr_ipaddr_is_inaddr_any(&inst->ipaddr)) {
-                       address.socket.inet.src_ipaddr = inst->ipaddr;
+                       socket.inet.src_ipaddr = inst->ipaddr;
 #ifdef WITH_IFINDEX_IPADDR_RESOLUTION
                } else if ((address->socket.inet.ifindex > 0) &&
-                          (fr_ipaddr_from_ifindex(&primary, thread->sockfd, &address.socket.inet.dst_ipaddr.af,
-                                                  &address.socket.inet.ifindex) == 0)) {
-                       address.socket.inet.src_ipaddr = primary;
+                          (fr_ipaddr_from_ifindex(&primary, thread->sockfd, &socket.inet.dst_ipaddr.af,
+                                                  &socket.inet.ifindex) == 0)) {
+                       socket.inet.src_ipaddr = primary;
 #endif
                } else if (((code[2] == FR_DHCP_OFFER) || (code[2] == FR_DHCP_ACK)) &&
                           ((sid = fr_dhcpv4_packet_get_option(packet, buffer_len, attr_dhcp_server_identifier)) != NULL) &&
                           (sid[1] == 4)) {
-                       memcpy(&address.socket.inet.src_ipaddr.addr.v4.s_addr, sid + 2, 4);
+                       memcpy(&socket.inet.src_ipaddr.addr.v4.s_addr, sid + 2, 4);
                }
 
                /*
@@ -302,9 +302,9 @@ static ssize_t mod_write(fr_listen_t *li, void *packet_ctx, UNUSED fr_time_t req
                 */
                if (packet->giaddr != INADDR_ANY) {
                        DEBUG("Reply will be sent to giaddr.");
-                       address.socket.inet.dst_ipaddr.addr.v4.s_addr = packet->giaddr;
-                       address.socket.inet.dst_port = inst->port;
-                       address.socket.inet.src_port = inst->port;
+                       socket.inet.dst_ipaddr.addr.v4.s_addr = packet->giaddr;
+                       socket.inet.dst_port = inst->port;
+                       socket.inet.src_port = inst->port;
 
                        /*
                         *      Increase the hop count for client
@@ -333,7 +333,7 @@ static ssize_t mod_write(fr_listen_t *li, void *packet_ctx, UNUSED fr_time_t req
                 */
                if (code[2] == FR_DHCP_NAK) {
                        DEBUG("Reply will be broadcast due to NAK.");
-                       address.socket.inet.dst_ipaddr.addr.v4.s_addr = INADDR_BROADCAST;
+                       socket.inet.dst_ipaddr.addr.v4.s_addr = INADDR_BROADCAST;
                        goto send_reply;
                }
 
@@ -350,7 +350,7 @@ static ssize_t mod_write(fr_listen_t *li, void *packet_ctx, UNUSED fr_time_t req
                 */
                if (request->ciaddr != INADDR_ANY) {
                        DEBUG("Reply will be unicast to CIADDR from original packet.");
-                       memcpy(&address.socket.inet.dst_ipaddr.addr.v4.s_addr, &request->ciaddr, 4);
+                       memcpy(&socket.inet.dst_ipaddr.addr.v4.s_addr, &request->ciaddr, 4);
                        goto send_reply;
                }
 
@@ -367,7 +367,7 @@ static ssize_t mod_write(fr_listen_t *li, void *packet_ctx, UNUSED fr_time_t req
                 */
                if (request->broadcast) {
                        DEBUG("Reply will be broadcast due to client request.");
-                       address.socket.inet.dst_ipaddr.addr.v4.s_addr = INADDR_BROADCAST;
+                       socket.inet.dst_ipaddr.addr.v4.s_addr = INADDR_BROADCAST;
                        goto send_reply;
                }
 
@@ -379,7 +379,7 @@ static ssize_t mod_write(fr_listen_t *li, void *packet_ctx, UNUSED fr_time_t req
                 *      This extension isn't in the RFC, but we find it useful.
                 */
                if ((packet->yiaddr == htonl(INADDR_ANY)) &&
-                   (address.socket.inet.dst_ipaddr.addr.v4.s_addr != htonl(INADDR_BROADCAST))) {
+                   (socket.inet.dst_ipaddr.addr.v4.s_addr != htonl(INADDR_BROADCAST))) {
                        DEBUG("Reply will be unicast to source IP from original packet.");
                        goto send_reply;
                }
@@ -413,7 +413,7 @@ static ssize_t mod_write(fr_listen_t *li, void *packet_ctx, UNUSED fr_time_t req
                         *      This check simply makes sure that we
                         *      don't needlessly update the ARP table.
                         */
-                       if (memcmp(&address.socket.inet.dst_ipaddr.addr.v4.s_addr, &packet->yiaddr, 4) == 0) {
+                       if (memcmp(&socket.inet.dst_ipaddr.addr.v4.s_addr, &packet->yiaddr, 4) == 0) {
                                DEBUG("Reply will be unicast to YIADDR.");
 
 #ifdef SIOCSARP
@@ -436,16 +436,16 @@ static ssize_t mod_write(fr_listen_t *li, void *packet_ctx, UNUSED fr_time_t req
                                 */
                                if (fr_arp_entry_add(thread->sockfd, inst->interface, ipaddr, macaddr) == 0) {
                                        DEBUG("Reply will be unicast to YIADDR, done ARP table updates.");
-                                       memcpy(&address.socket.inet.dst_ipaddr.addr.v4.s_addr, &packet->yiaddr, 4);
+                                       memcpy(&socket.inet.dst_ipaddr.addr.v4.s_addr, &packet->yiaddr, 4);
                                } else {
                                        DEBUG("Failed adding ARP entry.  Reply will be broadcast.");
-                                       address.socket.inet.dst_ipaddr.addr.v4.s_addr = INADDR_BROADCAST;
+                                       socket.inet.dst_ipaddr.addr.v4.s_addr = INADDR_BROADCAST;
                                }
 
 #endif
                        } else {
                                DEBUG("Reply will be broadcast as we do not create raw UDP sockets.");
-                               address.socket.inet.dst_ipaddr.addr.v4.s_addr = INADDR_BROADCAST;
+                               socket.inet.dst_ipaddr.addr.v4.s_addr = INADDR_BROADCAST;
                        }
                        break;
 
@@ -454,7 +454,7 @@ static ssize_t mod_write(fr_listen_t *li, void *packet_ctx, UNUSED fr_time_t req
                         */
                case FR_DHCP_ACK:
                        DEBUG("Reply will be unicast to YIADDR.");
-                       memcpy(&address.socket.inet.dst_ipaddr.addr.v4.s_addr, &packet->yiaddr, 4);
+                       memcpy(&socket.inet.dst_ipaddr.addr.v4.s_addr, &packet->yiaddr, 4);
                        break;
 
                default:
@@ -467,7 +467,7 @@ send_reply:
        /*
         *      proto_dhcpv4 takes care of suppressing do-not-respond, etc.
         */
-       data_size = udp_send(&address.socket, flags, buffer, buffer_len);
+       data_size = udp_send(&socket, flags, buffer, buffer_len);
 
        /*
         *      This socket is dead.  That's an error...
index 0f2c7083705fc1833daf572c95a8297c8199f477..897136228d543a0467e752469f49fcc944a23baa 100644 (file)
@@ -216,7 +216,7 @@ static ssize_t mod_write(fr_listen_t *li, void *packet_ctx, UNUSED fr_time_t req
        proto_dhcpv6_udp_thread_t       *thread = talloc_get_type_abort(li->thread_instance, proto_dhcpv6_udp_thread_t);
 
        fr_io_track_t                   *track = talloc_get_type_abort(packet_ctx, fr_io_track_t);
-       fr_io_address_t                 address = {};
+       fr_socket_t                     socket;
 
        int                             flags;
        ssize_t                         data_size;
@@ -234,8 +234,8 @@ static ssize_t mod_write(fr_listen_t *li, void *packet_ctx, UNUSED fr_time_t req
         *      Send packets to the originator, EXCEPT that we always
         *      originate packets from our src_ipaddr.
         */
-       fr_socket_addr_swap(&address.socket, &track->address->socket);
-       if (!fr_ipaddr_is_inaddr_any(&inst->src_ipaddr)) address.socket.inet.src_ipaddr = inst->src_ipaddr;
+       fr_socket_addr_swap(&socket, &track->address->socket);
+       if (!fr_ipaddr_is_inaddr_any(&inst->src_ipaddr)) socket.inet.src_ipaddr = inst->src_ipaddr;
 
        /*
         *      Figure out which kind of packet we're sending.
@@ -247,7 +247,7 @@ static ssize_t mod_write(fr_listen_t *li, void *packet_ctx, UNUSED fr_time_t req
        /*
         *      proto_dhcpv6 takes care of suppressing do-not-respond, etc.
         */
-       data_size = udp_send(&address.socket, flags, buffer, buffer_len);
+       data_size = udp_send(&socket, flags, buffer, buffer_len);
 
        /*
         *      This socket is dead.  That's an error...
index 63da911e2869c209d698e0de0bcd4819fff72a15..901c45fa1ca2b3c0f4d0bc79c0bd8ff9af65e4bb 100644 (file)
@@ -199,7 +199,7 @@ static ssize_t mod_write(fr_listen_t *li, void *packet_ctx, UNUSED fr_time_t req
        proto_radius_udp_thread_t       *thread = talloc_get_type_abort(li->thread_instance, proto_radius_udp_thread_t);
 
        fr_io_track_t                   *track = talloc_get_type_abort(packet_ctx, fr_io_track_t);
-       fr_io_address_t const           *address = track->address;
+       fr_socket_t                     socket;
 
        int                             flags;
        ssize_t                         data_size;
@@ -213,6 +213,12 @@ static ssize_t mod_write(fr_listen_t *li, void *packet_ctx, UNUSED fr_time_t req
 
        flags = UDP_FLAGS_CONNECTED * (thread->connection != NULL);
 
+       /*
+        *      Swap src/dst address so we send the response to
+        *      the client, not ourselves.
+        */
+       fr_socket_addr_swap(&socket, &track->address->socket);
+
        /*
         *      This handles the race condition where we get a DUP,
         *      but the original packet replies before we're run.
@@ -229,7 +235,7 @@ static ssize_t mod_write(fr_listen_t *li, void *packet_ctx, UNUSED fr_time_t req
 
                        memcpy(&packet, &track->reply, sizeof(packet)); /* const issues */
 
-                       (void) udp_send(&address->socket, flags, packet, track->reply_len);
+                       (void) udp_send(&socket, flags, packet, track->reply_len);
                }
 
                return buffer_len;
@@ -244,7 +250,7 @@ static ssize_t mod_write(fr_listen_t *li, void *packet_ctx, UNUSED fr_time_t req
         *      Only write replies if they're RADIUS packets.
         *      sometimes we want to NOT send a reply...
         */
-       data_size = udp_send(&address->socket, flags, buffer, buffer_len);
+       data_size = udp_send(&socket, flags, buffer, buffer_len);
 
        /*
         *      This socket is dead.  That's an error...
index 527bcaee7aef9299695f5b06dd34909f54edebb4..9215c0a498021cc8ff8ac0cb6fb3692b8898daf8 100644 (file)
@@ -202,7 +202,7 @@ static ssize_t mod_write(fr_listen_t *li, void *packet_ctx, UNUSED fr_time_t req
 {
        proto_vmps_udp_thread_t         *thread = talloc_get_type_abort(li->thread_instance, proto_vmps_udp_thread_t);
        fr_io_track_t                   *track = talloc_get_type_abort(packet_ctx, fr_io_track_t);
-       fr_io_address_t const           *address = track->address;
+       fr_socket_t                     socket;
 
        int                             flags;
        ssize_t                         data_size;
@@ -216,6 +216,8 @@ static ssize_t mod_write(fr_listen_t *li, void *packet_ctx, UNUSED fr_time_t req
 
        flags = UDP_FLAGS_CONNECTED * (thread->connection != NULL);
 
+       fr_socket_addr_swap(&socket, &track->address->socket);
+
        /*
         *      This handles the race condition where we get a DUP,
         *      but the original packet replies before we're run.
@@ -232,7 +234,7 @@ static ssize_t mod_write(fr_listen_t *li, void *packet_ctx, UNUSED fr_time_t req
 
                        memcpy(&packet, &track->reply, sizeof(packet)); /* const issues */
 
-                       (void) udp_send(&address->socket, flags, packet, track->reply_len);
+                       (void) udp_send(&socket, flags, packet, track->reply_len);
                }
 
                return buffer_len;
@@ -247,7 +249,7 @@ static ssize_t mod_write(fr_listen_t *li, void *packet_ctx, UNUSED fr_time_t req
         *      Only write replies if they're VMPS packets.
         *      sometimes we want to NOT send a reply...
         */
-       data_size = udp_send(&address->socket, flags, buffer, buffer_len);
+       data_size = udp_send(&socket, flags, buffer, buffer_len);
 
        /*
         *      This socket is dead.  That's an error...
index 7b500b4ec2c189223d07c88ff9b42909c090b7df..22805ebcc65f958795df867997bfffb9cf3dd437 100644 (file)
@@ -457,6 +457,8 @@ fr_radius_packet_t *fr_radius_packet_recv(TALLOC_CTX *ctx, int fd, int flags, ui
 int fr_radius_packet_send(fr_radius_packet_t *packet, fr_radius_packet_t const *original,
                          char const *secret)
 {
+       fr_socket_t     socket;
+
        /*
         *      Maybe it's a fake packet.  Don't send it.
         */
@@ -503,10 +505,16 @@ int fr_radius_packet_send(fr_radius_packet_t *packet, fr_radius_packet_t const *
                return -1;
        }
 
+       /*
+        *      Swap src/dst address so we send the response to
+        *      the client, not ourselves.
+        */
+       fr_socket_addr_swap(&socket, &packet->socket);
+
        /*
         *      And send it on it's way.
         */
-       return udp_send(&packet->socket, 0, packet->data, packet->data_len);
+       return udp_send(&socket, 0, packet->data, packet->data_len);
 }
 
 void _fr_radius_packet_log_hex(fr_log_t const *log, fr_radius_packet_t const *packet, char const *file, int line)