diff --git a/build.sbt b/build.sbt
index 9cc0a8e7..2681f52e 100644
--- a/build.sbt
+++ b/build.sbt
@@ -3,7 +3,8 @@ libraryDependencies ++= Seq(
"com.google.android" % "analytics" % "3.01",
"com.google.android" % "admob" % "6.4.1",
"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(
diff --git a/project/Build.scala b/project/Build.scala
index bd75ad11..e717f066 100644
--- a/project/Build.scala
+++ b/project/Build.scala
@@ -5,8 +5,8 @@ import sbtandroid._
import sbtandroid.AndroidPlugin._
object App {
- val version = "2.0.4"
- val versionCode = 55
+ val version = "2.0.5"
+ val versionCode = 56
}
object General {
diff --git a/src/main/jni/Application.mk b/src/main/jni/Application.mk
index a52bf0fa..bd947266 100644
--- a/src/main/jni/Application.mk
+++ b/src/main/jni/Application.mk
@@ -1,4 +1,4 @@
APP_ABI := armeabi x86
APP_PLATFORM := android-9
APP_STL := stlport_static
-NDK_TOOLCHAIN_VERSION := 4.8
+NDK_TOOLCHAIN_VERSION := 4.6
diff --git a/src/main/scala/be/jvb/iptypes/IpAddress.scala b/src/main/scala/be/jvb/iptypes/IpAddress.scala
deleted file mode 100644
index e88d3d8b..00000000
--- a/src/main/scala/be/jvb/iptypes/IpAddress.scala
+++ /dev/null
@@ -1,57 +0,0 @@
-package be.jvb.iptypes
-
-import java.net.InetAddress
-
-/**
- * Represents an IPv4 address.
- *
- * @author Jan Van Besien
- *
- * @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)
- }
-
-}
-
diff --git a/src/main/scala/be/jvb/iptypes/IpAddressPool.scala b/src/main/scala/be/jvb/iptypes/IpAddressPool.scala
deleted file mode 100644
index df3bbf00..00000000
--- a/src/main/scala/be/jvb/iptypes/IpAddressPool.scala
+++ /dev/null
@@ -1,253 +0,0 @@
-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 Jan Van Besien
- *
- * @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
diff --git a/src/main/scala/be/jvb/iptypes/IpAddressRange.scala b/src/main/scala/be/jvb/iptypes/IpAddressRange.scala
deleted file mode 100644
index 77dd8cd8..00000000
--- a/src/main/scala/be/jvb/iptypes/IpAddressRange.scala
+++ /dev/null
@@ -1,102 +0,0 @@
-package be.jvb.iptypes
-
-import scala.math.Ordered
-
-/**
- * Represents a continuous range of IPv4 ip addresses (bounds included).
- *
- * @author Jan Van Besien
- *
- * @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
- }
-}
diff --git a/src/main/scala/be/jvb/iptypes/IpNetwork.scala b/src/main/scala/be/jvb/iptypes/IpNetwork.scala
deleted file mode 100644
index 575915d8..00000000
--- a/src/main/scala/be/jvb/iptypes/IpNetwork.scala
+++ /dev/null
@@ -1,79 +0,0 @@
-package be.jvb.iptypes
-
-import java.lang.String
-
-/**
- * Represents an Ipv4 network (i.e. an address and a mask).
- *
- * @author Jan Van Besien
- *
- * @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
diff --git a/src/main/scala/be/jvb/iptypes/IpNetworkMask.scala b/src/main/scala/be/jvb/iptypes/IpNetworkMask.scala
deleted file mode 100644
index ea69914c..00000000
--- a/src/main/scala/be/jvb/iptypes/IpNetworkMask.scala
+++ /dev/null
@@ -1,67 +0,0 @@
-package be.jvb.iptypes
-
-import java.lang.IllegalArgumentException
-
-/**
- * Represents an IPv4 network mask.
- *
- * @author Jan Van Besien
- */
-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
diff --git a/src/main/scala/be/jvb/iptypes/MacAddress.scala b/src/main/scala/be/jvb/iptypes/MacAddress.scala
deleted file mode 100644
index e3a176d6..00000000
--- a/src/main/scala/be/jvb/iptypes/MacAddress.scala
+++ /dev/null
@@ -1,37 +0,0 @@
-package be.jvb.iptypes
-
-/**
- * Represents a MAC address.
- *
- * @author Jan Van Besien
- */
-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
-
-}
diff --git a/src/main/scala/be/jvb/iptypes/Radix.scala b/src/main/scala/be/jvb/iptypes/Radix.scala
deleted file mode 100644
index a1fb6a04..00000000
--- a/src/main/scala/be/jvb/iptypes/Radix.scala
+++ /dev/null
@@ -1,16 +0,0 @@
-package be.jvb.iptypes
-
-/**
- * Enumeration of possible radix values (hexadecimal and decimal).
- *
- * @author Jan Van Besien
- */
-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
diff --git a/src/main/scala/be/jvb/iptypes/SmallByteArray.scala b/src/main/scala/be/jvb/iptypes/SmallByteArray.scala
deleted file mode 100644
index 1aa882a6..00000000
--- a/src/main/scala/be/jvb/iptypes/SmallByteArray.scala
+++ /dev/null
@@ -1,145 +0,0 @@
-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 Jan Van Besien
- */
-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
- }
-}
diff --git a/src/main/scala/com/github/shadowsocks/ShadowVpnService.scala b/src/main/scala/com/github/shadowsocks/ShadowVpnService.scala
index f1b84ac6..af935eff 100644
--- a/src/main/scala/com/github/shadowsocks/ShadowVpnService.scala
+++ b/src/main/scala/com/github/shadowsocks/ShadowVpnService.scala
@@ -53,7 +53,8 @@ import org.apache.http.conn.util.InetAddressUtils
import android.os.Message
import scala.Some
import scala.concurrent.ops._
-import be.jvb.iptypes.{IpNetwork, IpAddress}
+import org.apache.commons.net.util.SubnetUtils
+import java.net.InetAddress
object ShadowVpnService {
def isServiceStarted(context: Context): Boolean = {
@@ -251,10 +252,7 @@ class ShadowVpnService extends VpnService {
def startVpn() {
- val proxy_address = new IpAddress(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 proxy_address = config.proxy
val builder = new Builder()
builder
@@ -267,24 +265,27 @@ class ShadowVpnService extends VpnService {
builder.addRoute("0.0.0.0", 0)
} else if (config.isGFWList) {
val gfwList = getResources.getStringArray(R.array.gfw_list)
- gfwList.foreach(addr => {
- val network = new IpNetwork(addr)
- if (!network.contains(proxy_address)) {
- builder.addRoute(network.address.toString, network.mask.prefixLength)
+ gfwList.foreach(cidr => {
+ val net = new SubnetUtils(cidr).getInfo
+ if (!net.isInRange(proxy_address)) {
+ val addr = cidr.split('/')
+ builder.addRoute(addr(0), addr(1).toInt)
}
})
} else {
for (i <- 1 to 254) {
- val network = new IpNetwork(i.toString + ".0.0.0/8")
- if (!network.contains(proxy_address) &&
- private_networks.forall(range => !network.contains(range))) {
- builder.addRoute(i + ".0.0.0", 8)
+ val addr = i.toString + ".0.0.0"
+ val cidr = addr + "/8"
+ val net = new SubnetUtils(cidr).getInfo
+ if (!net.isInRange(proxy_address)) {
+ if (!InetAddress.getByName(addr).isSiteLocalAddress) builder.addRoute(addr, 8)
} else {
for (j <- 0 to 255) {
- val subNetwork = new IpNetwork(i.toString + "." + j.toString + ".0.0/16")
- if (!subNetwork.contains(proxy_address) &&
- private_networks.forall(range => !range.overlaps(subNetwork))) {
- builder.addRoute(subNetwork.address.toString, subNetwork.mask.prefixLength)
+ val addr = i.toString + "." + j.toString + ".0.0"
+ val cidr = addr + "/16"
+ val net = new SubnetUtils(cidr).getInfo
+ if (!net.isInRange(proxy_address)) {
+ if (!InetAddress.getByName(addr).isSiteLocalAddress) builder.addRoute(addr, 16)
}
}
}
diff --git a/src/main/scala/com/github/shadowsocks/ShadowsocksService.scala b/src/main/scala/com/github/shadowsocks/ShadowsocksService.scala
index 580d368b..db05b328 100644
--- a/src/main/scala/com/github/shadowsocks/ShadowsocksService.scala
+++ b/src/main/scala/com/github/shadowsocks/ShadowsocksService.scala
@@ -303,6 +303,8 @@ class ShadowsocksService extends Service {
startDnsDaemon()
startRedsocksDaemon()
setupIptables
+ flushDNS()
+
true
}
@@ -496,6 +498,11 @@ class ShadowsocksService extends Service {
Service.START_STICKY
}
+ def flushDNS() {
+ Utils.runRootCommand("ndc resolver flushdefaultif\n"
+ + "ndc resolver flushif wlan0\n")
+ }
+
def setupIptables: Boolean = {
val init_sb = new StringBuilder
val http_sb = new StringBuilder
diff --git a/src/main/scala/com/github/shadowsocks/Utils.scala b/src/main/scala/com/github/shadowsocks/Utils.scala
index f0dd92ad..b7edae54 100644
--- a/src/main/scala/com/github/shadowsocks/Utils.scala
+++ b/src/main/scala/com/github/shadowsocks/Utils.scala
@@ -343,10 +343,14 @@ object Utils {
private def toggleAboveApiLevel17() {
// 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"
- + "settings put global airplane_mode_on 0\n"
- + "am broadcast -a android.intent.action.AIRPLANE_MODE --ez state false\n")
+
+ Utils.runRootCommand("ndc resolver flushdefaultif\n"
+ + "ndc resolver flushif wlan0\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) {