Discussion:
sd-bus example code for SetLinkDNS()
(too old to reply)
Tilman Baumann
2017-07-19 09:20:53 UTC
Permalink
Raw Message
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
Raw Message
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
Raw Message
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
Raw Message
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
Raw Message
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
Raw Message
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?)
- Always try to do the update but silently ignore if it fails and fall
back to updating resolve.conf instead?

I was going with the commandline option. But I'm beginning to hate it.
Do the right thing if you know what's right rings better with me.

I will have to introduce a option for domain filter (and search domain)
anyway, that stuff will never work out of the box.
The VPN protocol is one of those nasty ppp over ssl jobs. And the only
fields passed down to the client are the nameservers.

Cheers
Tilman
Post by Lennart Poettering
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.
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
2017-07-31 15:53:44 UTC
Permalink
Raw Message
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...