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