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