]> git.ipfire.org Git - thirdparty/freeradius-server.git/commitdiff
Add support for arbitrary test points in unit_test_attribute
authorArran Cudbard-Bell <a.cudbardb@freeradius.org>
Fri, 1 Dec 2017 00:42:06 +0000 (00:42 +0000)
committerArran Cudbard-Bell <a.cudbardb@freeradius.org>
Fri, 1 Dec 2017 00:49:19 +0000 (00:49 +0000)
src/lib/io/pair.h [new file with mode: 0644]
src/lib/io/proto.h
src/lib/io/test_point.h [new file with mode: 0644]
src/main/unit_test_attribute.c
src/tests/unit/ethernet.txt

diff --git a/src/lib/io/pair.h b/src/lib/io/pair.h
new file mode 100644 (file)
index 0000000..dccc11b
--- /dev/null
@@ -0,0 +1,36 @@
+/*
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
+ */
+#ifndef _FR_IO_PAIR_H
+#define _FR_IO_PAIR_H
+
+#include <freeradius-devel/value.h>
+
+/**
+ * $Id$
+ *
+ * @file io/pair.h
+ * @brief Encoder/decoder library interface
+ *
+ * @copyright 2017 The FreeRADIUS project
+ */
+
+typedef ssize_t (*fr_pair_encode_t)(uint8_t *out, size_t outlen, vp_cursor_t *cursor, void *encoder_ctx);
+
+typedef ssize_t (*fr_pair_decode_t)(TALLOC_CTX *ctx, vp_cursor_t *cursor,
+                                   uint8_t const *data, size_t data_len, void *decoder_ctx);
+
+#endif /* _FR_IO_PAIR_H */
+
index 97145caa143c981759a22084b548963c4f650353..3fef9c36970b973b78618af04e5bac9836de6fbb 100644 (file)
@@ -13,8 +13,8 @@
  *  along with this program; if not, write to the Free Software
  *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
  */
-#ifndef _FR_APPLICATION_H
-#define _FR_APPLICATION_H
+#ifndef _FR_IO_PROTO_H
+#define _FR_IO_PROTO_H
 
 #include <freeradius-devel/dl.h>
 #include <freeradius-devel/value.h>
