2 Unix SMB/CIFS implementation.
4 read a file containing DNS names, types and IP addresses
6 Copyright (C) Andrew Tridgell 1994-1998
7 Copyright (C) Jeremy Allison 2007
8 Copyright (C) Andrew Bartlett 2009-2011
10 This program is free software; you can redistribute it and/or modify
11 it under the terms of the GNU General Public License as published by
12 the Free Software Foundation; either version 3 of the License, or
13 (at your option) any later version.
15 This program is distributed in the hope that it will be useful,
16 but WITHOUT ANY WARRANTY; without even the implied warranty of
17 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 GNU General Public License for more details.
20 You should have received a copy of the GNU General Public License
21 along with this program. If not, see <http://www.gnu.org/licenses/>.
24 /* The purpose of this file is to read the file generated by the samba_dnsupdate script */
27 #include "lib/util/xfile.h"
28 #include "lib/util/util_net.h"
29 #include "system/filesys.h"
30 #include "system/network.h"
31 #include "libcli/nbt/libnbt.h"
32 #include "libcli/dns/dns.h"
38 /********************************************************
39 Start parsing the dns_hosts_file file.
40 *********************************************************/
42 static XFILE
*startdns_hosts_file(const char *fname
)
44 XFILE
*fp
= x_fopen(fname
,O_RDONLY
, 0);
46 DEBUG(4,("startdns_hosts_file: Can't open dns_hosts_file file %s. "
48 fname
, strerror(errno
)));
54 /********************************************************
55 Parse the next line in the dns_hosts_file file.
56 *********************************************************/
58 static bool getdns_hosts_fileent(TALLOC_CTX
*ctx
, XFILE
*fp
, char **pp_name
, char **pp_name_type
,
60 struct sockaddr_storage
*pss
, uint32_t *p_port
)
69 while(!x_feof(fp
) && !x_ferror(fp
)) {
70 char *name_type
= NULL
;
72 char *next_name
= NULL
;
79 if (!fgets_slash(line
,sizeof(line
),fp
)) {
89 if (next_token_talloc(ctx
, &ptr
, &name_type
, NULL
))
94 if (next_token_talloc(ctx
, &ptr
, &name
, NULL
))
96 if ((strcasecmp(name_type
, "A") == 0) ||
97 (strcasecmp(name_type
, "AAAA") == 0))
99 if (next_token_talloc(ctx
, &ptr
, &ip
, NULL
))
101 } else if (name_type
&& strcasecmp(name_type
, "SRV") == 0) {
102 if (next_token_talloc(ctx
, &ptr
, &next_name
, NULL
))
104 if (next_token_talloc(ctx
, &ptr
, &port
, NULL
))
106 } else if (name_type
&& strcasecmp(name_type
, "CNAME") == 0) {
107 if (next_token_talloc(ctx
, &ptr
, &next_name
, NULL
))
109 } else if (name_type
&& strcasecmp(name_type
, "NS") == 0) {
110 if (next_token_talloc(ctx
, &ptr
, &next_name
, NULL
))
116 if ((strcasecmp(name_type
, "A") == 0) ||
117 (strcasecmp(name_type
, "AAAA") == 0))
120 DEBUG(0,("getdns_hosts_fileent: Ill formed hosts A[AAA] record [%s]\n",
124 DEBUG(4, ("getdns_hosts_fileent: host entry: %s %s %s\n",
125 name_type
, name
, ip
));
126 if (!interpret_string_addr(pss
, ip
, AI_NUMERICHOST
)) {
127 DEBUG(0,("getdns_hosts_fileent: invalid address "
131 } else if (strcasecmp(name_type
, "SRV") == 0) {
133 DEBUG(0,("getdns_hosts_fileent: Ill formed hosts SRV record [%s]\n",
137 *p_port
= strtoul(port
, NULL
, 10);
138 if (*p_port
== UINT32_MAX
) {
139 DEBUG(0, ("getdns_hosts_fileent: Ill formed hosts SRV record [%s] (invalid port: %s)\n",
143 DEBUG(4, ("getdns_hosts_fileent: host entry: %s %s %s %u\n",
144 name_type
, name
, next_name
, (unsigned int)*p_port
));
145 *pp_next_name
= talloc_strdup(ctx
, next_name
);
146 if (!*pp_next_name
) {
149 } else if (strcasecmp(name_type
, "CNAME") == 0) {
151 DEBUG(0,("getdns_hosts_fileent: Ill formed hosts CNAME record [%s]\n",
155 DEBUG(4, ("getdns_hosts_fileent: host entry: %s %s %s\n",
156 name_type
, name
, next_name
));
157 *pp_next_name
= talloc_strdup(ctx
, next_name
);
158 if (!*pp_next_name
) {
161 } else if (strcasecmp(name_type
, "NS") == 0) {
163 DEBUG(0,("getdns_hosts_fileent: Ill formed hosts NS record [%s]\n",
167 DEBUG(4, ("getdns_hosts_fileent: NS entry: %s %s %s\n",
168 name_type
, name
, next_name
));
171 DEBUG(0,("getdns_hosts_fileent: unknown type %s\n", name_type
));
175 *pp_name
= talloc_strdup(ctx
, name
);
180 *pp_name_type
= talloc_strdup(ctx
, name_type
);
181 if (!*pp_name_type
) {
190 /********************************************************
191 Finish parsing the dns_hosts_file file.
192 *********************************************************/
194 static void enddns_hosts_file(XFILE
*fp
)
199 /********************************************************
200 Resolve via "dns_hosts" method.
201 *********************************************************/
203 static NTSTATUS
resolve_dns_hosts_file_as_dns_rr_recurse(const char *dns_hosts_file
,
204 const char *name
, bool srv_lookup
,
205 int level
, uint32_t port
,
207 struct dns_rr_srv
**return_rr
,
211 * "dns_hosts" means parse the local dns_hosts file.
215 char *host_name
= NULL
;
216 char *name_type
= NULL
;
217 char *next_name
= NULL
;
218 struct sockaddr_storage return_ss
;
220 NTSTATUS status
= NT_STATUS_OBJECT_NAME_NOT_FOUND
;
221 TALLOC_CTX
*ctx
= NULL
;
222 TALLOC_CTX
*ip_list_ctx
= NULL
;
223 struct dns_rr_srv
*rr
= NULL
;
227 /* Don't recurse forever, even on our own flat files */
229 DEBUG(0, ("resolve_dns_hosts_file recursion limit reached looking up %s!\n", name
));
235 DEBUG(3,("resolve_dns_hosts: (%d) "
236 "Attempting %s dns_hosts lookup for name %s\n",
237 level
, srv_lookup
? "SRV" : "A[AAA]", name
));
239 fp
= startdns_hosts_file(dns_hosts_file
);
242 return NT_STATUS_OBJECT_NAME_NOT_FOUND
;
244 ip_list_ctx
= talloc_new(mem_ctx
);
246 enddns_hosts_file(fp
);
247 return NT_STATUS_NO_MEMORY
;
250 ctx
= talloc_new(ip_list_ctx
);
252 talloc_free(ip_list_ctx
);
253 enddns_hosts_file(fp
);
254 return NT_STATUS_NO_MEMORY
;
257 while (getdns_hosts_fileent(ctx
, fp
, &host_name
, &name_type
, &next_name
, &return_ss
, &srv_port
)) {
258 if (!strequal(name
, host_name
)) {
259 /* continue at the bottom of the loop */
260 } else if (srv_lookup
) {
261 if (strcasecmp(name_type
, "SRV") == 0) {
262 NTSTATUS status_recurse
;
263 struct dns_rr_srv
*tmp_rr
;
265 /* we only accept one host name per SRV entry */
267 = resolve_dns_hosts_file_as_dns_rr_recurse(dns_hosts_file
, next_name
,
270 ip_list_ctx
, &tmp_rr
,
272 if (NT_STATUS_EQUAL(status_recurse
, NT_STATUS_OBJECT_NAME_NOT_FOUND
)) {
273 /* Don't fail on a dangling SRV record */
274 } else if (!NT_STATUS_IS_OK(status_recurse
)) {
275 enddns_hosts_file(fp
);
276 talloc_free(ip_list_ctx
);
277 return status_recurse
;
278 } else if (tmp_count
!= 1) {
279 status
= NT_STATUS_OBJECT_NAME_NOT_FOUND
;
281 status
= status_recurse
;
282 rr
= talloc_realloc(ip_list_ctx
, rr
, struct dns_rr_srv
, (*return_count
) + 1);
284 enddns_hosts_file(fp
);
285 return NT_STATUS_NO_MEMORY
;
287 talloc_steal(rr
, tmp_rr
);
288 rr
[*return_count
] = *tmp_rr
;
289 *return_count
= (*return_count
) + 1;
292 } else if (strcasecmp(name_type
, "CNAME") == 0) {
293 /* we only accept one host name per CNAME */
294 enddns_hosts_file(fp
);
295 status
= resolve_dns_hosts_file_as_dns_rr_recurse(dns_hosts_file
, next_name
, false,
297 mem_ctx
, return_rr
, return_count
);
298 talloc_free(ip_list_ctx
);
300 } else if ((strcasecmp(name_type
, "A") == 0) ||
301 (strcasecmp(name_type
, "AAAA") == 0))
303 if (*return_count
== 0) {
304 /* We are happy to keep looking for other possible A record matches */
305 rr
= talloc_zero(ip_list_ctx
,
310 enddns_hosts_file(fp
);
311 DEBUG(3,("resolve_dns_hosts: talloc_realloc fail !\n"));
312 return NT_STATUS_NO_MEMORY
;
315 rr
->hostname
= talloc_strdup(rr
, host_name
);
317 if (rr
->hostname
== NULL
) {
319 enddns_hosts_file(fp
);
320 DEBUG(3,("resolve_dns_hosts: talloc_realloc fail !\n"));
321 return NT_STATUS_NO_MEMORY
;
328 /* Set the specified port (possibly from a SRV lookup) into the structure we return */
329 set_sockaddr_port((struct sockaddr
*)&return_ss
, port
);
331 /* We are happy to keep looking for other possible A record matches */
332 rr
->ss_s
= talloc_realloc(rr
, rr
->ss_s
,
333 struct sockaddr_storage
,
336 if (rr
->ss_s
== NULL
) {
338 enddns_hosts_file(fp
);
339 DEBUG(3,("resolve_dns_hosts: talloc_realloc fail !\n"));
340 return NT_STATUS_NO_MEMORY
;
343 rr
->ss_s
[rr
->num_ips
] = return_ss
;
346 /* we found something */
347 status
= NT_STATUS_OK
;
351 ctx
= talloc_new(mem_ctx
);
353 enddns_hosts_file(fp
);
354 return NT_STATUS_NO_MEMORY
;
358 *return_rr
= talloc_steal(mem_ctx
, rr
);
359 TALLOC_FREE(ip_list_ctx
);
360 enddns_hosts_file(fp
);
364 /********************************************************
365 Resolve via "dns_hosts_file" method, returning a list of sockaddr_storage values
366 *********************************************************/
368 NTSTATUS
resolve_dns_hosts_file_as_sockaddr(const char *dns_hosts_file
,
369 const char *name
, bool srv_lookup
,
371 struct sockaddr_storage
**return_iplist
,
375 struct dns_rr_srv
*dns_rr
= NULL
;
376 int i
, j
, rr_count
= 0;
378 *return_iplist
= NULL
;
381 status
= resolve_dns_hosts_file_as_dns_rr_recurse(dns_hosts_file
, name
, srv_lookup
,
383 mem_ctx
, &dns_rr
, &rr_count
);
384 if (!NT_STATUS_IS_OK(status
)) {
385 DEBUG(3,("resolve_dns_hosts (sockaddr): "
386 "failed to obtain %s result records for for name %s: %s\n",
387 srv_lookup
? "SRV" : "A", name
, nt_errstr(status
)));
391 for (i
=0; i
< rr_count
; i
++) {
392 *return_iplist
= talloc_realloc(mem_ctx
, *return_iplist
, struct sockaddr_storage
, *return_count
+ dns_rr
[i
].num_ips
);
393 if (!*return_iplist
) {
394 return NT_STATUS_NO_MEMORY
;
396 for (j
=0; j
< dns_rr
[i
].num_ips
; j
++) {
397 (*return_iplist
)[*return_count
] = dns_rr
[i
].ss_s
[j
];
398 *return_count
= *return_count
+ 1;
401 DEBUG(3,("resolve_dns_hosts (sockaddr): "
402 "Found %d results for for name %s\n",
403 *return_count
, name
));
408 /********************************************************
409 Resolve via "dns_hosts_file" method, returning struct dns_rr_srv
410 *********************************************************/
412 NTSTATUS
resolve_dns_hosts_file_as_dns_rr(const char *dns_hosts_file
,
413 const char *name
, bool srv_lookup
,
415 struct dns_rr_srv
**return_rr
,
422 status
= resolve_dns_hosts_file_as_dns_rr_recurse(dns_hosts_file
, name
, srv_lookup
,
424 mem_ctx
, return_rr
, return_count
);
426 if (NT_STATUS_IS_OK(status
)) {
427 DEBUG(3,("resolve_dns_hosts (dns_rr): "
428 "Found %d %s result records for for name %s\n",
429 *return_count
, srv_lookup
? "SRV" : "A[AAA]", name
));
431 DEBUG(3,("resolve_dns_hosts (dns_rr): "
432 "failed to obtain %s result records for for name %s: %s\n",
433 srv_lookup
? "SRV" : "A[AAA]", name
, nt_errstr(status
)));