Fix logic for using udpfromto
[freeradius.git] / src / lib / vqp.c
1 /*
2  * vqp.c        Functions to send/receive VQP packets.
3  *
4  * Version:     $Id$
5  *
6  *   This library is free software; you can redistribute it and/or
7  *   modify it under the terms of the GNU Lesser General Public
8  *   License as published by the Free Software Foundation; either
9  *   version 2.1 of the License, or (at your option) any later version.
10  *
11  *   This library 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 GNU
14  *   Lesser General Public License for more details.
15  *
16  *   You should have received a copy of the GNU Lesser General Public
17  *   License along with this library; if not, write to the Free Software
18  *   Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
19  *
20  * Copyright 2007 Alan DeKok <aland@deployingradius.com>
21  */
22
23 #include        <freeradius-devel/ident.h>
24 RCSID("$Id$");
25
26 #include        <freeradius-devel/libradius.h>
27 #include        <freeradius-devel/udpfromto.h>
28 #include        <freeradius-devel/vqp.h>
29
30 #ifdef WITH_VMPS
31
32 #define MAX_VMPS_LEN (MAX_STRING_LEN - 1)
33
34 /*
35  *  http://www.openbsd.org/cgi-bin/cvsweb/src/usr.sbin/tcpdump/print-vqp.c
36  *
37  *  Some of how it works:
38  *
39  *  http://www.hackingciscoexposed.com/pdf/chapter12.pdf
40  *
41  * VLAN Query Protocol (VQP)
42  *
43  *    0                   1                   2                   3
44  *    0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
45  *   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
46  *   |    Version    |    Opcode     | Response Code |  Data Count   |
47  *   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
48  *   |                         Transaction ID                        |
49  *   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
50  *   |                            Type (1)                           |
51  *   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
52  *   |             Length            |            Data               /
53  *   /                                                               /
54  *   /                                                               /
55  *   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
56  *   |                            Type (n)                           |
57  *   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
58  *   |             Length            |            Data               /
59  *   /                                                               /
60  *   /                                                               /
61  *   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
62  *
63  * VQP is layered over UDP.  The default destination port is 1589.
64  *
65  */
66 #define VQP_HDR_LEN (8)
67 #define VQP_VERSION (1)
68 #define VQP_MAX_ATTRIBUTES (12)
69
70
71 /*
72  *      Wrapper for sendto which handles sendfromto, IPv6, and all
73  *      possible combinations.
74  *
75  *      FIXME:  This is just a copy of rad_sendto().
76  *      Duplicate code is bad.
77  */
78 static int vqp_sendto(int sockfd, void *data, size_t data_len, int flags,
79                       fr_ipaddr_t *src_ipaddr, fr_ipaddr_t *dst_ipaddr,
80                       int dst_port)
81 {
82         struct sockaddr_storage dst;
83         socklen_t               sizeof_dst;
84
85 #ifdef WITH_UDPFROMTO
86         struct sockaddr_storage src;
87         socklen_t               sizeof_src;
88
89         fr_ipaddr2sockaddr(src_ipaddr, 0, &src, &sizeof_src);
90 #else
91         src_ipaddr = src_ipaddr; /* -Wunused */
92 #endif
93
94         if (!fr_ipaddr2sockaddr(dst_ipaddr, dst_port, &dst, &sizeof_dst)) {
95                 return -1;   /* Unknown address family, Die Die Die! */
96         }
97
98 #ifdef WITH_UDPFROMTO
99         /*
100          *      Only IPv4 is supported for udpfromto.
101          *
102          *      And if they don't specify a source IP address, don't
103          *      use udpfromto.
104          */
105         if ((dst_ipaddr->af == AF_INET) &&
106             (src_ipaddr->af != AF_UNSPEC)) {
107                 return sendfromto(sockfd, data, data_len, flags,
108                                   (struct sockaddr *)&src, sizeof_src, 
109                                   (struct sockaddr *)&dst, sizeof_dst);
110         }
111 #else
112         src_ipaddr = src_ipaddr; /* -Wunused */
113 #endif
114
115         /*
116          *      No udpfromto, OR an IPv6 socket, fail gracefully.
117          */
118         return sendto(sockfd, data, data_len, flags, 
119                       (struct sockaddr *)&dst, sizeof_dst);
120 }
121
122 /*
123  *      Wrapper for recvfrom, which handles recvfromto, IPv6, and all
124  *      possible combinations.
125  *
126  *      FIXME:  This is copied from rad_recvfrom, with minor edits.
127  */
128 static ssize_t vqp_recvfrom(int sockfd, uint8_t **pbuf, int flags,
129                             fr_ipaddr_t *src_ipaddr, uint16_t *src_port,
130                             fr_ipaddr_t *dst_ipaddr, uint16_t *dst_port)
131 {
132         struct sockaddr_storage src;
133         struct sockaddr_storage dst;
134         socklen_t               sizeof_src = sizeof(src);
135         socklen_t               sizeof_dst = sizeof(dst);
136         ssize_t                 data_len;
137         uint8_t                 header[4];
138         void                    *buf;
139         size_t                  len;
140         int                     port;
141
142         memset(&src, 0, sizeof_src);
143         memset(&dst, 0, sizeof_dst);
144
145         /*
146          *      Get address family, etc. first, so we know if we
147          *      need to do udpfromto.
148          *
149          *      FIXME: udpfromto also does this, but it's not
150          *      a critical problem.
151          */
152         if (getsockname(sockfd, (struct sockaddr *)&dst,
153                         &sizeof_dst) < 0) return -1;
154
155         /*
156          *      Read the length of the packet, from the packet.
157          *      This lets us allocate the buffer to use for
158          *      reading the rest of the packet.
159          */
160         data_len = recvfrom(sockfd, header, sizeof(header), MSG_PEEK,
161                             (struct sockaddr *)&src, &sizeof_src);
162         if (data_len < 0) return -1;
163
164         /*
165          *      Too little data is available, discard the packet.
166          */
167         if (data_len < 4) {
168                 recvfrom(sockfd, header, sizeof(header), flags, 
169                          (struct sockaddr *)&src, &sizeof_src);
170                 return 0;
171
172                 /*
173                  *      Invalid version, packet type, or too many
174                  *      attributes.  Die.
175                  */
176         } else if ((header[0] != VQP_VERSION) ||
177                    (header[1] < 1) ||
178                    (header[1] > 4) ||
179                    (header[3] > VQP_MAX_ATTRIBUTES)) {
180                 recvfrom(sockfd, header, sizeof(header), flags,
181                          (struct sockaddr *)&src, &sizeof_src);
182                 return 0;
183
184         } else {                /* we got 4 bytes of data. */
185                 /*
186                  *      We don't care about the contents for now...
187                  */
188 #if 0
189                 /*
190                  *      How many attributes are in the packet.
191                  */
192                 len = header[3];
193
194                 if ((header[1] == 1) || (header[1] == 3)) {
195                         if (len != VQP_MAX_ATTRIBUTES) {
196                                 recvfrom(sockfd, header, sizeof(header), 0,
197                                          (struct sockaddr *)&src, &sizeof_src);
198                                 return 0;
199                         }
200                         /*
201                          *      Maximum length we support.
202                          */
203                         len = (12 * (4 + 4 + MAX_VMPS_LEN));
204
205                 } else {
206                         if (len != 2) {
207                                 recvfrom(sockfd, header, sizeof(header), 0, 
208                                  (struct sockaddr *)&src, &sizeof_src);
209                                 return 0;
210                         }
211                         /*
212                          *      Maximum length we support.
213                          */
214                         len = (12 * (4 + 4 + MAX_VMPS_LEN));
215                 }
216 #endif
217         }
218
219         /*
220          *      For now, be generous.
221          */
222         len = (12 * (4 + 4 + MAX_VMPS_LEN));
223
224         buf = malloc(len);
225         if (!buf) return -1;
226
227         /*
228          *      Receive the packet.  The OS will discard any data in the
229          *      packet after "len" bytes.
230          */
231 #ifdef WITH_UDPFROMTO
232         if (dst.ss_family == AF_INET) {
233                 data_len = recvfromto(sockfd, buf, len, flags,
234                                       (struct sockaddr *)&src, &sizeof_src, 
235                                       (struct sockaddr *)&dst, &sizeof_dst);
236         } else
237 #endif
238                 /*
239                  *      No udpfromto, OR an IPv6 socket.  Fail gracefully.
240                  */
241                 data_len = recvfrom(sockfd, buf, len, flags, 
242                                     (struct sockaddr *)&src, &sizeof_src);
243         if (data_len < 0) {
244                 free(buf);
245                 return data_len;
246         }
247
248         if (!fr_sockaddr2ipaddr(&src, sizeof_src, src_ipaddr, &port)) {
249                 free(buf);
250                 return -1;      /* Unknown address family, Die Die Die! */
251         }
252         *src_port = port;
253
254         fr_sockaddr2ipaddr(&dst, sizeof_dst, dst_ipaddr, &port);
255         *dst_port = port;
256
257         /*
258          *      Different address families should never happen.
259          */
260         if (src.ss_family != dst.ss_family) {
261                 free(buf);
262                 return -1;
263         }
264
265         /*
266          *      Tell the caller about the data
267          */
268         *pbuf = buf;
269
270         return data_len;
271 }
272
273 RADIUS_PACKET *vqp_recv(int sockfd)
274 {
275         uint8_t *ptr;
276         ssize_t length;
277         uint32_t id;
278         RADIUS_PACKET *packet;
279
280         /*
281          *      Allocate the new request data structure
282          */
283         if ((packet = malloc(sizeof(*packet))) == NULL) {
284                 fr_strerror_printf("out of memory");
285                 return NULL;
286         }
287         memset(packet, 0, sizeof(*packet));
288
289         packet->data_len = vqp_recvfrom(sockfd, &packet->data, 0,
290                                         &packet->src_ipaddr, &packet->src_port,
291                                         &packet->dst_ipaddr, &packet->dst_port);
292
293         /*
294          *      Check for socket errors.
295          */
296         if (packet->data_len < 0) {
297                 fr_strerror_printf("Error receiving packet: %s", strerror(errno));
298                 /* packet->data is NULL */
299                 free(packet);
300                 return NULL;
301         }
302
303
304         /*
305          *      We can only receive packets formatted in a way we
306          *      expect.  However, we accept MORE attributes in a
307          *      packet than normal implementations may send.
308          */
309         if (packet->data_len < VQP_HDR_LEN) {
310                 fr_strerror_printf("VQP packet is too short");
311                 rad_free(&packet);
312                 return NULL;
313         }
314
315         ptr = packet->data;
316
317         if (0) {
318                 int i;
319                 for (i = 0; i < packet->data_len; i++) {
320                         if ((i & 0x0f) == 0) fprintf(stderr, "%02x: ", i);
321                         fprintf(stderr, "%02x ", ptr[i]);
322                         if ((i & 0x0f) == 0x0f) fprintf(stderr, "\n");
323                 }
324           
325         }
326
327         if (ptr[3] > VQP_MAX_ATTRIBUTES) {
328                 fr_strerror_printf("Too many VQP attributes");
329                 rad_free(&packet);
330                 return NULL;
331         }
332
333         if (packet->data_len > VQP_HDR_LEN) {
334                 int attrlen;
335
336                 /*
337                  *      Skip the header.
338                  */
339                 ptr += VQP_HDR_LEN;
340                 length = packet->data_len - VQP_HDR_LEN;
341
342                 while (length > 0) {
343                         if (length < 7) {
344                                 fr_strerror_printf("Packet contains malformed attribute");
345                                 rad_free(&packet);
346                                 return NULL;
347                         }
348
349                         /*
350                          *      Attributes are 4 bytes
351                          *      0x00000c01 ... 0x00000c08
352                          */
353                         if ((ptr[0] != 0) || (ptr[1] != 0) ||
354                             (ptr[2] != 0x0c) || (ptr[3] < 1) || (ptr[3] > 8)) {
355                                 fr_strerror_printf("Packet contains invalid attribute");
356                                 rad_free(&packet);
357                                 return NULL;
358                         }
359
360                         /*
361                          *      Length is 2 bytes
362                          *
363                          *      We support lengths 1..253, for internal
364                          *      server reasons.  Also, there's no reason
365                          *      for bigger lengths to exist... admins
366                          *      won't be typing in a 32K vlan name.
367                          *
368                          *      Except for received ethernet frames...
369                          *      they get chopped to 253 internally.
370                          */
371                         if ((ptr[3] != 5) &&
372                             ((ptr[4] != 0) || (ptr[5] > MAX_VMPS_LEN))) {
373                                 fr_strerror_printf("Packet contains attribute with invalid length %02x %02x", ptr[4], ptr[5]);
374                                 rad_free(&packet);
375                                 return NULL;
376                         }
377                         attrlen = (ptr[4] << 8) | ptr[5];
378                         ptr += 6 + attrlen;
379                         length -= (6 + attrlen);
380                 }
381         }
382
383         packet->sockfd = sockfd;
384         packet->vps = NULL;
385
386         /*
387          *      This is more than a bit of a hack.
388          */
389         packet->code = PW_AUTHENTICATION_REQUEST;
390
391         memcpy(&id, packet->data + 4, 4);
392         packet->id = ntohl(id);
393
394         /*
395          *      FIXME: Create a fake "request authenticator", to
396          *      avoid duplicates?  Or is the VQP sequence number
397          *      adequate for this purpose?
398          */
399
400         return packet;
401 }
402
403 /*
404  *      We do NOT  mirror the old-style RADIUS code  that does encode,
405  *      sign && send in one function.  For VQP, the caller MUST perform
406  *      each task manually, and separately.
407  */
408 int vqp_send(RADIUS_PACKET *packet)
409 {
410         if (!packet || !packet->data || (packet->data_len < 8)) return -1;
411
412         /*
413          *      Don't print out the attributes, they were printed out
414          *      when it was encoded.
415          */
416
417         /*
418          *      And send it on it's way.
419          */
420         return vqp_sendto(packet->sockfd, packet->data, packet->data_len, 0,
421                           &packet->src_ipaddr, &packet->dst_ipaddr,
422                           packet->dst_port);
423 }
424
425
426 int vqp_decode(RADIUS_PACKET *packet)
427 {
428         uint8_t *ptr, *end;
429         int attribute, length;
430         VALUE_PAIR *vp, **tail;
431
432         if (!packet || !packet->data) return -1;
433
434         if (packet->data_len < VQP_HDR_LEN) return -1;
435
436         tail = &packet->vps;
437
438         vp = paircreate(PW_VQP_PACKET_TYPE, 0, PW_TYPE_OCTETS);
439         if (!vp) {
440                 fr_strerror_printf("No memory");
441                 return -1;
442         }
443         vp->lvalue = packet->data[1];
444         debug_pair(vp);
445
446         *tail = vp;
447         tail = &(vp->next);
448
449         vp = paircreate(PW_VQP_ERROR_CODE, 0, PW_TYPE_OCTETS);
450         if (!vp) {
451                 fr_strerror_printf("No memory");
452                 return -1;
453         }
454         vp->lvalue = packet->data[2];
455         debug_pair(vp);
456
457         *tail = vp;
458         tail = &(vp->next);
459
460         vp = paircreate(PW_VQP_SEQUENCE_NUMBER, 0, PW_TYPE_OCTETS);
461         if (!vp) {
462                 fr_strerror_printf("No memory");
463                 return -1;
464         }
465         vp->lvalue = packet->id; /* already set by vqp_recv */
466         debug_pair(vp);
467
468         *tail = vp;
469         tail = &(vp->next);
470
471         ptr = packet->data + VQP_HDR_LEN;
472         end = packet->data + packet->data_len;
473
474         /*
475          *      Note that vqp_recv() MUST ensure that the packet is
476          *      formatted in a way we expect, and that vqp_recv() MUST
477          *      be called before vqp_decode().
478          */
479         while (ptr < end) {
480                 attribute = (ptr[2] << 8) | ptr[3];
481                 length = (ptr[4] << 8) | ptr[5];
482                 ptr += 6;
483
484                 /*
485                  *      Hack to get the dictionaries to work correctly.
486                  */
487                 attribute |= 0x2000;
488                 vp = paircreate(attribute, 0, PW_TYPE_OCTETS);
489                 if (!vp) {
490                         pairfree(&packet->vps);
491
492                         fr_strerror_printf("No memory");
493                         return -1;
494                 }
495
496                 switch (vp->type) {
497                 case PW_TYPE_IPADDR:
498                         if (length == 4) {
499                                 memcpy(&vp->vp_ipaddr, ptr, 4);
500                                 vp->length = 4;
501                                 break;
502                         }
503                         vp->type = PW_TYPE_OCTETS;
504                         /* FALL-THROUGH */
505
506                 default:
507                 case PW_TYPE_OCTETS:
508                 case PW_TYPE_STRING:
509                         vp->length = (length > MAX_VMPS_LEN) ? MAX_VMPS_LEN : length;
510                         memcpy(vp->vp_octets, ptr, vp->length);
511                         vp->vp_octets[vp->length] = '\0';
512                         break;
513                 }
514                 ptr += length;
515                 debug_pair(vp);
516
517                 *tail = vp;
518                 tail = &(vp->next);
519         }
520
521         /*
522          *      FIXME: Map attributes to Calling-Station-Id, etc...
523          */
524
525         return 0;
526 }
527
528 /*
529  *      These are the MUST HAVE contents for a VQP packet.
530  *
531  *      We don't allow the caller to give less than these, because
532  *      it won't work.  We don't encode more than these, because the
533  *      clients will ignore it.
534  *
535  *      FIXME: Be more generous?  Look for CISCO + VQP attributes?
536  */
537 static int contents[5][VQP_MAX_ATTRIBUTES] = {
538         { 0,      0,      0,      0,      0,      0 },
539         { 0x0c01, 0x0c02, 0x0c03, 0x0c04, 0x0c07, 0x0c05 }, /* Join request */
540         { 0x0c03, 0x0c08, 0,      0,      0,      0 },  /* Join Response */
541         { 0x0c01, 0x0c02, 0x0c03, 0x0c04, 0x0c07, 0x0c08 }, /* Reconfirm */
542         { 0x0c03, 0x0c08, 0,      0,      0,      0 }
543 };
544
545 int vqp_encode(RADIUS_PACKET *packet, RADIUS_PACKET *original)
546 {
547         int i, code, length;
548         VALUE_PAIR *vp;
549         uint8_t *ptr;
550         VALUE_PAIR      *vps[VQP_MAX_ATTRIBUTES];
551
552         if (!packet) {
553                 fr_strerror_printf("Failed encoding VQP");
554                 return -1;
555         }
556
557         if (packet->data) return 0;
558
559         vp = pairfind(packet->vps, PW_VQP_PACKET_TYPE, 0);
560         if (!vp) {
561                 fr_strerror_printf("Failed to find VQP-Packet-Type in response packet");
562                 return -1;
563         }
564
565         code = vp->lvalue;
566         if ((code < 1) || (code > 4)) {
567                 fr_strerror_printf("Invalid value %d for VQP-Packet-Type", code);
568                 return -1;
569         }
570
571         length = VQP_HDR_LEN;
572         memset(vps, 0, sizeof(vps));
573
574         vp = pairfind(packet->vps, PW_VQP_ERROR_CODE, 0);
575
576         /*
577          *      FIXME: Map attributes from calling-station-Id, etc.
578          *
579          *      Maybe do this via rlm_vqp?  That's probably the
580          *      best place to add the code...
581          */
582
583         /*
584          *      No error: encode attributes.
585          */
586         if (!vp) for (i = 0; i < VQP_MAX_ATTRIBUTES; i++) {
587                 if (!contents[code][i]) break;
588
589                 vps[i] = pairfind(packet->vps, contents[code][i] | 0x2000, 0);
590
591                 /*
592                  *      FIXME: Print the name...
593                  */
594                 if (!vps[i]) {
595                         fr_strerror_printf("Failed to find VQP attribute %02x",
596                                    contents[code][i]);
597                         return -1;
598                 }
599
600                 length += 6;
601                 length += vps[i]->length;
602         }
603
604         packet->data = malloc(length);
605         if (!packet->data) {
606                 fr_strerror_printf("No memory");
607                 return -1;
608         }
609         packet->data_len = length;
610
611         ptr = packet->data;
612
613         ptr[0] = VQP_VERSION;
614         ptr[1] = code;
615
616         if (!vp) {
617                 ptr[2] = 0;
618         } else {
619                 ptr[2] = vp->lvalue & 0xff;
620                 return 0;
621         }
622
623         /*
624          *      The number of attributes is hard-coded.
625          */
626         if ((code == 1) || (code == 3)) {
627                 uint32_t sequence;
628
629                 ptr[3] = VQP_MAX_ATTRIBUTES;
630
631                 sequence = htonl(packet->id);
632                 memcpy(ptr + 4, &sequence, 4);
633         } else {
634                 if (!original) {
635                         fr_strerror_printf("Cannot send VQP response without request");
636                         return -1;
637                 }
638
639                 /*
640                  *      Packet Sequence Number
641                  */
642                 memcpy(ptr + 4, original->data + 4, 4);
643
644                 ptr[3] = 2;
645         }
646
647         ptr += 8;
648
649         /*
650          *      Encode the VP's.
651          */
652         for (i = 0; i < VQP_MAX_ATTRIBUTES; i++) {
653                 if (!vps[i]) break;
654                 vp = vps[i];
655
656                 debug_pair(vp);
657
658                 /*
659                  *      Type.  Note that we look at only the lower 8
660                  *      bits, as the upper 8 bits have been hacked.
661                  *      See also dictionary.vqp
662                  */
663                 ptr[0] = 0;
664                 ptr[1] = 0;
665                 ptr[2] = 0x0c;
666                 ptr[3] = vp->attribute & 0xff;
667
668                 /* Length */
669                 ptr[4] = 0;
670                 ptr[5] = vp->length & 0xff;
671
672                 ptr += 6;
673
674                 /* Data */
675                 switch (vp->type) {
676                 case PW_TYPE_IPADDR:
677                         memcpy(ptr, &vp->vp_ipaddr, 4);
678                         break;
679
680                 default:
681                 case PW_TYPE_OCTETS:
682                 case PW_TYPE_STRING:
683                         memcpy(ptr, vp->vp_octets, vp->length);
684                         break;
685                 }
686                 ptr += vp->length;
687         }
688
689         return 0;
690 }
691 #endif