Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 4399d1fb authored by Mohammed Althaf T's avatar Mohammed Althaf T 😊
Browse files

parental: Use mullvad as primary dns

parent 07a50a6b
Loading
Loading
Loading
Loading
Loading
+5 −0
Original line number Diff line number Diff line
@@ -3,6 +3,8 @@
    xmlns:tools="http://schemas.android.com/tools"
    android:sharedUserId="android.uid.system">

    <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
    <uses-permission android:name="android.permission.INTERNET" />
    <uses-permission android:name="android.permission.QUERY_ALL_PACKAGES"
        tools:ignore="QueryAllPackagesPermission" />
    <uses-permission android:name="android.permission.UPDATE_DEVICE_MANAGEMENT_RESOURCES"
@@ -56,6 +58,7 @@
                <action android:name="android.app.action.PROFILE_OWNER_CHANGED" />
                <action android:name="android.app.action.DEVICE_OWNER_CHANGED" />
                <action android:name="foundation.e.parental_control.RESTART_SERVICE" />
                <action android:name="foundation.e.parental_control.RESET_PRIVATE_DNS" />
            </intent-filter>
        </receiver>

@@ -67,6 +70,8 @@
            </intent-filter>
        </receiver>

        <service android:name=".DnsCheckService"/>

        <provider
            android:name=".data.ParentalContentProvider"
            android:authorities="foundation.e.parentalcontrol.provider"
+8 −0
Original line number Diff line number Diff line
@@ -24,6 +24,7 @@ import android.content.Context
import android.content.Intent
import android.util.Log
import android.widget.Toast
import foundation.e.parentalcontrol.data.DnsManager
import foundation.e.parentalcontrol.ui.view.MainUI
import foundation.e.parentalcontrol.utils.Constants
import java.util.Objects
@@ -67,6 +68,12 @@ class DeviceAdmin : DeviceAdminReceiver() {
                }
                setSettings(context)
            }
            Constants.RESET_PRIVATE_DNS -> {
                if (isAdminActive(context)) {
                    val mainUI = MainUI(context)
                    mainUI.setPrivateDns(DnsManager.FORCE_UPDATE)
                }
            }
            else -> super.onReceive(context, intent)
        }
    }
@@ -81,6 +88,7 @@ class DeviceAdmin : DeviceAdminReceiver() {
            val mainUI = MainUI(context)
            mainUI.setDefaultRestrictions()
            mainUI.setDefaultMessages()
            context.startService(Intent(context, DnsCheckService::class.java))
        }
    }

+114 −0
Original line number Diff line number Diff line
/*
 * Copyright (C) 2024 MURENA SAS
 *
 * 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 <https://www.gnu.org/licenses/>.
 *
 */
package foundation.e.parentalcontrol

import android.app.Service
import android.content.Context
import android.content.Intent
import android.net.ConnectivityManager
import android.net.Network
import android.os.IBinder
import android.util.Log
import foundation.e.parentalcontrol.utils.Constants
import foundation.e.parentalcontrol.utils.PrefsUtils
import foundation.e.parentalcontrol.utils.SystemUtils
import java.net.InetSocketAddress
import java.net.Socket
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.delay
import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext

class DnsCheckService : Service() {
    private val tag = "DnsCheckService"
    private val dnsPort = 53

    private lateinit var connectivityManager: ConnectivityManager
    private lateinit var networkCallback: ConnectivityManager.NetworkCallback

    override fun onCreate() {
        super.onCreate()

        // Register the network callback
        networkCallback =
            object : ConnectivityManager.NetworkCallback() {
                override fun onAvailable(network: Network) {
                    CoroutineScope(Dispatchers.IO).launch {
                        delay(5000) // Wait for 5 seconds
                        if (SystemUtils.isNetworkAvailable(this@DnsCheckService)) {
                            val activeDns =
                                when {
                                    isDnsReachable(Constants.DEFAULT_DNS_SERVER) ->
                                        Constants.DEFAULT_DNS_SERVER
                                    isDnsReachable(Constants.FALLBACK_DNS_SERVER) ->
                                        Constants.FALLBACK_DNS_SERVER
                                    else -> Constants.DEFAULT_DNS_SERVER
                                }

                            Log.d(tag, "Active DNS server: $activeDns")
                            resetPrivateDns(activeDns)
                        } else {
                            Log.d(tag, "Internet is not working, no DNS check performed.")
                            resetPrivateDns(Constants.DEFAULT_DNS_SERVER)
                        }
                    }
                }

                override fun onLost(network: Network) {
                    Log.d(tag, "Network lost, stopping DNS checks.")
                }
            }

        connectivityManager = getSystemService(Context.CONNECTIVITY_SERVICE) as ConnectivityManager
        connectivityManager.registerDefaultNetworkCallback(networkCallback)

        PrefsUtils.init(this)
    }

