diff options
author | Simon Kelley <simon@thekelleys.org.uk> | 2013-12-31 13:57:21 +0000 |
---|---|---|
committer | Simon Kelley <simon@thekelleys.org.uk> | 2013-12-31 13:57:21 +0000 |
commit | 91dff77ee080ec76461ce17b81355ebb23fbe604 (patch) | |
tree | e4177a7d3f1f4be2d29664e695525d9a40848154 | |
parent | f5d4a4a169cf30f11c7d44096c664ddfa45a132d (diff) | |
parent | c3e0b9b6e75001ea2d24a4f67537ed77d0f0210c (diff) | |
download | dnsmasq-dnssec.tar.gz |
Merge branch 'dnssec' of ssh://thekelleys.org.uk/var/cache/git/dnsmasq into dnssecdnssec
Conflicts:
src/forward.c
-rw-r--r-- | CHANGELOG | 3 | ||||
-rw-r--r-- | src/cache.c | 20 | ||||
-rw-r--r-- | src/dhcp-common.c | 14 | ||||
-rw-r--r-- | src/dns-protocol.h | 6 | ||||
-rw-r--r-- | src/dnsmasq.c | 6 | ||||
-rw-r--r-- | src/dnsmasq.h | 16 | ||||
-rw-r--r-- | src/dnssec.c | 359 | ||||
-rw-r--r-- | src/forward.c | 14 | ||||
-rw-r--r-- | src/option.c | 10 | ||||
-rw-r--r-- | src/rfc1035.c | 9 | ||||
-rw-r--r-- | src/slaac.c | 1 |
11 files changed, 419 insertions, 39 deletions
@@ -4,6 +4,9 @@ version 2.69 on the BSD platform. Thanks to Matthias Andree for valuable research on how to implement this. + Fix infinite loop associated with some --bogus-nxdomain + configs. Thanks fogobogo for the bug report. + version 2.68 Use random addresses for DHCPv6 temporary address diff --git a/src/cache.c b/src/cache.c index 1338681..cfbeae3 100644 --- a/src/cache.c +++ b/src/cache.c @@ -26,7 +26,7 @@ static union bigname *big_free = NULL; static int bignames_left, hash_size; static int uid = 1; #ifdef HAVE_DNSSEC -static struct keydata *keyblock_free = NULL; +static struct blockdata *keyblock_free = NULL; #endif /* type->string mapping: this is also used by the name-hash function as a mixing table. */ @@ -198,7 +198,7 @@ static void cache_free(struct crec *crecp) } #ifdef HAVE_DNSSEC else if (crecp->flags & (F_DNSKEY | F_DS)) - keydata_free(crecp->addr.key.keydata); + blockdata_free(crecp->addr.key.keydata); #endif } @@ -1361,10 +1361,10 @@ void log_query(unsigned int flags, char *name, struct all_addr *addr, char *arg) } #ifdef HAVE_DNSSEC -struct keydata *keydata_alloc(char *data, size_t len) +struct blockdata *blockdata_alloc(char *data, size_t len) { - struct keydata *block, *ret = NULL; - struct keydata **prev = &ret; + struct blockdata *block, *ret = NULL; + struct blockdata **prev = &ret; size_t blen; while (len > 0) @@ -1375,12 +1375,12 @@ struct keydata *keydata_alloc(char *data, size_t len) keyblock_free = block->next; } else - block = whine_malloc(sizeof(struct keydata)); + block = whine_malloc(sizeof(struct blockdata)); if (!block) { /* failed to alloc, free partial chain */ - keydata_free(ret); + blockdata_free(ret); return NULL; } @@ -1396,7 +1396,7 @@ struct keydata *keydata_alloc(char *data, size_t len) return ret; } -size_t keydata_walk(struct keydata **key, unsigned char **p, size_t cnt) +size_t blockdata_walk(struct blockdata **key, unsigned char **p, size_t cnt) { if (*p == NULL) *p = (*key)->key; @@ -1411,9 +1411,9 @@ size_t keydata_walk(struct keydata **key, unsigned char **p, size_t cnt) return MIN(cnt, (*key)->key + KEYBLOCK_LEN - (*p)); } -void keydata_free(struct keydata *blocks) +void blockdata_free(struct blockdata *blocks) { - struct keydata *tmp; + struct blockdata *tmp; if (blocks) { diff --git a/src/dhcp-common.c b/src/dhcp-common.c index a92d728..3f9979e 100644 --- a/src/dhcp-common.c +++ b/src/dhcp-common.c @@ -399,13 +399,13 @@ void dhcp_update_configs(struct dhcp_config *configs) if (cache_find_by_name(crec, config->hostname, 0, cacheflags)) { /* use primary (first) address */ - while (crec && !(crec->flags & F_REVERSE)) - crec = cache_find_by_name(crec, config->hostname, 0, cacheflags); - if (!crec) - continue; /* should be never */ - inet_ntop(prot, &crec->addr.addr, daemon->addrbuff, ADDRSTRLEN); - my_syslog(MS_DHCP | LOG_WARNING, _("%s has more than one address in hostsfile, using %s for DHCP"), - config->hostname, daemon->addrbuff); + while (crec && !(crec->flags & F_REVERSE)) + crec = cache_find_by_name(crec, config->hostname, 0, cacheflags); + if (!crec) + continue; /* should be never */ + inet_ntop(prot, &crec->addr.addr, daemon->addrbuff, ADDRSTRLEN); + my_syslog(MS_DHCP | LOG_WARNING, _("%s has more than one address in hostsfile, using %s for DHCP"), + config->hostname, daemon->addrbuff); } if (prot == AF_INET && diff --git a/src/dns-protocol.h b/src/dns-protocol.h index 07cc768..efecb1c 100644 --- a/src/dns-protocol.h +++ b/src/dns-protocol.h @@ -140,3 +140,9 @@ struct dns_header { GETLONG(var, ptr); \ (len) -= 4; \ } while (0) + +#define CHECK_LEN(header, pp, plen, len) \ + ((size_t)((pp) - (unsigned char *)(header) + (len)) <= (plen)) + +#define ADD_RDLEN(header, pp, plen, len) \ + (!CHECK_LEN(header, pp, plen, len) ? 0 : (((pp) += (len)), 1)) diff --git a/src/dnsmasq.c b/src/dnsmasq.c index f5ce7df..3e5f51e 100644 --- a/src/dnsmasq.c +++ b/src/dnsmasq.c @@ -81,8 +81,14 @@ int main (int argc, char **argv) umask(022); /* known umask, create leases and pid files as 0644 */ read_opts(argc, argv, compile_opts); + +#ifdef HAVE_DNSSEC if (option_bool(OPT_DNSSEC_VALID)) if (daemon->doctors) exit(1); /* TODO */ + + daemon->keyname = safe_malloc(MAXDNAME); +#endif + if (daemon->edns_pktsz < PACKETSZ) daemon->edns_pktsz = option_bool(OPT_DNSSEC_VALID) ? EDNS_PKTSZ : PACKETSZ; daemon->packet_buff_sz = daemon->edns_pktsz > DNSMASQ_PACKETSZ ? diff --git a/src/dnsmasq.h b/src/dnsmasq.h index bde72e2..8a3541a 100644 --- a/src/dnsmasq.h +++ b/src/dnsmasq.h @@ -335,8 +335,8 @@ union bigname { union bigname *next; /* freelist */ }; -struct keydata { - struct keydata *next; +struct blockdata { + struct blockdata *next; unsigned char key[KEYBLOCK_LEN]; }; @@ -528,6 +528,7 @@ struct frec { unsigned int crc; time_t time; #ifdef HAVE_DNSSEC + int class; struct blockdata *stash; /* Saved reply, whilst we validate */ size_t stash_len; struct frec *dependent; /* Query awaiting internally-generated DNSKEY or DS query */ @@ -581,7 +582,7 @@ struct dhcp_lease { struct in6_addr addr6; int iaid; struct slaac_address { - struct in6_addr addr, local; + struct in6_addr addr; time_t ping_time; int backoff; /* zero -> confirmed */ struct slaac_address *next; @@ -900,6 +901,9 @@ extern struct daemon { char *packet; /* packet buffer */ int packet_buff_sz; /* size of above */ char *namebuff; /* MAXDNAME size buffer */ +#ifdef HAVE_DNSSEC + char *keyname; /* MAXDNAME size buffer */ +#endif unsigned int local_answer, queries_forwarded, auth_answer; struct frec *frec_list; struct serverfd *sfds; @@ -1030,7 +1034,11 @@ int in_zone(struct auth_zone *zone, char *name, char **cut); #endif /* dnssec.c */ -int dnssec_validate(int flags, struct dns_header *header, size_t plen); +size_t dnssec_generate_query(struct dns_header *header, char *name, int class, int type); +int dnssec_validate_by_ds(time_t now, struct dns_header *header, size_t n, char *name, char *keyname, int class); +int dnssec_validate_ds(time_t now, struct dns_header *header, size_t plen, char *name, char *keyname, int class); +int validate_rrset(time_t now, struct dns_header *header, size_t plen, int class, int type, char *name, char *keyname); +int dnssec_validate_reply(struct dns_header *header, size_t plen, char *name, char *keyname, int *class); /* util.c */ void rand_init(void); diff --git a/src/dnssec.c b/src/dnssec.c index a1f7856..4a91137 100644 --- a/src/dnssec.c +++ b/src/dnssec.c @@ -21,11 +21,15 @@ /* Maximum length in octects of a domain name, in wire format */ #define MAXCDNAME 256 +#define MAXRRSET 16 + #define SERIAL_UNDEF -100 #define SERIAL_EQ 0 #define SERIAL_LT -1 #define SERIAL_GT 1 +static int dnskey_keytag(int alg, unsigned char *rdata, int rdlen); + /* Implement RFC1982 wrapped compare for 32-bit numbers */ static int serial_compare_32(unsigned long s1, unsigned long s2) { @@ -494,7 +498,359 @@ static int digestalg_add_rdata(int sigtype, struct dns_header *header, size_t pk return 1; } +size_t dnssec_generate_query(struct dns_header *header, char *name, int class, int type) +{ + unsigned char *p; + + header->qdcount = htons(1); + header->ancount = htons(0); + header->nscount = htons(0); + header->arcount = htons(0); + + header->hb3 = HB3_RD; + SET_OPCODE(header, QUERY); + header->hb4 = 0; + + /* ID filled in later */ + + p = (unsigned char *)(header+1); + + p = do_rfc1035_name(p, name); + PUTSHORT(type, p); + PUTSHORT(class, p); + + return add_do_bit(header, p - (unsigned char *)header, ((char *) header) + PACKETSZ); +} + +/* The DNS packet is expected to contain the answer to a DNSKEY query + Put all DNSKEYs in the answer which are valid into the cache. + return codes: + STAT_INSECURE bad packet, no DNSKEYs in reply. + STAT_SECURE At least one valid DNSKEY found and in cache. + STAT_BOGUS At least one DNSKEY found, which fails validation. + STAT_NEED_DS DS records to validate a key not found, name in namebuff +*/ +int dnssec_validate_by_ds(time_t now, struct dns_header *header, size_t plen, char *name, char *keyname, int class) +{ + unsigned char *p; + struct crec *crecp, *recp1; + int j, qtype, qclass, ttl, rdlen, flags, protocol, algo, gotone; + struct blockdata *key; + + if (ntohs(header->qdcount) != 1) + return STAT_INSECURE; + + if (!extract_name(header, plen, &p, name, 1, 4)) + return STAT_INSECURE; + + GETSHORT(qtype, p); + GETSHORT(qclass, p); + + if (qtype != T_DNSKEY || qclass != class) + return STAT_INSECURE; + + cache_start_insert(); + + for (gotone = 0, j = ntohs(header->ancount); j != 0; j--) + { + /* Ensure we have type, class TTL and length */ + if (!extract_name(header, plen, &p, name, 1, 10)) + return STAT_INSECURE; /* bad packet */ + + GETSHORT(qtype, p); + GETSHORT(qclass, p); + GETLONG(ttl, p); + GETSHORT(rdlen, p); + + if (qclass != class || qtype != T_DNSKEY || rdlen < 4) + { + /* skip all records other than DNSKEY */ + p += rdlen; + continue; + } + + crecp = cache_find_by_name(NULL, name, now, F_DS); + + /* length at least covers flags, protocol and algo now. */ + GETSHORT(flags, p); + protocol = *p++; + algo = *p++; + + /* See if we have cached a DS record which validates this key */ + for (recp1 = crecp; recp1; recp1 = cache_find_by_name(recp1, name, now, F_DS)) + if (recp1->addr.key.algo == algo && is_supported_digest(recp1->addr.key.digest)) + break; + + /* DS record needed to validate key is missing, return name of DS in namebuff */ + if (!recp1) + return STAT_NEED_DS; + else + { + int valid = 1; + /* calculate digest of canonicalised DNSKEY data using digest in (recp1->addr.key.digest) + and see if it equals digest stored in recp1 + */ + + if (!valid) + return STAT_BOGUS; + } + + if ((key = blockdata_alloc((char*)p, rdlen))) + { + + /* We've proved that the KEY is OK, store it in the cache */ + if ((crecp = cache_insert(name, NULL, now, ttl, F_FORWARD | F_DNSKEY))) + { + crecp->uid = rdlen; + crecp->addr.key.keydata = key; + crecp->addr.key.algo = algo; + crecp->addr.key.keytag = dnskey_keytag(algo, (char*)p, rdlen); + gotone = 1; + } + } + + } + + cache_end_insert(); + + + return gotone ? STAT_SECURE : STAT_INSECURE; +} +/* The DNS packet is expected to contain the answer to a DS query + Put all DSs in the answer which are valid into the cache. + return codes: + STAT_INSECURE bad packet, no DNSKEYs in reply. + STAT_SECURE At least one valid DS found and in cache. + STAT_BOGUS At least one DS found, which fails validation. + STAT_NEED_DNSKEY DNSKEY records to validate a DS not found, name in keyname +*/ + +int dnssec_validate_ds(time_t now, struct dns_header *header, size_t plen, char *name, char *keyname, int class) +{ + unsigned char *p = (unsigned char *)(header+1); + struct crec *crecp, *recp1; + int qtype, qclass, val, j, gotone; + struct blockdata *key; + + if (ntohs(header->qdcount) != 1) + return STAT_INSECURE; + + if (!extract_name(header, plen, &p, name, 1, 4)) + return STAT_INSECURE; + + GETSHORT(qtype, p); + GETSHORT(qclass, p); + + if (qtype != T_DS || qclass != class) + return STAT_INSECURE; + + val = validate_rrset(header, plen, class, T_DS, name, keyname); + + /* failed to validate or missing key. */ + if (val != STAT_SECURE) + return val; + + cache_start_insert(); + + for (gotone = 0, j = ntohs(header->ancount); j != 0; j--) + { + int ttl, rdlen, rc, algo; + + /* Ensure we have type, class TTL and length */ + if (!(rc = extract_name(header, plen, &p, name, 0, 10))) + return STAT_INSECURE; /* bad packet */ + + GETSHORT(qtype, p); + GETSHORT(qclass, p); + GETLONG(ttl, p); + GETSHORT(rdlen, p); + + /* check type, class and name, skip if not in DS rrset */ + if (qclass != class || qtype != T_DS || rc == 2) + { + p += rdlen; + continue; + } + + if ((key = blockdata_alloc((char*)p, rdlen))) + { + + /* We've proved that the DS is OK, store it in the cache */ + if ((crecp = cache_insert(name, NULL, now, ttl, F_FORWARD | F_DS))) + { + crecp->uid = rdlen; + crecp->addr.key.keydata = key; + crecp->addr.key.algo = algo; + crecp->addr.key.keytag = dnskey_keytag(algo, (char*)p, rdlen); + gotone = 1; + } + } + + } + + cache_end_insert(); + + + return gotone ? STAT_SECURE : STAT_INSECURE; +} + + +/* Validate a single RRset (class, type, name) in the supplied DNS reply + Return code: + STAT_SECURE if it validates. + STAT_INSECURE can't validate (no RRSIG, bad packet). + STAT_BOGUS signature is wrong. + STAT_NEED_KEY need DNSKEY to complete validation (name is returned in keyname) +*/ +int validate_rrset(time_t now, struct dns_header *header, size_t plen, int class, int type, char *name, char *keyname) +{ + unsigned char *p, *psav, *sig; + int rrsetidx, res, sigttl, sig_data_len, j; + struct crec *crecp; + void *rrset[MAXRRSET]; /* TODO: max RRset size? */ + int type_covered, algo, labels, orig_ttl, sig_expiration, sig_inception, key_tag; + + if (!(p = skip_questions(header, plen))) + return STAT_INSECURE; + + /* look for an RRSIG record for this RRset and get pointers to each record */ + for (rrsetidx = 0, sig = NULL, j = ntohs(header->ancount) + ntohs(header->nscount); + j != 0; j--) + { + unsigned char *pstart = p; + int stype, sclass, sttl, rdlen; + + if (!(res = extract_name(header, plen, &p, name, 0, 10))) + return STAT_INSECURE; /* bad packet */ + + GETSHORT(stype, p); + GETSHORT(sclass, p); + GETLONG(sttl, p); + GETSHORT(rdlen, p); + + if (!CHECK_LEN(header, p, plen, rdlen)) + return STAT_INSECURE; /* bad packet */ + + if (res == 2 || htons(stype) != T_RRSIG || htons(sclass) != class) + continue; + + if (htons(stype) == type) + { + rrset[rrsetidx++] = pstart; + if (rrsetidx == MAXRRSET) + return STAT_INSECURE; /* RRSET too big TODO */ + } + + if (htons(stype) == T_RRSIG) + { + /* name matches, RRSIG for correct class */ + /* enough data? */ + if (rdlen < 18) + return STAT_INSECURE; + + GETSHORT(type_covered, p); + algo = *p++; + labels = *p++; + GETLONG(orig_ttl, p); + GETLONG(sig_expiration, p); + GETLONG(sig_inception, p); + GETSHORT(key_tag, p); + + if (type_covered != type || + !check_date_range(sig_inception, sig_expiration)) + { + /* covers wrong type or out of date - skip */ + p = psav; + if (!ADD_RDLEN(header, p, plen, rdlen)) + return STAT_INSECURE; + continue; + } + + if (!extract_name(header, plen, &p, keyname, 1, 0)) + return STAT_INSECURE; + + /* OK, we have the signature record, see if the + relevant DNSKEY is in the cache. */ + for (crecp = cache_find_by_name(NULL, keyname, now, F_DNSKEY); + crecp; + crecp = cache_find_by_name(crecp, keyname, now, F_DNSKEY)) + if (crecp->addr.key.algo == algo && crecp->addr.key.keytag == key_tag) + break; + + /* No, abort for now whilst we get it */ + if (!crecp) + return STAT_NEED_KEY; + + /* Save point to signature data */ + sig = p; + sig_data_len = rdlen - (p - psav); + sigttl = sttl; + + /* next record */ + p = psav; + if (!ADD_RDLEN(header, p, plen, rdlen)) + return STAT_INSECURE; + } + } + + /* Didn't find RRSIG or RRset is empty */ + if (!sig || rrsetidx == 0) + return STAT_INSECURE; + + /* OK, we have an RRSIG and an RRset and we have a the DNSKEY that validates them. */ + + /* Sort RRset records in canonical order. */ + rrset_canonical_order_ctx.header = header; + rrset_canonical_order_ctx.pktlen = plen; + qsort(rrset, rrsetidx, sizeof(void*), rrset_canonical_order); + + /* Now initialize the signature verification algorithm and process the whole + RRset */ + VerifyAlgCtx *alg = verifyalg_alloc(algo); + if (!alg) + return STAT_INSECURE; + + alg->sig = sig; + alg->siglen = sig_data_len; + + u16 ntype = htons(type); + u16 nclass = htons(class); + u32 nsigttl = htonl(sigttl); + + /* TODO: we shouldn't need to convert this to wire here. Best solution would be: + - Use process_name() instead of extract_name() everywhere in dnssec code + - Convert from wire format to representation format only for querying/storing cache + */ + unsigned char owner_wire[MAXCDNAME]; + int owner_wire_len = convert_domain_to_wire(name, owner_wire); + + digestalg_begin(alg->vtbl->digest_algo); + digestalg_add_data(sigrdata, 18+signer_name_rdlen); + for (i = 0; i < rrsetidx; ++i) + { + p = (unsigned char*)(rrset[i]); + + digestalg_add_data(owner_wire, owner_wire_len); + digestalg_add_data(&ntype, 2); + digestalg_add_data(&nclass, 2); + digestalg_add_data(&nsigttl, 4); + + p += 8; + if (!digestalg_add_rdata(ntohs(sigtype), header, pktlen, p)) + return 0; + } + int digest_len = digestalg_len(); + memcpy(alg->digest, digestalg_final(), digest_len); + + if (alg->vtbl->verify(alg, crecp->addr.key.keydata, crecp_uid)) + return STAT_SECURE; + + return STAT_INSECURE; +} + + +#if 0 static int begin_rrsig_validation(struct dns_header *header, size_t pktlen, unsigned char *reply, int count, char *owner, int sigclass, int sigrdlen, unsigned char *sig, @@ -624,6 +980,7 @@ static int end_rrsig_validation(PendingRRSIGValidation *val, struct crec *crec_d return val->alg->vtbl->verify(val->alg, crec_dnskey->addr.key.keydata, crec_dnskey->uid); } + static void dnssec_parserrsig(struct dns_header *header, size_t pktlen, unsigned char *reply, int count, char *owner, int sigclass, int sigrdlen, unsigned char *sig) @@ -663,6 +1020,8 @@ static void dnssec_parserrsig(struct dns_header *header, size_t pktlen, } } +#endif /* comment out */ + /* Compute keytag (checksum to quickly index a key). See RFC4034 */ static int dnskey_keytag(int alg, unsigned char *rdata, int rdlen) { diff --git a/src/forward.c b/src/forward.c index a549727..ad50783 100644 --- a/src/forward.c +++ b/src/forward.c @@ -678,15 +678,19 @@ void reply_query(int fd, int family, time_t now) if (option_bool(OPT_DNSSEC_VALID) && !(forward->flags & FREC_CHECKING_DISABLED)) { int status; - char rrbitmap[256/8]; int class; if (forward->flags & FREC_DNSKEY_QUERY) +<<<<<<< HEAD status = dnssec_validate_by_ds(header, n, daemon->namebuff, &class); else if (forward->flags & FREC_DS_QUERY) status = dnssec_validate_dnskey(header, n, daemon->namebuff, &class); +======= + status = dnssec_validate_by_ds(now, header, n, daemon->namebuff, daemon->keyname, forward->class); + else if (forward->flags & FREC_DS_QUERY) + status = dnssec_validate_ds(now, header, n, daemon->namebuff, daemon->keyname, forward->class); else - status = dnssec_validate_reply(&rrbitmap, header, n, daemon->namebuff, &class); + status = dnssec_validate_reply(header, n, daemon->namebuff, daemon->keyname, &forward->class); /* Can't validate, as we're missing key data. Put this answer aside, whilst we get that. */ @@ -761,9 +765,9 @@ void reply_query(int fd, int family, time_t now) if (status == STAT_SECURE) { if (forward->flags & FREC_DNSKEY_QUERY) - status = dnssec_validate_by_ds(header, n, daemon->namebuff, &class); + status = dnssec_validate_by_ds(now, header, n, daemon->namebuff, daemon->keyname, forward->class); else if (forward->flags & FREC_DS_QUERY) - status = dnssec_validate_dnskey(header, n, daemon->namebuff, &class); + status = dnssec_validate_dnskey(now, header, n, daemon->namebuff, daemon->keyname, forward->class); if (status == STAT_NEED_DS || status == STAT_NEED_KEY) my_syslog(LOG_ERR, _("Unexpected missing data for DNSSEC validation")); @@ -773,7 +777,7 @@ void reply_query(int fd, int family, time_t now) /* All DNSKEY and DS records done and in cache, now finally validate original answer, provided last DNSKEY is OK. */ if (status == STAT_SECURE) - status = dnssec_validate_reply(&rrbitmap, header, n, daemon->namebuff, &class); + status = dnssec_validate_reply(header, n, daemon->namebuff, daemon->keyname, &forward->class); if (status == STAT_SECURE) cache_secure = 1; diff --git a/src/option.c b/src/option.c index edc3ae4..cadabd5 100644 --- a/src/option.c +++ b/src/option.c @@ -2737,7 +2737,7 @@ static int one_opt(int option, char *arg, char *errstr, char *gen_err, int comma else { char *cp, *lastp = NULL, last = 0; - int fac = 1; + int fac = 1, isdig = 0; if (strlen(a[j]) > 1) { @@ -2768,9 +2768,11 @@ static int one_opt(int option, char *arg, char *errstr, char *gen_err, int comma } for (cp = a[j]; *cp; cp++) - if (!isdigit((unsigned char)*cp) && *cp != ' ') + if (isdigit((unsigned char)*cp)) + isdig = 1; + else if (*cp != ' ') break; - + if (*cp) { if (lastp) @@ -2792,7 +2794,7 @@ static int one_opt(int option, char *arg, char *errstr, char *gen_err, int comma new->domain = strip_hostname(new->hostname); } } - else + else if (isdig) { new->lease_time = atoi(a[j]) * fac; /* Leases of a minute or less confuse diff --git a/src/rfc1035.c b/src/rfc1035.c index 7321d96..e547782 100644 --- a/src/rfc1035.c +++ b/src/rfc1035.c @@ -16,13 +16,6 @@ #include "dnsmasq.h" - -#define CHECK_LEN(header, pp, plen, len) \ - ((size_t)((pp) - (unsigned char *)(header) + (len)) <= (plen)) - -#define ADD_RDLEN(header, pp, plen, len) \ - (!CHECK_LEN(header, pp, plen, len) ? 0 : (((pp) += (len)), 1)) - int extract_name(struct dns_header *header, size_t plen, unsigned char **pp, char *name, int isExtract, int extrabytes) { @@ -1299,7 +1292,7 @@ int check_for_bogus_wildcard(struct dns_header *header, size_t qlen, char *name, /* Found a bogus address. Insert that info here, since there no SOA record to get the ttl from in the normal processing */ cache_start_insert(); - cache_insert(name, NULL, now, ttl, F_IPV4 | F_FORWARD | F_NEG | F_NXDOMAIN | F_CONFIG); + cache_insert(name, NULL, now, ttl, F_IPV4 | F_FORWARD | F_NEG | F_NXDOMAIN); cache_end_insert(); return 1; diff --git a/src/slaac.c b/src/slaac.c index 43c2c38..7eb4236 100644 --- a/src/slaac.c +++ b/src/slaac.c @@ -93,7 +93,6 @@ void slaac_add_addrs(struct dhcp_lease *lease, time_t now, int force) slaac->ping_time = now; slaac->backoff = 1; slaac->addr = addr; - slaac->local = context->local6; /* Do RA's to prod it */ ra_start_unsolicted(now, context); } |