5 use Getopt
::Long qw
/:config no_ignore_case bundling no_getopt_compat require_order/;
10 no if ($] >= 5.018), 'warnings' => 'experimental::smartmatch';
13 $host = "gateway.localdomain";
21 ZXHN-H108L [-h I<HOST>] [-u I<USER>] [-P I<PASS>] I<COMMAND>
29 =item info [ip|gw|dns1|dns2|downlink|uplink]
35 =item pfwd I<app_name> I<start_port>[-I<end_port>] I<dest_ip> [TCP|UDP|ALL]
37 =item pfwd --remove [--id I<num> | --name I<app_name> | --match-name I<pattern> | --port I<start_port>]
47 ) or pod2usage
(-exitval
=>2, -verbose
=>99);
51 pod2usage
(-exitval
=>2, -verbose
=>99);
60 my @curl_args = map {('-d', $_.'='.$param->{$_})} keys %$param;
62 run
['curl', '-sS', '-u', "$user:$pass", "http://$host$path", '--connect-timeout', '4', '--max-time', '5', @curl_args, @_], \
undef, \
$resp;
68 my $html = dispatch
"/advanced/adv_nat_virsvr.htm";
70 run
['pup', 'table table td.tabdata:not([width]) json{}'], \
$html, \
$resp;
74 @pfwd_fields = qw
/id label proto start_port end_port dest/;
78 my $pfwd_table_json = fetch_pfwd
();
79 my $html_elements = decode_json
$pfwd_table_json;
80 my @pfwd_lines = map { $_->{'text'} } @
$html_elements;
82 for my $line_num (0 .. $#pfwd_lines)
84 my $line = $pfwd_lines[$line_num];
87 my $pfwd_row_num = int($line_num / 6);
88 my $pfwd_col_num = $line_num % 6;
89 $pfwd[$pfwd_row_num][$pfwd_col_num] = $line;
96 my @pfwd = pfwd_table
();
97 my @pfwd = map { my $tr = $_; my $hr = {}; $hr->{$pfwd_fields[$_]} = $tr->[$_] for 0 .. $#pfwd_fields; $hr } @pfwd;
105 $resp = dispatch
"/Forms/tools_system_1", {restoreFlag
=>0}, "-L";
106 $resp =~ /The system is restarting. Please wait./;
111 $resp = dispatch
"/status/syslog.log";
116 my ($remove, $remove_id, $remove_name, $remove_name_pattern, $remove_start_port);
119 'remove' => \
$remove,
120 'id=i' => \
$remove_id,
121 'name=s' => \
$remove_name,
122 'match-name=s' => \
$remove_name_pattern,
123 'port=i' => \
$remove_start_port,
125 or pod2usage
(-exitval
=>2, -verbose
=>99);
129 if(not defined $remove_id)
131 my @pfwd = pfwd_hashlist
();
132 if(defined $remove_name) { ($remove_id) = map {$_->{'id'}} grep {$_->{'label'} eq $remove_name} @pfwd }
133 elsif(defined $remove_name_pattern) { ($remove_id) = map {$_->{'id'}} grep {$_->{'label'} =~ $remove_name_pattern} @pfwd }
134 elsif(defined $remove_start_port) { ($remove_id) = map {$_->{'id'}} grep {$_->{'start_port'} eq $remove_start_port} @pfwd }
137 if(defined $remove_id)
139 warn "Removing pfwd #$remove_id ...\n";
140 dispatch
"/Forms/adv_nat_virsvr_1", {VIRTUALSVR_index
=>$remove_id, VIRTUALSVR_IndexFlag
=>2};
149 my ($label, $portrange, $dest_ip, $proto) = @ARGV;
150 my ($start_port, $end_port);
151 if($portrange =~ /^(\d+)-(\d+)$/)
158 pod2usage
(-exitval
=>2, -verbose
=>99) unless $portrange =~ /^\d+$/;
159 $start_port = $end_port = $portrange;
161 $proto = 'ALL' unless $proto;
163 pod2usage
(-exitval
=>2, -verbose
=>99) unless $proto ~~ ['TCP', 'UDP', 'ALL'];
165 my @pfwd = pfwd_hashlist
();
167 my ($next_id) = map {$_->{'id'}} grep {$_->{'start_port'} eq 0} @pfwd;
168 die "no more slot\n" unless $next_id;
170 warn "Adding pfwd #$next_id ...\n";
171 my $httpresp = dispatch
"/Forms/adv_nat_virsvr_1", {
172 VIRTUALSVR_index
=>$next_id,
173 VIRTUALSVR_IndexFlag
=>0,
174 VIRTUALSVR_Application
=>$label,
175 VIRTUALSVR_App_idx
=>'-',
176 VSProtocolIndex
=>$proto,
177 VIRTUALSVR_startPort
=>$start_port,
178 VIRTUALSVR_endPort
=>$end_port,
179 VIRTUALSVR_localIP
=>$dest_ip,
182 if($httpresp =~ /^Location:.*error/m)
190 my @pfwd = pfwd_table
();
191 print join("\t", @pfwd_fields)."\n";
194 print join("\t", @
$row)."\n";
200 my $requested_info = shift @ARGV;
202 my $html = dispatch
"/status/status_deviceinfo.htm";
204 if($html =~ /WAN.*?IP Address.*?\n\s*(?'ip'[^<\s]+).*Default Gateway.*?\n\s*(?'gw'[^<\s]+).*Primary DNS.*?\n\s*(?'dns1'[^<\s]+).*Secondary DNS.*?\n\s*(?'dns2'[^<\s]+).*Data Rate.*?\n\s*(?'downlink'[^<]+).*?\n\s*(?'uplink'[^<]+)/s)
206 $info{$_} = $+{$_} for keys %+;
209 $info{'downlink'} = int $info{'downlink'};
210 $info{'uplink'} = int $info{'uplink'};
212 if(defined $requested_info)
214 print $info{$requested_info}."\n";
218 my %unit = (qw{downlink kbit
/s uplink kbit/s});
219 for my $k (qw
/ip gw dns1 dns2 downlink uplink/)
221 print "$k\t$info{$k}\t$unit{$k}\n";
227 pod2usage
(-exitval
=>2, -verbose
=>99);