sd-dns: initial commit

Origin: <http://0pointer.de/lennart/projects/libasyncns/>

[tomegun: renamed some more files asyncns -> sd-dns and moved to libsystemd-bus as
requested by Lennart]
This commit is contained in:
Daniel Buch 2014-01-06 13:41:59 +01:00 committed by Tom Gundersen
parent e0d4a0ac06
commit e963e3ada1
6 changed files with 1516 additions and 0 deletions

1
.gitignore vendored
View file

@ -134,6 +134,7 @@
/test-device-nodes
/test-dhcp-client
/test-dhcp-option
/test-dns
/test-ellipsize
/test-engine
/test-env-replace

View file

@ -665,6 +665,35 @@ test_rtnl_LDADD = \
tests += \
test-rtnl
# ------------------------------------------------------------------------------
noinst_LTLIBRARIES += \
libsystemd-dns.la
libsystemd_dns_la_SOURCES = \
src/systemd/sd-dns.h \
src/libsystemd-bus/sd-dns.c \
src/libsystemd-bus/dns-util.h
libsystemd_dns_la_LIBADD = \
libsystemd-shared.la
libsystemd_dns_la_CFLAGS = \
-pthread
test_dns_SOURCES = \
src/libsystemd-bus/test-dns.c \
src/systemd/sd-dns.h
test_dns_LDADD = \
libsystemd-dns.la
test_dns_LDFLAGS = \
-lresolv \
-pthread
tests += \
test-dns
# ------------------------------------------------------------------------------
noinst_LTLIBRARIES += \
libsystemd-shared.la

View file

@ -0,0 +1,8 @@
#pragma once
DEFINE_TRIVIAL_CLEANUP_FUNC(asyncns_t*, asyncns_free);
DEFINE_TRIVIAL_CLEANUP_FUNC(unsigned char *, asyncns_freeanswer);
DEFINE_TRIVIAL_CLEANUP_FUNC(struct addrinfo*, asyncns_freeaddrinfo);
#define _cleanup_asyncns_free_ _cleanup_(asyncns_freep)
#define _cleanup_asyncns_answer_free_ _cleanup_(asyncns_freeanswerp)
#define _cleanup_asyncns_addrinfo_free_ _cleanup_(asyncns_freeaddrinfop)

