// Path: Android/app/src/main/java/app/intra/net/doh/Prober.java
// public abstract class Prober {
// 
//   protected static final byte[] QUERY_DATA = {
//       0, 0,  // [0-1]   query ID
//       1, 0,  // [2-3]   flags, RD=1
//       0, 1,  // [4-5]   QDCOUNT (number of queries) = 1
//       0, 0,  // [6-7]   ANCOUNT (number of answers) = 0
//       0, 0,  // [8-9]   NSCOUNT (number of authoritative answers) = 0
//       0, 0,  // [10-11] ARCOUNT (number of additional records) = 0
//       // Start of first query
//       7, 'y', 'o', 'u', 't', 'u', 'b', 'e',
//       3, 'c', 'o', 'm',
//       0,  // null terminator of FQDN (DNS root)
//       0, 1,  // QTYPE = A
//       0, 1   // QCLASS = IN (Internet)
//   };
// 
//   public interface Callback {
//     void onCompleted(boolean succeeded);
//   }
// 
//   /**
//    * Called to execute the probe on a new thread.
//    * @param url The DOH server URL to probe.
//    * @param callback How to report the probe results
//    */
//   public abstract void probe(String url, Callback callback);
// }
// 
// Path: Android/app/src/main/java/app/intra/sys/VpnController.java
// public class VpnController {
// 
//   private static VpnController dnsVpnServiceState;
// 
//   public Object clone() throws CloneNotSupportedException {
//     throw new CloneNotSupportedException();
//   }
// 
//   public static synchronized VpnController getInstance() {
//     if (dnsVpnServiceState == null) {
//       dnsVpnServiceState = new VpnController();
//     }
//     return dnsVpnServiceState;
//   }
// 
//   private IntraVpnService intraVpnService = null;
//   private IntraVpnService.State connectionState = null;
//   private QueryTracker tracker = null;
// 
//   private VpnController() {}
// 
//   void setIntraVpnService(IntraVpnService intraVpnService) {
//     this.intraVpnService = intraVpnService;
//   }
// 
//   public @Nullable IntraVpnService getIntraVpnService() {
//     return this.intraVpnService;
//   }
// 
//   public synchronized void onConnectionStateChanged(Context context, IntraVpnService.State state) {
//     if (intraVpnService == null) {
//       // User clicked disable while the connection state was changing.
//       return;
//     }
//     connectionState = state;
//     stateChanged(context);
//   }
// 
//   private void stateChanged(Context context) {
//     Intent broadcast = new Intent(InternalNames.DNS_STATUS.name());
//     LocalBroadcastManager.getInstance(context).sendBroadcast(broadcast);
//   }
// 
//   public synchronized QueryTracker getTracker(Context context) {
//     if (tracker == null) {
//       tracker = new QueryTracker(context);
//     }
//     return tracker;
//   }
// 
//   public synchronized void start(Context context) {
//     if (intraVpnService != null) {
//       return;
//     }
//     PersistentState.setVpnEnabled(context, true);
//     stateChanged(context);
//     Intent startServiceIntent = new Intent(context, IntraVpnService.class);
//     if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
//       context.startForegroundService(startServiceIntent);
//     } else {
//       context.startService(startServiceIntent);
//     }
//   }
// 
//   synchronized void onStartComplete(Context context, boolean succeeded) {
//     if (!succeeded) {
//       // VPN setup only fails if VPN permission has been revoked.  If this happens, clear the
//       // user intent state and reset to the default state.
//       stop(context);
//     } else {
//       stateChanged(context);
//     }
//   }
// 
//   public synchronized void stop(Context context) {
//     PersistentState.setVpnEnabled(context, false);
//     connectionState = null;
//     if (intraVpnService != null) {
//       intraVpnService.signalStopService(true);
//     }
//     intraVpnService = null;
//     stateChanged(context);
//   }
// 
//   public synchronized VpnState getState(Context context) {
//     boolean requested = PersistentState.getVpnEnabled(context);
//     boolean on = intraVpnService != null && intraVpnService.isOn();
//     return new VpnState(requested, on, connectionState);
//   }
// 
// }


import android.content.Context;
import android.os.Build.VERSION;
import android.os.Build.VERSION_CODES;
import app.intra.net.doh.Prober;
import app.intra.sys.VpnController;
import doh.Transport;
import protect.Protector;
import tun2socks.Tun2socks;
/*
Copyright 2019 Jigsaw Operations LLC

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

https://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package app.intra.net.go;


/**
 * Implements a Probe using the Go-based DoH client.
 */
public class GoProber extends Prober {

  private final Context context;

  public GoProber(Context context) {
    this.context = context;
  }

