* Copyright (c) 1986, 1990 Regents of the University of California.
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. All advertising materials mentioning features or use of this software
* must display the following acknowledgement:
* This product includes software developed by the University of
* California, Berkeley and its contributors.
* 4. Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
static char sccsid
[] = "@(#)db_update.c 4.28 (Berkeley) 3/21/91";
#include <arpa/nameser.h>
extern struct timeval tt
;
extern struct sockaddr_in from_addr
; /* Source addr of last packet */
extern int needs_prime_cache
;
int max_cache_ttl
= (7*24*60*60); /* ONE_WEEK maximum ttl */
int min_cache_ttl
= (5*60); /* 5 minute minimum ttl */
* Update data base. Flags control the action.
* Inverse query tables modified.
db_update(name
, odp
, newdp
, flags
, htp
)
struct databuf
*odp
, *newdp
;
register struct namebuf
*np
;
register struct databuf
*dp
, *pdp
;
fprintf(ddt
,"db_update(%s, 0x%x, 0x%x, 0%o, 0x%x)%s\n",
name
, odp
, newdp
, flags
, htp
,
(odp
&& (odp
->d_flags
&DB_F_HINT
)) ? " hint":"" );
np
= nlookup(name
, &htp
, &fname
, newdp
!= NULL
);
if (np
== NULL
|| fname
!= name
)
/* Reflect certain updates in hint cache also... */
/* Don't stick data we are authoritative for in hints. */
if (!(flags
& DB_NOHINTS
) && (odp
!= NULL
) &&
(odp
->d_zone
<= 0) && !(odp
->d_flags
& DB_F_HINT
) &&
((name
[0] == '\0' && odp
->d_type
== T_NS
) ||
register struct databuf
*dp
;
fprintf(ddt
,"db_update: hint '%s' %d\n",
dp
= savedata(odp
->d_class
, odp
->d_type
, odp
->d_ttl
,
odp
->d_data
, odp
->d_size
);
if (db_update(name
, dp
,dp
, (flags
|DB_NOHINTS
), fcachetab
) != OK
) {
fprintf(ddt
, "db_update: hint %x freed\n", dp
);
for (dp
= np
->n_data
; dp
!= NULL
; ) {
if (!match(dp
, odp
->d_class
, odp
->d_type
)) {
if ((dp
->d_type
== T_CNAME
||
odp
->d_type
== T_CNAME
) &&
odp
->d_mark
== dp
->d_mark
&&
zones
[odp
->d_zone
].z_type
!= Z_CACHE
) {
"%s has CNAME and other data (illegal)\n",
"db_update: %s: CNAME and more (%d, %d)\n",
name
, odp
->d_type
, dp
->d_type
);
fprintf(ddt
,"db_update: flags = %#x, sizes = %d, %d (%d)\n",
flags
, odp
->d_size
, dp
->d_size
,
if (flags
& DB_NOTAUTH
&& dp
->d_zone
) {
"%s attempted update to auth zone %d '%s'\n",
inet_ntoa(from_addr
.sin_addr
),
dp
->d_zone
, zones
[dp
->d_zone
].z_origin
);
if ((flags
& DB_NODATA
) && !db_cmp(dp
, odp
)) {
/* refresh ttl if cache entry */
if (odp
->d_zone
!= 0) { /* XXX */
/* changing cache->auth */
dp
->d_zone
= odp
->d_zone
;
"db_update: cache entry now in auth zone\n");
if (odp
->d_ttl
> dp
->d_ttl
)
fprintf(ddt
,"db_update: new ttl %d, +%d\n",
dp
->d_ttl
, dp
->d_ttl
- tt
.tv_sec
);
* If the old databuf has some data, check that the
* data matches that in the new databuf (so UPDATED
* will delete only the matching RR)
dp
= rm_datum(dp
, np
, pdp
);
fprintf(ddt
,"db_update: adding%s %x\n",
(newdp
->d_flags
&DB_F_HINT
) ? " hint":"", newdp
);
if (!(newdp
->d_flags
& DB_F_HINT
))
addinv(np
, newdp
); /* modify inverse query tables */
/* Add to end of list, generally preserving order */
if ((dp
= np
->n_data
) == NULL
) {
/* XXX: need to check for duplicate WKS records and flag error */
while (dp
->d_next
!= NULL
) {
if ((flags
& DB_NODATA
) && !db_cmp(dp
, newdp
))
if ((flags
& DB_NODATA
) && !db_cmp(dp
, newdp
))
register struct databuf
*dp
;
if (dp
->d_zone
== 0 && !(dp
->d_flags
& DB_F_HINT
)) {
if (dp
->d_ttl
<= tt
.tv_sec
)
else if (dp
->d_ttl
< tt
.tv_sec
+min_cache_ttl
)
dp
->d_ttl
= tt
.tv_sec
+min_cache_ttl
;
else if (dp
->d_ttl
> tt
.tv_sec
+max_cache_ttl
)
dp
->d_ttl
= tt
.tv_sec
+max_cache_ttl
;
struct invbuf
*invtab
[INVHASHSZ
]; /* Inverse query hash table */
* Add data 'dp' to inverse query tables for name 'np'.
register struct invbuf
*ip
;
hval
= dhash(dp
->d_data
, dp
->d_size
);
for (ip
= invtab
[hval
]; ip
!= NULL
; ip
= ip
->i_next
)
for (i
= 0; i
< INVBLKSZ
; i
++)
if (ip
->i_dname
[i
] == NULL
) {
ip
->i_next
= invtab
[hval
];
* Remove data 'odp' from inverse query table.
register struct invbuf
*ip
;
register struct databuf
*dp
;
for (ip
= invtab
[dhash(odp
->d_data
, odp
->d_size
)]; ip
!= NULL
;
for (i
= 0; i
< INVBLKSZ
; i
++) {
if ((np
= ip
->i_dname
[i
]) == NULL
)
for (dp
= np
->n_data
; dp
!= NULL
; dp
= dp
->d_next
) {
if (!match(dp
, odp
->d_class
, odp
->d_type
))
ip
->i_dname
[i
] = ip
->i_dname
[i
+1];
* Compute hash value from data.
for (cp
= dp
; --n
>= 0; ) {
return (hval
% INVHASHSZ
);
* Compare type, class and data from databufs for equivalence.
* Must be case insensitive for some domain names.
* Return 0 if equivalent, nonzero otherwise.
register struct databuf
*dp1
, *dp2
;
register char *cp1
, *cp2
;
if (dp1
->d_type
!= dp2
->d_type
|| dp1
->d_class
!= dp2
->d_class
)
if (dp1
->d_size
!= dp2
->d_size
)
if (dp1
->d_mark
!= dp2
->d_mark
)
return(1); /* old and new RR's are distinct */
return(bcmp(dp1
->d_data
, dp2
->d_data
, dp1
->d_size
));
return(strcasecmp(dp1
->d_data
, dp2
->d_data
));
if (strncasecmp(++cp1
, ++cp2
, len
))
return(strncasecmp(++cp1
, ++cp2
, len
));
if (strcasecmp(dp1
->d_data
, dp2
->d_data
))
cp1
= dp1
->d_data
+ strlen(dp1
->d_data
) + 1;
cp2
= dp2
->d_data
+ strlen(dp2
->d_data
) + 1;
if (dp1
->d_type
!= T_SOA
)
return(strcasecmp(cp1
, cp2
));
if (strcasecmp(cp1
, cp2
))
return(bcmp(cp1
, cp2
, sizeof(u_long
) * 5));
if (*cp1
++ != *cp2
++ || *cp1
++ != *cp2
++) /* cmp prio */
return(strcasecmp(cp1
, cp2
));
if (dp1
->d_size
!= dp2
->d_size
)
return(bcmp(dp1
->d_data
, dp2
->d_data
, dp1
->d_size
));