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