mirror of
				https://github.com/Telecominfraproject/wlan-ap.git
				synced 2025-11-04 04:18:07 +00:00 
			
		
		
		
	udhnssnoop: move the code directly into the repo
Signed-off-by: John Crispin <john@phrozen.org>
This commit is contained in:
		@@ -6,12 +6,6 @@ PKG_RELEASE:=1
 | 
				
			|||||||
PKG_LICENSE:=GPL-2.0
 | 
					PKG_LICENSE:=GPL-2.0
 | 
				
			||||||
PKG_MAINTAINER:=John Crispin <john@phrozen.org>
 | 
					PKG_MAINTAINER:=John Crispin <john@phrozen.org>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
PKG_SOURCE_URL=https://github.com/blogic/udnssnoop.git
 | 
					 | 
				
			||||||
PKG_MIRROR_HASH:=afd17cc6aed4a151bc0f437b84491d751932a39f93f429418200e9e8be53dfad
 | 
					 | 
				
			||||||
PKG_SOURCE_PROTO:=git
 | 
					 | 
				
			||||||
PKG_SOURCE_DATE:=2021-04-12
 | 
					 | 
				
			||||||
PKG_SOURCE_VERSION:=67e1e5f0bfc12222aa59c54e7066b1c00a680e56
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
include $(INCLUDE_DIR)/package.mk
 | 
					include $(INCLUDE_DIR)/package.mk
 | 
				
			||||||
