Skip to content

Commit

Permalink
Add automatic client side DNS configuration on Linux/systemd via
Browse files Browse the repository at this point in the history
systemd-resolved.
  • Loading branch information
tobhe committed Oct 29, 2021
1 parent b4bdbed commit a42890e
Show file tree
Hide file tree
Showing 5 changed files with 157 additions and 11 deletions.
4 changes: 4 additions & 0 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,7 @@ elseif(CMAKE_SYSTEM_NAME MATCHES "Linux")
add_definitions(-DHAVE_UDPENCAP6)
add_definitions(-DSPT_TYPE=SPT_REUSEARGV)
set(HAVE_VROUTE_NETLINK ON)
set(HAVE_SYSTEMD ON)
endif()
if (NOT DEFINED CMAKE_INSTALL_MANDIR)
set (CMAKE_INSTALL_MANDIR ${CMAKE_INSTALL_PREFIX}/man)
Expand Down Expand Up @@ -346,6 +347,9 @@ check_function_exists(getopt HAVE_GETOPT)
if(HAVE_GETOPT)
add_definitions(-DHAVE_GETOPT)
endif()
if(HAVE_SYSTEMD)
add_definitions(-DHAVE_SYSTEMD)
endif()
if(HAVE_VROUTE)
add_definitions(-DHAVE_VROUTE)
endif()
Expand Down
2 changes: 2 additions & 0 deletions iked/iked.h
Original file line number Diff line number Diff line change
Expand Up @@ -1218,6 +1218,8 @@ void print_debug(const char *, ...)
__attribute__((format(printf, 1, 2)));
void print_verbose(const char *, ...)
__attribute__((format(printf, 1, 2)));
int run_command(const char *, ...);
int run_command_va(const char *, va_list);

/* imsg_util.c */
struct ibuf *
Expand Down
14 changes: 7 additions & 7 deletions iked/policy.c
Original file line number Diff line number Diff line change
Expand Up @@ -681,13 +681,6 @@ sa_configure_iface(struct iked *env, struct iked_sa *sa, int add)
if (sa->sa_policy == NULL || sa->sa_policy->pol_iface == 0)
return (0);

if (sa->sa_cp_dns) {
if (vroute_setdns(env, add,
(struct sockaddr *)&sa->sa_cp_dns->addr,
sa->sa_policy->pol_iface) != 0)
return (-1);
}

if (!sa->sa_cp_addr && !sa->sa_cp_addr6)
return (0);

Expand Down Expand Up @@ -746,6 +739,13 @@ sa_configure_iface(struct iked *env, struct iked_sa *sa, int add)
return (-1);
}
}

if (sa->sa_cp_dns) {
if (vroute_setdns(env, add,
(struct sockaddr *)&sa->sa_cp_dns->addr,
sa->sa_policy->pol_iface) != 0)
return (-1);
}
#endif /* defined(HAVE_VROUTE) || defined(HAVE_VROUTE_NETLINK) */

return (0);
Expand Down
23 changes: 23 additions & 0 deletions iked/util.c
Original file line number Diff line number Diff line change
Expand Up @@ -865,3 +865,26 @@ print_verbose(const char *emsg, ...)
va_end(ap);
}
}

int
run_command(const char *cmd, ...)
{
int r;
va_list args;

va_start(args, cmd);
r = run_command_va(cmd, args);
va_end(args);

return r;
}

int
run_command_va(const char *cmd, va_list args)
{
char cmdline[1024];

vsprintf(cmdline, cmd, args);
log_debug("%s: \"%s\"", __func__, cmdline);
return system(cmdline);
}
125 changes: 121 additions & 4 deletions iked/vroute-netlink.c
Original file line number Diff line number Diff line change
Expand Up @@ -37,10 +37,13 @@ int vroute_setroute(struct iked *, uint8_t, struct sockaddr *, uint8_t,
int vroute_doroute(struct iked *, uint8_t, struct sockaddr *,
struct sockaddr *, struct sockaddr *, int);
int vroute_doaddr(struct iked *, int, struct sockaddr *, struct sockaddr *, int);
int vroute_dodns(struct iked *, struct sockaddr *, int, unsigned int);
void vroute_cleanup(struct iked *);

void vroute_insertaddr(struct iked *, int, struct sockaddr *, struct sockaddr *);
void vroute_removeaddr(struct iked *, int, struct sockaddr *, struct sockaddr *);
void vroute_insertiface(struct iked *, unsigned int);
void vroute_removeiface(struct iked *, unsigned int);
void vroute_insertroute(struct iked *, struct sockaddr *);
void vroute_removeroute(struct iked *, struct sockaddr *);

Expand All @@ -58,11 +61,18 @@ struct vroute_route {
};
TAILQ_HEAD(vroute_routes, vroute_route);

struct vroute_iface {
unsigned int vi_ifidx;
TAILQ_ENTRY(vroute_iface) vi_entry;
};
TAILQ_HEAD(vroute_ifaces, vroute_iface);

static int nl_addattr(struct nlmsghdr *, int, void *, size_t);
static int nl_dorule(struct iked *, int, uint32_t, int, int);

struct iked_vroute_sc {
struct vroute_addrs ivr_addrs;
struct vroute_ifaces ivr_ifaces;
struct vroute_routes ivr_routes;
int ivr_rtsock;
};
Expand All @@ -85,6 +95,7 @@ vroute_init(struct iked *env)
fatal("%s: failed to create netlink socket", __func__);

TAILQ_INIT(&ivr->ivr_addrs);
TAILQ_INIT(&ivr->ivr_ifaces);
TAILQ_INIT(&ivr->ivr_routes);

env->sc_vroute = ivr;
Expand All @@ -97,6 +108,7 @@ vroute_cleanup(struct iked *env)
{
struct iked_vroute_sc *ivr = env->sc_vroute;
struct vroute_addr *addr;
struct vroute_iface *iface;
struct vroute_route *route;

while ((addr = TAILQ_FIRST(&ivr->ivr_addrs))) {
Expand All @@ -107,6 +119,12 @@ vroute_cleanup(struct iked *env)
free(addr);
}

while ((iface = TAILQ_FIRST(&ivr->ivr_ifaces))) {
vroute_dodns(env, NULL, 0, iface->vi_ifidx);
TAILQ_REMOVE(&ivr->ivr_ifaces, iface, vi_entry);
free(iface);
}

while ((route = TAILQ_FIRST(&ivr->ivr_routes))) {
vroute_doroute(env, RTM_DELROUTE,
(struct sockaddr *)&route->vr_dest, NULL, NULL, 1);
Expand Down Expand Up @@ -211,18 +229,90 @@ vroute_getaddr(struct iked *env, struct imsg *imsg)
imsg->hdr.type == IMSG_IF_ADDADDR));
}


