From 765bf837f3647ea1812bf41260635b9ed37a7635 Mon Sep 17 00:00:00 2001 From: Max Lv Date: Sat, 23 Nov 2013 14:44:51 +0800 Subject: [PATCH] use commons-net instead --- build.sbt | 3 +- project/Build.scala | 4 +- src/main/jni/Application.mk | 2 +- src/main/scala/be/jvb/iptypes/IpAddress.scala | 57 ---- .../scala/be/jvb/iptypes/IpAddressPool.scala | 253 ------------------ .../scala/be/jvb/iptypes/IpAddressRange.scala | 102 ------- src/main/scala/be/jvb/iptypes/IpNetwork.scala | 79 ------ .../scala/be/jvb/iptypes/IpNetworkMask.scala | 67 ----- .../scala/be/jvb/iptypes/MacAddress.scala | 37 --- src/main/scala/be/jvb/iptypes/Radix.scala | 16 -- .../scala/be/jvb/iptypes/SmallByteArray.scala | 145 ---------- .../github/shadowsocks/ShadowVpnService.scala | 35 +-- .../shadowsocks/ShadowsocksService.scala | 7 + .../scala/com/github/shadowsocks/Utils.scala | 12 +- 14 files changed, 38 insertions(+), 781 deletions(-) delete mode 100644 src/main/scala/be/jvb/iptypes/IpAddress.scala delete mode 100644 src/main/scala/be/jvb/iptypes/IpAddressPool.scala delete mode 100644 src/main/scala/be/jvb/iptypes/IpAddressRange.scala delete mode 100644 src/main/scala/be/jvb/iptypes/IpNetwork.scala delete mode 100644 src/main/scala/be/jvb/iptypes/IpNetworkMask.scala delete mode 100644 src/main/scala/be/jvb/iptypes/MacAddress.scala delete mode 100644 src/main/scala/be/jvb/iptypes/Radix.scala delete mode 100644 src/main/scala/be/jvb/iptypes/SmallByteArray.scala 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) {