diff --git a/src/common.c b/src/common.c index 0558ccbe..a3cc83b9 100644 --- a/src/common.c +++ b/src/common.c @@ -38,6 +38,7 @@ #include "common.h" #include "dhcpcd.h" +#include "eloop.h" #include "if-options.h" const char * @@ -214,3 +215,17 @@ is_root_local(void) return -1; #endif } + +uint32_t +lifetime_left(uint32_t lifetime, const struct timespec *acquired, const struct timespec *now) +{ + uint32_t elapsed; + + if (lifetime == INFINITE_LIFETIME) + return lifetime; + + elapsed = (uint32_t)eloop_timespec_diff(now, &acquired, NULL); + if (elapsed > lifetime) + return 0; + return lifetime - elapsed; +} diff --git a/src/common.h b/src/common.h index 97fffa5b..096f6bd4 100644 --- a/src/common.h +++ b/src/common.h @@ -141,6 +141,8 @@ # endif #endif +#define INFINITE_LIFETIME (~0U) + const char *hwaddr_ntoa(const void *, size_t, char *, size_t); size_t hwaddr_aton(uint8_t *, const char *); ssize_t readfile(const char *, void *, size_t); @@ -148,4 +150,5 @@ ssize_t writefile(const char *, mode_t, const void *, size_t); int filemtime(const char *, time_t *); char *get_line(char ** __restrict, ssize_t * __restrict); int is_root_local(void); +uint32_t lifetime_left(uint32_t, const struct timespec *, const struct timespec *); #endif diff --git a/src/if-linux.c b/src/if-linux.c index 5980574b..96bcbbb9 100644 --- a/src/if-linux.c +++ b/src/if-linux.c @@ -752,6 +752,11 @@ if_copyrt(struct dhcpcd_ctx *ctx, struct rt *rt, struct nlmsghdr *nlm) } break; } + case RTA_EXPIRES: + { + rt->rt_expires = *(uint32_t *)RTA_DATA(rta); + break; + } } if (sa != NULL) { @@ -1735,6 +1740,10 @@ if_route(unsigned char cmd, const struct rt *rt) if (!sa_is_loopback(&rt->rt_gateway)) add_attr_32(&nlm.hdr, sizeof(nlm), RTA_OIF, rt->rt_ifp->index); + /* add route lifetime */ + if (rt->rt_expires != 0) + add_attr_32(&nlm.hdr, sizeof(nlm), RTA_EXPIRES, rt->rt_expires); + if (rt->rt_metric != 0) add_attr_32(&nlm.hdr, sizeof(nlm), RTA_PRIORITY, rt->rt_metric); diff --git a/src/ipv6.c b/src/ipv6.c index a4221a8c..5128e524 100644 --- a/src/ipv6.c +++ b/src/ipv6.c @@ -2305,6 +2305,9 @@ inet6_raroutes(rb_tree_t *routes, struct dhcpcd_ctx *ctx) if (ctx->ra_routers == NULL) return 0; + struct timespec now; + clock_gettime(CLOCK_MONOTONIC, &now); + TAILQ_FOREACH(rap, ctx->ra_routers, next) { if (rap->expired) continue; @@ -2325,6 +2328,7 @@ inet6_raroutes(rb_tree_t *routes, struct dhcpcd_ctx *ctx) #ifdef HAVE_ROUTE_PREF rt->rt_pref = ipv6nd_rtpref(rinfo->flags); #endif + rt->rt_expires = lifetime_left(rap->lifetime, &rinfo->acquired, &now); rt_proto_add(routes, rt); } @@ -2339,6 +2343,8 @@ inet6_raroutes(rb_tree_t *routes, struct dhcpcd_ctx *ctx) #ifdef HAVE_ROUTE_PREF rt->rt_pref = ipv6nd_rtpref(rap->flags); #endif + rt->rt_expires = lifetime_left(rap->lifetime, &addr->acquired, &now); + rt_proto_add(routes, rt); } } @@ -2370,6 +2376,8 @@ inet6_raroutes(rb_tree_t *routes, struct dhcpcd_ctx *ctx) #ifdef HAVE_ROUTE_PREF rt->rt_pref = ipv6nd_rtpref(rap->flags); #endif + rt->rt_expires = lifetime_left(rap->lifetime, &rap->acquired, &now); + rt_proto_add(routes, rt); } return 0; diff --git a/src/route.h b/src/route.h index b9b0dfd6..6be2e1ea 100644 --- a/src/route.h +++ b/src/route.h @@ -120,6 +120,7 @@ struct rt { #define RTDF_GATELINK 0x40 /* Gateway is on link */ size_t rt_order; rb_node_t rt_tree; + uint32_t rt_expires; /* current lifetime of route */ }; extern const rb_tree_ops_t rt_compare_list_ops;