chiark / gitweb /
56654ec0473b2edcfcd4ee8d3812b9ba6ac80b1e
[elogind.git] / src / libsystemd-bus / test-dns.c
1 /***
2   This file is part of libasyncns.
3
4   Copyright 2005-2008 Lennart Poettering
5
6   libasyncns is free software; you can redistribute it and/or modify
7   it under the terms of the GNU Lesser General Public License as
8   published by the Free Software Foundation, either version 2.1 of the
9   License, or (at your option) any later version.
10
11   libasyncns is distributed in the hope that it will be useful, but
12   WITHOUT ANY WARRANTY; without even the implied warranty of
13   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14   Lesser General Public License for more details.
15
16   You should have received a copy of the GNU Lesser General Public
17   License along with libasyncns. If not, see
18   <http://www.gnu.org/licenses/>.
19  ***/
20
21 #if HAVE_CONFIG_H
22 #include <config.h>
23 #endif
24
25 #include <string.h>
26 #include <sys/types.h>
27 #include <sys/socket.h>
28 #include <arpa/inet.h>
29 #include <stdio.h>
30 #include <netinet/in.h>
31 #include <arpa/nameser.h>
32 #include <resolv.h>
33 #include <assert.h>
34 #include <signal.h>
35 #include <errno.h>
36
37 #include "sd-dns.h"
38 #include "dns-util.h"
39 #include "macro.h"
40
41 int main(int argc, char *argv[]) {
42         int r = 1, ret;
43         _cleanup_asyncns_free_ asyncns_t *asyncns = NULL;
44         _cleanup_asyncns_addrinfo_free_ struct addrinfo *ai = NULL;
45         _cleanup_asyncns_answer_free_ unsigned char *srv = NULL;
46         asyncns_query_t *q1, *q2, *q3;
47         struct addrinfo hints = {};
48         struct sockaddr_in sa = {};
49         char host[NI_MAXHOST] = "", serv[NI_MAXSERV] = "";
50
51         signal(SIGCHLD, SIG_IGN);
52
53         asyncns = asyncns_new(2);
54         if (!asyncns)
55                 log_oom();
56
57         /* Make a name -> address query */
58         hints.ai_family = PF_UNSPEC;
59         hints.ai_socktype = SOCK_STREAM;
60
61         q1 = asyncns_getaddrinfo(asyncns, argc >= 2 ? argv[1] : "www.heise.de", NULL, &hints);
62
63         if (!q1)
64                 fprintf(stderr, "asyncns_getaddrinfo(): %s\n", strerror(errno));
65
66         /* Make an address -> name query */
67         sa.sin_family = AF_INET;
68         sa.sin_addr.s_addr = inet_addr(argc >= 3 ? argv[2] : "193.99.144.71");
69         sa.sin_port = htons(80);
70
71         q2 = asyncns_getnameinfo(asyncns, (struct sockaddr*) &sa, sizeof(sa), 0, 1, 1);
72
73         if (!q2)
74                 fprintf(stderr, "asyncns_getnameinfo(): %s\n", strerror(errno));
75
76         /* Make a res_query() call */
77         q3 = asyncns_res_query(asyncns, "_xmpp-client._tcp.gmail.com", C_IN, T_SRV);
78
79         if (!q3)
80                 fprintf(stderr, "asyncns_res_query(): %s\n", strerror(errno));
81
82         /* Wait until the three queries are completed */
83         while (!asyncns_isdone(asyncns, q1)
84                         || !asyncns_isdone(asyncns, q2)
85                         || !asyncns_isdone(asyncns, q3)) {
86                 if (asyncns_wait(asyncns, 1) < 0) {
87                         fprintf(stderr, "asyncns_wait(): %s\n", strerror(errno));
88                 }
89         }
90
91         /* Interpret the result of the name -> addr query */
92         if ((ret = asyncns_getaddrinfo_done(asyncns, q1, &ai)))
93                 fprintf(stderr, "error: %s %i\n", gai_strerror(ret), ret);
94         else {
95                 struct addrinfo *i;
96
97                 for (i = ai; i; i = i->ai_next) {
98                         char t[256];
99                         const char *p = NULL;
100
101                         if (i->ai_family == PF_INET)
102                                 p = inet_ntop(AF_INET, &((struct sockaddr_in*) i->ai_addr)->sin_addr, t, sizeof(t));
103                         else if (i->ai_family == PF_INET6)
104                                 p = inet_ntop(AF_INET6, &((struct sockaddr_in6*) i->ai_addr)->sin6_addr, t, sizeof(t));
105
106                         printf("%s\n", p);
107                 }
108         }
109
110         /* Interpret the result of the addr -> name query */
111         if ((ret = asyncns_getnameinfo_done(asyncns, q2, host, sizeof(host), serv, sizeof(serv))))
112                 fprintf(stderr, "error: %s %i\n", gai_strerror(ret), ret);
113         else
114                 printf("%s -- %s\n", host, serv);
115
116         /* Interpret the result of the SRV lookup */
117         if ((ret = asyncns_res_done(asyncns, q3, &srv)) < 0) {
118                 fprintf(stderr, "error: %s %i\n", strerror(errno), ret);
119         } else if (ret == 0) {
120                 fprintf(stderr, "No reply for SRV lookup\n");
121         } else {
122                 int qdcount;
123                 int ancount;
124                 int len;
125                 const unsigned char *pos = srv + sizeof(HEADER);
126                 unsigned char *end = srv + ret;
127                 HEADER *head = (HEADER *)srv;
128                 char name[256];
129
130                 qdcount = ntohs(head->qdcount);
131                 ancount = ntohs(head->ancount);
132
133                 printf("%d answers for srv lookup:\n", ancount);
134
135                 /* Ignore the questions */
136                 while (qdcount-- > 0 && (len = dn_expand(srv, end, pos, name, 255)) >= 0) {
137                         assert(len >= 0);
138                         pos += len + QFIXEDSZ;
139                 }
140
141                 /* Parse the answers */
142                 while (ancount-- > 0 && (len = dn_expand(srv, end, pos, name, 255)) >= 0) {
143                         /* Ignore the initial string */
144                         uint16_t pref, weight, port;
145                         assert(len >= 0);
146                         pos += len;
147                         /* Ignore type, ttl, class and dlen */
148                         pos += 10;
149
150                         GETSHORT(pref, pos);
151                         GETSHORT(weight, pos);
152                         GETSHORT(port, pos);
153                         len = dn_expand(srv, end, pos, name, 255);
154                         printf("\tpreference: %2d weight: %2d port: %d host: %s\n",
155                                         pref, weight, port, name);
156
157                         pos += len;
158                 }
159         }
160
161         r = 0;
162
163         return r;
164 }