]> git.ipfire.org Git - thirdparty/unbound.git/commitdiff
- For #762: Introduce stat counters for downstream DNS Cookies per
authorGeorge Thessalonikefs <george@nlnetlabs.nl>
Tue, 8 Aug 2023 13:19:56 +0000 (15:19 +0200)
committerGeorge Thessalonikefs <george@nlnetlabs.nl>
Tue, 8 Aug 2023 13:19:56 +0000 (15:19 +0200)
  thread and total: num.queries_cookie_valid, num.queries_cookie_client,
  num.queries.cookie_invalid.

15 files changed:
daemon/remote.c
daemon/stats.c
daemon/stats.h
daemon/worker.c
doc/unbound-control.8.in
libunbound/unbound.h
smallapp/unbound-control.c
testcode/unitmain.c
testdata/stat_values.tdir/stat_values.pre
testdata/stat_values.tdir/stat_values.test
testdata/stat_values.tdir/stat_values_downstream_cookies.conf [new file with mode: 0644]
util/data/msgparse.c
util/data/msgparse.h
util/edns.c
util/edns.h

index c7bfa4e128f445db456eaed58978a6a77af1290e..4990fc8e91950ebabf9be1ac116806298f45c5ed 100644 (file)
@@ -672,6 +672,12 @@ print_stats(RES* ssl, const char* nm, struct ub_stats_info* s)
                (unsigned long)s->svr.num_queries)) return 0;
        if(!ssl_printf(ssl, "%s.num.queries_ip_ratelimited"SQ"%lu\n", nm,
                (unsigned long)s->svr.num_queries_ip_ratelimited)) return 0;
+       if(!ssl_printf(ssl, "%s.num.queries_cookie_valid"SQ"%lu\n", nm,
+               (unsigned long)s->svr.num_queries_cookie_valid)) return 0;
+       if(!ssl_printf(ssl, "%s.num.queries_cookie_client"SQ"%lu\n", nm,
+               (unsigned long)s->svr.num_queries_cookie_client)) return 0;
+       if(!ssl_printf(ssl, "%s.num.queries_cookie_invalid"SQ"%lu\n", nm,
+               (unsigned long)s->svr.num_queries_cookie_invalid)) return 0;
        if(!ssl_printf(ssl, "%s.num.cachehits"SQ"%lu\n", nm,
                (unsigned long)(s->svr.num_queries
                        - s->svr.num_queries_missed_cache))) return 0;
index fabbd9f606fce93d6274a308eae5092d26a8f6a4..4855bf1c1d2dd58833fd4377642c62707a4489f6 100644 (file)
@@ -435,6 +435,9 @@ void server_stats_add(struct ub_stats_info* total, struct ub_stats_info* a)
 {
        total->svr.num_queries += a->svr.num_queries;
        total->svr.num_queries_ip_ratelimited += a->svr.num_queries_ip_ratelimited;
+       total->svr.num_queries_cookie_valid += a->svr.num_queries_cookie_valid;
+       total->svr.num_queries_cookie_client += a->svr.num_queries_cookie_client;
+       total->svr.num_queries_cookie_invalid += a->svr.num_queries_cookie_invalid;
        total->svr.num_queries_missed_cache += a->svr.num_queries_missed_cache;
        total->svr.num_queries_prefetch += a->svr.num_queries_prefetch;
        total->svr.num_queries_timed_out += a->svr.num_queries_timed_out;
@@ -568,3 +571,16 @@ void server_stats_insrcode(struct ub_server_stats* stats, sldns_buffer* buf)
                        stats->ans_rcode_nodata ++;
        }
 }
+
+void server_stats_downstream_cookie(struct ub_server_stats* stats,
+       struct edns_data* edns)
+{
+       if(!(edns->edns_present && edns->cookie_present)) return;
+       if(edns->cookie_valid) {
+               stats->num_queries_cookie_valid++;
+       } else if(edns->cookie_client) {
+               stats->num_queries_cookie_client++;
+       } else {
+               stats->num_queries_cookie_invalid++;
+       }
+}
index 4e5e6cf8aed57d5ed371cd447728ecef3634c463..47bb20d7f8a7fce4549bfbc869c57c38dff28914 100644 (file)
@@ -126,4 +126,11 @@ void server_stats_insquery(struct ub_server_stats* stats, struct comm_point* c,
  */
 void server_stats_insrcode(struct ub_server_stats* stats, struct sldns_buffer* buf);
 
+/**
+ * Add DNS Cookie stats for this query
+ * @param stats: the stats
+ * @param edns: edns record
+ */
+void server_stats_downstream_cookie(struct ub_server_stats* stats,
+       struct edns_data* edns);
 #endif /* DAEMON_STATS_H */
index cdd636f81f79ba567f0ab18ceb7ec95ec194cd59..8c6fa3b9af3368451ba623868a63ad89b86aa36e 100644 (file)
@@ -1602,6 +1602,9 @@ worker_handle_request(struct comm_point* c, void* arg, int error,
                }
        }
 
