mirror of
http://thekelleys.org.uk/git/dnsmasq.git
synced 2026-11-12 16:50:54 +00:00
Compare commits
6
Commits
v2.93test1
...
v2.93test2
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
ed2ba5b07a | ||
|
|
729c16a8ac | ||
|
|
80acb76f46 | ||
|
|
f1fa05d754 | ||
|
|
b148ba4752 | ||
|
|
81f619612e |
No files matched your search
+5
-1
@@ -202,11 +202,15 @@ void *blockdata_retrieve(struct blockdata *block, size_t len, void *data)
|
|||||||
{
|
{
|
||||||
if (len > buff_len)
|
if (len > buff_len)
|
||||||
{
|
{
|
||||||
if (!(new = whine_malloc(len)))
|
blen = len + 1024;
|
||||||
|
if (!(new = whine_malloc(blen)))
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
if (buff)
|
if (buff)
|
||||||
free(buff);
|
free(buff);
|
||||||
|
|
||||||
buff = new;
|
buff = new;
|
||||||
|
buff_len = blen;
|
||||||
}
|
}
|
||||||
data = buff;
|
data = buff;
|
||||||
}
|
}
|
||||||
|
|||||||
+6
-5
@@ -864,6 +864,9 @@ int main (int argc, char **argv)
|
|||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
/* Don't start logging malloc before logging is set up. */
|
||||||
|
daemon->log_malloc = option_bool(OPT_LOG_MALLOC);
|
||||||
|
|
||||||
if (daemon->port == 0)
|
if (daemon->port == 0)
|
||||||
my_syslog(LOG_INFO, _("started, version %s DNS disabled"), VERSION);
|
my_syslog(LOG_INFO, _("started, version %s DNS disabled"), VERSION);
|
||||||
else
|
else
|
||||||
@@ -1977,11 +1980,11 @@ static void do_tcp_connection(struct listener *listener, time_t now, int slot)
|
|||||||
pid_t p;
|
pid_t p;
|
||||||
union mysockaddr tcp_addr;
|
union mysockaddr tcp_addr;
|
||||||
socklen_t tcp_len = sizeof(union mysockaddr);
|
socklen_t tcp_len = sizeof(union mysockaddr);
|
||||||
unsigned char *buff;
|
|
||||||
struct server *s;
|
struct server *s;
|
||||||
int flags, auth_dns = 0;
|
int flags, auth_dns = 0;
|
||||||
struct in_addr netmask;
|
struct in_addr netmask;
|
||||||
int pipefd[2];
|
int pipefd[2];
|
||||||
|
struct iovec tcpbuff;
|
||||||
#ifdef HAVE_LINUX_NETWORK
|
#ifdef HAVE_LINUX_NETWORK
|
||||||
unsigned char a = 0;
|
unsigned char a = 0;
|
||||||
#endif
|
#endif
|
||||||
@@ -2156,10 +2159,8 @@ static void do_tcp_connection(struct listener *listener, time_t now, int slot)
|
|||||||
if ((flags = fcntl(confd, F_GETFL, 0)) != -1)
|
if ((flags = fcntl(confd, F_GETFL, 0)) != -1)
|
||||||
while(retry_send(fcntl(confd, F_SETFL, flags & ~O_NONBLOCK)));
|
while(retry_send(fcntl(confd, F_SETFL, flags & ~O_NONBLOCK)));
|
||||||
|
|
||||||
buff = tcp_request(confd, now, &tcp_addr, netmask, auth_dns);
|
tcp_request(confd, now, &tcpbuff, &tcp_addr, netmask, auth_dns);
|
||||||
|
free(tcpbuff.iov_base);
|
||||||
if (buff)
|
|
||||||
free(buff);
|
|
||||||
|
|
||||||
for (s = daemon->servers; s; s = s->next)
|
for (s = daemon->servers; s; s = s->next)
|
||||||
if (s->tcpfd != -1)
|
if (s->tcpfd != -1)
|
||||||
|
|||||||
+12
-5
@@ -290,7 +290,8 @@ struct event_desc {
|
|||||||
#define OPT_AUTH_LOG 76
|
#define OPT_AUTH_LOG 76
|
||||||
#define OPT_LEASEQUERY 77
|
#define OPT_LEASEQUERY 77
|
||||||
#define OPT_LOG_ONLY_FAILED 78
|
#define OPT_LOG_ONLY_FAILED 78
|
||||||
#define OPT_LAST 79
|
#define OPT_LOG_MALLOC 79
|
||||||
|
#define OPT_LAST 80
|
||||||
|
|
||||||
#define OPTION_BITS (sizeof(unsigned int)*8)
|
#define OPTION_BITS (sizeof(unsigned int)*8)
|
||||||
#define OPTION_SIZE ( (OPT_LAST/OPTION_BITS)+((OPT_LAST%OPTION_BITS)!=0) )
|
#define OPTION_SIZE ( (OPT_LAST/OPTION_BITS)+((OPT_LAST%OPTION_BITS)!=0) )
|
||||||
@@ -1207,6 +1208,7 @@ extern struct daemon {
|
|||||||
int log_fac; /* log facility */
|
int log_fac; /* log facility */
|
||||||
char *log_file; /* optional log file */
|
char *log_file; /* optional log file */
|
||||||
int max_logs; /* queue limit */
|
int max_logs; /* queue limit */
|
||||||
|
int log_malloc; /* log malloc/realloc/free */
|
||||||
int randport_limit; /* Maximum number of source ports for query. */
|
int randport_limit; /* Maximum number of source ports for query. */
|
||||||
int cachesize, ftabsize;
|
int cachesize, ftabsize;
|
||||||
int port, query_port, min_port, max_port;
|
int port, query_port, min_port, max_port;
|
||||||
@@ -1495,8 +1497,12 @@ unsigned char *do_rfc1035_name(unsigned char *p, char *sval, char *limit);
|
|||||||
void *safe_malloc(size_t size);
|
void *safe_malloc(size_t size);
|
||||||
void safe_strncpy(char *dest, const char *src, size_t size);
|
void safe_strncpy(char *dest, const char *src, size_t size);
|
||||||
void safe_pipe(int *fd, int read_noblock);
|
void safe_pipe(int *fd, int read_noblock);
|
||||||
void *whine_malloc(size_t size);
|
#define whine_malloc(x) whine_malloc_real(__func__, __LINE__, (x))
|
||||||
void *whine_realloc(void *ptr, size_t size);
|
#define whine_realloc(x, y) whine_realloc_real(__func__, __LINE__, (x), (y))
|
||||||
|
#define free(x) free_real(__func__, __LINE__, (x))
|
||||||
|
void free_real(const char *func, unsigned int line, void *ptr);
|
||||||
|
void *whine_malloc_real(const char *func, unsigned int line, size_t size);
|
||||||
|
void *whine_realloc_real(const char *func, unsigned int line, void *ptr, size_t size);
|
||||||
int sa_len(union mysockaddr *addr);
|
int sa_len(union mysockaddr *addr);
|
||||||
int sockaddr_isequal(const union mysockaddr *s1, const union mysockaddr *s2);
|
int sockaddr_isequal(const union mysockaddr *s1, const union mysockaddr *s2);
|
||||||
int sockaddr_isnull(const union mysockaddr *s);
|
int sockaddr_isnull(const union mysockaddr *s);
|
||||||
@@ -1521,6 +1527,7 @@ int memcmp_masked(unsigned char *a, unsigned char *b, int len,
|
|||||||
int expand_buf(struct iovec *iov, size_t size);
|
int expand_buf(struct iovec *iov, size_t size);
|
||||||
char *print_mac(char *buff, unsigned char *mac, int len);
|
char *print_mac(char *buff, unsigned char *mac, int len);
|
||||||
int read_write(int fd, unsigned char *packet, int size, int rw);
|
int read_write(int fd, unsigned char *packet, int size, int rw);
|
||||||
|
int read_writev(int fd, struct iovec *iov, int iovcnt, int rw);
|
||||||
void close_fds(long max_fd, int spare1, int spare2, int spare3);
|
void close_fds(long max_fd, int spare1, int spare2, int spare3);
|
||||||
int wildcard_match(const char* wildcard, const char* match);
|
int wildcard_match(const char* wildcard, const char* match);
|
||||||
int wildcard_matchn(const char* wildcard, const char* match, int num);
|
int wildcard_matchn(const char* wildcard, const char* match, int num);
|
||||||
@@ -1563,8 +1570,8 @@ int tcp_from_udp(time_t now, int status, struct dns_header *header, ssize_t *n,
|
|||||||
int class, char *name, struct server *server,
|
int class, char *name, struct server *server,
|
||||||
int *keycount, int *validatecount);
|
int *keycount, int *validatecount);
|
||||||
#endif
|
#endif
|
||||||
unsigned char *tcp_request(int confd, time_t now,
|
void tcp_request(int confd, time_t now, struct iovec *bigbuff,
|
||||||
union mysockaddr *local_addr, struct in_addr netmask, int auth_dns);
|
union mysockaddr *local_addr, struct in_addr netmask, int auth_dns);
|
||||||
void server_gone(struct server *server);
|
void server_gone(struct server *server);
|
||||||
int send_from(int fd, int nowild, char *packet, size_t len,
|
int send_from(int fd, int nowild, char *packet, size_t len,
|
||||||
union mysockaddr *to, union all_addr *source,
|
union mysockaddr *to, union all_addr *source,
|
||||||
|
|||||||
+127
-126
@@ -135,9 +135,9 @@ static void log_query_mysockaddr(unsigned int flags, char *name, union mysockadd
|
|||||||
}
|
}
|
||||||
|
|
||||||
static void server_send(struct server *server, int fd,
|
static void server_send(struct server *server, int fd,
|
||||||
const void *header, size_t plen, int flags)
|
const void *header, size_t plen)
|
||||||
{
|
{
|
||||||
while (retry_send(sendto(fd, header, plen, flags,
|
while (retry_send(sendto(fd, header, plen, 0,
|
||||||
&server->addr.sa,
|
&server->addr.sa,
|
||||||
sa_len(&server->addr))));
|
sa_len(&server->addr))));
|
||||||
}
|
}
|
||||||
@@ -1074,7 +1074,7 @@ static void dnssec_validate(struct frec *forward, struct dns_header *header,
|
|||||||
set_outgoing_mark(orig, fd);
|
set_outgoing_mark(orig, fd);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
server_send(server, fd, header, nn, 0);
|
server_send(server, fd, header, nn);
|
||||||
server->queries++;
|
server->queries++;
|
||||||
#ifdef HAVE_DUMPFILE
|
#ifdef HAVE_DUMPFILE
|
||||||
dump_packet_udp(DUMP_SEC_QUERY, (void *)header, (size_t)nn, NULL, &server->addr, fd);
|
dump_packet_udp(DUMP_SEC_QUERY, (void *)header, (size_t)nn, NULL, &server->addr, fd);
|
||||||
@@ -2018,20 +2018,21 @@ void receive_query(struct listener *listen, time_t now)
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/* Send query in packet, qsize to a server determined by first,last,start and
|
/* Send query in header, qsize to a server determined by first,last,start and
|
||||||
get the reply. return reply size. */
|
get the reply into the buffer passed by outbuff. Return reply size. */
|
||||||
static ssize_t tcp_talk(int first, int last, int start, unsigned char *packet, size_t qsize,
|
static ssize_t tcp_talk(int first, int last, int start, struct dns_header *header, size_t qsize,
|
||||||
int have_mark, unsigned int mark, struct server **servp)
|
struct iovec *recvbuff, int have_mark, unsigned int mark, struct server **servp)
|
||||||
{
|
{
|
||||||
int firstsendto = -1;
|
int firstsendto = -1;
|
||||||
u16 *length = (u16 *)packet;
|
u16 length;
|
||||||
unsigned char *payload = &packet[2];
|
unsigned int rsize = 0;
|
||||||
struct dns_header *header = (struct dns_header *)payload;
|
|
||||||
unsigned int rsize;
|
|
||||||
int class, rclass, type, rtype;
|
int class, rclass, type, rtype;
|
||||||
unsigned char *p;
|
unsigned char *p;
|
||||||
struct blockdata *saved_question;
|
|
||||||
struct timeval tv;
|
struct timeval tv;
|
||||||
|
struct iovec sendio[2];
|
||||||
|
#ifdef MSG_FASTOPEN
|
||||||
|
struct msghdr msg;
|
||||||
|
#endif
|
||||||
|
|
||||||
(void)mark;
|
(void)mark;
|
||||||
(void)have_mark;
|
(void)have_mark;
|
||||||
@@ -2043,9 +2044,11 @@ static ssize_t tcp_talk(int first, int last, int start, unsigned char *packet,
|
|||||||
GETSHORT(type, p);
|
GETSHORT(type, p);
|
||||||
GETSHORT(class, p);
|
GETSHORT(class, p);
|
||||||
|
|
||||||
/* Save question for retry. */
|
length = htons(qsize);
|
||||||
if (!(saved_question = blockdata_alloc((char *)header, (size_t)qsize)))
|
sendio[0].iov_base = &length;
|
||||||
return 0;
|
sendio[0].iov_len = sizeof(length);
|
||||||
|
sendio[1].iov_base = header;
|
||||||
|
sendio[1].iov_len = qsize;
|
||||||
|
|
||||||
while (1)
|
while (1)
|
||||||
{
|
{
|
||||||
@@ -2068,10 +2071,6 @@ static ssize_t tcp_talk(int first, int last, int start, unsigned char *packet,
|
|||||||
*servp = serv = daemon->serverarray[start];
|
*servp = serv = daemon->serverarray[start];
|
||||||
|
|
||||||
retry:
|
retry:
|
||||||
blockdata_retrieve(saved_question, qsize, header);
|
|
||||||
|
|
||||||
*length = htons(qsize);
|
|
||||||
|
|
||||||
if (serv->tcpfd == -1)
|
if (serv->tcpfd == -1)
|
||||||
{
|
{
|
||||||
if ((serv->tcpfd = socket(serv->addr.sa.sa_family, SOCK_STREAM, 0)) == -1)
|
if ((serv->tcpfd = socket(serv->addr.sa.sa_family, SOCK_STREAM, 0)) == -1)
|
||||||
@@ -2102,9 +2101,16 @@ static ssize_t tcp_talk(int first, int last, int start, unsigned char *packet,
|
|||||||
tv.tv_sec += TCP_TIMEOUT;
|
tv.tv_sec += TCP_TIMEOUT;
|
||||||
setsockopt(serv->tcpfd, SOL_SOCKET, SO_RCVTIMEO, &tv, sizeof(tv));
|
setsockopt(serv->tcpfd, SOL_SOCKET, SO_RCVTIMEO, &tv, sizeof(tv));
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifdef MSG_FASTOPEN
|
#ifdef MSG_FASTOPEN
|
||||||
server_send(serv, serv->tcpfd, packet, qsize + sizeof(u16), MSG_FASTOPEN);
|
msg.msg_name = &serv->addr.sa;
|
||||||
|
msg.msg_namelen = sa_len(&serv->addr);
|
||||||
|
msg.msg_iov = sendio;
|
||||||
|
msg.msg_iovlen = 2;
|
||||||
|
msg.msg_control = NULL;
|
||||||
|
msg.msg_controllen = 0;
|
||||||
|
msg.msg_flags = 0;
|
||||||
|
|
||||||
|
while (retry_send(sendmsg(serv->tcpfd, &msg, MSG_FASTOPEN)));
|
||||||
|
|
||||||
if (errno == 0)
|
if (errno == 0)
|
||||||
data_sent = 1;
|
data_sent = 1;
|
||||||
@@ -2131,12 +2137,13 @@ static ssize_t tcp_talk(int first, int last, int start, unsigned char *packet,
|
|||||||
serv->flags &= ~SERV_GOT_TCP;
|
serv->flags &= ~SERV_GOT_TCP;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* We us the _ONCE veriant of read_write() here because we've set a timeout on the tcp socket
|
/* We use the _ONCE variant of read_write() here because we've set a timeout on the tcp socket
|
||||||
and wish to abort if the whole data is not read/written within the timeout. */
|
and wish to abort if the whole data is not read/written within the timeout. */
|
||||||
if ((!data_sent && !read_write(serv->tcpfd, (unsigned char *)packet, qsize + sizeof(u16), RW_WRITE_ONCE)) ||
|
if ((!data_sent && !read_writev(serv->tcpfd, sendio, 2, RW_WRITE_ONCE)) ||
|
||||||
!read_write(serv->tcpfd, (unsigned char *)length, sizeof (*length), RW_READ_ONCE) ||
|
!read_write(serv->tcpfd, (unsigned char *)&length, sizeof(length), RW_READ_ONCE) ||
|
||||||
!read_write(serv->tcpfd, payload, (rsize = ntohs(*length)), RW_READ_ONCE))
|
!expand_buf(recvbuff, (rsize = ntohs(length))) ||
|
||||||
{
|
!read_write(serv->tcpfd, recvbuff->iov_base, rsize, RW_READ_ONCE))
|
||||||
|
{
|
||||||
/* We get data then EOF, reopen connection to same server,
|
/* We get data then EOF, reopen connection to same server,
|
||||||
else try next. This avoids DoS from a server which accepts
|
else try next. This avoids DoS from a server which accepts
|
||||||
connections and then closes them. */
|
connections and then closes them. */
|
||||||
@@ -2149,28 +2156,28 @@ static ssize_t tcp_talk(int first, int last, int start, unsigned char *packet,
|
|||||||
else
|
else
|
||||||
goto failed;
|
goto failed;
|
||||||
}
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
/* If the question section of the reply doesn't match the question we sent, then
|
||||||
|
someone might be attempting to insert bogus values into the cache by
|
||||||
|
sending replies containing questions and bogus answers.
|
||||||
|
Try another server, or give up */
|
||||||
|
p = (unsigned char *)(((struct dns_header *)recvbuff->iov_base)+1);
|
||||||
|
if (extract_name(((struct dns_header *)recvbuff->iov_base), rsize, &p, daemon->namebuff, EXTR_NAME_COMPARE, 4) != 1)
|
||||||
|
continue;
|
||||||
|
GETSHORT(rtype, p);
|
||||||
|
GETSHORT(rclass, p);
|
||||||
|
|
||||||
/* If the question section of the reply doesn't match the question we sent, then
|
if (type != rtype || class != rclass)
|
||||||
someone might be attempting to insert bogus values into the cache by
|
continue;
|
||||||
sending replies containing questions and bogus answers.
|
}
|
||||||
Try another server, or give up */
|
|
||||||
p = (unsigned char *)(header+1);
|
|
||||||
if (extract_name(header, rsize, &p, daemon->namebuff, EXTR_NAME_COMPARE, 4) != 1)
|
|
||||||
continue;
|
|
||||||
GETSHORT(rtype, p);
|
|
||||||
GETSHORT(rclass, p);
|
|
||||||
|
|
||||||
if (type != rtype || class != rclass)
|
|
||||||
continue;
|
|
||||||
|
|
||||||
serv->flags |= SERV_GOT_TCP;
|
serv->flags |= SERV_GOT_TCP;
|
||||||
|
|
||||||
*servp = serv;
|
*servp = serv;
|
||||||
blockdata_free(saved_question);
|
|
||||||
return rsize;
|
return rsize;
|
||||||
}
|
}
|
||||||
|
|
||||||
blockdata_free(saved_question);
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -2182,19 +2189,16 @@ int tcp_from_udp(time_t now, int status, struct dns_header *header, ssize_t *ple
|
|||||||
int class, char *name, struct server *server,
|
int class, char *name, struct server *server,
|
||||||
int *keycount, int *validatecount)
|
int *keycount, int *validatecount)
|
||||||
{
|
{
|
||||||
unsigned char *packet = whine_malloc(65536 + MAXDNAME + RRFIXEDSZ + sizeof(u16));
|
|
||||||
struct dns_header *new_header = (struct dns_header *)&packet[2];
|
|
||||||
int start, first, last, new_status;
|
int start, first, last, new_status;
|
||||||
ssize_t n = *plenp;
|
ssize_t n = *plenp;
|
||||||
int log_save = daemon->log_display_id;
|
int log_save = daemon->log_display_id;
|
||||||
|
struct iovec recvbuff;
|
||||||
|
|
||||||
|
recvbuff.iov_len = 0;
|
||||||
|
recvbuff.iov_base = NULL;
|
||||||
|
|
||||||
*plenp = 0;
|
*plenp = 0;
|
||||||
|
|
||||||
if (!packet)
|
|
||||||
return STAT_ABANDONED;
|
|
||||||
|
|
||||||
memcpy(new_header, header, n);
|
|
||||||
|
|
||||||
/* Set TCP flag in logs. */
|
/* Set TCP flag in logs. */
|
||||||
daemon->log_display_id = -daemon->log_display_id;
|
daemon->log_display_id = -daemon->log_display_id;
|
||||||
|
|
||||||
@@ -2212,10 +2216,11 @@ int tcp_from_udp(time_t now, int status, struct dns_header *header, ssize_t *ple
|
|||||||
log_query_mysockaddr(F_NOEXTRA | F_DNSSEC | F_SERVER, name, &server->addr,
|
log_query_mysockaddr(F_NOEXTRA | F_DNSSEC | F_SERVER, name, &server->addr,
|
||||||
STAT_ISEQUAL(status, STAT_NEED_KEY) ? "dnssec-query[DNSKEY]" : "dnssec-query[DS]", 0);
|
STAT_ISEQUAL(status, STAT_NEED_KEY) ? "dnssec-query[DNSKEY]" : "dnssec-query[DS]", 0);
|
||||||
|
|
||||||
if ((n = tcp_talk(first, last, start, packet, n, 0, 0, &server)) == 0)
|
if ((n = tcp_talk(first, last, start, header, n, &recvbuff, 0, 0, &server)) == 0)
|
||||||
new_status = STAT_ABANDONED;
|
new_status = STAT_ABANDONED;
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
struct dns_header *new_header = (struct dns_header *)recvbuff.iov_base;
|
||||||
new_status = tcp_key_recurse(now, status, new_header, n, class, daemon->namebuff, daemon->keyname, server, 0, 0, keycount, validatecount);
|
new_status = tcp_key_recurse(now, status, new_header, n, class, daemon->namebuff, daemon->keyname, server, 0, 0, keycount, validatecount);
|
||||||
|
|
||||||
if (STAT_ISEQUAL(status, STAT_OK))
|
if (STAT_ISEQUAL(status, STAT_OK))
|
||||||
@@ -2252,7 +2257,7 @@ int tcp_from_udp(time_t now, int status, struct dns_header *header, ssize_t *ple
|
|||||||
}
|
}
|
||||||
|
|
||||||
daemon->log_display_id = log_save;
|
daemon->log_display_id = log_save;
|
||||||
free(packet);
|
free(recvbuff.iov_base);
|
||||||
return new_status;
|
return new_status;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -2262,8 +2267,11 @@ static int tcp_key_recurse(time_t now, int status, struct dns_header *header, si
|
|||||||
int have_mark, unsigned int mark, int *keycount, int *validatecount)
|
int have_mark, unsigned int mark, int *keycount, int *validatecount)
|
||||||
{
|
{
|
||||||
int first, last, start, new_status;
|
int first, last, start, new_status;
|
||||||
unsigned char *packet = NULL;
|
struct iovec new_packet;
|
||||||
struct dns_header *new_header = NULL;
|
struct dns_header *query_header = NULL, *new_header;
|
||||||
|
|
||||||
|
new_packet.iov_base = NULL;
|
||||||
|
new_packet.iov_len = 0;
|
||||||
|
|
||||||
while (1)
|
while (1)
|
||||||
{
|
{
|
||||||
@@ -2298,34 +2306,21 @@ static int tcp_key_recurse(time_t now, int status, struct dns_header *header, si
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* Can't validate because we need a key/DS whose name now in keyname.
|
/* Can't validate because we need a key/DS whose name now in keyname.
|
||||||
Make query for same, and recurse to validate */
|
Make query for same in UDP packet buffer, recurse to validate*/
|
||||||
if (!packet)
|
query_header = (struct dns_header *)daemon->packet;
|
||||||
{
|
daemon->srv_save = NULL;
|
||||||
packet = whine_malloc(65536 + MAXDNAME + RRFIXEDSZ + sizeof(u16));
|
|
||||||
new_header = (struct dns_header *)&packet[2];
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!packet)
|
m = dnssec_generate_query(query_header, ((unsigned char *)query_header) + daemon->edns_pktsz, keyname, class, 0,
|
||||||
{
|
|
||||||
new_status = STAT_ABANDONED;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
m = dnssec_generate_query(new_header, ((unsigned char *) new_header) + 65536, keyname, class, 0,
|
|
||||||
STAT_ISEQUAL(new_status, STAT_NEED_KEY) ? T_DNSKEY : T_DS);
|
STAT_ISEQUAL(new_status, STAT_NEED_KEY) ? T_DNSKEY : T_DS);
|
||||||
|
|
||||||
if ((start = dnssec_server(server, keyname, STAT_ISEQUAL(new_status, STAT_NEED_DS), &first, &last)) == -1)
|
if ((start = dnssec_server(server, keyname, STAT_ISEQUAL(new_status, STAT_NEED_DS), &first, &last)) == -1 ||
|
||||||
{
|
(m = tcp_talk(first, last, start, query_header, m, &new_packet, have_mark, mark, &server)) == 0)
|
||||||
new_status = STAT_ABANDONED;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
if ((m = tcp_talk(first, last, start, packet, m, have_mark, mark, &server)) == 0)
|
|
||||||
{
|
{
|
||||||
new_status = STAT_ABANDONED;
|
new_status = STAT_ABANDONED;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
new_header = new_packet.iov_base;
|
||||||
log_save = daemon->log_display_id;
|
log_save = daemon->log_display_id;
|
||||||
daemon->log_display_id = -(++daemon->log_id);
|
daemon->log_display_id = -(++daemon->log_id);
|
||||||
|
|
||||||
@@ -2342,8 +2337,7 @@ static int tcp_key_recurse(time_t now, int status, struct dns_header *header, si
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (packet)
|
free(new_packet.iov_base);
|
||||||
free(packet);
|
|
||||||
|
|
||||||
return new_status;
|
return new_status;
|
||||||
}
|
}
|
||||||
@@ -2353,11 +2347,11 @@ static int tcp_key_recurse(time_t now, int status, struct dns_header *header, si
|
|||||||
/* The daemon forks before calling this: it should deal with one connection,
|
/* The daemon forks before calling this: it should deal with one connection,
|
||||||
blocking as necessary, and then return. Note, need to be a bit careful
|
blocking as necessary, and then return. Note, need to be a bit careful
|
||||||
about resources for debug mode, when the fork is suppressed: that's
|
about resources for debug mode, when the fork is suppressed: that's
|
||||||
done by the caller. */
|
done by the caller, which also frees bigbuff. */
|
||||||
unsigned char *tcp_request(int confd, time_t now,
|
void tcp_request(int confd, time_t now, struct iovec *bigbuff,
|
||||||
union mysockaddr *local_addr, struct in_addr netmask, int auth_dns)
|
union mysockaddr *local_addr, struct in_addr netmask, int auth_dns)
|
||||||
{
|
{
|
||||||
size_t size = 0, saved_size = 0;
|
size_t size = 0;
|
||||||
int norebind = 0;
|
int norebind = 0;
|
||||||
#ifdef HAVE_CONNTRACK
|
#ifdef HAVE_CONNTRACK
|
||||||
int allowed = 1;
|
int allowed = 1;
|
||||||
@@ -2366,16 +2360,10 @@ unsigned char *tcp_request(int confd, time_t now,
|
|||||||
int local_auth = 0;
|
int local_auth = 0;
|
||||||
#endif
|
#endif
|
||||||
int checking_disabled, do_bit = 0, ad_reqd = 0, have_pseudoheader = 0;
|
int checking_disabled, do_bit = 0, ad_reqd = 0, have_pseudoheader = 0;
|
||||||
struct blockdata *saved_question = NULL;
|
|
||||||
unsigned short qtype;
|
unsigned short qtype;
|
||||||
unsigned int gotname = 0;
|
unsigned int gotname = 0;
|
||||||
/* Max TCP packet + slop + size */
|
u16 tcp_len, out_len;
|
||||||
unsigned char *packet = whine_malloc(65536 + MAXDNAME + RRFIXEDSZ + sizeof(u16));
|
struct dns_header *header, *out_header;
|
||||||
unsigned char *payload = &packet[2];
|
|
||||||
u16 tcp_len;
|
|
||||||
/* largest field in header is 16-bits, so this is still sufficiently aligned */
|
|
||||||
struct dns_header *header = (struct dns_header *)payload;
|
|
||||||
u16 *length = (u16 *)packet;
|
|
||||||
struct server *serv;
|
struct server *serv;
|
||||||
struct in_addr dst_addr_4;
|
struct in_addr dst_addr_4;
|
||||||
union mysockaddr peer_addr;
|
union mysockaddr peer_addr;
|
||||||
@@ -2385,9 +2373,13 @@ unsigned char *tcp_request(int confd, time_t now,
|
|||||||
unsigned int mark = 0;
|
unsigned int mark = 0;
|
||||||
int have_mark = 0;
|
int have_mark = 0;
|
||||||
int first, last, filtered, do_stale = 0;
|
int first, last, filtered, do_stale = 0;
|
||||||
|
struct iovec out_iov[2];
|
||||||
|
|
||||||
if (!packet || getpeername(confd, (struct sockaddr *)&peer_addr, &peer_len) == -1)
|
bigbuff->iov_base = NULL;
|
||||||
return packet;
|
bigbuff->iov_len = 0;
|
||||||
|
|
||||||
|
if (getpeername(confd, (struct sockaddr *)&peer_addr, &peer_len) == -1)
|
||||||
|
return;
|
||||||
|
|
||||||
#ifdef HAVE_CONNTRACK
|
#ifdef HAVE_CONNTRACK
|
||||||
/* Get connection mark of incoming query to set on outgoing connections. */
|
/* Get connection mark of incoming query to set on outgoing connections. */
|
||||||
@@ -2431,7 +2423,7 @@ unsigned char *tcp_request(int confd, time_t now,
|
|||||||
{
|
{
|
||||||
prettyprint_addr(&peer_addr, daemon->addrbuff);
|
prettyprint_addr(&peer_addr, daemon->addrbuff);
|
||||||
my_syslog(LOG_WARNING, _("ignoring query from non-local network %s"), daemon->addrbuff);
|
my_syslog(LOG_WARNING, _("ignoring query from non-local network %s"), daemon->addrbuff);
|
||||||
return packet;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -2449,18 +2441,26 @@ unsigned char *tcp_request(int confd, time_t now,
|
|||||||
if (query_count >= TCP_MAX_QUERIES)
|
if (query_count >= TCP_MAX_QUERIES)
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
/* Now get the query into the normal UDP packet buffer.
|
||||||
|
Ignore queries long than this. If we're answering locally,
|
||||||
|
copy the query into the output buffer, but for forwarding, tcp_talk()
|
||||||
|
wants the query in a a different buffer from the reply.
|
||||||
|
Note that we overwrote any saved UDP query - this onlt matters in debug mode. */
|
||||||
|
daemon->srv_save = NULL;
|
||||||
if (!read_write(confd, (unsigned char *)&tcp_len, sizeof(tcp_len), RW_READ) ||
|
if (!read_write(confd, (unsigned char *)&tcp_len, sizeof(tcp_len), RW_READ) ||
|
||||||
!(size = ntohs(tcp_len)) ||
|
!(size = ntohs(tcp_len)) || size > (size_t)daemon->packet_buff_sz ||
|
||||||
!read_write(confd, payload, size, RW_READ))
|
!read_write(confd, (unsigned char *)daemon->packet, size, RW_READ))
|
||||||
break;
|
break;
|
||||||
|
|
||||||
if (size < (int)sizeof(struct dns_header))
|
if (size < (int)sizeof(struct dns_header))
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
/* Clear buffer beyond request to avoid risk of
|
/* Make sure we have a buffer big enough for the largest answer. */
|
||||||
information disclosure. */
|
expand_buf(bigbuff, 65536 + MAXDNAME + RRFIXEDSZ);
|
||||||
memset(payload + size, 0, 65536 - size);
|
out_header = bigbuff->iov_base;
|
||||||
|
|
||||||
|
/* header == query */
|
||||||
|
header = (struct dns_header *)daemon->packet;
|
||||||
query_count++;
|
query_count++;
|
||||||
|
|
||||||
/* log_query gets called indirectly all over the place, so
|
/* log_query gets called indirectly all over the place, so
|
||||||
@@ -2479,9 +2479,6 @@ unsigned char *tcp_request(int confd, time_t now,
|
|||||||
ede = EDE_INVALID_DATA;
|
ede = EDE_INVALID_DATA;
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
if (saved_question)
|
|
||||||
blockdata_free(saved_question);
|
|
||||||
|
|
||||||
do_bit = 0;
|
do_bit = 0;
|
||||||
|
|
||||||
if (find_pseudoheader(header, (size_t)size, NULL, &pheader, NULL, NULL))
|
if (find_pseudoheader(header, (size_t)size, NULL, &pheader, NULL, NULL))
|
||||||
@@ -2496,9 +2493,12 @@ unsigned char *tcp_request(int confd, time_t now,
|
|||||||
do_bit = 1; /* do bit */
|
do_bit = 1; /* do bit */
|
||||||
}
|
}
|
||||||
|
|
||||||
size = add_edns0_config(header, size, ((unsigned char *) header) + 65536, &peer_addr, now, &cacheable);
|
size = add_edns0_config(header, size, ((unsigned char *) header) + daemon->edns_pktsz, &peer_addr, now, &cacheable);
|
||||||
saved_question = blockdata_alloc((char *)header, (size_t)size);
|
|
||||||
saved_size = size;
|
/* Clear buffer to avoid risk of information disclosure. */
|
||||||
|
memset(bigbuff->iov_base, 0, bigbuff->iov_len);
|
||||||
|
/* Copy query into output buffer for local answering */
|
||||||
|
memcpy(out_header, header, size);
|
||||||
|
|
||||||
log_query_mysockaddr((auth_dns ? F_NOERR | F_AUTH : 0) | F_QUERY | F_FORWARD, daemon->namebuff,
|
log_query_mysockaddr((auth_dns ? F_NOERR | F_AUTH : 0) | F_QUERY | F_FORWARD, daemon->namebuff,
|
||||||
&peer_addr, NULL, qtype);
|
&peer_addr, NULL, qtype);
|
||||||
@@ -2557,10 +2557,10 @@ unsigned char *tcp_request(int confd, time_t now,
|
|||||||
#endif
|
#endif
|
||||||
#ifdef HAVE_AUTH
|
#ifdef HAVE_AUTH
|
||||||
else if (auth_dns)
|
else if (auth_dns)
|
||||||
m = answer_auth(header, ((char *) header) + 65536, (size_t)size, now, &peer_addr, local_auth);
|
m = answer_auth(out_header, ((char *) out_header) + 65536, (size_t)size, now, &peer_addr, local_auth);
|
||||||
#endif
|
#endif
|
||||||
else
|
else
|
||||||
m = answer_request(header, ((char *) header) + 65536, (size_t)size,
|
m = answer_request(out_header, ((char *) out_header) + 65536, (size_t)size,
|
||||||
dst_addr_4, netmask, now, ad_reqd, do_bit, !cacheable, &stale, &filtered);
|
dst_addr_4, netmask, now, ad_reqd, do_bit, !cacheable, &stale, &filtered);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -2568,15 +2568,12 @@ unsigned char *tcp_request(int confd, time_t now,
|
|||||||
/* Do this by steam now we're not in the select() loop */
|
/* Do this by steam now we're not in the select() loop */
|
||||||
check_log_writer(1);
|
check_log_writer(1);
|
||||||
|
|
||||||
if (m == 0 && ede == EDE_UNSET && saved_question)
|
if (m == 0 && ede == EDE_UNSET)
|
||||||
{
|
{
|
||||||
struct server *master;
|
struct server *master;
|
||||||
int start;
|
int start;
|
||||||
int no_cache_dnssec = 0, cache_secure = 0, bogusanswer = 0;
|
int no_cache_dnssec = 0, cache_secure = 0, bogusanswer = 0;
|
||||||
|
|
||||||
blockdata_retrieve(saved_question, (size_t)saved_size, header);
|
|
||||||
size = saved_size;
|
|
||||||
|
|
||||||
/* save state of "cd" flag in query */
|
/* save state of "cd" flag in query */
|
||||||
checking_disabled = header->hb4 & HB4_CD;
|
checking_disabled = header->hb4 & HB4_CD;
|
||||||
|
|
||||||
@@ -2605,7 +2602,7 @@ unsigned char *tcp_request(int confd, time_t now,
|
|||||||
#ifdef HAVE_DNSSEC
|
#ifdef HAVE_DNSSEC
|
||||||
if (option_bool(OPT_DNSSEC_VALID))
|
if (option_bool(OPT_DNSSEC_VALID))
|
||||||
{
|
{
|
||||||
size = add_do_bit(header, size, ((unsigned char *) header) + 65536);
|
size = add_do_bit(header, size, ((unsigned char *) header) + daemon->edns_pktsz);
|
||||||
|
|
||||||
/* For debugging, set Checking Disabled, otherwise, have the upstream check too,
|
/* For debugging, set Checking Disabled, otherwise, have the upstream check too,
|
||||||
this allows it to select auth servers when one is returning bad data. */
|
this allows it to select auth servers when one is returning bad data. */
|
||||||
@@ -2615,12 +2612,14 @@ unsigned char *tcp_request(int confd, time_t now,
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
/* Loop round available servers until we succeed in connecting to one. */
|
/* Loop round available servers until we succeed in connecting to one. */
|
||||||
if ((m = tcp_talk(first, last, start, packet, size, have_mark, mark, &serv)) == 0)
|
if ((m = tcp_talk(first, last, start, header, size, bigbuff, have_mark, mark, &serv)) == 0)
|
||||||
ede = EDE_NETERR;
|
ede = EDE_NETERR;
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
/* just in case tcp_talk() expanded buffer - should never happen */
|
||||||
|
out_header = bigbuff->iov_base;
|
||||||
/* get query name again for logging - may have been overwritten */
|
/* get query name again for logging - may have been overwritten */
|
||||||
if (!extract_name(header, (unsigned int)size, NULL, daemon->namebuff, EXTR_NAME_EXTRACT, 0))
|
if (!extract_name(out_header, (unsigned int)size, NULL, daemon->namebuff, EXTR_NAME_EXTRACT, 0))
|
||||||
strcpy(daemon->namebuff, "query");
|
strcpy(daemon->namebuff, "query");
|
||||||
log_query_mysockaddr(F_SERVER | F_FORWARD, daemon->namebuff, &serv->addr, NULL, 0);
|
log_query_mysockaddr(F_SERVER | F_FORWARD, daemon->namebuff, &serv->addr, NULL, 0);
|
||||||
|
|
||||||
@@ -2636,7 +2635,8 @@ unsigned char *tcp_request(int confd, time_t now,
|
|||||||
{
|
{
|
||||||
int keycount = daemon->limit[LIMIT_WORK]; /* Limit to number of DNSSEC questions, to catch loops and avoid filling cache. */
|
int keycount = daemon->limit[LIMIT_WORK]; /* Limit to number of DNSSEC questions, to catch loops and avoid filling cache. */
|
||||||
int validatecount = daemon->limit[LIMIT_CRYPTO];
|
int validatecount = daemon->limit[LIMIT_CRYPTO];
|
||||||
int status = tcp_key_recurse(now, STAT_OK, header, m, 0, daemon->namebuff, daemon->keyname,
|
/* tcp_key_recurse() may overwrite packetbuf, and thuse *header is now invalid */
|
||||||
|
int status = tcp_key_recurse(now, STAT_OK, out_header, m, 0, daemon->namebuff, daemon->keyname,
|
||||||
serv, have_mark, mark, &keycount, &validatecount);
|
serv, have_mark, mark, &keycount, &validatecount);
|
||||||
char *result, *domain = "result";
|
char *result, *domain = "result";
|
||||||
|
|
||||||
@@ -2662,7 +2662,7 @@ unsigned char *tcp_request(int confd, time_t now,
|
|||||||
no_cache_dnssec = 1;
|
no_cache_dnssec = 1;
|
||||||
bogusanswer = 1;
|
bogusanswer = 1;
|
||||||
|
|
||||||
if (extract_name(header, m, NULL, daemon->namebuff, EXTR_NAME_EXTRACT, 0))
|
if (extract_name(out_header, m, NULL, daemon->namebuff, EXTR_NAME_EXTRACT, 0))
|
||||||
domain = daemon->namebuff;
|
domain = daemon->namebuff;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -2686,18 +2686,18 @@ unsigned char *tcp_request(int confd, time_t now,
|
|||||||
|
|
||||||
/* restore CD bit to the value in the query */
|
/* restore CD bit to the value in the query */
|
||||||
if (checking_disabled)
|
if (checking_disabled)
|
||||||
header->hb4 |= HB4_CD;
|
out_header->hb4 |= HB4_CD;
|
||||||
else
|
else
|
||||||
header->hb4 &= ~HB4_CD;
|
out_header->hb4 &= ~HB4_CD;
|
||||||
|
|
||||||
/* Never cache answers which are contingent on the source or MAC address EDSN0 option,
|
/* Never cache answers which are contingent on the source or MAC address EDSN0 option,
|
||||||
since the cache is ignorant of such things. */
|
since the cache is ignorant of such things. */
|
||||||
if (!cacheable)
|
if (!cacheable)
|
||||||
no_cache_dnssec = 1;
|
no_cache_dnssec = 1;
|
||||||
|
|
||||||
m = process_reply(header, now, serv, (unsigned int)m,
|
m = process_reply(out_header, now, serv, (unsigned int)m,
|
||||||
option_bool(OPT_NO_REBIND) && !norebind, no_cache_dnssec, cache_secure, bogusanswer,
|
option_bool(OPT_NO_REBIND) && !norebind, no_cache_dnssec, cache_secure, bogusanswer,
|
||||||
ad_reqd, do_bit, !have_pseudoheader, &peer_addr, ((unsigned char *)header) + 65536, ede);
|
ad_reqd, do_bit, !have_pseudoheader, &peer_addr, ((unsigned char *)out_header) + 65536, ede);
|
||||||
|
|
||||||
/* process_reply() adds pheader itself */
|
/* process_reply() adds pheader itself */
|
||||||
have_pseudoheader = 0;
|
have_pseudoheader = 0;
|
||||||
@@ -2712,8 +2712,8 @@ unsigned char *tcp_request(int confd, time_t now,
|
|||||||
/* In case of local answer or no connections made. */
|
/* In case of local answer or no connections made. */
|
||||||
if (m == 0)
|
if (m == 0)
|
||||||
{
|
{
|
||||||
if (!(m = make_local_answer(flags, gotname, size, header, daemon->namebuff,
|
if (!(m = make_local_answer(flags, gotname, size, out_header, daemon->namebuff,
|
||||||
((char *) header) + 65536, first, last, ede)))
|
((char *) out_header) + 65536, first, last, ede)))
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
else if (ede == EDE_UNSET)
|
else if (ede == EDE_UNSET)
|
||||||
@@ -2729,15 +2729,13 @@ unsigned char *tcp_request(int confd, time_t now,
|
|||||||
u16 swap = htons((u16)ede);
|
u16 swap = htons((u16)ede);
|
||||||
|
|
||||||
if (ede != EDE_UNSET)
|
if (ede != EDE_UNSET)
|
||||||
m = add_pseudoheader(header, m, ((unsigned char *) header) + 65536, EDNS0_OPTION_EDE, (unsigned char *)&swap, 2, do_bit, 0);
|
m = add_pseudoheader(out_header, m, ((unsigned char *) out_header) + 65536, EDNS0_OPTION_EDE, (unsigned char *)&swap, 2, do_bit, 0);
|
||||||
else
|
else
|
||||||
m = add_pseudoheader(header, m, ((unsigned char *) header) + 65536, 0, NULL, 0, do_bit, 0);
|
m = add_pseudoheader(out_header, m, ((unsigned char *) out_header) + 65536, 0, NULL, 0, do_bit, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
check_log_writer(1);
|
check_log_writer(1);
|
||||||
|
|
||||||
*length = htons(m);
|
|
||||||
|
|
||||||
#if defined(HAVE_CONNTRACK) && defined(HAVE_UBUS)
|
#if defined(HAVE_CONNTRACK) && defined(HAVE_UBUS)
|
||||||
#ifdef HAVE_AUTH
|
#ifdef HAVE_AUTH
|
||||||
if (!auth_dns || local_auth)
|
if (!auth_dns || local_auth)
|
||||||
@@ -2746,7 +2744,13 @@ unsigned char *tcp_request(int confd, time_t now,
|
|||||||
report_addresses(header, m, mark);
|
report_addresses(header, m, mark);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
if (!read_write(confd, packet, m + sizeof(u16), RW_WRITE))
|
/* use scatter-gather IO so that length doesn't end up in separate packet. */
|
||||||
|
out_len = htons(m);
|
||||||
|
out_iov[0].iov_len = sizeof(out_len);
|
||||||
|
out_iov[0].iov_base = &out_len;
|
||||||
|
out_iov[1].iov_len = m;
|
||||||
|
out_iov[1].iov_base = bigbuff->iov_base;
|
||||||
|
if (!read_writev(confd, out_iov, 2, RW_WRITE))
|
||||||
break;
|
break;
|
||||||
|
|
||||||
/* If we answered with stale data, this process will now try and get fresh data into
|
/* If we answered with stale data, this process will now try and get fresh data into
|
||||||
@@ -2763,17 +2767,14 @@ unsigned char *tcp_request(int confd, time_t now,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* If we ran once to get fresh data, confd is already closed. */
|
/* If we ran once to get fresh data, confd is already closed. */
|
||||||
if (!do_stale)
|
if (!do_stale)
|
||||||
{
|
{
|
||||||
shutdown(confd, SHUT_RDWR);
|
shutdown(confd, SHUT_RDWR);
|
||||||
close(confd);
|
close(confd);
|
||||||
}
|
}
|
||||||
|
|
||||||
blockdata_free(saved_question);
|
|
||||||
check_log_writer(1);
|
check_log_writer(1);
|
||||||
|
|
||||||
return packet;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* return a UDP socket bound to a random port, have to cope with straying into
|
/* return a UDP socket bound to a random port, have to cope with straying into
|
||||||
@@ -3274,7 +3275,7 @@ void resend_query(void)
|
|||||||
{
|
{
|
||||||
if (daemon->srv_save)
|
if (daemon->srv_save)
|
||||||
server_send(daemon->srv_save, daemon->fd_save,
|
server_send(daemon->srv_save, daemon->fd_save,
|
||||||
daemon->packet, daemon->packet_len, 0);
|
daemon->packet, daemon->packet_len);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* A server record is going away, remove references to it */
|
/* A server record is going away, remove references to it */
|
||||||
|
|||||||
@@ -197,6 +197,7 @@ struct myoption {
|
|||||||
#define LOPT_DO_ENCODE 388
|
#define LOPT_DO_ENCODE 388
|
||||||
#define LOPT_LEASEQUERY 389
|
#define LOPT_LEASEQUERY 389
|
||||||
#define LOPT_SPLIT_RELAY 390
|
#define LOPT_SPLIT_RELAY 390
|
||||||
|
#define LOPT_LOG_MALLOC 391
|
||||||
|
|
||||||
#ifdef HAVE_GETOPT_LONG
|
#ifdef HAVE_GETOPT_LONG
|
||||||
static const struct option opts[] =
|
static const struct option opts[] =
|
||||||
@@ -398,6 +399,7 @@ static const struct myoption opts[] =
|
|||||||
{ "no-ident", 0, 0, LOPT_NO_IDENT },
|
{ "no-ident", 0, 0, LOPT_NO_IDENT },
|
||||||
{ "max-tcp-connections", 1, 0, LOPT_MAX_PROCS },
|
{ "max-tcp-connections", 1, 0, LOPT_MAX_PROCS },
|
||||||
{ "leasequery", 2, 0, LOPT_LEASEQUERY },
|
{ "leasequery", 2, 0, LOPT_LEASEQUERY },
|
||||||
|
{ "log-malloc", 0, 0, LOPT_LOG_MALLOC },
|
||||||
{ NULL, 0, 0, 0 }
|
{ NULL, 0, 0, 0 }
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -606,6 +608,7 @@ static struct {
|
|||||||
{ LOPT_NO_IDENT, OPT_NO_IDENT, NULL, gettext_noop("Do not add CHAOS TXT records."), NULL },
|
{ LOPT_NO_IDENT, OPT_NO_IDENT, NULL, gettext_noop("Do not add CHAOS TXT records."), NULL },
|
||||||
{ LOPT_CACHE_RR, ARG_DUP, "<RR-type>", gettext_noop("Cache this DNS resource record type."), NULL },
|
{ LOPT_CACHE_RR, ARG_DUP, "<RR-type>", gettext_noop("Cache this DNS resource record type."), NULL },
|
||||||
{ LOPT_MAX_PROCS, ARG_ONE, "<integer>", gettext_noop("Maximum number of concurrent tcp connections."), NULL },
|
{ LOPT_MAX_PROCS, ARG_ONE, "<integer>", gettext_noop("Maximum number of concurrent tcp connections."), NULL },
|
||||||
|
{ LOPT_LOG_MALLOC, OPT_LOG_MALLOC, NULL, gettext_noop("Log memory allocation for debugging."), NULL },
|
||||||
{ 0, 0, NULL, NULL, NULL }
|
{ 0, 0, NULL, NULL, NULL }
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
+75
-39
@@ -341,26 +341,6 @@ void safe_pipe(int *fd, int read_noblock)
|
|||||||
die(_("cannot create pipe: %s"), NULL, EC_MISC);
|
die(_("cannot create pipe: %s"), NULL, EC_MISC);
|
||||||
}
|
}
|
||||||
|
|
||||||
void *whine_malloc(size_t size)
|
|
||||||
{
|
|
||||||
void *ret = calloc(1, size);
|
|
||||||
|
|
||||||
if (!ret)
|
|
||||||
my_syslog(LOG_ERR, _("failed to allocate %d bytes"), (int) size);
|
|
||||||
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
void *whine_realloc(void *ptr, size_t size)
|
|
||||||
{
|
|
||||||
void *ret = realloc(ptr, size);
|
|
||||||
|
|
||||||
if (!ret)
|
|
||||||
my_syslog(LOG_ERR, _("failed to reallocate %d bytes"), (int) size);
|
|
||||||
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
int sockaddr_isequal(const union mysockaddr *s1, const union mysockaddr *s2)
|
int sockaddr_isequal(const union mysockaddr *s1, const union mysockaddr *s2)
|
||||||
{
|
{
|
||||||
if (s1->sa.sa_family == s2->sa.sa_family)
|
if (s1->sa.sa_family == s2->sa.sa_family)
|
||||||
@@ -777,43 +757,60 @@ int retry_send(ssize_t rc)
|
|||||||
"once" fails on EAGAIN, as this a timeout.
|
"once" fails on EAGAIN, as this a timeout.
|
||||||
This indicates a timeout of a TCP socket.
|
This indicates a timeout of a TCP socket.
|
||||||
*/
|
*/
|
||||||
int read_write(int fd, unsigned char *packet, int size, int rw)
|
int read_writev(int fd, struct iovec *iov, int iovcnt, int rw)
|
||||||
{
|
{
|
||||||
ssize_t n, done;
|
int cur = 0;
|
||||||
|
ssize_t n, done = 0;
|
||||||
|
|
||||||
for (done = 0; done < size; done += n)
|
while (cur < iovcnt)
|
||||||
{
|
{
|
||||||
if (rw & 1)
|
iov[cur].iov_len -= done;
|
||||||
n = read(fd, &packet[done], (size_t)(size - done));
|
iov[cur].iov_base = ((char *)iov[cur].iov_base) + done;
|
||||||
else
|
|
||||||
n = write(fd, &packet[done], (size_t)(size - done));
|
|
||||||
|
|
||||||
if (n == 0)
|
if (rw & 1)
|
||||||
return 0;
|
n = readv(fd, &iov[cur], iovcnt - cur);
|
||||||
|
else
|
||||||
|
n = writev(fd, &iov[cur], iovcnt - cur);
|
||||||
|
|
||||||
|
iov[cur].iov_len += done;
|
||||||
|
iov[cur].iov_base = ((char *)iov[cur].iov_base) - done;
|
||||||
|
|
||||||
if (n == -1)
|
if (n == -1)
|
||||||
{
|
{
|
||||||
n = 0; /* don't mess with counter when we loop. */
|
|
||||||
|
|
||||||
if (errno == EINTR || errno == ENOMEM || errno == ENOBUFS)
|
if (errno == EINTR || errno == ENOMEM || errno == ENOBUFS)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
if (errno == EAGAIN || errno == EWOULDBLOCK)
|
if (!(rw & 2) && (errno == EAGAIN || errno == EWOULDBLOCK))
|
||||||
{
|
continue;
|
||||||
/* "once" variant */
|
|
||||||
if (rw & 2)
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (n == 0 && (rw & 1))
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
done += n;
|
||||||
|
while ((size_t)done >= iov[cur].iov_len)
|
||||||
|
done -= iov[cur++].iov_len;
|
||||||
}
|
}
|
||||||
|
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int read_write(int fd, unsigned char *packet, int size, int rw)
|
||||||
|
{
|
||||||
|
struct iovec iov;
|
||||||
|
|
||||||
|
/* size == 0 is not an error, just a NOOP. */
|
||||||
|
if (size == 0)
|
||||||
|
return 1;
|
||||||
|
|
||||||
|
iov.iov_len = (size_t)size;
|
||||||
|
iov.iov_base = packet;
|
||||||
|
|
||||||
|
return read_writev(fd, &iov, 1, rw);
|
||||||
|
}
|
||||||
|
|
||||||
/* close all fds except STDIN, STDOUT and STDERR, spare1, spare2 and spare3 */
|
/* close all fds except STDIN, STDOUT and STDERR, spare1, spare2 and spare3 */
|
||||||
void close_fds(long max_fd, int spare1, int spare2, int spare3)
|
void close_fds(long max_fd, int spare1, int spare2, int spare3)
|
||||||
{
|
{
|
||||||
@@ -949,3 +946,42 @@ int kernel_version(void)
|
|||||||
return version * 256 + (split ? atoi(split) : 0);
|
return version * 256 + (split ? atoi(split) : 0);
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#define hash_ptr(x) (((unsigned int)(((char *)(x)) - ((char *)NULL))) & 0xffffff)
|
||||||
|
|
||||||
|
void *whine_malloc_real(const char *func, unsigned int line, size_t size)
|
||||||
|
{
|
||||||
|
void *ret = calloc(1, size);
|
||||||
|
|
||||||
|
if (!ret)
|
||||||
|
my_syslog(LOG_ERR, _("failed to allocate %d bytes"), (int) size);
|
||||||
|
else if (daemon->log_malloc)
|
||||||
|
my_syslog(LOG_INFO, _("malloc: %s:%u %zu bytes at %x"), func, line, size, hash_ptr(ret));
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
void *whine_realloc_real(const char *func, unsigned int line, void *ptr, size_t size)
|
||||||
|
{
|
||||||
|
unsigned int old = hash_ptr(ptr);
|
||||||
|
void *ret = realloc(ptr, size);
|
||||||
|
|
||||||
|
if (!ret)
|
||||||
|
my_syslog(LOG_ERR, _("failed to reallocate %d bytes"), (int) size);
|
||||||
|
else if (daemon->log_malloc)
|
||||||
|
my_syslog(LOG_INFO, _("realloc: %s:%u %zu bytes from %x to %x"), func, line, size, old, hash_ptr(ret));
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
#undef free
|
||||||
|
void free_real(const char *func, unsigned int line, void *ptr)
|
||||||
|
{
|
||||||
|
if (ptr)
|
||||||
|
{
|
||||||
|
if (daemon->log_malloc)
|
||||||
|
my_syslog(LOG_INFO, _("free: %s:%u block at %x"), func, line, hash_ptr(ptr));
|
||||||
|
|
||||||
|
free(ptr);
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in new issue
Block a user