1 // SPDX-License-Identifier: GPL-2.0+ 2 /* 3 * Copyright (C) 2021 Felix Fietkau <nbd@nbd.name> 4 */ 5 #include <libubus.h> 6 7 #include "qosify.h" 8 9 static struct blob_buf b; 10 11 static int 12 qosify_ubus_add_array(struct blob_attr *attr, uint8_t val, enum qosify_map_id id) 13 { 14 struct blob_attr *cur; 15 int rem; 16 17 if (blobmsg_check_array(attr, BLOBMSG_TYPE_STRING) < 0) 18 return UBUS_STATUS_INVALID_ARGUMENT; 19 20 blobmsg_for_each_attr(cur, attr, rem) 21 qosify_map_set_entry(id, false, blobmsg_get_string(cur), val); 22 23 return 0; 24 } 25 26 static int 27 qosify_ubus_set_files(struct blob_attr *attr) 28 { 29 struct blob_attr *cur; 30 int rem; 31 32 if (blobmsg_check_array(attr, BLOBMSG_TYPE_STRING) < 0) 33 return UBUS_STATUS_INVALID_ARGUMENT; 34 35 qosify_map_clear_files(); 36 37 blobmsg_for_each_attr(cur, attr, rem) 38 qosify_map_load_file(blobmsg_get_string(cur)); 39 40 qosify_map_gc(); 41 42 return 0; 43 } 44 45 46 enum { 47 CL_ADD_DSCP, 48 CL_ADD_TIMEOUT, 49 CL_ADD_IPV4, 50 CL_ADD_IPV6, 51 CL_ADD_TCP_PORT, 52 CL_ADD_UDP_PORT, 53 CL_ADD_DNS, 54 __CL_ADD_MAX 55 }; 56 57 static const struct blobmsg_policy qosify_add_policy[__CL_ADD_MAX] = { 58 [CL_ADD_DSCP] = { "dscp", BLOBMSG_TYPE_STRING }, 59 [CL_ADD_TIMEOUT] = { "timeout", BLOBMSG_TYPE_INT32 }, 60 [CL_ADD_IPV4] = { "ipv4", BLOBMSG_TYPE_ARRAY }, 61 [CL_ADD_IPV6] = { "ipv6", BLOBMSG_TYPE_ARRAY }, 62 [CL_ADD_TCP_PORT] = { "tcp_port", BLOBMSG_TYPE_ARRAY }, 63 [CL_ADD_UDP_PORT] = { "udp_port", BLOBMSG_TYPE_ARRAY }, 64 [CL_ADD_DNS] = { "dns", BLOBMSG_TYPE_ARRAY }, 65 }; 66 67 68 static int 69 qosify_ubus_reload(struct ubus_context *ctx, struct ubus_object *obj, 70 struct ubus_request_data *req, const char *method, 71 struct blob_attr *msg) 72 { 73 qosify_map_reload(); 74 return 0; 75 } 76 77 78 static int 79 qosify_ubus_add(struct ubus_context *ctx, struct ubus_object *obj, 80 struct ubus_request_data *req, const char *method, 81 struct blob_attr *msg) 82 { 83 int prev_timemout = qosify_map_timeout; 84 struct blob_attr *tb[__CL_ADD_MAX]; 85 struct blob_attr *cur; 86 uint8_t dscp = 0xff; 87 int ret; 88 89 blobmsg_parse(qosify_add_policy, __CL_ADD_MAX, tb, 90 blobmsg_data(msg), blobmsg_len(msg)); 91 92 if (!strcmp(method, "add")) { 93 if ((cur = tb[CL_ADD_DSCP]) == NULL || 94 qosify_map_dscp_value(blobmsg_get_string(cur), &dscp)) 95 return UBUS_STATUS_INVALID_ARGUMENT; 96 97 if ((cur = tb[CL_ADD_TIMEOUT]) != NULL) 98 qosify_map_timeout = blobmsg_get_u32(cur); 99 } 100 101 if ((cur = tb[CL_ADD_IPV4]) != NULL && 102 (ret = qosify_ubus_add_array(cur, dscp, CL_MAP_IPV4_ADDR) != 0)) 103 return ret; 104 105 if ((cur = tb[CL_ADD_IPV6]) != NULL && 106 (ret = qosify_ubus_add_array(cur, dscp, CL_MAP_IPV6_ADDR) != 0)) 107 return ret; 108 109 if ((cur = tb[CL_ADD_TCP_PORT]) != NULL && 110 (ret = qosify_ubus_add_array(cur, dscp, CL_MAP_TCP_PORTS) != 0)) 111 return ret; 112 113 if ((cur = tb[CL_ADD_UDP_PORT]) != NULL && 114 (ret = qosify_ubus_add_array(cur, dscp, CL_MAP_UDP_PORTS) != 0)) 115 return ret; 116 117 if ((cur = tb[CL_ADD_DNS]) != NULL && 118 (ret = qosify_ubus_add_array(cur, dscp, CL_MAP_DNS) != 0)) 119 return ret; 120 121 qosify_map_timeout = prev_timemout; 122 123 return 0; 124 } 125 126 enum { 127 CL_CONFIG_RESET, 128 CL_CONFIG_FILES, 129 CL_CONFIG_TIMEOUT, 130 CL_CONFIG_DSCP_UDP, 131 CL_CONFIG_DSCP_TCP, 132 CL_CONFIG_DSCP_ICMP, 133 CL_CONFIG_INTERFACES, 134 CL_CONFIG_DEVICES, 135 CL_CONFIG_CLASSES, 136 __CL_CONFIG_MAX 137 }; 138 139 static const struct blobmsg_policy qosify_config_policy[__CL_CONFIG_MAX] = { 140 [CL_CONFIG_RESET] = { "reset", BLOBMSG_TYPE_BOOL }, 141 [CL_CONFIG_FILES] = { "files", BLOBMSG_TYPE_ARRAY }, 142 [CL_CONFIG_TIMEOUT] = { "timeout", BLOBMSG_TYPE_INT32 }, 143 [CL_CONFIG_DSCP_UDP] = { "dscp_default_udp", BLOBMSG_TYPE_STRING }, 144 [CL_CONFIG_DSCP_TCP] = { "dscp_default_tcp", BLOBMSG_TYPE_STRING }, 145 [CL_CONFIG_DSCP_ICMP] = { "dscp_icmp", BLOBMSG_TYPE_STRING }, 146 [CL_CONFIG_INTERFACES] = { "interfaces", BLOBMSG_TYPE_TABLE }, 147 [CL_CONFIG_DEVICES] = { "devices", BLOBMSG_TYPE_TABLE }, 148 [CL_CONFIG_CLASSES] = { "classes", BLOBMSG_TYPE_TABLE }, 149 }; 150 151 static int 152 qosify_ubus_config(struct ubus_context *ctx, struct ubus_object *obj, 153 struct ubus_request_data *req, const char *method, 154 struct blob_attr *msg) 155 { 156 struct blob_attr *tb[__CL_CONFIG_MAX]; 157 struct blob_attr *cur; 158 uint8_t dscp; 159 bool reset = false; 160 int ret; 161 162 blobmsg_parse(qosify_config_policy, __CL_CONFIG_MAX, tb, 163 blobmsg_data(msg), blobmsg_len(msg)); 164 165 if ((cur = tb[CL_CONFIG_RESET]) != NULL) 166 reset = blobmsg_get_bool(cur); 167 168 if (reset) 169 qosify_map_reset_config(); 170 171 if ((cur = tb[CL_CONFIG_CLASSES]) != NULL || reset) 172 qosify_map_set_classes(cur); 173 174 if ((cur = tb[CL_CONFIG_TIMEOUT]) != NULL) 175 qosify_map_timeout = blobmsg_get_u32(cur); 176 177 if ((cur = tb[CL_CONFIG_FILES]) != NULL && 178 (ret = qosify_ubus_set_files(cur) != 0)) 179 return ret; 180 181 if (map_parse_flow_config(&flow_config, msg, reset) || 182 map_fill_dscp_value(&config.dscp_icmp, tb[CL_CONFIG_DSCP_ICMP], reset)) 183 return UBUS_STATUS_INVALID_ARGUMENT; 184 185 map_fill_dscp_value(&dscp, tb[CL_CONFIG_DSCP_UDP], true); 186 if (dscp != 0xff) 187 qosify_map_set_dscp_default(CL_MAP_UDP_PORTS, dscp); 188 189 map_fill_dscp_value(&dscp, tb[CL_CONFIG_DSCP_TCP], true); 190 if (dscp != 0xff) 191 qosify_map_set_dscp_default(CL_MAP_TCP_PORTS, dscp); 192 193 qosify_map_update_config(); 194 195 qosify_iface_config_update(tb[CL_CONFIG_INTERFACES], tb[CL_CONFIG_DEVICES]); 196 197 qosify_iface_check(); 198 199 return 0; 200 } 201 202 203 static int 204 qosify_ubus_dump(struct ubus_context *ctx, struct ubus_object *obj, 205 struct ubus_request_data *req, const char *method, 206 struct blob_attr *msg) 207 { 208 blob_buf_init(&b, 0); 209 qosify_map_dump(&b); 210 ubus_send_reply(ctx, req, b.head); 211 blob_buf_free(&b); 212 213 return 0; 214 } 215 216 static int 217 qosify_ubus_status(struct ubus_context *ctx, struct ubus_object *obj, 218 struct ubus_request_data *req, const char *method, 219 struct blob_attr *msg) 220 { 221 blob_buf_init(&b, 0); 222 qosify_iface_status(&b); 223 ubus_send_reply(ctx, req, b.head); 224 blob_buf_free(&b); 225 226 return 0; 227 } 228 229 static int 230 qosify_ubus_check_devices(struct ubus_context *ctx, struct ubus_object *obj, 231 struct ubus_request_data *req, const char *method, 232 struct blob_attr *msg) 233 { 234 qosify_iface_check(); 235 236 return 0; 237 } 238 239 enum { 240 CL_DNS_HOST_NAME, 241 CL_DNS_HOST_TYPE, 242 CL_DNS_HOST_ADDR, 243 CL_DNS_HOST_TTL, 244 __CL_DNS_HOST_MAX 245 }; 246 247 static const struct blobmsg_policy qosify_dns_policy[__CL_DNS_HOST_MAX] = { 248 [CL_DNS_HOST_NAME] = { "name", BLOBMSG_TYPE_STRING }, 249 [CL_DNS_HOST_TYPE] = { "type", BLOBMSG_TYPE_STRING }, 250 [CL_DNS_HOST_ADDR] = { "address", BLOBMSG_TYPE_STRING }, 251 [CL_DNS_HOST_TTL] = { "ttl", BLOBMSG_TYPE_INT32 }, 252 }; 253 254 static int 255 __qosify_ubus_add_dns_host(struct blob_attr *msg) 256 { 257 struct blob_attr *tb[__CL_DNS_HOST_MAX]; 258 struct blob_attr *cur; 259 uint32_t ttl = 0; 260 261 blobmsg_parse(qosify_dns_policy, __CL_DNS_HOST_MAX, tb, 262 blobmsg_data(msg), blobmsg_len(msg)); 263 264 if (!tb[CL_DNS_HOST_NAME] || !tb[CL_DNS_HOST_TYPE] || 265 !tb[CL_DNS_HOST_ADDR]) 266 return UBUS_STATUS_INVALID_ARGUMENT; 267 268 if ((cur = tb[CL_DNS_HOST_TTL]) != NULL) 269 ttl = blobmsg_get_u32(cur); 270 271 if (qosify_map_add_dns_host(blobmsg_get_string(tb[CL_DNS_HOST_NAME]), 272 blobmsg_get_string(tb[CL_DNS_HOST_ADDR]), 273 blobmsg_get_string(tb[CL_DNS_HOST_TYPE]), 274 ttl)) 275 return UBUS_STATUS_INVALID_ARGUMENT; 276 277 return 0; 278 } 279 280 static int 281 qosify_ubus_add_dns_host(struct ubus_context *ctx, struct ubus_object *obj, 282 struct ubus_request_data *req, const char *method, 283 struct blob_attr *msg) 284 { 285 return __qosify_ubus_add_dns_host(msg); 286 } 287 288 static const struct ubus_method qosify_methods[] = { 289 UBUS_METHOD_NOARG("reload", qosify_ubus_reload), 290 UBUS_METHOD("add", qosify_ubus_add, qosify_add_policy), 291 UBUS_METHOD_MASK("remove", qosify_ubus_add, qosify_add_policy, 292 ((1 << __CL_ADD_MAX) - 1) & ~(1 << CL_ADD_DSCP)), 293 UBUS_METHOD("config", qosify_ubus_config, qosify_config_policy), 294 UBUS_METHOD_NOARG("dump", qosify_ubus_dump), 295 UBUS_METHOD_NOARG("status", qosify_ubus_status), 296 UBUS_METHOD("add_dns_host", qosify_ubus_add_dns_host, qosify_dns_policy), 297 UBUS_METHOD_NOARG("check_devices", qosify_ubus_check_devices), 298 }; 299 300 static struct ubus_object_type qosify_object_type = 301 UBUS_OBJECT_TYPE("qosify", qosify_methods); 302 303 static struct ubus_object qosify_object = { 304 .name = "qosify", 305 .type = &qosify_object_type, 306 .methods = qosify_methods, 307 .n_methods = ARRAY_SIZE(qosify_methods), 308 }; 309 310 static void 311 qosify_subscribe_dnsmasq(struct ubus_context *ctx) 312 { 313 static struct ubus_subscriber sub = { 314 .cb = qosify_ubus_add_dns_host, 315 }; 316 uint32_t id; 317 318 if (!sub.obj.id && 319 ubus_register_subscriber(ctx, &sub)) 320 return; 321 322 if (ubus_lookup_id(ctx, "dnsmasq.dns", &id)) 323 return; 324 325 ubus_subscribe(ctx, &sub, id); 326 } 327 328 static void 329 qosify_ubus_event_cb(struct ubus_context *ctx, struct ubus_event_handler *ev, 330 const char *type, struct blob_attr *msg) 331 { 332 static const struct blobmsg_policy policy = 333 { "path", BLOBMSG_TYPE_STRING }; 334 struct blob_attr *attr; 335 const char *path; 336 337 blobmsg_parse(&policy, 1, &attr, blobmsg_data(msg), blobmsg_len(msg)); 338 339 if (!attr) 340 return; 341 342 path = blobmsg_get_string(attr); 343 if (!strcmp(path, "dnsmasq.dns")) 344 qosify_subscribe_dnsmasq(ctx); 345 else if (!strcmp(path, "bridger")) 346 qosify_ubus_update_bridger(false); 347 } 348 349 350 static void 351 ubus_connect_handler(struct ubus_context *ctx) 352 { 353 static struct ubus_event_handler ev = { 354 .cb = qosify_ubus_event_cb 355 }; 356 357 ubus_add_object(ctx, &qosify_object); 358 ubus_register_event_handler(ctx, &ev, "ubus.object.add"); 359 qosify_subscribe_dnsmasq(ctx); 360 } 361 362 static struct ubus_auto_conn conn; 363 364 void qosify_ubus_update_bridger(bool shutdown) 365 { 366 struct ubus_request req; 367 uint32_t id; 368 void *c; 369 370 if (ubus_lookup_id(&conn.ctx, "bridger", &id)) 371 return; 372 373 blob_buf_init(&b, 0); 374 blobmsg_add_string(&b, "name", "qosify"); 375 c = blobmsg_open_array(&b, "devices"); 376 if (!shutdown) 377 qosify_iface_get_devices(&b); 378 blobmsg_close_array(&b, c); 379 380 ubus_invoke_async(&conn.ctx, id, "set_blacklist", b.head, &req); 381 } 382 383 int qosify_ubus_init(void) 384 { 385 conn.cb = ubus_connect_handler; 386 ubus_auto_connect(&conn); 387 388 return 0; 389 } 390 391 void qosify_ubus_stop(void) 392 { 393 qosify_ubus_update_bridger(true); 394 ubus_auto_shutdown(&conn); 395 } 396 397 struct iface_req { 398 char *name; 399 int len; 400 }; 401 402 static void 403 netifd_if_cb(struct ubus_request *req, int type, struct blob_attr *msg) 404 { 405 struct iface_req *ifr = req->priv; 406 enum { 407 IFS_ATTR_UP, 408 IFS_ATTR_DEV, 409 __IFS_ATTR_MAX 410 }; 411 static const struct blobmsg_policy policy[__IFS_ATTR_MAX] = { 412 [IFS_ATTR_UP] = { "up", BLOBMSG_TYPE_BOOL }, 413 [IFS_ATTR_DEV] = { "l3_device", BLOBMSG_TYPE_STRING }, 414 }; 415 struct blob_attr *tb[__IFS_ATTR_MAX]; 416 417 blobmsg_parse(policy, __IFS_ATTR_MAX, tb, blobmsg_data(msg), blobmsg_len(msg)); 418 419 if (!tb[IFS_ATTR_UP] || !tb[IFS_ATTR_DEV]) 420 return; 421 422 if (!blobmsg_get_bool(tb[IFS_ATTR_UP])) 423 return; 424 425 snprintf(ifr->name, ifr->len, "%s", blobmsg_get_string(tb[IFS_ATTR_DEV])); 426 } 427 428 int qosify_ubus_check_interface(const char *name, char *ifname, int ifname_len) 429 { 430 struct iface_req req = { ifname, ifname_len }; 431 char *obj_name = "network.interface."; 432 uint32_t id; 433 434 #define PREFIX "network.interface." 435 obj_name = alloca(sizeof(PREFIX) + strlen(name) + 1); 436 sprintf(obj_name, PREFIX "%s", name); 437 #undef PREFIX 438 439 ifname[0] = 0; 440 441 if (ubus_lookup_id(&conn.ctx, obj_name, &id)) 442 return -1; 443 444 blob_buf_init(&b, 0); 445 ubus_invoke(&conn.ctx, id, "status", b.head, netifd_if_cb, &req, 1000); 446 447 if (!ifname[0]) 448 return -1; 449 450 return 0; 451 } 452
This page was automatically generated by LXR 0.3.1. • OpenWrt