chiark / gitweb /
d08e1b5a05bdf2bb5be47bda937548931f93892f
[elogind.git] / src / libsystemd / sd-resolve / test-resolve.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   Copyright 2014 Daniel Buch
8
9   systemd is free software; you can redistribute it and/or modify it
10   under the terms of the GNU Lesser General Public License as published by
11   the Free Software Foundation; either version 2.1 of the License, or
12   (at your option) any later version.
13
14   systemd is distributed in the hope that it will be useful, but
15   WITHOUT ANY WARRANTY; without even the implied warranty of
16   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
17   Lesser General Public License for more details.
18
19   You should have received a copy of the GNU Lesser General Public License
20   along with systemd; If not, see <http://www.gnu.org/licenses/>.
21 ***/
22
23 #include <string.h>
24 #include <sys/types.h>
25 #include <sys/socket.h>
26 #include <arpa/inet.h>
27 #include <stdio.h>
28 #include <netinet/in.h>
29 #include <arpa/nameser.h>
30 #include <resolv.h>
31 #include <signal.h>
32 #include <errno.h>
33
34 #include "socket-util.h"
35 #include "sd-resolve.h"
36 #include "resolve-util.h"
37 #include "macro.h"
38
39 static int getaddrinfo_handler(sd_resolve_query *q, int ret, const struct addrinfo *ai, void *userdata) {
40         const struct addrinfo *i;
41
42         assert_se(q);
43
44         if (ret != 0) {
45                 log_error("getaddrinfo error: %s %i", gai_strerror(ret), ret);
46                 return 0;
47         }
48
49         for (i = ai; i; i = i->ai_next) {
50                 _cleanup_free_ char *addr = NULL;
51
52                 assert_se(sockaddr_pretty(i->ai_addr, i->ai_addrlen, false, &addr) == 0);
53                 puts(addr);
54         }
55
56         printf("canonical name: %s\n", strna(ai->ai_canonname));
57
58         return 0;
59 }
60
61 static int getnameinfo_handler(sd_resolve_query *q, int ret, const char *host, const char *serv, void *userdata) {
62         assert_se(q);
63
64         if (ret != 0) {
65                 log_error("getnameinfo error: %s %i", gai_strerror(ret), ret);
66                 return 0;
67         }
68
69         printf("Host: %s -- Serv: %s\n", strna(host), strna(serv));
70         return 0;
71 }
72
73 static int res_handler(sd_resolve_query *q, int ret, unsigned char *answer, void *userdata) {
74         int qdcount, ancount, len;
75         const unsigned char *pos = answer + sizeof(HEADER);
76         unsigned char *end = answer + ret;
77         HEADER *head = (HEADER *) answer;
78         char name[256];
79         assert_se(q);
80
81         if (ret < 0) {
82                 log_error("res_query() error: %s %i", strerror(errno), errno);
83                 return 0;
84         }
85
86         if (ret == 0) {
87                 log_error("No reply for SRV lookup");
88                 return 0;
89         }
90
91         qdcount = ntohs(head->qdcount);
92         ancount = ntohs(head->ancount);
93
94         printf("%d answers for srv lookup:\n", ancount);
95
96         /* Ignore the questions */
97         while (qdcount-- > 0 && (len = dn_expand(answer, end, pos, name, 255)) >= 0) {
98                 assert_se(len >= 0);
99                 pos += len + QFIXEDSZ;
100         }
101
102         /* Parse the answers */
103         while (ancount-- > 0 && (len = dn_expand(answer, end, pos, name, 255)) >= 0) {
104                 /* Ignore the initial string */
105                 uint16_t pref, weight, port;
106                 assert_se(len >= 0);
107                 pos += len;
108                 /* Ignore type, ttl, class and dlen */
109                 pos += 10;
110
111                 GETSHORT(pref, pos);
112                 GETSHORT(weight, pos);
113                 GETSHORT(port, pos);
114                 len = dn_expand(answer, end, pos, name, 255);
115                 printf("\tpreference: %2d weight: %2d port: %d host: %s\n",
116                        pref, weight, port, name);
117
118                 pos += len;
119         }
120
121         return 0;
122 }
123
124 int main(int argc, char *argv[]) {
125         _cleanup_resolve_query_unref_ sd_resolve_query *q1 = NULL, *q2 = NULL, *q3 = NULL;
126         _cleanup_resolve_unref_ sd_resolve *resolve = NULL;
127         int r = 0;
128
129         struct addrinfo hints = {
130                 .ai_family = PF_UNSPEC,
131                 .ai_socktype = SOCK_STREAM,
132                 .ai_flags = AI_CANONNAME
133         };
134
135         struct sockaddr_in sa = {
136                 .sin_family = AF_INET,
137                 .sin_port = htons(80)
138         };
139
140         assert_se(sd_resolve_default(&resolve) >= 0);
141
142         /* Test a floating resolver query */
143         sd_resolve_getaddrinfo(resolve, NULL, "redhat.com", "http", NULL, getaddrinfo_handler, NULL);
144
145         /* Make a name -> address query */
146         r = sd_resolve_getaddrinfo(resolve, &q1, argc >= 2 ? argv[1] : "www.heise.de", NULL, &hints, getaddrinfo_handler, NULL);
147         if (r < 0)
148                 log_error_errno(r, "sd_resolve_getaddrinfo(): %m");
149
150         /* Make an address -> name query */
151         sa.sin_addr.s_addr = inet_addr(argc >= 3 ? argv[2] : "193.99.144.71");
152         r = sd_resolve_getnameinfo(resolve, &q2, (struct sockaddr*) &sa, sizeof(sa), 0, SD_RESOLVE_GET_BOTH, getnameinfo_handler, NULL);
153         if (r < 0)
154                 log_error_errno(r, "sd_resolve_getnameinfo(): %m");
155
156         /* Make a res_query() call */
157         r = sd_resolve_res_query(resolve, &q3, "_xmpp-client._tcp.gmail.com", C_IN, T_SRV, res_handler, NULL);
158         if (r < 0)
159                 log_error_errno(r, "sd_resolve_res_query(): %m");
160
161         /* Wait until the three queries are completed */
162         while (sd_resolve_query_is_done(q1) == 0 ||
163                sd_resolve_query_is_done(q2) == 0 ||
164                sd_resolve_query_is_done(q3) == 0) {
165
166                 r = sd_resolve_wait(resolve, (uint64_t) -1);
167                 if (r < 0) {
168                         log_error_errno(r, "sd_resolve_wait(): %m");
169                         assert_not_reached("sd_resolve_wait() failed");
170                 }
171         }
172
173         return 0;
174 }