1158
src/libsystemd-bus/sd-dns.c Normal file

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,164 @@
/***
This file is part of libasyncns.
Copyright 2005-2008 Lennart Poettering
libasyncns is free software; you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as
published by the Free Software Foundation, either version 2.1 of the
License, or (at your option) any later version.
libasyncns is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with libasyncns. If not, see
<http://www.gnu.org/licenses/>.
***/
#if HAVE_CONFIG_H
#include <config.h>
#endif
#include <string.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <stdio.h>
#include <netinet/in.h>
#include <arpa/nameser.h>
#include <resolv.h>
#include <assert.h>
#include <signal.h>
#include <errno.h>
#include "sd-dns.h"
#include "dns-util.h"
#include "macro.h"
int main(int argc, char *argv[]) {
int r = 1, ret;
_cleanup_asyncns_free_ asyncns_t *asyncns = NULL;
_cleanup_asyncns_addrinfo_free_ struct addrinfo *ai = NULL;
_cleanup_asyncns_answer_free_ unsigned char *srv = NULL;
asyncns_query_t *q1, *q2, *q3;
struct addrinfo hints = {};
struct sockaddr_in sa = {};
char host[NI_MAXHOST] = "", serv[NI_MAXSERV] = "";
signal(SIGCHLD, SIG_IGN);
asyncns = asyncns_new(2);
if (!asyncns)
log_oom();
/* Make a name -> address query */
hints.ai_family = PF_UNSPEC;
hints.ai_socktype = SOCK_STREAM;
q1 = asyncns_getaddrinfo(asyncns, argc >= 2 ? argv[1] : "www.heise.de", NULL, &hints);
if (!q1)
fprintf(stderr, "asyncns_getaddrinfo(): %s\n", strerror(errno));
/* Make an address -> name query */
sa.sin_family = AF_INET;
sa.sin_addr.s_addr = inet_addr(argc >= 3 ? argv[2] : "193.99.144.71");
sa.sin_port = htons(80);
q2 = asyncns_getnameinfo(asyncns, (struct sockaddr*) &sa, sizeof(sa), 0, 1, 1);
if (!q2)
fprintf(stderr, "asyncns_getnameinfo(): %s\n", strerror(errno));
/* Make a res_query() call */
q3 = asyncns_res_query(asyncns, "_xmpp-client._tcp.gmail.com", C_IN, T_SRV);
if (!q3)
fprintf(stderr, "asyncns_res_query(): %s\n", strerror(errno));
/* Wait until the three queries are completed */
while (!asyncns_isdone(asyncns, q1)
|| !asyncns_isdone(asyncns, q2)
|| !asyncns_isdone(asyncns, q3)) {
if (asyncns_wait(asyncns, 1) < 0) {
fprintf(stderr, "asyncns_wait(): %s\n", strerror(errno));
}
}
/* Interpret the result of the name -> addr query */
if ((ret = asyncns_getaddrinfo_done(asyncns, q1, &ai)))
fprintf(stderr, "error: %s %i\n", gai_strerror(ret), ret);
else {
struct addrinfo *i;
for (i = ai; i; i = i->ai_next) {
char t[256];
const char *p = NULL;
if (i->ai_family == PF_INET)
p = inet_ntop(AF_INET, &((struct sockaddr_in*) i->ai_addr)->sin_addr, t, sizeof(t));
else if (i->ai_family == PF_INET6)
p = inet_ntop(AF_INET6, &((struct sockaddr_in6*) i->ai_addr)->sin6_addr, t, sizeof(t));
printf("%s\n", p);
}
}
/* Interpret the result of the addr -> name query */
if ((ret = asyncns_getnameinfo_done(asyncns, q2, host, sizeof(host), serv, sizeof(serv))))
fprintf(stderr, "error: %s %i\n", gai_strerror(ret), ret);
else
printf("%s -- %s\n", host, serv);
/* Interpret the result of the SRV lookup */
if ((ret = asyncns_res_done(asyncns, q3, &srv)) < 0) {
fprintf(stderr, "error: %s %i\n", strerror(errno), ret);
} else if (ret == 0) {
fprintf(stderr, "No reply for SRV lookup\n");
} else {
int qdcount;
int ancount;
int len;
const unsigned char *pos = srv + sizeof(HEADER);
unsigned char *end = srv + ret;
HEADER *head = (HEADER *)srv;
char name[256];
qdcount = ntohs(head->qdcount);
ancount = ntohs(head->ancount);
printf("%d answers for srv lookup:\n", ancount);
/* Ignore the questions */
while (qdcount-- > 0 && (len = dn_expand(srv, end, pos, name, 255)) >= 0) {
assert(len >= 0);
pos += len + QFIXEDSZ;
}
/* Parse the answers */
while (ancount-- > 0 && (len = dn_expand(srv, end, pos, name, 255)) >= 0) {
/* Ignore the initial string */
uint16_t pref, weight, port;
assert(len >= 0);
pos += len;
/* Ignore type, ttl, class and dlen */
pos += 10;
GETSHORT(pref, pos);
GETSHORT(weight, pos);
GETSHORT(port, pos);
len = dn_expand(srv, end, pos, name, 255);
printf("\tpreference: %2d weight: %2d port: %d host: %s\n",
pref, weight, port, name);
pos += len;
}
}
r = 0;
return r;
}

156
src/systemd/sd-dns.h Normal file
View file

