Seems suitably related and tun.c is one of the
huge ones.
In preparation of adding UTs for the code.
Change-Id: I62a8f62b9c0938cfcb99d184b07034515c076303
Signed-off-by: Frank Lichtenheld <frank@lichtenheld.com>
Acked-by: Gert Doering <gert@greenie.muc.de>
Gerrit URL: https://gerrit.openvpn.net/c/openvpn/+/1265
Message-Id: <20251011082217.27568-1-gert@greenie.muc.de>
URL: https://sourceforge.net/p/openvpn/mailman/message/59245240/
Signed-off-by: Gert Doering <gert@greenie.muc.de>
| ... | ... |
@@ -185,3 +185,203 @@ dhcp_extract_router_msg(struct buffer *ipbuf) |
| 185 | 185 |
} |
| 186 | 186 |
return 0; |
| 187 | 187 |
} |
| 188 |
+ |
|
| 189 |
+#if defined(_WIN32) |
|
| 190 |
+ |
|
| 191 |
+#if defined(__GNUC__) || defined(__clang__) |
|
| 192 |
+#pragma GCC diagnostic push |
|
| 193 |
+#pragma GCC diagnostic ignored "-Wconversion" |
|
| 194 |
+#endif |
|
| 195 |
+ |
|
| 196 |
+/* |
|
| 197 |
+ * Convert DHCP options from the command line / config file |
|
| 198 |
+ * into a raw DHCP-format options string. |
|
| 199 |
+ */ |
|
| 200 |
+ |
|
| 201 |
+static void |
|
| 202 |
+write_dhcp_u8(struct buffer *buf, const int type, const int data, bool *error) |
|
| 203 |
+{
|
|
| 204 |
+ if (!buf_safe(buf, 3)) |
|
| 205 |
+ {
|
|
| 206 |
+ *error = true; |
|
| 207 |
+ msg(M_WARN, "write_dhcp_u8: buffer overflow building DHCP options"); |
|
| 208 |
+ return; |
|
| 209 |
+ } |
|
| 210 |
+ buf_write_u8(buf, type); |
|
| 211 |
+ buf_write_u8(buf, 1); |
|
| 212 |
+ buf_write_u8(buf, data); |
|
| 213 |
+} |
|
| 214 |
+ |
|
| 215 |
+static void |
|
| 216 |
+write_dhcp_u32_array(struct buffer *buf, const int type, const uint32_t *data, |
|
| 217 |
+ const unsigned int len, bool *error) |
|
| 218 |
+{
|
|
| 219 |
+ if (len > 0) |
|
| 220 |
+ {
|
|
| 221 |
+ int i; |
|
| 222 |
+ const int size = len * sizeof(uint32_t); |
|
| 223 |
+ |
|
| 224 |
+ if (!buf_safe(buf, 2 + size)) |
|
| 225 |
+ {
|
|
| 226 |
+ *error = true; |
|
| 227 |
+ msg(M_WARN, "write_dhcp_u32_array: buffer overflow building DHCP options"); |
|
| 228 |
+ return; |
|
| 229 |
+ } |
|
| 230 |
+ if (size < 1 || size > 255) |
|
| 231 |
+ {
|
|
| 232 |
+ *error = true; |
|
| 233 |
+ msg(M_WARN, "write_dhcp_u32_array: size (%d) must be > 0 and <= 255", size); |
|
| 234 |
+ return; |
|
| 235 |
+ } |
|
| 236 |
+ buf_write_u8(buf, type); |
|
| 237 |
+ buf_write_u8(buf, size); |
|
| 238 |
+ for (i = 0; i < len; ++i) |
|
| 239 |
+ {
|
|
| 240 |
+ buf_write_u32(buf, data[i]); |
|
| 241 |
+ } |
|
| 242 |
+ } |
|
| 243 |
+} |
|
| 244 |
+ |
|
| 245 |
+static void |
|
| 246 |
+write_dhcp_str(struct buffer *buf, const int type, const char *str, bool *error) |
|
| 247 |
+{
|
|
| 248 |
+ const int len = strlen(str); |
|
| 249 |
+ if (!buf_safe(buf, 2 + len)) |
|
| 250 |
+ {
|
|
| 251 |
+ *error = true; |
|
| 252 |
+ msg(M_WARN, "write_dhcp_str: buffer overflow building DHCP options"); |
|
| 253 |
+ return; |
|
| 254 |
+ } |
|
| 255 |
+ if (len < 1 || len > 255) |
|
| 256 |
+ {
|
|
| 257 |
+ *error = true; |
|
| 258 |
+ msg(M_WARN, "write_dhcp_str: string '%s' must be > 0 bytes and <= 255 bytes", str); |
|
| 259 |
+ return; |
|
| 260 |
+ } |
|
| 261 |
+ buf_write_u8(buf, type); |
|
| 262 |
+ buf_write_u8(buf, len); |
|
| 263 |
+ buf_write(buf, str, len); |
|
| 264 |
+} |
|
| 265 |
+ |
|
| 266 |
+/* |
|
| 267 |
+ * RFC3397 states that multiple searchdomains are encoded as follows: |
|
| 268 |
+ * - at start the length of the entire option is given |
|
| 269 |
+ * - each subdomain is preceded by its length |
|
| 270 |
+ * - each searchdomain is separated by a NUL character |
|
| 271 |
+ * e.g. if you want "openvpn.net" and "duckduckgo.com" then you end up with |
|
| 272 |
+ * 0x1D 0x7 openvpn 0x3 net 0x00 0x0A duckduckgo 0x3 com 0x00 |
|
| 273 |
+ */ |
|
| 274 |
+static void |
|
| 275 |
+write_dhcp_search_str(struct buffer *buf, const int type, const char *const *str_array, |
|
| 276 |
+ int array_len, bool *error) |
|
| 277 |
+{
|
|
| 278 |
+ char tmp_buf[256]; |
|
| 279 |
+ int i; |
|
| 280 |
+ int len = 0; |
|
| 281 |
+ int label_length_pos; |
|
| 282 |
+ |
|
| 283 |
+ for (i = 0; i < array_len; i++) |
|
| 284 |
+ {
|
|
| 285 |
+ const char *ptr = str_array[i]; |
|
| 286 |
+ |
|
| 287 |
+ if (strlen(ptr) + len + 1 > sizeof(tmp_buf)) |
|
| 288 |
+ {
|
|
| 289 |
+ *error = true; |
|
| 290 |
+ msg(M_WARN, "write_dhcp_search_str: temp buffer overflow building DHCP options"); |
|
| 291 |
+ return; |
|
| 292 |
+ } |
|
| 293 |
+ /* Loop over all subdomains separated by a dot and replace the dot |
|
| 294 |
+ * with the length of the subdomain */ |
|
| 295 |
+ |
|
| 296 |
+ /* label_length_pos points to the byte to be replaced by the length |
|
| 297 |
+ * of the following domain label */ |
|
| 298 |
+ label_length_pos = len++; |
|
| 299 |
+ |
|
| 300 |
+ while (true) |
|
| 301 |
+ {
|
|
| 302 |
+ if (*ptr == '.' || *ptr == '\0') |
|
| 303 |
+ {
|
|
| 304 |
+ tmp_buf[label_length_pos] = (len - label_length_pos) - 1; |
|
| 305 |
+ label_length_pos = len; |
|
| 306 |
+ if (*ptr == '\0') |
|
| 307 |
+ {
|
|
| 308 |
+ break; |
|
| 309 |
+ } |
|
| 310 |
+ } |
|
| 311 |
+ tmp_buf[len++] = *ptr++; |
|
| 312 |
+ } |
|
| 313 |
+ /* And close off with an extra NUL char */ |
|
| 314 |
+ tmp_buf[len++] = 0; |
|
| 315 |
+ } |
|
| 316 |
+ |
|
| 317 |
+ if (!buf_safe(buf, 2 + len)) |
|
| 318 |
+ {
|
|
| 319 |
+ *error = true; |
|
| 320 |
+ msg(M_WARN, "write_search_dhcp_str: buffer overflow building DHCP options"); |
|
| 321 |
+ return; |
|
| 322 |
+ } |
|
| 323 |
+ if (len > 255) |
|
| 324 |
+ {
|
|
| 325 |
+ *error = true; |
|
| 326 |
+ msg(M_WARN, "write_dhcp_search_str: search domain string must be <= 255 bytes"); |
|
| 327 |
+ return; |
|
| 328 |
+ } |
|
| 329 |
+ |
|
| 330 |
+ buf_write_u8(buf, type); |
|
| 331 |
+ buf_write_u8(buf, len); |
|
| 332 |
+ buf_write(buf, tmp_buf, len); |
|
| 333 |
+} |
|
| 334 |
+ |
|
| 335 |
+#if defined(__GNUC__) || defined(__clang__) |
|
| 336 |
+#pragma GCC diagnostic pop |
|
| 337 |
+#endif |
|
| 338 |
+ |
|
| 339 |
+bool |
|
| 340 |
+build_dhcp_options_string(struct buffer *buf, const struct tuntap_options *o) |
|
| 341 |
+{
|
|
| 342 |
+ bool error = false; |
|
| 343 |
+ if (o->domain) |
|
| 344 |
+ {
|
|
| 345 |
+ write_dhcp_str(buf, 15, o->domain, &error); |
|
| 346 |
+ } |
|
| 347 |
+ |
|
| 348 |
+ if (o->netbios_scope) |
|
| 349 |
+ {
|
|
| 350 |
+ write_dhcp_str(buf, 47, o->netbios_scope, &error); |
|
| 351 |
+ } |
|
| 352 |
+ |
|
| 353 |
+ if (o->netbios_node_type) |
|
| 354 |
+ {
|
|
| 355 |
+ write_dhcp_u8(buf, 46, o->netbios_node_type, &error); |
|
| 356 |
+ } |
|
| 357 |
+ |
|
| 358 |
+ write_dhcp_u32_array(buf, 6, (uint32_t *)o->dns, o->dns_len, &error); |
|
| 359 |
+ write_dhcp_u32_array(buf, 44, (uint32_t *)o->wins, o->wins_len, &error); |
|
| 360 |
+ write_dhcp_u32_array(buf, 42, (uint32_t *)o->ntp, o->ntp_len, &error); |
|
| 361 |
+ write_dhcp_u32_array(buf, 45, (uint32_t *)o->nbdd, o->nbdd_len, &error); |
|
| 362 |
+ |
|
| 363 |
+ if (o->domain_search_list_len > 0) |
|
| 364 |
+ {
|
|
| 365 |
+ write_dhcp_search_str(buf, 119, o->domain_search_list, o->domain_search_list_len, &error); |
|
| 366 |
+ } |
|
| 367 |
+ |
|
| 368 |
+ /* the MS DHCP server option 'Disable Netbios-over-TCP/IP |
|
| 369 |
+ * is implemented as vendor option 001, value 002. |
|
| 370 |
+ * A value of 001 means 'leave NBT alone' which is the default */ |
|
| 371 |
+ if (o->disable_nbt) |
|
| 372 |
+ {
|
|
| 373 |
+ if (!buf_safe(buf, 8)) |
|
| 374 |
+ {
|
|
| 375 |
+ msg(M_WARN, "build_dhcp_options_string: buffer overflow building DHCP options"); |
|
| 376 |
+ return false; |
|
| 377 |
+ } |
|
| 378 |
+ buf_write_u8(buf, 43); |
|
| 379 |
+ buf_write_u8(buf, 6); /* total length field */ |
|
| 380 |
+ buf_write_u8(buf, 0x001); |
|
| 381 |
+ buf_write_u8(buf, 4); /* length of the vendor specified field */ |
|
| 382 |
+ buf_write_u32(buf, 0x002); |
|
| 383 |
+ } |
|
| 384 |
+ return !error; |
|
| 385 |
+} |
|
| 386 |
+ |
|
| 387 |
+#endif /* defined(_WIN32) */ |
| ... | ... |
@@ -84,4 +84,10 @@ struct dhcp_full |
| 84 | 84 |
|
| 85 | 85 |
in_addr_t dhcp_extract_router_msg(struct buffer *ipbuf); |
| 86 | 86 |
|
| 87 |
+#if defined(_WIN32) |
|
| 88 |
+#include "tun.h" |
|
| 89 |
+ |
|
| 90 |
+bool build_dhcp_options_string(struct buffer *buf, const struct tuntap_options *o); |
|
| 91 |
+#endif |
|
| 92 |
+ |
|
| 87 | 93 |
#endif /* ifndef DHCP_H */ |
| ... | ... |
@@ -45,6 +45,7 @@ |
| 45 | 45 |
#include "win32.h" |
| 46 | 46 |
#include "wfp_block.h" |
| 47 | 47 |
#include "networking.h" |
| 48 |
+#include "dhcp.h" |
|
| 48 | 49 |
|
| 49 | 50 |
#include "memdbg.h" |
| 50 | 51 |
|
| ... | ... |
@@ -5554,202 +5555,6 @@ tun_standby(struct tuntap *tt) |
| 5554 | 5554 |
return ret; |
| 5555 | 5555 |
} |
| 5556 | 5556 |
|
| 5557 |
-#if defined(__GNUC__) || defined(__clang__) |
|
| 5558 |
-#pragma GCC diagnostic push |
|
| 5559 |
-#pragma GCC diagnostic ignored "-Wconversion" |
|
| 5560 |
-#endif |
|
| 5561 |
- |
|
| 5562 |
-/* |
|
| 5563 |
- * Convert DHCP options from the command line / config file |
|
| 5564 |
- * into a raw DHCP-format options string. |
|
| 5565 |
- */ |
|
| 5566 |
- |
|
| 5567 |
-static void |
|
| 5568 |
-write_dhcp_u8(struct buffer *buf, const int type, const int data, bool *error) |
|
| 5569 |
-{
|
|
| 5570 |
- if (!buf_safe(buf, 3)) |
|
| 5571 |
- {
|
|
| 5572 |
- *error = true; |
|
| 5573 |
- msg(M_WARN, "write_dhcp_u8: buffer overflow building DHCP options"); |
|
| 5574 |
- return; |
|
| 5575 |
- } |
|
| 5576 |
- buf_write_u8(buf, type); |
|
| 5577 |
- buf_write_u8(buf, 1); |
|
| 5578 |
- buf_write_u8(buf, data); |
|
| 5579 |
-} |
|
| 5580 |
- |
|
| 5581 |
-static void |
|
| 5582 |
-write_dhcp_u32_array(struct buffer *buf, const int type, const uint32_t *data, |
|
| 5583 |
- const unsigned int len, bool *error) |
|
| 5584 |
-{
|
|
| 5585 |
- if (len > 0) |
|
| 5586 |
- {
|
|
| 5587 |
- int i; |
|
| 5588 |
- const int size = len * sizeof(uint32_t); |
|
| 5589 |
- |
|
| 5590 |
- if (!buf_safe(buf, 2 + size)) |
|
| 5591 |
- {
|
|
| 5592 |
- *error = true; |
|
| 5593 |
- msg(M_WARN, "write_dhcp_u32_array: buffer overflow building DHCP options"); |
|
| 5594 |
- return; |
|
| 5595 |
- } |
|
| 5596 |
- if (size < 1 || size > 255) |
|
| 5597 |
- {
|
|
| 5598 |
- *error = true; |
|
| 5599 |
- msg(M_WARN, "write_dhcp_u32_array: size (%d) must be > 0 and <= 255", size); |
|
| 5600 |
- return; |
|
| 5601 |
- } |
|
| 5602 |
- buf_write_u8(buf, type); |
|
| 5603 |
- buf_write_u8(buf, size); |
|
| 5604 |
- for (i = 0; i < len; ++i) |
|
| 5605 |
- {
|
|
| 5606 |
- buf_write_u32(buf, data[i]); |
|
| 5607 |
- } |
|
| 5608 |
- } |
|
| 5609 |
-} |
|
| 5610 |
- |
|
| 5611 |
-static void |
|
| 5612 |
-write_dhcp_str(struct buffer *buf, const int type, const char *str, bool *error) |
|
| 5613 |
-{
|
|
| 5614 |
- const int len = strlen(str); |
|
| 5615 |
- if (!buf_safe(buf, 2 + len)) |
|
| 5616 |
- {
|
|
| 5617 |
- *error = true; |
|
| 5618 |
- msg(M_WARN, "write_dhcp_str: buffer overflow building DHCP options"); |
|
| 5619 |
- return; |
|
| 5620 |
- } |
|
| 5621 |
- if (len < 1 || len > 255) |
|
| 5622 |
- {
|
|
| 5623 |
- *error = true; |
|
| 5624 |
- msg(M_WARN, "write_dhcp_str: string '%s' must be > 0 bytes and <= 255 bytes", str); |
|
| 5625 |
- return; |
|
| 5626 |
- } |
|
| 5627 |
- buf_write_u8(buf, type); |
|
| 5628 |
- buf_write_u8(buf, len); |
|
| 5629 |
- buf_write(buf, str, len); |
|
| 5630 |
-} |
|
| 5631 |
- |
|
| 5632 |
-/* |
|
| 5633 |
- * RFC3397 states that multiple searchdomains are encoded as follows: |
|
| 5634 |
- * - at start the length of the entire option is given |
|
| 5635 |
- * - each subdomain is preceded by its length |
|
| 5636 |
- * - each searchdomain is separated by a NUL character |
|
| 5637 |
- * e.g. if you want "openvpn.net" and "duckduckgo.com" then you end up with |
|
| 5638 |
- * 0x1D 0x7 openvpn 0x3 net 0x00 0x0A duckduckgo 0x3 com 0x00 |
|
| 5639 |
- */ |
|
| 5640 |
-static void |
|
| 5641 |
-write_dhcp_search_str(struct buffer *buf, const int type, const char *const *str_array, |
|
| 5642 |
- int array_len, bool *error) |
|
| 5643 |
-{
|
|
| 5644 |
- char tmp_buf[256]; |
|
| 5645 |
- int i; |
|
| 5646 |
- int len = 0; |
|
| 5647 |
- int label_length_pos; |
|
| 5648 |
- |
|
| 5649 |
- for (i = 0; i < array_len; i++) |
|
| 5650 |
- {
|
|
| 5651 |
- const char *ptr = str_array[i]; |
|
| 5652 |
- |
|
| 5653 |
- if (strlen(ptr) + len + 1 > sizeof(tmp_buf)) |
|
| 5654 |
- {
|
|
| 5655 |
- *error = true; |
|
| 5656 |
- msg(M_WARN, "write_dhcp_search_str: temp buffer overflow building DHCP options"); |
|
| 5657 |
- return; |
|
| 5658 |
- } |
|
| 5659 |
- /* Loop over all subdomains separated by a dot and replace the dot |
|
| 5660 |
- * with the length of the subdomain */ |
|
| 5661 |
- |
|
| 5662 |
- /* label_length_pos points to the byte to be replaced by the length |
|
| 5663 |
- * of the following domain label */ |
|
| 5664 |
- label_length_pos = len++; |
|
| 5665 |
- |
|
| 5666 |
- while (true) |
|
| 5667 |
- {
|
|
| 5668 |
- if (*ptr == '.' || *ptr == '\0') |
|
| 5669 |
- {
|
|
| 5670 |
- tmp_buf[label_length_pos] = (len - label_length_pos) - 1; |
|
| 5671 |
- label_length_pos = len; |
|
| 5672 |
- if (*ptr == '\0') |
|
| 5673 |
- {
|
|
| 5674 |
- break; |
|
| 5675 |
- } |
|
| 5676 |
- } |
|
| 5677 |
- tmp_buf[len++] = *ptr++; |
|
| 5678 |
- } |
|
| 5679 |
- /* And close off with an extra NUL char */ |
|
| 5680 |
- tmp_buf[len++] = 0; |
|
| 5681 |
- } |
|
| 5682 |
- |
|
| 5683 |
- if (!buf_safe(buf, 2 + len)) |
|
| 5684 |
- {
|
|
| 5685 |
- *error = true; |
|
| 5686 |
- msg(M_WARN, "write_search_dhcp_str: buffer overflow building DHCP options"); |
|
| 5687 |
- return; |
|
| 5688 |
- } |
|
| 5689 |
- if (len > 255) |
|
| 5690 |
- {
|
|
| 5691 |
- *error = true; |
|
| 5692 |
- msg(M_WARN, "write_dhcp_search_str: search domain string must be <= 255 bytes"); |
|
| 5693 |
- return; |
|
| 5694 |
- } |
|
| 5695 |
- |
|
| 5696 |
- buf_write_u8(buf, type); |
|
| 5697 |
- buf_write_u8(buf, len); |
|
| 5698 |
- buf_write(buf, tmp_buf, len); |
|
| 5699 |
-} |
|
| 5700 |
- |
|
| 5701 |
-#if defined(__GNUC__) || defined(__clang__) |
|
| 5702 |
-#pragma GCC diagnostic pop |
|
| 5703 |
-#endif |
|
| 5704 |
- |
|
| 5705 |
-static bool |
|
| 5706 |
-build_dhcp_options_string(struct buffer *buf, const struct tuntap_options *o) |
|
| 5707 |
-{
|
|
| 5708 |
- bool error = false; |
|
| 5709 |
- if (o->domain) |
|
| 5710 |
- {
|
|
| 5711 |
- write_dhcp_str(buf, 15, o->domain, &error); |
|
| 5712 |
- } |
|
| 5713 |
- |
|
| 5714 |
- if (o->netbios_scope) |
|
| 5715 |
- {
|
|
| 5716 |
- write_dhcp_str(buf, 47, o->netbios_scope, &error); |
|
| 5717 |
- } |
|
| 5718 |
- |
|
| 5719 |
- if (o->netbios_node_type) |
|
| 5720 |
- {
|
|
| 5721 |
- write_dhcp_u8(buf, 46, o->netbios_node_type, &error); |
|
| 5722 |
- } |
|
| 5723 |
- |
|
| 5724 |
- write_dhcp_u32_array(buf, 6, (uint32_t *)o->dns, o->dns_len, &error); |
|
| 5725 |
- write_dhcp_u32_array(buf, 44, (uint32_t *)o->wins, o->wins_len, &error); |
|
| 5726 |
- write_dhcp_u32_array(buf, 42, (uint32_t *)o->ntp, o->ntp_len, &error); |
|
| 5727 |
- write_dhcp_u32_array(buf, 45, (uint32_t *)o->nbdd, o->nbdd_len, &error); |
|
| 5728 |
- |
|
| 5729 |
- if (o->domain_search_list_len > 0) |
|
| 5730 |
- {
|
|
| 5731 |
- write_dhcp_search_str(buf, 119, o->domain_search_list, o->domain_search_list_len, &error); |
|
| 5732 |
- } |
|
| 5733 |
- |
|
| 5734 |
- /* the MS DHCP server option 'Disable Netbios-over-TCP/IP |
|
| 5735 |
- * is implemented as vendor option 001, value 002. |
|
| 5736 |
- * A value of 001 means 'leave NBT alone' which is the default */ |
|
| 5737 |
- if (o->disable_nbt) |
|
| 5738 |
- {
|
|
| 5739 |
- if (!buf_safe(buf, 8)) |
|
| 5740 |
- {
|
|
| 5741 |
- msg(M_WARN, "build_dhcp_options_string: buffer overflow building DHCP options"); |
|
| 5742 |
- return false; |
|
| 5743 |
- } |
|
| 5744 |
- buf_write_u8(buf, 43); |
|
| 5745 |
- buf_write_u8(buf, 6); /* total length field */ |
|
| 5746 |
- buf_write_u8(buf, 0x001); |
|
| 5747 |
- buf_write_u8(buf, 4); /* length of the vendor specified field */ |
|
| 5748 |
- buf_write_u32(buf, 0x002); |
|
| 5749 |
- } |
|
| 5750 |
- return !error; |
|
| 5751 |
-} |
|
| 5752 |
- |
|
| 5753 | 5557 |
static void |
| 5754 | 5558 |
fork_dhcp_action(struct tuntap *tt) |
| 5755 | 5559 |
{
|