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
))
91 if (next_token_talloc(ctx
, &ptr
, &name
, NULL
))
93 if (name_type
&& strcasecmp(name_type
, "A") == 0) {
94 if (next_token_talloc(ctx
, &ptr
, &ip
, NULL
))
96 } else if (name_type
&& strcasecmp(name_type
, "SRV") == 0) {
97 if (next_token_talloc(ctx
, &ptr
, &next_name
, NULL
))
99 if (next_token_talloc(ctx
, &ptr
, &port
, NULL
))
101 } else if (name_type
&& strcasecmp(name_type
, "CNAME") == 0) {
102 if (next_token_talloc(ctx
, &ptr
, &next_name
, NULL
))
108 if (strcasecmp(name_type
, "A") == 0) {
110 DEBUG(0,("getdns_hosts_fileent: Ill formed hosts A record [%s]\n",
114 DEBUG(4, ("getdns_hosts_fileent: host entry: %s %s %s\n",
115 name_type
, name
, ip
));
116 if (!interpret_string_addr(pss
, ip
, AI_NUMERICHOST
)) {
117 DEBUG(0,("getdns_hosts_fileent: invalid address "
121 } else if (strcasecmp(name_type
, "SRV") == 0) {
123 DEBUG(0,("getdns_hosts_fileent: Ill formed hosts SRV record [%s]\n",
127 *p_port
= strtoul(port
, NULL
, 10);
128 if (*p_port
== UINT32_MAX
) {
129 DEBUG(0, ("getdns_hosts_fileent: Ill formed hosts SRV record [%s] (invalid port: %s)\n",
133 DEBUG(4, ("getdns_hosts_fileent: host entry: %s %s %s %u\n",
134 name_type
, name
, next_name
, (unsigned int)*p_port
));
135 *pp_next_name
= talloc_strdup(ctx
, next_name
);
136 if (!*pp_next_name
) {
139 } else if (strcasecmp(name_type
, "CNAME") == 0) {
141 DEBUG(0,("getdns_hosts_fileent: Ill formed hosts CNAME record [%s]\n",
145 DEBUG(4, ("getdns_hosts_fileent: host entry: %s %s %s\n",
146 name_type
, name
, next_name
));
147 *pp_next_name
= talloc_strdup(ctx
, next_name
);
148 if (!*pp_next_name
) {
152 DEBUG(0,("getdns_hosts_fileent: unknown type %s\n", name_type
));
156 *pp_name
= talloc_strdup(ctx
, name
);
161 *pp_name_type
= talloc_strdup(ctx
, name_type
);
162 if (!*pp_name_type
) {
171 /********************************************************
172 Finish parsing the dns_hosts_file file.
173 *********************************************************/
175 static void enddns_hosts_file(XFILE
*fp
)
180 /********************************************************
181 Resolve via "dns_hosts" method.
182 *********************************************************/
184 static NTSTATUS
resolve_dns_hosts_file_as_dns_rr_recurse(const char *dns_hosts_file
,
185 const char *name
, bool srv_lookup
,
186 int level
, uint32_t port
,
188 struct dns_rr_srv
**return_rr
,
192 * "dns_hosts" means parse the local dns_hosts file.
196 char *host_name
= NULL
;
197 char *name_type
= NULL
;
198 char *next_name
= NULL
;
199 struct sockaddr_storage return_ss
;
201 NTSTATUS status
= NT_STATUS_OBJECT_NAME_NOT_FOUND
;
202 TALLOC_CTX
*ctx
= NULL
;
203 TALLOC_CTX
*ip_list_ctx
= NULL
;
204 struct dns_rr_srv
*rr
= NULL
;
208 /* Don't recurse forever, even on our own flat files */
210 DEBUG(0, ("resolve_dns_hosts_file recursion limit reached looking up %s!\n", name
));
216 DEBUG(3,("resolve_dns_hosts: (%d) "
217 "Attempting %s dns_hosts lookup for name %s\n",
218 level
, srv_lookup
? "SRV" : "A", name
));
220 fp
= startdns_hosts_file(dns_hosts_file
);
223 return NT_STATUS_OBJECT_NAME_NOT_FOUND
;
225 ip_list_ctx
= talloc_new(mem_ctx
);
227 enddns_hosts_file(fp
);
228 return NT_STATUS_NO_MEMORY
;
231 ctx
= talloc_new(ip_list_ctx
);
233 talloc_free(ip_list_ctx
);
234 enddns_hosts_file(fp
);
235 return NT_STATUS_NO_MEMORY
;
238 while (getdns_hosts_fileent(ctx
, fp
, &host_name
, &name_type
, &next_name
, &return_ss
, &srv_port
)) {
239 if (!strequal(name
, host_name
)) {
240 /* continue at the bottom of the loop */
241 } else if (srv_lookup
) {
242 if (strcasecmp(name_type
, "SRV") == 0) {
243 NTSTATUS status_recurse
;
244 struct dns_rr_srv
*tmp_rr
;
246 /* we only accept one host name per SRV entry */
248 = resolve_dns_hosts_file_as_dns_rr_recurse(dns_hosts_file
, next_name
,
251 ip_list_ctx
, &tmp_rr
,
253 if (NT_STATUS_EQUAL(status_recurse
, NT_STATUS_OBJECT_NAME_NOT_FOUND
)) {
254 /* Don't fail on a dangling SRV record */
255 } else if (!NT_STATUS_IS_OK(status_recurse
)) {
256 enddns_hosts_file(fp
);
257 talloc_free(ip_list_ctx
);
258 return status_recurse
;
259 } else if (tmp_count
!= 1) {
260 status
= NT_STATUS_OBJECT_NAME_NOT_FOUND
;
262 status
= status_recurse
;
263 rr
= talloc_realloc(ip_list_ctx
, rr
, struct dns_rr_srv
, (*return_count
) + 1);
265 enddns_hosts_file(fp
);
266 return NT_STATUS_NO_MEMORY
;
268 talloc_steal(rr
, tmp_rr
);
269 rr
[*return_count
] = *tmp_rr
;
270 *return_count
= (*return_count
) + 1;
273 } else if (strcasecmp(name_type
, "CNAME") == 0) {
274 /* we only accept one host name per CNAME */
275 enddns_hosts_file(fp
);
276 status
= resolve_dns_hosts_file_as_dns_rr_recurse(dns_hosts_file
, next_name
, false,
278 mem_ctx
, return_rr
, return_count
);
279 talloc_free(ip_list_ctx
);
281 } else if (strcasecmp(name_type
, "A") == 0) {
282 if (*return_count
== 0) {
283 /* We are happy to keep looking for other possible A record matches */
284 rr
= talloc_zero(ip_list_ctx
,
289 enddns_hosts_file(fp
);
290 DEBUG(3,("resolve_dns_hosts: talloc_realloc fail !\n"));
291 return NT_STATUS_NO_MEMORY
;
294 rr
->hostname
= talloc_strdup(rr
, host_name
);
296 if (rr
->hostname
== NULL
) {
298 enddns_hosts_file(fp
);
299 DEBUG(3,("resolve_dns_hosts: talloc_realloc fail !\n"));
300 return NT_STATUS_NO_MEMORY
;
307 /* Set the specified port (possibly from a SRV lookup) into the structure we return */
308 set_sockaddr_port((struct sockaddr
*)&return_ss
, port
);
310 /* We are happy to keep looking for other possible A record matches */
311 rr
->ss_s
= talloc_realloc(rr
, rr
->ss_s
,
312 struct sockaddr_storage
,
315 if (rr
->ss_s
== NULL
) {
317 enddns_hosts_file(fp
);
318 DEBUG(3,("resolve_dns_hosts: talloc_realloc fail !\n"));
319 return NT_STATUS_NO_MEMORY
;
322 rr
->ss_s
[rr
->num_ips
] = return_ss
;
325 /* we found something */
326 status
= NT_STATUS_OK
;
330 ctx
= talloc_new(mem_ctx
);
332 enddns_hosts_file(fp
);
333 return NT_STATUS_NO_MEMORY
;
337 *return_rr
= talloc_steal(mem_ctx
, rr
);
338 TALLOC_FREE(ip_list_ctx
);
339 enddns_hosts_file(fp
);
343 /********************************************************
344 Resolve via "dns_hosts_file" method, returning a list of sockaddr_storage values
345 *********************************************************/
347 NTSTATUS
resolve_dns_hosts_file_as_sockaddr(const char *dns_hosts_file
,
348 const char *name
, bool srv_lookup
,
350 struct sockaddr_storage
**return_iplist
,
354 struct dns_rr_srv
*dns_rr
= NULL
;
355 int i
, j
, rr_count
= 0;
357 *return_iplist
= NULL
;
360 status
= resolve_dns_hosts_file_as_dns_rr_recurse(dns_hosts_file
, name
, srv_lookup
,
362 mem_ctx
, &dns_rr
, &rr_count
);
363 if (!NT_STATUS_IS_OK(status
)) {
364 DEBUG(3,("resolve_dns_hosts (sockaddr): "
365 "failed to obtain %s result records for for name %s: %s\n",
366 srv_lookup
? "SRV" : "A", name
, nt_errstr(status
)));
370 for (i
=0; i
< rr_count
; i
++) {
371 *return_iplist
= talloc_realloc(mem_ctx
, *return_iplist
, struct sockaddr_storage
, *return_count
+ dns_rr
[i
].num_ips
);
372 if (!*return_iplist
) {
373 return NT_STATUS_NO_MEMORY
;
375 for (j
=0; j
< dns_rr
[i
].num_ips
; j
++) {
376 (*return_iplist
)[*return_count
] = dns_rr
[i
].ss_s
[j
];
377 *return_count
= *return_count
+ 1;
380 DEBUG(3,("resolve_dns_hosts (sockaddr): "
381 "Found %d results for for name %s\n",
382 *return_count
, name
));
387 /********************************************************
388 Resolve via "dns_hosts_file" method, returning struct dns_rr_srv
389 *********************************************************/
391 NTSTATUS
resolve_dns_hosts_file_as_dns_rr(const char *dns_hosts_file
,
392 const char *name
, bool srv_lookup
,
394 struct dns_rr_srv
**return_rr
,
401 status
= resolve_dns_hosts_file_as_dns_rr_recurse(dns_hosts_file
, name
, srv_lookup
,
403 mem_ctx
, return_rr
, return_count
);
405 if (NT_STATUS_IS_OK(status
)) {
406 DEBUG(3,("resolve_dns_hosts (dns_rr): "
407 "Found %d %s result records for for name %s\n",
408 *return_count
, srv_lookup
? "SRV" : "A", name
));
410 DEBUG(3,("resolve_dns_hosts (dns_rr): "
411 "failed to obtain %s result records for for name %s: %s\n",
412 srv_lookup
? "SRV" : "A", name
, nt_errstr(status
)));