  @Override
  public void probe(String url, Callback callback) {
    new Thread(() -> {
      String dohIPs = GoVpnAdapter.getIpString(context, url);
      try {
        // Protection isn't needed for Lollipop+, or if the VPN is not active.
        Protector protector = VERSION.SDK_INT >= VERSION_CODES.LOLLIPOP ? null :
// Path: Android/app/src/main/java/app/intra/net/doh/Prober.java
// public abstract class Prober {
// 
//   protected static final byte[] QUERY_DATA = {
//       0, 0,  // [0-1]   query ID
//       1, 0,  // [2-3]   flags, RD=1
//       0, 1,  // [4-5]   QDCOUNT (number of queries) = 1
//       0, 0,  // [6-7]   ANCOUNT (number of answers) = 0
//       0, 0,  // [8-9]   NSCOUNT (number of authoritative answers) = 0
//       0, 0,  // [10-11] ARCOUNT (number of additional records) = 0
//       // Start of first query
//       7, 'y', 'o', 'u', 't', 'u', 'b', 'e',
//       3, 'c', 'o', 'm',
//       0,  // null terminator of FQDN (DNS root)
//       0, 1,  // QTYPE = A
//       0, 1   // QCLASS = IN (Internet)
//   };
// 
//   public interface Callback {
//     void onCompleted(boolean succeeded);
//   }
// 
//   /**
//    * Called to execute the probe on a new thread.
//    * @param url The DOH server URL to probe.
//    * @param callback How to report the probe results
//    */
//   public abstract void probe(String url, Callback callback);
// }
// 
// Path: Android/app/src/main/java/app/intra/sys/VpnController.java
// public class VpnController {
// 
//   private static VpnController dnsVpnServiceState;
// 
//   public Object clone() throws CloneNotSupportedException {
//     throw new CloneNotSupportedException();
//   }
// 
//   public static synchronized VpnController getInstance() {
//     if (dnsVpnServiceState == null) {
//       dnsVpnServiceState = new VpnController();
//     }
//     return dnsVpnServiceState;
//   }
// 
//   private IntraVpnService intraVpnService = null;
//   private IntraVpnService.State connectionState = null;
//   private QueryTracker tracker = null;
// 
//   private VpnController() {}
// 
//   void setIntraVpnService(IntraVpnService intraVpnService) {
//     this.intraVpnService = intraVpnService;
//   }
// 
//   public @Nullable IntraVpnService getIntraVpnService() {
//     return this.intraVpnService;
//   }
// 
//   public synchronized void onConnectionStateChanged(Context context, IntraVpnService.State state) {
//     if (intraVpnService == null) {
//       // User clicked disable while the connection state was changing.
//       return;
//     }
//     connectionState = state;
//     stateChanged(context);
//   }
// 
//   private void stateChanged(Context context) {
//     Intent broadcast = new Intent(InternalNames.DNS_STATUS.name());
//     LocalBroadcastManager.getInstance(context).sendBroadcast(broadcast);
//   }
// 
//   public synchronized QueryTracker getTracker(Context context) {
//     if (tracker == null) {
//       tracker = new QueryTracker(context);
//     }
//     return tracker;
//   }
// 
//   public synchronized void start(Context context) {
//     if (intraVpnService != null) {
//       return;
//     }
//     PersistentState.setVpnEnabled(context, true);
//     stateChanged(context);
//     Intent startServiceIntent = new Intent(context, IntraVpnService.class);
//     if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
//       context.startForegroundService(startServiceIntent);
//     } else {
//       context.startService(startServiceIntent);
//     }
//   }
// 
//   synchronized void onStartComplete(Context context, boolean succeeded) {
//     if (!succeeded) {
//       // VPN setup only fails if VPN permission has been revoked.  If this happens, clear the
//       // user intent state and reset to the default state.
//       stop(context);
//     } else {
//       stateChanged(context);
//     }
//   }
// 
//   public synchronized void stop(Context context) {
//     PersistentState.setVpnEnabled(context, false);
//     connectionState = null;
//     if (intraVpnService != null) {
//       intraVpnService.signalStopService(true);
//     }
//     intraVpnService = null;
//     stateChanged(context);
//   }
// 
//   public synchronized VpnState getState(Context context) {
//     boolean requested = PersistentState.getVpnEnabled(context);
//     boolean on = intraVpnService != null && intraVpnService.isOn();
//     return new VpnState(requested, on, connectionState);
//   }
// 
// }


// Path: Android/app/src/main/java/app/intra/net/go/GoProber.java
import android.content.Context;
import android.os.Build.VERSION;
import android.os.Build.VERSION_CODES;
import app.intra.net.doh.Prober;
import app.intra.sys.VpnController;
import doh.Transport;
import protect.Protector;
import tun2socks.Tun2socks;

/*
Copyright 2019 Jigsaw Operations LLC

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

https://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package app.intra.net.go;


/**
 * Implements a Probe using the Go-based DoH client.
 */
public class GoProber extends Prober {

  private final Context context;

  public GoProber(Context context) {
    this.context = context;
  }

  @Override
  public void probe(String url, Callback callback) {
    new Thread(() -> {
      String dohIPs = GoVpnAdapter.getIpString(context, url);
      try {
        // Protection isn't needed for Lollipop+, or if the VPN is not active.
        Protector protector = VERSION.SDK_INT >= VERSION_CODES.LOLLIPOP ? null :
            VpnController.getInstance().getIntraVpnService();