After an evaluation, GNOME has moved from Bugzilla to GitLab. Learn more about GitLab.
No new issues can be reported in GNOME Bugzilla anymore.
To report an issue in a GNOME project, go to GNOME GitLab.
Do not go to GNOME Gitlab for: Bluefish, Doxygen, GnuCash, GStreamer, java-gnome, LDTP, NetworkManager, Tomboy.
Bug 719851 - [review th/bg719851_keyfile_route_addr_fix] Keyfile plugin writes invalid ipv6 routes
[review th/bg719851_keyfile_route_addr_fix] Keyfile plugin writes invalid ipv...
Status: RESOLVED FIXED
Product: NetworkManager
Classification: Platform
Component: general
git master
Other Linux
: Normal normal
: ---
Assigned To: NetworkManager maintainer(s)
NetworkManager maintainer(s)
Depends on:
Blocks:
 
 
Reported: 2013-12-04 15:39 UTC by Thomas Haller
Modified: 2013-12-09 17:46 UTC
See Also:
GNOME target: ---
GNOME version: ---



Description Thomas Haller 2013-12-04 15:39:11 UTC
Keyfile plugin wrote for me the route:

route2=a:b:c:d::/64,1

which is invalid and cannot be re-read again.
Comment 1 Thomas Haller 2013-12-04 15:42:52 UTC
Please review th/bg719851_keyfile_route_addr_fix



Not that this changes how routes are written, after the patch it would write:

[ip4]
route1=3.4.5.6/26,,1 (a)
[ip6]
route1=6:7:8:9:0:1:2:3/126,,1  (b)


(b) is no problem, because without this patch, current NM would actually write
"route1=6:7:8:9:0:1:2:3/126,1" which is wrong anyway -- although with this patch, such a wrong route could be re-read again.


