[mdns] add 'port' property to config file

This CL adds a 'port' property to the config file schema so that mDNS
can be run on a port other than 5353.

DX-1365 #comment

TEST: No behavior change. Test for regressions:
      $ avahi-browse -t _fuchsia._udp.
Change-Id: I8d0c3aaa95f1ac75a4462b0c45b318a64fad7508
diff --git a/garnet/bin/mdns/service/address_prober.cc b/garnet/bin/mdns/service/address_prober.cc
index a7691de..206b38f 100644
--- a/garnet/bin/mdns/service/address_prober.cc
+++ b/garnet/bin/mdns/service/address_prober.cc
@@ -16,7 +16,7 @@
 const std::string& AddressProber::ResourceName() { return host_full_name(); }
 
 void AddressProber::SendProposedResources(MdnsResourceSection section) {
-  SendAddresses(section);
+  SendAddresses(section, MdnsAddresses::V4MulticastReply(mdns_port()));
 }
 
 }  // namespace mdns
diff --git a/garnet/bin/mdns/service/address_responder.cc b/garnet/bin/mdns/service/address_responder.cc
index 16a93bc..f4d9a44 100644
--- a/garnet/bin/mdns/service/address_responder.cc
+++ b/garnet/bin/mdns/service/address_responder.cc
@@ -14,9 +14,11 @@
 
 AddressResponder::~AddressResponder() {}
 
-void AddressResponder::Start(const std::string& host_full_name) {
+void AddressResponder::Start(const std::string& host_full_name,
+                             inet::IpPort mdns_port) {
   FXL_DCHECK(!host_full_name.empty());
 
+  MdnsAgent::Start(host_full_name, mdns_port);
   host_full_name_ = host_full_name;
 }
 
diff --git a/garnet/bin/mdns/service/address_responder.h b/garnet/bin/mdns/service/address_responder.h
index cab7760..bf1f0c4 100644
--- a/garnet/bin/mdns/service/address_responder.h
+++ b/garnet/bin/mdns/service/address_responder.h
@@ -23,7 +23,8 @@
   ~AddressResponder() override;
 
   // MdnsAgent overrides.
-  void Start(const std::string& host_full_name) override;
+  void Start(const std::string& host_full_name,
+             inet::IpPort mdns_port) override;
 
   void ReceiveQuestion(const DnsQuestion& question,
                        const ReplyAddress& reply_address) override;
diff --git a/garnet/bin/mdns/service/config.cc b/garnet/bin/mdns/service/config.cc
index 840ece9..1ed3cd3 100644
--- a/garnet/bin/mdns/service/config.cc
+++ b/garnet/bin/mdns/service/config.cc
@@ -17,6 +17,11 @@
   "type": "object",
   "additionalProperties": false,
   "properties": {
+    "port": {
+      "type": "integer",
+      "minimum": 1,
+      "maximum": 65535
+    },
     "perform_host_name_probe": {
       "type": "boolean"
     },
@@ -89,6 +94,13 @@
                                const std::string& host_name) {
   FXL_DCHECK(document.IsObject());
 
+  if (document.HasMember(kPortKey)) {
+    FXL_DCHECK(document[kPortKey].IsUint());
+    FXL_DCHECK(document[kPortKey].GetUint() >= 1);
+    FXL_DCHECK(document[kPortKey].GetUint() <= 65535);
+    mdns_port_ = inet::IpPort::From_uint16_t(document[kPortKey].GetUint());
+  }
+
   if (document.HasMember(kPerformHostNameProbeKey)) {
     FXL_DCHECK(document[kPerformHostNameProbeKey].IsBool());
     SetPerformHostNameProbe(document[kPerformHostNameProbeKey].GetBool());
diff --git a/garnet/bin/mdns/service/config.h b/garnet/bin/mdns/service/config.h
index 4e47289..9d827fd 100644
--- a/garnet/bin/mdns/service/config.h
+++ b/garnet/bin/mdns/service/config.h
@@ -8,6 +8,7 @@
 #include <optional>
 
 #include "garnet/bin/mdns/service/mdns.h"
+#include "garnet/bin/mdns/service/mdns_addresses.h"
 #include "lib/json/json_parser.h"
 #include "rapidjson/document.h"
 
@@ -39,6 +40,9 @@
   // an empty string.
   std::string error() { return parser_.error_str(); }
 
+  // Returns the port to use for mDNS multicast communication (normally 5353).
+  inet::IpPort mdns_port() { return mdns_port_; }
+
   // Indicates whether a probe should be performed for the hostname.
   bool perform_host_name_probe() {
     return perform_host_name_probe_.has_value()
@@ -66,6 +70,7 @@
   void SetPerformHostNameProbe(bool perform_host_name_probe);
 
   json::JSONParser parser_;
+  inet::IpPort mdns_port_ = MdnsAddresses::kDefaultMdnsPort;
   std::optional<bool> perform_host_name_probe_;
   std::vector<Publication> publications_;
 };
diff --git a/garnet/bin/mdns/service/host_name_resolver.cc b/garnet/bin/mdns/service/host_name_resolver.cc
index 412bdde..7a728ec 100644
--- a/garnet/bin/mdns/service/host_name_resolver.cc
+++ b/garnet/bin/mdns/service/host_name_resolver.cc
@@ -24,10 +24,13 @@
 
 HostNameResolver::~HostNameResolver() {}
 
-void HostNameResolver::Start(const std::string& host_full_name) {
+void HostNameResolver::Start(const std::string& host_full_name,
+                             inet::IpPort mdns_port) {
   // Note that |host_full_name_| is the name we're trying to resolve, not the
   // name of the local host, which is the (ignored) parameter to this method.
 
+  MdnsAgent::Start(host_full_name, mdns_port);
+
   SendQuestion(std::make_shared<DnsQuestion>(host_full_name_, DnsType::kA));
   SendQuestion(std::make_shared<DnsQuestion>(host_full_name_, DnsType::kAaaa));
 
diff --git a/garnet/bin/mdns/service/host_name_resolver.h b/garnet/bin/mdns/service/host_name_resolver.h
index 24566d2..6a4a70c 100644
--- a/garnet/bin/mdns/service/host_name_resolver.h
+++ b/garnet/bin/mdns/service/host_name_resolver.h
@@ -26,7 +26,8 @@
   ~HostNameResolver() override;
 
   // MdnsAgent overrides.
-  void Start(const std::string& host_full_name) override;
+  void Start(const std::string& host_full_name,
+             inet::IpPort mdns_port) override;
 
   void ReceiveResource(const DnsResource& resource,
                        MdnsResourceSection section) override;
diff --git a/garnet/bin/mdns/service/instance_prober.cc b/garnet/bin/mdns/service/instance_prober.cc
index 557232c..af9cd99 100644
--- a/garnet/bin/mdns/service/instance_prober.cc
+++ b/garnet/bin/mdns/service/instance_prober.cc
@@ -12,8 +12,7 @@
 InstanceProber::InstanceProber(MdnsAgent::Host* host,
                                const std::string& service_name,
                                const std::string& instance_name,
-                               inet::IpPort port,
-                               CompletionCallback callback)
+                               inet::IpPort port, CompletionCallback callback)
     : Prober(host, DnsType::kSrv, std::move(callback)),
       instance_full_name_(
           MdnsNames::LocalInstanceFullName(instance_name, service_name)),
@@ -30,7 +29,8 @@
       std::make_shared<DnsResource>(instance_full_name_, DnsType::kSrv);
   srv_resource->srv_.port_ = port_;
   srv_resource->srv_.target_ = host_full_name();
-  SendResource(srv_resource, section);
+  SendResource(srv_resource, section,
+               MdnsAddresses::V4MulticastReply(mdns_port()));
 }
 
 }  // namespace mdns
diff --git a/garnet/bin/mdns/service/instance_requestor.cc b/garnet/bin/mdns/service/instance_requestor.cc
index 98f2ac4..1be9300 100644
--- a/garnet/bin/mdns/service/instance_requestor.cc
+++ b/garnet/bin/mdns/service/instance_requestor.cc
@@ -38,7 +38,9 @@
   }
 }
 
-void InstanceRequestor::Start(const std::string& host_full_name) {
+void InstanceRequestor::Start(const std::string& host_full_name,
+                              inet::IpPort mdns_port) {
+  MdnsAgent::Start(host_full_name, mdns_port);
   SendQuery();
 }
 
diff --git a/garnet/bin/mdns/service/instance_requestor.h b/garnet/bin/mdns/service/instance_requestor.h
index 9f48d36..cb5c416 100644
--- a/garnet/bin/mdns/service/instance_requestor.h
+++ b/garnet/bin/mdns/service/instance_requestor.h
@@ -33,7 +33,8 @@
   void RemoveSubscriber(Mdns::Subscriber* subscriber);
 
   // MdnsAgent overrides.
-  void Start(const std::string& host_full_name) override;
+  void Start(const std::string& host_full_name,
+             inet::IpPort mdns_port) override;
 
   void ReceiveResource(const DnsResource& resource,
                        MdnsResourceSection section) override;
diff --git a/garnet/bin/mdns/service/instance_responder.cc b/garnet/bin/mdns/service/instance_responder.cc
index 6f6a35d..9308e7b 100644
--- a/garnet/bin/mdns/service/instance_responder.cc
+++ b/garnet/bin/mdns/service/instance_responder.cc
@@ -25,9 +25,12 @@
 
 InstanceResponder::~InstanceResponder() {}
 
-void InstanceResponder::Start(const std::string& host_full_name) {
+void InstanceResponder::Start(const std::string& host_full_name,
+                              inet::IpPort mdns_port) {
   FXL_DCHECK(!host_full_name.empty());
 
+  MdnsAgent::Start(host_full_name, mdns_port);
+
   host_full_name_ = host_full_name;
 
   Reannounce();
@@ -82,7 +85,8 @@
   for (const std::string& subtype : subtypes_) {
     if (std::find(subtypes.begin(), subtypes.end(), subtype) ==
         subtypes.end()) {
-      SendSubtypePtrRecord(subtype, 0);
+      SendSubtypePtrRecord(subtype, 0,
+                           MdnsAddresses::V4MulticastReply(mdns_port()));
     }
   }
 
@@ -99,10 +103,12 @@
 }
 
 void InstanceResponder::SendAnnouncement() {
-  GetAndSendPublication(false);
+  GetAndSendPublication(false, "",
+                        MdnsAddresses::V4MulticastReply(mdns_port()));
 
   for (const std::string& subtype : subtypes_) {
-    SendSubtypePtrRecord(subtype);
+    SendSubtypePtrRecord(subtype, DnsResource::kShortTimeToLive,
+                         MdnsAddresses::V4MulticastReply(mdns_port()));
   }
 
   if (announcement_interval_ > kMaxAnnouncementInterval) {
@@ -189,7 +195,8 @@
   publication.srv_ttl_seconds_ = 0;
   publication.txt_ttl_seconds_ = 0;
 
-  SendPublication(publication);
+  SendPublication(publication, "",
+                  MdnsAddresses::V4MulticastReply(mdns_port()));
 }
 
 }  // namespace mdns
diff --git a/garnet/bin/mdns/service/instance_responder.h b/garnet/bin/mdns/service/instance_responder.h
index c777fa1..dfd7e7e 100644
--- a/garnet/bin/mdns/service/instance_responder.h
+++ b/garnet/bin/mdns/service/instance_responder.h
@@ -28,7 +28,8 @@
   ~InstanceResponder() override;
 
   // MdnsAgent overrides.
-  void Start(const std::string& host_full_name) override;
+  void Start(const std::string& host_full_name,
+             inet::IpPort mdns_port) override;
 
   void ReceiveQuestion(const DnsQuestion& question,
                        const ReplyAddress& reply_address) override;
@@ -60,21 +61,17 @@
 
   // Gets an |Mdns::Publication| from |mdns_responder_| and, if not null, sends
   // it. An empty |subtype| indicates no subtype.
-  void GetAndSendPublication(bool query, const std::string& subtype = "",
-                             const ReplyAddress& reply_address =
-                                 MdnsAddresses::kV4MulticastReply) const;
+  void GetAndSendPublication(bool query, const std::string& subtype,
+                             const ReplyAddress& reply_address) const;
 
   // Sends a publication. An empty |subtype| indicates no subtype.
   void SendPublication(const Mdns::Publication& publication,
-                       const std::string& subtype = "",
-                       const ReplyAddress& reply_address =
-                           MdnsAddresses::kV4MulticastReply) const;
+                       const std::string& subtype,
+                       const ReplyAddress& reply_address) const;
 
   // Sends a subtype PTR record for this instance.
-  void SendSubtypePtrRecord(const std::string& subtype,
-                            uint32_t ttl = DnsResource::kShortTimeToLive,
-                            const ReplyAddress& reply_address =
-                                MdnsAddresses::kV4MulticastReply) const;
+  void SendSubtypePtrRecord(const std::string& subtype, uint32_t ttl,
+                            const ReplyAddress& reply_address) const;
 
   // Sends a publication with zero ttls, indicating the service instance is
   // no longer published.
diff --git a/garnet/bin/mdns/service/mdns.cc b/garnet/bin/mdns/service/mdns.cc
index 0fa8564..c985e23 100644
--- a/garnet/bin/mdns/service/mdns.cc
+++ b/garnet/bin/mdns/service/mdns.cc
@@ -37,8 +37,8 @@
 }
 
 void Mdns::Start(fuchsia::netstack::NetstackPtr netstack,
-                 const std::string& host_name, bool perform_address_probe,
-                 fit::closure ready_callback) {
+                 const std::string& host_name, inet::IpPort mdns_port,
+                 bool perform_address_probe, fit::closure ready_callback) {
   FXL_DCHECK(!host_name.empty());
   FXL_DCHECK(ready_callback);
   FXL_DCHECK(state_ == State::kNotStarted);
@@ -47,6 +47,7 @@
   state_ = State::kWaitingForInterfaces;
 
   original_host_name_ = host_name;
+  mdns_port_ = mdns_port;
 
   // Create a resource renewer agent to keep resources alive.
   resource_renewer_ = std::make_shared<ResourceRenewer>(this);
@@ -55,7 +56,7 @@
   AddAgent(std::make_shared<AddressResponder>(this));
 
   transceiver_.Start(
-      std::move(netstack),
+      std::move(netstack), mdns_port,
       [this, perform_address_probe]() {
         // TODO(dalesat): Link changes that create host name conflicts.
         // Once we have a NIC and we've decided on a unique host name, we
@@ -80,11 +81,11 @@
         for (auto& question : message->questions_) {
           // We reply to questions using unicast if specifically requested in
           // the question or if the sender's port isn't 5353.
-          ReceiveQuestion(*question, (question->unicast_response_ ||
-                                      reply_address.socket_address().port() !=
-                                          MdnsAddresses::kMdnsPort)
-                                         ? reply_address
-                                         : MdnsAddresses::kV4MulticastReply);
+          ReceiveQuestion(*question,
+                          (question->unicast_response_ ||
+                           reply_address.socket_address().port() != mdns_port_)
+                              ? reply_address
+                              : MdnsAddresses::V4MulticastReply(mdns_port_));
         }
 
         for (auto& resource : message->answers_) {
@@ -212,7 +213,7 @@
   // We don't use |AddAgent| here, because agents added that way don't
   // actually participate until we're done probing for host name conflicts.
   agents_.emplace(address_prober.get(), address_prober);
-  address_prober->Start(host_full_name_);
+  address_prober->Start(host_full_name_, mdns_port_);
   SendMessages();
 }
 
@@ -231,7 +232,7 @@
 
   // |resource_renewer_| doesn't need to be started, but we do it
   // anyway in case that changes.
-  resource_renewer_->Start(host_full_name_);
+  resource_renewer_->Start(host_full_name_, mdns_port_);
 
   for (auto agent : agents_awaiting_start_) {
     AddAgent(agent);
@@ -263,7 +264,8 @@
 void Mdns::SendQuestion(std::shared_ptr<DnsQuestion> question) {
   FXL_DCHECK(question);
   DnsMessage& message =
-      outbound_messages_by_reply_address_[MdnsAddresses::kV4MulticastReply];
+      outbound_messages_by_reply_address_[MdnsAddresses::V4MulticastReply(
+          mdns_port_)];
   message.questions_.push_back(question);
 }
 
@@ -345,7 +347,7 @@
   if (state_ == State::kActive) {
     agents_.emplace(agent.get(), agent);
     FXL_DCHECK(!host_full_name_.empty());
-    agent->Start(host_full_name_);
+    agent->Start(host_full_name_, mdns_port_);
     SendMessages();
   } else {
     agents_awaiting_start_.push_back(agent);
@@ -406,7 +408,7 @@
 
 #ifdef MDNS_TRACE
     if (verbose_) {
-      if (reply_address == MdnsAddresses::kV4MulticastReply) {
+      if (reply_address == MdnsAddresses::V4MulticastReply(mdns_port_)) {
         FXL_LOG(INFO) << "Outbound message (multicast): " << message;
       } else {
         FXL_LOG(INFO) << "Outbound message to " << reply_address << ":"
diff --git a/garnet/bin/mdns/service/mdns.h b/garnet/bin/mdns/service/mdns.h
index 9c7867b..21cd810 100644
--- a/garnet/bin/mdns/service/mdns.h
+++ b/garnet/bin/mdns/service/mdns.h
@@ -144,7 +144,8 @@
   // calls to |ResolveHostName|, |SubscribeToService| and
   // |PublishServiceInstance|.
   void Start(fuchsia::netstack::NetstackPtr, const std::string& host_name,
-             bool perform_address_probe, fit::closure ready_callback);
+             inet::IpPort mdns_port, bool perform_address_probe,
+             fit::closure ready_callback);
 
   // Stops the transceiver.
   void Stop();
@@ -278,6 +279,7 @@
   async_dispatcher_t* dispatcher_;
   MdnsTransceiver transceiver_;
   std::string original_host_name_;
+  inet::IpPort mdns_port_;
   fit::closure ready_callback_;
   uint32_t next_host_name_deduplicator_ = 2;
   std::string host_name_;
diff --git a/garnet/bin/mdns/service/mdns_addresses.cc b/garnet/bin/mdns/service/mdns_addresses.cc
index 2369dfa..a95beef 100644
--- a/garnet/bin/mdns/service/mdns_addresses.cc
+++ b/garnet/bin/mdns/service/mdns_addresses.cc
@@ -7,26 +7,32 @@
 namespace mdns {
 
 // static
-const inet::IpPort MdnsAddresses::kMdnsPort = inet::IpPort::From_uint16_t(5353);
+const inet::IpPort MdnsAddresses::kDefaultMdnsPort =
+    inet::IpPort::From_uint16_t(5353);
 
 // static
-const inet::SocketAddress MdnsAddresses::kV4Multicast(224, 0, 0, 251,
-                                                      kMdnsPort);
+inet::SocketAddress MdnsAddresses::V4Multicast(inet::IpPort port) {
+  return inet::SocketAddress(224, 0, 0, 251, port);
+}
 
 // static
-const inet::SocketAddress MdnsAddresses::kV6Multicast(0xff02, 0xfb, kMdnsPort);
+inet::SocketAddress MdnsAddresses::V6Multicast(inet::IpPort port) {
+  return inet::SocketAddress(0xff02, 0xfb, port);
+}
 
 // static
-const inet::SocketAddress MdnsAddresses::kV4Bind(INADDR_ANY, kMdnsPort);
+inet::SocketAddress MdnsAddresses::V4Bind(inet::IpPort port) {
+  return inet::SocketAddress(INADDR_ANY, port);
+}
 
 // static
-const inet::SocketAddress MdnsAddresses::kV6Bind(in6addr_any, kMdnsPort);
+inet::SocketAddress MdnsAddresses::V6Bind(inet::IpPort port) {
+  return inet::SocketAddress(in6addr_any, port);
+}
 
 // static
-const ReplyAddress MdnsAddresses::kV4MulticastReply(MdnsAddresses::kV4Multicast,
-                                                    inet::IpAddress());
+ReplyAddress MdnsAddresses::V4MulticastReply(inet::IpPort port) {
+  return ReplyAddress(V4Multicast(port), inet::IpAddress());
+}
 
-// static
-const ReplyAddress MdnsAddresses::kV6MulticastReply(MdnsAddresses::kV6Multicast,
-                                                    inet::IpAddress());
 }  // namespace mdns
diff --git a/garnet/bin/mdns/service/mdns_addresses.h b/garnet/bin/mdns/service/mdns_addresses.h
index 9888315..88d2032 100644
--- a/garnet/bin/mdns/service/mdns_addresses.h
+++ b/garnet/bin/mdns/service/mdns_addresses.h
@@ -14,15 +14,14 @@
 namespace mdns {
 
 struct MdnsAddresses {
-  static const inet::IpPort kMdnsPort;
+  static const inet::IpPort kDefaultMdnsPort;
 
-  static const inet::SocketAddress kV4Multicast;
-  static const inet::SocketAddress kV6Multicast;
-  static const inet::SocketAddress kV4Bind;
-  static const inet::SocketAddress kV6Bind;
+  static inet::SocketAddress V4Multicast(inet::IpPort port);
+  static inet::SocketAddress V6Multicast(inet::IpPort port);
+  static inet::SocketAddress V4Bind(inet::IpPort port);
+  static inet::SocketAddress V6Bind(inet::IpPort port);
 
-  static const ReplyAddress kV4MulticastReply;
-  static const ReplyAddress kV6MulticastReply;
+  static ReplyAddress V4MulticastReply(inet::IpPort port);
 };
 
 }  // namespace mdns
diff --git a/garnet/bin/mdns/service/mdns_agent.h b/garnet/bin/mdns/service/mdns_agent.h
index 08a54c8..ebe980a 100644
--- a/garnet/bin/mdns/service/mdns_agent.h
+++ b/garnet/bin/mdns/service/mdns_agent.h
@@ -5,10 +5,10 @@
 #ifndef GARNET_BIN_MDNS_SERVICE_MDNS_AGENT_H_
 #define GARNET_BIN_MDNS_SERVICE_MDNS_AGENT_H_
 
-#include <memory>
-
 #include <lib/fit/function.h>
 
+#include <memory>
+
 #include "garnet/bin/mdns/service/dns_message.h"
 #include "garnet/bin/mdns/service/mdns_addresses.h"
 #include "garnet/lib/inet/socket_address.h"
@@ -63,7 +63,11 @@
 
   // Starts the agent. This method is never called before a shared pointer to
   // the agent is created, so |shared_from_this| is safe to call.
-  virtual void Start(const std::string& host_full_name) {}
+  // Specializations should call this method first.
+  virtual void Start(const std::string& host_full_name,
+                     inet::IpPort mdns_port) {
+    mdns_port_ = mdns_port;
+  }
 
   // Presents a received question. This agent must not call |RemoveSelf| during
   // a call to this method.
@@ -86,6 +90,8 @@
  protected:
   MdnsAgent(Host* host) : host_(host) { FXL_DCHECK(host_); }
 
+  inet::IpPort mdns_port() const { return mdns_port_; }
+
   // Posts a task to be executed at the specified time. Scheduled tasks posted
   // by agents that have since been removed are not executed.
   void PostTaskForTime(fit::closure task, fxl::TimePoint target_time) {
@@ -97,22 +103,16 @@
     host_->SendQuestion(question);
   }
 
-  // Sends a resource to the specified address. The default |reply_address|
-  // |kV4MulticastReply| sends the resource to the V4 or V6
-  // multicast address.
+  // Sends a resource to the specified address.
   void SendResource(std::shared_ptr<DnsResource> resource,
                     MdnsResourceSection section,
-                    const ReplyAddress& reply_address =
-                        MdnsAddresses::kV4MulticastReply) const {
+                    const ReplyAddress& reply_address) const {
     host_->SendResource(resource, section, reply_address);
   }
 
-  // Sends address resources to the specified address. The default
-  // |reply_address| |kV4MulticastReply| sends the addresses to the V4 or V6
-  // multicast address.
+  // Sends address resources to the specified address.
   void SendAddresses(MdnsResourceSection section,
-                     const ReplyAddress& reply_address =
-                         MdnsAddresses::kV4MulticastReply) const {
+                     const ReplyAddress& reply_address) const {
     host_->SendAddresses(section, reply_address);
   }
 
@@ -137,6 +137,7 @@
 
  private:
   Host* host_;
+  inet::IpPort mdns_port_;
 };
 
 }  // namespace mdns
diff --git a/garnet/bin/mdns/service/mdns_interface_transceiver.cc b/garnet/bin/mdns/service/mdns_interface_transceiver.cc
index 7cfdf71..ea5ae79 100644
--- a/garnet/bin/mdns/service/mdns_interface_transceiver.cc
+++ b/garnet/bin/mdns/service/mdns_interface_transceiver.cc
@@ -10,8 +10,10 @@
 #include <lib/async/default.h>
 #include <poll.h>
 #include <sys/socket.h>
+
 #include <algorithm>
 #include <iostream>
+
 #include "garnet/bin/mdns/service/dns_formatting.h"
 #include "garnet/bin/mdns/service/dns_reading.h"
 #include "garnet/bin/mdns/service/dns_writing.h"
@@ -19,9 +21,9 @@
 #include "garnet/bin/mdns/service/mdns_interface_transceiver_v4.h"
 #include "garnet/bin/mdns/service/mdns_interface_transceiver_v6.h"
 #include "lib/fostr/hex_dump.h"
+#include "src/lib/files/unique_fd.h"
 #include "src/lib/fxl/logging.h"
 #include "src/lib/fxl/time/time_delta.h"
-#include "src/lib/files/unique_fd.h"
 
 namespace mdns {
 
@@ -46,12 +48,15 @@
 
 MdnsInterfaceTransceiver::~MdnsInterfaceTransceiver() {}
 
-bool MdnsInterfaceTransceiver::Start(InboundMessageCallback callback) {
+bool MdnsInterfaceTransceiver::Start(inet::IpPort mdns_port,
+                                     InboundMessageCallback callback) {
   FXL_DCHECK(callback);
   FXL_DCHECK(!socket_fd_.is_valid()) << "Start called when already started.";
 
+  mdns_port_ = mdns_port;
+
   std::cerr << "Starting mDNS on interface " << name_ << " " << address_
-            << "\n";
+            << " using port " << mdns_port_ << "\n";
 
   socket_fd_ = fxl::UniqueFD(socket(address_.family(), SOCK_DGRAM, 0));
 
@@ -93,7 +98,7 @@
   FXL_DCHECK(message);
   FXL_DCHECK(address.is_valid());
   FXL_DCHECK(address.family() == address_.family() ||
-             address == MdnsAddresses::kV4Multicast);
+             address == MdnsAddresses::V4Multicast(mdns_port_));
 
   FixUpAddresses(&message->answers_);
   FixUpAddresses(&message->authorities_);
@@ -120,7 +125,7 @@
   DnsMessage message;
   message.answers_.push_back(GetAddressResource(host_full_name));
 
-  SendMessage(&message, MdnsAddresses::kV4Multicast);
+  SendMessage(&message, MdnsAddresses::V4Multicast(mdns_port_));
 }
 
 void MdnsInterfaceTransceiver::SendAddressGoodbye(
@@ -130,7 +135,7 @@
   message.answers_.push_back(MakeAddressResource(host_full_name, address_));
   message.answers_.back()->time_to_live_ = 0;
 
-  SendMessage(&message, MdnsAddresses::kV4Multicast);
+  SendMessage(&message, MdnsAddresses::V4Multicast(mdns_port_));
 }
 
 void MdnsInterfaceTransceiver::LogTraffic() {
diff --git a/garnet/bin/mdns/service/mdns_interface_transceiver.h b/garnet/bin/mdns/service/mdns_interface_transceiver.h
index f8784bf..fcb0d44 100644
--- a/garnet/bin/mdns/service/mdns_interface_transceiver.h
+++ b/garnet/bin/mdns/service/mdns_interface_transceiver.h
@@ -5,18 +5,18 @@
 #ifndef GARNET_BIN_MDNS_SERVICE_MDNS_INTERFACE_TRANSCEIVER_H_
 #define GARNET_BIN_MDNS_SERVICE_MDNS_INTERFACE_TRANSCEIVER_H_
 
+#include <lib/fit/function.h>
+
 #include <memory>
 #include <vector>
 
-#include <lib/fit/function.h>
-
 #include "garnet/bin/mdns/service/dns_message.h"
 #include "garnet/bin/mdns/service/reply_address.h"
 #include "garnet/lib/inet/ip_address.h"
 #include "garnet/lib/inet/socket_address.h"
 #include "lib/fsl/tasks/fd_waiter.h"
-#include "src/lib/fxl/macros.h"
 #include "src/lib/files/unique_fd.h"
+#include "src/lib/fxl/macros.h"
 
 namespace mdns {
 
@@ -44,7 +44,7 @@
   uint32_t index() const { return index_; }
 
   // Starts the interface transceiver.
-  bool Start(InboundMessageCallback callback);
+  bool Start(inet::IpPort mdns_port, InboundMessageCallback callback);
 
   // Stops the interface transceiver.
   void Stop();
@@ -53,8 +53,8 @@
   void SetAlternateAddress(const inet::IpAddress& alternate_address);
 
   // Sends a message to the specified address. A V6 interface will send to
-  // |MdnsAddresses::kV6Multicast| if |reply_address| is
-  // |MdnsAddresses::kV4Multicast|. This method expects there to be at most two
+  // |MdnsAddresses::V6Multicast| if |reply_address| is
+  // |MdnsAddresses::V4Multicast|. This method expects there to be at most two
   // address records per record vector and, if there are two, that they are
   // adjacent. The same constraints will apply when this method returns.
   void SendMessage(DnsMessage* message, const inet::SocketAddress& address);
@@ -77,6 +77,7 @@
                            uint32_t index);
 
   const fxl::UniqueFD& socket_fd() const { return socket_fd_; }
+  inet::IpPort mdns_port() const { return mdns_port_; }
 
   virtual int SetOptionDisableMulticastLoop() = 0;
   virtual int SetOptionJoinMulticastGroup() = 0;
@@ -123,6 +124,7 @@
   fsl::FDWaiter fd_waiter_;
   std::vector<uint8_t> inbound_buffer_;
   std::vector<uint8_t> outbound_buffer_;
+  inet::IpPort mdns_port_;
   InboundMessageCallback inbound_message_callback_;
   std::shared_ptr<DnsResource> address_resource_;
   std::shared_ptr<DnsResource> alternate_address_resource_;
diff --git a/garnet/bin/mdns/service/mdns_interface_transceiver_v4.cc b/garnet/bin/mdns/service/mdns_interface_transceiver_v4.cc
index 2e2cdc0..8439a7e 100644
--- a/garnet/bin/mdns/service/mdns_interface_transceiver_v4.cc
+++ b/garnet/bin/mdns/service/mdns_interface_transceiver_v4.cc
@@ -35,7 +35,7 @@
 int MdnsInterfaceTransceiverV4::SetOptionJoinMulticastGroup() {
   ip_mreqn param;
   param.imr_multiaddr.s_addr =
-      MdnsAddresses::kV4Multicast.as_sockaddr_in().sin_addr.s_addr;
+      MdnsAddresses::V4Multicast(mdns_port()).as_sockaddr_in().sin_addr.s_addr;
   param.imr_address = address().as_in_addr();
   param.imr_ifindex = index();
   int result = setsockopt(socket_fd().get(), IPPROTO_IP, IP_ADD_MEMBERSHIP,
@@ -95,8 +95,9 @@
 }
 
 int MdnsInterfaceTransceiverV4::Bind() {
-  int result = bind(socket_fd().get(), MdnsAddresses::kV4Bind.as_sockaddr(),
-                    MdnsAddresses::kV4Bind.socklen());
+  int result =
+      bind(socket_fd().get(), MdnsAddresses::V4Bind(mdns_port()).as_sockaddr(),
+           MdnsAddresses::V4Bind(mdns_port()).socklen());
   if (result < 0) {
     FXL_LOG(ERROR) << "Failed to bind socket to V4 address, "
                    << strerror(errno);
diff --git a/garnet/bin/mdns/service/mdns_interface_transceiver_v6.cc b/garnet/bin/mdns/service/mdns_interface_transceiver_v6.cc
index b7e807f..d58cd4a 100644
--- a/garnet/bin/mdns/service/mdns_interface_transceiver_v6.cc
+++ b/garnet/bin/mdns/service/mdns_interface_transceiver_v6.cc
@@ -41,7 +41,7 @@
 int MdnsInterfaceTransceiverV6::SetOptionJoinMulticastGroup() {
   ipv6_mreq param;
   param.ipv6mr_multiaddr =
-      MdnsAddresses::kV6Multicast.as_sockaddr_in6().sin6_addr;
+      MdnsAddresses::V6Multicast(mdns_port()).as_sockaddr_in6().sin6_addr;
   param.ipv6mr_interface = index();
   int result = setsockopt(socket_fd().get(), IPPROTO_IPV6, IPV6_JOIN_GROUP,
                           &param, sizeof(param));
@@ -125,8 +125,9 @@
 }
 
 int MdnsInterfaceTransceiverV6::Bind() {
-  int result = bind(socket_fd().get(), MdnsAddresses::kV6Bind.as_sockaddr(),
-                    MdnsAddresses::kV6Bind.socklen());
+  int result =
+      bind(socket_fd().get(), MdnsAddresses::V6Bind(mdns_port()).as_sockaddr(),
+           MdnsAddresses::V6Bind(mdns_port()).socklen());
   if (result < 0) {
     FXL_LOG(ERROR) << "Failed to bind socket to V6 address, "
                    << strerror(errno);
@@ -137,10 +138,10 @@
 
 int MdnsInterfaceTransceiverV6::SendTo(const void* buffer, size_t size,
                                        const inet::SocketAddress& address) {
-  if (address == MdnsAddresses::kV4Multicast) {
+  if (address == MdnsAddresses::V4Multicast(mdns_port())) {
     return sendto(socket_fd().get(), buffer, size, 0,
-                  MdnsAddresses::kV6Multicast.as_sockaddr(),
-                  MdnsAddresses::kV6Multicast.socklen());
+                  MdnsAddresses::V6Multicast(mdns_port()).as_sockaddr(),
+                  MdnsAddresses::V6Multicast(mdns_port()).socklen());
   }
 
   return sendto(socket_fd().get(), buffer, size, 0, address.as_sockaddr(),
diff --git a/garnet/bin/mdns/service/mdns_service_impl.cc b/garnet/bin/mdns/service/mdns_service_impl.cc
index a3dae9e..f015a37 100644
--- a/garnet/bin/mdns/service/mdns_service_impl.cc
+++ b/garnet/bin/mdns/service/mdns_service_impl.cc
@@ -68,7 +68,7 @@
   }
 
   mdns_.Start(component_context_->svc()->Connect<fuchsia::netstack::Netstack>(),
-              host_name, config_.perform_host_name_probe(),
+              host_name, config_.mdns_port(), config_.perform_host_name_probe(),
               fit::bind_member(this, &MdnsServiceImpl::OnReady));
 }
 
diff --git a/garnet/bin/mdns/service/mdns_transceiver.cc b/garnet/bin/mdns/service/mdns_transceiver.cc
index 6dda06a..d7afd38 100644
--- a/garnet/bin/mdns/service/mdns_transceiver.cc
+++ b/garnet/bin/mdns/service/mdns_transceiver.cc
@@ -7,6 +7,7 @@
 #include <arpa/inet.h>
 #include <errno.h>
 #include <sys/socket.h>
+
 #include "garnet/bin/mdns/service/mdns_addresses.h"
 #include "garnet/bin/mdns/service/mdns_fidl_util.h"
 #include "src/lib/files/unique_fd.h"
@@ -19,6 +20,7 @@
 MdnsTransceiver::~MdnsTransceiver() {}
 
 void MdnsTransceiver::Start(fuchsia::netstack::NetstackPtr netstack,
+                            inet::IpPort mdns_port,
                             fit::closure link_change_callback,
                             InboundMessageCallback inbound_message_callback) {
   FXL_DCHECK(netstack);
@@ -26,6 +28,7 @@
   FXL_DCHECK(inbound_message_callback);
 
   netstack_ = std::move(netstack);
+  mdns_port_ = mdns_port;
   link_change_callback_ = std::move(link_change_callback);
   inbound_message_callback_ = std::move(inbound_message_callback);
 
@@ -54,7 +57,8 @@
                                   const ReplyAddress& reply_address) {
   FXL_DCHECK(message);
 
-  if (reply_address.socket_address() == MdnsAddresses::kV4Multicast) {
+  if (reply_address.socket_address() ==
+      MdnsAddresses::V4Multicast(mdns_port_)) {
     for (auto& [address, interface] : interface_transceivers_by_address_) {
       FXL_DCHECK(interface);
       interface->SendMessage(message, reply_address.socket_address());
@@ -179,7 +183,8 @@
   auto interface_transceiver =
       MdnsInterfaceTransceiver::Create(address, name, id);
 
-  if (!interface_transceiver->Start(inbound_message_callback_.share())) {
+  if (!interface_transceiver->Start(mdns_port_,
+                                    inbound_message_callback_.share())) {
     // Couldn't start the transceiver.
     return result_on_fail;
   }
diff --git a/garnet/bin/mdns/service/mdns_transceiver.h b/garnet/bin/mdns/service/mdns_transceiver.h
index 479b611..c433834 100644
--- a/garnet/bin/mdns/service/mdns_transceiver.h
+++ b/garnet/bin/mdns/service/mdns_transceiver.h
@@ -8,9 +8,11 @@
 #include <fuchsia/netstack/cpp/fidl.h>
 #include <lib/fit/function.h>
 #include <netinet/in.h>
+
 #include <memory>
 #include <unordered_map>
 #include <vector>
+
 #include "garnet/bin/mdns/service/mdns_interface_transceiver.h"
 #include "src/lib/fxl/macros.h"
 
@@ -27,7 +29,7 @@
   ~MdnsTransceiver();
 
   // Starts the transceiver.
-  void Start(fuchsia::netstack::NetstackPtr netstack,
+  void Start(fuchsia::netstack::NetstackPtr netstack, inet::IpPort mdns_port,
              fit::closure link_change_callback,
              InboundMessageCallback inbound_message_callback);
 
@@ -38,8 +40,8 @@
   bool has_interfaces() { return !interface_transceivers_by_address_.empty(); }
 
   // Sends a message to the specified address. A V6 interface will send to
-  // |MdnsAddresses::kV6Multicast| if |reply_address.socket_address()| is
-  // |MdnsAddresses::kV4Multicast|.
+  // |MdnsAddresses::V6Multicast| if |reply_address.socket_address()| is
+  // |MdnsAddresses::V4Multicast|.
   void SendMessage(DnsMessage* message, const ReplyAddress& reply_address);
 
   // Writes log messages describing lifetime traffic.
@@ -64,6 +66,7 @@
                          std::unique_ptr<MdnsInterfaceTransceiver>>* prev);
 
   fuchsia::netstack::NetstackPtr netstack_;
+  inet::IpPort mdns_port_;
   fit::closure link_change_callback_;
   InboundMessageCallback inbound_message_callback_;
   std::string host_full_name_;
diff --git a/garnet/bin/mdns/service/prober.cc b/garnet/bin/mdns/service/prober.cc
index eaef2ec..ff6498f 100644
--- a/garnet/bin/mdns/service/prober.cc
+++ b/garnet/bin/mdns/service/prober.cc
@@ -4,10 +4,11 @@
 
 #include "garnet/bin/mdns/service/prober.h"
 
+#include <zircon/syscalls.h>
+
 #include "src/lib/fxl/logging.h"
 #include "src/lib/fxl/time/time_delta.h"
 #include "src/lib/fxl/time/time_point.h"
-#include <zircon/syscalls.h>
 
 namespace mdns {
 
@@ -22,8 +23,11 @@
 
 Prober::~Prober() {}
 
-void Prober::Start(const std::string& host_full_name) {
+void Prober::Start(const std::string& host_full_name, inet::IpPort mdns_port) {
   FXL_DCHECK(!host_full_name.empty());
+
+  MdnsAgent::Start(host_full_name, mdns_port);
+
   host_full_name_ = host_full_name;
 
   question_ = std::make_shared<DnsQuestion>(ResourceName(), DnsType::kAny);
@@ -57,8 +61,7 @@
 fxl::TimeDelta Prober::InitialDelay() {
   uint64_t random = 0;
   zx_cprng_draw(&random, sizeof(random));
-  int64_t random_nonnegative_int64 =
-      static_cast<int64_t>(random >> 1);
+  int64_t random_nonnegative_int64 = static_cast<int64_t>(random >> 1);
   FXL_DCHECK(random_nonnegative_int64 >= 0);
   return fxl::TimeDelta::FromNanoseconds(random_nonnegative_int64 %
                                          kMaxProbeInterval.ToNanoseconds());
diff --git a/garnet/bin/mdns/service/prober.h b/garnet/bin/mdns/service/prober.h
index 0209b87..928135b 100644
--- a/garnet/bin/mdns/service/prober.h
+++ b/garnet/bin/mdns/service/prober.h
@@ -5,11 +5,11 @@
 #ifndef GARNET_BIN_MDNS_SERVICE_PROBER_H_
 #define GARNET_BIN_MDNS_SERVICE_PROBER_H_
 
+#include <lib/fit/function.h>
+
 #include <memory>
 #include <string>
 
-#include <lib/fit/function.h>
-
 #include "garnet/bin/mdns/service/mdns_agent.h"
 #include "src/lib/fxl/time/time_delta.h"
 
@@ -42,7 +42,7 @@
   ~Prober() override;
 
   // MdnsAgent overrides.
-  void Start(const std::string& host_full_name) final;
+  void Start(const std::string& host_full_name, inet::IpPort mdns_port) final;
 
   void ReceiveResource(const DnsResource& resource,
                        MdnsResourceSection section) final;
diff --git a/garnet/bin/mdns/service/resource_renewer.cc b/garnet/bin/mdns/service/resource_renewer.cc
index 412cca1..bc19336 100644
--- a/garnet/bin/mdns/service/resource_renewer.cc
+++ b/garnet/bin/mdns/service/resource_renewer.cc
@@ -74,7 +74,8 @@
       std::shared_ptr<DnsResource> resource =
           std::make_shared<DnsResource>(entry->name_, entry->type_);
       resource->time_to_live_ = 0;
-      SendResource(resource, MdnsResourceSection::kExpired);
+      SendResource(resource, MdnsResourceSection::kExpired,
+                   MdnsAddresses::V4MulticastReply(mdns_port()));
       EraseEntry(entry);
     } else {
       // Need to query.
diff --git a/garnet/bin/mdns/service/test/config_test.cc b/garnet/bin/mdns/service/test/config_test.cc
index 2524542..da98384 100644
--- a/garnet/bin/mdns/service/test/config_test.cc
+++ b/garnet/bin/mdns/service/test/config_test.cc
@@ -45,6 +45,7 @@
   under_test.ReadConfigFiles(kHostName, kTestDir);
   EXPECT_TRUE(under_test.valid());
   EXPECT_EQ("", under_test.error());
+  EXPECT_EQ(inet::IpPort::From_uint16_t(5353), under_test.mdns_port());
   EXPECT_TRUE(under_test.perform_host_name_probe());
   EXPECT_TRUE(under_test.publications().empty());
 
@@ -55,6 +56,7 @@
 TEST(ConfigTest, OneValidFile) {
   EXPECT_TRUE(files::CreateDirectory(kTestDir));
   EXPECT_TRUE(WriteFile("valid", R"({
+    "port": 5454,
     "perform_host_name_probe": false,
     "publications" : [
       {"service" : "_fuchsia._udp.", "port" : 5353, "perform_probe" : false,
@@ -66,6 +68,7 @@
   under_test.ReadConfigFiles(kHostName, kTestDir);
   EXPECT_TRUE(under_test.valid());
   EXPECT_EQ("", under_test.error());
+  EXPECT_EQ(inet::IpPort::From_uint16_t(5454), under_test.mdns_port());
   EXPECT_FALSE(under_test.perform_host_name_probe());
   EXPECT_EQ(1u, under_test.publications().size());
   EXPECT_TRUE(
@@ -135,6 +138,7 @@
   under_test.ReadConfigFiles(kHostName, kTestDir);
   EXPECT_TRUE(under_test.valid());
   EXPECT_EQ("", under_test.error());
+  EXPECT_EQ(inet::IpPort::From_uint16_t(5353), under_test.mdns_port());
   EXPECT_FALSE(under_test.perform_host_name_probe());
   EXPECT_EQ(2u, under_test.publications().size());