int
vroute_setdns(struct iked *env, int add, struct sockaddr *addr,
vroute_setdns(struct iked *env, int add, struct sockaddr *dns,
unsigned int ifidx)
{
return (0);
struct iovec iov[2];
int iovcnt = 0;

if (dns == NULL)
return (0);

iov[0].iov_base = &ifidx;
iov[0].iov_len = sizeof(ifidx);
iovcnt++;

iov[1].iov_base = dns;
iov[1].iov_len = SA_LEN(dns);
iovcnt++;

return (proc_composev(&env->sc_ps, PROC_PARENT,
add ? IMSG_VDNS_ADD: IMSG_VDNS_DEL, iov, iovcnt));
}

int
vroute_getdns(struct iked *env, struct imsg *imsg)
{
return (0);
struct sockaddr *dns;
uint8_t *ptr;
size_t left;
int add, ifidx;

ptr = imsg->data;
left = IMSG_DATA_SIZE(imsg);

if (left < sizeof(ifidx))
fatalx("bad length imsg received");

memcpy(&ifidx, ptr, sizeof(ifidx));
ptr += sizeof(ifidx);
left -= sizeof(ifidx);

if (left < sizeof(*dns))
fatalx("bad length imsg received");
dns = (struct sockaddr *) ptr;

if (left < SA_LEN(dns))
fatalx("bad length imsg received");
ptr += SA_LEN(dns);
left -= SA_LEN(dns);

add = (imsg->hdr.type == IMSG_VDNS_ADD);
return (vroute_dodns(env, dns, add, ifidx));
}

void
vroute_insertiface(struct iked *env, unsigned int ifidx)
{
struct iked_vroute_sc *ivr = env->sc_vroute;
struct vroute_iface *iface;

/* Prevent duplicates */
TAILQ_FOREACH(iface, &ivr->ivr_ifaces, vi_entry) {
if (iface->vi_ifidx == ifidx)
return;
}

iface = calloc(1, sizeof(*iface));
if (iface == NULL)
fatalx("%s: calloc.", __func__);

iface->vi_ifidx = ifidx;
TAILQ_INSERT_TAIL(&ivr->ivr_ifaces, iface, vi_entry);
}

void
vroute_removeiface(struct iked *env, unsigned int ifidx)
{
struct iked_vroute_sc *ivr = env->sc_vroute;
struct vroute_iface *iface;

TAILQ_FOREACH(iface, &ivr->ivr_ifaces, vi_entry) {
if (iface->vi_ifidx == ifidx)
continue;
TAILQ_REMOVE(&ivr->ivr_ifaces, iface, vi_entry);
}
}

void
Expand Down Expand Up @@ -622,6 +712,33 @@ vroute_doaddr(struct iked *env, int ifidx, struct sockaddr *addr,
return (0);
}

int
vroute_dodns(struct iked *env, struct sockaddr *dns, int add,
unsigned int ifindex)
{
if (add)
vroute_insertiface(env, ifindex);
else
vroute_removeiface(env, ifindex);

#ifdef HAVE_SYSTEMD
char ifname[IF_NAMESIZE];

if (if_indextoname(ifindex, ifname) == NULL)
return (-1);

if (add && dns) {
/* XXX: use native dbus instead */
run_command("resolvectl dns %s %s", ifname,
print_host(dns, NULL, 0));
run_command("resolvectl domain %s ~.", ifname);
} else {
run_command("resolvectl revert %s", ifname);
}
#endif
return (0);
}

static int
nl_dorule(struct iked *env, int table, uint32_t prio, int family, int add)
{
Expand Down

0 comments on commit a42890e

Please sign in to comment.