+       /* Get stats for cookies */
+       server_stats_downstream_cookie(&worker->stats, &edns);
+
        /* If the IP rate limiting check was postponed, check now. */
        if(!pre_edns_ip_ratelimit) {
                /* NOTE: we always check the repinfo->client_address.
index acbc89abe054fbb90b2a1b43fa12771f52b3b3f6..7823de3aade4816485edb12fe53a27389214c60a 100644 (file)
@@ -369,6 +369,15 @@ number of queries received by thread
 .I threadX.num.queries_ip_ratelimited
 number of queries rate limited by thread
 .TP
+.I threadX.num.queries_cookie_valid
+number of queries with a valid DNS Cookie by thread
+.TP
+.I threadX.num.queries_cookie_client
+number of queries with a client part only DNS Cookie by thread
+.TP
+.I threadX.num.queries_cookie_invalid
+number of queries with an invalid DNS Cookie by thread
+.TP
 .I threadX.num.cachehits
 number of queries that were successfully answered using a cache lookup
 .TP
@@ -446,6 +455,18 @@ buffers are full.
 .I total.num.queries
 summed over threads.
 .TP
+.I total.num.queries_ip_ratelimited
+summed over threads.
+.TP
+.I total.num.queries_cookie_valid
+summed over threads.
+.TP
+.I total.num.queries_cookie_client
+summed over threads.
+.TP
+.I total.num.queries_cookie_invalid
+summed over threads.
+.TP
 .I total.num.cachehits
 summed over threads.
 .TP
@@ -611,7 +632,7 @@ ratelimiting.
 .TP
 .I num.query.dnscrypt.shared_secret.cachemiss
 The number of dnscrypt queries that did not find a shared secret in the cache.
-The can be use to compute the shared secret hitrate.
+This can be used to compute the shared secret hitrate.
 .TP
 .I num.query.dnscrypt.replay
 The number of dnscrypt queries that found a nonce hit in the nonce cache and
index 97be66a88f2b77a8d679bd6b2de6be83dbf19865..bb8e8acf033cead0c537bbc0e2051da2a1f14a27 100644 (file)
@@ -695,6 +695,12 @@ struct ub_server_stats {
        long long num_queries;
        /** number of queries that have been dropped/ratelimited by ip. */
        long long num_queries_ip_ratelimited;
+       /** number of queries with a valid DNS Cookie. */
+       long long num_queries_cookie_valid;
+       /** number of queries with only the client part of the DNS Cookie. */
+       long long num_queries_cookie_client;
+       /** number of queries with invalid DNS Cookie. */
+       long long num_queries_cookie_invalid;
        /** number of queries that had a cache-miss. */
        long long num_queries_missed_cache;
        /** number of prefetch queries - cachehits with prefetch */
index 891ce23ac0fd556c2484845590afedb50221efda..c4f73006196619009be4bc9eabe6a9e172674b30 100644 (file)
@@ -204,6 +204,12 @@ static void pr_stats(const char* nm, struct ub_stats_info* s)
        PR_UL_NM("num.queries", s->svr.num_queries);
        PR_UL_NM("num.queries_ip_ratelimited",
                s->svr.num_queries_ip_ratelimited);
+       PR_UL_NM("num.queries_cookie_valid",
+               s->svr.num_queries_cookie_valid);
+       PR_UL_NM("num.queries_cookie_client",
+               s->svr.num_queries_cookie_client);
+       PR_UL_NM("num.queries_cookie_invalid",
+               s->svr.num_queries_cookie_invalid);
        PR_UL_NM("num.cachehits",
                s->svr.num_queries - s->svr.num_queries_missed_cache);
        PR_UL_NM("num.cachemiss", s->svr.num_queries_missed_cache);
index f7eec421ebf9c646a630ef8d06867ade65727f02..647cbca3b05b42a90c8154e376cbe31e99279288 100644 (file)
@@ -557,7 +557,7 @@ edns_cookie_invalid_version(void)
        memcpy(buf + 16, "\306\063\144\144", 4);
        unit_assert(edns_cookie_server_validate(client_cookie,
                sizeof(client_cookie), server_secret, sizeof(server_secret), 1,
-               buf, timestamp) == 0);
+               buf, timestamp) == COOKIE_STATUS_INVALID);
        edns_cookie_server_write(buf, server_secret, 1, timestamp);
        unit_assert(memcmp(server_cookie, buf, 24) == 0);
 }