@ -0,0 +1,156 @@
#ifndef fooasyncnshfoo
#define fooasyncnshfoo
/***
This file is part of libasyncns.
Copyright 2005-2008 Lennart Poettering
libasyncns is free software; you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as
published by the Free Software Foundation, either version 2.1 of the
License, or (at your option) any later version.
libasyncns is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with libasyncns. If not, see
<http://www.gnu.org/licenses/>.
***/
#include <sys/types.h>
#include <sys/socket.h>
#include <netdb.h>
#include "macro.h"
#include "util.h"
/** \mainpage
*
* \section moo Method of operation
*
* To use libasyncns allocate an asyncns_t object with
* asyncns_new(). This will spawn a number of worker threads (or processes, depending on what is available) which
* are subsequently used to process the queries the controlling
* program issues via asyncns_getaddrinfo() and
* asyncns_getnameinfo(). Use asyncns_free() to shut down the worker
* threads/processes.
*
* Since libasyncns may fork off new processes you have to make sure that
* your program is not irritated by spurious SIGCHLD signals.
*/
/** \example asyncns-test.c
* An example program */
/** An opaque libasyncns session structure */
typedef struct asyncns asyncns_t;
/** An opaque libasyncns query structure */
typedef struct asyncns_query asyncns_query_t;
/** Allocate a new libasyncns session with n_proc worker processes/threads */
asyncns_t* asyncns_new(unsigned n_proc);
/** Free a libasyncns session. This destroys all attached
* asyncns_query_t objects automatically */
void asyncns_free(asyncns_t *asyncns);
/** Return the UNIX file descriptor to select() for readability
* on. Use this function to integrate libasyncns with your custom main
* loop. */
int asyncns_fd(asyncns_t *asyncns);
/** Process pending responses. After this function is called you can
* get the next completed query object(s) using asyncns_getnext(). If
* block is non-zero wait until at least one response has been
* processed. If block is zero, process all pending responses and
* return. */
int asyncns_wait(asyncns_t *asyncns, int block);
/** Issue a name to address query on the specified session. The
* arguments are compatible with the ones of libc's
* getaddrinfo(3). The function returns a new query object. When the
* query is completed you may retrieve the results using
* asyncns_getaddrinfo_done().*/
asyncns_query_t* asyncns_getaddrinfo(asyncns_t *asyncns, const char *node, const char *service, const struct addrinfo *hints);
/** Retrieve the results of a preceding asyncns_getaddrinfo()
* call. Returns a addrinfo structure and a return value compatible
* with libc's getaddrinfo(3). The query object q is destroyed by this
* call and may not be used any further. Make sure to free the
* returned addrinfo structure with asyncns_freeaddrinfo() and not
* libc's freeaddrinfo(3)! If the query is not completed yet EAI_AGAIN
* is returned.*/
int asyncns_getaddrinfo_done(asyncns_t *asyncns, asyncns_query_t* q, struct addrinfo **ret_res);
/** Issue an address to name query on the specified session. The
* arguments are compatible with the ones of libc's
* getnameinfo(3). The function returns a new query object. When the
* query is completed you may retrieve the results using
* asyncns_getnameinfo_done(). Set gethost (resp. getserv) to non-zero
* if you want to query the hostname (resp. the service name). */
asyncns_query_t* asyncns_getnameinfo(asyncns_t *asyncns, const struct sockaddr *sa, socklen_t salen, int flags, int gethost, int getserv);
/** Retrieve the results of a preceding asyncns_getnameinfo()
* call. Returns the hostname and the service name in ret_host and
* ret_serv. The query object q is destroyed by this call and may not
* be used any further. If the query is not completed yet EAI_AGAIN is
* returned. */
int asyncns_getnameinfo_done(asyncns_t *asyncns, asyncns_query_t* q, char *ret_host, size_t hostlen, char *ret_serv, size_t servlen);
/** Issue a resolver query on the specified session. The arguments are
* compatible with the ones of libc's res_query(3). The function returns a new
* query object. When the query is completed you may retrieve the results using
* asyncns_res_done(). */
asyncns_query_t* asyncns_res_query(asyncns_t *asyncns, const char *dname, int class, int type);
/** Issue an resolver query on the specified session. The arguments are
* compatible with the ones of libc's res_search(3). The function returns a new
* query object. When the query is completed you may retrieve the results using
* asyncns_res_done(). */
asyncns_query_t* asyncns_res_search(asyncns_t *asyncns, const char *dname, int class, int type);
/** Retrieve the results of a preceding asyncns_res_query() or
* asyncns_res_search call. The query object q is destroyed by this
* call and may not be used any further. Returns a pointer to the
* answer of the res_query call. If the query is not completed yet
* -EAGAIN is returned, on failure -errno is returned, otherwise the
* length of answer is returned. Make sure to free the answer is a
* call to asyncns_freeanswer(). */
int asyncns_res_done(asyncns_t *asyncns, asyncns_query_t* q, unsigned char **answer);
/** Return the next completed query object. If no query has been
* completed yet, return NULL. Please note that you need to run
* asyncns_wait() before this function will return sensible data. */
asyncns_query_t* asyncns_getnext(asyncns_t *asyncns);
/** Return the number of query objects (completed or not) attached to
* this session */
int asyncns_getnqueries(asyncns_t *asyncns);
/** Cancel a currently running query. q is is destroyed by this call
* and may not be used any futher. */
void asyncns_cancel(asyncns_t *asyncns, asyncns_query_t* q);
/** Free the addrinfo structure as returned by
* asyncns_getaddrinfo_done(). Make sure to use this functions instead
* of the libc's freeaddrinfo()! */
void asyncns_freeaddrinfo(struct addrinfo *ai);
/** Free the answer data as returned by asyncns_res_done().*/
void asyncns_freeanswer(unsigned char *answer);
/** Returns non-zero when the query operation specified by q has been completed */
int asyncns_isdone(asyncns_t *asyncns, asyncns_query_t*q);
/** Assign some opaque userdata with a query object */
void asyncns_setuserdata(asyncns_t *asyncns, asyncns_query_t *q, void *userdata);
/** Return userdata assigned to a query object. Use
* asyncns_setuserdata() to set this data. If no data has been set
* prior to this call it returns NULL. */
void* asyncns_getuserdata(asyncns_t *asyncns, asyncns_query_t *q);
#endif