Coverage Report

Created: 2025-05-04 06:22

/src/openweave-core/src/test-apps/ToolCommonOptions.cpp
Line
Count
Source (jump to first uncovered line)
1
/*
2
 *
3
 *    Copyright (c) 2013-2017 Nest Labs, Inc.
4
 *    All rights reserved.
5
 *
6
 *    Licensed under the Apache License, Version 2.0 (the "License");
7
 *    you may not use this file except in compliance with the License.
8
 *    You may obtain a copy of the License at
9
 *
10
 *        http://www.apache.org/licenses/LICENSE-2.0
11
 *
12
 *    Unless required by applicable law or agreed to in writing, software
13
 *    distributed under the License is distributed on an "AS IS" BASIS,
14
 *    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15
 *    See the License for the specific language governing permissions and
16
 *    limitations under the License.
17
 */
18
19
/**
20
 *    @file
21
 *      Common command-line option handling code for test applications.
22
 *
23
 */
24
25
26
#ifndef __STDC_LIMIT_MACROS
27
#define __STDC_LIMIT_MACROS
28
#endif
29
#define __STDC_FORMAT_MACROS
30
31
#include <inttypes.h>
32
#include <stdint.h>
33
#include <stdio.h>
34
35
#include "ToolCommonOptions.h"
36
#include "TestPersistedStorageImplementation.h"
37
#include <Weave/WeaveVersion.h>
38
#include <Weave/Profiles/service-directory/ServiceDirectory.h>
39
#include <SystemLayer/SystemFaultInjection.h>
40
#include <Weave/Support/WeaveFaultInjection.h>
41
#include <InetLayer/InetFaultInjection.h>
42
43
using namespace nl::Inet;
44
using namespace nl::Weave;
45
46
// Global Variables
47
48
NetworkOptions gNetworkOptions;
49
WeaveNodeOptions gWeaveNodeOptions;
50
WeaveSecurityMode gWeaveSecurityMode;
51
WRMPOptions gWRMPOptions;
52
GroupKeyEncOptions gGroupKeyEncOptions;
53
GeneralSecurityOptions gGeneralSecurityOptions;
54
ServiceDirClientOptions gServiceDirClientOptions;
55
FaultInjectionOptions gFaultInjectionOptions;
56
57
NetworkOptions::NetworkOptions()
58
10
{
59
10
    static OptionDef optionDefs[] =
60
10
    {
61
10
        { "local-addr",     kArgumentRequired, 'a' },
62
10
        { "node-addr",      kArgumentRequired, kToolCommonOpt_NodeAddr }, /* alias for local-addr */
63
#if WEAVE_SYSTEM_CONFIG_USE_LWIP
64
        { "tap-device",     kArgumentRequired, kToolCommonOpt_TapDevice },
65
        { "ipv4-gateway",   kArgumentRequired, kToolCommonOpt_IPv4GatewayAddr },
66
        { "ipv6-gateway",   kArgumentRequired, kToolCommonOpt_IPv6GatewayAddr },
67
        { "dns-server",     kArgumentRequired, 'X' },
68
        { "debug-lwip",     kNoArgument,       kToolCommonOpt_DebugLwIP },
69
        { "event-delay",    kArgumentRequired, kToolCommonOpt_EventDelay },
70
        { "tap-system-config", kNoArgument,    kToolCommonOpt_TapInterfaceConfig },
71
#endif
72
10
        { }
73
10
    };
74
10
    OptionDefs = optionDefs;
75
76
10
    HelpGroupName = "NETWORK OPTIONS";
77
78
10
    OptionHelp =
79
10
        "  -a, --local-addr, --node-addr <ip-addr>\n"
80
10
        "       Local address for the node.\n"
81
10
        "\n"
82
#if WEAVE_SYSTEM_CONFIG_USE_LWIP
83
        "  --tap-device <tap-dev-name>\n"
84
        "       TAP device name for LwIP hosted OS usage. Defaults to weave-dev-<node-id>.\n"
85
        "\n"
86
        "  --ipv4-gateway <ip-addr>\n"
87
        "       Address of default IPv4 gateway.\n"
88
        "\n"
89
        "  --ipv6-gateway <ip-addr>\n"
90
        "       Address of default IPv6 gateway.\n"
91
        "\n"
92
        "  -X, --dns-server <ip-addr>\n"
93
        "       IPv4 address of local DNS server.\n"
94
        "\n"
95
        "  --debug-lwip\n"
96
        "       Enable LwIP debug messages.\n"
97
        "\n"
98
        "  --event-delay <int>\n"
99
        "       Delay event processing by specified number of iterations. Defaults to 0.\n"
100
        "\n"
101
        "  --tap-system-config\n"
102
        "       Use configuration on each of the Linux TAP interfaces to configure LwIP's interfaces.\n"
103
        "\n"
104
#endif // WEAVE_SYSTEM_CONFIG_USE_LWIP
105
10
        ;
106
107
    // Defaults.
108
10
    LocalIPv4Addr.clear();
109
10
    LocalIPv6Addr.clear();
110
111
#if WEAVE_SYSTEM_CONFIG_USE_LWIP
112
    TapDeviceName.clear();
113
    LwIPDebugFlags = 0;
114
    EventDelay = 0;
115
    IPv4GatewayAddr.clear();
116
    IPv6GatewayAddr.clear();
117
    DNSServerAddr = nl::Inet::IPAddress::Any;
118
    TapUseSystemConfig = false;
119
#endif // WEAVE_SYSTEM_CONFIG_USE_LWIP
120
10
}
121
122
bool NetworkOptions::HandleOption(const char *progName, OptionSet *optSet, int id, const char *name, const char *arg)
123
0
{
124
0
    nl::Inet::IPAddress localAddr;
125
126
0
    switch (id)
127
0
    {
128
0
    case 'a':
129
0
    case kToolCommonOpt_NodeAddr:
130
0
        if (!ParseIPAddress(arg, localAddr))
131
0
        {
132
0
            PrintArgError("%s: Invalid value specified for local IP address: %s\n", progName, arg);
133
0
            return false;
134
0
        }
135
0
#if INET_CONFIG_ENABLE_IPV4
136
0
        if (localAddr.IsIPv4())
137
0
        {
138
0
            LocalIPv4Addr.push_back(localAddr);
139
0
        }
140
0
        else
141
0
        {
142
0
            LocalIPv6Addr.push_back(localAddr);
143
0
        }
144
#else // INET_CONFIG_ENABLE_IPV4
145
        LocalIPv6Addr.push_back(localAddr);
146
#endif // INET_CONFIG_ENABLE_IPV4
147
0
        break;
148
149
#if WEAVE_SYSTEM_CONFIG_USE_LWIP
150
    case 'X':
151
        if (!ParseIPAddress(arg, DNSServerAddr))
152
        {
153
            PrintArgError("%s: Invalid value specified for DNS server address: %s\n", progName, arg);
154
            return false;
155
        }
156
        break;
157
    case kToolCommonOpt_TapDevice:
158
        TapDeviceName.push_back(arg);
159
        break;
160
161
    case kToolCommonOpt_IPv4GatewayAddr:
162
        {
163
            if (!ParseIPAddress(arg, localAddr) || !localAddr.IsIPv4())
164
            {
165
                PrintArgError("%s: Invalid value specified for IPv4 gateway address: %s\n", progName, arg);
166
                return false;
167
            }
168
            IPv4GatewayAddr.push_back(localAddr);
169
        }
170
        break;
171
172
    case kToolCommonOpt_IPv6GatewayAddr:
173
        {
174
            if (!ParseIPAddress(arg, localAddr))
175
            {
176
                PrintArgError("%s: Invalid value specified for IPv6 gateway address: %s\n", progName, arg);
177
                return false;
178
            }
179
            IPv6GatewayAddr.push_back(localAddr);
180
        }
181
        break;
182
183
    case kToolCommonOpt_DebugLwIP:
184
#if defined(LWIP_DEBUG)
185
        gLwIP_DebugFlags = (LWIP_DBG_ON|LWIP_DBG_TRACE|LWIP_DBG_STATE|LWIP_DBG_FRESH|LWIP_DBG_HALT);
186
#endif
187
        break;
188
    case kToolCommonOpt_EventDelay:
189
        if (!ParseInt(arg, EventDelay))
190
        {
191
            PrintArgError("%s: Invalid value specified for event delay: %s\n", progName, arg);
192
            return false;
193
        }
194
        break;
195
196
      case kToolCommonOpt_TapInterfaceConfig:
197
        TapUseSystemConfig = true;
198
        break;
199
#endif // WEAVE_SYSTEM_CONFIG_USE_LWIP
200
201
0
    default:
202
0
        PrintArgError("%s: INTERNAL ERROR: Unhandled option: %s\n", progName, name);
203
0
        return false;
204
0
    }
205
206
0
    return true;
207
0
}
208
209
WeaveNodeOptions::WeaveNodeOptions()
210
10
{
211
10
    static OptionDef optionDefs[] =
212
10
    {
213
10
        { "fabric-id",              kArgumentRequired, 'f'                                },
214
10
        { "node-id",                kArgumentRequired, 'n'                                },
215
10
        { "subnet",                 kArgumentRequired, 'N'                                },
216
10
        { "pairing-code",           kArgumentRequired, kToolCommonOpt_PairingCode         },
217
10
        { "persistent-cntr-file",   kArgumentRequired, kToolCommonOpt_PersistentCntrFile  },
218
10
#if WEAVE_CONFIG_ENABLE_EPHEMERAL_UDP_PORT
219
10
        { "use-ephemeral-udp-port", kNoArgument,       kToolCommonOpt_UseEphemeralUDPPort },
220
10
#endif // WEAVE_CONFIG_ENABLE_EPHEMERAL_UDP_PORT
221
10
        { }
222
10
    };
223
10
    OptionDefs = optionDefs;
224
225
10
    HelpGroupName = "WEAVE NODE OPTIONS";
226
227
10
    OptionHelp =
228
10
        "  -f, --fabric-id <num>\n"
229
10
        "       Weave fabric id. Defaults to 1 unless --node-addr specified.\n"
230
10
        "\n"
231
10
        "  -n, --node-id <num>\n"
232
10
        "       Node id for local node. Defaults to 1 unless --node-addr specified.\n"
233
10
        "\n"
234
10
        "  -N, --subnet <num>\n"
235
10
        "       Subnet number for local node. Defaults to 1 unless --node-addr specified.\n"
236
10
        "\n"
237
10
        "  --pairing-code <string>\n"
238
10
        "       Pairing code string to use for PASE authentication.  Defaults to 'TEST'.\n"
239
10
        "\n"
240
10
        "  --persistent-cntr-file <counter-file>\n"
241
10
        "       File used to persist group message counter and event counters. Counters are stored in the following format:\n"
242
10
        "           CounterOneKey      (e.g. EncMsgCntr)\n"
243
10
        "           CounterOneValue    (e.g. 0x00000078)\n"
244
10
        "           CounterTwoKey      (e.g. ProductionEIDC)\n"
245
10
        "           CounterTwoValue    (e.g. 0x34FA78E4)\n"
246
10
        "       The intention was to store these data in a human interpreted format so\n"
247
10
        "       developers can manually modify this file. When this file is modified manually\n"
248
10
        "       developers should stick to this format - any other format will result in error.\n"
249
10
        "       If persistent-cntr-file option is not specified then by default counters are not persisted.\n"
250
10
        "\n"
251
10
#if WEAVE_CONFIG_ENABLE_EPHEMERAL_UDP_PORT
252
10
        "  --use-ephemeral-udp-port\n"
253
10
        "       Use an ephemeral UDP source port when initiating Weave exchanges with another node.\n"
254
10
        "\n"
255
10
#endif // WEAVE_CONFIG_ENABLE_EPHEMERAL_UDP_PORT
256
10
        ;
257
258
    // Defaults.
259
10
    FabricId = nl::Weave::kFabricIdDefaultForTest;
260
10
    LocalNodeId = 1;
261
10
    SubnetId = 1;
262
10
    FabricIdSet = false;
263
10
    LocalNodeIdSet = false;
264
10
    SubnetIdSet = false;
265
10
    PairingCode = "TEST";
266
10
    UseEphemeralUDPPort = false;
267
10
}
268
269
WeaveNodeOptions::~WeaveNodeOptions()
270
0
{
271
0
    if (sPersistentStoreFile != NULL)
272
0
        fclose(sPersistentStoreFile);
273
0
}
274
275
bool WeaveNodeOptions::HandleOption(const char *progName, OptionSet *optSet, int id, const char *name, const char *arg)
276
0
{
277
0
    switch (id)
278
0
    {
279
0
    case 'f':
280
0
        if (!ParseFabricId(arg, FabricId))
281
0
        {
282
0
            PrintArgError("%s: Invalid value specified for fabric id: %s\n", progName, arg);
283
0
            return false;
284
0
        }
285
0
        FabricIdSet = true;
286
0
        break;
287
0
    case 'n':
288
0
        if (!ParseNodeId(arg, LocalNodeId))
289
0
        {
290
0
            PrintArgError("%s: Invalid value specified for local node id: %s\n", progName, arg);
291
0
            return false;
292
0
        }
293
0
        LocalNodeIdSet = true;
294
0
        break;
295
0
    case 'N':
296
0
        if (!ParseSubnetId(arg, SubnetId))
297
0
        {
298
0
            PrintArgError("%s: Invalid value specified for local subnet: %s\n", progName, arg);
299
0
            return false;
300
0
        }
301
0
        SubnetIdSet = true;
302
0
        break;
303
0
    case kToolCommonOpt_PairingCode:
304
0
        PairingCode = arg;
305
0
        break;
306
0
    case kToolCommonOpt_PersistentCntrFile:
307
        // If file already exists then open it for write/update.
308
0
        if ((sPersistentStoreFile = fopen(arg, "r")) == NULL)
309
0
        {
310
0
            sPersistentStoreFile = fopen(arg, "w+");
311
0
        }
312
        // If file doesn't exist then open it for read/update.
313
0
        else
314
0
        {
315
0
            fclose(sPersistentStoreFile);
316
0
            sPersistentStoreFile = fopen(arg, "r+");
317
0
        }
318
319
0
        if (sPersistentStoreFile == NULL)
320
0
        {
321
0
            printf("Unable to open %s\n%s\n", arg, strerror(errno));
322
0
            return false;
323
0
        }
324
0
        break;
325
0
    case kToolCommonOpt_UseEphemeralUDPPort:
326
0
        UseEphemeralUDPPort = true;
327
0
        break;
328
0
    default:
329
0
        PrintArgError("%s: INTERNAL ERROR: Unhandled option: %s\n", progName, name);
330
0
        return false;
331
0
    }
332
333
0
    return true;
334
0
}
335
336
WeaveSecurityMode::WeaveSecurityMode()
337
10
{
338
10
    static OptionDef optionDefs[] =
339
10
    {
340
10
        { "no-security",   kNoArgument,       kToolCommonOpt_SecurityNone       },
341
10
        { "case",          kNoArgument,       kToolCommonOpt_SecurityCASE       },
342
10
        { "case-shared",   kNoArgument,       kToolCommonOpt_SecurityCASEShared },
343
10
        { "pase",          kNoArgument,       kToolCommonOpt_SecurityPASE       },
344
10
        { "group-enc",     kNoArgument,       kToolCommonOpt_SecurityGroupEnc   },
345
10
        { "take",          kNoArgument,       kToolCommonOpt_SecurityTAKE       },
346
10
        { }
347
10
    };
348
349
10
    OptionDefs = optionDefs;
350
351
10
    HelpGroupName = "WEAVE SECURITY OPTIONS";
352
353
10
    OptionHelp =
354
10
            "  --no-security\n"
355
10
            "       Use no security session\n"
356
10
            "\n"
357
10
            "  --pase\n"
358
10
            "       Use PASE to create an authenticated session and encrypt messages using\n"
359
10
            "       the negotiated session key.\n"
360
10
            "\n"
361
10
            "  --case\n"
362
10
            "       Use CASE to create an authenticated session and encrypt messages using\n"
363
10
            "       the negotiated session key.\n"
364
10
            "\n"
365
10
            "  --case-shared\n"
366
10
            "       Use CASE to create an authenticated shared session to the Nest Core router\n"
367
10
            "       and encrypt messages using the negotiated session key.\n"
368
10
            "\n"
369
10
            "  --take\n"
370
10
            "       Use TAKE to create an authenticated session and encrypt messages using\n"
371
10
            "       the negotiated session key.\n"
372
10
            "\n"
373
10
#if WEAVE_CONFIG_USE_APP_GROUP_KEYS_FOR_MSG_ENC
374
10
            "  --group-enc\n"
375
10
            "       Use a group key to encrypt messages.\n"
376
10
            "       When group key encryption option is chosen the key id should be also specified.\n"
377
10
            "       Below are two examples how group key id can be specified:\n"
378
10
            "          --group-enc-key-id 0x00005536\n"
379
10
            "          --group-enc-key-type r --group-enc-root-key c --group-enc-epoch-key-num 2 --group-enc-app-key-num 54\n"
380
10
            "       Note that both examples describe the same rotating group key derived from client\n"
381
10
            "       root key, epoch key number 4 and app group master key number 54 (0x36).\n"
382
10
            "\n"
383
10
#endif // WEAVE_CONFIG_USE_APP_GROUP_KEYS_FOR_MSG_ENC
384
10
            ;
385
386
    // Defaults.
387
10
    SecurityMode = kNone;
388
389
10
}
390
391
bool WeaveSecurityMode::HandleOption(const char *progName, OptionSet *optSet, int id, const char *name, const char *arg)
392
0
{
393
0
    switch (id)
394
0
    {
395
0
        case kToolCommonOpt_SecurityNone:
396
0
            SecurityMode = kNone;
397
0
            break;
398
0
        case kToolCommonOpt_SecurityCASE:
399
0
            SecurityMode = kCASE;
400
0
            break;
401
0
        case kToolCommonOpt_SecurityCASEShared:
402
0
            SecurityMode = kCASEShared;
403
0
            break;
404
0
        case kToolCommonOpt_SecurityPASE:
405
0
            SecurityMode = kPASE;
406
0
            break;
407
0
        case kToolCommonOpt_SecurityGroupEnc:
408
0
            SecurityMode = kGroupEnc;
409
0
            break;
410
0
        case kToolCommonOpt_SecurityTAKE:
411
0
            SecurityMode = kTAKE;
412
0
            break;
413
0
        default:
414
0
            PrintArgError("%s: INTERNAL ERROR: Unhandled option: %s\n", progName, name);
415
0
            return false;
416
0
    }
417
418
0
    return true;
419
0
}
420
421
422
WRMPOptions::WRMPOptions()
423
10
{
424
10
    static OptionDef optionDefs[] =
425
10
    {
426
10
#if WEAVE_CONFIG_ENABLE_RELIABLE_MESSAGING
427
10
        { "wrmp-ack-delay",        kArgumentRequired, kToolCommonOpt_WRMPACKDelay        },
428
10
        { "wrmp-retrans-interval", kArgumentRequired, kToolCommonOpt_WRMPRetransInterval },
429
10
        { "wrmp-retrans-count",    kArgumentRequired, kToolCommonOpt_WRMPRetransCount    },
430
10
#endif // WEAVE_CONFIG_ENABLE_RELIABLE_MESSAGING
431
10
        { }
432
10
    };
433
10
    OptionDefs = optionDefs;
434
435
10
    HelpGroupName = "WEAVE RELIABLE MESSAGING OPTIONS";
436
437
10
    OptionHelp =
438
10
#if WEAVE_CONFIG_ENABLE_RELIABLE_MESSAGING
439
10
        "  --wrmp-ack-delay <ms>\n"
440
10
        "       Set the WRMP maximum pending ACK delay (defaults to 200ms).\n"
441
10
        "\n"
442
10
        "  --wrmp-retrans-interval <ms>\n"
443
10
        "       Set the WRMP retransmission interval (defaults to 200ms).\n"
444
10
        "\n"
445
10
        "  --wrmp-retrans-count <int>\n"
446
10
        "       Set the WRMP retransmission count (defaults to 3).\n"
447
10
        "\n"
448
10
#endif // WEAVE_CONFIG_ENABLE_RELIABLE_MESSAGING
449
10
        "";
450
451
    // Defaults.
452
10
    ACKDelay = WEAVE_CONFIG_WRMP_DEFAULT_ACK_TIMEOUT;
453
10
    RetransInterval = WEAVE_CONFIG_WRMP_DEFAULT_ACTIVE_RETRANS_TIMEOUT;
454
10
    RetransCount = WEAVE_CONFIG_WRMP_DEFAULT_MAX_RETRANS;
455
10
}
456
457
nl::Weave::WRMPConfig WRMPOptions::GetWRMPConfig() const
458
0
{
459
0
    nl::Weave::WRMPConfig wrmpConfig;
460
0
    memset(&wrmpConfig, 0, sizeof(wrmpConfig));
461
0
    wrmpConfig.mInitialRetransTimeout = RetransInterval;
462
0
    wrmpConfig.mActiveRetransTimeout = RetransInterval;
463
0
    wrmpConfig.mAckPiggybackTimeout = ACKDelay;
464
0
    wrmpConfig.mMaxRetrans = RetransCount;
465
0
    return wrmpConfig;
466
0
}
467
468
bool WRMPOptions::HandleOption(const char *progName, OptionSet *optSet, int id, const char *name, const char *arg)
469
0
{
470
0
    switch (id)
471
0
    {
472
0
#if WEAVE_CONFIG_ENABLE_RELIABLE_MESSAGING
473
0
    case kToolCommonOpt_WRMPACKDelay:
474
0
        if (!ParseInt(arg, ACKDelay))
475
0
        {
476
0
            PrintArgError("%s: Invalid value specified for WRMP ACK delay: %s\n", progName, arg);
477
0
            return false;
478
0
        }
479
0
        break;
480
0
    case kToolCommonOpt_WRMPRetransInterval:
481
0
        if (!ParseInt(arg, RetransInterval))
482
0
        {
483
0
            PrintArgError("%s: Invalid value specified for WRMP retransmission interval: %s\n", progName, arg);
484
0
            return false;
485
0
        }
486
0
        break;
487
0
    case kToolCommonOpt_WRMPRetransCount:
488
0
        if (!ParseInt(arg, RetransCount))
489
0
        {
490
0
            PrintArgError("%s: Invalid value specified for WRMP retransmission count: %s\n", progName, arg);
491
0
            return false;
492
0
        }
493
0
        break;
494
0
#endif // WEAVE_CONFIG_ENABLE_RELIABLE_MESSAGING
495
0
    default:
496
0
        PrintArgError("%s: INTERNAL ERROR: Unhandled option: %s\n", progName, name);
497
0
        return false;
498
0
    }
499
500
0
    return true;
501
0
}
502
503
GroupKeyEncOptions::GroupKeyEncOptions()
504
10
{
505
10
    static OptionDef optionDefs[] =
506
10
    {
507
10
#if WEAVE_CONFIG_USE_APP_GROUP_KEYS_FOR_MSG_ENC
508
10
        { "group-enc-key-id",           kArgumentRequired, kToolCommonOpt_GroupEncKeyId                },
509
10
        { "group-enc-key-type",         kArgumentRequired, kToolCommonOpt_GroupEncKeyType              },
510
10
        { "group-enc-root-key",         kArgumentRequired, kToolCommonOpt_GroupEncRootKey              },
511
10
        { "group-enc-epoch-key-num",    kArgumentRequired, kToolCommonOpt_GroupEncEpochKeyNum          },
512
10
        { "group-enc-app-key-num",      kArgumentRequired, kToolCommonOpt_GroupEncAppGroupMasterKeyNum },
513
10
#endif
514
10
        { }
515
10
    };
516
10
    OptionDefs = optionDefs;
517
518
10
    HelpGroupName = "GROUP KEY MESSAGE ENCRYPTION OPTIONS";
519
520
10
    OptionHelp =
521
10
#if WEAVE_CONFIG_USE_APP_GROUP_KEYS_FOR_MSG_ENC
522
10
        "  --group-enc-key-id <int>\n"
523
10
        "       Key id of the group key that should be used to encrypt messages. This option\n"
524
10
        "       overrides any of the following options.\n"
525
10
        "\n"
526
10
        "  --group-enc-key-type <key-type>\n"
527
10
        "       Key type of the group key to be used for encrypting messages.\n"
528
10
        "       Valid values for <key-type> are:\n"
529
10
        "           r - rotating message encryption group key.\n"
530
10
        "           s - static message encryption group key.\n"
531
10
        "\n"
532
10
        "  --group-enc-root-key <root-type>\n"
533
10
        "       Root key type to be used to generate the group key id for encrypting messages.\n"
534
10
        "       Valid values for <root-type> are:\n"
535
10
        "           f - fabric root key.\n"
536
10
        "           c - client root key.\n"
537
10
        "           s - service root key.\n"
538
10
        "\n"
539
10
        "  --group-enc-epoch-key-num <int>\n"
540
10
        "       Epoch key number to be used to generate the group key id for encrypting messages.\n"
541
10
        "       when group key encyption option is chosen.\n"
542
10
        "\n"
543
10
        "  --group-enc-app-key-num <int>\n"
544
10
        "       Application group master key number to be used to generate the group key id for\n"
545
10
        "       encrypting messages.\n"
546
10
        "\n"
547
10
#endif // WEAVE_CONFIG_USE_APP_GROUP_KEYS_FOR_MSG_ENC
548
10
        "";
549
550
    // Defaults.
551
10
    EncKeyId = WeaveKeyId::kNone;
552
10
    EncKeyType = WeaveKeyId::kType_None;
553
10
    RootKeyId = WeaveKeyId::kNone;
554
10
    EpochKeyId = WeaveKeyId::kNone;
555
10
    AppGroupMasterKeyId = WeaveKeyId::kNone;
556
10
}
557
558
uint32_t GroupKeyEncOptions::GetEncKeyId() const
559
0
{
560
0
    if (EncKeyId != WeaveKeyId::kNone)
561
0
        return EncKeyId;
562
0
    if (EncKeyType == WeaveKeyId::kType_None)
563
0
        return WeaveKeyId::kNone;
564
0
    if (RootKeyId == WeaveKeyId::kNone || AppGroupMasterKeyId == WeaveKeyId::kNone)
565
0
        return WeaveKeyId::kNone;
566
0
    return WeaveKeyId::MakeAppKeyId(EncKeyType, RootKeyId,
567
0
                (EncKeyType == WeaveKeyId::kType_AppRotatingKey) ? EpochKeyId : WeaveKeyId::kNone,
568
0
                AppGroupMasterKeyId,
569
0
                (EncKeyType == WeaveKeyId::kType_AppRotatingKey && EpochKeyId == WeaveKeyId::kNone));
570
0
}
571
572
bool GroupKeyEncOptions::HandleOption(const char *progName, OptionSet *optSet, int id, const char *name, const char *arg)
573
0
{
574
0
    switch (id)
575
0
    {
576
0
#if WEAVE_CONFIG_USE_APP_GROUP_KEYS_FOR_MSG_ENC
577
0
    case kToolCommonOpt_GroupEncKeyId:
578
0
        if (!ParseInt(arg, EncKeyId, 0) || !WeaveKeyId::IsValidKeyId(EncKeyId) || !WeaveKeyId::IsAppGroupKey(EncKeyId))
579
0
        {
580
0
            PrintArgError("%s: Invalid value specified for the group encryption key id: %s\n", progName, arg);
581
0
            return false;
582
0
        }
583
0
        break;
584
0
    case kToolCommonOpt_GroupEncKeyType:
585
0
    {
586
0
        bool invalidKeyType;
587
0
        invalidKeyType = false;
588
0
        if (strlen(arg) != 1)
589
0
        {
590
0
            invalidKeyType = true;
591
0
        }
592
0
        else if (*arg == 'r')
593
0
        {
594
0
            EncKeyType = WeaveKeyId::kType_AppRotatingKey;
595
0
        }
596
0
        else if (*arg == 's')
597
0
        {
598
0
            EncKeyType = WeaveKeyId::kType_AppStaticKey;
599
0
        }
600
0
        else
601
0
        {
602
0
            invalidKeyType = true;
603
0
        }
604
605
0
        if (invalidKeyType)
606
0
        {
607
0
            PrintArgError("%s: Invalid value specified for the group encryption key type: %s\n", progName, arg);
608
0
            return false;
609
0
        }
610
0
        break;
611
0
    }
612
0
    case kToolCommonOpt_GroupEncRootKey:
613
0
    {
614
0
        bool invalidRootKey;
615
0
        invalidRootKey = false;
616
0
        if (strlen(arg) != 1)
617
0
        {
618
0
            invalidRootKey = true;
619
0
        }
620
0
        else if (*arg == 'f')
621
0
        {
622
0
            RootKeyId = WeaveKeyId::kFabricRootKey;
623
0
        }
624
0
        else if (*arg == 'c')
625
0
        {
626
0
            RootKeyId = WeaveKeyId::kClientRootKey;
627
0
        }
628
0
        else if (*arg == 's')
629
0
        {
630
0
            RootKeyId = WeaveKeyId::kServiceRootKey;
631
0
        }
632
0
        else
633
0
        {
634
0
            invalidRootKey = true;
635
0
        }
636
637
0
        if (invalidRootKey)
638
0
        {
639
0
            PrintArgError("%s: Invalid value specified for the root key: %s\n", progName, arg);
640
0
            return false;
641
0
        }
642
0
        break;
643
0
    }
644
0
    case kToolCommonOpt_GroupEncEpochKeyNum:
645
0
    {
646
0
        uint32_t epochKeyNum;
647
0
        if (!ParseInt(arg, epochKeyNum, 0) || epochKeyNum > 7)
648
0
        {
649
0
            PrintArgError("%s: Invalid value specified for the epoch key number: %s\n", progName, arg);
650
0
            return false;
651
0
        }
652
0
        EpochKeyId = WeaveKeyId::MakeEpochKeyId(epochKeyNum);
653
0
        break;
654
0
    }
655
0
    case kToolCommonOpt_GroupEncAppGroupMasterKeyNum:
656
0
    {
657
0
        uint32_t masterKeyNum;
658
0
        if (!ParseInt(arg, masterKeyNum, 0) || masterKeyNum > 127)
659
0
        {
660
0
            PrintArgError("%s: Invalid value specified for the group master key number: %s\n", progName, arg);
661
0
            return false;
662
0
        }
663
0
        AppGroupMasterKeyId = WeaveKeyId::MakeAppGroupMasterKeyId(masterKeyNum);
664
0
        break;
665
0
    }
666
0
#endif // WEAVE_CONFIG_USE_APP_GROUP_KEYS_FOR_MSG_ENC
667
0
    default:
668
0
        PrintArgError("%s: INTERNAL ERROR: Unhandled option: %s\n", progName, name);
669
0
        return false;
670
0
    }
671
672
0
    return true;
673
0
}
674
675
GeneralSecurityOptions::GeneralSecurityOptions()
676
10
{
677
10
    static OptionDef optionDefs[] =
678
10
    {
679
10
#if WEAVE_CONFIG_ENABLE_CASE_RESPONDER
680
10
        { "idle-session-timeout",           kArgumentRequired, kToolCommonOpt_GeneralSecurityIdleSessionTimeout                },
681
10
        { "session-establishment-timeout",  kArgumentRequired, kToolCommonOpt_GeneralSecuritySessionEstablishmentTimeout       },
682
10
#endif
683
10
        { }
684
10
    };
685
10
    OptionDefs = optionDefs;
686
687
10
    HelpGroupName = "GENERAL SECURITY OPTIONS";
688
689
10
    OptionHelp =
690
10
        "  --idle-session-timeout <int>\n"
691
10
        "       The number of milliseconds after which an idle session will be removed.\n"
692
10
        "\n"
693
10
        "  --session-establishment-timeout <int>\n"
694
10
        "       The number of milliseconds after which an in-progress session establishment will timeout.\n"
695
10
        "\n"
696
10
        "";
697
698
    // Defaults.
699
10
    IdleSessionTimeout = WEAVE_CONFIG_DEFAULT_SECURITY_SESSION_IDLE_TIMEOUT;
700
10
    SessionEstablishmentTimeout = WEAVE_CONFIG_DEFAULT_SECURITY_SESSION_ESTABLISHMENT_TIMEOUT;
701
10
}
702
703
uint32_t GeneralSecurityOptions::GetIdleSessionTimeout() const
704
0
{
705
0
    return IdleSessionTimeout;
706
0
}
707
708
uint32_t GeneralSecurityOptions::GetSessionEstablishmentTimeout() const
709
0
{
710
0
    return SessionEstablishmentTimeout;
711
0
}
712
713
bool GeneralSecurityOptions::HandleOption(const char *progName, OptionSet *optSet, int id, const char *name, const char *arg)
714
0
{
715
0
    switch (id)
716
0
    {
717
0
    case kToolCommonOpt_GeneralSecurityIdleSessionTimeout:
718
0
        if ((!ParseInt(arg, IdleSessionTimeout)) || IdleSessionTimeout == 0)
719
0
        {
720
0
            PrintArgError("%s: Invalid value specified for the idle session timeout: %s\n", progName, arg);
721
0
            return false;
722
0
        }
723
0
        break;
724
0
    case kToolCommonOpt_GeneralSecuritySessionEstablishmentTimeout:
725
0
        if ((!ParseInt(arg, SessionEstablishmentTimeout)) || SessionEstablishmentTimeout == 0)
726
0
        {
727
0
            PrintArgError("%s: Invalid value specified for the session establishment timeout: %s\n", progName, arg);
728
0
            return false;
729
0
        }
730
0
        break;
731
0
    default:
732
0
        PrintArgError("%s: INTERNAL ERROR: Unhandled option: %s\n", progName, name);
733
0
        return false;
734
0
    }
735
736
0
    return true;
737
0
}
738
739
ServiceDirClientOptions::ServiceDirClientOptions()
740
10
{
741
10
    static OptionDef optionDefs[] =
742
10
    {
743
10
#if WEAVE_CONFIG_ENABLE_SERVICE_DIRECTORY
744
10
        { "service-dir-server",             kArgumentRequired, kToolCommonOpt_ServiceDirServer },
745
10
        { "service-dir-url",                kArgumentRequired, kToolCommonOpt_ServiceDirServer }, // deprecated alias for service-dir-server
746
10
#if WEAVE_CONFIG_ENABLE_DNS_RESOLVER
747
10
        { "service-dir-dns-options",        kArgumentRequired, kToolCommonOpt_ServiceDirDNSOptions },
748
10
        { "service-dir-target-dns-options", kArgumentRequired, kToolCommonOpt_ServiceDirTargetDNSOptions },
749
10
#endif // WEAVE_CONFIG_ENABLE_DNS_RESOLVER
750
10
#endif // WEAVE_CONFIG_ENABLE_SERVICE_DIRECTORY
751
10
        { }
752
10
    };
753
10
    OptionDefs = optionDefs;
754
755
10
    HelpGroupName = "SERVICE DIRECTORY OPTIONS";
756
757
10
    OptionHelp =
758
10
#if WEAVE_CONFIG_ENABLE_SERVICE_DIRECTORY
759
10
        "  --service-dir-server <host-name-or-ip-addr>[:<port>]\n"
760
10
        "       Use the specified server when making service directory requests.\n"
761
10
        "       (Deprecated alias: --service-dir-url)\n"
762
10
        "\n"
763
10
#if WEAVE_CONFIG_ENABLE_DNS_RESOLVER
764
10
        "  --service-dir-dns-options <dns-options>\n"
765
10
        "  --service-dir-target-dns-options <dns-options>\n"
766
10
        "       Use the specified DNS options when resolving hostnames during a\n"
767
10
        "       service connection attempt.  The first option controls the DNS\n"
768
10
        "       options used when connecting to the ServiceDirectory endpoint\n"
769
10
        "       itself.  The second option controls the DNS option used when\n"
770
10
        "       connecting to the endpoint that is ultimate target of the service\n"
771
10
        "       connection.  <dns-options> can be one of the following keywords:\n"
772
10
        "           Any (the default)\n"
773
10
        "              - Resolve IPv4 and/or IPv6 addresses in the native order\n"
774
10
        "                returned by the name server.\n"
775
10
        "           IPv4Only\n"
776
10
        "              - Resolve IPv4 addresses only.\n"
777
10
        "           IPv6Only\n"
778
10
        "              - Resolve IPv6 addresses only.\n"
779
10
        "           IPv4Preferred\n"
780
10
        "              - Resolve IPv4 and/or IPv6 addresses, with IPv4 addresses\n"
781
10
        "                given preference over IPv6.\n"
782
10
        "           IPv6Preferred\n"
783
10
        "              - Resolve IPv4 and/or IPv6 addresses, with IPv6 addresses\n"
784
10
        "                given preference over IPv4.\n"
785
10
        "\n"
786
10
#endif // WEAVE_CONFIG_ENABLE_DNS_RESOLVER
787
10
#endif // WEAVE_CONFIG_ENABLE_SERVICE_DIRECTORY
788
10
        "";
789
790
    // Defaults.
791
10
    ServerHost = "frontdoor.integration.nestlabs.com";
792
10
    ServerPort = WEAVE_PORT;
793
10
#if WEAVE_CONFIG_ENABLE_DNS_RESOLVER
794
10
    DNSOptions_ServiceDirEndpoint = kDNSOption_AddrFamily_Any;
795
10
    DNSOptions_TargetEndpoint = kDNSOption_AddrFamily_Any;
796
10
#endif
797
10
}
798
799
bool ServiceDirClientOptions::HandleOption(const char *progName, OptionSet *optSet, int id, const char *name, const char *arg)
800
0
{
801
0
    WEAVE_ERROR err;
802
0
    const char *host;
803
0
    uint16_t hostLen;
804
805
0
    switch (id)
806
0
    {
807
0
#if WEAVE_CONFIG_ENABLE_SERVICE_DIRECTORY
808
0
    case kToolCommonOpt_ServiceDirServer:
809
0
        err = ParseHostAndPort(arg, strlen(arg), host, hostLen, ServerPort);
810
0
        if (err != WEAVE_NO_ERROR)
811
0
        {
812
0
            PrintArgError("%s: Invalid value specified for Service Directory server name: %s\n", progName, arg);
813
0
            return false;
814
0
        }
815
0
        ServerHost = strndup(host, hostLen);
816
0
        if (ServerPort == 0)
817
0
            ServerPort = WEAVE_PORT;
818
0
        break;
819
0
#if WEAVE_CONFIG_ENABLE_DNS_RESOLVER
820
0
    case kToolCommonOpt_ServiceDirDNSOptions:
821
0
        if (!ParseDNSOptions(progName, name, arg, DNSOptions_ServiceDirEndpoint))
822
0
        {
823
0
            return false;
824
0
        }
825
0
        break;
826
0
    case kToolCommonOpt_ServiceDirTargetDNSOptions:
827
0
        if (!ParseDNSOptions(progName, name, arg, DNSOptions_TargetEndpoint))
828
0
        {
829
0
            return false;
830
0
        }
831
0
        break;
832
0
#endif // WEAVE_CONFIG_ENABLE_DNS_RESOLVER
833
0
#endif // WEAVE_CONFIG_ENABLE_SERVICE_DIRECTORY
834
0
    default:
835
0
        PrintArgError("%s: INTERNAL ERROR: Unhandled option: %s\n", progName, name);
836
0
        return false;
837
0
    }
838
839
0
    return true;
840
0
}
841
842
WEAVE_ERROR ServiceDirClientOptions::GetRootDirectoryEntry(uint8_t *buf, uint16_t bufSize)
843
0
{
844
0
    using namespace nl::Weave::Encoding;
845
0
    using namespace nl::Weave::Profiles::ServiceDirectory;
846
847
0
    WEAVE_ERROR err = WEAVE_NO_ERROR;
848
0
    uint8_t serverHostLen = (uint8_t)strlen(ServerHost);
849
0
    uint8_t hostPortListLength = 1;
850
851
0
    VerifyOrExit(bufSize >= (1 + 8 + 1 + 1 + serverHostLen + 2), err = WEAVE_ERROR_BUFFER_TOO_SMALL);
852
853
0
    Write8(buf,  kDirectoryEntryType_HostPortList | (hostPortListLength & kMask_HostPortListLen));
854
0
    LittleEndian::Write64(buf, kServiceEndpoint_Directory);  // Service Endpoint Id = Directory Service
855
0
    Write8(buf, kHostIdType_FullyQualified |  kMask_PortIdPresent);
856
0
    Write8(buf, serverHostLen);
857
0
    memcpy(buf, ServerHost, serverHostLen); buf += serverHostLen;
858
0
    LittleEndian::Write16(buf, ServerPort);
859
860
0
exit:
861
0
    return err;
862
0
}
863
864
WEAVE_ERROR GetRootServiceDirectoryEntry(uint8_t *buf, uint16_t bufSize)
865
0
{
866
0
    return gServiceDirClientOptions.GetRootDirectoryEntry(buf, bufSize);
867
0
}
868
869
void ServiceDirClientOptions::OverrideConnectArguments(ServiceConnectBeginArgs & args)
870
0
{
871
0
#if WEAVE_CONFIG_ENABLE_DNS_RESOLVER
872
873
    // If specific DNS options have been set for the connection to the
874
    // ServiceDirectory endpoint, override the default DNS options.
875
0
    if (args.ServiceEndpoint == kServiceEndpoint_Directory)
876
0
    {
877
0
        if (DNSOptions_ServiceDirEndpoint != kDNSOption_AddrFamily_Any)
878
0
        {
879
0
            args.DNSOptions = DNSOptions_ServiceDirEndpoint;
880
0
        }
881
0
    }
882
883
    // Otherwise, if specific DNS options have been set for all other service connections
884
    // override the default DNS options.
885
0
    else
886
0
    {
887
0
        if (DNSOptions_TargetEndpoint != kDNSOption_AddrFamily_Any)
888
0
        {
889
0
            args.DNSOptions = DNSOptions_TargetEndpoint;
890
0
        }
891
0
    }
892
893
0
#endif // WEAVE_CONFIG_ENABLE_DNS_RESOLVER
894
0
}
895
896
void OverrideServiceConnectArguments(::nl::Weave::Profiles::ServiceDirectory::ServiceConnectBeginArgs & args)
897
0
{
898
0
    gServiceDirClientOptions.OverrideConnectArguments(args);
899
0
}
900
901
FaultInjectionOptions::FaultInjectionOptions()
902
10
{
903
10
    static OptionDef optionDefs[] =
904
10
    {
905
10
#if WEAVE_CONFIG_TEST || WEAVE_SYSTEM_CONFIG_TEST || INET_CONFIG_TEST
906
10
        { "faults",                kArgumentRequired, kToolCommonOpt_FaultInjection      },
907
10
        { "iterations",            kArgumentRequired, kToolCommonOpt_FaultTestIterations },
908
10
        { "debug-resource-usage",  kNoArgument,       kToolCommonOpt_DebugResourceUsage  },
909
10
        { "print-fault-counters",  kNoArgument,       kToolCommonOpt_PrintFaultCounters  },
910
10
        { "extra-cleanup-time",    kArgumentRequired, kToolCommonOpt_ExtraCleanupTime },
911
10
#endif
912
10
        { }
913
10
    };
914
10
    OptionDefs = optionDefs;
915
916
10
    HelpGroupName = "FAULT INJECTION OPTIONS";
917
918
10
    OptionHelp =
919
10
#if WEAVE_CONFIG_TEST || WEAVE_SYSTEM_CONFIG_TEST || INET_CONFIG_TEST
920
10
        "  --faults <fault-string>\n"
921
10
        "       Inject specified fault(s) into the operation of the tool at runtime.\n"
922
10
        "\n"
923
10
        "  --iterations <int>\n"
924
10
        "       Execute the program operation the given number of times\n"
925
10
        "\n"
926
10
        "  --debug-resource-usage\n"
927
10
        "       Print all stats counters before exiting.\n"
928
10
        "\n"
929
10
        "  --print-fault-counters\n"
930
10
        "       Print the fault-injection counters before exiting.\n"
931
10
        "\n"
932
10
        "  --extra-cleanup-time\n"
933
10
        "       Allow extra time before asserting resource leaks; this is useful when\n"
934
10
        "       running fault-injection tests to let the system free stale ExchangeContext\n"
935
10
        "       instances after WRMP has exhausted all retransmission; a failed WRMP transmission\n"
936
10
        "       should fail a normal happy-sequence test, but not necessarily a fault-injection test.\n"
937
10
        "       The value is in milliseconds; a common value is 10000.\n"
938
10
        "\n"
939
10
#endif
940
10
        "";
941
942
    // Defaults
943
10
    TestIterations = 1;
944
10
    DebugResourceUsage = false;
945
10
    PrintFaultCounters = false;
946
10
    ExtraCleanupTimeMsec = 0;
947
10
}
948
949
bool FaultInjectionOptions::HandleOption(const char *progName, OptionSet *optSet, int id, const char *name, const char *arg)
950
0
{
951
0
    using namespace nl::FaultInjection;
952
953
0
    GetManagerFn faultMgrFnTable[] =
954
0
    {
955
0
        nl::Weave::FaultInjection::GetManager,
956
0
        nl::Inet::FaultInjection::GetManager,
957
0
        nl::Weave::System::FaultInjection::GetManager
958
0
    };
959
0
    size_t faultMgrFnTableLen = sizeof(faultMgrFnTable) / sizeof(faultMgrFnTable[0]);
960
961
0
    switch (id)
962
0
    {
963
0
#if WEAVE_CONFIG_TEST || WEAVE_SYSTEM_CONFIG_TEST || INET_CONFIG_TEST
964
0
    case kToolCommonOpt_FaultInjection:
965
0
    {
966
0
        char *mutableArg = strdup(arg);
967
0
        bool parseRes = ParseFaultInjectionStr(mutableArg, faultMgrFnTable, faultMgrFnTableLen);
968
0
        free(mutableArg);
969
0
        if (!parseRes)
970
0
        {
971
0
            PrintArgError("%s: Invalid string specified for fault injection option: %s\n", progName, arg);
972
0
            return false;
973
0
        }
974
0
        break;
975
0
    }
976
0
    case kToolCommonOpt_FaultTestIterations:
977
0
        if ((!ParseInt(arg, TestIterations)) || (TestIterations == 0))
978
0
        {
979
0
            PrintArgError("%s: Invalid value specified for the number of iterations to execute: %s\n", progName, arg);
980
0
            return false;
981
0
        }
982
0
        break;
983
0
    case kToolCommonOpt_DebugResourceUsage:
984
0
        DebugResourceUsage = true;
985
0
        break;
986
0
    case kToolCommonOpt_PrintFaultCounters:
987
0
        PrintFaultCounters = true;
988
0
        break;
989
0
    case kToolCommonOpt_ExtraCleanupTime:
990
0
        if ((!ParseInt(arg, ExtraCleanupTimeMsec)) || (ExtraCleanupTimeMsec == 0))
991
0
        {
992
0
            PrintArgError("%s: Invalid value specified for the extra time to wait before checking for leaks: %s\n", progName, arg);
993
0
            return false;
994
0
        }
995
0
        break;
996
0
#endif // WEAVE_CONFIG_TEST || WEAVE_SYSTEM_CONFIG_TEST || INET_CONFIG_TEST
997
0
    default:
998
0
        PrintArgError("%s: INTERNAL ERROR: Unhandled option: %s\n", progName, name);
999
0
        return false;
1000
0
    }
1001
1002
0
    return true;
1003
0
}
1004
1005
1006
#if WEAVE_CONFIG_ENABLE_DNS_RESOLVER
1007
1008
static bool GetToken(const char * & inStr, const char * & token, size_t & tokenLen, const char * sepChars)
1009
0
{
1010
0
    token = inStr;
1011
1012
    // Skip leading whitespace
1013
0
    while (*token != 0 && isspace(*token))
1014
0
    {
1015
0
        token++;
1016
0
    }
1017
1018
    // Check no more tokens.
1019
0
    if (*token == 0)
1020
0
    {
1021
0
        return false;
1022
0
    }
1023
1024
    // Find end of token and advance inStr beyond end of token.
1025
0
    const char * tokenEnd = strpbrk(token, sepChars);
1026
0
    if (tokenEnd != NULL)
1027
0
    {
1028
0
        tokenLen = tokenEnd - inStr;
1029
0
        inStr = tokenEnd + 1;
1030
0
    }
1031
0
    else
1032
0
    {
1033
0
        tokenLen = strlen(token);
1034
0
        inStr += tokenLen;
1035
0
    }
1036
1037
    // Trim trailing whitespace.
1038
0
    while (tokenLen > 0 && isspace(token[tokenLen - 1]))
1039
0
    {
1040
0
        tokenLen--;
1041
0
    }
1042
1043
0
    return true;
1044
0
}
1045
1046
static bool MatchToken(const char * token, size_t tokenLen, const char * expectedStr)
1047
0
{
1048
0
    return strlen(expectedStr) == tokenLen && strncasecmp(expectedStr, token, tokenLen) == 0;
1049
0
}
1050
1051
/**
1052
 * Parse a string representation of the nl::Inet::DNSOptions enumeration.
1053
 */
