7 #include <FindDirectory.h>
8 #include <NetAddress.h>
9 #include <NetEndpoint.h>
16 #define PRINT(a...) printf(a)
25 BRawNetBuffer::BRawNetBuffer()
31 BRawNetBuffer::BRawNetBuffer(off_t size
)
34 fBuffer
.SetSize(size
);
38 BRawNetBuffer::BRawNetBuffer(const void* buf
, size_t size
)
45 BRawNetBuffer::AppendUint16(uint16 value
)
47 uint16 netVal
= B_HOST_TO_BENDIAN_INT16(value
);
48 ssize_t sizeW
= fBuffer
.WriteAt(fWritePosition
, &netVal
, sizeof(uint16
));
49 if (sizeW
== B_NO_MEMORY
)
51 fWritePosition
+= sizeof(uint16
);
57 BRawNetBuffer::AppendString(const char* string
)
59 size_t length
= strlen(string
) + 1;
60 ssize_t sizeW
= fBuffer
.WriteAt(fWritePosition
, string
, length
);
61 if (sizeW
== B_NO_MEMORY
)
63 fWritePosition
+= length
;
69 BRawNetBuffer::ReadUint16(uint16
& value
)
72 ssize_t sizeW
= fBuffer
.ReadAt(fReadPosition
, &netVal
, sizeof(uint16
));
75 value
= B_BENDIAN_TO_HOST_INT16(netVal
);
76 fReadPosition
+= sizeof(uint16
);
82 BRawNetBuffer::ReadUint32(uint32
& value
)
85 ssize_t sizeW
= fBuffer
.ReadAt(fReadPosition
, &netVal
, sizeof(uint32
));
88 value
= B_BENDIAN_TO_HOST_INT32(netVal
);
89 fReadPosition
+= sizeof(uint32
);
95 BRawNetBuffer::ReadString(BString
& string
)
98 ssize_t bytesRead
= _ReadStringAt(string
, fReadPosition
);
101 fReadPosition
+= bytesRead
;
107 BRawNetBuffer::SkipReading(off_t skip
)
109 if (fReadPosition
+ skip
> (off_t
)fBuffer
.BufferLength())
111 fReadPosition
+= skip
;
117 BRawNetBuffer::_Init(const void* buf
, size_t size
)
121 fBuffer
.WriteAt(fWritePosition
, buf
, size
);
126 BRawNetBuffer::_ReadStringAt(BString
& string
, off_t pos
)
128 if (pos
>= (off_t
)fBuffer
.BufferLength())
131 ssize_t bytesRead
= 0;
132 char* buffer
= (char*)fBuffer
.Buffer();
133 buffer
= &buffer
[pos
];
134 // if the string is compressed we have to follow the links to the
136 while (pos
< (off_t
)fBuffer
.BufferLength() && *buffer
!= 0) {
137 if (uint8(*buffer
) == 192) {
138 // found a pointer mark
141 off_t subPos
= uint8(*buffer
);
142 _ReadStringAt(string
, subPos
);
145 string
.Append(buffer
, 1);
154 // #pragma mark - DNSTools
158 DNSTools::GetDNSServers(BObjectList
<BString
>* serverList
)
160 // TODO: reading resolv.conf ourselves shouldn't be needed.
161 // we should have some function to retrieve the dns list
162 #define MATCH(line, name) \
163 (!strncmp(line, name, sizeof(name) - 1) && \
164 (line[sizeof(name) - 1] == ' ' || \
165 line[sizeof(name) - 1] == '\t'))
168 if (find_directory(B_SYSTEM_SETTINGS_DIRECTORY
, &path
) != B_OK
)
169 return B_ENTRY_NOT_FOUND
;
171 path
.Append("network/resolv.conf");
173 register FILE* fp
= fopen(path
.Path(), "r");
175 fprintf(stderr
, "failed to open '%s' to read nameservers: %s\n",
176 path
.Path(), strerror(errno
));
177 return B_ENTRY_NOT_FOUND
;
182 register char *cp
; //, **pp;
186 // read the config file
187 while (fgets(buf
, sizeof(buf
), fp
) != NULL
) {
189 if (*buf
== ';' || *buf
== '#')
192 // read nameservers to query
193 if (MATCH(buf
, "nameserver") && nserv
< MAXNS
) {
195 cp
= buf
+ sizeof("nameserver") - 1;
196 while (*cp
== ' ' || *cp
== '\t')
198 cp
[strcspn(cp
, ";# \t\n")] = '\0';
199 if ((*cp
!= '\0') && (*cp
!= '\n')) {
200 serverList
->AddItem(new BString(cp
));
214 DNSTools::ConvertToDNSName(const BString
& string
)
216 BString outString
= string
;
217 int32 dot
, lastDot
, diff
;
219 dot
= string
.FindFirst(".");
220 if (dot
!= B_ERROR
) {
221 outString
.Prepend((char*)&dot
, 1);
222 // because we prepend a char add 1 more
226 dot
= outString
.FindFirst(".", lastDot
+ 1);
230 // set a counts to the dot
231 diff
= dot
- 1 - lastDot
;
232 outString
[lastDot
] = (char)diff
;
238 diff
= outString
.CountChars() - 1 - lastDot
;
239 outString
[lastDot
] = (char)diff
;
246 DNSTools::ConvertFromDNSName(const BString
& string
)
248 if (string
.Length() == 0)
251 BString outString
= string
;
252 int32 dot
= string
[0];
254 outString
.Remove(0, sizeof(char));
256 if (nextDot
>= outString
.Length())
258 dot
= outString
[nextDot
];
262 outString
[nextDot
] = '.';
269 // #pragma mark - DNSQuery
270 // see http://tools.ietf.org/html/rfc1035 for more information about DNS
278 DNSQuery::~DNSQuery()
284 DNSQuery::ReadDNSServer(in_addr
* add
)
286 // list owns the items
287 BObjectList
<BString
> dnsServerList(5, true);
288 status_t status
= DNSTools::GetDNSServers(&dnsServerList
);
292 BString
* firstDNS
= dnsServerList
.ItemAt(0);
293 if (firstDNS
== NULL
|| inet_aton(firstDNS
->String(), add
) != 1)
296 PRINT("dns server found: %s \n", firstDNS
->String());
302 DNSQuery::GetMXRecords(const BString
& serverName
,
303 BObjectList
<mx_record
>* mxList
, bigtime_t timeout
)
305 // get the DNS server to ask for the mx record
307 if (ReadDNSServer(&dnsAddress
) != B_OK
)
310 // create dns query package
311 BRawNetBuffer buffer
;
313 _SetMXHeader(&header
);
314 _AppendQueryHeader(buffer
, &header
);
316 BString serverNameConv
= DNSTools::ConvertToDNSName(serverName
);
317 buffer
.AppendString(serverNameConv
);
318 buffer
.AppendUint16(uint16(MX_RECORD
));
319 buffer
.AppendUint16(uint16(1));
322 PRINT("send buffer\n");
323 BNetAddress
netAddress(dnsAddress
, 53);
324 BNetEndpoint
netEndpoint(SOCK_DGRAM
);
325 if (netEndpoint
.InitCheck() != B_OK
)
328 if (netEndpoint
.Connect(netAddress
) != B_OK
)
330 PRINT("Connected\n");
332 int32 bytesSend
= netEndpoint
.Send(buffer
.Data(), buffer
.Size());
333 if (bytesSend
== B_ERROR
)
335 PRINT("bytes send %i\n", int(bytesSend
));
338 BRawNetBuffer
receiBuffer(512);
339 netEndpoint
.SetTimeout(timeout
);
341 int32 bytesRecei
= netEndpoint
.ReceiveFrom(receiBuffer
.Data(), 512,
343 if (bytesRecei
== B_ERROR
)
345 PRINT("bytes received %i\n", int(bytesRecei
));
347 dns_header receiHeader
;
349 _ReadQueryHeader(receiBuffer
, &receiHeader
);
350 PRINT("Package contains :");
351 PRINT("%d Questions, ", receiHeader
.q_count
);
352 PRINT("%d Answers, ", receiHeader
.ans_count
);
353 PRINT("%d Authoritative Servers, ", receiHeader
.auth_count
);
354 PRINT("%d Additional records\n", receiHeader
.add_count
);
356 // remove name and Question
359 receiBuffer
.ReadString(dummyS
);
360 receiBuffer
.ReadUint16(dummy
);
361 receiBuffer
.ReadUint16(dummy
);
363 bool mxRecordFound
= false;
364 for (int i
= 0; i
< receiHeader
.ans_count
; i
++) {
365 resource_record_head rrHead
;
366 _ReadResourceRecord(receiBuffer
, &rrHead
);
367 if (rrHead
.type
== MX_RECORD
) {
368 mx_record
* mxRec
= new mx_record
;
369 _ReadMXRecord(receiBuffer
, mxRec
);
370 PRINT("MX record found pri %i, name %s\n",
371 mxRec
->priority
, mxRec
->serverName
.String());
372 // Add mx record to the list
373 mxList
->AddItem(mxRec
);
374 mxRecordFound
= true;
376 buffer
.SkipReading(rrHead
.dataLength
);
388 DNSQuery::_GetUniqueID()
390 int32 nextId
= atomic_add(&gID
, 1);
399 DNSQuery::_SetMXHeader(dns_header
* header
)
401 header
->id
= _GetUniqueID();
402 header
->qr
= 0; //This is a query
403 header
->opcode
= 0; //This is a standard query
404 header
->aa
= 0; //Not Authoritative
405 header
->tc
= 0; //This message is not truncated
406 header
->rd
= 1; //Recursion Desired
407 header
->ra
= 0; //Recursion not available! hey we dont have it (lol)
410 header
->q_count
= 1; //we have only 1 question
411 header
->ans_count
= 0;
412 header
->auth_count
= 0;
413 header
->add_count
= 0;
418 DNSQuery::_AppendQueryHeader(BRawNetBuffer
& buffer
, const dns_header
* header
)
420 buffer
.AppendUint16(header
->id
);
422 data
|= header
->rcode
;
423 data
|= header
->z
<< 4;
424 data
|= header
->ra
<< 7;
425 data
|= header
->rd
<< 8;
426 data
|= header
->tc
<< 9;
427 data
|= header
->aa
<< 10;
428 data
|= header
->opcode
<< 11;
429 data
|= header
->qr
<< 15;
430 buffer
.AppendUint16(data
);
431 buffer
.AppendUint16(header
->q_count
);
432 buffer
.AppendUint16(header
->ans_count
);
433 buffer
.AppendUint16(header
->auth_count
);
434 buffer
.AppendUint16(header
->add_count
);
439 DNSQuery::_ReadQueryHeader(BRawNetBuffer
& buffer
, dns_header
* header
)
441 buffer
.ReadUint16(header
->id
);
443 buffer
.ReadUint16(data
);
444 header
->rcode
= data
& 0x0F;
445 header
->z
= (data
>> 4) & 0x07;
446 header
->ra
= (data
>> 7) & 0x01;
447 header
->rd
= (data
>> 8) & 0x01;
448 header
->tc
= (data
>> 9) & 0x01;
449 header
->aa
= (data
>> 10) & 0x01;
450 header
->opcode
= (data
>> 11) & 0x0F;
451 header
->qr
= (data
>> 15) & 0x01;
452 buffer
.ReadUint16(header
->q_count
);
453 buffer
.ReadUint16(header
->ans_count
);
454 buffer
.ReadUint16(header
->auth_count
);
455 buffer
.ReadUint16(header
->add_count
);
460 DNSQuery::_ReadMXRecord(BRawNetBuffer
& buffer
, mx_record
* mxRecord
)
462 buffer
.ReadUint16(mxRecord
->priority
);
463 buffer
.ReadString(mxRecord
->serverName
);
464 mxRecord
->serverName
= DNSTools::ConvertFromDNSName(mxRecord
->serverName
);
469 DNSQuery::_ReadResourceRecord(BRawNetBuffer
& buffer
,
470 resource_record_head
*rrHead
)
472 buffer
.ReadString(rrHead
->name
);
473 buffer
.ReadUint16(rrHead
->type
);
474 buffer
.ReadUint16(rrHead
->dataClass
);
475 buffer
.ReadUint32(rrHead
->ttl
);
476 buffer
.ReadUint16(rrHead
->dataLength
);