From 18e7be6bf80df6b86965ba93391b205339fc7267 Mon Sep 17 00:00:00 2001 From: Kai Huuhko Date: Sat, 5 Mar 2016 08:20:56 +0200 Subject: [PATCH] Add support for IPv6 --- econnman-bin.in | 212 ++++++++++++++++++++++++++++++++++++++++++++---- 1 file changed, 197 insertions(+), 15 deletions(-) diff --git a/econnman-bin.in b/econnman-bin.in index 2715f1d..4f23acb 100755 --- a/econnman-bin.in +++ b/econnman-bin.in @@ -56,10 +56,10 @@ except: dbus_ml = DBusEcoreMainLoop() bus = dbus.SystemBus(mainloop=dbus_ml) -log = logging.getLogger("econnman") +log = logging.getLogger("econnman-bin") log_handler = logging.StreamHandler() log_formatter = logging.Formatter( - "%(relativeCreated)d %(levelname)s %(name)s: %(message)s" + "%(created)d %(name)s [%(levelname)s]:: %(message)s (@lineno %(lineno)d)" ) log_handler.setFormatter(log_formatter) log.addHandler(log_handler) @@ -347,6 +347,20 @@ class ObjectView(object): sc.callback_changed_add(callback) return sc, items + def add_label_and_segment_control(self, box, options, callback, label): + lb = self.add_label(box, label) + + sc = SegmentControl(box) + sc.size_hint_weight = EXPAND_HORIZ + sc.size_hint_align = FILL_BOTH + items = {} + for o in options: + items[o] = sc.item_add(None, o) + sc.show() + box.pack_end(sc) + sc.callback_changed_add(callback) + return lb, sc, items + def add_frame_and_box(self, box, label): fr = Frame(box) fr.size_hint_weight = EXPAND_HORIZ @@ -925,6 +939,28 @@ class ServiceView(ObjectView): """ bus_interface = "net.connman.Service" + ipv4_fields = (#("Method", "ipv4_method"), + ("Address", "ipv4_address"), + ("Netmask", "ipv4_netmask"), + ("Gateway", "ipv4_gateway"), + ) + ipv6_fields = (#("Method", "ipv6_method"), + ("Address", "ipv6_address"), + ("Prefix Length", "ipv6_prefix_length"), + ("Gateway", "ipv6_gateway"), + #("Privacy", "ipv6_privacy"), + ) + proxy_fields = (("Method", "proxy_method"), + ("URL", "proxy_url"), + ("Servers", "proxy_servers"), + ("Excludes", "proxy_excludes"), + ) + vpn_fields = ( # named Provider in spec + ("Host", "vpn_host"), + ("Domain", "vpn_domain"), + ("Name", "vpn_name"), + ("Type", "vpn_type"), + ) eth_fields = (("Method", "eth_method"), ("Interface", "eth_iface"), ("Address", "eth_addr"), @@ -932,15 +968,6 @@ class ServiceView(ObjectView): ("Speed", "eth_speed"), ("Duplex", "eth_duplex"), ) - vpn_fields = (("Host", "vpn_host"), - ("Domain", "vpn_domain"), - ("Name", "vpn_name"), - ("Type", "vpn_type"), - ) - ipv4_fields = (("Address", "ipv4_address"), - ("Netmask", "ipv4_netmask"), - ("Gateway", "ipv4_gateway"), - ) top_widgets = ( "connect", @@ -959,6 +986,7 @@ class ServiceView(ObjectView): "domains_label", "domains_entry", "ipv4_frame", + "ipv6_frame", "proxy_frame", "ethernet_frame", "vpn_frame", @@ -1033,10 +1061,22 @@ class ServiceView(ObjectView): en.callback_unfocused_add(self._on_ipv4_property_unfocused) setattr(self, attr, en) - # section: IPv6: similar to ipv4? refactor ipv4? - if properties.get("IPv6"): - fr, bx = self.add_frame_and_box(self.box, "IPv6") - lb = self.add_label(bx, "TODO") + # section: IPv6 + self.ipv6_properties = {"IPv6": {}, "IPv6.Configuration": {}} + fr, bx = self.add_frame_and_box(self.box, "IPv6") + self.ipv6_frame = fr + self.ipv6_box = bx + options = ("Automatic", "Manual", "Off") + self.ipv6_method, self.ipv6_method_items = self.add_segment_control( + bx, options, self._on_ipv6_method) + for name, attr in self.ipv6_fields: + lb, en = self.add_label_and_entry(bx, name) + en.callback_activated_add(self._on_ipv6_property_changed) + en.callback_unfocused_add(self._on_ipv6_property_unfocused) + setattr(self, attr, en) + options = ("Disabled", "Enabled", "Prefered") + self.ipv6_privacy_lb, self.ipv6_privacy, self.ipv6_privacy_items = self.add_label_and_segment_control( + bx, options, self._on_ipv6_privacy, "Privacy") # section: Proxy: custom contents for direct, auto and manual # - direct: nothing @@ -1186,6 +1226,11 @@ class ServiceView(ObjectView): self.ipv4_address.disabled = value self.ipv4_netmask.disabled = value self.ipv4_gateway.disabled = value + self.ipv6_method.disabled = value + self.ipv6_address.disabled = value + self.ipv6_prefix_length.disabled = value + self.ipv6_gateway.disabled = value + self.ipv6_privacy.disabled = value self.proxy_method.disabled = value elif name == "Favorite": value = bool(value) @@ -1250,6 +1295,47 @@ class ServiceView(ObjectView): self.ipv4_method_items["Off"].selected = True elif method: log.error("Unknown method: %s", method) + elif name in ("IPv6", "IPv6.Configuration"): + self.ipv6_properties[name] = value + used = self.ipv6_properties["IPv6"] + conf = self.ipv6_properties["IPv6.Configuration"] + + def get_val(name): + v = used.get(name) or conf.get(name) + if not v: + return "" + return str(v) + self.ipv6_address.text = get_val("Address") + self.ipv6_prefix_length.text = get_val("PrefixLength") + self.ipv6_gateway.text = get_val("Gateway") + + method = str(conf.get("Method", "")) + editable = (method == "manual") and (not self.immutable) + self.ipv6_address.editable = editable + self.ipv6_prefix_length.editable = editable + self.ipv6_gateway.editable = editable + # privacy has only meaning if Method is set to "auto" + editable = (method == "auto") and (not self.immutable) + self.ipv6_privacy.disabled = not editable + + if method in ("auto", "fixed", "6to4"): + self.ipv6_method_items["Automatic"].selected = True + elif method == "manual": + self.ipv6_method_items["Manual"].selected = True + elif method == "off": + self.ipv6_method_items["Off"].selected = True + elif method: + log.error("Unknown method: %s", method) + + privacy = str(conf.get("Privacy", "")) + if privacy == "disabled": + self.ipv6_privacy_items["Disabled"].selected = True + elif privacy == "enabled": + self.ipv6_privacy_items["Enabled"].selected = True + elif privacy == "prefered": + self.ipv6_privacy_items["Prefered"].selected = True + elif privacy: + log.error("Unknown privacy: %s", privacy) elif name in ("Proxy", "Proxy.Configuration"): self.proxy_properties[name] = value @@ -1437,6 +1523,102 @@ class ServiceView(ObjectView): self.ipv4_netmask.text = get_val("Netmask") self.ipv4_gateway.text = get_val("Gateway") + def _ipv6_apply(self): + value = self.ipv6_method.item_selected.text + if value == "Automatic": + method = "auto" + elif value == "Manual": + method = "manual" + elif value == "Off": + method = "off" + + def make_variant(s): + return dbus.String(s, variant_level=1) + new = {"Method": make_variant(method)} + if method == "manual": + if self.ipv6_address.text: + new["Address"] = make_variant(self.ipv6_address.text) + if self.ipv6_prefix_length.text: + new["PrefixLength"] = make_variant(self.ipv6_prefix_length.text) + if self.ipv6_gateway.text: + new["Gateway"] = make_variant(self.ipv6_gateway.text) + value = self.ipv6_privacy.item_selected.text + if value: + new["Privacy"] = make_variant(value) + if len(new) == 1: # no properties yet + return + + conf = self.ipv6_properties["IPv6.Configuration"] + changed = [] + for k, v in new.items(): + if conf.get(k) != v: + changed.append(k) + log.debug("Changed IPv6: %s", ", ".join(changed)) + if not changed: + return + + def on_reply(): + log.info("Set IPv6=%s", new) + + def on_error(exc): + log.error("Failed to set IPv6.Configuration=%s: %s", new, exc) + popup_error(self.obj, "Failed to Apply IPv6", + exc.get_dbus_message()) + self.bus_obj.SetProperty( + "IPv6.Configuration", new, + reply_handler=on_reply, error_handler=on_error + ) + + def _on_ipv6_method(self, obj, item): + if item.text == "Automatic": + method = "auto" + elif item.text == "Manual": + method = "manual" + elif item.text == "Off": + method = "off" + conf = self.ipv6_properties["IPv6.Configuration"] + + editable = (method == "manual") and (not self.immutable) + self.ipv6_address.editable = editable + self.ipv6_prefix_length.editable = editable + self.ipv6_gateway.editable = editable + # privacy has only meaning if Method is set to "auto" + editable = (method == "auto") and (not self.immutable) + self.ipv6_privacy.disabled = not editable + + if method == conf["Method"]: + return + self._ipv6_apply() + + def _on_ipv6_privacy(self, obj, item): + if item.text == "Disabled": + privacy = "disabled" + elif item.text == "Enabled": + privacy = "enabled" + elif item.text == "Prefered": + privacy = "prefered" + conf = self.ipv6_properties["IPv6.Configuration"] + if privacy == conf["Privacy"]: + return + self._ipv6_apply() + + def _on_ipv6_property_changed(self, obj): + self._ipv6_apply() + + def _on_ipv6_property_unfocused(self, obj): + used = self.ipv6_properties["IPv6"] + conf = self.ipv6_properties["IPv6.Configuration"] + + def get_val(name): + v = used.get(name) or conf.get(name) + if not v: + return "" + return str(v) + self.ipv6_address.text = get_val("Address") + self.ipv6_prefix_length.text = get_val("PrefixLength") + self.ipv6_gateway.text = get_val("Gateway") + #self.ipv6_privacy.text = get_val("Privacy") + def _on_proxy_method(self, obj, item): if item.text == "Direct": method = "direct"