Compare commits

..
13 changed files with 296 additions and 43 deletions

No files matched your search

+19
View File
@@ -40,6 +40,25 @@ version 2.73
nameservers in the unsigned parts of the DNS tree nameservers in the unsigned parts of the DNS tree
which don't respond well to DNSSEC queries. which don't respond well to DNSSEC queries.
Add --log-queries=extra option, which makes logs easier
to search automatically.
Add --min-cache-ttl option. I've resisted this for a long
time, on the grounds that disbelieving TTLs is never a
good idea, but I've been persuaded that there are
sometimes reasons to do it. (Step forward, GFW).
To avoid misuse, there's a hard limit on the TTL
floor of one hour. Thansk to RinSatsuki for the patch.
Cope with multiple interfaces with the same link-local
address. (IPv6 addresses are scoped, so this is allowed.)
Thanks to Cory Benfield for help with this.
Add --dhcp-hostsdir. This allows addition of new host
configurations to a running dnsmasq instance much more
cheaply than having dnsmasq re-read all its existing
configuration each time.
version 2.72 version 2.72
Add ra-advrouter mode, for RFC-3775 mobile IPv6 support. Add ra-advrouter mode, for RFC-3775 mobile IPv6 support.
+19 -1
View File
@@ -81,6 +81,12 @@ the upstream DNS servers.
.B --max-cache-ttl=<time> .B --max-cache-ttl=<time>
Set a maximum TTL value for entries in the cache. Set a maximum TTL value for entries in the cache.
.TP .TP
.B --min-cache-ttl=<time>
Extend short TTL values to the time given when caching them. Note that
artificially extending TTL values is in general a bad idea, do not do it
unless you have a good reason, and understand what you are doing.
Dnsmasq limits the value of this option to one hour, unless recompiled.
.TP
.B --auth-ttl=<time> .B --auth-ttl=<time>
Set the TTL value returned in answers from the authoritative server. Set the TTL value returned in answers from the authoritative server.
.TP .TP
@@ -98,7 +104,10 @@ only, to stop dnsmasq daemonising in production, use
.B -k. .B -k.
.TP .TP
.B \-q, --log-queries .B \-q, --log-queries
Log the results of DNS queries handled by dnsmasq. Enable a full cache dump on receipt of SIGUSR1. Log the results of DNS queries handled by dnsmasq. Enable a full cache dump on receipt of SIGUSR1. If the argument "extra" is supplied, ie
.B --log-queries=extra
then the log has extra information at the start of each line.
This consists of a serial number which ties together the log lines associated with an individual query, and the IP address of the requestor.
.TP .TP
.B \-8, --log-facility=<facility> .B \-8, --log-facility=<facility>
Set the facility to which dnsmasq will send syslog entries, this Set the facility to which dnsmasq will send syslog entries, this
@@ -968,6 +977,15 @@ is given, then read all the files contained in that directory. The advantage of
using this option is the same as for --dhcp-hostsfile: the using this option is the same as for --dhcp-hostsfile: the
dhcp-optsfile will be re-read when dnsmasq receives SIGHUP. Note that dhcp-optsfile will be re-read when dnsmasq receives SIGHUP. Note that
it is possible to encode the information in a it is possible to encode the information in a
.TP
.B --dhcp-hostsdir=<path>
This is exactly equivalent to dhcp-hostfile, except for the following. The path MUST be a
directory, and not an individual file. Changed or new files within
the directory are read automatically, without the need to send SIGHUP.
If a file is deleted for changed after it has been read by dnsmasq, then the
host record it contained will remain until dnsmasq recieves a SIGHUP, or
is restarted; ie host records are only added dynamically.
.TP
.B --dhcp-boot .B --dhcp-boot
flag as DHCP options, using the options names bootfile-name, flag as DHCP options, using the options names bootfile-name,
server-ip-address and tftp-server. This allows these to be included server-ip-address and tftp-server. This allows these to be included
+4 -1
View File
@@ -413,7 +413,10 @@ size_t answer_auth(struct dns_header *header, char *limit, size_t qlen, time_t n
peer_addr->in.sin_port = 0; peer_addr->in.sin_port = 0;
#ifdef HAVE_IPV6 #ifdef HAVE_IPV6
else else
peer_addr->in6.sin6_port = 0; {
peer_addr->in6.sin6_port = 0;
peer_addr->in6.sin6_scope_id = 0;
}
#endif #endif
for (peers = daemon->auth_peers; peers; peers = peers->next) for (peers = daemon->auth_peers; peers; peers = peers->next)
+13 -2
View File
@@ -461,9 +461,11 @@ struct crec *cache_insert(char *name, struct all_addr *addr,
if (flags & (F_IPV4 | F_IPV6 | F_CNAME)) if (flags & (F_IPV4 | F_IPV6 | F_CNAME))
{ {
log_query(flags | F_UPSTREAM, name, addr, NULL); log_query(flags | F_UPSTREAM, name, addr, NULL);
/* Don;t mess with TTL for DNSSEC records. */ /* Don't mess with TTL for DNSSEC records. */
if (daemon->max_cache_ttl != 0 && daemon->max_cache_ttl < ttl) if (daemon->max_cache_ttl != 0 && daemon->max_cache_ttl < ttl)
ttl = daemon->max_cache_ttl; ttl = daemon->max_cache_ttl;
if (daemon->min_cache_ttl != 0 && daemon->min_cache_ttl > ttl)
ttl = daemon->min_cache_ttl;
} }
/* if previous insertion failed give up now. */ /* if previous insertion failed give up now. */
@@ -1638,7 +1640,16 @@ void log_query(unsigned int flags, char *name, struct all_addr *addr, char *arg)
if (strlen(name) == 0) if (strlen(name) == 0)
name = "."; name = ".";
my_syslog(LOG_INFO, "%s %s %s %s", source, name, verb, dest); if (option_bool(OPT_EXTRALOG))
{
int port = prettyprint_addr(daemon->log_source_addr, daemon->addrbuff2);
if (flags & F_NOEXTRA)
my_syslog(LOG_INFO, "* %s/%u %s %s %s %s", daemon->addrbuff2, port, source, name, verb, dest);
else
my_syslog(LOG_INFO, "%u %s/%u %s %s %s %s", daemon->log_display_id, daemon->addrbuff2, port, source, name, verb, dest);
}
else
my_syslog(LOG_INFO, "%s %s %s %s", source, name, verb, dest);
} }
+2
View File
@@ -17,6 +17,7 @@
#define FTABSIZ 150 /* max number of outstanding requests (default) */ #define FTABSIZ 150 /* max number of outstanding requests (default) */
#define MAX_PROCS 20 /* max no children for TCP requests */ #define MAX_PROCS 20 /* max no children for TCP requests */
#define CHILD_LIFETIME 150 /* secs 'till terminated (RFC1035 suggests > 120s) */ #define CHILD_LIFETIME 150 /* secs 'till terminated (RFC1035 suggests > 120s) */
#define TCP_MAX_QUERIES 100 /* Maximum number of queries per incoming TCP connection */
#define EDNS_PKTSZ 4096 /* default max EDNS.0 UDP packet from RFC5625 */ #define EDNS_PKTSZ 4096 /* default max EDNS.0 UDP packet from RFC5625 */
#define KEYBLOCK_LEN 40 /* choose to mininise fragmentation when storing DNSSEC keys */ #define KEYBLOCK_LEN 40 /* choose to mininise fragmentation when storing DNSSEC keys */
#define DNSSEC_WORK 50 /* Max number of queries to validate one question */ #define DNSSEC_WORK 50 /* Max number of queries to validate one question */
@@ -26,6 +27,7 @@
#define RANDOM_SOCKS 64 /* max simultaneous random ports */ #define RANDOM_SOCKS 64 /* max simultaneous random ports */
#define LEASE_RETRY 60 /* on error, retry writing leasefile after LEASE_RETRY seconds */ #define LEASE_RETRY 60 /* on error, retry writing leasefile after LEASE_RETRY seconds */
#define CACHESIZ 150 /* default cache size */ #define CACHESIZ 150 /* default cache size */
#define TTL_FLOOR_LIMIT 3600 /* don't allow --min-cache-ttl to raise TTL above this under any circumstances */
#define MAXLEASES 1000 /* maximum number of DHCP leases */ #define MAXLEASES 1000 /* maximum number of DHCP leases */
#define PING_WAIT 3 /* wait for ping address-in-use test */ #define PING_WAIT 3 /* wait for ping address-in-use test */
#define PING_CACHE_TIME 30 /* Ping test assumed to be valid this long. */ #define PING_CACHE_TIME 30 /* Ping test assumed to be valid this long. */
+25 -8
View File
@@ -93,6 +93,8 @@ int main (int argc, char **argv)
daemon->packet = safe_malloc(daemon->packet_buff_sz); daemon->packet = safe_malloc(daemon->packet_buff_sz);
daemon->addrbuff = safe_malloc(ADDRSTRLEN); daemon->addrbuff = safe_malloc(ADDRSTRLEN);
if (option_bool(OPT_EXTRALOG))
daemon->addrbuff2 = safe_malloc(ADDRSTRLEN);
#ifdef HAVE_DNSSEC #ifdef HAVE_DNSSEC
if (option_bool(OPT_DNSSEC_VALID)) if (option_bool(OPT_DNSSEC_VALID))
@@ -140,6 +142,9 @@ int main (int argc, char **argv)
set_option_bool(OPT_NOWILD); set_option_bool(OPT_NOWILD);
reset_option_bool(OPT_CLEVERBIND); reset_option_bool(OPT_CLEVERBIND);
} }
if (daemon->inotify_hosts)
die(_("dhcp-hostsdir not supported on this platform"), NULL, EC_BADCONF);
#endif #endif
if (option_bool(OPT_DNSSEC_VALID)) if (option_bool(OPT_DNSSEC_VALID))
@@ -314,13 +319,16 @@ int main (int argc, char **argv)
#ifdef HAVE_DNSSEC #ifdef HAVE_DNSSEC
blockdata_init(); blockdata_init();
#endif #endif
}
#ifdef HAVE_LINUX_NETWORK #ifdef HAVE_LINUX_NETWORK
if (!option_bool(OPT_NO_POLL)) if ((!option_bool(OPT_NO_POLL) && daemon->port != 0) ||
inotify_dnsmasq_init(); daemon->dhcp || daemon->doing_dhcp6)
inotify_dnsmasq_init();
else
daemon->inotifyfd = -1;
#endif #endif
}
if (option_bool(OPT_DBUS)) if (option_bool(OPT_DBUS))
#ifdef HAVE_DBUS #ifdef HAVE_DBUS
{ {
@@ -743,7 +751,7 @@ int main (int argc, char **argv)
#endif #endif
#ifdef HAVE_TFTP #ifdef HAVE_TFTP
if (option_bool(OPT_TFTP)) if (option_bool(OPT_TFTP))
{ {
#ifdef FD_SETSIZE #ifdef FD_SETSIZE
if (FD_SETSIZE < (unsigned)max_fd) if (FD_SETSIZE < (unsigned)max_fd)
@@ -868,7 +876,7 @@ int main (int argc, char **argv)
#if defined(HAVE_LINUX_NETWORK) #if defined(HAVE_LINUX_NETWORK)
FD_SET(daemon->netlinkfd, &rset); FD_SET(daemon->netlinkfd, &rset);
bump_maxfd(daemon->netlinkfd, &maxfd); bump_maxfd(daemon->netlinkfd, &maxfd);
if (daemon->port != 0 && !option_bool(OPT_NO_POLL)) if (daemon->inotifyfd != -1)
{ {
FD_SET(daemon->inotifyfd, &rset); FD_SET(daemon->inotifyfd, &rset);
bump_maxfd(daemon->inotifyfd, &maxfd); bump_maxfd(daemon->inotifyfd, &maxfd);
@@ -941,8 +949,11 @@ int main (int argc, char **argv)
#endif #endif
#ifdef HAVE_LINUX_NETWORK #ifdef HAVE_LINUX_NETWORK
if (daemon->port != 0 && !option_bool(OPT_NO_POLL) && FD_ISSET(daemon->inotifyfd, &rset) && inotify_check()) if (daemon->inotifyfd != -1 && FD_ISSET(daemon->inotifyfd, &rset) && inotify_check(now))
poll_resolv(1, 1, now); {
if (daemon->port != 0 && !option_bool(OPT_NO_POLL))
poll_resolv(1, 1, now);
}
#else #else
/* Check for changes to resolv files once per second max. */ /* Check for changes to resolv files once per second max. */
/* Don't go silent for long periods if the clock goes backwards. */ /* Don't go silent for long periods if the clock goes backwards. */
@@ -1383,6 +1394,9 @@ void clear_cache_and_reload(time_t now)
if (option_bool(OPT_ETHERS)) if (option_bool(OPT_ETHERS))
dhcp_read_ethers(); dhcp_read_ethers();
reread_dhcp(); reread_dhcp();
#ifdef HAVE_LINUX_NETWORK
set_dhcp_inotify();
#endif
dhcp_update_configs(daemon->dhcp_conf); dhcp_update_configs(daemon->dhcp_conf);
lease_update_from_configs(); lease_update_from_configs();
lease_update_file(now); lease_update_file(now);
@@ -1587,6 +1601,9 @@ static void check_dns_listeners(fd_set *set, time_t now)
} }
} }
close(confd); close(confd);
/* The child can use up to TCP_MAX_QUERIES ids, so skip that many. */
daemon->log_id += TCP_MAX_QUERIES;
} }
#endif #endif
else else
+19 -7
View File
@@ -238,7 +238,8 @@ struct event_desc {
#define OPT_DNSSEC_NO_SIGN 48 #define OPT_DNSSEC_NO_SIGN 48
#define OPT_LOCAL_SERVICE 49 #define OPT_LOCAL_SERVICE 49
#define OPT_LOOP_DETECT 50 #define OPT_LOOP_DETECT 50
#define OPT_LAST 51 #define OPT_EXTRALOG 51
#define OPT_LAST 52
/* extra flags for my_syslog, we use a couple of facilities since they are known /* extra flags for my_syslog, we use a couple of facilities since they are known
not to occupy the same bits as priorities, no matter how syslog.h is set up. */ not to occupy the same bits as priorities, no matter how syslog.h is set up. */
@@ -442,6 +443,7 @@ struct crec {
#define F_NO_RR (1u<<25) #define F_NO_RR (1u<<25)
#define F_IPSET (1u<<26) #define F_IPSET (1u<<26)
#define F_NSIGMATCH (1u<<27) #define F_NSIGMATCH (1u<<27)
#define F_NOEXTRA (1u<<28)
/* Values of uid in crecs with F_CONFIG bit set. */ /* Values of uid in crecs with F_CONFIG bit set. */
#define SRC_INTERFACE 0 #define SRC_INTERFACE 0
@@ -548,13 +550,17 @@ struct resolvc {
#endif #endif
}; };
/* adn-hosts parms from command-line (also dhcp-hostsfile and dhcp-optsfile */ /* adn-hosts parms from command-line (also dhcp-hostsfile and dhcp-optsfile and dhcp-hostsdir*/
#define AH_DIR 1 #define AH_DIR 1
#define AH_INACTIVE 2 #define AH_INACTIVE 2
#define AH_WD_DONE 4
struct hostsfile { struct hostsfile {
struct hostsfile *next; struct hostsfile *next;
int flags; int flags;
char *fname; char *fname;
#ifdef HAVE_LINUX_NETWORK
int wd; /* inotify watch descriptor */
#endif
unsigned int index; /* matches to cache entries for logging */ unsigned int index; /* matches to cache entries for logging */
}; };
@@ -599,7 +605,7 @@ struct frec {
#endif #endif
unsigned int iface; unsigned int iface;
unsigned short orig_id, new_id; unsigned short orig_id, new_id;
int fd, forwardall, flags; int log_id, fd, forwardall, flags;
time_t time; time_t time;
unsigned char *hash[HASH_SIZE]; unsigned char *hash[HASH_SIZE];
#ifdef HAVE_DNSSEC #ifdef HAVE_DNSSEC
@@ -941,7 +947,7 @@ extern struct daemon {
int max_logs; /* queue limit */ int max_logs; /* queue limit */
int cachesize, ftabsize; int cachesize, ftabsize;
int port, query_port, min_port; int port, query_port, min_port;
unsigned long local_ttl, neg_ttl, max_ttl, max_cache_ttl, auth_ttl; unsigned long local_ttl, neg_ttl, max_ttl, min_cache_ttl, max_cache_ttl, auth_ttl;
struct hostsfile *addn_hosts; struct hostsfile *addn_hosts;
struct dhcp_context *dhcp, *dhcp6; struct dhcp_context *dhcp, *dhcp6;
struct ra_interface *ra_interfaces; struct ra_interface *ra_interfaces;
@@ -959,7 +965,7 @@ extern struct daemon {
int doing_ra, doing_dhcp6; int doing_ra, doing_dhcp6;
struct dhcp_netid_list *dhcp_ignore, *dhcp_ignore_names, *dhcp_gen_names; struct dhcp_netid_list *dhcp_ignore, *dhcp_ignore_names, *dhcp_gen_names;
struct dhcp_netid_list *force_broadcast, *bootp_dynamic; struct dhcp_netid_list *force_broadcast, *bootp_dynamic;
struct hostsfile *dhcp_hosts_file, *dhcp_opts_file; struct hostsfile *dhcp_hosts_file, *dhcp_opts_file, *inotify_hosts;
int dhcp_max, tftp_max; int dhcp_max, tftp_max;
int dhcp_server_port, dhcp_client_port; int dhcp_server_port, dhcp_client_port;
int start_tftp_port, end_tftp_port; int start_tftp_port, end_tftp_port;
@@ -1002,6 +1008,8 @@ extern struct daemon {
struct randfd randomsocks[RANDOM_SOCKS]; struct randfd randomsocks[RANDOM_SOCKS];
int v6pktinfo; int v6pktinfo;
struct addrlist *interface_addrs; /* list of all addresses/prefix lengths associated with all local interfaces */ struct addrlist *interface_addrs; /* list of all addresses/prefix lengths associated with all local interfaces */
int log_id, log_display_id; /* ids of transactions for logging */
union mysockaddr *log_source_addr;
/* DHCP state */ /* DHCP state */
int dhcpfd, helperfd, pxefd; int dhcpfd, helperfd, pxefd;
@@ -1033,6 +1041,7 @@ extern struct daemon {
/* utility string buffer, hold max sized IP address as string */ /* utility string buffer, hold max sized IP address as string */
char *addrbuff; char *addrbuff;
char *addrbuff2; /* only allocated when OPT_EXTRALOG */
} *daemon; } *daemon;
@@ -1192,7 +1201,7 @@ void reset_option_bool(unsigned int opt);
struct hostsfile *expand_filelist(struct hostsfile *list); struct hostsfile *expand_filelist(struct hostsfile *list);
char *parse_server(char *arg, union mysockaddr *addr, char *parse_server(char *arg, union mysockaddr *addr,
union mysockaddr *source_addr, char *interface, int *flags); union mysockaddr *source_addr, char *interface, int *flags);
int option_read_hostsfile(char *file);
/* forward.c */ /* forward.c */
void reply_query(int fd, int family, time_t now); void reply_query(int fd, int family, time_t now);
void receive_query(struct listener *listen, time_t now); void receive_query(struct listener *listen, time_t now);
@@ -1481,5 +1490,8 @@ int detect_loop(char *query, int type);
/* inotify.c */ /* inotify.c */
#ifdef HAVE_LINUX_NETWORK #ifdef HAVE_LINUX_NETWORK
void inotify_dnsmasq_init(); void inotify_dnsmasq_init();
int inotify_check(void); int inotify_check(time_t now);
# ifdef HAVE_DHCP
void set_dhcp_inotify(void);
# endif
#endif #endif
+15 -8
View File
@@ -1038,7 +1038,7 @@ int dnssec_validate_by_ds(time_t now, struct dns_header *header, size_t plen, ch
else else
{ {
a.addr.keytag = keytag; a.addr.keytag = keytag;
log_query(F_KEYTAG | F_UPSTREAM, name, &a, "DNSKEY keytag %u"); log_query(F_NOEXTRA | F_KEYTAG | F_UPSTREAM, name, &a, "DNSKEY keytag %u");
recp1->addr.key.keylen = rdlen - 4; recp1->addr.key.keylen = rdlen - 4;
recp1->addr.key.keydata = key; recp1->addr.key.keydata = key;
@@ -1092,7 +1092,7 @@ int dnssec_validate_by_ds(time_t now, struct dns_header *header, size_t plen, ch
return STAT_SECURE; return STAT_SECURE;
} }
log_query(F_UPSTREAM, name, NULL, "BOGUS DNSKEY"); log_query(F_NOEXTRA | F_UPSTREAM, name, NULL, "BOGUS DNSKEY");
return STAT_BOGUS; return STAT_BOGUS;
} }
@@ -1136,7 +1136,7 @@ int dnssec_validate_ds(time_t now, struct dns_header *header, size_t plen, char
if (val == STAT_BOGUS) if (val == STAT_BOGUS)
{ {
log_query(F_UPSTREAM, name, NULL, "BOGUS DS"); log_query(F_NOEXTRA | F_UPSTREAM, name, NULL, "BOGUS DS");
return STAT_BOGUS; return STAT_BOGUS;
} }
@@ -1201,7 +1201,7 @@ int dnssec_validate_ds(time_t now, struct dns_header *header, size_t plen, char
cache_end_insert(); cache_end_insert();
log_query(F_UPSTREAM, name, NULL, nons ? "no delegation" : "no DS"); log_query(F_NOEXTRA | F_UPSTREAM, name, NULL, nons ? "no delegation" : "no DS");
} }
return nons ? STAT_NO_NS : STAT_NO_DS; return nons ? STAT_NO_NS : STAT_NO_DS;
@@ -1818,11 +1818,14 @@ int dnssec_validate_reply(time_t now, struct dns_header *header, size_t plen, ch
struct blockdata *key; struct blockdata *key;
struct crec *crecp; struct crec *crecp;
char *wildname; char *wildname;
int have_wildcard = 0;
rc = validate_rrset(now, header, plen, class1, type1, name, keyname, &wildname, NULL, 0, 0, 0); rc = validate_rrset(now, header, plen, class1, type1, name, keyname, &wildname, NULL, 0, 0, 0);
if (rc == STAT_SECURE_WILDCARD) if (rc == STAT_SECURE_WILDCARD)
{ {
have_wildcard = 1;
/* An attacker replay a wildcard answer with a different /* An attacker replay a wildcard answer with a different
answer and overlay a genuine RR. To prove this answer and overlay a genuine RR. To prove this
hasn't happened, the answer must prove that hasn't happened, the answer must prove that
@@ -1885,7 +1888,7 @@ int dnssec_validate_reply(time_t now, struct dns_header *header, size_t plen, ch
else else
{ {
a.addr.keytag = keytag; a.addr.keytag = keytag;
log_query(F_KEYTAG | F_UPSTREAM, name, &a, "DS keytag %u"); log_query(F_NOEXTRA | F_KEYTAG | F_UPSTREAM, name, &a, "DS keytag %u");
crecp->addr.ds.digest = digest; crecp->addr.ds.digest = digest;
crecp->addr.ds.keydata = key; crecp->addr.ds.keydata = key;
crecp->addr.ds.algo = algo; crecp->addr.ds.algo = algo;
@@ -1913,7 +1916,11 @@ int dnssec_validate_reply(time_t now, struct dns_header *header, size_t plen, ch
p2 += 13; /* labels, orig_ttl, expiration, inception */ p2 += 13; /* labels, orig_ttl, expiration, inception */
GETSHORT(keytag, p2); GETSHORT(keytag, p2);
if ((key = blockdata_alloc((char*)psave, rdlen2))) /* We don't cache sigs for wildcard answers, because to reproduce the
answer from the cache will require one or more NSEC/NSEC3 records
which we don't cache. The lack of the RRSIG ensures that a query for
this RRset asking for a secure answer will always be forwarded. */
if (!have_wildcard && (key = blockdata_alloc((char*)psave, rdlen2)))
{ {
if (!(crecp = cache_insert(name, &a, now, ttl, F_FORWARD | F_DNSKEY | F_DS))) if (!(crecp = cache_insert(name, &a, now, ttl, F_FORWARD | F_DNSKEY | F_DS)))
blockdata_free(key); blockdata_free(key);
@@ -2058,10 +2065,10 @@ size_t dnssec_generate_query(struct dns_header *header, char *end, char *name, i
char *types = querystr("dnssec-query", type); char *types = querystr("dnssec-query", type);
if (addr->sa.sa_family == AF_INET) if (addr->sa.sa_family == AF_INET)
log_query(F_DNSSEC | F_IPV4, name, (struct all_addr *)&addr->in.sin_addr, types); log_query(F_NOEXTRA | F_DNSSEC | F_IPV4, name, (struct all_addr *)&addr->in.sin_addr, types);
#ifdef HAVE_IPV6 #ifdef HAVE_IPV6
else else
log_query(F_DNSSEC | F_IPV6, name, (struct all_addr *)&addr->in6.sin6_addr, types); log_query(F_NOEXTRA | F_DNSSEC | F_IPV6, name, (struct all_addr *)&addr->in6.sin6_addr, types);
#endif #endif
header->qdcount = htons(1); header->qdcount = htons(1);
+27 -5
View File
@@ -279,10 +279,10 @@ static int forward_query(int udpfd, union mysockaddr *udpaddr,
plen = forward->stash_len; plen = forward->stash_len;
if (forward->sentto->addr.sa.sa_family == AF_INET) if (forward->sentto->addr.sa.sa_family == AF_INET)
log_query(F_DNSSEC | F_IPV4, "retry", (struct all_addr *)&forward->sentto->addr.in.sin_addr, "dnssec"); log_query(F_NOEXTRA | F_DNSSEC | F_IPV4, "retry", (struct all_addr *)&forward->sentto->addr.in.sin_addr, "dnssec");
#ifdef HAVE_IPV6 #ifdef HAVE_IPV6
else else
log_query(F_DNSSEC | F_IPV6, "retry", (struct all_addr *)&forward->sentto->addr.in6.sin6_addr, "dnssec"); log_query(F_NOEXTRA | F_DNSSEC | F_IPV6, "retry", (struct all_addr *)&forward->sentto->addr.in6.sin6_addr, "dnssec");
#endif #endif
if (forward->sentto->sfd) if (forward->sentto->sfd)
@@ -389,6 +389,9 @@ static int forward_query(int udpfd, union mysockaddr *udpaddr,
struct server *firstsentto = start; struct server *firstsentto = start;
int forwarded = 0; int forwarded = 0;
/* If a query is retried, use the log_id for the retry when logging the answer. */
forward->log_id = daemon->log_id;
if (option_bool(OPT_ADD_MAC)) if (option_bool(OPT_ADD_MAC))
plen = add_mac(header, plen, ((char *) header) + daemon->packet_buff_sz, &forward->source); plen = add_mac(header, plen, ((char *) header) + daemon->packet_buff_sz, &forward->source);
@@ -725,11 +728,16 @@ void reply_query(int fd, int family, time_t now)
if (!(forward = lookup_frec(ntohs(header->id), hash))) if (!(forward = lookup_frec(ntohs(header->id), hash)))
return; return;
/* log_query gets called indirectly all over the place, so
pass these in global variables - sorry. */
daemon->log_display_id = forward->log_id;
daemon->log_source_addr = &forward->source;
if (daemon->ignore_addr && RCODE(header) == NOERROR && if (daemon->ignore_addr && RCODE(header) == NOERROR &&
check_for_ignored_address(header, n, daemon->ignore_addr)) check_for_ignored_address(header, n, daemon->ignore_addr))
return; return;
if ((RCODE(header) == SERVFAIL || RCODE(header) == REFUSED) && if (RCODE(header) == REFUSED &&
!option_bool(OPT_ORDER) && !option_bool(OPT_ORDER) &&
forward->forwardall == 0) forward->forwardall == 0)
/* for broken servers, attempt to send to another one. */ /* for broken servers, attempt to send to another one. */
@@ -1258,6 +1266,11 @@ void receive_query(struct listener *listen, time_t now)
dst_addr_4.s_addr = 0; dst_addr_4.s_addr = 0;
} }
} }
/* log_query gets called indirectly all over the place, so
pass these in global variables - sorry. */
daemon->log_display_id = ++daemon->log_id;
daemon->log_source_addr = &source_addr;
if (extract_request(header, (size_t)n, daemon->namebuff, &type)) if (extract_request(header, (size_t)n, daemon->namebuff, &type))
{ {
@@ -1675,7 +1688,8 @@ unsigned char *tcp_request(int confd, time_t now,
struct in_addr dst_addr_4; struct in_addr dst_addr_4;
union mysockaddr peer_addr; union mysockaddr peer_addr;
socklen_t peer_len = sizeof(union mysockaddr); socklen_t peer_len = sizeof(union mysockaddr);
int query_count = 0;
if (getpeername(confd, (struct sockaddr *)&peer_addr, &peer_len) == -1) if (getpeername(confd, (struct sockaddr *)&peer_addr, &peer_len) == -1)
return packet; return packet;
@@ -1712,7 +1726,8 @@ unsigned char *tcp_request(int confd, time_t now,
while (1) while (1)
{ {
if (!packet || if (query_count == TCP_MAX_QUERIES ||
!packet ||
!read_write(confd, &c1, 1, 1) || !read_write(confd, &c2, 1, 1) || !read_write(confd, &c1, 1, 1) || !read_write(confd, &c2, 1, 1) ||
!(size = c1 << 8 | c2) || !(size = c1 << 8 | c2) ||
!read_write(confd, payload, size, 1)) !read_write(confd, payload, size, 1))
@@ -1721,6 +1736,13 @@ unsigned char *tcp_request(int confd, time_t now,
if (size < (int)sizeof(struct dns_header)) if (size < (int)sizeof(struct dns_header))
continue; continue;
query_count++;
/* log_query gets called indirectly all over the place, so
pass these in global variables - sorry. */
daemon->log_display_id = ++daemon->log_id;
daemon->log_source_addr = &peer_addr;
check_subnet = 0; check_subnet = 0;
/* save state of "cd" flag in query */ /* save state of "cd" flag in query */
+113 -6
View File
@@ -19,6 +19,11 @@
#include <sys/inotify.h> #include <sys/inotify.h>
#ifdef HAVE_DHCP
static void check_for_dhcp_inotify(struct inotify_event *in, time_t now);
#endif
/* the strategy is to set a inotify on the directories containing /* the strategy is to set a inotify on the directories containing
resolv files, for any files in the directory which are close-write resolv files, for any files in the directory which are close-write
or moved into the directory. or moved into the directory.
@@ -40,8 +45,6 @@ void inotify_dnsmasq_init()
struct resolvc *res; struct resolvc *res;
inotify_buffer = safe_malloc(INOTIFY_SZ); inotify_buffer = safe_malloc(INOTIFY_SZ);
daemon->inotifyfd = inotify_init1(IN_NONBLOCK | IN_CLOEXEC); daemon->inotifyfd = inotify_init1(IN_NONBLOCK | IN_CLOEXEC);
if (daemon->inotifyfd == -1) if (daemon->inotifyfd == -1)
@@ -66,6 +69,7 @@ void inotify_dnsmasq_init()
{ {
*d = 0; /* make path just directory */ *d = 0; /* make path just directory */
res->wd = inotify_add_watch(daemon->inotifyfd, path, IN_CLOSE_WRITE | IN_MOVED_TO); res->wd = inotify_add_watch(daemon->inotifyfd, path, IN_CLOSE_WRITE | IN_MOVED_TO);
res->file = d+1; /* pointer to filename */ res->file = d+1; /* pointer to filename */
*d = '/'; *d = '/';
@@ -78,7 +82,7 @@ void inotify_dnsmasq_init()
} }
} }
int inotify_check(void) int inotify_check(time_t now)
{ {
int hit = 0; int hit = 0;
@@ -101,13 +105,116 @@ int inotify_check(void)
for (res = daemon->resolv_files; res; res = res->next) for (res = daemon->resolv_files; res; res = res->next)
if (res->wd == in->wd && in->len != 0 && strcmp(res->file, in->name) == 0) if (res->wd == in->wd && in->len != 0 && strcmp(res->file, in->name) == 0)
hit = 1; hit = 1;
#ifdef HAVE_DHCP
if (daemon->dhcp || daemon->doing_dhcp6)
check_for_dhcp_inotify(in, now);
#endif
} }
} }
return hit; return hit;
} }
#endif #ifdef HAVE_DHCP
/* initialisation for dhcp-hostdir. Set inotify watch for each directory, and read pre-existing files */
void set_dhcp_inotify(void)
{
struct hostsfile *ah;
for (ah = daemon->inotify_hosts; ah; ah = ah->next)
{
DIR *dir_stream = NULL;
struct dirent *ent;
struct stat buf;
if (stat(ah->fname, &buf) == -1 || !(S_ISDIR(buf.st_mode)))
{
my_syslog(LOG_ERR, _("bad directory in dhcp-hostsdir %s"), ah->fname);
continue;
}
if (!(ah->flags & AH_WD_DONE))
{
ah->wd = inotify_add_watch(daemon->inotifyfd, ah->fname, IN_CLOSE_WRITE | IN_MOVED_TO);
ah->flags |= AH_WD_DONE;
}
/* Read contents of dir _after_ calling add_watch, in the ho[e of avoiding
a race which misses files being added as we start */
if (ah->wd == -1 || !(dir_stream = opendir(ah->fname)))
{
my_syslog(LOG_ERR, _("failed to create inotify for %s"), ah->fname);
continue;
}
while ((ent = readdir(dir_stream)))
{
size_t lendir = strlen(ah->fname);
size_t lenfile = strlen(ent->d_name);
char *path;
/* ignore emacs backups and dotfiles */
if (lenfile == 0 ||
ent->d_name[lenfile - 1] == '~' ||
(ent->d_name[0] == '#' && ent->d_name[lenfile - 1] == '#') ||
ent->d_name[0] == '.')
continue;
if ((path = whine_malloc(lendir + lenfile + 2)))
{
strcpy(path, ah->fname);
strcat(path, "/");
strcat(path, ent->d_name);
/* ignore non-regular files */
if (stat(path, &buf) != -1 && S_ISREG(buf.st_mode))
option_read_hostsfile(path);
free(path);
}
}
}
}
static void check_for_dhcp_inotify(struct inotify_event *in, time_t now)
{
struct hostsfile *ah;
/* ignore emacs backups and dotfiles */
if (in->len == 0 ||
in->name[in->len - 1] == '~' ||
(in->name[0] == '#' && in->name[in->len - 1] == '#') ||
in->name[0] == '.')
return;
for (ah = daemon->inotify_hosts; ah; ah = ah->next)
if (ah->wd == in->wd)
{
size_t lendir = strlen(ah->fname);
char *path;
if ((path = whine_malloc(lendir + in->len + 2)))
{
strcpy(path, ah->fname);
strcat(path, "/");
strcat(path, in->name);
if (option_read_hostsfile(path))
{
/* Propogate the consequences of loading a new dhcp-host */
dhcp_update_configs(daemon->dhcp_conf);
lease_update_from_configs();
lease_update_file(now);
lease_update_dns(1);
}
free(path);
}
return;
}
}
#endif /* DHCP */
#endif /* LINUX_NETWORK */
+38 -4
View File
@@ -148,6 +148,8 @@ struct myoption {
#define LOPT_DNSSEC_TIME 336 #define LOPT_DNSSEC_TIME 336
#define LOPT_LOOP_DETECT 337 #define LOPT_LOOP_DETECT 337
#define LOPT_IGNORE_ADDR 338 #define LOPT_IGNORE_ADDR 338
#define LOPT_MINCTTL 339
#define LOPT_DHCP_INOTIFY 340
#ifdef HAVE_GETOPT_LONG #ifdef HAVE_GETOPT_LONG
static const struct option opts[] = static const struct option opts[] =
@@ -160,7 +162,7 @@ static const struct myoption opts[] =
{ "no-poll", 0, 0, 'n' }, { "no-poll", 0, 0, 'n' },
{ "help", 0, 0, 'w' }, { "help", 0, 0, 'w' },
{ "no-daemon", 0, 0, 'd' }, { "no-daemon", 0, 0, 'd' },
{ "log-queries", 0, 0, 'q' }, { "log-queries", 2, 0, 'q' },
{ "user", 2, 0, 'u' }, { "user", 2, 0, 'u' },
{ "group", 2, 0, 'g' }, { "group", 2, 0, 'g' },
{ "resolv-file", 2, 0, 'r' }, { "resolv-file", 2, 0, 'r' },
@@ -246,6 +248,7 @@ static const struct myoption opts[] =
{ "interface-name", 1, 0, LOPT_INTNAME }, { "interface-name", 1, 0, LOPT_INTNAME },
{ "dhcp-hostsfile", 1, 0, LOPT_DHCP_HOST }, { "dhcp-hostsfile", 1, 0, LOPT_DHCP_HOST },
{ "dhcp-optsfile", 1, 0, LOPT_DHCP_OPTS }, { "dhcp-optsfile", 1, 0, LOPT_DHCP_OPTS },
{ "dhcp-hostsdir", 1, 0, LOPT_DHCP_INOTIFY },
{ "dhcp-no-override", 0, 0, LOPT_OVERRIDE }, { "dhcp-no-override", 0, 0, LOPT_OVERRIDE },
{ "tftp-port-range", 1, 0, LOPT_TFTPPORTS }, { "tftp-port-range", 1, 0, LOPT_TFTPPORTS },
{ "stop-dns-rebind", 0, 0, LOPT_REBIND }, { "stop-dns-rebind", 0, 0, LOPT_REBIND },
@@ -255,6 +258,7 @@ static const struct myoption opts[] =
{ "dhcp-broadcast", 2, 0, LOPT_BROADCAST }, { "dhcp-broadcast", 2, 0, LOPT_BROADCAST },
{ "neg-ttl", 1, 0, LOPT_NEGTTL }, { "neg-ttl", 1, 0, LOPT_NEGTTL },
{ "max-ttl", 1, 0, LOPT_MAXTTL }, { "max-ttl", 1, 0, LOPT_MAXTTL },
{ "min-cache-ttl", 1, 0, LOPT_MINCTTL },
{ "max-cache-ttl", 1, 0, LOPT_MAXCTTL }, { "max-cache-ttl", 1, 0, LOPT_MAXCTTL },
{ "dhcp-alternate-port", 2, 0, LOPT_ALTPORT }, { "dhcp-alternate-port", 2, 0, LOPT_ALTPORT },
{ "dhcp-scriptuser", 1, 0, LOPT_SCRIPTUSR }, { "dhcp-scriptuser", 1, 0, LOPT_SCRIPTUSR },
@@ -333,6 +337,7 @@ static struct {
{ 'G', ARG_DUP, "<hostspec>", gettext_noop("Set address or hostname for a specified machine."), NULL }, { 'G', ARG_DUP, "<hostspec>", gettext_noop("Set address or hostname for a specified machine."), NULL },
{ LOPT_DHCP_HOST, ARG_DUP, "<path>", gettext_noop("Read DHCP host specs from file."), NULL }, { LOPT_DHCP_HOST, ARG_DUP, "<path>", gettext_noop("Read DHCP host specs from file."), NULL },
{ LOPT_DHCP_OPTS, ARG_DUP, "<path>", gettext_noop("Read DHCP option specs from file."), NULL }, { LOPT_DHCP_OPTS, ARG_DUP, "<path>", gettext_noop("Read DHCP option specs from file."), NULL },
{ LOPT_DHCP_INOTIFY, ARG_DUP, "<path>", gettext_noop("Read DHCP host specs from a directory."), NULL },
{ LOPT_TAG_IF, ARG_DUP, "tag-expression", gettext_noop("Evaluate conditional tag expression."), NULL }, { LOPT_TAG_IF, ARG_DUP, "tag-expression", gettext_noop("Evaluate conditional tag expression."), NULL },
{ 'h', OPT_NO_HOSTS, NULL, gettext_noop("Do NOT load %s file."), HOSTSFILE }, { 'h', OPT_NO_HOSTS, NULL, gettext_noop("Do NOT load %s file."), HOSTSFILE },
{ 'H', ARG_DUP, "<path>", gettext_noop("Specify a hosts file to be read in addition to %s."), HOSTSFILE }, { 'H', ARG_DUP, "<path>", gettext_noop("Specify a hosts file to be read in addition to %s."), HOSTSFILE },
@@ -357,7 +362,7 @@ static struct {
{ LOPT_FORCE, ARG_DUP, "<optspec>", gettext_noop("DHCP option sent even if the client does not request it."), NULL}, { LOPT_FORCE, ARG_DUP, "<optspec>", gettext_noop("DHCP option sent even if the client does not request it."), NULL},
{ 'p', ARG_ONE, "<integer>", gettext_noop("Specify port to listen for DNS requests on (defaults to 53)."), NULL }, { 'p', ARG_ONE, "<integer>", gettext_noop("Specify port to listen for DNS requests on (defaults to 53)."), NULL },
{ 'P', ARG_ONE, "<integer>", gettext_noop("Maximum supported UDP packet size for EDNS.0 (defaults to %s)."), "*" }, { 'P', ARG_ONE, "<integer>", gettext_noop("Maximum supported UDP packet size for EDNS.0 (defaults to %s)."), "*" },
{ 'q', OPT_LOG, NULL, gettext_noop("Log DNS queries."), NULL }, { 'q', ARG_DUP, NULL, gettext_noop("Log DNS queries."), NULL },
{ 'Q', ARG_ONE, "<integer>", gettext_noop("Force the originating port for upstream DNS queries."), NULL }, { 'Q', ARG_ONE, "<integer>", gettext_noop("Force the originating port for upstream DNS queries."), NULL },
{ 'R', OPT_NO_RESOLV, NULL, gettext_noop("Do NOT read resolv.conf."), NULL }, { 'R', OPT_NO_RESOLV, NULL, gettext_noop("Do NOT read resolv.conf."), NULL },
{ 'r', ARG_DUP, "<path>", gettext_noop("Specify path to resolv.conf (defaults to %s)."), RESOLVFILE }, { 'r', ARG_DUP, "<path>", gettext_noop("Specify path to resolv.conf (defaults to %s)."), RESOLVFILE },
@@ -370,6 +375,8 @@ static struct {
{ 'T', ARG_ONE, "<integer>", gettext_noop("Specify time-to-live in seconds for replies from /etc/hosts."), NULL }, { 'T', ARG_ONE, "<integer>", gettext_noop("Specify time-to-live in seconds for replies from /etc/hosts."), NULL },
{ LOPT_NEGTTL, ARG_ONE, "<integer>", gettext_noop("Specify time-to-live in seconds for negative caching."), NULL }, { LOPT_NEGTTL, ARG_ONE, "<integer>", gettext_noop("Specify time-to-live in seconds for negative caching."), NULL },
{ LOPT_MAXTTL, ARG_ONE, "<integer>", gettext_noop("Specify time-to-live in seconds for maximum TTL to send to clients."), NULL }, { LOPT_MAXTTL, ARG_ONE, "<integer>", gettext_noop("Specify time-to-live in seconds for maximum TTL to send to clients."), NULL },
{ LOPT_MAXCTTL, ARG_ONE, "<integer>", gettext_noop("Specify time-to-live ceiling for cache."), NULL },
{ LOPT_MINCTTL, ARG_ONE, "<integer>", gettext_noop("Specify time-to-live floor for cache."), NULL },
{ 'u', ARG_ONE, "<username>", gettext_noop("Change to this user after startup. (defaults to %s)."), CHUSER }, { 'u', ARG_ONE, "<username>", gettext_noop("Change to this user after startup. (defaults to %s)."), CHUSER },
{ 'U', ARG_DUP, "set:<tag>,<class>", gettext_noop("Map DHCP vendor class to tag."), NULL }, { 'U', ARG_DUP, "set:<tag>,<class>", gettext_noop("Map DHCP vendor class to tag."), NULL },
{ 'v', 0, NULL, gettext_noop("Display dnsmasq version and copyright information."), NULL }, { 'v', 0, NULL, gettext_noop("Display dnsmasq version and copyright information."), NULL },
@@ -1705,8 +1712,9 @@ static int one_opt(int option, char *arg, char *errstr, char *gen_err, int comma
break; break;
#endif /* HAVE_DHCP */ #endif /* HAVE_DHCP */
case LOPT_DHCP_HOST: /* --dhcp-hostfile */ case LOPT_DHCP_HOST: /* --dhcp-hostsfile */
case LOPT_DHCP_OPTS: /* --dhcp-optsfile */ case LOPT_DHCP_OPTS: /* --dhcp-optsfile */
case LOPT_DHCP_INOTIFY: /* dhcp-hostsdir */
case 'H': /* --addn-hosts */ case 'H': /* --addn-hosts */
{ {
struct hostsfile *new = opt_malloc(sizeof(struct hostsfile)); struct hostsfile *new = opt_malloc(sizeof(struct hostsfile));
@@ -1729,6 +1737,12 @@ static int one_opt(int option, char *arg, char *errstr, char *gen_err, int comma
new->next = daemon->dhcp_opts_file; new->next = daemon->dhcp_opts_file;
daemon->dhcp_opts_file = new; daemon->dhcp_opts_file = new;
} }
else if (option == LOPT_DHCP_INOTIFY)
{
new->next = daemon->inotify_hosts;
daemon->inotify_hosts = new;
}
break; break;
} }
@@ -2421,6 +2435,12 @@ static int one_opt(int option, char *arg, char *errstr, char *gen_err, int comma
ret_err(gen_err); ret_err(gen_err);
break; break;
case 'q': /* --log-queries */
set_option_bool(OPT_LOG);
if (arg && strcmp(arg, "extra") == 0)
set_option_bool(OPT_EXTRALOG);
break;
case LOPT_MAX_LOGS: /* --log-async */ case LOPT_MAX_LOGS: /* --log-async */
daemon->max_logs = LOG_MAX; /* default */ daemon->max_logs = LOG_MAX; /* default */
if (arg && !atoi_check(arg, &daemon->max_logs)) if (arg && !atoi_check(arg, &daemon->max_logs))
@@ -2450,6 +2470,7 @@ static int one_opt(int option, char *arg, char *errstr, char *gen_err, int comma
case 'T': /* --local-ttl */ case 'T': /* --local-ttl */
case LOPT_NEGTTL: /* --neg-ttl */ case LOPT_NEGTTL: /* --neg-ttl */
case LOPT_MAXTTL: /* --max-ttl */ case LOPT_MAXTTL: /* --max-ttl */
case LOPT_MINCTTL: /* --min-cache-ttl */
case LOPT_MAXCTTL: /* --max-cache-ttl */ case LOPT_MAXCTTL: /* --max-cache-ttl */
case LOPT_AUTHTTL: /* --auth-ttl */ case LOPT_AUTHTTL: /* --auth-ttl */
{ {
@@ -2460,6 +2481,12 @@ static int one_opt(int option, char *arg, char *errstr, char *gen_err, int comma
daemon->neg_ttl = (unsigned long)ttl; daemon->neg_ttl = (unsigned long)ttl;
else if (option == LOPT_MAXTTL) else if (option == LOPT_MAXTTL)
daemon->max_ttl = (unsigned long)ttl; daemon->max_ttl = (unsigned long)ttl;
else if (option == LOPT_MINCTTL)
{
if (ttl > TTL_FLOOR_LIMIT)
ttl = TTL_FLOOR_LIMIT;
daemon->min_cache_ttl = (unsigned long)ttl;
}
else if (option == LOPT_MAXCTTL) else if (option == LOPT_MAXCTTL)
daemon->max_cache_ttl = (unsigned long)ttl; daemon->max_cache_ttl = (unsigned long)ttl;
else if (option == LOPT_AUTHTTL) else if (option == LOPT_AUTHTTL)
@@ -4024,6 +4051,13 @@ static void read_file(char *file, FILE *f, int hard_opt)
fclose(f); fclose(f);
} }
#ifdef HAVE_DHCP
int option_read_hostsfile(char *file)
{
return one_file(file, LOPT_BANK);
}
#endif
static int one_file(char *file, int hard_opt) static int one_file(char *file, int hard_opt)
{ {
FILE *f; FILE *f;
@@ -4121,7 +4155,7 @@ struct hostsfile *expand_filelist(struct hostsfile *list)
/* don't read this as a file */ /* don't read this as a file */
ah->flags |= AH_INACTIVE; ah->flags |= AH_INACTIVE;
if (!(dir_stream = opendir(ah->fname))) if (!(dir_stream = opendir(ah->fname)))
my_syslog(LOG_ERR, _("cannot access directory %s: %s"), my_syslog(LOG_ERR, _("cannot access directory %s: %s"),
ah->fname, strerror(errno)); ah->fname, strerror(errno));
+1 -1
View File
@@ -1643,7 +1643,7 @@ size_t answer_request(struct dns_header *header, char *limit, size_t qlen,
{ {
if (crecp->flags & F_NXDOMAIN) if (crecp->flags & F_NXDOMAIN)
nxdomain = 1; nxdomain = 1;
log_query(F_UPSTREAM, name, NULL, "secure no DS"); log_query(F_UPSTREAM, name, NULL, "no DS");
} }
else if ((keydata = blockdata_retrieve(crecp->addr.ds.keydata, crecp->addr.ds.keylen, NULL))) else if ((keydata = blockdata_retrieve(crecp->addr.ds.keydata, crecp->addr.ds.keylen, NULL)))
{ {
+1
View File
@@ -274,6 +274,7 @@ int sockaddr_isequal(union mysockaddr *s1, union mysockaddr *s2)
#ifdef HAVE_IPV6 #ifdef HAVE_IPV6
if (s1->sa.sa_family == AF_INET6 && if (s1->sa.sa_family == AF_INET6 &&
s1->in6.sin6_port == s2->in6.sin6_port && s1->in6.sin6_port == s2->in6.sin6_port &&
s1->in6.sin6_scope_id == s2->in6.sin6_scope_id &&
IN6_ARE_ADDR_EQUAL(&s1->in6.sin6_addr, &s2->in6.sin6_addr)) IN6_ARE_ADDR_EQUAL(&s1->in6.sin6_addr, &s2->in6.sin6_addr))
return 1; return 1;
#endif #endif