├── bin
├── index.php
├── php_root
├── start_suricata
├── suricata-update.cron
├── start_ips
├── suricataips.sh
├── suricata2mikrotik.sh
├── daemon_ips_clean.php
├── daemon_ips_hunter.php
└── daemon_ips_process.php
├── share
├── index.php
├── ssh
│ ├── openssl.cnf
│ ├── Net
│ │ ├── SCP.php
│ │ └── SFTP
│ │ │ └── Stream.php
│ ├── Crypt
│ │ ├── Random.php
│ │ ├── RC4.php
│ │ ├── AES.php
│ │ └── Hash.php
│ └── File
│ │ └── ANSI.php
├── sshkey.pub
├── routeros_api.php
└── functions.php
├── www
├── favicon.ico
├── sql.php
└── a.css
├── index.php
├── README.md
├── config.php
├── schema.sql
└── LICENSE
/bin/index.php:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/share/index.php:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/www/favicon.ico:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/www/sql.php:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/elmaxid/Suricata2MikroTik/HEAD/www/sql.php
--------------------------------------------------------------------------------
/bin/php_root:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/elmaxid/Suricata2MikroTik/HEAD/bin/php_root
--------------------------------------------------------------------------------
/share/ssh/openssl.cnf:
--------------------------------------------------------------------------------
1 | # minimalist openssl.cnf file for use with phpseclib
2 |
3 | HOME = .
4 | RANDFILE = $ENV::HOME/.rnd
5 |
6 | [ v3_ca ]
--------------------------------------------------------------------------------
/bin/start_suricata:
--------------------------------------------------------------------------------
1 | /usr/local/bin/trafr -s | /usr/bin/suricata -c /etc/suricata/suricata.yaml --pidfile /var/run/suricata.pid -r /dev/stdin &
2 |
3 |
4 |
--------------------------------------------------------------------------------
/bin/suricata-update.cron:
--------------------------------------------------------------------------------
1 | #suricata-update --reload-command "service suricataips restart" -v -f
2 | suricata-update --reload-command "service suricataips restart" -v
3 |
4 |
--------------------------------------------------------------------------------
/bin/start_ips:
--------------------------------------------------------------------------------
1 | cd /var/www/html/suricata2mikrotik/
2 | php bin/daemon_ips_hunter.php &
3 | sleep 1;
4 | php bin/daemon_ips_process.php &
5 | sleep 1;
6 | php bin/daemon_ips_clean.php &
7 |
--------------------------------------------------------------------------------
/index.php:
--------------------------------------------------------------------------------
1 |
21 |
--------------------------------------------------------------------------------
/share/sshkey.pub:
--------------------------------------------------------------------------------
1 | ssh-dss AAAAB3NzaC1kc3MAAACBAMoArDGl13YOaykala8/zQoZzzTjpMK/+nQebfx/A9QGmNM1ug0Fnz3vl89Dt7CgQsqLJSk4OevRuHA+8IcOJqx2PeJF2eUyzNJlMIPFM1+NgPayhWxCLWfISuzPmpTHc6TSnrQnnUn48ef3c4gq8OzkdY4kq7ng8w+5Y3gFmvZTAAAAFQCyIRcsx/HtqvkWy9WeITopxyuPlwAAAIB36O6ltmqIDKYkoJdn/o0fwf5wId+uMRQxaRclfg6dSCM4AZHAT1tEtzQ1LjYWCCParU2nVCjZny0lfye9WbxeCIC7+8NL+3DyStXq/ES4NHmwmNnD6IUZ/xleUbIvEo4PwNRmQgAb2nCuQBvN77q/2aR5xmRhDB1LmOa9P79vOQAAAIAvkikNBNeHkimRk6XP3tydizh3wS2ikttowo+NXeVdhLbCZigIxZnhjkrXXoDehXiLs8leQqhFjR3K9ppmzvgoto9YHn3PE05HspH1/YYobEO+wKdnlx2G5gx1NAm8scpIoj56nTeKyNT++zPe/CrdhQNd15vi40g5FqMw7XNJAw== root@OraculoV2
2 |
--------------------------------------------------------------------------------
/bin/suricataips.sh:
--------------------------------------------------------------------------------
1 | #! /bin/bash
2 |
3 | ### BEGIN INIT INFO
4 | # Provides: suricataips
5 | # Required-Start: $all
6 | # Required-Stop: $local_fs
7 | # Default-Start: 2 3 4 5
8 | # Default-Stop: 0 1 6
9 | # Short-Description: Suricata service
10 | # Description: Run Suricata service sudo -u Suricata-user
11 | ### END INIT INFO
12 |
13 | # Carry out specific functions when asked to by the system
14 | case "$1" in
15 | start)
16 | echo "Starting Suricata..."
17 | # bash -c 'cd /var/www/html/suricata2ips/bin/ && ./start-Suricata.sh'
18 | bash -c 'cd /usr/local/bin/ && start_suricata'
19 | ;;
20 | stop)
21 | echo "Stopping Suricata..."
22 | # bash -c 'cd /var/www/html/suricata2ips/bin/ && ./stop-Suricata.sh'
23 | bash -c 'pkill trafr'
24 | sleep 2
25 | ;;
26 | restart)
27 | $0 stop
28 | sleep 5
29 | $0 start
30 | ;;
31 |
32 | *)
33 | echo "Usage: /etc/init.d/suricataips {start|stop|restart}"
34 | exit 1
35 | ;;
36 | esac
37 |
38 | exit 0
--------------------------------------------------------------------------------
/bin/suricata2mikrotik.sh:
--------------------------------------------------------------------------------
1 | #! /bin/bash
2 |
3 | ### BEGIN INIT INFO
4 | # Provides: suricata2mikrotik
5 | # Required-Start: $remote_fs $syslog
6 | # Required-Stop: $local_fs
7 | # Default-Start: 2 3 4 5
8 | # Default-Stop: 0 1 6
9 | # Short-Description: Suricata service
10 | # Description: Run Suricata service sudo -u Suricata-user
11 | ### END INIT INFO
12 |
13 | # Carry out specific functions when asked to by the system
14 | case "$1" in
15 | start)
16 | echo "Starting Suricata2MikroTik..."
17 | # bash -c 'cd /var/www/html/suricata2ips/bin/ && ./start-Suricata.sh'
18 | bash -c 'cd /usr/local/bin/ && start_ips'
19 | ;;
20 | stop)
21 | echo "Stopping Suricata2MikroTik..."
22 | # bash -c 'cd /var/www/html/suricata2ips/bin/ && ./stop-Suricata.sh'
23 | bash -c 'rm /tmp/suricata2mikrotik.pid '
24 | sleep 2
25 | ;;
26 | restart)
27 | $0 stop
28 | sleep 11
29 | $0 start
30 | ;;
31 |
32 | *)
33 | echo "Usage: /etc/init.d/suricata2mikrotik {start|stop|restart}"
34 | exit 1
35 | ;;
36 | esac
37 |
38 | exit 0
--------------------------------------------------------------------------------
/bin/daemon_ips_clean.php:
--------------------------------------------------------------------------------
1 | query( $SQL ) ) {
39 | die( 'There was an error running the query [' . $connect->error . ']' );
40 | } //!$result = $connect->query( $SQL )
41 | mysqli_free_result( $result );
42 | sleep( 10 );
43 | /* Sleep 10 seconds then do again */
44 | mysqli_ping( $connect );
45 | } //file_exists( $PID_app_file )
46 | echo "Shutdown services Clean DB\n";
47 | unlink( $cfg[PID_app_file] );
48 | $connect->close();
49 | ?>
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # Suricata2MikroTik
2 |
3 | Module for Suricata to read eve.json file and looking for specified alerts. If found it, then connect to router MikroTik via API and block the Attack with Firewall.
4 |
5 | This is similar like ips-mikrotik-suricata but works with eve.json and not with barnyard2. https://github.com/elmaxid/ips-mikrotik-suricata
6 |
7 |
8 | Changelog:
9 | 18 February 19: v1.1: Add SSH Support
10 | 31 October 18: v1.0
11 |
12 | * Init version
13 |
14 |
15 | Requeriment:
16 |
17 | * Suricata
18 | * IP and login for router MikroTik RouterOS
19 | * GIT
20 |
21 | ** Features
22 |
23 | * Detect an Alert from Suricata and connect to RouterOS to block de Attack source IP Address
24 | * Notification:
25 | * Email
26 | * Telegram (API Bot)
27 |
28 | Instalation
29 |
30 | Once we have Suricata working and running on our network, the next step is the instalation of Suricata2MikroTik:
31 |
32 | To install, Clone the repository and copy to /var/www/html/suricata2mikrotik
33 |
34 | cd /var/www/html/
35 |
36 | git clone https://github.com/elmaxid/Suricata2MikroTik
37 |
38 | cd suricata2mikrotik
39 |
40 | -- to Config
41 |
42 | * Edit the file config.php with DB and API Logins
43 |
44 | * Create the DB schema
45 |
46 | mysql -u username -p < schema.sql
47 |
48 | * Copy start_ips and start_suricata to /usr/local/bin
49 |
50 | * Give permisions
51 | chmod +x /usr/local/bin/start*
52 |
53 |
54 | ----
55 |
56 | How work it
57 |
58 | For run Suricata, you need to redirect the traffic from MikroTik RouterOS to Suricata server, to do it just use Packet Sniffer or Mangle Send To TZSP Action.
--------------------------------------------------------------------------------
/config.php:
--------------------------------------------------------------------------------
1 | 0=yes)',
23 | `json_raw` longtext COLLATE utf8_unicode_ci,
24 | PRIMARY KEY (`que_id`),
25 | KEY `que_added` (`que_added`)
26 | ) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci COMMENT='Queue of ip addresses to block on firewall';
27 |
28 |
29 | DROP TABLE IF EXISTS `sigs_to_block`;
30 | CREATE TABLE `sigs_to_block` (
31 | `sig_name` text COLLATE utf8_unicode_ci NOT NULL,
32 | `src_or_dst` char(3) COLLATE utf8_unicode_ci NOT NULL DEFAULT 'src',
33 | `timeout` varchar(12) COLLATE utf8_unicode_ci NOT NULL DEFAULT '01:00:00',
34 | `active` int(1) NOT NULL DEFAULT '1',
35 | `id` int(1) NOT NULL AUTO_INCREMENT,
36 | PRIMARY KEY (`id`),
37 | UNIQUE KEY `sig_name_unique_index` (`sig_name`(64))
38 | ) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci;
39 |
40 | INSERT INTO `sigs_to_block` (`sig_name`, `src_or_dst`, `timeout`, `active`, `id`) VALUES
41 | ('ET COMPROMISED Known Compromised or Hostile Host Traffic', 'src', '01:00:00', 1, 1),
42 | ('ET POLICY Suspicious inbound to', 'src', '01:00:00', 1, 2),
43 | ('ET DROP Dshield Block Listed Source', 'src', '01:00:00', 1, 3),
44 | ('ET SCAN Sipvicious Scan', 'src', '01:00:00', 1, 4),
45 | ('ET SCAN Sipvicious User-Agent Detected (friendly-scanner)', 'src', '01:00:00', 1, 5),
46 | ('ET DROP Spamhaus DROP Listed Traffic Inbound', 'src', '01:00:00', 1, 6),
47 | ('ET POLICY Outgoing Basic Auth Base64 HTTP Password detected unencrypted', 'dst', '23:59:59', 1, 7),
48 | ('ET CINS Active Threat Intelligence Poor Reputation IP', 'src', '01:00:00', 1, 8),
49 | ('GPL SNMP public access udp', 'src', '01:00:00', 1, 9),
50 | ('ET TOR Known Tor Relay/Router (Not Exit) Node Traffic', 'src', '01:00:00', 1, 10),
51 | ('GPL DNS named version attempt', 'src', '01:00:00', 1, 11),
52 | ('ET VOIP Modified Sipvicious Asterisk PBX User-Agent', 'src', '01:00:00', 1, 12),
53 | ('GPL RPC xdmcp info query', 'src', '01:00:00', 1, 13),
54 | ('GPL RPC portmap listing UDP 111', 'src', '01:00:00', 1, 14),
55 | ('GPL ATTACK_RESPONSE id check returned root', 'src', '00:01:10', 1, 15),
56 | ('ET VOIP Multiple Unauthorized SIP Responses UDP', 'dst', '00:59:59', 1, 16),
57 | ('ET SCAN Behavioral Unusually fast Terminal Server Traffic, Potential Scan or Infection (Inbound)', 'src', '00:10:00', 1, 18),
58 | ('ET DOS Possible NTP DDoS Inbound Frequent', 'src', '00:10:00', 1, 19),
59 | ('ET SCAN SipCLI VOIP Scan', 'src', '01:00:00', 1, 20),
60 | ('ET POLICY GNU/Linux APT', 'src', '01:00:00', 1, 21),
61 | ('ATTACK [PTsecurity]', 'src', '01:00:00', 1, 22),
62 | ('ETN AGGRESSIVE IPs', 'src', '01:00:00', 1, 25);
63 |
64 | -- 2018-10-31 21:57:40
--------------------------------------------------------------------------------
/www/a.css:
--------------------------------------------------------------------------------
1 | .colorgraph {
2 | height: 5px;
3 | border-top: 0;
4 | background: #c4e17f;
5 | border-radius: 5px;
6 | background-image: -webkit-linear-gradient(left, #c4e17f, #c4e17f 12.5%, #f7fdca 12.5%, #f7fdca 25%, #fecf71 25%, #fecf71 37.5%, #f0776c 37.5%, #f0776c 50%, #db9dbe 50%, #db9dbe 62.5%, #c49cde 62.5%, #c49cde 75%, #669ae1 75%, #669ae1 87.5%, #62c2e4 87.5%, #62c2e4);
7 | background-image: -moz-linear-gradient(left, #c4e17f, #c4e17f 12.5%, #f7fdca 12.5%, #f7fdca 25%, #fecf71 25%, #fecf71 37.5%, #f0776c 37.5%, #f0776c 50%, #db9dbe 50%, #db9dbe 62.5%, #c49cde 62.5%, #c49cde 75%, #669ae1 75%, #669ae1 87.5%, #62c2e4 87.5%, #62c2e4);
8 | background-image: -o-linear-gradient(left, #c4e17f, #c4e17f 12.5%, #f7fdca 12.5%, #f7fdca 25%, #fecf71 25%, #fecf71 37.5%, #f0776c 37.5%, #f0776c 50%, #db9dbe 50%, #db9dbe 62.5%, #c49cde 62.5%, #c49cde 75%, #669ae1 75%, #669ae1 87.5%, #62c2e4 87.5%, #62c2e4);
9 | background-image: linear-gradient(to right, #c4e17f, #c4e17f 12.5%, #f7fdca 12.5%, #f7fdca 25%, #fecf71 25%, #fecf71 37.5%, #f0776c 37.5%, #f0776c 50%, #db9dbe 50%, #db9dbe 62.5%, #c49cde 62.5%, #c49cde 75%, #669ae1 75%, #669ae1 87.5%, #62c2e4 87.5%, #62c2e4);
10 | }
11 |
12 | body {
13 | background-color: #dedede;
14 | }
15 |
16 | .topbar {
17 | background: #2A3F54;
18 | border-color: #2A3F54;
19 | border-radius: 0px;
20 | }
21 |
22 | .topbar .navbar-header a {
23 | color: #ffffff;
24 | }
25 |
26 | .wrapper {
27 | padding-left: 0px;
28 | -webkit-transition: all 0.5s ease;
29 | -moz-transition: all 0.5s ease;
30 | -o-transition: all 0.5s ease;
31 | transition: all 0.5s ease;
32 | }
33 |
34 | .sidebar {
35 | z-index: 1000;
36 | position: fixed;
37 | top: 50px;
38 | left: -50px;
39 | width: 50px;
40 | height: 100%;
41 | overflow-y: auto;
42 | background: #2A3F54;
43 | color: #ffffff;
44 | -webkit-transition: all 0.5s ease;
45 | -moz-transition: all 0.5s ease;
46 | -o-transition: all 0.5s ease;
47 | transition: all 0.5s ease;
48 | }
49 |
50 | .main {
51 | width: 100%;
52 | position: relative;
53 | padding-bottom:20px;
54 | }
55 |
56 | .wrapper.toggled {
57 | padding-left: 50px;
58 | }
59 |
60 | .wrapper.toggled .sidebar {
61 | left: 0;
62 | }
63 |
64 | /* Sidebar Styles */
65 |
66 | .sidebar-nav {
67 | position: absolute;
68 | top: 52px;
69 | width: 50px;
70 | margin: 0;
71 | padding: 0;
72 | list-style: none;
73 | }
74 | .sidebar-nav li {
75 | line-height: 40px;
76 | }
77 | .sidebar-nav li a {
78 | display: block;
79 | text-decoration: none;
80 | color: #e8e8e8;
81 | padding: 0;
82 | text-align:center;
83 | }
84 |
85 | .sidebar-nav li a:hover, .sidebar-nav li.active a {
86 | text-decoration: none;
87 | color: #fff;
88 | background: #fff;
89 | background: rgba(255,255,255,0.2);
90 | }
91 |
92 | .sidebar-nav li a:active,
93 | .sidebar-nav li a:focus {
94 | text-decoration: none;
95 | }
96 |
97 | .sidebar-nav li span, .subbar li span {
98 | display : none;
99 | }
100 |
101 | nav.subbar {
102 | position: relative;
103 | width: 100%;
104 | border-radius: 0px;
105 | background: #fff;
106 | margin: 50px 0 -50px 0;
107 | padding: 10px 0 0 0;
108 | z-index: 2;
109 | }
110 | nav.subbar > ul.nav.nav-tabs {
111 | padding: 0 5px;
112 | }
113 |
114 | nav.subbar > ul.nav.nav-tabs > li.active > a {
115 | background: #dedede;
116 | border-top: 1px solid #a6a6a6;
117 | border-left: 1px solid #a6a6a6;
118 | border-right: 1px solid #a6a6a6;
119 | border-radius: 0px;
120 | }
121 |
122 | .content {
123 | margin-top: 70px;
124 | padding: 0 30px;
125 | }
126 |
127 | @media(min-width:768px){
128 | .subbar li span {
129 | display: inline;
130 | }
131 | }
132 |
133 | @media(min-width:992px) {
134 | .wrapper {
135 | padding-left: 50px;
136 | }
137 |
138 | .sidebar {
139 | left: 0;
140 | width: 50px;
141 | }
142 |
143 | .wrapper.toggled {
144 | padding-left: 200px;
145 | }
146 |
147 | .wrapper.toggled .sidebar, .wrapper.toggled .sidebar-nav {
148 | width: 200px;
149 | }
150 |
151 | .wrapper.toggled .sidebar-nav li a {
152 | text-align: left;
153 | padding: 0 0 0 10px;
154 | }
155 |
156 | .wrapper.toggled .sidebar-nav li span {
157 | display: inline;
158 | }
159 |
160 | }
161 |
162 | .navbar-btn {
163 | background: none;
164 | border: none;
165 | height: 35px;
166 | min-width: 35px;
167 | color: #fff;
168 | }
169 | .navbar-text {
170 | margin-top: 14px;
171 | margin-bottom: 14px;
172 | }
173 | @media (min-width: 768px) {
174 | .navbar-text {
175 | float: left;
176 | margin-left: 15px;
177 | margin-right: 15px;
178 | }
179 | }
180 |
181 |
182 |
183 |
184 | .animationload {
185 | background-color: #fff;
186 | height: 100%;
187 | left: 0;
188 | position: fixed;
189 | top: 0;
190 | width: 100%;
191 | z-index: 10000;
192 | }
193 | .osahanloading {
194 | animation: 1.5s linear 0s normal none infinite running osahanloading;
195 | background: #fed37f none repeat scroll 0 0;
196 | border-radius: 50px;
197 | height: 50px;
198 | left: 50%;
199 | margin-left: -25px;
200 | margin-top: -25px;
201 | position: absolute;
202 | top: 50%;
203 | width: 50px;
204 | }
205 | .osahanloading::after {
206 | animation: 1.5s linear 0s normal none infinite running osahanloading_after;
207 | border-color: #85d6de transparent;
208 | border-radius: 80px;
209 | border-style: solid;
210 | border-width: 10px;
211 | content: "";
212 | height: 80px;
213 | left: -15px;
214 | position: absolute;
215 | top: -15px;
216 | width: 80px;
217 | }
218 | @keyframes osahanloading {
219 | 0% {
220 | transform: rotate(0deg);
221 | }
222 | 50% {
223 | background: #85d6de none repeat scroll 0 0;
224 | transform: rotate(180deg);
225 | }
226 | 100% {
227 | transform: rotate(360deg);
228 | }
229 | }
230 |
--------------------------------------------------------------------------------
/bin/daemon_ips_hunter.php:
--------------------------------------------------------------------------------
1 | bloquear
37 | #
38 | # conectarse via API
39 | # conectarse via SSH
40 | #
41 | # TODO: Hacer que se quede la regla o se borre con el clean
42 |
43 |
44 | /*
45 | ALERTA
46 |
47 |
48 | {"timestamp":"2018-10-30T16:40:33.914426+0000","flow_id":1176372373961457,"pcap_cnt":1642642,"event_type":"alert","src_ip":"217.160.0.187","src_port":80,"dest_ip":"192.168.10.17","dest_port":50101,"proto":"TCP","alert":{"action":"allowed","gid":1,"signature_id":2100498,"rev":7,"signature":"GPL ATTACK_RESPONSE id check returned root","category":"Potentially Bad Traffic","severity":2},"http":{"hostname":"testmyids.com","url":"\/","http_user_agent":"curl\/7.43.0","http_content_type":"text\/html","http_method":"GET","protocol":"HTTP\/1.1","status":200,"length":39},"app_proto":"http","flow":{"pkts_toserver":12,"pkts_toclient":5,"bytes_toserver":953,"bytes_toclient":644,"start":"2018-10-30T16:40:25.998129+0000"}}
49 |
50 |
51 | HTTP
52 |
53 | {"timestamp":"2018-10-30T16:40:33.672909+0000","flow_id":1176372373961457,"pcap_cnt":1642193,"event_type":"http","src_ip":"192.168.10.17","src_port":50101,"dest_ip":"217.160.0.187","dest_port":80,"proto":"TCP","tx_id":0,"http":{"hostname":"testmyids.com","url":"\/","http_user_agent":"curl\/7.43.0","http_content_type":"text\/html","accept":"*\/*","connection":"keep-alive","content_length":"39","content_type":"text\/html","date":"Tue, 30 Oct 2018 16:40:33 GMT","last_modified":"Mon, 15 Jan 2007 23:11:55 GMT","server":"Apache","http_method":"GET","protocol":"HTTP\/1.1","status":200,"length":39}}
54 |
55 |
56 | */
57 |
58 | touch( $cfg['PID_app_file'] );
59 |
60 |
61 | $handle = popen("tail -f /var/log/suricata/eve.json 2>&1", 'r');
62 | // $handle = popen("tail -n 200 /var/log/suricata/eve.json 2>&1", 'r');
63 | while(!feof($handle)) {
64 | #Rule to block, from cache with 3 minutes to refresh
65 | $block_rules=get_cache_rules_to_block();
66 |
67 | unset($datos_to_db); unset($need_block);
68 |
69 | $buffer = fgets($handle);
70 | // $line=json_decode($buffer,true);
71 | if (!file_exists( $cfg['PID_app_file'] )) {
72 | exit(0);
73 | }
74 | // echo "$buffer
\n";
75 | $array = json_decode($buffer, true);
76 | $time = $array['timestamp'];
77 | $date = strtotime($time);
78 | $fixed = date('l, F d Y g:iA', $date);
79 | $date_db = date("Y-m-d H:i:s", $date);
80 | if (isset($array['alert']['signature']) && !empty($array['alert']['signature'])) {
81 |
82 | // echo var_dump($buffer)."
\n";;
83 | // $need_block= array_search_partial($block_rules, $array['alert']['signature']);
84 | #Busco si existe la firma en el array de las --firmas a bloquear---
85 | $need_block= array_search_multiarray_strpos( $block_rules,'sig_name', $array['alert']['signature'] );
86 | if ($need_block ) {
87 |
88 | // if ($block_rules)
89 | $datos_to_db[que_added]=get_now();
90 | $datos_to_db[que_timeout]=$need_block[timeout];
91 | ($need_block[src_or_dst]=='src') ? $datos_to_db[que_ip_adr]=ip2long($array['src_ip']):$datos_to_db[que_ip_adr]=ip2long($array['dest_ip']);
92 | $datos_to_db[que_sig_name]=$array['alert']['signature'];
93 | $datos_to_db[que_sig_sid]=$array['alert']['signature_id'];
94 | $datos_to_db[que_sig_gid]=$array['alert']['gid'];
95 | $datos_to_db[que_event_timestamp]=$date_db;
96 | $datos_to_db[json_raw]=serialize($array);
97 | insert_db( 'block_queue', $datos_to_db );
98 |
99 | if ( $DEBUG ) _log("Alert Found: ". $datos_to_db[que_sig_name]. " FROM ".$array['src_ip']. " TO: ".$array['dest_ip']);
100 |
101 |
102 |
103 | // echo var_dump($datos_to_db)."BLOCK
\n";;
104 |
105 | // echo "BLOCKEDDD.......".$need_block." \n";
106 | /* echo "
107 |
108 | | " . $fixed . " |
109 | " . $array['src_ip'] . " |
110 | " . $array['src_port'] . " |
111 | " . $array['dest_ip'] . " |
112 | " . $array['dest_port'] . " |
113 | " . $array['alert']['signature'] . " |
114 | - |
115 | - |
116 |
\n";*/
117 |
118 | }
119 |
120 | }
121 |
122 | // ob_flush();
123 | // flush();
124 | usleep(400);
125 | }
126 | pclose($handle);
127 | unlink( $cfg['PID_app_file'] );
128 |
129 | /**
130 | * [get_cache_rules_to_block get rules to block from cache and refresh it every 2 minutes]
131 | * @return [type] [description]
132 | */
133 | function get_cache_rules_to_block(){
134 | global $CACHE;
135 | $elapsed=minutos_transcurridos($CACHE[rules_block][time],get_now());
136 | if ($elapsed>1) {
137 | _log("Reloading Rules to block. Getting from DB. ".$elapsed);
138 | $CACHE[rules_block][time]=get_now();
139 | $CACHE[rules_block][rules]=get_rules2block_db();
140 | return $CACHE[rules_block][rules];
141 |
142 | }else {
143 | // _log("Rules to block. Getting from cache ".$elapsed);
144 | return $CACHE[rules_block][rules];
145 | }
146 |
147 | }
148 |
--------------------------------------------------------------------------------
/bin/daemon_ips_process.php:
--------------------------------------------------------------------------------
1 | query($SQL))
66 | {
67 | die('There was an error running the query [' . $connect->error . ']');
68 | } //!$result = $connect->query( $SQL )
69 |
70 | // Reconnecting avoid timeout or API not responding (>v6.43)
71 |
72 | $elapsed = minutos_transcurridos($start_connection_api, get_now());
73 | if ($elapsed > $router['restart_conn_time'])
74 | {
75 | $start_connection_api = get_now();
76 | if ($router['conn'] == 'API')
77 | {
78 | if ($DEBUG) _log("Restarting API Connection. Time elapsed. " . $elapsed);
79 |
80 | // Reconexion
81 |
82 | $API->disconnect();
83 | sleep(1);
84 | _api_connect_MikroTik($router);
85 | }
86 |
87 | if ($DEBUG) _log("OK ReConnected to " . $router['ip']);
88 | }
89 |
90 | $count = $result->num_rows;
91 | if ($count == 0)
92 | {
93 | if ($DEBUG) _log("Sleeping for new entry " . $elapsed);
94 | sleep(2);
95 | continue;
96 | }
97 |
98 | while ($row = $result->fetch_assoc())
99 | {
100 | if (!check_ip_in_whilelist($row['ip']))
101 | {
102 | /* Does not match local address... */
103 |
104 | // Avoid process same last ip
105 |
106 | if ($last_ip == $row['ip'])
107 | {
108 | if ($DEBUG) _log("SAME Last IP.");
109 | usleep(500);
110 | break 1;
111 | }
112 | else
113 | {
114 |
115 | // Block IP
116 |
117 | /* Now add the address into the Blocked address-list group */
118 | $comment_tmp = "From SuricataIPS, " . $row['que_sig_name'] . " => " . $row['que_sig_gid'] . ":" . $row['que_sig_sid'] . " => event timestamp: " . $row['que_event_timestamp'];
119 | if ($DEBUG) _log("Pushing to " . $router['ip']);
120 | if ($router['conn'] == 'API')
121 | {
122 | $API->comm("/ip/firewall/address-list/add", array(
123 | "list" => $router['address_list_block'],
124 | "address" => $row['ip'],
125 | "timeout" => $row['que_timeout'],
126 | "comment" => $comment_tmp
127 | ));
128 | }
129 | elseif ($router['conn'] == 'SSH')
130 | {
131 | unset($cmd); //clean last cmd
132 | $cmd = '/ip fi address-list add list="' . $router['address_list_block'] . '" address="' . $row['ip'] . '" comment="' . $comment_tmp . '" timeout="' . $row['que_timeout'] . '"';
133 | $ssh_log = _ssh_connect_MikroTik($router, $cmd);
134 | if ($DEBUG) _log($ssh_log);
135 | }
136 |
137 | // si esta activo el api de telegram, avisar
138 |
139 | if ($active_api_telegram)
140 | {
141 | $comment_tmp.= " => IP: " . $row['ip'] . " => Timeout: " . $row['que_timeout'];
142 | send_to_telegram($comment_tmp);
143 | }
144 |
145 | // si esta activo el mail envio por correo el alerta
146 |
147 | if ($active_mail_report)
148 | {
149 | /* Send email indicating bad block attempt*/
150 | $to = 'noreply@gmail.com';
151 | $subject = 'Suricata on snort-host: attempted block on local address';
152 | $message = 'A record in the block_queue indicated a block on a local IP Address (' . $row['ip'] . ")\r\n";
153 | $message = $message . "\r\n";
154 | $message = $message . "The signature ID is " . $row['que_sig_id'] . " named: " . $row['que_sig_name'] . "\r\n";
155 | $message = $message . " with a que_id of " . $row['que_id'] . "\r\n\r\n";
156 | $message = $message . "Check the src_or_dst field in events_to_block for the signature to make sure it is correct (src/dst).\r\n\r\n";
157 | $message = $message . "The record was not processed but marked as completed.\r\n";
158 | $headers = 'From: noreply@gmail.com' . "\r\n" . 'Reply-To: noreply@gmail.com' . "\r\n" . 'X-Mailer: PHP/' . phpversion();
159 |
160 | // mail($to, $subject, $message, $headers);
161 | //
162 |
163 | }
164 |
165 | $last_ip = $row['ip']; //update last IP
166 | } //else
167 | if ($DEBUG) _log($comment_tmp);
168 | } // ! whilelist
169 |
170 | // # IP EN lista excepcion
171 |
172 | else
173 | {
174 | if ($DEBUG) _log("Exception IP " . $row['ip']);
175 | }
176 |
177 | // $SQL2 = "UPDATE block_queue set que_processed = 1 WHERE que_id = " . $row[ 'que_id' ] . ";";
178 | // actualizo todos los que tengan el mismo ip
179 |
180 | $SQL2 = "UPDATE block_queue set que_processed = 1 WHERE que_ip_adr = " . ip2long($row['ip']) . ";";
181 | if (!$result2 = $connect->query($SQL2))
182 | {
183 | _log('There was an error running the query [' . $connect->error . ']');
184 | die('There was an error running the query [' . $connect->error . ']');
185 | } //!$result2 = $connect->query( $SQL2 )
186 | mysqli_free_result($result2);
187 | } //eof while
188 | mysqli_free_result($result);
189 | usleep(5000);
190 |
191 | // sleep( 1 );
192 |
193 | /* Sleep 2 seconds then do again */
194 | mysqli_ping($connect);
195 | } //while grande
196 |
197 | // file_exists( $cfg[PID_app_file] )
198 |
199 | if ($DEBUG) _log("Disconnect to " . $router['ip']);
200 |
201 | if ($router['conn'] == 'API') $API->disconnect();
202 | echo "Shutdown services cron\n";
203 | unlink($cfg['PID_app_file']);
204 |
205 | // db close
206 |
207 | $connect->close();
208 |
209 | function _api_connect_MikroTik($router = NULL)
210 | {
211 | if (!$router) return false;
212 | global $DEBUG;
213 | global $API;
214 | global $start_connection_api;
215 | $API = new RouterosAPI();
216 | try
217 | {
218 | if ($DEBUG) _log("Trying to connect to " . $router['ip']);
219 | $API->connect($router['ip'], $router['user'], $router['pass']);
220 | $start_connection_api = get_now(); //Define que se inicia ahora la conexion para reiniciarla cada 5 minutos.
221 | if ($DEBUG) _log("OK Connected to " . $router['ip']);
222 | return true;
223 | }
224 |
225 | catch(Exception $e)
226 | {
227 | _log("ERROR API CONNECTION " . $router['ip']);
228 | die('Unable to connect to RouterOS. Error:' . $e);
229 | }
230 | }
231 |
232 | // Ejecuta un comando ssh remoto
233 |
234 | function _ssh_connect_MikroTik($router = NULL, $cmd = NULL)
235 | {
236 | global $ssh;
237 | if (!$router) return false;
238 | if (!$cmd) return false;
239 | include_once ('Net/SSH2.php');
240 |
241 | // define('NET_SSH2_LOGGING', NET_SSH2_LOG_COMPLEX);
242 |
243 | $ssh = new Net_SSH2($router['ip'], $router['port']);
244 | if (!$ssh->login($router['user'], $router['pass']))
245 | {
246 | return ('ERR_LOGIN');
247 | }
248 |
249 | return $ssh->exec($cmd . "\n"); // note the "\n"
250 | }
251 |
252 | ?>
--------------------------------------------------------------------------------
/share/ssh/Net/SCP.php:
--------------------------------------------------------------------------------
1 |
13 | * login('username', 'password')) {
19 | * exit('bad login');
20 | * }
21 |
22 | * $scp = new Net_SCP($ssh);
23 | * $scp->put('abcd', str_repeat('x', 1024*1024));
24 | * ?>
25 | *
26 | *
27 | * LICENSE: Permission is hereby granted, free of charge, to any person obtaining a copy
28 | * of this software and associated documentation files (the "Software"), to deal
29 | * in the Software without restriction, including without limitation the rights
30 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
31 | * copies of the Software, and to permit persons to whom the Software is
32 | * furnished to do so, subject to the following conditions:
33 | *
34 | * The above copyright notice and this permission notice shall be included in
35 | * all copies or substantial portions of the Software.
36 | *
37 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
38 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
39 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
40 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
41 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
42 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
43 | * THE SOFTWARE.
44 | *
45 | * @category Net
46 | * @package Net_SCP
47 | * @author Jim Wigginton
48 | * @copyright MMX Jim Wigginton
49 | * @license http://www.opensource.org/licenses/mit-license.html MIT License
50 | * @link http://phpseclib.sourceforge.net
51 | */
52 |
53 | /**#@+
54 | * @access public
55 | * @see Net_SCP::put()
56 | */
57 | /**
58 | * Reads data from a local file.
59 | */
60 | define('NET_SCP_LOCAL_FILE', 1);
61 | /**
62 | * Reads data from a string.
63 | */
64 | define('NET_SCP_STRING', 2);
65 | /**#@-*/
66 |
67 | /**#@+
68 | * @access private
69 | * @see Net_SCP::_send()
70 | * @see Net_SCP::_receive()
71 | */
72 | /**
73 | * SSH1 is being used.
74 | */
75 | define('NET_SCP_SSH1', 1);
76 | /**
77 | * SSH2 is being used.
78 | */
79 | define('NET_SCP_SSH2', 2);
80 | /**#@-*/
81 |
82 | /**
83 | * Pure-PHP implementations of SCP.
84 | *
85 | * @author Jim Wigginton
86 | * @version 0.1.0
87 | * @access public
88 | * @package Net_SCP
89 | */
90 | class Net_SCP {
91 | /**
92 | * SSH Object
93 | *
94 | * @var Object
95 | * @access private
96 | */
97 | var $ssh;
98 |
99 | /**
100 | * Packet Size
101 | *
102 | * @var Integer
103 | * @access private
104 | */
105 | var $packet_size;
106 |
107 | /**
108 | * Mode
109 | *
110 | * @var Integer
111 | * @access private
112 | */
113 | var $mode;
114 |
115 | /**
116 | * Default Constructor.
117 | *
118 | * Connects to an SSH server
119 | *
120 | * @param String $host
121 | * @param optional Integer $port
122 | * @param optional Integer $timeout
123 | * @return Net_SCP
124 | * @access public
125 | */
126 | function Net_SCP($ssh)
127 | {
128 | if (!is_object($ssh)) {
129 | return;
130 | }
131 |
132 | switch (strtolower(get_class($ssh))) {
133 | case'net_ssh2':
134 | $this->mode = NET_SCP_SSH2;
135 | break;
136 | case 'net_ssh1':
137 | $this->packet_size = 50000;
138 | $this->mode = NET_SCP_SSH1;
139 | break;
140 | default:
141 | return;
142 | }
143 |
144 | $this->ssh = $ssh;
145 | }
146 |
147 | /**
148 | * Uploads a file to the SCP server.
149 | *
150 | * By default, Net_SCP::put() does not read from the local filesystem. $data is dumped directly into $remote_file.
151 | * So, for example, if you set $data to 'filename.ext' and then do Net_SCP::get(), you will get a file, twelve bytes
152 | * long, containing 'filename.ext' as its contents.
153 | *
154 | * Setting $mode to NET_SFTP_LOCAL_FILE will change the above behavior. With NET_SFTP_LOCAL_FILE, $remote_file will
155 | * contain as many bytes as filename.ext does on your local filesystem. If your filename.ext is 1MB then that is how
156 | * large $remote_file will be, as well.
157 | *
158 | * Currently, only binary mode is supported. As such, if the line endings need to be adjusted, you will need to take
159 | * care of that, yourself.
160 | *
161 | * @param String $remote_file
162 | * @param String $data
163 | * @param optional Integer $mode
164 | * @return Boolean
165 | * @access public
166 | */
167 | function put($remote_file, $data, $mode = NET_SCP_STRING)
168 | {
169 | if (!isset($this->ssh)) {
170 | return false;
171 | }
172 |
173 | $this->ssh->exec('scp -t ' . $remote_file, false); // -t = to
174 |
175 | $temp = $this->_receive();
176 | if ($temp !== chr(0)) {
177 | return false;
178 | }
179 |
180 | if ($this->mode == NET_SCP_SSH2) {
181 | $this->packet_size = $this->ssh->packet_size_client_to_server[NET_SSH2_CHANNEL_EXEC];
182 | }
183 |
184 | $remote_file = basename($remote_file);
185 | $this->_send('C0644 ' . strlen($data) . ' ' . $remote_file . "\n");
186 |
187 | $temp = $this->_receive();
188 | if ($temp !== chr(0)) {
189 | return false;
190 | }
191 |
192 | if ($mode == NET_SCP_STRING) {
193 | $this->_send($data);
194 | } else {
195 | if (!is_file($data)) {
196 | user_error("$data is not a valid file", E_USER_NOTICE);
197 | return false;
198 | }
199 | $fp = @fopen($data, 'rb');
200 | if (!$fp) {
201 | return false;
202 | }
203 | $size = filesize($data);
204 | for ($i = 0; $i < $size; $i += $this->packet_size) {
205 | $this->_send(fgets($fp, $this->packet_size));
206 | }
207 | fclose($fp);
208 | }
209 | $this->_close();
210 | }
211 |
212 | /**
213 | * Downloads a file from the SCP server.
214 | *
215 | * Returns a string containing the contents of $remote_file if $local_file is left undefined or a boolean false if
216 | * the operation was unsuccessful. If $local_file is defined, returns true or false depending on the success of the
217 | * operation
218 | *
219 | * @param String $remote_file
220 | * @param optional String $local_file
221 | * @return Mixed
222 | * @access public
223 | */
224 | function get($remote_file, $local_file = false)
225 | {
226 | if (!isset($this->ssh)) {
227 | return false;
228 | }
229 |
230 | $this->ssh->exec('scp -f ' . $remote_file, false); // -f = from
231 |
232 | $this->_send("\0");
233 |
234 | if (!preg_match('#(?[^ ]+) (?\d+) (?.+)#', rtrim($this->_receive()), $info)) {
235 | return false;
236 | }
237 |
238 | $this->_send("\0");
239 |
240 | $size = 0;
241 |
242 | if ($local_file !== false) {
243 | $fp = @fopen($local_file, 'wb');
244 | if (!$fp) {
245 | return false;
246 | }
247 | }
248 |
249 | $content = '';
250 | while ($size < $info['size']) {
251 | $data = $this->_receive();
252 | // SCP usually seems to split stuff out into 16k chunks
253 | $size+= strlen($data);
254 |
255 | if ($local_file === false) {
256 | $content.= $data;
257 | } else {
258 | fputs($fp, $data);
259 | }
260 | }
261 |
262 | $this->_close();
263 |
264 | if ($local_file !== false) {
265 | fclose($fp);
266 | return true;
267 | }
268 |
269 | return $content;
270 | }
271 |
272 | /**
273 | * Sends a packet to an SSH server
274 | *
275 | * @param String $data
276 | * @access private
277 | */
278 | function _send($data)
279 | {
280 | switch ($this->mode) {
281 | case NET_SCP_SSH2:
282 | $this->ssh->_send_channel_packet(NET_SSH2_CHANNEL_EXEC, $data);
283 | break;
284 | case NET_SCP_SSH1:
285 | $data = pack('CNa*', NET_SSH1_CMSG_STDIN_DATA, strlen($data), $data);
286 | $this->ssh->_send_binary_packet($data);
287 | }
288 | }
289 |
290 | /**
291 | * Receives a packet from an SSH server
292 | *
293 | * @return String
294 | * @access private
295 | */
296 | function _receive()
297 | {
298 | switch ($this->mode) {
299 | case NET_SCP_SSH2:
300 | return $this->ssh->_get_channel_packet(NET_SSH2_CHANNEL_EXEC, true);
301 | case NET_SCP_SSH1:
302 | if (!$this->ssh->bitmap) {
303 | return false;
304 | }
305 | while (true) {
306 | $response = $this->ssh->_get_binary_packet();
307 | switch ($response[NET_SSH1_RESPONSE_TYPE]) {
308 | case NET_SSH1_SMSG_STDOUT_DATA:
309 | extract(unpack('Nlength', $response[NET_SSH1_RESPONSE_DATA]));
310 | return $this->ssh->_string_shift($response[NET_SSH1_RESPONSE_DATA], $length);
311 | case NET_SSH1_SMSG_STDERR_DATA:
312 | break;
313 | case NET_SSH1_SMSG_EXITSTATUS:
314 | $this->ssh->_send_binary_packet(chr(NET_SSH1_CMSG_EXIT_CONFIRMATION));
315 | fclose($this->ssh->fsock);
316 | $this->ssh->bitmap = 0;
317 | return false;
318 | default:
319 | user_error('Unknown packet received', E_USER_NOTICE);
320 | return false;
321 | }
322 | }
323 | }
324 | }
325 |
326 | /**
327 | * Closes the connection to an SSH server
328 | *
329 | * @access private
330 | */
331 | function _close()
332 | {
333 | switch ($this->mode) {
334 | case NET_SCP_SSH2:
335 | $this->ssh->_close_channel(NET_SSH2_CHANNEL_EXEC);
336 | break;
337 | case NET_SCP_SSH1:
338 | $this->ssh->disconnect();
339 | }
340 | }
341 | }
342 |
--------------------------------------------------------------------------------
/share/ssh/Crypt/Random.php:
--------------------------------------------------------------------------------
1 |
11 | *
16 | *
17 | *
18 | * LICENSE: Permission is hereby granted, free of charge, to any person obtaining a copy
19 | * of this software and associated documentation files (the "Software"), to deal
20 | * in the Software without restriction, including without limitation the rights
21 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
22 | * copies of the Software, and to permit persons to whom the Software is
23 | * furnished to do so, subject to the following conditions:
24 | *
25 | * The above copyright notice and this permission notice shall be included in
26 | * all copies or substantial portions of the Software.
27 | *
28 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
29 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
30 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
31 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
32 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
33 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
34 | * THE SOFTWARE.
35 | *
36 | * @category Crypt
37 | * @package Crypt_Random
38 | * @author Jim Wigginton
39 | * @copyright MMVII Jim Wigginton
40 | * @license http://www.opensource.org/licenses/mit-license.html MIT License
41 | * @link http://phpseclib.sourceforge.net
42 | */
43 |
44 | /**
45 | * "Is Windows" test
46 | *
47 | * @access private
48 | */
49 | define('CRYPT_RANDOM_IS_WINDOWS', strtoupper(substr(PHP_OS, 0, 3)) === 'WIN');
50 |
51 | /**
52 | * Generate a random string.
53 | *
54 | * Although microoptimizations are generally discouraged as they impair readability this function is ripe with
55 | * microoptimizations because this function has the potential of being called a huge number of times.
56 | * eg. for RSA key generation.
57 | *
58 | * @param Integer $length
59 | * @return String
60 | * @access public
61 | */
62 | function crypt_random_string($length)
63 | {
64 | if (CRYPT_RANDOM_IS_WINDOWS) {
65 | // method 1. prior to PHP 5.3 this would call rand() on windows hence the function_exists('class_alias') call.
66 | // ie. class_alias is a function that was introduced in PHP 5.3
67 | if (function_exists('mcrypt_create_iv') && function_exists('class_alias')) {
68 | return mcrypt_create_iv($length);
69 | }
70 | // method 2. openssl_random_pseudo_bytes was introduced in PHP 5.3.0 but prior to PHP 5.3.4 there was,
71 | // to quote , "possible blocking behavior". as of 5.3.4
72 | // openssl_random_pseudo_bytes and mcrypt_create_iv do the exact same thing on Windows. ie. they both
73 | // call php_win32_get_random_bytes():
74 | //
75 | // https://github.com/php/php-src/blob/7014a0eb6d1611151a286c0ff4f2238f92c120d6/ext/openssl/openssl.c#L5008
76 | // https://github.com/php/php-src/blob/7014a0eb6d1611151a286c0ff4f2238f92c120d6/ext/mcrypt/mcrypt.c#L1392
77 | //
78 | // php_win32_get_random_bytes() is defined thusly:
79 | //
80 | // https://github.com/php/php-src/blob/7014a0eb6d1611151a286c0ff4f2238f92c120d6/win32/winutil.c#L80
81 | //
82 | // we're calling it, all the same, in the off chance that the mcrypt extension is not available
83 | if (function_exists('openssl_random_pseudo_bytes') && version_compare(PHP_VERSION, '5.3.4', '>=')) {
84 | return openssl_random_pseudo_bytes($length);
85 | }
86 | } else {
87 | // method 1. the fastest
88 | if (function_exists('openssl_random_pseudo_bytes')) {
89 | return openssl_random_pseudo_bytes($length);
90 | }
91 | // method 2
92 | static $fp = true;
93 | if ($fp === true) {
94 | // warning's will be output unles the error suppression operator is used. errors such as
95 | // "open_basedir restriction in effect", "Permission denied", "No such file or directory", etc.
96 | $fp = @fopen('/dev/urandom', 'rb');
97 | }
98 | if ($fp !== true && $fp !== false) { // surprisingly faster than !is_bool() or is_resource()
99 | return fread($fp, $length);
100 | }
101 | // method 3. pretty much does the same thing as method 2 per the following url:
102 | // https://github.com/php/php-src/blob/7014a0eb6d1611151a286c0ff4f2238f92c120d6/ext/mcrypt/mcrypt.c#L1391
103 | // surprisingly slower than method 2. maybe that's because mcrypt_create_iv does a bunch of error checking that we're
104 | // not doing. regardless, this'll only be called if this PHP script couldn't open /dev/urandom due to open_basedir
105 | // restrictions or some such
106 | if (function_exists('mcrypt_create_iv')) {
107 | return mcrypt_create_iv($length, MCRYPT_DEV_URANDOM);
108 | }
109 | }
110 | // at this point we have no choice but to use a pure-PHP CSPRNG
111 |
112 | // cascade entropy across multiple PHP instances by fixing the session and collecting all
113 | // environmental variables, including the previous session data and the current session
114 | // data.
115 | //
116 | // mt_rand seeds itself by looking at the PID and the time, both of which are (relatively)
117 | // easy to guess at. linux uses mouse clicks, keyboard timings, etc, as entropy sources, but
118 | // PHP isn't low level to be able to use those as sources and on a web server there's not likely
119 | // going to be a ton of keyboard or mouse action. web servers do have one thing that we can use
120 | // however. a ton of people visiting the website. obviously you don't want to base your seeding
121 | // soley on parameters a potential attacker sends but (1) not everything in $_SERVER is controlled
122 | // by the user and (2) this isn't just looking at the data sent by the current user - it's based
123 | // on the data sent by all users. one user requests the page and a hash of their info is saved.
124 | // another user visits the page and the serialization of their data is utilized along with the
125 | // server envirnment stuff and a hash of the previous http request data (which itself utilizes
126 | // a hash of the session data before that). certainly an attacker should be assumed to have
127 | // full control over his own http requests. he, however, is not going to have control over
128 | // everyone's http requests.
129 | static $crypto = false, $v;
130 | if ($crypto === false) {
131 | // save old session data
132 | $old_session_id = session_id();
133 | $old_use_cookies = ini_get('session.use_cookies');
134 | $old_session_cache_limiter = session_cache_limiter();
135 | if (isset($_SESSION)) {
136 | $_OLD_SESSION = $_SESSION;
137 | }
138 | if ($old_session_id != '') {
139 | session_write_close();
140 | }
141 |
142 | session_id(1);
143 | ini_set('session.use_cookies', 0);
144 | session_cache_limiter('');
145 | session_start();
146 |
147 | $v = $seed = $_SESSION['seed'] = pack('H*', sha1(
148 | serialize($_SERVER) .
149 | serialize($_POST) .
150 | serialize($_GET) .
151 | serialize($_COOKIE) .
152 | serialize($GLOBALS) .
153 | serialize($_SESSION) .
154 | serialize($_OLD_SESSION)
155 | ));
156 | if (!isset($_SESSION['count'])) {
157 | $_SESSION['count'] = 0;
158 | }
159 | $_SESSION['count']++;
160 |
161 | session_write_close();
162 |
163 | // restore old session data
164 | if ($old_session_id != '') {
165 | session_id($old_session_id);
166 | session_start();
167 | ini_set('session.use_cookies', $old_use_cookies);
168 | session_cache_limiter($old_session_cache_limiter);
169 | } else {
170 | if (isset($_OLD_SESSION)) {
171 | $_SESSION = $_OLD_SESSION;
172 | unset($_OLD_SESSION);
173 | } else {
174 | unset($_SESSION);
175 | }
176 | }
177 |
178 | // in SSH2 a shared secret and an exchange hash are generated through the key exchange process.
179 | // the IV client to server is the hash of that "nonce" with the letter A and for the encryption key it's the letter C.
180 | // if the hash doesn't produce enough a key or an IV that's long enough concat successive hashes of the
181 | // original hash and the current hash. we'll be emulating that. for more info see the following URL:
182 | //
183 | // http://tools.ietf.org/html/rfc4253#section-7.2
184 | //
185 | // see the is_string($crypto) part for an example of how to expand the keys
186 | $key = pack('H*', sha1($seed . 'A'));
187 | $iv = pack('H*', sha1($seed . 'C'));
188 |
189 | // ciphers are used as per the nist.gov link below. also, see this link:
190 | //
191 | // http://en.wikipedia.org/wiki/Cryptographically_secure_pseudorandom_number_generator#Designs_based_on_cryptographic_primitives
192 | switch (true) {
193 | case class_exists('Crypt_AES'):
194 | $crypto = new Crypt_AES(CRYPT_AES_MODE_CTR);
195 | break;
196 | case class_exists('Crypt_TripleDES'):
197 | $crypto = new Crypt_TripleDES(CRYPT_DES_MODE_CTR);
198 | break;
199 | case class_exists('Crypt_DES'):
200 | $crypto = new Crypt_DES(CRYPT_DES_MODE_CTR);
201 | break;
202 | case class_exists('Crypt_RC4'):
203 | $crypto = new Crypt_RC4();
204 | break;
205 | default:
206 | $crypto = $seed;
207 | return crypt_random_string($length);
208 | }
209 |
210 | $crypto->setKey($key);
211 | $crypto->setIV($iv);
212 | $crypto->enableContinuousBuffer();
213 | }
214 |
215 | if (is_string($crypto)) {
216 | // the following is based off of ANSI X9.31:
217 | //
218 | // http://csrc.nist.gov/groups/STM/cavp/documents/rng/931rngext.pdf
219 | //
220 | // OpenSSL uses that same standard for it's random numbers:
221 | //
222 | // http://www.opensource.apple.com/source/OpenSSL/OpenSSL-38/openssl/fips-1.0/rand/fips_rand.c
223 | // (do a search for "ANS X9.31 A.2.4")
224 | //
225 | // ANSI X9.31 recommends ciphers be used and phpseclib does use them if they're available (see
226 | // later on in the code) but if they're not we'll use sha1
227 | $result = '';
228 | while (strlen($result) < $length) { // each loop adds 20 bytes
229 | // microtime() isn't packed as "densely" as it could be but then neither is that the idea.
230 | // the idea is simply to ensure that each "block" has a unique element to it.
231 | $i = pack('H*', sha1(microtime()));
232 | $r = pack('H*', sha1($i ^ $v));
233 | $v = pack('H*', sha1($r ^ $i));
234 | $result.= $r;
235 | }
236 | return substr($result, 0, $length);
237 | }
238 |
239 | //return $crypto->encrypt(str_repeat("\0", $length));
240 |
241 | $result = '';
242 | while (strlen($result) < $length) {
243 | $i = $crypto->encrypt(microtime());
244 | $r = $crypto->encrypt($i ^ $v);
245 | $v = $crypto->encrypt($r ^ $i);
246 | $result.= $r;
247 | }
248 | return substr($result, 0, $length);
249 | }
250 |
--------------------------------------------------------------------------------
/share/routeros_api.php:
--------------------------------------------------------------------------------
1 | debug) {
53 | echo $text . "\n";
54 | }
55 | }
56 |
57 |
58 | /**
59 | *
60 | *
61 | * @param string $length
62 | *
63 | * @return void
64 | */
65 | public function encodeLength($length)
66 | {
67 | if ($length < 0x80) {
68 | $length = chr($length);
69 | } elseif ($length < 0x4000) {
70 | $length |= 0x8000;
71 | $length = chr(($length >> 8) & 0xFF) . chr($length & 0xFF);
72 | } elseif ($length < 0x200000) {
73 | $length |= 0xC00000;
74 | $length = chr(($length >> 16) & 0xFF) . chr(($length >> 8) & 0xFF) . chr($length & 0xFF);
75 | } elseif ($length < 0x10000000) {
76 | $length |= 0xE0000000;
77 | $length = chr(($length >> 24) & 0xFF) . chr(($length >> 16) & 0xFF) . chr(($length >> 8) & 0xFF) . chr($length & 0xFF);
78 | } elseif ($length >= 0x10000000) {
79 | $length = chr(0xF0) . chr(($length >> 24) & 0xFF) . chr(($length >> 16) & 0xFF) . chr(($length >> 8) & 0xFF) . chr($length & 0xFF);
80 | }
81 |
82 | return $length;
83 | }
84 |
85 |
86 | /**
87 | * Login to RouterOS
88 | *
89 | * @param string $ip Hostname (IP or domain) of the RouterOS server
90 | * @param string $login The RouterOS username
91 | * @param string $password The RouterOS password
92 | *
93 | * @return boolean If we are connected or not
94 | */
95 | public function connect($ip, $login, $password)
96 | {
97 | for ($ATTEMPT = 1; $ATTEMPT <= $this->attempts; $ATTEMPT++) {
98 | $this->connected = false;
99 | $PROTOCOL = ($this->ssl ? 'ssl://' : '' );
100 | $context = stream_context_create(array('ssl' => array('ciphers' => 'ADH:ALL', 'verify_peer' => false, 'verify_peer_name' => false)));
101 | $this->debug('Connection attempt #' . $ATTEMPT . ' to ' . $PROTOCOL . $ip . ':' . $this->port . '...');
102 | $this->socket = @stream_socket_client($PROTOCOL . $ip.':'. $this->port, $this->error_no, $this->error_str, $this->timeout, STREAM_CLIENT_CONNECT,$context);
103 | if ($this->socket) {
104 | socket_set_timeout($this->socket, $this->timeout);
105 | $this->write('/login', false);
106 | $this->write('=name=' . $login, false);
107 | $this->write('=password=' . $password);
108 | $RESPONSE = $this->read(false);
109 | if (isset($RESPONSE[0])) {
110 | if ($RESPONSE[0] == '!done') {
111 | if (!isset($RESPONSE[1])) {
112 | // Login method post-v6.43
113 | $this->connected = true;
114 | break;
115 | } else {
116 | // Login method pre-v6.43
117 | $MATCHES = array();
118 | if (preg_match_all('/[^=]+/i', $RESPONSE[1], $MATCHES)) {
119 | if ($MATCHES[0][0] == 'ret' && strlen($MATCHES[0][1]) == 32) {
120 | $this->write('/login', false);
121 | $this->write('=name=' . $login, false);
122 | $this->write('=response=00' . md5(chr(0) . $password . pack('H*', $MATCHES[0][1])));
123 | $RESPONSE = $this->read(false);
124 | if (isset($RESPONSE[0]) && $RESPONSE[0] == '!done') {
125 | $this->connected = true;
126 | break;
127 | }
128 | }
129 | }
130 | }
131 | }
132 | }
133 | fclose($this->socket);
134 | }
135 | sleep($this->delay);
136 | }
137 |
138 | if ($this->connected) {
139 | $this->debug('Connected...');
140 | } else {
141 | $this->debug('Error...');
142 | }
143 | return $this->connected;
144 | }
145 |
146 |
147 | /**
148 | * Disconnect from RouterOS
149 | *
150 | * @return void
151 | */
152 | public function disconnect()
153 | {
154 | // let's make sure this socket is still valid. it may have been closed by something else
155 | if( is_resource($this->socket) ) {
156 | fclose($this->socket);
157 | }
158 | $this->connected = false;
159 | $this->debug('Disconnected...');
160 | }
161 |
162 |
163 | /**
164 | * Parse response from Router OS
165 | *
166 | * @param array $response Response data
167 | *
168 | * @return array Array with parsed data
169 | */
170 | public function parseResponse($response)
171 | {
172 | if (is_array($response)) {
173 | $PARSED = array();
174 | $CURRENT = null;
175 | $singlevalue = null;
176 | foreach ($response as $x) {
177 | if (in_array($x, array('!fatal','!re','!trap'))) {
178 | if ($x == '!re') {
179 | $CURRENT =& $PARSED[];
180 | } else {
181 | $CURRENT =& $PARSED[$x][];
182 | }
183 | } elseif ($x != '!done') {
184 | $MATCHES = array();
185 | if (preg_match_all('/[^=]+/i', $x, $MATCHES)) {
186 | if ($MATCHES[0][0] == 'ret') {
187 | $singlevalue = $MATCHES[0][1];
188 | }
189 | $CURRENT[$MATCHES[0][0]] = (isset($MATCHES[0][1]) ? $MATCHES[0][1] : '');
190 | }
191 | }
192 | }
193 |
194 | if (empty($PARSED) && !is_null($singlevalue)) {
195 | $PARSED = $singlevalue;
196 | }
197 |
198 | return $PARSED;
199 | } else {
200 | return array();
201 | }
202 | }
203 |
204 |
205 | /**
206 | * Parse response from Router OS
207 | *
208 | * @param array $response Response data
209 | *
210 | * @return array Array with parsed data
211 | */
212 | public function parseResponse4Smarty($response)
213 | {
214 | if (is_array($response)) {
215 | $PARSED = array();
216 | $CURRENT = null;
217 | $singlevalue = null;
218 | foreach ($response as $x) {
219 | if (in_array($x, array('!fatal','!re','!trap'))) {
220 | if ($x == '!re') {
221 | $CURRENT =& $PARSED[];
222 | } else {
223 | $CURRENT =& $PARSED[$x][];
224 | }
225 | } elseif ($x != '!done') {
226 | $MATCHES = array();
227 | if (preg_match_all('/[^=]+/i', $x, $MATCHES)) {
228 | if ($MATCHES[0][0] == 'ret') {
229 | $singlevalue = $MATCHES[0][1];
230 | }
231 | $CURRENT[$MATCHES[0][0]] = (isset($MATCHES[0][1]) ? $MATCHES[0][1] : '');
232 | }
233 | }
234 | }
235 | foreach ($PARSED as $key => $value) {
236 | $PARSED[$key] = $this->arrayChangeKeyName($value);
237 | }
238 | return $PARSED;
239 | if (empty($PARSED) && !is_null($singlevalue)) {
240 | $PARSED = $singlevalue;
241 | }
242 | } else {
243 | return array();
244 | }
245 | }
246 |
247 |
248 | /**
249 | * Change "-" and "/" from array key to "_"
250 | *
251 | * @param array $array Input array
252 | *
253 | * @return array Array with changed key names
254 | */
255 | public function arrayChangeKeyName(&$array)
256 | {
257 | if (is_array($array)) {
258 | foreach ($array as $k => $v) {
259 | $tmp = str_replace("-", "_", $k);
260 | $tmp = str_replace("/", "_", $tmp);
261 | if ($tmp) {
262 | $array_new[$tmp] = $v;
263 | } else {
264 | $array_new[$k] = $v;
265 | }
266 | }
267 | return $array_new;
268 | } else {
269 | return $array;
270 | }
271 | }
272 |
273 |
274 | /**
275 | * Read data from Router OS
276 | *
277 | * @param boolean $parse Parse the data? default: true
278 | *
279 | * @return array Array with parsed or unparsed data
280 | */
281 | public function read($parse = true)
282 | {
283 | $RESPONSE = array();
284 | $receiveddone = false;
285 | while (true) {
286 | // Read the first byte of input which gives us some or all of the length
287 | // of the remaining reply.
288 | $BYTE = ord(fread($this->socket, 1));
289 | $LENGTH = 0;
290 | // If the first bit is set then we need to remove the first four bits, shift left 8
291 | // and then read another byte in.
292 | // We repeat this for the second and third bits.
293 | // If the fourth bit is set, we need to remove anything left in the first byte
294 | // and then read in yet another byte.
295 | if ($BYTE & 128) {
296 | if (($BYTE & 192) == 128) {
297 | $LENGTH = (($BYTE & 63) << 8) + ord(fread($this->socket, 1));
298 | } else {
299 | if (($BYTE & 224) == 192) {
300 | $LENGTH = (($BYTE & 31) << 8) + ord(fread($this->socket, 1));
301 | $LENGTH = ($LENGTH << 8) + ord(fread($this->socket, 1));
302 | } else {
303 | if (($BYTE & 240) == 224) {
304 | $LENGTH = (($BYTE & 15) << 8) + ord(fread($this->socket, 1));
305 | $LENGTH = ($LENGTH << 8) + ord(fread($this->socket, 1));
306 | $LENGTH = ($LENGTH << 8) + ord(fread($this->socket, 1));
307 | } else {
308 | $LENGTH = ord(fread($this->socket, 1));
309 | $LENGTH = ($LENGTH << 8) + ord(fread($this->socket, 1));
310 | $LENGTH = ($LENGTH << 8) + ord(fread($this->socket, 1));
311 | $LENGTH = ($LENGTH << 8) + ord(fread($this->socket, 1));
312 | }
313 | }
314 | }
315 | } else {
316 | $LENGTH = $BYTE;
317 | }
318 |
319 | $_ = "";
320 |
321 | // If we have got more characters to read, read them in.
322 | if ($LENGTH > 0) {
323 | $_ = "";
324 | $retlen = 0;
325 | while ($retlen < $LENGTH) {
326 | $toread = $LENGTH - $retlen;
327 | $_ .= fread($this->socket, $toread);
328 | $retlen = strlen($_);
329 | }
330 | $RESPONSE[] = $_;
331 | $this->debug('>>> [' . $retlen . '/' . $LENGTH . '] bytes read.');
332 | }
333 |
334 | // If we get a !done, make a note of it.
335 | if ($_ == "!done") {
336 | $receiveddone = true;
337 | }
338 |
339 | $STATUS = socket_get_status($this->socket);
340 | if ($LENGTH > 0) {
341 | $this->debug('>>> [' . $LENGTH . ', ' . $STATUS['unread_bytes'] . ']' . $_);
342 | }
343 |
344 | if ((!$this->connected && !$STATUS['unread_bytes']) || ($this->connected && !$STATUS['unread_bytes'] && $receiveddone)) {
345 | break;
346 | }
347 | }
348 |
349 | if ($parse) {
350 | $RESPONSE = $this->parseResponse($RESPONSE);
351 | }
352 |
353 | return $RESPONSE;
354 | }
355 |
356 |
357 | /**
358 | * Write (send) data to Router OS
359 | *
360 | * @param string $command A string with the command to send
361 | * @param mixed $param2 If we set an integer, the command will send this data as a "tag"
362 | * If we set it to boolean true, the funcion will send the comand and finish
363 | * If we set it to boolean false, the funcion will send the comand and wait for next command
364 | * Default: true
365 | *
366 | * @return boolean Return false if no command especified
367 | */
368 | public function write($command, $param2 = true)
369 | {
370 | if ($command) {
371 | $data = explode("\n", $command);
372 | foreach ($data as $com) {
373 | $com = trim($com);
374 | fwrite($this->socket, $this->encodeLength(strlen($com)) . $com);
375 | $this->debug('<<< [' . strlen($com) . '] ' . $com);
376 | }
377 |
378 | if (gettype($param2) == 'integer') {
379 | fwrite($this->socket, $this->encodeLength(strlen('.tag=' . $param2)) . '.tag=' . $param2 . chr(0));
380 | $this->debug('<<< [' . strlen('.tag=' . $param2) . '] .tag=' . $param2);
381 | } elseif (gettype($param2) == 'boolean') {
382 | fwrite($this->socket, ($param2 ? chr(0) : ''));
383 | }
384 |
385 | return true;
386 | } else {
387 | return false;
388 | }
389 | }
390 |
391 |
392 | /**
393 | * Write (send) data to Router OS
394 | *
395 | * @param string $com A string with the command to send
396 | * @param array $arr An array with arguments or queries
397 | *
398 | * @return array Array with parsed
399 | */
400 | public function comm($com, $arr = array())
401 | {
402 | $count = count($arr);
403 | $this->write($com, !$arr);
404 | $i = 0;
405 | if ($this->isIterable($arr)) {
406 | foreach ($arr as $k => $v) {
407 | switch ($k[0]) {
408 | case "?":
409 | $el = "$k=$v";
410 | break;
411 | case "~":
412 | $el = "$k~$v";
413 | break;
414 | default:
415 | $el = "=$k=$v";
416 | break;
417 | }
418 |
419 | $last = ($i++ == $count - 1);
420 | $this->write($el, $last);
421 | }
422 | }
423 |
424 | return $this->read();
425 | }
426 |
427 | /**
428 | * Standard destructor
429 | *
430 | * @return void
431 | */
432 | public function __destruct()
433 | {
434 | $this->disconnect();
435 | }
436 | }
437 |
--------------------------------------------------------------------------------
/share/functions.php:
--------------------------------------------------------------------------------
1 | query($SQL))
68 | {
69 | die('There was an error running the query [' . $connect->error . ']');
70 | } //!$result = $db_->query( $SQL )
71 | $row = $result->fetch_assoc();
72 | return $row;
73 | }
74 |
75 | /**
76 | * [insert_db agrega un nuevo registro en una db]
77 | * @param [type] $dbname [description]
78 | * @param [type] $datos [description]
79 | * @return [type] [description]
80 | */
81 |
82 | function insert_db($dbname = NULL, $datos = NULL, $delayed = false)
83 | {
84 | global $connect;
85 | if (!$datos) return false;
86 | if (!$dbname) return false;
87 | $sql = "INSERT ";
88 | if ($delayed) $sql.= " delayed ";
89 | $sql.= " INTO $dbname ";
90 | foreach($datos as $key => $valor)
91 |
92 | {
93 | $sql_init.= "`" . $key . "`,";
94 | $sql_final.= "'" . $valor . "',";
95 | } //$datos as $key => $valor
96 |
97 | $sql_init = substr($sql_init, 0, -1);
98 | $sql_final = substr($sql_final, 0, -1);
99 |
100 |
101 | $sql.= " ( " . $sql_init . " ) VALUES (" . $sql_final . ") ;";
102 |
103 | // echo $sql;
104 |
105 | $result = $connect->query($sql);
106 |
107 | if ($connect->error)
108 | {
109 | die('Error, insert query failed ' . $connect->error . $sql);
110 | }
111 | elseif ($result)
112 | {
113 | return (true);
114 | } //$result
115 | else
116 | {
117 | return (false);
118 | }
119 | }
120 |
121 | function mysql_con()
122 | {
123 | global $cfg;
124 | global $connect;
125 | $i = 0;
126 | while ($i < 100)
127 | {
128 | $connect = new mysqli($cfg['db_server'], $cfg['db_user_name'], $cfg['db_password'], $cfg['db_database']);
129 | if ($connect->connect_error > 0)
130 | {
131 | print ('Unable to connect to database [' . $connect->connect_error . ']');
132 | sleep(10);
133 | $i = $i + 10;
134 | } //$connect->connect_errno > 0
135 | else
136 | {
137 | $i = 100;
138 | $connect_DB = true;
139 | }
140 | } //$i < 100+
141 | return $connect;
142 | }
143 |
144 | /**
145 | * [array_search_partial busca un string en un valor de un array y devuelve el key]
146 | * @param [type] $arr [description]
147 | * @param [type] $keyword [description]
148 | * @return [type] [description]
149 | */
150 |
151 | function array_search_partial($arr, $keyword)
152 | {
153 | foreach($arr as $index => $string)
154 | {
155 | if (strpos($keyword, $string) !== FALSE) return $index;
156 | } //$arr as $index => $string
157 | }
158 |
159 | /**
160 | * [partial_search_array Busca si existe parte de un string en un array]
161 | * @param [type] $haystack [description]
162 | * @param [type] $needle [description]
163 | * @return [type] [description]
164 | */
165 |
166 | function partial_search_array($haystack, $needle)
167 | {
168 | foreach($haystack as $item)
169 | {
170 | if (strpos($item, $needle) !== false)
171 | {
172 | return true;
173 | } //strpos( $item, $needle ) !== false
174 | } //$haystack as $item
175 | return false;
176 | }
177 |
178 | /**
179 | * [array_search_multiarray_strpos busca en un array por un key y devuelve si encuentra el string ]
180 | * @param [type] $array [description]
181 | * @param [type] $field [description]
182 | * @param [type] $string_to_search [description]
183 | * @return [type] [description]
184 | */
185 |
186 | function array_search_multiarray_strpos($array, $field, $string_to_search)
187 | {
188 | foreach($array as $key => $p)
189 | {
190 |
191 | // if ( $p[ $field ] === $value )
192 |
193 | if (strpos($string_to_search, $p[$field]) !== FALSE) return $p;
194 | } //$array as $key => $product
195 | return false;
196 | }
197 |
198 | /**
199 | * [partial_search_array Busca si existe parte de un string en un array]
200 | * @param [type] $haystack [description]
201 | * @param [type] $needle [description]
202 | * @return [type] [description]
203 | */
204 |
205 | function partial_search_array_special($haystack, $needle)
206 | {
207 | foreach($haystack as $item)
208 | {
209 | if (count($needle) > count($item))
210 | { //busco item en needle
211 | if (strpos($item, $needle) !== false)
212 | {
213 | return true;
214 | } //strpos( $item, $needle ) !== false
215 | } //count( $needle ) > count( $item )
216 | else
217 | { //busco needle en item
218 | if (strpos($needle, $item) !== false)
219 | {
220 | return true;
221 | } //strpos( $needle, $item ) !== false
222 | }
223 | } //$haystack as $item
224 | return false;
225 | }
226 |
227 | /**
228 | * [get_total_rules_active Get the total record of active rules]
229 | * @return [type] [description]
230 | */
231 |
232 | function get_total_rules_active($status=false)
233 | {
234 | global $connect;
235 | $SQL = "SELECT count(*) as TOTAL FROM `block_queue` ";
236 | if (is_numeric($status)) $SQL.=" WHERE que_processed='".$status."' ;";
237 | // echo $SQL;
238 | if (!$result = $connect->query($SQL))
239 | {
240 | die('There was an error running the query [' . $connect->error . ']');
241 | } //!$result = $connect->query( $SQL )
242 | $row = $result->fetch_assoc();
243 | return $row[TOTAL];
244 | }
245 |
246 | /**
247 | * [get_rules_db Get array with rules on DB]
248 | * @return [type] [description]
249 | */
250 |
251 | function get_rules2block_db()
252 | {
253 | global $connect;
254 | $SQL = "SELECT * FROM sigs_to_block order by sig_name ;";
255 | if (!$result = $connect->query($SQL))
256 | {
257 | die('There was an error running the query [' . $connect->error . ']');
258 | } //!$result = $connect->query( $SQL )
259 | while ($row = $result->fetch_assoc())
260 | {
261 | $array_tmp[] = $row;
262 | } //$row = $result->fetch_assoc()
263 | return $array_tmp;
264 | }
265 |
266 | /**
267 | * [check_connect_router_API check API connection ]
268 | * @return [type] [description]
269 | */
270 |
271 | function check_connect_router_API()
272 | {
273 | global $router;
274 | require ('routeros_api.php');
275 |
276 | $API = new RouterosAPI();
277 | if ($API->connect($router['ip'], $router['user'], $router['pass'])) return "OK";
278 | else return ('Unable to connect to RouterOS. Error:' . $e);
279 | $API->disconnect();
280 | }
281 |
282 | /**
283 | * [check_service_running check service running]
284 | * @param string $service [description]
285 | * @return [type] [description]
286 | */
287 |
288 | function check_service_running($service = "ids")
289 | {
290 | global $cfg;
291 | if ($service == "ids") $cmd = "suricata -c /etc/suricata/suricata.yaml";
292 | elseif ($service == "ips")
293 | if (file_exists($cfg['PID_app_file'])) return "OK";
294 | else return "NO";
295 | $cmd_exec = "ps ax | grep -v grep | grep '$cmd' | wc -l";
296 |
297 | // echo $cmd_exec;
298 |
299 | $ret = exec($cmd_exec);
300 |
301 | // return $ret;
302 |
303 | if ($ret) return "OK";
304 | else return "NO";
305 | }
306 |
307 | function obtiene_server_status()
308 | {
309 |
310 | // UPTIME
311 |
312 | $res[uptime] = shell_exec("uptime | grep -ohe 'up .*' | sed 's/,//g' | awk '{ print $2\" \"$3 }'");
313 | $res[server_uptime] = $res[uptime];
314 |
315 | // MEMORY
316 |
317 | if (false === ($str = @file("/proc/meminfo"))) return false;
318 | $str = implode("", $str);
319 | preg_match_all("/MemTotal\s{0,}\:+\s{0,}([\d\.]+).+?MemFree\s{0,}\:+\s{0,}([\d\.]+).+?Cached\s{0,}\:+\s{0,}([\d\.]+).+?SwapTotal\s{0,}\:+\s{0,}([\d\.]+).+?SwapFree\s{0,}\:+\s{0,}([\d\.]+)/s", $str, $buf);
320 | $res['memTotal'] = round($buf[1][0], 2);
321 | $res['memFree'] = round($buf[2][0], 2);
322 | $res['memCached'] = round($buf[3][0], 2);
323 | $res['memUsed'] = ($res['memTotal'] - $res['memFree']);
324 | $res['memPercent'] = (floatval($res['memTotal']) != 0) ? round($res['memUsed'] / $res['memTotal'] * 100, 2) : 0;
325 | $res['memRealUsed'] = ($res['memTotal'] - $res['memFree'] - $res['memCached']);
326 | $res['memRealPercent'] = (floatval($res['memTotal']) != 0) ? round($res['memRealUsed'] / $res['memTotal'] * 100, 2) : 0;
327 | $res['swapTotal'] = round($buf[4][0], 2);
328 | $res['swapFree'] = round($buf[5][0], 2);
329 | $res['swapUsed'] = ($res['swapTotal'] - $res['swapFree']);
330 | $res['swapPercent'] = (floatval($res['swapTotal']) != 0) ? round($res['swapUsed'] / $res['swapTotal'] * 100, 2) : 0;
331 |
332 | // LOAD AVG
333 |
334 | if (false === ($str = @file("/proc/loadavg"))) return false;
335 | $str = explode(" ", implode("", $str));
336 | $str = array_chunk($str, 4);
337 | $res['loadAvg'] = implode(" ", $str[0]);
338 | $res['memTotal'] = filesize_format($res['memTotal'] * 1024);
339 | $res['memUsed'] = filesize_format($res['memUsed'] * 1024);
340 | $res['memCached'] = filesize_format($res['memCached'] * 1024);
341 | $res['swapTotal'] = filesize_format($res['swapTotal'] * 1024, '', 'GB');
342 | $res['swapFree'] = filesize_format($res['swapFree'] * 1024);
343 | $res['swapUsed'] = filesize_format($res['swapUsed'] * 1024);
344 | return $res;
345 | }
346 |
347 | // * Format a number of bytes into a human readable format.
348 | // * Optionally choose the output format and/or force a particular unit
349 |
350 | function filesize_format($size, $level = 0, $precision = 2, $base = 1024)
351 | {
352 | $unit = array(
353 | 'B',
354 | 'kB',
355 | 'MB',
356 | 'GB',
357 | 'TB',
358 | 'PB',
359 | 'EB',
360 | 'ZB',
361 | 'YB'
362 | );
363 | $times = floor(log($size, $base));
364 | return sprintf("%." . $precision . "f", $size / pow($base, ($times + $level))) . " " . $unit[$times + $level];
365 | }
366 |
367 | // Facebook like
368 |
369 | function format_fecha($time)
370 | {
371 | if ($time !== intval($time))
372 | {
373 | $time = strtotime($time);
374 | } //$time !== intval( $time )
375 | $d = time() - $time;
376 | if ($time < strtotime(date('Y-m-d 00:00:00')) - 60 * 60 * 24 * 3)
377 | {
378 | $format = 'F j';
379 | if (date('Y') !== date('Y', $time))
380 | {
381 | $format.= ", Y";
382 | } //date( 'Y' ) !== date( 'Y', $time )
383 | return date($format, $time);
384 | } //$time < strtotime( date( 'Y-m-d 00:00:00' ) ) - 60 * 60 * 24 * 3
385 | if ($d >= 60 * 60 * 24)
386 | {
387 | $day = 'Ayer';
388 | if (date('l', time() - 60 * 60 * 24) !== date('l', $time))
389 | {
390 | $day = date('l', $time);
391 | } //date( 'l', time() - 60 * 60 * 24 ) !== date( 'l', $time )
392 | return $day . " a las " . date('g:ia', $time);
393 | } //$d >= 60 * 60 * 24
394 | if ($d >= 60 * 60 * 2)
395 | {
396 | return intval($d / (60 * 60)) . " hours ago";
397 | } //$d >= 60 * 60 * 2
398 | if ($d >= 60 * 60)
399 | {
400 | return "1 hour ago";
401 | } //$d >= 60 * 60
402 | if ($d >= 60 * 2)
403 | {
404 | return intval($d / 60) . " minutes ago";
405 | } //$d >= 60 * 2
406 | if ($d >= 60)
407 | {
408 | return "a minute ago";
409 | } //$d >= 60
410 | if ($d >= 2)
411 | {
412 | return intval($d) . " seconds";
413 | } //$d >= 2
414 | return "a few seconds ago";
415 | }
416 |
417 | function get_server_uptime()
418 | {
419 | $exec_uptime = preg_split("/[\s]+/", trim(shell_exec('uptime')));
420 | $uptime = $exec_uptime[2] . ' Days';
421 | return $uptime;
422 | }
423 |
424 | /**
425 | * [is_IPv4_IPv6 chequea si es un ipv4 o ipv6]
426 | * @param [type] $ip [description]
427 | * @return boolean [description]
428 | */
429 |
430 | function is_IPv4_IPv6($ip = NULL)
431 | {
432 | if (filter_var($ip, FILTER_VALIDATE_IP, FILTER_FLAG_IPV4))
433 | {
434 |
435 | // echo "Valid IPv4";
436 |
437 | return 4;
438 | }
439 | elseif (filter_var($ip, FILTER_VALIDATE_IP, FILTER_FLAG_IPV6))
440 | {
441 |
442 | // echo "Valid IPv6";
443 |
444 | return 6;
445 | }
446 |
447 | return false;
448 | }
449 |
450 | /**
451 | * [check_ip_in_whilelist check if ip is in whilelist]
452 | * @param [type] $ip [description]
453 | * @return [type] [description]
454 | */
455 |
456 | function check_ip_in_whilelist($ip = NULL)
457 | {
458 | global $cfg;
459 | foreach($cfg['whitelist'] as $range)
460 | {
461 | if (ip_in_range($ip, $range)) return true;
462 | }
463 |
464 | return false;
465 | }
466 |
467 | /**
468 | * Check if a given ip is in a network
469 | * @param string $ip IP to check in IPV4 format eg. 127.0.0.1
470 | * @param string $range IP/CIDR netmask eg. 127.0.0.0/24, also 127.0.0.1 is accepted and /32 assumed
471 | * @return boolean true if the ip is in this range / false if not.
472 | */
473 |
474 | function ip_in_range($ip, $range)
475 | {
476 | if (strpos($range, '/') == false)
477 | {
478 | $range.= '/32';
479 | }
480 |
481 | // $range is in IP/CIDR format eg 127.0.0.1/24
482 |
483 | list($range, $netmask) = explode('/', $range, 2);
484 | $range_decimal = ip2long($range);
485 | $ip_decimal = ip2long($ip);
486 | $wildcard_decimal = pow(2, (32 - $netmask)) - 1;
487 | $netmask_decimal = ~ $wildcard_decimal;
488 | return (($ip_decimal & $netmask_decimal) == ($range_decimal & $netmask_decimal));
489 | }
490 |
491 | /**
492 | * [json_object_to_html show json on html]
493 | * @param [type] $json_object_string [description]
494 | * @return [type] [description]
495 | */
496 |
497 | function json_object_to_html($json_object_string)
498 | {
499 | $json_object = json_decode($json_object_string);
500 | if (!is_object($json_object))
501 | {
502 | if (is_array($json_object))
503 | {
504 | $result = "[
";
505 | foreach($json_object as $json_obj)
506 | {
507 | $result.= "" . json_object_to_html(json_encode($json_obj)) . "
";
508 | if (end($json_object) != $json_obj) $result.= ",";
509 | }
510 |
511 | return $result . " ]
";
512 | }
513 | else return json_decode($json_object_string);
514 | }
515 |
516 | $result = "";
517 | foreach($json_object as $key => $value)
518 | {
519 | $str_value = json_object_to_html(json_encode($value));
520 | $result.= "$key : $str_value
";
521 | }
522 |
523 | return $result;
524 | }
525 | /**
526 | * [show_credits credits]
527 | * @return [type] [description]
528 | */
529 | function show_credits()
530 | {
531 | return '
532 |
533 | MKE Solutions
534 |
535 |
536 |
Suricata2Mikrotik CE -Community Edition- '.VERSION.'
537 |
Designed by Maximiliano Dobladez
538 |
539 |
';
540 | }
--------------------------------------------------------------------------------
/share/ssh/Crypt/RC4.php:
--------------------------------------------------------------------------------
1 |
21 | * setKey('abcdefgh');
27 | *
28 | * $size = 10 * 1024;
29 | * $plaintext = '';
30 | * for ($i = 0; $i < $size; $i++) {
31 | * $plaintext.= 'a';
32 | * }
33 | *
34 | * echo $rc4->decrypt($rc4->encrypt($plaintext));
35 | * ?>
36 | *
37 | *
38 | * LICENSE: Permission is hereby granted, free of charge, to any person obtaining a copy
39 | * of this software and associated documentation files (the "Software"), to deal
40 | * in the Software without restriction, including without limitation the rights
41 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
42 | * copies of the Software, and to permit persons to whom the Software is
43 | * furnished to do so, subject to the following conditions:
44 | *
45 | * The above copyright notice and this permission notice shall be included in
46 | * all copies or substantial portions of the Software.
47 | *
48 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
49 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
50 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
51 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
52 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
53 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
54 | * THE SOFTWARE.
55 | *
56 | * @category Crypt
57 | * @package Crypt_RC4
58 | * @author Jim Wigginton
59 | * @copyright MMVII Jim Wigginton
60 | * @license http://www.opensource.org/licenses/mit-license.html MIT License
61 | * @link http://phpseclib.sourceforge.net
62 | */
63 |
64 | /**#@+
65 | * @access private
66 | * @see Crypt_RC4::Crypt_RC4()
67 | */
68 | /**
69 | * Toggles the internal implementation
70 | */
71 | define('CRYPT_RC4_MODE_INTERNAL', 1);
72 | /**
73 | * Toggles the mcrypt implementation
74 | */
75 | define('CRYPT_RC4_MODE_MCRYPT', 2);
76 | /**#@-*/
77 |
78 | /**#@+
79 | * @access private
80 | * @see Crypt_RC4::_crypt()
81 | */
82 | define('CRYPT_RC4_ENCRYPT', 0);
83 | define('CRYPT_RC4_DECRYPT', 1);
84 | /**#@-*/
85 |
86 | /**
87 | * Pure-PHP implementation of RC4.
88 | *
89 | * @author Jim Wigginton
90 | * @version 0.1.0
91 | * @access public
92 | * @package Crypt_RC4
93 | */
94 | class Crypt_RC4 {
95 | /**
96 | * The Key
97 | *
98 | * @see Crypt_RC4::setKey()
99 | * @var String
100 | * @access private
101 | */
102 | var $key = "\0";
103 |
104 | /**
105 | * The Key Stream for encryption
106 | *
107 | * If CRYPT_RC4_MODE == CRYPT_RC4_MODE_MCRYPT, this will be equal to the mcrypt object
108 | *
109 | * @see Crypt_RC4::setKey()
110 | * @var Array
111 | * @access private
112 | */
113 | var $encryptStream = false;
114 |
115 | /**
116 | * The Key Stream for decryption
117 | *
118 | * If CRYPT_RC4_MODE == CRYPT_RC4_MODE_MCRYPT, this will be equal to the mcrypt object
119 | *
120 | * @see Crypt_RC4::setKey()
121 | * @var Array
122 | * @access private
123 | */
124 | var $decryptStream = false;
125 |
126 | /**
127 | * The $i and $j indexes for encryption
128 | *
129 | * @see Crypt_RC4::_crypt()
130 | * @var Integer
131 | * @access private
132 | */
133 | var $encryptIndex = 0;
134 |
135 | /**
136 | * The $i and $j indexes for decryption
137 | *
138 | * @see Crypt_RC4::_crypt()
139 | * @var Integer
140 | * @access private
141 | */
142 | var $decryptIndex = 0;
143 |
144 | /**
145 | * The Encryption Algorithm
146 | *
147 | * Only used if CRYPT_RC4_MODE == CRYPT_RC4_MODE_MCRYPT. Only possible values are MCRYPT_RC4 or MCRYPT_ARCFOUR.
148 | *
149 | * @see Crypt_RC4::Crypt_RC4()
150 | * @var Integer
151 | * @access private
152 | */
153 | var $mode;
154 |
155 | /**
156 | * Continuous Buffer status
157 | *
158 | * @see Crypt_RC4::enableContinuousBuffer()
159 | * @var Boolean
160 | * @access private
161 | */
162 | var $continuousBuffer = false;
163 |
164 | /**
165 | * Default Constructor.
166 | *
167 | * Determines whether or not the mcrypt extension should be used.
168 | *
169 | * @return Crypt_RC4
170 | * @access public
171 | */
172 | function Crypt_RC4()
173 | {
174 | if ( !defined('CRYPT_RC4_MODE') ) {
175 | switch (true) {
176 | case extension_loaded('mcrypt') && (defined('MCRYPT_ARCFOUR') || defined('MCRYPT_RC4')) && in_array('arcfour', mcrypt_list_algorithms()):
177 | define('CRYPT_RC4_MODE', CRYPT_RC4_MODE_MCRYPT);
178 | break;
179 | default:
180 | define('CRYPT_RC4_MODE', CRYPT_RC4_MODE_INTERNAL);
181 | }
182 | }
183 |
184 | switch ( CRYPT_RC4_MODE ) {
185 | case CRYPT_RC4_MODE_MCRYPT:
186 | switch (true) {
187 | case defined('MCRYPT_ARCFOUR'):
188 | $this->mode = MCRYPT_ARCFOUR;
189 | break;
190 | case defined('MCRYPT_RC4');
191 | $this->mode = MCRYPT_RC4;
192 | }
193 | $this->encryptStream = mcrypt_module_open($this->mode, '', MCRYPT_MODE_STREAM, '');
194 | $this->decryptStream = mcrypt_module_open($this->mode, '', MCRYPT_MODE_STREAM, '');
195 |
196 | }
197 | }
198 |
199 | /**
200 | * Sets the key.
201 | *
202 | * Keys can be between 1 and 256 bytes long. If they are longer then 256 bytes, the first 256 bytes will
203 | * be used. If no key is explicitly set, it'll be assumed to be a single null byte.
204 | *
205 | * @access public
206 | * @param String $key
207 | */
208 | function setKey($key)
209 | {
210 | $this->key = $key;
211 |
212 | if ( CRYPT_RC4_MODE == CRYPT_RC4_MODE_MCRYPT ) {
213 | mcrypt_generic_init($this->encryptStream, $this->key, '');
214 | mcrypt_generic_init($this->decryptStream, $this->key, '');
215 | return;
216 | }
217 |
218 | $keyLength = strlen($key);
219 | $keyStream = array();
220 | for ($i = 0; $i < 256; $i++) {
221 | $keyStream[$i] = $i;
222 | }
223 | $j = 0;
224 | for ($i = 0; $i < 256; $i++) {
225 | $j = ($j + $keyStream[$i] + ord($key[$i % $keyLength])) & 255;
226 | $temp = $keyStream[$i];
227 | $keyStream[$i] = $keyStream[$j];
228 | $keyStream[$j] = $temp;
229 | }
230 |
231 | $this->encryptIndex = $this->decryptIndex = array(0, 0);
232 | $this->encryptStream = $this->decryptStream = $keyStream;
233 | }
234 |
235 | /**
236 | * Sets the password.
237 | *
238 | * Depending on what $method is set to, setPassword()'s (optional) parameters are as follows:
239 | * {@link http://en.wikipedia.org/wiki/PBKDF2 pbkdf2}:
240 | * $hash, $salt, $count, $dkLen
241 | *
242 | * @param String $password
243 | * @param optional String $method
244 | * @access public
245 | */
246 | function setPassword($password, $method = 'pbkdf2')
247 | {
248 | $key = '';
249 |
250 | switch ($method) {
251 | default: // 'pbkdf2'
252 | list(, , $hash, $salt, $count) = func_get_args();
253 | if (!isset($hash)) {
254 | $hash = 'sha1';
255 | }
256 | // WPA and WPA2 use the SSID as the salt
257 | if (!isset($salt)) {
258 | $salt = 'phpseclib/salt';
259 | }
260 | // RFC2898#section-4.2 uses 1,000 iterations by default
261 | // WPA and WPA2 use 4,096.
262 | if (!isset($count)) {
263 | $count = 1000;
264 | }
265 | if (!isset($dkLen)) {
266 | $dkLen = 128;
267 | }
268 |
269 | if (!class_exists('Crypt_Hash')) {
270 | require_once('Crypt/Hash.php');
271 | }
272 |
273 | $i = 1;
274 | while (strlen($key) < $dkLen) {
275 | //$dk.= $this->_pbkdf($password, $salt, $count, $i++);
276 | $hmac = new Crypt_Hash();
277 | $hmac->setHash($hash);
278 | $hmac->setKey($password);
279 | $f = $u = $hmac->hash($salt . pack('N', $i++));
280 | for ($j = 2; $j <= $count; $j++) {
281 | $u = $hmac->hash($u);
282 | $f^= $u;
283 | }
284 | $key.= $f;
285 | }
286 | }
287 |
288 | $this->setKey(substr($key, 0, $dkLen));
289 | }
290 |
291 | /**
292 | * Dummy function.
293 | *
294 | * Some protocols, such as WEP, prepend an "initialization vector" to the key, effectively creating a new key [1].
295 | * If you need to use an initialization vector in this manner, feel free to prepend it to the key, yourself, before
296 | * calling setKey().
297 | *
298 | * [1] WEP's initialization vectors (IV's) are used in a somewhat insecure way. Since, in that protocol,
299 | * the IV's are relatively easy to predict, an attack described by
300 | * {@link http://www.drizzle.com/~aboba/IEEE/rc4_ksaproc.pdf Scott Fluhrer, Itsik Mantin, and Adi Shamir}
301 | * can be used to quickly guess at the rest of the key. The following links elaborate:
302 | *
303 | * {@link http://www.rsa.com/rsalabs/node.asp?id=2009 http://www.rsa.com/rsalabs/node.asp?id=2009}
304 | * {@link http://en.wikipedia.org/wiki/Related_key_attack http://en.wikipedia.org/wiki/Related_key_attack}
305 | *
306 | * @param String $iv
307 | * @see Crypt_RC4::setKey()
308 | * @access public
309 | */
310 | function setIV($iv)
311 | {
312 | }
313 |
314 | /**
315 | * Encrypts a message.
316 | *
317 | * @see Crypt_RC4::_crypt()
318 | * @access public
319 | * @param String $plaintext
320 | */
321 | function encrypt($plaintext)
322 | {
323 | return $this->_crypt($plaintext, CRYPT_RC4_ENCRYPT);
324 | }
325 |
326 | /**
327 | * Decrypts a message.
328 | *
329 | * $this->decrypt($this->encrypt($plaintext)) == $this->encrypt($this->encrypt($plaintext)).
330 | * Atleast if the continuous buffer is disabled.
331 | *
332 | * @see Crypt_RC4::_crypt()
333 | * @access public
334 | * @param String $ciphertext
335 | */
336 | function decrypt($ciphertext)
337 | {
338 | return $this->_crypt($ciphertext, CRYPT_RC4_DECRYPT);
339 | }
340 |
341 | /**
342 | * Encrypts or decrypts a message.
343 | *
344 | * @see Crypt_RC4::encrypt()
345 | * @see Crypt_RC4::decrypt()
346 | * @access private
347 | * @param String $text
348 | * @param Integer $mode
349 | */
350 | function _crypt($text, $mode)
351 | {
352 | if ( CRYPT_RC4_MODE == CRYPT_RC4_MODE_MCRYPT ) {
353 | $keyStream = $mode == CRYPT_RC4_ENCRYPT ? 'encryptStream' : 'decryptStream';
354 |
355 | if (!$this->continuousBuffer) {
356 | mcrypt_generic_init($this->$keyStream, $this->key, '');
357 | }
358 |
359 | return mcrypt_generic($this->$keyStream, $text);
360 | }
361 |
362 | if ($this->encryptStream === false) {
363 | $this->setKey($this->key);
364 | }
365 |
366 | switch ($mode) {
367 | case CRYPT_RC4_ENCRYPT:
368 | $keyStream = $this->encryptStream;
369 | list($i, $j) = $this->encryptIndex;
370 | break;
371 | case CRYPT_RC4_DECRYPT:
372 | $keyStream = $this->decryptStream;
373 | list($i, $j) = $this->decryptIndex;
374 | }
375 |
376 | $newText = '';
377 | for ($k = 0; $k < strlen($text); $k++) {
378 | $i = ($i + 1) & 255;
379 | $j = ($j + $keyStream[$i]) & 255;
380 | $temp = $keyStream[$i];
381 | $keyStream[$i] = $keyStream[$j];
382 | $keyStream[$j] = $temp;
383 | $temp = $keyStream[($keyStream[$i] + $keyStream[$j]) & 255];
384 | $newText.= chr(ord($text[$k]) ^ $temp);
385 | }
386 |
387 | if ($this->continuousBuffer) {
388 | switch ($mode) {
389 | case CRYPT_RC4_ENCRYPT:
390 | $this->encryptStream = $keyStream;
391 | $this->encryptIndex = array($i, $j);
392 | break;
393 | case CRYPT_RC4_DECRYPT:
394 | $this->decryptStream = $keyStream;
395 | $this->decryptIndex = array($i, $j);
396 | }
397 | }
398 |
399 | return $newText;
400 | }
401 |
402 | /**
403 | * Treat consecutive "packets" as if they are a continuous buffer.
404 | *
405 | * Say you have a 16-byte plaintext $plaintext. Using the default behavior, the two following code snippets
406 | * will yield different outputs:
407 | *
408 | *
409 | * echo $rc4->encrypt(substr($plaintext, 0, 8));
410 | * echo $rc4->encrypt(substr($plaintext, 8, 8));
411 | *
412 | *
413 | * echo $rc4->encrypt($plaintext);
414 | *
415 | *
416 | * The solution is to enable the continuous buffer. Although this will resolve the above discrepancy, it creates
417 | * another, as demonstrated with the following:
418 | *
419 | *
420 | * $rc4->encrypt(substr($plaintext, 0, 8));
421 | * echo $rc4->decrypt($des->encrypt(substr($plaintext, 8, 8)));
422 | *
423 | *
424 | * echo $rc4->decrypt($des->encrypt(substr($plaintext, 8, 8)));
425 | *
426 | *
427 | * With the continuous buffer disabled, these would yield the same output. With it enabled, they yield different
428 | * outputs. The reason is due to the fact that the initialization vector's change after every encryption /
429 | * decryption round when the continuous buffer is enabled. When it's disabled, they remain constant.
430 | *
431 | * Put another way, when the continuous buffer is enabled, the state of the Crypt_DES() object changes after each
432 | * encryption / decryption round, whereas otherwise, it'd remain constant. For this reason, it's recommended that
433 | * continuous buffers not be used. They do offer better security and are, in fact, sometimes required (SSH uses them),
434 | * however, they are also less intuitive and more likely to cause you problems.
435 | *
436 | * @see Crypt_RC4::disableContinuousBuffer()
437 | * @access public
438 | */
439 | function enableContinuousBuffer()
440 | {
441 | if ( CRYPT_RC4_MODE == CRYPT_RC4_MODE_MCRYPT ) {
442 | mcrypt_generic_init($this->encryptStream, $this->key, '');
443 | mcrypt_generic_init($this->decryptStream, $this->key, '');
444 | }
445 |
446 | $this->continuousBuffer = true;
447 | }
448 |
449 | /**
450 | * Treat consecutive packets as if they are a discontinuous buffer.
451 | *
452 | * The default behavior.
453 | *
454 | * @see Crypt_RC4::enableContinuousBuffer()
455 | * @access public
456 | */
457 | function disableContinuousBuffer()
458 | {
459 | if ( CRYPT_RC4_MODE == CRYPT_RC4_MODE_INTERNAL ) {
460 | $this->encryptIndex = $this->decryptIndex = array(0, 0);
461 | $this->encryptStream = $this->decryptStream = false;
462 | }
463 |
464 | $this->continuousBuffer = false;
465 | }
466 |
467 | /**
468 | * Dummy function.
469 | *
470 | * Since RC4 is a stream cipher and not a block cipher, no padding is necessary. The only reason this function is
471 | * included is so that you can switch between a block cipher and a stream cipher transparently.
472 | *
473 | * @see Crypt_RC4::disablePadding()
474 | * @access public
475 | */
476 | function enablePadding()
477 | {
478 | }
479 |
480 | /**
481 | * Dummy function.
482 | *
483 | * @see Crypt_RC4::enablePadding()
484 | * @access public
485 | */
486 | function disablePadding()
487 | {
488 | }
489 | }
490 |
491 | // vim: ts=4:sw=4:et:
492 | // vim6: fdl=1:
493 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | GNU GENERAL PUBLIC LICENSE
2 | Version 2, June 1991
3 |
4 | Copyright (C) 1989, 1991 Free Software Foundation, Inc.,
5 | 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
6 | Everyone is permitted to copy and distribute verbatim copies
7 | of this license document, but changing it is not allowed.
8 |
9 | Preamble
10 |
11 | The licenses for most software are designed to take away your
12 | freedom to share and change it. By contrast, the GNU General Public
13 | License is intended to guarantee your freedom to share and change free
14 | software--to make sure the software is free for all its users. This
15 | General Public License applies to most of the Free Software
16 | Foundation's software and to any other program whose authors commit to
17 | using it. (Some other Free Software Foundation software is covered by
18 | the GNU Lesser General Public License instead.) You can apply it to
19 | your programs, too.
20 |
21 | When we speak of free software, we are referring to freedom, not
22 | price. Our General Public Licenses are designed to make sure that you
23 | have the freedom to distribute copies of free software (and charge for
24 | this service if you wish), that you receive source code or can get it
25 | if you want it, that you can change the software or use pieces of it
26 | in new free programs; and that you know you can do these things.
27 |
28 | To protect your rights, we need to make restrictions that forbid
29 | anyone to deny you these rights or to ask you to surrender the rights.
30 | These restrictions translate to certain responsibilities for you if you
31 | distribute copies of the software, or if you modify it.
32 |
33 | For example, if you distribute copies of such a program, whether
34 | gratis or for a fee, you must give the recipients all the rights that
35 | you have. You must make sure that they, too, receive or can get the
36 | source code. And you must show them these terms so they know their
37 | rights.
38 |
39 | We protect your rights with two steps: (1) copyright the software, and
40 | (2) offer you this license which gives you legal permission to copy,
41 | distribute and/or modify the software.
42 |
43 | Also, for each author's protection and ours, we want to make certain
44 | that everyone understands that there is no warranty for this free
45 | software. If the software is modified by someone else and passed on, we
46 | want its recipients to know that what they have is not the original, so
47 | that any problems introduced by others will not reflect on the original
48 | authors' reputations.
49 |
50 | Finally, any free program is threatened constantly by software
51 | patents. We wish to avoid the danger that redistributors of a free
52 | program will individually obtain patent licenses, in effect making the
53 | program proprietary. To prevent this, we have made it clear that any
54 | patent must be licensed for everyone's free use or not licensed at all.
55 |
56 | The precise terms and conditions for copying, distribution and
57 | modification follow.
58 |
59 | GNU GENERAL PUBLIC LICENSE
60 | TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
61 |
62 | 0. This License applies to any program or other work which contains
63 | a notice placed by the copyright holder saying it may be distributed
64 | under the terms of this General Public License. The "Program", below,
65 | refers to any such program or work, and a "work based on the Program"
66 | means either the Program or any derivative work under copyright law:
67 | that is to say, a work containing the Program or a portion of it,
68 | either verbatim or with modifications and/or translated into another
69 | language. (Hereinafter, translation is included without limitation in
70 | the term "modification".) Each licensee is addressed as "you".
71 |
72 | Activities other than copying, distribution and modification are not
73 | covered by this License; they are outside its scope. The act of
74 | running the Program is not restricted, and the output from the Program
75 | is covered only if its contents constitute a work based on the
76 | Program (independent of having been made by running the Program).
77 | Whether that is true depends on what the Program does.
78 |
79 | 1. You may copy and distribute verbatim copies of the Program's
80 | source code as you receive it, in any medium, provided that you
81 | conspicuously and appropriately publish on each copy an appropriate
82 | copyright notice and disclaimer of warranty; keep intact all the
83 | notices that refer to this License and to the absence of any warranty;
84 | and give any other recipients of the Program a copy of this License
85 | along with the Program.
86 |
87 | You may charge a fee for the physical act of transferring a copy, and
88 | you may at your option offer warranty protection in exchange for a fee.
89 |
90 | 2. You may modify your copy or copies of the Program or any portion
91 | of it, thus forming a work based on the Program, and copy and
92 | distribute such modifications or work under the terms of Section 1
93 | above, provided that you also meet all of these conditions:
94 |
95 | a) You must cause the modified files to carry prominent notices
96 | stating that you changed the files and the date of any change.
97 |
98 | b) You must cause any work that you distribute or publish, that in
99 | whole or in part contains or is derived from the Program or any
100 | part thereof, to be licensed as a whole at no charge to all third
101 | parties under the terms of this License.
102 |
103 | c) If the modified program normally reads commands interactively
104 | when run, you must cause it, when started running for such
105 | interactive use in the most ordinary way, to print or display an
106 | announcement including an appropriate copyright notice and a
107 | notice that there is no warranty (or else, saying that you provide
108 | a warranty) and that users may redistribute the program under
109 | these conditions, and telling the user how to view a copy of this
110 | License. (Exception: if the Program itself is interactive but
111 | does not normally print such an announcement, your work based on
112 | the Program is not required to print an announcement.)
113 |
114 | These requirements apply to the modified work as a whole. If
115 | identifiable sections of that work are not derived from the Program,
116 | and can be reasonably considered independent and separate works in
117 | themselves, then this License, and its terms, do not apply to those
118 | sections when you distribute them as separate works. But when you
119 | distribute the same sections as part of a whole which is a work based
120 | on the Program, the distribution of the whole must be on the terms of
121 | this License, whose permissions for other licensees extend to the
122 | entire whole, and thus to each and every part regardless of who wrote it.
123 |
124 | Thus, it is not the intent of this section to claim rights or contest
125 | your rights to work written entirely by you; rather, the intent is to
126 | exercise the right to control the distribution of derivative or
127 | collective works based on the Program.
128 |
129 | In addition, mere aggregation of another work not based on the Program
130 | with the Program (or with a work based on the Program) on a volume of
131 | a storage or distribution medium does not bring the other work under
132 | the scope of this License.
133 |
134 | 3. You may copy and distribute the Program (or a work based on it,
135 | under Section 2) in object code or executable form under the terms of
136 | Sections 1 and 2 above provided that you also do one of the following:
137 |
138 | a) Accompany it with the complete corresponding machine-readable
139 | source code, which must be distributed under the terms of Sections
140 | 1 and 2 above on a medium customarily used for software interchange; or,
141 |
142 | b) Accompany it with a written offer, valid for at least three
143 | years, to give any third party, for a charge no more than your
144 | cost of physically performing source distribution, a complete
145 | machine-readable copy of the corresponding source code, to be
146 | distributed under the terms of Sections 1 and 2 above on a medium
147 | customarily used for software interchange; or,
148 |
149 | c) Accompany it with the information you received as to the offer
150 | to distribute corresponding source code. (This alternative is
151 | allowed only for noncommercial distribution and only if you
152 | received the program in object code or executable form with such
153 | an offer, in accord with Subsection b above.)
154 |
155 | The source code for a work means the preferred form of the work for
156 | making modifications to it. For an executable work, complete source
157 | code means all the source code for all modules it contains, plus any
158 | associated interface definition files, plus the scripts used to
159 | control compilation and installation of the executable. However, as a
160 | special exception, the source code distributed need not include
161 | anything that is normally distributed (in either source or binary
162 | form) with the major components (compiler, kernel, and so on) of the
163 | operating system on which the executable runs, unless that component
164 | itself accompanies the executable.
165 |
166 | If distribution of executable or object code is made by offering
167 | access to copy from a designated place, then offering equivalent
168 | access to copy the source code from the same place counts as
169 | distribution of the source code, even though third parties are not
170 | compelled to copy the source along with the object code.
171 |
172 | 4. You may not copy, modify, sublicense, or distribute the Program
173 | except as expressly provided under this License. Any attempt
174 | otherwise to copy, modify, sublicense or distribute the Program is
175 | void, and will automatically terminate your rights under this License.
176 | However, parties who have received copies, or rights, from you under
177 | this License will not have their licenses terminated so long as such
178 | parties remain in full compliance.
179 |
180 | 5. You are not required to accept this License, since you have not
181 | signed it. However, nothing else grants you permission to modify or
182 | distribute the Program or its derivative works. These actions are
183 | prohibited by law if you do not accept this License. Therefore, by
184 | modifying or distributing the Program (or any work based on the
185 | Program), you indicate your acceptance of this License to do so, and
186 | all its terms and conditions for copying, distributing or modifying
187 | the Program or works based on it.
188 |
189 | 6. Each time you redistribute the Program (or any work based on the
190 | Program), the recipient automatically receives a license from the
191 | original licensor to copy, distribute or modify the Program subject to
192 | these terms and conditions. You may not impose any further
193 | restrictions on the recipients' exercise of the rights granted herein.
194 | You are not responsible for enforcing compliance by third parties to
195 | this License.
196 |
197 | 7. If, as a consequence of a court judgment or allegation of patent
198 | infringement or for any other reason (not limited to patent issues),
199 | conditions are imposed on you (whether by court order, agreement or
200 | otherwise) that contradict the conditions of this License, they do not
201 | excuse you from the conditions of this License. If you cannot
202 | distribute so as to satisfy simultaneously your obligations under this
203 | License and any other pertinent obligations, then as a consequence you
204 | may not distribute the Program at all. For example, if a patent
205 | license would not permit royalty-free redistribution of the Program by
206 | all those who receive copies directly or indirectly through you, then
207 | the only way you could satisfy both it and this License would be to
208 | refrain entirely from distribution of the Program.
209 |
210 | If any portion of this section is held invalid or unenforceable under
211 | any particular circumstance, the balance of the section is intended to
212 | apply and the section as a whole is intended to apply in other
213 | circumstances.
214 |
215 | It is not the purpose of this section to induce you to infringe any
216 | patents or other property right claims or to contest validity of any
217 | such claims; this section has the sole purpose of protecting the
218 | integrity of the free software distribution system, which is
219 | implemented by public license practices. Many people have made
220 | generous contributions to the wide range of software distributed
221 | through that system in reliance on consistent application of that
222 | system; it is up to the author/donor to decide if he or she is willing
223 | to distribute software through any other system and a licensee cannot
224 | impose that choice.
225 |
226 | This section is intended to make thoroughly clear what is believed to
227 | be a consequence of the rest of this License.
228 |
229 | 8. If the distribution and/or use of the Program is restricted in
230 | certain countries either by patents or by copyrighted interfaces, the
231 | original copyright holder who places the Program under this License
232 | may add an explicit geographical distribution limitation excluding
233 | those countries, so that distribution is permitted only in or among
234 | countries not thus excluded. In such case, this License incorporates
235 | the limitation as if written in the body of this License.
236 |
237 | 9. The Free Software Foundation may publish revised and/or new versions
238 | of the General Public License from time to time. Such new versions will
239 | be similar in spirit to the present version, but may differ in detail to
240 | address new problems or concerns.
241 |
242 | Each version is given a distinguishing version number. If the Program
243 | specifies a version number of this License which applies to it and "any
244 | later version", you have the option of following the terms and conditions
245 | either of that version or of any later version published by the Free
246 | Software Foundation. If the Program does not specify a version number of
247 | this License, you may choose any version ever published by the Free Software
248 | Foundation.
249 |
250 | 10. If you wish to incorporate parts of the Program into other free
251 | programs whose distribution conditions are different, write to the author
252 | to ask for permission. For software which is copyrighted by the Free
253 | Software Foundation, write to the Free Software Foundation; we sometimes
254 | make exceptions for this. Our decision will be guided by the two goals
255 | of preserving the free status of all derivatives of our free software and
256 | of promoting the sharing and reuse of software generally.
257 |
258 | NO WARRANTY
259 |
260 | 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
261 | FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
262 | OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
263 | PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
264 | OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
265 | MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS
266 | TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE
267 | PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
268 | REPAIR OR CORRECTION.
269 |
270 | 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
271 | WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
272 | REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
273 | INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
274 | OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
275 | TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
276 | YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
277 | PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
278 | POSSIBILITY OF SUCH DAMAGES.
279 |
280 | END OF TERMS AND CONDITIONS
281 |
282 | How to Apply These Terms to Your New Programs
283 |
284 | If you develop a new program, and you want it to be of the greatest
285 | possible use to the public, the best way to achieve this is to make it
286 | free software which everyone can redistribute and change under these terms.
287 |
288 | To do so, attach the following notices to the program. It is safest
289 | to attach them to the start of each source file to most effectively
290 | convey the exclusion of warranty; and each file should have at least
291 | the "copyright" line and a pointer to where the full notice is found.
292 |
293 |
294 | Copyright (C)
295 |
296 | This program is free software; you can redistribute it and/or modify
297 | it under the terms of the GNU General Public License as published by
298 | the Free Software Foundation; either version 2 of the License, or
299 | (at your option) any later version.
300 |
301 | This program is distributed in the hope that it will be useful,
302 | but WITHOUT ANY WARRANTY; without even the implied warranty of
303 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
304 | GNU General Public License for more details.
305 |
306 | You should have received a copy of the GNU General Public License along
307 | with this program; if not, write to the Free Software Foundation, Inc.,
308 | 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
309 |
310 | Also add information on how to contact you by electronic and paper mail.
311 |
312 | If the program is interactive, make it output a short notice like this
313 | when it starts in an interactive mode:
314 |
315 | Gnomovision version 69, Copyright (C) year name of author
316 | Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
317 | This is free software, and you are welcome to redistribute it
318 | under certain conditions; type `show c' for details.
319 |
320 | The hypothetical commands `show w' and `show c' should show the appropriate
321 | parts of the General Public License. Of course, the commands you use may
322 | be called something other than `show w' and `show c'; they could even be
323 | mouse-clicks or menu items--whatever suits your program.
324 |
325 | You should also get your employer (if you work as a programmer) or your
326 | school, if any, to sign a "copyright disclaimer" for the program, if
327 | necessary. Here is a sample; alter the names:
328 |
329 | Yoyodyne, Inc., hereby disclaims all copyright interest in the program
330 | `Gnomovision' (which makes passes at compilers) written by James Hacker.
331 |
332 | , 1 April 1989
333 | Ty Coon, President of Vice
334 |
335 | This General Public License does not permit incorporating your program into
336 | proprietary programs. If your program is a subroutine library, you may
337 | consider it more useful to permit linking proprietary applications with the
338 | library. If this is what you want to do, use the GNU Lesser General
339 | Public License instead of this License.
340 |
--------------------------------------------------------------------------------
/share/ssh/Crypt/AES.php:
--------------------------------------------------------------------------------
1 |
22 | * setKey('abcdefghijklmnop');
28 | *
29 | * $size = 10 * 1024;
30 | * $plaintext = '';
31 | * for ($i = 0; $i < $size; $i++) {
32 | * $plaintext.= 'a';
33 | * }
34 | *
35 | * echo $aes->decrypt($aes->encrypt($plaintext));
36 | * ?>
37 | *
38 | *
39 | * LICENSE: Permission is hereby granted, free of charge, to any person obtaining a copy
40 | * of this software and associated documentation files (the "Software"), to deal
41 | * in the Software without restriction, including without limitation the rights
42 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
43 | * copies of the Software, and to permit persons to whom the Software is
44 | * furnished to do so, subject to the following conditions:
45 | *
46 | * The above copyright notice and this permission notice shall be included in
47 | * all copies or substantial portions of the Software.
48 | *
49 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
50 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
51 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
52 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
53 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
54 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
55 | * THE SOFTWARE.
56 | *
57 | * @category Crypt
58 | * @package Crypt_AES
59 | * @author Jim Wigginton
60 | * @copyright MMVIII Jim Wigginton
61 | * @license http://www.opensource.org/licenses/mit-license.html MIT License
62 | * @link http://phpseclib.sourceforge.net
63 | */
64 |
65 | /**
66 | * Include Crypt_Rijndael
67 | */
68 | if (!class_exists('Crypt_Rijndael')) {
69 | require_once 'Rijndael.php';
70 | }
71 |
72 | /**#@+
73 | * @access public
74 | * @see Crypt_AES::encrypt()
75 | * @see Crypt_AES::decrypt()
76 | */
77 | /**
78 | * Encrypt / decrypt using the Counter mode.
79 | *
80 | * Set to -1 since that's what Crypt/Random.php uses to index the CTR mode.
81 | *
82 | * @link http://en.wikipedia.org/wiki/Block_cipher_modes_of_operation#Counter_.28CTR.29
83 | */
84 | define('CRYPT_AES_MODE_CTR', -1);
85 | /**
86 | * Encrypt / decrypt using the Electronic Code Book mode.
87 | *
88 | * @link http://en.wikipedia.org/wiki/Block_cipher_modes_of_operation#Electronic_codebook_.28ECB.29
89 | */
90 | define('CRYPT_AES_MODE_ECB', 1);
91 | /**
92 | * Encrypt / decrypt using the Code Book Chaining mode.
93 | *
94 | * @link http://en.wikipedia.org/wiki/Block_cipher_modes_of_operation#Cipher-block_chaining_.28CBC.29
95 | */
96 | define('CRYPT_AES_MODE_CBC', 2);
97 | /**
98 | * Encrypt / decrypt using the Cipher Feedback mode.
99 | *
100 | * @link http://en.wikipedia.org/wiki/Block_cipher_modes_of_operation#Cipher_feedback_.28CFB.29
101 | */
102 | define('CRYPT_AES_MODE_CFB', 3);
103 | /**
104 | * Encrypt / decrypt using the Cipher Feedback mode.
105 | *
106 | * @link http://en.wikipedia.org/wiki/Block_cipher_modes_of_operation#Output_feedback_.28OFB.29
107 | */
108 | define('CRYPT_AES_MODE_OFB', 4);
109 | /**#@-*/
110 |
111 | /**#@+
112 | * @access private
113 | * @see Crypt_AES::Crypt_AES()
114 | */
115 | /**
116 | * Toggles the internal implementation
117 | */
118 | define('CRYPT_AES_MODE_INTERNAL', 1);
119 | /**
120 | * Toggles the mcrypt implementation
121 | */
122 | define('CRYPT_AES_MODE_MCRYPT', 2);
123 | /**#@-*/
124 |
125 | /**
126 | * Pure-PHP implementation of AES.
127 | *
128 | * @author Jim Wigginton
129 | * @version 0.1.0
130 | * @access public
131 | * @package Crypt_AES
132 | */
133 | class Crypt_AES extends Crypt_Rijndael {
134 | /**
135 | * mcrypt resource for encryption
136 | *
137 | * The mcrypt resource can be recreated every time something needs to be created or it can be created just once.
138 | * Since mcrypt operates in continuous mode, by default, it'll need to be recreated when in non-continuous mode.
139 | *
140 | * @see Crypt_AES::encrypt()
141 | * @var String
142 | * @access private
143 | */
144 | var $enmcrypt;
145 |
146 | /**
147 | * mcrypt resource for decryption
148 | *
149 | * The mcrypt resource can be recreated every time something needs to be created or it can be created just once.
150 | * Since mcrypt operates in continuous mode, by default, it'll need to be recreated when in non-continuous mode.
151 | *
152 | * @see Crypt_AES::decrypt()
153 | * @var String
154 | * @access private
155 | */
156 | var $demcrypt;
157 |
158 | /**
159 | * mcrypt resource for CFB mode
160 | *
161 | * @see Crypt_AES::encrypt()
162 | * @see Crypt_AES::decrypt()
163 | * @var String
164 | * @access private
165 | */
166 | var $ecb;
167 |
168 | /**
169 | * Default Constructor.
170 | *
171 | * Determines whether or not the mcrypt extension should be used. $mode should only, at present, be
172 | * CRYPT_AES_MODE_ECB or CRYPT_AES_MODE_CBC. If not explictly set, CRYPT_AES_MODE_CBC will be used.
173 | *
174 | * @param optional Integer $mode
175 | * @return Crypt_AES
176 | * @access public
177 | */
178 | function Crypt_AES($mode = CRYPT_AES_MODE_CBC)
179 | {
180 | if ( !defined('CRYPT_AES_MODE') ) {
181 | switch (true) {
182 | case extension_loaded('mcrypt') && in_array('rijndael-128', mcrypt_list_algorithms()):
183 | define('CRYPT_AES_MODE', CRYPT_AES_MODE_MCRYPT);
184 | break;
185 | default:
186 | define('CRYPT_AES_MODE', CRYPT_AES_MODE_INTERNAL);
187 | }
188 | }
189 |
190 | switch ( CRYPT_AES_MODE ) {
191 | case CRYPT_AES_MODE_MCRYPT:
192 | switch ($mode) {
193 | case CRYPT_AES_MODE_ECB:
194 | $this->paddable = true;
195 | $this->mode = MCRYPT_MODE_ECB;
196 | break;
197 | case CRYPT_AES_MODE_CTR:
198 | // ctr doesn't have a constant associated with it even though it appears to be fairly widely
199 | // supported. in lieu of knowing just how widely supported it is, i've, for now, opted not to
200 | // include a compatibility layer. the layer has been implemented but, for now, is commented out.
201 | $this->mode = 'ctr';
202 | //$this->mode = in_array('ctr', mcrypt_list_modes()) ? 'ctr' : CRYPT_AES_MODE_CTR;
203 | break;
204 | case CRYPT_AES_MODE_CFB:
205 | $this->mode = 'ncfb';
206 | break;
207 | case CRYPT_AES_MODE_OFB:
208 | $this->mode = MCRYPT_MODE_NOFB;
209 | break;
210 | case CRYPT_AES_MODE_CBC:
211 | default:
212 | $this->paddable = true;
213 | $this->mode = MCRYPT_MODE_CBC;
214 | }
215 |
216 | break;
217 | default:
218 | switch ($mode) {
219 | case CRYPT_AES_MODE_ECB:
220 | $this->paddable = true;
221 | $this->mode = CRYPT_RIJNDAEL_MODE_ECB;
222 | break;
223 | case CRYPT_AES_MODE_CTR:
224 | $this->mode = CRYPT_RIJNDAEL_MODE_CTR;
225 | break;
226 | case CRYPT_AES_MODE_CFB:
227 | $this->mode = CRYPT_RIJNDAEL_MODE_CFB;
228 | break;
229 | case CRYPT_AES_MODE_OFB:
230 | $this->mode = CRYPT_RIJNDAEL_MODE_OFB;
231 | break;
232 | case CRYPT_AES_MODE_CBC:
233 | default:
234 | $this->paddable = true;
235 | $this->mode = CRYPT_RIJNDAEL_MODE_CBC;
236 | }
237 | }
238 |
239 | if (CRYPT_AES_MODE == CRYPT_AES_MODE_INTERNAL) {
240 | parent::Crypt_Rijndael($this->mode);
241 | }
242 |
243 | }
244 |
245 | /**
246 | * Dummy function
247 | *
248 | * Since Crypt_AES extends Crypt_Rijndael, this function is, technically, available, but it doesn't do anything.
249 | *
250 | * @access public
251 | * @param Integer $length
252 | */
253 | function setBlockLength($length)
254 | {
255 | return;
256 | }
257 |
258 | /**
259 | * Sets the initialization vector. (optional)
260 | *
261 | * SetIV is not required when CRYPT_RIJNDAEL_MODE_ECB is being used. If not explictly set, it'll be assumed
262 | * to be all zero's.
263 | *
264 | * @access public
265 | * @param String $iv
266 | */
267 | function setIV($iv)
268 | {
269 | parent::setIV($iv);
270 | if ( CRYPT_AES_MODE == CRYPT_AES_MODE_MCRYPT ) {
271 | $this->changed = true;
272 | }
273 | }
274 |
275 | /**
276 | * Encrypts a message.
277 | *
278 | * $plaintext will be padded with up to 16 additional bytes. Other AES implementations may or may not pad in the
279 | * same manner. Other common approaches to padding and the reasons why it's necessary are discussed in the following
280 | * URL:
281 | *
282 | * {@link http://www.di-mgt.com.au/cryptopad.html http://www.di-mgt.com.au/cryptopad.html}
283 | *
284 | * An alternative to padding is to, separately, send the length of the file. This is what SSH, in fact, does.
285 | * strlen($plaintext) will still need to be a multiple of 16, however, arbitrary values can be added to make it that
286 | * length.
287 | *
288 | * @see Crypt_AES::decrypt()
289 | * @access public
290 | * @param String $plaintext
291 | */
292 | function encrypt($plaintext)
293 | {
294 | if ( CRYPT_AES_MODE == CRYPT_AES_MODE_MCRYPT ) {
295 | $this->_mcryptSetup();
296 |
297 | // re: http://phpseclib.sourceforge.net/cfb-demo.phps
298 | // using mcrypt's default handing of CFB the above would output two different things. using phpseclib's
299 | // rewritten CFB implementation the above outputs the same thing twice.
300 | if ($this->mode == 'ncfb' && $this->continuousBuffer) {
301 | $iv = &$this->encryptIV;
302 | $pos = &$this->enbuffer['pos'];
303 | $len = strlen($plaintext);
304 | $ciphertext = '';
305 | $i = 0;
306 | if ($pos) {
307 | $orig_pos = $pos;
308 | $max = 16 - $pos;
309 | if ($len >= $max) {
310 | $i = $max;
311 | $len-= $max;
312 | $pos = 0;
313 | } else {
314 | $i = $len;
315 | $pos+= $len;
316 | $len = 0;
317 | }
318 | $ciphertext = substr($iv, $orig_pos) ^ $plaintext;
319 | $iv = substr_replace($iv, $ciphertext, $orig_pos, $i);
320 | $this->enbuffer['enmcrypt_init'] = true;
321 | }
322 | if ($len >= 16) {
323 | if ($this->enbuffer['enmcrypt_init'] === false || $len > 280) {
324 | if ($this->enbuffer['enmcrypt_init'] === true) {
325 | mcrypt_generic_init($this->enmcrypt, $this->key, $iv);
326 | $this->enbuffer['enmcrypt_init'] = false;
327 | }
328 | $ciphertext.= mcrypt_generic($this->enmcrypt, substr($plaintext, $i, $len - $len % 16));
329 | $iv = substr($ciphertext, -16);
330 | $len%= 16;
331 | } else {
332 | while ($len >= 16) {
333 | $iv = mcrypt_generic($this->ecb, $iv) ^ substr($plaintext, $i, 16);
334 | $ciphertext.= $iv;
335 | $len-= 16;
336 | $i+= 16;
337 | }
338 | }
339 | }
340 |
341 | if ($len) {
342 | $iv = mcrypt_generic($this->ecb, $iv);
343 | $block = $iv ^ substr($plaintext, -$len);
344 | $iv = substr_replace($iv, $block, 0, $len);
345 | $ciphertext.= $block;
346 | $pos = $len;
347 | }
348 |
349 | return $ciphertext;
350 | }
351 |
352 | if ($this->paddable) {
353 | $plaintext = $this->_pad($plaintext);
354 | }
355 |
356 | $ciphertext = mcrypt_generic($this->enmcrypt, $plaintext);
357 |
358 | if (!$this->continuousBuffer) {
359 | mcrypt_generic_init($this->enmcrypt, $this->key, $this->iv);
360 | }
361 |
362 | return $ciphertext;
363 | }
364 |
365 | return parent::encrypt($plaintext);
366 | }
367 |
368 | /**
369 | * Decrypts a message.
370 | *
371 | * If strlen($ciphertext) is not a multiple of 16, null bytes will be added to the end of the string until it is.
372 | *
373 | * @see Crypt_AES::encrypt()
374 | * @access public
375 | * @param String $ciphertext
376 | */
377 | function decrypt($ciphertext)
378 | {
379 | if ( CRYPT_AES_MODE == CRYPT_AES_MODE_MCRYPT ) {
380 | $this->_mcryptSetup();
381 |
382 | if ($this->mode == 'ncfb' && $this->continuousBuffer) {
383 | $iv = &$this->decryptIV;
384 | $pos = &$this->debuffer['pos'];
385 | $len = strlen($ciphertext);
386 | $plaintext = '';
387 | $i = 0;
388 | if ($pos) {
389 | $orig_pos = $pos;
390 | $max = 16 - $pos;
391 | if ($len >= $max) {
392 | $i = $max;
393 | $len-= $max;
394 | $pos = 0;
395 | } else {
396 | $i = $len;
397 | $pos+= $len;
398 | $len = 0;
399 | }
400 | // ie. $i = min($max, $len), $len-= $i, $pos+= $i, $pos%= $blocksize
401 | $plaintext = substr($iv, $orig_pos) ^ $ciphertext;
402 | $iv = substr_replace($iv, substr($ciphertext, 0, $i), $orig_pos, $i);
403 | }
404 | if ($len >= 16) {
405 | $cb = substr($ciphertext, $i, $len - $len % 16);
406 | $plaintext.= mcrypt_generic($this->ecb, $iv . $cb) ^ $cb;
407 | $iv = substr($cb, -16);
408 | $len%= 16;
409 | }
410 | if ($len) {
411 | $iv = mcrypt_generic($this->ecb, $iv);
412 | $plaintext.= $iv ^ substr($ciphertext, -$len);
413 | $iv = substr_replace($iv, substr($ciphertext, -$len), 0, $len);
414 | $pos = $len;
415 | }
416 |
417 | return $plaintext;
418 | }
419 |
420 | if ($this->paddable) {
421 | // we pad with chr(0) since that's what mcrypt_generic does. to quote from http://php.net/function.mcrypt-generic :
422 | // "The data is padded with "\0" to make sure the length of the data is n * blocksize."
423 | $ciphertext = str_pad($ciphertext, (strlen($ciphertext) + 15) & 0xFFFFFFF0, chr(0));
424 | }
425 |
426 | $plaintext = mdecrypt_generic($this->demcrypt, $ciphertext);
427 |
428 | if (!$this->continuousBuffer) {
429 | mcrypt_generic_init($this->demcrypt, $this->key, $this->iv);
430 | }
431 |
432 | return $this->paddable ? $this->_unpad($plaintext) : $plaintext;
433 | }
434 |
435 | return parent::decrypt($ciphertext);
436 | }
437 |
438 | /**
439 | * Setup mcrypt
440 | *
441 | * Validates all the variables.
442 | *
443 | * @access private
444 | */
445 | function _mcryptSetup()
446 | {
447 | if (!$this->changed) {
448 | return;
449 | }
450 |
451 | if (!$this->explicit_key_length) {
452 | // this just copied from Crypt_Rijndael::_setup()
453 | $length = strlen($this->key) >> 2;
454 | if ($length > 8) {
455 | $length = 8;
456 | } else if ($length < 4) {
457 | $length = 4;
458 | }
459 | $this->Nk = $length;
460 | $this->key_size = $length << 2;
461 | }
462 |
463 | switch ($this->Nk) {
464 | case 4: // 128
465 | $this->key_size = 16;
466 | break;
467 | case 5: // 160
468 | case 6: // 192
469 | $this->key_size = 24;
470 | break;
471 | case 7: // 224
472 | case 8: // 256
473 | $this->key_size = 32;
474 | }
475 |
476 | $this->key = str_pad(substr($this->key, 0, $this->key_size), $this->key_size, chr(0));
477 | $this->encryptIV = $this->decryptIV = $this->iv = str_pad(substr($this->iv, 0, 16), 16, chr(0));
478 |
479 | if (!isset($this->enmcrypt)) {
480 | $mode = $this->mode;
481 | //$mode = $this->mode == CRYPT_AES_MODE_CTR ? MCRYPT_MODE_ECB : $this->mode;
482 |
483 | $this->demcrypt = mcrypt_module_open(MCRYPT_RIJNDAEL_128, '', $mode, '');
484 | $this->enmcrypt = mcrypt_module_open(MCRYPT_RIJNDAEL_128, '', $mode, '');
485 |
486 | if ($mode == 'ncfb') {
487 | $this->ecb = mcrypt_module_open(MCRYPT_RIJNDAEL_128, '', MCRYPT_MODE_ECB, '');
488 | }
489 |
490 | } // else should mcrypt_generic_deinit be called?
491 |
492 | mcrypt_generic_init($this->demcrypt, $this->key, $this->iv);
493 | mcrypt_generic_init($this->enmcrypt, $this->key, $this->iv);
494 |
495 | if ($this->mode == 'ncfb') {
496 | mcrypt_generic_init($this->ecb, $this->key, "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0");
497 | }
498 |
499 | $this->changed = false;
500 | }
501 |
502 | /**
503 | * Treat consecutive "packets" as if they are a continuous buffer.
504 | *
505 | * The default behavior.
506 | *
507 | * @see Crypt_Rijndael::disableContinuousBuffer()
508 | * @access public
509 | */
510 | function enableContinuousBuffer()
511 | {
512 | parent::enableContinuousBuffer();
513 |
514 | if (CRYPT_AES_MODE == CRYPT_AES_MODE_MCRYPT) {
515 | $this->enbuffer['enmcrypt_init'] = true;
516 | $this->debuffer['demcrypt_init'] = true;
517 | }
518 | }
519 |
520 | /**
521 | * Treat consecutive packets as if they are a discontinuous buffer.
522 | *
523 | * The default behavior.
524 | *
525 | * @see Crypt_Rijndael::enableContinuousBuffer()
526 | * @access public
527 | */
528 | function disableContinuousBuffer()
529 | {
530 | parent::disableContinuousBuffer();
531 |
532 | if (CRYPT_AES_MODE == CRYPT_AES_MODE_MCRYPT) {
533 | mcrypt_generic_init($this->enmcrypt, $this->key, $this->iv);
534 | mcrypt_generic_init($this->demcrypt, $this->key, $this->iv);
535 | }
536 | }
537 | }
538 |
539 | // vim: ts=4:sw=4:et:
540 | // vim6: fdl=1:
541 |
--------------------------------------------------------------------------------
/share/ssh/File/ANSI.php:
--------------------------------------------------------------------------------
1 |
35 | * @copyright MMXII Jim Wigginton
36 | * @license http://www.opensource.org/licenses/mit-license.html MIT License
37 | * @link http://phpseclib.sourceforge.net
38 | */
39 |
40 | /**
41 | * Pure-PHP ANSI Decoder
42 | *
43 | * @author Jim Wigginton
44 | * @version 0.3.0
45 | * @access public
46 | * @package File_ANSI
47 | */
48 | class File_ANSI {
49 | /**
50 | * Max Width
51 | *
52 | * @var Integer
53 | * @access private
54 | */
55 | var $max_x;
56 |
57 | /**
58 | * Max Height
59 | *
60 | * @var Integer
61 | * @access private
62 | */
63 | var $max_y;
64 |
65 | /**
66 | * Max History
67 | *
68 | * @var Integer
69 | * @access private
70 | */
71 | var $max_history;
72 |
73 | /**
74 | * History
75 | *
76 | * @var Array
77 | * @access private
78 | */
79 | var $history;
80 |
81 | /**
82 | * History Attributes
83 | *
84 | * @var Array
85 | * @access private
86 | */
87 | var $history_attrs;
88 |
89 | /**
90 | * Current Column
91 | *
92 | * @var Integer
93 | * @access private
94 | */
95 | var $x;
96 |
97 | /**
98 | * Current Row
99 | *
100 | * @var Integer
101 | * @access private
102 | */
103 | var $y;
104 |
105 | /**
106 | * Old Column
107 | *
108 | * @var Integer
109 | * @access private
110 | */
111 | var $old_x;
112 |
113 | /**
114 | * Old Row
115 | *
116 | * @var Integer
117 | * @access private
118 | */
119 | var $old_y;
120 |
121 | /**
122 | * An empty attribute row
123 | *
124 | * @var Array
125 | * @access private
126 | */
127 | var $attr_row;
128 |
129 | /**
130 | * The current screen text
131 | *
132 | * @var Array
133 | * @access private
134 | */
135 | var $screen;
136 |
137 | /**
138 | * The current screen attributes
139 | *
140 | * @var Array
141 | * @access private
142 | */
143 | var $attrs;
144 |
145 | /**
146 | * The current foreground color
147 | *
148 | * @var String
149 | * @access private
150 | */
151 | var $foreground;
152 |
153 | /**
154 | * The current background color
155 | *
156 | * @var String
157 | * @access private
158 | */
159 | var $background;
160 |
161 | /**
162 | * Bold flag
163 | *
164 | * @var Boolean
165 | * @access private
166 | */
167 | var $bold;
168 |
169 | /**
170 | * Underline flag
171 | *
172 | * @var Boolean
173 | * @access private
174 | */
175 | var $underline;
176 |
177 | /**
178 | * Blink flag
179 | *
180 | * @var Boolean
181 | * @access private
182 | */
183 | var $blink;
184 |
185 | /**
186 | * Reverse flag
187 | *
188 | * @var Boolean
189 | * @access private
190 | */
191 | var $reverse;
192 |
193 | /**
194 | * Color flag
195 | *
196 | * @var Boolean
197 | * @access private
198 | */
199 | var $color;
200 |
201 | /**
202 | * Current ANSI code
203 | *
204 | * @var String
205 | * @access private
206 | */
207 | var $ansi;
208 |
209 | /**
210 | * Default Constructor.
211 | *
212 | * @return File_ANSI
213 | * @access public
214 | */
215 | function File_ANSI()
216 | {
217 | $this->setHistory(200);
218 | $this->setDimensions(80, 24);
219 | }
220 |
221 | /**
222 | * Set terminal width and height
223 | *
224 | * Resets the screen as well
225 | *
226 | * @param Integer $x
227 | * @param Integer $y
228 | * @access public
229 | */
230 | function setDimensions($x, $y)
231 | {
232 | $this->max_x = $x - 1;
233 | $this->max_y = $y - 1;
234 | $this->x = $this->y = 0;
235 | $this->history = $this->history_attrs = array();
236 | $this->attr_row = array_fill(0, $this->max_x + 1, '');
237 | $this->screen = array_fill(0, $this->max_y + 1, '');
238 | $this->attrs = array_fill(0, $this->max_y + 1, $this->attr_row);
239 | $this->foreground = 'white';
240 | $this->background = 'black';
241 | $this->bold = false;
242 | $this->underline = false;
243 | $this->blink = false;
244 | $this->reverse = false;
245 | $this->color = false;
246 |
247 | $this->ansi = '';
248 | }
249 |
250 | /**
251 | * Set the number of lines that should be logged past the terminal height
252 | *
253 | * @param Integer $x
254 | * @param Integer $y
255 | * @access public
256 | */
257 | function setHistory($history)
258 | {
259 | $this->max_history = $history;
260 | }
261 |
262 | /**
263 | * Load a string
264 | *
265 | * @param String $source
266 | * @access public
267 | */
268 | function loadString($source)
269 | {
270 | $this->setDimensions($this->max_x + 1, $this->max_y + 1);
271 | $this->appendString($source);
272 | }
273 |
274 | /**
275 | * Appdend a string
276 | *
277 | * @param String $source
278 | * @access public
279 | */
280 | function appendString($source)
281 | {
282 | for ($i = 0; $i < strlen($source); $i++) {
283 | if (strlen($this->ansi)) {
284 | $this->ansi.= $source[$i];
285 | $chr = ord($source[$i]);
286 | // http://en.wikipedia.org/wiki/ANSI_escape_code#Sequence_elements
287 | // single character CSI's not currently supported
288 | switch (true) {
289 | case $this->ansi == "\x1B=":
290 | $this->ansi = '';
291 | continue 2;
292 | case strlen($this->ansi) == 2 && $chr >= 64 && $chr <= 95 && $chr != ord('['):
293 | case strlen($this->ansi) > 2 && $chr >= 64 && $chr <= 126:
294 | break;
295 | default:
296 | continue 2;
297 | }
298 | // http://ascii-table.com/ansi-escape-sequences-vt-100.php
299 | switch ($this->ansi) {
300 | case "\x1B[H": // Move cursor to upper left corner
301 | $this->old_x = $this->x;
302 | $this->old_y = $this->y;
303 | $this->x = $this->y = 0;
304 | break;
305 | case "\x1B[J": // Clear screen from cursor down
306 | $this->history = array_merge($this->history, array_slice(array_splice($this->screen, $this->y + 1), 0, $this->old_y));
307 | $this->screen = array_merge($this->screen, array_fill($this->y, $this->max_y, ''));
308 |
309 | $this->history_attrs = array_merge($this->history_attrs, array_slice(array_splice($this->attrs, $this->y + 1), 0, $this->old_y));
310 | $this->attrs = array_merge($this->attrs, array_fill($this->y, $this->max_y, $this->attr_row));
311 |
312 | if (count($this->history) == $this->max_history) {
313 | array_shift($this->history);
314 | array_shift($this->history_attrs);
315 | }
316 | case "\x1B[K": // Clear screen from cursor right
317 | $this->screen[$this->y] = substr($this->screen[$this->y], 0, $this->x);
318 |
319 | array_splice($this->attrs[$this->y], $this->x + 1);
320 | break;
321 | case "\x1B[2K": // Clear entire line
322 | $this->screen[$this->y] = str_repeat(' ', $this->x);
323 | $this->attrs[$this->y] = $this->attr_row;
324 | break;
325 | case "\x1B[?1h": // set cursor key to application
326 | case "\x1B[?25h": // show the cursor
327 | break;
328 | case "\x1BE": // Move to next line
329 | $this->_newLine();
330 | $this->x = 0;
331 | break;
332 | default:
333 | switch (true) {
334 | case preg_match('#\x1B\[(\d+);(\d+)H#', $this->ansi, $match): // Move cursor to screen location v,h
335 | $this->old_x = $this->x;
336 | $this->old_y = $this->y;
337 | $this->x = $match[2] - 1;
338 | $this->y = $match[1] - 1;
339 | break;
340 | case preg_match('#\x1B\[(\d+)C#', $this->ansi, $match): // Move cursor right n lines
341 | $this->old_x = $this->x;
342 | $x = $match[1] - 1;
343 | break;
344 | case preg_match('#\x1B\[(\d+);(\d+)r#', $this->ansi, $match): // Set top and bottom lines of a window
345 | break;
346 | case preg_match('#\x1B\[(\d*(?:;\d*)*)m#', $this->ansi, $match): // character attributes
347 | $mods = explode(';', $match[1]);
348 | foreach ($mods as $mod) {
349 | switch ($mod) {
350 | case 0: // Turn off character attributes
351 | $this->attrs[$this->y][$this->x] = '';
352 |
353 | if ($this->bold) $this->attrs[$this->y][$this->x].= '';
354 | if ($this->underline) $this->attrs[$this->y][$this->x].= '';
355 | if ($this->blink) $this->attrs[$this->y][$this->x].= '';
356 | if ($this->color) $this->attrs[$this->y][$this->x].= '';
357 |
358 | if ($this->reverse) {
359 | $temp = $this->background;
360 | $this->background = $this->foreground;
361 | $this->foreground = $temp;
362 | }
363 |
364 | $this->bold = $this->underline = $this->blink = $this->color = $this->reverse = false;
365 | break;
366 | case 1: // Turn bold mode on
367 | if (!$this->bold) {
368 | $this->attrs[$this->y][$this->x] = '';
369 | $this->bold = true;
370 | }
371 | break;
372 | case 4: // Turn underline mode on
373 | if (!$this->underline) {
374 | $this->attrs[$this->y][$this->x] = '';
375 | $this->underline = true;
376 | }
377 | break;
378 | case 5: // Turn blinking mode on
379 | if (!$this->blink) {
380 | $this->attrs[$this->y][$this->x] = '