    override fun onDestroy() {
        super.onDestroy()
        connectivityManager.unregisterNetworkCallback(networkCallback)
    }

    override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int = START_STICKY

    private fun resetPrivateDns(dnsHost: String) {
        PrefsUtils.setDefaultPrivateDns(dnsHost)
        val intent = Intent(this, DeviceAdmin::class.java)
        intent.action = Constants.RESET_PRIVATE_DNS
        this.sendBroadcast(intent)
    }

    private suspend fun isDnsReachable(host: String, port: Int = dnsPort): Boolean {
        return withContext(Dispatchers.IO) {
            try {
                Socket().use { socket ->
                    val socketAddress = InetSocketAddress(host, port)
                    socket.connect(socketAddress, 2000) // 2-second timeout
                    true
                }
            } catch (e: Exception) {
                e.printStackTrace()
                false
            }
        }
    }

    override fun onBind(intent: Intent?): IBinder? = null
}
+30 −0
Original line number Diff line number Diff line
/*
 * Copyright (C) 2024 MURENA SAS
 *
 * 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 <https://www.gnu.org/licenses/>.
 *
 */
package foundation.e.parentalcontrol.data

import androidx.annotation.IntDef

class DnsManager {

    companion object {
        const val DEFAULT = 0
        const val FORCE_UPDATE = 1
    }

    @IntDef(DEFAULT, FORCE_UPDATE) @Retention(AnnotationRetention.SOURCE) annotation class DnsMode
}
+15 −12
Original line number Diff line number Diff line
@@ -36,6 +36,7 @@ import com.android.net.module.util.ConnectivitySettingsUtils
import foundation.e.parentalcontrol.BuildConfig
import foundation.e.parentalcontrol.DeviceAdmin
import foundation.e.parentalcontrol.R
import foundation.e.parentalcontrol.data.DnsManager
import foundation.e.parentalcontrol.data.LoginStatus
import foundation.e.parentalcontrol.providers.AppLoungeData
import foundation.e.parentalcontrol.ui.buttons.ToggleWithText
@@ -154,10 +155,12 @@ class MainUI(context: Context) {
        }
    }

    private fun setPrivateDns() {
    fun setPrivateDns(@DnsManager.DnsMode mode: Int = DnsManager.DEFAULT) {
        if (!dA.isAdminActive(mContext)) return

        // Set default private dns
        if (!isThisRestrictionSet(dnsSettingsRestriction)) {
            val cloudflareDnsHostName = mContext.getString(R.string.family_cloudflare_dns_com)
        if (!isThisRestrictionSet(dnsSettingsRestriction) || mode == DnsManager.FORCE_UPDATE) {
            val defaultDnsHostName = PrefsUtils.getDefaultPrivateDns()
            val currentDnsHostMode =
                Settings.Global.getString(
                    mContext.contentResolver,
@@ -184,7 +187,7 @@ class MainUI(context: Context) {
            Settings.Global.putString(
                mContext.contentResolver,
                ConnectivitySettingsUtils.PRIVATE_DNS_SPECIFIER,
                cloudflareDnsHostName
                defaultDnsHostName
            )
        }

@@ -300,30 +303,30 @@ class MainUI(context: Context) {
            }
        )

        val cloudflareDnsHostName = stringResource(R.string.family_cloudflare_dns_com)
        val cloudflareToggleState = remember {
        val defaultDnsHostName = Constants.DEFAULT_DNS_SERVER
        val defaultToggleState = remember {
            val isHostname =
                Settings.Global.getString(
                    mContext.contentResolver,
                    ConnectivitySettingsUtils.PRIVATE_DNS_MODE
                ) == ConnectivitySettingsUtils.PRIVATE_DNS_MODE_PROVIDER_HOSTNAME_STRING
            val isCloudflareDns =
            val isDefaultDns =
                Settings.Global.getString(
                    mContext.contentResolver,
                    ConnectivitySettingsUtils.PRIVATE_DNS_SPECIFIER
                ) == cloudflareDnsHostName
            mutableStateOf(isHostname && isCloudflareDns && dnsSettingsToggleState)
                ) == defaultDnsHostName
            mutableStateOf(isHostname && isDefaultDns && dnsSettingsToggleState)
        }
        ToggleWithText(
            text = stringResource(R.string.block_malware_and_adult_content_with_cloudflare),
            isChecked = cloudflareToggleState.value,
            text = stringResource(R.string.block_malware_and_adult_content_with_dns),
            isChecked = defaultToggleState.value,
            onCheckedChange = { isActive ->
                if (isActive) {
                    setPrivateDns()
                } else {
                    removePrivateDns()
                }
                cloudflareToggleState.value = isActive
                defaultToggleState.value = isActive
            }
        )

Loading