1/* 2Copyright (C) 2020 Derry <destan19@126.com> 3 4Permission is hereby granted, free of charge, to any person obtaining a copy 5of this software and associated documentation files (the "Software"), to deal 6in the Software without restriction, including without limitation the rights 7to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 8copies of the Software, and to permit persons to whom the Software is 9furnished to do so, subject to the following conditions: 10 11The above copyright notice and this permission notice shall be included in 12all copies or substantial portions of the Software. 13 14THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 17AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 19OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 20THE SOFTWARE. 21*/ 22#include <unistd.h> 23#include <stdlib.h> 24#include <string.h> 25#include <libubox/uloop.h> 26#include <libubox/utils.h> 27#include <libubus.h> 28#include <sys/socket.h> 29#include <linux/netlink.h> 30#include <linux/socket.h> 31#include <sys/socket.h> 32#include <json-c/json.h> 33#include <sys/time.h> 34#include <libubox/blobmsg_json.h> 35#include <libubox/blobmsg.h> 36#include "appfilter_user.h" 37#include "appfilter_config.h" 38 39struct ubus_context *ubus_ctx = NULL; 40static struct blob_buf b; 41 42extern char *format_time(int timetamp); 43 44void get_hostname_by_mac(char *mac, char *hostname) 45{ 46 if (!mac || !hostname) 47 return; 48 FILE *fp = fopen("/tmp/dhcp.leases", "r"); 49 if (!fp) 50 { 51 printf("open dhcp lease file....failed\n"); 52 return; 53 } 54 char line_buf[256] = {0}; 55 while (fgets(line_buf, sizeof(line_buf), fp)) 56 { 57 char hostname_buf[128] = {0}; 58 char mac_buf[32] = {0}; 59 sscanf(line_buf, "%*s %s %*s %s", mac_buf, hostname_buf); 60 if (0 == strcmp(mac, mac_buf)) 61 { 62 strcpy(hostname, hostname_buf); 63 } 64 } 65 fclose(fp); 66} 67 68void ubus_dump_visit_list(struct blob_buf *b, char *mac) 69{ 70 int i, j; 71 void *c, *array; 72 void *t; 73 void *s; 74 75 array = blobmsg_open_array(b, "dev_list"); 76 77 for (i = 0; i < MAX_DEV_NODE_HASH_SIZE; i++) 78 { 79 dev_node_t *node = dev_hash_table[i]; 80 while (node) 81 { 82 if (mac && strcmp(mac, node->mac)) 83 { 84 node = node->next; 85 continue; 86 } 87 t = blobmsg_open_table(b, NULL); 88 blobmsg_add_string(b, "hostname", "unknown"); 89 blobmsg_add_string(b, "mac", node->mac); 90 blobmsg_add_string(b, "ip", node->ip); 91 void *visit_array; 92 93 visit_array = blobmsg_open_array(b, "visit_info"); 94 for (j = 0; j < MAX_VISIT_HASH_SIZE; j++) 95 { 96 visit_info_t *p_info = node->visit_htable[j]; 97 while (p_info) 98 { 99 char *first_time_str = format_time(p_info->first_time); 100 char *latest_time_str = format_time(p_info->latest_time); 101 int total_time = p_info->latest_time - p_info->first_time; 102 s = blobmsg_open_table(b, NULL); 103 blobmsg_add_string(b, "appname", "unknown"); 104 blobmsg_add_u32(b, "appid", p_info->appid); 105 blobmsg_add_u32(b, "latest_action", p_info->action); 106 blobmsg_add_u32(b, "first_time", p_info->first_time); 107 blobmsg_add_u32(b, "latest_time", p_info->latest_time); 108 blobmsg_close_table(b, s); 109 if (first_time_str) 110 free(first_time_str); 111 if (latest_time_str) 112 free(latest_time_str); 113 p_info = p_info->next; 114 } 115 } 116 117 blobmsg_close_array(b, visit_array); 118 blobmsg_close_table(b, t); 119 node = node->next; 120 } 121 } 122 blobmsg_close_array(b, array); 123} 124 125void update_app_visit_time_list(char *mac, struct app_visit_stat_info *visit_info) 126{ 127 int i, j, s; 128 int num = 0; 129 130 dev_node_t *node = find_dev_node(mac); 131 if (!node) 132 { 133 printf("not found mac:%s\n", mac); 134 return; 135 } 136 for (i = 0; i < MAX_APP_TYPE; i++) 137 { 138 for (j = 0; j < MAX_APP_ID_NUM; j++) 139 { 140 unsigned long long min = visit_info->visit_list[0].total_time; 141 int min_index = 0; 142 if (node->stat[i][j].total_time == 0) 143 continue; 144 if (num < MAX_APP_STAT_NUM) 145 { 146 min_index = num; 147 } 148 else 149 { 150 for (s = 0; s < MAX_APP_STAT_NUM; s++) 151 { 152 if (visit_info->visit_list[s].total_time < min) 153 { 154 min_index = s; 155 break; 156 } 157 } 158 } 159 num++; 160 if (node->stat[i][j].total_time > visit_info->visit_list[min_index].total_time) 161 { 162 visit_info->visit_list[min_index].total_time = node->stat[i][j].total_time; 163 visit_info->visit_list[min_index].app_id = (i + 1) * 1000 + j + 1; 164 } 165 } 166 } 167 if (num < MAX_APP_STAT_NUM) 168 visit_info->num = num; 169 else 170 visit_info->num = MAX_APP_STAT_NUM; 171} 172 173void update_app_class_visit_time_list(char *mac, int *visit_time) 174{ 175 int i, j, s; 176 int num = 0; 177 178 dev_node_t *node = find_dev_node(mac); 179 if (!node) 180 { 181 printf("not found mac:%s\n", mac); 182 return; 183 } 184 for (i = 0; i < MAX_APP_TYPE; i++) 185 { 186 for (j = 0; j < MAX_APP_ID_NUM; j++) 187 { 188 if (node->stat[i][j].total_time == 0) 189 continue; 190 visit_time[i] += node->stat[i][j].total_time; 191 } 192 } 193} 194 195void ubus_get_dev_visit_time_info(char *mac, struct blob_buf *b) 196{ 197 int i, j; 198 void *c, *array; 199 void *t; 200 void *s; 201 struct app_visit_stat_info info; 202 memset((char *)&info, 0x0, sizeof(info)); 203 update_app_visit_time_list(mac, &info); 204} 205 206static int 207appfilter_handle_visit_list(struct ubus_context *ctx, struct ubus_object *obj, 208 struct ubus_request_data *req, const char *method, 209 struct blob_attr *msg) 210{ 211 int ret; 212 blob_buf_init(&b, 0); 213 char *msg_obj_str = blobmsg_format_json(msg, true); 214 if (!msg_obj_str) 215 { 216 printf("format json failed\n"); 217 return 0; 218 } 219 220 struct json_object *req_obj = json_tokener_parse(msg_obj_str); 221 struct json_object *mac_obj = json_object_object_get(req_obj, "mac"); 222 223 if (!mac_obj) 224 { 225 ubus_dump_visit_list(&b, NULL); 226 } 227 else 228 ubus_dump_visit_list(&b, json_object_get_string(mac_obj)); 229 ubus_send_reply(ctx, req, b.head); 230 return 0; 231} 232 233typedef struct app_visit_time_info 234{ 235 int app_id; 236 unsigned long long total_time; 237} app_visit_time_info_t; 238 239int visit_time_compare(const void *a, const void *b) 240{ 241 app_visit_time_info_t *p1 = (app_visit_time_info_t *)a; 242 app_visit_time_info_t *p2 = (app_visit_time_info_t *)b; 243 return p1->total_time < p2->total_time ? 1 : -1; 244} 245 246#define MAX_STAT_APP_NUM 128 247void update_top5_app(dev_node_t *node, app_visit_time_info_t top5_app_list[]) 248{ 249 int i, j; 250 //memset(app_array, 0x0, sizeof(int) *size); 251 app_visit_time_info_t app_visit_array[MAX_STAT_APP_NUM]; 252 memset(app_visit_array, 0x0, sizeof(app_visit_array)); 253 int app_visit_num = 0; 254 255 for (i = 0; i < MAX_APP_TYPE; i++) 256 { 257 for (j = 0; j < MAX_APP_ID_NUM; j++) 258 { 259 if (node->stat[i][j].total_time == 0) 260 continue; 261 app_visit_array[app_visit_num].app_id = (i + 1) * 1000 + j + 1; 262 app_visit_array[app_visit_num].total_time = node->stat[i][j].total_time; 263 app_visit_num++; 264 } 265 } 266 267 qsort((void *)app_visit_array, app_visit_num, sizeof(app_visit_time_info_t), visit_time_compare); 268#if 0 269for (i = 0; i < app_visit_num; i++){ 270printf("appid %d-----------total time %llu\n", app_visit_array[i].app_id, 271app_visit_array[i].total_time); 272} 273#endif 274 for (i = 0; i < 5; i++) 275 { 276 top5_app_list[i] = app_visit_array[i]; 277 //printf("appid %d-----------total time %llu\n", app_visit_array[i].app_id, 278 // app_visit_array[i].total_time); 279 } 280} 281 282static int 283appfilter_handle_dev_list(struct ubus_context *ctx, struct ubus_object *obj, 284 struct ubus_request_data *req, const char *method, 285 struct blob_attr *msg) 286{ 287 int i, j; 288 struct json_object *root_obj = json_object_new_object(); 289 290 struct json_object *dev_array = json_object_new_array(); 291 int count = 0; 292 for (i = 0; i < MAX_DEV_NODE_HASH_SIZE; i++) 293 { 294 295 dev_node_t *node = dev_hash_table[i]; 296 while (node) 297 { 298 if (node->online == 0) 299 { 300 301 node = node->next; 302 continue; 303 } 304 struct json_object *dev_obj = json_object_new_object(); 305 struct json_object *app_array = json_object_new_array(); 306 app_visit_time_info_t top5_app_list[5]; 307 memset(top5_app_list, 0x0, sizeof(top5_app_list)); 308 update_top5_app(node, top5_app_list); 309 310 for (j = 0; j < 5; j++) 311 { 312 if (top5_app_list[j].app_id == 0) 313 break; 314 struct json_object *app_obj = json_object_new_object(); 315 json_object_object_add(app_obj, "id", json_object_new_int(top5_app_list[j].app_id)); 316 json_object_object_add(app_obj, "name", json_object_new_string(get_app_name_by_id(top5_app_list[j].app_id))); 317 json_object_array_add(app_array, app_obj); 318 } 319 320 json_object_object_add(dev_obj, "applist", app_array); 321 json_object_object_add(dev_obj, "mac", json_object_new_string(node->mac)); 322 char hostname[128] = {0}; 323 get_hostname_by_mac(node->mac, hostname); 324 json_object_object_add(dev_obj, "ip", json_object_new_string(node->ip)); 325 326 json_object_object_add(dev_obj, "online", json_object_new_int(1)); 327 json_object_object_add(dev_obj, "hostname", json_object_new_string(hostname)); 328 json_object_object_add(dev_obj, "latest_app", json_object_new_string("test")); 329 json_object_array_add(dev_array, dev_obj); 330 331 node = node->next; 332 count++; 333 if (count >= MAX_SUPPORT_DEV_NUM) 334 goto END; 335 } 336 } 337 for (i = 0; i < MAX_DEV_NODE_HASH_SIZE; i++) 338 { 339 dev_node_t *node = dev_hash_table[i]; 340 while (node) 341 { 342 if (node->online != 0) 343 { 344 345 node = node->next; 346 continue; 347 } 348 struct json_object *dev_obj = json_object_new_object(); 349 struct json_object *app_array = json_object_new_array(); 350 app_visit_time_info_t top5_app_list[5]; 351 memset(top5_app_list, 0x0, sizeof(top5_app_list)); 352 update_top5_app(node, top5_app_list); 353 354 for (j = 0; j < 5; j++) 355 { 356 if (top5_app_list[j].app_id == 0) 357 break; 358 struct json_object *app_obj = json_object_new_object(); 359 json_object_object_add(app_obj, "id", json_object_new_int(top5_app_list[j].app_id)); 360 json_object_object_add(app_obj, "name", json_object_new_string(get_app_name_by_id(top5_app_list[j].app_id))); 361 json_object_array_add(app_array, app_obj); 362 } 363 364 json_object_object_add(dev_obj, "applist", app_array); 365 json_object_object_add(dev_obj, "mac", json_object_new_string(node->mac)); 366 char hostname[32] = {0}; 367 get_hostname_by_mac(node->mac, hostname); 368 json_object_object_add(dev_obj, "ip", json_object_new_string(node->ip)); 369 370 json_object_object_add(dev_obj, "online", json_object_new_int(0)); 371 json_object_object_add(dev_obj, "hostname", json_object_new_string(hostname)); 372 json_object_object_add(dev_obj, "latest_app", json_object_new_string("test")); 373 json_object_array_add(dev_array, dev_obj); 374 node = node->next; 375 count++; 376 if (count >= MAX_SUPPORT_DEV_NUM) 377 goto END; 378 } 379 } 380 381END: 382 383 json_object_object_add(root_obj, "devlist", dev_array); 384 blob_buf_init(&b, 0); 385 blobmsg_add_object(&b, root_obj); 386 ubus_send_reply(ctx, req, b.head); 387 json_object_put(root_obj); 388 return 0; 389} 390 391static int 392appfilter_handle_visit_time(struct ubus_context *ctx, struct ubus_object *obj, 393 struct ubus_request_data *req, const char *method, 394 struct blob_attr *msg) 395{ 396 int ret; 397 struct app_visit_stat_info info; 398 blob_buf_init(&b, 0); 399 memset((char *)&info, 0x0, sizeof(info)); 400 char *msg_obj_str = blobmsg_format_json(msg, true); 401 if (!msg_obj_str) 402 { 403 printf("format json failed\n"); 404 return 0; 405 } 406 407 struct json_object *req_obj = json_tokener_parse(msg_obj_str); 408 struct json_object *mac_obj = json_object_object_get(req_obj, "mac"); 409 if (!mac_obj) 410 { 411 printf("mac is NULL\n"); 412 return 0; 413 } 414 update_app_visit_time_list(json_object_get_string(mac_obj), &info); 415 416 struct json_object *resp_obj = json_object_new_object(); 417 struct json_object *app_info_array = json_object_new_array(); 418 json_object_object_add(resp_obj, "app_list", app_info_array); 419 int i; 420 for (i = 0; i < info.num; i++) 421 { 422 struct json_object *app_info_obj = json_object_new_object(); 423 json_object_object_add(app_info_obj, "app_id", 424 json_object_new_string(get_app_name_by_id(info.visit_list[i].app_id))); 425 json_object_object_add(app_info_obj, "visit_time", 426 json_object_new_int(info.visit_list[i].total_time)); 427 json_object_array_add(app_info_array, app_info_obj); 428 } 429 430 blobmsg_add_object(&b, resp_obj); 431 ubus_send_reply(ctx, req, b.head); 432 json_object_put(resp_obj); 433 json_object_put(req_obj); 434 return 0; 435} 436 437static int 438handle_app_class_visit_time(struct ubus_context *ctx, struct ubus_object *obj, 439 struct ubus_request_data *req, const char *method, 440 struct blob_attr *msg) 441{ 442 int ret; 443 int i; 444 blob_buf_init(&b, 0); 445 char *msg_obj_str = blobmsg_format_json(msg, true); 446 if (!msg_obj_str) 447 { 448 printf("format json failed\n"); 449 return 0; 450 } 451 452 struct json_object *req_obj = json_tokener_parse(msg_obj_str); 453 struct json_object *mac_obj = json_object_object_get(req_obj, "mac"); 454 if (!mac_obj) 455 { 456 printf("mac is NULL\n"); 457 return 0; 458 } 459 int app_class_visit_time[MAX_APP_TYPE]; 460 memset(app_class_visit_time, 0x0, sizeof(app_class_visit_time)); 461 update_app_class_visit_time_list(json_object_get_string(mac_obj), app_class_visit_time); 462 463 struct json_object *resp_obj = json_object_new_object(); 464 struct json_object *app_class_array = json_object_new_array(); 465 json_object_object_add(resp_obj, "class_list", app_class_array); 466 for (i = 0; i < MAX_APP_TYPE; i++) 467 { 468 if (i >= g_cur_class_num) 469 break; 470 struct json_object *app_class_obj = json_object_new_object(); 471 json_object_object_add(app_class_obj, "type", json_object_new_int(i)); 472 json_object_object_add(app_class_obj, "name", json_object_new_string(CLASS_NAME_TABLE[i])); 473 json_object_object_add(app_class_obj, "visit_time", json_object_new_int(app_class_visit_time[i])); 474 json_object_array_add(app_class_array, app_class_obj); 475 } 476 477 blobmsg_add_object(&b, resp_obj); 478 ubus_send_reply(ctx, req, b.head); 479 json_object_put(resp_obj); 480 json_object_put(req_obj); 481 return 0; 482} 483 484static const struct blobmsg_policy empty_policy[1] = { 485 //[DEV_NAME] = { .name = "name", .type = BLOBMSG_TYPE_STRING }, 486}; 487 488static struct ubus_method appfilter_object_methods[] = { 489 UBUS_METHOD("visit_list", appfilter_handle_visit_list, empty_policy), 490 UBUS_METHOD("dev_visit_time", appfilter_handle_visit_time, empty_policy), 491 UBUS_METHOD("app_class_visit_time", handle_app_class_visit_time, empty_policy), 492 UBUS_METHOD("dev_list", appfilter_handle_dev_list, empty_policy), 493}; 494 495static struct ubus_object_type main_object_type = 496 UBUS_OBJECT_TYPE("appfilter", appfilter_object_methods); 497 498static struct ubus_object main_object = { 499 .name = "appfilter", 500 .type = &main_object_type, 501 .methods = appfilter_object_methods, 502 .n_methods = ARRAY_SIZE(appfilter_object_methods), 503}; 504 505static void appfilter_add_object(struct ubus_object *obj) 506{ 507 int ret = ubus_add_object(ubus_ctx, obj); 508 509 if (ret != 0) 510 fprintf(stderr, "Failed to publish object '%s': %s\n", obj->name, ubus_strerror(ret)); 511} 512 513int appfilter_ubus_init(void) 514{ 515 ubus_ctx = ubus_connect("/var/run/ubus/ubus.sock"); 516 if (!ubus_ctx){ 517 ubus_ctx = ubus_connect("/var/run/ubus.sock"); 518 } 519 if (!ubus_ctx){ 520 return -EIO; 521 } 522 523 appfilter_add_object(&main_object); 524 ubus_add_uloop(ubus_ctx); 525 return 0; 526} 527