(a) might be a problem, because if a new NM writes such a route, and older version of NM could not re-read it again. Older NM would write and expect "route1=3.4.5.6/26,0.0.0.0,1" instead.
I think, this is acceptable, because it just means, that newer NM writes a configuration, that older NM does not understand (in a rather unusual case).
Comment 2 Thomas Haller 2013-12-04 15:59:46 UTC
(In reply to comment #1)

> (b) is no problem, because without this patch, current NM would actually write
> "route1=6:7:8:9:0:1:2:3/126,1" which is wrong anyway -- although with this
> patch, such a wrong route could be re-read again.

Actually, if NM would not omit the :: gateway, old NM could actually read
route1=6:7:8:9:0:1:2:3/126,::,1

Don't know, if we care about this(?) Should we always write the gateway, even if it is 0.0.0.0/:: ?
Comment 3 Dan Winship 2013-12-04 16:18:50 UTC
(In reply to comment #1)
> I think, this is acceptable, because it just means, that newer NM writes a
> configuration, that older NM does not understand (in a rather unusual case).

Well, I had to keep switching back to NM 0.9.8 to test things while doing those releases, and it would have been annoying if some of my connections hadn't worked.

But it sounds from your last comment like you've found a fully-compatible way to write things anyway? If so, go with that.
Comment 4 Thomas Haller 2013-12-04 18:53:35 UTC
reworked, rebased to master and repushed.

Now writer will/should always write something, that also old versions can read too.
Comment 5 Dan Williams 2013-12-04 21:26:07 UTC
> keyfile: fix reader and writer for writing routes

in reader.c::build_ip6_address_or_route():

+ if (!metric_str && get_one_int (gateway_str, G_MAXUINT32, NULL, &metric)) {
+     addr = in6addr_any;
+     metric_str = NULL;

can remove the metric_str = NULL there since it was already checked for NULL just above.

Also, it looks like the branch adds then removes the reader testcases for "route3=6:7:8:9:0:1:2:3/126,::,1"; should we add that back in as a valid testcase?  If somebody hand-writes the keyfile, I can see them using that notation and that should probably be valid.

writer.c::write_ip4_values():

I don't think we need the (unsigned long) cast for plen at all?  The prefix will never be > 128, and the 'plen' variable is a 'guint32', so it shouldn't need a long conversion at all.  I think we can go with just "%u" here and no cast.  Same thing for 'metric' too.

Also, instead of "allow_omitting_specified_gateway", perhaps it should be "force_write_gateway"?  That would change the if() in ip6_array_to_addr_prefix() to a clearer:

 if (force_write_gateway || !IN6_IS_ADDR_UNSPECIFIED())

The parameter's intention is to force writing the gateway or to leave it up to IN6_IS_ADDR_UNSPECIFIED(), and I think 'force_write_gateway' is a clearer name here.  At least in my head, when I'm saying to myself what the code is doing when reviewing the patch :)

Good catch BTW.  Thanks!
Comment 6 Pavel Simerda 2013-12-05 10:47:29 UTC
Looks good.

We might additionaly want to switch the comments to use ',' as a separator instead of '/' if ',' is clearly the preferred one.
Comment 7 Pavel Simerda 2013-12-05 10:50:50 UTC
(In reply to comment #5)
> Also, it looks like the branch adds then removes the reader testcases for
> "route3=6:7:8:9:0:1:2:3/126,::,1"; should we add that back in as a valid
> testcase?  If somebody hand-writes the keyfile, I can see them using that
> notation and that should probably be valid.

+1
Comment 8 Pavel Simerda 2013-12-05 10:57:23 UTC
(In reply to comment #7)
> (In reply to comment #5)
> > Also, it looks like the branch adds then removes the reader testcases for
> > "route3=6:7:8:9:0:1:2:3/126,::,1"; should we add that back in as a valid
> > testcase?  If somebody hand-writes the keyfile, I can see them using that
> > notation and that should probably be valid.
> 
> +1

As far as I understand (talking with thomas on IRC), this format actually happens to be the preferred one (:: being optional).
Comment 9 Thomas Haller 2013-12-05 12:21:42 UTC
(In reply to comment #5)

I pushed some !fixup that should address the issues up to now.


> > keyfile: fix reader and writer for writing routes
> 
> in reader.c::build_ip6_address_or_route():
> 
> + if (!metric_str && get_one_int (gateway_str, G_MAXUINT32, NULL, &metric)) {
> +     addr = in6addr_any;
> +     metric_str = NULL;
> 
> can remove the metric_str = NULL there since it was already checked for NULL
> just above.

I don't agree. I even extended the check when to try the workaround. For example, before my last fixup, it would also accept an the address "address1=a:b:c:d::/64,5" (which would be wrong). Without !metric_str it would read "route1=a:b:c:d::/64,4,5" as "route1=a:b:c:d::/64,::,4" instead of failing with error.


> Also, it looks like the branch adds then removes the reader testcases for
> "route3=6:7:8:9:0:1:2:3/126,::,1"; should we add that back in as a valid
> testcase?  If somebody hand-writes the keyfile, I can see them using that
> notation and that should probably be valid.

Commit "keyfile: add test cases for reading route and addresses" adds two tests:
+#route3=6:7:8:9:0:1:2:3/126,,1
+route3=6:7:8:9:0:1:2:3/126,::,1
+route4=7:8:9:0:1:2:3:4/125/::,5
With route3 I would like to test the commented-out syntax, but before the following patch, that syntax is not yes supported. So, at first, route3 and route4 test the very same syntax (because the reader is agnostic to the delimiter). Only after "keyfile: fix reader and writer for writing routes" I uncomment what I really want to test with route3. 


> writer.c::write_ip4_values():
> 
> I don't think we need the (unsigned long) cast for plen at all?  The prefix
> will never be > 128, and the 'plen' variable is a 'guint32', so it shouldn't
> need a long conversion at all.  I think we can go with just "%u" here and no
> cast.  Same thing for 'metric' too.

%u expects an unsigned int and the argument is guint32. C promotes some types (char, short, ...) to int. But still, it depends on the compiler/platform whether guint32 gets really passed over as an unsigned int. With this cast it is always correct. I just changed the format for plen from %lu to %u (you are right, no overflow possible there because plen is <= 128).

> Also, instead of "allow_omitting_specified_gateway", perhaps it should be
> "force_write_gateway"?  That would change the if() in
> ip6_array_to_addr_prefix() to a clearer:
> 
>  if (force_write_gateway || !IN6_IS_ADDR_UNSPECIFIED())
> 
> The parameter's intention is to force writing the gateway or to leave it up to
> IN6_IS_ADDR_UNSPECIFIED(), and I think 'force_write_gateway' is a clearer name
> here.  At least in my head, when I'm saying to myself what the code is doing
> when reviewing the patch :)

Agree, this double negative was confusing.
Comment 10 Thomas Haller 2013-12-05 12:24:02 UTC
(In reply to comment #8)
> (In reply to comment #7)
> > (In reply to comment #5)
> > > Also, it looks like the branch adds then removes the reader testcases for
> > > "route3=6:7:8:9:0:1:2:3/126,::,1"; should we add that back in as a valid
> > > testcase?  If somebody hand-writes the keyfile, I can see them using that
> > > notation and that should probably be valid.
> > 
> > +1
> 
> As far as I understand (talking with thomas on IRC), this format actually
> happens to be the preferred one (:: being optional).

Indeed, "6:7:8:9:0:1:2:3/126,::,1" will be the preferred format. This is already tested by route4. Note that this form gets tested as route4 (route3 is there to test the other form).
Comment 11 Dan Williams 2013-12-05 23:18:59 UTC
(In reply to comment #9)
> (In reply to comment #5)
> 
> I pushed some !fixup that should address the issues up to now.
> 
> 
> > > keyfile: fix reader and writer for writing routes
> > 
> > in reader.c::build_ip6_address_or_route():
> > 
> > + if (!metric_str && get_one_int (gateway_str, G_MAXUINT32, NULL, &metric)) {
> > +     addr = in6addr_any;
> > +     metric_str = NULL;
> > 
> > can remove the metric_str = NULL there since it was already checked for NULL
> > just above.
> 
> I don't agree. I even extended the check when to try the workaround. For
> example, before my last fixup, it would also accept an the address
> "address1=a:b:c:d::/64,5" (which would be wrong). Without !metric_str it would
> read "route1=a:b:c:d::/64,4,5" as "route1=a:b:c:d::/64,::,4" instead of failing
> with error.

I mean make this patch on top:

 if (!metric_str && get_one_int (...)) {
     addr = in6addr_any;
-    metric_str = NULL;

since the if() can only run if metric_str == NULL, there's no point in setting it to NULL inside the if() too.
Comment 12 Dan Williams 2013-12-05 23:23:22 UTC
Rest of the fixups look OK to me.
Comment 13 Thomas Haller 2013-12-06 12:49:57 UTC
(In reply to comment #11)

>  if (!metric_str && get_one_int (...)) {
>      addr = in6addr_any;
> -    metric_str = NULL;

Oh yes! pushed a !fixup.
Comment 14 Dan Williams 2013-12-09 15:44:02 UTC
Looks good to me then.