From: Alan T. DeKok Date: Mon, 4 Mar 2013 19:47:36 +0000 (-0500) Subject: Added DHCP-Relay-IP-Address X-Git-Tag: release_2_2_1~124 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=b4c509e85997a68b22840a72d295f5c0a4fa09a0;p=thirdparty%2Ffreeradius-server.git Added DHCP-Relay-IP-Address only in the reply, which is copied from the original giaddr --- diff --git a/share/dictionary.dhcp b/share/dictionary.dhcp index 3c610872ada..d2cd8f40246 100644 --- a/share/dictionary.dhcp +++ b/share/dictionary.dhcp @@ -50,6 +50,10 @@ ATTRIBUTE DHCP-Boot-Filename 269 string # 128 octets ATTRIBUTE DHCP-Relay-To-IP-Address 270 ipaddr ATTRIBUTE DHCP-Relay-Max-Hop-Count 271 integer +# This is copied from the request packet, giaddr, and +# added to the reply packet by the server core. +ATTRIBUTE DHCP-Relay-IP-Address 272 ipaddr + VALUE DHCP-Flags Broadcast 0x8000 diff --git a/src/main/dhcpd.c b/src/main/dhcpd.c index 1c6d5db9e7d..d12e42cd21f 100644 --- a/src/main/dhcpd.c +++ b/src/main/dhcpd.c @@ -271,6 +271,21 @@ static int dhcp_process(REQUEST *request) VALUE_PAIR *vp; dhcp_socket_t *sock; + /* + * If there's a giaddr, save it as the Relay-IP-Address + * in the response. That way the later code knows where + * to send the reply. + */ + vp = pairfind(request->packet->vps, DHCP2ATTR(266)); /* DHCP-Gateway-IP-Address */ + if (vp && (vp->vp_ipaddr != htonl(INADDR_ANY))) { + VALUE_PAIR *relay; + + /* DHCP-Relay-IP-Address */ + relay = radius_paircreate(request, &request->reply->vps, + DHCP2ATTR(272), PW_TYPE_IPADDR); + if (relay) relay->vp_ipaddr = vp->vp_ipaddr; + } + vp = pairfind(request->packet->vps, DHCP2ATTR(53)); /* DHCP-Message-Type */ if (vp) { DICT_VALUE *dv = dict_valbyattr(DHCP2ATTR(53), vp->vp_integer); @@ -396,17 +411,41 @@ static int dhcp_process(REQUEST *request) request->reply->dst_port = request->packet->src_port; request->reply->src_port = request->packet->dst_port; + /* + * Answer to client's nearest DHCP relay. + * + * Which may be different than the giaddr given in the + * packet to the client. i.e. the relay may have a + * public IP, but the gateway a private one. + */ + vp = pairfind(request->reply->vps, DHCP2ATTR(272)); /* DHCP-Relay-IP-Address */ + if (vp) { + RDEBUG("DHCP: Reply will be unicast to giaddr from original packet"); + request->reply->dst_ipaddr.ipaddr.ip4addr.s_addr = vp->vp_ipaddr; + return 1; + } + + /* + * Answer to client's nearest DHCP gateway. In this + * case, the client can reach the gateway, as can the + * server. + */ vp = pairfind(request->reply->vps, DHCP2ATTR(266)); /* DHCP-Gateway-IP-Address */ if (vp && (vp->vp_ipaddr != htonl(INADDR_ANY))) { - /* Answer to client's nearest DHCP relay */ RDEBUG("DHCP: Reply will be unicast to giaddr"); request->reply->dst_ipaddr.ipaddr.ip4addr.s_addr = vp->vp_ipaddr; + return 1; + } - } else if ((request->reply->code == PW_DHCP_NAK) || - ((vp = pairfind(request->reply->vps, DHCP2ATTR(262))) /* DHCP-Flags */ && - (vp->vp_integer & 0x8000) && - ((vp = pairfind(request->reply->vps, DHCP2ATTR(263))) /* DHCP-Client-IP-Address */ && - (vp->vp_ipaddr == htonl(INADDR_ANY))))) { + /* + * If it's a NAK, or the broadcast flag was set, ond + * there's no client-ip-address, send a broadcast. + */ + if ((request->reply->code == PW_DHCP_NAK) || + ((vp = pairfind(request->reply->vps, DHCP2ATTR(262))) && /* DHCP-Flags */ + (vp->vp_integer & 0x8000) && + ((vp = pairfind(request->reply->vps, DHCP2ATTR(263))) && /* DHCP-Client-IP-Address */ + (vp->vp_ipaddr == htonl(INADDR_ANY))))) { /* * RFC 2131, page 23 * @@ -417,43 +456,46 @@ static int dhcp_process(REQUEST *request) */ RDEBUG("DHCP: Reply will be broadcast"); request->reply->dst_ipaddr.ipaddr.ip4addr.s_addr = htonl(INADDR_BROADCAST); - } else { - /* - * RFC 2131, page 23 - * - * Unicast to - * - ciaddr if present - * otherwise to yiaddr - */ - if ((vp = pairfind(request->reply->vps, DHCP2ATTR(263))) /* DHCP-Client-IP-Address */ && - (vp->vp_ipaddr != htonl(INADDR_ANY))) { - RDEBUG("DHCP: Reply will be sent unicast to client-ip-address"); - request->reply->dst_ipaddr.ipaddr.ip4addr.s_addr = vp->vp_ipaddr; - } else { - vp = pairfind(request->reply->vps, DHCP2ATTR(264)); /* DHCP-Your-IP-Address */ - if (!vp) { - DEBUG("DHCP: Failed to find IP Address for request."); - return -1; - } - - RDEBUG("DHCP: Reply will be sent unicast to your-ip-address"); - request->reply->dst_ipaddr.ipaddr.ip4addr.s_addr = vp->vp_ipaddr; - - /* - * When sending a DHCP_OFFER, make sure our ARP table - * contains an entry for the client IP address, or else - * packet may not be forwarded if it was the first time - * the client was requesting an IP address. - */ - if (request->reply->code == PW_DHCP_OFFER) { - VALUE_PAIR *hwvp = pairfind(request->reply->vps, DHCP2ATTR(267)); /* DHCP-Client-Hardware-Address */ + return 1; + } - if (!hwvp) return -1; + /* + * RFC 2131, page 23 + * + * Unicast to ciaddr if present, otherwise to yiaddr. + */ + if ((vp = pairfind(request->reply->vps, DHCP2ATTR(263))) && /* DHCP-Client-IP-Address */ + (vp->vp_ipaddr != htonl(INADDR_ANY))) { + RDEBUG("DHCP: Reply will be sent unicast to client-ip-address"); + request->reply->dst_ipaddr.ipaddr.ip4addr.s_addr = vp->vp_ipaddr; + return 1; + } - if (fr_dhcp_add_arp_entry(request->reply->sockfd, sock->src_interface, hwvp, vp) < 0) { - return -1; - } - } + vp = pairfind(request->reply->vps, DHCP2ATTR(264)); /* DHCP-Your-IP-Address */ + if (!vp) { + DEBUG("DHCP: Failed to find DHCP-Your-IP-Address for request."); + return -1; + } + + RDEBUG("DHCP: Reply will be sent unicast to your-ip-address"); + request->reply->dst_ipaddr.ipaddr.ip4addr.s_addr = vp->vp_ipaddr; + + /* + * When sending a DHCP_OFFER, make sure our ARP table + * contains an entry for the client IP address. + * Otherwise the packet may not be sent to the client, as + * the OS has no ARP entry for it. + * + * This is a cute hack to avoid us having to create a raw + * socket to send DHCP packets. + */ + if (request->reply->code == PW_DHCP_OFFER) { + VALUE_PAIR *hwvp = pairfind(request->reply->vps, DHCP2ATTR(267)); /* DHCP-Client-Hardware-Address */ + + if (!hwvp) return -1; + + if (fr_dhcp_add_arp_entry(request->reply->sockfd, sock->src_interface, hwvp, vp) < 0) { + return -1; } } @@ -511,8 +553,6 @@ static int dhcp_socket_parse(CONF_SECTION *cs, rad_listen_t *this) sock->suppress_responses = FALSE; cp = cf_pair_find(cs, "suppress_responses"); if (cp) { - const char *value; - cf_item_parse(cs, "suppress_responses", PW_TYPE_BOOLEAN, &sock->suppress_responses, NULL); }