diff --git a/src/config.c b/src/config.c index 34f134e0c3550a0c2b8ad6014a622b6d4330509b..dc05072f537aad9157cced1e0da5b3db8819af8d 100644 --- a/src/config.c +++ b/src/config.c @@ -299,18 +299,40 @@ static void create_mac_list(size_t i, struct uci_section *s) static void update_profile_pointer(size_t i, struct uci_section *s) { struct uci_element *element = NULL; + struct uci_element *e = NULL; + struct uci_section *sec = NULL; + int profile_found = 0; uci_foreach_element(&s->options, element) { - struct uci_option *option = (uci_to_option(element)); + struct uci_option *option = (uci_to_option(element)); if (strcmp(option->e.name, "profile") != 0) continue; - int j; + uci_foreach_element(&url_pkg->sections, e) { + struct uci_element *elem = NULL; + struct uci_option *opt = NULL; + + profile_found = 0; + sec = uci_to_section(e); + if (strcmp(sec->type, "profile") != 0) + continue; + uci_foreach_element(&sec->options, elem) { + opt = (uci_to_option(elem)); + if (strcmp(opt->e.name, "name") == 0) { + profile_found = 1; + break; + } + } + + if (profile_found == 1) { + int j; - for (j = 0; j < profile_cnt; j++) { - if (strcmp(option->v.string, (url_profile + j)->name) == 0) { - (url_filter + i)->p = &url_profile[j]; - break; + for (j = 0; j < profile_cnt; j++) { + if (strcmp(opt->v.string, (url_profile + j)->name) == 0) { + (url_filter + i)->p = &url_profile[j]; + return; + } + } } } diff --git a/src/filter.c b/src/filter.c index 876179c5cd235a6d3c82dbbe698ce4c952dc08e9..931dbd22977e273ac4706c9ac45ff5e58e88e524 100644 --- a/src/filter.c +++ b/src/filter.c @@ -46,6 +46,7 @@ #define CHECK_GLOBAL_URL_LIST -1 #define URL_SUCCESS 1 #define MAX_IP_LEN 32 +#define DNS_HDR_LEN_OVER_TCP 2U struct ubus_context *ctx; struct nfq_handle *nfq_h; @@ -186,9 +187,31 @@ static int get_ip_packet_payload(unsigned char *data_p, uint8_t *proto, size_t l payload_offset = (((size_t)iph->ihl)<<2U) + sizeof(struct udphdr) + sizeof(struct dnshdr); } else if (*proto == IPPROTO_TCP) { - // Return the payload offset in case of tcp packet. tcp_header = (const struct tcphdr *)(data_p + (iph->ihl<<2U)); - payload_offset = (((size_t)iph->ihl)<<2U) + ((size_t)tcp_header->doff<<2U); + + // If the packet is dns response then return the payload_offset as + // 0 and update the dns cache with the ip address. + if (ntohs(tcp_header->source) == DNS_PORT) { + unsigned char dns_payload[len + 1]; + + memset(dns_payload, '\0', len + 1U); + if (len <= ((((size_t)iph->ihl)<<2U) + ((size_t)tcp_header->doff<<2U) + DNS_HDR_LEN_OVER_TCP)) { + return -1; + } + memcpy(dns_payload, data_p+(((size_t)iph->ihl)<<2U) + ((size_t)tcp_header->doff<<2U) + DNS_HDR_LEN_OVER_TCP, len-((((size_t)iph->ihl)<<2U) + ((size_t)tcp_header->doff<<2U) + DNS_HDR_LEN_OVER_TCP) + 1U); + if ('\0' == dns_payload[0]) { + syslog(LOG_ERR, "payload is null"); + return -1; + } + parse_dns_response(dns_payload); + return 0; + } + else if (ntohs(tcp_header->dest) == DNS_PORT) { + // If the packet is dns query then return the payload offset. + payload_offset = (((size_t)iph->ihl)<<2U) + ((size_t)tcp_header->doff<<2U) + sizeof(struct dnshdr) + DNS_HDR_LEN_OVER_TCP; + } + else + payload_offset = (((size_t)iph->ihl)<<2U) + ((size_t)tcp_header->doff<<2U); } else { syslog(LOG_ERR, "Unknown protocol"); return -1; @@ -235,7 +258,33 @@ static int get_ip_packet_payload(unsigned char *data_p, uint8_t *proto, size_t l payload_offset += sizeof(struct udphdr) + sizeof(struct dnshdr); } else if (*proto == IPPROTO_TCP) { tcp_header = (const struct tcphdr *)((uint8_t *)ip6h + payload_offset); - payload_offset += ((size_t)tcp_header->doff<<2U); + + // Don't process DNS packets if ipv6 is not enabled + if (!is_ipv6_enabled()) + return 1; + // If the packet is dns response then return the payload_offset as + // 0 and update the dns cache with the ip address. + if (ntohs(tcp_header->source) == DNS_PORT) { + unsigned char dns_payload[len + 1]; + + memset(dns_payload, '\0', len + 1U); + if (len <= ((((size_t)iph->ihl)<<2U) + ((size_t)tcp_header->doff<<2U) + DNS_HDR_LEN_OVER_TCP)) { + return -1; + } + memcpy(dns_payload, data_p+payload_offset+((size_t)tcp_header->doff<<2U) + DNS_HDR_LEN_OVER_TCP, len-(payload_offset+((size_t)tcp_header->doff<<2U) + DNS_HDR_LEN_OVER_TCP) + 1U); + if ('\0' == dns_payload[0]) { + syslog(LOG_ERR, "payload is null"); + return -1; + } + parse_dns_response(dns_payload); + return 0; + } + else if (ntohs(tcp_header->dest) == DNS_PORT) { + // If the packet is dns query then return the payload offset. + payload_offset += ((size_t)tcp_header->doff<<2U) + sizeof(struct dnshdr) + DNS_HDR_LEN_OVER_TCP; + } + else + payload_offset += ((size_t)tcp_header->doff<<2U); } else { syslog(LOG_ERR, "Unknown protocol"); return -1; @@ -681,6 +730,9 @@ static int get_payload_pkt(int proto, unsigned char *data, int payload_offset, { if (proto == IPPROTO_TCP) { + // If the packet is a dns reponse then accept the packet. + if (payload_offset == 0) + return PKT_ACCEPT; // Check if its https packet or not, if yes then update the // payload_pkt with destination ip address. if (!is_ipv6) { @@ -776,6 +828,9 @@ static int handle_packet_filtering(struct nfq_data *payload) // Get the URL(http)/Destination IP address(https)/Domain name(DNS) if ((proto == IPPROTO_TCP) && is_ipv6) { + // If the packet is a dns reponse then accept the packet. + if (payload_offset == 0) + return PKT_ACCEPT; memset(ipv6_addr_str, 0, MAX_IPV6_LEN); ret = get_ipv6_tcp_payload_pkt(data, ipv6_addr_str, &is_https_packet);