Correctly handle large attributes
[freeradius.git] / src / lib / dhcp.c
1 /*
2  * dhcp.c       Functions to send/receive dhcp packets.
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 Alan DeKok <aland@deployingradius.com>
22  */
23
24 #include        <freeradius-devel/ident.h>
25 RCSID("$Id$")
26
27 #include <freeradius-devel/libradius.h>
28 #include <freeradius-devel/udpfromto.h>
29 #include <freeradius-devel/dhcp.h>
30
31 #ifdef WITH_DHCP
32 #define DHCP_CHADDR_LEN (16)
33 #define DHCP_SNAME_LEN  (64)
34 #define DHCP_FILE_LEN   (128)
35 #define DHCP_VEND_LEN   (308)
36 #define DHCP_OPTION_MAGIC_NUMBER (0x63825363)
37
38 #ifndef INADDR_BROADCAST
39 #define INADDR_BROADCAST INADDR_NONE
40 #endif
41
42 typedef struct dhcp_packet_t {
43         uint8_t         opcode;
44         uint8_t         htype;
45         uint8_t         hlen;
46         uint8_t         hops;
47         uint32_t        xid;    /* 4 */
48         uint16_t        secs;   /* 8 */
49         uint16_t        flags;
50         uint32_t        ciaddr; /* 12 */
51         uint32_t        yiaddr; /* 16 */
52         uint32_t        siaddr; /* 20 */
53         uint32_t        giaddr; /* 24 */
54         uint8_t         chaddr[DHCP_CHADDR_LEN]; /* 28 */
55         uint8_t         sname[DHCP_SNAME_LEN]; /* 44 */
56         uint8_t         file[DHCP_FILE_LEN]; /* 108 */
57         uint32_t        option_format; /* 236 */
58         uint8_t         options[DHCP_VEND_LEN];
59 } dhcp_packet_t;
60
61 typedef struct dhcp_option_t {
62         uint8_t         code;
63         uint8_t         length;
64 } dhcp_option_t;
65
66 /*
67  *      INADDR_ANY : 68 -> INADDR_BROADCAST : 67        DISCOVER
68  *      INADDR_BROADCAST : 68 <- SERVER_IP : 67         OFFER
69  *      INADDR_ANY : 68 -> INADDR_BROADCAST : 67        REQUEST
70  *      INADDR_BROADCAST : 68 <- SERVER_IP : 67         ACK
71  */
72 static const char *dhcp_header_names[] = {
73         "DHCP-Opcode",
74         "DHCP-Hardware-Type",
75         "DHCP-Hardware-Address-Length",
76         "DHCP-Hop-Count",
77         "DHCP-Transaction-Id",
78         "DHCP-Number-of-Seconds",
79         "DHCP-Flags",
80         "DHCP-Client-IP-Address",
81         "DHCP-Your-IP-Address",
82         "DHCP-Server-IP-Address",
83         "DHCP-Gateway-IP-Address",
84         "DHCP-Client-Hardware-Address",
85         "DHCP-Server-Host-Name",
86         "DHCP-Boot-Filename",
87
88         NULL
89 };
90
91 static const char *dhcp_message_types[] = {
92         "invalid",
93         "DHCP-Discover",
94         "DHCP-Offer",
95         "DHCP-Request",
96         "DHCP-Decline",
97         "DHCP-Ack",
98         "DHCP-NAK",
99         "DHCP-Release",
100         "DHCP-Inform",
101         "DHCP-Force-Renew",
102 };
103
104 static int dhcp_header_sizes[] = {
105         1, 1, 1, 1,
106         4, 2, 2, 4,
107         4, 4, 4,
108         DHCP_CHADDR_LEN,
109         DHCP_SNAME_LEN,
110         DHCP_FILE_LEN
111 };
112
113
114 /*
115  *      Some clients silently ignore responses less than 300 bytes.
116  */
117 #define MIN_PACKET_SIZE (244)
118 #define DEFAULT_PACKET_SIZE (300)
119 #define MAX_PACKET_SIZE (1500 - 40)
120
121 #define DHCP_OPTION_FIELD (0)
122 #define DHCP_FILE_FIELD   (1)
123 #define DHCP_SNAME_FIELD  (2)
124
125 static uint8_t *dhcp_get_option(dhcp_packet_t *packet, size_t packet_size,
126                                 unsigned int option)
127                                 
128 {
129         int overload = 0;
130         int field = DHCP_OPTION_FIELD;
131         size_t where, size;
132         uint8_t *data = packet->options;
133
134         where = 0;
135         size = packet_size - offsetof(dhcp_packet_t, options);
136         data = &packet->options[where];
137
138         while (where < size) {
139                 if (data[0] == 0) { /* padding */
140                         where++;
141                         continue;
142                 }
143
144                 if (data[0] == 255) { /* end of options */
145                         if ((field == DHCP_OPTION_FIELD) &&
146                             (overload & DHCP_FILE_FIELD)) {
147                                 data = packet->file;
148                                 where = 0;
149                                 size = sizeof(packet->file);
150                                 field = DHCP_FILE_FIELD;
151                                 continue;
152
153                         } else if ((field == DHCP_FILE_FIELD) &&
154                                    (overload && DHCP_SNAME_FIELD)) {
155                                 data = packet->sname;
156                                 where = 0;
157                                 size = sizeof(packet->sname);
158                                 field = DHCP_SNAME_FIELD;
159                                 continue;
160                         }
161
162                         return NULL;
163                 }
164
165                 /*
166                  *      We MUST have a real option here.
167                  */
168                 if ((where + 2) > size) {
169                         fr_strerror_printf("Options overflow field at %u",
170                                            data - (uint8_t *) packet);
171                         return NULL;
172                 }
173
174                 if ((where + 2 + data[1]) > size) {
175                         fr_strerror_printf("Option length overflows field at %u",
176                                            data - (uint8_t *) packet);
177                         return NULL;
178                 }
179
180                 if (data[0] == option) return data;
181
182                 if (data[0] == 52) { /* overload sname and/or file */
183                         overload = data[3];
184                 }
185
186                 where += data[1] + 2;
187                 data += data[1] + 2;
188         }
189
190         return NULL;
191 }
192
193 /*
194  *      DHCPv4 is only for IPv4.  Broadcast only works if udpfromto is
195  *      defined.
196  */
197 RADIUS_PACKET *fr_dhcp_recv(int sockfd)
198 {
199         uint32_t                magic;
200         struct sockaddr_storage src;
201         struct sockaddr_storage dst;
202         socklen_t               sizeof_src;
203         socklen_t               sizeof_dst;
204         RADIUS_PACKET           *packet;
205         int port;
206         uint8_t                 *code;
207
208         packet = rad_alloc(0);
209         if (!packet) return NULL;
210         memset(packet, 0, sizeof(packet));
211
212         packet->data = malloc(MAX_PACKET_SIZE);
213         if (!packet->data) {
214                 rad_free(&packet);
215                 return NULL;
216         }
217
218         packet->sockfd = sockfd;
219         sizeof_src = sizeof(src);
220 #ifdef WITH_UDPFROMTO
221         sizeof_dst = sizeof(dst);
222         packet->data_len = recvfromto(sockfd, packet->data, MAX_PACKET_SIZE, 0,
223                                       (struct sockaddr *)&src, &sizeof_src,
224                                       (struct sockaddr *)&dst, &sizeof_dst);
225 #else
226         packet->data_len = recvfrom(sockfd, packet->data, MAX_PACKET_SIZE, 0,
227                                     (struct sockaddr *)&src, &sizeof_src);
228 #endif
229
230         if (packet->data_len <= 0) {
231                 fprintf(stderr, "Failed reading DHCP socket: %s", strerror(errno));
232                 rad_free(&packet);
233                 return NULL;
234         }
235
236         if (packet->data_len < MIN_PACKET_SIZE) {
237                 fprintf(stderr, "DHCP packet is too small (%d < %d)",
238                       packet->data_len, MIN_PACKET_SIZE);
239                 rad_free(&packet);
240                 return NULL;
241         }
242
243         if (packet->data[0] != 1) {
244                 fprintf(stderr, "Cannot receive DHCP server messages");
245                 rad_free(&packet);
246                 return NULL;
247         }
248
249         if (packet->data[1] != 1) {
250                 fprintf(stderr, "DHCP can only receive ethernet requests, not type %02x",
251                       packet->data[1]);
252                 rad_free(&packet);
253                 return NULL;
254         }
255
256         if (packet->data[2] != 6) {
257                 fprintf(stderr, "Ethernet HW length is wrong length %d\n",
258                         packet->data[2]);
259                 rad_free(&packet);
260                 return NULL;
261         }
262
263         memcpy(&magic, packet->data + 236, 4);
264         magic = ntohl(magic);
265         if (magic != DHCP_OPTION_MAGIC_NUMBER) {
266                 fprintf(stderr, "Cannot do BOOTP\n");
267                 rad_free(&packet);
268                 return NULL;
269         }
270
271         /*
272          *      Create unique keys for the packet.
273          */
274         memcpy(&magic, packet->data + 4, 4);
275         packet->id = ntohl(magic);
276
277         code = dhcp_get_option((dhcp_packet_t *) packet->data,
278                                packet->data_len, 53);
279         if (!code) {
280                 fr_strerror_printf("No message-type option was found in the packet");
281                 rad_free(&packet);
282                 return NULL;
283         }
284
285         if ((code[1] < 1) || (code[2] == 0) || (code[2] > 8)) {
286                 fr_strerror_printf("Unknown value for message-type option");
287                 rad_free(&packet);
288                 return NULL;
289         }
290
291         packet->code = code[2] | PW_DHCP_OFFSET;
292
293         /*
294          *      Create a unique vector from the MAC address and the
295          *      DHCP opcode.  This is a hack for the RADIUS
296          *      infrastructure in the rest of the server.
297          *
298          *      Note: packet->data[2] == 6, which is smaller than
299          *      sizeof(packet->vector)
300          *
301          *      FIXME:  Look for client-identifier in packet,
302          *      and use that, too?
303          */
304         memset(packet->vector, 0, sizeof(packet->vector));
305         memcpy(packet->vector, packet->data + 28, packet->data[2]);
306         packet->vector[packet->data[2]] = packet->code & 0xff;
307
308         /*
309          *      FIXME: for DISCOVER / REQUEST: src_port == dst_port + 1
310          *      FIXME: for OFFER / ACK       : src_port = dst_port - 1
311          */
312
313         /*
314          *      Unique keys are xid, client mac, and client ID?
315          */
316
317         /*
318          *      FIXME: More checks, like DHCP packet type?
319          */
320
321         sizeof_dst = sizeof(dst);
322
323 #ifndef WITH_UDPFROMTO
324         /*
325          *      This should never fail...
326          */
327         getsockname(sockfd, (struct sockaddr *) &dst, &sizeof_dst);
328 #endif
329         
330         fr_sockaddr2ipaddr(&dst, sizeof_dst, &packet->dst_ipaddr, &port);
331         packet->dst_port = port;
332
333         fr_sockaddr2ipaddr(&src, sizeof_src, &packet->src_ipaddr, &port);
334         packet->src_port = port;
335
336         if (fr_debug_flag > 1) {
337                 char type_buf[64];
338                 const char *name = type_buf;
339                 char src_ip_buf[256], dst_ip_buf[256];
340                 
341                 if ((packet->code >= PW_DHCP_DISCOVER) &&
342                     (packet->code <= PW_DHCP_INFORM)) {
343                         name = dhcp_message_types[packet->code - PW_DHCP_OFFSET];
344                 } else {
345                         snprintf(type_buf, sizeof(type_buf), "%d",
346                                  packet->code - PW_DHCP_OFFSET);
347                 }
348
349                 printf("Received %s of id %08x from %s:%d to %s:%d\n",
350                        name, (unsigned int) packet->id,
351                        inet_ntop(packet->src_ipaddr.af,
352                                  &packet->src_ipaddr.ipaddr,
353                                  src_ip_buf, sizeof(src_ip_buf)),
354                        packet->src_port,
355                        inet_ntop(packet->dst_ipaddr.af,
356                                  &packet->dst_ipaddr.ipaddr,
357                                  dst_ip_buf, sizeof(dst_ip_buf)),
358                        packet->dst_port);
359                 fflush(stdout);
360         }
361
362         return packet;
363 }
364
365
366 /*
367  *      Send a DHCP packet.
368  */
369 int fr_dhcp_send(RADIUS_PACKET *packet)
370 {
371         struct sockaddr_storage dst;
372         socklen_t               sizeof_dst;
373 #ifdef WITH_UDPFROMTO
374         struct sockaddr_storage src;
375         socklen_t               sizeof_src;
376 #endif
377
378         fr_ipaddr2sockaddr(&packet->dst_ipaddr, packet->dst_port,
379                            &dst, &sizeof_dst);
380
381 #ifndef WITH_UDPFROMTO
382         /*
383          *      Assume that the packet is encoded before sending it.
384          */
385         return sendto(packet->sockfd, packet->data, packet->data_len, 0,
386                       (struct sockaddr *)&dst, sizeof_dst);
387 #else
388         fr_ipaddr2sockaddr(&packet->src_ipaddr, packet->src_port,
389                            &src, &sizeof_src);
390
391         return sendfromto(packet->sockfd,
392                           packet->data, packet->data_len, 0,
393                           (struct sockaddr *)&src, sizeof_src,
394                           (struct sockaddr *)&dst, sizeof_dst);
395 #endif
396 }
397
398
399 int fr_dhcp_decode(RADIUS_PACKET *packet)
400 {
401         int i;
402         ssize_t total;
403         uint8_t *p;
404         uint32_t giaddr;
405         VALUE_PAIR *head, *vp, **tail;
406         VALUE_PAIR *maxms, *mtu;
407         char buffer[2048];
408
409         head = NULL;
410         tail = &head;
411         p = packet->data;
412         
413         if ((fr_debug_flag > 2) && fr_log_fp) {
414                 for (i = 0; i < packet->data_len; i++) {
415                         if ((i & 0x0f) == 0x00) fprintf(stderr, "%d: ", i);
416                         fprintf(fr_log_fp, "%02x ", packet->data[i]);
417                         if ((i & 0x0f) == 0x0f) fprintf(fr_log_fp, "\n");
418                 }
419                 fprintf(fr_log_fp, "\n");
420         }
421
422         if (packet->data[1] != 1) {
423                 fprintf(stderr, "Packet is not Ethernet: %u\n",
424                       packet->data[1]);
425                 return -1;
426         }
427
428         /*
429          *      Decode the header.
430          */
431         for (i = 0; i < 14; i++) {
432                 vp = pairmake(dhcp_header_names[i], NULL, T_OP_EQ);
433                 if (!vp) {
434                         fprintf(stderr, "Parse error %s\n", fr_strerror());
435                         pairfree(&head);
436                         return -1;
437                 }
438
439
440                 if ((i == 11) && 
441                     (packet->data[1] == 1) &&
442                     (packet->data[2] == 6)) {
443                         vp->type = PW_TYPE_ETHERNET;
444                 }
445
446                 switch (vp->type) {
447                 case PW_TYPE_BYTE:
448                         vp->vp_integer = p[0];
449                         vp->length = 1;
450                         break;
451                         
452                 case PW_TYPE_SHORT:
453                         vp->vp_integer = (p[0] << 8) | p[1];
454                         vp->length = 2;
455                         break;
456                         
457                 case PW_TYPE_INTEGER:
458                         memcpy(&vp->vp_integer, p, 4);
459                         vp->vp_integer = ntohl(vp->vp_integer);
460                         vp->length = 4;
461                         break;
462                         
463                 case PW_TYPE_IPADDR:
464                         memcpy(&vp->vp_ipaddr, p, 4);
465                         vp->length = 4;
466                         break;
467                         
468                 case PW_TYPE_STRING:
469                         memcpy(vp->vp_strvalue, p, dhcp_header_sizes[i]);
470                         vp->vp_strvalue[dhcp_header_sizes[i]] = '\0';
471                         vp->length = strlen(vp->vp_strvalue);
472                         if (vp->length == 0) {
473                                 pairfree(&vp);
474                         }
475                         break;
476                         
477                 case PW_TYPE_OCTETS:
478                         memcpy(vp->vp_octets, p, packet->data[2]);
479                         vp->length = packet->data[2];
480                         break;
481                         
482                 case PW_TYPE_ETHERNET:
483                         memcpy(vp->vp_ether, p, sizeof(vp->vp_ether));
484                         vp->length = sizeof(vp->vp_ether);
485                         break;
486                         
487                 default:
488                         fprintf(stderr, "BAD TYPE %d\n", vp->type);
489                         pairfree(&vp);
490                         break;
491                 }
492                 p += dhcp_header_sizes[i];
493
494                 if (!vp) continue;
495                 
496                 if (fr_debug_flag > 1) {
497                         vp_prints(buffer, sizeof(buffer), vp);
498                         fprintf(stderr, "\t%s\n", buffer);
499                 }
500                 *tail = vp;
501                 tail = &vp->next;
502         }
503         
504         /*
505          *      Loop over the options.
506          */
507         p = packet->data + 240;
508         total = packet->data_len - 240;
509
510         /*
511          *      FIXME: This should also check sname && file fields.
512          *      See the dhcp_get_option() function above.
513          */
514         while (total > 0) {
515                 int num_entries, alen;
516                 DICT_ATTR *da;
517
518                 if (*p == 0) break;
519                 if (*p == 255) break; /* end of options signifier */
520
521                 if (p[1] >= 253) {
522                         fprintf(stderr, "Attribute too long %u %u\n",
523                               p[0], p[1]);
524                         goto do_next;
525                 }
526                                 
527                 da = dict_attrbyvalue(DHCP2ATTR(p[0]));
528                 if (!da) {
529                         fprintf(stderr, "Attribute not in our dictionary: %u\n",
530                               p[0]);
531                 do_next:
532                         total -= 2;
533                         total -= p[1];
534                         p += p[1];
535                         p += 2;
536                         continue;
537                 }
538
539                 vp = NULL;
540                 num_entries = 1;
541                 alen = p[1];
542                 p += 2;
543
544                 if (da->flags.array) {
545                         switch (da->type) {
546                         case PW_TYPE_BYTE:
547                                 num_entries = alen;
548                                 alen = 1;
549                                 break;
550
551                         case PW_TYPE_SHORT:
552                                 if ((alen & 0x01) != 0) goto raw;
553                                 num_entries = alen / 2;
554                                 alen = 2;
555                                 break;
556
557                         case PW_TYPE_IPADDR:
558                         case PW_TYPE_INTEGER:
559                         case PW_TYPE_DATE:
560                                 if ((alen & 0x03) != 0) goto raw;
561                                 num_entries = alen / 4;
562                                 alen = 4;
563                                 break;
564
565                         default:
566                                 break; /* really an internal sanity failure */
567                         }
568                 } else {
569                         num_entries = 1;
570
571                         switch (da->type) {
572                         case PW_TYPE_BYTE:
573                                 if (alen != 1) goto raw;
574                                 break;
575
576                         case PW_TYPE_SHORT:
577                                 if (alen != 2) goto raw;
578                                 break;
579
580                         case PW_TYPE_IPADDR:
581                         case PW_TYPE_INTEGER:
582                         case PW_TYPE_DATE:
583                                 if (alen != 4) goto raw;
584                                 break;
585
586                         default:
587                                 break;
588                         }
589                 }
590
591                 for (i = 0; i < num_entries; i++) {
592                         vp = pairmake(da->name, NULL, T_OP_EQ);
593                         if (!vp) {
594                                 fprintf(stderr, "Cannot build attribute %s\n",
595                                         fr_strerror());
596                                 pairfree(&head);
597                                 return -1;
598                         }
599
600                         /*
601                          *      Hacks for ease of use.
602                          */
603                         if ((da->attr == DHCP2ATTR(0x3d)) &&
604                             !da->flags.array &&
605                             (alen == 7) && (*p == 1) && (num_entries == 1)) {
606                                 vp->type = PW_TYPE_ETHERNET;
607                                 memcpy(vp->vp_octets, p + 1, 6);
608                         } else
609
610                                 switch (vp->type) {
611                                 case PW_TYPE_BYTE:
612                                         vp->vp_integer = p[0];
613                                         break;
614                                 
615                                 case PW_TYPE_SHORT:
616                                         vp->vp_integer = (p[0] << 8) | p[1];
617                                         break;
618
619                                 case PW_TYPE_INTEGER:
620                                         memcpy(&vp->vp_integer, p, 4);
621                                         vp->vp_integer = ntohl(vp->vp_integer);
622                                         break;
623
624                                 case PW_TYPE_IPADDR:
625                                         memcpy(&vp->vp_ipaddr, p , 4);
626                                         vp->length = 4;
627                                         break;
628
629                                 case PW_TYPE_STRING:
630                                         memcpy(vp->vp_strvalue, p , alen);
631                                         vp->vp_strvalue[alen] = '\0';
632                                         break;
633
634                                 raw:
635                                         vp = pairmake(da->name, NULL, T_OP_EQ);
636                                         if (!vp) {
637                                                 fprintf(stderr, "Cannot build attribute %s\n", fr_strerror());
638                                                 pairfree(&head);
639                                                 return -1;
640                                         }
641
642                                         vp->type = PW_TYPE_OCTETS;
643                                 
644                                 case PW_TYPE_OCTETS:
645                                         memcpy(vp->vp_octets, p, alen);
646                                         break;
647                                 
648                                 default:
649                                         fprintf(stderr, "Internal sanity check %d %d\n", vp->type, __LINE__);
650                                         pairfree(&vp);
651                                         break;
652                                 } /* switch over type */
653                                 
654                         vp->length = alen;
655
656                         if (fr_debug_flag > 1) {
657                                 vp_prints(buffer, sizeof(buffer), vp);
658                                 fprintf(stderr, "\t%s\n", buffer);
659                         }
660
661                         *tail = vp;
662                         tail = &vp->next;
663                         p += alen;
664                 } /* loop over array entries */
665                 
666                 total -= 2;
667                 total -= (alen * num_entries);
668         }
669
670         /*
671          *      If DHCP request, set ciaddr to zero.
672          */
673
674         /*
675          *      Set broadcast flag for broken vendors, but only if
676          *      giaddr isn't set.
677          */
678         memcpy(&giaddr, packet->data + 24, sizeof(giaddr));
679         if (giaddr == htonl(INADDR_ANY)) {
680                 /*
681                  *      DHCP Opcode is request
682                  */
683                 vp = pairfind(head, DHCP2ATTR(256));
684                 if (vp && vp->lvalue == 3) {
685                         /*
686                          *      Vendor is "MSFT 98"
687                          */
688                         vp = pairfind(head, DHCP2ATTR(63));
689                         if (vp && (strcmp(vp->vp_strvalue, "MSFT 98") == 0)) {
690                                 vp = pairfind(head, DHCP2ATTR(262));
691
692                                 /*
693                                  *      Reply should be broadcast.
694                                  */
695                                 if (vp) vp->lvalue |= 0x8000;
696                                 packet->data[10] |= 0x80;                       
697                         }
698                 }
699         }
700
701         /*
702          *      FIXME: Nuke attributes that aren't used in the normal
703          *      header for discover/requests.
704          */
705         packet->vps = head;
706
707         /*
708          *      Client can request a LARGER size, but not a smaller
709          *      one.  They also cannot request a size larger than MTU.
710          */
711         maxms = pairfind(packet->vps, DHCP2ATTR(57));
712         mtu = pairfind(packet->vps, DHCP2ATTR(26));
713
714         if (mtu && (mtu->vp_integer < DEFAULT_PACKET_SIZE)) {
715                 fprintf(stderr, "DHCP Fatal: Client says MTU is smaller than minimum permitted by the specification.");
716                 return -1;
717         }
718
719         if (maxms && (maxms->vp_integer < DEFAULT_PACKET_SIZE)) {
720                 fprintf(stderr, "DHCP WARNING: Client says maximum message size is smaller than minimum permitted by the specification: fixing it");
721                 maxms->vp_integer = DEFAULT_PACKET_SIZE;
722         }
723
724         if (maxms && mtu && (maxms->vp_integer > mtu->vp_integer)) {
725                 fprintf(stderr, "DHCP WARNING: Client says MTU is smaller than maximum message size: fixing it");
726                 maxms->vp_integer = mtu->vp_integer;
727         }
728
729         if (fr_debug_flag) fflush(stdout);
730
731         return 0;
732 }
733
734
735 static int attr_cmp(const void *one, const void *two)
736 {
737         const VALUE_PAIR * const *a = one;
738         const VALUE_PAIR * const *b = two;
739
740         /*
741          *      DHCP-Message-Type is first, for simplicity.
742          */
743         if (((*a)->attribute == DHCP2ATTR(53)) &&
744             (*b)->attribute != DHCP2ATTR(53)) return -1;
745
746         /*
747          *      Relay-Agent is last
748          */
749         if (((*a)->attribute == DHCP2ATTR(82)) &&
750             (*b)->attribute != DHCP2ATTR(82)) return +1;
751
752         return ((*a)->attribute - (*b)->attribute);
753 }
754
755
756 static size_t fr_dhcp_vp2attr(VALUE_PAIR *vp, uint8_t *p, size_t room)
757 {
758         size_t length;
759         uint32_t lvalue;
760
761         /*
762          *      FIXME: Check room!
763          */
764         room = room;            /* -Wunused */
765
766         /*
767          *      Search for all attributes of the same
768          *      type, and pack them into the same
769          *      attribute.
770          */
771         switch (vp->type) {
772         case PW_TYPE_BYTE:
773                 length = 1;
774                 *p = vp->vp_integer & 0xff;
775                 break;
776                 
777         case PW_TYPE_SHORT:
778                 length = 2;
779                 p[0] = (vp->vp_integer >> 8) & 0xff;
780                 p[1] = vp->vp_integer & 0xff;
781                 break;
782                 
783         case PW_TYPE_INTEGER:
784                 length = 4;
785                 lvalue = htonl(vp->vp_integer);
786                 memcpy(p, &lvalue, 4);
787                 break;
788                 
789         case PW_TYPE_IPADDR:
790                 length = 4;
791                 memcpy(p, &vp->vp_ipaddr, 4);
792                 break;
793                 
794         case PW_TYPE_ETHERNET:
795                 length = 6;
796                 memcpy(p, &vp->vp_ether, 6);
797                 break;
798                 
799         case PW_TYPE_STRING:
800                 memcpy(p, vp->vp_strvalue, vp->length);
801                 length = vp->length;
802                 break;
803                 
804         case PW_TYPE_OCTETS:
805                 memcpy(p, vp->vp_octets, vp->length);
806                 length = vp->length;
807                 break;
808                 
809         default:
810                 fprintf(stderr, "BAD TYPE2 %d\n", vp->type);
811                 length = 0;
812                 break;
813         }
814
815         return length;
816 }
817
818 int fr_dhcp_encode(RADIUS_PACKET *packet, RADIUS_PACKET *original)
819 {
820         int i, num_vps;
821         uint8_t *p;
822         VALUE_PAIR *vp;
823         uint32_t lvalue, mms;
824         size_t dhcp_size, length;
825         dhcp_packet_t *dhcp;
826         char buffer[1024];
827
828         if (packet->data) return 0;
829
830         packet->data = malloc(MAX_PACKET_SIZE);
831         if (!packet->data) return -1;
832
833         packet->data_len = MAX_PACKET_SIZE;
834
835         if (packet->code == 0) packet->code = PW_DHCP_NAK;
836
837         /*
838          *      FIXME: allow it to send client packets.
839          */
840         if (!original) {
841                 fr_strerror_printf("Need original to send response!");
842                 return -1;
843         }
844
845         packet->dst_ipaddr.af = AF_INET;
846         packet->src_ipaddr.af = AF_INET;
847
848         packet->dst_port = original->src_port;
849         packet->src_port = original->dst_port;
850
851         /*
852          *      Note that for DHCP, we NEVER send the response to the
853          *      source IP address of the request.  It may have
854          *      traversed multiple relays, and we need to send the request
855          *      to the relay closest to the client.
856          *
857          *      if giaddr, send to giaddr.
858          *      if NAK, send broadcast packet
859          *      if ciaddr, unicast to ciaddr
860          *      if flags & 0x8000, broadcast (client request)
861          *      if sent from 0.0.0.0, broadcast response
862          *      unicast to client yiaddr
863          */
864
865         /*
866          *      FIXME: alignment issues.  We likely don't want to
867          *      de-reference the packet structure directly..
868          */
869         dhcp = (dhcp_packet_t *) original->data;
870
871         if (dhcp->giaddr != htonl(INADDR_ANY)) {
872                 packet->dst_ipaddr.ipaddr.ip4addr.s_addr = dhcp->giaddr;
873
874                 if (dhcp->giaddr != htonl(INADDR_LOOPBACK)) {
875                         packet->dst_port = original->dst_port;
876                 } else {
877                         packet->dst_port = original->src_port; /* debugging */
878                 }
879
880         } else if (packet->code == PW_DHCP_NAK) {
881                 packet->dst_ipaddr.ipaddr.ip4addr.s_addr = htonl(INADDR_BROADCAST);
882                 
883         } else if (dhcp->ciaddr != htonl(INADDR_ANY)) {
884                 packet->dst_ipaddr.ipaddr.ip4addr.s_addr = dhcp->ciaddr;
885
886         } else if ((dhcp->flags & 0x8000) != 0) {
887                 packet->dst_ipaddr.ipaddr.ip4addr.s_addr = htonl(INADDR_BROADCAST);
888
889         } else if (packet->dst_ipaddr.ipaddr.ip4addr.s_addr == htonl(INADDR_ANY)) {
890                 packet->dst_ipaddr.ipaddr.ip4addr.s_addr = htonl(INADDR_BROADCAST);
891
892         } else if (dhcp->yiaddr != htonl(INADDR_ANY)) {
893                 packet->dst_ipaddr.ipaddr.ip4addr.s_addr = dhcp->yiaddr;
894
895         } else {
896                 /* leave destination IP alone. */
897         }
898
899         /*
900          *      Rewrite the source IP to be our own, if we know it.
901          */
902         if (packet->src_ipaddr.ipaddr.ip4addr.s_addr == htonl(INADDR_BROADCAST)) {
903                 packet->src_ipaddr.ipaddr.ip4addr.s_addr = htonl(INADDR_ANY);
904         }
905
906         if (fr_debug_flag > 1) {
907                 char type_buf[64];
908                 const char *name = type_buf;
909                 char src_ip_buf[256], dst_ip_buf[256];
910                 
911                 if ((packet->code >= PW_DHCP_DISCOVER) &&
912                     (packet->code <= PW_DHCP_INFORM)) {
913                         name = dhcp_message_types[packet->code - PW_DHCP_OFFSET];
914                 } else {
915                         snprintf(type_buf, sizeof(type_buf), "%d",
916                                  packet->code - PW_DHCP_OFFSET);
917                 }
918
919                 printf("Sending %s of id %08x from %s:%d to %s:%d\n",
920                        name, (unsigned int) packet->id,
921                        inet_ntop(packet->src_ipaddr.af,
922                                  &packet->src_ipaddr.ipaddr,
923                                  src_ip_buf, sizeof(src_ip_buf)),
924                        packet->src_port,
925                        inet_ntop(packet->dst_ipaddr.af,
926                                  &packet->dst_ipaddr.ipaddr,
927                                  dst_ip_buf, sizeof(dst_ip_buf)),
928                        packet->dst_port);
929                 fflush(stdout);
930         }
931
932         p = packet->data;
933
934         mms = DEFAULT_PACKET_SIZE; /* maximum message size */
935
936         /*
937          *      Client can request a LARGER size, but not a smaller
938          *      one.  They also cannot request a size larger than MTU.
939          */
940         vp = pairfind(original->vps, DHCP2ATTR(57));
941         if (vp && (vp->vp_integer > mms)) {
942                 mms = vp->vp_integer;
943                 
944                 if (mms > MAX_PACKET_SIZE) mms = MAX_PACKET_SIZE;
945         }
946
947         /*
948          *      RFC 3118: Authentication option.
949          */
950         vp = pairfind(packet->vps, DHCP2ATTR(90));
951         if (vp) {
952                 if (vp->length < 2) {
953                         memset(vp->vp_octets + vp->length, 0,
954                                2 - vp->length);
955                         vp->length = 2;
956                 }
957
958                 if (vp->length < 3) {
959                         struct timeval tv;
960
961                         gettimeofday(&tv, NULL);
962                         vp->vp_octets[2] = 0;
963                         timeval2ntp(&tv, vp->vp_octets + 3);
964                         vp->length = 3 + 8;
965                 }
966
967                 /*
968                  *      Configuration token (clear-text token)
969                  */
970                 if (vp->vp_octets[0] == 0) {
971                         VALUE_PAIR *pass;
972                         vp->vp_octets[1] = 0;
973
974                         pass = pairfind(packet->vps, PW_CLEARTEXT_PASSWORD);
975                         if (pass) {
976                                 length = pass->length;
977                                 if ((length + 11) > sizeof(vp->vp_octets)) {
978                                         length -= ((length + 11) - sizeof(vp->vp_octets));
979                                 }
980                                 memcpy(vp->vp_octets + 11, pass->vp_strvalue,
981                                        length);
982                                 vp->length = length + 11;
983                         } else {
984                                 vp->length = 11 + 8;
985                                 memset(vp->vp_octets + 11, 0, 8);
986                                 vp->length = 11 + 8;
987                         }
988                 } else {        /* we don't support this type! */
989                         fprintf(stderr, "DHCP-Authentication %d unsupported\n",
990                                 vp->vp_octets[0]);
991                 }
992         }
993
994         if (!original) {
995                 *p++ = 1;       /* client message */
996         } else {
997                 *p++ = 2;       /* server message */
998         }
999         *p++ = 1;               /* hardware type = ethernet */
1000         *p++ = original->data[2];
1001         *p++ = 0;               /* hops */
1002
1003         if (!original) {        /* Xid */
1004                 lvalue = fr_rand();
1005                 memcpy(p, &lvalue, 4);
1006         } else {
1007                 memcpy(p, original->data + 4, 4);
1008         }
1009         p += 4;
1010
1011         memset(p, 0, 2);        /* secs are zero */
1012         p += 2;
1013
1014         memcpy(p, original->data + 10, 6); /* copy flags && ciaddr */
1015
1016         /*
1017          *      Allow the admin to set the broadcast flag.
1018          */
1019         vp = pairfind(packet->vps, DHCP2ATTR(262));
1020         if (vp) {
1021                 p[0] |= (vp->vp_integer & 0xff00) >> 8;
1022                 p[1] |= (vp->vp_integer & 0xff);
1023         }
1024
1025         p += 6;
1026
1027         /*
1028          *      Set client IP address.
1029          */
1030         vp = pairfind(packet->vps, DHCP2ATTR(264)); /* Your IP address */
1031         if (vp) {
1032                 lvalue = vp->vp_ipaddr;
1033         } else {
1034                 lvalue = htonl(INADDR_ANY);
1035         }
1036         memcpy(p, &lvalue, 4);  /* your IP address */
1037         p += 4;
1038
1039         vp = pairfind(packet->vps, DHCP2ATTR(265)); /* server IP address */
1040         if (!vp) vp = pairfind(packet->vps, DHCP2ATTR(54)); /* identifier */
1041         if (vp) {
1042                 lvalue = vp->vp_ipaddr;
1043         } else {
1044                 lvalue = htonl(INADDR_ANY);
1045         }
1046         memcpy(p, &lvalue, 4);  /* Server IP address */
1047         p += 4;
1048
1049         memcpy(p, original->data + 24, 4); /* copy gateway IP address */
1050         p += 4;
1051
1052         memcpy(p, original->data + 28, DHCP_CHADDR_LEN);
1053         p += DHCP_CHADDR_LEN;
1054
1055         memset(p, 0, 192);      /* bootp legacy */
1056         p += 192;
1057
1058         lvalue = htonl(DHCP_OPTION_MAGIC_NUMBER); /* DHCP magic number */
1059         memcpy(p, &lvalue, 4);
1060         p += 4;
1061
1062         /*
1063          *      Print the header.
1064          */
1065         if (fr_debug_flag > 1) {
1066                 uint8_t *pp = p;
1067
1068                 p = packet->data;
1069
1070                 for (i = 0; i < 14; i++) {
1071                         vp = pairmake(dhcp_header_names[i], NULL, T_OP_EQ);
1072                         if (!vp) {
1073                                 fprintf(stderr, "Parse error %s\n", fr_strerror());
1074                                 return -1;
1075                         }
1076                         
1077                         switch (vp->type) {
1078                         case PW_TYPE_BYTE:
1079                                 vp->vp_integer = p[0];
1080                                 vp->length = 1;
1081                                 break;
1082                                 
1083                         case PW_TYPE_SHORT:
1084                                 vp->vp_integer = (p[0] << 8) | p[1];
1085                                 vp->length = 2;
1086                                 break;
1087                                 
1088                         case PW_TYPE_INTEGER:
1089                                 memcpy(&vp->vp_integer, p, 4);
1090                                 vp->vp_integer = ntohl(vp->vp_integer);
1091                                 vp->length = 4;
1092                                 break;
1093                                 
1094                         case PW_TYPE_IPADDR:
1095                                 memcpy(&vp->vp_ipaddr, p, 4);
1096                                 vp->length = 4;
1097                                 break;
1098                                 
1099                         case PW_TYPE_STRING:
1100                                 memcpy(vp->vp_strvalue, p, dhcp_header_sizes[i]);
1101                                 vp->vp_strvalue[dhcp_header_sizes[i]] = '\0';
1102                                 vp->length = strlen(vp->vp_strvalue);
1103                                 break;
1104                                 
1105                         case PW_TYPE_OCTETS: /* only for Client HW Address */
1106                                 memcpy(vp->vp_octets, p, packet->data[2]);
1107                                 vp->length = packet->data[2];
1108                                 break;
1109                                 
1110                         case PW_TYPE_ETHERNET: /* only for Client HW Address */
1111                                 memcpy(vp->vp_ether, p, sizeof(vp->vp_ether));
1112                                 vp->length = sizeof(vp->vp_ether);
1113                                 break;
1114                                 
1115                         default:
1116                                 fprintf(stderr, "Internal sanity check failed %d %d\n", vp->type, __LINE__);
1117                                 pairfree(&vp);
1118                                 break;
1119                         }
1120                         
1121                         p += dhcp_header_sizes[i];
1122                         
1123                         vp_prints(buffer, sizeof(buffer), vp);
1124                         fprintf(stderr, "\t%s\n", buffer);
1125                         pairfree(&vp);
1126                 }
1127
1128                 /*
1129                  *      Jump over DHCP magic number, response, etc.
1130                  */
1131                 p = pp;
1132         }
1133
1134         /*
1135          *      Before packing the attributes, re-order them so that
1136          *      the array ones are all contiguous.  This simplifies
1137          *      the later code.
1138          */
1139         num_vps = 0;
1140         for (vp = packet->vps; vp != NULL; vp = vp->next) {
1141                 num_vps++;
1142         }
1143         if (num_vps > 1) {
1144                 VALUE_PAIR **array, **last;
1145
1146                 array = malloc(num_vps * sizeof(VALUE_PAIR *));
1147                 
1148                 i = 0;
1149                 for (vp = packet->vps; vp != NULL; vp = vp->next) {
1150                         array[i++] = vp;
1151                 }
1152                 
1153                 /*
1154                  *      Sort the attributes.
1155                  */
1156                 qsort(array, (size_t) num_vps, sizeof(VALUE_PAIR *),
1157                       attr_cmp);
1158                 
1159                 last = &packet->vps;
1160                 for (i = 0; i < num_vps; i++) {
1161                         *last = array[i];
1162                         array[i]->next = NULL;
1163                         last = &(array[i]->next);
1164                 }
1165                 free(array);
1166         }
1167
1168         p[0] = 0x35;            /* DHCP-Message-Type */
1169         p[1] = 1;
1170         p[2] = packet->code - PW_DHCP_OFFSET;
1171         p += 3;
1172
1173         /*
1174          *      Pack in the attributes.
1175          */
1176         vp = packet->vps;
1177         while (vp) {
1178                 int num_entries = 1;
1179                 
1180                 VALUE_PAIR *same;
1181                 uint8_t *plength, *pattr;
1182
1183                 if (!IS_DHCP_ATTR(vp)) goto next;
1184                 if (vp->attribute == DHCP2ATTR(53)) goto next; /* already done */
1185                 if (((vp->attribute & 0xffff) > 255) &&
1186                     (DHCP_BASE_ATTR(vp->attribute) != PW_DHCP_OPTION_82)) goto next;
1187
1188                 length = vp->length;
1189
1190                 for (same = vp->next; same != NULL; same = same->next) {
1191                         if (same->attribute != vp->attribute) break;
1192                         num_entries++;
1193                 }
1194
1195                 /*
1196                  *      For client-identifier
1197                  */
1198                 if ((vp->type == PW_TYPE_ETHERNET) &&
1199                     (vp->length == 6) &&
1200                     (num_entries == 1)) {
1201                         vp->type = PW_TYPE_OCTETS;
1202                         memmove(vp->vp_octets + 1, vp->vp_octets, 6);
1203                         vp->vp_octets[0] = 1;
1204                 }
1205
1206                 pattr = p;
1207                 *(p++) = vp->attribute & 0xff;
1208                 plength = p;
1209                 *(p++) = 0;     /* header isn't included in attr length */
1210
1211                 for (i = 0; i < num_entries; i++) {
1212                         if (fr_debug_flag > 1) {
1213                                 vp_prints(buffer, sizeof(buffer), vp);
1214                                 fprintf(stderr, "\t%s\n", buffer);
1215                         }
1216
1217                         length = fr_dhcp_vp2attr(vp, p, 0);
1218
1219                         /*
1220                          *      This will never happen due to FreeRADIUS
1221                          *      limitations: sizeof(vp->vp_octets) < 255
1222                          */
1223                         if (length > 255) {
1224                                 fprintf(stderr, "WARNING Ignoring too long attribute %s!\n", vp->name);
1225                                 break;
1226                         }
1227
1228                         /*
1229                          *      More than one attribute of the same type
1230                          *      in a row: they are packed together
1231                          *      into the same TLV.  If we overflow,
1232                          *      go bananas!
1233                          */
1234                         if ((*plength + length) > 255) {
1235                                 fprintf(stderr, "WARNING Ignoring too long attribute %s!\n", vp->name);
1236                                 break;
1237                         }
1238                         
1239                         *plength += length;
1240                         p += length;
1241
1242                         if (vp->next &&
1243                             (vp->next->attribute == vp->attribute))
1244                                 vp = vp->next;
1245                 } /* loop over num_entries */
1246
1247                 if (DHCP_BASE_ATTR(vp->attribute) == PW_DHCP_OPTION_82) {
1248                         plength[2] = plength[0] - 2;
1249                 }
1250
1251         next:
1252                 vp = vp->next;
1253         }
1254
1255         p[0] = 0xff;            /* end of option option */
1256         p[1] = 0x00;
1257         p += 2;
1258         dhcp_size = p - packet->data;
1259
1260         /*
1261          *      FIXME: if (dhcp_size > mms),
1262          *        then we put the extra options into the "sname" and "file"
1263          *        fields, AND set the "end option option" in the "options"
1264          *        field.  We also set the "overload option",
1265          *        and put options into the "file" field, followed by
1266          *        the "sname" field.  Where each option is completely
1267          *        enclosed in the "file" and/or "sname" field, AND
1268          *        followed by the "end of option", and MUST be followed
1269          *        by padding option.
1270          *
1271          *      Yuck.  That sucks...
1272          */
1273         packet->data_len = dhcp_size;
1274
1275         /*
1276          *      FIXME: This may set it to broadcast, which we don't
1277          *      want.  Instead, set it to the real address of the
1278          *      socket.
1279          */
1280         packet->src_ipaddr = original->dst_ipaddr;
1281
1282         packet->sockfd = original->sockfd;
1283
1284         if (packet->data_len < DEFAULT_PACKET_SIZE) {
1285                 memset(packet->data + packet->data_len, 0,
1286                        DEFAULT_PACKET_SIZE - packet->data_len);
1287                 packet->data_len = DEFAULT_PACKET_SIZE;
1288         }
1289
1290         if ((fr_debug_flag > 2) && fr_log_fp) {
1291                 for (i = 0; i < packet->data_len; i++) {
1292                         if ((i & 0x0f) == 0x00) fprintf(fr_log_fp, "%d: ", i);
1293                         fprintf(fr_log_fp, "%02x ", packet->data[i]);
1294                         if ((i & 0x0f) == 0x0f) fprintf(fr_log_fp, "\n");
1295                 }
1296                 fprintf(fr_log_fp, "\n");
1297         }
1298
1299         return 0;
1300 }
1301 #endif /* WITH_DHCP */