Discussion:
[systemd-devel] sd-bus example code for SetLinkDNS()
Tilman Baumann
2017-07-19 09:20:53 UTC
Permalink
Hi folks,

I'm trying to teach a vpn software (openfortivpn) how to properly set up
DNS in a systemd-resolve environment.

I'm trying to set up a equivalent to this in C.
busctl call org.freedesktop.resolve1 /org/freedesktop/resolve1
org.freedesktop.resolve1.Manager SetLinkDNS 'ia(iay)' 16 2 2 4 10 10 10
10 2 4 10 10 10 11
[https://gist.github.com/tbaumann/d484efb2e27613654a52dbe11cfe53b8]

I came up with this quick proof of concept code based on the example
code in the sd-bus docu.
Of course it segfaults. No surprise, I have done nothing to hint at the
length of the inner byte array. (ay)

I was unable to find any example code that would give me a hint on how
to pass such more complex data structures into sd_bus_call_method()

int SetLinkDNSv4(sd_bus *bus, int if_index, struct in_addr ns1, struct
in_addr ns2) {
sd_bus_error error = SD_BUS_ERROR_NULL;
sd_bus_message *m = NULL;
int r;
struct dns_address {
int sin_family;
struct in_addr ip_addr;
};
struct dns_address addresses[2];


addresses[0].sin_family = AF_INET;
addresses[0].ip_addr = ns1;
addresses[1].sin_family = AF_INET;
addresses[1].ip_addr = ns2;

r = sd_bus_call_method(bus,
"org.freedesktop.resolve1", /*
service to contact */
"/org/freedesktop/resolve1", /* object
path */
"org.freedesktop.resolve1.Manager", /*
interface name */
"SetLinkDNS", /* method
name */
&error, /* object
to return error in */
&m, /* return
message on success */
"ia(iay)", /* input
signature */
if_index,
2, /* Array
size */
addresses);
}

[Full code:
https://gist.github.com/tbaumann/0f466c984c858767c966458d53483697]

My guess is that I can have it easier if I somehow use
sd_bus_message_append() to assemble the message. But I don't see a clear
path either.

Also, the length of the array can be one or two. So that bit is variable
too.

Thanks for any hints
Tilman Baumann
Tilman Baumann
2017-07-21 12:04:26 UTC
Permalink
Any hint?

I would be happy to just see some similar code that deals with arrays of
complex structures. If I see a example that is similar, I'm sure I can
learn from it.
So if anybody knows of a code example that does that...

Thanks
Post by Tilman Baumann
Hi folks,
I'm trying to teach a vpn software (openfortivpn) how to properly set up
DNS in a systemd-resolve environment.
I'm trying to set up a equivalent to this in C.
busctl call org.freedesktop.resolve1 /org/freedesktop/resolve1
org.freedesktop.resolve1.Manager SetLinkDNS 'ia(iay)' 16 2 2 4 10 10 10
10 2 4 10 10 10 11
[https://gist.github.com/tbaumann/d484efb2e27613654a52dbe11cfe53b8]
I came up with this quick proof of concept code based on the example
code in the sd-bus docu.
Of course it segfaults. No surprise, I have done nothing to hint at the
length of the inner byte array. (ay)
I was unable to find any example code that would give me a hint on how
to pass such more complex data structures into sd_bus_call_method()
int SetLinkDNSv4(sd_bus *bus, int if_index, struct in_addr ns1, struct
in_addr ns2) {
sd_bus_error error = SD_BUS_ERROR_NULL;
sd_bus_message *m = NULL;
int r;
struct dns_address {
int sin_family;
struct in_addr ip_addr;
};
struct dns_address addresses[2];
addresses[0].sin_family = AF_INET;
addresses[0].ip_addr = ns1;
addresses[1].sin_family = AF_INET;
addresses[1].ip_addr = ns2;
r = sd_bus_call_method(bus,
"org.freedesktop.resolve1", /*
service to contact */
"/org/freedesktop/resolve1", /* object
path */
"org.freedesktop.resolve1.Manager", /*
interface name */
"SetLinkDNS", /* method
name */
&error, /* object
to return error in */
&m, /* return
message on success */
"ia(iay)", /* input
signature */
if_index,
2, /* Array
size */
addresses);
}
https://gist.github.com/tbaumann/0f466c984c858767c966458d53483697]
My guess is that I can have it easier if I somehow use
sd_bus_message_append() to assemble the message. But I don't see a clear
path either.
Also, the length of the array can be one or two. So that bit is variable
too.
Thanks for any hints
Tilman Baumann
_______________________________________________
systemd-devel mailing list
https://lists.freedesktop.org/mailman/listinfo/systemd-devel
Lennart Poettering
2017-07-21 12:35:41 UTC
Permalink
Post by Tilman Baumann
Hi folks,
I'm trying to teach a vpn software (openfortivpn) how to properly set up
DNS in a systemd-resolve environment.
I'm trying to set up a equivalent to this in C.
busctl call org.freedesktop.resolve1 /org/freedesktop/resolve1
org.freedesktop.resolve1.Manager SetLinkDNS 'ia(iay)' 16 2 2 4 10 10 10
10 2 4 10 10 10 11
[https://gist.github.com/tbaumann/d484efb2e27613654a52dbe11cfe53b8]
I came up with this quick proof of concept code based on the example
code in the sd-bus docu.
Of course it segfaults. No surprise, I have done nothing to hint at the
length of the inner byte array. (ay)
I was unable to find any example code that would give me a hint on how
to pass such more complex data structures into sd_bus_call_method()
int SetLinkDNSv4(sd_bus *bus, int if_index, struct in_addr ns1, struct
in_addr ns2) {
sd_bus_error error = SD_BUS_ERROR_NULL;
sd_bus_message *m = NULL;
int r;
struct dns_address {
int sin_family;
struct in_addr ip_addr;
};
struct dns_address addresses[2];
addresses[0].sin_family = AF_INET;
addresses[0].ip_addr = ns1;
addresses[1].sin_family = AF_INET;
addresses[1].ip_addr = ns2;
r = sd_bus_call_method(bus,
"org.freedesktop.resolve1", /*
service to contact */
"/org/freedesktop/resolve1", /* object
path */
"org.freedesktop.resolve1.Manager", /*
interface name */
"SetLinkDNS", /* method
name */
&error, /* object
to return error in */
&m, /* return
message on success */
"ia(iay)", /* input
signature */
if_index,
2, /* Array
size */
addresses);
}
https://gist.github.com/tbaumann/0f466c984c858767c966458d53483697]
My guess is that I can have it easier if I somehow use
sd_bus_message_append() to assemble the message. But I don't see a clear
path either.
You have to do something like this:

sd_bus_message_new_method(..., &m);
sd_bus_message_append(m, "i", ifindex);
sd_bus_message_open_container(m, 'a', '(iay)');
for (i = 0; i < n_addresses; i++) {
sd_bus_message_open_container(m, '(', "iay"));
sd_bus_message_append(m, "i", addresses[i].sin_family);
sd_bus_message_append_array(m, 'y', &addresses[i].ip_addr, sizeof(addresses[i].ip_addr));
sd_bus_message_close_container(m);
}
sd_bus_message_close_container(m);
sd_bus_message_send(..., m);
sd_bus_message_unref(m);

(not tested, just written down from the top of my head, and of course,
don't forget to add proper error checking)

Lennart
--
Lennart Poettering, Red Hat
Tilman Baumann
2017-07-21 12:44:59 UTC
Permalink
Post by Lennart Poettering
Post by Tilman Baumann
My guess is that I can have it easier if I somehow use
sd_bus_message_append() to assemble the message. But I don't see a clear
path either.
sd_bus_message_new_method(..., &m);
sd_bus_message_append(m, "i", ifindex);
sd_bus_message_open_container(m, 'a', '(iay)');
for (i = 0; i < n_addresses; i++) {
sd_bus_message_open_container(m, '(', "iay"));
sd_bus_message_append(m, "i", addresses[i].sin_family);
sd_bus_message_append_array(m, 'y', &addresses[i].ip_addr, sizeof(addresses[i].ip_addr));
sd_bus_message_close_container(m);
}
sd_bus_message_close_container(m);
sd_bus_message_send(..., m);
sd_bus_message_unref(m);
(not tested, just written down from the top of my head, and of course,
don't forget to add proper error checking)
Phantastic, thanks Lennart
Tilman Baumann
2017-07-21 15:13:18 UTC
Permalink
Post by Lennart Poettering
Post by Tilman Baumann
My guess is that I can have it easier if I somehow use
sd_bus_message_append() to assemble the message. But I don't see a clear
path either.
sd_bus_message_new_method(..., &m);
sd_bus_message_append(m, "i", ifindex);
sd_bus_message_open_container(m, 'a', '(iay)');
for (i = 0; i < n_addresses; i++) {
sd_bus_message_open_container(m, '(', "iay"));
sd_bus_message_append(m, "i", addresses[i].sin_family);
sd_bus_message_append_array(m, 'y', &addresses[i].ip_addr, sizeof(addresses[i].ip_addr));
sd_bus_message_close_container(m);
}
sd_bus_message_close_container(m);
sd_bus_message_send(..., m);
sd_bus_message_unref(m);
And here the working solution for the permanent record.
r = sd_bus_message_new_method_call(
bus, &m,
"org.freedesktop.resolve1",
"/org/freedesktop/resolve1",
"org.freedesktop.resolve1.Manager",
"SetLinkDNS");
r = sd_bus_message_append(m, "i", if_index);
r = sd_bus_message_open_container(m, 'a', "(iay)");
for (int i = 0; i < addresses_size; i++) {
fprintf(stderr, "server %d\n", i);
r = sd_bus_message_open_container(m, 'r', "iay");
r = sd_bus_message_append(m, "i", addresses[i].sin_family);
r = sd_bus_message_append_array(m, 'y', &addresses[i].ip_addr,
sizeof(addresses[i].ip_addr));
r = sd_bus_message_close_container(m);
}
r = sd_bus_message_close_container(m);
r = sd_bus_call(bus, m, 0, &error, &reply);
Tilman Baumann
2017-07-25 11:29:23 UTC
Permalink
This post might be inappropriate. Click to display it.
Lennart Poettering
2017-07-31 15:53:44 UTC
Permalink
Post by Tilman Baumann
Little follow-up question. What would you say is best practice for a vpn
client?
- Add commandline option --update-systemd-resolved or so
- Autodetect existence of the interface and just do it? (How?)
Just issue the bus commands, and if you get a service not found error back
use the traditional way. If resolved is around it should be used, and
it it isn't then it shouldn't be used... I think making the user
configure resolved usage at two places is just intransparent and makes
things harder for the user.

Lennart
--
Lennart Poettering, Red Hat
Loading...