GCC Code Coverage Report


Directory: ../replacer/
File: storage.c
Date: 2025-09-18 11:49:41
Exec Total Coverage
Lines: 99 114 86.8%
Functions: 8 11 72.7%
Branches: 63 79 79.7%

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