dhcpv6.c 25 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858
  1. /**
  2. * Copyright (C) 2012-2013 Steven Barth <steven@midlink.org>
  3. * Copyright (C) 2018 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. */
  16. #include <errno.h>
  17. #include <unistd.h>
  18. #include <stddef.h>
  19. #include <resolv.h>
  20. #include <sys/timerfd.h>
  21. #include <arpa/inet.h>
  22. #include <libubox/utils.h>
  23. #include "odhcpd.h"
  24. #include "dhcpv6.h"
  25. #ifdef DHCPV4_SUPPORT
  26. #include "dhcpv4.h"
  27. #endif
  28. static void relay_client_request(struct sockaddr_in6 *source,
  29. const void *data, size_t len, struct interface *iface);
  30. static void relay_server_response(uint8_t *data, size_t len);
  31. static void handle_dhcpv6(void *addr, void *data, size_t len,
  32. struct interface *iface, void *dest);
  33. static void handle_client_request(void *addr, void *data, size_t len,
  34. struct interface *iface, void *dest_addr);
  35. /* Create socket and register events */
  36. int dhcpv6_init(void)
  37. {
  38. return dhcpv6_ia_init();
  39. }
  40. int dhcpv6_setup_interface(struct interface *iface, bool enable)
  41. {
  42. int ret = 0;
  43. enable = enable && (iface->dhcpv6 != MODE_DISABLED);
  44. if (iface->dhcpv6_event.uloop.fd >= 0) {
  45. uloop_fd_delete(&iface->dhcpv6_event.uloop);
  46. close(iface->dhcpv6_event.uloop.fd);
  47. iface->dhcpv6_event.uloop.fd = -1;
  48. }
  49. /* Configure multicast settings */
  50. if (enable) {
  51. struct sockaddr_in6 bind_addr = {AF_INET6, htons(DHCPV6_SERVER_PORT),
  52. 0, IN6ADDR_ANY_INIT, 0};
  53. struct ipv6_mreq mreq;
  54. int val = 1;
  55. iface->dhcpv6_event.uloop.fd = socket(AF_INET6, SOCK_DGRAM | SOCK_CLOEXEC, IPPROTO_UDP);
  56. if (iface->dhcpv6_event.uloop.fd < 0) {
  57. syslog(LOG_ERR, "socket(AF_INET6): %m");
  58. ret = -1;
  59. goto out;
  60. }
  61. /* Basic IPv6 configuration */
  62. if (setsockopt(iface->dhcpv6_event.uloop.fd, SOL_SOCKET, SO_BINDTODEVICE,
  63. iface->ifname, strlen(iface->ifname)) < 0) {
  64. syslog(LOG_ERR, "setsockopt(SO_BINDTODEVICE): %m");
  65. ret = -1;
  66. goto out;
  67. }
  68. if (setsockopt(iface->dhcpv6_event.uloop.fd, IPPROTO_IPV6, IPV6_V6ONLY,
  69. &val, sizeof(val)) < 0) {
  70. syslog(LOG_ERR, "setsockopt(IPV6_V6ONLY): %m");
  71. ret = -1;
  72. goto out;
  73. }
  74. if (setsockopt(iface->dhcpv6_event.uloop.fd, SOL_SOCKET, SO_REUSEADDR,
  75. &val, sizeof(val)) < 0) {
  76. syslog(LOG_ERR, "setsockopt(SO_REUSEADDR): %m");
  77. ret = -1;
  78. goto out;
  79. }
  80. if (setsockopt(iface->dhcpv6_event.uloop.fd, IPPROTO_IPV6, IPV6_RECVPKTINFO,
  81. &val, sizeof(val)) < 0) {
  82. syslog(LOG_ERR, "setsockopt(IPV6_RECVPKTINFO): %m");
  83. ret = -1;
  84. goto out;
  85. }
  86. val = DHCPV6_HOP_COUNT_LIMIT;
  87. if (setsockopt(iface->dhcpv6_event.uloop.fd, IPPROTO_IPV6, IPV6_MULTICAST_HOPS,
  88. &val, sizeof(val)) < 0) {
  89. syslog(LOG_ERR, "setsockopt(IPV6_MULTICAST_HOPS): %m");
  90. ret = -1;
  91. goto out;
  92. }
  93. val = 0;
  94. if (setsockopt(iface->dhcpv6_event.uloop.fd, IPPROTO_IPV6, IPV6_MULTICAST_LOOP,
  95. &val, sizeof(val)) < 0) {
  96. syslog(LOG_ERR, "setsockopt(IPV6_MULTICAST_LOOP): %m");
  97. ret = -1;
  98. goto out;
  99. }
  100. if (bind(iface->dhcpv6_event.uloop.fd, (struct sockaddr*)&bind_addr,
  101. sizeof(bind_addr)) < 0) {
  102. syslog(LOG_ERR, "bind(): %m");
  103. ret = -1;
  104. goto out;
  105. }
  106. memset(&mreq, 0, sizeof(mreq));
  107. inet_pton(AF_INET6, ALL_DHCPV6_RELAYS, &mreq.ipv6mr_multiaddr);
  108. mreq.ipv6mr_interface = iface->ifindex;
  109. if (setsockopt(iface->dhcpv6_event.uloop.fd, IPPROTO_IPV6, IPV6_ADD_MEMBERSHIP,
  110. &mreq, sizeof(mreq)) < 0) {
  111. syslog(LOG_ERR, "setsockopt(IPV6_ADD_MEMBERSHIP): %m");
  112. ret = -1;
  113. goto out;
  114. }
  115. if (iface->dhcpv6 == MODE_SERVER) {
  116. memset(&mreq, 0, sizeof(mreq));
  117. inet_pton(AF_INET6, ALL_DHCPV6_SERVERS, &mreq.ipv6mr_multiaddr);
  118. mreq.ipv6mr_interface = iface->ifindex;
  119. if (setsockopt(iface->dhcpv6_event.uloop.fd, IPPROTO_IPV6, IPV6_ADD_MEMBERSHIP,
  120. &mreq, sizeof(mreq)) < 0) {
  121. syslog(LOG_ERR, "setsockopt(IPV6_ADD_MEMBERSHIP): %m");
  122. ret = -1;
  123. goto out;
  124. }
  125. }
  126. iface->dhcpv6_event.handle_dgram = handle_dhcpv6;
  127. odhcpd_register(&iface->dhcpv6_event);
  128. }
  129. ret = dhcpv6_ia_setup_interface(iface, enable);
  130. out:
  131. if (ret < 0 && iface->dhcpv6_event.uloop.fd >= 0) {
  132. close(iface->dhcpv6_event.uloop.fd);
  133. iface->dhcpv6_event.uloop.fd = -1;
  134. }
  135. return ret;
  136. }
  137. enum {
  138. IOV_NESTED = 0,
  139. IOV_DEST,
  140. IOV_MAXRT,
  141. #define IOV_STAT IOV_MAXRT
  142. IOV_RAPID_COMMIT,
  143. IOV_DNS,
  144. IOV_DNS_ADDR,
  145. IOV_SEARCH,
  146. IOV_SEARCH_DOMAIN,
  147. IOV_PDBUF,
  148. #define IOV_REFRESH IOV_PDBUF
  149. IOV_CERID,
  150. IOV_DHCPV6_RAW,
  151. IOV_NTP,
  152. IOV_NTP_ADDR,
  153. IOV_SNTP,
  154. IOV_SNTP_ADDR,
  155. IOV_RELAY_MSG,
  156. IOV_DHCPV4O6_SERVER,
  157. IOV_TOTAL
  158. };
  159. static void handle_nested_message(uint8_t *data, size_t len,
  160. struct dhcpv6_client_header **c_hdr, uint8_t **opts,
  161. uint8_t **end, struct iovec iov[IOV_TOTAL])
  162. {
  163. struct dhcpv6_relay_header *r_hdr = (struct dhcpv6_relay_header *)data;
  164. uint16_t otype, olen;
  165. uint8_t *odata;
  166. if (iov[IOV_NESTED].iov_base == NULL) {
  167. iov[IOV_NESTED].iov_base = data;
  168. iov[IOV_NESTED].iov_len = len;
  169. }
  170. if (len < sizeof(struct dhcpv6_client_header))
  171. return;
  172. if (r_hdr->msg_type != DHCPV6_MSG_RELAY_FORW) {
  173. iov[IOV_NESTED].iov_len = data - (uint8_t *)iov[IOV_NESTED].iov_base;
  174. *c_hdr = (void *)data;
  175. *opts = (uint8_t *)&(*c_hdr)[1];
  176. *end = data + len;
  177. return;
  178. }
  179. dhcpv6_for_each_option(r_hdr->options, data + len, otype, olen, odata) {
  180. if (otype == DHCPV6_OPT_RELAY_MSG) {
  181. iov[IOV_RELAY_MSG].iov_base = odata + olen;
  182. iov[IOV_RELAY_MSG].iov_len = (((uint8_t *)iov[IOV_NESTED].iov_base) +
  183. iov[IOV_NESTED].iov_len) - (odata + olen);
  184. handle_nested_message(odata, olen, c_hdr, opts, end, iov);
  185. return;
  186. }
  187. }
  188. }
  189. static void update_nested_message(uint8_t *data, size_t len, ssize_t pdiff)
  190. {
  191. struct dhcpv6_relay_header *hdr = (struct dhcpv6_relay_header*)data;
  192. if (hdr->msg_type != DHCPV6_MSG_RELAY_FORW)
  193. return;
  194. hdr->msg_type = DHCPV6_MSG_RELAY_REPL;
  195. uint16_t otype, olen;
  196. uint8_t *odata;
  197. dhcpv6_for_each_option(hdr->options, data + len, otype, olen, odata) {
  198. if (otype == DHCPV6_OPT_RELAY_MSG) {
  199. olen += pdiff;
  200. odata[-2] = (olen >> 8) & 0xff;
  201. odata[-1] = olen & 0xff;
  202. update_nested_message(odata, olen - pdiff, pdiff);
  203. return;
  204. }
  205. }
  206. }
  207. #ifdef DHCPV4_SUPPORT
  208. struct dhcpv4_msg_data {
  209. uint8_t *msg;
  210. size_t maxsize;
  211. ssize_t len;
  212. };
  213. static int send_reply(_unused const void *buf, size_t len,
  214. _unused const struct sockaddr *dest, _unused socklen_t dest_len,
  215. _unused void *opaque)
  216. {
  217. struct dhcpv4_msg_data *reply = opaque;
  218. if (len > reply->maxsize) {
  219. syslog(LOG_ERR, "4o6: reply too large, %zu > %zu", len, reply->maxsize);
  220. reply->len = -1;
  221. } else {
  222. memcpy(reply->msg, buf, len);
  223. reply->len = len;
  224. }
  225. return reply->len;
  226. }
  227. static ssize_t dhcpv6_4o6_query(uint8_t *buf, size_t buflen,
  228. struct interface *iface,
  229. const struct sockaddr_in6 *addr,
  230. const void *data, const uint8_t *end)
  231. {
  232. const struct dhcpv6_client_header *hdr = data;
  233. uint16_t otype, olen, msgv4_len = 0;
  234. uint8_t *msgv4_data = NULL;
  235. uint8_t *start = (uint8_t *)&hdr[1], *odata;
  236. struct sockaddr_in addrv4;
  237. struct dhcpv4_msg_data reply = { .msg = buf, .maxsize = buflen, .len = -1 };
  238. dhcpv6_for_each_option(start, end, otype, olen, odata) {
  239. if (otype == DHCPV6_OPT_DHCPV4_MSG) {
  240. msgv4_data = odata;
  241. msgv4_len = olen;
  242. }
  243. }
  244. if (!msgv4_data || msgv4_len == 0) {
  245. syslog(LOG_ERR, "4o6: missing DHCPv4 message option (%d)", DHCPV6_OPT_DHCPV4_MSG);
  246. return -1;
  247. }
  248. // Dummy IPv4 address
  249. memset(&addrv4, 0, sizeof(addrv4));
  250. addrv4.sin_family = AF_INET;
  251. addrv4.sin_addr.s_addr = INADDR_ANY;
  252. addrv4.sin_port = htons(DHCPV4_CLIENT_PORT);
  253. dhcpv4_handle_msg(&addrv4, msgv4_data, msgv4_len,
  254. iface, NULL, send_reply, &reply);
  255. return reply.len;
  256. }
  257. #endif /* DHCPV4_SUPPORT */
  258. /* Simple DHCPv6-server for information requests */
  259. static void handle_client_request(void *addr, void *data, size_t len,
  260. struct interface *iface, void *dest_addr)
  261. {
  262. struct dhcpv6_client_header *hdr = data;
  263. uint8_t *opts = (uint8_t *)&hdr[1], *opts_end = (uint8_t *)data + len;
  264. bool o_rapid_commit = false;
  265. if (len < sizeof(*hdr))
  266. return;
  267. syslog(LOG_DEBUG, "Got a DHCPv6-request on %s", iface->name);
  268. /* Construct reply message */
  269. struct __attribute__((packed)) {
  270. uint8_t msg_type;
  271. uint8_t tr_id[3];
  272. uint16_t serverid_type;
  273. uint16_t serverid_length;
  274. uint16_t duid_type;
  275. uint16_t hardware_type;
  276. uint8_t mac[6];
  277. uint16_t clientid_type;
  278. uint16_t clientid_length;
  279. uint8_t clientid_buf[130];
  280. } dest = {
  281. .msg_type = DHCPV6_MSG_REPLY,
  282. .serverid_type = htons(DHCPV6_OPT_SERVERID),
  283. .serverid_length = htons(10),
  284. .duid_type = htons(3),
  285. .hardware_type = htons(1),
  286. .clientid_type = htons(DHCPV6_OPT_CLIENTID),
  287. .clientid_buf = {0}
  288. };
  289. odhcpd_get_mac(iface, dest.mac);
  290. struct __attribute__((packed)) {
  291. uint16_t type;
  292. uint16_t len;
  293. uint32_t value;
  294. } maxrt = {htons(DHCPV6_OPT_SOL_MAX_RT), htons(sizeof(maxrt) - 4),
  295. htonl(60)};
  296. struct __attribute__((packed)) {
  297. uint16_t type;
  298. uint16_t len;
  299. } rapid_commit = {htons(DHCPV6_OPT_RAPID_COMMIT), 0};
  300. struct __attribute__((packed)) {
  301. uint16_t type;
  302. uint16_t len;
  303. uint16_t value;
  304. } stat = {htons(DHCPV6_OPT_STATUS), htons(sizeof(stat) - 4),
  305. htons(DHCPV6_STATUS_USEMULTICAST)};
  306. struct __attribute__((packed)) {
  307. uint16_t type;
  308. uint16_t len;
  309. uint32_t value;
  310. } refresh = {htons(DHCPV6_OPT_INFO_REFRESH), htons(sizeof(uint32_t)),
  311. htonl(600)};
  312. struct in6_addr dns_addr, *dns_addr_ptr = iface->dns;
  313. size_t dns_cnt = iface->dns_cnt;
  314. if ((dns_cnt == 0) &&
  315. !odhcpd_get_interface_dns_addr(iface, &dns_addr)) {
  316. dns_addr_ptr = &dns_addr;
  317. dns_cnt = 1;
  318. }
  319. struct {
  320. uint16_t type;
  321. uint16_t len;
  322. } dns = {htons(DHCPV6_OPT_DNS_SERVERS), htons(dns_cnt * sizeof(*dns_addr_ptr))};
  323. /* SNTP */
  324. struct in6_addr *sntp_addr_ptr = iface->dhcpv6_sntp;
  325. size_t sntp_cnt = 0;
  326. struct {
  327. uint16_t type;
  328. uint16_t len;
  329. } dhcpv6_sntp;
  330. /* NTP */
  331. uint8_t *ntp_ptr = iface->dhcpv6_ntp;
  332. uint16_t ntp_len = iface->dhcpv6_ntp_len;
  333. size_t ntp_cnt = 0;
  334. struct {
  335. uint16_t type;
  336. uint16_t len;
  337. } ntp;
  338. uint16_t otype, olen;
  339. uint16_t *reqopts = NULL;
  340. uint8_t *odata;
  341. size_t reqopts_len = 0;
  342. dhcpv6_for_each_option(opts, opts_end, otype, olen, odata) {
  343. if (otype == DHCPV6_OPT_ORO) {
  344. reqopts_len = olen;
  345. reqopts = (uint16_t *)odata;
  346. }
  347. }
  348. for(size_t opt = 0; opt < reqopts_len/2; opt++) {
  349. if (iface->dhcpv6_sntp_cnt != 0 &&
  350. DHCPV6_OPT_SNTP_SERVERS == ntohs(reqopts[opt])) {
  351. sntp_cnt = iface->dhcpv6_sntp_cnt;
  352. dhcpv6_sntp.type = htons(DHCPV6_OPT_SNTP_SERVERS);
  353. dhcpv6_sntp.len = htons(sntp_cnt * sizeof(*sntp_addr_ptr));
  354. } else if (iface->dhcpv6_ntp_cnt != 0 &&
  355. DHCPV6_OPT_NTP_SERVERS == ntohs(reqopts[opt])) {
  356. ntp_cnt = iface->dhcpv6_ntp_cnt;
  357. ntp.type = htons(DHCPV6_OPT_NTP_SERVERS);
  358. ntp.len = htons(ntp_len);
  359. }
  360. }
  361. /* DNS Search options */
  362. uint8_t search_buf[256], *search_domain = iface->search;
  363. size_t search_len = iface->search_len;
  364. if (!search_domain && !res_init() && _res.dnsrch[0] && _res.dnsrch[0][0]) {
  365. int len = dn_comp(_res.dnsrch[0], search_buf,
  366. sizeof(search_buf), NULL, NULL);
  367. if (len > 0) {
  368. search_domain = search_buf;
  369. search_len = len;
  370. }
  371. }
  372. struct {
  373. uint16_t type;
  374. uint16_t len;
  375. } search = {htons(DHCPV6_OPT_DNS_DOMAIN), htons(search_len)};
  376. struct __attribute__((packed)) dhcpv4o6_server {
  377. uint16_t type;
  378. uint16_t len;
  379. struct in6_addr addr;
  380. } dhcpv4o6_server = {htons(DHCPV6_OPT_4O6_SERVER), htons(sizeof(struct in6_addr)),
  381. IN6ADDR_ANY_INIT};
  382. struct dhcpv6_cer_id cerid = {
  383. #ifdef EXT_CER_ID
  384. .type = htons(EXT_CER_ID),
  385. #endif
  386. .len = htons(36),
  387. .addr = iface->dhcpv6_pd_cer,
  388. };
  389. uint8_t pdbuf[512];
  390. struct iovec iov[IOV_TOTAL] = {
  391. [IOV_NESTED] = {NULL, 0},
  392. [IOV_DEST] = {&dest, (uint8_t*)&dest.clientid_type - (uint8_t*)&dest},
  393. [IOV_MAXRT] = {&maxrt, sizeof(maxrt)},
  394. [IOV_RAPID_COMMIT] = {&rapid_commit, 0},
  395. [IOV_DNS] = {&dns, (dns_cnt) ? sizeof(dns) : 0},
  396. [IOV_DNS_ADDR] = {dns_addr_ptr, dns_cnt * sizeof(*dns_addr_ptr)},
  397. [IOV_SEARCH] = {&search, (search_len) ? sizeof(search) : 0},
  398. [IOV_SEARCH_DOMAIN] = {search_domain, search_len},
  399. [IOV_PDBUF] = {pdbuf, 0},
  400. [IOV_CERID] = {&cerid, 0},
  401. [IOV_DHCPV6_RAW] = {iface->dhcpv6_raw, iface->dhcpv6_raw_len},
  402. [IOV_NTP] = {&ntp, (ntp_cnt) ? sizeof(ntp) : 0},
  403. [IOV_NTP_ADDR] = {ntp_ptr, (ntp_cnt) ? ntp_len : 0},
  404. [IOV_SNTP] = {&dhcpv6_sntp, (sntp_cnt) ? sizeof(dhcpv6_sntp) : 0},
  405. [IOV_SNTP_ADDR] = {sntp_addr_ptr, sntp_cnt * sizeof(*sntp_addr_ptr)},
  406. [IOV_RELAY_MSG] = {NULL, 0},
  407. [IOV_DHCPV4O6_SERVER] = {&dhcpv4o6_server, 0},
  408. };
  409. if (hdr->msg_type == DHCPV6_MSG_RELAY_FORW)
  410. handle_nested_message(data, len, &hdr, &opts, &opts_end, iov);
  411. switch (hdr->msg_type) {
  412. case DHCPV6_MSG_SOLICIT:
  413. case DHCPV6_MSG_REQUEST:
  414. case DHCPV6_MSG_CONFIRM:
  415. case DHCPV6_MSG_RENEW:
  416. case DHCPV6_MSG_REBIND:
  417. case DHCPV6_MSG_RELEASE:
  418. case DHCPV6_MSG_DECLINE:
  419. case DHCPV6_MSG_INFORMATION_REQUEST:
  420. case DHCPV6_MSG_RELAY_FORW:
  421. #ifdef DHCPV4_SUPPORT
  422. case DHCPV6_MSG_DHCPV4_QUERY:
  423. #endif
  424. break; /* Valid message types for clients */
  425. case DHCPV6_MSG_ADVERTISE:
  426. case DHCPV6_MSG_REPLY:
  427. case DHCPV6_MSG_RECONFIGURE:
  428. case DHCPV6_MSG_RELAY_REPL:
  429. case DHCPV6_MSG_DHCPV4_RESPONSE:
  430. #ifndef DHCPV4_SUPPORT
  431. case DHCPV6_MSG_DHCPV4_QUERY:
  432. #endif
  433. default:
  434. return; /* Invalid message types for clients */
  435. }
  436. if (!IN6_IS_ADDR_MULTICAST((struct in6_addr *)dest_addr) && iov[IOV_NESTED].iov_len == 0 &&
  437. (hdr->msg_type == DHCPV6_MSG_SOLICIT || hdr->msg_type == DHCPV6_MSG_CONFIRM ||
  438. hdr->msg_type == DHCPV6_MSG_REBIND || hdr->msg_type == DHCPV6_MSG_INFORMATION_REQUEST))
  439. return;
  440. memcpy(dest.tr_id, hdr->transaction_id, sizeof(dest.tr_id));
  441. /* Go through options and find what we need */
  442. dhcpv6_for_each_option(opts, opts_end, otype, olen, odata) {
  443. if (otype == DHCPV6_OPT_CLIENTID && olen <= 130) {
  444. dest.clientid_length = htons(olen);
  445. memcpy(dest.clientid_buf, odata, olen);
  446. iov[IOV_DEST].iov_len += 4 + olen;
  447. } else if (otype == DHCPV6_OPT_SERVERID) {
  448. if (olen != ntohs(dest.serverid_length) ||
  449. memcmp(odata, &dest.duid_type, olen))
  450. return; /* Not for us */
  451. } else if (iface->filter_class && otype == DHCPV6_OPT_USER_CLASS) {
  452. uint8_t *c = odata, *cend = &odata[olen];
  453. for (; &c[2] <= cend && &c[2 + (c[0] << 8) + c[1]] <= cend; c = &c[2 + (c[0] << 8) + c[1]]) {
  454. size_t elen = strlen(iface->filter_class);
  455. if (((((size_t)c[0]) << 8) | c[1]) == elen && !memcmp(&c[2], iface->filter_class, elen))
  456. return; /* Ignore from homenet */
  457. }
  458. } else if (otype == DHCPV6_OPT_IA_PD) {
  459. #ifdef EXT_CER_ID
  460. iov[IOV_CERID].iov_len = sizeof(cerid);
  461. if (IN6_IS_ADDR_UNSPECIFIED(&cerid.addr)) {
  462. struct odhcpd_ipaddr *addrs;
  463. ssize_t len = netlink_get_interface_addrs(0, true, &addrs);
  464. for (ssize_t i = 0; i < len; ++i)
  465. if (IN6_IS_ADDR_UNSPECIFIED(&cerid.addr)
  466. || memcmp(&addrs[i].addr, &cerid.addr, sizeof(cerid.addr)) < 0)
  467. cerid.addr = addrs[i].addr.in6;
  468. free(addrs);
  469. }
  470. #endif
  471. } else if (otype == DHCPV6_OPT_RAPID_COMMIT && hdr->msg_type == DHCPV6_MSG_SOLICIT) {
  472. iov[IOV_RAPID_COMMIT].iov_len = sizeof(rapid_commit);
  473. o_rapid_commit = true;
  474. } else if (otype == DHCPV6_OPT_ORO) {
  475. for (int i=0; i < olen/2; i++) {
  476. uint16_t option = ntohs(((uint16_t *)odata)[i]);
  477. switch (option) {
  478. #ifdef DHCPV4_SUPPORT
  479. case DHCPV6_OPT_4O6_SERVER:
  480. if (iface->dhcpv4) {
  481. /* According to RFC 7341, 7.2. DHCP 4o6 Server Address Option Format:
  482. * This option may also carry no IPv6 addresses, which instructs the
  483. * client to use the All_DHCP_Relay_Agents_and_Servers multicast address
  484. * as the destination address.
  485. *
  486. * The ISC dhclient logs a missing IPv6 address as an error but seems to
  487. * work anyway:
  488. * dhcp4-o-dhcp6-server: expecting at least 16 bytes; got 0
  489. *
  490. * Include the All_DHCP_Relay_Agents_and_Servers multicast address
  491. * to make it explicit which address to use. */
  492. struct dhcpv4o6_server *server = iov[IOV_DHCPV4O6_SERVER].iov_base;
  493. inet_pton(AF_INET6, ALL_DHCPV6_RELAYS, &server->addr);
  494. iov[IOV_DHCPV4O6_SERVER].iov_len = sizeof(dhcpv4o6_server);
  495. }
  496. break;
  497. #endif /* DHCPV4_SUPPORT */
  498. default:
  499. break;
  500. }
  501. }
  502. }
  503. }
  504. if (!IN6_IS_ADDR_MULTICAST((struct in6_addr *)dest_addr) && iov[IOV_NESTED].iov_len == 0 &&
  505. (hdr->msg_type == DHCPV6_MSG_REQUEST || hdr->msg_type == DHCPV6_MSG_RENEW ||
  506. hdr->msg_type == DHCPV6_MSG_RELEASE || hdr->msg_type == DHCPV6_MSG_DECLINE)) {
  507. iov[IOV_STAT].iov_base = &stat;
  508. iov[IOV_STAT].iov_len = sizeof(stat);
  509. for (ssize_t i = IOV_STAT + 1; i < IOV_TOTAL; ++i)
  510. iov[i].iov_len = 0;
  511. odhcpd_send(iface->dhcpv6_event.uloop.fd, addr, iov, ARRAY_SIZE(iov), iface);
  512. return;
  513. }
  514. if (hdr->msg_type == DHCPV6_MSG_SOLICIT && !o_rapid_commit) {
  515. dest.msg_type = DHCPV6_MSG_ADVERTISE;
  516. } else if (hdr->msg_type == DHCPV6_MSG_INFORMATION_REQUEST) {
  517. iov[IOV_REFRESH].iov_base = &refresh;
  518. iov[IOV_REFRESH].iov_len = sizeof(refresh);
  519. /* Return inf max rt option in reply to information request */
  520. maxrt.type = htons(DHCPV6_OPT_INF_MAX_RT);
  521. }
  522. #ifdef DHCPV4_SUPPORT
  523. if (hdr->msg_type == DHCPV6_MSG_DHCPV4_QUERY) {
  524. struct _packed dhcpv4_msg_data {
  525. uint16_t type;
  526. uint16_t len;
  527. uint8_t msg[1];
  528. } *msg_opt = (struct dhcpv4_msg_data*)pdbuf;
  529. ssize_t msglen;
  530. memset(pdbuf, 0, sizeof(pdbuf));
  531. msglen = dhcpv6_4o6_query(msg_opt->msg, sizeof(pdbuf) - sizeof(*msg_opt) + 1,
  532. iface, addr, (const void *)hdr, opts_end);
  533. if (msglen <= 0) {
  534. syslog(LOG_ERR, "4o6: query failed");
  535. return;
  536. }
  537. msg_opt->type = htons(DHCPV6_OPT_DHCPV4_MSG);
  538. msg_opt->len = htons(msglen);
  539. iov[IOV_PDBUF].iov_len = sizeof(*msg_opt) - 1 + msglen;
  540. dest.msg_type = DHCPV6_MSG_DHCPV4_RESPONSE;
  541. } else
  542. #endif /* DHCPV4_SUPPORT */
  543. if (hdr->msg_type != DHCPV6_MSG_INFORMATION_REQUEST) {
  544. ssize_t ialen = dhcpv6_ia_handle_IAs(pdbuf, sizeof(pdbuf), iface, addr, (const void *)hdr, opts_end);
  545. iov[IOV_PDBUF].iov_len = ialen;
  546. if (ialen < 0 ||
  547. (ialen == 0 && (hdr->msg_type == DHCPV6_MSG_REBIND || hdr->msg_type == DHCPV6_MSG_CONFIRM)))
  548. return;
  549. }
  550. if (iov[IOV_NESTED].iov_len > 0) /* Update length */
  551. update_nested_message(data, len, iov[IOV_DEST].iov_len + iov[IOV_MAXRT].iov_len +
  552. iov[IOV_RAPID_COMMIT].iov_len + iov[IOV_DNS].iov_len +
  553. iov[IOV_DNS_ADDR].iov_len + iov[IOV_SEARCH].iov_len +
  554. iov[IOV_SEARCH_DOMAIN].iov_len + iov[IOV_PDBUF].iov_len +
  555. iov[IOV_DHCPV4O6_SERVER].iov_len +
  556. iov[IOV_CERID].iov_len + iov[IOV_DHCPV6_RAW].iov_len +
  557. iov[IOV_NTP].iov_len + iov[IOV_NTP_ADDR].iov_len +
  558. iov[IOV_SNTP].iov_len + iov[IOV_SNTP_ADDR].iov_len -
  559. (4 + opts_end - opts));
  560. syslog(LOG_DEBUG, "Sending a DHCPv6-%s on %s", iov[IOV_NESTED].iov_len ? "relay-reply" : "reply", iface->name);
  561. odhcpd_send(iface->dhcpv6_event.uloop.fd, addr, iov, ARRAY_SIZE(iov), iface);
  562. }
  563. /* Central DHCPv6-relay handler */
  564. static void handle_dhcpv6(void *addr, void *data, size_t len,
  565. struct interface *iface, void *dest_addr)
  566. {
  567. if (iface->dhcpv6 == MODE_SERVER) {
  568. handle_client_request(addr, data, len, iface, dest_addr);
  569. } else if (iface->dhcpv6 == MODE_RELAY) {
  570. if (iface->master)
  571. relay_server_response(data, len);
  572. else
  573. relay_client_request(addr, data, len, iface);
  574. }
  575. }
  576. /* Relay server response (regular relay server handling) */
  577. static void relay_server_response(uint8_t *data, size_t len)
  578. {
  579. /* Information we need to gather */
  580. uint8_t *payload_data = NULL;
  581. size_t payload_len = 0;
  582. int32_t ifaceidx = 0;
  583. struct sockaddr_in6 target = {AF_INET6, htons(DHCPV6_CLIENT_PORT),
  584. 0, IN6ADDR_ANY_INIT, 0};
  585. int otype, olen;
  586. uint8_t *odata, *end = data + len;
  587. /* Relay DHCPv6 reply from server to client */
  588. struct dhcpv6_relay_header *h = (void*)data;
  589. syslog(LOG_DEBUG, "Got a DHCPv6-relay-reply");
  590. if (len < sizeof(*h) || h->msg_type != DHCPV6_MSG_RELAY_REPL)
  591. return;
  592. memcpy(&target.sin6_addr, &h->peer_address, sizeof(struct in6_addr));
  593. /* Go through options and find what we need */
  594. dhcpv6_for_each_option(h->options, end, otype, olen, odata) {
  595. if (otype == DHCPV6_OPT_INTERFACE_ID
  596. && olen == sizeof(ifaceidx)) {
  597. memcpy(&ifaceidx, odata, sizeof(ifaceidx));
  598. } else if (otype == DHCPV6_OPT_RELAY_MSG) {
  599. payload_data = odata;
  600. payload_len = olen;
  601. }
  602. }
  603. /* Invalid interface-id or basic payload */
  604. struct interface *iface = odhcpd_get_interface_by_index(ifaceidx);
  605. if (!iface || iface->master || !payload_data || payload_len < 4)
  606. return;
  607. bool is_authenticated = false;
  608. struct in6_addr *dns_ptr = NULL;
  609. size_t dns_count = 0;
  610. /* If the payload is relay-reply we have to send to the server port */
  611. if (payload_data[0] == DHCPV6_MSG_RELAY_REPL) {
  612. target.sin6_port = htons(DHCPV6_SERVER_PORT);
  613. } else { /* Go through the payload data */
  614. struct dhcpv6_client_header *h = (void*)payload_data;
  615. end = payload_data + payload_len;
  616. dhcpv6_for_each_option(&h[1], end, otype, olen, odata) {
  617. if (otype == DHCPV6_OPT_DNS_SERVERS && olen >= 16) {
  618. dns_ptr = (struct in6_addr*)odata;
  619. dns_count = olen / 16;
  620. } else if (otype == DHCPV6_OPT_AUTH) {
  621. is_authenticated = true;
  622. }
  623. }
  624. }
  625. /* Rewrite DNS servers if requested */
  626. if (iface->always_rewrite_dns && dns_ptr && dns_count > 0) {
  627. if (is_authenticated)
  628. return; /* Impossible to rewrite */
  629. const struct in6_addr *rewrite = iface->dns;
  630. struct in6_addr addr;
  631. size_t rewrite_cnt = iface->dns_cnt;
  632. if (rewrite_cnt == 0) {
  633. if (odhcpd_get_interface_dns_addr(iface, &addr))
  634. return; /* Unable to get interface address */
  635. rewrite = &addr;
  636. rewrite_cnt = 1;
  637. }
  638. /* Copy over any other addresses */
  639. for (size_t i = 0; i < dns_count; ++i) {
  640. size_t j = (i < rewrite_cnt) ? i : rewrite_cnt - 1;
  641. memcpy(&dns_ptr[i], &rewrite[j], sizeof(*rewrite));
  642. }
  643. }
  644. struct iovec iov = {payload_data, payload_len};
  645. syslog(LOG_DEBUG, "Sending a DHCPv6-reply on %s", iface->name);
  646. odhcpd_send(iface->dhcpv6_event.uloop.fd, &target, &iov, 1, iface);
  647. }
  648. static struct odhcpd_ipaddr *relay_link_address(struct interface *iface)
  649. {
  650. struct odhcpd_ipaddr *addr = NULL;
  651. time_t now = odhcpd_time();
  652. for (size_t i = 0; i < iface->addr6_len; i++) {
  653. if (iface->addr6[i].valid_lt <= (uint32_t)now)
  654. continue;
  655. if (iface->addr6[i].preferred_lt > (uint32_t)now) {
  656. addr = &iface->addr6[i];
  657. break;
  658. }
  659. if (!addr || (iface->addr6[i].valid_lt > addr->valid_lt))
  660. addr = &iface->addr6[i];
  661. }
  662. return addr;
  663. }
  664. /* Relay client request (regular DHCPv6-relay) */
  665. static void relay_client_request(struct sockaddr_in6 *source,
  666. const void *data, size_t len, struct interface *iface)
  667. {
  668. const struct dhcpv6_relay_header *h = data;
  669. /* Construct our forwarding envelope */
  670. struct dhcpv6_relay_forward_envelope hdr = {
  671. .msg_type = DHCPV6_MSG_RELAY_FORW,
  672. .hop_count = 0,
  673. .interface_id_type = htons(DHCPV6_OPT_INTERFACE_ID),
  674. .interface_id_len = htons(sizeof(uint32_t)),
  675. .relay_message_type = htons(DHCPV6_OPT_RELAY_MSG),
  676. .relay_message_len = htons(len),
  677. };
  678. struct iovec iov[2] = {{&hdr, sizeof(hdr)}, {(void *)data, len}};
  679. struct interface *c;
  680. struct odhcpd_ipaddr *ip;
  681. struct sockaddr_in6 s;
  682. if (h->msg_type == DHCPV6_MSG_RELAY_REPL ||
  683. h->msg_type == DHCPV6_MSG_RECONFIGURE ||
  684. h->msg_type == DHCPV6_MSG_REPLY ||
  685. h->msg_type == DHCPV6_MSG_ADVERTISE)
  686. return; /* Invalid message types for client */
  687. syslog(LOG_DEBUG, "Got a DHCPv6-request on %s", iface->name);
  688. if (h->msg_type == DHCPV6_MSG_RELAY_FORW) { /* handle relay-forward */
  689. if (h->hop_count >= DHCPV6_HOP_COUNT_LIMIT)
  690. return; /* Invalid hop count */
  691. hdr.hop_count = h->hop_count + 1;
  692. }
  693. /* use memcpy here as the destination fields are unaligned */
  694. memcpy(&hdr.peer_address, &source->sin6_addr, sizeof(struct in6_addr));
  695. memcpy(&hdr.interface_id_data, &iface->ifindex, sizeof(iface->ifindex));
  696. /* Detect public IP of slave interface to use as link-address */
  697. ip = relay_link_address(iface);
  698. if (ip)
  699. memcpy(&hdr.link_address, &ip->addr.in6, sizeof(hdr.link_address));
  700. memset(&s, 0, sizeof(s));
  701. s.sin6_family = AF_INET6;
  702. s.sin6_port = htons(DHCPV6_SERVER_PORT);
  703. inet_pton(AF_INET6, ALL_DHCPV6_SERVERS, &s.sin6_addr);
  704. avl_for_each_element(&interfaces, c, avl) {
  705. if (!c->master || c->dhcpv6 != MODE_RELAY)
  706. continue;
  707. if (!ip) {
  708. /* No suitable address! Is the slave not configured yet?
  709. * Detect public IP of master interface and use it instead
  710. * This is WRONG and probably violates the RFC. However
  711. * otherwise we have a hen and egg problem because the
  712. * slave-interface cannot be auto-configured. */
  713. ip = relay_link_address(c);
  714. if (!ip)
  715. continue; /* Could not obtain a suitable address */
  716. memcpy(&hdr.link_address, &ip->addr.in6, sizeof(hdr.link_address));
  717. ip = NULL;
  718. }
  719. syslog(LOG_DEBUG, "Sending a DHCPv6-relay-forward on %s", c->name);
  720. odhcpd_send(c->dhcpv6_event.uloop.fd, &s, iov, 2, c);
  721. }
  722. }