@@ -587,7 +587,7 @@ edns_cookie_invalid_hash(void)
        memcpy(buf + 16, "\313\000\161\313", 4);
        unit_assert(edns_cookie_server_validate(client_cookie,
                sizeof(client_cookie), server_secret, sizeof(server_secret), 1,
-               buf, timestamp) == 0);
+               buf, timestamp) == COOKIE_STATUS_INVALID);
        edns_cookie_server_write(buf, server_secret, 1, timestamp);
        unit_assert(memcmp(server_cookie, buf, 24) == 0);
 }
@@ -620,13 +620,13 @@ edns_cookie_rfc9018_a3_better(void)
        memcpy(buf + 16, "\313\000\161\313", 4);
        unit_assert(edns_cookie_server_validate(client_cookie,
                sizeof(client_cookie), server_secret, sizeof(server_secret), 1,
-               buf, timestamp) == -1);
+               buf, timestamp) == COOKIE_STATUS_VALID_RENEW);
        edns_cookie_server_write(buf, server_secret, 1, timestamp);
        unit_assert(memcmp(server_cookie, buf, 24) == 0);
 }
 
-/* Complete hash-valid client cookie; more than 60 minutes old; needs a
- * refreshed server cookie. */
+/* Complete hash-valid client cookie; more than 60 minutes old (expired);
+ * needs a refreshed server cookie. */
 static void
 edns_cookie_rfc9018_a3(void)
 {
@@ -651,7 +651,7 @@ edns_cookie_rfc9018_a3(void)
        memcpy(buf + 16, "\313\000\161\313", 4);
        unit_assert(edns_cookie_server_validate(client_cookie,
                sizeof(client_cookie), server_secret, sizeof(server_secret), 1,
-               buf, timestamp) == 0);
+               buf, timestamp) == COOKIE_STATUS_EXPIRED);
        edns_cookie_server_write(buf, server_secret, 1, timestamp);
        unit_assert(memcmp(server_cookie, buf, 24) == 0);
 }
@@ -682,7 +682,7 @@ edns_cookie_rfc9018_a2(void)
        memcpy(buf + 16, "\306\063\144\144", 4);
        unit_assert(edns_cookie_server_validate(client_cookie,
                sizeof(client_cookie), server_secret, sizeof(server_secret), 1,
-               buf, timestamp) == -1);
+               buf, timestamp) == COOKIE_STATUS_VALID_RENEW);
        edns_cookie_server_write(buf, server_secret, 1, timestamp);
        unit_assert(memcmp(server_cookie, buf, 24) == 0);
 }
@@ -711,7 +711,7 @@ edns_cookie_rfc9018_a1(void)
                sizeof(client_cookie),
                /* these will not be used; it will return invalid
                 * because of the size. */
-               NULL, 0, 1, NULL, 0) == 0);
+               NULL, 0, 1, NULL, 0) == COOKIE_STATUS_CLIENT_ONLY);
        edns_cookie_server_write(buf, server_secret, 1, timestamp);
        unit_assert(memcmp(server_cookie, buf, 24) == 0);
 }
index ad1166a06362d701304a6da34a68b970c6375933..7b6eefdfaa49be049aa6ac517fd300a4bfd1b07d 100644 (file)
@@ -37,6 +37,7 @@ echo "FWD_EXPIRED_PID=$FWD_EXPIRED_PID" >> .tpkg.var.test
 # make config file
 sed -e 's/@PORT\@/'$UNBOUND_PORT'/' -e 's/@TOPORT\@/'$FWD_PORT'/' -e 's/@EXPIREDPORT\@/'$FWD_EXPIRED_PORT'/' -e 's/@CONTROL_PORT\@/'$CONTROL_PORT'/' < stat_values.conf > ub.conf
 sed -e 's/@PORT\@/'$UNBOUND_PORT'/' -e 's/@TOPORT\@/'$FWD_PORT'/' -e 's/@EXPIREDPORT\@/'$FWD_EXPIRED_PORT'/' -e 's/@CONTROL_PORT\@/'$CONTROL_PORT'/' < stat_values_cachedb.conf > ub_cachedb.conf
