Passed
Push — 2.x ( 335e99...b197ca )
by Terry
01:56
created

Iptables   A

Complexity

Total Complexity 35

Size/Duplication

Total Lines 259
Duplicated Lines 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
eloc 99
dl 0
loc 259
rs 9.6
c 1
b 0
f 0
wmc 35

8 Methods

Rating   Name   Duplication   Size   Complexity  
A __construct() 0 3 1
A ip4status() 0 3 1
A ip4() 0 3 1
A ip6() 0 3 1
A ip6status() 0 3 1
F iptablesFormPost() 0 102 21
B iptables() 0 46 6
A iptablesStatus() 0 30 3
1
<?php
2
/*
3
 * This file is part of the Shieldon package.
4
 *
5
 * (c) Terry L. <[email protected]>
6
 *
7
 * For the full copyright and license information, please view the LICENSE
8
 * file that was distributed with this source code.
9
 */
10
11
declare(strict_types=1);
12
13
namespace Shieldon\Firewall\Panel;
14
15
use Psr\Http\Message\ResponseInterface;
16
use Shieldon\Firewall\Panel\BaseController;
17
use function Shieldon\Firewall\__;
18
use function Shieldon\Firewall\get_request;
19
20
use SplFileObject;
21
use ReflectionObject;
22
23
use function filter_var;
24
use function is_numeric;
25
use function in_array;
26
use function file;
27
use function file_put_contents;
28
use function sleep;
29
use function file_exists;
30
use function explode;
31
use function trim;
32
33
/**
34
 * The bridge between the Shieldon firewall and the Iptables firewall.
35
 */
