1 /* $NetBSD: dns-example.c,v 1.1.1.2 2017/01/31 21:14:53 christos Exp $ */ 2 /* 3 This example code shows how to use the high-level, low-level, and 4 server-level interfaces of evdns. 5 6 XXX It's pretty ugly and should probably be cleaned up. 7 */ 8 9 #include <event2/event-config.h> 10 11 /* Compatibility for possible missing IPv6 declarations */ 12 #include "../ipv6-internal.h" 13 14 #include <sys/types.h> 15 16 #ifdef EVENT__HAVE_UNISTD_H 17 #include <unistd.h> 18 #endif 19 20 #ifdef _WIN32 21 #include <winsock2.h> 22 #include <ws2tcpip.h> 23 #include <getopt.h> 24 #else 25 #include <sys/socket.h> 26 #include <netinet/in.h> 27 #include <arpa/inet.h> 28 #endif 29 30 #include <event2/event.h> 31 #include <event2/dns.h> 32 #include <event2/dns_struct.h> 33 #include <event2/util.h> 34 35 #ifdef EVENT__HAVE_NETINET_IN6_H 36 #include <netinet/in6.h> 37 #endif 38 39 #include <stdio.h> 40 #include <stdlib.h> 41 #include <string.h> 42 43 #define u32 ev_uint32_t 44 #define u8 ev_uint8_t 45 46 static const char * 47 debug_ntoa(u32 address) 48 { 49 static char buf[32]; 50 u32 a = ntohl(address); 51 evutil_snprintf(buf, sizeof(buf), "%d.%d.%d.%d", 52 (int)(u8)((a>>24)&0xff), 53 (int)(u8)((a>>16)&0xff), 54 (int)(u8)((a>>8 )&0xff), 55 (int)(u8)((a )&0xff)); 56 return buf; 57 } 58 59 static void 60 main_callback(int result, char type, int count, int ttl, 61 void *addrs, void *orig) { 62 char *n = (char*)orig; 63 int i; 64 for (i = 0; i < count; ++i) { 65 if (type == DNS_IPv4_A) { 66 printf("%s: %s\n", n, debug_ntoa(((u32*)addrs)[i])); 67 } else if (type == DNS_PTR) { 68 printf("%s: %s\n", n, ((char**)addrs)[i]); 69 } 70 } 71 if (!count) { 72 printf("%s: No answer (%d)\n", n, result); 73 } 74 fflush(stdout); 75 } 76 77 static void 78 gai_callback(int err, struct evutil_addrinfo *ai, void *arg) 79 { 80 const char *name = arg; 81 int i; 82 if (err) { 83 printf("%s: %s\n", name, evutil_gai_strerror(err)); 84 } 85 if (ai && ai->ai_canonname) 86 printf(" %s ==> %s\n", name, ai->ai_canonname); 87 for (i=0; ai; ai = ai->ai_next, ++i) { 88 char buf[128]; 89 if (ai->ai_family == PF_INET) { 90 struct sockaddr_in *sin = 91 (struct sockaddr_in*)ai->ai_addr; 92 evutil_inet_ntop(AF_INET, &sin->sin_addr, buf, 93 sizeof(buf)); 94 printf("[%d] %s: %s\n",i,name,buf); 95 } else { 96 struct sockaddr_in6 *sin6 = 97 (struct sockaddr_in6*)ai->ai_addr; 98 evutil_inet_ntop(AF_INET6, &sin6->sin6_addr, buf, 99 sizeof(buf)); 100 printf("[%d] %s: %s\n",i,name,buf); 101 } 102 } 103 } 104 105 static void 106 evdns_server_callback(struct evdns_server_request *req, void *data) 107 { 108 int i, r; 109 (void)data; 110 /* dummy; give 192.168.11.11 as an answer for all A questions, 111 * give foo.bar.example.com as an answer for all PTR questions. */ 112 for (i = 0; i < req->nquestions; ++i) { 113 u32 ans = htonl(0xc0a80b0bUL); 114 if (req->questions[i]->type == EVDNS_TYPE_A && 115 req->questions[i]->dns_question_class == EVDNS_CLASS_INET) { 116 printf(" -- replying for %s (A)\n", req->questions[i]->name); 117 r = evdns_server_request_add_a_reply(req, req->questions[i]->name, 118 1, &ans, 10); 119 if (r<0) 120 printf("eeep, didn't work.\n"); 121 } else if (req->questions[i]->type == EVDNS_TYPE_PTR && 122 req->questions[i]->dns_question_class == EVDNS_CLASS_INET) { 123 printf(" -- replying for %s (PTR)\n", req->questions[i]->name); 124 r = evdns_server_request_add_ptr_reply(req, NULL, req->questions[i]->name, 125 "foo.bar.example.com", 10); 126 if (r<0) 127 printf("ugh, no luck"); 128 } else { 129 printf(" -- skipping %s [%d %d]\n", req->questions[i]->name, 130 req->questions[i]->type, req->questions[i]->dns_question_class); 131 } 132 } 133 134 r = evdns_server_request_respond(req, 0); 135 if (r<0) 136 printf("eeek, couldn't send reply.\n"); 137 } 138 139 static int verbose = 0; 140 141 static void 142 logfn(int is_warn, const char *msg) { 143 if (!is_warn && !verbose) 144 return; 145 fprintf(stderr, "%s: %s\n", is_warn?"WARN":"INFO", msg); 146 } 147 148 int 149 main(int c, char **v) { 150 struct options { 151 int reverse; 152 int use_getaddrinfo; 153 int servertest; 154 const char *resolv_conf; 155 const char *ns; 156 }; 157 struct options o; 158 char opt; 159 struct event_base *event_base = NULL; 160 struct evdns_base *evdns_base = NULL; 161 162 memset(&o, 0, sizeof(o)); 163 164 if (c < 2) { 165 fprintf(stderr, "syntax: %s [-x] [-v] [-c resolv.conf] [-s ns] hostname\n", v[0]); 166 fprintf(stderr, "syntax: %s [-T]\n", v[0]); 167 return 1; 168 } 169 170 while ((opt = getopt(c, v, "xvc:Ts:")) != -1) { 171 switch (opt) { 172 case 'x': o.reverse = 1; break; 173 case 'v': ++verbose; break; 174 case 'g': o.use_getaddrinfo = 1; break; 175 case 'T': o.servertest = 1; break; 176 case 'c': o.resolv_conf = optarg; break; 177 case 's': o.ns = optarg; break; 178 default : fprintf(stderr, "Unknown option %c\n", opt); break; 179 } 180 } 181 182 #ifdef _WIN32 183 { 184 WSADATA WSAData; 185 WSAStartup(0x101, &WSAData); 186 } 187 #endif 188 189 event_base = event_base_new(); 190 evdns_base = evdns_base_new(event_base, EVDNS_BASE_DISABLE_WHEN_INACTIVE); 191 evdns_set_log_fn(logfn); 192 193 if (o.servertest) { 194 evutil_socket_t sock; 195 struct sockaddr_in my_addr; 196 sock = socket(PF_INET, SOCK_DGRAM, 0); 197 if (sock == -1) { 198 perror("socket"); 199 exit(1); 200 } 201 evutil_make_socket_nonblocking(sock); 202 my_addr.sin_family = AF_INET; 203 my_addr.sin_port = htons(10053); 204 my_addr.sin_addr.s_addr = INADDR_ANY; 205 if (bind(sock, (struct sockaddr*)&my_addr, sizeof(my_addr))<0) { 206 perror("bind"); 207 exit(1); 208 } 209 evdns_add_server_port_with_base(event_base, sock, 0, evdns_server_callback, NULL); 210 } 211 if (optind < c) { 212 int res; 213 #ifdef _WIN32 214 if (o.resolv_conf == NULL && !o.ns) 215 res = evdns_base_config_windows_nameservers(evdns_base); 216 else 217 #endif 218 if (o.ns) 219 res = evdns_base_nameserver_ip_add(evdns_base, o.ns); 220 else 221 res = evdns_base_resolv_conf_parse(evdns_base, 222 DNS_OPTION_NAMESERVERS, o.resolv_conf); 223 224 if (res < 0) { 225 fprintf(stderr, "Couldn't configure nameservers"); 226 return 1; 227 } 228 } 229 230 printf("EVUTIL_AI_CANONNAME in example = %d\n", EVUTIL_AI_CANONNAME); 231 for (; optind < c; ++optind) { 232 if (o.reverse) { 233 struct in_addr addr; 234 if (evutil_inet_pton(AF_INET, v[optind], &addr)!=1) { 235 fprintf(stderr, "Skipping non-IP %s\n", v[optind]); 236 continue; 237 } 238 fprintf(stderr, "resolving %s...\n",v[optind]); 239 evdns_base_resolve_reverse(evdns_base, &addr, 0, main_callback, v[optind]); 240 } else if (o.use_getaddrinfo) { 241 struct evutil_addrinfo hints; 242 memset(&hints, 0, sizeof(hints)); 243 hints.ai_family = PF_UNSPEC; 244 hints.ai_protocol = IPPROTO_TCP; 245 hints.ai_flags = EVUTIL_AI_CANONNAME; 246 fprintf(stderr, "resolving (fwd) %s...\n",v[optind]); 247 evdns_getaddrinfo(evdns_base, v[optind], NULL, &hints, 248 gai_callback, v[optind]); 249 } else { 250 fprintf(stderr, "resolving (fwd) %s...\n",v[optind]); 251 evdns_base_resolve_ipv4(evdns_base, v[optind], 0, main_callback, v[optind]); 252 } 253 } 254 fflush(stdout); 255 event_base_dispatch(event_base); 256 return 0; 257 } 258 259