aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSergey Poznyakoff <gray@gnu.org>2020-10-31 10:10:52 +0200
committerSergey Poznyakoff <gray@gnu.org>2020-10-31 10:10:52 +0200
commit72b0e2ae885e60d7530e483e98d61a64061fd13d (patch)
tree9900c925176a90bb1e68eb03e140770e0fafded8
parentb746d5746013cc2795df3e535085d23c25519c75 (diff)
downloadnsu-72b0e2ae885e60d7530e483e98d61a64061fd13d.tar.gz
nsu-72b0e2ae885e60d7530e483e98d61a64061fd13d.tar.bz2
Introduce functions for sending requests
* Makefile: Add io.c * io.c: New file. * nsu.h (nsu_sockaddr): New data type. (nsu_nsend): New proto. * main.c (send_update_query): Use nsu_nsend instead of res_nsend.
-rw-r--r--.gitignore1
-rw-r--r--Makefile7
-rw-r--r--io.c218
-rw-r--r--main.c85
-rw-r--r--nsu.h21
5 files changed, 304 insertions, 28 deletions
diff --git a/.gitignore b/.gitignore
index c2eed98..c05a9c9 100644
--- a/.gitignore
+++ b/.gitignore
@@ -5,6 +5,7 @@
nsu
tmp/
.gdbinit
+TAGS
TODO
core
lex.yy.c
diff --git a/Makefile b/Makefile
index f9bb6c8..bc27076 100644
--- a/Makefile
+++ b/Makefile
@@ -3,7 +3,7 @@ CFLAGS=-ggdb
APPSRC=main.c y.tab.c lex.yy.c
APPOBJ=${APPSRC:.c=.o}
-NSUSRC=nsu.c typestr.c alg.c log.c
+NSUSRC=nsu.c typestr.c alg.c log.c io.c
NSUOBJ=${NSUSRC:.c=.o}
OBJS=$(NSUOBJ) $(APPOBJ)
@@ -27,3 +27,8 @@ clean:
allclean: clean
rm -f lex.yy.c y.tab.c y.tab.h
+ETAGS = etags
+ETAGSFLAGS=
+
+tags:
+ $(ETAGS) $(ETAGSFLAGS) $(NSUSRC) main.c grammar.y lexer.l
diff --git a/io.c b/io.c
new file mode 100644
index 0000000..09654f1
--- /dev/null
+++ b/io.c
@@ -0,0 +1,218 @@
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <poll.h>
+#include <errno.h>
+#include <string.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include "nsu.h"
+
+static int
+nsu_nsend_dg(res_state statp, nsu_sockaddr *a, u_char *qbuf, size_t qlen,
+ u_char *rbuf, size_t rlen, size_t *return_len)
+{
+ struct pollfd pfd;
+ UPDATE_HEADER *uhp;
+ int retry = 0;
+ int result = NSU_SEND_SYSERR;
+ int ec;
+
+ nsu_log(NSU_LOG_DEBUG, "sending query %d via UDP",
+ ((HEADER*)qbuf)->id);
+ pfd.fd = socket(a->addr.sa.sa_family, SOCK_DGRAM, 0);
+ if (pfd.fd == -1) {
+ return NSU_SEND_SYSERR;
+ }
+ pfd.events = POLLOUT;
+ while (1) {
+ ssize_t n;
+ int rc;
+
+ rc = poll(&pfd, 1, statp->retrans * 1000);
+ if (rc < 0) {
+ result = NSU_SEND_SYSERR;
+ break;
+ }
+ if (rc == 0) {
+ if (retry == statp->retry) {
+ result = NSU_SEND_TIMEOUT;
+ break;
+ }
+ retry++;
+ continue;
+ }
+ if (pfd.revents & POLLOUT) {
+ n = sendto(pfd.fd, qbuf, qlen, MSG_NOSIGNAL,
+ &a->addr.sa, a->len);
+ if (n < 0) {
+ if (errno == EINTR || errno == EAGAIN) {
+ continue;
+ }
+ result = NSU_SEND_SYSERR;
+ break;
+ }
+ pfd.events = POLLIN;
+ } else if (pfd.revents & POLLIN) {
+ nsu_sockaddr fromaddr;
+ HEADER *hp;
+
+ fromaddr.len = sizeof(fromaddr.addr);
+ n = recvfrom(pfd.fd, rbuf, rlen, 0,
+ &fromaddr.addr.sa, &fromaddr.len);
+ if (n < 0) {
+ if (errno == EINTR || errno == EAGAIN) {
+ continue;
+ }
+ result = NSU_SEND_SYSERR;
+ break;
+ }
+ pfd.events = 0;
+ if (!(statp->options & RES_INSECURE1) &&
+ !(fromaddr.len == a->len &&
+ memcmp(&fromaddr.addr, &a->addr, a->len) == 0)) {
+ nsu_log(NSU_LOG_DEBUG, "%s",
+ "response from the wrong server");
+ //FIXME
+ result = NSU_SEND_BADSERV;
+ break;
+ }
+
+ hp = (HEADER*)rbuf;
+ if (hp->tc) {
+ result = NSU_SEND_RETRYTCP;
+ break;
+ }
+ *return_len = n;
+ result = NSU_SEND_OK;
+ break;
+ } else if (pfd.revents & POLLERR) {
+ result = NSU_SEND_SYSERR;
+ break;
+ } else if (pfd.revents & POLLHUP) {
+ result = NSU_SEND_PEERCLOSE;
+ break;
+ } else if (pfd.revents & POLLNVAL) {
+ result = NSU_SEND_SYSERR;
+ errno = EINVAL;
+ break;
+ } else
+ abort();
+ }
+
+ if (result == NSU_SEND_SYSERR)
+ ec = errno;
+ close(pfd.fd);
+ if (result == NSU_SEND_SYSERR)
+ errno = ec;
+
+ return result;
+}
+
+static int
+nsu_nsend_vc(res_state statp, nsu_sockaddr *a, u_char *qbuf, size_t qlen,
+ u_char *rbuf, size_t rlen, size_t *return_len)
+{
+ struct pollfd pfd;
+ int retry = 0;
+ int result = NSU_SEND_SYSERR;
+ int ec;
+
+ nsu_log(NSU_LOG_DEBUG, "sending query %d via TCP",
+ ((HEADER*)qbuf)->id);
+ pfd.fd = socket(a->addr.sa.sa_family, SOCK_STREAM, 0);
+ if (pfd.fd == -1) {
+ return NSU_SEND_SYSERR;
+ }
+ pfd.events = POLLOUT;
+
+ if (connect(pfd.fd, &a->addr.sa, a->len)) {
+ ec = errno;
+ close(pfd.fd);
+ errno = ec;
+ return NSU_SEND_SYSERR;
+ }
+
+ //FIXME: bind?
+
+ while (1) {
+ ssize_t n;
+ int rc;
+
+ rc = poll(&pfd, 1, statp->retrans * 1000);
+ if (rc < 0) {
+ result = NSU_SEND_SYSERR;
+ break;
+ }
+ if (rc == 0) {
+ if (retry == statp->retry) {
+ result = NSU_SEND_TIMEOUT;
+ break;
+ }
+ retry++;
+ continue;
+ }
+ if (pfd.revents & POLLOUT) {
+ n = write(pfd.fd, qbuf, qlen);
+ if (n < 0) {
+ if (errno == EINTR || errno == EAGAIN) {
+ continue;
+ }
+ result = NSU_SEND_SYSERR;
+ break;
+ }
+ pfd.events = POLLIN;
+ } else if (pfd.revents & POLLIN) {
+ n = read(pfd.fd, rbuf, rlen);
+ if (n < 0) {
+ if (errno == EINTR || errno == EAGAIN) {
+ continue;
+ }
+ result = NSU_SEND_SYSERR;
+ break;
+ }
+ *return_len = n;
+ result = NSU_SEND_OK;
+ break;
+ } else if (pfd.revents & POLLERR) {
+ result = NSU_SEND_SYSERR;
+ break;
+ } else if (pfd.revents & POLLHUP) {
+ result = NSU_SEND_PEERCLOSE;
+ break;
+ } else if (pfd.revents & POLLNVAL) {
+ result = NSU_SEND_SYSERR;
+ errno = EINVAL;
+ break;
+ } else
+ abort();
+ }
+
+ if (result == NSU_SEND_SYSERR)
+ ec = errno;
+ close(pfd.fd);
+ if (result == NSU_SEND_SYSERR)
+ errno = ec;
+
+ return result;
+}
+
+int
+nsu_nsend(res_state statp, nsu_sockaddr *a, u_char *qbuf, size_t qlen,
+ u_char *rbuf, size_t rlen, size_t *return_len)
+{
+ int result;
+
+ if (!qbuf || !rbuf || qlen < sizeof(UPDATE_HEADER) || rlen < sizeof(UPDATE_HEADER)) {
+ errno = EINVAL;
+ return NSU_SEND_SYSERR;
+ }
+
+ result = nsu_nsend_dg(statp, a, qbuf, qlen, rbuf, rlen, return_len);
+ if (result == NSU_SEND_RETRYTCP && (statp->options & RES_USEVC))
+ result = nsu_nsend_vc(statp, a, qbuf, qlen, rbuf, rlen, return_len);
+
+ return result;
+}
+
+
diff --git a/main.c b/main.c
index 6524685..5c95cef 100644
--- a/main.c
+++ b/main.c
@@ -411,38 +411,70 @@ enum {
update_retry
};
+static char const *
+nsu_sockaddr_str(nsu_sockaddr *nsa, char *name, size_t namelen)
+{
+ getnameinfo(&nsa->addr.sa, nsa->len,
+ name, namelen,
+ NULL, 0,
+ NI_NUMERICHOST);
+ return name;
+}
+
int
-send_update_query(res_state state, char const *zone, u_char *qbuf, int qlen)
+send_update_query(res_state state, nsu_sockaddr *nsa,
+ char const *zone, u_char *qbuf, int qlen)
{
union {
UPDATE_HEADER hdr;
- u_char buf[NS_PACKETSZ*2];
+ u_char buf[NS_PACKETSZ];
} response;
- int rlen;
+ size_t rlen;
ns_msg handle;
int rcode;
+ char name[NS_MAXDNAME];
+ char const *nsname = NULL;
+ int rc;
if (nsu_log_enabled(NSU_LOG_DEBUG) || state->options & RES_DEBUG) {
- char name[NS_MAXDNAME];
-
- getnameinfo((struct sockaddr*)state->nsaddr_list,
- sizeof(state->nsaddr_list[0]),
- name, sizeof(name),
- NULL, 0,
- NI_NUMERICHOST);
+ nsname = nsu_sockaddr_str(nsa, name, sizeof(name));
nsu_log_msg(NSU_LOG_DEBUG, "trying nameserver %s", name);
}
- rlen = res_nsend(state, qbuf, qlen,
- (u_char *) &response,
- sizeof(response));
-
- if (rlen < 0) {
- if (errno == ECONNREFUSED) { /* no server on the host */
- panic("connection refused");
- } else {
- /* anything else: no response */
- panic("no response");
+ rc = nsu_nsend(state, nsa, qbuf, qlen,
+ (u_char *) &response,
+ sizeof(response),
+ &rlen);
+
+ if (rc == NSU_SEND_OK) {
+
+ } else {
+ if (!nsname)
+ nsname = nsu_sockaddr_str(nsa, name, sizeof(name));
+ switch (rc) {
+ case NSU_SEND_SYSERR:
+ panic("%s: can't send: %s", nsname, strerror(errno));
+ break;
+
+ case NSU_SEND_TIMEOUT:
+ panic("%s: server timeout", nsname);
+ break;
+
+ case NSU_SEND_BADSERV:
+ panic("%s: response from another server", nsname);
+ break;
+
+ case NSU_SEND_RETRYTCP:
+ panic("%s: response too long; retry using TCP",
+ nsname);
+ break;
+
+ case NSU_SEND_PEERCLOSE:
+ panic("%s: server closed connection", nsname);
+ break;
+
+ default:
+ abort();
}
return update_fail;
}
@@ -471,9 +503,8 @@ send_update_query(res_state state, char const *zone, u_char *qbuf, int qlen)
if (nsu_log_enabled(NSU_LOG_DEBUG)
|| state->options & RES_DEBUG) {
char name[NS_MAXDNAME];
-
- getnameinfo((struct sockaddr*)state->nsaddr_list,
- sizeof(state->nsaddr_list[0]),
+
+ getnameinfo(&nsa->addr.sa, nsa->len,
name, sizeof(name),
NULL, 0,
NI_NUMERICHOST);
@@ -504,6 +535,7 @@ run_update(nsu_rr *prereq, int num_prereq,
int rc;
int i;
struct __res_state rstate;
+ nsu_sockaddr addr;
if (!domain_name) {
char *p = update->name;
@@ -546,11 +578,10 @@ run_update(nsu_rr *prereq, int num_prereq,
res_ninit(&rstate);
- rstate.nscount = 1;
+ addr.len = sizeof(struct sockaddr_in);
for (i = 0; i < nscount; i++) {
- memcpy(&rstate.nsaddr_list[0], nstab + i,
- sizeof(rstate.nsaddr_list[0]));
- rc = send_update_query(&rstate, zone, query.buf, qlen);
+ memcpy(&addr.addr, &nstab[i], sizeof(nstab[0]));
+ rc = send_update_query(&rstate, &addr, zone, query.buf, qlen);
if (rc != update_retry)
break;
}
diff --git a/nsu.h b/nsu.h
index 2016266..57a182c 100644
--- a/nsu.h
+++ b/nsu.h
@@ -177,6 +177,27 @@ int nsu_keyfile_private_read(char const *filename,
uint8_t **pkey, size_t *pkey_len);
int nsu_keyfile_read(char const *name, struct nsu_tsig **ptsig);
+
+typedef struct {
+ socklen_t len;
+ union {
+ struct sockaddr sa;
+ struct sockaddr_in in4;
+ struct sockaddr_in6 in6;
+ } addr;
+} nsu_sockaddr;
+
+enum {
+ NSU_SEND_OK,
+ NSU_SEND_SYSERR,
+ NSU_SEND_TIMEOUT,
+ NSU_SEND_BADSERV,
+ NSU_SEND_RETRYTCP,
+ NSU_SEND_PEERCLOSE
+};
+
+int nsu_nsend(res_state statp, nsu_sockaddr *a, u_char *qbuf, size_t qlen,
+ u_char *rbuf, size_t rlen, size_t *return_len);

Return to:

Send suggestions and report system problems to the System administrator.