+sed -e 's/@PORT\@/'$UNBOUND_PORT'/'                                                                          -e 's/@CONTROL_PORT\@/'$CONTROL_PORT'/' < stat_values_downstream_cookies.conf > ub_downstream_cookies.conf
 # start unbound in the background
 $PRE/unbound -d -c ub.conf >unbound.log 2>&1 &
 UNBOUND_PID=$!
index c9ed66d82c9ffec4106333285cdef4083e0880ab..8366ba88b926e479167e0d2206b66c0359d83a2d 100644 (file)
@@ -414,6 +414,97 @@ rrset.cache.count=3
 infra.cache.count=2"
 
 
+# Bring the downstream DNS Cookies configured Unbound up
+kill_pid $UNBOUND_PID  # kill current Unbound
+$PRE/unbound -d -c ub_downstream_cookies.conf >unbound.log 2>&1 &
+UNBOUND_PID=$!
+echo "UNBOUND_PID=$UNBOUND_PID" >> .tpkg.var.test
+wait_unbound_up unbound.log
+
+echo
+echo "[ Get a DNS Cookie. ]"
+echo "> dig www.local.zone +tcp +ednsopt=10:0102030405060708"
+dig @127.0.0.1 -p $UNBOUND_PORT +tcp +ednsopt=10:0102030405060708 +retry=0 +time=1 www.local.zone. | tee outfile
+echo "> check answer"
+if grep "192.0.2.1" outfile; then
+       echo "OK"
+else
+       end 1
+fi
+# Save valid cookie
+valid_cookie=`grep "COOKIE: " outfile | cut -d ' ' -f 3`
+invalid_cookie=`echo $valid_cookie | tr '0' '4'`
+check_stats "\
+total.num.queries=1
+total.num.queries_cookie_client=1
+total.num.cachehits=1
+num.query.type.A=1
+num.query.class.IN=1
+num.query.opcode.QUERY=1
+num.query.flags.RD=1
+num.query.flags.AD=1
+num.query.edns.present=1
+num.query.tcp=1
+num.answer.rcode.NOERROR=1"
+
+echo
+echo "[ Present the valid DNS Cookie. ]"
+echo "> dig www.local.zone +ednsopt=10:valid_cookie"
+dig @127.0.0.1 -p $UNBOUND_PORT +ednsopt=10:$valid_cookie +retry=0 +time=1 www.local.zone. | tee outfile
+echo "> check answer"
+if grep "192.0.2.1" outfile; then
+       echo "OK"
+else
+       end 1
+fi
+check_stats "\
+total.num.queries=1
+total.num.queries_cookie_valid=1
+total.num.cachehits=1
+num.query.type.A=1
+num.query.class.IN=1
+num.query.opcode.QUERY=1
+num.query.flags.RD=1
+num.query.flags.AD=1
+num.query.edns.present=1
+num.answer.rcode.NOERROR=1"
+
+echo
+echo "[ Present an invalid DNS Cookie. ]"
+echo "> dig www.local.zone +ednsopt=10:invalid_cookie"
+dig @127.0.0.1 -p $UNBOUND_PORT +ednsopt=10:$invalid_cookie +retry=0 +time=1 www.local.zone. | tee outfile
+echo "> check answer"
+if grep "192.0.2.1" outfile; then
+       end 1
+else
+       echo "OK"
+fi
+# A lot of stats are missing since BADCOOKIE error response is before
+# those stat calculations.
+# BADCOOKIE is an extended error code; we record YXRRSET below.
+check_stats "\
+total.num.queries=1
+total.num.queries_cookie_invalid=1
+total.num.cachehits=1
+num.answer.rcode.YXRRSET=1"
+
+echo
+echo "[ Present no DNS Cookie. ]"
+echo "> dig www.local.zone +ignore"
+dig @127.0.0.1 -p $UNBOUND_PORT +ignore +retry=0 +time=1 www.local.zone. | tee outfile
+echo "> check answer"
+if grep "192.0.2.1" outfile; then
+       end 1
+else
+       echo "OK"
+fi
+# A lot of stats are missing since REFUSED error response because of no DNS
+# Cookie is before those stat calculations.
+check_stats "\
+total.num.queries=1
+total.num.cachehits=1
+num.answer.rcode.REFUSED=1"
+
 if test x$USE_CACHEDB = "x1"; then
 
 # Bring the cachedb configured Unbound up
