9c8085df90410f954fa926ba13a3847ed4cd81dd
[freeradius.git] / src / modules / proto_dhcp / dhcpd.c
1 /*
2  * dhcp.c       DHCP processing.
3  *
4  * Version:     $Id$
5  *
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.
10  *
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.
15  *
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
19  *
20  * Copyright 2008 The FreeRADIUS server project
21  * Copyright 2008,2011 Alan DeKok <aland@deployingradius.com>
22  */
23
24 /*
25  * Standard sequence:
26  *      INADDR_ANY : 68 -> INADDR_BROADCAST : 67        DISCOVER
27  *      CLIENT_IP : 68 <- DHCP_SERVER_IP : 67           OFFER
28  *      INADDR_ANY : 68 -> INADDR_BROADCAST : 67        REQUEST
29  *      CLIENT_IP : 68 <- DHCP_SERVER_IP : 67           ACK
30  *
31  * Relay sequence:
32  *      INADDR_ANY : 68 -> INADDR_BROADCAST : 67        DISCOVER
33  *      RELAY_IP : 67 -> NEXT_SERVER_IP : 67            DISCOVER
34  *                              (NEXT_SERVER_IP can be a relay itself)
35  *      FIRST_RELAY_IP : 67 <- DHCP_SERVER_IP : 67      OFFER
36  *      CLIENT_IP : 68 <- FIRST_RELAY_IP : 67           OFFER
37  *      INADDR_ANY : 68 -> INADDR_BROADCAST : 67        REQUEST
38  *      RELAY_IP : 67 -> NEXT_SERVER_IP : 67            REQUEST
39  *                              (NEXT_SERVER_IP can be a relay itself)
40  *      FIRST_RELAY_IP : 67 <- DHCP_SERVER_IP : 67      ACK
41  *      CLIENT_IP : 68 <- FIRST_RELAY_IP : 67           ACK
42  *
43  * Note: NACK are broadcasted, rest is unicast, unless client asked
44  * for a broadcast
45  */
46
47
48 #include <freeradius-devel/radiusd.h>
49 #include <freeradius-devel/modules.h>
50 #include <freeradius-devel/protocol.h>
51 #include <freeradius-devel/process.h>
52 #include <freeradius-devel/dhcp.h>
53 #include <freeradius-devel/rad_assert.h>
54
55 #ifndef __MINGW32__
56 #include <sys/ioctl.h>
57 #endif
58
59 /*
60  *      Same contents as listen_socket_t.
61  */
62 typedef struct dhcp_socket_t {
63         listen_socket_t lsock;
64
65         /*
66          *      DHCP-specific additions.
67          */
68         bool            suppress_responses;
69         RADCLIENT       dhcp_client;
70         char const      *src_interface;
71         fr_ipaddr_t     src_ipaddr;
72 } dhcp_socket_t;
73
74 #ifdef WITH_UDPFROMTO
75 static int dhcprelay_process_client_request(REQUEST *request)
76 {
77         uint8_t maxhops = 16;
78         VALUE_PAIR *vp, *giaddr;
79         dhcp_socket_t *sock;
80
81         rad_assert(request->packet->data[0] == 1);
82
83         /*
84          *      Do the forward by ourselves, do not rely on dhcp_socket_send()
85          */
86         request->reply->code = 0;
87
88         /*
89          * It's invalid to have giaddr=0 AND a relay option
90          */
91         giaddr = fr_pair_find_by_num(request->packet->vps, 266, DHCP_MAGIC_VENDOR, TAG_ANY); /* DHCP-Gateway-IP-Address */
92         if (giaddr && (giaddr->vp_ipaddr == htonl(INADDR_ANY)) &&
93             fr_pair_find_by_num(request->packet->vps, 82, DHCP_MAGIC_VENDOR, TAG_ANY)) { /* DHCP-Relay-Agent-Information */
94                 DEBUG("DHCP: Received packet with giaddr = 0 and containing relay option: Discarding packet\n");
95                 return 1;
96         }
97
98         /*
99          * RFC 1542 (BOOTP), page 15
100          *
101          * Drop requests if hop-count > 16 or admin specified another value
102          */
103         if ((vp = fr_pair_find_by_num(request->config, 271, DHCP_MAGIC_VENDOR, TAG_ANY))) { /* DHCP-Relay-Max-Hop-Count */
104             maxhops = vp->vp_integer;
105         }
106         vp = fr_pair_find_by_num(request->packet->vps, 259, DHCP_MAGIC_VENDOR, TAG_ANY); /* DHCP-Hop-Count */
107         rad_assert(vp != NULL);
108         if (vp->vp_integer > maxhops) {
109                 DEBUG("DHCP: Number of hops is greater than %d: not relaying\n", maxhops);
110                 return 1;
111         } else {
112             /* Increment hop count */
113             vp->vp_integer++;
114         }
115
116         sock = request->listener->data;
117
118         /*
119          *      Forward the request to the next server using the
120          *      incoming request as a template.
121          */
122         /* set SRC ipaddr/port to the listener ipaddr/port */
123         request->packet->src_ipaddr.af = AF_INET;
124         request->packet->src_ipaddr.ipaddr.ip4addr.s_addr = sock->lsock.my_ipaddr.ipaddr.ip4addr.s_addr;
125         request->packet->src_port = sock->lsock.my_port;
126
127         vp = fr_pair_find_by_num(request->config, 270, DHCP_MAGIC_VENDOR, TAG_ANY); /* DHCP-Relay-To-IP-Address */
128         rad_assert(vp != NULL);
129
130         /* set DEST ipaddr/port to the next server ipaddr/port */
131         request->packet->dst_ipaddr.af = AF_INET;
132         request->packet->dst_ipaddr.ipaddr.ip4addr.s_addr = vp->vp_ipaddr;
133         request->packet->dst_port = sock->lsock.my_port;
134
135         if (fr_dhcp_encode(request->packet) < 0) {
136                 DEBUG("dhcprelay_process_client_request: ERROR in fr_dhcp_encode\n");
137                 return -1;
138         }
139
140         return fr_dhcp_send(request->packet);
141 }
142
143
144 /*
145  *      We've seen a reply from a server.
146  *      i.e. we're a relay.
147  */
148 static int dhcprelay_process_server_reply(REQUEST *request)
149 {
150         VALUE_PAIR *vp, *giaddr;
151         dhcp_socket_t *sock;
152
153         rad_assert(request->packet->data[0] == 2);
154
155         /*
156          * Do the forward by ourselves, do not rely on dhcp_socket_send()
157          */
158         request->reply->code = 0;
159
160         sock = request->listener->data;
161
162         /*
163          * Check that packet is for us.
164          */
165         giaddr = fr_pair_find_by_num(request->packet->vps, 266, DHCP_MAGIC_VENDOR, TAG_ANY); /* DHCP-Gateway-IP-Address */
166
167         /* --with-udpfromto is needed just for the following test */
168         if (!giaddr || giaddr->vp_ipaddr != request->packet->dst_ipaddr.ipaddr.ip4addr.s_addr) {
169                 DEBUG("DHCP: Packet received from server was not for us (was for 0x%x). Discarding packet",
170                     ntohl(request->packet->dst_ipaddr.ipaddr.ip4addr.s_addr));
171                 return 1;
172         }
173
174         /* set SRC ipaddr/port to the listener ipaddr/port */
175         request->packet->src_ipaddr.af = AF_INET;
176         request->packet->src_port = sock->lsock.my_port;
177
178         /* set DEST ipaddr/port to clientip/68 or broadcast in specific cases */
179         request->packet->dst_ipaddr.af = AF_INET;
180
181         /*
182          *      We're a relay, and send the reply to giaddr.
183          */
184         request->reply->dst_ipaddr.ipaddr.ip4addr.s_addr = giaddr->vp_ipaddr;
185         request->reply->dst_port = request->packet->dst_port;           /* server port */
186
187         if ((request->packet->code == PW_DHCP_NAK) ||
188             !sock->src_interface ||
189             ((vp = fr_pair_find_by_num(request->packet->vps, 262, DHCP_MAGIC_VENDOR, TAG_ANY)) /* DHCP-Flags */ &&
190              (vp->vp_integer & 0x8000) &&
191              ((vp = fr_pair_find_by_num(request->packet->vps, 263, DHCP_MAGIC_VENDOR, TAG_ANY)) /* DHCP-Client-IP-Address */ &&
192               (vp->vp_ipaddr == htonl(INADDR_ANY))))) {
193                 /*
194                  * RFC 2131, page 23
195                  *
196                  * Broadcast on
197                  * - DHCPNAK
198                  * or
199                  * - Broadcast flag is set up and ciaddr == NULL
200                  */
201                 RDEBUG("DHCP: response will be  broadcast");
202                 request->packet->dst_ipaddr.ipaddr.ip4addr.s_addr = htonl(INADDR_BROADCAST);
203         } else {
204                 /*
205                  * RFC 2131, page 23
206                  *
207                  * Unicast to
208                  * - ciaddr if present
209                  * otherwise to yiaddr
210                  */
211                 if ((vp = fr_pair_find_by_num(request->packet->vps, 263, DHCP_MAGIC_VENDOR, TAG_ANY)) /* DHCP-Client-IP-Address */ &&
212                     (vp->vp_ipaddr != htonl(INADDR_ANY))) {
213                         request->packet->dst_ipaddr.ipaddr.ip4addr.s_addr = vp->vp_ipaddr;
214                 } else {
215                         vp = fr_pair_find_by_num(request->packet->vps, 264, DHCP_MAGIC_VENDOR, TAG_ANY); /* DHCP-Your-IP-Address */
216                         if (!vp) {
217                                 DEBUG("DHCP: Failed to find IP Address for request");
218                                 return -1;
219                         }
220
221                         RDEBUG("DHCP: response will be unicast to your-ip-address");
222                         request->packet->dst_ipaddr.ipaddr.ip4addr.s_addr = vp->vp_ipaddr;
223
224                         /*
225                          * When sending a DHCP_OFFER, make sure our ARP table
226                          * contains an entry for the client IP address, or else
227                          * packet may not be forwarded if it was the first time
228                          * the client was requesting an IP address.
229                          */
230                         if (request->packet->code == PW_DHCP_OFFER) {
231                                 VALUE_PAIR *hwvp = fr_pair_find_by_num(request->packet->vps, 267, DHCP_MAGIC_VENDOR, TAG_ANY); /* DHCP-Client-Hardware-Address */
232                                 if (hwvp == NULL) {
233                                         DEBUG("DHCP: DHCP_OFFER packet received with "
234                                             "no Client Hardware Address. Discarding packet");
235                                         return 1;
236                                 }
237                                 if (fr_dhcp_add_arp_entry(request->packet->sockfd, sock->src_interface, hwvp, vp) < 0) {
238                                         DEBUG("%s", fr_strerror());
239                                         return -1;
240                                 }
241                         }
242                 }
243         }
244
245         if (fr_dhcp_encode(request->packet) < 0) {
246                 DEBUG("dhcprelay_process_server_reply: ERROR in fr_dhcp_encode\n");
247                 return -1;
248         }
249
250         return fr_dhcp_send(request->packet);
251 }
252 #else  /* WITH_UDPFROMTO */
253 static int dhcprelay_process_server_reply(UNUSED REQUEST *request)
254 {
255         WARN("DHCP Relaying requires the server to be configured with UDPFROMTO");
256         return -1;
257 }
258
259 static int dhcprelay_process_client_request(UNUSED REQUEST *request)
260 {
261         WARN("DHCP Relaying requires the server to be configured with UDPFROMTO");
262         return -1;
263 }
264
265 #endif  /* WITH_UDPFROMTO */
266
267 static const uint32_t attrnums[] = {
268         57,     /* DHCP-DHCP-Maximum-Msg-Size */
269         256,    /* DHCP-Opcode */
270         257,    /* DHCP-Hardware-Type */
271         258,    /* DHCP-Hardware-Address-Length */
272         259,    /* DHCP-Hop-Count */
273         260,    /* DHCP-Transaction-Id */
274         262,    /* DHCP-Flags */
275         263,    /* DHCP-Client-IP-Address */
276         266,    /* DHCP-Gateway-IP-Address */
277         267     /* DHCP-Client-Hardware-Address */
278 };
279
280 static int dhcp_process(REQUEST *request)
281 {
282         int rcode;
283         unsigned int i;
284         VALUE_PAIR *vp;
285         dhcp_socket_t *sock;
286
287         /*
288          *      If there's a giaddr, save it as the Relay-IP-Address
289          *      in the response.  That way the later code knows where
290          *      to send the reply.
291          */
292         vp = fr_pair_find_by_num(request->packet->vps, 266, DHCP_MAGIC_VENDOR, TAG_ANY); /* DHCP-Gateway-IP-Address */
293         if (vp && (vp->vp_ipaddr != htonl(INADDR_ANY))) {
294                 VALUE_PAIR *relay;
295
296                 /* DHCP-Relay-IP-Address */
297                 relay = radius_pair_create(request->reply, &request->reply->vps,
298                                           272, DHCP_MAGIC_VENDOR);
299                 if (relay) relay->vp_ipaddr = vp->vp_ipaddr;
300         }
301
302         vp = fr_pair_find_by_num(request->packet->vps, 53, DHCP_MAGIC_VENDOR, TAG_ANY); /* DHCP-Message-Type */
303         if (vp) {
304                 DICT_VALUE *dv = dict_valbyattr(53, DHCP_MAGIC_VENDOR, vp->vp_integer);
305                 DEBUG("Trying sub-section dhcp %s {...}",
306                       dv ? dv->name : "<unknown>");
307                 rcode = process_post_auth(vp->vp_integer, request);
308         } else {
309                 DEBUG("DHCP: Failed to find DHCP-Message-Type in packet!");
310                 rcode = RLM_MODULE_FAIL;
311         }
312
313         vp = fr_pair_find_by_num(request->reply->vps, 53, DHCP_MAGIC_VENDOR, TAG_ANY); /* DHCP-Message-Type */
314         if (vp) {
315                 request->reply->code = vp->vp_integer;
316                 if ((request->reply->code != 0) &&
317                     (request->reply->code < PW_DHCP_OFFSET)) {
318                         request->reply->code += PW_DHCP_OFFSET;
319                 }
320         }
321         else switch (rcode) {
322         case RLM_MODULE_OK:
323         case RLM_MODULE_UPDATED:
324                 if (request->packet->code == PW_DHCP_DISCOVER) {
325                         request->reply->code = PW_DHCP_OFFER;
326                         break;
327
328                 } else if (request->packet->code == PW_DHCP_REQUEST) {
329                         request->reply->code = PW_DHCP_ACK;
330                         break;
331                 }
332                 request->reply->code = PW_DHCP_NAK;
333                 break;
334
335         default:
336         case RLM_MODULE_REJECT:
337         case RLM_MODULE_FAIL:
338         case RLM_MODULE_INVALID:
339         case RLM_MODULE_NOOP:
340         case RLM_MODULE_NOTFOUND:
341                 if (request->packet->code == PW_DHCP_DISCOVER) {
342                         request->reply->code = 0; /* ignore the packet */
343                 } else {
344                         request->reply->code = PW_DHCP_NAK;
345                 }
346                 break;
347
348         case RLM_MODULE_HANDLED:
349                 request->reply->code = 0; /* ignore the packet */
350                 break;
351         }
352
353         /*
354          *      TODO: Handle 'output' of RLM_MODULE when acting as a
355          *      DHCP relay We may want to not forward packets in
356          *      certain circumstances.
357          */
358
359         /*
360          *      Handle requests when acting as a DHCP relay
361          */
362         vp = fr_pair_find_by_num(request->packet->vps, 256, DHCP_MAGIC_VENDOR, TAG_ANY); /* DHCP-Opcode */
363         if (!vp) {
364                 RDEBUG("FAILURE: Someone deleted the DHCP-Opcode!");
365                 return 1;
366         }
367
368         /* BOOTREPLY received on port 67 (i.e. from a server) */
369         if (vp->vp_integer == 2) {
370                 return dhcprelay_process_server_reply(request);
371         }
372
373         /* Packet from client, and we have DHCP-Relay-To-IP-Address */
374         if (fr_pair_find_by_num(request->config, 270, DHCP_MAGIC_VENDOR, TAG_ANY)) {
375                 return dhcprelay_process_client_request(request);
376         }
377
378         /* else it's a packet from a client, without relaying */
379         rad_assert(vp->vp_integer == 1); /* BOOTREQUEST */
380
381         sock = request->listener->data;
382
383         /*
384          *      Handle requests when acting as a DHCP server
385          */
386
387         /*
388          *      Releases don't get replies.
389          */
390         if (request->packet->code == PW_DHCP_RELEASE) {
391                 request->reply->code = 0;
392         }
393
394         if (request->reply->code == 0) {
395                 return 1;
396         }
397
398         request->reply->sockfd = request->packet->sockfd;
399
400         /*
401          *      Copy specific fields from packet to reply, if they
402          *      don't already exist
403          */
404         for (i = 0; i < sizeof(attrnums) / sizeof(attrnums[0]); i++) {
405                 uint32_t attr = attrnums[i];
406
407                 if (fr_pair_find_by_num(request->reply->vps, attr, DHCP_MAGIC_VENDOR, TAG_ANY)) continue;
408
409                 vp = fr_pair_find_by_num(request->packet->vps, attr, DHCP_MAGIC_VENDOR, TAG_ANY);
410                 if (vp) {
411                         fr_pair_add(&request->reply->vps, fr_pair_copy(request->reply, vp));
412                 }
413         }
414
415         vp = fr_pair_find_by_num(request->reply->vps, 256, DHCP_MAGIC_VENDOR, TAG_ANY); /* DHCP-Opcode */
416         rad_assert(vp != NULL);
417         vp->vp_integer = 2; /* BOOTREPLY */
418
419         /*
420          *      Allow NAKs to be delayed for a short period of time.
421          */
422         if (request->reply->code == PW_DHCP_NAK) {
423                 vp = fr_pair_find_by_num(request->reply->vps, PW_FREERADIUS_RESPONSE_DELAY, 0, TAG_ANY);
424                 if (vp) {
425                         if (vp->vp_integer <= 10) {
426                                 request->response_delay.tv_sec = vp->vp_integer;
427                                 request->response_delay.tv_usec = 0;
428                         } else {
429                                 request->response_delay.tv_sec = 10;
430                                 request->response_delay.tv_usec = 0;
431                         }
432                 } else {
433 #define USEC 1000000
434                         vp = fr_pair_find_by_num(request->reply->vps, PW_FREERADIUS_RESPONSE_DELAY_USEC, 0, TAG_ANY);
435                         if (vp) {
436                                 if (vp->vp_integer <= 10 * USEC) {
437                                         request->response_delay.tv_sec = vp->vp_integer / USEC;
438                                         request->response_delay.tv_usec = vp->vp_integer % USEC;
439                                 } else {
440                                         request->response_delay.tv_sec = 10;
441                                         request->response_delay.tv_usec = 0;
442                                 }
443                         }
444                 }
445         }
446
447         /*
448          *      Prepare the reply packet for sending through dhcp_socket_send()
449          */
450         request->reply->dst_ipaddr.af = AF_INET;
451         request->reply->src_ipaddr.af = AF_INET;
452         request->reply->src_ipaddr.prefix = 32;
453
454         /*
455          *      Packet-Src-IP-Address has highest precedence
456          */
457         vp = fr_pair_find_by_num(request->reply->vps, PW_PACKET_SRC_IP_ADDRESS, 0, TAG_ANY);
458         if (vp) {
459                 request->reply->src_ipaddr.ipaddr.ip4addr.s_addr = vp->vp_ipaddr;
460         /*
461          *      The request was unicast (via a relay)
462          */
463         } else if (request->packet->dst_ipaddr.ipaddr.ip4addr.s_addr != htonl(INADDR_BROADCAST)) {
464                 request->reply->src_ipaddr.ipaddr.ip4addr.s_addr = request->packet->dst_ipaddr.ipaddr.ip4addr.s_addr;
465         /*
466          *      The listener was bound to an IP address, or we determined
467          *      the address automatically, as it was the only address bound
468          *      to the interface, and we bound to the interface.
469          */
470         } else if (sock->src_ipaddr.ipaddr.ip4addr.s_addr != htonl(INADDR_ANY)) {
471                 request->reply->src_ipaddr.ipaddr.ip4addr.s_addr = sock->src_ipaddr.ipaddr.ip4addr.s_addr;
472         /*
473          *      There's a Server-Identification attribute
474          */
475         } else if ((vp = fr_pair_find_by_num(request->reply->vps, 54, DHCP_MAGIC_VENDOR, TAG_ANY))) {
476                 request->reply->src_ipaddr.ipaddr.ip4addr.s_addr = vp->vp_ipaddr;
477         } else {
478                 REDEBUG("Unable to determine correct src_ipaddr for response");
479                 return -1;
480         }
481         request->reply->dst_port = request->packet->src_port;
482         request->reply->src_port = request->packet->dst_port;
483
484         /*
485          *      Answer to client's nearest DHCP relay.
486          *
487          *      Which may be different than the giaddr given in the
488          *      packet to the client.  i.e. the relay may have a
489          *      public IP, but the gateway a private one.
490          */
491         vp = fr_pair_find_by_num(request->reply->vps, 272, DHCP_MAGIC_VENDOR, TAG_ANY); /* DHCP-Relay-IP-Address */
492         if (vp && (vp->vp_ipaddr != ntohl(INADDR_ANY))) {
493                 RDEBUG("DHCP: Reply will be unicast to giaddr from original packet");
494                 request->reply->dst_ipaddr.ipaddr.ip4addr.s_addr = vp->vp_ipaddr;
495                 request->reply->dst_port = request->packet->dst_port;
496
497                 vp = fr_pair_find_by_num(request->reply->vps, PW_PACKET_DST_PORT, 0, TAG_ANY);
498                 if (vp) request->reply->dst_port = vp->vp_integer;
499
500                 return 1;
501         }
502
503         /*
504          *      Answer to client's nearest DHCP gateway.  In this
505          *      case, the client can reach the gateway, as can the
506          *      server.
507          *
508          *      We also use *our* source port as the destination port.
509          *      Gateways are servers, and listen on the server port,
510          *      not the client port.
511          */
512         vp = fr_pair_find_by_num(request->reply->vps, 266, DHCP_MAGIC_VENDOR, TAG_ANY); /* DHCP-Gateway-IP-Address */
513         if (vp && (vp->vp_ipaddr != htonl(INADDR_ANY))) {
514                 RDEBUG("DHCP: Reply will be unicast to giaddr");
515                 request->reply->dst_ipaddr.ipaddr.ip4addr.s_addr = vp->vp_ipaddr;
516                 request->reply->dst_port = request->packet->dst_port;
517                 return 1;
518         }
519
520         /*
521          *      If it's a NAK, or the broadcast flag was set, ond
522          *      there's no client-ip-address, send a broadcast.
523          */
524         if ((request->reply->code == PW_DHCP_NAK) ||
525             ((vp = fr_pair_find_by_num(request->reply->vps, 262, DHCP_MAGIC_VENDOR, TAG_ANY)) && /* DHCP-Flags */
526              (vp->vp_integer & 0x8000) &&
527              ((vp = fr_pair_find_by_num(request->reply->vps, 263, DHCP_MAGIC_VENDOR, TAG_ANY)) && /* DHCP-Client-IP-Address */
528               (vp->vp_ipaddr == htonl(INADDR_ANY))))) {
529                 /*
530                  * RFC 2131, page 23
531                  *
532                  * Broadcast on
533                  * - DHCPNAK
534                  * or
535                  * - Broadcast flag is set up and ciaddr == NULL
536                  */
537                 RDEBUG("DHCP: Reply will be broadcast");
538                 request->reply->dst_ipaddr.ipaddr.ip4addr.s_addr = htonl(INADDR_BROADCAST);
539                 return 1;
540         }
541
542         /*
543          *      RFC 2131, page 23
544          *
545          *      Unicast to ciaddr if present, otherwise to yiaddr.
546          */
547         if ((vp = fr_pair_find_by_num(request->reply->vps, 263, DHCP_MAGIC_VENDOR, TAG_ANY)) && /* DHCP-Client-IP-Address */
548             (vp->vp_ipaddr != htonl(INADDR_ANY))) {
549                 RDEBUG("DHCP: Reply will be sent unicast to client-ip-address");
550                 request->reply->dst_ipaddr.ipaddr.ip4addr.s_addr = vp->vp_ipaddr;
551                 return 1;
552         }
553
554         vp = fr_pair_find_by_num(request->reply->vps, 264, DHCP_MAGIC_VENDOR, TAG_ANY); /* DHCP-Your-IP-Address */
555         if (!vp) {
556                 RDEBUG("DHCP: Failed to find DHCP-Client-IP-Address or DHCP-Your-IP-Address for request; "
557                        "not responding");
558                 /*
559                  *      There is nowhere to send the response to, so don't bother.
560                  */
561                 request->reply->code = 0;
562                 return -1;
563         }
564
565 #ifdef SIOCSARP
566         /*
567          *      The system is configured to listen for broadcast
568          *      packets, which means we'll need to send unicast
569          *      replies, to IPs which haven't yet been assigned.
570          *      Therefore, we need to update the ARP table.
571          *
572          *      However, they haven't specified a interface.  So we
573          *      can't update the ARP table.  And we must send a
574          *      broadcast response.
575          */
576         if (sock->lsock.broadcast && !sock->src_interface) {
577                 WARN("You MUST set \"interface\" if you have \"broadcast = yes\"");
578                 RDEBUG("DHCP: Reply will be broadcast as no interface was defined");
579                 request->reply->dst_ipaddr.ipaddr.ip4addr.s_addr = htonl(INADDR_BROADCAST);
580                 return 1;
581         }
582
583         RDEBUG("DHCP: Reply will be unicast to your-ip-address");
584         request->reply->dst_ipaddr.ipaddr.ip4addr.s_addr = vp->vp_ipaddr;
585
586         /*
587          *      When sending a DHCP_OFFER, make sure our ARP table
588          *      contains an entry for the client IP address.
589          *      Otherwise the packet may not be sent to the client, as
590          *      the OS has no ARP entry for it.
591          *
592          *      This is a cute hack to avoid us having to create a raw
593          *      socket to send DHCP packets.
594          */
595         if (request->reply->code == PW_DHCP_OFFER) {
596                 VALUE_PAIR *hwvp = fr_pair_find_by_num(request->reply->vps, 267, DHCP_MAGIC_VENDOR, TAG_ANY); /* DHCP-Client-Hardware-Address */
597
598                 if (!hwvp) return -1;
599
600                 if (fr_dhcp_add_arp_entry(request->reply->sockfd, sock->src_interface, hwvp, vp) < 0) {
601                         RDEBUG("Failed adding arp entry: %s", fr_strerror());
602                         return -1;
603                 }
604         }
605 #else
606         if (request->packet->src_ipaddr.ipaddr.ip4addr.s_addr != ntohl(INADDR_NONE)) {
607                 RDEBUG("DHCP: Request will be unicast to the unicast source IP address");
608                 request->reply->dst_ipaddr.ipaddr.ip4addr.s_addr = request->packet->src_ipaddr.ipaddr.ip4addr.s_addr;
609         } else {
610                 RDEBUG("DHCP: Reply will be broadcast as this system does not support ARP updates");
611                 request->reply->dst_ipaddr.ipaddr.ip4addr.s_addr = htonl(INADDR_BROADCAST);
612         }
613 #endif
614
615         return 1;
616 }
617
618 static int dhcp_socket_parse(CONF_SECTION *cs, rad_listen_t *this)
619 {
620         int rcode, broadcast = 1;
621         int on = 1;
622         dhcp_socket_t *sock;
623         RADCLIENT *client;
624         CONF_PAIR *cp;
625
626         /*
627          *      Set if before parsing, so the user can forcibly turn
628          *      it off later.
629          */
630         this->nodup = true;
631
632         rcode = common_socket_parse(cs, this);
633         if (rcode != 0) return rcode;
634
635         if (check_config) return 0;
636
637         sock = this->data;
638
639         if (!sock->lsock.interface) {
640                 WARN("No \"interface\" setting is defined.  Only unicast DHCP will work");
641         }
642
643         /*
644          *      See whether or not we enable broadcast packets.
645          */
646         cp = cf_pair_find(cs, "broadcast");
647         if (cp) {
648                 char const *value = cf_pair_value(cp);
649                 if (value && (strcmp(value, "no") == 0)) {
650                         broadcast = 0;
651                 }
652         }
653
654         if (broadcast) {
655                 if (setsockopt(this->fd, SOL_SOCKET, SO_BROADCAST, &on, sizeof(on)) < 0) {
656                         ERROR("Can't set broadcast option: %s\n",
657                                fr_syserror(errno));
658                         return -1;
659                 }
660         }
661
662         if (setsockopt(this->fd, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on)) < 0) {
663                 ERROR("Can't set re-use addres option: %s\n",
664                        fr_syserror(errno));
665                 return -1;
666         }
667
668         /*
669          *      Undocumented extension for testing without
670          *      destroying your network!
671          */
672         sock->suppress_responses = false;
673         cp = cf_pair_find(cs, "suppress_responses");
674         if (cp) {
675                 rcode = cf_item_parse(cs, "suppress_responses", FR_ITEM_POINTER(PW_TYPE_BOOLEAN, &sock->suppress_responses), NULL);
676                 if (rcode < 0) return -1;
677         }
678
679         cp = cf_pair_find(cs, "src_interface");
680         if (cp) {
681                 rcode = cf_item_parse(cs, "src_interface", FR_ITEM_POINTER(PW_TYPE_STRING, &sock->src_interface), NULL);
682                 if (rcode < 0) return -1;
683         } else {
684                 sock->src_interface = sock->lsock.interface;
685         }
686
687         if (!sock->src_interface && sock->lsock.interface) {
688                 sock->src_interface = talloc_typed_strdup(sock, sock->lsock.interface);
689         }
690
691         cp = cf_pair_find(cs, "src_ipaddr");
692         if (cp) {
693                 memset(&sock->src_ipaddr, 0, sizeof(sock->src_ipaddr));
694                 sock->src_ipaddr.ipaddr.ip4addr.s_addr = htonl(INADDR_NONE);
695                 rcode = cf_item_parse(cs, "src_ipaddr", FR_ITEM_POINTER(PW_TYPE_IPV4_ADDR, &sock->src_ipaddr), NULL);
696                 if (rcode < 0) return -1;
697
698                 sock->src_ipaddr.af = AF_INET;
699         } else {
700                 memcpy(&sock->src_ipaddr, &sock->lsock.my_ipaddr, sizeof(sock->src_ipaddr));
701         }
702
703         /*
704          *      Initialize the fake client.
705          */
706         client = &sock->dhcp_client;
707         memset(client, 0, sizeof(*client));
708         client->ipaddr.af = AF_INET;
709         client->ipaddr.ipaddr.ip4addr.s_addr = ntohl(INADDR_NONE);
710         client->ipaddr.prefix = 0;
711         client->longname = client->shortname = "dhcp";
712         client->secret = client->shortname;
713         client->nas_type = talloc_typed_strdup(sock, "none");
714
715         return 0;
716 }
717
718
719 /*
720  *      Check if an incoming request is "ok"
721  *
722  *      It takes packets, not requests.  It sees if the packet looks
723  *      OK.  If so, it does a number of sanity checks on it.
724  */
725 static int dhcp_socket_recv(rad_listen_t *listener)
726 {
727         RADIUS_PACKET   *packet;
728         dhcp_socket_t   *sock;
729
730         packet = fr_dhcp_recv(listener->fd);
731         if (!packet) {
732                 ERROR("%s", fr_strerror());
733                 return 0;
734         }
735
736         sock = listener->data;
737         if (!request_receive(NULL, listener, packet, &sock->dhcp_client, dhcp_process)) {
738                 rad_free(&packet);
739                 return 0;
740         }
741
742         return 1;
743 }
744
745
746 /*
747  *      Send an authentication response packet
748  */
749 static int dhcp_socket_send(rad_listen_t *listener, REQUEST *request)
750 {
751         dhcp_socket_t   *sock;
752
753         rad_assert(request->listener == listener);
754         rad_assert(listener->send == dhcp_socket_send);
755
756         if (request->reply->code == 0) return 0; /* don't reply */
757
758         if (fr_dhcp_encode(request->reply) < 0) {
759                 DEBUG("dhcp_socket_send: ERROR\n");
760                 return -1;
761         }
762
763         sock = listener->data;
764         if (sock->suppress_responses) return 0;
765
766         return fr_dhcp_send(request->reply);
767 }
768
769
770 static int dhcp_socket_encode(UNUSED rad_listen_t *listener, UNUSED REQUEST *request)
771 {
772         DEBUG2("NO ENCODE!");
773         return 0;
774 }
775
776
777 static int dhcp_socket_decode(UNUSED rad_listen_t *listener, REQUEST *request)
778 {
779         return fr_dhcp_decode(request->packet);
780 }
781
782 extern fr_protocol_t proto_dhcp;
783 fr_protocol_t proto_dhcp = {
784         .magic          = RLM_MODULE_INIT,
785         .name           = "dhcp",
786         .inst_size      = sizeof(dhcp_socket_t),
787         .parse          = dhcp_socket_parse,
788         .recv           = dhcp_socket_recv,
789         .send           = dhcp_socket_send,
790         .print          = common_socket_print,
791         .encode         = dhcp_socket_encode,
792         .decode         = dhcp_socket_decode
793 };