From: Arran Cudbard-Bell Date: Fri, 6 Nov 2020 17:52:23 +0000 (-0600) Subject: Swap src/dst before we call udp_send X-Git-Url: http://git.ipfire.org/gitweb.cgi?a=commitdiff_plain;h=9ec0375f48aaa42de4eca7b02f30eccd3ba6843b;p=thirdparty%2Ffreeradius-server.git Swap src/dst before we call udp_send --- diff --git a/src/modules/proto_dhcpv4/proto_dhcpv4_udp.c b/src/modules/proto_dhcpv4/proto_dhcpv4_udp.c index e6d5ac99bca..0f15e000e48 100644 --- a/src/modules/proto_dhcpv4/proto_dhcpv4_udp.c +++ b/src/modules/proto_dhcpv4/proto_dhcpv4_udp.c @@ -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... diff --git a/src/modules/proto_dhcpv6/proto_dhcpv6_udp.c b/src/modules/proto_dhcpv6/proto_dhcpv6_udp.c index 0f2c7083705..897136228d5 100644 --- a/src/modules/proto_dhcpv6/proto_dhcpv6_udp.c +++ b/src/modules/proto_dhcpv6/proto_dhcpv6_udp.c @@ -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... diff --git a/src/modules/proto_radius/proto_radius_udp.c b/src/modules/proto_radius/proto_radius_udp.c index 63da911e286..901c45fa1ca 100644 --- a/src/modules/proto_radius/proto_radius_udp.c +++ b/src/modules/proto_radius/proto_radius_udp.c @@ -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... diff --git a/src/modules/proto_vmps/proto_vmps_udp.c b/src/modules/proto_vmps/proto_vmps_udp.c index 527bcaee7ae..9215c0a4980 100644 --- a/src/modules/proto_vmps/proto_vmps_udp.c +++ b/src/modules/proto_vmps/proto_vmps_udp.c @@ -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... diff --git a/src/protocols/radius/packet.c b/src/protocols/radius/packet.c index 7b500b4ec2c..22805ebcc65 100644 --- a/src/protocols/radius/packet.c +++ b/src/protocols/radius/packet.c @@ -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)