GCC Code Coverage Report


Directory: ../replacer/
Coverage: low: ≥ 0% medium: ≥ 75.0% high: ≥ 90.0%
Coverage Exec / Excl / Total
Lines: 88.2% 105 / 0 / 119
Functions: 80.0% 8 / 0 / 10
Branches: 79.7% 63 / 0 / 79

storage.c
Line Branch Exec Source
1 #include <stdio.h>
2 #include <stdlib.h>
3 #include <string.h>
4 #include <strings.h>
5
6 #include <inttypes.h>
7 #include <stdint.h>
8 #include <pthread.h>
9 #include <pwd.h>
10 #include <time.h>
11
12 #include <sys/types.h>
13 #include <sys/socket.h>
14 #include <sys/un.h>
15
16 #include <stdlib.h>
17
18 #include <sys/time.h>
19 #include <unistd.h>
20 #include <sys/ioctl.h>
21
22 #include <errno.h>
23 #include <fcntl.h>
24 #include <yaml.h>
25
26 #include "global_data.h"
27 #include "queue.h"
28
29 #include "storage.h"
30 #include "stringfunc.h"
31
32 #include "unit_test_common.h"
33 #include "counters-saver.h"
34
35 static long sign_id = 0;
36 static uint64_t hdb_version = 0;
37
38 void i360_set_sign(long id) {
39 sign_id = id;
40 }
41
42 void i360_set_hdb_version(uint64_t ver) {
43 hdb_version = ver;
44 }
45
46 #ifndef UNIT_TESTING
47 static int i360_socket_set_non_blocking(int fd) {
48 int flags;
49
50 flags = fcntl(fd, F_GETFL, NULL);
51
52 if (flags < 0) {
53 return -1;
54 }
55
56 flags |= O_NONBLOCK;
57
58 if (fcntl(fd, F_SETFL, flags) < 0) {
59 return -1;
60 }
61 return 0;
62 }
63
64 // do a nonblocking connect
65 // return -1 on a system call error, 0 on success
66 // sa - host to connect to, filled by caller
67 // sock - the socket to connect
68 // timeout - how long to wait to connect in millisecs
69 int conn_nonb(int sock, struct sockaddr *sa, socklen_t __len, int timeout) {
70 int flags = 0, error = 0, ret = 0;
71 fd_set rset, wset;
72 socklen_t len = sizeof(error);
73 struct timeval ts;
74
75 ts.tv_sec = timeout / 1000;
76 ts.tv_usec = (timeout % 1000) * 1000;
77
78 // clear out descriptor sets for select
79 // add socket to the descriptor sets
80 FD_ZERO(&rset);
81 FD_SET(sock, &rset);
82 wset = rset; // structure assignment ok
83
84 // set socket nonblocking flag
85 if ((flags = fcntl(sock, F_GETFL, 0)) < 0)
86 return -1;
87
88 if (fcntl(sock, F_SETFL, flags | O_NONBLOCK) < 0)
89 return -1;
90
91 // initiate non-blocking connect
92 if ((ret = connect(sock, sa, __len)) < 0)
93 if (errno != EINPROGRESS)
94 return -1;
95
96 if (ret == 0) // then connect succeeded right away
97 goto done;
98
99 // we are waiting for connect to complete now
100 if ((ret = select(sock + 1, &rset, &wset, NULL, (timeout) ? &ts : NULL)) < 0)
101 return -1;
102 if (ret == 0) { // we had a timeout
103 errno = ETIMEDOUT;
104 return -1;
105 }
106
107 // we had a positivite return so a descriptor is ready
108 if (FD_ISSET(sock, &rset) || FD_ISSET(sock, &wset)) {
109 if (getsockopt(sock, SOL_SOCKET, SO_ERROR, &error, &len) < 0)
110 return -1;
111 }
112 else
113 return -1;
114
115 if (error) { // check if we had a socket error
116 errno = error;
117 return -1;
118 }
119
120 done:
121 // put socket back in blocking mode
122 if (fcntl(sock, F_SETFL, flags) < 0)
123 return -1;
124
125 return 0;
126 }
127
128 int i360_connect_to_server(char *s_name, int buf_sz, int timeout) {
129 int sock;
130 struct sockaddr_un server;
131 int sendbuff = buf_sz;
132
133 sock = socket(AF_UNIX, SOCK_STREAM, 0);
134 if (sock < 0) {
135 return -1;
136 }
137 server.sun_family = AF_UNIX;
138 strcpy(server.sun_path, s_name);
139
140 if (!timeout) {
141 if (connect(sock, (struct sockaddr *)&server, sizeof(struct sockaddr_un)) < 0) {
142 close(sock);
143 return -1;
144 }
145 }
146 else {
147 if (conn_nonb(sock, (struct sockaddr *)&server, sizeof(struct sockaddr_un), timeout) < 0) {
148 close(sock);
149 return -1;
150 }
151 }
152
153 if (i360_socket_set_non_blocking(sock) < 0) {
154 close(sock);
155 return -1;
156 }
157
158 if (sendbuff > 1024)
159 setsockopt(sock, SOL_SOCKET, SO_SNDBUF, &sendbuff, sizeof(sendbuff));
160
161 return sock;
162 }
163
164 int i360_isclosed(int sock) {
165 fd_set rfd;
166 FD_ZERO(&rfd);
167 FD_SET(sock, &rfd);
168 struct timeval tv = {0, 0};
169 select(sock + 1, &rfd, 0, 0, &tv);
170 if (!FD_ISSET(sock, &rfd))
171 return 0;
172 int n = 0;
173 ioctl(sock, FIONREAD, &n);
174 return n == 0;
175 }
176
177 ssize_t i360_write_connect(int *fd, const void *buf, size_t count, char *s_name, int buf_sz,
178 __attribute__((unused)) void *mx, int timeout) {
179 ssize_t ret;
180 if (!fd) {
181 return -1;
182 }
183 if ((*fd < 0) || i360_isclosed(*fd)) {
184 *fd = i360_connect_to_server(s_name, buf_sz, timeout);
185 if (*fd < 0) {
186 return -1;
187 }
188 i360_connections_stats_new_conn();
189 }
190
191 do {
192 ret = write(*fd, buf, count);
193 } while ((ret < 0) && (errno == EINTR));
194
195 return ret;
196 }
197
198 time_t i360_get_tmstmp() {
199 return time(NULL);
200 }
201 #endif
202
203 1 uint16_t i360_get_little_e_size(int size) {
204 1 unsigned int i = 1;
205 1 char *c = (char *)&i;
206
1/2
✓ Branch 2 → 3 taken 1 time.
✗ Branch 2 → 4 not taken.
1 if (*c)
207 1 return (uint16_t)size;
208 else {
209 uint16_t new_size = (uint16_t)size;
210 return (new_size >> 8) | (new_size << 8);
211 }
212 }
213
214 1 uint16_t i360_get_big_e_size(int size) {
215 1 unsigned int i = 1;
216 1 char *c = (char *)&i;
217
1/2
✗ Branch 2 → 3 not taken.
✓ Branch 2 → 4 taken 1 time.
1 if (!*c)
218 return (uint16_t)size;
219 else {
220 1 uint16_t new_size = (uint16_t)size;
221 1 return (new_size >> 8) | (new_size << 8);
222 }
223 }
224
225 #define ENVBUFFER 4096
226
227 #ifndef UNIT_TESTING
228 const char *ENV_INDEX[] = {"A", "B", "C", "D", "E", "F", "G", "H", "I", "J", "K", "L", "M",
229 "N", "O", "P", "Q", "R", "S", "T", "U", "V", "W", "X", "Y", "Z"};
230 #define MAX_PARAM_BUF 128
231 #define MAX_SIGN_BUF 256
232 #define MAX_IP_BUF 64
233 #define MAX_HDB_VER_BUF 20
234
235 char *i360_init_proto_data_mon(const i360_monitoring_data_t *mon_data, int *length) {
236 char *buf = NULL;
237 int len = 0;
238 *length = 0;
239 I360stats__MonitoringStats data = I360STATS__MONITORING_STATS__INIT;
240
241 if (mon_data == NULL)
242 return NULL;
243
244 data.module_duration = mon_data->module_duration;
245 data.total_connections = mon_data->total_connections;
246 data.total_packets_sent = mon_data->total_packets_sent;
247 data.total_requests = mon_data->total_requests;
248
249 len = i360stats__monitoring_stats__get_packed_size(&data);
250
251 send_params_buffer *buf_send = calloc(1, (len * sizeof(uint8_t)) + sizeof(uint16_t));
252 if (buf_send) {
253 i360stats__monitoring_stats__pack(&data, (uint8_t *)&buf_send->buffer);
254 *length = len + sizeof(uint16_t);
255 buf_send->size = i360_get_big_e_size(len);
256 }
257
258 buf = (char *)buf_send;
259 return buf;
260 }
261
262 int i360_init_proto_data_failure(const i360_log_data_t *ld, char *aux_env[], size_t aux_env_len, char *buf) {
263 int env_idx = 0;
264 size_t buf_left = MAX_FAILURE_BUF_LEN;
265 char tmp_buf[MAX_FAILURE_BUF_LEN] = {0};
266 char *env[MAX_FAILURE_BUF_SIZE];
267
268 I360parcel__SendInfo data = I360PARCEL__SEND_INFO__INIT;
269 I360parcel__ProactiveQueue php_info = I360PARCEL__PROACTIVE_QUEUE__INIT;
270
271 if (buf == NULL || ld == NULL)
272 return -1;
273
274 php_info.version = ld->version;
275 php_info.script = (char *)ld->script_name;
276 php_info.recognizer_id = ld->chains->recognizer_id;
277 php_info.recognizer_sub_id = ld->chains->chain_id;
278
279 switch (ld->chains->action) {
280 case BLOCK_FUNC:
281 php_info.action = I360PARCEL__PROACTIVE_QUEUE__ACTION__BLOCK;
282 break;
283 case KILL_SCRIPT:
284 php_info.action = I360PARCEL__PROACTIVE_QUEUE__ACTION__KILL;
285 break;
286 case DISABLED:
287 php_info.action = I360PARCEL__PROACTIVE_QUEUE__ACTION__DISABLED;
288 break;
289 case LOG_ONLY:
290 // failthrough
291 case NO_ACTION:
292 // failthrough
293 default:
294 php_info.action = I360PARCEL__PROACTIVE_QUEUE__ACTION__LOG;
295 break;
296 }
297 php_info.has_action = 1;
298
299 char description[MAX_FAILURE_BUF_LEN] = {0};
300 memcpy(description, ld->chains->recognizer_desr, strlen(ld->chains->recognizer_desr));
301 php_info.recognizer_name = description;
302
303 char sign_buf[MAX_FAILURE_BUF_LEN] = {0};
304 if (sign_id) {
305 i360_strnadd(sign_buf, "sign=", 5, MAX_FAILURE_BUF_LEN, (buf_left = MAX_FAILURE_BUF_LEN, &buf_left));
306 i360_ltoa(sign_id, tmp_buf, 10);
307 i360_strnadd(sign_buf, tmp_buf, strlen(tmp_buf), MAX_FAILURE_BUF_LEN, &buf_left);
308 env[env_idx++] = sign_buf;
309 }
310
311 char dbv_buf[MAX_FAILURE_BUF_LEN] = {0};
312 if (!i360_get_database_version()) {
313 i360_strnadd(dbv_buf, "dbver=v1", 8, MAX_FAILURE_BUF_LEN, (buf_left = MAX_FAILURE_BUF_LEN, &buf_left));
314 }
315 else {
316 i360_strnadd(dbv_buf, "dbver=v2", 8, MAX_FAILURE_BUF_LEN, (buf_left = MAX_FAILURE_BUF_LEN, &buf_left));
317 }
318 env[env_idx++] = dbv_buf;
319
320 char hdbv_buf[MAX_HDB_VER_BUF] = {0};
321 if (hdb_version) {
322 i360_strnadd(hdbv_buf, "hdb_ver=", 8, MAX_HDB_VER_BUF, (buf_left = MAX_HDB_VER_BUF, &buf_left));
323 i360_ltoa(hdb_version, tmp_buf, 10);
324 i360_strnadd(hdbv_buf, tmp_buf, strlen(tmp_buf), MAX_HDB_VER_BUF, &buf_left);
325 env[env_idx++] = hdbv_buf;
326 }
327
328 char i360_ver_buf[MAX_FAILURE_BUF_LEN] = {0};
329 i360_strnadd(i360_ver_buf, "I_I360_V=", 9, MAX_FAILURE_BUF_LEN, (buf_left = MAX_FAILURE_BUF_LEN, &buf_left));
330 i360_strnadd(i360_ver_buf, PHP_I360_VERSION, strlen(PHP_I360_VERSION), MAX_FAILURE_BUF_LEN, &buf_left);
331 env[env_idx++] = i360_ver_buf;
332
333 char uid_buf[MAX_FAILURE_BUF_LEN];
334 uid_t store_uid = getuid();
335 i360_strnadd(uid_buf, "PHPAP_UID=", 10, MAX_FAILURE_BUF_LEN, (buf_left = MAX_FAILURE_BUF_LEN, &buf_left));
336 i360_itoa((int)store_uid, tmp_buf, 10);
337 i360_strnadd(uid_buf, tmp_buf, strlen(tmp_buf), MAX_FAILURE_BUF_LEN, &buf_left);
338 env[env_idx++] = uid_buf;
339
340 char gid_buf[MAX_FAILURE_BUF_LEN];
341 gid_t store_gid = getgid();
342 i360_strnadd(gid_buf, "PHPAP_GID=", 10, MAX_FAILURE_BUF_LEN, (buf_left = MAX_FAILURE_BUF_LEN, &buf_left));
343 i360_itoa((int)store_gid, tmp_buf, 10);
344 i360_strnadd(gid_buf, tmp_buf, strlen(tmp_buf), MAX_FAILURE_BUF_LEN, &buf_left);
345 env[env_idx++] = gid_buf;
346
347 char current_script_filename_buf[MAX_FAILURE_FILENAME_LEN] = "current_script=";
348 const char *current_script_filename = i360_get_cur_php_fname();
349 if (current_script_filename != NULL && strlen(current_script_filename)) {
350 strncat(current_script_filename_buf, current_script_filename, MAX_FAILURE_FILENAME_LEN - 16);
351 }
352 else {
353 strcat(current_script_filename_buf, "[no script]");
354 }
355 env[env_idx++] = current_script_filename_buf;
356
357 // Process server_env
358 char *script_uri = NULL;
359 char *server_name = NULL;
360 char *script_filename = NULL;
361 params_list *server_env = i360_get_global_server();
362 if (server_env->head) {
363 params_item *item = server_env->head;
364 while (item) {
365 // add host to env
366 if (i360_has_prefix(item->param, "PHPE_SERVER_NAME") == 1) {
367 server_name = item->param;
368 }
369 // add uri to env
370 else if (i360_has_prefix(item->param, "PHPE_SCRIPT_URI") == 1) {
371 script_uri = item->param;
372 }
373 // add script_filename to env
374 else if (i360_has_prefix(item->param, "SCRIPT_FILENAME") == 1) {
375 script_filename = item->param;
376 }
377
378 item = item->next;
379 }
380 }
381 if (server_name) {
382 env[env_idx++] = server_name;
383 }
384 if (script_uri) {
385 env[env_idx++] = script_uri;
386 }
387 if (script_filename) {
388 env[env_idx++] = script_filename;
389 }
390
391 /* Auxiliary env data */
392 size_t i;
393 for (i = 0; i < aux_env_len && env_idx < MAX_FAILURE_BUF_SIZE; i++) {
394 env[env_idx++] = aux_env[i];
395 }
396
397 php_info.n_env = env_idx;
398 php_info.env = env;
399
400 data.proactive = &php_info;
401 data.timestamp = i360_get_tmstmp();
402 data.method = I360PARCEL__SEND_INFO__METHOD__PROACTIVE;
403 I360parcel__ProactiveEnvMeta env_meta = I360PARCEL__PROACTIVE_ENV_META__INIT;
404 if (ld->application_id) {
405 env_meta.app_id = (char *)ld->application_id;
406 if (ld->application_instance_id) {
407 env_meta.instance_uid = (char *)ld->application_instance_id;
408 }
409 data.env_meta = &env_meta;
410 }
411
412 char ip_buf[MAX_IP_BUF] = {0};
413 if (ld->ip) {
414 strncpy(ip_buf, ld->ip, MAX_IP_BUF - 1);
415 char *comma = strchr(ip_buf, ',');
416 if (comma) {
417 *comma = 0;
418 }
419 }
420 else {
421 strncpy(ip_buf, "127.0.0.1", MAX_IP_BUF - 1);
422 }
423 data.ip = ip_buf;
424
425 /* Protobuf serialization */
426 size_t payload_len = i360parcel__send_info__get_packed_size(&data);
427 size_t len = payload_len + sizeof(uint16_t);
428 uint8_t packed[len];
429
430 uint16_t be_payload_len = i360_get_big_e_size(payload_len);
431 memcpy(packed, &be_payload_len, sizeof(uint16_t));
432
433 i360parcel__send_info__pack(&data, packed + sizeof(uint16_t));
434
435 memcpy(buf, packed, len);
436
437 return (int)len;
438 }
439
440 char *i360_init_proto_data(const i360_log_data_t *ld, int *length) {
441 *length = 0;
442 char env_buf[ENVBUFFER];
443 char ip_buf[MAX_IP_BUF];
444 size_t buf_left = ENVBUFFER;
445 char description[MAX_FILE_STRING] = {0};
446 char param_buf[MAX_PARAM_BUF] = {0};
447 char sign_buf[MAX_SIGN_BUF] = {0};
448 char hdbv_buf[MAX_HDB_VER_BUF] = {0};
449 if (!ld || !ld->chains || !ld->chains->recognizer_id)
450 return NULL;
451 I360parcel__SendInfo data = I360PARCEL__SEND_INFO__INIT;
452 I360parcel__ProactiveQueue php_info = I360PARCEL__PROACTIVE_QUEUE__INIT;
453 char *buf = NULL;
454 size_t len = 0;
455
456 if (!i360_is_prepared_buffer_fixed()) {
457 if (!i360_get_database_version()) {
458 i360_strnadd(env_buf, "dbver=v1", 8, ENVBUFFER, (buf_left = ENVBUFFER, &buf_left));
459 }
460 else {
461 i360_strnadd(env_buf, "dbver=v2", 8, ENVBUFFER, (buf_left = ENVBUFFER, &buf_left));
462 }
463 i360_add_prepared_buffer_req_data(env_buf);
464
465 if (hdb_version) {
466 i360_strnadd(env_buf, "hdb_ver=", 8, ENVBUFFER, (buf_left = ENVBUFFER, &buf_left));
467 sprintf(hdbv_buf, "%" PRIu64, hdb_version);
468 i360_strnadd(env_buf, hdbv_buf, strlen(hdbv_buf), ENVBUFFER, &buf_left);
469 i360_add_prepared_buffer_req_data(env_buf);
470 }
471
472 if (sign_id) {
473 i360_strnadd(env_buf, "sign=", 5, ENVBUFFER, (buf_left = ENVBUFFER, &buf_left));
474 i360_ltoa(sign_id, sign_buf, 10);
475 i360_strnadd(env_buf, sign_buf, strlen(sign_buf), ENVBUFFER, &buf_left);
476 i360_add_prepared_buffer_req_data(env_buf);
477 }
478
479 i360_strnadd(env_buf, "I_I360_V=", 9, ENVBUFFER, (buf_left = ENVBUFFER, &buf_left));
480 i360_strnadd(env_buf, PHP_I360_VERSION, strlen(PHP_I360_VERSION), ENVBUFFER, &buf_left);
481 i360_add_prepared_buffer_req_data(env_buf);
482
483 uid_t store_uid = getuid();
484 gid_t store_gid = getgid();
485
486 i360_strnadd(env_buf, "PHPAP_UID=", 10, ENVBUFFER, (buf_left = ENVBUFFER, &buf_left));
487 i360_itoa((int)store_uid, param_buf, 10);
488 i360_strnadd(env_buf, param_buf, strlen(param_buf), ENVBUFFER, &buf_left);
489 i360_add_prepared_buffer_req_data(env_buf);
490
491 i360_strnadd(env_buf, "PHPAP_GID=", 10, ENVBUFFER, (buf_left = ENVBUFFER, &buf_left));
492 i360_itoa((int)store_gid, param_buf, 10);
493 i360_strnadd(env_buf, param_buf, strlen(param_buf), ENVBUFFER, &buf_left);
494 i360_add_prepared_buffer_req_data(env_buf);
495
496 if (ld->script_schema) {
497 i360_strnadd(env_buf, "PHPAP_SCHEMA=", 13, ENVBUFFER, (buf_left = ENVBUFFER, &buf_left));
498 i360_strnadd(env_buf, ld->script_schema, strlen(ld->script_schema), ENVBUFFER, &buf_left);
499 i360_add_prepared_buffer_req_data(env_buf);
500 }
501
502 params_list *serv = (params_list *)ld->server;
503 if (serv->head) {
504 params_item *item = serv->head;
505 while (item) {
506 i360_add_prepared_buffer_req_data(item->param);
507 item = item->next;
508 }
509 }
510 }
511
512 if (!i360_is_prepared_buffer_fixed()) {
513 i360_fix_prepared_buffer();
514 }
515 else {
516 i360_restore_buffer_for_dynamic();
517 }
518
519 if (ld->include_stack && ld->include_stack[0]) {
520 i360_strnadd(env_buf, "INCLUDE_STACK=", sizeof("INCLUDE_STACK=")-1, ENVBUFFER, (buf_left = ENVBUFFER, &buf_left));
521 i360_strnadd(env_buf, ld->include_stack, strlen(ld->include_stack), ENVBUFFER, &buf_left);
522 i360_add_prepared_buffer_dyn_data(env_buf);
523 }
524
525 if (ld->hash && *ld->hash) {
526 i360_strnadd(env_buf, "qhash=", 6, ENVBUFFER, (buf_left = ENVBUFFER, &buf_left));
527 i360_strnadd(env_buf, ld->hash, strlen(ld->hash), ENVBUFFER, &buf_left);
528 i360_add_prepared_buffer_dyn_data(env_buf);
529 }
530
531 if (ld->last_funcname) {
532 i360_strnadd(env_buf, "PHPFP_NAM=", 10, ENVBUFFER, (buf_left = ENVBUFFER, &buf_left));
533 i360_strnadd(env_buf, ld->last_funcname, strlen(ld->last_funcname), ENVBUFFER, &buf_left);
534 i360_add_prepared_buffer_dyn_data(env_buf);
535 }
536
537 if (ld->qhashfn) {
538 i360_strnadd(env_buf, ld->qhash_version ? "EF_1_NAME=" : "EF_0_NAME=", 10, ENVBUFFER,
539 (buf_left = ENVBUFFER, &buf_left));
540 i360_strnadd(env_buf, ld->qhashfn, strlen(ld->qhashfn), ENVBUFFER, &buf_left);
541 i360_add_prepared_buffer_dyn_data(env_buf);
542 }
543
544 if (ld->qhashlast) {
545 i360_strnadd(env_buf, ld->qhash_version ? "EF_1_LAST_HASH=" : "EF_0_LAST_HASH=", 15, ENVBUFFER,
546 (buf_left = ENVBUFFER, &buf_left));
547 i360_strnadd(env_buf, ld->qhashlast, strlen(ld->qhashlast), ENVBUFFER, &buf_left);
548 i360_add_prepared_buffer_dyn_data(env_buf);
549 }
550
551 if (ld->qhashlen) {
552 i360_strnadd(env_buf, ld->qhash_version ? "EF_1_LEN=" : "EF_0_LEN=", 9, ENVBUFFER,
553 (buf_left = ENVBUFFER, &buf_left));
554 i360_itoa(ld->qhashlen, param_buf, 10);
555 i360_strnadd(env_buf, param_buf, strlen(param_buf), ENVBUFFER, &buf_left);
556 i360_add_prepared_buffer_dyn_data(env_buf);
557 }
558
559 /*
560 i360_strnadd(env_buf, "PHPE_rdlt=", 10, ENVBUFFER, (buf_left = ENVBUFFER, &buf_left));
561 i360_lltoa((long long)ld->running_delta, param_buf, 10);
562 i360_strnadd(env_buf, param_buf, strlen(param_buf), ENVBUFFER, &buf_left);
563 i360_add_prepared_buffer_dyn_data(env_buf);
564 */
565
566 php_info.version = ld->version;
567
568 php_info.script = (char *)ld->script_name;
569
570 php_info.queue_string = (char *)ld->queue;
571
572 // check for any log
573 if (ld->chains->recognizer_id == 2) {
574 php_info.recognizer_id = 2;
575 php_info.has_recognizer_sub_id = 0;
576 php_info.action = I360PARCEL__PROACTIVE_QUEUE__ACTION__LOG;
577 php_info.has_action = 1;
578 strncpy(description, "test:test", MAX_FILE_STRING);
579 php_info.recognizer_name = (char *)&description;
580 }
581 else {
582 php_info.recognizer_id = ld->chains->recognizer_id;
583 php_info.recognizer_sub_id = ld->chains->chain_id;
584 php_info.has_recognizer_sub_id = 1;
585 switch (ld->chains->action) {
586 case LOG_ONLY:
587 php_info.action = I360PARCEL__PROACTIVE_QUEUE__ACTION__LOG;
588 break;
589 case BLOCK_FUNC:
590 php_info.action = I360PARCEL__PROACTIVE_QUEUE__ACTION__BLOCK;
591 break;
592 case KILL_SCRIPT:
593 php_info.action = I360PARCEL__PROACTIVE_QUEUE__ACTION__KILL;
594 break;
595 case DISABLED:
596 php_info.action = I360PARCEL__PROACTIVE_QUEUE__ACTION__DISABLED;
597 break;
598 case NO_ACTION: /* -Werror=switch */
599 default:
600 break;
601 }
602 php_info.has_action = 1;
603 memcpy(description, ld->chains->recognizer_desr, strlen(ld->chains->recognizer_desr));
604 size_t desc_buf_left = MAX_FILE_STRING - strnlen(description, MAX_FILE_STRING);
605 i360_strnadd(description, ":", 1, MAX_FILE_STRING, &desc_buf_left);
606 i360_strnadd(description, ld->chains->ruldescr, strlen(ld->chains->ruldescr), MAX_FILE_STRING, &desc_buf_left);
607 php_info.recognizer_name = (char *)&description;
608 }
609
610 if (i360_prepared_buffer_length()) {
611 php_info.n_env = i360_prepared_buffer_length() + i360_get_params_new_numb();
612 php_info.env = calloc(i360_prepared_buffer_length() + i360_get_params_new_numb(), sizeof(char *));
613 if (!php_info.env) {
614 return NULL;
615 }
616 int index = 0;
617 while (index < i360_prepared_buffer_length()) {
618 php_info.env[index] = i360_prepared_buffer_get(index);
619 index++;
620 }
621 int jndex = 0;
622 while (jndex < i360_get_params_new_numb()) {
623 php_info.env[index + jndex] = i360_get_params_new_raw(jndex);
624 jndex++;
625 }
626 }
627
628 I360parcel__ProactiveEnvMeta env_meta = I360PARCEL__PROACTIVE_ENV_META__INIT;
629 if (ld->application_id) {
630 env_meta.app_id = (char *)ld->application_id;
631 if (ld->application_instance_id) {
632 env_meta.instance_uid = (char *)ld->application_instance_id;
633 }
634 data.env_meta = &env_meta;
635 }
636 data.proactive = &php_info;
637 data.timestamp = i360_get_tmstmp();
638 if (ld->ip) {
639 memset(ip_buf, 0, MAX_IP_BUF);
640 strncpy(ip_buf, ld->ip, MAX_IP_BUF - 1);
641 char *comma = strchr(ip_buf, ',');
642 if (comma) {
643 *comma = 0;
644 }
645 }
646 else {
647 strncpy(ip_buf, "127.0.0.1", MAX_IP_BUF - 1);
648 }
649 data.ip = ip_buf;
650 data.method = I360PARCEL__SEND_INFO__METHOD__PROACTIVE;
651
652 len = i360parcel__send_info__get_packed_size(&data);
653
654 send_params_buffer *buf_send = calloc(1, (len * sizeof(uint8_t)) + sizeof(uint16_t));
655
656 if (buf_send) {
657 i360parcel__send_info__pack(&data, (uint8_t *)&buf_send->buffer);
658 *length = len + sizeof(uint16_t);
659 buf_send->size = i360_get_big_e_size(len);
660 }
661
662 buf = (char *)buf_send;
663
664 if (php_info.env)
665 free(php_info.env);
666 return buf;
667 }
668
669 char *i360_init_proto_data_stats(int *length, const char *script_name, const char *uri, const char *method, const char *app_id, const char *instance_uid) {
670 char *buf = NULL;
671 int len = 0;
672 *length = 0;
673 I360stats__ProactiveStats php_info = I360STATS__PROACTIVE_STATS__INIT;
674 php_info.uri = (char *)(uri ? uri : "no_uri");
675 php_info.script = (char *)(script_name ? script_name : "no_script");
676 if (method != NULL && !strcasecmp(method, "get")) {
677 php_info.method = I360STATS__PROACTIVE_STATS__METHOD__GET;
678 }
679 else if (method != NULL && !strcasecmp(method, "post")) {
680 php_info.method = I360STATS__PROACTIVE_STATS__METHOD__POST;
681 }
682 else {
683 php_info.method = I360STATS__PROACTIVE_STATS__METHOD__OTHER;
684 }
685 php_info.version = 1;
686
687 if (i360_counter_saver_is_active()) {
688 php_info.inpd = (uint64_t)i360_counter_saver_global_counter_in_pd_get();
689 php_info.global = (uint64_t)i360_counter_saver_global_counter_get();
690 if (i360_counter_saver_get_items()) {
691 php_info.n_rulesid = i360_counter_saver_get_items();
692 php_info.n_exectimes = i360_counter_saver_get_items();
693 php_info.rulesid = calloc(php_info.n_rulesid, sizeof(uint32_t));
694 if (!php_info.rulesid) {
695 return NULL;
696 }
697 php_info.exectimes = calloc(php_info.n_rulesid, sizeof(uint64_t));
698 if (!php_info.exectimes) {
699 free(php_info.rulesid);
700 return NULL;
701 }
702 size_t index = 0;
703 for (index = 0; index < php_info.n_rulesid; index++) {
704 i360_counter_saver_array_item *tmp_item = i360_counter_saver_index(index);
705 php_info.rulesid[index] = (uint32_t)tmp_item->key;
706 php_info.exectimes[index] = (uint64_t)tmp_item->value;
707 }
708 }
709 if (i360_dbgcounter_saver_get_items()) {
710 php_info.n_dbgrulesid = i360_dbgcounter_saver_get_items();
711 php_info.n_dbgexectimes = i360_dbgcounter_saver_get_items();
712 php_info.dbgrulesid = calloc(php_info.n_dbgrulesid, sizeof(uint32_t));
713 if (!php_info.dbgrulesid) {
714 if (php_info.rulesid)
715 free(php_info.rulesid);
716 if (php_info.exectimes)
717 free(php_info.exectimes);
718 return NULL;
719 }
720 php_info.dbgexectimes = calloc(php_info.n_dbgrulesid, sizeof(uint64_t));
721 if (!php_info.dbgexectimes) {
722 if (php_info.rulesid)
723 free(php_info.rulesid);
724 if (php_info.exectimes)
725 free(php_info.exectimes);
726 free(php_info.dbgrulesid);
727 return NULL;
728 }
729 size_t index = 0;
730 for (index = 0; index < php_info.n_dbgrulesid; index++) {
731 i360_counter_saver_array_item *tmp_item = i360_dbgcounter_saver_index(index);
732 php_info.dbgrulesid[index] = (uint32_t)tmp_item->key;
733 php_info.dbgexectimes[index] = (uint64_t)tmp_item->value;
734 }
735 }
736 }
737 I360stats__ProactiveEnvMeta env_meta = I360STATS__PROACTIVE_ENV_META__INIT;
738 if (app_id) {
739 env_meta.app_id = (char *)app_id;
740 if (instance_uid) {
741 env_meta.instance_uid = (char *)instance_uid;
742 }
743 php_info.env_meta = &env_meta;
744 }
745
746 len = i360stats__proactive_stats__get_packed_size(&php_info);
747
748 send_params_buffer *buf_send = calloc(1, (len * sizeof(uint8_t)) + sizeof(uint16_t));
749 if (buf_send) {
750 i360stats__proactive_stats__pack(&php_info, (uint8_t *)&buf_send->buffer);
751 *length = len + sizeof(uint16_t);
752 buf_send->size = i360_get_big_e_size(len);
753 }
754
755 buf = (char *)buf_send;
756
757 if (php_info.rulesid)
758 free(php_info.rulesid);
759 if (php_info.exectimes)
760 free(php_info.exectimes);
761 if (php_info.dbgrulesid)
762 free(php_info.dbgrulesid);
763 if (php_info.dbgexectimes)
764 free(php_info.dbgexectimes);
765
766 return buf;
767 }
768 #endif
769
770 14 static int i360_parse_mode(char *value) {
771
1/2
✗ Branch 2 → 3 not taken.
✓ Branch 2 → 4 taken 14 times.
14 if (!strcmp(value, "DISABLED"))
772 return DISABLED;
773
2/2
✓ Branch 4 → 5 taken 8 times.
✓ Branch 4 → 6 taken 6 times.
14 else if (!strcmp(value, "LOG"))
774 8 return LOG_ONLY;
775
2/2
✓ Branch 6 → 7 taken 2 times.
✓ Branch 6 → 8 taken 4 times.
6 else if (!strcmp(value, "BLOCK"))
776 2 return BLOCK_FUNC;
777
2/2
✓ Branch 8 → 9 taken 2 times.
✓ Branch 8 → 10 taken 2 times.
4 else if (!strcmp(value, "KILL"))
778 2 return KILL_SCRIPT;
779 else
780 2 return -1;
781 }
782
783 static inline
784 15 void i360_parse_bool(const char *str, int *value) {
785
2/2
✓ Branch 2 → 3 taken 8 times.
✓ Branch 2 → 4 taken 7 times.
15 if (!strcasecmp(str, "on") ||
786
2/2
✓ Branch 3 → 4 taken 3 times.
✓ Branch 3 → 5 taken 5 times.
8 !strcasecmp(str, "true")) {
787 10 *value = 1;
788 }
789
1/2
✓ Branch 5 → 6 taken 5 times.
✗ Branch 5 → 7 not taken.
5 else if (!!strcasecmp(str, "null")) {
790 5 *value = 0;
791 }
792 15 }
793
794 #define SECTION_NONE 0
795 #define SECTION_PROACTIVE_DEFENCE 1
796 #define SECTION_PERMISSIONS 2
797
798 static inline
799 58 int i360_yaml_section_name_to_id(char *name) {
800
2/2
✓ Branch 2 → 3 taken 38 times.
✓ Branch 2 → 7 taken 20 times.
58 if (name) {
801
2/2
✓ Branch 3 → 4 taken 17 times.
✓ Branch 3 → 5 taken 21 times.
38 if (!strcmp(name, "PROACTIVE_DEFENCE")) {
802 17 return SECTION_PROACTIVE_DEFENCE;
803 }
804
2/2
✓ Branch 5 → 6 taken 5 times.
✓ Branch 5 → 7 taken 16 times.
21 else if (!strcmp(name, "PERMISSIONS")) {
805 5 return SECTION_PERMISSIONS;
806 }
807 }
808 36 return SECTION_NONE;
809 }
810
811 static inline
812 266 void i360_yaml_parse_key_value(int section_id, char *key, char *value, int *mode, i360_yaml_config_t *config) {
813
2/2
✓ Branch 2 → 3 taken 24 times.
✓ Branch 2 → 16 taken 242 times.
266 if (section_id == SECTION_PROACTIVE_DEFENCE) {
814
3/4
✓ Branch 3 → 4 taken 10 times.
✓ Branch 3 → 6 taken 14 times.
✓ Branch 4 → 5 taken 10 times.
✗ Branch 4 → 6 not taken.
24 if (!strcmp(key, "blamer") && config) {
815 10 i360_parse_bool(value, &config->blamer);
816 }
817
1/4
✗ Branch 6 → 7 not taken.
✓ Branch 6 → 9 taken 24 times.
✗ Branch 7 → 8 not taken.
✗ Branch 7 → 9 not taken.
24 if (!strcmp(key, "jit_compatible_mode") && config) {
818 i360_parse_bool(value, &config->jit);
819 }
820
1/4
✗ Branch 9 → 10 not taken.
✓ Branch 9 → 12 taken 24 times.
✗ Branch 10 → 11 not taken.
✗ Branch 10 → 12 not taken.
24 if (!strcmp(key, "log_whitelisted") && config) {
821 i360_parse_bool(value, &config->log_whitelisted);
822 }
823
3/4
✓ Branch 12 → 13 taken 14 times.
✓ Branch 12 → 16 taken 10 times.
✓ Branch 13 → 14 taken 14 times.
✗ Branch 13 → 16 not taken.
24 if (!strcmp(key, "mode") && mode) {
824 14 *mode = i360_parse_mode(value);
825 }
826 }
827
2/2
✓ Branch 16 → 17 taken 12 times.
✓ Branch 16 → 20 taken 254 times.
266 if (section_id == SECTION_PERMISSIONS) {
828
3/4
✓ Branch 17 → 18 taken 5 times.
✓ Branch 17 → 20 taken 7 times.
✓ Branch 18 → 19 taken 5 times.
✗ Branch 18 → 20 not taken.
12 if (!strcmp(key, "user_override_proactive_defense") && config) {
829 5 i360_parse_bool(value, &config->override);
830 }
831 }
832 266 }
833
834 static inline
835 23 int i360_yaml_read(yaml_parser_t parser, i360_yaml_config_t *config) {
836 23 yaml_token_t token, key = { .type = YAML_NO_TOKEN };
837 23 int is_key = 0, is_value = 0;
838 23 int section_id = SECTION_NONE;
839 23 int mode = -1;
840
841 #define EXTRACT(token) ((char*)token.data.scalar.value)
842
843 do {
844 1312 yaml_parser_scan(&parser, &token);
845
846
7/7
✓ Branch 4 → 5 taken 259 times.
✓ Branch 4 → 6 taken 259 times.
✓ Branch 4 → 7 taken 58 times.
✓ Branch 4 → 10 taken 525 times.
✓ Branch 4 → 16 taken 1 time.
✓ Branch 4 → 20 taken 71 times.
✓ Branch 4 → 21 taken 139 times.
1312 switch (token.type) {
847 259 case YAML_KEY_TOKEN:
848 259 is_key = 1; is_value = 0;
849 259 break;
850 259 case YAML_VALUE_TOKEN:
851 259 is_key = 0; is_value = 1;
852 259 break;
853 58 case YAML_BLOCK_MAPPING_START_TOKEN:
854 // Previous key is the section name, read which section it is
855 58 section_id = i360_yaml_section_name_to_id(EXTRACT(key));
856 58 yaml_token_delete(&key);
857 58 break;
858 525 case YAML_SCALAR_TOKEN:
859
2/2
✓ Branch 10 → 11 taken 259 times.
✓ Branch 10 → 12 taken 266 times.
525 if (is_key) {
860 259 key = token;
861 259 continue;
862 }
863
1/2
✓ Branch 12 → 13 taken 266 times.
✗ Branch 12 → 15 not taken.
266 if (is_value) {
864 // interpret here
865 266 i360_yaml_parse_key_value(section_id, EXTRACT(key), EXTRACT(token), &mode, config);
866 // interpret here
867 266 yaml_token_delete(&key);
868 }
869 266 break;
870 1 case YAML_NO_TOKEN:
871 1 yaml_token_delete(&token);
872
1/2
✓ Branch 17 → 18 taken 1 time.
✗ Branch 17 → 19 not taken.
1 if (config) {
873 1 config->blamer = -1;
874 1 config->jit = -1;
875 1 config->override = -1;
876 1 config->log_whitelisted = -1;
877 }
878 1 return -1;
879 71 case YAML_BLOCK_END_TOKEN:
880 71 section_id = SECTION_NONE;
881 210 default:
882 // fall through is deliberate
883 210 break;
884 }
885
2/2
✓ Branch 22 → 23 taken 1030 times.
✓ Branch 22 → 24 taken 22 times.
1052 if (token.type != YAML_STREAM_END_TOKEN)
886 1030 yaml_token_delete(&token);
887
2/2
✓ Branch 24 → 25 taken 1289 times.
✓ Branch 24 → 26 taken 22 times.
1311 } while (token.type != YAML_STREAM_END_TOKEN);
888
889 22 yaml_token_delete(&token);
890
891 22 return mode;
892 }
893
894 /* location:
895 * global == 0 - global i360 config
896 * local == 1 - user-specified config
897 */
898 28 int i360_parse_yaml_conf(const char *filename, int location, i360_yaml_config_t *config) {
899 yaml_parser_t parser;
900 28 int mode = -1;
901
902 28 FILE *fh = fopen(filename, "r");
903 /* error with user-specified config -> use global config */
904
4/4
✓ Branch 3 → 4 taken 5 times.
✓ Branch 3 → 6 taken 23 times.
✓ Branch 4 → 5 taken 4 times.
✓ Branch 4 → 6 taken 1 time.
28 if (fh == NULL && location == 1)
905 4 return -1;
906 /* error with global config -> mode disabled */
907
2/2
✓ Branch 6 → 7 taken 1 time.
✓ Branch 6 → 8 taken 23 times.
24 else if (fh == NULL)
908 1 return DISABLED;
909
910
1/2
✗ Branch 9 → 10 not taken.
✓ Branch 9 → 12 taken 23 times.
23 if (!yaml_parser_initialize(&parser)) {
911 fclose(fh);
912 return DISABLED;
913 }
914 23 yaml_parser_set_input_file(&parser, fh);
915
916 23 mode = i360_yaml_read(parser, config);
917
918 23 yaml_parser_delete(&parser);
919 23 fclose(fh);
920
921 /* proactive_defence not specified -> use global config */
922
4/4
✓ Branch 16 → 17 taken 11 times.
✓ Branch 16 → 19 taken 12 times.
✓ Branch 17 → 18 taken 7 times.
✓ Branch 17 → 19 taken 4 times.
23 if (mode < 0 && location == 1)
923 7 return -1;
924 /* proactive_defence not specified in global config -> disabled */
925
2/2
✓ Branch 19 → 20 taken 4 times.
✓ Branch 19 → 21 taken 12 times.
16 else if (mode < 0)
926 4 return DISABLED;
927
928 12 return mode;
929 }
930