Commit 765bf837 authored by Max Lv's avatar Max Lv

use commons-net instead

parent be6f31de
...@@ -3,7 +3,8 @@ libraryDependencies ++= Seq( ...@@ -3,7 +3,8 @@ libraryDependencies ++= Seq(
"com.google.android" % "analytics" % "3.01", "com.google.android" % "analytics" % "3.01",
"com.google.android" % "admob" % "6.4.1", "com.google.android" % "admob" % "6.4.1",
"dnsjava" % "dnsjava" % "2.1.5", "dnsjava" % "dnsjava" % "2.1.5",
"org.scalaj" %% "scalaj-http" % "0.3.10" "org.scalaj" %% "scalaj-http" % "0.3.10",
"commons-net" % "commons-net" % "3.3"
) )
libraryDependencies ++= Seq( libraryDependencies ++= Seq(
......
...@@ -5,8 +5,8 @@ import sbtandroid._ ...@@ -5,8 +5,8 @@ import sbtandroid._
import sbtandroid.AndroidPlugin._ import sbtandroid.AndroidPlugin._
object App { object App {
val version = "2.0.4" val version = "2.0.5"
val versionCode = 55 val versionCode = 56
} }
object General { object General {
......
APP_ABI := armeabi x86 APP_ABI := armeabi x86
APP_PLATFORM := android-9 APP_PLATFORM := android-9
APP_STL := stlport_static APP_STL := stlport_static
NDK_TOOLCHAIN_VERSION := 4.8 NDK_TOOLCHAIN_VERSION := 4.6
package be.jvb.iptypes
import java.net.InetAddress
/**
* Represents an IPv4 address.
*
* @author <a href="http://janvanbesien.blogspot.com">Jan Van Besien</a>
*
* @param value 32bit value of the ip address (only 32 least significant bits are used)
*/
class IpAddress(val value: Long) extends SmallByteArray {
/**
* Construct from a CIDR format string representation (e.g. "192.168.0.1").
*/
def this(address: String) = this (SmallByteArray.parseAsLong(address, IpAddress.N_BYTES, DEC()))
/**
* Construct from a java.net.InetAddress.
*/
def this(inetAddress: InetAddress) = {
this (if (inetAddress == null) throw new IllegalArgumentException("can not create from [null]") else inetAddress
.getHostAddress)
}
protected def nBytes = IpAddress.N_BYTES
protected def radix = DEC()
/**
* Addition. Will never overflow, but wraps around when the highest ip address has been reached.
*/
def +(value: Long) = new IpAddress((this.value + value) & maxValue)
/**
* Substraction. Will never underflow, but wraps around when the lowest ip address has been reached.
*/
def -(value: Long) = new IpAddress((this.value - value) & maxValue)
/**
* Convert to java.net.InetAddress.
*/
def toInetAddress: InetAddress = InetAddress.getByName(toString)
}
object IpAddress {
val N_BYTES = 4
def apply(string: String): IpAddress = new IpAddress(SmallByteArray.parseAsLong(string, N_BYTES, DEC()))
def unapply(ipAddress: IpAddress): Option[String] = {
Some(ipAddress.toString)
}
}
package be.jvb.iptypes
import scala.collection.immutable._
import scala.collection.mutable.ListBuffer
/**
* Represents a pool of IPv4 addresses. A pool is a range of addresses, from which some can be "allocated" and some can be
* "free".
*
* @author <a href="http://janvanbesien.blogspot.com">Jan Van Besien</a>
*
* @param first first address in the pool
* @param last last address in the pool
* @param freeRanges sorted set of all free ranges in this pool. All free ranges should be contained in the range from first to last;
* none of the free ranges should overlap; and the set of free ranges should contain as little fragments as necessary.
*/
class IpAddressPool private(override val first: IpAddress, override val last: IpAddress, val freeRanges: SortedSet[IpAddressRange])
extends IpAddressRange(first, last) {
validateFreeRanges(freeRanges)
/**
* Construct a pool which is completely free.
*/
def this(first: IpAddress, last: IpAddress) = {
// the whole ranges is free initially
this (first, last, TreeSet[IpAddressRange](new IpAddressRange(first, last)))
}
/**
* Construct a pool which is completely free from an existing address range.
*/
def this(range: IpAddressRange) = {
this (range.first, range.last)
}
private def validateFreeRanges(toValidate: SortedSet[IpAddressRange]) = {
if (!toValidate.isEmpty && !checkWithinBounds(toValidate))
throw new IllegalArgumentException("invalid free ranges: not all within pool range")
}
private def checkWithinBounds(toValidate: SortedSet[IpAddressRange]): Boolean = {
toValidate.firstKey.first >= first && toValidate.lastKey.last <= last
}
/**
* Allocate the first free address in the pool.
*
* @returns the pool after allocation and the allocated address (or None if no address was free)
*/
def allocate(): (IpAddressPool, Option[IpAddress]) = {
if (!isExhausted) {
// get the first range of free addresses, and take the first address of that range
val range: IpAddressRange = freeRanges.firstKey
val toAllocate: IpAddress = range.first
doAllocate(toAllocate, range)
} else {
(this, None)
}
}
/**
* Allocate the given address in the pool.
*
* @param toAllocate address to allocate in the pool
* @returns the pool after allocation and the allocated address (or None if the address was not free in this pool)
*/
def allocate(toAllocate: IpAddress): (IpAddressPool, Option[IpAddress]) = {
if (!contains(toAllocate))
throw new IllegalArgumentException("can not allocate address which is not contained in the range of the pool [" + toAllocate + "]")
// go find the range that contains the requested address
findFreeRangeContaining(toAllocate) match {
case Some(range) => doAllocate(toAllocate, range) // allocate in the range we found
case None => {
(this, None) // no free range found for the requested address
}
}
}
private def findFreeRangeContaining(toAllocate: IpAddress): Option[IpAddressRange] = {
// split around the address to allocate
val head = freeRanges.until(new IpAddressRange(toAllocate, toAllocate))
val tail = freeRanges.from(new IpAddressRange(toAllocate, toAllocate))
// the range we need is either the first of the tail, or the last of the head, or it doesn't exist
if (!head.isEmpty && head.lastKey.contains(toAllocate)) {
Some(head.lastKey)
}
else if (!tail.isEmpty && tail.firstKey.contains(toAllocate)) {
Some(tail.firstKey)
}
else {
None
}
}
/**
* Allocate the given address in the given range. It is assumed at this point that the range actually contains
* the address, and that the range is one of the free ranges of the pool.
*/
private def doAllocate(toAllocate: IpAddress, range: IpAddressRange): (IpAddressPool, Option[IpAddress]) = {
// remove the range and replace with ranges without the allocated address
val newRanges = range - toAllocate
// note: the cast to SortedSet is a workaround until scala 2.8 (http://stackoverflow.com/questions/1271426/scala-immutable-sortedset-are-not-stable-on-deletion)
val remainingRanges = (freeRanges ++ newRanges).asInstanceOf[SortedSet[IpAddressRange]] - range
(new IpAddressPool(this.first, this.last, remainingRanges.asInstanceOf[SortedSet[IpAddressRange]]), Some(toAllocate))
}
/**
* Deallocate the given address in the pool. The given address will be free in the returned pool.
*
* @returns the pool after deallocation
*/
def deAllocate(address: IpAddress): IpAddressPool = {
if (!contains(address))
throw new IllegalArgumentException("can not deallocate address which is not contained in the range of the pool [" + address + "]")
new IpAddressPool(first, last, addAddressToFreeRanges(address))
}
/**
* Add the given address as a free address in the set of free ranges. The implementation tries to merge existing ranges
* as much as possible to prevent fragmentation.
*/
private def addAddressToFreeRanges(address: IpAddress): SortedSet[IpAddressRange] = {
val freeRangeBeforeAddress: Iterable[IpAddressRange] = freeRanges.filter(element => element.last + 1 == address)
val freeRangeAfterAddress: Iterable[IpAddressRange] = freeRanges.filter(element => element.first - 1 == address)
if (freeRangeBeforeAddress.isEmpty && freeRangeAfterAddress.isEmpty) {
// no match -> nothing to "defragment"
freeRanges + new IpAddressRange(address, address)
} else {
if (!freeRangeBeforeAddress.isEmpty && !freeRangeAfterAddress.isEmpty) {
// first and last match -> merge the 2 existing ranges
(freeRanges -
freeRangeBeforeAddress.toSeq(0) -
freeRangeAfterAddress.toSeq(0) +
new IpAddressRange(freeRangeBeforeAddress.toSeq(0).first, freeRangeAfterAddress.toSeq(0).last)).
asInstanceOf[SortedSet[IpAddressRange]] // workaround, see above
} else if (!freeRangeBeforeAddress.isEmpty) {
// append
(freeRanges -
freeRangeBeforeAddress.toSeq(0) +
(freeRangeBeforeAddress.toSeq(0) + address)).
asInstanceOf[SortedSet[IpAddressRange]] // workaround, see above
} else {
// prepend
(freeRanges -
freeRangeAfterAddress.toSeq(0) +
(freeRangeAfterAddress.toSeq(0) + address)).
asInstanceOf[SortedSet[IpAddressRange]] // workaround, see above
}
}
}
def isExhausted: Boolean = {
freeRanges.isEmpty
}
def isFree(address: IpAddress): Boolean = {
// lookup the address in all free ranges, if true in one, the result is true
freeRanges.map(_ contains address).reduceLeft((x, y) => x || y)
}
/**
* @return the number of free ranges fragments
*/
def fragments(): Int = {
freeRanges.size
}
/**
* @return a stream of all free addresses in the pool
*/
def freeAddresses(): Stream[IpAddress] = {
toAddressesStream(freeRanges.toList)
}
/**
* @return a stream of all allocated addresses in the pool
*/
def allocatedAddresses(): Stream[IpAddress] = {
toAddressesStream(allocatedRanges.toList)
}
/**
* @return ranges of allocated addresses in the pool
* @note the pool implementation keeps track of the free addresses, so this operation is more expensive than the freeRanges() one
*/
def allocatedRanges: List[IpAddressRange] = {
if (freeRanges.isEmpty) {
// one big range of allocated addresses
List[IpAddressRange](new IpAddressRange(first, last))
} else {
makeNonEmptyListOfAllocatedRanges()
}
}
private def makeNonEmptyListOfAllocatedRanges(): List[IpAddressRange] = {
val allocatedRanges: ListBuffer[IpAddressRange] = new ListBuffer[IpAddressRange]()
var currentStart: IpAddress = first
var currentEnd: IpAddress = null
for (freeRange <- freeRanges) {
currentEnd = freeRange.first
if (currentEnd != currentStart) { // occurs if first free range starts at the beginning of the pool
allocatedRanges.append(new IpAddressRange(currentStart, currentEnd - 1))
}
currentStart = freeRange.last + 1
}
if (currentStart <= last) { // occurs if the last free range didn't reach until the end of the pool
allocatedRanges.append(new IpAddressRange(currentStart, last))
}
allocatedRanges.toList
}
// /**
// * @return ranges of free addresses in the pool
// */
// def freeRanges(): SortedSet[IpAddressRange] = freeRanges
private def toAddressesStream(ranges: List[IpAddressRange]): Stream[IpAddress] = {
if (ranges.isEmpty) {
Stream.empty
} else {
Stream.concat(ranges.head.addresses, toAddressesStream(ranges.tail))
}
}
override def toString: String = {
"IpAddressPool " + super.toString + " with free ranges " + freeRanges.toString
}
// TODO: toStringRepresentation which can also be parsed back into an IpAddressPool
// equals implemented as suggested in staircase book
override def equals(other: Any): Boolean = {
other match {
case that: IpAddressPool => super.equals(that) && this.freeRanges == that.freeRanges
case _ => false
}
}
protected override def canEqual(other: Any): Boolean = {
other.isInstanceOf[IpAddressPool]
}
override def hashCode = {
41 * (41 + first.hashCode) + last.hashCode
}
}
\ No newline at end of file
package be.jvb.iptypes
import scala.math.Ordered
/**
* Represents a continuous range of IPv4 ip addresses (bounds included).
*
* @author <a href="http://janvanbesien.blogspot.com">Jan Van Besien</a>
*
* @param first first address in the range
* @param last last address in the range
*/
class IpAddressRange(val first: IpAddress, val last: IpAddress) extends Ordered[IpAddressRange] {
if (last < first)
throw new IllegalArgumentException("Cannot create ip address range with last address > first address")
def contains(address: IpAddress): Boolean = {
address >= first && address <= last
}
def contains(range: IpAddressRange): Boolean = {
contains(range.first) && contains(range.last)
}
def overlaps(range: IpAddressRange): Boolean = {
contains(range.first) || contains(range.last) || range.contains(first) || range.contains(last)
}
def length = {
last.value - first.value + 1
}
def addresses: Stream[IpAddress] = {
if (first < last) {
Stream.cons(first, new IpAddressRange(first + 1, last).addresses)
} else {
Stream.cons(first, Stream.empty)
}
}
/**
* Ip address ranges are ordered on the first address, or on the second address if the first is equal.
*/
def compare(that: IpAddressRange): Int = {
if (this.first != that.first)
this.first.compare(that.first)
else
this.last.compare(that.last)
}
/**
* Remove an address from the range, resulting in one, none or two new ranges.
*/
def -(address: IpAddress): List[IpAddressRange] = {
if (address eq null)
throw new IllegalArgumentException("invalid address [null]")
if (!contains(address))
List(this)
else if (address == first && address == last)
List()
else if (address == first)
List(new IpAddressRange(first + 1, last))
else if (address == last)
List(new IpAddressRange(first, last - 1))
else
List(new IpAddressRange(first, address - 1), new IpAddressRange(address + 1, last))
}
/**
* Extend the range just enough at its head or tail such that the given address is included.
*/
def +(address: IpAddress): IpAddressRange = {
if (address < first)
new IpAddressRange(address, last)
else if (address > last)
new IpAddressRange(first, address)
else
this
}
override def toString: String = {
first.toString + " - " + last.toString
}
// equals implemented as suggested in staircase book
override def equals(other: Any): Boolean = {
other match {
case that: IpAddressRange => that.canEqual(this) && this.first == that.first && this.last == that.last
case _ => false
}
}
protected def canEqual(other: Any): Boolean = {
other.isInstanceOf[IpAddressRange]
}
override def hashCode = {
41 * (41 + first.hashCode) + last.hashCode
}
}
package be.jvb.iptypes
import java.lang.String
/**
* Represents an Ipv4 network (i.e. an address and a mask).
*
* @author <a href="http://janvanbesien.blogspot.com">Jan Van Besien</a>
*
* @param address network address of the network
* @param mask network mask of the network
*/
class IpNetwork(val address: IpAddress, val mask: IpNetworkMask)
extends IpAddressRange(IpNetwork.first(address, mask), IpNetwork.last(address, mask)) {
/**
* Construct a network from two addresses. This will create the smallest possible network ("longest prefix match") which contains
* both addresses.
*/
def this(first: IpAddress, last: IpAddress) = this (first, IpNetworkMask.longestPrefixNetwork(first, last))
private def this(addressAndMask: (IpAddress, IpNetworkMask)) = this (addressAndMask._1, addressAndMask._2)
/**
* Construct a network from a CIDR notation (e.g. "192.168.0.0/24" or "192.168.0.0/255.255.255.0")
*/
def this(network: String) = this (IpNetwork.parseAddressAndMaskFromCidrNotation(network))
/**
* @return CIDR notation
*/
override def toString: String = first.toString + "/" + mask.prefixLength
}
object IpNetwork {
/**
* get the first address from a network which contains the given address.
*/
private[iptypes] def first(address: IpAddress, mask: IpNetworkMask): IpAddress = {
new IpAddress(address.value & mask.value)
}
/**
* get the last address from a network which contains the given address.
*/
private[iptypes] def last(address: IpAddress, mask: IpNetworkMask): IpAddress = {
first(address, mask) + (0xFFFFFFFFL >> mask.prefixLength)
}
private[iptypes] def parseAddressAndMaskFromCidrNotation(cidrString: String): (IpAddress, IpNetworkMask) = {
if (!cidrString.contains("/"))
throw new IllegalArgumentException("no CIDR format [" + cidrString + "]")
val addressAndMask: (String, String) = splitInAddressAndMask(cidrString)
val address = new IpAddress(addressAndMask._1)
val mask = parseNetworkMask(addressAndMask._2)
(address, mask)
}
private def splitInAddressAndMask(cidrString: String): (String, String) = {
val addressAndMask: Array[String] = cidrString.split("/")
if (addressAndMask.length != 2)
throw new IllegalArgumentException("no CIDR format [" + cidrString + "]")
(addressAndMask(0), addressAndMask(1))
}
private def parseNetworkMask(mask: String) = {
try
{
if (mask.contains("."))
new IpNetworkMask(mask)
else
IpNetworkMask.fromPrefixLength(Integer.parseInt(mask))
} catch {
case e: Exception => throw new IllegalArgumentException("not a valid network mask [" + mask + "]", e)
}
}
}
\ No newline at end of file
package be.jvb.iptypes
import java.lang.IllegalArgumentException
/**
* Represents an IPv4 network mask.
*
* @author <a href="http://janvanbesien.blogspot.com">Jan Van Besien</a>
*/
class IpNetworkMask(override val value: Long) extends IpAddress(value) {
def this(address: String) = this (SmallByteArray.parseAsLong(address, IpAddress.N_BYTES, DEC()))
checkMaskValidity()
private def checkMaskValidity() = {
if (!IpNetworkMask.VALID_MASK_VALUES.contains(value))
throw new IllegalArgumentException("Not a valid ip network mask [" + this + "]")
}
def prefixLength = {
IpNetworkMask.fromLongToPrefixLength(value)
}
}
object IpNetworkMask {
private[iptypes] val VALID_MASK_VALUES = for (prefixLength <- 0 to 32) yield fromPrefixLenthToLong(
prefixLength)
/**
* Convert a prefix length (e.g. 24) into a network mask (e.g. 255.255.255.0). IpNetworkMask hasn't got a public constructor for this, because
* it would be confusing with the constructor that takes a long.
*/
def fromPrefixLength(prefixLength: Int): IpNetworkMask = {
new IpNetworkMask(fromPrefixLenthToLong(prefixLength))
}
private[iptypes] def fromPrefixLenthToLong(prefixLength: Int): Long = {
(((1L << 32) - 1) << (32 - prefixLength)) & 0xFFFFFFFFL
}
private[iptypes] def fromLongToPrefixLength(value: Long): Int = {
val lsb: Long = value & 0xFFFFFFFFL
var result: Int = 0
var bit: Long = 1L << 31
while (((lsb & bit) != 0) && (result < 32)) {
bit = bit >> 1
result += 1
}
result
}
/**
* Construct a network mask which has the longest matching prefix to still contain both given addresses.
*/
def longestPrefixNetwork(first: IpAddress, last: IpAddress): IpNetworkMask = {
IpNetworkMask.fromPrefixLength(IpNetworkMask.fromLongToPrefixLength(~first.value ^ last.value))
}
def apply(string: String): IpNetworkMask = new IpNetworkMask(SmallByteArray.parseAsLong(string, IpAddress.N_BYTES, DEC()))
def unapply(ipNetworkMask: IpNetworkMask): Option[String] = {
Some(ipNetworkMask.toString)
}
}
\ No newline at end of file
package be.jvb.iptypes
/**
* Represents a MAC address.
*
* @author <a href="http://janvanbesien.blogspot.com">Jan Van Besien</a>
*/
class MacAddress(val value: Long) extends SmallByteArray {
def this(address: String) = this(SmallByteArray.parseAsLong(address, MacAddress.N_BYTES, HEX()))
protected def nBytes = MacAddress.N_BYTES
protected def radix = HEX()
override def zeroPaddingUpTo = 2
/**
* Addition. Will never overflow, but wraps around when the highest MAC address has been reached.
*/
def +(value: Long) = new MacAddress((this.value + value) & maxValue)
/**
* Substraction. Will never underflow, but wraps around when the lowest MAC address has been reached.
*/
def -(value: Long) = new MacAddress((this.value - value) & maxValue)
}
object MacAddress {
val N_BYTES = 6
// def apply(string: String): MacAddress = new MacAddress(SmallByteArray.parseAsLong(string, N_BYTES))
// def unapply(macAddress: MacAddress): Some[String] = macAddress.toString
}
package be.jvb.iptypes
/**
* Enumeration of possible radix values (hexadecimal and decimal).
*
* @author <a href="http://janvanbesien.blogspot.com">Jan Van Besien</a>
*/
private[iptypes] sealed trait Radix {
val radix:Int
}
private[iptypes] final case class HEX() extends Radix {
override val radix = 16
}
private[iptypes] final case class DEC() extends Radix {
override val radix = 10
}
\ No newline at end of file
package be.jvb.iptypes
import java.util.Arrays
import scala.math.Ordered
import java.util
/**
* Represents a byte array which is small enough to fit in a long (max 8 bytes).
*
* @author <a href="http://janvanbesien.blogspot.com">Jan Van Besien</a>
*/
private[iptypes] trait SmallByteArray extends Ordered[SmallByteArray] {
val value: Long
/** How many bytes do we use (max 8). */
protected def nBytes: Int
/** In what radix do we represent the bytes when converting to a string. */
protected def radix: Radix
/** Do we need to padd the bytes with zeros when converting to a string. */
protected def zeroPaddingUpTo: Int = 0
val maxValue = Math.pow(2, nBytes * 8).toLong - 1
if (nBytes < 0 || nBytes > 8) {
throw new IllegalArgumentException("SmallByteArray can be used for arrays of length 0 to 8 only")
}
if (value > maxValue || value < 0) {
throw new IllegalArgumentException("out of range [0x" + java.lang.Long.toHexString(value) + "] with [" + nBytes + "] bytes")
}
/**
* @return integer array of the bytes in this byte array.
*/
def toIntArray: Array[Int] = {
val ints = new Array[Int](nBytes)
for (i <- 0 until nBytes) {
ints(i) = (((value << i * 8) >>> 8 * (nBytes - 1)) & 0xFF).asInstanceOf[Int]
}
ints.foreach((anInt) => assert(anInt >= 0 && anInt <= 255))
ints
}
/**
* @return byte array of the bytes in this byte array.
*/
def toByteArray: Array[Byte] = {
val bytes = new Array[Byte](nBytes)
for (i <- 0 until nBytes) {
bytes(i) = (((value << i * 8) >>> 8 * (nBytes - 1)) & 0xFF).asInstanceOf[Byte]
}
bytes
}
override def compare(that: SmallByteArray): Int = {
this.value.compare(that.value)
}
// equals implemented as suggested in staircase book
override def equals(other: Any): Boolean = {
other match {
case that: SmallByteArray => that.canEqual(this) && this.value == that.value
case _ => false
}
}
protected def canEqual(other: Any): Boolean = {
other.isInstanceOf[SmallByteArray]
}
override def hashCode = {
value.hashCode
}
/**
* @return String representation of the byte array, with "." between every byte.
*/
override def toString: String = {
val ints = toIntArray
val strings = for (i <- 0 until nBytes) yield String.format(formatString, ints(i).asInstanceOf[Object])
strings.mkString(".")
}
private lazy val formatString = {
radix match {
case HEX() => {
if (zeroPaddingUpTo != 0)
"%0" + zeroPaddingUpTo + "X"
else
"%X"
}
case DEC() => {
if (zeroPaddingUpTo != 0)
"%0" + zeroPaddingUpTo + "d"
else
"%d"
}
}
}
}
object SmallByteArray {
private[iptypes] def parseAsLong(string: String, length: Int, radix: Radix): Long = {
if (string eq null)
throw new IllegalArgumentException("can not parse [null]")
val longArray = parseAsLongArray(string, radix)
validate(longArray, length)
mergeBytesOfArrayIntoLong(longArray)
}
private def parseAsLongArray(string: String, radix: Radix): Array[Long] = {
string.split("\\.").map(java.lang.Long.parseLong(_, radix.radix))
}
private def validate(array: Array[Long], length: Int) = {
if (array.length != length)
throw new IllegalArgumentException("can not parse values [" + util.Arrays.toString(array) + "] into a SmallByteArray of [" + length + "] bytes")
if (!array.filter(_ < 0).isEmpty)
throw new IllegalArgumentException("each element should be positive [" + util.Arrays.toString(array) + "]")
if (!array.filter(_ > 255).isEmpty)
throw new IllegalArgumentException("each element should be less than 255 [" + util.Arrays.toString(array) + "]")
}
private def mergeBytesOfArrayIntoLong(array: Array[Long]): Long = {
var result = 0L
for (i <- 0 until array.length) {
result |= (array(i) << ((array.length - i - 1) * 8))
}
result
}
}
...@@ -53,7 +53,8 @@ import org.apache.http.conn.util.InetAddressUtils ...@@ -53,7 +53,8 @@ import org.apache.http.conn.util.InetAddressUtils
import android.os.Message import android.os.Message
import scala.Some import scala.Some
import scala.concurrent.ops._ import scala.concurrent.ops._
import be.jvb.iptypes.{IpNetwork, IpAddress} import org.apache.commons.net.util.SubnetUtils
import java.net.InetAddress
object ShadowVpnService { object ShadowVpnService {
def isServiceStarted(context: Context): Boolean = { def isServiceStarted(context: Context): Boolean = {
...@@ -251,10 +252,7 @@ class ShadowVpnService extends VpnService { ...@@ -251,10 +252,7 @@ class ShadowVpnService extends VpnService {
def startVpn() { def startVpn() {
val proxy_address = new IpAddress(config.proxy) val proxy_address = config.proxy
val private_networks = Array[IpNetwork](new IpNetwork("127.0.0.0/8"),
new IpNetwork("10.0.0.0/8"), new IpNetwork("172.16.0.0/12"), new IpNetwork("192.168.0.0/16"))
val builder = new Builder() val builder = new Builder()
builder builder
...@@ -267,24 +265,27 @@ class ShadowVpnService extends VpnService { ...@@ -267,24 +265,27 @@ class ShadowVpnService extends VpnService {
builder.addRoute("0.0.0.0", 0) builder.addRoute("0.0.0.0", 0)
} else if (config.isGFWList) { } else if (config.isGFWList) {
val gfwList = getResources.getStringArray(R.array.gfw_list) val gfwList = getResources.getStringArray(R.array.gfw_list)
gfwList.foreach(addr => { gfwList.foreach(cidr => {
val network = new IpNetwork(addr) val net = new SubnetUtils(cidr).getInfo
if (!network.contains(proxy_address)) { if (!net.isInRange(proxy_address)) {
builder.addRoute(network.address.toString, network.mask.prefixLength) val addr = cidr.split('/')
builder.addRoute(addr(0), addr(1).toInt)
} }
}) })
} else { } else {
for (i <- 1 to 254) { for (i <- 1 to 254) {
val network = new IpNetwork(i.toString + ".0.0.0/8") val addr = i.toString + ".0.0.0"
if (!network.contains(proxy_address) && val cidr = addr + "/8"
private_networks.forall(range => !network.contains(range))) { val net = new SubnetUtils(cidr).getInfo
builder.addRoute(i + ".0.0.0", 8) if (!net.isInRange(proxy_address)) {
if (!InetAddress.getByName(addr).isSiteLocalAddress) builder.addRoute(addr, 8)
} else { } else {
for (j <- 0 to 255) { for (j <- 0 to 255) {
val subNetwork = new IpNetwork(i.toString + "." + j.toString + ".0.0/16") val addr = i.toString + "." + j.toString + ".0.0"
if (!subNetwork.contains(proxy_address) && val cidr = addr + "/16"
private_networks.forall(range => !range.overlaps(subNetwork))) { val net = new SubnetUtils(cidr).getInfo
builder.addRoute(subNetwork.address.toString, subNetwork.mask.prefixLength) if (!net.isInRange(proxy_address)) {
if (!InetAddress.getByName(addr).isSiteLocalAddress) builder.addRoute(addr, 16)
} }
} }
} }
......
...@@ -303,6 +303,8 @@ class ShadowsocksService extends Service { ...@@ -303,6 +303,8 @@ class ShadowsocksService extends Service {
startDnsDaemon() startDnsDaemon()
startRedsocksDaemon() startRedsocksDaemon()
setupIptables setupIptables
flushDNS()
true true
} }
...@@ -496,6 +498,11 @@ class ShadowsocksService extends Service { ...@@ -496,6 +498,11 @@ class ShadowsocksService extends Service {
Service.START_STICKY Service.START_STICKY
} }
def flushDNS() {
Utils.runRootCommand("ndc resolver flushdefaultif\n"
+ "ndc resolver flushif wlan0\n")
}
def setupIptables: Boolean = { def setupIptables: Boolean = {
val init_sb = new StringBuilder val init_sb = new StringBuilder
val http_sb = new StringBuilder val http_sb = new StringBuilder
......
...@@ -343,10 +343,14 @@ object Utils { ...@@ -343,10 +343,14 @@ object Utils {
private def toggleAboveApiLevel17() { private def toggleAboveApiLevel17() {
// Android 4.2 and above // Android 4.2 and above
Utils.runRootCommand("settings put global airplane_mode_on 1\n"
+ "am broadcast -a android.intent.action.AIRPLANE_MODE --ez state true\n" Utils.runRootCommand("ndc resolver flushdefaultif\n"
+ "settings put global airplane_mode_on 0\n" + "ndc resolver flushif wlan0\n")
+ "am broadcast -a android.intent.action.AIRPLANE_MODE --ez state false\n")
//Utils.runRootCommand("settings put global airplane_mode_on 1\n"
// + "am broadcast -a android.intent.action.AIRPLANE_MODE --ez state true\n"
// + "settings put global airplane_mode_on 0\n"
// + "am broadcast -a android.intent.action.AIRPLANE_MODE --ez state false\n")
} }
private def toggleBelowApiLevel17(context: Context) { private def toggleBelowApiLevel17(context: Context) {
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment