]> git.ipfire.org Git - thirdparty/FORT-validator.git/commitdiff
rsync: Add --max-size to default rsync arguments
authorAlberto Leiva Popper <ydahhrk@gmail.com>
Mon, 20 Sep 2021 18:49:35 +0000 (13:49 -0500)
committerAlberto Leiva Popper <ydahhrk@gmail.com>
Thu, 23 Sep 2021 16:42:53 +0000 (11:42 -0500)
Applies the patch from the previous commit to the rsync code.

Also adds documentation.

12 files changed:
docs/usage.md
src/config.c
src/config.h
src/config/rrdp_conf.c
src/config/sync_strategy.c
src/http/http.c
src/rsync/rsync.c
src/uri.c
test/Makefile.am
test/rsync_test.c
test/rtr/pdu_handler_test.c
test/uri_test.c [new file with mode: 0644]

index 09d6a8a14c30345f18e0192a04e559760fea61ae..2de3c2bc33054bb0a70ff07ef7a0b42348cbb22f 100644 (file)
@@ -54,6 +54,7 @@ description: Guide to use arguments of FORT Validator.
        40. [`--http.transfer-timeout`](#--httptransfer-timeout)
        41. [`--http.low-speed-limit`](#--httplow-speed-limit)
        41. [`--http.low-speed-time`](#--httplow-speed-time)
+       41. [`--http.max-file-size`](#--httpmax-file-size)
        42. [`--http.ca-path`](#--httpca-path)
        43. [`--output.roa`](#--outputroa)
        44. [`--output.bgpsec`](#--outputbgpsec)
@@ -127,6 +128,7 @@ description: Guide to use arguments of FORT Validator.
        [--http.transfer-timeout=<unsigned integer>]
        [--http.low-speed-limit=<unsigned integer>]
        [--http.low-speed-time=<unsigned integer>]
+       [--http.max-file-size=<unsigned integer>]
        [--http.ca-path=<directory>]
        [--log.enabled=true|false]
        [--log.output=syslog|console]
@@ -669,14 +671,12 @@ See [`--rsync.priority`](#--rsyncpriority).
 
 - **Type:** Integer
 - **Availability:** `argv` and JSON
-- **Default:** 2
+- **Default:** 0
 - **Range:** 0--[`UINT_MAX`](http://pubs.opengroup.org/onlinepubs/9699919799/basedefs/limits.h.html)
 
-Maximum number of retries whenever there's an error requesting an HTTP URI.
-
-A value of **0** means **no retries**.
+Number of additional HTTP requests after a failed attempt.
 
-Whenever is necessary to request an HTTP URI, the validator will try the request at least once. If there was an error requesting the URI, the validator will retry at most `--http.retry.count` times to fetch the file, waiting [`--http.retry.interval`](#--httpretryinterval) seconds between each retry.
+If a transient error is returned when Fort tries to perform an HTTP transfer, it will retry this number of times before giving up. Setting the number to 0 makes Fort do no retries (which is the default). "Transient error" is a timeout, an HTTP 408 response code, or an HTTP 5xx response code.
 
 ### `--http.retry.interval`
 
@@ -710,7 +710,7 @@ _**All requests are made using HTTPS, verifying the peer and the certificate nam
 
 Timeout (in seconds) for the connect phase.
 
-Whenever an HTTP connection will try to be established, the validator will wait a maximum of `http.connect-timeout` for the peer to respond to the connection request; if the timeout is reached, the connection attempt will be ceased.
+Whenever an HTTP connection will try to be established, the validator will wait a maximum of `http.connect-timeout` for the peer to respond to the connection request; if the timeout is reached, the connection attempt will be aborted.
 
 The value specified (either by the argument or the default value) is utilized in libcurl's option [CURLOPT_CONNECTTIMEOUT](https://curl.haxx.se/libcurl/c/CURLOPT_CONNECTTIMEOUT.html).
 
@@ -765,6 +765,19 @@ It is the number of seconds that the transfer speed should be below `--http.low-
 
 See [`--http.low-speed-limit`](#--httplow-speed-limit).
 
+### `--http.max-file-size`
+
+- **Type:** Integer
+- **Availability:** `argv` and JSON
+- **Default:** 10,000,000 (10 Megabytes)
+- **Range:** 0--2,000,000,000 (2 Gigabytes)
+
+The maximum amount of bytes files are allowed to length during HTTP transfers. Files that exceed this limit are dropped, either early (through [CURLOPT_MAXFILESIZE](https://curl.haxx.se/libcurl/c/CURLOPT_MAXFILESIZE.html)) or as they hit the limit (when the file size is not known prior to download).
+
+This is intended to prevent malicious RPKI repositories from stagnating Fort.
+
+As of 2021-09-20, the largest legitimate file I found in the repositories was aprox. 1120 kilobytes.
+
 ### `--http.ca-path`
 
 - **Type:** String (Path to directory)
@@ -1012,7 +1025,7 @@ Useful if you want `root`, but the root certificate is separated from the rest o
 
 - **Type:** Integer
 - **Availability:** `argv` and JSON
-- **Default:** 2
+- **Default:** 0
 - **Range:** 0--[`UINT_MAX`](http://pubs.opengroup.org/onlinepubs/9699919799/basedefs/limits.h.html)
 
 Maximum number of retries whenever there's an error executing an RSYNC.
@@ -1097,7 +1110,9 @@ The configuration options are mostly the same as the ones from the `argv` interf
                "<a href="#--httpuser-agent">user-agent</a>": "{{ page.command }}/{{ site.fort-latest-version }}",
                "<a href="#--httpconnect-timeout">connect-timeout</a>": 30,
                "<a href="#--httptransfer-timeout">transfer-timeout</a>": 0,
-               "<a href="#--httpidle-timeout">idle-timeout</a>": 15,
+               "<a href="#--httplow-speed-limit">low-speed-limit</a>": 30,
+               "<a href="#--httplow-speed-time">low-speed-time</a>": 10,
+               "<a href="#--httpmax-file-size">max-file-size</a>": 10000000,
                "<a href="#--httpca-path">ca-path</a>": "/usr/local/ssl/certs"
        },
 
@@ -1225,21 +1240,21 @@ Name of the program needed to invoke an rsync file transfer.
 
 - **Type:** String array
 - **Availability:** JSON only
-- **Default:** `[ "--recursive", "--delete", "--times", "--contimeout=20", "--timeout=15", "$REMOTE", "$LOCAL" ]`
+- **Default:** `[ "--recursive", "--delete", "--times", "--contimeout=20", "--timeout=15", "--max-size", "$HTTP_MAX_FILE_SIZE", "$REMOTE", "$LOCAL" ]`
 
 Arguments needed by [`rsync.program`](#rsyncprogram) to perform a recursive rsync.
 
-Fort will replace `"$REMOTE"` with the remote URL it needs to download, and `"$LOCAL"` with the target local directory where the file is supposed to be dropped.
+Fort will replace `"$REMOTE"` with the remote URL it needs to download, `"$LOCAL"` with the target local directory where the file is supposed to be dropped, and `"$HTTP_MAX_FILE_SIZE"` with [`--http.max-file-size`](#--httpmax-file-size).
 
 ### rsync.arguments-flat
 
 - **Type:** String array
 - **Availability:** JSON only
-- **Default:** `[ "--times", "--contimeout=20", "--timeout=15", "--dirs", "$REMOTE", "$LOCAL" ]`
+- **Default:** `[ "--times", "--contimeout=20", "--timeout=15", "--max-size", "$HTTP_MAX_FILE_SIZE", "--dirs", "$REMOTE", "$LOCAL" ]`
 
 Arguments needed by [`rsync.program`](#rsyncprogram) to perform a single-file rsync.
 
-Fort will replace `"$REMOTE"` with the remote URL it needs to download, and `"$LOCAL"` with the target local directory where the file is supposed to be dropped.
+Fort will replace `"$REMOTE"` with the remote URL it needs to download, `"$LOCAL"` with the target local directory where the file is supposed to be dropped, and `"$HTTP_MAX_FILE_SIZE"` with [`--http.max-file-size`](#--httpmax-file-size).
 
 ### `incidences`
 
@@ -1256,11 +1271,10 @@ A listing of actions to be performed by validation upon encountering certain err
 - **Availability:** `argv` and JSON
 - **Default:** `root-except-ta`
 
-> ![img/warn.svg](img/warn.svg) This argument **will be DEPRECATED**. Use [`--rsync.strategy`](#--rsyncstrategy) or [`--rsync.enabled`](#--rsyncenabled) (if rsync is meant to be disabled) instead.
+> ![img/warn.svg](img/warn.svg) This argument **is DEPRECATED**. Use [`--rsync.strategy`](#--rsyncstrategy) or [`--rsync.enabled`](#--rsyncenabled) (if rsync is meant to be disabled) instead.
 
 rsync synchronization strategy. Commands the way rsync URLs are approached during downloads.
 
-Despite this argument will be deprecated, it still can be utilized. Its possible values and behaviour will be as listed here:
 - `off`: will disable rsync execution, setting [`--rsync.enabled`](#--rsyncenabled) as `false`. So, using `--sync-strategy=off` will be the same as `--rsync.enabled=false`.
 - `strict`: will be the same as `--rsync.strategy=strict`, see [`strict`](#strict).
 - `root`: will be the same as `--rsync.strategy=root`, see [`root`](#root).
index 9143c015665b4fa0a477aa208eeab378136a9250..d4fdb7d221b405ab2b69f79d53555a9444ce1011 100644 (file)
@@ -308,7 +308,7 @@ static const struct option_field options[] = {
                .name = "sync-strategy",
                .type = &gt_sync_strategy,
                .offset = offsetof(struct rpki_config, sync_strategy),
-               .doc = "RSYNC download strategy. Will be deprecated, use 'rsync.strategy' instead.",
+               .doc = "RSYNC download strategy. Deprecated; use 'rsync.strategy' instead.",
        }, {
                .id = 2001,
                .name = "shuffle-uris",
@@ -526,13 +526,13 @@ static const struct option_field options[] = {
                .name = "rrdp.enabled",
                .type = &gt_rrdp_enabled,
                .offset = offsetof(struct rpki_config, rrdp.enabled),
-               .doc = "Enables RRDP execution. Will be deprecated, use 'http.enabled' instead.",
+               .doc = "Enables RRDP execution. Deprecated; use 'http.enabled' instead.",
        }, {
                .id = 10001,
                .name = "rrdp.priority",
                .type = &gt_rrdp_priority,
                .offset = offsetof(struct rpki_config, rrdp.priority),
-               .doc = "Priority of execution to fetch repositories files, a higher value means higher priority. Will be deprecated, use 'http.priority' instead.",
+               .doc = "Priority of execution to fetch repositories files, a higher value means higher priority. Deprecated; use 'http.priority' instead.",
                .min = 0,
                .max = 100,
        }, {
@@ -540,7 +540,7 @@ static const struct option_field options[] = {
                .name = "rrdp.retry.count",
                .type = &gt_rrdp_retry_count,
                .offset = offsetof(struct rpki_config, rrdp.retry.count),
-               .doc = "Maximum amount of retries whenever there's an error fetching RRDP files. Will be deprecated, use 'http.retry.count' instead.",
+               .doc = "Maximum amount of retries whenever there's an error fetching RRDP files. Deprecated; use 'http.retry.count' instead.",
                .min = 0,
                .max = UINT_MAX,
        }, {
@@ -548,7 +548,7 @@ static const struct option_field options[] = {
                .name = "rrdp.retry.interval",
                .type = &gt_rrdp_retry_interval,
                .offset = offsetof(struct rpki_config, rrdp.retry.interval),
-               .doc = "Period (in seconds) to wait between retries after an error ocurred fetching RRDP files. Will be deprecated, use 'http.retry.interval' instead.",
+               .doc = "Period (in seconds) to wait between retries after an error ocurred fetching RRDP files. Deprecated; use 'http.retry.interval' instead.",
                .min = 0,
                .max = UINT_MAX,
        },
@@ -981,6 +981,7 @@ set_default_values(void)
                "--times",
                "--contimeout=20",
                "--timeout=15",
+               "--max-size", "$HTTP_MAX_FILE_SIZE",
                "$REMOTE",
                "$LOCAL",
        };
@@ -989,6 +990,7 @@ set_default_values(void)
                "--times",
                "--contimeout=20",
                "--timeout=15",
+               "--max-size", "$HTTP_MAX_FILE_SIZE",
                "--dirs",
                "$REMOTE",
                "$LOCAL",
@@ -1037,7 +1039,7 @@ set_default_values(void)
        rpki_config.rsync.enabled = true;
        rpki_config.rsync.priority = 50;
        rpki_config.rsync.strategy = RSYNC_ROOT_EXCEPT_TA;
-       rpki_config.rsync.retry.count = 2;
+       rpki_config.rsync.retry.count = 0;
        rpki_config.rsync.retry.interval = 5;
        rpki_config.rsync.program = strdup("rsync");
        if (rpki_config.rsync.program == NULL) {
@@ -1058,7 +1060,7 @@ set_default_values(void)
        /* By default, has a higher priority than rsync */
        rpki_config.http.enabled = true;
        rpki_config.http.priority = 60;
-       rpki_config.http.retry.count = 2;
+       rpki_config.http.retry.count = 0;
        rpki_config.http.retry.interval = 5;
        rpki_config.http.user_agent = strdup(PACKAGE_NAME "/" PACKAGE_VERSION);
        if (rpki_config.http.user_agent == NULL) {
index bbc0be76480b79d495c30239ee1922de7e38d58c..f5ffe1b366f2c6dc489318a26a6beccdb5550539 100644 (file)
@@ -81,7 +81,7 @@ uint32_t config_get_val_log_facility(void);
  */
 void config_set_rsync_enabled(bool);
 void config_set_http_enabled(bool);
-/* TODO (later) This will be deprecated */
+/* TODO (later) Deprecated */
 void config_set_rrdp_enabled(bool);
 
 /* TODO (later) Remove when sync-strategy is fully deprecated */
index ee533196ae3695efc243e963c99f61c210d03e61..cbc509cc183b32880032fbbd5ef65cb493fa5e78 100644 (file)
@@ -26,7 +26,7 @@ set_rrdp_enabled(char const *name, bool value)
 {
        /* Warn about future deprecation */
        if (strcmp(name, "rrdp.enabled") == 0)
-               pr_op_warn("'rrdp.enabled' will be deprecated, use 'http.enabled' instead.");
+               pr_op_warn("'rrdp.enabled' is deprecated; use 'http.enabled' instead.");
 
        config_set_rrdp_enabled(value);
        config_set_http_enabled(value);
@@ -38,7 +38,7 @@ set_priority(char const *name, uint32_t value)
 {
        /* Warn about future deprecation */
        if (strcmp(name, "rrdp.priority") == 0)
-               pr_op_warn("'rrdp.priority' will be deprecated, use 'http.priority' instead.");
+               pr_op_warn("'rrdp.priority' is deprecated; use 'http.priority' instead.");
 
        config_set_rrdp_priority(value);
        config_set_http_priority(value);
@@ -50,7 +50,7 @@ set_retry_count(char const *name, unsigned int value)
 {
        /* Warn about future deprecation */
        if (strcmp(name, "rrdp.retry.count") == 0)
-               pr_op_warn("'rrdp.retry.count' will be deprecated, use 'http.retry.count' instead.");
+               pr_op_warn("'rrdp.retry.count' is deprecated; use 'http.retry.count' instead.");
 
        config_set_rrdp_retry_count(value);
        config_set_http_retry_count(value);
@@ -62,7 +62,7 @@ set_retry_interval(char const *name, unsigned int value)
 {
        /* Warn about future deprecation */
        if (strcmp(name, "rrdp.retry.interval") == 0)
-               pr_op_warn("'rrdp.retry.interval' will be deprecated, use 'http.retry.interval' instead.");
+               pr_op_warn("'rrdp.retry.interval' is deprecated; use 'http.retry.interval' instead.");
 
        config_set_rrdp_retry_interval(value);
        config_set_http_retry_interval(value);
index 224d5c41ecb988428248bc6f7a73a813bb46c2c6..ada711f15e6c6efb35419b4371647f20ab1766ce 100644 (file)
@@ -48,7 +48,7 @@ parse_argv_sync_strategy(struct option_field const *field, char const *str,
 {
        int error;
 
-       pr_op_warn("'sync-strategy' will be deprecated.");
+       pr_op_warn("'sync-strategy' is deprecated.");
        pr_op_warn("Use 'rsync.strategy' instead; or 'rsync.enabled=false' if you wish to use 'off' strategy.");
 
        if (strcmp(str, RSYNC_VALUE_OFF) == 0) {
index 5ad47efe4972c8cf15e0bbf3be457f672153fe3e..d73236dc417dc5e8a7a41e74ce990dd1539aae65 100644 (file)
@@ -91,7 +91,7 @@ write_callback(void *data, size_t size, size_t nmemb, void *userp)
                return 0; /* Ugh. See fread(3) */
        }
 
-       return fwrite(data, size, nmemb, userp);
+       return fwrite(data, size, nmemb, arg->dst);
 }
 
 static void
@@ -258,17 +258,17 @@ http_fetch(struct http_handler *handler, char const *uri, long *response_code,
                return 0;
        }
 
-       if (*response_code >= HTTP_BAD_REQUEST)
-               return pr_val_err("Error requesting URL %s (received HTTP code %ld): %s",
-                   uri, *response_code, curl_err_string(handler, res));
-
-       pr_val_err("Error requesting URL %s: %s", uri,
-           curl_err_string(handler, res));
+       pr_val_err("Error requesting URL %s: %s. (HTTP code: %ld)", uri,
+           curl_err_string(handler, res), *response_code);
        if (log_operation)
-               pr_op_err("Error requesting URL %s: %s", uri,
-                   curl_err_string(handler, res));
+               pr_op_err("Error requesting URL %s: %s. (HTTP code: %ld)", uri,
+                   curl_err_string(handler, res), *response_code);
 
-       return EREQFAILED;
+       /*
+        * TODO (performance) FILESIZE_EXCEEDED is probably not the only error
+        * code that should cancel retries.
+        */
+       return (res == CURLE_FILESIZE_EXCEEDED) ? -EFBIG : EREQFAILED;
 }
 
 static void
@@ -329,8 +329,9 @@ __http_download_file(struct rpki_uri *uri, long *response_code, long ims_value,
                        break; /* Note: Usually happy path */
 
                if (retries == config_get_http_retry_count()) {
-                       pr_val_warn("Max HTTP retries (%u) reached requesting for '%s', won't retry again.",
-                           retries, uri_get_global(uri));
+                       if (retries > 0)
+                               pr_val_warn("Max HTTP retries (%u) reached requesting for '%s', won't retry again.",
+                                   retries, uri_get_global(uri));
                        break;
                }
                pr_val_warn("Retrying HTTP request '%s' in %u seconds, %u attempts remaining.",
index 8e5d608022d408ab4fd0324bdf20b99153564b93..05640568bae0b7e7174a111388c9c1fe0a00ad53 100644 (file)
@@ -192,6 +192,32 @@ duplicate_fds(int fds[2][2])
        close(fds[1][0]);
 }
 
+static int
+uint2string(unsigned int uint, char **result)
+{
+       char *str;
+       int str_len;
+
+       str_len = snprintf(NULL, 0, "%u", uint);
+       if (str_len < 0)
+               return pr_val_err("Cannot compute length of '%u' string: Unknown cause", uint);
+
+       str_len++; /* Null chara */
+
+       str = malloc(str_len * sizeof(char));
+       if (str == NULL)
+               return pr_enomem();
+
+       str_len = snprintf(str, str_len, "%u", uint);
+       if (str_len < 0) {
+               free(str);
+               return pr_val_err("Cannot convert '%u' into a string: Unknown cause", uint);
+       }
+
+       *result = str;
+       return 0;
+}
+
 static void
 release_args(char **args, unsigned int size)
 {
@@ -209,6 +235,7 @@ prepare_rsync(struct rpki_uri *uri, bool is_ta, char ***args, size_t *args_len)
        struct string_array const *config_args;
        char **copy_args;
        unsigned int i;
+       int error;
 
        config_args = config_get_rsync_args(is_ta);
        /*
@@ -231,8 +258,14 @@ prepare_rsync(struct rpki_uri *uri, bool is_ta, char ***args, size_t *args_len)
                        copy_args[i + 1] = strdup(uri_get_global(uri));
                else if (strcmp(config_args->array[i], "$LOCAL") == 0)
                        copy_args[i + 1] = strdup(uri_get_local(uri));
-               else
+               else if (strcmp(config_args->array[i], "$HTTP_MAX_FILE_SIZE") == 0) {
+                       error = uint2string(config_get_http_max_file_size(),
+                           &copy_args[i + 1]);
+                       if (error)
+                               return error;
+               } else
                        copy_args[i + 1] = strdup(config_args->array[i]);
+
                if (copy_args[i + 1] == NULL) {
                        release_args(copy_args, i);
                        return pr_enomem();
@@ -457,8 +490,9 @@ do_rsync(struct rpki_uri *uri, bool is_ta, bool log_operation)
                                goto release_args;
 
                        if (retries == config_get_rsync_retry_count()) {
-                               pr_val_warn("Max RSYNC retries (%u) reached on '%s', won't retry again.",
-                                   retries, uri_get_global(uri));
+                               if (retries > 0)
+                                       pr_val_warn("Max RSYNC retries (%u) reached on '%s', won't retry again.",
+                                           retries, uri_get_global(uri));
                                error = EREQFAILED;
                                goto release_args;
                        }
index 93a5db0107080e2bae37ae96ae34bd82fed68648..da92e8e64db8cf4e2afcfa291c779502209e9599 100644 (file)
--- a/src/uri.c
+++ b/src/uri.c
@@ -134,12 +134,62 @@ str2global(char const *str, size_t str_len, struct rpki_uri *uri)
        return 0;
 }
 
+static bool
+ia5_starts_with_dot_slash(IA5String_t *string)
+{
+       if (string->size < 2)
+               return false;
+       return string->buf[0] == '.' && string->buf[1] == '/';
+}
+
+/*
+ * Files referenced by manifests are not allowed to be anywhere other than the
+ * manifest's own directory.
+ *
+ * I think. RFC 6486:
+ *
+ *     A manifest is a signed object that enumerates all the signed objects
+ *     (files) in the repository publication point (directory) that are
+ *     associated with an authority responsible for publishing at that
+ *     publication point.
+ *
+ * This function checks @ia5 does not contain slashes after the starting chain
+ * of "./"s.
+ */
+static int
+validate_current_directory(IA5String_t *string)
+{
+       IA5String_t clone;
+       size_t i;
+
+       if (string->size == 0)
+               return pr_val_err("Manifest contains a file with an empty string as a name.");
+       if (string->buf[0] == '/')
+               return pr_val_err("Manifest contains a file with an absolute URL.");
+
+       clone.buf = string->buf;
+       clone.size = string->size;
+       while (ia5_starts_with_dot_slash(&clone)) {
+               clone.buf += 2;
+               clone.size -= 2;
+       }
+
+       if (clone.size == 0)
+               return pr_val_err("Manifest contains a file that appears to be a directory.");
+
+       for (i = 0; i < clone.size; i++)
+               if (clone.buf[i] == '/')
+                       return pr_val_err("Manifest contains a URL that references a separate repository publication point.");
+
+       return 0;
+}
+
 /**
  * Initializes @uri->global given manifest path @mft and its referenced file
  * @ia5.
  *
- * ie. if @mft is "rsync://a/b/c.mft" and @ia5 is "d/e/f.cer", @uri->global will
- * be "rsync://a/b/d/e/f.cer".
+ * ie. if @mft is "rsync://a/b/c.mft" and @ia5 is "d.cer", @uri->global will
+ * be "rsync://a/b/d.cer".
  *
  * Assumes that @mft is a "global" URL. (ie. extracted from rpki_uri.global.)
  */
@@ -165,6 +215,10 @@ ia5str2global(struct rpki_uri *uri, char const *mft, IA5String_t *ia5)
                        return error;
        }
 
+       error = validate_current_directory(ia5);
+       if (error)
+               return error;
+
        slash_pos = strrchr(mft, '/');
        if (slash_pos == NULL) {
                joined = malloc(ia5->size + 1);
index 2dc362870db6e04c13ccc39e1a3e6c3d1fcad2e6..bb5231439dfd61e79c3aa464a9dcab38f1f3aa12 100644 (file)
@@ -29,6 +29,7 @@ check_PROGRAMS += rsync.test
 check_PROGRAMS += serial.test
 check_PROGRAMS += tal.test
 check_PROGRAMS += thread_pool.test
+check_PROGRAMS += uri.test
 check_PROGRAMS += vcard.test
 check_PROGRAMS += vrps.test
 check_PROGRAMS += xml.test
@@ -66,6 +67,9 @@ tal_test_LDADD = ${MY_LDADD}
 thread_pool_test_SOURCES = thread_pool_test.c
 thread_pool_test_LDADD = ${MY_LDADD}
 
+uri_test_SOURCES = uri_test.c
+uri_test_LDADD = ${MY_LDADD}
+
 vcard_test_SOURCES = vcard_test.c
 vcard_test_LDADD = ${MY_LDADD}
 
index ca5b61d1a4fa52ceb6a40730cadba3d54c75d867..53c3be05b08c8a3f6e569da326c53f5d3290a6dd 100644 (file)
@@ -16,9 +16,28 @@ state_retrieve(void)
        return NULL;
 }
 
-START_TEST(rsync_load_normal)
-{
+#define CK_STR(uint, string)                                           \
+       ck_assert_int_eq(0, uint2string(uint, &str));                   \
+       ck_assert_str_eq(string, str);                                  \
+       free(str);
 
+START_TEST(rsync_test_uint2string)
+{
+       char *str;
+
+       CK_STR(0, "0");
+       CK_STR(1, "1");
+       CK_STR(9, "9");
+       CK_STR(10, "10");
+       CK_STR(100, "100");
+       CK_STR(1000, "1000");
+       CK_STR(10000, "10000");
+       CK_STR(100000, "100000");
+       CK_STR(1000000, "1000000");
+       CK_STR(10000000, "10000000");
+       CK_STR(100000000, "100000000");
+       CK_STR(1000000000, "1000000000");
+       CK_STR(4294967295, "4294967295");
 }
 END_TEST
 
@@ -144,7 +163,7 @@ Suite *rsync_load_suite(void)
        TCase *core, *prefix_equals, *uri_list, *test_get_prefix;
 
        core = tcase_create("Core");
-       tcase_add_test(core, rsync_load_normal);
+       tcase_add_test(core, rsync_test_uint2string);
 
        prefix_equals = tcase_create("PrefixEquals");
        tcase_add_test(prefix_equals, rsync_test_prefix_equals);
index 70479e297a40a1d094fe695ec41a7e9bdfcb9e31..3e6571a4047c8c432fea5197fcb40cdd3e9dc6fb 100644 (file)
@@ -174,13 +174,13 @@ send_prefix_pdu(int fd, uint8_t version, struct vrp const *vrp, uint8_t flags)
 
        switch (vrp->addr_fam) {
        case AF_INET:
-               PR_DEBUG_MSG("%s asn%u IPv4", flags2str(flags), vrp->asn);
+               printf("%s asn%u IPv4\n", flags2str(flags), vrp->asn);
                break;
        case AF_INET6:
-               PR_DEBUG_MSG("%s asn%u IPv6", flags2str(flags), vrp->asn);
+               printf("%s asn%u IPv6\n", flags2str(flags), vrp->asn);
                break;
        default:
-               PR_DEBUG_MSG("%s asn%u Unknown", flags2str(flags), vrp->asn);
+               printf("%s asn%u Unknown\n", flags2str(flags), vrp->asn);
                break;
        }
 
@@ -201,7 +201,7 @@ send_router_key_pdu(int fd, uint8_t version,
         */
        uint8_t pdu_type = pop_expected_pdu();
        pr_op_info("    Server sent Router Key PDU.");
-       PR_DEBUG_MSG("%s asn%u RK", flags2str(flags), router_key->as);
+       printf("%s asn%u RK\n", flags2str(flags), router_key->as);
        ck_assert_msg(pdu_type == PDU_TYPE_ROUTER_KEY,
            "Server sent a Router Key. Expected PDU type was %d.", pdu_type);
        return 0;
@@ -293,7 +293,6 @@ START_TEST(test_typical_exchange)
 
        /* From serial 1: Run and validate */
        ck_assert_int_eq(0, handle_serial_query_pdu(0, &request));
-       PR_DEBUG;
        ck_assert_uint_eq(false, has_expected_pdus());
 
        /* From serial 2: Init client request */
diff --git a/test/uri_test.c b/test/uri_test.c
new file mode 100644 (file)
index 0000000..be5c1b9
--- /dev/null
@@ -0,0 +1,70 @@
+#include <check.h>
+#include <errno.h>
+#include <stdint.h>
+
+#include "uri.c"
+#include "common.c"
+#include "log.c"
+#include "impersonator.c"
+
+static int
+test_validate(char const *src)
+{
+       uint8_t buffer[32];
+       IA5String_t dst;
+       unsigned int i;
+
+       dst.size = strlen(src);
+
+       memcpy(buffer, src, dst.size);
+       for (i = dst.size; i < 31; i++)
+               buffer[i] = '_';
+       buffer[31] = 0;
+
+       dst.buf = buffer;
+
+       return validate_current_directory(&dst);
+}
+
+START_TEST(check_validate_current_directory)
+{
+       ck_assert_int_eq(0, test_validate("file"));
+       ck_assert_int_eq(-EINVAL, test_validate(""));
+       ck_assert_int_eq(-EINVAL, test_validate("/file"));
+       ck_assert_int_eq(0, test_validate("./file"));
+       ck_assert_int_eq(0, test_validate("././file"));
+       ck_assert_int_eq(0, test_validate("./././././file"));
+       ck_assert_int_eq(-EINVAL, test_validate("./././././"));
+       ck_assert_int_eq(-EINVAL, test_validate("./././././file/"));
+       ck_assert_int_eq(-EINVAL, test_validate("./././././file/b"));
+}
+END_TEST
+
+Suite *address_load_suite(void)
+{
+       Suite *suite;
+       TCase *core;
+
+       core = tcase_create("Core");
+       tcase_add_test(core, check_validate_current_directory);
+
+       suite = suite_create("Encoding checking");
+       suite_add_tcase(suite, core);
+       return suite;
+}
+
+int main(void)
+{
+       Suite *suite;
+       SRunner *runner;
+       int tests_failed;
+
+       suite = address_load_suite();
+
+       runner = srunner_create(suite);
+       srunner_run_all(runner, CK_NORMAL);
+       tests_failed = srunner_ntests_failed(runner);
+       srunner_free(runner);
+
+       return (tests_failed == 0) ? EXIT_SUCCESS : EXIT_FAILURE;
+}