~ubuntu-branches/ubuntu/karmic/pdnsd/karmic

« back to all changes in this revision

Viewing changes to src/hash.c

  • Committer: Bazaar Package Importer
  • Author(s): Michael Ablassmeier
  • Date: 2006-10-12 08:18:52 UTC
  • mfrom: (3.1.3 edgy)
  • Revision ID: james.westby@ubuntu.com-20061012081852-k70ha1vynt2vu7mg
Tags: 1.2.4par-0.2
* Non-maintainer upload.
* Check for bind named pidfile in initscript and do not
  try to startup, otherwise pdnsd installation bails
  out if named is running on the same host (Closes: #389609)
* add --no-create-home to adduser call.

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
1
/* hash.c - Manage hashes for cached dns records
 
2
 
2
3
   Copyright (C) 2000, 2001 Thomas Moestl
3
 
 
4
 
   With modifications by Paul Rombouts, 2003.
 
4
   Copyright (C) 2003, 2005 Paul A. Rombouts
5
5
 
6
6
This file is part of the pdnsd package.
7
7
 
29
29
#include "cache.h"
30
30
#include "error.h"
31
31
#include "helpers.h"
 
32
#include "consts.h"
32
33
 
33
34
#if !defined(lint) && !defined(NO_RCSIDS)
34
35
static char rcsid[]="$Id: hash.c,v 1.12 2001/06/02 23:08:13 tmm Exp $";
35
36
#endif
36
37
 
37
38
/* This is not a perfect hash, but I hope it holds. It is designed for 1024 hash
38
 
 * buckets, and hashes only strings with the allowed dns characters
39
 
 * [a-zA-Z0-9\-\.] = 64, but with case-insensitivity = 38
 
39
 * buckets, and hashes strings with case-insensitivity.
40
40
 * It is position-aware in a limited way. 
41
41
 * It is exactly seen a two-way hash: because I do not want to exaggerate
42
42
 * the hash buckets (i do have 1024), but I hash strings and string-comparisons
43
43
 * are expensive, I save another 32 bit hash in each hash element that is checked
44
 
 * before the string 
 
44
 * before the string. The 32 bit hash is also used to order the entries in a hash chain.
45
45
 * I hope not to have all too much collision concentration.
46
46
 *
47
47
 * The ip hash was removed. I don't think it concentrated the collisions too much.
50
50
 * Some measurements seem to indicate that the hash algorithm is doing reasonable well.
51
51
 */
52
52
 
53
 
static const unsigned char values[256]={
54
 
#include "hashconvtable.h"
55
 
};
56
 
 
57
 
/*
58
 
 * The hash structures are the same for an ip and an dns hash, so we use
59
 
 * an additional element in debug mode to report misuse.
60
 
 */
61
53
dns_hash_ent_t *hash_buckets[HASH_NUM_BUCKETS];
62
54
 
63
55
 
64
56
/*
65
 
 * Hash a dns name (dotted) to HASH_SZ bit.
66
 
 */
67
 
static long dns_shash(const unsigned char *str)
68
 
{
69
 
        unsigned long acc,i;
70
 
        unsigned char c;
71
 
        acc=0;
72
 
        for (i=0;(c=str[i]);i++) {
73
 
                acc+=values[c]<<(i%(HASH_SZ-5));
74
 
        }
75
 
        acc=(acc&HASH_BITMASK)+((acc&(~HASH_BITMASK))>>HASH_SZ);
76
 
        acc=(acc&HASH_BITMASK)+((acc&(~HASH_BITMASK))>>HASH_SZ);
77
 
#ifdef DEBUG_HASH
78
 
        printf("Diagnostic: dns hash for %s: %03lx\n",str,acc&HASH_BITMASK);
79
 
#endif
80
 
        return acc&HASH_BITMASK;
81
 
}
82
 
 
83
 
/*
84
 
 * Hash a dns name (dotted) to 32 bit.
85
 
 */
86
 
static unsigned long dns_rhash(const unsigned char *str)
87
 
{
88
 
        unsigned long acc,i;
89
 
        unsigned char c;
90
 
        acc=0;
91
 
        for (i=0;(c=str[i]);i++) {
92
 
                acc+=values[c]<<(i%25);
93
 
        }
94
 
#ifdef DEBUG_HASH
95
 
        printf("Diagnostic: dns rhash for %s: %04lx\n",str,acc);
96
 
#endif
97
 
        return acc;
 
57
 * Hash a dns name (length-byte string format) to HASH_SZ bit.
 
58
 * *rhash is set to a long int hash.
 
59
 */
 
60
static unsigned dns_hash(const unsigned char *str, unsigned long *rhash)
 
61
{
 
62
        unsigned s,i,lb,c;
 
63
        unsigned long r;
 
64
        s=0; r=0;
 
65
        i=0;
 
66
        while((lb=str[i])) {
 
67
                s+=lb<<(i%(HASH_SZ-5));
 
68
                r+=((unsigned long)lb)<<(i%(8*sizeof(unsigned long)-7));
 
69
                ++i;
 
70
                do {
 
71
                        c=toupper(str[i]);
 
72
                        s+=c<<(i%(HASH_SZ-5));
 
73
                        r+=((unsigned long)c)<<(i%(8*sizeof(unsigned long)-7));
 
74
                        ++i;
 
75
                } while(--lb);
 
76
        }
 
77
        s=(s&HASH_BITMASK)+((s&(~HASH_BITMASK))>>HASH_SZ);
 
78
        s=(s&HASH_BITMASK)+((s&(~HASH_BITMASK))>>HASH_SZ);
 
79
        s &= HASH_BITMASK;
 
80
#ifdef DEBUG_HASH
 
81
        {
 
82
                unsigned char buf[256];
 
83
                printf("Diagnostic: hashes for %s: %03x,%04lx\n",rhn2str(str,buf,sizeof(buf)),s,r);
 
84
        }
 
85
#endif
 
86
        if(rhash) *rhash=r;
 
87
        return s;
98
88
}
99
89
 
100
90
/*
101
91
 * Initialize hash to hold a dns hash table
102
92
 */
103
 
/* void mk_dns_hash()
 
93
/* This is now defined as an inline function in hash.h */
 
94
#if 0
 
95
void mk_dns_hash()
104
96
{
105
97
        int i;
106
98
        for(i=0;i<HASH_NUM_BUCKETS;i++)
107
99
                hash_buckets[i]=NULL;
108
 
} */
109
 
 
110
 
/*
111
 
 * Add an entry to the hash. data->qname is your key, data will be returned
112
 
 * by dns_lookup
113
 
 */
114
 
void add_dns_hash(dns_cent_t *data) 
115
 
{
116
 
        const unsigned char *key=data->qname;
117
 
        int idx=dns_shash(key);
 
100
}
 
101
#endif
 
102
 
 
103
/*
 
104
  Lookup in the hash table for key. If it is found, return the pointer to the cache entry.
 
105
  If no entry is found, return 0.
 
106
  If loc is not NULL, it will used to store information about the location within the hash table
 
107
  This can be used to add an entry with add_dns_hash() or delete the entry with del_dns_hash_ent().
 
108
*/
 
109
dns_cent_t *dns_lookup(const unsigned char *key, dns_hash_loc_t *loc)
 
110
{
 
111
        dns_cent_t *retval=NULL;
 
112
        unsigned idx;
 
113
        unsigned long rh;
 
114
        dns_hash_ent_t **hep,*he;
 
115
 
 
116
        idx = dns_hash(key,&rh);
 
117
        hep = &hash_buckets[idx];
 
118
        while ((he= *hep) && he->rhash<=rh) {
 
119
                if (he->rhash==rh && rhnicmp(key,he->data->qname)) {
 
120
                        retval = he->data;
 
121
                        break;
 
122
                }
 
123
                hep = &he->next;
 
124
        }
 
125
        if(loc) {
 
126
                loc->pos = hep;
 
127
                loc->rhash = rh;
 
128
        }
 
129
        return retval;
 
130
}
 
131
 
 
132
/*
 
133
  Add an entry to the hash.
 
134
  loc contains the location where the the new entry should be inserted
 
135
  (this location can be obtained with dns_lookup).
 
136
*/
 
137
void add_dns_hash(dns_cent_t *data, dns_hash_loc_t *loc) 
 
138
{
118
139
        dns_hash_ent_t *he;
 
140
 
119
141
        he=malloc(sizeof(dns_hash_ent_t));
120
142
        if (!he) {
121
143
                log_error("Out of memory.");
122
144
                pdnsd_exit();
123
145
        }
124
 
        he->next=hash_buckets[idx];
125
 
        he->rhash=dns_rhash(key);
126
 
        he->data=data;
127
 
        hash_buckets[idx]=he;
 
146
        he->next = *(loc->pos);
 
147
        he->rhash = loc->rhash;
 
148
        he->data = data;
 
149
        *(loc->pos) = he;
 
150
}
 
151
 
 
152
/*
 
153
  Delete the hash entry indentified by the location returned by dns_lookup().
 
154
*/
 
155
dns_cent_t *del_dns_hash_ent(dns_hash_loc_t *loc)
 
156
{
 
157
        dns_hash_ent_t *he = *(loc->pos);
 
158
        dns_cent_t *data;
 
159
 
 
160
        *(loc->pos) = he->next;
 
161
        data = he->data;
 
162
        free(he);
 
163
        return data;
128
164
}
129
165
 
130
166
/*
133
169
 */
134
170
dns_cent_t *del_dns_hash(const unsigned char *key) 
135
171
{
136
 
        int idx=dns_shash(key);
137
 
        unsigned long rh=dns_rhash(key);
 
172
        unsigned idx;
 
173
        unsigned long rh;
138
174
        dns_hash_ent_t **hep,*he;
139
175
        dns_cent_t *data;
140
 
        hep=&hash_buckets[idx];
141
 
        while ((he= *hep)) {
142
 
                if (he->rhash==rh && stricomp(key,he->data->qname)) {
143
 
                        *hep=he->next;
144
 
                        data=he->data;
 
176
 
 
177
        idx = dns_hash(key,&rh);
 
178
        hep = &hash_buckets[idx];
 
179
        while ((he= *hep) && he->rhash<=rh) {
 
180
                if (he->rhash==rh && rhnicmp(key,he->data->qname)) {
 
181
                        *hep = he->next;
 
182
                        data = he->data;
145
183
                        free(he);
146
184
                        return data;
147
185
                }
148
 
                hep=&he->next;
149
 
        }
150
 
        return NULL;   /* not found */
151
 
}
152
 
 
153
 
/*
154
 
 * Lookup in the hash table for key. If it is found, return the data pointer as given by
155
 
 * add_dns_hash. If no entry is found, return 0.
156
 
 */
157
 
dns_cent_t *dns_lookup(const unsigned char *key)
158
 
{
159
 
        int idx=dns_shash(key);
160
 
        unsigned long rh=dns_rhash(key);
161
 
        dns_hash_ent_t *he;
162
 
        he=hash_buckets[idx];
163
 
        while (he) {
164
 
                if (he->rhash==rh && stricomp(key,he->data->qname))
165
 
                        return he->data;
166
 
 
167
 
                he=he->next;
168
 
        }
169
 
        return NULL;   /* not found */
 
186
                hep = &he->next;
 
187
        }
 
188
        return NULL;   /* not found */
 
189
}
 
190
 
 
191
 
 
192
/*
 
193
 * Delete all entries in a hash bucket.
 
194
 */
 
195
void free_dns_hash_bucket(int i)
 
196
{
 
197
        dns_hash_ent_t *he,*hen;
 
198
 
 
199
        he=hash_buckets[i];
 
200
        hash_buckets[i]=NULL;
 
201
        while (he) {
 
202
                hen=he->next;
 
203
                del_cent(he->data);
 
204
                free(he);
 
205
                he=hen;
 
206
        }
 
207
}
 
208
 
 
209
/*
 
210
 * Delete all entries in a hash bucket whose names match those in
 
211
 * an include/exclude list.
 
212
 */
 
213
void free_dns_hash_selected(int i, slist_array sla)
 
214
{
 
215
        dns_hash_ent_t **hep,*he,*hen;
 
216
        int j,m=DA_NEL(sla);
 
217
 
 
218
        hep= &hash_buckets[i];
 
219
        he= *hep;
 
220
 
 
221
        while (he) {
 
222
                unsigned char *name=he->data->qname;
 
223
                for(j=0;j<m;++j) {
 
224
                        slist_t *sl=&DA_INDEX(sla,j);
 
225
                        int nrem,lrem;
 
226
                        domain_match(name,sl->domain,&nrem,&lrem);
 
227
                        if(!lrem && (!sl->exact || !nrem)) {
 
228
                                if(sl->rule==C_INCLUDED)
 
229
                                        goto delete_entry;
 
230
                                else
 
231
                                        break;
 
232
                        }
 
233
                }
 
234
                /* default policy is not to delete */
 
235
                hep= &he->next;
 
236
                he= *hep;
 
237
                continue;
 
238
 
 
239
        delete_entry:
 
240
                *hep=hen=he->next;;
 
241
                del_cent(he->data);
 
242
                free(he);
 
243
                he=hen;
 
244
        }
170
245
}
171
246
 
172
247
/*
178
253
        dns_hash_ent_t *he,*hen;
179
254
        for (i=0;i<HASH_NUM_BUCKETS;i++) {
180
255
                he=hash_buckets[i];
 
256
                hash_buckets[i]=NULL;
181
257
                while (he) {
 
258
                        hen=he->next;
182
259
                        del_cent(he->data);
183
 
                        hen=he->next;
184
260
                        free(he);
185
261
                        he=hen;
186
262
                }
230
306
        return NULL;
231
307
}
232
308
 
233
 
#ifdef DBGHASH
 
309
#ifdef DEBUG_HASH
234
310
void dumphash()
235
311
{
236
 
        int i, j;
237
 
        dns_hash_ent_t *he;
 
312
        if(debug_p) {
 
313
                int i, j;
 
314
                dns_hash_ent_t *he;
238
315
        
239
 
        for (i=0; i<HASH_NUM_BUCKETS; i++) {
240
 
                for (j=0, he=hash_buckets[i]; he; he=he->next, j++) ;
241
 
                DEBUG_MSG("bucket %d: %d entries\n", i, j);
 
316
                for (i=0; i<HASH_NUM_BUCKETS; i++) {
 
317
                        for (j=0, he=hash_buckets[i]; he; he=he->next, j++) ;
 
318
                        DEBUG_MSG("bucket %d: %d entries\n", i, j);
 
319
                }
242
320
        }
243
321
}
244
322
#endif