]> git.ipfire.org Git - thirdparty/freeradius-server.git/commitdiff
Handle relayed packets better...
authorAlan T. DeKok <aland@freeradius.org>
Tue, 28 Jun 2011 15:28:00 +0000 (17:28 +0200)
committerAlan T. DeKok <aland@freeradius.org>
Tue, 28 Jun 2011 15:28:00 +0000 (17:28 +0200)
If the request  a client packet, we can relay it using
the existing code.

If the request is a server packet, then it MUST be from
the real server, and we MUST be acting as a relay.  In that
case, set the giaddr to 0.0.0.0, and forward the packet to the
yiaddr.

And do something with broadcast replies...

src/main/dhcpd.c

index 959c561a4878e15dc94bf4f2e81e1018e661c5c3..6ddd46c3db1848abee0166b8c05d3f4863c71391 100644 (file)
@@ -59,12 +59,14 @@ static int dhcp_process(REQUEST *request)
        }
 
        /*
-        *      Look for Relay attribute, and forward it if necessary.
+        *      For messages from a client, look for Relay attribute,
+        *      and forward it if necessary.
         */
-       vp = pairfind(request->config_items, DHCP2ATTR(270));
+       if (request->packet->data[0] == 1) {
+               vp = pairfind(request->config_items, DHCP2ATTR(270));
+       }
        if (vp) {
                VALUE_PAIR *giaddr;
-               RADIUS_PACKET relayed;
                
                /*
                 *      Find the original giaddr.
@@ -86,49 +88,77 @@ static int dhcp_process(REQUEST *request)
                }
 
                /*
-                *      Forward it VERBATIM to the next server, rather
-                *      than to the client.
+                *      Say there's no "original" packet.  Instead,
+                *      just forward the "response".
+                */
+               rad_free(&request->reply);
+               request->reply = request->packet;
+               request->packet = NULL;
+
+               request->reply->src_ipaddr = request->reply->dst_ipaddr;
+               request->reply->src_port = request->reply->dst_port;
+               request->reply->dst_ipaddr.af = AF_INET;
+               request->reply->dst_ipaddr.ipaddr.ip4addr.s_addr = vp->vp_ipaddr;
+               /*
+                *      Don't change the destination port.  It's the
+                *      server port.
                 */
-               memcpy(&relayed, request->packet, sizeof(relayed));
 
-               relayed.dst_ipaddr.af = AF_INET;
-               relayed.dst_ipaddr.ipaddr.ip4addr.s_addr = vp->vp_ipaddr;
-               relayed.dst_port = request->packet->dst_port;
+               /*
+                *      Hop count goes up.
+                */
+               vp = pairfind(request->reply->vps, DHCP2ATTR(259));
+               if (vp) vp->vp_integer++;
+               
+               return 1;
+       }
 
-               relayed.src_ipaddr = request->packet->dst_ipaddr;
-               relayed.src_port = request->packet->dst_port;
+       /*
+        *      Responses from a server.  Handle them differently.
+        */
+       if (request->packet->data[0] == 2) {
+               /*
+                *      Delete any existing giaddr.  If we received a
+                *      message from the server, then we're NOT the
+                *      server.  So we must be the destination of the
+                *      giaddr field.
+                */
+               pairdelete(&request->packet->vps, DHCP2ATTR(266));
 
-               relayed.data = rad_malloc(relayed.data_len);
-               memcpy(relayed.data, request->packet->data, request->packet->data_len);
-               relayed.vps = NULL;
+               rad_free(&request->reply);
+               request->reply = request->packet;
+               request->packet = NULL;
 
                /*
-                *      If we were told to re-write the giaddr, do so.
+                *      Search for client IP address.
                 */
-               if (giaddr) {
-                       memcpy(relayed.data + 24, &giaddr->vp_ipaddr, 4);
+               vp = pairfind(request->packet->vps, DHCP2ATTR(264));
+               if (!vp) {
+                       request->reply->code = 0;
+                       RDEBUG("DHCP: No YIAddr in the reply. Discarding packet");
+                       return 1;
                }
 
                /*
-                *      The only field that changes is the number of hops.
-                *
-                *      FIXME: Allow for re-writing of the entire
-                *      packet contents!  This should be as simple as
-                *      re-encoding the packet from
-                *      request->packet->vps!
+                *      FROM us, TO the client's IP, OUR port + 1.
                 */
-               relayed.data[3]++; /* number of hops */
-               
+               request->reply->src_ipaddr = request->reply->dst_ipaddr;
+               request->reply->src_port = request->reply->dst_port;
+               request->reply->dst_ipaddr.af = AF_INET;
+               request->reply->dst_ipaddr.ipaddr.ip4addr.s_addr = vp->vp_ipaddr;
+               request->reply->dst_port++;
+
                /*
-                *      Forward the relayed packet VERBATIM, don't
-                *      respond to the client, and forget completely
-                *      about this request.
+                *      Hop count goes down.
                 */
-               fr_dhcp_send(&relayed);
-               free(relayed.data);
-
-               request->reply->code = 0; /* don't reply to the client */
+               vp = pairfind(request->reply->vps, DHCP2ATTR(259));
+               if (vp && (vp->vp_integer > 0)) vp->vp_integer--;
 
+               /*
+                *      FIXME: Keep original somewhere?  If the
+                *      broadcast flags are set, use them here?
+                */
+               
                return 1;
        }