include $(INCLUDE_DIR)/cmake.mk
 | 
					include $(INCLUDE_DIR)/cmake.mk
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										4
									
								
								feeds/ucentral/udnssnoop/src/.gitignore
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										4
									
								
								feeds/ucentral/udnssnoop/src/.gitignore
									
									
									
									
										vendored
									
									
										Normal file
									
								
							@@ -0,0 +1,4 @@
 | 
				
			|||||||
 | 
					CMakeCache.txt
 | 
				
			||||||
 | 
					CMakeFiles/
 | 
				
			||||||
 | 
					cmake_install.cmake
 | 
				
			||||||
 | 
					udnssnoop
 | 
				
			||||||
							
								
								
									
										16
									
								
								feeds/ucentral/udnssnoop/src/CMakeLists.txt
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										16
									
								
								feeds/ucentral/udnssnoop/src/CMakeLists.txt
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,16 @@
 | 
				
			|||||||
 | 
					cmake_minimum_required(VERSION 2.6)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					PROJECT(udnssnoop C)
 | 
				
			||||||
 | 
					INCLUDE(GNUInstallDirs)
 | 
				
			||||||
 | 
					ADD_DEFINITIONS(-Os -ggdb -Wall -Werror --std=gnu99 -Wmissing-declarations)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					SET(CMAKE_SHARED_LIBRARY_LINK_C_FLAGS "")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					SET(SOURCES main.c dns.c)
 | 
				
			||||||
 | 
					SET(LIBS ubox ubus resolv)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					ADD_EXECUTABLE(udnssnoop ${SOURCES})
 | 
				
			||||||
 | 
					TARGET_LINK_LIBRARIES(udnssnoop ${LIBS})
 | 
				
			||||||
 | 
					INSTALL(TARGETS udnssnoop
 | 
				
			||||||
 | 
						RUNTIME DESTINATION ${CMAKE_INSTALL_SBINDIR}
 | 
				
			||||||
 | 
					)
 | 
				
			||||||
							
								
								
									
										215
									
								
								feeds/ucentral/udnssnoop/src/dns.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										215
									
								
								feeds/ucentral/udnssnoop/src/dns.c
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,215 @@
 | 
				
			|||||||
 | 
					/* SPDX-License-Identifier: BSD-3-Clause */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include "dns.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static char name_buffer[MAX_NAME_LEN + 1];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static int
 | 
				
			||||||
 | 
					scan_name(const uint8_t *buffer, int len)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						int offset = 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						while (len && (*buffer != '\0')) {
 | 
				
			||||||
 | 
							int l = *buffer;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							if (IS_COMPRESSED(l))
 | 
				
			||||||
 | 
								return offset + 2;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							if (l + 1 > len) return -1;
 | 
				
			||||||
 | 
							len -= l + 1;
 | 
				
			||||||
 | 
							offset += l + 1;
 | 
				
			||||||
 | 
							buffer += l + 1;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (!len || !offset || (*buffer != '\0'))
 | 
				
			||||||
 | 
							return -1;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return offset + 1;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static struct dns_header*
 | 
				
			||||||
 | 
					dns_consume_header(uint8_t **data, int *len)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						struct dns_header *h = (struct dns_header *) *data;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (*len < sizeof(struct dns_header))
 | 
				
			||||||
 | 
							return NULL;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						h->id = be16_to_cpu(h->id);
 | 
				
			||||||
 | 
						h->flags = be16_to_cpu(h->flags);
 | 
				
			||||||
 | 
						h->questions = be16_to_cpu(h->questions);
 | 
				
			||||||
 | 
						h->answers = be16_to_cpu(h->answers);
 | 
				
			||||||
 | 
						h->authority = be16_to_cpu(h->authority);
 | 
				
			||||||
 | 
						h->additional = be16_to_cpu(h->additional);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						*len -= sizeof(struct dns_header);
 | 
				
			||||||
 | 
						*data += sizeof(struct dns_header);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return h;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static struct dns_question*
 | 
				
			||||||
 | 
					dns_consume_question(uint8_t **data, int *len)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						struct dns_question *q = (struct dns_question *) *data;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (*len < sizeof(struct dns_question))
 | 
				
			||||||
 | 
							return NULL;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						q->type = be16_to_cpu(q->type);
 | 
				
			||||||
 | 
						q->class = be16_to_cpu(q->class);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						*len -= sizeof(struct dns_question);
 | 
				
			||||||
 | 
						*data += sizeof(struct dns_question);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return q;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static struct dns_answer*
 | 
				
			||||||
 | 
					dns_consume_answer(uint8_t **data, int *len)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						struct dns_answer *a = (struct dns_answer *) *data;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (*len < sizeof(struct dns_answer))
 | 
				
			||||||
 | 
							return NULL;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						a->type = be16_to_cpu(a->type);
 | 
				
			||||||
 | 
						a->class = be16_to_cpu(a->class);
 | 
				
			||||||
 | 
						a->ttl = be32_to_cpu(a->ttl);
 | 
				
			||||||
 | 
						a->rdlength = be16_to_cpu(a->rdlength);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						*len -= sizeof(struct dns_answer);
 | 
				
			||||||
 | 
						*data += sizeof(struct dns_answer);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return a;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static char *
 | 
				
			||||||
 | 
					dns_consume_name(const uint8_t *base, int blen, uint8_t **data, int *len)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						int nlen = scan_name(*data, *len);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (nlen < 1)
 | 
				
			||||||
 | 
							return NULL;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (dn_expand(base, base + blen, *data, name_buffer, MAX_NAME_LEN) < 0) {
 | 
				
			||||||
 | 
							perror("dns_consume_name/dn_expand");
 | 
				
			||||||
 | 
							return NULL;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						*len -= nlen;
 | 
				
			||||||
 | 
						*data += nlen;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return name_buffer;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static int
 | 
				
			||||||
 | 
					parse_answer(uint8_t *buffer, int len, uint8_t **b, int *rlen)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						char *name = dns_consume_name(buffer, len, b, rlen);
 | 
				
			||||||
 | 
						struct dns_answer *a;
 | 
				
			||||||
 | 
						uint8_t *rdata;
 | 
				
			||||||
 | 
						char ipbuf[33];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (*rlen < 0) {
 | 
				
			||||||
 | 
							fprintf(stderr, "dropping: bad answer - bad length\n");
 | 
				
			||||||
 | 
							return -1;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						a = dns_consume_answer(b, rlen);
 | 
				
			||||||
 | 
						if (!a) {
 | 
				
			||||||
 | 
							fprintf(stderr, "dropping: bad answer - bad buffer\n");
 | 
				
			||||||
 | 
							return -1;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (!name) {
 | 
				
			||||||
 | 
							return 0;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if ((a->class & ~CLASS_FLUSH) != CLASS_IN) {
 | 
				
			||||||
 | 
							fprintf(stderr, "dropping: class\n");
 | 
				
			||||||
 | 
							return -1;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						rdata = *b;
 | 
				
			||||||
 | 
						if (a->rdlength > *rlen) {
 | 
				
			||||||
 | 
							fprintf(stderr, "dropping: bad answer - bad rlen\n");
 | 
				
			||||||
 | 
							return -1;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						*rlen -= a->rdlength;
 | 
				
			||||||
 | 
						*b += a->rdlength;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						switch (a->type) {
 | 
				
			||||||
 | 
						case TYPE_A:
 | 
				
			||||||
 | 
							if (a->rdlength != 4)
 | 
				
			||||||
 | 
								return 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							if (!inet_ntop(AF_INET, rdata, ipbuf, sizeof(ipbuf)))
 | 
				
			||||||
 | 
								return 0;
 | 
				
			||||||
 | 
							break;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						case TYPE_AAAA:
 | 
				
			||||||
 | 
							if (a->rdlength != 16)
 | 
				
			||||||
 | 
								return 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							if (!inet_ntop(AF_INET6, rdata, ipbuf, sizeof(ipbuf)))
 | 
				
			||||||
 | 
								return 0;
 | 
				
			||||||
 | 
							break;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						default:
 | 
				
			||||||
 | 
							return 0;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						ubus_notify_qosify(name, ipbuf, a->type, a->ttl);
 | 
				
			||||||
 | 
						printf("%s %s %" PRIu32 "\n", name, ipbuf, a->ttl);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return 0;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void
 | 
				
			||||||
 | 
					dns_handle_packet(uint8_t *buffer, int len)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						struct dns_header *h;
 | 
				
			||||||
 | 
						uint8_t *b = buffer;
 | 
				
			||||||
 | 
						int rlen = len;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						h = dns_consume_header(&b, &rlen);
 | 
				
			||||||
 | 
						if (!h) {
 | 
				
			||||||
 | 
							fprintf(stderr, "dropping: bad header\n");
 | 
				
			||||||
 | 
							return;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (!(h->flags & FLAG_RESPONSE))
 | 
				
			||||||
 | 
							return;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (!h->answers)
 | 
				
			||||||
 | 
							return;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						while (h->questions-- > 0) {
 | 
				
			||||||
 | 
							char *name = dns_consume_name(buffer, len, &b, &rlen);
 | 
				
			||||||
 | 
							struct dns_question *q;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							if (!name || rlen < 0)
 | 
				
			||||||
 | 
								return;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							q = dns_consume_question(&b, &rlen);
 | 
				
			||||||
 | 
							if (!q) {
 | 
				
			||||||
 | 
								fprintf(stderr, "dropping: bad question\n");
 | 
				
			||||||
 | 
								return;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						while (h->answers-- > 0)
 | 
				
			||||||
 | 
							if (parse_answer(buffer, len, &b, &rlen))
 | 
				
			||||||
 | 
								return;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/*	while (h->authority-- > 0)
 | 
				
			||||||
 | 
							if (parse_answer(buffer, len, &b, &rlen))
 | 
				
			||||||
 | 
								return;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						while (h->additional-- > 0)
 | 
				
			||||||
 | 
							if (parse_answer(buffer, len, &b, &rlen))
 | 
				
			||||||
 | 
								return;
 | 
				
			||||||
 | 
					*/
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										86
									
								
								feeds/ucentral/udnssnoop/src/dns.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										86
									
								
								feeds/ucentral/udnssnoop/src/dns.h
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,86 @@
 | 
				
			|||||||
 | 
					/* SPDX-License-Identifier: BSD-3-Clause */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#ifndef _DNS_H__
 | 
				
			||||||
 | 
					#define _DNS_H__
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#define _GNU_SOURCE
 | 
				
			||||||
 | 
					#include <stdio.h>
 | 
				
			||||||
 | 
					#include <stdlib.h>
 | 
				
			||||||
 | 
					#include <stdint.h>
 | 
				
			||||||
 | 
					#include <string.h>
 | 
				
			||||||
 | 
					#include <inttypes.h>
 | 
				
			||||||
 | 
					#include <netinet/ip.h>
 | 
				
			||||||
 | 
					#include <netinet/in.h>
 | 
				
			||||||
 | 
					#include <sys/socket.h>
 | 
				
			||||||
 | 
					#include <arpa/inet.h>
 | 
				
			||||||
 | 
					#include <linux/if_ether.h>
 | 
				
			||||||
 | 
					#include <linux/filter.h>
 | 
				
			||||||
 | 
					#include <linux/udp.h>
 | 
				
			||||||
 | 
					#include <netinet/ip6.h>
 | 
				
			||||||
 | 
					#include <arpa/inet.h>
 | 
				
			||||||
 | 
					#include <arpa/nameser.h>
 | 
				
			||||||
 | 
					#include <resolv.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include <libubox/avl-cmp.h>
 | 
				
			||||||
 | 
					#include <libubox/utils.h>
 | 
				
			||||||
 | 
					#include <libubox/uloop.h>
 | 
				
			||||||
 | 
					#include <libubox/ulog.h>
 | 
				
			||||||
 | 
					#include <libubus.h>
 | 
				
			||||||
 | 
					#include <uci.h>
 | 
				
			||||||
 | 
					#include <uci_blob.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#define FLAG_RESPONSE		0x8000
 | 
				
			||||||
 | 
					#define FLAG_AUTHORATIVE	0x0400
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#define TYPE_A			0x0001
 | 
				
			||||||
 | 
					#define TYPE_PTR		0x000C
 | 
				
			||||||
 | 
					#define TYPE_TXT		0x0010
 | 
				
			||||||
 | 
					#define TYPE_AAAA		0x001c
 | 
				
			||||||
 | 
					#define TYPE_SRV		0x0021
 | 
				
			||||||
 | 
					#define TYPE_ANY		0x00ff
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#define IS_COMPRESSED(x)	((x & 0xc0) == 0xc0)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#define CLASS_FLUSH		0x8000
 | 
				
			||||||
 | 
					#define CLASS_UNICAST		0x8000
 | 
				
			||||||
 | 
					#define CLASS_IN		0x0001
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#define MAX_NAME_LEN            8096
 | 
				
			||||||
 | 
					#define MAX_DATA_LEN            8096
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					struct vlan_hdr {
 | 
				
			||||||
 | 
						uint16_t h_vlan_TCI;
 | 
				
			||||||
 | 
						uint16_t h_vlan_encapsulated_proto;
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					struct dns_header {
 | 
				
			||||||
 | 
						uint16_t id;
 | 
				
			||||||
 | 
						uint16_t flags;
 | 
				
			||||||
 | 
						uint16_t questions;
 | 
				
			||||||
 | 
						uint16_t answers;
 | 
				
			||||||
 | 
						uint16_t authority;
 | 
				
			||||||
 | 
						uint16_t additional;
 | 
				
			||||||
 | 
					} __attribute__((packed));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					struct dns_srv_data {
 | 
				
			||||||
 | 
						uint16_t priority;
 | 
				
			||||||
 | 
						uint16_t weight;
 | 
				
			||||||
 | 
						uint16_t port;
 | 
				
			||||||
 | 
					} __attribute__((packed));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					struct dns_answer {
 | 
				
			||||||
 | 
						uint16_t type;
 | 
				
			||||||
 | 
						uint16_t class;
 | 
				
			||||||
 | 
						uint32_t ttl;
 | 
				
			||||||
 | 
						uint16_t rdlength;
 | 
				
			||||||
 | 
					} __attribute__((packed));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					struct dns_question {
 | 
				
			||||||
 | 
						uint16_t type;
 | 
				
			||||||
 | 
						uint16_t class;
 | 
				
			||||||
 | 
					} __attribute__((packed));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void dns_handle_packet(uint8_t *buffer, int len);
 | 
				
			||||||
 | 
					void ubus_notify_qosify(char *name, char *address, int type, int ttl);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
							
								
								
									
										282
									
								
								feeds/ucentral/udnssnoop/src/main.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										282
									
								
								feeds/ucentral/udnssnoop/src/main.c
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,282 @@
 | 
				
			|||||||
 | 
					/* SPDX-License-Identifier: BSD-3-Clause */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* code is derived from hapd proxy_arp snooping */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include "dns.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					 /* sudo tcpdump -s 3000 -dd greater 96 and '(ip or ip6)' and '(udp or tcp)' and '(port 53)' */
 | 
				
			||||||
 | 
					static struct sock_filter dns_sock_filter_insns[] = {
 | 
				
			||||||
 | 
						{ 0x80, 0, 0, 0x00000000 },
 | 
				
			||||||
 | 
						{ 0x35, 0, 19, 0x00000060 },
 | 
				
			||||||
 | 
						{ 0x28, 0, 0, 0x0000000c },
 | 
				
			||||||
 | 
						{ 0x15, 0, 9, 0x00000800 },
 | 
				
			||||||
 | 
						{ 0x30, 0, 0, 0x00000017 },
 | 
				
			||||||
 | 
						{ 0x15, 0, 15, 0x00000011 },
 | 
				
			||||||
 | 
						{ 0x28, 0, 0, 0x00000014 },
 | 
				
			||||||
 | 
						{ 0x45, 13, 0, 0x00001fff },
 | 
				
			||||||
 | 
						{ 0xb1, 0, 0, 0x0000000e },
 | 
				
			||||||
 | 
						{ 0x48, 0, 0, 0x0000000e },
 | 
				
			||||||
 | 
						{ 0x15, 9, 0, 0x00000035 },
 | 
				
			||||||
 | 
						{ 0x48, 0, 0, 0x00000010 },
 | 
				
			||||||
 | 
						{ 0x15, 7, 8, 0x00000035 },
 | 
				
			||||||
 | 
						{ 0x15, 0, 7, 0x000086dd },
 | 
				
			||||||
 | 
						{ 0x30, 0, 0, 0x00000014 },
 | 
				
			||||||
 | 
						{ 0x15, 0, 5, 0x00000011 },
 | 
				
			||||||
 | 
						{ 0x28, 0, 0, 0x00000036 },
 | 
				
			||||||
 | 
						{ 0x15, 2, 0, 0x00000035 },
 | 
				
			||||||
 | 
						{ 0x28, 0, 0, 0x00000038 },
 | 
				
			||||||
 | 
						{ 0x15, 0, 1, 0x00000035 },
 | 
				
			||||||
 | 
						{ 0x6, 0, 0, 0x00000bb8 },
 | 
				
			||||||
 | 
						{ 0x6, 0, 0, 0x00000000 },
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static const struct sock_fprog sock_filter = {
 | 
				
			||||||
 | 
						.len = ARRAY_SIZE(dns_sock_filter_insns),
 | 
				
			||||||
 | 
						.filter = dns_sock_filter_insns,
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static struct ubus_auto_conn conn;
 | 
				
			||||||
 | 
					static struct uloop_fd fd;
 | 
				
			||||||
 | 
					static struct blob_buf b;
 | 
				
			||||||
 | 
					static char *ifname;
 | 
				
			||||||
 | 
					static int qosify;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static struct ubus_object_type ubus_object_type = {
 | 
				
			||||||
 | 
						.name = "dnssnoop"
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static void ubus_state_handler(struct ubus_context *ctx, struct ubus_object *obj)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					struct ubus_object ubus_object = {
 | 
				
			||||||
 | 
						.name = "dnssnoop",
 | 
				
			||||||
 | 
						.type = &ubus_object_type,
 | 
				
			||||||
 | 
						.subscribe_cb = ubus_state_handler,
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static int
 | 
				
			||||||
 | 
					proto_is_vlan(uint16_t h_proto)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						return !!(h_proto == ETH_P_8021Q ||
 | 
				
			||||||
 | 
							  h_proto == ETH_P_8021AD);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static int
 | 
				
			||||||
 | 
					consume_buffer(uint8_t **buf, int *len, int size)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						if (size > *len)
 | 
				
			||||||
 | 
							return -1;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						*buf += size;
 | 
				
			||||||
 | 
						*len -= size;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return 0;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static void
 | 
				
			||||||
 | 
					packet_handle(uint8_t *buf, int len)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						struct ethhdr *eth = (struct ethhdr *)buf;
 | 
				
			||||||
 | 
						uint16_t h_proto;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (consume_buffer(&buf, &len, sizeof(*eth)))
 | 
				
			||||||
 | 
							return;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						h_proto = eth->h_proto;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (proto_is_vlan(ntohs(h_proto))) {
 | 
				
			||||||
 | 
							struct vlan_hdr *vlanh = (struct vlan_hdr *)buf;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							if (consume_buffer(&buf, &len, sizeof(struct vlan_hdr)))
 | 
				
			||||||
 | 
								return;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							h_proto = vlanh->h_vlan_encapsulated_proto;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						switch (ntohs(eth->h_proto)) {
 | 
				
			||||||
 | 
						case ETH_P_IP:
 | 
				
			||||||
 | 
							if (consume_buffer(&buf, &len, sizeof(struct ip)))
 | 
				
			||||||
 | 
								return;
 | 
				
			||||||
 | 
							break;
 | 
				
			||||||
 | 
						case ETH_P_IPV6:
 | 
				
			||||||
 | 
							if (consume_buffer(&buf, &len, sizeof(struct ip6_hdr)))
 | 
				
			||||||
 | 
								return;
 | 
				
			||||||
 | 
							break;
 | 
				
			||||||
 | 
						default:
 | 
				
			||||||
 | 
							return;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (consume_buffer(&buf, &len, sizeof(struct udphdr)))
 | 
				
			||||||
 | 
							return;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						dns_handle_packet(buf, len);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static void
 | 
				
			||||||
 | 
					socket_fd_cb(struct uloop_fd *fd, unsigned int events)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						uint8_t buf[8192];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						do {
 | 
				
			||||||
 | 
							int len = recvfrom(fd->fd, buf, sizeof(buf), MSG_DONTWAIT, NULL, NULL);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							if (len <= 0) {
 | 
				
			||||||
 | 
								switch (errno) {
 | 
				
			||||||
 | 
								case EINTR:
 | 
				
			||||||
 | 
								case EAGAIN:
 | 
				
			||||||
 | 
									return;
 | 
				
			||||||
 | 
								default:
 | 
				
			||||||
 | 
									exit(1);
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
								break;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							packet_handle(buf, len);
 | 
				
			||||||
 | 
						} while (true);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static int
 | 
				
			||||||
 | 
					socket_open(void)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						int sock;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						sock = socket(PF_PACKET, SOCK_RAW, htons(ETH_P_ALL));
 | 
				
			||||||
 | 
						if (sock == -1) {
 | 
				
			||||||
 | 
							ULOG_ERR("failed to open socket on %s\n", ifname);
 | 
				
			||||||
 | 
							return -1;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (setsockopt(sock, SOL_SOCKET, SO_BINDTODEVICE, ifname, strlen(ifname))) {
 | 
				
			||||||
 | 
							ULOG_ERR("failed to bind socket to %s\n", ifname);
 | 
				
			||||||
 | 
							close(sock);
 | 
				
			||||||
 | 
							return -1;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (setsockopt(sock, SOL_SOCKET, SO_ATTACH_FILTER,
 | 
				
			||||||
 | 
							       &sock_filter, sizeof(struct sock_fprog))) {
 | 
				
			||||||
 | 
							ULOG_ERR("failed to attach filter to %s\n", ifname);
 | 
				
			||||||
 | 
							close(sock);
 | 
				
			||||||
 | 
							return -1;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return sock;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static void
 | 
				
			||||||
 | 
					snoop_start(void)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						int sock = socket_open();
 | 
				
			||||||
 | 
						if (sock == -1) {
 | 
				
			||||||
 | 
							ULOG_ERR("failed to open socket on %s\n", ifname);
 | 
				
			||||||
 | 
							return;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						fd.cb = socket_fd_cb;
 | 
				
			||||||
 | 
						fd.fd = sock;
 | 
				
			||||||
 | 
						uloop_fd_add(&fd, ULOOP_READ);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void
 | 
				
			||||||
 | 
					ubus_notify_qosify(char *name, char *address, int type, int ttl)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						if (!qosify)
 | 
				
			||||||
 | 
							return;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						blob_buf_init(&b, 0);
 | 
				
			||||||
 | 
						switch (type) {
 | 
				
			||||||
 | 
						case TYPE_AAAA:
 | 
				
			||||||
 | 
							blobmsg_add_string(&b, "type", "AAAA");
 | 
				
			||||||
 | 
							break;
 | 
				
			||||||
 | 
						case TYPE_A:
 | 
				
			||||||
 | 
							blobmsg_add_string(&b, "type", "A");
 | 
				
			||||||
 | 
							break;
 | 
				
			||||||
 | 
						default:
 | 
				
			||||||
 | 
							return;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						blobmsg_add_string(&b, "name", name);
 | 
				
			||||||
 | 
						blobmsg_add_string(&b, "address", address);
 | 
				
			||||||
 | 
					        blobmsg_add_u32(&b, "ttl", ttl);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						ubus_invoke(&conn.ctx, qosify, "add_dns_host", b.head, NULL, NULL, 200);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static void
 | 
				
			||||||
 | 
					ubus_handle_status(struct ubus_context *ctx,  struct ubus_event_handler *ev,
 | 
				
			||||||
 | 
						      const char *type, struct blob_attr *msg)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						enum {
 | 
				
			||||||
 | 
							EVENT_ID,
 | 
				
			||||||
 | 
							EVENT_PATH,
 | 
				
			||||||
 | 
							__EVENT_MAX
 | 
				
			||||||
 | 
						};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						static const struct blobmsg_policy status_policy[__EVENT_MAX] = {
 | 
				
			||||||
 | 
							[EVENT_ID] = { .name = "id", .type = BLOBMSG_TYPE_INT32 },
 | 
				
			||||||
 | 
							[EVENT_PATH] = { .name = "path", .type = BLOBMSG_TYPE_STRING },
 | 
				
			||||||
 | 
						};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						struct blob_attr *tb[__EVENT_MAX];
 | 
				
			||||||
 | 
						uint32_t id;
 | 
				
			||||||
 | 
						char *path;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						blobmsg_parse(status_policy, __EVENT_MAX, tb, blob_data(msg), blob_len(msg));
 | 
				
			||||||
 | 
						if (!tb[EVENT_ID] || !tb[EVENT_PATH])
 | 
				
			||||||
 | 
							return;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						path = blobmsg_get_string(tb[EVENT_PATH]);
 | 
				
			||||||
 | 
						id = blobmsg_get_u32(tb[EVENT_ID]);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (strcmp(path, "qosify"))
 | 
				
			||||||
 | 
							return;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (!strcmp("ubus.object.remove", type))
 | 
				
			||||||
 | 
							qosify = 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (!strcmp("ubus.object.add", type))
 | 
				
			||||||
 | 
							qosify = id;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static void
 | 
				
			||||||
 | 
					ubus_lookup_cb(struct ubus_context *ctx, struct ubus_object_data *obj,
 | 
				
			||||||
 | 
					                    void *priv)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						if (strcmp(obj->path, "qosify"))
 | 
				
			||||||
 | 
							return;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						qosify = obj->id;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static struct ubus_event_handler ubus_status_handler = { .cb = ubus_handle_status };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static void
 | 
				
			||||||
 | 
					ubus_connect_handler(struct ubus_context *ctx)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					        ULOG_NOTE("connected to ubus\n");
 | 
				
			||||||
 | 
						ubus_add_object(ctx, &ubus_object);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						ubus_register_event_handler(ctx, &ubus_status_handler, "ubus.object.add");
 | 
				
			||||||
 | 
						ubus_register_event_handler(ctx, &ubus_status_handler, "ubus.object.remove");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						ubus_lookup(ctx, NULL, ubus_lookup_cb, NULL);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					int
 | 
				
			||||||
 | 
					main(int argc, char **argv)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						if (argc != 2)
 | 
				
			||||||
 | 
							return -1;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						ifname = argv[1];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						ulog_open(ULOG_STDIO | ULOG_SYSLOG, LOG_DAEMON, "udnssnoop");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						uloop_init();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						conn.cb = ubus_connect_handler;
 | 
				
			||||||
 | 
					        ubus_auto_connect(&conn);
 | 
				
			||||||
 | 
						snoop_start();
 | 
				
			||||||
 | 
						uloop_run();
 | 
				
			||||||
 | 
						uloop_done();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return 0;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
		Reference in New Issue
	
	Block a user