• source navigation  • diff markup  • identifier search  • freetext search  • 

Sources/odhcpd/src/dhcpv6.c

  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 <arpa/inet.h>
 20 
 21 #include <libubox/utils.h>
 22 
 23 #include "odhcpd.h"
 24 #include "dhcpv6.h"
 25 #include "dhcpv6-pxe.h"
 26 #ifdef DHCPV4_SUPPORT
 27 #include "dhcpv4.h"
 28 #endif
 29 
 30 static void relay_client_request(struct sockaddr_in6 *source,
 31                 const void *data, size_t len, struct interface *iface);
 32 static void relay_server_response(uint8_t *data, size_t len);
 33 
 34 static void handle_dhcpv6(void *addr, void *data, size_t len,
 35                 struct interface *iface, void *dest);
 36 static void handle_client_request(void *addr, void *data, size_t len,
 37                 struct interface *iface, void *dest_addr);
 38 
 39 
 40 /* Create socket and register events */
 41 int dhcpv6_init(void)
 42 {
 43         return dhcpv6_ia_init();
 44 }
 45 
 46 int dhcpv6_setup_interface(struct interface *iface, bool enable)
 47 {
 48         int ret = 0;
 49 
 50         enable = enable && (iface->dhcpv6 != MODE_DISABLED);
 51 
 52         if (iface->dhcpv6_event.uloop.fd >= 0) {
 53                 uloop_fd_delete(&iface->dhcpv6_event.uloop);
 54                 close(iface->dhcpv6_event.uloop.fd);
 55                 iface->dhcpv6_event.uloop.fd = -1;
 56         }
 57 
 58         /* Configure multicast settings */
 59         if (enable) {
 60                 struct sockaddr_in6 bind_addr = {AF_INET6, htons(DHCPV6_SERVER_PORT),
 61                                         0, IN6ADDR_ANY_INIT, 0};
 62                 struct ipv6_mreq mreq;
 63                 int val = 1;
 64 
 65                 iface->dhcpv6_event.uloop.fd = socket(AF_INET6, SOCK_DGRAM | SOCK_CLOEXEC, IPPROTO_UDP);
 66                 if (iface->dhcpv6_event.uloop.fd < 0) {
 67                         error("socket(AF_INET6): %m");
 68                         ret = -1;
 69                         goto out;
 70                 }
 71 
 72                 /* Basic IPv6 configuration */
 73                 if (setsockopt(iface->dhcpv6_event.uloop.fd, SOL_SOCKET, SO_BINDTODEVICE,
 74                                         iface->ifname, strlen(iface->ifname)) < 0) {
 75                         error("setsockopt(SO_BINDTODEVICE): %m");
 76                         ret = -1;
 77                         goto out;
 78                 }
 79 
 80                 if (setsockopt(iface->dhcpv6_event.uloop.fd, IPPROTO_IPV6, IPV6_V6ONLY,
 81                                         &val, sizeof(val)) < 0) {
 82                         error("setsockopt(IPV6_V6ONLY): %m");
 83                         ret = -1;
 84                         goto out;
 85                 }
 86 
 87                 if (setsockopt(iface->dhcpv6_event.uloop.fd, SOL_SOCKET, SO_REUSEADDR,
 88                                         &val, sizeof(val)) < 0) {
 89                         error("setsockopt(SO_REUSEADDR): %m");
 90                         ret = -1;
 91                         goto out;
 92                 }
 93 
 94                 if (setsockopt(iface->dhcpv6_event.uloop.fd, IPPROTO_IPV6, IPV6_RECVPKTINFO,
 95                                         &val, sizeof(val)) < 0) {
 96                         error("setsockopt(IPV6_RECVPKTINFO): %m");
 97                         ret = -1;
 98                         goto out;
 99                 }
100 
101                 val = DHCPV6_HOP_COUNT_LIMIT;
102                 if (setsockopt(iface->dhcpv6_event.uloop.fd, IPPROTO_IPV6, IPV6_MULTICAST_HOPS,
103                                         &val, sizeof(val)) < 0) {
104                         error("setsockopt(IPV6_MULTICAST_HOPS): %m");
105                         ret = -1;
106                         goto out;
107                 }
108 
109                 val = 0;
110                 if (setsockopt(iface->dhcpv6_event.uloop.fd, IPPROTO_IPV6, IPV6_MULTICAST_LOOP,
111                                         &val, sizeof(val)) < 0) {
112                         error("setsockopt(IPV6_MULTICAST_LOOP): %m");
113                         ret = -1;
114                         goto out;
115                 }
116 
117                 if (bind(iface->dhcpv6_event.uloop.fd, (struct sockaddr*)&bind_addr,
118                                         sizeof(bind_addr)) < 0) {
119                         error("bind(): %m");
120                         ret = -1;
121                         goto out;
122                 }
123 
124                 memset(&mreq, 0, sizeof(mreq));
125                 inet_pton(AF_INET6, ALL_DHCPV6_RELAYS, &mreq.ipv6mr_multiaddr);
126                 mreq.ipv6mr_interface = iface->ifindex;
127 
128                 if (setsockopt(iface->dhcpv6_event.uloop.fd, IPPROTO_IPV6, IPV6_ADD_MEMBERSHIP,
129                                         &mreq, sizeof(mreq)) < 0) {
130                         error("setsockopt(IPV6_ADD_MEMBERSHIP): %m");
131                         ret = -1;
132                         goto out;
133                 }
134 
135                 if (iface->dhcpv6 == MODE_SERVER) {
136                         memset(&mreq, 0, sizeof(mreq));
137                         inet_pton(AF_INET6, ALL_DHCPV6_SERVERS, &mreq.ipv6mr_multiaddr);
138                         mreq.ipv6mr_interface = iface->ifindex;
139 
140                         if (setsockopt(iface->dhcpv6_event.uloop.fd, IPPROTO_IPV6, IPV6_ADD_MEMBERSHIP,
141                                                 &mreq, sizeof(mreq)) < 0) {
142                                 error("setsockopt(IPV6_ADD_MEMBERSHIP): %m");
143                                 ret = -1;
144                                 goto out;
145                         }
146                 }
147 
148                 iface->dhcpv6_event.handle_dgram = handle_dhcpv6;
149                 odhcpd_register(&iface->dhcpv6_event);
150         }
151 
152         ret = dhcpv6_ia_setup_interface(iface, enable);
153 
154 out:
155         if (ret < 0 && iface->dhcpv6_event.uloop.fd >= 0) {
156                 close(iface->dhcpv6_event.uloop.fd);
157                 iface->dhcpv6_event.uloop.fd = -1;
158         }
159 
160         return ret;
161 }
162 
163 enum {
164         IOV_NESTED = 0,
165         IOV_DEST,
166         IOV_CLIENTID,
167         IOV_MAXRT,
168 #define IOV_STAT IOV_MAXRT
169         IOV_RAPID_COMMIT,
170         IOV_DNS,
171         IOV_DNS_ADDR,
172         IOV_SEARCH,
173         IOV_SEARCH_DOMAIN,
174         IOV_PDBUF,
175 #define IOV_REFRESH IOV_PDBUF
176         IOV_DHCPV6_RAW,
177         IOV_NTP,
178         IOV_NTP_ADDR,
179         IOV_SNTP,
180         IOV_SNTP_ADDR,
181         IOV_RELAY_MSG,
182         IOV_DHCPV4O6_SERVER,
183         IOV_DNR,
184         IOV_BOOTFILE_URL,
185         IOV_POSIX_TZ,
186         IOV_POSIX_TZ_STR,
187         IOV_TZDB_TZ,
188         IOV_TZDB_TZ_STR,
189         IOV_CAPT_PORTAL,
190         IOV_CAPT_PORTAL_URI,
191         IOV_TOTAL
192 };
193 
194 static void handle_nested_message(uint8_t *data, size_t len,
195                                   struct dhcpv6_client_header **c_hdr, uint8_t **opts,
196                                   uint8_t **end, struct iovec iov[IOV_TOTAL])
197 {
198         struct dhcpv6_relay_header *r_hdr = (struct dhcpv6_relay_header *)data;
199         uint16_t otype, olen;
200         uint8_t *odata;
201 
202         if (iov[IOV_NESTED].iov_base == NULL) {
203                 iov[IOV_NESTED].iov_base = data;
204                 iov[IOV_NESTED].iov_len = len;
205         }
206 
207         if (len < sizeof(struct dhcpv6_client_header))
208                 return;
209 
210         if (r_hdr->msg_type != DHCPV6_MSG_RELAY_FORW) {
211                 iov[IOV_NESTED].iov_len = data - (uint8_t *)iov[IOV_NESTED].iov_base;
212                 *c_hdr = (void *)data;
213                 *opts = (uint8_t *)&(*c_hdr)[1];
214                 *end = data + len;
215                 return;
216         }
217 
218         dhcpv6_for_each_option(r_hdr->options, data + len, otype, olen, odata) {
219                 if (otype == DHCPV6_OPT_RELAY_MSG) {
220                         iov[IOV_RELAY_MSG].iov_base = odata + olen;
221                         iov[IOV_RELAY_MSG].iov_len = (((uint8_t *)iov[IOV_NESTED].iov_base) +
222                                         iov[IOV_NESTED].iov_len) - (odata + olen);
223                         handle_nested_message(odata, olen, c_hdr, opts, end, iov);
224                         return;
225                 }
226         }
227 }
228 
229 
230 static void update_nested_message(uint8_t *data, size_t len, ssize_t pdiff)
231 {
232         struct dhcpv6_relay_header *hdr = (struct dhcpv6_relay_header*)data;
233         if (hdr->msg_type != DHCPV6_MSG_RELAY_FORW)
234                 return;
235 
236         hdr->msg_type = DHCPV6_MSG_RELAY_REPL;
237 
238         uint16_t otype, olen;
239         uint8_t *odata;
240         dhcpv6_for_each_option(hdr->options, data + len, otype, olen, odata) {
241                 if (otype == DHCPV6_OPT_RELAY_MSG) {
242                         olen += pdiff;
243                         odata[-2] = (olen >> 8) & 0xff;
244                         odata[-1] = olen & 0xff;
245                         update_nested_message(odata, olen - pdiff, pdiff);
246                         return;
247                 }
248         }
249 }
250 
251 #ifdef DHCPV4_SUPPORT
252 
253 struct dhcpv4_msg_data {
254         uint8_t *msg;
255         size_t maxsize;
256         ssize_t len;
257 };
258 
259 static ssize_t dhcpv6_4o6_send_reply(struct iovec *iov, size_t iov_len,
260                                      _o_unused struct sockaddr *dest,
261                                      _o_unused socklen_t dest_len,
262                                      void *opaque)
263 {
264         struct dhcpv4_msg_data *reply = opaque;
265         size_t len = 0;
266 
267         for (size_t i = 0; i < iov_len; i++)
268                 len += iov[i].iov_len;
269 
270         if (len > reply->maxsize) {
271                 error("4o6: reply too large, %zu > %zu", len, reply->maxsize);
272                 reply->len = -1;
273                 return -1;
274         }
275 
276         for (size_t i = 0, off = 0; i < iov_len; i++) {
277                 memcpy(reply->msg + off, iov[i].iov_base, iov[i].iov_len);
278                 off += iov[i].iov_len;
279         }
280         reply->len = len;
281 
282         return len;
283 }
284 
285 static ssize_t dhcpv6_4o6_query(uint8_t *buf, size_t buflen,
286                                 struct interface *iface,
287                                 const struct sockaddr_in6 *addr,
288                                 const void *data, const uint8_t *end)
289 {
290         const struct dhcpv6_client_header *hdr = data;
291         uint16_t otype, olen, msgv4_len = 0;
292         uint8_t *msgv4_data = NULL;
293         uint8_t *start = (uint8_t *)&hdr[1], *odata;
294         struct sockaddr_in addrv4;
295         struct dhcpv4_msg_data reply = { .msg = buf, .maxsize = buflen, .len = -1 };
296 
297         dhcpv6_for_each_option(start, end, otype, olen, odata) {
298                 if (otype == DHCPV6_OPT_DHCPV4_MSG) {
299                         msgv4_data = odata;
300                         msgv4_len = olen;
301                 }
302         }
303 
304         if (!msgv4_data || msgv4_len == 0) {
305                 error("4o6: missing DHCPv4 message option (%d)", DHCPV6_OPT_DHCPV4_MSG);
306                 return -1;
307         }
308 
309         // Dummy IPv4 address
310         memset(&addrv4, 0, sizeof(addrv4));
311         addrv4.sin_family = AF_INET;
312         addrv4.sin_addr.s_addr = INADDR_ANY;
313         addrv4.sin_port = htons(DHCPV4_CLIENT_PORT);
314 
315         dhcpv4_handle_msg(&addrv4, msgv4_data, msgv4_len,
316                           iface, NULL, dhcpv6_4o6_send_reply, &reply);
317 
318         return reply.len;
319 }
320 #endif  /* DHCPV4_SUPPORT */
321 
322 /* Simple DHCPv6-server for information requests */
323 static void handle_client_request(void *addr, void *data, size_t len,
324                 struct interface *iface, void *dest_addr)
325 {
326         struct dhcpv6_client_header *hdr = data;
327         uint8_t *opts = (uint8_t *)&hdr[1], *opts_end = (uint8_t *)data + len;
328         bool o_rapid_commit = false;
329 
330         if (len < sizeof(*hdr))
331                 return;
332 
333         switch (hdr->msg_type) {
334         /* Valid message types for clients */
335         case DHCPV6_MSG_SOLICIT:
336         case DHCPV6_MSG_REQUEST:
337         case DHCPV6_MSG_CONFIRM:
338         case DHCPV6_MSG_RENEW:
339         case DHCPV6_MSG_REBIND:
340         case DHCPV6_MSG_RELEASE:
341         case DHCPV6_MSG_DECLINE:
342         case DHCPV6_MSG_INFORMATION_REQUEST:
343         case DHCPV6_MSG_RELAY_FORW:
344 #ifdef DHCPV4_SUPPORT
345         /* if we include DHCPV4 support, handle this message type */
346         case DHCPV6_MSG_DHCPV4_QUERY:
347 #endif
348                 break;
349         /* Invalid message types for clients i.e. server messages */
350         case DHCPV6_MSG_ADVERTISE:
351         case DHCPV6_MSG_REPLY:
352         case DHCPV6_MSG_RECONFIGURE:
353         case DHCPV6_MSG_RELAY_REPL:
354 #ifndef DHCPV4_SUPPORT
355         /* if we omit DHCPV4 support, ignore this client message type */
356         case DHCPV6_MSG_DHCPV4_QUERY:
357 #endif
358         case DHCPV6_MSG_DHCPV4_RESPONSE:
359         default:
360                 return;
361         }
362 
363         debug("Got a DHCPv6-request on %s", iface->name);
364 
365         /* Construct reply message */
366         struct _o_packed {
367                 uint8_t msg_type;
368                 uint8_t tr_id[3];
369                 uint16_t serverid_type;
370                 uint16_t serverid_length;
371                 uint8_t serverid_buf[DUID_MAX_LEN];
372         } dest = {
373                 .msg_type = DHCPV6_MSG_REPLY,
374                 .serverid_type = htons(DHCPV6_OPT_SERVERID),
375                 .serverid_length = 0,
376                 .serverid_buf = { 0 },
377         };
378 
379         if (config.default_duid_len > 0) {
380                 memcpy(dest.serverid_buf, config.default_duid, config.default_duid_len);
381                 dest.serverid_length = htons(config.default_duid_len);
382         } else {
383                 uint16_t duid_ll_hdr[] = { htons(DUID_TYPE_LL), htons(ARPHRD_ETHER) };
384                 memcpy(dest.serverid_buf, duid_ll_hdr, sizeof(duid_ll_hdr));
385                 odhcpd_get_mac(iface, &dest.serverid_buf[sizeof(duid_ll_hdr)]);
386                 dest.serverid_length = htons(sizeof(duid_ll_hdr) + ETH_ALEN);
387         }
388 
389         struct _o_packed {
390                 uint16_t type;
391                 uint16_t len;
392                 uint8_t buf[DUID_MAX_LEN];
393         } clientid = {
394                 .type = htons(DHCPV6_OPT_CLIENTID),
395                 .len = 0,
396                 .buf = { 0 },
397         };
398 
399         struct _o_packed {
400                 uint16_t type;
401                 uint16_t len;
402                 uint32_t value;
403         } maxrt = {htons(DHCPV6_OPT_SOL_MAX_RT), htons(sizeof(maxrt) - DHCPV6_OPT_HDR_SIZE),
404                         htonl(60)};
405 
406         struct _o_packed {
407                 uint16_t type;
408                 uint16_t len;
409         } rapid_commit = {htons(DHCPV6_OPT_RAPID_COMMIT), 0};
410 
411         struct _o_packed {
412                 uint16_t type;
413                 uint16_t len;
414                 uint16_t value;
415         } stat = {htons(DHCPV6_OPT_STATUS), htons(sizeof(stat) - DHCPV6_OPT_HDR_SIZE),
416                         htons(DHCPV6_STATUS_USEMULTICAST)};
417 
418         struct _o_packed {
419                 uint16_t type;
420                 uint16_t len;
421                 uint32_t value;
422         } refresh = {htons(DHCPV6_OPT_INFO_REFRESH), htons(sizeof(uint32_t)),
423                         htonl(600)};
424 
425         struct in6_addr *dns_addrs6 = NULL, dns_addr6;
426         size_t dns_addrs6_cnt = 0;
427 
428         if (iface->dns_addrs6_cnt > 0) {
429                 dns_addrs6 = iface->dns_addrs6;
430                 dns_addrs6_cnt = iface->dns_addrs6_cnt;
431         } else if (!odhcpd_get_interface_dns_addr6(iface, &dns_addr6)) {
432                 dns_addrs6 = &dns_addr6;
433                 dns_addrs6_cnt = 1;
434         }
435 
436         struct {
437                 uint16_t type;
438                 uint16_t len;
439         } dns_hdr = { htons(DHCPV6_OPT_DNS_SERVERS), htons(dns_addrs6_cnt * sizeof(*dns_addrs6)) };
440 
441         /* SNTP */
442         struct in6_addr *sntp_addr_ptr = iface->dhcpv6_sntp;
443         size_t sntp_cnt = 0;
444         struct {
445                 uint16_t type;
446                 uint16_t len;
447         } dhcpv6_sntp;
448 
449         /* RFC 4833 - Timezones */
450         bool posix_want = false;
451         uint8_t *posix_ptr = sys_conf.posix_tz;
452         uint16_t posix_len = sys_conf.posix_tz_len;
453         /* RFC 4833 - OPTION_NEW_POSIX_TIMEZONE (41)
454          * e.g. EST5EDT4,M3.2.0/02:00,M11.1.0/02:00
455          * Variable-length opaque tz_string blob.
456          */
457         struct {
458                 uint16_t type;
459                 uint16_t len;
460         } posix_tz;
461 
462         bool tzdb_want = false;
463         uint8_t *tzdb_ptr = sys_conf.tzdb_tz;
464         uint16_t tzdb_len = sys_conf.tzdb_tz_len;
465         /* RFC 4833 - OPTION_NEW_TZDB_TIMEZONE (42)
466          * e.g. Europe/Zurich
467          * Variable-length opaque tz_name blob.
468          */
469         struct {
470                 uint16_t type;
471                 uint16_t len;
472         } tzdb_tz;
473 
474         /* NTP */
475         uint8_t *ntp_ptr = iface->dhcpv6_ntp;
476         uint16_t ntp_len = iface->dhcpv6_ntp_len;
477         size_t ntp_cnt = 0;
478         struct {
479                 uint16_t type;
480                 uint16_t len;
481         } ntp;
482 
483         /* DNR */
484         struct dhcpv6_dnr {
485                 uint16_t type;
486                 uint16_t len;
487                 uint16_t priority;
488                 uint16_t adn_len;
489                 uint8_t body[];
490         };
491         struct dhcpv6_dnr *dnrs = NULL;
492         size_t dnrs_len = 0;
493 
494         /* RFC8910 Captive-Portal URI */
495         uint8_t *capt_portal_ptr = (uint8_t *)iface->captive_portal_uri;
496         size_t capt_portal_len = iface->captive_portal_uri_len;
497         struct {
498                 uint16_t type;
499                 uint16_t len;
500         } capt_portal;
501 
502         /* RFC8910 §2:
503          * DHCP servers MAY send the Captive Portal option without any explicit request
504          * If it is configured, send it.
505          */
506         capt_portal.type = htons(DHCPV6_OPT_CAPTIVE_PORTAL);
507         capt_portal.len = htons(capt_portal_len);
508 
509         uint16_t otype, olen;
510         uint8_t *odata;
511         uint16_t *reqopts = NULL;
512         size_t reqopts_cnt = 0;
513 
514         /* FIXME: this should be merged with the second loop further down */
515         dhcpv6_for_each_option(opts, opts_end, otype, olen, odata) {
516                 /* Requested options, array of uint16_t, RFC 8415 §21.7 */
517                 if (otype == DHCPV6_OPT_ORO) {
518                         reqopts_cnt = olen / sizeof(uint16_t);
519                         reqopts = (uint16_t *)odata;
520                         break;
521                 }
522         }
523 
524         /* Requested options */
525         for (size_t i = 0; i < reqopts_cnt; i++) {
526                 uint16_t opt = ntohs(reqopts[i]);
527 
528                 switch (opt) {
529                 case DHCPV6_OPT_SNTP_SERVERS:
530                         sntp_cnt = iface->dhcpv6_sntp_cnt;
531                         dhcpv6_sntp.type = htons(DHCPV6_OPT_SNTP_SERVERS);
532                         dhcpv6_sntp.len = htons(sntp_cnt * sizeof(*sntp_addr_ptr));
533                         break;
534 
535                 case DHCPV6_OPT_NTP_SERVERS:
536                         ntp_cnt = iface->dhcpv6_ntp_cnt;
537                         ntp.type = htons(DHCPV6_OPT_NTP_SERVERS);
538                         ntp.len = htons(ntp_len);
539                         break;
540 
541                 case DHCPV6_OPT_NEW_POSIX_TIMEZONE:
542                         posix_want = true;
543                         posix_tz.type = htons(DHCPV6_OPT_NEW_POSIX_TIMEZONE);
544                         posix_tz.len = htons(posix_len);
545                         break;
546 
547                 case DHCPV6_OPT_NEW_TZDB_TIMEZONE:
548                         tzdb_want = true;
549                         tzdb_tz.type = htons(DHCPV6_OPT_NEW_TZDB_TIMEZONE);
550                         tzdb_tz.len = htons(tzdb_len);
551                         break;
552 
553                 case DHCPV6_OPT_DNR:
554                         for (size_t j = 0; j < iface->dnr_cnt; j++) {
555                                 struct dnr_options *dnr = &iface->dnr[j];
556 
557                                 if (dnr->addr6_cnt == 0 && dnr->addr4_cnt > 0)
558                                         continue;
559 
560                                 dnrs_len += sizeof(struct dhcpv6_dnr);
561                                 dnrs_len += dnr->adn_len;
562 
563                                 if (dnr->addr6_cnt > 0 || dnr->svc_len > 0) {
564                                         dnrs_len += sizeof(uint16_t);
565                                         dnrs_len += dnr->addr6_cnt * sizeof(*dnr->addr6);
566                                         dnrs_len += dnr->svc_len;
567                                 }
568                         }
569 
570                         dnrs = alloca(dnrs_len);
571                         uint8_t *pos = (uint8_t *)dnrs;
572 
573                         for (size_t j = 0; j < iface->dnr_cnt; j++) {
574                                 struct dnr_options *dnr = &iface->dnr[j];
575                                 struct dhcpv6_dnr *d6dnr = (struct dhcpv6_dnr *)pos;
576                                 uint16_t d6dnr_type_be = htons(DHCPV6_OPT_DNR);
577                                 uint16_t d6dnr_len = 2 * sizeof(uint16_t) + dnr->adn_len;
578                                 uint16_t d6dnr_len_be;
579                                 uint16_t d6dnr_priority_be = htons(dnr->priority);
580                                 uint16_t d6dnr_adn_len_be = htons(dnr->adn_len);
581 
582                                 if (dnr->addr6_cnt == 0 && dnr->addr4_cnt > 0)
583                                         continue;
584 
585                                 /* memcpy as the struct is unaligned */
586                                 memcpy(&d6dnr->type, &d6dnr_type_be, sizeof(d6dnr_type_be));
587                                 memcpy(&d6dnr->priority, &d6dnr_priority_be, sizeof(d6dnr_priority_be));
588                                 memcpy(&d6dnr->adn_len, &d6dnr_adn_len_be, sizeof(d6dnr_adn_len_be));
589 
590                                 pos = d6dnr->body;
591                                 memcpy(pos, dnr->adn, dnr->adn_len);
592                                 pos += dnr->adn_len;
593 
594                                 if (dnr->addr6_cnt > 0 || dnr->svc_len > 0) {
595                                         uint16_t addr6_len = dnr->addr6_cnt * sizeof(*dnr->addr6);
596                                         uint16_t addr6_len_be = htons(addr6_len);
597 
598                                         memcpy(pos, &addr6_len_be, sizeof(addr6_len_be));
599                                         pos += sizeof(addr6_len_be);
600                                         memcpy(pos, dnr->addr6, addr6_len);
601                                         pos += addr6_len;
602                                         memcpy(pos, dnr->svc, dnr->svc_len);
603                                         pos += dnr->svc_len;
604 
605                                         d6dnr_len += sizeof(addr6_len_be) + addr6_len + dnr->svc_len;
606                                 }
607 
608                                 d6dnr_len_be = htons(d6dnr_len);
609                                 memcpy(&d6dnr->len, &d6dnr_len_be, sizeof(d6dnr_len_be));
610                         }
611                         break;
612                 }
613         }
614 
615         /* DNS Search options */
616         struct {
617                 uint16_t type;
618                 uint16_t len;
619         } dns_search_hdr = { htons(DHCPV6_OPT_DNS_DOMAIN), htons(iface->dns_search_len) };
620 
621 
622         struct _o_packed dhcpv4o6_server {
623                 uint16_t type;
624                 uint16_t len;
625                 struct in6_addr addr;
626         } dhcpv4o6_server = {htons(DHCPV6_OPT_4O6_SERVER), htons(sizeof(struct in6_addr)),
627                         IN6ADDR_ANY_INIT};
628 
629         uint8_t pdbuf[512];
630         struct iovec iov[IOV_TOTAL] = {
631                 [IOV_NESTED] = {NULL, 0},
632                 [IOV_DEST] = {&dest, offsetof(typeof(dest), serverid_buf) + ntohs(dest.serverid_length) },
633                 [IOV_CLIENTID] = {&clientid, 0},
634                 [IOV_MAXRT] = {&maxrt, sizeof(maxrt)},
635                 [IOV_RAPID_COMMIT] = {&rapid_commit, 0},
636                 [IOV_DNS] = { &dns_hdr, (dns_addrs6_cnt) ? sizeof(dns_hdr) : 0},
637                 [IOV_DNS_ADDR] = { dns_addrs6, dns_addrs6_cnt * sizeof(*dns_addrs6) },
638                 [IOV_SEARCH] = { &dns_search_hdr, iface->dns_search_len ? sizeof(dns_search_hdr) : 0 },
639                 [IOV_SEARCH_DOMAIN] = { iface->dns_search, iface->dns_search_len },
640                 [IOV_PDBUF] = {pdbuf, 0},
641                 [IOV_DHCPV6_RAW] = {iface->dhcpv6_raw, iface->dhcpv6_raw_len},
642                 [IOV_NTP] = {&ntp, (ntp_cnt) ? sizeof(ntp) : 0},
643                 [IOV_NTP_ADDR] = {ntp_ptr, (ntp_cnt) ? ntp_len : 0},
644                 [IOV_SNTP] = {&dhcpv6_sntp, (sntp_cnt) ? sizeof(dhcpv6_sntp) : 0},
645                 [IOV_SNTP_ADDR] = {sntp_addr_ptr, sntp_cnt * sizeof(*sntp_addr_ptr)},
646                 [IOV_POSIX_TZ] = {&posix_tz, (posix_want) ? sizeof(posix_tz) : 0},
647                 [IOV_POSIX_TZ_STR] = {posix_ptr, (posix_want) ? posix_len : 0 },
648                 [IOV_TZDB_TZ] = {&tzdb_tz, (tzdb_want) ? sizeof(tzdb_tz) : 0},
649                 [IOV_TZDB_TZ_STR] = {tzdb_ptr, (tzdb_want) ? tzdb_len : 0 },
650                 [IOV_DNR] = {dnrs, dnrs_len},
651                 [IOV_RELAY_MSG] = {NULL, 0},
652                 [IOV_DHCPV4O6_SERVER] = {&dhcpv4o6_server, 0},
653                 [IOV_CAPT_PORTAL] = {&capt_portal, capt_portal_len ? sizeof(capt_portal) : 0},
654                 [IOV_CAPT_PORTAL_URI] = {capt_portal_ptr, capt_portal_len ? capt_portal_len : 0},
655                 [IOV_BOOTFILE_URL] = {NULL, 0}
656         };
657 
658         if (hdr->msg_type == DHCPV6_MSG_RELAY_FORW)
659                 handle_nested_message(data, len, &hdr, &opts, &opts_end, iov);
660 
661         if (!IN6_IS_ADDR_MULTICAST((struct in6_addr *)dest_addr) && iov[IOV_NESTED].iov_len == 0 &&
662             (hdr->msg_type == DHCPV6_MSG_SOLICIT || hdr->msg_type == DHCPV6_MSG_CONFIRM ||
663              hdr->msg_type == DHCPV6_MSG_REBIND || hdr->msg_type == DHCPV6_MSG_INFORMATION_REQUEST))
664                 return;
665 
666         memcpy(dest.tr_id, hdr->transaction_id, sizeof(dest.tr_id));
667 
668         /* Go through options and find what we need */
669         dhcpv6_for_each_option(opts, opts_end, otype, olen, odata) {
670                 if (otype == DHCPV6_OPT_CLIENTID && olen <= DUID_MAX_LEN) {
671                         clientid.len = htons(olen);
672                         memcpy(clientid.buf, odata, olen);
673                         iov[IOV_CLIENTID].iov_len = offsetof(typeof(clientid), buf) + olen;
674                 } else if (otype == DHCPV6_OPT_SERVERID) {
675                         if (olen != ntohs(dest.serverid_length) ||
676                             memcmp(odata, &dest.serverid_buf, olen))
677                                 return; /* Not for us */
678                 } else if (otype == DHCPV6_OPT_RAPID_COMMIT && hdr->msg_type == DHCPV6_MSG_SOLICIT) {
679                         iov[IOV_RAPID_COMMIT].iov_len = sizeof(rapid_commit);
680                         o_rapid_commit = true;
681                 } else if (otype == DHCPV6_OPT_ORO) {
682                         for (int i=0; i < olen/2; i++) {
683                                 uint16_t option = ntohs(((uint16_t *)odata)[i]);
684 
685                                 switch (option) {
686 #ifdef DHCPV4_SUPPORT
687                                 case DHCPV6_OPT_4O6_SERVER:
688                                         if (iface->dhcpv4) {
689                                                 /* According to RFC 7341, 7.2. DHCP 4o6 Server Address Option Format:
690                                                  * This option may also carry no IPv6 addresses, which instructs the
691                                                  * client to use the All_DHCP_Relay_Agents_and_Servers multicast address
692                                                  * as the destination address.
693                                                  *
694                                                  * The ISC dhclient logs a missing IPv6 address as an error but seems to
695                                                  * work anyway:
696                                                  * dhcp4-o-dhcp6-server: expecting at least 16 bytes; got 0
697                                                  *
698                                                  * Include the All_DHCP_Relay_Agents_and_Servers multicast address
699                                                  * to make it explicit which address to use. */
700                                                 struct dhcpv4o6_server *server = iov[IOV_DHCPV4O6_SERVER].iov_base;
701 
702                                                 inet_pton(AF_INET6, ALL_DHCPV6_RELAYS, &server->addr);
703 
704                                                 iov[IOV_DHCPV4O6_SERVER].iov_len = sizeof(dhcpv4o6_server);
705                                         }
706                                         break;
707 #endif /* DHCPV4_SUPPORT */
708                                 default:
709                                         break;
710                                 }
711                         }
712                 } else if (otype == DHCPV6_OPT_CLIENT_ARCH) {
713                         uint16_t arch_code = ntohs(((uint16_t*)odata)[0]);
714                         ipv6_pxe_serve_boot_url(arch_code, &iov[IOV_BOOTFILE_URL]);
715                 }
716         }
717 
718         if (dest.serverid_length == clientid.len && 
719             !memcmp(clientid.buf, dest.serverid_buf, dest.serverid_length)) {
720                 /* Bail if we are in a network loop where we talk with ourself */
721                 return;         
722         }
723 
724         if (!IN6_IS_ADDR_MULTICAST((struct in6_addr *)dest_addr) && iov[IOV_NESTED].iov_len == 0 &&
725             (hdr->msg_type == DHCPV6_MSG_REQUEST || hdr->msg_type == DHCPV6_MSG_RENEW ||
726              hdr->msg_type == DHCPV6_MSG_RELEASE || hdr->msg_type == DHCPV6_MSG_DECLINE)) {
727                 iov[IOV_STAT].iov_base = &stat;
728                 iov[IOV_STAT].iov_len = sizeof(stat);
729 
730                 for (ssize_t i = IOV_STAT + 1; i < IOV_TOTAL; ++i)
731                         iov[i].iov_len = 0;
732 
733                 odhcpd_send(iface->dhcpv6_event.uloop.fd, addr, iov, ARRAY_SIZE(iov), iface);
734                 return;
735         }
736 
737         if (hdr->msg_type == DHCPV6_MSG_SOLICIT && !o_rapid_commit) {
738                 dest.msg_type = DHCPV6_MSG_ADVERTISE;
739         } else if (hdr->msg_type == DHCPV6_MSG_INFORMATION_REQUEST) {
740                 iov[IOV_REFRESH].iov_base = &refresh;
741                 iov[IOV_REFRESH].iov_len = sizeof(refresh);
742 
743                 /* Return inf max rt option in reply to information request */
744                 maxrt.type = htons(DHCPV6_OPT_INF_MAX_RT);
745         }
746 
747 #ifdef DHCPV4_SUPPORT
748         if (hdr->msg_type == DHCPV6_MSG_DHCPV4_QUERY) {
749                 struct _o_packed dhcpv4_msg_data {
750                         uint16_t type;
751                         uint16_t len;
752                         uint8_t msg[1];
753                 } *msg_opt = (struct dhcpv4_msg_data*)pdbuf;
754                 ssize_t msglen;
755 
756                 memset(pdbuf, 0, sizeof(pdbuf));
757 
758                 msglen = dhcpv6_4o6_query(msg_opt->msg, sizeof(pdbuf) - sizeof(*msg_opt) + 1,
759                                                 iface, addr, (const void *)hdr, opts_end);
760                 if (msglen <= 0) {
761                         error("4o6: query failed");
762                         return;
763                 }
764 
765                 msg_opt->type = htons(DHCPV6_OPT_DHCPV4_MSG);
766                 msg_opt->len = htons(msglen);
767                 iov[IOV_PDBUF].iov_len = sizeof(*msg_opt) - 1 + msglen;
768                 dest.msg_type = DHCPV6_MSG_DHCPV4_RESPONSE;
769         } else
770 #endif  /* DHCPV4_SUPPORT */
771 
772         if (hdr->msg_type != DHCPV6_MSG_INFORMATION_REQUEST) {
773                 ssize_t ialen = dhcpv6_ia_handle_IAs(pdbuf, sizeof(pdbuf), iface, addr, (const void *)hdr, opts_end);
774 
775                 iov[IOV_PDBUF].iov_len = ialen;
776                 if (ialen < 0 ||
777                     (ialen == 0 && (hdr->msg_type == DHCPV6_MSG_REBIND || hdr->msg_type == DHCPV6_MSG_CONFIRM)))
778                         return;
779         }
780 
781         if (iov[IOV_NESTED].iov_len > 0) /* Update length */
782                 update_nested_message(data, len, iov[IOV_DEST].iov_len + iov[IOV_MAXRT].iov_len +
783                                       iov[IOV_RAPID_COMMIT].iov_len + iov[IOV_DNS].iov_len +
784                                       iov[IOV_DNS_ADDR].iov_len + iov[IOV_SEARCH].iov_len +
785                                       iov[IOV_SEARCH_DOMAIN].iov_len + iov[IOV_PDBUF].iov_len +
786                                       iov[IOV_DHCPV4O6_SERVER].iov_len +
787                                       iov[IOV_DHCPV6_RAW].iov_len +
788                                       iov[IOV_NTP].iov_len + iov[IOV_NTP_ADDR].iov_len +
789                                       iov[IOV_SNTP].iov_len + iov[IOV_SNTP_ADDR].iov_len +
790                                       iov[IOV_POSIX_TZ].iov_len + iov[IOV_POSIX_TZ_STR].iov_len +
791                                       iov[IOV_TZDB_TZ].iov_len + iov[IOV_TZDB_TZ_STR].iov_len +
792                                       iov[IOV_CAPT_PORTAL].iov_len + iov[IOV_CAPT_PORTAL_URI].iov_len +
793                                       iov[IOV_DNR].iov_len + iov[IOV_BOOTFILE_URL].iov_len -
794                                       (4 + opts_end - opts));
795 
796         debug("Sending a DHCPv6-%s on %s", iov[IOV_NESTED].iov_len ? "relay-reply" : "reply", iface->name);
797 
798         odhcpd_send(iface->dhcpv6_event.uloop.fd, addr, iov, ARRAY_SIZE(iov), iface);
799 }
800 
801 
802 /* Central DHCPv6-relay handler */
803 static void handle_dhcpv6(void *addr, void *data, size_t len,
804                 struct interface *iface, void *dest_addr)
805 {
806         if (iface->dhcpv6 == MODE_SERVER) {
807                 handle_client_request(addr, data, len, iface, dest_addr);
808         } else if (iface->dhcpv6 == MODE_RELAY) {
809                 if (iface->master)
810                         relay_server_response(data, len);
811                 else
812                         relay_client_request(addr, data, len, iface);
813         }
814 }
815 
816 
817 /* Relay server response (regular relay server handling) */
818 static void relay_server_response(uint8_t *data, size_t len)
819 {
820         /* Information we need to gather */
821         uint8_t *payload_data = NULL;
822         size_t payload_len = 0;
823         int32_t ifaceidx = 0;
824         struct sockaddr_in6 target = {AF_INET6, htons(DHCPV6_CLIENT_PORT),
825                 0, IN6ADDR_ANY_INIT, 0};
826         uint16_t otype, olen;
827         uint8_t *odata, *end = data + len;
828         /* Relay DHCPv6 reply from server to client */
829         struct dhcpv6_relay_header *h = (void*)data;
830 
831         debug("Got a DHCPv6-relay-reply");
832 
833         if (len < sizeof(*h) || h->msg_type != DHCPV6_MSG_RELAY_REPL)
834                 return;
835 
836         memcpy(&target.sin6_addr, &h->peer_address, sizeof(struct in6_addr));
837 
838         /* Go through options and find what we need */
839         dhcpv6_for_each_option(h->options, end, otype, olen, odata) {
840                 if (otype == DHCPV6_OPT_INTERFACE_ID
841                                 && olen == sizeof(ifaceidx)) {
842                         memcpy(&ifaceidx, odata, sizeof(ifaceidx));
843                 } else if (otype == DHCPV6_OPT_RELAY_MSG) {
844                         payload_data = odata;
845                         payload_len = olen;
846                 }
847         }
848 
849         /* Invalid interface-id or basic payload */
850         struct interface *iface = odhcpd_get_interface_by_index(ifaceidx);
851         if (!iface || iface->master || !payload_data || payload_len < 4)
852                 return;
853 
854         bool is_authenticated = false;
855         struct in6_addr *dns_addrs6 = NULL;
856         size_t dns_addrs6_cnt = 0;
857 
858         /* If the payload is relay-reply we have to send to the server port */
859         if (payload_data[0] == DHCPV6_MSG_RELAY_REPL) {
860                 target.sin6_port = htons(DHCPV6_SERVER_PORT);
861         } else { /* Go through the payload data */
862                 struct dhcpv6_client_header *dch = (void*)payload_data;
863                 end = payload_data + payload_len;
864 
865                 dhcpv6_for_each_option(&dch[1], end, otype, olen, odata) {
866                         if (otype == DHCPV6_OPT_DNS_SERVERS && olen >= sizeof(struct in6_addr)) {
867                                 dns_addrs6 = (struct in6_addr*)odata;
868                                 dns_addrs6_cnt = olen / sizeof(struct in6_addr);
869                         } else if (otype == DHCPV6_OPT_AUTH) {
870                                 is_authenticated = true;
871                         }
872                 }
873         }
874 
875         /* Rewrite DNS servers if requested */
876         if (iface->always_rewrite_dns && dns_addrs6 && dns_addrs6_cnt > 0) {
877                 if (is_authenticated)
878                         return; /* Impossible to rewrite */
879 
880                 const struct in6_addr *rewrite = iface->dns_addrs6;
881                 struct in6_addr addr;
882                 size_t rewrite_cnt = iface->dns_addrs6_cnt;
883 
884                 if (rewrite_cnt == 0) {
885                         if (odhcpd_get_interface_dns_addr6(iface, &addr))
886                                 return; /* Unable to get interface address */
887 
888                         rewrite = &addr;
889                         rewrite_cnt = 1;
890                 }
891 
892                 /* Copy over any other addresses */
893                 for (size_t i = 0; i < dns_addrs6_cnt; ++i) {
894                         size_t j = (i < rewrite_cnt) ? i : rewrite_cnt - 1;
895                         memcpy(&dns_addrs6[i], &rewrite[j], sizeof(*rewrite));
896                 }
897         }
898 
899         struct iovec iov = {payload_data, payload_len};
900 
901         debug("Sending a DHCPv6-reply on %s", iface->name);
902 
903         odhcpd_send(iface->dhcpv6_event.uloop.fd, &target, &iov, 1, iface);
904 }
905 
906 static struct odhcpd_ipaddr *relay_link_address(struct interface *iface)
907 {
908         struct odhcpd_ipaddr *addr = NULL;
909         time_t now = odhcpd_time();
910 
911         for (size_t i = 0; i < iface->addr6_len; i++) {
912                 if (iface->addr6[i].valid_lt <= (uint32_t)now)
913                         continue;
914 
915                 if (iface->addr6[i].preferred_lt > (uint32_t)now) {
916                         addr = &iface->addr6[i];
917                         break;
918                 }
919 
920                 if (!addr || (iface->addr6[i].valid_lt > addr->valid_lt))
921                         addr = &iface->addr6[i];
922         }
923 
924         return addr;
925 }
926 
927 /* Relay client request (regular DHCPv6-relay) */
928 static void relay_client_request(struct sockaddr_in6 *source,
929                 const void *data, size_t len, struct interface *iface)
930 {
931         const struct dhcpv6_relay_header *h = data;
932         /* Construct our forwarding envelope */
933         struct dhcpv6_relay_forward_envelope hdr = {
934                 .msg_type = DHCPV6_MSG_RELAY_FORW,
935                 .hop_count = 0,
936                 .interface_id_type = htons(DHCPV6_OPT_INTERFACE_ID),
937                 .interface_id_len = htons(sizeof(uint32_t)),
938                 .relay_message_type = htons(DHCPV6_OPT_RELAY_MSG),
939                 .relay_message_len = htons(len),
940         };
941         struct iovec iov[2] = {{&hdr, sizeof(hdr)}, {(void *)data, len}};
942         struct interface *c;
943         struct odhcpd_ipaddr *ip;
944         struct sockaddr_in6 s;
945 
946         switch (h->msg_type) {
947         /* Valid message types from clients */
948         case DHCPV6_MSG_SOLICIT:
949         case DHCPV6_MSG_REQUEST:
950         case DHCPV6_MSG_CONFIRM:
951         case DHCPV6_MSG_RENEW:
952         case DHCPV6_MSG_REBIND:
953         case DHCPV6_MSG_RELEASE:
954         case DHCPV6_MSG_DECLINE:
955         case DHCPV6_MSG_INFORMATION_REQUEST:
956         case DHCPV6_MSG_RELAY_FORW:
957         case DHCPV6_MSG_DHCPV4_QUERY:
958                 break;
959         /* Invalid message types from clients i.e. server messages */
960         case DHCPV6_MSG_ADVERTISE:
961         case DHCPV6_MSG_REPLY:
962         case DHCPV6_MSG_RECONFIGURE:
963         case DHCPV6_MSG_RELAY_REPL:
964         case DHCPV6_MSG_DHCPV4_RESPONSE:
965                 return;
966         default:
967                 break;
968         }
969 
970         debug("Got a DHCPv6-request on %s", iface->name);
971 
972         if (h->msg_type == DHCPV6_MSG_RELAY_FORW) { /* handle relay-forward */
973                 if (h->hop_count >= DHCPV6_HOP_COUNT_LIMIT)
974                         return; /* Invalid hop count */
975 
976                 hdr.hop_count = h->hop_count + 1;
977         }
978 
979         /* use memcpy here as the destination fields are unaligned */
980         memcpy(&hdr.peer_address, &source->sin6_addr, sizeof(struct in6_addr));
981         memcpy(&hdr.interface_id_data, &iface->ifindex, sizeof(iface->ifindex));
982 
983         /* Detect public IP of slave interface to use as link-address */
984         ip = relay_link_address(iface);
985         if (ip)
986                 memcpy(&hdr.link_address, &ip->addr.in6, sizeof(hdr.link_address));
987 
988         memset(&s, 0, sizeof(s));
989         s.sin6_family = AF_INET6;
990         s.sin6_port = htons(DHCPV6_SERVER_PORT);
991         inet_pton(AF_INET6, ALL_DHCPV6_SERVERS, &s.sin6_addr);
992 
993         avl_for_each_element(&interfaces, c, avl) {
994                 if (!c->master || c->dhcpv6 != MODE_RELAY)
995                         continue;
996 
997                 if (!ip) {
998                         /* No suitable address! Is the slave not configured yet?
999                          * Detect public IP of master interface and use it instead
1000                          * This is WRONG and probably violates the RFC. However
1001                          * otherwise we have a hen and egg problem because the
1002                          * slave-interface cannot be auto-configured. */
1003                         ip = relay_link_address(c);
1004                         if (!ip)
1005                                 continue; /* Could not obtain a suitable address */
1006 
1007                         memcpy(&hdr.link_address, &ip->addr.in6, sizeof(hdr.link_address));
1008                         ip = NULL;
1009                 }
1010 
1011                 debug("Sending a DHCPv6-relay-forward on %s", c->name);
1012 
1013                 odhcpd_send(c->dhcpv6_event.uloop.fd, &s, iov, 2, c);
1014         }
1015 }
1016 

This page was automatically generated by LXR 0.3.1.  •  OpenWrt