tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

dns-example.c (6759B)


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