Android examples for Network:IPv6
Tries to force the interface to reset its IPv6 addresses by setting it down and then up.
/***************************************************************************** * Project: Android IPv6Config//from w w w . j ava 2 s. c om * Description: Android application to change IPv6 kernel configuration * Author: Ren? Mayrhofer * Copyright: Ren? Mayrhofer, 2011-2014 * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 3 * as published by the Free Software Foundation. *****************************************************************************/ import java.io.File; import java.io.IOException; import java.net.Inet4Address; import java.net.Inet6Address; import java.net.InetAddress; import java.util.HashMap; import java.util.LinkedList; import java.util.List; import java.util.StringTokenizer; import java.util.logging.Level; import java.util.logging.Logger; public class Main{ /** Our logger for this class. */ private final static Logger logger = java.util.logging.Logger .getLogger(Constants.LOG_TAG); /** Identifies the gateway of a route. */ private final static String ROUTE_GATEWAY = "via"; /** Identifies the device of a route. */ private final static String ROUTE_DEVICE = "dev"; /** Search for the "ip" and "busybox" binaries at these locations. */ public final static String[] LINUX_BINARY_LOCATIONS = { "/sbin/", "/bin/", "/system/bin/", "/system/xbin/" }; /** Preferred is to use the "ip" binary directly. * @see BUSYBOX_BINARY_PREFIX */ public final static String IP_BINARY = "ip"; /** But if no (working) ip binary can be found, then try to use busybox with an "ip" applet. * @see IP_BINARY */ public final static String BUSYBOX_BINARY = "busybox"; /** Command to get and set network interface addresses and options under modern Linux systems. */ private final static String ADDRESSES_COMMAND = " addr"; /** Command to get and set routes under modern Linux systems. */ private final static String ROUTES_COMMAND = " route"; /** Option to select only IPv6 addresses/routes. */ private final static String OPTION_IPv6_ONLY = " -6 "; /** Simply the shell command (and if necessary path) to execute a standard POSIX shell. */ public final static String SH_COMMAND = "sh"; /** Path for the IPv6 configuration kernel options. */ public final static String IPV6_CONFIG_TREE = "/proc/sys/net/ipv6/conf/"; /** Interface "name" to denote all network interface for kernel configuration options. */ private final static String CONF_INTERFACES_ALL = "all"; /** Interface "name" to denote the default kernel configuration options for new (hotplug enabled) network interfaces. */ private final static String CONF_INTERFACES_DEFAULT = "default"; /** Command to get and set network interface status under modern Linux systems (up/down mostly). */ private final static String SET_INTERFACE = " link set "; /** Option to set network interface up. */ private final static String UP = " up"; /** Option to set network interface down. */ private final static String DOWN = " down"; /** Option to add network interface / addresses / routes. */ private final static String ADD = " add "; /** Delay between setting an interface down and up to force its IPv6 address to be reset (in milliseconds). */ public final static int INTERFACE_DOWN_UP_DELAY = 100; /** Static initializer: find out where to call the "ip" binary from and remember for future use. */ private static String ipBinaryLocation = null; private static String ipBinaryTriedPaths = null; /** Tries to force the interface to reset its addresses by setting it down and then up. */ public static boolean forceAddressReload(String iface) { String cmd = getIPCommandLocation() + SET_INTERFACE + iface + " "; try { if (Command.executeCommand(SH_COMMAND, true, cmd + DOWN, null, null) == 0) { // wait just a little for the interface to properly go down Thread.sleep(INTERFACE_DOWN_UP_DELAY); if (Command.executeCommand(SH_COMMAND, true, cmd + UP, null, null) == 0) { logger.finer("Reset interface " + iface + " to force address reload"); return true; } else { logger.warning("Set interface " + iface + " down but was unable to set it up again"); return false; } } else { logger.warning("Unable to set interface " + iface + " down"); return false; } } catch (IOException e) { logger.severe("Unable to execute system command, new addresses may not have been set (access privileges missing?) " + e); return false; } catch (InterruptedException e) { return false; } } /** Tries to force all specified interfaces to reset their addresses by setting them down and then up. */ public static boolean forceAddressReload(List<String> ifaces) { boolean ret = true; LinkedList<String> downedIfaces = new LinkedList<String>(); String cmd = getIPCommandLocation() + SET_INTERFACE; // remember the default route so that we can restore it later on String currentDefaultRoute = getIPv4DefaultRouteSpecification(); try { // first set all interfaces down for (String iface : ifaces) { // only try to enable if this is indeed known as an IPv6-capable interface to the kernel File configDir = new File(IPV6_CONFIG_TREE + iface); if (configDir.isDirectory() && !iface.equals(CONF_INTERFACES_ALL) && !iface.equals(CONF_INTERFACES_DEFAULT)) { if (Command.executeCommand(SH_COMMAND, true, cmd + iface + DOWN, null, null) == 0) downedIfaces.add(iface); else { logger.warning("Unable to set interface " + iface + " down, will not try to set it up again"); ret = false; } } } // then wait just a little for the interfaces to properly go down Thread.sleep(INTERFACE_DOWN_UP_DELAY); // and start all those again that were set down for (String iface : downedIfaces) { if (Command.executeCommand(SH_COMMAND, true, cmd + iface + UP, null, null) == 0) logger.finer("Reset interface " + iface + " to force address reload"); else { logger.warning("Set interface " + iface + " down but was unable to set it up again"); ret = false; } } // if we had one, restore old default route if (currentDefaultRoute != null && currentDefaultRoute.length() > 0) { if (Command.executeCommand(SH_COMMAND, true, getIPCommandLocation() + ROUTES_COMMAND + ADD + currentDefaultRoute, null, null) == 0) logger.fine("Reloaded default route '" + currentDefaultRoute + "'"); else { logger.warning("Unable to reload default route '" + currentDefaultRoute + "', connectivity may be broken until next network interface change!"); } } return ret; } catch (IOException e) { logger.severe("Unable to execute system command, new addresses may not have been set (access privileges missing?) " + e); return false; } catch (InterruptedException e) { return false; } } /** Helper to locate a usable "ip" command or null if none is found. */ public static String getIPCommandLocation() { if (ipBinaryLocation == null) { ipBinaryTriedPaths = ""; if (!tryIPBinaries(LINUX_BINARY_LOCATIONS, IP_BINARY, null) && !tryIPBinaries(LINUX_BINARY_LOCATIONS, BUSYBOX_BINARY, IP_BINARY)) logger.severe("Could not find ip binary in" + ipBinaryTriedPaths + ", will be unable to read network interface details"); } return ipBinaryLocation; } /** Returns the IPv4 default route specification (the full line of * "ip route" output) for restoring it later on (e.g. after an interface * reload) or null if no default route is known. */ public static String getIPv4DefaultRouteSpecification() { LinkedList<RouteDetail> routes; try { routes = LinuxIPCommandHelper.getRouteOutput(false); for (RouteDetail route : routes) { if (route.target.equalsIgnoreCase("default") || route.target.equals("0.0.0.0/0")) { // ok, default route found logger.info("Found default IPv4 route pointing to gateway '" + route.gateway + "' on interface '" + route.iface + "'"); return route.fullRouteLine; } } } catch (IOException e) { logger.warning("Unable to query Linux IPv4 main routing table" + e); } return null; } /** Helper function to try a list of paths with a command to verify if "ip addr" can be executed correctly. * * @return true if a working "ip addr" call could be made, false otherwise. If true is returned, * the working full binary path is stored in ipBinaryLocation. * @see ipBinaryLocation */ private static boolean tryIPBinaries(String[] paths, String cmd, String cmd2) { for (String path : paths) { String binary = path + cmd; // sanity check: can we actually execute our command? logger.finer("Checking for availibility of command '" + binary + "'"); if (new File(binary).canRead()) { if (cmd2 != null) binary = binary + " " + cmd2; /* second sanity check: does this binary work? * (E.g. on the Samsung Galaxy S2, there actually is a binary under * /system/bin/ip that claims to work, but doesn't). */ try { logger.fine("Trying to execute cmd '" + binary + ADDRESSES_COMMAND + "'"); Command.executeCommand(binary + ADDRESSES_COMMAND, false, false, null); logger.fine("Found working ip binary in " + binary); ipBinaryLocation = binary; return true; } catch (Exception e) { logger.warning("Found ip binary in " + binary + ", but does not behave as expected. Trying next location."); } } ipBinaryTriedPaths = ipBinaryTriedPaths + " '" + binary + "'"; } return false; } /** Returns the list of routes in the main routing table. * * @param queryIPv6 If true, then IPv6 routes are queried. If false, then IPv4 routes are queried. */ public static LinkedList<RouteDetail> getRouteOutput(boolean queryIPv6) throws IOException { String cmd = getIPCommandLocation() + (queryIPv6 ? OPTION_IPv6_ONLY : "") + ROUTES_COMMAND; StringTokenizer lines = null; LinkedList<RouteDetail> list = new LinkedList<RouteDetail>(); logger.warning("Acquiring route details with command '" + cmd + "'"); try { lines = new StringTokenizer(Command.executeCommand(cmd, false, false, null), "\n"); } catch (Exception e) { logger.log(Level.WARNING, "Tried to parse routes, but could not", e); } RouteDetail cur = null; while (lines != null && lines.hasMoreTokens()) { String line = lines.nextToken(); logger.finest("getRouteOutput: parsing line '" + line + "'"); StringTokenizer fields = new StringTokenizer(line, " \t"); // the first field is always the target cur = new RouteDetail(); cur.fullRouteLine = line; cur.target = fields.nextToken(); // then we get options defined by "dev" or "via" (and others that we ignore) while (fields.hasMoreTokens()) { String opt = fields.nextToken().trim(); logger.finest("getRouteOutput: trying to parse option '" + opt + "'"); if (opt.equals(ROUTE_GATEWAY) && fields.hasMoreTokens()) { cur.gateway = InetAddress.getByName(fields.nextToken() .trim()); logger.finest("getRouteOutput: found gateway " + cur.gateway + " for target " + cur.target); } else if (opt.equals(ROUTE_DEVICE) && fields.hasMoreTokens()) { cur.iface = fields.nextToken().trim(); logger.finest("getRouteOutput: found interface " + cur.iface + " for target " + cur.target); } else { logger.finest("getRouteOutput: ignoring unknown option '" + opt + "' or no further field in string. Cannot parse."); } } // line finished, add route to list list.add(cur); } return list; } }