2 * dhcp.c DHCP processing. Done poorly for now.
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
20 * Copyright 2008 The FreeRADIUS server project
21 * Copyright 2008 Alan DeKok <aland@deployingradius.com>
24 #include <freeradius-devel/radiusd.h>
25 #include <freeradius-devel/modules.h>
26 #include <freeradius-devel/conffile.h>
27 #include <freeradius-devel/rad_assert.h>
33 * Same layout, etc. as listen_socket_t.
35 typedef struct dhcp_socket_t {
41 #ifdef SO_BINDTODEVICE
42 const char *interface;
44 int suppress_responses;
45 RADCLIENT dhcp_client;
48 static int dhcp_process(REQUEST *request)
53 vp = pairfind(request->packet->vps, DHCP2ATTR(53)); /* DHCP-Message-Type */
55 DICT_VALUE *dv = dict_valbyattr(DHCP2ATTR(53), vp->vp_integer);
56 DEBUG("Trying sub-section dhcp %s {...}",
57 dv->name ? dv->name : "<unknown>");
58 rcode = module_post_auth(vp->vp_integer, request);
60 DEBUG("DHCP: Failed to find DHCP-Message-Type in packet!");
61 rcode = RLM_MODULE_FAIL;
65 * Look for Relay attribute, and forward it if so...
68 vp = pairfind(request->reply->vps, DHCP2ATTR(53)); /* DHCP-Message-Type */
70 request->reply->code = vp->vp_integer;
71 if (request->reply->code < PW_DHCP_OFFSET) {
72 request->reply->code += PW_DHCP_OFFSET;
77 case RLM_MODULE_UPDATED:
78 if (request->packet->code == PW_DHCP_DISCOVER) {
79 request->reply->code = PW_DHCP_OFFER;
82 } else if (request->packet->code == PW_DHCP_REQUEST) {
83 request->reply->code = PW_DHCP_ACK;
90 case RLM_MODULE_REJECT:
92 case RLM_MODULE_INVALID:
94 case RLM_MODULE_NOTFOUND:
95 request->reply->code = PW_DHCP_NAK;
98 case RLM_MODULE_HANDLED:
105 static int dhcp_socket_parse(CONF_SECTION *cs, rad_listen_t *this)
113 rcode = listen_socket_parse(cs, this);
114 if (rcode != 0) return rcode;
119 * FIXME: Parse config file option for "do broadast = yes/no"
121 if (setsockopt(this->fd, SOL_SOCKET, SO_BROADCAST, &on, sizeof(on)) < 0) {
122 radlog(L_ERR, "Can't set broadcast option: %s\n",
127 if (setsockopt(this->fd, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on)) < 0) {
128 radlog(L_ERR, "Can't set re-use addres option: %s\n",
134 * Undocumented extension for testing without
135 * destroying your network!
137 sock->suppress_responses = FALSE;
138 cp = cf_pair_find(cs, "suppress_responses");
142 value = cf_pair_value(cp);
144 if (value && (strcmp(value, "yes") == 0)) {
145 sock->suppress_responses = TRUE;
150 * Initialize the fake client.
152 client = &sock->dhcp_client;
153 memset(client, 0, sizeof(*client));
154 client->ipaddr.af = AF_INET;
155 client->ipaddr.ipaddr.ip4addr.s_addr = INADDR_NONE;
157 client->longname = client->shortname = "dhcp";
158 client->secret = client->shortname;
159 client->nastype = strdup("none");
166 * Check if an incoming request is "ok"
168 * It takes packets, not requests. It sees if the packet looks
169 * OK. If so, it does a number of sanity checks on it.
171 static int dhcp_socket_recv(rad_listen_t *listener,
172 RAD_REQUEST_FUNP *pfun, REQUEST **prequest)
174 RADIUS_PACKET *packet;
177 packet = fr_dhcp_recv(listener->fd);
179 radlog(L_ERR, "%s", fr_strerror());
183 sock = listener->data;
184 if (!received_request(listener, packet, prequest, &sock->dhcp_client)) {
189 *pfun = dhcp_process;
196 * Send an authentication response packet
198 static int dhcp_socket_send(rad_listen_t *listener, REQUEST *request)
202 rad_assert(request->listener == listener);
203 rad_assert(listener->send == dhcp_socket_send);
205 if (request->reply->code == 0) return 0; /* don't reply */
207 if (fr_dhcp_encode(request->reply, request->packet) < 0) {
211 sock = listener->data;
212 if (sock->suppress_responses) return 0;
215 * Don't send anything
217 return fr_dhcp_send(request->reply);
221 static int dhcp_socket_encode(UNUSED rad_listen_t *listener, REQUEST *request)
223 DEBUG2("NO ENCODE!");
225 return fr_dhcp_encode(request->reply, request->packet);
229 static int dhcp_socket_decode(UNUSED rad_listen_t *listener, REQUEST *request)
231 return fr_dhcp_decode(request->packet);
235 frs_module_t frs_dhcp = {
236 FRS_MODULE_INIT, RAD_LISTEN_DHCP, "dhcp",
237 dhcp_socket_parse, NULL,
238 dhcp_socket_recv, dhcp_socket_send,
239 listen_socket_print, dhcp_socket_encode, dhcp_socket_decode
241 #endif /* WITH_DHCP */