36
class Iptables extends BaseController
37
{
38
    /**
39
     * Constructor
40
     */
41
    public function __construct() 
42
    {
43
        parent::__construct();
44
    }
45
46
    /**
47
     * The IPv4 table.
48
     *
49
     * @return ResponseInterface
50
     */
51
    public function ip4(): ResponseInterface
52
    {
53
        return $this->iptables('IPv4');
54
    }
55
56
    /**
57
     * The IPv6 table.
58
     *
59
     * @return ResponseInterface
60
     */
61
    public function ip6(): ResponseInterface
62
    {
63
        return $this->iptables('IPv6');
64
    }
65
66
    /**
67
     * The IPv4 table.
68
     *
69
     * @return \Psr\Http\Message\ResponseInterface
70
     */
71
    public function ip4status(): ResponseInterface
72
    {
73
        return $this->iptablesStatus('IPv4');
74
    }
75
76
    /**
77
     * The IPv6 table.
78
     *
79
     * @return \Psr\Http\Message\ResponseInterface
80
     */
81
    public function ip6status(): ResponseInterface
82
    {
83
        return $this->iptablesStatus('IPv6');
84
    }
85
86
    /**
87
     * Detect and handle form post action.
88
     *
89
     * @param string $type              IPv4 or IPv6
90
     * @param string $commandLogFile    The log file contains executed commands.
91
     * @param string $iptablesQueueFile The file contains the commands that wil 
92
     *                                  be executed by Iptables
93
     *
94
     * @return void
95
     */
96
    private function iptablesFormPost(string $type, string $commandLogFile, string $iptablesQueueFile)
97
    {
98
        $postParams = get_request()->getParsedBody();
99
100
        $con1 = (
101
            isset($postParams['ip']) &&
102
            filter_var(explode('/', $postParams['ip'])[0], FILTER_VALIDATE_IP)
103
        );
104
105
        $con2 = (
106
            isset($postParams['port']) &&
107
            (
108
                is_numeric($postParams['port']) ||
109
                $postParams['port'] === 'all' ||
110
                $postParams['port'] === 'custom'
111
            )
112
        );
113
114
        $con3 = (
115
            isset($postParams['subnet']) && 
116
            (
117
                is_numeric($postParams['subnet']) || 
118
                $postParams['subnet'] === 'null'
119
            )
120
        );
121
122
        $con4 = (
123
            isset($postParams['protocol']) && 
124
            in_array($postParams['protocol'], ['tcp', 'udp', 'all'])
125
        );
126
127
        $con5 = (
128
            isset($postParams['action']) && 
129
            in_array($postParams['action'], ['allow', 'deny'])
130
        );
131
132
        if ($con1 && $con2 && $con3 && $con4 && $con5) {
133
            $ip       = $postParams['ip'];
134
            $port     = $postParams['port'];
135
            $subnet   = $postParams['subnet'];
136
            $protocol = $postParams['protocol'];
137
            $action   = $postParams['action'];
138
            $cPort    = $postParams['port_custom'] ?? 'all';
139
140
            $isRemoval = false;
141
142
            if (isset($postParams['remove']) && $postParams['remove'] === 'yes') {
143
                $isRemoval = true;
144
            }
145
146
            if ('custom' === $port) {
147
                $port = $cPort;
148
            }
149
150
            $ipv = '4';
151
152
            if ('IPv6' === $type) {
153
                $ipv = '6';
154
            }
155
156
            /**
157
             * The process of add or remove command string from two files:
158
             * 
159
             * (1) The command file -
160
             *     This file is used on display the commands on the page 
161
             *     Iptables Manager.
162
             * (2) The queue file -
163
             *     This file is a bridge between Shieldon Firewall and Iptalbes.
164
             *     ipbales_bridge.sh will monitor this file, once commands come, 
165
             *     transforming the commands into Iptables syntax commands and 
166
             *     then execute the Iptables commands.
167
             */
168
            if (!$isRemoval) {
169
                $originCommandString = "add,$ipv,$ip,$subnet,$port,$protocol,$action";
170
171
                // Delete line from the log file.
172
                $fileArr = file($commandLogFile);
173
174
                if (is_array($fileArr)) {
175
                    $keyFound = array_search(trim($originCommandString), $fileArr);
176
                    unset($fileArr[$keyFound]);
177
178
                    $t = [];
179
                    $i = 0;
180
                    foreach ($fileArr as $f) {
181
                        $t[$i] = trim($f);
182
                        $i++;
183
                    }
184
                    file_put_contents($commandLogFile, implode(PHP_EOL, $t));
185
                }
186
187
                $applyCommand = "delete,$ipv,$ip,$subnet,$port,$protocol,$action";
188
189
                file_put_contents($iptablesQueueFile, $applyCommand . "\n", FILE_APPEND | LOCK_EX);
190
191
                // Becase we need system cronjob done, and then the web page will show the actual results.
192
                sleep(10);
193
            } else {
194
                $applyCommand = "add,$ipv,$ip,$subnet,$port,$protocol,$action";
195
196
                file_put_contents($iptablesQueueFile, $applyCommand . "\n", FILE_APPEND | LOCK_EX);
197
                sleep(1);
198
            }
199
        }
200
    }
201
202
    /**
203
     * System layer firwall - iptables
204
     * 
205
     * @param string $type The type of IP address.
206
     *
207
     * @return void
208
     */
209
    protected function iptables(string $type = 'IPv4'): ResponseInterface
210
    {
211
        $reflection = new ReflectionObject($this->kernel);
212
        $t = $reflection->getProperty('properties');
213
        $t->setAccessible(true);
214
        $properties = $t->getValue($this->kernel);
215
216
        $dir = $properties['iptables_watching_folder'];
217
218
        // The iptables log files.
219
        $commandLogFile = $dir . '/ipv4_command.log';
220
221
        if ('IPv6' === $type) {
222
            $commandLogFile = $dir . '/ipv6_command.log';
223
        }
224
225
        $iptablesQueueFile = $dir . '/iptables_queue.log';
226
227
        if ('POST' === get_request()->getMethod()) {
228
            $this->iptablesFormPost($type, $commandLogFile, $iptablesQueueFile);
229
        }
230
231
        $data[] = [];
0 ignored issues
show
Comprehensibility Best Practice introduced by
$data was never initialized. Although not strictly required by PHP, it is generally a good practice to add $data = array(); before regardless.
Loading history...
232
        $ipCommand = '';
233
234
        if (file_exists($commandLogFile)) {
235
            $file = new SplFileObject($commandLogFile);
236
237
            $ipCommand = [];
238
239
            while (!$file->eof()) {
240
                $line = trim($file->fgets());
241
                $ipInfo = explode(',', $line);
242
243
                if (!empty($ipInfo[4])) {
244
                    $ipCommand[] = $ipInfo;
245
                }
246
            }
247
        }
248
249
        $data['ipCommand'] = $ipCommand;
250
        $data['type'] = $type;
251
252
        $data['title'] = __('panel', 'title_iptables_manager', 'Iptables Manager') . ' (' . $type . ')';
253
254
        return $this->renderPage('panel/iptables_manager', $data);
0 ignored issues
show
Bug Best Practice introduced by
The expression return $this->renderPage...tables_manager', $data) returns the type Psr\Http\Message\ResponseInterface which is incompatible with the documented return type void.
Loading history...
255
    }
256
257
    /**
258
     * System layer firwall - iptables Status
259
     * iptables -L
260
     * 
261
     * @param string $type The type of IP address.
262
     *
263
     * @return \Psr\Http\Message\ResponseInterface
264
     */
265
    protected function iptablesStatus(string $type = 'IPv4'): ResponseInterface
266
    {
267
        $data[] = [];
0 ignored issues
show
Comprehensibility Best Practice introduced by
$data was never initialized. Although not strictly required by PHP, it is generally a good practice to add $data = array(); before regardless.
Loading history...
268
269
        $reflection = new ReflectionObject($this->kernel);
270
        $t = $reflection->getProperty('properties');
271
        $t->setAccessible(true);
272
        $properties = $t->getValue($this->kernel);
273
274
        $dir = $properties['iptables_watching_folder'];
275
276
        // The iptables log files.
277
        $ipStatusFile = $dir . '/ipv4_status.log';
278
279
        if ('IPv6' === $type) {
280
            $ipStatusFile = $dir . '/ipv6_status.log';
281
        }
282
        
283
        $ipStatus = '';
284
285
        if (file_exists($ipStatusFile)) {
286
            $ipStatus = file_get_contents($ipStatusFile);
287
        }
288
289
        $data['ipStatus'] = $ipStatus;
290
        $data['type'] = $type;
291
292
        $data['title'] = __('panel', 'title_iptables_status', 'Iptables Status') . ' (' . $type . ')';
293
294
        return $this->renderPage('panel/iptables_status', $data);
295
    }
296
}
297
298