From: Remi Gacogne Date: Tue, 4 Feb 2025 16:03:51 +0000 (+0100) Subject: dnsdist: Delint xdp.py X-Git-Tag: dnsdist-2.0.0-alpha1~124^2 X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=refs%2Fpull%2F15120%2Fhead;p=thirdparty%2Fpdns.git dnsdist: Delint xdp.py --- diff --git a/contrib/xdp.py b/contrib/xdp.py index 9ad0124931..c8e05d581f 100644 --- a/contrib/xdp.py +++ b/contrib/xdp.py @@ -7,7 +7,78 @@ import netaddr from bcc import BPF # Constants -QTYPES = {'LOC': 29, '*': 255, 'IXFR': 251, 'UINFO': 100, 'NSEC3': 50, 'AAAA': 28, 'CNAME': 5, 'MINFO': 14, 'EID': 31, 'GPOS': 27, 'X25': 19, 'HINFO': 13, 'CAA': 257, 'NULL': 10, 'DNSKEY': 48, 'DS': 43, 'ISDN': 20, 'SOA': 6, 'RP': 17, 'UID': 101, 'TALINK': 58, 'TKEY': 249, 'PX': 26, 'NSAP-PTR': 23, 'TXT': 16, 'IPSECKEY': 45, 'DNAME': 39, 'MAILA': 254, 'AFSDB': 18, 'SSHFP': 44, 'NS': 2, 'PTR': 12, 'SPF': 99, 'TA': 32768, 'A': 1, 'NXT': 30, 'AXFR': 252, 'RKEY': 57, 'KEY': 25, 'NIMLOC': 32, 'A6': 38, 'TLSA': 52, 'MG': 8, 'HIP': 55, 'NSEC': 47, 'GID': 102, 'SRV': 33, 'DLV': 32769, 'NSEC3PARAM': 51, 'UNSPEC': 103, 'TSIG': 250, 'ATMA': 34, 'RRSIG': 46, 'OPT': 41, 'MD': 3, 'NAPTR': 35, 'MF': 4, 'MB': 7, 'DHCID': 49, 'MX': 15, 'MAILB': 253, 'CERT': 37, 'NINFO': 56, 'APL': 42, 'MR': 9, 'SIG': 24, 'WKS': 11, 'KX': 36, 'NSAP': 22, 'RT': 21, 'SINK': 40} +QTYPES = {'LOC': 29, + '*': 255, + 'IXFR': 251, + 'UINFO': 100, + 'NSEC3': 50, + 'AAAA': 28, + 'CNAME': 5, + 'MINFO': 14, + 'EID': 31, + 'GPOS': 27, + 'X25': 19, + 'HINFO': 13, + 'CAA': 257, + 'NULL': 10, + 'DNSKEY': 48, + 'DS': 43, + 'ISDN': 20, + 'SOA': 6, + 'RP': 17, + 'UID': 101, + 'TALINK': 58, + 'TKEY': 249, + 'PX': 26, + 'NSAP-PTR': 23, + 'TXT': 16, + 'IPSECKEY': 45, + 'DNAME': 39, + 'MAILA': 254, + 'AFSDB': 18, + 'SSHFP': 44, + 'NS': 2, + 'PTR': 12, + 'SPF': 99, + 'TA': 32768, + 'A': 1, + 'NXT': 30, + 'AXFR': 252, + 'RKEY': 57, + 'KEY': 25, + 'NIMLOC': 32, + 'A6': 38, + 'TLSA': 52, + 'MG': 8, + 'HIP': 55, + 'NSEC': 47, + 'GID': 102, + 'SRV': 33, + 'DLV': 32769, + 'NSEC3PARAM': 51, + 'UNSPEC': 103, + 'TSIG': 250, + 'ATMA': 34, + 'RRSIG': 46, + 'OPT': 41, + 'MD': 3, + 'NAPTR': 35, + 'MF': 4, + 'MB': 7, + 'DHCID': 49, + 'MX': 15, + 'MAILB': 253, + 'CERT': 37, + 'NINFO': 56, + 'APL': 42, + 'MR': 9, + 'SIG': 24, + 'WKS': 11, + 'KX': 36, + 'NSAP': 22, + 'RT': 21, + 'SINK': 40 +} INV_QTYPES = {v: k for k, v in QTYPES.items()} ACTIONS = {1 : 'DROP', 2 : 'TC'} @@ -22,27 +93,32 @@ blocked_ipv4 = [("192.0.2.1", TC_ACTION)] blocked_ipv6 = [("2001:db8::1", TC_ACTION)] blocked_cidr4 = [("192.0.1.1/24", TC_ACTION)] blocked_cidr6 = [("2001:db8::1/128", TC_ACTION)] -blocked_qnames = [("localhost", "A", DROP_ACTION), ("test.com", "*", TC_ACTION)] +blocked_qnames = [("localhost", "A", DROP_ACTION), + ("test.com", "*", TC_ACTION)] # Main parser = argparse.ArgumentParser(description='XDP helper for DNSDist') -parser.add_argument('--interface', '-i', type=str, default='eth0', help='The interface on which the filter will be attached') -parser.add_argument('--maps-size', '-m', type=int, default=1024, help='Maximum number of entries in the eBPF maps') -parser.add_argument('--number-of-queues', '-q', type=int, default=64, help='Maximum number of network queues in XSK (AF_XDP) mode') -parser.add_argument('--xsk', action='store_true', help='Enable XSK (AF_XDP) mode', default=False) +parser.add_argument('--interface', '-i', type=str, default='eth0', + help='The interface on which the filter will be attached') +parser.add_argument('--maps-size', '-m', type=int, default=1024, + help='Maximum number of entries in the eBPF maps') +parser.add_argument('--number-of-queues', '-q', type=int, default=64, + help='Maximum number of network queues in XSK (AF_XDP) mode') +parser.add_argument('--xsk', action='store_true', default=False, + help='Enable XSK (AF_XDP) mode') parameters = parser.parse_args() cflag = [f'-DDDIST_MAX_NUMBER_OF_QUEUES={parameters.number_of_queues}', f'-DDDIST_MAPS_SIZE={parameters.maps_size}'] if parameters.xsk: - print(f'Enabling XSK (AF_XDP) on {parameters.interface}..') - cflag.append('-DUseXsk') + print(f'Enabling XSK (AF_XDP) on {parameters.interface}..') + cflag.append('-DUseXsk') else: - Ports = [53] - portsStr = ', '.join(str(port) for port in Ports) - print(f'Enabling XDP on {parameters.interface} and ports {portsStr}..') - IN_DNS_PORT_SET = "||".join("COMPARE_PORT((x),"+str(i)+")" for i in Ports) - cflag.append(r"-DIN_DNS_PORT_SET(x)=(" + IN_DNS_PORT_SET + r")") + ports = [53] + ports_str = ', '.join(str(port) for port in ports) + print(f'Enabling XDP on {parameters.interface} and ports {ports_str}..') + IN_DNS_PORT_SET = "||".join("COMPARE_PORT((x),"+str(i)+")" for i in ports) + cflag.append(r"-DIN_DNS_PORT_SET(x)=(" + IN_DNS_PORT_SET + r")") xdp = BPF(src_file="xdp-filter.ebpf.src", cflags=cflag) @@ -54,96 +130,103 @@ v6filter = xdp.get_table("v6filter") cidr4filter = xdp.get_table("cidr4filter") cidr6filter = xdp.get_table("cidr6filter") qnamefilter = xdp.get_table("qnamefilter") -xskDestinations = None +xsk_destinations4 = None +xsk_destinations6 = None if parameters.xsk: - xskDestinations = xdp.get_table("xskDestinationsV4") + xsk_destinations4 = xdp.get_table("xskDestinationsV4") + xsk_destinations6 = xdp.get_table("xskDestinationsV6") for ip in blocked_ipv4: - print(f"Blocking {ip}") - key = v4filter.Key(int(netaddr.IPAddress(ip[0]).value)) - leaf = v4filter.Leaf() - leaf.counter = 0 - leaf.action = ip[1] - v4filter[key] = leaf + print(f"Blocking {ip}") + key = v4filter.Key(int(netaddr.IPAddress(ip[0]).value)) + leaf = v4filter.Leaf() + leaf.counter = 0 + leaf.action = ip[1] + v4filter[key] = leaf for ip in blocked_ipv6: - print(f"Blocking {ip}") - ipv6_int = int(netaddr.IPAddress(ip[0]).value) - ipv6_bytes = bytearray([(ipv6_int & (255 << 8*(15-i))) >> (8*(15-i)) for i in range(16)]) - key = (ct.c_uint8 * 16).from_buffer(ipv6_bytes) - leaf = v6filter.Leaf() - leaf.counter = 0 - leaf.action = ip[1] - v6filter[key] = leaf + print(f"Blocking {ip}") + ipv6_int = int(netaddr.IPAddress(ip[0]).value) + ipv6_bytes = bytearray([(ipv6_int & (255 << 8*(15-i))) >> (8*(15-i)) for i in range(16)]) + key = (ct.c_uint8 * 16).from_buffer(ipv6_bytes) + leaf = v6filter.Leaf() + leaf.counter = 0 + leaf.action = ip[1] + v6filter[key] = leaf for item in blocked_cidr4: - print(f"Blocking {item}") - key = cidr4filter.Key() - network = netaddr.IPNetwork(item[0]) - key.cidr = network.prefixlen - key.addr = socket.htonl(network.network.value) - leaf = cidr4filter.Leaf() - leaf.counter = 0 - leaf.action = item[1] - cidr4filter[key] = leaf + print(f"Blocking {item}") + key = cidr4filter.Key() + network = netaddr.IPNetwork(item[0]) + key.cidr = network.prefixlen + key.addr = socket.htonl(network.network.value) + leaf = cidr4filter.Leaf() + leaf.counter = 0 + leaf.action = item[1] + cidr4filter[key] = leaf for item in blocked_cidr6: - print(f"Blocking {item}") - key = cidr6filter.Key() - network = netaddr.IPNetwork(item[0]) - key.cidr = network.prefixlen - ipv6_int = int(network.network.value) - ipv6_bytes = bytearray([(ipv6_int & (255 << 8*(15-i))) >> (8*(15-i)) for i in range(16)]) - key.addr.in6_u.u6_addr8 = (ct.c_uint8 * 16).from_buffer(ipv6_bytes) - leaf = cidr6filter.Leaf() - leaf.counter = 0 - leaf.action = item[1] - cidr6filter[key] = leaf + print(f"Blocking {item}") + key = cidr6filter.Key() + network = netaddr.IPNetwork(item[0]) + key.cidr = network.prefixlen + ipv6_int = int(network.network.value) + ipv6_bytes = bytearray([(ipv6_int & (255 << 8*(15-i))) >> (8*(15-i)) for i in range(16)]) + key.addr.in6_u.u6_addr8 = (ct.c_uint8 * 16).from_buffer(ipv6_bytes) + leaf = cidr6filter.Leaf() + leaf.counter = 0 + leaf.action = item[1] + cidr6filter[key] = leaf for qname in blocked_qnames: - print(f"Blocking {qname}") - key = qnamefilter.Key() - qn = bytearray() - for sub in qname[0].split('.'): - qn.append(len(sub)) - for ch in sub: - qn.append(ord(ch)) - qn.extend((0,) * (255 - len(qn))) - key.qname = (ct.c_ubyte * 255).from_buffer(qn) - key.qtype = ct.c_uint16(QTYPES[qname[1]]) - leaf = qnamefilter.Leaf() - leaf.counter = 0 - leaf.action = qname[2] - qnamefilter[key] = leaf + print(f"Blocking {qname}") + key = qnamefilter.Key() + qn = bytearray() + for sub in qname[0].split('.'): + qn.append(len(sub)) + for ch in sub: + qn.append(ord(ch)) + qn.extend((0,) * (255 - len(qn))) + key.qname = (ct.c_ubyte * 255).from_buffer(qn) + key.qtype = ct.c_uint16(QTYPES[qname[1]]) + leaf = qnamefilter.Leaf() + leaf.counter = 0 + leaf.action = qname[2] + qnamefilter[key] = leaf print(f"Filter is ready on {parameters.interface}") try: - xdp.trace_print() + xdp.trace_print() except KeyboardInterrupt: - pass + pass if v4filter or v6filter or cidr4filter or cidr6filter: - print("Blocked networks:") - for item in v4filter.items(): - print(f"- {str(netaddr.IPAddress(item[0].value))} ({ACTIONS[item[1].action]}): {item[1].counter}") - for item in v6filter.items(): - print(f"- {str(socket.inet_ntop(socket.AF_INET6, item[0]))} ({ACTIONS[item[1].action]}): {item[1].counter}") - for item in cidr4filter.items(): - addr = netaddr.IPAddress(socket.ntohl(item[0].addr)) - print(f"- {str(addr)}/{str(item[0].cidr)} ({ACTIONS[item[1].action]}): {item[1].counter}") - for item in cidr6filter.items(): - print(f"- {str(socket.inet_ntop(socket.AF_INET6, item[0].addr))}/{str(item[0].cidr)} ({ACTIONS[item[1].action]}): {item[1].counter}") + print("Blocked networks:") + for item in v4filter.items(): + print(f"- {str(netaddr.IPAddress(item[0].value))} ({ACTIONS[item[1].action]}): {item[1].counter}") + + for item in v6filter.items(): + print(f"- {str(socket.inet_ntop(socket.AF_INET6, item[0]))} ({ACTIONS[item[1].action]}): {item[1].counter}") + + for item in cidr4filter.items(): + addr = netaddr.IPAddress(socket.ntohl(item[0].addr)) + print(f"- {str(addr)}/{str(item[0].cidr)} ({ACTIONS[item[1].action]}): {item[1].counter}") + + for item in cidr6filter.items(): + print(f"- {str(socket.inet_ntop(socket.AF_INET6, item[0].addr))}/{str(item[0].cidr)} ({ACTIONS[item[1].action]}): {item[1].counter}") if qnamefilter: - print("Blocked query names:") - for item in qnamefilter.items(): - print(f"- {''.join(map(chr, item[0].qname)).strip()}/{INV_QTYPES[item[0].qtype]} ({ACTIONS[item[1].action]}): {item[1].counter}") - -if parameters.xsk and xskDestinations: - print("Content of the AF_XDP (XSK) routing map:") - for item in xskDestinations.items(): - print(f"- {str(netaddr.IPAddress(socket.ntohl(item[0].addr)))}:{str(socket.ntohs(item[0].port))}") + print("Blocked query names:") + for item in qnamefilter.items(): + print(f"- {''.join(map(chr, item[0].qname)).strip()}/{INV_QTYPES[item[0].qtype]} ({ACTIONS[item[1].action]}): {item[1].counter}") + +if parameters.xsk and (xsk_destinations4 or xsk_destinations6): + print("Content of the AF_XDP (XSK) routing maps:") + for item in xsk_destinations4.items(): + print(f"- {str(netaddr.IPAddress(socket.ntohl(item[0].addr)))}:{str(socket.ntohs(item[0].port))}") + for item in xsk_destinations6.items(): + print(f"- {str(socket.inet_ntop(socket.AF_INET6, item[0].addr))}:{str(socket.ntohs(item[0].port))}") xdp.remove_xdp(parameters.interface, 0)