{"id":605,"date":"2012-04-01T12:02:02","date_gmt":"2012-04-01T12:02:02","guid":{"rendered":"http:\/\/www.kernelcrash.com\/blog\/?p=605"},"modified":"2012-04-03T05:12:21","modified_gmt":"2012-04-03T05:12:21","slug":"updating-networkmanager-via-the-command-line","status":"publish","type":"post","link":"https:\/\/www.kernelcrash.com\/blog\/updating-networkmanager-via-the-command-line\/2012\/04\/01\/","title":{"rendered":"Updating NetworkManager via the command line"},"content":{"rendered":"<p>NetworkManager is one of those things in the linux world that many SysAdmins hate. It&#8217;s a bit like your mother-in-law; it means well but is really really irritating. On any new system I set up, the first thing I do is get rid of it, and just use the old-school config files way of setting up your networking. As an experienced sysadmin, my mind is always trying to think ahead to &#8216;how is someone going to troubleshoot this some time in the future&#8217;. Config files and ifconfig and route commands are pretty easy and well understood. NetworkManager is something that appears to make things easier but if it doesn&#8217;t quite work the way you want it can be a bucket of pain.<\/p>\n<p>Which leads me to this post. I was helping to set up a Fedora 16 system recently that had already been installed &#8230; and given that NetworkManager is the default, the sysadmin who set it up left it using NetworkManager. The thing is they had left out the DNS nameserver settings and I needed some name resolution. Of course the easy solution is edit \/etc\/resolv.conf and add in a nameserver line and in less than 30 seconds (assuming you have the network connectivity in place) you have name resolution. This is what I did and of course it worked and I was happy.<\/p>\n<p>But then there was a power failure at the site and the server rebooted. It came up OK and the first thing I noticed was that \/etc\/resolv.conf did not have a nameserver entry in it. I knew straight away &#8220;Oh, that&#8217;s NetworkManager overwriting \/etc\/resolv.conf on boot&#8221;. So what to do to fix it? The normal answer is &#8220;Hop on the console, go to whatever Network preferences is called this week and add in the DNS IP to the Wired Connection in NetworkManager&#8221;. Unfortunately I did not have console access to this server. I did have a remote ssh connection so I tried logging in with x forwarding on, checked that I could launch an xterm, and tried running nm-applet .. which just hung and did not launch the GUI. I also sudo&#8217;d to root, made sure all my xauth and DISPLAY was right, checked that I could launch an xterm, then tried nm-applet &#8230; and again &#8216;nothing&#8217;. The thing is I had kind of seem this behaviour before on redhat-ish systems &#8230; and come to the conclusion that &#8220;PolicyKit is evil&#8221;.<\/p>\n<p>So what next? Surely there must be a command line interface to NetworkManager? Nope. The closest thing is nmcli, but it has the great non-feature of not letting you change much. Sure it can give you some great status info, let you enable and disable some stuff, but no-can-do if you want to just update the DNS server.<\/p>\n<p>Some googling later, and I&#8217;m finding some info about using dbus-send to query and control NetworkManager. In the examples below each dbus-send command gives you a little bit more info for typing in the next command (eg. the first one returns \/org\/freedesktop\/NetworkManager\/ActiveConnection\/0 on my system for the list of active connections)<\/p>\n<blockquote>\n<pre>#work out the active connections\r\n dbus-send --system --print-reply --dest=org.freedesktop.NetworkManager \\\r\n\/org\/freedesktop\/NetworkManager org.freedesktop.DBus.Properties.Get \\\r\nstring:org.freedesktop.NetworkManager string:ActiveConnections<\/pre>\n<\/blockquote>\n<blockquote>\n<pre>#get the list of devices\r\n dbus-send --system --print-reply --dest=org.freedesktop.NetworkManager \\\r\n \/org\/freedesktop\/NetworkManager\/ActiveConnection\/0 \\\r\norg.freedesktop.DBus.Properties.Get \\\r\nstring:org.freedesktop.NetworkManager.Connection.Active string:Devices<\/pre>\n<\/blockquote>\n<blockquote>\n<pre>#get the list of IP4Config stuff\r\n dbus-send --system --print-reply --dest=org.freedesktop.NetworkManager \\\r\n\/org\/freedesktop\/NetworkManager\/Devices\/1 \\\r\norg.freedesktop.DBus.Properties.Get \\\r\nstring:org.freedesktop.NetworkManager.Device string:Ip4Config<\/pre>\n<\/blockquote>\n<blockquote>\n<pre># print the nameservers. I knew this was the right command as I\r\n#tried it on a test system that already had a DNS server assigned\r\n dbus-send --system --print-reply --dest=org.freedesktop.NetworkManager \\\r\n\/org\/freedesktop\/NetworkManager\/IP4Config\/0 \\\r\norg.freedesktop.DBus.Properties.Get \\\r\nstring:org.freedesktop.NetworkManager.IP4Config string:Nameservers<\/pre>\n<\/blockquote>\n<p>OK now, so I could drill down to get the nameserver detail. Great. Surely there is some easy way to then set it? After more googling it eventually transpired that the IP4Config stuff I was getting was a read-only dbussy thing. And that there must be some other way to actually &#8216;write&#8217; to the settings. After more sleuthing (and using the GUI tool d-feet), I worked out this command;<\/p>\n<blockquote>\n<pre>dbus-send --system --print-reply --dest=org.freedesktop.NetworkManager \\\r\n\/org\/freedesktop\/NetworkManager\/Settings\/0 \\\r\norg.freedesktop.NetworkManager.Settings.Connection.GetSettings<\/pre>\n<\/blockquote>\n<p>That prints out a heap of stuff including my IP address and DNS info, but its all in UINT32 type format, so an IP address like 192.168.0.100 is shown as;<\/p>\n<blockquote>\n<pre>uint32 1677764800<\/pre>\n<\/blockquote>\n<p>So how did I figure out that &#8216;Settings\/0&#8217; bit? You can get a list of the settings available with;<\/p>\n<blockquote>\n<pre>dbus-send --system --print-reply --dest=org.freedesktop.NetworkManager \\\r\n\/org\/freedesktop\/NetworkManager\/Settings \\\r\n org.freedesktop.NetworkManager.Settings.ListConnections<\/pre>\n<\/blockquote>\n<p>OK, now I thought there must be a way of using dbus-send to update the DNS address. I tried a few different ideas that all failed, and then found some stackoverflow comment indicating in the dbus-send man page how &#8216;D-Bus supports more types than these, but dbus-send currently does not&#8217;. Great.<\/p>\n<p>So then I looked at the\u00a0<a href=\"http:\/\/cgit.freedesktop.org\/NetworkManager\/NetworkManager\/tree\/examples\/python\">python examples that come with NetworkManager.<\/a>\u00a0I&#8217;m not that great at python, but I fudged my way through them. Many of the examples did not run, and \u00a0I suspected that the version of NetworkManager I had was different to the one the examples were aimed at. Anyway, the biggest set of hints was in the update-secrets.py example, and eventually I hacked it and came up with the following python script (change-dns.py &#8230; Note that you might need to tailor this script if your settings is not Settings\/0)<\/p>\n<blockquote>\n<pre>#!\/usr\/bin\/env python\r\nimport dbus\r\nimport sys\r\nimport socket,struct<\/pre>\n<pre>def dottedQuadToNum(ip):\r\n   \"convert decimal dotted quad string to long integer\"\r\n   return struct.unpack('&lt;L',socket.inet_aton(ip))[0]\r\n\r\nif len(sys.argv) != 2:\r\n   sys.exit(\"Must supply ip address for dns; eg. 192.168.0.1\")\r\n\r\nx = dottedQuadToNum(sys.argv[1])\r\nbus = dbus.SystemBus()\r\nproxy = bus.get_object(\"org.freedesktop.NetworkManager\", \"\/org\/freedesktop\/NetworkManager\/Settings\/0\")\r\n\r\nsettings = dbus.Interface(proxy, \"org.freedesktop.NetworkManager.Settings.Connection\")\r\n\r\nconfig = settings.GetSettings()\r\ns_ipv4 = config['ipv4']\r\ns_ipv4['dns'] = dbus.Array([dbus.UInt32(x)], signature=dbus.Signature('u'), variant_level=1)\r\n\r\nsettings.Update(config)<\/pre>\n<\/blockquote>\n<p>So now I could run my script (called change-dns.py) with<\/p>\n<blockquote>\n<pre>.\/change-dns.py 192.168.0.123<\/pre>\n<\/blockquote>\n<p>And then run that GetSettings dbus-send again to check that it changed.<\/p>\n<blockquote>\n<pre>dbus-send --system --print-reply --dest=org.freedesktop.NetworkManager \\\r\n\/org\/freedesktop\/NetworkManager\/Settings\/0 \\\r\norg.freedesktop.NetworkManager.Settings.Connection.GetSettings<\/pre>\n<\/blockquote>\n<p>So yes it did work, but it does not immediately update \/etc\/resolv.conf, so I still manually updated \/etc\/resolv.conf. Checking on a test system, NetworkManager does overwrite \/etc\/resolv.conf with the correct value after you reboot.<\/p>\n<p>What about if you want to set two nameservers and perhaps a default search (eg. &#8216;search local&#8217;). Try changing the end of the script to accept two IP addresses;<\/p>\n<blockquote>\n<pre>if len(sys.argv) != 3:\r\n   sys.exit(\"Must supply two ip addresses for dns; eg. 192.168.0.1 192.168.0.2\")\r\n\r\nx = dottedQuadToNum(sys.argv[1])\r\ny = dottedQuadToNum(sys.argv[2])<\/pre>\n<pre>bus = dbus.SystemBus()\r\nproxy = bus.get_object(\"org.freedesktop.NetworkManager\", \"\/org\/freedesktop\/NetworkManager\/Settings\/0\")\r\n\r\nsettings = dbus.Interface(proxy, \"org.freedesktop.NetworkManager.Settings.Connection\")\r\n\r\nconfig = settings.GetSettings()\r\ns_ipv4 = config['ipv4']<\/pre>\n<pre>s_ipv4['dns'] = dbus.Array([dbus.UInt32(x), dbus.UInt32(y)], signature=dbus.Signature('u'), variant_level=1)\r\ns_ipv4['dns-search'] = dbus.Array([dbus.String(u'local')], signature=dbus.Signature('s'), variant_level=1)<\/pre>\n<pre>settings.Update(config)<\/pre>\n<pre><\/pre>\n<\/blockquote>\n<p>Just a side note in case you are trawling the net trying to figure out how you can change an IP address on the command line using dbus, basically the change-dns.py script just needs the &#8216;s_ipv4[&#8216;dns&#8217;] = dbus.Array&#8230;.&#8217; lines changed to something like;<\/p>\n<p style=\"text-align: left;\">s_ipv4[&#8216;addresses&#8217;] = dbus.Array([dbus.Array([dbus.UInt32(1962977472L), dbus.UInt32(24L), dbus.UInt32(16820416L)], signature=dbus.Signature(&#8216;u&#8217;))], signature=dbus.Signature(&#8216;au&#8217;), variant_level=1)<\/p>\n<p>The tricky part is figuring out the numbers. There are three numbers (all ending in a capital &#8216;L&#8217;). The first is the IP, the 2nd the netmask, the 3rd the default route. In the example above the IP address is 192.168.0.117. I usually use a programmers calculator, convert that to hex; C0A80075, then reverse all the octets; 7500A8C0 and then convert that to decimal; 1962977472 (of course, its much easier if you use the dottedQuadToNum function in the python script)<\/p>\n","protected":false},"excerpt":{"rendered":"<p>NetworkManager is one of those things in the linux world that many SysAdmins hate. It&#8217;s a bit like your mother-in-law; it means well but is really really irritating. On any new system I set up, the first thing I do is get rid of it, and just use the old-school config files way of setting [&hellip;]<\/p>\n","protected":false},"author":2,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[1],"tags":[],"class_list":["post-605","post","type-post","status-publish","format-standard","hentry","category-uncategorized"],"_links":{"self":[{"href":"https:\/\/www.kernelcrash.com\/blog\/wp-json\/wp\/v2\/posts\/605","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/www.kernelcrash.com\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.kernelcrash.com\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.kernelcrash.com\/blog\/wp-json\/wp\/v2\/users\/2"}],"replies":[{"embeddable":true,"href":"https:\/\/www.kernelcrash.com\/blog\/wp-json\/wp\/v2\/comments?post=605"}],"version-history":[{"count":20,"href":"https:\/\/www.kernelcrash.com\/blog\/wp-json\/wp\/v2\/posts\/605\/revisions"}],"predecessor-version":[{"id":625,"href":"https:\/\/www.kernelcrash.com\/blog\/wp-json\/wp\/v2\/posts\/605\/revisions\/625"}],"wp:attachment":[{"href":"https:\/\/www.kernelcrash.com\/blog\/wp-json\/wp\/v2\/media?parent=605"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.kernelcrash.com\/blog\/wp-json\/wp\/v2\/categories?post=605"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.kernelcrash.com\/blog\/wp-json\/wp\/v2\/tags?post=605"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}