-
Notifications
You must be signed in to change notification settings - Fork 0
/
addp.pl
1914 lines (1832 loc) · 82.5 KB
/
addp.pl
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
#!/usr/bin/perl
# addp.pl: Digi device detection and control via ADDP and SNMP
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
####
# TODO: Obtain Digi Wifi device to see if more addp codes come back.
# TODO: Obtain Digi MEI device to see is more snmp codes come back
# TODO: verify implementation of DVKT. I don't have a development kit.
# not TODO: ipv6, no evidence that it is documented or implemented in any Digi utility..
# There are more switches in the addp readme but they appear to be not implemented.
# TODO: should we add -q -m MAC1,MAC2,MAC3
# TODO: I've read that some devices require an encrypted password.
# TODO: What is ADDP response code 25? Reported by PortServer TS, not reported by Digi One SP.
# not TODO: Try to support B&B VESP, a Digi OEM product. Structures are completely different.
# TODO: Provide code to WireShark team so they can decode these packets
# TODO: Improve SNMP name detection with more Digi models.
# TODO: ADDP repeater/proxy to allow scans on distant networks.
# TODO: Finalize location of drpadmin
# TODO: Set g_src when github is done
# http://www.digi.com/wiki/developer/index.php/Advanced_Device_Discovery_Protocol_(ADDP)
# http://qbeukes.blogspot.com/2009/11/advanced-digi-discovery-protocol_21.html
# https://github.com/christophgysin/addp
# This is a remake of Digi's ADDP and SDDP in Perl. Digi does not supply a 64 bit version of ADDP
# and Digi ADDP does not produce a brief output suitable for use in drpadmin.
# This is named addp.pl instead of addp to avoid conflicting with any addp
# already installed. Tab completion will show it.
# The ADDP protocol is Copyright (C) Digi Corporation
# Related Digi Programs
# 81000137_X.tgz dgrp: tty driver in C source
# 40002188_H.tgz Digi Port Authority DPA: SNMP and ADDP gui in tcl/tk, aging badly, hard to get working.
# 40002188_H.tgz sddp: SNMP cli in compiled C
# 40002889_A.tgz addp: cli in compiled C, also 40002890_A.tgz
# addplib-1.0.jar ADDP Library: sdk in java
# AddpClient.jar Digi Device Discovery Tool: ADDP gui in java, lots of inaccurate codes
# Digi DCRabbit, https://github.com/digidotcom/DCRabbit_10
# netos74, not generally available
# Related non Digi programs
# drpadmin: A remake for Linux dgrp of the tui drpadmin found in SCO, HP UX, and Solaris
# Metasploit::addp.rb https://github.com/rapid7/metasploit-fraamework/blob/master/lib/rex/proto/addp.rb
use strict;
use warnings;
use integer; # Changes bitwise operations to signed. Signed is useless if you can't control the size.
use bytes;
no utf8;
no overloading;
no locale;
use Socket qw(PF_INET SOCK_STREAM pack_sockaddr_in inet_aton);
use IO::Socket;
#use IO::Socket::Multicast;
use IO::Select;
use Socket qw(IPPROTO_TCP TCP_NODELAY);
use Time::HiRes qw(gettimeofday tv_interval usleep);
use Getopt::Long qw(:config bundling no_ignore_case no_auto_abbrev no_getopt_compat no_permute require_order);
use Data::Dumper;
my $g_src='github: addp.pl';
sub usage {
my $usage= <<EOF;
Commands: -Q -q -R -S
Usage examples:
addp.pl -Q # query all devices
addp.pl -Q --snmp # query all devices ADDP and SNMP. This catches non ADDP devices like the PortServer II. Name detection isn't perfect.
addp.pl -q -m 000001 -n 192.168.1.5 # Using only the specified interface, query specific device with MAC scanned from short Digi MAC barcode label.
addp.pl -R -m 000000000001 # reboot device with the default password with MAC scanned from long Digi MAC barcode label.
addp.pl -S -m 00-00-00-00-00-01 -d # set device to DHCP with the default password and Windows MAC format. -d On also works.
addp.pl -S -m 00-00-00-00-00-01 -d Off # set device to static with current settings. Avoid this because it can leave the unit unreachable at address 0.0.0.0. Use -S.
addp.pl -R -m 00:00:00:00:00:01 -S -d -p '1234' # set device to DHCP and reboot using specified password. -R and -S can be in any order.
addp.pl -S -m 00:00:00:00:00:01 -a 192.168.1.50/24 -g 0.0.0.0 # set device to static IP with no gateway.
addp.pl -S -m 00:00:00:00:00:01 -a 192.168.1.50 -s 255.255.255.0 -g 192.168.1.1 # set device to static IP with gateway.
addp.pl -S # show which options are needed for -S
addp.pl -S -d # show which remaining options are still needed for -S
addp.pl -S -d -a 192.168.50.50/24 # Conflicting options will get you nowhere.
See source for other less common commands and options.
EOF
#addp.pl -Q -addip 10.1.10.10 # Query ADDP device across VPN
#addp.pl -R -addip 10.1.10.10 # Reboot ADDP device across VPN. MAC will be retrieved automatically or you can supply it with -m
print $usage;
exit 1;
}
usage() if (scalar @ARGV == 0);
my $opt_IPAddress='';
my $opt_IPSubnet=''; # can be derived from IP specified like 192.168.1.10/24
my $opt_MACAddress='';
my $opt_BindAddress='';
my $opt_IPGateway='';
my $opt_DHCP;
my $DefaultPassword="dbps";
my $opt_Password; # -p '' is allowed. Digi Device Discovery Tool tries blank passwords first.
my $opt_QueryAll=0;
my $opt_QueryMAC=0;
my $opt_SaveSettings=0;
my $opt_RebootDevice=0;
my $opt_TimeoutS=2; # Timeout in seconds to wait for multiple queries to return. This time isn't exact.
my $opt_Debug=0; # 0=normal responses, 1=debug received responses, 2=debug sent and received responses
my $opt_Quiet=0; # supress normal responses. -Q or -q responses cannot be suppressed
my $opt_LimitQuery=0; # 0 for all results, >0 to only show n results or less. Usually used with --query-short.
my $opt_BackingStore=''; # '' for all results, /etc/dgrp.backing.store to supress output of already configured devices
my $opt_QueryShort=0; # 0 for full detail, 1 for a one line summary. 1 enables SNMP searches to catch non addp Digi products.
my %BackingStore; # $_{$ip}=1 foreach ip in the backing store
my $opt_Version=0; # Show version and exit. Can be combined with 1 or more --quiet to remove version cruft.
my $opt_DataDump=''; # Dump transmit and responses to a file. May help with bug reports.
my $opt_DataRead=''; # Read and decode responses from file. Usually used with --debug.
my $opt_SNMP=''; # Perform SNMP broadcasts along with addp. Only works with -Q for broadcasts.
my $opt_DecodeAddp=''; # Decode addp from Wireshark copy bytes hex stream (data only)
# addp.pl --debug=1 --decode-addp '44564b540001001cffffffffffff1510bf6db409c83d44a3a36d21797d2f73f914020200'
my $opt_Magic='DIGI'; # Specify alternate magic. See %ADDP_MAGICS. You can specify any 4 letter magic you like but things won't well well if you just make one up. The GUIs reuse the magic from received responses.
my $opt_GUID; # Specify alternate GUID.
my $opt_Vendor; # Specify Vendor for GUID.
my $DefaultAddpIP="224.0.5.128";
my $opt_AddpIP; # Send addp packets directly to the IP instead of the multicast.
# Makes it harder for eavesdroppers to capture passwords in -R and -S packets.
# Can be used with -Q to find the MAC address of units behind routers and across VPN.
# Used with -R or -S, the MAC can be left off and it will be retrieved automatically.
# This allows reboot or configuration of units across routers without having to manually retrieve the MAC.
my $opt_SignedBytes=''; # Convert a series of signed integers to hex bytes. Read the GUID from VendorGuid.class
my $opt_ConflictOverride=0; # Lets you specify any command line options you want. Might be dangerous, cause strange errors, or crash the program. Mainly used for making the program. If you need it for something useful that works then it's a bug that should be reported.
# These options are made to be as close to addp as possible so this can be a drop in replacement for as much as we support.
GetOptions(
"ip-address|a=s" => \$opt_IPAddress,
"ip-subnet|s=s" => \$opt_IPSubnet,
"mac-address|m=s"=> \$opt_MACAddress,
"interface|n=s" => \$opt_BindAddress,
"ip-gateway|g=s" => \$opt_IPGateway,
"use-dhcp|d:s" => \$opt_DHCP,
"password|p=s" => \$opt_Password,
"query-all|Q" => \$opt_QueryAll,
"query-mac|q" => \$opt_QueryMAC,
# Todo: -C return a list of available country codes (Wireless only)
"save-settings|S"=> \$opt_SaveSettings,
"reboot-device|R"=> \$opt_RebootDevice,
# Todo: -W Save wireless settings
# Todo: -I Auto ssid
# Todo: -e encryption
# Todo: -i ssid string
# Todo: -A Network authentication
# Todo: -P TX Enhanced power
# Todo: -k Encryption key
# Todo: -c country code
# According to the getopts string in addp, these missing options are not implemented in addp.
# I can't find them in DPA.
# Some are implemented in addplib-1.0.jar
# new options, long form only!
"timeout=i" => \$opt_TimeoutS,
"debug=i" => \$opt_Debug,
"quiet+" => \$opt_Quiet,
"limit-query=i" => \$opt_LimitQuery,
"backing-store=s" => \$opt_BackingStore,
"query-short" => \$opt_QueryShort,
"version" => \$opt_Version,
"data-dump=s" => \$opt_DataDump,
"data-read=s" => \$opt_DataRead,
"snmp" => \$opt_SNMP,
"decode-addp=s" => \$opt_DecodeAddp, # no point in decode-snmp. Wireshark already does this though somewhat less informative than we do.
"magic=s" => \$opt_Magic,
"guid=s" => \$opt_GUID,
"vendor=i" => \$opt_Vendor,
"addpip=s" => \$opt_AddpIP,
"signed-bytes=s" => \$opt_SignedBytes,
"conflict-override" => \$opt_ConflictOverride,
) or die("Error in command line arguments\n");
if ($opt_Version) {
# Do not add comments to or change the quotes on the next lines. They are expected to be sed by distros.
my $distro='Arch Linux';
my $version='1.0';
if ($opt_Quiet==2) {
printf("%s",$version);
} elsif ($opt_Quiet==1) {
printf("%s-%s",$version,$distro);
} else {
printf("Version %s for %s\n",$version,$distro);
}
exit(0);
}
# converts to a number decimal, octal, or hex. Binary is not accepted.
# to duplicate what Windows ping accepts
# Desirable numbers range from 0 to 255
# Returns >255 for invalid or negative numbers
sub hexOctDec {
my ($arg_num)=(@_);
#print STDERR "hexOctDec Checking ".$arg_num."\n";
return 256 if (not defined($arg_num));
return oct($arg_num) if ($arg_num =~ m/^0[0-7]+/ or $arg_num =~ m/^0[xX][[:xdigit:]]+/);
return $arg_num+0 if ($arg_num =~ m/^\d+$/); # leading 0 taken above
return 256; # we don't accept 0b binary or text
}
sub hexOctDecCheck {
if (hexOctDec('0b111') != 256
or hexOctDec('0x101') != 257
or hexOctDec('0401') != 257
or hexOctDec('www') != 256
or hexOctDec('0ww') != 256
or hexOctDec('') != 256
or hexOctDec('-6') != 256
) {
die("hexOctDecCheck failed\n");
}
}
hexOctDecCheck() if ($opt_Debug);
# Return 0 if valid, 1 if not valid
# $subnet: 0=normal IP check, 1=must be valid CIDR subnet
sub isNotValidIP {
my ($arg_ip,$arg_subnet)=(@_);
if (length($arg_ip)) {
# Strawberry perl 5.24 inet_aton("255.255.255.256") pauses for a few seconds trying to calculate this.
# inet_aton does DNS lookups on addresses it can't convert to numbers like 255.255.255.256 or www.google.com.
# We accept IP addresses only, including octal and hex because, anoyingly enough, Windows ping accepts this
# ping 0x0A.1.012.1 to ping a cable modem at 10.1.10.1
my @ips=split(/\./,$arg_ip);
return 1 if (scalar @ips != 4);
foreach (@ips) {
return 1 if (hexOctDec($_)>255);
}
my $ipn=inet_aton($arg_ip);
if (not defined $ipn) { return 1; }
if ($arg_subnet) {
my $ipb=unpack("B*",$ipn);
if (not $ipb =~ m/^1*0*$/) { return 1; }
}
}
return 0;
}
#print isNotValidIP('128.0.0.1',0); die();
# early fixes to options
sub optfixup {
if (length($opt_IPSubnet)==0 and $opt_IPAddress =~ m/^([^\/]+)\/([0-9]{1,2})$/ and isNotValidIP($1,0)==0 and $2>0 and $2<=32) {
$opt_IPAddress=$1;
$opt_IPSubnet=inet_ntoa(pack("N",oct("0b"."1" x $2."0" x (32-$2))));
}
}
optfixup();
# From AddpClient.jar MagicCookie.class and http://ftp1.digi.com/support/documentation/html/90001429/com/digi/addp/AddpClient.html
my %ADDP_MAGICS=(
'DIGI' => "Digi Commercial Products",
'DVKT' => "Digi Development Kit (new)", # NetSilicon
'DGDP' => "Digi Development Kit (pre 6.0)",
);
# from AddpClient.jar VendorGuid.class. Converted with option --signed-bytes
my %ADDP_GUIDS=(
'NETSILICON' => "bf6db409-c83d-44a3-a36d-21797d2f73f9",
'DIGI' => "fbb24a71-1ff7-4ade-f54d-3b1fb24d2941",
'INSIDE' => "e34e79d8-1c5d-40a1-e60a-33b9eef78837",
'EMBRACE' => "e42a6f12-b212-4e05-fb6c-2f9c8b28ad59",
);
# $arg_mac: the MAC address in one of many text forms like "00:00:00:00:00:00"
# $arg_short: 1 if short MAC 00:00:00 is allowed, 0 if full 12 digit MAC is required
# return: 0 if MAC is valid, 1 if MAC is not valid
# an empty MAC is considered invalid
# Copy-paste mistakes are permitted: -00-00-00 :00:00:00
# Slop variations not allowed: 00-00-00:00:00:00 0000:00
sub isNotValidMAC {
my ($arg_mac,$arg_short)=(@_);
$arg_mac=lc $arg_mac;
$arg_mac =~ tr/123456789abcdef/000000000000000/ ;
#printf STDERR ("Testing MAC %s, short=%u\n",$arg_mac,$arg_short);
return 1 if (length($arg_mac)==0);
return 0 if ($arg_mac eq '00:00:00:00:00:00' or $arg_mac eq '00-00-00-00-00-00' or $arg_mac eq '000000000000');
return 1 if (not $arg_short);
return 0 if ($arg_mac eq ':00:00:00' or $arg_mac eq '-00-00-00' or $arg_mac eq '00:00:00' or $arg_mac eq '00-00-00' or $arg_mac eq '000000');
return 1;
}
# Check option values for bad formatting or out of rage.
# Options are modified after being shown to the user in their original form.
# We blank out or correct invalid values to prevent more checking. Improper values can be blanked out but it's not necessary.
use constant {
ADDP_OPCODE_MAGIC_LEN => 4,
};
sub opterrors {
my $errors=0;
if (length($opt_Magic) != ADDP_OPCODE_MAGIC_LEN) {
printf STDERR ("--magic is %u characters. Try %s\n",ADDP_OPCODE_MAGIC_LEN,join(" ",sort keys %ADDP_MAGICS));
$errors++;
$opt_Magic='';
}
if ($opt_Debug<0) {
printf STDERR ("--debug <0, let's not!\n");
$errors++;
$opt_Debug=0;
}
if (length($opt_MACAddress) and isNotValidMAC($opt_MACAddress,1)) {
printf STDERR ("Invalid MAC address %s\n",$opt_MACAddress);
$errors++;
$opt_MACAddress='';
}
if (isNotValidIP($opt_BindAddress,0)) {
printf STDERR ("Invalid IP address -a %s\n",$opt_BindAddress);
$errors++;
$opt_BindAddress='';
}
if (isNotValidIP($opt_IPAddress,0)) {
printf STDERR ("Invalid IP address -a %s\n",$opt_IPAddress);
$errors++;
$opt_IPAddress='';
}
if (isNotValidIP($opt_IPSubnet,1)) {
printf STDERR ("Invalid subnet -s %s\n",$opt_IPSubnet);
$errors++;
$opt_IPSubnet='';
}
if (isNotValidIP($opt_IPGateway,0)) {
printf STDERR ("Invalid gateway -g %s\n",$opt_IPGateway);
$errors++;
$opt_IPGateway='';
}
if (length($opt_IPAddress) and length($opt_IPSubnet) and length($opt_IPGateway)) {
my $iperrors=0;
my $i=inet_aton($opt_IPAddress);
my $s=inet_aton($opt_IPSubnet);
my $sn=unpack("B*",$s); $sn =~ /^(1*)0*$/; $sn=length($1);
my $g=inet_aton($opt_IPGateway);
if ( inet_ntoa($g) ne '0.0.0.0' and inet_ntoa($i & $s) ne inet_ntoa($g & $s) ){ # We could have used cmp but this is already done.
printf STDERR ("Gateway -g %s not in subnet of -a %s\n",$opt_IPGateway,$opt_IPAddress);
$iperrors++;
}
if ($sn < 31) { # no broadcast on /31 or /32
my $ig=inet_ntoa($i);
if ( $ig eq inet_ntoa($i | ~$s) or $ig eq inet_ntoa($i & $s) ){
printf STDERR ("ip -a %s cannot be broadcast\n",$opt_IPAddress);
$iperrors++;
}
$ig=inet_ntoa($g);
if ( $ig ne '0.0.0.0' and ($ig eq inet_ntoa($g | ~$s) or $ig eq inet_ntoa($g & $s)) ){
printf STDERR ("gateway -g %s cannot be broadcast\n",$opt_IPGateway);
$iperrors++;
}
}
if ($iperrors) {
$errors += $iperrors;
$opt_IPAddress='';
$opt_IPSubnet='';
$opt_IPGateway='';
}
}
if (length($opt_IPAddress) and length($opt_IPGateway)) {
my $i=inet_aton($opt_IPAddress);
my $g=inet_aton($opt_IPGateway);
if ( inet_ntoa($i) eq inet_ntoa($g) ){
printf STDERR ("Gateway -g %s cannot be same as IP -a %s\n",$opt_IPGateway,$opt_IPAddress);
$errors++;
$opt_IPAddress='';
$opt_IPGateway='';
}
}
if ($opt_TimeoutS<1 or $opt_TimeoutS>100) {
printf STDERR ("--timeout must be between 1 and 100 seconds\n");
$errors++;
$opt_TimeoutS=1;
}
if ($opt_LimitQuery<0) {
printf STDERR ("--limit-query must be >=0\n");
$errors++;
$opt_LimitQuery=0;
}
if (defined $opt_GUID) {
my $guid=$opt_GUID;
$guid =~ s/-//g;
if (not $ADDP_GUIDS{uc $guid} and not $guid =~ m/^[[:xdigit:]]{32}$/ ) {
print STDERR "--guid must be 32 hex digits or one of the builtins\n";
print STDERR join(" ",sort keys %ADDP_GUIDS),"\n";
$errors++;
undef $opt_GUID;
}
}
if (defined $opt_Vendor and ($opt_Vendor<0 or $opt_Vendor>65535)) {
print STDERR "--vendor ranges from 0-65535\n";
$errors++;
undef $opt_Vendor;
}
if (defined $opt_AddpIP) {
if (isNotValidIP($opt_AddpIP,0)) {
printf STDERR ("--addpip %s not valid IP\n",$opt_AddpIP);
$errors++;
$opt_AddpIP='';
} else {
my $i=inet_aton($opt_AddpIP);
if ( inet_ntoa($i) eq '255.255.255.255' ) {
printf STDERR ("--addpip %s cannot be broadcast. Digi ADDP devices don't respond to it.\nYou can try the broadcast for your subnet but you'll find that doesn't work either.\n",$opt_AddpIP);
$errors++;
}
}
}
return $errors;
}
# check for option conflicts and optional requirements.
# This functions as a rudimentary help for options
sub optconflicts {
my $errors=0;
{
my $xcmd=sprintf("%s%s%s",
,length($opt_DataRead)?"--data-read ":""
,length($opt_DecodeAddp)?"--decode-addp ":""
,length($opt_SignedBytes)?"--signed-bytes ":""
); # Don't show these unless asked for
my $cmds=($opt_QueryMAC?1:0) + ($opt_SaveSettings?1:0) + (length($opt_DataRead)?1:0) + (length($opt_DecodeAddp)?1:0) + (length($opt_SignedBytes)?1:0);
if ( ($opt_QueryAll?1:0) + $cmds + ($opt_RebootDevice?1:0) == 0) {
print STDERR "Must specify one or more of -Q -q -S -R\n";
$errors++;
} elsif ( ($opt_QueryAll?1:0) + $cmds > 1 ) {
printf STDERR ("Commands -Q -q -S %scannot be stacked. -R stacks with some commands.\n",$xcmd);
$errors++;
}
if ($cmds and $opt_SNMP) {
printf STDERR ("--snmp only works with -Q, can't be used with -q -S -R %s\n",$xcmd);
$errors++;
}
}
if ($opt_QueryAll or $opt_QueryMAC) {
if ($opt_QueryAll) {
if (length($opt_MACAddress)) {
print STDERR "-m MAC cannot be used with -Q, try -q\n";
$errors++;
}
# Turns out this is useful for learning the MAC of a remote device.
#if (defined $opt_AddpIP) {
# print STDERR "--addpip is not useful with -Q. Only local subnets can be scanned. Try -q\n";
# $errors++;
#}
} else {
if ($opt_LimitQuery) {
print STDERR "--limit-query can only be used with -Q\n";
$errors++;
}
if ($opt_BackingStore) {
print STDERR "--backing-store can only be used with -Q\n";
$errors++;
}
if ($opt_QueryShort) {
print STDERR "--query-short can only be used with -Q\n";
$errors++;
}
}
# Replaced below
# if ($opt_QueryMAC) {
# if (length($opt_MACAddress)==0) {
# print STDERR "-m MAC is required for -q. Try -Q to scan all.\n";
# $errors++;
# }
# }
if (length($opt_IPAddress)) {
print STDERR "-a IPAddress cannot be used with -Q -q\n";
$errors++;
}
if (length($opt_IPSubnet)) {
print STDERR "-s subnet cannot be used with -Q -q\n";
$errors++;
}
if (length($opt_IPGateway)) {
print STDERR "-g gateway cannot be used with -Q -q\n";
$errors++;
}
if (defined $opt_DHCP) {
print STDERR "-d DHCP cannot be used with -Q -q\n";
$errors++;
}
if (defined $opt_Password) {
print STDERR "-p password cannot be used with -Q -q\n";
$errors++;
}
if ($opt_SaveSettings) {
print STDERR "-S save settings cannot be used with -Q -q\n";
$errors++;
}
if ($opt_RebootDevice) {
print STDERR "-R reboot cannot be used with -Q -q\n";
$errors++;
}
}
if ($opt_QueryMAC or $opt_SaveSettings or $opt_RebootDevice) {
if (length($opt_MACAddress) == 0) {
if (not defined $opt_AddpIP or $DefaultAddpIP eq $opt_AddpIP or $opt_QueryMAC) {
print STDERR "-m MAC is required for options -R -S -q\n";
$errors++;
if (defined $opt_AddpIP and $DefaultAddpIP ne $opt_AddpIP) {
print STDERR "Try -Q to query from --addpip\n";
}
}
} else {
my $mac=lc $opt_MACAddress;
$mac =~ s/[:-]//g;
if ($mac eq 'ffffffffffff') {
# Rebooting every Digi in the fleet would be stupid, wouldn't it? Fortunately the devices don't allow this.
print STDERR "-m MAC cannot be broadcast for -R -S -q\n";
$errors++;
if ($opt_SaveSettings or $opt_RebootDevice) {
print STDERR "Digi devices do not respond to broadcast -R or -S.\n";
}
if ($opt_QueryMAC) {
print STDERR "try -Q to query all\n";
}
}
}
}
if ($opt_SaveSettings) {
if (not defined $opt_DHCP) {
my $optdhcperrors=0;
if (length($opt_IPAddress)==0) {
print STDERR "-a IPAddress is required for option -S\n";
$errors++;
$optdhcperrors++;
}
if (length($opt_IPSubnet)==0) {
print STDERR "-s subnet or -a with /netmask is required for option -S\n";
$errors++;
$optdhcperrors++;
}
if (length($opt_IPGateway)==0) {
print STDERR "-g gateway is required for option -S. Specify 0.0.0.0 for no gateway\n";
$errors++;
$optdhcperrors++;
}
if ($optdhcperrors) {
print STDERR "alternately, -d DHCP can be used with option -S\n";
}
}
} else {
if (length($opt_IPAddress)) {
print STDERR "-a IPAddress requires option -S\n";
$errors++;
}
if (length($opt_IPSubnet)) {
print STDERR "-s subnet requires option -S\n";
$errors++;
}
if (length($opt_IPGateway)) {
print STDERR "-g gateway requires option -S\n";
$errors++;
}
if (defined $opt_DHCP) {
print STDERR "-d DHCP requires option -S\n";
$errors++;
}
}
if (defined $opt_DHCP) {
if (not(length($opt_DHCP)==0 or lc $opt_DHCP eq 'on' or lc $opt_DHCP eq 'off')) {
print STDERR "option -d must be blank, on, or off\n";
$errors++;
}
if (length($opt_IPAddress)) {
print STDERR "-a IPAddress cannot be combined with option -d DHCP\n";
$errors++;
}
if (length($opt_IPSubnet)) {
print STDERR "-s subnet cannot be combined with option -d DHCP\n";
$errors++;
}
if (length($opt_IPGateway)) {
print STDERR "-g gateway cannot be combined with option -d DHCP\n";
$errors++;
}
}
if ($opt_Quiet) {
if ($opt_Debug) {
print STDERR "--quiet and --debug don't make sense together.\n";
$errors++;
}
if (length($opt_DataRead)) {
print STDERR "--quiet and --data-read don't make sense together.\n";
$errors++;
}
}
if (length($opt_DataRead)) {
if (length($opt_IPAddress)) {
print STDERR "-a IPAddress cannot be used with --data-read\n";
$errors++;
}
if (length($opt_IPSubnet)) {
print STDERR "-s subnet cannot be used with --data-read\n";
$errors++;
}
if (length($opt_IPGateway)) {
print STDERR "-g gateway cannot be used with --data-read\n";
$errors++;
}
if (defined $opt_DHCP) {
print STDERR "-d DHCP cannot be used with --data-read\n";
$errors++;
}
if (defined $opt_Password) {
print STDERR "-p password cannot be used with --data-read\n";
$errors++;
}
}
if ($opt_SNMP) {
if (length($opt_IPAddress)) {
print STDERR "-a IPAddress cannot be used with --data-read\n";
$errors++;
}
if (length($opt_IPSubnet)) {
print STDERR "-s subnet cannot be used with --data-read\n";
$errors++;
}
if (length($opt_IPGateway)) {
print STDERR "-g gateway cannot be used with --data-read\n";
$errors++;
}
if (defined $opt_DHCP) {
print STDERR "-d DHCP cannot be used with --data-read\n";
$errors++;
}
if (defined $opt_Password) {
print STDERR "-p password cannot be used with --data-read\n";
$errors++;
}
}
if (length($opt_DataDump) and length($opt_DataRead)) {
print STDERR "--data-dump and --data-read cannot be specified together\n";
$errors++;
}
if (defined $opt_Vendor != defined $opt_GUID) { # boolean xor
print STDERR "--vendor and --guid must be specified together\n";
$errors++;
}
return $errors;
}
{
my $err=opterrors(); # ensure we see messages from both
my $con=optconflicts();
die("Error in command line arguments\n") if ( $err or $con and not $opt_ConflictOverride);
print STDERR "Override, continuing. This program might crash or behave unexpectedly.\n" if ($con);
}
sub optclean_MAC {
if (length($opt_MACAddress)) {
$opt_MACAddress = lc $opt_MACAddress;
$opt_MACAddress =~ s/[:-]//g;
if (length($opt_MACAddress)==6 ) {
$opt_MACAddress="00409d".$opt_MACAddress; # Digi OID
}
}
}
# Here we clean and fix various arguments for easy use below.
sub optclean {
$opt_Password=$DefaultPassword if (not defined $opt_Password);
# We don't pack("H*") the MAC address because we need to string compare it down below
optclean_MAC();
$opt_IPAddress=inet_ntoa(inet_aton($opt_IPAddress)) if (length($opt_IPAddress));
$opt_IPSubnet =inet_ntoa(inet_aton($opt_IPSubnet)) if (length($opt_IPSubnet));
$opt_IPGateway=inet_ntoa(inet_aton($opt_IPGateway)) if (length($opt_IPGateway));
if ($opt_GUID) {
$opt_GUID=$ADDP_GUIDS{uc $opt_GUID} if ($ADDP_GUIDS{uc $opt_GUID});
$opt_GUID =~ s/-//g;
$opt_GUID=pack("H*",$opt_GUID);
}
$opt_AddpIP=$DefaultAddpIP if (not defined $opt_AddpIP);
}
optclean();
sub readBackingStore {
if (not open(my $fh, '<', $opt_BackingStore)) {
printf STDERR ("--backing-store file not found %s\n",$opt_BackingStore);
} else {
my @row;
my $ip;
while(my $row=<$fh>) {
if ($row =~ m/^[a-z]{1,2}\s+[0-9]/ ) {
@row=split(/\s+/,$row);
$ip=$row[1];
if (isNotValidIP($ip,0)==0) {
$BackingStore{$ip}=1;
}
}
}
close($fh);
}
}
readBackingStore() if ($opt_BackingStore);
# http://perldoc.perl.org/constant.html#CAVEATS
use constant {
ADDP_PACKET_DISCOVERY_REQUEST => 0x0001, # CONF
ADDP_PACKET_DISCOVERY_RESPONSE => 0x0002,
ADDP_PACKET_STATIC_NETCONFIG_REQUEST => 0x0003, # ADDR
ADDP_PACKET_STATIC_NETCONFIG_RESPONSE => 0x0004,
ADDP_PACKET_REBOOT_REQUEST => 0x0005, # REBOOT
ADDP_PACKET_REBOOT_RESPONSE => 0x0006,
ADDP_PACKET_DHCP_REQUEST => 0x0007, # WL
ADDP_PACKET_DHCP_RESPONSE => 0x0008,
# CMD_SET_WL_REQ = 9 # from Metasploit addp.rb
# CMD_SET_WL_REP = 10
# CMD_SET_WL_COUNTRIES_REQ = 11
# CMD_SET_WL_COUNTRIES_REP = 12
# ADDP_PACKET_EDP_REQUEST => 13, # From AddpClient.class, Digi Device Cloud EDP
# ADDP_PACKET_CMD_CONT => 14, # Appears to not be a reply of 13. From addplib-1.0.jar MessageType.class
};
my %ADDP_PACKET_NAME=(
ADDP_PACKET_DISCOVERY_REQUEST ,'Discovery Request',
ADDP_PACKET_DISCOVERY_RESPONSE ,'Discovery Response',
ADDP_PACKET_STATIC_NETCONFIG_REQUEST ,'Static Request',
ADDP_PACKET_STATIC_NETCONFIG_RESPONSE,'Static Response',
ADDP_PACKET_REBOOT_REQUEST ,'Reboot Request',
ADDP_PACKET_REBOOT_RESPONSE ,'Reboot Response',
ADDP_PACKET_DHCP_REQUEST ,'DHCP Request',
ADDP_PACKET_DHCP_RESPONSE ,'DHCP Response',
);
use constant {
ADDP_OPCODE_MAC =>0x01,
ADDP_OPCODE_IPADDR =>0x02,
ADDP_OPCODE_SUBMASK =>0x03,
ADDP_OPCODE_NETNAME =>0x04, # Supressed if blank. addp shows (null)
ADDP_OPCODE_DOMAIN =>0x05,
ADDP_OPCODE_HWTYPE =>0x06,
ADDP_OPCODE_HWREV =>0x07,
ADDP_OPCODE_FIRMWARE =>0x08, # ADDP_FEPREV
ADDP_OPCODE_RESULTMESSAGE=>0x09, # ADDP_MSG
ADDP_OPCODE_RESULTFLAG =>0x0A, # 10 # ADDP_RESULT
ADDP_OPCODE_GATEWAY =>0x0B, # 11
ADDP_OPCODE_CONFIGERR =>0x0C, # 12 # ADDP_ADVIOSRY [sic]
ADDP_OPCODE_HWNAME =>0x0D, # 13
ADDP_OPCODE_REALPORT =>0x0E, # 14
ADDP_OPCODE_DNS =>0x0F, # 15
ADDP_OPCODE_DHCP =>0x10, # 16
ADDP_OPCODE_ERRCODE =>0x11, # 17
ADDP_OPCODE_PORT_CNT =>0x12, # 18
ADDP_OPCODE_SECURE_RP =>0x13, # 19
ADDP_OPCODE_VERSION =>0x14, # 20
ADDP_OPCODE_VENDORGUID =>0x15, # 21
# ADDP_OPCODE_IF_TYPE =>22, # From DeviceData.class in AddpClient.jar, and PayloadOpCode.class in addplib-1.0.jar
# ADDP_OPCODE_AF_CHALLENGE =>23, # From DeviceData.class
# ADDP_OPCODE_AF_CAP_PORT =>24, # From DeviceData.class
ADDP_OPCODE_UNKNOWN19 =>0x19, # 25 not defined in DeviceData.class, unknown in Metasploit addp.rb, not defined in PayloadOpCode.class
# It's returned by PortServer TS. Does noone at Digi know what this is?
# ADDP_OPCODE_EDP_DEVID =>26, # From DeviceData.class
# ADDP_OPCODE_EDP_ENABLED =>27, # From DeviceData.class
# ADDP_OPCODE_EDP_URL =>28, # From DeviceData.class
# ADDP_OPCODE_WL_SSID =>224, # From DeviceData.class
# ADDP_OPCODE_WL_AUTO_SSID =>225, # From DeviceData.class
# ADDP_OPCODE_WL_TX_ENH_POWR,226, # From DeviceData.class
# ADDP_OPCODE_WL_AUTH_MODE =>227, # From DeviceData.class
# ADDP_OPCODE_WL_ENC_MODE =>228, # From DeviceData.class
# ADDP_OPCODE_WL_ENC_KEY =>229, # From DeviceData.class
# ADDP_OPCODE_WL_CUR_COUNTRY=>230, # From DeviceData.class
# ADDP_OPCODE_WL_COUNTRY_LIST=>231, # From DeviceData.class
};
# We only leave in the constants used for sending. Received item sizes are specified in the returned packet.
# Noone notices all the invalid lengths because they are never used.
use constant { #-1 = unlimited length
ADDP_OPCODE_MAC_LEN => 6,
ADDP_OPCODE_IPADDR_LEN => 4,
ADDP_OPCODE_SUBMASK_LEN => 4,
#ADDP_OPCODE_NETNAME_LEN => -1,
#ADDP_OPCODE_DOMAIN_LEN => -1,
#ADDP_OPCODE_HWTYPE_LEN => 1,
#ADDP_OPCODE_HWREV_LEN => 1,
#ADDP_OPCODE_FIRMWARE_LEN => -1,
#ADDP_OPCODE_RESULTMSG_LEN => -1,
#ADDP_OPCODE_RESULTFLAG_LEN => 1,
ADDP_OPCODE_GATEWAY_LEN => 4,
#ADDP_OPCODE_CONFIGERR_LEN => 2, # Should be 1
#ADDP_OPCODE_HWNAME_LEN => -1,
#ADDP_OPCODE_REALPORT_LEN => 4, # 2 in PayloadOpCode.class
#ADDP_OPCODE_DNS_LEN => 4,
#ADDP_OPCODE_DHCP_LEN => 4, # 1 in PayloadOpCode.class
#ADDP_OPCODE_ERRCODE_LEN => 1,
#ADDP_OPCODE_PORT_CNT_LEN => 1,
#ADDP_OPCODE_SECURE_RP_LEN => 4, # 1 in PayloadOpCode.class which can't store the default port 1027. Must be at least 2.
#ADDP_OPCODE_VERSION_LEN => 2,
#ADDP_OPCODE_VENDOR_GUID_LEN => 16,
#ADDP_OPCODE_IF_TYPE_LEN => 1,
#ADDP_OPCODE_CHALLENGE_LEN => 14,
#ADDP_OPCODE_CAP_PORT_LEN => 2,
#ADDP_OPCODE_EDP_DEVID_LEN => 16,
#ADDP_OPCODE_EDP_ENABLED_LEN => 1,
#ADDP_OPCODE_EDP_URL_LEN => -1,
#ADDP_OPCODE_WL_SSID_LEN => -1,
#ADDP_OPCODE_WL_AUTO_SSID_LEN => 2,
#ADDP_OPCODE_WL_TX_ENH_POWR_LEN => 2,
#ADDP_OPCODE_WL_AUTH_MODE_LEN => 2,
#ADDP_OPCODE_WL_ENC_MODE_LEN => 2,
#ADDP_OPCODE_WL_ENC_KEY_LEN => -1,
#ADDP_OPCODE_WL_CUR_COUNTRY_LEN => 2,
#ADDP_OPCODE_WL_COUNTRY_LIST_LEN => -1,
};
# These are named to closely match Digi's addp output and some vars
my %ADDP_OPCODE_FIELD=(
ADDP_OPCODE_MAC ,'MAC',
ADDP_OPCODE_IPADDR ,'IP',
ADDP_OPCODE_SUBMASK ,'Submask',
ADDP_OPCODE_NETNAME ,'Name',
ADDP_OPCODE_DOMAIN ,'Domain',
ADDP_OPCODE_HWTYPE ,'HWType',
ADDP_OPCODE_HWREV ,'Revision',
ADDP_OPCODE_FIRMWARE ,'Firmware',
ADDP_OPCODE_RESULTMESSAGE,'Message',
ADDP_OPCODE_RESULTFLAG ,'Result',
ADDP_OPCODE_GATEWAY ,'Gateway',
ADDP_OPCODE_CONFIGERR ,'ConfigEr',
ADDP_OPCODE_HWNAME ,'Hardware',
ADDP_OPCODE_REALPORT ,'RealPort',
ADDP_OPCODE_DNS ,'DNS',
ADDP_OPCODE_DHCP ,'DHCP',
ADDP_OPCODE_ERRCODE ,'Error',
ADDP_OPCODE_PORT_CNT ,'Ports',
ADDP_OPCODE_SECURE_RP ,'SecureRP',
ADDP_OPCODE_VERSION ,'Version',
ADDP_OPCODE_VENDORGUID ,'VendGUID',
ADDP_OPCODE_UNKNOWN19 ,'Unknown',
);
#print Dumper(\%ADDP_OPCODE_FIELD); die();
# ?=unknown, -Custom, M=MAC address, S=string, I=IP, u=unsigned number
my %ADDP_OPCODE_TYPE=(
ADDP_OPCODE_MAC ,'M',
ADDP_OPCODE_IPADDR ,'I',
ADDP_OPCODE_SUBMASK ,'I',
ADDP_OPCODE_NETNAME ,'S',
ADDP_OPCODE_DOMAIN ,'S',
ADDP_OPCODE_HWTYPE ,'u',
ADDP_OPCODE_HWREV ,'u',
ADDP_OPCODE_FIRMWARE ,'S',
ADDP_OPCODE_RESULTMESSAGE,'S',
ADDP_OPCODE_RESULTFLAG ,'-',
ADDP_OPCODE_GATEWAY ,'I',
ADDP_OPCODE_CONFIGERR ,'-',
ADDP_OPCODE_HWNAME ,'S',
ADDP_OPCODE_REALPORT ,'u',
ADDP_OPCODE_DNS ,'I',
ADDP_OPCODE_DHCP ,'-',
ADDP_OPCODE_ERRCODE ,'-',
ADDP_OPCODE_PORT_CNT ,'u',
ADDP_OPCODE_SECURE_RP ,'u',
ADDP_OPCODE_VERSION ,'u',
ADDP_OPCODE_VENDORGUID ,'-',
ADDP_OPCODE_UNKNOWN19 ,'u', # 'u' shows as a number. '?' shows as hex. Either work.
);
#print Dumper(\%ADDP_OPCODE_TYPE); die();
my @ADDP_ERROR_CODE=(
'Success',
'Authentication Failure',
'Unit has address', # from AddpDevice$AddpError.class
'Invalid Value',
'Invalid Data', # from AddpDevice$AddpError.class
'Unsupported command', # from AddpDevice$AddpError.class
'Unable to save value',
);
# from addp.h
my @ADDP_WIRELESS_AUTO=(
'Disabled',
'Enabled',
);
# These wifi strings might change if we need to match the command line usage of any Digi programs
# from AddpDevice$AddpError.class
my @ADDP_WLAN_ENCMODE=(
'Unknown',
'None',
'WEP40',
'WEP128', # Where is WPA and WPA2?
);
#print Dumper(\@ADDP_WLAN_ENCMODE); die();
# from AddpDevice$AddpError.class
my @ADDP_WLAN_AUTHMODE=(
'Unknown',
'Open System',
'Shared Key',
'Open Shared Key',
);
#print Dumper(\@ADDP_WLAN_AUTHMODE); die();
my %ADDP_RESULT_FLAGS=(
0x00 => 'Success',
0xFF => 'Failure',
);
#print Dumper(\%ADDP_RESULT_FLAGS);
my @ADDP_CONFIG_ERRORS=(
'No',
'Digi in different subnet than sender',
);
my @ADDP_BOOLEAN_FLAGS=(
'Off',
'On',
);
# From Metasploit addp.rp.
# Interesting that PortServer II Rack 16 would be defined since it doesn't respond to ADDP
# The PortServer II is why I wrote all the SNMP code.
my @ADDP_HWTYPES=qw/
unknown ps3_desk8 ps3_desk16 ps3_desk32 ps3_rack16 ps2_desk16 ps2_rack16
lets_desk1 lets_desk2 lets_desk4 dorpia_dinrail1 nubox01 nubox02 nubox04
digione_sp digione_ia digione_em
/;
#print Dumper(\@ADDP_HWTYPES); die();
# $arg_bytes: constant width of hex and ascii, often 8
# $arg_data: binary string to dump. "\n" is printed on all but the last line so you can print more.
# $arg_supress: 0 to show printable ascii, 1 to show all as "..." for known binary values where showing ascii would be inappropriate
# Returns nothing.
sub print_hex_dump {
my ($arg_bytes,$arg_data,$arg_supress)=(@_);
my $pdh_write;
while(length($arg_data)) {
if(length($arg_data) > $arg_bytes) {
$pdh_write=substr($arg_data,0,$arg_bytes);
$arg_data=substr($arg_data,$arg_bytes);
} else {
$pdh_write=$arg_data;
$arg_data="";
}
printf("%*s ",$arg_bytes*3-1,join(" ",unpack("(H2)*",$pdh_write)));
if ($arg_supress) {
$pdh_write='.' x length($pdh_write);
} else {
$pdh_write =~ s/[\x00-\x1F\x7F-\xFF]/./g;
}
printf("%-*s ",$arg_bytes,$pdh_write);
print "\n" if (length($arg_data));
}
}
# returns hex spaced out. DE AD BE EF
# $arg_killspace: The extra space at the end is: 0=put on, 1=left off
sub space_hex {
my ($arg_bin,$arg_killspace)=(@_);
my $rv=join(" ",unpack("(H2)*",$arg_bin)); # Should be faster than regex.
$rv.=" " if (not $arg_killspace);
return($rv);
}
# $arg_print: 0=don't print just return hash, 1=print like addp, 2=print hex like blog with Perl hash
# $arg_frto: "to" for send, "from" for receive, "command" for command line --addp-decode
# $arg_ip: IP address to or from. May or may not include port number as desired.
# $arg_packet: UDP packet to decode
# Returns %hash of decoded items for response codes.
# Digi addp prints in a prefab order with some forced values. We print in the order found in the packet.
sub addp_decode {
my ($arg_print,$arg_frto,$arg_ip,$arg_packet)=(@_);
my %rv;
my $bytes=8;
my ($magic,$packettype,$payloadsize,$payload)=unpack("a".ADDP_OPCODE_MAGIC_LEN."nna*",$arg_packet);
if (not $ADDP_MAGICS{$magic}) {
print "Not a Digi ADDP packet\n" if ($arg_print);
} elsif (length($payload) != $payloadsize) {
print "Damaged Digi ADDP packet\n" if ($arg_print);
} elsif (not $ADDP_PACKET_NAME{$packettype}) {
print "Unknown packet type $packettype\n" if ($arg_print);
} else {
%rv=(
$arg_frto => $arg_ip,
Magic => $magic,
PacketType => $packettype,
);
#if ($packettype eq +ADDP_PACKET_DISCOVERY_RESPONSE) {
# $rv{$ADDP_OPCODE_FIELD{+ADDP_OPCODE_NETNAME}}=''; # supressed if blank
# $rv{$ADDP_OPCODE_FIELD{+ADDP_OPCODE_SECURE_RP}}=0; # not returned for unsupported models
#}
if ($arg_print > 1) {
printf("%*s%s %s\n",$bytes*4+1,"",$arg_frto,$arg_ip);
print_hex_dump($bytes,$magic ,0); printf("Magic %s %s\n",$magic,$ADDP_MAGICS{$magic});
print_hex_dump($bytes,substr($arg_packet,4,2),1); printf("Packet Type (0x%4.4X) %s\n",$packettype,$ADDP_PACKET_NAME{$packettype});
print_hex_dump($bytes,substr($arg_packet,6,2),1); printf("Payload Size (%u bytes)\n",$payloadsize);
} elsif ($arg_print == 1 and $opt_QueryShort==0) {
printf("%-8s: %s\n",$arg_frto,$arg_ip);
printf("%-8s: %s %s\n","Magic",$magic,$ADDP_MAGICS{$magic});
printf("%-8s: %s\n","Type",$ADDP_PACKET_NAME{$packettype});