From 923bc7a1afeb0b920e60e14846987ae1d2d7dca4 Mon Sep 17 00:00:00 2001 From: John Hixson Date: Thu, 7 Dec 2017 09:36:32 -0500 Subject: [PATCH] Freenas/master mdns fixes (#22) * mDNS fixes for Samba (work in progress). * Fix mDNS - Can advertise on individual interfaces * Fix mDNS browsing in smbclient Signed-off-by: Timur I. Bakeyev --- source3/client/dnsbrowse.c | 17 ++-- source3/smbd/dnsregister.c | 193 +++++++++++++++++++++++++++++---------------- 2 files changed, 137 insertions(+), 73 deletions(-) diff --git a/source3/client/dnsbrowse.c b/source3/client/dnsbrowse.c index efd57d42d88..83aef966d2a 100644 --- a/source3/client/dnsbrowse.c +++ b/source3/client/dnsbrowse.c @@ -39,6 +39,7 @@ struct mdns_smbsrv_result struct mdns_browse_state { struct mdns_smbsrv_result *listhead; /* Browse result list head */ + TALLOC_CTX * ctx; int browseDone; }; @@ -64,7 +65,7 @@ static void do_smb_resolve(struct mdns_smbsrv_result *browsesrv) struct timeval tv; DNSServiceErrorType err; - TALLOC_CTX * ctx = talloc_tos(); + TALLOC_CTX * ctx = talloc_new(NULL); err = DNSServiceResolve(&mdns_conn_sdref, 0 /* flags */, browsesrv->ifIndex, @@ -91,7 +91,7 @@ static void do_smb_resolve(struct mdns_s } } - TALLOC_FREE(fdset); + TALLOC_FREE(ctx); DNSServiceRefDeallocate(mdns_conn_sdref); } @@ -124,18 +125,19 @@ do_smb_browse_reply(DNSServiceRef sdRef, DNSServiceFlags flags, return; } - bresult = talloc_array(talloc_tos(), struct mdns_smbsrv_result, 1); + bresult = talloc_array(bstatep->ctx, struct mdns_smbsrv_result, 1); if (bresult == NULL) { return; } + bresult->nextResult = NULL; if (bstatep->listhead != NULL) { bresult->nextResult = bstatep->listhead; } - bresult->serviceName = talloc_strdup(talloc_tos(), serviceName); - bresult->regType = talloc_strdup(talloc_tos(), regtype); - bresult->domain = talloc_strdup(talloc_tos(), replyDomain); + bresult->serviceName = talloc_strdup(bstatep->ctx, serviceName); + bresult->regType = talloc_strdup(bstatep->ctx, regtype); + bresult->domain = talloc_strdup(bstatep->ctx, replyDomain); bresult->ifIndex = interfaceIndex; bstatep->listhead = bresult; } @@ -151,10 +153,13 @@ int do_smb_browse(void) DNSServiceRef mdns_conn_sdref = NULL; DNSServiceErrorType err; - TALLOC_CTX * ctx = talloc_stackframe(); + TALLOC_CTX * ctx = talloc_new(NULL); ZERO_STRUCT(bstate); + bstate.ctx = ctx; + bstate.listhead = NULL; + err = DNSServiceBrowse(&mdns_conn_sdref, 0, 0, "_smb._tcp", "", do_smb_browse_reply, &bstate); diff --git a/source3/smbd/dnsregister.c b/source3/smbd/dnsregister.c index df189001a09..f25b60f4611 100644 --- a/source3/smbd/dnsregister.c +++ b/source3/smbd/dnsregister.c @@ -36,85 +36,111 @@ #include struct dns_reg_state { - struct tevent_context *event_ctx; - uint16_t port; - DNSServiceRef srv_ref; - struct tevent_timer *te; - int fd; - struct tevent_fd *fde; + int count; + struct reg_state { + DNSServiceRef srv_ref; + TALLOC_CTX *mem_ctx; + struct tevent_context *event_ctx; + struct tevent_timer *te; + struct tevent_fd *fde; + uint16_t port; + int if_index; + int fd; + } *drs; }; -static int dns_reg_state_destructor(struct dns_reg_state *dns_state) +static void dns_register_smbd_retry(struct tevent_context *ctx, + struct tevent_timer *te, + struct timeval now, + void *private_data); +static void dns_register_smbd_fde_handler(struct tevent_context *ev, + struct tevent_fd *fde, + uint16_t flags, + void *private_data); + + +static int reg_state_destructor(struct reg_state *state) { - if (dns_state->srv_ref != NULL) { + if (state == NULL) { + return -1; + } + + if (state->srv_ref != NULL) { /* Close connection to the mDNS daemon */ - DNSServiceRefDeallocate(dns_state->srv_ref); - dns_state->srv_ref = NULL; + DNSServiceRefDeallocate(state->srv_ref); + state->srv_ref = NULL; } /* Clear event handler */ - TALLOC_FREE(dns_state->te); - TALLOC_FREE(dns_state->fde); - dns_state->fd = -1; + TALLOC_FREE(state->te); + TALLOC_FREE(state->fde); + state->fd = -1; return 0; } -static void dns_register_smbd_retry(struct tevent_context *ctx, - struct tevent_timer *te, - struct timeval now, - void *private_data); -static void dns_register_smbd_fde_handler(struct tevent_context *ev, - struct tevent_fd *fde, - uint16_t flags, - void *private_data); -static bool dns_register_smbd_schedule(struct dns_reg_state *dns_state, +static bool dns_register_smbd_schedule(struct reg_state *state, struct timeval tval) { - dns_reg_state_destructor(dns_state); + reg_state_destructor(state); - dns_state->te = tevent_add_timer(dns_state->event_ctx, - dns_state, + state->te = tevent_add_timer(state->event_ctx, + state->mem_ctx, tval, dns_register_smbd_retry, - dns_state); - if (!dns_state->te) { + state); + if (!state->te) { return false; } return true; } +static void dns_register_smbd_callback(DNSServiceRef service, + DNSServiceFlags flags, + DNSServiceErrorType errorCode, + const char *name, + const char *type, + const char *domain, + void *context) +{ + if (errorCode != kDNSServiceErr_NoError) { + DEBUG(6, ("error=%d\n", errorCode)); + } else { + DEBUG(6, ("%-15s %s.%s%s\n", "REGISTER", name, type, domain)); + } +} + static void dns_register_smbd_retry(struct tevent_context *ctx, struct tevent_timer *te, struct timeval now, void *private_data) { - struct dns_reg_state *dns_state = talloc_get_type_abort(private_data, - struct dns_reg_state); + struct reg_state *state = (struct reg_state *)private_data; DNSServiceErrorType err; - dns_reg_state_destructor(dns_state); + reg_state_destructor(state); - DEBUG(6, ("registering _smb._tcp service on port %d\n", - dns_state->port)); + DEBUG(6, ("registering _smb._tcp service on port %d index %d\n", + state->port, state->if_index)); /* 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(dns_state->port), - 0 /* TXT record len */, - NULL /* TXT record data */, - NULL /* callback func */, - NULL /* callback context */); + err = DNSServiceRegister(&state->srv_ref, + 0 /* flags */, + state->if_index /* interface index */, + NULL /* service name */, + "_smb._tcp" /* service type */, + NULL /* domain */, + "" /* SRV target host name */, + htons(state->port) /* port */, + 0 /* TXT record len */, + NULL /* TXT record data */, + dns_register_smbd_callback /* callback func */, + NULL /* callback context */); if (err != kDNSServiceErr_NoError) { /* Failed to register service. Schedule a re-try attempt. @@ -123,24 +149,24 @@ static void dns_register_smbd_retry(struct tevent_context *ctx, goto retry; } - dns_state->fd = DNSServiceRefSockFD(dns_state->srv_ref); - if (dns_state->fd == -1) { + state->fd = DNSServiceRefSockFD(state->srv_ref); + if (state->fd == -1) { goto retry; } - dns_state->fde = tevent_add_fd(dns_state->event_ctx, - dns_state, - dns_state->fd, - TEVENT_FD_READ, - dns_register_smbd_fde_handler, - dns_state); - if (!dns_state->fde) { + state->fde = tevent_add_fd(state->event_ctx, + state->mem_ctx, + state->fd, + TEVENT_FD_READ, + dns_register_smbd_fde_handler, + state); + if (!state->fde) { goto retry; } return; retry: - dns_register_smbd_schedule(dns_state, + dns_register_smbd_schedule(state, timeval_current_ofs(DNS_REG_RETRY_INTERVAL, 0)); } @@ -150,44 +176,77 @@ static void dns_register_smbd_fde_handler(struct tevent_context *ev, uint16_t flags, void *private_data) { - struct dns_reg_state *dns_state = talloc_get_type_abort(private_data, - struct dns_reg_state); + struct reg_state *state = (struct reg_state *)private_data; DNSServiceErrorType err; - err = DNSServiceProcessResult(dns_state->srv_ref); + err = DNSServiceProcessResult(state->srv_ref); if (err != kDNSServiceErr_NoError) { - DEBUG(3, ("failed to process mDNS result (err %d), re-trying\n", - err)); + DEBUG(3, ("failed to process mDNS result (err %d), re-trying\n", err)); goto retry; } - talloc_free(dns_state); return; retry: - dns_register_smbd_schedule(dns_state, - timeval_current_ofs(DNS_REG_RETRY_INTERVAL, 0)); + dns_register_smbd_schedule(state, timeval_zero()); } +static int dns_reg_state_destructor(struct dns_reg_state *state) +{ + if (state != NULL) { + talloc_free(state); + } + return 0; +} + + bool smbd_setup_mdns_registration(struct tevent_context *ev, TALLOC_CTX *mem_ctx, uint16_t port) { struct dns_reg_state *dns_state; + bool bind_all = true; + int i; dns_state = talloc_zero(mem_ctx, struct dns_reg_state); - if (dns_state == NULL) { + if (dns_state == NULL) + return false; + + if (lp_interfaces() && lp_bind_interfaces_only()) + bind_all = false; + + dns_state->count = iface_count(); + if (dns_state->count <= 0 || bind_all == true) + dns_state->count = 1; + + dns_state->drs = talloc_array(mem_ctx, struct reg_state, dns_state->count); + if (dns_state->drs == NULL) { + talloc_free(dns_state); return false; } - dns_state->event_ctx = ev; - dns_state->port = port; - dns_state->fd = -1; - talloc_set_destructor(dns_state, dns_reg_state_destructor); + for (i = 0; i < dns_state->count; i++) { + struct interface *iface = get_interface(i); + struct reg_state *state = &dns_state->drs[i]; + + state->mem_ctx = mem_ctx; + state->srv_ref = NULL; + state->event_ctx = ev; + state->te = NULL; + state->fde = NULL; + state->port = port; + state->fd = -1; + + state->if_index = bind_all ? kDNSServiceInterfaceIndexAny : iface->if_index; - return dns_register_smbd_schedule(dns_state, timeval_zero()); + dns_register_smbd_schedule(&dns_state->drs[i], timeval_zero()); + } + + talloc_set_destructor(dns_state, dns_reg_state_destructor); + return true; } + #else /* WITH_DNSSD_SUPPORT */ bool smbd_setup_mdns_registration(struct tevent_context *ev, -- 2.14.2