|
26 | 26 | #include <netlink/attr.h>
|
27 | 27 |
|
28 | 28 | #include <arpa/inet.h>
|
| 29 | +#include <net/route.h> |
29 | 30 | #include <libubox/list.h>
|
30 | 31 |
|
31 | 32 | #include "odhcpd.h"
|
@@ -54,8 +55,15 @@ static struct event_socket rtnl_event = {
|
54 | 55 | .sock_bufsize = 133120,
|
55 | 56 | };
|
56 | 57 |
|
57 |
| -int netlink_init(void) |
| 58 | +static FILE *fp_ipv6_route = NULL; |
| 59 | + |
| 60 | +int netlink_init(bool ipv6) |
58 | 61 | {
|
| 62 | + if (ipv6 && !(fp_ipv6_route = fopen("/proc/net/ipv6_route", "r"))) { |
| 63 | + syslog(LOG_ERR, "fopen(/proc/net/ipv6_route): %m"); |
| 64 | + goto err; |
| 65 | + } |
| 66 | + |
59 | 67 | rtnl_socket = create_socket(NETLINK_ROUTE);
|
60 | 68 | if (!rtnl_socket) {
|
61 | 69 | syslog(LOG_ERR, "Unable to open nl socket: %m");
|
@@ -100,9 +108,67 @@ int netlink_init(void)
|
100 | 108 | rtnl_event.ev.uloop.fd = -1;
|
101 | 109 | }
|
102 | 110 |
|
| 111 | + if (fp_ipv6_route) { |
| 112 | + fclose(fp_ipv6_route); |
| 113 | + fp_ipv6_route = NULL; |
| 114 | + } |
| 115 | + |
103 | 116 | return -1;
|
104 | 117 | }
|
105 | 118 |
|
| 119 | +/* Detect whether a default IPv6 route exists */ |
| 120 | +bool netlink_default_ipv6_route_exists() |
| 121 | +{ |
| 122 | + bool found_default = false; |
| 123 | + char line[512], ifname[16]; |
| 124 | + |
| 125 | + if (!fp_ipv6_route) |
| 126 | + return false; |
| 127 | + rewind(fp_ipv6_route); |
| 128 | + |
| 129 | + while (fgets(line, sizeof(line), fp_ipv6_route)) { |
| 130 | + if (sscanf(line, "00000000000000000000000000000000 00 " |
| 131 | + "%*s %*s %*s %*s %*s %*s %*s %15s", ifname) && |
| 132 | + strcmp(ifname, "lo")) { |
| 133 | + found_default = true; |
| 134 | + break; |
| 135 | + } |
| 136 | + } |
| 137 | + |
| 138 | + return found_default; |
| 139 | +} |
| 140 | + |
| 141 | +/* Find the source prefixes of all IPv6 addresses */ |
| 142 | +static void find_addr6_dprefix(struct odhcpd_ipaddr *n, ssize_t len) |
| 143 | +{ |
| 144 | + struct odhcpd_ipaddr p = { .addr.in6 = IN6ADDR_ANY_INIT, .prefix = 0, |
| 145 | + .dprefix = 0, .preferred = 0, .valid = 0}; |
| 146 | + char line[512]; |
| 147 | + uint32_t rflags; |
| 148 | + |
| 149 | + if (!fp_ipv6_route || len <= 0) |
| 150 | + return; |
| 151 | + rewind(fp_ipv6_route); |
| 152 | + |
| 153 | + while (fgets(line, sizeof(line), fp_ipv6_route)) { |
| 154 | + if (sscanf(line, "%8" SCNx32 "%8" SCNx32 "%*8" SCNx32 "%*8" SCNx32 " %hhx %*s " |
| 155 | + "%*s 00000000000000000000000000000000 %*s %*s %*s %" SCNx32 " lo", |
| 156 | + &p.addr.in6.s6_addr32[0], &p.addr.in6.s6_addr32[1], &p.prefix, &rflags) && |
| 157 | + p.prefix > 0 && (rflags & RTF_NONEXTHOP) && (rflags & RTF_REJECT)) { |
| 158 | + // Find source prefixes by scanning through unreachable-routes |
| 159 | + p.addr.in6.s6_addr32[0] = htonl(p.addr.in6.s6_addr32[0]); |
| 160 | + p.addr.in6.s6_addr32[1] = htonl(p.addr.in6.s6_addr32[1]); |
| 161 | + |
| 162 | + for (ssize_t i = 0; i < len; ++i) { |
| 163 | + if (n[i].prefix <= 64 && n[i].prefix >= p.prefix && |
| 164 | + !odhcpd_bmemcmp(&p.addr.in6, &n[i].addr.in6, p.prefix)) { |
| 165 | + n[i].dprefix = p.prefix; |
| 166 | + break; |
| 167 | + } |
| 168 | + } |
| 169 | + } |
| 170 | + } |
| 171 | +} |
106 | 172 |
|
107 | 173 | int netlink_add_netevent_handler(struct netevent_handler *handler)
|
108 | 174 | {
|
@@ -212,6 +278,20 @@ static void refresh_iface_addr6(int ifindex)
|
212 | 278 | }
|
213 | 279 |
|
214 | 280 | if (change) {
|
| 281 | + /* |
| 282 | + * Remove invalid prefixes that were added back to the interface. |
| 283 | + */ |
| 284 | + for (ssize_t i = 0; i < len; ++i) { |
| 285 | + size_t j = 0; |
| 286 | + while (j < iface->invalid_addr6_len) { |
| 287 | + if (addr[i].prefix <= iface->invalid_addr6[j].prefix && |
| 288 | + odhcpd_bmemcmp(&addr[i].addr.in6, &iface->invalid_addr6[j].addr.in6, iface->invalid_addr6[j].prefix) == 0) |
| 289 | + odhcpd_del_intf_invalid_addr6(iface, j); |
| 290 | + else |
| 291 | + ++j; |
| 292 | + } |
| 293 | + } |
| 294 | + |
215 | 295 | /*
|
216 | 296 | * Keep track on removed prefixes, so we could advertise them as invalid
|
217 | 297 | * for at least a couple of times.
|
@@ -756,6 +836,9 @@ ssize_t netlink_get_interface_addrs(int ifindex, bool v6, struct odhcpd_ipaddr *
|
756 | 836 | addr[i].valid += now;
|
757 | 837 | }
|
758 | 838 |
|
| 839 | + if (v6) |
| 840 | + find_addr6_dprefix(addr, ctxt.ret); |
| 841 | + |
759 | 842 | free:
|
760 | 843 | nlmsg_free(msg);
|
761 | 844 | out:
|
|
0 commit comments