summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRishi Srivatsavai <rishisv@gmail.com>2007-12-13 20:56:29 -0800
committerJames Peach <jpeach@samba.org>2007-12-13 20:56:29 -0800
commit12ac4c3119b3b7712e670d95d61413d97ecafaef (patch)
tree67a8dad20a20d9bbbfb54b325b46f671fd61f824
parent819a74ed8f1d2b312a22cc803235aaece0e24697 (diff)
downloadsamba-12ac4c3119b3b7712e670d95d61413d97ecafaef.tar.gz
samba-12ac4c3119b3b7712e670d95d61413d97ecafaef.tar.bz2
samba-12ac4c3119b3b7712e670d95d61413d97ecafaef.zip
Register the smb service with mDNS if mSDN is supported.
If mDNS is supported, attempt to register the first port we are listening on for the _smb._tcp service. This provides more reliable service discovery than NetBIOS browsing. (This used to be commit 1e7241517d1f55d60af22570e0c9feb280e3fdb5)
-rw-r--r--source3/Makefile.in1
-rw-r--r--source3/include/includes.h14
-rw-r--r--source3/smbd/dnsregister.c212
-rw-r--r--source3/smbd/server.c50
4 files changed, 268 insertions, 9 deletions
diff --git a/source3/Makefile.in b/source3/Makefile.in
index d26f688f80..5a8d7e19a8 100644
--- a/source3/Makefile.in
+++ b/source3/Makefile.in
@@ -547,6 +547,7 @@ SMBD_OBJ_SRV = smbd/files.o smbd/chgpasswd.o smbd/connection.o \
$(AFS_SETTOKEN_OBJ) smbd/aio.o smbd/statvfs.o \
smbd/dmapi.o \
smbd/file_access.o \
+ smbd/dnsregister.o \
$(MANGLE_OBJ) @VFS_STATIC@
SMBD_OBJ_BASE = $(PARAM_WITHOUT_REG_OBJ) $(SMBD_OBJ_SRV) $(LIBSMB_OBJ) \
diff --git a/source3/include/includes.h b/source3/include/includes.h
index 4e420881ae..22451741a1 100644
--- a/source3/include/includes.h
+++ b/source3/include/includes.h
@@ -752,6 +752,20 @@ struct printjob;
#include "smb_ldap.h"
+struct dns_reg_state;
+
+void dns_register_smbd(struct dns_reg_state ** dns_state_ptr,
+ unsigned port,
+ int *maxfd,
+ fd_set *listen_set,
+ struct timeval *timeout);
+
+void dns_register_close(struct dns_reg_state ** dns_state_ptr);
+
+
+bool dns_register_smbd_reply(struct dns_reg_state *dns_state,
+ fd_set *lfds, struct timeval *timeout);
+
/*
* Reasons for cache flush.
*/
diff --git a/source3/smbd/dnsregister.c b/source3/smbd/dnsregister.c
new file mode 100644
index 0000000000..fcd97b5dab
--- /dev/null
+++ b/source3/smbd/dnsregister.c
@@ -0,0 +1,212 @@
+/*
+ Unix SMB/CIFS implementation.
+ DNS-SD registration
+ Copyright (C) Rishi Srivatsavai 2007
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include <includes.h>
+#include <dns_sd.h>
+
+/* Uses DNS service discovery (libdns_sd) to
+ * register the SMB service. SMB service is registered
+ * on ".local" domain via Multicast DNS & any
+ * other unicast DNS domains available.
+ *
+ * Users use the smbclient -B (Browse) option to
+ * browse for advertised SMB services.
+ */
+
+#define DNS_REG_RETRY_INTERVAL (5*60) /* in seconds */
+
+struct dns_reg_state {
+ DNSServiceRef srv_ref;
+ struct timed_event *retry_handler;
+};
+
+#ifdef WITH_DNSSD_SUPPORT
+
+void dns_register_close(struct dns_reg_state **dns_state_ptr)
+{
+ int mdnsd_conn_fd;
+ struct dns_reg_state *dns_state = *dns_state_ptr;
+
+ if (dns_state == NULL) {
+ return;
+ }
+
+ if (dns_state->srv_ref != NULL) {
+ /* Close connection to the mDNS daemon */
+ DNSServiceRefDeallocate(dns_state->srv_ref);
+ dns_state->srv_ref = NULL;
+ }
+
+ /* Clear event handler */
+ if (dns_state->retry_handler != NULL) {
+ TALLOC_FREE(dns_state->retry_handler);
+ dns_state->retry_handler = NULL;
+ }
+
+ talloc_free(dns_state);
+ *dns_state_ptr = NULL;
+}
+
+static void dns_register_smbd_retry(struct event_context *ctx,
+ struct timed_event *te,
+ const struct timeval *now,
+ void *private_data)
+{
+ struct dns_reg_state *dns_state = (struct dns_reg_state *)private_data;
+
+ /* Clear previous registration state to force new
+ * registration attempt. Clears event handler.
+ */
+ dns_register_close(dns_state);
+}
+
+static void schedule_dns_register_smbd_retry(struct dns_reg_state *dns_state,
+ struct timeval *timeout)
+{
+ struct timed_event * event;
+
+ dns_state->srv_ref = NULL;
+ event= event_add_timed(smbd_event_context(),
+ NULL,
+ timeval_current_ofs(DNS_REG_RETRY_INTERVAL, 0),
+ "DNS registration handler",
+ dns_register_smbd_retry,
+ dns_state);
+
+ dns_state->retry_handler = event;
+ get_timed_events_timeout(smbd_event_context(), timeout);
+}
+
+/* Kick off a mDNS request to register the "_smb._tcp" on the specified port.
+ * We really ought to register on all the ports we are listening on. This will
+ * have to be an exercise for some-one who knows the DNS registration API a bit
+ * better.
+ */
+void dns_register_smbd(struct dns_reg_state ** dns_state_ptr,
+ unsigned port,
+ int *maxfd,
+ fd_set *listen_set,
+ struct timeval *timeout)
+{
+ int mdnsd_conn_fd;
+ DNSServiceErrorType err;
+ struct dns_reg_state *dns_state = *dns_state_ptr;
+
+ if (dns_state == NULL) {
+ *dns_state_ptr = dns_state = talloc(NULL, struct dns_reg_state);
+ if (dns_state == NULL) {
+ return;
+ }
+ }
+
+ /* Quit if a re-try attempt has been scheduled. */
+ if (dns_state->retry_handler != NULL) {
+ return;
+ }
+
+ /* If a registration is active add conn
+ * fd to select listen_set and return
+ */
+ if (dns_state->srv_ref != NULL) {
+ mdnsd_conn_fd = DNSServiceRefSockFD(dns_state->srv_ref);
+ FD_SET(mdnsd_conn_fd, listen_set);
+ return;
+ }
+
+ DEBUG(6, ("registering _smb._tcp service on port %d\n", port));
+
+ /* Register service with DNS. Connects with the mDNS
+ * daemon running on the local system to perform DNS
+ * service registration.
+ */
+ err = DNSServiceRegister(&dns_state->srv_ref, 0 /* flags */,
+ kDNSServiceInterfaceIndexAny,
+ NULL /* service name */,
+ "_smb._tcp" /* service type */,
+ NULL /* domain */,
+ "" /* SRV target host name */,
+ htons(port),
+ 0 /* TXT record len */,
+ NULL /* TXT record data */,
+ NULL /* callback func */,
+ NULL /* callback context */);
+
+ if (err != kDNSServiceErr_NoError) {
+ /* Failed to register service. Schedule a re-try attempt.
+ */
+ DEBUG(3, ("unable to register with mDNS (err %d)\n", err));
+ schedule_dns_register_smbd_retry(dns_state, timeout);
+ return;
+ }
+
+ mdnsd_conn_fd = DNSServiceRefSockFD(dns_state->srv_ref);
+ FD_SET(mdnsd_conn_fd, listen_set);
+ *maxfd = MAX(*maxfd, mdnsd_conn_fd);
+ *timeout = timeval_zero();
+
+}
+
+/* Processes reply from mDNS daemon. Returns true if a reply was received */
+bool dns_register_smbd_reply(struct dns_reg_state *dns_state,
+ fd_set *lfds, struct timeval *timeout)
+{
+ int mdnsd_conn_fd = -1;
+
+ if (dns_state->srv_ref == NULL) {
+ return false;
+ }
+
+ mdnsd_conn_fd = DNSServiceRefSockFD(dns_state->srv_ref);
+
+ /* Process reply from daemon. Handles any errors. */
+ if ((mdnsd_conn_fd != -1) && (FD_ISSET(mdnsd_conn_fd,lfds)) ) {
+ DNSServiceErrorType err;
+
+ err = DNSServiceProcessResult(dns_state->srv_ref);
+ if (err != kDNSServiceErr_NoError) {
+ DEBUG(3, ("failed to process mDNS result (err %d), re-trying\n",
+ err));
+ schedule_dns_register_smbd_retry(dns_state, timeout);
+ }
+
+ return true;
+ }
+
+ return false;
+}
+
+#else /* WITH_DNSSD_SUPPORT */
+
+ void dns_register_smbd(struct dns_reg_state ** dns_state_ptr,
+ unsigned port,
+ int *maxfd,
+ fd_set *listen_set,
+ struct timeval *timeout)
+{}
+
+ void dns_register_close(struct dns_reg_state ** dns_state_ptr)
+{}
+
+ bool dns_register_smbd_reply(struct dns_reg_state *dns_state,
+ fd_set *lfds, struct timeval *timeout)
+{
+ return false;
+}
+
+#endif /* WITH_DNSSD_SUPPORT */
diff --git a/source3/smbd/server.c b/source3/smbd/server.c
index 0aa8dac18d..41d036a8b9 100644
--- a/source3/smbd/server.c
+++ b/source3/smbd/server.c
@@ -311,6 +311,8 @@ static bool open_sockets_smbd(bool is_daemon, bool interactive, const char *smb_
int maxfd = 0;
int i;
char *ports;
+ struct dns_reg_state * dns_reg = NULL;
+ unsigned dns_port = 0;
if (!is_daemon) {
return open_sockets_inetd();
@@ -372,6 +374,14 @@ static bool open_sockets_smbd(bool is_daemon, bool interactive, const char *smb_
if (port == 0 || port > 0xffff) {
continue;
}
+
+ /* Keep the first port for mDNS service
+ * registration.
+ */
+ if (dns_port == 0) {
+ dns_port = port;
+ }
+
s = fd_listenset[num_sockets] =
open_socket_in(SOCK_STREAM, port, 0,
ifss, True);
@@ -436,6 +446,14 @@ static bool open_sockets_smbd(bool is_daemon, bool interactive, const char *smb_
if (port == 0 || port > 0xffff) {
continue;
}
+
+ /* Keep the first port for mDNS service
+ * registration.
+ */
+ if (dns_port == 0) {
+ dns_port = port;
+ }
+
/* open an incoming socket */
if (!interpret_string_addr(&ss, sock_tok,
AI_NUMERICHOST|AI_PASSIVE)) {
@@ -543,6 +561,12 @@ static bool open_sockets_smbd(bool is_daemon, bool interactive, const char *smb_
FD_ZERO(&w_fds);
GetTimeOfDay(&now);
+ /* Kick off our mDNS registration. */
+ if (dns_port != 0) {
+ dns_register_smbd(&dns_reg, dns_port, &maxfd,
+ &r_fds, &idle_timeout);
+ }
+
event_add_to_select_args(smbd_event_context(), &now,
&r_fds, &w_fds, &idle_timeout,
&maxfd);
@@ -567,6 +591,11 @@ static bool open_sockets_smbd(bool is_daemon, bool interactive, const char *smb_
continue;
}
+ /* process pending nDNS responses */
+ if (dns_register_smbd_reply(dns_reg, &r_fds, &idle_timeout)) {
+ --num;
+ }
+
if (run_events(smbd_event_context(), num, &r_fds, &w_fds)) {
continue;
}
@@ -624,6 +653,9 @@ static bool open_sockets_smbd(bool is_daemon, bool interactive, const char *smb_
for(i = 0; i < num_sockets; i++)
close(fd_listenset[i]);
+ /* close our mDNS daemon handle */
+ dns_register_close(&dns_reg);
+
/* close our standard file
descriptors */
close_low_fds(False);
@@ -964,8 +996,6 @@ extern void build_options(bool screen);
};
TALLOC_CTX *frame = talloc_stackframe(); /* Setup tos. */
- load_case_tables();
-
TimeInit();
#ifdef HAVE_SET_AUTH_PARAMETERS
@@ -1002,11 +1032,20 @@ extern void build_options(bool screen);
}
poptFreeContext(pc);
+ if (interactive) {
+ Fork = False;
+ log_stdout = True;
+ }
+
+ setup_logging(argv[0],log_stdout);
+
if (print_build_options) {
build_options(True); /* Display output to screen as well as debug */
exit(0);
}
+ load_case_tables();
+
#ifdef HAVE_SETLUID
/* needed for SecureWare on SCO */
setluid(0);
@@ -1016,11 +1055,6 @@ extern void build_options(bool screen);
set_remote_machine_name("smbd", False);
- if (interactive) {
- Fork = False;
- log_stdout = True;
- }
-
if (interactive && (DEBUGLEVEL >= 9)) {
talloc_enable_leak_report();
}
@@ -1030,8 +1064,6 @@ extern void build_options(bool screen);
exit(1);
}
- setup_logging(argv[0],log_stdout);
-
/* we want to re-seed early to prevent time delays causing
client problems at a later date. (tridge) */
generate_random_buffer(NULL, 0);