1054
bool ParseDNSOptions(const char * progName, const char *argName, const char * arg, uint8_t & dnsOptions)
1055
0
{
1056
0
    const char * token;
1057
0
    size_t tokenLen;
1058
1059
0
    dnsOptions = kDNSOption_AddrFamily_Any;
1060
1061
0
    while (GetToken(arg, token, tokenLen, ",|:"))
1062
0
    {
1063
0
        if (MatchToken(token, tokenLen, "Any"))
1064
0
        {
1065
0
            dnsOptions = (dnsOptions & ~kDNSOption_AddrFamily_Mask) | kDNSOption_AddrFamily_Any;
1066
0
        }
1067
0
        else if (MatchToken(token, tokenLen, "IPv4Only"))
1068
0
        {
1069
0
#if INET_CONFIG_ENABLE_IPV4
1070
0
            dnsOptions = (dnsOptions & ~kDNSOption_AddrFamily_Mask) | kDNSOption_AddrFamily_IPv4Only;
1071
#else
1072
            PrintArgError("%s: DNSOption IPv4Only not supported\n", progName);
1073
            return false;
1074
#endif
1075
0
        }
1076
0
        else if (MatchToken(token, tokenLen, "IPv4Preferred"))
1077
0
        {
1078
0
#if INET_CONFIG_ENABLE_IPV4
1079
0
            dnsOptions = (dnsOptions & ~kDNSOption_AddrFamily_Mask) | kDNSOption_AddrFamily_IPv4Preferred;
1080
#else
1081
            PrintArgError("%s: DNSOption IPv4Preferred not supported\n", progName);
1082
            return false;
1083
#endif
1084
0
        }
1085
0
        else if (MatchToken(token, tokenLen, "IPv6Only"))
1086
0
        {
1087
0
            dnsOptions = (dnsOptions & ~kDNSOption_AddrFamily_Mask) | kDNSOption_AddrFamily_IPv6Only;
1088
0
        }
1089
0
        else if (MatchToken(token, tokenLen, "IPv6Preferred"))
1090
0
        {
1091
0
            dnsOptions = (dnsOptions & ~kDNSOption_AddrFamily_Mask) | kDNSOption_AddrFamily_IPv6Preferred;
1092
0
        }
1093
0
        else
1094
0
        {
1095
0
            PrintArgError("%s: Unrecognized value specified for %s: %*s\n", progName, argName, tokenLen, token);
1096
0
            return false;
1097
0
        }
1098
0
    }
1099
1100
0
    return true;
1101
0
}
1102
1103
bool ResolveWeaveNetworkOptions(const char *progName, WeaveNodeOptions &weaveOptions, NetworkOptions &networkOptions)
1104
0
{
1105
0
    if (!networkOptions.LocalIPv6Addr.empty())
1106
0
    {
1107
0
        if (!networkOptions.LocalIPv6Addr[0].IsIPv6ULA())
1108
0
        {
1109
0
            PrintArgError("%s: Local address must be an IPv6 ULA\n", progName);
1110
0
            return false;
1111
0
        }
1112
1113
0
        if (!weaveOptions.FabricIdSet)
1114
0
            weaveOptions.FabricId = networkOptions.LocalIPv6Addr[0].GlobalId();
1115
0
        if (!weaveOptions.LocalNodeIdSet)
1116
0
            weaveOptions.LocalNodeId = IPv6InterfaceIdToWeaveNodeId(networkOptions.LocalIPv6Addr[0].InterfaceId());
1117
0
        if (!weaveOptions.SubnetIdSet)
1118
0
            weaveOptions.SubnetId = networkOptions.LocalIPv6Addr[0].Subnet();
1119
0
    }
1120
0
    return true;
1121
0
}
1122
1123
#endif // WEAVE_CONFIG_ENABLE_DNS_RESOLVER