COVERAGE SUMMARY
FILE SUMMARY
NameExecutedRoutines%ExecutedLines%Unexecuted
/home/matt/eu/rds/include/std/net/dns.e22100.00%3535100.00%0
ROUTINE SUMMARY
RoutineExecutedLinesUnexecuted
host_by_addr()22100.00%0
host_by_name()22100.00%0
LINE COVERAGE DETAIL
#Executed
1
--****
2
-- == DNS
3
--
4
-- Based on EuNet project, version 1.3.2 at SourceForge.
5
--
6
-- <>
7
--
8
9
namespace dns
10
11
include std/socket.e
12
include std/get.e
13
142
constant BLOCK_SIZE = 4096
152
enum M_SOCK_GETHOSTBYNAME=79, M_SOCK_GETHOSTBYADDR
16
17
--****
18
-- === Constants
19
202
public enum ADDR_FLAGS, ADDR_FAMILY, ADDR_TYPE, ADDR_PROTOCOL, ADDR_ADDRESS
21
222
public enum HOST_OFFICIAL_NAME, HOST_ALIASES, HOST_IPS, HOST_TYPE
23
24
public constant
252
DNS_QUERY_STANDARD = 0,
262
DNS_QUERY_ACCEPT_TRUNCATED_RESPONSE = 1,
272
DNS_QUERY_USE_TCP_ONLY = 2,
282
DNS_QUERY_NO_RECURSION = 4,
292
DNS_QUERY_BYPASS_CACHE = 8,
302
DNS_QUERY_NO_WIRE_QUERY = 16,
312
DNS_QUERY_NO_LOCAL_NAME = 32,
322
DNS_QUERY_NO_HOSTS_FILE = 64,
332
DNS_QUERY_NO_NETBT = 128,
342
DNS_QUERY_WIRE_ONLY = 256,
352
DNS_QUERY_RETURN_MESSAGE = 512,
362
DNS_QUERY_TREAT_AS_FQDN = #1000,
372
DNS_QUERY_DONT_RESET_TTL_VALUES = #100000,
382
DNS_QUERY_RESERVED = #FF000000,
39
402
NS_C_IN = 1,
412
NS_C_ANY = 255,
422
NS_KT_RSA = 1,
432
NS_KT_DH = 2,
442
NS_KT_DSA = 3,
452
NS_KT_PRIVATE = 254,
462
NS_T_A = 1,
472
NS_T_NS = 2,
482
NS_T_PTR = 12,
492
NS_T_MX = 15,
502
NS_T_AAAA = 28,
512
NS_T_A6 = 38,
522
NS_T_ANY = 255
53
54
--****
55
-- === General Routines
56
57
/*
58
ifdef WIN32 then
59
constant dnsdll_ = open_dll("dnsapi.dll")
60
61
constant getaddrinfo_ = define_c_func(sockdll_,"getaddrinfo",{C_POINTER,C_POINTER,C_POINTER,C_POINTER},C_INT)
62
constant dnsquery_ = define_c_func(dnsdll_,"DnsQuery_A",{C_POINTER,C_USHORT,C_INT,C_POINTER,C_POINTER,C_POINTER},C_INT)
63
constant dnsrlfree_ = define_c_proc(dnsdll_,"DnsRecordListFree",{C_POINTER,C_INT})
64
constant dnsexpand_ = -1
65
constant freeaddrinfo_ = define_c_proc(sockdll_,"freeaddrinfo",{C_POINTER})
66
67
elsifdef LINUX or SUNOS then
68
constant dnsdll_ = open_dll("libresolv.so")
69
70
elsifdef FREEBSD then
71
constant dnsdll_ = open_dll("libc.so")
72
73
elsifdef OSX then
74
constant dnsdll_ = open_dll("libresolv.dylib")
75
76
end ifdef
77
78
ifdef UNIX then
79
constant dnsquery_ = define_c_func(dnsdll_,"res_query",{C_POINTER,C_INT,C_INT,C_POINTER,C_INT},C_INT)
80
constant dnsrlfree_ = -1
81
constant dnsexpand_ = define_c_func(dnsdll_,"dn_expand",{C_POINTER,C_POINTER,C_POINTER,C_POINTER,C_INT},C_INT)
82
constant getaddrinfo_ = define_c_func(dll_,"getaddrinfo",{C_POINTER,C_POINTER,C_POINTER,C_POINTER},C_INT)
83
constant freeaddrinfo_ = define_c_proc(dll_,"freeaddrinfo",{C_POINTER})
84
end ifdef
85
86
function _socket_trim(sequence s)
87
atom c
88
sequence rs
89
rs = s
90
c = 1
91
while c <= length(s) and rs[c] <= 32 do
92
c = c + 1
93
end while
94
rs = rs[c .. $]
95
c = length(rs)
96
while c > 0 and rs[c] <= 32 do
97
c = c - 1
98
end while
99
rs = rs[1..c]
100
return rs
101
end function
102
103
-- Returns a set of sequences of {ip_addr, q_type, order} resolving the IP address for
104
-- the given domain name and/or host.
105
-- At present, only A,MX,and NS queries are supported.
106
-- Error 9501 = No record found
107
108
function unix_dnsquery(sequence dname, integer q_type)
109
atom nameptr, rtnptr, success, ptrptr, dnameptr, qlen
110
atom answer_start, answer_end, num_as_rec, num_qr_rec
111
sequence rtn, line, subx
112
object temp
113
114
nameptr = allocate_string(dname&0)
115
rtnptr = allocate(BLOCK_SIZE*8)
116
success = c_func(dnsquery_,{nameptr,NS_C_IN,q_type,rtnptr,BLOCK_SIZE*8})
117
if success < 0 then
118
free(nameptr)
119
free(rtnptr)
120
return success
121
end if
122
-- The parsing of rtnptr is significantly more difficult in Linux than
123
-- in Windows. Much of the code that follows is based on Postfix-2.5.1/
124
-- src/dns/dns_lookup.c.
125
if success > BLOCK_SIZE * 8 then -- The Answer has been truncated & is invalid.
126
free(nameptr)
127
free(rtnptr)
128
return -2
129
end if
130
-- Size of Header = 12 bytes. # Query = [5..6], # Answer = [7..8], # Auth = [9..10]
131
-- # Res = [11..12]
132
num_qr_rec = (peek(rtnptr+4)*256)+peek(rtnptr+5)
133
num_as_rec = (peek(rtnptr+6)*256)+peek(rtnptr+7)
134
if num_as_rec = 0 then
135
free(nameptr)
136
free(rtnptr)
137
return 9501 -- No Data
138
end if
139
ptrptr = rtnptr + 12 -- Start of query record
140
dnameptr = allocate(1024)
141
for ctr = 1 to num_qr_rec do
142
qlen = c_func(dnsexpand_,{rtnptr,rtnptr+success,ptrptr,dnameptr,1024})
143
if qlen < 0 then
144
free(dnameptr)
145
free(nameptr)
146
free(rtnptr)
147
return qlen
148
end if
149
ptrptr = ptrptr + qlen + 4
150
end for
151
answer_start = ptrptr
152
answer_end = rtnptr + success
153
154
-- Now we're finally at the answer section
155
rtn = {}
156
for seq = 1 to num_as_rec do
157
line = repeat(0,8)
158
subx = repeat(0,32)
159
if ptrptr >= answer_end then
160
free(dnameptr)
161
free(nameptr)
162
free(rtnptr)
163
return -4
164
end if
165
qlen = c_func(dnsexpand_,{rtnptr,answer_end,ptrptr,dnameptr,1024})
166
if qlen < 0 then
167
free(dnameptr)
168
free(nameptr)
169
free(rtnptr)
170
return -5
171
end if
172
line[2] = peek_string(dnameptr)
173
ptrptr = ptrptr + qlen
174
if ptrptr+10 >= answer_end then
175
free(dnameptr)
176
free(nameptr)
177
free(rtnptr)
178
return -4
179
end if
180
line[3] = (peek(ptrptr)*256)+peek(ptrptr+1) -- type
181
line[7] = (peek(ptrptr+2)*256)+peek(ptrptr+3) -- Class
182
line[6] = (peek(ptrptr+4)*256*256*256)+(peek(ptrptr+5)*256*256)+
183
(peek(ptrptr+6)*256)+peek(ptrptr+7) -- TTL
184
line[4] = (peek(ptrptr+8)*256)+peek(ptrptr+9) -- Data Length
185
ptrptr = ptrptr + 10
186
if ptrptr + line[4] - 1 >= answer_end then
187
free(dnameptr)
188
free(nameptr)
189
free(rtnptr)
190
return -4
191
end if
192
if line[3] = NS_T_NS then
193
qlen = c_func(dnsexpand_,{rtnptr,answer_end,ptrptr,dnameptr,1024})
194
if qlen > 0 then
195
subx[1] = peek_string(dnameptr)
196
temp = unix_dnsquery(subx[1],NS_T_A)
197
if atom(temp) then
198
rtn = append(rtn,{subx[1],line[3],seq})
199
else
200
for ctr = 1 to length(temp) do
201
rtn = append(rtn,{temp[ctr][1],line[3],seq+ctr-1})
202
end for
203
end if
204
end if
205
elsif line[3] = NS_T_MX then
206
subx[2] = (peek(ptrptr)*256)+peek(ptrptr+1) -- Priority
207
qlen = c_func(dnsexpand_,{rtnptr,answer_end,ptrptr+2,dnameptr,1024})
208
if qlen > 0 then
209
subx[1] = peek_string(dnameptr)
210
temp = unix_dnsquery(subx[1],NS_T_A)
211
if atom(temp) then
212
rtn = append(rtn,{subx[1],line[3],subx[2]})
213
else
214
for ctr = 1 to length(temp) do
215
rtn = append(rtn,{temp[ctr][1],line[3],subx[2]+ctr-1})
216
end for
217
end if
218
end if
219
elsif line[3] = NS_T_A and line[4] >= 4 then
220
subx[1] = sprintf("%d.%d.%d.%d",{peek(ptrptr),peek(ptrptr+1),
221
peek(ptrptr+2),peek(ptrptr+3)})
222
if q_type = NS_T_ANY or q_type = NS_T_A then
223
rtn = append(rtn,{subx[1],line[3],seq})
224
end if
225
elsif line[3] = NS_T_PTR then
226
227
end if
228
ptrptr = ptrptr + line[4]
229
230
end for
231
232
-- Finally, we're done.
233
free(dnameptr)
234
free(nameptr)
235
free(rtnptr)
236
237
return rtn
238
239
end function
240
241
242
function windows_dnsquery(sequence dname, integer q_type, atom options)
243
-- NOTE: This function does not work on Windows versions below Windows 2000.
244
245
atom success,nameptr, rtnptr, recptr, seq
246
sequence rtn, line, subx
247
object temp
248
249
if dnsquery_ < 0 then
250
return -999
251
end if
252
253
nameptr = allocate_string(dname)
254
rtnptr = allocate(4)
255
success = c_func(dnsquery_,{nameptr,q_type,options,0,rtnptr,0})
256
if success != 0 then
257
free(nameptr)
258
free(rtnptr)
259
return success
260
end if
261
rtn = {}
262
recptr = peek4u(rtnptr)
263
seq = 1
264
while recptr > 0 do
265
line = repeat(0,8)
266
subx = repeat(0,32)
267
line[1]=peek4u(recptr) -- Pointer to the next record
268
line[2]=peek4u(recptr+4) -- Pointer to the name string
269
line[3]=peek(recptr+8)+(peek(recptr+9)*256) -- type
270
line[4]=peek(recptr+10)+(peek(recptr+11)*256) -- Data Length
271
line[5]=peek4u(recptr+12) -- Flags
272
line[6]=peek4u(recptr+16) -- TTL
273
line[7]=peek4u(recptr+20) -- reserved
274
if line[3] = NS_T_MX then
275
subx[1] = peek_string(peek4u(recptr+24)) -- Mail server name
276
subx[2] = peek(recptr+28)+(peek(recptr+29)*256) -- Preference
277
temp = windows_dnsquery(subx[1],NS_T_A,options)
278
if atom(temp) then
279
rtn = append(rtn,{subx[1],line[3],subx[2]})
280
else
281
for ctr = 1 to length(temp) do
282
rtn = append(rtn,{temp[ctr][1],line[3],subx[2]+ctr-1})
283
end for
284
end if
285
elsif line[3] = NS_T_NS then
286
subx[1] = peek_string(peek4u(recptr+24)) -- NS server name
287
temp = windows_dnsquery(subx[1],NS_T_A,options)
288
if atom(temp) then
289
rtn = append(rtn,{subx[1],line[3],seq})
290
else
291
for ctr = 1 to length(temp) do
292
rtn = append(rtn,{temp[ctr][1],line[3],seq+ctr-1})
293
end for
294
end if
295
elsif line[3] = NS_T_A then
296
subx[1] = sprintf("%d.%d.%d.%d",{peek(recptr+24),peek(recptr+25),
297
peek(recptr+26),peek(recptr+27)})
298
if q_type = NS_T_ANY or q_type = NS_T_A then
299
rtn = append(rtn,{subx[1],line[3],seq})
300
end if
301
elsif line[3] = NS_T_PTR then
302
303
end if
304
recptr = line[1]
305
seq = seq + 1
306
end while
307
c_proc(dnsrlfree_,{peek4u(rtnptr),1})
308
free(nameptr)
309
free(rtnptr)
310
311
return rtn
312
313
end function
314
315
316
--**
317
-- Query DNS info.
318
--
319
-- Parameters:
320
-- # ##dname## : a string, the name to look up
321
-- # ##q_type## : an integer, the type of lookup requested
322
-- # ##options## : an atom,
323
--
324
-- Returns:
325
-- An **object**, either a negative integer on error, or a sequence of sequences in the form {{string ip_address, integer query_type, integer priority},...}.
326
--
327
-- Comments:
328
--
329
-- For standard A record lookups, getaddrinfo is preferred.
330
-- But sometimes, more advanced DNS lookups are required. Eventually,
331
-- this routine will support all types of DNS lookups. In Euphoria
332
-- 4.0, only NS, MX, and A lookups are accepted.
333
--
334
-- Example 1:
335
--
336
-- result = dnsquery("yahoo.com",NS_T_MX,0)
337
-- if atom(result) then
338
-- puts(1,"Uh, oh!")
339
-- else
340
-- for ctr = 1 to length(result) do
341
-- printf(1,"%s\t%d\t%d\n",result[ctr])
342
-- end for
343
-- end if
344
--
345
--
346
-- See Also:
347
-- [[:getaddrinfo]], [[:gethostbyname]], [[:getmxrr]], [[:getnsrr]]
348
349
public function dnsquery(sequence dname, integer q_type, atom options)
350
ifdef WIN32 then
351
return windows_dnsquery(dname, q_type, options)
352
elsifdef UNIX then
353
return unix_dnsquery(dname,q_type)
354
end ifdef
355
356
return -999 -- TODO: -999 or -1?
357
end function
358
359
-------------------------------------------------------------------------------
360
-- getmxrr
361
-------------------------------------------------------------------------------
362
363
--**
364
-- Find a mail server for a given domain. If none can be found,
365
-- attempt a smart query by looking up common variations on
366
-- domain_name.
367
--
368
-- Parameters:
369
-- # ##dname## : a string, the name to look up
370
-- # ##options## : an atom,
371
--
372
-- Returns:
373
--
374
-- An **object**, either a negative integer on error, or a sequence of sequences in the form {{string ip_address, integer query_type, integer priority},...}.
375
--
376
-- See Also:
377
-- [[:dnsquery]]
378
379
public function getmxrr(sequence dname, atom options)
380
object rtn
381
382
-- Error 9003 = MS: RCODE_NAME_ERROR - Something's there, but it's not exact.
383
-- Error 9501 = No Data Found
384
385
dname = _socket_trim(dname)
386
rtn = dnsquery(dname,NS_T_MX,options)
387
if sequence(rtn) and length(rtn)>0 then
388
return rtn
389
end if
390
if rtn = 9501 or rtn = 9003 or rtn = -1 or
391
(sequence(rtn) and length(rtn)=0) then
392
rtn = dnsquery("mail."&dname,NS_T_MX,options)
393
end if
394
return rtn
395
end function
396
397
-------------------------------------------------------------------------------
398
-- getnsrr
399
-------------------------------------------------------------------------------
400
401
--**
402
-- Find a name server for a given domain. If none can be found,
403
-- attempt a smart query by looking up common variations on
404
-- domain_name.
405
--
406
-- Parameters:
407
-- # ##dname## : a string, the name to look up
408
-- # ##options## : an atom,
409
--
410
-- Returns:
411
-- An **object**, either a negative integer on error, or a sequence of sequences in the form {{string ip_address, integer query_type, integer priority},...}.
412
--
413
-- See Also:
414
-- [[:dnsquery]]
415
416
public function getnsrr(sequence dname, atom options)
417
return dnsquery(dname,NS_T_NS,options)
418
end function
419
420
-------------------------------------------------------------------------------
421
-- GetAddrInfo
422
-------------------------------------------------------------------------------
423
-- Returns a sequence of sequences {atom flags, atom family, atom socktype, atom protocol, sequence inet_addr}
424
-- on success or an error code on failure
425
426
--memset(&hints, 0, sizeof(hints));
427
--hints.ai_flags = AI_NUMERICHOST;
428
--hints.ai_family = PF_UNSPEC;
429
--hints.ai_socktype = 0;
430
--hints.ai_protocol = 0;
431
--hints.ai_addrlen = 0;
432
--hints.ai_canonname = NULL;
433
--hints.ai_addr = NULL;
434
--hints.ai_next = NULL;
435
--getaddrinfo(ip, port, &hints, &aiList)
436
--nodename A pointer to a NULL-terminated ANSI string that contains a host (node) name or a numeric host address string. For the Internet protocol, the numeric host address string is a dotted-decimal IPv4 address or an IPv6 hex address.
437
--servname A pointer to a NULL-terminated ANSI string that contains either a service name or port number represented as a string.
438
--hints A pointer to an addrinfo structure that provides hints about the type of socket the caller supports. See Remarks.
439
--res A pointer to a linked list of one or more addrinfo structures that contains response information about the host.
440
441
function unix_getaddrinfo(object node, object service, object hints)
442
atom addrinfo, success, node_ptr, service_ptr, hints_ptr, addrinfo_ptr,
443
svcport, cpos
444
sequence rtn, val
445
446
hints = hints -- TODO -- not implemented.
447
addrinfo = allocate(32)
448
poke(addrinfo,repeat(0,32))
449
if sequence(node) then
450
node_ptr = allocate_string(node)
451
else
452
node_ptr = node
453
end if
454
svcport = 0
455
if sequence(service) then
456
service_ptr = allocate_string(service)
457
val = value(service)
458
if val[1] = GET_SUCCESS then
459
svcport = val[2]
460
end if
461
else
462
service_ptr = service
463
if service > 0 and service <= #FFFF then
464
svcport = service
465
service_ptr = 0
466
end if
467
end if
468
hints_ptr = 0 -- Not yet implemented
469
success = c_func(getaddrinfo_,{node_ptr,service_ptr,hints_ptr,addrinfo})
470
if success != 0 then
471
free(addrinfo)
472
if sequence(node) then free(node_ptr) end if
473
if sequence(service) then free(service_ptr) end if
474
return 0
475
end if
476
rtn = {}
477
-- addrinfo is a pointer to a pointer to a structure in Linux.
478
addrinfo_ptr = peek4u(addrinfo)
479
-- 27 Nov 2007: Only one addrinfo structure is supported
480
-- while addrinfo_ptr != 0 do
481
rtn = append(rtn,{
482
peek4u(addrinfo_ptr),
483
peek4u(addrinfo_ptr+4),
484
peek4u(addrinfo_ptr+8),
485
peek4u(addrinfo_ptr+12),
486
get_sockaddr(peek4u(addrinfo_ptr+20))
487
})
488
489
addrinfo_ptr = peek4u(addrinfo_ptr+28)
490
-- end while
491
492
c_proc(freeaddrinfo_,{peek4u(addrinfo)})
493
494
if length(rtn[1][5])=0 and sequence(node) then
495
rtn[1][5] = gethostbyname(node)
496
if sequence(service) and svcport = 0 then
497
rtn[1][5] = rtn[1][5] & sprintf(":%d",getservbyname(service))
498
elsif svcport > 0 then
499
rtn[1][5] = rtn[1][5] & sprintf(":%d",svcport)
500
end if
501
elsif svcport > 0 then
502
cpos = find(':',rtn[1][5])
503
if cpos = 0 or cpos = length(rtn[1][5]) or
504
eu:compare(rtn[1][5][$ - 1 .. $],":0")=0 then
505
if cpos = 0 then
506
rtn[1][5] = rtn[1][5] & sprintf(":%d",svcport)
507
else
508
rtn[1][5] = rtn[1][5][1..cpos-1] & sprintf(":%d",svcport)
509
end if
510
end if
511
end if
512
513
free(addrinfo)
514
515
return rtn
516
end function
517
518
function windows_getaddrinfo(object node, object service, object hints)
519
return unix_getaddrinfo(node, service, hints)
520
end function
521
522
--**
523
-- Retrieve information about a given server name and named service.
524
--
525
-- Parameters:
526
-- # ##node## : an object, ???
527
-- # ##service## : an object, ???
528
-- # ##hints## : an object, currently not used
529
--
530
-- Returns:
531
-- A **sequence**, of sequences containing the requested information.
532
-- The inner sequences have fields that can be accessed with public constants
533
--
534
-- * ADDR_FLAGS
535
-- * ADDR_FAMILY
536
-- * ADDR_TYPE
537
-- * ADDR_PROTOCOL
538
-- * ADDR_ADDRESS
539
--
540
-- Comments:
541
-- Different DNS servers may return conflicting information about a
542
-- name, but getaddrinfo will only return the first. Future
543
-- versions will allow multiple entries to be returned, so this
544
-- return format will keep programs using this library from breaking
545
-- when the functionality is added. The hints parameter is not
546
-- currently used. Service may be either a string containing the
547
-- service name, a string containing the port number, or an integer
548
-- port number between 0 and 65535.
549
--
550
-- Example 1:
551
--
552
-- puts(1,"The IP address and port for http://www.yahoo.com is "&
553
-- getaddrinfo("www.yahoo.com","http",0)&"\n")
554
--
555
556
public function getaddrinfo(object node, object service, object hints)
557
ifdef WIN32 then
558
return windows_getaddrinfo(node,service,hints)
559
elsifdef UNIX then
560
return unix_getaddrinfo(node,service,hints)
561
end ifdef
562
563
return -999
564
end function
565
*/
566
567
--**
568
-- Get the host information by name.
569
--
570
-- Parameters:
571
-- # ##name## : host name
572
--
573
-- Returns:
574
-- A ##sequence##, containing
575
--
576
-- {
577
-- official name,
578
-- { alias1, alias2, ... },
579
-- { ip1, ip2, ... },
580
-- address_type
581
-- }
582
--
583
--
584
-- Example 1:
585
--
586
-- object data = host_by_name("www.google.com")
587
-- -- data = {
588
-- -- "www.l.google.com",
589
-- -- {
590
-- -- "www.google.com"
591
-- -- },
592
-- -- {
593
-- -- "74.125.93.104",
594
-- -- "74.125.93.147",
595
-- -- ...
596
-- -- },
597
-- -- 2
598
-- -- }
599
--
600
--
601
6024
6034
return machine_func(M_SOCK_GETHOSTBYNAME, { name })
604
end function
605
606
--**
607
-- Get the host information by address.
608
--
609
-- Parameters:
610
-- # ##address## : host address
611
--
612
-- Returns:
613
-- A ##sequence##, containing
614
--
615
-- {
616
-- official name,
617
-- { alias1, alias2, ... },
618
-- { ip1, ip2, ... },
619
-- address_type
620
-- }
621
--
622
--
623
-- Example 1:
624
--
625
-- object data = host_by_addr("74.125.93.147")
626
-- -- data = {
627
-- -- "www.l.google.com",
628
-- -- {
629
-- -- "www.google.com"
630
-- -- },
631
-- -- {
632
-- -- "74.125.93.104",
633
-- -- "74.125.93.147",
634
-- -- ...
635
-- -- },
636
-- -- 2
637
-- -- }
638
--
639
--
640
6411
6421
return machine_func(M_SOCK_GETHOSTBYADDR, { address })
643
end function