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

This page was automatically generated by LXR 0.3.1.  •  OpenWrt