@@ -109,9 +109,9 @@ typedef ssize_t (*fr_proto_decode_t)(void *proto_ctx, uint8_t const *data, size_
  * know anything about how the data will be used (e.g. reject delay
  * on Access-Reject)
  *
- * @param[in] proto_ctx        as created by #fr_proto_decode_t.
- * @param[out] buffer          the buffer where the raw packet will be written
- * @param[in] buffer_len       the length of the buffer
+ * @param[in] proto_ctx                as created by #fr_proto_decode_t.
+ * @param[out] buffer          the buffer where the raw packet will be written.
+ * @param[in] buffer_len       the length of the buffer.
  * @return
  *     - <0 on error.  May indicate the number of bytes (as a negative) offset,
  *       that would have been needed to encode the total packet data.
@@ -188,5 +188,5 @@ typedef struct {
        fr_proto_stack_frame_t  frame[FR_PROTO_STACK_MAX + 1];
        int                     depth;
 } fr_proto_stack_t;
-#endif /* _FR_APPLICATION_H */
+#endif /* _FR_IO_PROTO_H */
 
diff --git a/src/lib/io/test_point.h b/src/lib/io/test_point.h
new file mode 100644 (file)
index 0000000..6eaef69
--- /dev/null
@@ -0,0 +1,60 @@
+/*
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
+ */
+#ifndef _FR_TEST_POINT_H
+#define _FR_TEST_POINT_H
+
+#include "proto.h"
+#include "pair.h"
+
+/** Allocate an encoder/decoder ctx
+ *
+ * @param[in] ctx      to allocate the test point context in.
+ * @return proto or pair encoder or decoder ctx.
+ */
+typedef void *(*fr_test_point_ctx_alloc_t)(TALLOC_CTX *ctx);
+
+/** Entry point for protocol decoders
+ *
+ */
+typedef struct {
+       fr_test_point_ctx_alloc_t       test_ctx;       //!< Allocate a test ctx for the encoder.
+       fr_proto_decode_t               func;           //!< Decoder for proto layer.
+} fr_test_point_proto_decode_t;
+
+/** Entry point for protocol encoders
+ *
+ */
+typedef struct {
+       fr_test_point_ctx_alloc_t       test_ctx;       //!< Allocate a test ctx for the encoder.
+       fr_proto_encode_t               func;           //!< Encoder for proto layer.
+} fr_test_point_proto_encode_t;
+
+/** Entry point for pair decoders
+ *
+ */
+typedef struct {
+       fr_test_point_ctx_alloc_t       test_ctx;       //!< Allocate a test ctx for the encoder.
+       fr_pair_decode_t                func;           //!< Decoder for pairs.
+} fr_test_point_pair_decode_t;
+
+/** Entry point for pair encoders
+ *
+ */
+typedef struct {
+       fr_test_point_ctx_alloc_t       test_ctx;       //!< Allocate a test ctx for the encoder.
+       fr_pair_encode_t                func;           //!< Encoder for pairs.
+} fr_test_point_pair_encode_t;
+#endif /* _FR_TEST_POINT_H */
index 3d1d86bebab999b61326d9a5b74dc60d66889e60..c00e1121553ed8f23bb7745be0e62f94be58ca3d 100644 (file)
@@ -35,7 +35,8 @@ typedef struct REQUEST REQUEST;
 #include <freeradius-devel/radpaths.h>
 #include <freeradius-devel/dhcpv4/dhcpv4.h>
 #include <freeradius-devel/cf_parse.h>
-#include <freeradius-devel/io/proto.h>
+#include <freeradius-devel/dl.h>
+#include <freeradius-devel/io/test_point.h>
 
 #ifdef WITH_TACACS
 #include "../modules/proto_tacacs/tacacs.h"
@@ -84,7 +85,7 @@ static RADIUS_PACKET my_packet = {
 static char *my_secret = NULL;
 
 static char proto_name_prev[128];
-static void *dl_handle, *dl_symbol;
+static void *dl_handle;
 
 /*
  *     End of hacks for xlat
@@ -531,20 +532,20 @@ static int encode_rfc(char *buffer, uint8_t *output, size_t outlen)
 
 static void parse_condition(char const *input, char *output, size_t outlen)
 {
-       ssize_t slen;
+       ssize_t dec_len;
        char const *error = NULL;
        fr_cond_t *cond;
 
-       slen = fr_cond_tokenize(NULL, NULL, input, &cond, &error, FR_COND_ONE_PASS);
-       if (slen <= 0) {
-               snprintf(output, outlen, "ERROR offset %d %s", (int) -slen, error);
+       dec_len = fr_cond_tokenize(NULL, NULL, input, &cond, &error, FR_COND_ONE_PASS);
+       if (dec_len <= 0) {
+               snprintf(output, outlen, "ERROR offset %d %s", (int) -dec_len, error);
                return;
        }
 
-       input += slen;
+       input += dec_len;
        if (*input != '\0') {
                talloc_free(cond);
-               snprintf(output, outlen, "ERROR offset %d 'Too much text'", (int) slen);
+               snprintf(output, outlen, "ERROR offset %d 'Too much text'", (int) dec_len);
                return;
        }
 
@@ -555,19 +556,19 @@ static void parse_condition(char const *input, char *output, size_t outlen)
 
 static void parse_xlat(char const *input, char *output, size_t outlen)
 {
-       ssize_t slen;
+       ssize_t dec_len;
        char const *error = NULL;
        char *fmt = talloc_typed_strdup(NULL, input);
        xlat_exp_t *head;
 
-       slen = xlat_tokenize(fmt, fmt, &head, &error);
-       if (slen <= 0) {
-               snprintf(output, outlen, "ERROR offset %d '%s'", (int) -slen, error);
+       dec_len = xlat_tokenize(fmt, fmt, &head, &error);
+       if (dec_len <= 0) {
+               snprintf(output, outlen, "ERROR offset %d '%s'", (int) -dec_len, error);
                return;
        }
 
-       if (input[slen] != '\0') {
-               snprintf(output, outlen, "ERROR offset %d 'Too much text'", (int) slen);
+       if (input[dec_len] != '\0') {
+               snprintf(output, outlen, "ERROR offset %d 'Too much text'", (int) dec_len);
                return;
        }
 
@@ -575,55 +576,77 @@ static void parse_xlat(char const *input, char *output, size_t outlen)
        talloc_free(fmt);
 }
 
-static int load_proto_library(void **handle, void **symbol, char *proto_name)
+static void unload_proto_library(void)
 {
-       char dl_name[128];
-       char *p;
-
-       if (strcmp(proto_name_prev, proto_name) == 0) {
-               if (handle) *handle = dl_handle;
-               if (symbol) *symbol = dl_symbol;
-               return 0;
-       }
-
-       snprintf(dl_name, sizeof(dl_name), "libfreeradius-%s", proto_name);
        if (dl_handle) {
                dlclose(dl_handle);
                dl_handle = NULL;
        }
+}
+
+static size_t load_proto_library(char const *proto_name)
+{
+       char dl_name[128];
+
+       if (strcmp(proto_name_prev, proto_name) != 0) {
+               /*
+                *      Ensure the old proto library is unloaded
+                */
+               unload_proto_library();
+
+               snprintf(dl_name, sizeof(dl_name), "libfreeradius-%s", proto_name);
+               if (dl_handle) {
+                       dlclose(dl_handle);
+                       dl_handle = NULL;
+               }
+
+               dl_handle = dl_by_name(dl_name);
+               if (!dl_handle) {
+                       fprintf(stderr, "Failed to link to library \"%s\": %s\n", dl_name, fr_strerror());
+                       unload_proto_library();
+                       return -1;
+               }
+
+               strcpy(proto_name_prev, proto_name);
+       }
+
+       return strlen(proto_name);
+}
+
+static size_t load_test_point_by_command(void **symbol, char *command, size_t offset, char const *dflt_symbol)
+{
+       char const *p, *q;
+       char const *symbol_name;
+       void *dl_symbol;
 
-       dl_handle = dl_by_name(dl_name);
        if (!dl_handle) {
-               fprintf(stderr, "Failed to link to library \"%s\": %s\n", dl_name, fr_strerror());
-               return -1;
+               fprintf(stderr, "No protocol library loaded. Specify library with \"load <proto name>\"\n");
+               exit(EXIT_FAILURE);
        }
 
+       p = command + offset;
+       q = strchr(p, '.');
 
        /*
-        *      Can't have '-' in variable names.
+        *      Use the dflt_symbol name as the test point
         */
-       for (p = dl_name; *p; p++) if (*p == '-') *p = '_';
+       if (!q) {
+               symbol_name = dflt_symbol;
+       } else {
+               symbol_name = q + 1;
+       }
 
-       dl_symbol = dlsym(dl_handle, dl_name);
+       dl_symbol = dlsym(dl_handle, symbol_name);
        if (!dl_symbol) {
-               fprintf(stderr, "Symbol \"%s\" not exported by library\n", dl_name);
-               dlclose(dl_handle);
-               return -1;
+               fprintf(stderr, "Test point (symbol \"%s\") not exported by library\n", symbol_name);
+               unload_proto_library();
+               exit(EXIT_FAILURE);
        }
+       *symbol = dl_symbol;
 
-       if (handle) *handle = dl_handle;
-       if (symbol) *symbol = dl_symbol;
-
-       return 0;
-}
+       p += strlen(p);
 