diff --git a/testdata/stat_values.tdir/stat_values_downstream_cookies.conf b/testdata/stat_values.tdir/stat_values_downstream_cookies.conf
new file mode 100644 (file)
index 0000000..21e7882
--- /dev/null
@@ -0,0 +1,32 @@
+server:
+       verbosity: 5
+       module-config: "iterator"
+       num-threads: 1
+       interface: 127.0.0.1
+       port: @PORT@
+       use-syslog: no
+       directory: ""
+       pidfile: "unbound.pid"
+       chroot: ""
+       username: ""
+       extended-statistics: yes
+       identity: "stat_values"
+       outbound-msg-retry: 0
+       root-key-sentinel: no
+       trust-anchor-signaling: no
+
+       local-zone: local.zone static
+       local-data: "www.local.zone A 192.0.2.1"
+
+       answer-cookie: yes
+       access-control: 127.0.0.1 allow_cookie
+
+remote-control:
+       control-enable: yes
+       control-interface: 127.0.0.1
+       # control-interface: ::1
+       control-port: @CONTROL_PORT@
+       server-key-file: "unbound_server.key"
+       server-cert-file: "unbound_server.pem"
+       control-key-file: "unbound_control.key"
+       control-cert-file: "unbound_control.pem"
index 6aa853c151f56765823f95947279b0d55ecd0fb7..8cef37a1753e6f37b62843b5813b9ccbc6d806f0 100644 (file)
@@ -971,7 +971,7 @@ parse_edns_options_from_query(uint8_t* rdata_ptr, size_t rdata_len,
                uint16_t opt_code = sldns_read_uint16(rdata_ptr);
                uint16_t opt_len = sldns_read_uint16(rdata_ptr+2);
                uint8_t server_cookie[40];
-               int cookie_is_valid;
+               enum edns_cookie_val_status cookie_val_status;
                int cookie_is_v4 = 1;
 
                rdata_ptr += 4;
@@ -1064,12 +1064,14 @@ parse_edns_options_from_query(uint8_t* rdata_ptr, size_t rdata_len,
                                        &((struct sockaddr_in6*)&repinfo->remote_addr)->sin6_addr, 16);
                        }
 
