chiark / gitweb /
libsystemd-rtnl: merge into libsystemd
[elogind.git] / src / libsystemd / 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 #include <string.h>
23 #include <sys/types.h>
24 #include <sys/socket.h>
25 #include <arpa/inet.h>
26 #include <stdio.h>
27 #include <netinet/in.h>
28 #include <arpa/nameser.h>
29 #include <resolv.h>
30 #include <assert.h>
31 #include <signal.h>
32 #include <errno.h>
33
34 #include "sd-dns.h"
35 #include "dns-util.h"
36 #include "macro.h"
37
38 int main(int argc, char *argv[]) {
39         int r = 1, ret;
40         _cleanup_asyncns_free_ asyncns_t *asyncns = NULL;
41         _cleanup_asyncns_addrinfo_free_ struct addrinfo *ai = NULL;
42         _cleanup_asyncns_answer_free_ unsigned char *srv = NULL;
43         asyncns_query_t *q1, *q2, *q3;
44         struct addrinfo hints = {};
45         struct sockaddr_in sa = {};
46         char host[NI_MAXHOST] = "", serv[NI_MAXSERV] = "";
47
48         signal(SIGCHLD, SIG_IGN);
49
50         asyncns = asyncns_new(2);
51         if (!asyncns)
52                 log_oom();
53
54         /* Make a name -> address query */
55         hints.ai_family = PF_UNSPEC;
56         hints.ai_socktype = SOCK_STREAM;
57
58         q1 = asyncns_getaddrinfo(asyncns, argc >= 2 ? argv[1] : "www.heise.de", NULL, &hints);
59         if (!q1)
60                 fprintf(stderr, "asyncns_getaddrinfo(): %s\n", strerror(errno));
61
62         /* Make an address -> name query */
63         sa.sin_family = AF_INET;
64         sa.sin_addr.s_addr = inet_addr(argc >= 3 ? argv[2] : "193.99.144.71");
65         sa.sin_port = htons(80);
66
67         q2 = asyncns_getnameinfo(asyncns, (struct sockaddr*) &sa, sizeof(sa), 0, 1, 1);
68         if (!q2)
69                 fprintf(stderr, "asyncns_getnameinfo(): %s\n", strerror(errno));
70
71         /* Make a res_query() call */
72         q3 = asyncns_res_query(asyncns, "_xmpp-client._tcp.gmail.com", C_IN, T_SRV);
73         if (!q3)
74                 fprintf(stderr, "asyncns_res_query(): %s\n", strerror(errno));
75
76         /* Wait until the three queries are completed */
77         while (!asyncns_isdone(asyncns, q1) ||
78                !asyncns_isdone(asyncns, q2) ||
79                !asyncns_isdone(asyncns, q3)) {
80                 if (asyncns_wait(asyncns, 1) < 0)
81                         fprintf(stderr, "asyncns_wait(): %s\n", strerror(errno));
82         }
83
84         /* Interpret the result of the name -> addr query */
85         ret = asyncns_getaddrinfo_done(asyncns, q1, &ai);
86         if (ret)
87                 fprintf(stderr, "error: %s %i\n", gai_strerror(ret), ret);
88         else {
89                 struct addrinfo *i;
90
91                 for (i = ai; i; i = i->ai_next) {
92                         char t[256];
93                         const char *p = NULL;
94
95                         if (i->ai_family == PF_INET)
96                                 p = inet_ntop(AF_INET, &((struct sockaddr_in*) i->ai_addr)->sin_addr, t, sizeof(t));
97                         else if (i->ai_family == PF_INET6)
98                                 p = inet_ntop(AF_INET6, &((struct sockaddr_in6*) i->ai_addr)->sin6_addr, t, sizeof(t));
99
100                         printf("%s\n", p);
101                 }
102         }
103
104         /* Interpret the result of the addr -> name query */
105         ret = asyncns_getnameinfo_done(asyncns, q2, host, sizeof(host), serv, sizeof(serv));
106         if (ret)
107                 fprintf(stderr, "error: %s %i\n", gai_strerror(ret), ret);
108         else
109                 printf("%s -- %s\n", host, serv);
110
111         /* Interpret the result of the SRV lookup */
112         ret = asyncns_res_done(asyncns, q3, &srv);
113         if (ret < 0) {
114                 fprintf(stderr, "error: %s %i\n", strerror(errno), ret);
115         } else if (ret == 0) {
116                 fprintf(stderr, "No reply for SRV lookup\n");
117         } else {
118                 int qdcount;
119                 int ancount;
120                 int len;
121                 const unsigned char *pos = srv + sizeof(HEADER);
122                 unsigned char *end = srv + ret;
123                 HEADER *head = (HEADER *)srv;
124                 char name[256];
125
126                 qdcount = ntohs(head->qdcount);
127                 ancount = ntohs(head->ancount);
128
129                 printf("%d answers for srv lookup:\n", ancount);
130
131                 /* Ignore the questions */
132                 while (qdcount-- > 0 && (len = dn_expand(srv, end, pos, name, 255)) >= 0) {
133                         assert(len >= 0);
134                         pos += len + QFIXEDSZ;
135                 }
136
137                 /* Parse the answers */
138                 while (ancount-- > 0 && (len = dn_expand(srv, end, pos, name, 255)) >= 0) {
139                         /* Ignore the initial string */
140                         uint16_t pref, weight, port;
141                         assert(len >= 0);
142                         pos += len;
143                         /* Ignore type, ttl, class and dlen */
144                         pos += 10;
145
146                         GETSHORT(pref, pos);
147                         GETSHORT(weight, pos);
148                         GETSHORT(port, pos);
149                         len = dn_expand(srv, end, pos, name, 255);
150                         printf("\tpreference: %2d weight: %2d port: %d host: %s\n",
151                                         pref, weight, port, name);
152
153                         pos += len;
154                 }
155         }
156
157         r = 0;
158
159         return r;
160 }