1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
|
/*
** Copyright 1998 - 2011 Double Precision, Inc.
** See COPYING for distribution information.
*/
#ifndef rfc1035_h
#define rfc1035_h
#if HAVE_CONFIG_H
#include "rfc1035/config.h"
#endif
#include "random128/random128.h"
#include "md5/md5.h"
#include <stdio.h>
#include <sys/types.h>
#include <sys/socket.h>
#if HAVE_NETINET_IN_H
#include <netinet/in.h>
#endif
#if HAVE_STDINT_H
#include <stdint.h>
#endif
#ifdef __cplusplus
extern "C" {
#endif
#if RFC1035_IPV6
typedef struct in6_addr RFC1035_ADDR;
typedef struct sockaddr_in6 RFC1035_SOCKADDR;
typedef struct sockaddr_storage RFC1035_NETADDR;
#define RFC1035_ADDRANY in6addr_any
#else
typedef struct in_addr RFC1035_ADDR;
typedef struct sockaddr_in RFC1035_SOCKADDR;
typedef struct sockaddr RFC1035_NETADDR;
extern struct in_addr rfc1035_addr_any;
#define RFC1035_ADDRANY rfc1035_addr_any
#endif
#define RFC1035_TYPE_A 1
#define RFC1035_TYPE_NS 2
#define RFC1035_TYPE_MD 3
#define RFC1035_TYPE_MF 4
#define RFC1035_TYPE_CNAME 5
#define RFC1035_TYPE_SOA 6
#define RFC1035_TYPE_MB 7
#define RFC1035_TYPE_MG 8
#define RFC1035_TYPE_MR 9
#define RFC1035_TYPE_NULL 10
#define RFC1035_TYPE_WKS 11
#define RFC1035_TYPE_PTR 12
#define RFC1035_TYPE_HINFO 13
#define RFC1035_TYPE_MINFO 14
#define RFC1035_TYPE_MX 15
#define RFC1035_TYPE_TXT 16
#define RFC1035_TYPE_AAAA 28 /* RFC 1886. Even if we don't have
IPv6 */
#define RFC1035_TYPE_OPT 41
#define RFC1035_TYPE_RRSIG 46
#define RFC1035_TYPE_AXFR 252
#define RFC1035_TYPE_MAILB 253
#define RFC1035_TYPE_MAILA 254
#define RFC1035_TYPE_ANY 255
void rfc1035_type_itostr(int, void (*)(const char *, void *), void *);
int rfc1035_type_strtoi(const char *);
#define RFC1035_CLASS_IN 1
#define RFC1035_CLASS_CSNET 2
#define RFC1035_CLASS_CHAOS 3
#define RFC1035_CLASS_HESIOD 4
#define RFC1035_CLASS_ANY 255
const char *rfc1035_class_itostr(int);
int rfc1035_class_strtoi(const char *);
#define RFC1035_OPCODE_QUERY 0
#define RFC1035_OPCODE_IQUERY 1
#define RFC1035_OPCODE_STATUS 2
const char *rfc1035_opcode_itostr(int);
int rfc1035_opcode_strtoi(const char *);
#define RFC1035_RCODE_NOERROR 0
#define RFC1035_RCODE_FORMAT 1
#define RFC1035_RCODE_SERVFAIL 2
#define RFC1035_RCODE_NXDOMAIN 3
#define RFC1035_RCODE_UNIMPLEMENTED 4
#define RFC1035_RCODE_REFUSED 5
const char *rfc1035_rcode_itostr(int);
int rfc1035_rcode_strtoi(const char *);
struct rfc1035_query {
const char *name;
unsigned qtype, qclass;
} ;
struct rfc1035_reply; /* Defined below */
struct rfc1035_rr; /* Defined below */
/*
** The init family of functions perform various initializations. Calling them
** is optional, as librfc1035.a will use defaults if not specified.
*/
#define RFC1035_MAXNS 10
#define RFC1035_DEFAULT_INITIAL_TIMEOUT 5
#define RFC1035_DEFAULT_MAXIMUM_BACKOFF 3
/* Resolver state */
struct rfc1035_res {
RFC1035_ADDR nameservers[RFC1035_MAXNS];
int rfc1035_nnameservers;
char *rfc1035_defaultdomain;
int norecursive; /* Do not set the recursive flag, for specialized apps */
int dnssec_payload_size; /* Enable dnssec requests */
unsigned rfc1035_good_ns;
unsigned rfc1035_timeout_initial; /* Initial timeout */
unsigned rfc1035_timeout_backoff; /* Maximum exponential backoff */
random128binbuf randseed;
MD5_DIGEST randbuf;
unsigned randptr;
} ;
extern struct rfc1035_res rfc1035_default_resolver;
void rfc1035_init_timeout(struct rfc1035_res *, unsigned, unsigned);
/*
** Specify timeout in seconds,
** and maximum exponential backoff.
*/
void rfc1035_init_ns(struct rfc1035_res *, const RFC1035_ADDR *, unsigned);
/* Specify nameservers to query (max 10) */
void rfc1035_init_norecursive(struct rfc1035_res *, int);
/* Set the no-recursive flag, if you don't want the NS to do recursive queries on your behalf */
void rfc1035_init_dnssec_enable(struct rfc1035_res *, int);
/* Enable/disable dnssec/edns0 */
void rfc1035_init_edns_payload(struct rfc1035_res *, int);
/* Set edns0 payload size */
void rfc1035_init_resolv(struct rfc1035_res *);
/* Read /etc/resolv.conf for nameservers */
void rfc1035_destroy_resolv(struct rfc1035_res *);
/* Destroy the resolver object */
/*
** Most people will only need to call rfc1035_resolve or
** rfc1035_resolve_cname. The return value from _resolve functions
** should be interpreted as follows:
** NULL - internal failure (treat it as a soft DNS error)
** ptr->rcode = RFC1035_RCODE_NOERROR - success
** ptr->rcode = RFC1035_RCODE_NXDOMAIN - hard DNS error
** ptr->rcode = RFC1035_RCODE_TEMPFAIL - soft DNS error
** ptr->rcode = any other value - log abnormal result,
** handle as soft DNS error
*/
struct rfc1035_reply *rfc1035_resolve(
struct rfc1035_res *, /* Pointer to a resolver structure */
int, /* Opcode, see above. */
const char *, /* Query name */
unsigned, /* Query type, see above. */
unsigned); /* Query class, see above. */
/*
** Multiple queries. Most servers don't support this.
*/
struct rfc1035_reply *rfc1035_resolve_multiple(
struct rfc1035_res *, /* Pointer to a resolver structure */
int, /* opcode */
const struct rfc1035_query *, /* Array of queries */
unsigned); /* Array size */
/*
** rfc1035_resolve_cname is like _resolve, but starts with the default
** servers, and automatically reissues the query if the received response
** is a CNAME. If successful, it returns an INDEX into the allrrs array
** containing the first answer. To get the next answers, call
** rfc1035_replysearch_all with return value+1. If not succesfull, -1
** is returned.
**
** Note - if the returned index points to a CNAME, this is because a CNAME
** pointed to another CNAME -- it's BAD!
**
** It takes a POINTER to the 'id' counter, which is incremented if a
** second query needs to be issued.
**
** If takes a POINTER to the rfc1035_reply structure, which will be either
** null on exit, or point to the reply received. The pointer MAY be not null
** even if the return value is -1.
**
** Suggested logic:
** Return value >= 0, succesfull query.
** Return value <= -1, ptr is not null, and rcode = RFC1035_RCODE_NXDOMAIN,
** hard DNS error.
** Return value <= -1, ptr is not null, and rcode = RFC1035_RCODE_TEMPFAIL,
** soft DNS error.
** Other situations: log the abnormal result, handle as soft DNS error.
*/
#define RFC1035_ERR_CNAME_RECURSIVE -2
/* Specific error code for a recursive CNAME record - prohibited */
int rfc1035_resolve_cname(
struct rfc1035_res *, /* Pointer to a resolver structure */
char *, /* RFC1035_MAXNAMESIZE buffer with
** the name to query */
unsigned, /* Query type */
unsigned, /* Query class */
struct rfc1035_reply **, /* Ptr set to reply received */
int); /* Extended flags: */
#define RFC1035_X_RANDOMIZE 1 /* Randomize query results */
/*
** rfc1035_resolve_cname_multiple is a version of rfc1035_resolve_cname
** that accepts an array of qtypes, and issues a query for each qtype.
**
** qtypes points to a 0-terminated list of RRs.
*/
int rfc1035_resolve_cname_multiple(struct rfc1035_res *res,
char *namebuf,
/* RFC1035_MAXNAMESIZE buffer with
** the name to query */
unsigned char *qtypes,
unsigned qclass,
struct rfc1035_reply **ptr,
int x_flags);
/*
** Always call replyfree when done.
*/
void rfc1035_replyfree(struct rfc1035_reply *);
/*
** !!!ALL!!! the const char * pointers in rfc1035_reply are NOT
** standard C strings, but DNS-compressed strings. Call
** replyhostname to translate those to C strings.
*/
const char *rfc1035_replyhostname(
const struct rfc1035_reply *, /* The reply */
const char *, /* The const char ptr */
char *); /* Buffer where to put hostname. All strings are
** guaranteed to fit into RFC1035_MAXNAMESIZE+1 byte
** buffer.
** replyhostname returns this pointer.
*/
/* Some value added code, look up A and PTR records. */
int rfc1035_a(struct rfc1035_res *,
const char *, /* Host name */
RFC1035_ADDR **, /* We allocate array of IP addresses */
unsigned *); /* We return # of IP addresses here */
int rfc1035_ptr(struct rfc1035_res *,
const RFC1035_ADDR *, /* Query PTR for this address */
char *); /* Result - RFC1035_MAXNAMESIZE+1 buf */
int rfc1035_ptr_x(struct rfc1035_res *res, const RFC1035_ADDR *addr,
void (*cb_func)(const char *, void *),
void *cb_arg); /* Invoke a callback function instead
** (multiple callbacks possible)
*/
/* ---------------------- */
/* Replyuncompress is a lower-level function taking a pointer to
** the const char *. When it returns, the const char * is advanced
** past the end of the compressed string in the DNS data.
** replyuncompress returns its third argument, or NULL if there was
** an error. */
const char *rfc1035_replyuncompress(const char **,
const struct rfc1035_reply *, char *);
#define RFC1035_MAXNAMESIZE 255
/*
** Compare two hostnames. Return 0 if they match, non-zero if they
** don't.
*/
int rfc1035_hostnamecmp(const char *, const char *);
/*
** After we receive a reply, search for the answer there. Returns
** an index in the respective section, or -1 if not found.
** If we find a CNAME, we return a pointer to it instead, so make
** sure to check for that!
*/
int rfc1035_replysearch_an(
const struct rfc1035_res *, /* The resolver */
const struct rfc1035_reply *, /* The reply */
const char *, /* Hostname to search */
unsigned, /* Type */
unsigned, /* Class */
int); /* Starting position, 1st time use 0 */
int rfc1035_replysearch_ns(
const struct rfc1035_res *, /* The resolver */
const struct rfc1035_reply *, /* The reply */
const char *, /* Hostname to search */
unsigned, /* Type */
unsigned, /* Class */
int); /* Starting position, 1st time use 0 */
int rfc1035_replysearch_all(
const struct rfc1035_res *, /* The resolver */
const struct rfc1035_reply *, /* The reply */
const char *, /* Hostname to search */
unsigned, /* Type */
unsigned, /* Class */
int); /* Starting position, 1st time use 0 */
/*
** Low level functions follow.
*/
/*
** rfc1035_mkquery() constructs a query to be sent. The query is
** composed by REPEATEDLY running the caller-provided function,
** which will be called REPEATEDLY to build the query, part by part.
*/
int rfc1035_mkquery(struct rfc1035_res *, /* resolver structure */
unsigned, /* opcode */
#define RFC1035_RESOLVE_RECURSIVE 1 /* Ask nameserver to do the recursion */
const struct rfc1035_query *, /* questions */
unsigned, /* Number of questions */
void (*)(const char *, unsigned, void *),
/* Function - called repetitively
** to build the query */
void *); /* Third arg to function */
/**************************************************************************/
/* Low level input/output functions. Most people won't need to use these */
/**************************************************************************/
int rfc1035_open_udp(int *af); /* Create a UDP socket */
int rfc1035_send_udp(int, /* File descriptor from rfc1035_open */
const struct sockaddr *, int, /* Send to this name server */
const char *, /* The query */
unsigned); /* Query length */
/*
** Returns 0, or non-zero if failed.
*/
int rfc1035_wait_reply(int, /* File descriptor from rfc1035_open */
unsigned); /* Number of seconds to wait, use 0 for default */
/* Returns 0 when reply is waiting, non-0 if timeout expired */
int rfc1035_wait_query(int, /* File descriptor from rfc1035_open */
unsigned); /* Number of seconds to wait, use 0 for default */
/* Like reply, but we select for writing */
char *rfc1035_query_udp(struct rfc1035_res *,
int, /* file descriptor */
const struct sockaddr *, int, /* Attempt number */
const char *, /* query */
unsigned, /* query length */
int *, /* # of bytes received */
unsigned); /* # of seconds to wait for response */
/*
** Jumbo function: sends the indicated query via UDP, waits for
** a validated reply. Returns pointer to dynamically allocated
** memory with the reply. Returns NULL if there was an error.
** errno will be set to EAGAIN if the response timed out
** (if the UDP stack returns an error, we fake an EAGAIN).
** After getting EAGAIN, attempt number should be incremented,
** and we should try again.
** Fake ETIMEDOUT is returned if no more attempts are possible.
*/
int rfc1035_open_tcp(struct rfc1035_res *, const RFC1035_ADDR *);
/*
** Create a TCP socket for this attempt #,
** returns negative for a failure, and sets
** errno.
*/
/*
** Attempt to transmit the indicated query on this TCP socket.
** Return 0 for successfull transmission.
*/
int rfc1035_send_tcp(int, /* file descriptor */
const char *, /* query */
unsigned); /* query length */
/*
** Attempt to receive a reply on this TCP socket.
** Returns pointer to dynamically malloced memory, or null if error.
*/
char *rfc1035_recv_tcp(struct rfc1035_res *,
int, /* file descriptor */
int *, /* * initialized to contain msg length */
unsigned); /* # of seconds to wait for a response */
char *rfc1035_query_tcp(struct rfc1035_res *,
int, /* file descriptor */
const char *, /* query */
unsigned, /* query length */
int *, /* * initialized to contain msg length */
unsigned); /* # of seconds to wait for response */
/*************************************************/
/* Parse a raw response into a useful structure. */
/*************************************************/
struct rfc1035_rr {
const char *rrname; /* NOT a null term str, a ptr into the raw resp */
unsigned rrtype, rrclass;
RFC1035_UINT32 ttl;
unsigned rdlength;
const char *rdata; /* Raw data, parsed record follows: */
union {
struct {
const char *hinfo_str;
const char *os_str;
} hinfo;
struct in_addr inaddr; /* A */
#if RFC1035_IPV6
struct in6_addr in6addr; /* AAAA */
#endif
const char *domainname;
/* CNAME, MB, MD, MF, MG, MR, NS, PTR */
struct {
const char *rmailbx_label;
const char *emailbx_label;
} minfo;
struct {
unsigned preference;
const char *mx_label;
} mx;
struct {
const char *mname_label;
const char *rname_label;
RFC1035_UINT32 serial;
RFC1035_UINT32 refresh;
RFC1035_UINT32 retry;
RFC1035_UINT32 expire;
RFC1035_UINT32 minimum;
} soa;
struct {
RFC1035_UINT16 type_covered;
unsigned char algorithm;
unsigned char labels;
RFC1035_UINT16 original_ttl;
RFC1035_UINT32 signature_expiration;
RFC1035_UINT32 signature_inception;
RFC1035_UINT16 key_tag;
const char *signer_name;
const char *signature;
RFC1035_UINT16 signature_len;
} rrsig;
/* As are just represented by rdata/rdlength */
/* TXTs are parsed directly from rdata/rdlength */
/* WKS are parsed directly */
} rr;
} ;
struct rfc1035_reply {
struct rfc1035_reply *next; /* AXFRs have a linked list here */
const char *reply; /* The raw reply, for convenience's sake */
unsigned replylen; /* The length of the reply */
char *mallocedbuf; /* If not NULL, dynamically allocated
** memory that holds the reply.
*/
RFC1035_NETADDR server_addr; /* Replying server */
unsigned char qr;
unsigned char opcode;
unsigned char aa;
unsigned char tc;
unsigned char rd;
unsigned char ra;
unsigned char ad;
unsigned char cd;
unsigned char rcode;
unsigned qdcount;
unsigned ancount;
unsigned nscount;
unsigned arcount;
struct rfc1035_query *qdptr; /* sizeof qdcount */
struct rfc1035_rr *anptr;
struct rfc1035_rr *nsptr;
struct rfc1035_rr *arptr;
struct rfc1035_rr **allrrs; /* Pointers to all RR records,
** add ancount+nscount+arcount for
** the size of the array */
} ;
struct rfc1035_reply *rfc1035_replyparse(const char *, unsigned);
void rfc1035_rr_rand_an(struct rfc1035_reply *rr);
void rfc1035_rr_rand_ns(struct rfc1035_reply *rr);
void rfc1035_rr_rand_ar(struct rfc1035_reply *rr);
void rfc1035_rr_rand(struct rfc1035_reply *rr);
void rfc1035_dump(struct rfc1035_reply *, FILE *);
const char *rfc1035_fmttime(unsigned long, char *);
#define RFC1035_MAXTIMEBUFSIZE 40
char *rfc1035_dumprrdata(struct rfc1035_reply *, struct rfc1035_rr *);
int rfc1035_rr_gettxt(struct rfc1035_rr *,
int,
char buf[256]);
/*
** I ignore any possible bugs in the resolver functions, and roll my own,
** for IPv4.
*/
void rfc1035_ntoa_ipv4(const struct in_addr *in, char *buf);
int rfc1035_aton_ipv4(const char *p, struct in_addr *in4);
#if RFC1035_IPV6
void rfc1035_ipv6to4(struct in_addr *, const struct in6_addr *);
void rfc1035_ipv4to6(struct in6_addr *, const struct in_addr *);
#endif
/*
** Extract network address from a socket address.
*/
int rfc1035_sockaddrip(const RFC1035_NETADDR *, /* Socket address buffer */
int, /* Length of address */
RFC1035_ADDR *); /* Address saved here */
int rfc1035_sockaddrport(const RFC1035_NETADDR *, /* Socket address buffer */
int, /* Length of address */
int *); /* Port saved here */
#if RFC1035_IPV6
#define RFC1035_NTOABUFSIZE INET6_ADDRSTRLEN
#else
#define RFC1035_NTOABUFSIZE 16
#endif
void rfc1035_ntoa(const RFC1035_ADDR *, char *);
int rfc1035_aton(const char *, RFC1035_ADDR *);
/*
** New function that compares two addresses -- handles both IPv4 and IPv6:
*/
int rfc1035_same_ip(const void *, int, const void *, int);
int rfc1035_bindsource(int sockfd, /* Socket fd */
const struct sockaddr *addr, /* Buffer to socket address */
int addrlen); /* Size of socket address */
/*
** First try to create an IPv6 socket, then, if we fail, an IPv4 socket.
*/
int rfc1035_mksocket(int sock_type, /* socket type to create */
int sock_protocol, /* socket protocol to create */
int *af); /* If succeed, address family created */
/*
** Take the destination address, and create a socket address structure
** suitable for connecting to this address.
*/
int rfc1035_mkaddress(int af, /* AF_INET or AF_INET6 */
/* buf is initiailized to the sender's ip address. */
RFC1035_NETADDR *buf, /* Buffer for the created address */
const RFC1035_ADDR *addr, /* Network address */
int port, /* Network port (network byte order) */
const struct sockaddr **ptr, /* Will point to buf */
int *len); /* Will be size of socket address */
/*
** A convenient interface to the SIOCGIFCONF ioctl.
*/
struct rfc1035_ifconf {
struct rfc1035_ifconf *next;
char *ifname;
RFC1035_ADDR ifaddr;
};
struct rfc1035_ifconf *rfc1035_ifconf(int *errflag);
void rfc1035_ifconf_free(struct rfc1035_ifconf *ifconf_list);
/*
** Outstanding UDP queries.
*/
/* common query buffer */
struct querybuf {
char qbuf[512];
unsigned qbuflen;
} ;
struct rfc1035_udp_query_response;
/* How many queries, and the queries */
struct rfc1035_udp_query_responses {
int n_queries;
struct rfc1035_udp_query_response *queries;
};
/* Each query, and response already receives so far, if any. */
struct rfc1035_udp_query_response {
const char *query;
unsigned querylen;
char *response;
unsigned resplen;
};
/*
** Allocate a new rfc1035_udp_query_responses.
** Copies each query into the rfc1035_udp_query_response, each response is
** initialized to null.
*/
struct rfc1035_udp_query_responses *
rfc1035_udp_query_response_alloc(const char **queries,
const unsigned *querylens,
int n_queries);
struct rfc1035_udp_query_responses *
rfc1035_udp_query_response_alloc_bis(struct querybuf *queries,
int n_queries);
/*
** Send all queries via UDPs, wait for responses.
**
** Returns non-0 if all queries are received, 0 if not. EAGAIN indicates
** a timeout, and this can be called again with the same
** rfc1035_udp_query_responses object; this resends all queries for which
** no response was received, and this will wait for the remaining responses.
*/
int rfc1035_udp_query_multi(struct rfc1035_res *res,
/* Socket: */
int fd,
/* Where to send it to */
const struct sockaddr *sin, int sin_len,
/* The queries */
struct rfc1035_udp_query_responses *qr,
/* How long to wait for responses, in seconds. */
unsigned w);
/*
** Deallocate rfc1035_udp_query_responses. Each non-NULL response pointer
** gets free()d.
*/
void rfc1035_udp_query_response_free(struct rfc1035_udp_query_responses *);
#ifdef __cplusplus
}
#endif
#endif
|