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 <sys/socket.h> 26#include <linux/netlink.h> 27#include <linux/socket.h> 28#include <sys/socket.h> 29#include <sys/time.h> 30#include <libubox/uloop.h> 31#include <libubox/utils.h> 32#include <libubus.h> 33#include <json-c/json.h> 34#include "appfilter_user.h" 35#include "appfilter_netlink.h" 36#define MAX_NL_RCV_BUF_SIZE 4096 37 38#define REPORT_INTERVAL_SECS 60 39void appfilter_nl_handler(struct uloop_fd *u, unsigned int ev) 40{ 41 int ret; 42 int i; 43 char buf[MAX_NL_RCV_BUF_SIZE]; 44 struct sockaddr_nl nladdr; 45 struct iovec iov = {buf, sizeof(buf)}; 46 struct nlmsghdr *h; 47 int type; 48 int id; 49 char *mac = NULL; 50 51 struct msghdr msg = { 52 .msg_name = &nladdr, 53 .msg_namelen = sizeof(nladdr), 54 .msg_iov = &iov, 55 .msg_iovlen = 1, 56 }; 57 58 do 59 { 60 ret = recvmsg(u->fd, &msg, 0); 61 } while ((-1 == ret) && (EINTR == errno)); 62 63 if (ret < 0) 64 { 65 printf("recv msg error\n"); 66 return; 67 } 68 else if (0 == ret) 69 { 70 return; 71 } 72 73 h = (struct nlmsghdr *)buf; 74 char *kmsg = (char *)NLMSG_DATA(h); 75 struct af_msg_hdr *af_hdr = (struct af_msg_hdr *)kmsg; 76 if (af_hdr->magic != 0xa0b0c0d0) 77 { 78 printf("magic error %x\n", af_hdr->magic); 79 return; 80 } 81 if (af_hdr->len <= 0 || af_hdr->len >= MAX_OAF_NETLINK_MSG_LEN) 82 { 83 printf("data len error\n"); 84 return; 85 } 86 87 char *kdata = kmsg + sizeof(struct af_msg_hdr); 88 struct json_object *root = json_tokener_parse(kdata); 89 if (!root) 90 { 91 printf("parse json failed:%s", kdata); 92 return; 93 } 94 95 struct json_object *mac_obj = json_object_object_get(root, "mac"); 96 97 if (!mac_obj) 98 { 99 printf("parse mac obj failed\n"); 100 json_object_put(root); 101 return; 102 } 103 104 mac = json_object_get_string(mac_obj); 105 106 dev_node_t *node = find_dev_node(mac); 107 108 if (!node) 109 { 110 node = add_dev_node(mac); 111 if (!node) 112 { 113 printf("add dev node failed\n"); 114 json_object_put(root); 115 return; 116 } 117 } 118 119 struct json_object *ip_obj = json_object_object_get(root, "ip"); 120 if (ip_obj) 121 strncpy(node->ip, json_object_get_string(ip_obj), sizeof(node->ip)); 122 struct json_object *visit_array = json_object_object_get(root, "visit_info"); 123 if (!visit_array) 124 { 125 json_object_put(root); 126 return; 127 } 128 for (i = 0; i < json_object_array_length(visit_array); i++) 129 { 130 struct json_object *visit_obj = json_object_array_get_idx(visit_array, i); 131 struct json_object *appid_obj = json_object_object_get(visit_obj, "appid"); 132 struct json_object *action_obj = json_object_object_get(visit_obj, "latest_action"); 133 struct json_object *up_obj = json_object_object_get(visit_obj, "up_bytes"); 134 struct json_object *down_obj = json_object_object_get(visit_obj, "down_bytes"); 135 struct timeval cur_time; 136 137 gettimeofday(&cur_time, NULL); 138 int appid = json_object_get_int(appid_obj); 139 int action = json_object_get_int(action_obj); 140 141 type = appid / 1000; 142 id = appid % 1000; 143 if (id <= 0 || type <= 0) 144 continue; 145 node->stat[type - 1][id - 1].total_time += REPORT_INTERVAL_SECS; 146 147 // node->stat[type - 1][id - 1].total_down_bytes += json_object_get_int(down_obj); 148 // node->stat[type - 1][id - 1].total_up_bytes += json_object_get_int(up_obj); 149 150 int hash = hash_appid(appid); 151 visit_info_t *head = node->visit_htable[hash]; 152 153 if (head && (cur_time.tv_sec - head->latest_time) < 300) 154 { 155 head->latest_time = cur_time.tv_sec; 156 } 157 else 158 { 159 visit_info_t *visit_node = (visit_info_t *)calloc(1, sizeof(visit_info_t)); 160 visit_node->action = action; 161 visit_node->appid = appid; 162 visit_node->latest_time = cur_time.tv_sec; 163 visit_node->first_time = cur_time.tv_sec - MIN_VISIT_TIME; 164 visit_node->next = NULL; 165 add_visit_info_node(&node->visit_htable[hash], visit_node); 166 } 167 } 168 169 json_object_put(root); 170} 171 172#define MAX_NL_MSG_LEN 1024 173int send_msg_to_kernel(int fd, void *msg, int len) 174{ 175 struct sockaddr_nl saddr, daddr; 176 memset(&daddr, 0, sizeof(daddr)); 177 daddr.nl_family = AF_NETLINK; 178 daddr.nl_pid = 0; // to kernel 179 daddr.nl_groups = 0; 180 int ret = 0; 181 struct nlmsghdr *nlh = NULL; 182 nlh = (struct nlmsghdr *)malloc(NLMSG_SPACE(MAX_NL_MSG_LEN)); 183 nlh->nlmsg_len = NLMSG_SPACE(MAX_NL_MSG_LEN); 184 nlh->nlmsg_flags = 0; 185 nlh->nlmsg_type = 0; 186 nlh->nlmsg_seq = 0; 187 nlh->nlmsg_pid = DEFAULT_USR_NL_PID; 188 189 char msg_buf[MAX_NL_MSG_LEN] = {0}; 190 struct af_msg_hdr *hdr = (struct af_msg_hdr *)msg_buf; 191 hdr->magic = 0xa0b0c0d0; 192 hdr->len = len; 193 char *p_data = msg_buf + sizeof(struct af_msg_hdr); 194 memcpy(p_data, msg, len); 195 196 memcpy(NLMSG_DATA(nlh), msg_buf, len + sizeof(struct af_msg_hdr)); 197 198 ret = sendto(fd, nlh, nlh->nlmsg_len, 0, (struct sockaddr *)&daddr, sizeof(struct sockaddr_nl)); 199 if (!ret) 200 { 201 perror("sendto error\n"); 202 return -1; 203 } 204 205 return 0; 206} 207 208int appfilter_nl_init(void) 209{ 210 int fd; 211 struct sockaddr_nl nls; 212 fd = socket(AF_NETLINK, SOCK_RAW, OAF_NETLINK_ID); 213 if (fd < 0) 214 { 215 printf("Connect netlink %d failed %s", OAF_NETLINK_ID, strerror(errno)); 216 exit(1); 217 } 218 memset(&nls, 0, sizeof(struct sockaddr_nl)); 219 nls.nl_pid = DEFAULT_USR_NL_PID; 220 nls.nl_groups = 0; 221 nls.nl_family = AF_NETLINK; 222 223 if (bind(fd, (void *)&nls, sizeof(struct sockaddr_nl))) 224 { 225 printf("Bind failed %s\n", strerror(errno)); 226 exit(1); 227 } 228 229 return fd; 230} 231