Zmaster
Zmaster

Reputation: 13

C# DNS Server redirection

I am trying to make my own dns server from scratch which will filter out domains with adult content and redirect user to web page with info that url they are trying to load contains adult content and that is is blocked.

So far so good, I have setup my own http server and I am replacing Ip addresses of blacklisted domain with my own server to display error (Not sure if this is right way to do it, and does other dna servers do it the same way).

Problem occures when I try to blacklist domain with https setup in which case after redirection browser displays error about untrusted source or something similar.

Is there a way to bypass this situation, or maybe to display my web page some other way?

SOLUTION:

It turned out it cannot be done with DNS as I planned, because I couldn't find out which domain is client tying to access so I could create fake certificate. After that I switched to proxy server instead of DNS server.

When client tries to connect to proxy server (for my solution I used TcpListener) first request will be CONNECT and it wont be encrypted so I could read domain from "Host" header and decide if domain should be blocked.

If blocked create fake certificate, open ssl connection (here is an example how to establish Ssl connection) and return block page as response, else with TcpClient make connection to real server and tunnel data both ways (Do not make SslStream, read and write directly to NetworkStream)

using(SslStream sslStream = new SslStream(context.ClientNetworkStream))
{
    sslStream.AuthenticateAsServer(fakeCert);

    sslStream.Write(blockPageData, 0, blockPageData.Length);
}

Also, how to create fake certificate:

public void CreateCertificate(string domain, string path, X509Certificate2 rootCert, string certPassword)
{
    string dirPath = Path.GetDirectoryName(path);

    if (!Directory.Exists(dirPath))
    {
        Directory.CreateDirectory(dirPath);
    }

    SubjectAlternativeNameBuilder sanBuilder = new SubjectAlternativeNameBuilder();
    sanBuilder.AddDnsName(domain);

    X500DistinguishedName distinguishedName = new X500DistinguishedName($"CN={domain}");

    using (RSA rsa = RSA.Create(2048))
    {
        CertificateRequest request = new CertificateRequest(distinguishedName, rsa, HashAlgorithmName.SHA256, RSASignaturePadding.Pkcs1);

        request.CertificateExtensions.Add(new X509KeyUsageExtension(X509KeyUsageFlags.DataEncipherment | X509KeyUsageFlags.KeyEncipherment | X509KeyUsageFlags.DigitalSignature, false));


        request.CertificateExtensions.Add(
            new X509EnhancedKeyUsageExtension(
                new OidCollection { new Oid("1.3.6.1.5.5.7.3.1") }, false));

        request.CertificateExtensions.Add(sanBuilder.Build());

        //Generates a cert, but does not provide a private key.
        using (X509Certificate2 certificate = request.Create(rootCert, new DateTimeOffset(rootCert.NotBefore), new DateTimeOffset(rootCert.NotAfter), new byte[] { 0, 1, 2, 3 }))
        {
            X509Certificate2 certWithPrivateKey = certificate.CopyWithPrivateKey(rsa);

            byte[] certBuffer = certWithPrivateKey.Export(X509ContentType.Pkcs12, certPassword);

            using (Stream stream = File.Create(path))
            {
                stream.Write(certBuffer, 0, certBuffer.Length);
            }
        }
    }
}          

Upvotes: 1

Views: 753

Answers (1)

Caius Jard
Caius Jard

Reputation: 74605

You're going to struggle with this one because the premise has a basic flaw:

  • your user has typed https://prawnsite.com into their browser
  • your DNS server has recognized it as an adult site and returned an Ip of 10.0.0.1 instead of the real 12.34.56.78
  • the browser has connected to 10.0.0.1 and is trying to do certificate exchange and get an ask cert that identifies the server truly as prawnsite.com, before it does anything else
  • your server doesn't have a certificate for that domain (but it could have if you obtained one)

There wouldn't me much worth in ssl certificates if any hacker could lash up a site that looks like your bank, infiltrate dns and redirect it so all the people on a particular ISP will be pointed to the fake site instead, and harvest their details. Which is basically what you're trying to do without the harvesting part. One of the major ideas of SSL as security is that the end user can be sure their computer really is talking to the server they want to be talking to, it's not just about encrypting the data so that people along the way (interim routers) can't grab it and inspect it

I mentioned that you could obtain a certificate for every site in your list; you may be able to find a service that issues basic ssl certificates intended for encrypting traffic but not validating server owner identity, on the fly. Have a google for "ssl on the fly" and see if anyone does it. Basic certs might well work for you, if for example the user isn't expecting (or doesn't care about) Extended Validation / green address bar. With an EV cert the issuer makes of sure the identity they are issuing for, but for a basic cert you just end up with a cert that bears the domain name being secured and once installed on your server the cert exchange will work out and the user's browser won't show any error


All that said, I think it might also be possible for you to install your custom web server on every user's machine, and code it up so that it creates and issues its own certificates based on its own trusted root certificate that has also been installed, and then send your porn site users to localhost.. like you would with a development certificate

Take a look at how Fiddler web debugging proxy does man-in-the-middle so you can inspect web traffic with it when the connection between the browser and the server is HTTPS (actually the browser connects to Fiddler and then Fiddler connects to server so it's two connections). Running your http server as a proxy server could also work out for what you need

Upvotes: 3

Related Questions