dhcpv6-ia.c 46 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708
  1. /**
  2. * Copyright (C) 2013 Steven Barth <steven@midlink.org>
  3. * Copyright (C) 2016 Hans Dedecker <dedeckeh@gmail.com>
  4. *
  5. * This program is free software; you can redistribute it and/or modify
  6. * it under the terms of the GNU General Public License v2 as published by
  7. * the Free Software Foundation.
  8. *
  9. * This program is distributed in the hope that it will be useful,
  10. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  11. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  12. * GNU General Public License for more details.
  13. *
  14. */
  15. #include "odhcpd.h"
  16. #include "dhcpv6.h"
  17. #include "dhcpv4.h"
  18. #include <time.h>
  19. #include <errno.h>
  20. #include <fcntl.h>
  21. #include <stdio.h>
  22. #include <poll.h>
  23. #include <alloca.h>
  24. #include <resolv.h>
  25. #include <limits.h>
  26. #include <stdlib.h>
  27. #include <string.h>
  28. #include <unistd.h>
  29. #include <libgen.h>
  30. #include <stdbool.h>
  31. #include <arpa/inet.h>
  32. #include <sys/timerfd.h>
  33. #include <libubox/md5.h>
  34. #include <libubox/usock.h>
  35. #define ADDR_ENTRY_VALID_IA_ADDR(iface, i, m, addrs) \
  36. ((iface)->dhcpv6_assignall || (i) == (m) || \
  37. (addrs)[(i)].prefix > 64)
  38. static void dhcpv6_netevent_cb(unsigned long event, struct netevent_handler_info *info);
  39. static void apply_lease(struct dhcp_assignment *a, bool add);
  40. static void set_border_assignment_size(struct interface *iface, struct dhcp_assignment *b);
  41. static void handle_addrlist_change(struct netevent_handler_info *info);
  42. static void start_reconf(struct dhcp_assignment *a);
  43. static void stop_reconf(struct dhcp_assignment *a);
  44. static void valid_until_cb(struct uloop_timeout *event);
  45. static struct netevent_handler dhcpv6_netevent_handler = { .cb = dhcpv6_netevent_cb, };
  46. static struct uloop_timeout valid_until_timeout = {.cb = valid_until_cb};
  47. static uint32_t serial = 0;
  48. static uint8_t statemd5[16];
  49. int dhcpv6_ia_init(void)
  50. {
  51. uloop_timeout_set(&valid_until_timeout, 1000);
  52. netlink_add_netevent_handler(&dhcpv6_netevent_handler);
  53. return 0;
  54. }
  55. int dhcpv6_ia_setup_interface(struct interface *iface, bool enable)
  56. {
  57. enable = enable && (iface->dhcpv6 == MODE_SERVER);
  58. if (enable) {
  59. struct dhcp_assignment *border;
  60. if (list_empty(&iface->ia_assignments)) {
  61. border = alloc_assignment(0);
  62. if (!border) {
  63. syslog(LOG_WARNING, "Failed to alloc border on %s", iface->name);
  64. return -1;
  65. }
  66. border->length = 64;
  67. list_add(&border->head, &iface->ia_assignments);
  68. } else
  69. border = list_last_entry(&iface->ia_assignments, struct dhcp_assignment, head);
  70. set_border_assignment_size(iface, border);
  71. } else {
  72. struct dhcp_assignment *c;
  73. while (!list_empty(&iface->ia_assignments)) {
  74. c = list_first_entry(&iface->ia_assignments, struct dhcp_assignment, head);
  75. free_assignment(c);
  76. }
  77. }
  78. return 0;
  79. }
  80. static void dhcpv6_netevent_cb(unsigned long event, struct netevent_handler_info *info)
  81. {
  82. struct interface *iface = info->iface;
  83. if (!iface || iface->dhcpv6 != MODE_SERVER)
  84. return;
  85. switch (event) {
  86. case NETEV_ADDR6LIST_CHANGE:
  87. handle_addrlist_change(info);
  88. break;
  89. default:
  90. break;
  91. }
  92. }
  93. static inline bool valid_prefix_length(const struct dhcp_assignment *a, const uint8_t prefix_length)
  94. {
  95. return (a->managed_size || a->length > prefix_length);
  96. }
  97. static inline bool valid_addr(const struct odhcpd_ipaddr *addr, time_t now)
  98. {
  99. return (addr->prefix <= 96 && addr->preferred_lt > (uint32_t)now);
  100. }
  101. static size_t get_preferred_addr(const struct odhcpd_ipaddr *addrs, const size_t addrlen)
  102. {
  103. size_t i, m;
  104. for (i = 0, m = 0; i < addrlen; ++i) {
  105. if (addrs[i].preferred_lt > addrs[m].preferred_lt ||
  106. (addrs[i].preferred_lt == addrs[m].preferred_lt &&
  107. memcmp(&addrs[i].addr, &addrs[m].addr, 16) > 0))
  108. m = i;
  109. }
  110. return m;
  111. }
  112. static int send_reconf(struct dhcp_assignment *assign)
  113. {
  114. struct {
  115. struct dhcpv6_client_header hdr;
  116. uint16_t srvid_type;
  117. uint16_t srvid_len;
  118. uint16_t duid_type;
  119. uint16_t hardware_type;
  120. uint8_t mac[6];
  121. uint16_t msg_type;
  122. uint16_t msg_len;
  123. uint8_t msg_id;
  124. struct dhcpv6_auth_reconfigure auth;
  125. uint16_t clid_type;
  126. uint16_t clid_len;
  127. uint8_t clid_data[128];
  128. } __attribute__((packed)) reconf_msg = {
  129. .hdr = {DHCPV6_MSG_RECONFIGURE, {0, 0, 0}},
  130. .srvid_type = htons(DHCPV6_OPT_SERVERID),
  131. .srvid_len = htons(10),
  132. .duid_type = htons(3),
  133. .hardware_type = htons(1),
  134. .msg_type = htons(DHCPV6_OPT_RECONF_MSG),
  135. .msg_len = htons(1),
  136. .msg_id = DHCPV6_MSG_RENEW,
  137. .auth = {htons(DHCPV6_OPT_AUTH),
  138. htons(sizeof(reconf_msg.auth) - 4), 3, 1, 0,
  139. {htonl(time(NULL)), htonl(++serial)}, 2, {0}},
  140. .clid_type = htons(DHCPV6_OPT_CLIENTID),
  141. .clid_len = htons(assign->clid_len),
  142. .clid_data = {0},
  143. };
  144. struct interface *iface = assign->iface;
  145. odhcpd_get_mac(iface, reconf_msg.mac);
  146. memcpy(reconf_msg.clid_data, assign->clid_data, assign->clid_len);
  147. struct iovec iov = {&reconf_msg, sizeof(reconf_msg) - 128 + assign->clid_len};
  148. md5_ctx_t md5;
  149. uint8_t secretbytes[64];
  150. memset(secretbytes, 0, sizeof(secretbytes));
  151. memcpy(secretbytes, assign->key, sizeof(assign->key));
  152. for (size_t i = 0; i < sizeof(secretbytes); ++i)
  153. secretbytes[i] ^= 0x36;
  154. md5_begin(&md5);
  155. md5_hash(secretbytes, sizeof(secretbytes), &md5);
  156. md5_hash(iov.iov_base, iov.iov_len, &md5);
  157. md5_end(reconf_msg.auth.key, &md5);
  158. for (size_t i = 0; i < sizeof(secretbytes); ++i) {
  159. secretbytes[i] ^= 0x36;
  160. secretbytes[i] ^= 0x5c;
  161. }
  162. md5_begin(&md5);
  163. md5_hash(secretbytes, sizeof(secretbytes), &md5);
  164. md5_hash(reconf_msg.auth.key, 16, &md5);
  165. md5_end(reconf_msg.auth.key, &md5);
  166. return odhcpd_send(iface->dhcpv6_event.uloop.fd, &assign->peer, &iov, 1, iface);
  167. }
  168. static void dhcpv6_ia_free_assignment(struct dhcp_assignment *a)
  169. {
  170. if (a->managed_sock.fd.registered) {
  171. ustream_free(&a->managed_sock.stream);
  172. close(a->managed_sock.fd.fd);
  173. }
  174. if ((a->flags & OAF_BOUND) && (a->flags & OAF_DHCPV6_PD))
  175. apply_lease(a, false);
  176. if (a->reconf_cnt)
  177. stop_reconf(a);
  178. free(a->managed);
  179. }
  180. void dhcpv6_ia_enum_addrs(struct interface *iface, struct dhcp_assignment *c,
  181. time_t now, dhcpv6_binding_cb_handler_t func, void *arg)
  182. {
  183. struct odhcpd_ipaddr *addrs = (c->managed) ? c->managed : iface->addr6;
  184. size_t addrlen = (c->managed) ? (size_t)c->managed_size : iface->addr6_len;
  185. size_t m = get_preferred_addr(addrs, addrlen);
  186. for (size_t i = 0; i < addrlen; ++i) {
  187. struct in6_addr addr;
  188. uint32_t preferred_lt, valid_lt;
  189. int prefix = c->managed ? addrs[i].prefix : c->length;
  190. if (!valid_addr(&addrs[i], now))
  191. continue;
  192. /* Filter Out Prefixes */
  193. if (ADDR_MATCH_PIO_FILTER(&addrs[i], iface)) {
  194. char addrbuf[INET6_ADDRSTRLEN];
  195. syslog(LOG_INFO, "Address %s filtered out on %s",
  196. inet_ntop(AF_INET6, &addrs[i].addr.in6, addrbuf, sizeof(addrbuf)),
  197. iface->name);
  198. continue;
  199. }
  200. addr = addrs[i].addr.in6;
  201. preferred_lt = addrs[i].preferred_lt;
  202. valid_lt = addrs[i].valid_lt;
  203. if (c->flags & OAF_DHCPV6_NA) {
  204. if (!ADDR_ENTRY_VALID_IA_ADDR(iface, i, m, addrs))
  205. continue;
  206. addr.s6_addr32[2] = htonl(c->assigned_host_id >> 32);
  207. addr.s6_addr32[3] = htonl(c->assigned_host_id & UINT32_MAX);
  208. } else {
  209. if (!valid_prefix_length(c, addrs[i].prefix))
  210. continue;
  211. addr.s6_addr32[1] |= htonl(c->assigned_subnet_id);
  212. addr.s6_addr32[2] = addr.s6_addr32[3] = 0;
  213. }
  214. if (preferred_lt > (uint32_t)c->preferred_until)
  215. preferred_lt = c->preferred_until;
  216. if (preferred_lt > (uint32_t)c->valid_until)
  217. preferred_lt = c->valid_until;
  218. if (preferred_lt != UINT32_MAX)
  219. preferred_lt -= now;
  220. if (valid_lt > (uint32_t)c->valid_until)
  221. valid_lt = c->valid_until;
  222. if (valid_lt != UINT32_MAX)
  223. valid_lt -= now;
  224. func(&addr, prefix, preferred_lt, valid_lt, arg);
  225. }
  226. }
  227. struct write_ctxt {
  228. FILE *fp;
  229. md5_ctx_t md5;
  230. struct dhcp_assignment *c;
  231. struct interface *iface;
  232. char *buf;
  233. int buf_len;
  234. int buf_idx;
  235. };
  236. static void dhcpv6_write_ia_addrhosts(struct in6_addr *addr, int prefix, _unused uint32_t pref_lt,
  237. _unused uint32_t valid_lt, void *arg)
  238. {
  239. struct write_ctxt *ctxt = (struct write_ctxt *)arg;
  240. char ipbuf[INET6_ADDRSTRLEN];
  241. if ((ctxt->c->flags & OAF_DHCPV6_NA) && ctxt->c->hostname &&
  242. !(ctxt->c->flags & OAF_BROKEN_HOSTNAME)) {
  243. inet_ntop(AF_INET6, addr, ipbuf, sizeof(ipbuf) - 1);
  244. fputs(ipbuf, ctxt->fp);
  245. char b[256];
  246. if (dn_expand(ctxt->iface->search, ctxt->iface->search + ctxt->iface->search_len,
  247. ctxt->iface->search, b, sizeof(b)) > 0)
  248. fprintf(ctxt->fp, "\t%s.%s", ctxt->c->hostname, b);
  249. fprintf(ctxt->fp, "\t%s\n", ctxt->c->hostname);
  250. }
  251. }
  252. static void dhcpv6_write_ia_addr(struct in6_addr *addr, int prefix, _unused uint32_t pref_lt,
  253. _unused uint32_t valid_lt, void *arg)
  254. {
  255. struct write_ctxt *ctxt = (struct write_ctxt *)arg;
  256. char ipbuf[INET6_ADDRSTRLEN];
  257. inet_ntop(AF_INET6, addr, ipbuf, sizeof(ipbuf) - 1);
  258. if ((ctxt->c->flags & OAF_DHCPV6_NA) && ctxt->c->hostname &&
  259. !(ctxt->c->flags & OAF_BROKEN_HOSTNAME)) {
  260. fputs(ipbuf, ctxt->fp);
  261. char b[256];
  262. if (dn_expand(ctxt->iface->search, ctxt->iface->search + ctxt->iface->search_len,
  263. ctxt->iface->search, b, sizeof(b)) > 0)
  264. fprintf(ctxt->fp, "\t%s.%s", ctxt->c->hostname, b);
  265. fprintf(ctxt->fp, "\t%s\n", ctxt->c->hostname);
  266. md5_hash(ipbuf, strlen(ipbuf), &ctxt->md5);
  267. md5_hash(ctxt->c->hostname, strlen(ctxt->c->hostname), &ctxt->md5);
  268. }
  269. ctxt->buf_idx += snprintf(ctxt->buf + ctxt->buf_idx,ctxt->buf_len - ctxt->buf_idx,
  270. "%s/%d ", ipbuf, prefix);
  271. }
  272. static void dhcpv6_ia_write_hostsfile(time_t now)
  273. {
  274. struct write_ctxt ctxt;
  275. unsigned hostsfile_strlen = strlen(config.dhcp_hostsfile) + 1;
  276. unsigned tmp_hostsfile_strlen = hostsfile_strlen + 1; /* space for . */
  277. char *tmp_hostsfile = alloca(tmp_hostsfile_strlen);
  278. char *dir_hostsfile;
  279. char *base_hostsfile;
  280. char *pdir_hostsfile;
  281. char *pbase_hostsfile;
  282. int fd, ret;
  283. dir_hostsfile = strndup(config.dhcp_hostsfile, hostsfile_strlen);
  284. base_hostsfile = strndup(config.dhcp_hostsfile, hostsfile_strlen);
  285. pdir_hostsfile = dirname(dir_hostsfile);
  286. pbase_hostsfile = basename(base_hostsfile);
  287. snprintf(tmp_hostsfile, tmp_hostsfile_strlen, "%s/.%s", pdir_hostsfile, pbase_hostsfile);
  288. free(dir_hostsfile);
  289. free(base_hostsfile);
  290. fd = open(tmp_hostsfile, O_CREAT | O_WRONLY | O_CLOEXEC, 0644);
  291. if (fd < 0)
  292. return;
  293. ret = lockf(fd, F_LOCK, 0);
  294. if (ret < 0) {
  295. close(fd);
  296. return;
  297. }
  298. if (ftruncate(fd, 0) < 0) {}
  299. ctxt.fp = fdopen(fd, "w");
  300. if (!ctxt.fp) {
  301. close(fd);
  302. return;
  303. }
  304. avl_for_each_element(&interfaces, ctxt.iface, avl) {
  305. if (ctxt.iface->dhcpv6 != MODE_SERVER &&
  306. ctxt.iface->dhcpv4 != MODE_SERVER)
  307. continue;
  308. if (ctxt.iface->dhcpv6 == MODE_SERVER) {
  309. list_for_each_entry(ctxt.c, &ctxt.iface->ia_assignments, head) {
  310. if (!(ctxt.c->flags & OAF_BOUND) || ctxt.c->managed_size < 0)
  311. continue;
  312. if (INFINITE_VALID(ctxt.c->valid_until) || ctxt.c->valid_until > now)
  313. dhcpv6_ia_enum_addrs(ctxt.iface, ctxt.c, now,
  314. dhcpv6_write_ia_addrhosts, &ctxt);
  315. }
  316. }
  317. if (ctxt.iface->dhcpv4 == MODE_SERVER) {
  318. struct dhcp_assignment *c;
  319. list_for_each_entry(c, &ctxt.iface->dhcpv4_assignments, head) {
  320. if (!(c->flags & OAF_BOUND))
  321. continue;
  322. char ipbuf[INET6_ADDRSTRLEN];
  323. struct in_addr addr = {.s_addr = c->addr};
  324. inet_ntop(AF_INET, &addr, ipbuf, sizeof(ipbuf) - 1);
  325. if (c->hostname && !(c->flags & OAF_BROKEN_HOSTNAME)) {
  326. fputs(ipbuf, ctxt.fp);
  327. char b[256];
  328. if (dn_expand(ctxt.iface->search,
  329. ctxt.iface->search + ctxt.iface->search_len,
  330. ctxt.iface->search, b, sizeof(b)) > 0)
  331. fprintf(ctxt.fp, "\t%s.%s", c->hostname, b);
  332. fprintf(ctxt.fp, "\t%s\n", c->hostname);
  333. }
  334. }
  335. }
  336. }
  337. fclose(ctxt.fp);
  338. rename(tmp_hostsfile, config.dhcp_hostsfile);
  339. }
  340. void dhcpv6_ia_write_statefile(void)
  341. {
  342. struct write_ctxt ctxt;
  343. md5_begin(&ctxt.md5);
  344. if (config.dhcp_statefile) {
  345. unsigned statefile_strlen = strlen(config.dhcp_statefile) + 1;
  346. unsigned tmp_statefile_strlen = statefile_strlen + 1; /* space for . */
  347. char *tmp_statefile = alloca(tmp_statefile_strlen);
  348. char *dir_statefile;
  349. char *base_statefile;
  350. char *pdir_statefile;
  351. char *pbase_statefile;
  352. time_t now = odhcpd_time(), wall_time = time(NULL);
  353. int fd, ret;
  354. char leasebuf[512];
  355. dir_statefile = strndup(config.dhcp_statefile, statefile_strlen);
  356. base_statefile = strndup(config.dhcp_statefile, statefile_strlen);
  357. pdir_statefile = dirname(dir_statefile);
  358. pbase_statefile = basename(base_statefile);
  359. snprintf(tmp_statefile, tmp_statefile_strlen, "%s/.%s", pdir_statefile, pbase_statefile);
  360. free(dir_statefile);
  361. free(base_statefile);
  362. fd = open(tmp_statefile, O_CREAT | O_WRONLY | O_CLOEXEC, 0644);
  363. if (fd < 0)
  364. return;
  365. ret = lockf(fd, F_LOCK, 0);
  366. if (ret < 0) {
  367. close(fd);
  368. return;
  369. }
  370. if (ftruncate(fd, 0) < 0) {}
  371. ctxt.fp = fdopen(fd, "w");
  372. if (!ctxt.fp) {
  373. close(fd);
  374. return;
  375. }
  376. ctxt.buf = leasebuf;
  377. ctxt.buf_len = sizeof(leasebuf);
  378. avl_for_each_element(&interfaces, ctxt.iface, avl) {
  379. if (ctxt.iface->dhcpv6 != MODE_SERVER &&
  380. ctxt.iface->dhcpv4 != MODE_SERVER)
  381. continue;
  382. if (ctxt.iface->dhcpv6 == MODE_SERVER) {
  383. list_for_each_entry(ctxt.c, &ctxt.iface->ia_assignments, head) {
  384. if (!(ctxt.c->flags & OAF_BOUND) || ctxt.c->managed_size < 0)
  385. continue;
  386. char duidbuf[264];
  387. odhcpd_hexlify(duidbuf, ctxt.c->clid_data, ctxt.c->clid_len);
  388. /* iface DUID iaid hostname lifetime assigned_host_id length [addrs...] */
  389. ctxt.buf_idx = snprintf(ctxt.buf, ctxt.buf_len, "# %s %s %x %s%s %"PRId64" ",
  390. ctxt.iface->ifname, duidbuf, ntohl(ctxt.c->iaid),
  391. (ctxt.c->flags & OAF_BROKEN_HOSTNAME) ? "broken\\x20" : "",
  392. (ctxt.c->hostname ? ctxt.c->hostname : "-"),
  393. (ctxt.c->valid_until > now ?
  394. (int64_t)(ctxt.c->valid_until - now + wall_time) :
  395. (INFINITE_VALID(ctxt.c->valid_until) ? -1 : 0)));
  396. if (ctxt.c->flags & OAF_DHCPV6_NA)
  397. ctxt.buf_idx += snprintf(ctxt.buf + ctxt.buf_idx, ctxt.buf_len - ctxt.buf_idx,
  398. "%" PRIx64" %u ", ctxt.c->assigned_host_id, (unsigned)ctxt.c->length);
  399. else
  400. ctxt.buf_idx += snprintf(ctxt.buf + ctxt.buf_idx, ctxt.buf_len - ctxt.buf_idx,
  401. "%" PRIx32" %u ", ctxt.c->assigned_subnet_id, (unsigned)ctxt.c->length);
  402. if (INFINITE_VALID(ctxt.c->valid_until) || ctxt.c->valid_until > now)
  403. dhcpv6_ia_enum_addrs(ctxt.iface, ctxt.c, now,
  404. dhcpv6_write_ia_addr, &ctxt);
  405. ctxt.buf[ctxt.buf_idx - 1] = '\n';
  406. fwrite(ctxt.buf, 1, ctxt.buf_idx, ctxt.fp);
  407. }
  408. }
  409. if (ctxt.iface->dhcpv4 == MODE_SERVER) {
  410. struct dhcp_assignment *c;
  411. list_for_each_entry(c, &ctxt.iface->dhcpv4_assignments, head) {
  412. if (!(c->flags & OAF_BOUND))
  413. continue;
  414. char ipbuf[INET6_ADDRSTRLEN];
  415. char duidbuf[16];
  416. odhcpd_hexlify(duidbuf, c->hwaddr, sizeof(c->hwaddr));
  417. /* iface DUID iaid hostname lifetime assigned length [addrs...] */
  418. ctxt.buf_idx = snprintf(ctxt.buf, ctxt.buf_len, "# %s %s ipv4 %s%s %"PRId64" %x 32 ",
  419. ctxt.iface->ifname, duidbuf,
  420. (c->flags & OAF_BROKEN_HOSTNAME) ? "broken\\x20" : "",
  421. (c->hostname ? c->hostname : "-"),
  422. (c->valid_until > now ?
  423. (int64_t)(c->valid_until - now + wall_time) :
  424. (INFINITE_VALID(c->valid_until) ? -1 : 0)),
  425. ntohl(c->addr));
  426. struct in_addr addr = {.s_addr = c->addr};
  427. inet_ntop(AF_INET, &addr, ipbuf, sizeof(ipbuf) - 1);
  428. if (c->hostname && !(c->flags & OAF_BROKEN_HOSTNAME)) {
  429. fputs(ipbuf, ctxt.fp);
  430. char b[256];
  431. if (dn_expand(ctxt.iface->search,
  432. ctxt.iface->search + ctxt.iface->search_len,
  433. ctxt.iface->search, b, sizeof(b)) > 0)
  434. fprintf(ctxt.fp, "\t%s.%s", c->hostname, b);
  435. fprintf(ctxt.fp, "\t%s\n", c->hostname);
  436. md5_hash(ipbuf, strlen(ipbuf), &ctxt.md5);
  437. md5_hash(c->hostname, strlen(c->hostname), &ctxt.md5);
  438. }
  439. ctxt.buf_idx += snprintf(ctxt.buf + ctxt.buf_idx,
  440. ctxt.buf_len - ctxt.buf_idx,
  441. "%s/32 ", ipbuf);
  442. ctxt.buf[ctxt.buf_idx - 1] = '\n';
  443. fwrite(ctxt.buf, 1, ctxt.buf_idx, ctxt.fp);
  444. }
  445. }
  446. }
  447. fclose(ctxt.fp);
  448. uint8_t newmd5[16];
  449. md5_end(newmd5, &ctxt.md5);
  450. rename(tmp_statefile, config.dhcp_statefile);
  451. if (memcmp(newmd5, statemd5, sizeof(newmd5))) {
  452. memcpy(statemd5, newmd5, sizeof(statemd5));
  453. if (config.dhcp_hostsfile)
  454. dhcpv6_ia_write_hostsfile(now);
  455. if (config.dhcp_cb) {
  456. char *argv[2] = {config.dhcp_cb, NULL};
  457. if (!vfork()) {
  458. execv(argv[0], argv);
  459. _exit(128);
  460. }
  461. }
  462. }
  463. }
  464. }
  465. static void __apply_lease(struct dhcp_assignment *a,
  466. struct odhcpd_ipaddr *addrs, ssize_t addr_len, bool add)
  467. {
  468. if (a->flags & OAF_DHCPV6_NA)
  469. return;
  470. for (ssize_t i = 0; i < addr_len; ++i) {
  471. struct in6_addr prefix;
  472. if (ADDR_MATCH_PIO_FILTER(&addrs[i], a->iface))
  473. continue;
  474. prefix = addrs[i].addr.in6;
  475. prefix.s6_addr32[1] |= htonl(a->assigned_subnet_id);
  476. prefix.s6_addr32[2] = prefix.s6_addr32[3] = 0;
  477. netlink_setup_route(&prefix, (a->managed_size) ? addrs[i].prefix : a->length,
  478. a->iface->ifindex, &a->peer.sin6_addr, 1024, add);
  479. }
  480. }
  481. static void apply_lease(struct dhcp_assignment *a, bool add)
  482. {
  483. struct interface *iface = a->iface;
  484. struct odhcpd_ipaddr *addrs = (a->managed) ? a->managed : iface->addr6;
  485. ssize_t addrlen = (a->managed) ? a->managed_size : (ssize_t)iface->addr6_len;
  486. __apply_lease(a, addrs, addrlen, add);
  487. }
  488. /* Set border assignment size based on the IPv6 address prefixes */
  489. static void set_border_assignment_size(struct interface *iface, struct dhcp_assignment *b)
  490. {
  491. time_t now = odhcpd_time();
  492. int minprefix = -1;
  493. for (size_t i = 0; i < iface->addr6_len; ++i) {
  494. struct odhcpd_ipaddr *addr = &iface->addr6[i];
  495. if (ADDR_MATCH_PIO_FILTER(addr, iface))
  496. continue;
  497. if (addr->preferred_lt > (uint32_t)now &&
  498. addr->prefix < 64 &&
  499. addr->prefix > minprefix)
  500. minprefix = addr->prefix;
  501. }
  502. if (minprefix > 32 && minprefix <= 64)
  503. b->assigned_subnet_id = 1U << (64 - minprefix);
  504. else
  505. b->assigned_subnet_id = 0;
  506. }
  507. /* More data was received from TCP connection */
  508. static void managed_handle_pd_data(struct ustream *s, _unused int bytes_new)
  509. {
  510. struct ustream_fd *fd = container_of(s, struct ustream_fd, stream);
  511. struct dhcp_assignment *c = container_of(fd, struct dhcp_assignment, managed_sock);
  512. time_t now = odhcpd_time();
  513. bool first = c->managed_size < 0;
  514. for (;;) {
  515. int pending;
  516. char *data = ustream_get_read_buf(s, &pending);
  517. char *end = memmem(data, pending, "\n\n", 2);
  518. if (!end)
  519. break;
  520. end += 2;
  521. end[-1] = 0;
  522. c->managed_size = 0;
  523. if (c->accept_reconf)
  524. c->reconf_cnt = 1;
  525. char *saveptr;
  526. for (char *line = strtok_r(data, "\n", &saveptr); line; line = strtok_r(NULL, "\n", &saveptr)) {
  527. c->managed = realloc(c->managed, (c->managed_size + 1) * sizeof(*c->managed));
  528. struct odhcpd_ipaddr *n = &c->managed[c->managed_size];
  529. char *saveptr2, *x = strtok_r(line, "/", &saveptr2);
  530. if (!x || inet_pton(AF_INET6, x, &n->addr) < 1)
  531. continue;
  532. x = strtok_r(NULL, ",", &saveptr2);
  533. if (sscanf(x, "%hhu", &n->prefix) < 1)
  534. continue;
  535. x = strtok_r(NULL, ",", &saveptr2);
  536. if (sscanf(x, "%u", &n->preferred_lt) < 1)
  537. continue;
  538. x = strtok_r(NULL, ",", &saveptr2);
  539. if (sscanf(x, "%u", &n->valid_lt) < 1)
  540. continue;
  541. if (n->preferred_lt > n->valid_lt)
  542. continue;
  543. if (UINT32_MAX - now < n->preferred_lt)
  544. n->preferred_lt = UINT32_MAX;
  545. else
  546. n->preferred_lt += now;
  547. if (UINT32_MAX - now < n->valid_lt)
  548. n->valid_lt = UINT32_MAX;
  549. else
  550. n->valid_lt += now;
  551. n->dprefix = 0;
  552. ++c->managed_size;
  553. }
  554. ustream_consume(s, end - data);
  555. }
  556. if (first && c->managed_size == 0)
  557. free_assignment(c);
  558. else if (first)
  559. c->valid_until = now + 150;
  560. }
  561. /* TCP transmission has ended, either because of success or timeout or other error */
  562. static void managed_handle_pd_done(struct ustream *s)
  563. {
  564. struct ustream_fd *fd = container_of(s, struct ustream_fd, stream);
  565. struct dhcp_assignment *c = container_of(fd, struct dhcp_assignment, managed_sock);
  566. c->valid_until = odhcpd_time() + 15;
  567. c->managed_size = 0;
  568. if (c->accept_reconf)
  569. c->reconf_cnt = 1;
  570. }
  571. static bool assign_pd(struct interface *iface, struct dhcp_assignment *assign)
  572. {
  573. struct dhcp_assignment *c;
  574. if (iface->dhcpv6_pd_manager[0]) {
  575. int fd = usock(USOCK_UNIX | USOCK_TCP, iface->dhcpv6_pd_manager, NULL);
  576. if (fd >= 0) {
  577. struct pollfd pfd = { .fd = fd, .events = POLLIN };
  578. char iaidbuf[298];
  579. odhcpd_hexlify(iaidbuf, assign->clid_data, assign->clid_len);
  580. assign->managed_sock.stream.notify_read = managed_handle_pd_data;
  581. assign->managed_sock.stream.notify_state = managed_handle_pd_done;
  582. ustream_fd_init(&assign->managed_sock, fd);
  583. ustream_printf(&assign->managed_sock.stream, "%s,%x\n::/%d,0,0\n\n",
  584. iaidbuf, assign->iaid, assign->length);
  585. ustream_write_pending(&assign->managed_sock.stream);
  586. assign->managed_size = -1;
  587. assign->valid_until = odhcpd_time() + 15;
  588. list_add(&assign->head, &iface->ia_assignments);
  589. /* Wait initial period of up to 250ms for immediate assignment */
  590. if (poll(&pfd, 1, 250) < 0) {
  591. syslog(LOG_ERR, "poll(): %m");
  592. return false;
  593. }
  594. managed_handle_pd_data(&assign->managed_sock.stream, 0);
  595. if (fcntl(fd, F_GETFL) >= 0 && assign->managed_size > 0)
  596. return true;
  597. }
  598. return false;
  599. } else if (iface->addr6_len < 1)
  600. return false;
  601. /* Try honoring the hint first */
  602. uint32_t current = 1, asize = (1 << (64 - assign->length)) - 1;
  603. if (assign->assigned_subnet_id) {
  604. list_for_each_entry(c, &iface->ia_assignments, head) {
  605. if (c->flags & OAF_DHCPV6_NA)
  606. continue;
  607. if (assign->assigned_subnet_id >= current && assign->assigned_subnet_id + asize < c->assigned_subnet_id) {
  608. list_add_tail(&assign->head, &c->head);
  609. if (assign->flags & OAF_BOUND)
  610. apply_lease(assign, true);
  611. return true;
  612. }
  613. current = (c->assigned_subnet_id + (1 << (64 - c->length)));
  614. }
  615. }
  616. /* Fallback to a variable assignment */
  617. current = 1;
  618. list_for_each_entry(c, &iface->ia_assignments, head) {
  619. if (c->flags & OAF_DHCPV6_NA)
  620. continue;
  621. current = (current + asize) & (~asize);
  622. if (current + asize < c->assigned_subnet_id) {
  623. assign->assigned_subnet_id = current;
  624. list_add_tail(&assign->head, &c->head);
  625. if (assign->flags & OAF_BOUND)
  626. apply_lease(assign, true);
  627. return true;
  628. }
  629. current = (c->assigned_subnet_id + (1 << (64 - c->length)));
  630. }
  631. return false;
  632. }
  633. /* Check iid against reserved IPv6 interface identifiers.
  634. Refer to:
  635. http://www.iana.org/assignments/ipv6-interface-ids */
  636. static bool is_reserved_ipv6_iid(uint64_t iid)
  637. {
  638. if (iid == 0x0000000000000000)
  639. /* Subnet-Router Anycast [RFC4291] */
  640. return true;
  641. if ((iid & 0xFFFFFFFFFF000000) == 0x02005EFFFE000000)
  642. /* Reserved IPv6 Interface Identifiers corresponding
  643. to the IANA Ethernet Block [RFC4291] */
  644. return true;
  645. if ((iid & 0xFFFFFFFFFFFFFF80) == 0xFDFFFFFFFFFFFF80)
  646. /* Reserved Subnet Anycast Addresses [RFC2526] */
  647. return true;
  648. return false;
  649. }
  650. static bool assign_na(struct interface *iface, struct dhcp_assignment *a)
  651. {
  652. struct dhcp_assignment *c;
  653. uint32_t seed = 0;
  654. /* Preconfigured assignment by static lease */
  655. if (a->assigned_host_id) {
  656. list_for_each_entry(c, &iface->ia_assignments, head) {
  657. if (!(c->flags & OAF_DHCPV6_NA) || c->assigned_host_id > a->assigned_host_id ) {
  658. list_add_tail(&a->head, &c->head);
  659. return true;
  660. } else if (c->assigned_host_id == a->assigned_host_id)
  661. return false;
  662. }
  663. }
  664. /* Seed RNG with checksum of DUID */
  665. for (size_t i = 0; i < a->clid_len; ++i)
  666. seed += a->clid_data[i];
  667. srandom(seed);
  668. /* Try to assign up to 100x */
  669. for (size_t i = 0; i < 100; ++i) {
  670. uint64_t try;
  671. if (iface->dhcpv6_hostid_len > 32) {
  672. uint32_t mask_high;
  673. if (iface->dhcpv6_hostid_len >= 64)
  674. mask_high = UINT32_MAX;
  675. else
  676. mask_high = (1 << (iface->dhcpv6_hostid_len - 32)) - 1;
  677. do {
  678. try = (uint32_t)random();
  679. try |= (uint64_t)((uint32_t)random() & mask_high) << 32;
  680. } while (try < 0x100);
  681. } else {
  682. uint32_t mask_low;
  683. if (iface->dhcpv6_hostid_len == 32)
  684. mask_low = UINT32_MAX;
  685. else
  686. mask_low = (1 << iface->dhcpv6_hostid_len) - 1;
  687. do try = ((uint32_t)random()) & mask_low; while (try < 0x100);
  688. }
  689. if (is_reserved_ipv6_iid(try))
  690. continue;
  691. if (config_find_lease_by_hostid(try))
  692. continue;
  693. list_for_each_entry(c, &iface->ia_assignments, head) {
  694. if (!(c->flags & OAF_DHCPV6_NA) || c->assigned_host_id > try) {
  695. a->assigned_host_id = try;
  696. list_add_tail(&a->head, &c->head);
  697. return true;
  698. } else if (c->assigned_host_id == try)
  699. break;
  700. }
  701. }
  702. return false;
  703. }
  704. static void handle_addrlist_change(struct netevent_handler_info *info)
  705. {
  706. struct interface *iface = info->iface;
  707. struct dhcp_assignment *c, *d, *border = list_last_entry(
  708. &iface->ia_assignments, struct dhcp_assignment, head);
  709. struct list_head reassign = LIST_HEAD_INIT(reassign);
  710. time_t now = odhcpd_time();
  711. list_for_each_entry(c, &iface->ia_assignments, head) {
  712. if ((c->flags & OAF_DHCPV6_PD) && !(iface->ra_flags & ND_RA_FLAG_MANAGED)
  713. && (c->flags & OAF_BOUND))
  714. __apply_lease(c, info->addrs_old.addrs,
  715. info->addrs_old.len, false);
  716. }
  717. set_border_assignment_size(iface, border);
  718. list_for_each_entry_safe(c, d, &iface->ia_assignments, head) {
  719. if (c->clid_len == 0 ||
  720. !(c->flags & OAF_DHCPV6_PD) ||
  721. (!INFINITE_VALID(c->valid_until) && c->valid_until < now) ||
  722. c->managed_size)
  723. continue;
  724. if (c->assigned_subnet_id >= border->assigned_subnet_id)
  725. list_move(&c->head, &reassign);
  726. else if (c->flags & OAF_BOUND)
  727. apply_lease(c, true);
  728. if (c->accept_reconf && c->reconf_cnt == 0) {
  729. struct dhcp_assignment *a;
  730. start_reconf(c);
  731. /* Leave all other assignments of that client alone */
  732. list_for_each_entry(a, &iface->ia_assignments, head)
  733. if (a != c && a->clid_len == c->clid_len &&
  734. !memcmp(a->clid_data, c->clid_data, a->clid_len))
  735. a->reconf_cnt = INT_MAX;
  736. }
  737. }
  738. while (!list_empty(&reassign)) {
  739. c = list_first_entry(&reassign, struct dhcp_assignment, head);
  740. list_del_init(&c->head);
  741. if (!assign_pd(iface, c))
  742. free_assignment(c);
  743. }
  744. dhcpv6_ia_write_statefile();
  745. }
  746. static void reconf_timeout_cb(struct uloop_timeout *event)
  747. {
  748. struct dhcp_assignment *a = container_of(event, struct dhcp_assignment, reconf_timer);
  749. if (a->reconf_cnt > 0 && a->reconf_cnt < DHCPV6_REC_MAX_RC) {
  750. send_reconf(a);
  751. uloop_timeout_set(&a->reconf_timer,
  752. DHCPV6_REC_TIMEOUT << a->reconf_cnt);
  753. a->reconf_cnt++;
  754. } else
  755. stop_reconf(a);
  756. }
  757. static void start_reconf(struct dhcp_assignment *a)
  758. {
  759. uloop_timeout_set(&a->reconf_timer,
  760. DHCPV6_REC_TIMEOUT << a->reconf_cnt);
  761. a->reconf_timer.cb = reconf_timeout_cb;
  762. a->reconf_cnt++;
  763. send_reconf(a);
  764. }
  765. static void stop_reconf(struct dhcp_assignment *a)
  766. {
  767. uloop_timeout_cancel(&a->reconf_timer);
  768. a->reconf_cnt = 0;
  769. a->reconf_timer.cb = NULL;
  770. }
  771. static void valid_until_cb(struct uloop_timeout *event)
  772. {
  773. struct interface *iface;
  774. time_t now = odhcpd_time();
  775. avl_for_each_element(&interfaces, iface, avl) {
  776. struct dhcp_assignment *a, *n;
  777. if (iface->dhcpv6 != MODE_SERVER)
  778. continue;
  779. list_for_each_entry_safe(a, n, &iface->ia_assignments, head) {
  780. if (a->clid_len > 0 && !INFINITE_VALID(a->valid_until) && a->valid_until < now)
  781. free_assignment(a);
  782. }
  783. }
  784. uloop_timeout_set(event, 1000);
  785. }
  786. static size_t build_ia(uint8_t *buf, size_t buflen, uint16_t status,
  787. const struct dhcpv6_ia_hdr *ia, struct dhcp_assignment *a,
  788. struct interface *iface, bool request)
  789. {
  790. struct dhcpv6_ia_hdr o_ia = {
  791. .type = ia->type,
  792. .len = 0,
  793. .iaid = ia->iaid,
  794. .t1 = 0,
  795. .t2 = 0,
  796. };
  797. size_t ia_len = sizeof(o_ia);
  798. time_t now = odhcpd_time();
  799. if (buflen < ia_len)
  800. return 0;
  801. if (status) {
  802. struct __attribute__((packed)) {
  803. uint16_t type;
  804. uint16_t len;
  805. uint16_t val;
  806. } o_status = {
  807. .type = htons(DHCPV6_OPT_STATUS),
  808. .len = htons(sizeof(o_status) - 4),
  809. .val = htons(status),
  810. };
  811. memcpy(buf + ia_len, &o_status, sizeof(o_status));
  812. ia_len += sizeof(o_status);
  813. o_ia.len = htons(ia_len - 4);
  814. memcpy(buf, &o_ia, sizeof(o_ia));
  815. return ia_len;
  816. }
  817. if (a) {
  818. uint32_t leasetime, preferred_lt;
  819. if (a->leasetime) {
  820. leasetime = a->leasetime;
  821. preferred_lt = a->leasetime;
  822. } else {
  823. leasetime = iface->dhcp_leasetime;
  824. preferred_lt = iface->preferred_lifetime;
  825. }
  826. uint32_t valid_lt = leasetime;
  827. struct odhcpd_ipaddr *addrs = (a->managed) ? a->managed : iface->addr6;
  828. size_t addrlen = (a->managed) ? (size_t)a->managed_size : iface->addr6_len;
  829. size_t m = get_preferred_addr(addrs, addrlen);
  830. for (size_t i = 0; i < addrlen; ++i) {
  831. uint32_t prefix_preferred_lt, prefix_valid_lt;
  832. if (!valid_addr(&addrs[i], now))
  833. continue;
  834. /* Filter Out Prefixes */
  835. if (ADDR_MATCH_PIO_FILTER(&addrs[i], iface)) {
  836. char addrbuf[INET6_ADDRSTRLEN];
  837. syslog(LOG_INFO, "Address %s filtered out on %s",
  838. inet_ntop(AF_INET6, &addrs[i].addr.in6, addrbuf, sizeof(addrbuf)),
  839. iface->name);
  840. continue;
  841. }
  842. prefix_preferred_lt = addrs[i].preferred_lt;
  843. prefix_valid_lt = addrs[i].valid_lt;
  844. if (prefix_preferred_lt != UINT32_MAX)
  845. prefix_preferred_lt -= now;
  846. if (prefix_preferred_lt > preferred_lt)
  847. prefix_preferred_lt = preferred_lt;
  848. if (prefix_valid_lt != UINT32_MAX)
  849. prefix_valid_lt -= now;
  850. if (prefix_valid_lt > leasetime)
  851. prefix_valid_lt = leasetime;
  852. if (prefix_preferred_lt > prefix_valid_lt)
  853. prefix_preferred_lt = prefix_valid_lt;
  854. if (a->flags & OAF_DHCPV6_PD) {
  855. struct dhcpv6_ia_prefix o_ia_p = {
  856. .type = htons(DHCPV6_OPT_IA_PREFIX),
  857. .len = htons(sizeof(o_ia_p) - 4),
  858. .preferred_lt = htonl(prefix_preferred_lt),
  859. .valid_lt = htonl(prefix_valid_lt),
  860. .prefix = (a->managed_size) ? addrs[i].prefix : a->length,
  861. .addr = addrs[i].addr.in6,
  862. };
  863. o_ia_p.addr.s6_addr32[1] |= htonl(a->assigned_subnet_id);
  864. o_ia_p.addr.s6_addr32[2] = o_ia_p.addr.s6_addr32[3] = 0;
  865. if (!valid_prefix_length(a, addrs[i].prefix))
  866. continue;
  867. if (buflen < ia_len + sizeof(o_ia_p))
  868. return 0;
  869. memcpy(buf + ia_len, &o_ia_p, sizeof(o_ia_p));
  870. ia_len += sizeof(o_ia_p);
  871. }
  872. if (a->flags & OAF_DHCPV6_NA) {
  873. struct dhcpv6_ia_addr o_ia_a = {
  874. .type = htons(DHCPV6_OPT_IA_ADDR),
  875. .len = htons(sizeof(o_ia_a) - 4),
  876. .addr = addrs[i].addr.in6,
  877. .preferred_lt = htonl(prefix_preferred_lt),
  878. .valid_lt = htonl(prefix_valid_lt)
  879. };
  880. o_ia_a.addr.s6_addr32[2] = htonl(a->assigned_host_id >> 32);
  881. o_ia_a.addr.s6_addr32[3] = htonl(a->assigned_host_id & UINT32_MAX);
  882. if (!ADDR_ENTRY_VALID_IA_ADDR(iface, i, m, addrs))
  883. continue;
  884. if (buflen < ia_len + sizeof(o_ia_a))
  885. return 0;
  886. memcpy(buf + ia_len, &o_ia_a, sizeof(o_ia_a));
  887. ia_len += sizeof(o_ia_a);
  888. }
  889. /* Calculate T1 / T2 based on non-deprecated addresses */
  890. if (prefix_preferred_lt > 0) {
  891. if (prefix_preferred_lt < preferred_lt)
  892. preferred_lt = prefix_preferred_lt;
  893. if (prefix_valid_lt < valid_lt)
  894. valid_lt = prefix_valid_lt;
  895. }
  896. }
  897. if (!INFINITE_VALID(a->valid_until))
  898. /* UINT32_MAX is RFC defined as infinite lease-time */
  899. a->valid_until = (valid_lt == UINT32_MAX) ? 0 : valid_lt + now;
  900. if (!INFINITE_VALID(a->preferred_until))
  901. /* UINT32_MAX is RFC defined as infinite lease-time */
  902. a->preferred_until = (preferred_lt == UINT32_MAX) ? 0 : preferred_lt + now;
  903. o_ia.t1 = htonl((preferred_lt == UINT32_MAX) ? preferred_lt : preferred_lt * 5 / 10);
  904. o_ia.t2 = htonl((preferred_lt == UINT32_MAX) ? preferred_lt : preferred_lt * 8 / 10);
  905. if (!o_ia.t1)
  906. o_ia.t1 = htonl(1);
  907. if (!o_ia.t2)
  908. o_ia.t2 = htonl(1);
  909. }
  910. if (!request) {
  911. uint8_t *odata, *end = ((uint8_t*)ia) + htons(ia->len) + 4;
  912. uint16_t otype, olen;
  913. dhcpv6_for_each_option((uint8_t*)&ia[1], end, otype, olen, odata) {
  914. struct dhcpv6_ia_prefix *ia_p = (struct dhcpv6_ia_prefix *)&odata[-4];
  915. struct dhcpv6_ia_addr *ia_a = (struct dhcpv6_ia_addr *)&odata[-4];
  916. bool found = false;
  917. if ((otype != DHCPV6_OPT_IA_PREFIX || olen < sizeof(*ia_p) - 4) &&
  918. (otype != DHCPV6_OPT_IA_ADDR || olen < sizeof(*ia_a) - 4))
  919. continue;
  920. if (a) {
  921. struct odhcpd_ipaddr *addrs = (a->managed) ? a->managed : iface->addr6;
  922. size_t addrlen = (a->managed) ? (size_t)a->managed_size : iface->addr6_len;
  923. for (size_t i = 0; i < addrlen; ++i) {
  924. struct in6_addr addr;
  925. if (!valid_addr(&addrs[i], now))
  926. continue;
  927. if (!valid_prefix_length(a, addrs[i].prefix))
  928. continue;
  929. if (ADDR_MATCH_PIO_FILTER(&addrs[i], iface))
  930. continue;
  931. addr = addrs[i].addr.in6;
  932. if (ia->type == htons(DHCPV6_OPT_IA_PD)) {
  933. addr.s6_addr32[1] |= htonl(a->assigned_subnet_id);
  934. addr.s6_addr32[2] = addr.s6_addr32[3] = 0;
  935. if (!memcmp(&ia_p->addr, &addr, sizeof(addr)) &&
  936. ia_p->prefix == ((a->managed) ? addrs[i].prefix : a->length))
  937. found = true;
  938. } else {
  939. addr.s6_addr32[2] = htonl(a->assigned_host_id >> 32);
  940. addr.s6_addr32[3] = htonl(a->assigned_host_id & UINT32_MAX);
  941. if (!memcmp(&ia_a->addr, &addr, sizeof(addr)))
  942. found = true;
  943. }
  944. }
  945. }
  946. if (!found) {
  947. if (otype == DHCPV6_OPT_IA_PREFIX) {
  948. struct dhcpv6_ia_prefix o_ia_p = {
  949. .type = htons(DHCPV6_OPT_IA_PREFIX),
  950. .len = htons(sizeof(o_ia_p) - 4),
  951. .preferred_lt = 0,
  952. .valid_lt = 0,
  953. .prefix = ia_p->prefix,
  954. .addr = ia_p->addr,
  955. };
  956. if (buflen < ia_len + sizeof(o_ia_p))
  957. return 0;
  958. memcpy(buf + ia_len, &o_ia_p, sizeof(o_ia_p));
  959. ia_len += sizeof(o_ia_p);
  960. } else {
  961. struct dhcpv6_ia_addr o_ia_a = {
  962. .type = htons(DHCPV6_OPT_IA_ADDR),
  963. .len = htons(sizeof(o_ia_a) - 4),
  964. .addr = ia_a->addr,
  965. .preferred_lt = 0,
  966. .valid_lt = 0,
  967. };
  968. if (buflen < ia_len + sizeof(o_ia_a))
  969. continue;
  970. memcpy(buf + ia_len, &o_ia_a, sizeof(o_ia_a));
  971. ia_len += sizeof(o_ia_a);
  972. }
  973. }
  974. }
  975. }
  976. o_ia.len = htons(ia_len - 4);
  977. memcpy(buf, &o_ia, sizeof(o_ia));
  978. return ia_len;
  979. }
  980. struct log_ctxt {
  981. char *buf;
  982. int buf_len;
  983. int buf_idx;
  984. };
  985. static void dhcpv6_log_ia_addr(struct in6_addr *addr, int prefix, _unused uint32_t pref_lt,
  986. _unused uint32_t valid_lt, void *arg)
  987. {
  988. struct log_ctxt *ctxt = (struct log_ctxt *)arg;
  989. char addrbuf[INET6_ADDRSTRLEN];
  990. inet_ntop(AF_INET6, addr, addrbuf, sizeof(addrbuf));
  991. ctxt->buf_idx += snprintf(ctxt->buf + ctxt->buf_idx, ctxt->buf_len - ctxt->buf_idx,
  992. "%s/%d ", addrbuf, prefix);
  993. }
  994. static void dhcpv6_log(uint8_t msgtype, struct interface *iface, time_t now,
  995. const char *duidbuf, bool is_pd, struct dhcp_assignment *a, int code)
  996. {
  997. const char *type = "UNKNOWN";
  998. const char *status = "UNKNOWN";
  999. switch (msgtype) {
  1000. case DHCPV6_MSG_SOLICIT:
  1001. type = "SOLICIT";
  1002. break;
  1003. case DHCPV6_MSG_REQUEST:
  1004. type = "REQUEST";
  1005. break;
  1006. case DHCPV6_MSG_CONFIRM:
  1007. type = "CONFIRM";
  1008. break;
  1009. case DHCPV6_MSG_RENEW:
  1010. type = "RENEW";
  1011. break;
  1012. case DHCPV6_MSG_REBIND:
  1013. type = "REBIND";
  1014. break;
  1015. case DHCPV6_MSG_RELEASE:
  1016. type = "RELEASE";
  1017. break;
  1018. case DHCPV6_MSG_DECLINE:
  1019. type = "DECLINE";
  1020. break;
  1021. }
  1022. switch (code) {
  1023. case DHCPV6_STATUS_OK:
  1024. status = "ok";
  1025. break;
  1026. case DHCPV6_STATUS_NOADDRSAVAIL:
  1027. status = "no addresses available";
  1028. break;
  1029. case DHCPV6_STATUS_NOBINDING:
  1030. status = "no binding";
  1031. break;
  1032. case DHCPV6_STATUS_NOTONLINK:
  1033. status = "not on-link";
  1034. break;
  1035. case DHCPV6_STATUS_NOPREFIXAVAIL:
  1036. status = "no prefix available";
  1037. break;
  1038. }
  1039. char leasebuf[256] = "";
  1040. if (a) {
  1041. struct log_ctxt ctxt = {.buf = leasebuf,
  1042. .buf_len = sizeof(leasebuf),
  1043. .buf_idx = 0 };
  1044. dhcpv6_ia_enum_addrs(iface, a, now, dhcpv6_log_ia_addr, &ctxt);
  1045. }
  1046. syslog(LOG_INFO, "DHCPV6 %s %s from %s on %s: %s %s", type, (is_pd) ? "IA_PD" : "IA_NA",
  1047. duidbuf, iface->name, status, leasebuf);
  1048. }
  1049. static bool dhcpv6_ia_on_link(const struct dhcpv6_ia_hdr *ia, struct dhcp_assignment *a,
  1050. struct interface *iface)
  1051. {
  1052. struct odhcpd_ipaddr *addrs = (a && a->managed) ? a->managed : iface->addr6;
  1053. size_t addrlen = (a && a->managed) ? (size_t)a->managed_size : iface->addr6_len;
  1054. time_t now = odhcpd_time();
  1055. uint8_t *odata, *end = ((uint8_t*)ia) + htons(ia->len) + 4;
  1056. uint16_t otype, olen;
  1057. bool onlink = true;
  1058. dhcpv6_for_each_option((uint8_t*)&ia[1], end, otype, olen, odata) {
  1059. struct dhcpv6_ia_prefix *p = (struct dhcpv6_ia_prefix *)&odata[-4];
  1060. struct dhcpv6_ia_addr *n = (struct dhcpv6_ia_addr *)&odata[-4];
  1061. if ((otype != DHCPV6_OPT_IA_PREFIX || olen < sizeof(*p) - 4) &&
  1062. (otype != DHCPV6_OPT_IA_ADDR || olen < sizeof(*n) - 4))
  1063. continue;
  1064. onlink = false;
  1065. for (size_t i = 0; i < addrlen; ++i) {
  1066. if (!valid_addr(&addrs[i], now))
  1067. continue;
  1068. if (ADDR_MATCH_PIO_FILTER(&addrs[i], iface))
  1069. continue;
  1070. if (ia->type == htons(DHCPV6_OPT_IA_PD)) {
  1071. if (p->prefix < addrs[i].prefix ||
  1072. odhcpd_bmemcmp(&p->addr, &addrs[i].addr.in6, addrs[i].prefix))
  1073. continue;
  1074. } else if (odhcpd_bmemcmp(&n->addr, &addrs[i].addr.in6, addrs[i].prefix))
  1075. continue;
  1076. onlink = true;
  1077. }
  1078. if (!onlink)
  1079. break;
  1080. }
  1081. return onlink;
  1082. }
  1083. ssize_t dhcpv6_ia_handle_IAs(uint8_t *buf, size_t buflen, struct interface *iface,
  1084. const struct sockaddr_in6 *addr, const void *data, const uint8_t *end)
  1085. {
  1086. struct lease *l;
  1087. struct dhcp_assignment *first = NULL;
  1088. const struct dhcpv6_client_header *hdr = data;
  1089. time_t now = odhcpd_time();
  1090. uint16_t otype, olen, clid_len = 0;
  1091. uint8_t *start = (uint8_t *)&hdr[1], *odata;
  1092. uint8_t *clid_data = NULL, mac[6] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff};
  1093. size_t hostname_len = 0, response_len = 0;
  1094. bool notonlink = false, rapid_commit = false, accept_reconf = false;
  1095. char duidbuf[261], hostname[256];
  1096. dhcpv6_for_each_option(start, end, otype, olen, odata) {
  1097. if (otype == DHCPV6_OPT_CLIENTID) {
  1098. clid_data = odata;
  1099. clid_len = olen;
  1100. if (olen == 14 && odata[0] == 0 && odata[1] == 1)
  1101. memcpy(mac, &odata[8], sizeof(mac));
  1102. else if (olen == 10 && odata[0] == 0 && odata[1] == 3)
  1103. memcpy(mac, &odata[4], sizeof(mac));
  1104. if (olen <= 130)
  1105. odhcpd_hexlify(duidbuf, odata, olen);
  1106. } else if (otype == DHCPV6_OPT_FQDN && olen >= 2 && olen <= 255) {
  1107. uint8_t fqdn_buf[256];
  1108. memcpy(fqdn_buf, odata, olen);
  1109. fqdn_buf[olen++] = 0;
  1110. if (dn_expand(&fqdn_buf[1], &fqdn_buf[olen], &fqdn_buf[1], hostname, sizeof(hostname)) > 0)
  1111. hostname_len = strcspn(hostname, ".");
  1112. } else if (otype == DHCPV6_OPT_RECONF_ACCEPT)
  1113. accept_reconf = true;
  1114. else if (otype == DHCPV6_OPT_RAPID_COMMIT && hdr->msg_type == DHCPV6_MSG_SOLICIT)
  1115. rapid_commit = true;
  1116. }
  1117. if (!clid_data || !clid_len || clid_len > 130)
  1118. goto out;
  1119. l = config_find_lease_by_duid(clid_data, clid_len);
  1120. if (!l)
  1121. l = config_find_lease_by_mac(mac);
  1122. dhcpv6_for_each_option(start, end, otype, olen, odata) {
  1123. bool is_pd = (otype == DHCPV6_OPT_IA_PD);
  1124. bool is_na = (otype == DHCPV6_OPT_IA_NA);
  1125. bool ia_addr_present = false;
  1126. if (!is_pd && !is_na)
  1127. continue;
  1128. struct dhcpv6_ia_hdr *ia = (struct dhcpv6_ia_hdr*)&odata[-4];
  1129. size_t ia_response_len = 0;
  1130. uint8_t reqlen = (is_pd) ? 62 : 128;
  1131. uint32_t reqhint = 0;
  1132. /* Parse request hint for IA-PD */
  1133. if (is_pd) {
  1134. uint8_t *sdata;
  1135. uint16_t stype, slen;
  1136. dhcpv6_for_each_option(&ia[1], odata + olen, stype, slen, sdata) {
  1137. if (stype != DHCPV6_OPT_IA_PREFIX || slen < sizeof(struct dhcpv6_ia_prefix) - 4)
  1138. continue;
  1139. struct dhcpv6_ia_prefix *p = (struct dhcpv6_ia_prefix*)&sdata[-4];
  1140. if (p->prefix) {
  1141. reqlen = p->prefix;
  1142. reqhint = ntohl(p->addr.s6_addr32[1]);
  1143. if (reqlen > 32 && reqlen <= 64)
  1144. reqhint &= (1U << (64 - reqlen)) - 1;
  1145. }
  1146. }
  1147. if (reqlen > 64)
  1148. reqlen = 64;
  1149. /*
  1150. * A requesting router can include a desired prefix length for its
  1151. * delegation. The delegating router (us) is not required to honor
  1152. * the hint (RFC3633, section 11.2, we MAY choose to use the
  1153. * information in the option; RFC8168, section 3.2 has several SHOULDs
  1154. * about desired choices for selecting a prefix to delegate).
  1155. *
  1156. * We support a policy setting to conserve prefix space, which purposely
  1157. * assigns prefixes that might not match the requesting router's hint.
  1158. *
  1159. * If the minimum prefix length is set in this interface's
  1160. * configuration, we use it as a floor for the requested (hinted)
  1161. * prefix length. This allows us to conserve prefix space so that
  1162. * any single router can't grab too much of it. Consider if we have
  1163. * an interface with a /56 prefix. A requesting router could ask for
  1164. * a /58 and take 1/4 of our total address space. But if we set a
  1165. * minimum of /60, we can limit each requesting router to get only
  1166. * 1/16 of our total address space.
  1167. */
  1168. if (iface->dhcpv6_pd_min_len && reqlen < iface->dhcpv6_pd_min_len) {
  1169. syslog(LOG_INFO, "clamping requested PD from %d to %d",
  1170. reqlen, iface->dhcpv6_pd_min_len);
  1171. reqlen = iface->dhcpv6_pd_min_len;
  1172. }
  1173. } else if (is_na) {
  1174. uint8_t *sdata;
  1175. uint16_t stype, slen;
  1176. dhcpv6_for_each_option(&ia[1], odata + olen, stype, slen, sdata) {
  1177. if (stype != DHCPV6_OPT_IA_ADDR || slen < sizeof(struct dhcpv6_ia_addr) - 4)
  1178. continue;
  1179. ia_addr_present = true;
  1180. }
  1181. }
  1182. /* Find assignment */
  1183. struct dhcp_assignment *c, *a = NULL;
  1184. list_for_each_entry(c, &iface->ia_assignments, head) {
  1185. if ((c->clid_len == clid_len && !memcmp(c->clid_data, clid_data, clid_len)) &&
  1186. c->iaid == ia->iaid && (INFINITE_VALID(c->valid_until) || now < c->valid_until) &&
  1187. ((is_pd && (c->flags & OAF_DHCPV6_PD)) || (is_na && (c->flags & OAF_DHCPV6_NA)))) {
  1188. a = c;
  1189. /* Reset state */
  1190. if (a->flags & OAF_BOUND)
  1191. apply_lease(a, false);
  1192. stop_reconf(a);
  1193. break;
  1194. }
  1195. }
  1196. if (l && a && a->lease != l) {
  1197. free_assignment(a);
  1198. a = NULL;
  1199. }
  1200. /* Generic message handling */
  1201. uint16_t status = DHCPV6_STATUS_OK;
  1202. if (a && a->managed_size < 0)
  1203. return -1;
  1204. if (hdr->msg_type == DHCPV6_MSG_SOLICIT ||
  1205. hdr->msg_type == DHCPV6_MSG_REQUEST ||
  1206. (hdr->msg_type == DHCPV6_MSG_REBIND && !a)) {
  1207. bool assigned = !!a;
  1208. if (!a) {
  1209. if ((!iface->no_dynamic_dhcp || (l && is_na)) &&
  1210. (iface->dhcpv6_pd || iface->dhcpv6_na)) {
  1211. /* Create new binding */
  1212. a = alloc_assignment(clid_len);
  1213. if (a) {
  1214. a->clid_len = clid_len;
  1215. memcpy(a->clid_data, clid_data, clid_len);
  1216. a->iaid = ia->iaid;
  1217. a->length = reqlen;
  1218. a->peer = *addr;
  1219. if (is_na)
  1220. a->assigned_host_id = l ? l->hostid : 0;
  1221. else
  1222. a->assigned_subnet_id = reqhint;
  1223. a->valid_until = now;
  1224. a->preferred_until = now;
  1225. a->dhcp_free_cb = dhcpv6_ia_free_assignment;
  1226. a->iface = iface;
  1227. a->flags = (is_pd ? OAF_DHCPV6_PD : OAF_DHCPV6_NA);
  1228. if (first)
  1229. memcpy(a->key, first->key, sizeof(a->key));
  1230. else
  1231. odhcpd_urandom(a->key, sizeof(a->key));
  1232. if (is_pd && iface->dhcpv6_pd)
  1233. while (!(assigned = assign_pd(iface, a)) &&
  1234. !a->managed_size && ++a->length <= 64);
  1235. else if (is_na && iface->dhcpv6_na)
  1236. assigned = assign_na(iface, a);
  1237. if (l && assigned) {
  1238. a->flags |= OAF_STATIC;
  1239. if (l->hostname)
  1240. a->hostname = strdup(l->hostname);
  1241. if (l->leasetime)
  1242. a->leasetime = l->leasetime;
  1243. list_add(&a->lease_list, &l->assignments);
  1244. a->lease = l;
  1245. }
  1246. if (a->managed_size && !assigned)
  1247. return -1;
  1248. }
  1249. }
  1250. }
  1251. if (!assigned || iface->addr6_len == 0)
  1252. /* Set error status */
  1253. status = (is_pd) ? DHCPV6_STATUS_NOPREFIXAVAIL : DHCPV6_STATUS_NOADDRSAVAIL;
  1254. else if (hdr->msg_type == DHCPV6_MSG_REQUEST && !dhcpv6_ia_on_link(ia, a, iface)) {
  1255. /* Send NOTONLINK status for the IA */
  1256. status = DHCPV6_STATUS_NOTONLINK;
  1257. assigned = false;
  1258. } else if (accept_reconf && assigned && !first &&
  1259. hdr->msg_type != DHCPV6_MSG_REBIND) {
  1260. size_t handshake_len = 4;
  1261. buf[0] = 0;
  1262. buf[1] = DHCPV6_OPT_RECONF_ACCEPT;
  1263. buf[2] = 0;
  1264. buf[3] = 0;
  1265. if (hdr->msg_type == DHCPV6_MSG_REQUEST) {
  1266. struct dhcpv6_auth_reconfigure auth = {
  1267. htons(DHCPV6_OPT_AUTH),
  1268. htons(sizeof(auth) - 4),
  1269. 3, 1, 0,
  1270. {htonl(time(NULL)), htonl(++serial)},
  1271. 1,
  1272. {0}
  1273. };
  1274. memcpy(auth.key, a->key, sizeof(a->key));
  1275. memcpy(buf + handshake_len, &auth, sizeof(auth));
  1276. handshake_len += sizeof(auth);
  1277. }
  1278. buf += handshake_len;
  1279. buflen -= handshake_len;
  1280. response_len += handshake_len;
  1281. first = a;
  1282. }
  1283. ia_response_len = build_ia(buf, buflen, status, ia, a, iface,
  1284. hdr->msg_type == DHCPV6_MSG_REBIND ? false : true);
  1285. /* Was only a solicitation: mark binding for removal */
  1286. if (assigned && hdr->msg_type == DHCPV6_MSG_SOLICIT && !rapid_commit) {
  1287. a->flags &= ~OAF_BOUND;
  1288. a->flags |= OAF_TENTATIVE;
  1289. /* Keep tentative assignment around for 60 seconds */
  1290. a->valid_until = now + 60;
  1291. } else if (assigned &&
  1292. ((hdr->msg_type == DHCPV6_MSG_SOLICIT && rapid_commit) ||
  1293. hdr->msg_type == DHCPV6_MSG_REQUEST ||
  1294. hdr->msg_type == DHCPV6_MSG_REBIND)) {
  1295. if ((!(a->flags & OAF_STATIC) || !a->hostname) && hostname_len > 0) {
  1296. a->hostname = realloc(a->hostname, hostname_len + 1);
  1297. if (a->hostname) {
  1298. memcpy(a->hostname, hostname, hostname_len);
  1299. a->hostname[hostname_len] = 0;
  1300. if (odhcpd_valid_hostname(a->hostname))
  1301. a->flags &= ~OAF_BROKEN_HOSTNAME;
  1302. else
  1303. a->flags |= OAF_BROKEN_HOSTNAME;
  1304. }
  1305. }
  1306. a->accept_reconf = accept_reconf;
  1307. a->flags &= ~OAF_TENTATIVE;
  1308. a->flags |= OAF_BOUND;
  1309. apply_lease(a, true);
  1310. } else if (!assigned && a && a->managed_size == 0) {
  1311. /* Cleanup failed assignment */
  1312. free_assignment(a);
  1313. a = NULL;
  1314. }
  1315. } else if (hdr->msg_type == DHCPV6_MSG_RENEW ||
  1316. hdr->msg_type == DHCPV6_MSG_RELEASE ||
  1317. hdr->msg_type == DHCPV6_MSG_REBIND ||
  1318. hdr->msg_type == DHCPV6_MSG_DECLINE) {
  1319. if (!a && hdr->msg_type != DHCPV6_MSG_REBIND) {
  1320. status = DHCPV6_STATUS_NOBINDING;
  1321. ia_response_len = build_ia(buf, buflen, status, ia, a, iface, false);
  1322. } else if (hdr->msg_type == DHCPV6_MSG_RENEW ||
  1323. hdr->msg_type == DHCPV6_MSG_REBIND) {
  1324. ia_response_len = build_ia(buf, buflen, status, ia, a, iface, false);
  1325. if (a) {
  1326. a->flags |= OAF_BOUND;
  1327. apply_lease(a, true);
  1328. }
  1329. } else if (hdr->msg_type == DHCPV6_MSG_RELEASE) {
  1330. a->valid_until = now - 1;
  1331. } else if ((a->flags & OAF_DHCPV6_NA) && hdr->msg_type == DHCPV6_MSG_DECLINE) {
  1332. a->flags &= ~OAF_BOUND;
  1333. if (!(a->flags & OAF_STATIC) || a->lease->hostid != a->assigned_host_id) {
  1334. memset(a->clid_data, 0, a->clid_len);
  1335. a->valid_until = now + 3600; /* Block address for 1h */
  1336. } else
  1337. a->valid_until = now - 1;
  1338. }
  1339. } else if (hdr->msg_type == DHCPV6_MSG_CONFIRM) {
  1340. if (ia_addr_present && !dhcpv6_ia_on_link(ia, a, iface)) {
  1341. notonlink = true;
  1342. break;
  1343. }
  1344. if (!ia_addr_present || !a || !(a->flags & OAF_BOUND)) {
  1345. response_len = 0;
  1346. goto out;
  1347. }
  1348. }
  1349. buf += ia_response_len;
  1350. buflen -= ia_response_len;
  1351. response_len += ia_response_len;
  1352. dhcpv6_log(hdr->msg_type, iface, now, duidbuf, is_pd, a, status);
  1353. }
  1354. switch (hdr->msg_type) {
  1355. case DHCPV6_MSG_RELEASE:
  1356. case DHCPV6_MSG_DECLINE:
  1357. case DHCPV6_MSG_CONFIRM:
  1358. if (response_len + 6 < buflen) {
  1359. buf[0] = 0;
  1360. buf[1] = DHCPV6_OPT_STATUS;
  1361. buf[2] = 0;
  1362. buf[3] = 2;
  1363. buf[4] = 0;
  1364. buf[5] = (notonlink) ? DHCPV6_STATUS_NOTONLINK : DHCPV6_STATUS_OK;
  1365. response_len += 6;
  1366. }
  1367. break;
  1368. default:
  1369. break;
  1370. }
  1371. dhcpv6_ia_write_statefile();
  1372. out:
  1373. return response_len;
  1374. }