Home | History | Annotate | Line # | Download | only in validator
      1      1.1  christos /*
      2      1.1  christos  * validator/val_kentry.c - validator key entry definition.
      3      1.1  christos  *
      4      1.1  christos  * Copyright (c) 2007, NLnet Labs. All rights reserved.
      5      1.1  christos  *
      6      1.1  christos  * This software is open source.
      7      1.1  christos  *
      8      1.1  christos  * Redistribution and use in source and binary forms, with or without
      9      1.1  christos  * modification, are permitted provided that the following conditions
     10      1.1  christos  * are met:
     11      1.1  christos  *
     12      1.1  christos  * Redistributions of source code must retain the above copyright notice,
     13      1.1  christos  * this list of conditions and the following disclaimer.
     14      1.1  christos  *
     15      1.1  christos  * Redistributions in binary form must reproduce the above copyright notice,
     16      1.1  christos  * this list of conditions and the following disclaimer in the documentation
     17      1.1  christos  * and/or other materials provided with the distribution.
     18      1.1  christos  *
     19      1.1  christos  * Neither the name of the NLNET LABS nor the names of its contributors may
     20      1.1  christos  * be used to endorse or promote products derived from this software without
     21      1.1  christos  * specific prior written permission.
     22      1.1  christos  *
     23      1.1  christos  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
     24      1.1  christos  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
     25      1.1  christos  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
     26      1.1  christos  * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
     27      1.1  christos  * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
     28      1.1  christos  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
     29      1.1  christos  * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
     30      1.1  christos  * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
     31      1.1  christos  * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
     32      1.1  christos  * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
     33      1.1  christos  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
     34      1.1  christos  */
     35      1.1  christos 
     36      1.1  christos /**
     37      1.1  christos  * \file
     38      1.1  christos  *
     39      1.1  christos  * This file contains functions for dealing with validator key entries.
     40      1.1  christos  */
     41      1.1  christos #include "config.h"
     42      1.1  christos #include "validator/val_kentry.h"
     43      1.1  christos #include "util/data/packed_rrset.h"
     44      1.1  christos #include "util/data/dname.h"
     45      1.1  christos #include "util/storage/lookup3.h"
     46      1.1  christos #include "util/regional.h"
     47      1.1  christos #include "util/net_help.h"
     48      1.1  christos #include "sldns/rrdef.h"
     49      1.1  christos #include "sldns/keyraw.h"
     50      1.1  christos 
     51      1.1  christos size_t
     52      1.1  christos key_entry_sizefunc(void* key, void* data)
     53      1.1  christos {
     54      1.1  christos 	struct key_entry_key* kk = (struct key_entry_key*)key;
     55      1.1  christos 	struct key_entry_data* kd = (struct key_entry_data*)data;
     56      1.1  christos 	size_t s = sizeof(*kk) + kk->namelen;
     57      1.1  christos 	s += sizeof(*kd) + lock_get_mem(&kk->entry.lock);
     58      1.1  christos 	if(kd->rrset_data)
     59      1.1  christos 		s += packed_rrset_sizeof(kd->rrset_data);
     60      1.1  christos 	if(kd->reason)
     61      1.1  christos 		s += strlen(kd->reason)+1;
     62      1.1  christos 	if(kd->algo)
     63      1.1  christos 		s += strlen((char*)kd->algo)+1;
     64      1.1  christos 	return s;
     65      1.1  christos }
     66      1.1  christos 
     67      1.1  christos int
     68      1.1  christos key_entry_compfunc(void* k1, void* k2)
     69      1.1  christos {
     70      1.1  christos 	struct key_entry_key* n1 = (struct key_entry_key*)k1;
     71      1.1  christos 	struct key_entry_key* n2 = (struct key_entry_key*)k2;
     72      1.1  christos 	if(n1->key_class != n2->key_class) {
     73      1.1  christos 		if(n1->key_class < n2->key_class)
     74      1.1  christos 			return -1;
     75      1.1  christos 		return 1;
     76      1.1  christos 	}
     77      1.1  christos 	return query_dname_compare(n1->name, n2->name);
     78      1.1  christos }
     79      1.1  christos 
     80      1.1  christos void
     81      1.1  christos key_entry_delkeyfunc(void* key, void* ATTR_UNUSED(userarg))
     82      1.1  christos {
     83      1.1  christos 	struct key_entry_key* kk = (struct key_entry_key*)key;
     84      1.1  christos 	if(!key)
     85      1.1  christos 		return;
     86      1.1  christos 	lock_rw_destroy(&kk->entry.lock);
     87      1.1  christos 	free(kk->name);
     88      1.1  christos 	free(kk);
     89      1.1  christos }
     90      1.1  christos 
     91      1.1  christos void
     92      1.1  christos key_entry_deldatafunc(void* data, void* ATTR_UNUSED(userarg))
     93      1.1  christos {
     94      1.1  christos 	struct key_entry_data* kd = (struct key_entry_data*)data;
     95      1.1  christos 	free(kd->reason);
     96      1.1  christos 	free(kd->rrset_data);
     97      1.1  christos 	free(kd->algo);
     98      1.1  christos 	free(kd);
     99      1.1  christos }
    100      1.1  christos 
    101      1.1  christos void
    102      1.1  christos key_entry_hash(struct key_entry_key* kk)
    103      1.1  christos {
    104      1.1  christos 	kk->entry.hash = 0x654;
    105      1.1  christos 	kk->entry.hash = hashlittle(&kk->key_class, sizeof(kk->key_class),
    106      1.1  christos 		kk->entry.hash);
    107      1.1  christos 	kk->entry.hash = dname_query_hash(kk->name, kk->entry.hash);
    108      1.1  christos }
    109      1.1  christos 
    110      1.1  christos struct key_entry_key*
    111      1.1  christos key_entry_copy_toregion(struct key_entry_key* kkey, struct regional* region)
    112      1.1  christos {
    113      1.1  christos 	struct key_entry_key* newk;
    114      1.1  christos 	newk = regional_alloc_init(region, kkey, sizeof(*kkey));
    115      1.1  christos 	if(!newk)
    116      1.1  christos 		return NULL;
    117      1.1  christos 	newk->name = regional_alloc_init(region, kkey->name, kkey->namelen);
    118      1.1  christos 	if(!newk->name)
    119      1.1  christos 		return NULL;
    120      1.1  christos 	newk->entry.key = newk;
    121      1.1  christos 	if(newk->entry.data) {
    122      1.1  christos 		/* copy data element */
    123      1.1  christos 		struct key_entry_data *d = (struct key_entry_data*)
    124      1.1  christos 			kkey->entry.data;
    125      1.1  christos 		struct key_entry_data *newd;
    126      1.1  christos 		newd = regional_alloc_init(region, d, sizeof(*d));
    127      1.1  christos 		if(!newd)
    128      1.1  christos 			return NULL;
    129      1.1  christos 		/* copy rrset */
    130      1.1  christos 		if(d->rrset_data) {
    131      1.1  christos 			newd->rrset_data = regional_alloc_init(region,
    132      1.1  christos 				d->rrset_data,
    133      1.1  christos 				packed_rrset_sizeof(d->rrset_data));
    134      1.1  christos 			if(!newd->rrset_data)
    135      1.1  christos 				return NULL;
    136      1.1  christos 			packed_rrset_ptr_fixup(newd->rrset_data);
    137      1.1  christos 		}
    138      1.1  christos 		if(d->reason) {
    139      1.1  christos 			newd->reason = regional_strdup(region, d->reason);
    140      1.1  christos 			if(!newd->reason)
    141      1.1  christos 				return NULL;
    142      1.1  christos 		}
    143      1.1  christos 		if(d->algo) {
    144      1.1  christos 			newd->algo = (uint8_t*)regional_strdup(region,
    145      1.1  christos 				(char*)d->algo);
    146      1.1  christos 			if(!newd->algo)
    147      1.1  christos 				return NULL;
    148      1.1  christos 		}
    149      1.1  christos 		newk->entry.data = newd;
    150      1.1  christos 	}
    151      1.1  christos 	return newk;
    152      1.1  christos }
    153      1.1  christos 
    154      1.1  christos struct key_entry_key*
    155  1.1.1.3  christos key_entry_copy(struct key_entry_key* kkey, int copy_reason)
    156      1.1  christos {
    157      1.1  christos 	struct key_entry_key* newk;
    158      1.1  christos 	if(!kkey)
    159      1.1  christos 		return NULL;
    160      1.1  christos 	newk = memdup(kkey, sizeof(*kkey));
    161      1.1  christos 	if(!newk)
    162      1.1  christos 		return NULL;
    163      1.1  christos 	newk->name = memdup(kkey->name, kkey->namelen);
    164      1.1  christos 	if(!newk->name) {
    165      1.1  christos 		free(newk);
    166      1.1  christos 		return NULL;
    167      1.1  christos 	}
    168      1.1  christos 	lock_rw_init(&newk->entry.lock);
    169      1.1  christos 	newk->entry.key = newk;
    170      1.1  christos 	if(newk->entry.data) {
    171      1.1  christos 		/* copy data element */
    172      1.1  christos 		struct key_entry_data *d = (struct key_entry_data*)
    173      1.1  christos 			kkey->entry.data;
    174      1.1  christos 		struct key_entry_data *newd;
    175      1.1  christos 		newd = memdup(d, sizeof(*d));
    176      1.1  christos 		if(!newd) {
    177      1.1  christos 			free(newk->name);
    178      1.1  christos 			free(newk);
    179      1.1  christos 			return NULL;
    180      1.1  christos 		}
    181      1.1  christos 		/* copy rrset */
    182      1.1  christos 		if(d->rrset_data) {
    183      1.1  christos 			newd->rrset_data = memdup(d->rrset_data,
    184      1.1  christos 				packed_rrset_sizeof(d->rrset_data));
    185      1.1  christos 			if(!newd->rrset_data) {
    186      1.1  christos 				free(newd);
    187      1.1  christos 				free(newk->name);
    188      1.1  christos 				free(newk);
    189      1.1  christos 				return NULL;
    190      1.1  christos 			}
    191      1.1  christos 			packed_rrset_ptr_fixup(newd->rrset_data);
    192      1.1  christos 		}
    193  1.1.1.3  christos 		if(copy_reason && d->reason && *d->reason != 0) {
    194      1.1  christos 			newd->reason = strdup(d->reason);
    195      1.1  christos 			if(!newd->reason) {
    196      1.1  christos 				free(newd->rrset_data);
    197      1.1  christos 				free(newd);
    198      1.1  christos 				free(newk->name);
    199      1.1  christos 				free(newk);
    200      1.1  christos 				return NULL;
    201      1.1  christos 			}
    202  1.1.1.3  christos 		} else {
    203  1.1.1.3  christos 			newd->reason = NULL;
    204      1.1  christos 		}
    205      1.1  christos 		if(d->algo) {
    206      1.1  christos 			newd->algo = (uint8_t*)strdup((char*)d->algo);
    207      1.1  christos 			if(!newd->algo) {
    208      1.1  christos 				free(newd->rrset_data);
    209      1.1  christos 				free(newd->reason);
    210      1.1  christos 				free(newd);
    211      1.1  christos 				free(newk->name);
    212      1.1  christos 				free(newk);
    213      1.1  christos 				return NULL;
    214      1.1  christos 			}
    215      1.1  christos 		}
    216      1.1  christos 		newk->entry.data = newd;
    217      1.1  christos 	}
    218      1.1  christos 	return newk;
    219      1.1  christos }
    220      1.1  christos 
    221      1.1  christos int
    222      1.1  christos key_entry_isnull(struct key_entry_key* kkey)
    223      1.1  christos {
    224      1.1  christos 	struct key_entry_data* d = (struct key_entry_data*)kkey->entry.data;
    225      1.1  christos 	return (!d->isbad && d->rrset_data == NULL);
    226      1.1  christos }
    227      1.1  christos 
    228      1.1  christos int
    229      1.1  christos key_entry_isgood(struct key_entry_key* kkey)
    230      1.1  christos {
    231      1.1  christos 	struct key_entry_data* d = (struct key_entry_data*)kkey->entry.data;
    232      1.1  christos 	return (!d->isbad && d->rrset_data != NULL);
    233      1.1  christos }
    234      1.1  christos 
    235      1.1  christos int
    236      1.1  christos key_entry_isbad(struct key_entry_key* kkey)
    237      1.1  christos {
    238      1.1  christos 	struct key_entry_data* d = (struct key_entry_data*)kkey->entry.data;
    239      1.1  christos 	return (int)(d->isbad);
    240      1.1  christos }
    241      1.1  christos 
    242      1.1  christos char*
    243      1.1  christos key_entry_get_reason(struct key_entry_key* kkey)
    244      1.1  christos {
    245      1.1  christos 	struct key_entry_data* d = (struct key_entry_data*)kkey->entry.data;
    246      1.1  christos 	return d->reason;
    247      1.1  christos }
    248      1.1  christos 
    249  1.1.1.2  christos sldns_ede_code
    250  1.1.1.2  christos key_entry_get_reason_bogus(struct key_entry_key* kkey)
    251  1.1.1.2  christos {
    252  1.1.1.2  christos 	struct key_entry_data* d = (struct key_entry_data*)kkey->entry.data;
    253  1.1.1.2  christos 	return d->reason_bogus;
    254  1.1.1.2  christos 
    255  1.1.1.2  christos }
    256  1.1.1.2  christos 
    257      1.1  christos /** setup key entry in region */
    258      1.1  christos static int
    259      1.1  christos key_entry_setup(struct regional* region,
    260      1.1  christos 	uint8_t* name, size_t namelen, uint16_t dclass,
    261      1.1  christos 	struct key_entry_key** k, struct key_entry_data** d)
    262      1.1  christos {
    263      1.1  christos 	*k = regional_alloc(region, sizeof(**k));
    264      1.1  christos 	if(!*k)
    265      1.1  christos 		return 0;
    266      1.1  christos 	memset(*k, 0, sizeof(**k));
    267      1.1  christos 	(*k)->entry.key = *k;
    268      1.1  christos 	(*k)->name = regional_alloc_init(region, name, namelen);
    269      1.1  christos 	if(!(*k)->name)
    270      1.1  christos 		return 0;
    271      1.1  christos 	(*k)->namelen = namelen;
    272      1.1  christos 	(*k)->key_class = dclass;
    273      1.1  christos 	*d = regional_alloc(region, sizeof(**d));
    274      1.1  christos 	if(!*d)
    275      1.1  christos 		return 0;
    276      1.1  christos 	(*k)->entry.data = *d;
    277      1.1  christos 	return 1;
    278      1.1  christos }
    279      1.1  christos 
    280      1.1  christos struct key_entry_key*
    281      1.1  christos key_entry_create_null(struct regional* region,
    282      1.1  christos 	uint8_t* name, size_t namelen, uint16_t dclass, time_t ttl,
    283  1.1.1.3  christos 	sldns_ede_code reason_bogus, const char* reason,
    284      1.1  christos 	time_t now)
    285      1.1  christos {
    286      1.1  christos 	struct key_entry_key* k;
    287      1.1  christos 	struct key_entry_data* d;
    288      1.1  christos 	if(!key_entry_setup(region, name, namelen, dclass, &k, &d))
    289      1.1  christos 		return NULL;
    290      1.1  christos 	d->ttl = now + ttl;
    291      1.1  christos 	d->isbad = 0;
    292  1.1.1.3  christos 	d->reason = (!reason || *reason == 0)
    293  1.1.1.3  christos 		?NULL :(char*)regional_strdup(region, reason);
    294  1.1.1.3  christos 		/* On allocation error we don't store the reason string */
    295  1.1.1.3  christos 	d->reason_bogus = reason_bogus;
    296      1.1  christos 	d->rrset_type = LDNS_RR_TYPE_DNSKEY;
    297      1.1  christos 	d->rrset_data = NULL;
    298      1.1  christos 	d->algo = NULL;
    299      1.1  christos 	return k;
    300      1.1  christos }
    301      1.1  christos 
    302      1.1  christos struct key_entry_key*
    303      1.1  christos key_entry_create_rrset(struct regional* region,
    304      1.1  christos 	uint8_t* name, size_t namelen, uint16_t dclass,
    305  1.1.1.3  christos 	struct ub_packed_rrset_key* rrset, uint8_t* sigalg,
    306  1.1.1.3  christos 	sldns_ede_code reason_bogus, const char* reason,
    307  1.1.1.3  christos 	time_t now)
    308      1.1  christos {
    309      1.1  christos 	struct key_entry_key* k;
    310      1.1  christos 	struct key_entry_data* d;
    311      1.1  christos 	struct packed_rrset_data* rd = (struct packed_rrset_data*)
    312      1.1  christos 		rrset->entry.data;
    313      1.1  christos 	if(!key_entry_setup(region, name, namelen, dclass, &k, &d))
    314      1.1  christos 		return NULL;
    315      1.1  christos 	d->ttl = rd->ttl + now;
    316      1.1  christos 	d->isbad = 0;
    317  1.1.1.3  christos 	d->reason = (!reason || *reason == 0)
    318  1.1.1.3  christos 		?NULL :(char*)regional_strdup(region, reason);
    319  1.1.1.3  christos 		/* On allocation error we don't store the reason string */
    320  1.1.1.3  christos 	d->reason_bogus = reason_bogus;
    321      1.1  christos 	d->rrset_type = ntohs(rrset->rk.type);
    322      1.1  christos 	d->rrset_data = (struct packed_rrset_data*)regional_alloc_init(region,
    323      1.1  christos 		rd, packed_rrset_sizeof(rd));
    324      1.1  christos 	if(!d->rrset_data)
    325      1.1  christos 		return NULL;
    326      1.1  christos 	if(sigalg) {
    327      1.1  christos 		d->algo = (uint8_t*)regional_strdup(region, (char*)sigalg);
    328      1.1  christos 		if(!d->algo)
    329      1.1  christos 			return NULL;
    330      1.1  christos 	} else d->algo = NULL;
    331      1.1  christos 	packed_rrset_ptr_fixup(d->rrset_data);
    332      1.1  christos 	return k;
    333      1.1  christos }
    334      1.1  christos 
    335      1.1  christos struct key_entry_key*
    336      1.1  christos key_entry_create_bad(struct regional* region,
    337  1.1.1.3  christos 	uint8_t* name, size_t namelen, uint16_t dclass, time_t ttl,
    338  1.1.1.3  christos 	sldns_ede_code reason_bogus, const char* reason,
    339      1.1  christos 	time_t now)
    340      1.1  christos {
    341      1.1  christos 	struct key_entry_key* k;
    342      1.1  christos 	struct key_entry_data* d;
    343      1.1  christos 	if(!key_entry_setup(region, name, namelen, dclass, &k, &d))
    344      1.1  christos 		return NULL;
    345      1.1  christos 	d->ttl = now + ttl;
    346      1.1  christos 	d->isbad = 1;
    347  1.1.1.3  christos 	d->reason = (!reason || *reason == 0)
    348  1.1.1.3  christos 		?NULL :(char*)regional_strdup(region, reason);
    349  1.1.1.3  christos 		/* On allocation error we don't store the reason string */
    350  1.1.1.3  christos 	d->reason_bogus = reason_bogus;
    351      1.1  christos 	d->rrset_type = LDNS_RR_TYPE_DNSKEY;
    352      1.1  christos 	d->rrset_data = NULL;
    353      1.1  christos 	d->algo = NULL;
    354      1.1  christos 	return k;
    355      1.1  christos }
    356      1.1  christos 
    357      1.1  christos struct ub_packed_rrset_key*
    358      1.1  christos key_entry_get_rrset(struct key_entry_key* kkey, struct regional* region)
    359      1.1  christos {
    360      1.1  christos 	struct key_entry_data* d = (struct key_entry_data*)kkey->entry.data;
    361      1.1  christos 	struct ub_packed_rrset_key* rrk;
    362      1.1  christos 	struct packed_rrset_data* rrd;
    363      1.1  christos 	if(!d || !d->rrset_data)
    364      1.1  christos 		return NULL;
    365      1.1  christos 	rrk = regional_alloc(region, sizeof(*rrk));
    366      1.1  christos 	if(!rrk)
    367      1.1  christos 		return NULL;
    368      1.1  christos 	memset(rrk, 0, sizeof(*rrk));
    369      1.1  christos 	rrk->rk.dname = regional_alloc_init(region, kkey->name, kkey->namelen);
    370      1.1  christos 	if(!rrk->rk.dname)
    371      1.1  christos 		return NULL;
    372      1.1  christos 	rrk->rk.dname_len = kkey->namelen;
    373      1.1  christos 	rrk->rk.type = htons(d->rrset_type);
    374      1.1  christos 	rrk->rk.rrset_class = htons(kkey->key_class);
    375      1.1  christos 	rrk->entry.key = rrk;
    376      1.1  christos 	rrd = regional_alloc_init(region, d->rrset_data,
    377      1.1  christos 		packed_rrset_sizeof(d->rrset_data));
    378      1.1  christos 	if(!rrd)
    379      1.1  christos 		return NULL;
    380      1.1  christos 	rrk->entry.data = rrd;
    381      1.1  christos 	packed_rrset_ptr_fixup(rrd);
    382      1.1  christos 	return rrk;
    383      1.1  christos }
    384      1.1  christos 
    385      1.1  christos /** Get size of key in keyset */
    386      1.1  christos static size_t
    387      1.1  christos dnskey_get_keysize(struct packed_rrset_data* data, size_t idx)
    388      1.1  christos {
    389      1.1  christos 	unsigned char* pk;
    390      1.1  christos 	unsigned int pklen = 0;
    391      1.1  christos 	int algo;
    392      1.1  christos 	if(data->rr_len[idx] < 2+5)
    393      1.1  christos 		return 0;
    394      1.1  christos 	algo = (int)data->rr_data[idx][2+3];
    395      1.1  christos 	pk = (unsigned char*)data->rr_data[idx]+2+4;
    396      1.1  christos 	pklen = (unsigned)data->rr_len[idx]-2-4;
    397      1.1  christos 	return sldns_rr_dnskey_key_size_raw(pk, pklen, algo);
    398      1.1  christos }
    399      1.1  christos 
    400      1.1  christos /** get dnskey flags from data */
    401      1.1  christos static uint16_t
    402      1.1  christos kd_get_flags(struct packed_rrset_data* data, size_t idx)
    403      1.1  christos {
    404      1.1  christos 	uint16_t f;
    405      1.1  christos 	if(data->rr_len[idx] < 2+2)
    406      1.1  christos 		return 0;
    407      1.1  christos 	memmove(&f, data->rr_data[idx]+2, 2);
    408      1.1  christos 	f = ntohs(f);
    409      1.1  christos 	return f;
    410      1.1  christos }
    411      1.1  christos 
    412      1.1  christos size_t
    413      1.1  christos key_entry_keysize(struct key_entry_key* kkey)
    414      1.1  christos {
    415      1.1  christos 	struct packed_rrset_data* d;
    416      1.1  christos 	/* compute size of smallest ZSK key in the rrset */
    417      1.1  christos 	size_t i;
    418      1.1  christos 	size_t bits = 0;
    419      1.1  christos 	if(!key_entry_isgood(kkey))
    420      1.1  christos 		return 0;
    421      1.1  christos 	d = ((struct key_entry_data*)kkey->entry.data)->rrset_data;
    422      1.1  christos 	for(i=0; i<d->count; i++) {
    423      1.1  christos 		if(!(kd_get_flags(d, i) & DNSKEY_BIT_ZSK))
    424      1.1  christos 			continue;
    425      1.1  christos 		if(i==0 || dnskey_get_keysize(d, i) < bits)
    426      1.1  christos 			bits = dnskey_get_keysize(d, i);
    427      1.1  christos 	}
    428      1.1  christos 	return bits;
    429      1.1  christos }
    430