content: /*
   * Copyright (C) 2011 The Android Open Source Project
   *
   * 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
   *
   *      http://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 com.android.internal.net;
  
  import android.annotation.UnsupportedAppUsage;
  import android.app.PendingIntent;
  import android.content.ComponentName;
  import android.content.Context;
  import android.content.Intent;
  import android.content.pm.PackageManager;
  import android.content.pm.PackageManager.NameNotFoundException;
  import android.content.pm.ResolveInfo;
  import android.content.res.Resources;
  import android.net.IpPrefix;
  import android.net.LinkAddress;
  import android.net.Network;
  import android.net.ProxyInfo;
  import android.net.RouteInfo;
  import android.os.Parcel;
  import android.os.Parcelable;
  import android.os.UserHandle;
  
  import java.net.Inet4Address;
  import java.net.InetAddress;
  import java.util.ArrayList;
  import java.util.Arrays;
  import java.util.List;
  
  /**
   * A simple container used to carry information in VpnBuilder, VpnDialogs,
   * and com.android.server.connectivity.Vpn. Internal use only.
   *
   * @hide
   */
  public class VpnConfig implements Parcelable {
  
      public static final String SERVICE_INTERFACE = "android.net.VpnService";
  
      public static final String DIALOGS_PACKAGE = "com.android.vpndialogs";
  
      public static final String LEGACY_VPN = "[Legacy VPN]";
  
      public static Intent getIntentForConfirmation() {
          Intent intent = new Intent();
          ComponentName componentName = ComponentName.unflattenFromString(
                  Resources.getSystem().getString(
                          com.android.internal.R.string.config_customVpnConfirmDialogComponent));
          intent.setClassName(componentName.getPackageName(), componentName.getClassName());
          return intent;
      }
  
      /** NOTE: This should only be used for legacy VPN. */
      public static PendingIntent getIntentForStatusPanel(Context context) {
          Intent intent = new Intent();
          intent.setClassName(DIALOGS_PACKAGE, DIALOGS_PACKAGE + ".ManageDialog");
          intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_NO_HISTORY |
                  Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS);
          return PendingIntent.getActivityAsUser(context, 0, intent, 0, null, UserHandle.CURRENT);
      }
  
      public static CharSequence getVpnLabel(Context context, String packageName)
              throws NameNotFoundException {
          PackageManager pm = context.getPackageManager();
          Intent intent = new Intent(SERVICE_INTERFACE);
          intent.setPackage(packageName);
          List<ResolveInfo> services = pm.queryIntentServices(intent, 0 /* flags */);
          if (services != null && services.size() == 1) {
              // This app contains exactly one VPN service. Call loadLabel, which will attempt to
              // load the service's label, and fall back to the app label if none is present.
              return services.get(0).loadLabel(pm);
          } else {
              return pm.getApplicationInfo(packageName, 0).loadLabel(pm);
          }
      }
  
      public String user;
      public String interfaze;
      public String session;
      public int mtu = -1;
      public List<LinkAddress> addresses = new ArrayList<LinkAddress>();
      public List<RouteInfo> routes = new ArrayList<RouteInfo>();
      public List<String> dnsServers;
      public List<String> searchDomains;
      public List<String> allowedApplications;
      public List<String> disallowedApplications;
      public PendingIntent configureIntent;
      public long startTime = -1;
      public boolean legacy;
      public boolean blocking;
      public boolean allowBypass;
      public boolean allowIPv4;
      public boolean allowIPv6;
      public boolean isMetered = true;
      public Network[] underlyingNetworks;
      public ProxyInfo proxyInfo;
  
      public void updateAllowedFamilies(InetAddress address) {
          if (address instanceof Inet4Address) {
              allowIPv4 = true;
          } else {
              allowIPv6 = true;
          }
      }
  
      public void addLegacyRoutes(String routesStr) {
          if (routesStr.trim().equals("")) {
              return;
          }
          String[] routes = routesStr.trim().split(" ");
          for (String route : routes) {
              //each route is ip/prefix
              RouteInfo info = new RouteInfo(new IpPrefix(route), null);
              this.routes.add(info);
              updateAllowedFamilies(info.getDestination().getAddress());
          }
      }
  
      public void addLegacyAddresses(String addressesStr) {
          if (addressesStr.trim().equals("")) {
              return;
          }
          String[] addresses = addressesStr.trim().split(" ");
          for (String address : addresses) {
              //each address is ip/prefix
              LinkAddress addr = new LinkAddress(address);
              this.addresses.add(addr);
              updateAllowedFamilies(addr.getAddress());
          }
      }
  
      @Override
      public int describeContents() {
          return 0;
      }
  
      @Override
      public void writeToParcel(Parcel out, int flags) {
          out.writeString(user);
          out.writeString(interfaze);
          out.writeString(session);
          out.writeInt(mtu);
          out.writeTypedList(addresses);
          out.writeTypedList(routes);
          out.writeStringList(dnsServers);
          out.writeStringList(searchDomains);
          out.writeStringList(allowedApplications);
          out.writeStringList(disallowedApplications);
          out.writeParcelable(configureIntent, flags);
          out.writeLong(startTime);
          out.writeInt(legacy ? 1 : 0);
          out.writeInt(blocking ? 1 : 0);
          out.writeInt(allowBypass ? 1 : 0);
          out.writeInt(allowIPv4 ? 1 : 0);
          out.writeInt(allowIPv6 ? 1 : 0);
          out.writeInt(isMetered ? 1 : 0);
          out.writeTypedArray(underlyingNetworks, flags);
          out.writeParcelable(proxyInfo, flags);
      }
  
      public static final Parcelable.Creator<VpnConfig> CREATOR =
              new Parcelable.Creator<VpnConfig>() {
          @Override
          public VpnConfig createFromParcel(Parcel in) {
              VpnConfig config = new VpnConfig();
              config.user = in.readString();
              config.interfaze = in.readString();
              config.session = in.readString();
              config.mtu = in.readInt();
              in.readTypedList(config.addresses, LinkAddress.CREATOR);
              in.readTypedList(config.routes, RouteInfo.CREATOR);
              config.dnsServers = in.createStringArrayList();
              config.searchDomains = in.createStringArrayList();
              config.allowedApplications = in.createStringArrayList();
              config.disallowedApplications = in.createStringArrayList();
              config.configureIntent = in.readParcelable(null);
              config.startTime = in.readLong();
              config.legacy = in.readInt() != 0;
              config.blocking = in.readInt() != 0;
              config.allowBypass = in.readInt() != 0;
              config.allowIPv4 = in.readInt() != 0;
              config.allowIPv6 = in.readInt() != 0;
              config.isMetered = in.readInt() != 0;
              config.underlyingNetworks = in.createTypedArray(Network.CREATOR);
              config.proxyInfo = in.readParcelable(null);
              return config;
          }
  
          @Override
          public VpnConfig[] newArray(int size) {
              return new VpnConfig[size];
          }
      };
  
      @Override
      public String toString() {
          return new StringBuilder()
                  .append("VpnConfig")
                  .append("{ user=").append(user)
                  .append(", interface=").append(interfaze)
                  .append(", session=").append(session)
                  .append(", mtu=").append(mtu)
                  .append(", addresses=").append(toString(addresses))
                  .append(", routes=").append(toString(routes))
                  .append(", dns=").append(toString(dnsServers))
                  .append(", searchDomains=").append(toString(searchDomains))
                  .append(", allowedApps=").append(toString(allowedApplications))
                  .append(", disallowedApps=").append(toString(disallowedApplications))
                  .append(", configureIntent=").append(configureIntent)
                  .append(", startTime=").append(startTime)
                  .append(", legacy=").append(legacy)
                  .append(", blocking=").append(blocking)
                  .append(", allowBypass=").append(allowBypass)
                  .append(", allowIPv4=").append(allowIPv4)
                  .append(", allowIPv6=").append(allowIPv6)
                  .append(", underlyingNetworks=").append(Arrays.toString(underlyingNetworks))
                  .append(", proxyInfo=").append(proxyInfo.toString())
                  .append("}")
                  .toString();
      }
  
      static <T> String toString(List<T> ls) {
          if (ls == null) {
              return "null";
          }
          return Arrays.toString(ls.toArray());
      }
  }
  