DnsQuery.kt 3.71 KB
Newer Older
1
2
3
package com.frostnerd.smokescreen.database.entities

import android.util.Base64
Daniel Wolf's avatar
Daniel Wolf committed
4
5
6
7
import androidx.room.Entity
import androidx.room.Ignore
import androidx.room.PrimaryKey
import androidx.room.TypeConverters
8
import com.frostnerd.dnstunnelproxy.QueryListener
9
import com.frostnerd.smokescreen.database.converters.DnsTypeConverter
10
import com.frostnerd.smokescreen.database.converters.QuerySourceConverter
11
12
import com.frostnerd.smokescreen.database.converters.StringListConverter
import com.frostnerd.smokescreen.database.recordFromBase64
Daniel Wolf's avatar
Daniel Wolf committed
13
14
15
import com.frostnerd.smokescreen.equalsAny
import org.minidns.record.A
import org.minidns.record.AAAA
16
17
import org.minidns.record.Record

Daniel Wolf's avatar
Daniel Wolf committed
18
19
/*
 * Copyright (C) 2019 Daniel Wolf (Ch4t4r)
20
 *
Daniel Wolf's avatar
Daniel Wolf committed
21
22
23
24
25
26
27
28
29
30
31
32
33
34
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.

 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.

 * You should have received a copy of the GNU General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 *
 * You can contact the developer at daniel.wolf@frostnerd.com.
35
36
 */
@Entity(tableName = "DnsQuery")
37
@TypeConverters(DnsTypeConverter::class, StringListConverter::class, QuerySourceConverter::class)
38
39
40
41
42
data class DnsQuery(
    @PrimaryKey(autoGenerate = true) var id: Long = 0,
    val type: Record.TYPE,
    val name: String,
    var askedServer: String?,
43
    var responseSource:QueryListener.Source,
44
45
    val questionTime: Long,
    var responseTime: Long = 0,
Daniel Wolf's avatar
Daniel Wolf committed
46
47
    var responses: List<String>,
    var isHostBlockedByDnsServer:Boolean = responsesBlockHost(responses)
48
) {
49
50
    @delegate:Ignore
    val shortName:String by lazy { calculateShortName() }
Daniel Wolf's avatar
Daniel Wolf committed
51
52
53
54
    @delegate:Ignore
    val parsedResponses:List<Record<*>> by lazy {
        parseResponses(responses)
    }
55
56
57

    companion object {
        private val SHORT_DOMAIN_REGEX = "^((?:[^.]{1,3}\\.)+)([\\w]{4,})(?:\\.(?:[^.]*))*\$".toRegex()
Daniel Wolf's avatar
Daniel Wolf committed
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76

        private fun responsesBlockHost(responses:List<String>):Boolean {
            return parseResponses(responses).any {
                (it.type == Record.TYPE.A && (it.payload as A).toString() == "0.0.0.0") ||
                        (it.type == Record.TYPE.AAAA && (it.payload as AAAA).toString().equalsAny("::0", "0:0:0:0:0:0:0:0"))
            }
        }

        private fun parseResponses(responses:List<String>): List<Record<*>> {
            if(responses.isEmpty()) return emptyList()

            val parsedResponses = mutableListOf<Record<*>>()
            for (response in responses) {
                parsedResponses.add(recordFromBase64(response))
            }
            return parsedResponses
        }

        fun encodeResponse(record: Record<*>):String = Base64.encodeToString(record.toByteArray(), Base64.NO_WRAP)
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
    }

    /**
     * Returns a shortened representation of the name.
     * E.g frostnerd.com for ads.frostnerd.com, or "dgfhd" for "dgfhd"
     */
    private fun calculateShortName():String {
        val match = SHORT_DOMAIN_REGEX.matchEntire(name.reversed())
        if(match != null) {
            if(match.groups.size == 3) {
                return match.groupValues[2].reversed() + match.groupValues[1].reversed()
            }
            return name
        } else return name
    }

93
94
95
96
    override fun toString(): String {
        return "DnsQuery(id=$id, type=$type, name='$name', askedServer=$askedServer, questionTime=$questionTime, responseTime=$responseTime, responses={${responses.size}})"
    }
}