Commit eb5af5ae authored by Daniel Salzman's avatar Daniel Salzman

semchecks: adapt to multiple CDS/CDNSKEY feature

parent 2bcaf766
......@@ -113,17 +113,17 @@ static const char *error_messages[SEM_ERR_UNKNOWN + 1] = {
[SEM_ERR_CDS_NONE] =
"missing CDS",
[SEM_ERR_CDS_MULTIPLE] =
"multiple CDS records",
[SEM_ERR_CDS_NOT_MATCH] =
"CDS not match CDNSKEY",
[SEM_ERR_CDNSKEY_NONE] =
"missing CDNSKEY",
[SEM_ERR_CDNSKEY_MULTIPLE] =
"multiple CDNSKEY records",
[SEM_ERR_CDNSKEY_NO_DNSKEY] =
"CDNSKEY not match DNSKEY",
[SEM_ERR_CDNSKEY_NO_CDS] =
"CDNSKEY without corresponding CDS",
[SEM_ERR_CDNSKEY_INVALID_DELETE] =
"invalid CDNSKEY/CDS for DNSSEC delete algorithm",
[SEM_ERR_UNKNOWN] =
"unknown error"
......@@ -517,57 +517,99 @@ static int check_submission(const zone_node_t *node, semchecks_data_t *data)
return KNOT_EOK;
}
if (cdss->count != 1) {
data->handler->cb(data->handler, data->zone, node,
SEM_ERR_CDS_MULTIPLE, NULL);
}
if (cdnskeys->count != 1) {
const knot_rdataset_t *dnskeys = node_rdataset(data->zone->apex,
KNOT_RRTYPE_DNSKEY);
if (dnskeys == NULL) {
data->handler->cb(data->handler, data->zone, node,
SEM_ERR_CDNSKEY_MULTIPLE, NULL);
SEM_ERR_DNSKEY_NONE, NULL);
}
knot_rdata_t *cdnskey = cdnskeys->rdata;
knot_rdata_t *cds = cdss->rdata;
uint8_t digest_type = knot_ds_digest_type(cdss->rdata);
const uint8_t *empty_cds = (uint8_t *)"\x00\x00\x00\x00\x00";
const uint8_t *empty_cdnskey = (uint8_t *)"\x00\x00\x03\x00\x00";
bool delete_cds = false, delete_cdnskey = false;
const knot_rdataset_t *dnskeys = node_rdataset(data->zone->apex,
KNOT_RRTYPE_DNSKEY);
for (int i = 0; dnskeys != NULL && i < dnskeys->count; i++) {
knot_rdata_t *dnskey = knot_rdataset_at(dnskeys, i);
if (knot_rdata_cmp(dnskey, cdnskey) != 0) {
// check every CDNSKEY for corresponding DNSKEY
for (int i = 0; i < cdnskeys->count; i++) {
knot_rdata_t *cdnskey = knot_rdataset_at(cdnskeys, i);
// skip delete-dnssec CDNSKEY
if (cdnskey->len == 5 && memcmp(cdnskey->data, empty_cdnskey, 5) == 0) {
delete_cdnskey = true;
continue;
}
dnssec_key_t *key;
int ret = dnssec_key_from_rdata(&key, data->zone->apex->owner,
dnskey->data, dnskey->len);
if (ret != KNOT_EOK) {
return ret;
bool match = false;
for (int j = 0; j < dnskeys->count; j++) {
knot_rdata_t *dnskey = knot_rdataset_at(dnskeys, j);
if (knot_rdata_cmp(dnskey, cdnskey) == 0) {
match = true;
break;
}
}
if (!match) {
data->handler->cb(data->handler, data->zone, node,
SEM_ERR_CDNSKEY_NO_DNSKEY, NULL);
}
}
dnssec_binary_t cds_calc = { 0 };
dnssec_binary_t cds_orig = { .size = cds->len, .data = cds->data };
ret = dnssec_key_create_ds(key, digest_type, &cds_calc);
if (ret != KNOT_EOK) {
dnssec_key_free(key);
return ret;
// check every CDS for corresponding CDNSKEY
for (int i = 0; i < cdss->count; i++) {
knot_rdata_t *cds = knot_rdataset_at(cdss, i);
uint8_t digest_type = knot_ds_digest_type(cds);
// skip delete-dnssec CDS
if (cds->len == 5 && memcmp(cds->data, empty_cds, 5) == 0) {
delete_cds = true;
continue;
}
ret = dnssec_binary_cmp(&cds_orig, &cds_calc);
dnssec_binary_free(&cds_calc);
dnssec_key_free(key);
if (ret == 0) {
return KNOT_EOK;
} else {
bool match = false;
for (int j = 0; j < cdnskeys->count; j++) {
knot_rdata_t *cdnskey = knot_rdataset_at(cdnskeys, j);
dnssec_key_t *key;
int ret = dnssec_key_from_rdata(&key, data->zone->apex->owner,
cdnskey->data, cdnskey->len);
if (ret != KNOT_EOK) {
continue;
}
dnssec_binary_t cds_calc = { 0 };
dnssec_binary_t cds_orig = { .size = cds->len, .data = cds->data };
ret = dnssec_key_create_ds(key, digest_type, &cds_calc);
if (ret != KNOT_EOK) {
dnssec_key_free(key);
return ret;
}
ret = dnssec_binary_cmp(&cds_orig, &cds_calc);
dnssec_binary_free(&cds_calc);
dnssec_key_free(key);
if (ret == 0) {
match = true;
break;
}
}
if (!match) {
data->handler->cb(data->handler, data->zone, node,
SEM_ERR_CDS_NOT_MATCH, NULL);
}
}
if (dnskeys != NULL) {
// check delete-dnssec records
if ((delete_cds && (!delete_cdnskey || cdss->count > 1)) ||
(delete_cdnskey && (!delete_cds || cdnskeys->count > 1))) {
data->handler->cb(data->handler, data->zone, node,
SEM_ERR_CDNSKEY_NO_DNSKEY, NULL);
SEM_ERR_CDNSKEY_INVALID_DELETE, NULL);
}
// check orphaned CDS
if (cdss->count < cdnskeys->count) {
data->handler->cb(data->handler, data->zone, node,
SEM_ERR_CDNSKEY_NO_CDS, NULL);
}
return KNOT_EOK;
}
......
/* Copyright (C) 2017 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz>
/* Copyright (C) 2018 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz>
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
......@@ -73,12 +73,12 @@ typedef enum {
SEM_ERR_DNSKEY_RDATA_PROTOCOL,
SEM_ERR_CDS_NONE,
SEM_ERR_CDS_MULTIPLE,
SEM_ERR_CDS_NOT_MATCH,
SEM_ERR_CDNSKEY_NONE,
SEM_ERR_CDNSKEY_MULTIPLE,
SEM_ERR_CDNSKEY_NO_DNSKEY,
SEM_ERR_CDNSKEY_NO_CDS,
SEM_ERR_CDNSKEY_INVALID_DELETE,
// General error!
SEM_ERR_UNKNOWN
......
;; Zone dump (Knot DNS 2.5.0-dev)
example.com. 3600 SOA dns2.example.com. hostmaster.example.com. 2010135808 10800 3600 1209600 7200
example.com. 3600 NS dns2.example.com.
example.com. 3600 MX 10 mail.example.com.
example.com. 3600 DNSKEY 256 3 8 AwEAAdKraxDdGTL4HDOkXTDI1Md1UdHuYhVwYkB+u2umVjTJ1H9Qb2oBryqwXI+gklnuCqrH1znkDvzGEAeHRQUCbtKbjmqErTAcRRHW3D+6jsOGXzbyGCfbyzRBwsbNCLWr3ONpPi5JOWEeCUJfyc/mRXcmh5uYl1JvzAM1zprtljZt
example.com. 3600 DNSKEY 257 3 8 AwEAAcQ1EqTPebcJyUnpxO3Xjx6ehRtsiZYToARoJsJG12XR6Ci9yy4SCCsejtaWIFO4XVfM2BHzFWqmABtQHtN7AazXAFMLsrSE4DYbgk5WmnQv5Jloi6jhhmmXwr8EOi3HR2jdG0gVq/Tax7ztNNZsflJrs3rZs2TVO00BkyyOkmO35jCNbGPUwm5cW1vse137BMa7jAcMyNLPIiQubj1/mJcIyzF2duvfpjBTgEmSvNcXqLfYFjK8lG4NodQG8AcK0MvWqN4mxW/hK0U9nMSjhCnfzPg5tjyqdheWRyhkLGjM/mR7gBhtqoSPMr+2KMJQEHYAd/AP8YgaovS8N1fJyh0=
example.com. 3600 DNSKEY 257 3 8 AwEAAetE6qfN/GbtMmvM0PXUTyskauES2FKfjqLVz7EQlfS8iAFWLi1eHjHXDkueZ1OYRzQ4IBy6MIsce4XVXLQoS8njtfaU7c5NZvktH5la7JuH32KYr3PdWL5KDsUdED3GSxfNV+DbcYU80AZxTxy6Bm6EP+DztL1dpYrmqr8JRl+qlSbmLIrPemZFUEQzhiepcYMWviDUz+ixSVzjEzpMCLsrNxA30Ziiq9GKA8KKlFHdAmxuNcH0TzRndpo6bu5nKyJHiREIazHVuPBEzUmHtcWETCDs9UVsbji2Z2ozqLz9cqnfYV/kOD+OZBAqvZ0n/4lgdSiBtvByLCXoWEYIGRs=
example.com. 3600 CDS 0 0 0 00
example.com. 3600 CDNSKEY 0 3 0 AA==
dns2.example.com. 3600 A 192.0.2.1
;; Zone dump (Knot DNS 2.5.0-dev)
example.com. 3600 SOA dns2.example.com. hostmaster.example.com. 2010135808 10800 3600 1209600 7200
example.com. 3600 NS dns2.example.com.
example.com. 3600 MX 10 mail.example.com.
example.com. 3600 DNSKEY 256 3 8 AwEAAdKraxDdGTL4HDOkXTDI1Md1UdHuYhVwYkB+u2umVjTJ1H9Qb2oBryqwXI+gklnuCqrH1znkDvzGEAeHRQUCbtKbjmqErTAcRRHW3D+6jsOGXzbyGCfbyzRBwsbNCLWr3ONpPi5JOWEeCUJfyc/mRXcmh5uYl1JvzAM1zprtljZt
example.com. 3600 DNSKEY 257 3 8 AwEAAcQ1EqTPebcJyUnpxO3Xjx6ehRtsiZYToARoJsJG12XR6Ci9yy4SCCsejtaWIFO4XVfM2BHzFWqmABtQHtN7AazXAFMLsrSE4DYbgk5WmnQv5Jloi6jhhmmXwr8EOi3HR2jdG0gVq/Tax7ztNNZsflJrs3rZs2TVO00BkyyOkmO35jCNbGPUwm5cW1vse137BMa7jAcMyNLPIiQubj1/mJcIyzF2duvfpjBTgEmSvNcXqLfYFjK8lG4NodQG8AcK0MvWqN4mxW/hK0U9nMSjhCnfzPg5tjyqdheWRyhkLGjM/mR7gBhtqoSPMr+2KMJQEHYAd/AP8YgaovS8N1fJyh0=
example.com. 3600 DNSKEY 257 3 8 AwEAAetE6qfN/GbtMmvM0PXUTyskauES2FKfjqLVz7EQlfS8iAFWLi1eHjHXDkueZ1OYRzQ4IBy6MIsce4XVXLQoS8njtfaU7c5NZvktH5la7JuH32KYr3PdWL5KDsUdED3GSxfNV+DbcYU80AZxTxy6Bm6EP+DztL1dpYrmqr8JRl+qlSbmLIrPemZFUEQzhiepcYMWviDUz+ixSVzjEzpMCLsrNxA30Ziiq9GKA8KKlFHdAmxuNcH0TzRndpo6bu5nKyJHiREIazHVuPBEzUmHtcWETCDs9UVsbji2Z2ozqLz9cqnfYV/kOD+OZBAqvZ0n/4lgdSiBtvByLCXoWEYIGRs=
example.com. 3600 CDS 0 0 0 00
example.com. 3600 CDNSKEY 0 3 0 BA==
dns2.example.com. 3600 A 192.0.2.1
;; Zone dump (Knot DNS 2.5.0-dev)
example.com. 3600 SOA dns2.example.com. hostmaster.example.com. 2010135808 10800 3600 1209600 7200
example.com. 3600 NS dns2.example.com.
example.com. 3600 MX 10 mail.example.com.
example.com. 3600 DNSKEY 256 3 8 AwEAAdKraxDdGTL4HDOkXTDI1Md1UdHuYhVwYkB+u2umVjTJ1H9Qb2oBryqwXI+gklnuCqrH1znkDvzGEAeHRQUCbtKbjmqErTAcRRHW3D+6jsOGXzbyGCfbyzRBwsbNCLWr3ONpPi5JOWEeCUJfyc/mRXcmh5uYl1JvzAM1zprtljZt
example.com. 3600 DNSKEY 257 3 8 AwEAAcQ1EqTPebcJyUnpxO3Xjx6ehRtsiZYToARoJsJG12XR6Ci9yy4SCCsejtaWIFO4XVfM2BHzFWqmABtQHtN7AazXAFMLsrSE4DYbgk5WmnQv5Jloi6jhhmmXwr8EOi3HR2jdG0gVq/Tax7ztNNZsflJrs3rZs2TVO00BkyyOkmO35jCNbGPUwm5cW1vse137BMa7jAcMyNLPIiQubj1/mJcIyzF2duvfpjBTgEmSvNcXqLfYFjK8lG4NodQG8AcK0MvWqN4mxW/hK0U9nMSjhCnfzPg5tjyqdheWRyhkLGjM/mR7gBhtqoSPMr+2KMJQEHYAd/AP8YgaovS8N1fJyh0=
example.com. 3600 DNSKEY 257 3 8 AwEAAetE6qfN/GbtMmvM0PXUTyskauES2FKfjqLVz7EQlfS8iAFWLi1eHjHXDkueZ1OYRzQ4IBy6MIsce4XVXLQoS8njtfaU7c5NZvktH5la7JuH32KYr3PdWL5KDsUdED3GSxfNV+DbcYU80AZxTxy6Bm6EP+DztL1dpYrmqr8JRl+qlSbmLIrPemZFUEQzhiepcYMWviDUz+ixSVzjEzpMCLsrNxA30Ziiq9GKA8KKlFHdAmxuNcH0TzRndpo6bu5nKyJHiREIazHVuPBEzUmHtcWETCDs9UVsbji2Z2ozqLz9cqnfYV/kOD+OZBAqvZ0n/4lgdSiBtvByLCXoWEYIGRs=
example.com. 3600 CDS 0 0 0 01
example.com. 3600 CDNSKEY 0 3 0 AA==
dns2.example.com. 3600 A 192.0.2.1
......@@ -7,7 +7,5 @@ example.com. 3600 DNSKEY 257 3 8 AwEAAcQ1EqTPebcJyUnpxO3Xjx6ehRtsiZYToAR
example.com. 3600 DNSKEY 257 3 8 AwEAAetE6qfN/GbtMmvM0PXUTyskauES2FKfjqLVz7EQlfS8iAFWLi1eHjHXDkueZ1OYRzQ4IBy6MIsce4XVXLQoS8njtfaU7c5NZvktH5la7JuH32KYr3PdWL5KDsUdED3GSxfNV+DbcYU80AZxTxy6Bm6EP+DztL1dpYrmqr8JRl+qlSbmLIrPemZFUEQzhiepcYMWviDUz+ixSVzjEzpMCLsrNxA30Ziiq9GKA8KKlFHdAmxuNcH0TzRndpo6bu5nKyJHiREIazHVuPBEzUmHtcWETCDs9UVsbji2Z2ozqLz9cqnfYV/kOD+OZBAqvZ0n/4lgdSiBtvByLCXoWEYIGRs=
example.com. 3600 CDNSKEY 257 3 8 AwEAAcQ1EqTPebcJyUnpxO3Xjx6ehRtsiZYToARoJsJG12XR6Ci9yy4SCCsejtaWIFO4XVfM2BHzFWqmABtQHtN7AazXAFMLsrSE4DYbgk5WmnQv5Jloi6jhhmmXwr8EOi3HR2jdG0gVq/Tax7ztNNZsflJrs3rZs2TVO00BkyyOkmO35jCNbGPUwm5cW1vse137BMa7jAcMyNLPIiQubj1/mJcIyzF2duvfpjBTgEmSvNcXqLfYFjK8lG4NodQG8AcK0MvWqN4mxW/hK0U9nMSjhCnfzPg5tjyqdheWRyhkLGjM/mR7gBhtqoSPMr+2KMJQEHYAd/AP8YgaovS8N1fJyh0=
example.com. 3600 CDNSKEY 257 3 8 AwEAAetE6qfN/GbtMmvM0PXUTyskauES2FKfjqLVz7EQlfS8iAFWLi1eHjHXDkueZ1OYRzQ4IBy6MIsce4XVXLQoS8njtfaU7c5NZvktH5la7JuH32KYr3PdWL5KDsUdED3GSxfNV+DbcYU80AZxTxy6Bm6EP+DztL1dpYrmqr8JRl+qlSbmLIrPemZFUEQzhiepcYMWviDUz+ixSVzjEzpMCLsrNxA30Ziiq9GKA8KKlFHdAmxuNcH0TzRndpo6bu5nKyJHiREIazHVuPBEzUmHtcWETCDs9UVsbji2Z2ozqLz9cqnfYV/kOD+OZBAqvZ0n/4lgdSiBtvByLCXoWEYIGRs=
example.com. 3600 CDS 53851 8 2 6F8129D687EC387C948E6F4B0AC9AA01481CCEBF7570AFEC582897E7725122D6
example.com. 3600 CDS 53852 8 2 6F8129D687EC387C948E6F4B0AC9AA01481CCEBF7570AFEC582897E7725122D6
dns2.example.com. 3600 A 192.0.2.1
;; Zone dump (Knot DNS 2.5.0-dev)
example.com. 3600 SOA dns2.example.com. hostmaster.example.com. 2010135808 10800 3600 1209600 7200
example.com. 3600 NS dns2.example.com.
example.com. 3600 MX 10 mail.example.com.
example.com. 3600 DNSKEY 256 3 8 AwEAAdKraxDdGTL4HDOkXTDI1Md1UdHuYhVwYkB+u2umVjTJ1H9Qb2oBryqwXI+gklnuCqrH1znkDvzGEAeHRQUCbtKbjmqErTAcRRHW3D+6jsOGXzbyGCfbyzRBwsbNCLWr3ONpPi5JOWEeCUJfyc/mRXcmh5uYl1JvzAM1zprtljZt
example.com. 3600 DNSKEY 257 3 8 AwEAAcQ1EqTPebcJyUnpxO3Xjx6ehRtsiZYToARoJsJG12XR6Ci9yy4SCCsejtaWIFO4XVfM2BHzFWqmABtQHtN7AazXAFMLsrSE4DYbgk5WmnQv5Jloi6jhhmmXwr8EOi3HR2jdG0gVq/Tax7ztNNZsflJrs3rZs2TVO00BkyyOkmO35jCNbGPUwm5cW1vse137BMa7jAcMyNLPIiQubj1/mJcIyzF2duvfpjBTgEmSvNcXqLfYFjK8lG4NodQG8AcK0MvWqN4mxW/hK0U9nMSjhCnfzPg5tjyqdheWRyhkLGjM/mR7gBhtqoSPMr+2KMJQEHYAd/AP8YgaovS8N1fJyh0=
example.com. 3600 DNSKEY 257 3 8 AwEAAetE6qfN/GbtMmvM0PXUTyskauES2FKfjqLVz7EQlfS8iAFWLi1eHjHXDkueZ1OYRzQ4IBy6MIsce4XVXLQoS8njtfaU7c5NZvktH5la7JuH32KYr3PdWL5KDsUdED3GSxfNV+DbcYU80AZxTxy6Bm6EP+DztL1dpYrmqr8JRl+qlSbmLIrPemZFUEQzhiepcYMWviDUz+ixSVzjEzpMCLsrNxA30Ziiq9GKA8KKlFHdAmxuNcH0TzRndpo6bu5nKyJHiREIazHVuPBEzUmHtcWETCDs9UVsbji2Z2ozqLz9cqnfYV/kOD+OZBAqvZ0n/4lgdSiBtvByLCXoWEYIGRs=
example.com. 3600 DNSKEY 257 3 8 AwEAAaulfU2biYVBiUsGwAyCXbA+gm0yWgH2Z71S16R2YNERlb0he9Od28DcFd0HbaKdFnw/CtX7Z2UWs6/IRu8QmHGn6SKDsLzZ5StdPsJDKilfvSlEcQeqrRAncug1SnA5BogNQSD0/02Yw5KDGn7ALCSYlNgOgy7l+D/urlkuxgsPWvqYXnlxaIcKt96fndwmkfZ5eF+WAqxguaNcvm146NA53wRrWx8BQbcHk1R+WcQGqFcVOlifCs9zV+87QJy2H660QKqOVDgt8PF8QmRRJqzOKpu29T+Vd1dM3zjBJ7deLaNH2E5p7Bbp1eeOCeOtWpCG6XfaRmZIF3ZWVM6Ways=
example.com. 3600 CDNSKEY 257 3 8 AwEAAcQ1EqTPebcJyUnpxO3Xjx6ehRtsiZYToARoJsJG12XR6Ci9yy4SCCsejtaWIFO4XVfM2BHzFWqmABtQHtN7AazXAFMLsrSE4DYbgk5WmnQv5Jloi6jhhmmXwr8EOi3HR2jdG0gVq/Tax7ztNNZsflJrs3rZs2TVO00BkyyOkmO35jCNbGPUwm5cW1vse137BMa7jAcMyNLPIiQubj1/mJcIyzF2duvfpjBTgEmSvNcXqLfYFjK8lG4NodQG8AcK0MvWqN4mxW/hK0U9nMSjhCnfzPg5tjyqdheWRyhkLGjM/mR7gBhtqoSPMr+2KMJQEHYAd/AP8YgaovS8N1fJyh0=
example.com. 3600 CDS 53851 8 2 6F8129D687EC387C948E6F4B0AC9AA01481CCEBF7570AFEC582897E7725122D6
example.com. 0 CDS 56474 8 2 260E7ADB07D1ECC40DEE79EFF6527CF7119C0AFC1CFA5DAC1ADFE342568CF32D
dns2.example.com. 3600 A 192.0.2.1
......@@ -41,9 +41,9 @@ if [ ! -x $KZONECHECK ]; then
fi
# error messages exported from knot/src/zone/semantic-check.c
CDNSKEY_MULTIPLE="multiple CDNSKEY records"
CDNSKEY_NONE="missing CDNSKEY"
CDS_MULTIPLE="multiple CDS records"
CDNSKEY_NO_CDS="CDNSKEY without corresponding CDS"
CDNSKEY_DELETE="invalid CDNSKEY/CDS for DNSSEC delete algorithm"
CDS_NONE="missing CDS"
CDS_NOT_MATCH="CDS not match CDNSKEY"
CNAME_EXTRA_RECORDS="more records exist at CNAME"
......@@ -115,8 +115,10 @@ expect_error "cdnskey.invalid.param" 0 1 "$CDS_NOT_MATCH"
expect_error "cdnskey.nocds" 0 1 "$CDS_NONE"
expect_error "cdnskey.nocdnskey" 0 1 "$CDNSKEY_NONE"
expect_error "cdnskey.nodnskey" 0 1 "$CDNSKEY_NOT_MATCH"
expect_error "cdnskey.two" 0 1 "$CDS_MULTIPLE"
expect_error "cdnskey.two" 0 1 "$CDNSKEY_MULTIPLE"
expect_error "cdnskey.orphan.cds" 0 1 "$CDS_NOT_MATCH"
expect_error "cdnskey.orphan.cdnskey" 0 1 "$CDNSKEY_NO_CDS"
expect_error "cdnskey.delete.invalid.cds" 0 1 "$CDNSKEY_DELETE"
expect_error "cdnskey.delete.invalid.cdnskey" 0 1 "$CDNSKEY_DELETE"
test_correct "rrsig_ttl.signed"
test_correct "no_error_delegaton_bitmap.signed"
......@@ -124,6 +126,7 @@ test_correct "no_error_nsec3_delegation.signed"
test_correct "no_error_nsec3_optout.signed"
test_correct "no_error_wildcard_glue.zone"
test_correct "cdnskey.cds"
test_correct "cdnskey.delete.both"
test_correct "dname_apex_nsec3.signed"
rm $LOG
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment