#L3PD: bsc#1229286
diff --git a/proxy/proxy/salt-broker/salt-broker b/proxy/proxy/salt-broker/salt-broker
index a014c4d46e3..14238f5d411 100755
--- a/proxy/proxy/salt-broker/salt-broker
+++ b/proxy/proxy/salt-broker/salt-broker
@@ -28,6 +28,7 @@
 '''
 
 # Import python libs
+import ipaddress
 import logging
 import logging.handlers
 import multiprocessing
@@ -40,8 +41,11 @@ import time
 import traceback
 import yaml
 
-# Import RHN libs
-from spacewalk.common.rhnConfig import RHNOptions
+try:
+    # Import RHN libs
+    from spacewalk.common.rhnConfig import RHNOptions
+except ImportError:
+    RHNOptions = None
 
 # Import pyzmq lib
 import zmq
@@ -58,6 +62,18 @@ log = logging.getLogger(__name__)
 log.setLevel(logging.DEBUG)
 
 
+def ip_bracket(addr, strip=False):
+    """
+    Ensure IP addresses are URI-compatible - specifically, add brackets
+    around IPv6 literals if they are not already present.
+    """
+    addr = str(addr)
+    addr = addr.lstrip("[")
+    addr = addr.rstrip("]")
+    addr = ipaddress.ip_address(addr)
+    return ("[{}]" if addr.version == 6 and not strip else "{}").format(addr)
+
+
 class AbstractChannelProxy(multiprocessing.Process):
     """
     Abstract class for ChannelProxy objects
@@ -71,21 +87,20 @@ class AbstractChannelProxy(multiprocessing.Process):
         pass
 
     _BACKEND_SOCKOPTS = (
-        (zmq.TCP_KEEPALIVE, "tcp_keepalive"),
-        (zmq.TCP_KEEPALIVE_IDLE, "tcp_keepalive_idle"),
-        (zmq.TCP_KEEPALIVE_CNT, "tcp_keepalive_cnt"),
-        (zmq.TCP_KEEPALIVE_INTVL, "tcp_keepalive_intvl"),
-        (zmq.CONNECT_TIMEOUT, "connect_timeout"),
-        (zmq.RECONNECT_IVL, "reconnect_ivl"),
-        (zmq.HEARTBEAT_IVL, "heartbeat_ivl"),
-        (zmq.HEARTBEAT_TIMEOUT, "heartbeat_timeout"),
+        ("TCP_KEEPALIVE", "tcp_keepalive"),
+        ("TCP_KEEPALIVE_IDLE", "tcp_keepalive_idle"),
+        ("TCP_KEEPALIVE_CNT", "tcp_keepalive_cnt"),
+        ("TCP_KEEPALIVE_INTVL", "tcp_keepalive_intvl"),
+        ("CONNECT_TIMEOUT", "connect_timeout"),
+        ("RECONNECT_IVL", "reconnect_ivl"),
+        ("HEARTBEAT_IVL", "heartbeat_ivl"),
+        ("HEARTBEAT_TIMEOUT", "heartbeat_timeout"),
     )
     _FRONTEND_SOCKOPTS = ()
 
     def __init__(self, opts):
         self.opts = opts
         self.backend_connected = False
-        self.backend_ever_connected = False
         if "master" not in self.opts:
             raise self.ChannelException(
                 '[{}] No "master" opts is provided'.format(
@@ -112,7 +127,12 @@ class AbstractChannelProxy(multiprocessing.Process):
                 )
             )
             self.backend = context.socket(self._backend_sock_type)
-            self.set_sockopts(self.backend, self._BACKEND_SOCKOPTS)
+            self.set_sockopts(
+                self.backend,
+                self._BACKEND_SOCKOPTS,
+                self.backend_type,
+                self.opts["master_ip"],
+            )
 
             self.reconnect_retries = self.opts["drop_after_retries"]
             if self.reconnect_retries != -1:
@@ -126,6 +146,12 @@ class AbstractChannelProxy(multiprocessing.Process):
 
             if self.opts["wait_for_backend"]:
                 while not self.backend_connected:
+                    if self.backend.closed:
+                        log.warning(
+                            "Backend %s socket was closed while waiting for it. Terminating...",
+                            self.backend_type,
+                        )
+                        return
                     time.sleep(0.5)
 
             log.debug(
@@ -135,12 +161,26 @@ class AbstractChannelProxy(multiprocessing.Process):
             )
 
             self.frontend = context.socket(self._frontend_sock_type)
-            self.set_sockopts(self.frontend, self._FRONTEND_SOCKOPTS)
+            self.set_sockopts(
+                self.frontend,
+                self._FRONTEND_SOCKOPTS,
+                self.frontend_type,
+                self.opts["interface"],
+            )
 
             self.frontend.bind(self._frontend_uri)
 
             # Forward all messages
-            zmq.proxy(self.frontend, self.backend)
+            log.info("Staring ZMQ proxy on %s and %s sockets", self.frontend_type, self.backend_type)
+            try:
+                zmq.proxy(self.frontend, self.backend)
+            except Exception as e:
+                log.error(
+                    "Error while processing proxy with %s and %s sockets. Terminating...",
+                    self.frontend_type,
+                    self.backend_type
+                )
+                return
 
         except zmq.ZMQError as zmq_error:
             if self.reconnect_retries == 0:
@@ -154,13 +194,37 @@ class AbstractChannelProxy(multiprocessing.Process):
             log.error("Exception: %s", exc)
             log.debug("Traceback: %s", traceback.format_exc())
 
-    def set_sockopts(self, socket, sockopts):
-        for opt, opt_src in sockopts:
+    def set_sockopts(self, socket, sockopts, sock_type, addr=None):
+
+        def __set_sock_opt(opt, val, opt_name, sock_type):
+            log.debug(
+                "Setting socket opt %s to %s on %s", opt_name, val, sock_type
+            )
+            socket.setsockopt(opt, val)
+
+        for opt_name, opt_src in sockopts:
+            opt = getattr(zmq, opt_name, None)
+            if opt is None:
+                log.error("Unable to find '%s' socket opt", opt_name)
+                continue
             if opt_src in self.opts:
-                socket.setsockopt(
-                    opt,
-                    self.opts[opt_src],
-                )
+                opt_val = self.opts[opt_src]
+            elif isinstance(opt_src, tuple) and len(opt_src) == 1:
+                opt_val = opt_src[0]
+            else:
+                log.error("Unable to find '%s' value for socket opt", opt_name)
+                continue
+            __set_sock_opt(opt, opt_val, opt_name, sock_type)
+        if (
+            self.opts["ipv6"] is True
+            or (addr is not None and ":" in addr)
+        ) and hasattr(zmq, "IPV4ONLY"):
+            # IPv6 sockets work for both IPv6 and IPv4 addresses
+            __set_sock_opt(zmq.IPV4ONLY, 0, "IPV4ONLY", sock_type)
+        if (
+            addr is not None and ":" in addr
+        ) and hasattr(zmq, "IPV6"):
+            __set_sock_opt(zmq.IPV6, 1, "IPV6", sock_type)
 
     def backend_socket_monitor(self, monitor_socket):
         while monitor_socket.poll():
@@ -172,14 +236,8 @@ class AbstractChannelProxy(multiprocessing.Process):
                 elif mon_evt["event"] == zmq.EVENT_CONNECTED:
                     log.info("{} socket connected".format(self.backend_type))
                     self.backend_connected = True
-                    self.backend_ever_connected = True
                     self.reconnect_retries = self.opts["drop_after_retries"]
                 elif mon_evt["event"] == zmq.EVENT_CONNECT_RETRIED:
-                    if (
-                        not self.backend_ever_connected
-                        and self.opts["wait_for_backend"]
-                    ):
-                        continue
                     if self.reconnect_retries == 0:
                         log.warning(
                             "Closing {} socket due to retry attempts reached!".format(
@@ -213,8 +271,8 @@ class PubChannelProxy(AbstractChannelProxy):
 
     # Prevent stopping publishing messages on XPUB socket. (bsc#1182954)
     _FRONTEND_SOCKOPTS = (
-        (zmq.XPUB_VERBOSE, (1,)),
-        (zmq.XPUB_VERBOSER, (1,)),
+        ("XPUB_VERBOSE", (1,)),
+        ("XPUB_VERBOSER", (1,)),
     )
 
     def __init__(self, opts):
@@ -228,11 +286,11 @@ class PubChannelProxy(AbstractChannelProxy):
         self.frontend_type = "XPUB"
 
         self._backend_uri = "tcp://{}:{}".format(
-            self.opts["master_ip"],
+            ip_bracket(self.opts["master_ip"]),
             self.opts["publish_port"],
         )
         self._frontend_uri = "tcp://{}:{}".format(
-            self.opts["interface"],
+            ip_bracket(self.opts["interface"]),
             self.opts["publish_port"],
         )
 
@@ -256,11 +314,11 @@ class RetChannelProxy(AbstractChannelProxy):
         self.frontend_type = "ROUTER"
 
         self._backend_uri = "tcp://{}:{}".format(
-            self.opts["master_ip"],
+            ip_bracket(self.opts["master_ip"]),
             self.opts["ret_port"],
         )
         self._frontend_uri = "tcp://{}:{}".format(
-            self.opts["interface"],
+            ip_bracket(self.opts["interface"]),
             self.opts["ret_port"],
         )
 
@@ -362,11 +420,12 @@ class SaltBroker(object):
 if __name__ == "__main__":
     # Try to get config from /etc/rhn/rhn.conf
     rhn_parent = None
-    rhn_proxy_conf = RHNOptions(component="proxy")
-    rhn_proxy_conf.parse()
-    if rhn_proxy_conf.get("rhn_parent"):
-        log.debug("Using 'rhn_parent' from /etc/rhn/rhn.conf as 'master'")
-        rhn_parent = rhn_proxy_conf["rhn_parent"]
+    if RHNOptions is not None:
+        rhn_proxy_conf = RHNOptions(component="proxy")
+        rhn_proxy_conf.parse()
+        if rhn_proxy_conf.get("rhn_parent"):
+            log.debug("Using 'rhn_parent' from /etc/rhn/rhn.conf as 'master'")
+            rhn_parent = rhn_proxy_conf["rhn_parent"]
 
     # Check for the config file
     if not os.path.isfile(SALT_BROKER_CONF_FILE):
@@ -377,6 +436,7 @@ if __name__ == "__main__":
         "publish_port": "4505",
         "ret_port": "4506",
         "interface": "0.0.0.0",
+        "ipv6": False,
         "tcp_keepalive": True,
         "tcp_keepalive_idle": 300,
         "tcp_keepalive_cnt": -1,