-                       cookie_is_valid = edns_cookie_server_validate(
+                       cookie_val_status = edns_cookie_server_validate(
                                rdata_ptr, opt_len, cfg->cookie_secret,
                                cfg->cookie_secret_len, cookie_is_v4,
                                server_cookie, now);
-                       if(cookie_is_valid != 0) edns->cookie_valid = 1;
-                       if(cookie_is_valid == 1) {
+                       switch(cookie_val_status) {
+                       case COOKIE_STATUS_VALID:
+                       case COOKIE_STATUS_VALID_RENEW:
+                               edns->cookie_valid = 1;
                                /* Reuse cookie */
                                if(!edns_opt_list_append(
                                        &edns->opt_list_out, LDNS_EDNS_COOKIE,
@@ -1081,13 +1083,22 @@ parse_edns_options_from_query(uint8_t* rdata_ptr, size_t rdata_len,
                                 * options. Done!
                                 */
                                break;
-                       }
-                       edns_cookie_server_write(server_cookie,
-                               cfg->cookie_secret, cookie_is_v4, now);
-                       if(!edns_opt_list_append(&edns->opt_list_out,
-                               LDNS_EDNS_COOKIE, 24, server_cookie, region)) {
-                               log_err("out of memory");
-                               return LDNS_RCODE_SERVFAIL;
+                       case COOKIE_STATUS_CLIENT_ONLY:
+                               edns->cookie_client = 1;
+                               /* fallthrough */
+                       case COOKIE_STATUS_FUTURE:
+                       case COOKIE_STATUS_EXPIRED:
+                       case COOKIE_STATUS_INVALID:
+                       default:
+                               edns_cookie_server_write(server_cookie,
+                                       cfg->cookie_secret, cookie_is_v4, now);
+                               if(!edns_opt_list_append(&edns->opt_list_out,
+                                       LDNS_EDNS_COOKIE, 24, server_cookie,
+                                       region)) {
+                                       log_err("out of memory");
+                                       return LDNS_RCODE_SERVFAIL;
+                               }
+                               break;
                        }
                        break;
                default:
index 74493b76e8bc9a2a291e086bbdaa8c61dc35343e..b7dc235d677c73338d75a87f6e69cdf91089cd59 100644 (file)
@@ -243,6 +243,8 @@ struct edns_data {
        unsigned int cookie_present : 1;
        /** if the cookie validated */
        unsigned int cookie_valid   : 1;
+       /** if the cookie holds only the client part */
+       unsigned int cookie_client  : 1;
 };     
 
 /**
index d4db29a65a005c10da87b44d11a34d6d4fd2a4d9..2b4047f0b60067adea4e55174595dae4ae04a40f 100644 (file)
@@ -153,7 +153,7 @@ edns_cookie_server_write(uint8_t* buf, const uint8_t* secret, int v4,
        memcpy(buf + 16, hash, 8);
 }
 
-int
+enum edns_cookie_val_status
 edns_cookie_server_validate(const uint8_t* cookie, size_t cookie_len,
        const uint8_t* secret, size_t secret_len, int v4,
        const uint8_t* hash_input, uint32_t now)
@@ -162,26 +162,28 @@ edns_cookie_server_validate(const uint8_t* cookie, size_t cookie_len,
        uint32_t timestamp;
        uint32_t subt_1982 = 0; /* Initialize for the compiler; unused value */
        int comp_1982;
-       if(cookie_len != 24 ||      /* RFC9018 cookies are 24 bytes long */
-               secret_len != 16 || /* RFC9018 cookies have 16 byte secrets */
-               cookie[8] != 1)     /* RFC9018 cookies are cookie version 1 */
-               return 0;
+       if(cookie_len != 24)
+               /* RFC9018 cookies are 24 bytes long */
+               return COOKIE_STATUS_CLIENT_ONLY;
+       if(secret_len != 16 ||  /* RFC9018 cookies have 16 byte secrets */
+               cookie[8] != 1) /* RFC9018 cookies are cookie version 1 */
+               return COOKIE_STATUS_INVALID;
        timestamp = sldns_read_uint32(cookie + 12);
        if((comp_1982 = compare_1982(now, timestamp)) > 0
                && (subt_1982 = subtract_1982(timestamp, now)) > 3600)
                /* Cookie is older than 1 hour (see RFC9018 Section 4.3.) */
-               return 0;
+               return COOKIE_STATUS_EXPIRED;
        if(comp_1982 <= 0 && subtract_1982(now, timestamp) > 300)
                /* Cookie time is more than 5 minutes in the future.
                 * (see RFC9018 Section 4.3.) */
-               return 0;
+               return COOKIE_STATUS_FUTURE;
        if(memcmp(edns_cookie_server_hash(hash_input, secret, v4, hash),
                cookie + 16, 8) != 0)
                /* Hashes do not match */
-               return 0;
+               return COOKIE_STATUS_INVALID;
        if(comp_1982 > 0 && subt_1982 > 1800)
                /* Valid cookie but older than 30 minutes, so create a new one
                 * anyway */
-               return -1;
-       return 1;
+               return COOKIE_STATUS_VALID_RENEW;
+       return COOKIE_STATUS_VALID;
 }
index 190e69634635fd5839770e48a9b73a2e2b9db7cb..5da0ecb290a711a27ceb9c78fea3446bf06c720b 100644 (file)
@@ -75,6 +75,15 @@ struct edns_string_addr {
        size_t string_len;
 };
 
+enum edns_cookie_val_status {
+       COOKIE_STATUS_CLIENT_ONLY = -3,
+       COOKIE_STATUS_FUTURE = -2,
+       COOKIE_STATUS_EXPIRED = -1,
+       COOKIE_STATUS_INVALID = 0,
+       COOKIE_STATUS_VALID = 1,
+       COOKIE_STATUS_VALID_RENEW = 2,
+};
+
 /**
  * Create structure to hold EDNS strings
  * @return: newly created edns_strings, NULL on alloc failure.
@@ -149,10 +158,11 @@ void edns_cookie_server_write(uint8_t* buf, const uint8_t* secret, int v4,
  * @param hash_input: pointer to the hash input for validation. It needs to be:
  *     Client Cookie | Version | Reserved | Timestamp | Client-IP
  * @param now: the current time.
- * return 1 if valid, -1 if valid but a new one SHOULD be generated, else 0.
+ * return edns_cookie_val_status with the cookie validation status i.e.,
+ *     <=0 for invalid, else valid.
  */
-int edns_cookie_server_validate(const uint8_t* cookie, size_t cookie_len,
-       const uint8_t* secret, size_t secret_len, int v4,
+enum edns_cookie_val_status edns_cookie_server_validate(const uint8_t* cookie,
+       size_t cookie_len, const uint8_t* secret, size_t secret_len, int v4,
        const uint8_t* hash_input, uint32_t now);
 
 #endif