Browse code

Move build_dhcp_options_string from tun to dhcp

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>

Frank Lichtenheld authored on 2025/10/11 17:22:11
Showing 3 changed files
... ...
@@ -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
 {