-static void unload_proto_library(void)
-{
-       if (dl_handle) {
-               dl_symbol = NULL;
-               dlclose(dl_handle);
-               dl_handle = NULL;
-       }
+       return p - command;
 }
 
 static void process_file(fr_dict_t *dict, const char *root_dir, char const *filename)
@@ -636,8 +659,7 @@ static void process_file(fr_dict_t *dict, const char *root_dir, char const *file
        char            output[8192];
        char            directory[8192];
        uint8_t         *attr, data[2048];
-
-
+       TALLOC_CTX      *tp_ctx = talloc_init("tp_ctx");
 
        if (strcmp(filename, "-") == 0) {
                fp = stdin;
@@ -1077,27 +1099,146 @@ static void process_file(fr_dict_t *dict, const char *root_dir, char const *file
                        continue;
                }
 
+
+               if (strcmp(test_type, "load") == 0) {
+                       p += 5;
+                       p += load_proto_library(p);
+                       continue;
+               }
+
+               /*
+                *      Generic pair decode test point
+                */
+               if (strncmp(test_type, "decode-pair", 11) == 0) {
+                       fr_test_point_pair_decode_t     *tp;
+                       ssize_t                         dec_len = 0;
+                       vp_cursor_t                     cursor;
+                       void                            *decoder_ctx;
+
+                       p += load_test_point_by_command((void **)&tp, test_type, 11, "tp_decode") + 1;
+                       decoder_ctx = tp->test_ctx(tp_ctx);
+
+                       if (strcmp(p, "-") == 0) {
+                               attr = data;
+                               len = data_len;
+                       } else {
+                               attr = data;
+                               len = encode_hex(p, data, sizeof(data));
+                               if (len == 0) {
+                                       fprintf(stderr, "Failed decoding hex string at line %d of %s\n",
+                                               lineno, directory);
+                                       exit(EXIT_FAILURE);
+                               }
+                       }
+
+                       fr_pair_cursor_init(&cursor, &head);
+                       while (len > 0) {
+                               dec_len = tp->func(tp_ctx, &cursor, attr, len, decoder_ctx);
+                               if (dec_len < 0) {
+                                       fr_pair_list_free(&head);
+                                       break;
+                               }
+                               if (dec_len > len) {
+                                       fprintf(stderr, "Internal sanity check failed at %d\n", __LINE__);
+                                       exit(EXIT_FAILURE);
+                               }
+                               attr += dec_len;
+                               len -= dec_len;
+                       }
+
+                       /*
+                        *      Output may be an error, and we ignore
+                        *      it if so.
+                        */
+                       if (head) {
+                               p = output;
+                               for (vp = fr_pair_cursor_first(&cursor);
+                                    vp;
+                                    vp = fr_pair_cursor_next(&cursor)) {
+                                       fr_pair_snprint(p, sizeof(output) - (p - output), vp);
+                                       p += strlen(p);
+
+                                       if (vp->next) {
+                                               strcpy(p, ", ");
+                                               p += 2;
+                                       }
+                               }
+
+                               fr_pair_list_free(&head);
+                       } else if (dec_len < 0) {
+                               strlcpy(output, fr_strerror(), sizeof(output));
+                       } else { /* zero-length attribute */
+                               *output = '\0';
+                       }
+                       talloc_free_children(tp_ctx);
+                       continue;
+               }
+
+               /*
+                *      Generic pair encode test point
+                */
+               if (strncmp(test_type, "encode-pair", 11) == 0) {
+                       fr_test_point_pair_encode_t     *tp;
+                       ssize_t                         enc_len = 0;
+                       vp_cursor_t                     cursor;
+                       void                            *encoder_ctx;
+
+                       p += load_test_point_by_command((void **)&tp, test_type, 11, "tp_encode") + 1;
+                       encoder_ctx = tp->test_ctx(tp_ctx);
+
+                       /*
+                        *      Encode the previous output
+                        */
+                       if (strcmp(p, "-") == 0) p = output;
+
+                       if (fr_pair_list_afrom_str(tp_ctx, p, &head) != T_EOL) {
+                               strlcpy(output, fr_strerror(), sizeof(output));
+                               continue;
+                       }
+
+                       attr = data;
+                       fr_pair_cursor_init(&cursor, &head);
+                       while ((vp = fr_pair_cursor_current(&cursor))) {
+                               enc_len = tp->func(attr, data + sizeof(data) - attr, &cursor, encoder_ctx);
+                               if (enc_len < 0) {
+                                       fprintf(stderr, "Failed encoding %s: %s\n", vp->da->name, fr_strerror());
+                                       exit(EXIT_FAILURE);
+                               }
+
+                               attr += enc_len;
+                               if (enc_len == 0) break;
+                       }
+                       fr_pair_list_free(&head);
+
+                       outlen = attr - data;
+
+                       talloc_free_children(tp_ctx);
+                       goto print_hex;
+               }
+
                /*
-                *      Generic decode test point
+                *      Generic proto decode test point
                 */
-               if (strncmp(test_type, "decode-", 7)) {
-                       fr_proto_lib_t *lib;
+               if (strncmp(test_type, "decode-proto", 12) == 0) {
+                       fr_test_point_proto_decode_t *tp;
+
+                       p += load_test_point_by_command((void **)&tp, test_type, 12, "tp_decode");
 
-                       if (load_proto_library(NULL, (void **)&lib, test_type + 7) < 0) exit(EXIT_FAILURE);
                        continue;
                }
 
                /*
-                *      Generic encode test point
+                *      Generic proto encode test point
                 */
-               if (strncmp(test_type, "encode-", 7)) {
-                       fr_proto_lib_t *lib;
+               if (strncmp(test_type, "encode-proto", 12) == 0) {
+                       fr_test_point_proto_encode_t *tp;
+
+                       p += load_test_point_by_command((void **)&tp, test_type, 12, "tp_encode");
 
-                       if (load_proto_library(NULL, (void **)&lib, test_type + 7) < 0) exit(EXIT_FAILURE);
                        continue;
                }
 
-               fprintf(stderr, "Unknown input at line %d of %s\n", lineno, directory);
+               fprintf(stderr, "Unknown input at line %d of %s: %s\n", lineno, directory, p);
 
                exit(EXIT_FAILURE);
        }
@@ -1140,9 +1281,11 @@ int main(int argc, char *argv[])
                case 'd':
                        radius_dir = optarg;
                        break;
+
                case 'D':
                        dict_dir = optarg;
                        break;
+
                case 'x':
                        fr_debug_lvl++;
                        rad_debug_lvl = fr_debug_lvl;
@@ -1150,9 +1293,11 @@ int main(int argc, char *argv[])
                        default_log.dst = L_DST_STDOUT;
                        default_log.fd = STDOUT_FILENO;
                        break;
+
                case 'M':
                        talloc_enable_leak_report();
                        break;
+
                case 'h':
                default:
                        usage();
index 2016eeeeb7b33bb1a042024e7407b21e8d0a5b82..034aff8d5eb81a31328813cde1bc78c66195baab 100644 (file)
@@ -1,6 +1,7 @@
 #
 #  Tests for the ethernet encoder/decoder
 #
+load ethernet
 
-encode-ethernet Ethernet-Src-Address = 0x010203040506, Ethernet-Dst-Address = 0x060504030201
+encode-proto.libfreeradius_ethernet Ethernet-Src-Address = 0x010203040506, Ethernet-Dst-Address = 0x060504030201
 # data 06 04 05 04 03 02 01 01 02 03 04 05 06 00 00