Jump to content
Not connected, Your IP: 3.15.6.140
Staff

Eddie 2.17beta released

Recommended Posts

Hello!

 

We're very glad to inform you that a new Eddie Air client version has been released: 2.17beta. It is ready for public beta testing.

 

How to test our experimental release:

  • Go to download page of your OS
  • Click on Other versions

    client-experimental-howto-1.png

  • Click on Experimental

    client-experimental-howto-2.png

  • Look at the changelog if you wish
  • Download and install
Please see the changelog:

https://eddie.website/changelog/?software=client&format=html

Share this post


Link to post

Hi Staff,

 

I just installed the new beta (2.17.1) on a MacOS laptop running the latest High Sierra (10.13.6).  Upon firing up the Eddie beta, I got the attached error window.  Eddie closed itself immediately after I clicked the "OK" button on the error window, so I didn't have a chance to grab logs (Eddie didn't finish starting up all the way when the error window popped).  Had no internet connectivity after that until I rebooted the machine.  I did install the beta over 2.16.3, fwiw, in case that's an issue.  Although I have done that in the past with betas and not encountered any issues.  Rolled back to 2.16.3 for now.  If there's more I can do go help get useful info about this issue, please let me know.

 

Many thanks...

Share this post


Link to post

I downloaded it to try it out with Ubuntu 18.04.1.  It downloaded okay and seemed to install just fine, but it crashes very early every time I try to use it.  I mean, it just closes without warning when I try to use it: sometimes it's while I'm logging in, sometimes it when I'm trying to choose a server, and other times just when I'm moving the mouse.  I haven't had it stay open longer than a minute.  So I'm back to using 2.16.3 for now.

Share this post


Link to post

Hi Staff,

 

I just installed the new beta (2.17.1) on a MacOS laptop running the latest High Sierra (10.13.6).  Upon firing up the Eddie beta, I got the attached error window.  Eddie closed itself immediately after I clicked the "OK" button on the error window, so I didn't have a chance to grab logs (Eddie didn't finish starting up all the way when the error window popped).  Had no internet connectivity after that until I rebooted the machine.  I did install the beta over 2.16.3, fwiw, in case that's an issue.  Although I have done that in the past with betas and not encountered any issues.  Rolled back to 2.16.3 for now.  If there's more I can do go help get useful info about this issue, please let me know.

 

Many thanks...

 

Same issue happened to me on a MacOS iMac (High Sierra 10.3.6 too) after installing Eddie 2.17.1 (new beta). It seems to happen randomly though. Sometimes I can connect to a server at first attempt, another time the error message appears, then Eddie closes itself. I did not install this new version over 2.16.3 but deleted it before and rebooted the machine, then installed 2.17.1. Still, I have the same problem.

Share this post


Link to post

i'm on Windows 8.1 x64 and have the same problem, i cant even really start eddie to connect to a server. :/
 
seems to be a curl/ipv6/.Net problem?
 
 
event viewer says:

Faulting application name: Eddie-UI.exe, version: 2.16.0.0, time stamp: 0x5ba6502a
Faulting module name: KERNELBASE.dll, version: 6.3.9600.18938, time stamp: 0x5a7ddf0a
Exception code: 0xe0434352
Fault offset: 0x0000000000008eac
Faulting process id: 0xc20
Faulting application start time: 0x01d4530e1a889ab9
Faulting application path: C:\Program Files\AirVPN\Eddie-UI.exe
Faulting module path: C:\Windows\system32\KERNELBASE.dll
Report Id: 595a6e51-bf01-11e8-82b6-00e04c5125c8
Faulting package full name:
Faulting package-relative application ID:

 

and:

Application: Eddie-UI.exe
Framework Version: v4.0.30319
Description: The process was terminated due to an unhandled exception.
Exception Info: System.Exception
at Eddie.Core.Tools.Curl.Fetch(Eddie.Core.HttpRequest)
at Eddie.Core.Jobs.Updater.OnRun()
at Eddie.Core.Job.Run()
at System.Threading.ExecutionContext.RunInternal(System.Threading.ExecutionContext, System.Threading.ContextCallback, System.Object, Boolean)
at System.Threading.ExecutionContext.Run(System.Threading.ExecutionContext, System.Threading.ContextCallback, System.Object, Boolean)
at System.Threading.ExecutionContext.Run(System.Threading.ExecutionContext, System.Threading.ContextCallback, System.Object)
at System.Threading.ThreadHelper.ThreadStart()


“We rip out so much of ourselves to be cured of things faster than we should that we go bankrupt by the age of thirty and have less to offer each time we start with someone new. But to feel nothing so as not to feel anything—what a waste!”

Share this post


Link to post

Linux Mint 17.3 LTS (14.04 LTS), installed the latest 2.17.1 beta eddie-ui over v2.16.3 and upon restart saw notification about "removing network lock" before applying it again, then the new v2.17.1 would grind for a good while (couldn't switch to Servers tab) before crashing and apparently taking DNS down with the ship.

 

COMMAND=/usr/bin/notify-send --urgency=low --expire-time=2000 --icon=dialog-information Eddie Unexpected error. Please contact our support staff. - curl: (6) Could not resolve host: eddie.website -   at Eddie.Core.Tools.Curl.Fetch (Eddie.Core.HttpRequest request) [0x00000] in <filename unknown>:0 #012  at Eddie.Core.Engine.FetchUrl (Eddie.Core.HttpRequest request) [0x00000] in <filename unknown>:0 #012  at Eddie.Core.Jobs.Updater.OnRun () [0x00000] in <filename unknown>:0 #012  at Eddie.Core.Job.Run () [0x00000] in <filename unknown>:0 #012  at System.Threading.Thread.StartInternal () [0x00000] in <filename unknown>:0
 

 

After rebooting naked connections worked so I relaunched eddie 2.17.1 but the same issue happened again.

 

For some reason the .deb of previous version 2.16.3 wasn't in /var/cache/apt/archives so I ended up redownloading it, uninstalling the latest beta (wouldn't allow downgrades) and reinstalling the v2.16.3.

 

I would suggest pulling the latest version from the channel while you figure out the root of the problem. The changelog looks very appealing.

Share this post


Link to post

Similar experience on Fedora 28. Here's the relevant part of the log with debug enabled:

 

F 2018.09.23 09:52:32 - Unexpected error. Please contact our support staff. - curl: (28) Connection timed out after 20001 milliseconds - at Eddie.Core.Tools.Curl.Fetch (Eddie.Core.HttpRequest request) [0x007fe] in :0
F 2018.09.23 09:52:32 - at Eddie.Core.Engine.FetchUrl (Eddie.Core.HttpRequest request) [0x00010] in :0
F 2018.09.23 09:52:32 - at Eddie.Core.Jobs.Updater.OnRun () [0x000e9] in :0
F 2018.09.23 09:52:32 - at Eddie.Core.Job.Run () [0x0000d] in :0
F 2018.09.23 09:52:32 - at System.Threading.ThreadHelper.ThreadStart_Context (System.Object state) [0x00017] in <90910314e0f14f998fc0d35c0199e8a7>:0
F 2018.09.23 09:52:32 - at System.Threading.ExecutionContext.RunInternal (System.Threading.ExecutionContext executionContext, System.Threading.ContextCallback callback, System.Object state, System.Boolean preserveSyncCtx) [0x0008d] in <90910314e0f14f998fc0d35c0199e8a7>:0
F 2018.09.23 09:52:32 - at System.Threading.ExecutionContext.Run (System.Threading.ExecutionContext executionContext, System.Threading.ContextCallback callback, System.Object state, System.Boolean preserveSyncCtx) [0x00000] in <90910314e0f14f998fc0d35c0199e8a7>:0
F 2018.09.23 09:52:32 - at System.Threading.ExecutionContext.Run (System.Threading.ExecutionContext executionContext, System.Threading.ContextCallback callback, System.Object state) [0x00031] in <90910314e0f14f998fc0d35c0199e8a7>:0
F 2018.09.23 09:52:32 - at System.Threading.ThreadHelper.ThreadStart () [0x0000b] in <90910314e0f14f998fc0d35c0199e8a7>:0

 

I was only able to reproduce the error by enabling Activate Network Lock at startup in the settings. I thought a possible culprit could be the New Eddie version notification feature introduced in this release.

 

Going with that hunch, I tried a couple of things

 

Changing the Update channel selection to None from its default Stable (as aside, it should probably be changed to Beta for beta releases) didn't help. I was hoping for the update check and the call to curl to be bypassed altogether.

 

Enabling Connect at startup also didn't help. I was hoping it might in case the problem was the failure to include the update URL in the default.xml file and thus in the iptables rules created on startup when network lock is enabled.

 

That's about as far as I got. Still using the new beta, as I don't use auto network lock and the feature works fine when activated manually.

 

 

 

Share this post


Link to post

Same here... (Ubuntu 18.04)

 

Just quits itself after a couple of seconds...

 

2018.09.23 14:40:37 - OpenVPN Driver - Found, /dev/net/tun
. 2018.09.23 14:40:37 - OpenVPN - Version: 2.4.4 - OpenSSL 1.1.0g 2 Nov 2017, LZO 2.08 (/usr/sbin/openvpn)
. 2018.09.23 14:40:37 - SSH - Version: OpenSSH_7.6p1 Ubuntu-4, OpenSSL 1.0.2n 7 Dec 2017 (/usr/bin/ssh)
. 2018.09.23 14:40:37 - SSL - Version: stunnel 5.44 (/usr/bin/stunnel4)
. 2018.09.23 14:40:37 - curl - Version: 7.58.0 (/usr/bin/curl)
. 2018.09.23 14:40:37 - Certification Authorities: /usr/share/eddie-ui/cacert.pem
. 2018.09.23 14:40:37 - Recovery. Unexpected crash?
! 2018.09.23 14:40:37 - Deactivation of Network Lock
! 2018.09.23 14:40:37 - Activation of Network Lock - Linux iptables
. 2018.09.23 14:40:37 - Network lock not enabled on IPv6 layer. IPv6 seems disabled at system level.
I 2018.09.23 14:40:40 - Ready
. 2018.09.23 14:40:40 - Collect information about AirVPN completed
F 2018.09.23 14:41:00 - Unexpected error. Please contact our support staff. - curl: (28) Connection timed out after 20001 milliseconds - at Eddie.Core.Tools.Curl.Fetch (Eddie.Core.HttpRequest request) [0x007fe] in :0
F 2018.09.23 14:41:00 - at Eddie.Core.Engine.FetchUrl (Eddie.Core.HttpRequest request) [0x00010] in :0
F 2018.09.23 14:41:00 - at Eddie.Core.Jobs.Updater.OnRun () [0x000e9] in :0
F 2018.09.23 14:41:00 - at Eddie.Core.Job.Run () [0x0000d] in :0
F 2018.09.23 14:41:00 - at System.Threading.ThreadHelper.ThreadStart_Context (System.Object state) [0x00017] in <8f2c484307284b51944a1a13a14c0266>:0
F 2018.09.23 14:41:00 - at System.Threading.ExecutionContext.RunInternal (System.Threading.ExecutionContext executionContext, System.Threading.ContextCallback callback, System.Object state, System.Boolean preserveSyncCtx) [0x0008d] in <8f2c484307284b51944a1a13a14c0266>:0
F 2018.09.23 14:41:00 - at System.Threading.ExecutionContext.Run (System.Threading.ExecutionContext executionContext, System.Threading.ContextCallback callback, System.Object state, System.Boolean preserveSyncCtx) [0x00000] in <8f2c484307284b51944a1a13a14c0266>:0
F 2018.09.23 14:41:00 - at System.Threading.ExecutionContext.Run (System.Threading.ExecutionContext executionContext, System.Threading.ContextCallback callback, System.Object state) [0x00031] in <8f2c484307284b51944a1a13a14c0266>:0
F 2018.09.23 14:41:00 - at System.Threading.ThreadHelper.ThreadStart () [0x0000b] in <8f2c484307284b51944a1a13a14c0266>:0
[ERROR] FATAL UNHANDLED EXCEPTION: System.Exception: curl: (28) Connection timed out after 20001 milliseconds
at Eddie.Core.Tools.Curl.Fetch (Eddie.Core.HttpRequest request) [0x007fe] in :0
at Eddie.Core.Engine.FetchUrl (Eddie.Core.HttpRequest request) [0x00010] in :0
at Eddie.Core.Jobs.Updater.OnRun () [0x000e9] in :0
at Eddie.Core.Job.Run () [0x0000d] in :0
at System.Threading.ThreadHelper.ThreadStart_Context (System.Object state) [0x00017] in <8f2c484307284b51944a1a13a14c0266>:0
at System.Threading.ExecutionContext.RunInternal (System.Threading.ExecutionContext executionContext, System.Threading.ContextCallback callback, System.Object state, System.Boolean preserveSyncCtx) [0x0008d] in <8f2c484307284b51944a1a13a14c0266>:0
at System.Threading.ExecutionContext.Run (System.Threading.ExecutionContext executionContext, System.Threading.ContextCallback callback, System.Object state, System.Boolean preserveSyncCtx) [0x00000] in <8f2c484307284b51944a1a13a14c0266>:0
at System.Threading.ExecutionContext.Run (System.Threading.ExecutionContext executionContext, System.Threading.ContextCallback callback, System.Object state) [0x00031] in <8f2c484307284b51944a1a13a14c0266>:0
at System.Threading.ThreadHelper.ThreadStart () [0x0000b] in <8f2c484307284b51944a1a13a14c0266>:0
 
EDIT: "spe" seems to be right. After unticking "Activate Network Lock On Startup" no more crashes so far. Nevertheless, i would consider the current version as unstable.
 
Kind regards
 
Fox

Share this post


Link to post
Guest

An update (2.17.2) that address the issue is available now.

 

Might want to update the changelog page. 

Share this post


Link to post

Everything smooth here latest beta version and Debian. There where in terminal unseen message like this

"Collect information about AirVPN completed"...

 

and this i have been stable to beta always =>

"(eddie-tray:31260): GLib-GObject-WARNING **: /build/glib2.0-B1uXKV/glib2.0-2.50.3/./gobject/gsignal.c:2523: signal 'child-added' is invalid for instance '0x2153750' of type 'GtkMenu'"...

 

But all works well, OS DE is Cinnamon.


"You don't have to be a genius to sound like one." - BDS

Share this post


Link to post

Nice!  Updated Eddie (2.17.2) fixes the issue for me as well...MacOS 10.13.6...Network Lock enabled at startup.

 

Many thanks for the great and speedy work, as always, Staff! 

Share this post


Link to post
Guest

Minor issue on arch linux (Plasma desktop). Minimizing to tray no longer works properly: it minimize to tray but taskbar entry is not disappearing and always visible. See screenshot:

 

5PJLhGa.png

Share this post


Link to post

I tried this on Windows 7. There were problems. Browsers had difficulties with finding web sites on internet. I was able to browse some sites, but too many of them gave errors. Could not find IP or DNS of the site....

 

I tried different web browsers and problem was the same with all of them. I cleared all caches and did reboot my computer, but that didn't help.

 

I went back to version 2.16.1 and browsers are able to find those web sites again.

Share this post


Link to post

i had what you can see on the picture after turning on my PC this morning, and even clicking on "Refresh connections list, ping results, discovered informations" did nothing

i then disabled "Network Lock" and everything was working as it should work.

so i enabled "Network Lock" again and clicked on "Refresh connections list, ping results, discovered informations", and again nothing worked :/

 

it seems "curl" or something else can not connect through the activated "Network Lock".

i never had that problem before.

eddie version was/is [2.17.2], and is running on Windows 8.1 x64.

 

oh and before anyone ask if i was connected to any server, "no" i was not connected at all, and my internet connection was working.

 

 

forget all that, i seems it was an option in Eddie, under "Network Lock", and it was called "Allow ping"  :/

it does not matter how often i re-install Eddie, it's always off by default.

it should be on by default.

 

 

just my two cents


“We rip out so much of ourselves to be cured of things faster than we should that we go bankrupt by the age of thirty and have less to offer each time we start with someone new. But to feel nothing so as not to feel anything—what a waste!”

Share this post


Link to post

Eddie 2.17.2 is leaking the DNS, even if I use these directives. I use Mint 19. In the earlier Eddie version (2.16) leak was prevented with those, but not anymore!

 

dhcp-option DOMAIN-ROUTE .
up /etc/openvpn/update-systemd-resolved
down /etc/openvpn/update-systemd-resolved
script-security 2
down-pre
 

 

An urgent fix is needed. I have read that Gnu/Linux doesn't leak DNS itself, and the problem lies usually in the resolv.conf. However, the directives above have taken care of it previously.

Share this post


Link to post

@rohko

 

Correct, DNS leaks do not exist in Linux. This is a different issue and must be investigated anyway, but it's not related to DNS leaks.

 

How does Eddie handle DNS (check "Preferences" > "DNS")?

 

Since you rely on that script to handle the DNS push, Eddie must not interfere and you can focus on why your script does not work. Make sure to set "DNS Switch Mode" to "None" in "Preferences" > "DNS".

 

Alternatively, disable your script, enable DNS push handling by Eddie itself (try with "DNS switch mode" set to "Automatic") and check whether the problem persists or not. If it does send a full system report generated by Eddie and taken just after the problem has occurred, please ("Logs" > LIIFE BELT icon > "Copy All" icon > paste into your message).

 

Kind regards

Share this post


Link to post

Thanks for a quick response.

Here's quite technical report what's happening now. I'm sorry if it looks unclear.

 

The first test.

I set DNS switch mode in the Preferences as Disabled. Then Eddie used these directives:

client
dev tun
auth-nocache
resolv-retry infinite
nobind
persist-key
persist-tun
verb 3
connect-retry-max 1
ping 10
ping-exit 32
explicit-exit-notify 5
dhcp-option DOMAIN-ROUTE .
up /etc/openvpn/update-systemd-resolved
down /etc/openvpn/update-systemd-resolved
script-security 2
down-pre

 

The scipt update-systemd-resolved is the following from github:

#!/usr/bin/env bash
#
# OpenVPN helper to add DHCP information into systemd-resolved via DBus.
# Copyright (C) 2016, Jonathan Wright <jon@than.io>
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program.  If not, see <http://www.gnu.org/licenses/>.

# This script will parse DHCP options set via OpenVPN (dhcp-option) to update
# systemd-resolved directly via DBus, instead of updating /etc/resolv.conf. To
# install, set as the 'up' and 'down' script in your OpenVPN configuration file
# or via the command-line arguments, alongside setting the 'down-pre' option to
# run the 'down' script before the device is closed. For example:
#   up /etc/openvpn/scripts/update-systemd-resolved
#   down /etc/openvpn/scripts/update-systemd-resolved
#   down-pre

# Define what needs to be called via DBus
DBUS_DEST="org.freedesktop.resolve1"
DBUS_NODE="/org/freedesktop/resolve1"

SCRIPT_NAME="${BASH_SOURCE[0]##*/}"

log() {
  logger -s -t "$SCRIPT_NAME" "$@"
}

for level in emerg err warning info debug; do
  printf -v functext -- '%s() { log -p user.%s -- "$@" ; }' "$level" "$level"
  eval "$functext"
done

usage() {
  err "${1:?${1}. }. Usage: ${SCRIPT_NAME} up|down device_name."
}

busctl_call() {
  # Preserve busctl's exit status
  busctl call "$DBUS_DEST" "$DBUS_NODE" "${DBUS_DEST}.Manager" "$@" || {
    local -i status=$?
    emerg "'busctl' exited with status $status"
    return $status
  }
}

get_link_info() {
  dev="$1"
  shift

  link=''
  link="$(ip link show dev "$dev")" || return $?

  echo "$dev" "${link%%:*}"
}

dhcp_settings() {
  for foreign_option in "${!foreign_option_@}"; do
    foreign_option_value="${!foreign_option}"

    [[ "$foreign_option_value" == *dhcp-option* ]] \
      && echo "${foreign_option_value#dhcp-option }"
  done
}

up() {
  local link="$1"
  shift
  local if_index="$1"
  shift

  info "Link '$link' coming up"

  # Preset values for processing -- will be altered in the various process_*
  # functions.
  local -a dns_servers=() dns_domain=() dns_search=() dns_routed=()
  local -i dns_server_count=0 dns_domain_count=0 dns_search_count=0 dns_routed_count=0
  local dns_sec=""

  while read -r setting; do
    setting_type="${setting%% *}"
    setting_value="${setting#* }"

    process_setting_function="${setting_type,,}"
    process_setting_function="process_${process_setting_function//-/_}"

    if declare -f "$process_setting_function" &>/dev/null; then
      "$process_setting_function" "$setting_value" || return $?
    else
      warning "Not a recognized DHCP setting: '${setting}'"
    fi
  done < <(dhcp_settings)

  if [[ "${#dns_servers[*]}" -gt 0 ]]; then
    busctl_params=("$if_index" "$dns_server_count" "${dns_servers[@]}")
    info "SetLinkDNS(${busctl_params[*]})"
    busctl_call SetLinkDNS 'ia(iay)' "${busctl_params[@]}" || return $?
  fi

  if [[ "${#dns_domain[*]}" -gt 0 \
     || "${#dns_search[*]}" -gt 0 \
     || "${#dns_routed[*]}" -gt 0 ]]; then
    dns_count=$((dns_domain_count+dns_search_count+dns_routed_count))
    busctl_params=("$if_index" "$dns_count")
    if [[ "${#dns_domain[*]}" -gt 0 ]]; then
      busctl_params+=("${dns_domain[@]}")
    fi
    if [[ "${#dns_search[*]}" -gt 0 ]]; then
      busctl_params+=("${dns_search[@]}")
    fi
    if [[ "${#dns_routed[*]}" -gt 0 ]]; then
      busctl_params+=("${dns_routed[@]}")
    fi
    info "SetLinkDomains(${busctl_params[*]})"
    busctl_call SetLinkDomains 'ia(sb)' "${busctl_params[@]}" || return $?
  fi

  if [[ -n "${dns_sec}" ]]; then
    if [[ "${dns_sec}" == "default" ]]; then
      # We need to provide an empty string to use the default settings
      info "SetLinkDNSSEC($if_index '')"
      busctl_call SetLinkDNSSEC 'is' "$if_index" "" || return $?
    else
      info "SetLinkDNSSEC($if_index ${dns_sec})"
      busctl_call SetLinkDNSSEC 'is' "$if_index" "${dns_sec}" || return $?
    fi
  fi
}

down() {
  local link="$1"
  shift
  local if_index="$1"
  shift

  info "Link '$link' going down"
  if [[ "$(whoami 2>/dev/null)" != "root" ]]; then
    # Cleanly handle the priviledge dropped case by not calling RevertLink
    info "Priviledges dropped in the client: Cannot call RevertLink."
  else
    busctl_call RevertLink i "$if_index"
  fi
}

process_dns() {
  address="$1"
  shift

  if looks_like_ipv6 "$address"; then
    process_dns_ipv6 "$address" || return $?
  elif looks_like_ipv4 "$address"; then
    process_dns_ipv4 "$address" || return $?
  else
    err "Not a valid IPv6 or IPv4 address: '$address'"
    return 1
  fi
}

process_dns6() {
  address="$1"
  shift

  if looks_like_ipv6 "$address"; then
    process_dns_ipv6 "$address" || return $?
  elif looks_like_ipv4 "$address"; then
    process_dns_ipv4 "$address" || return $?
  else
    err "Not a valid IPv6 or IPv4 address: '$address'"
    return 1
  fi
}

looks_like_ipv4() {
  [[ -n "$1" ]] && {
    local dots="${1//[^.]}"
    (( ${#dots} == 3 ))
  }
}

looks_like_ipv6() {
  [[ -n "$1" ]] && {
    local colons="${1//[^:]}"
    (( ${#colons} >= 2 ))
  }
}

process_dns_ipv4() {
  local address="$1"
  shift

  info "Adding IPv4 DNS Server ${address}"
  (( dns_server_count += 1 ))
  dns_servers+=(2 4 ${address//./ })
}

# Enforces RFC 5952:
#   1. Don't shorten a single 0 field to '::'
#   2. Only longest run of zeros should be compressed
#   3. If there are multiple longest runs, the leftmost should be compressed
#   4. Address must be maximally compressed, so no all-zero runs next to '::'
#
# ...
#
# Thank goodness we don't have to handle port numbers, though 
parse_ipv6() {
  local raw_address="$1"

  log_invalid_ipv6() {
    local message="'$raw_address' is not a valid IPv6 address"
    emerg "${message}: $*"
  }

  trap -- 'unset -f log_invalid_ipv6' RETURN

  if [[ "$raw_address" == *::*::* ]]; then
    log_invalid_ipv6 "address cannot contain more than one '::'"
    return 1
  elif [[ "$raw_address" =~ :0+:: ]] || [[ "$raw_address" =~ ::0+: ]]; then
    log_invalid_ipv6 "address contains a 0-group adjacent to '::' and is not maximally shortened"
    return 1
  fi

  local -i length=8
  local -a raw_segments=()

  IFS=$':' read -r -a raw_segments <<<"$raw_address"

  local -i raw_length="${#raw_segments[@]}"

  if (( raw_length > length )); then
    log_invalid_ipv6 "expected ${length} segments, got ${raw_length}"
    return 1
  fi

  # Store zero-runs keyed to their sizes, storing all non-zero segments prefixed
  # with a token marking them as such.
  local nonzero_prefix=$'!'
  local -i zero_run_i=0 compressed_i=0
  local -a tokenized_segments=()
  local decimal_segment='' next_decimal_segment=''

  for (( i = 0 ; i < raw_length ; i++ )); do
    raw_segment="${raw_segments[i]}"

    printf -v decimal_segment -- '%d' "0x${raw_segment:-0}"

    # We're in the compressed group.  The length of this run should be
    # enough to bring the total number of segments to 8.
    if [[ -z "$raw_segment" ]]; then
      (( compressed_i = zero_run_i ))

      # `+ 1' because the length of the current segment is counted in
      # `raw_length'.
      (( tokenized_segments[zero_run_i] = ((length - raw_length) + 1) ))

      # If we have an address like `::1', skip processing the next group to
      # avoid double-counting the zero-run, and increment the number of
      # 0-groups to add since the second empty group is counted in
      # `raw_length'.
      if [[ -z "${raw_segments[i + 1]}" ]]; then
        (( i++ ))
        (( tokenized_segments[zero_run_i]++ ))
      fi

      (( zero_run_i++ ))
    elif (( decimal_segment == 0 )); then
      (( tokenized_segments[zero_run_i]++ ))

      # The run is over if the next segment is not 0, so increment the
      # tracking index.
      printf -v next_decimal_segment -- '%d' "0x${raw_segments[i + 1]}"

      (( next_decimal_segment != 0 )) && (( zero_run_i++ ))
    else
      # Prefix the raw segment with `nonzero_prefix' to mark this as a
      # non-zero field.
      tokenized_segments[zero_run_i]="${nonzero_prefix}${decimal_segment}"
      (( zero_run_i++ ))
    fi
  done

  if [[ "$raw_address" == *::* ]]; then
    if (( ${#tokenized_segments[*]} == length )); then
      log_invalid_ipv6 "single '0' fields should not be compressed"
      return 1
    else
      local -i largest_run_i=0 largest_run=0

      for (( i = 0 ; i < ${#tokenized_segments[@]}; i ++ )); do
        # Skip groups that aren't zero-runs
        [[ "${tokenized_segments[i]:0:1}" == "$nonzero_prefix" ]] && continue

        if (( tokenized_segments[i] > largest_run )); then
          (( largest_run_i = i ))
          largest_run="${tokenized_segments[i]}"
        fi
      done

      local -i compressed_run="${tokenized_segments[compressed_i]}"

      if (( largest_run > compressed_run )); then
        log_invalid_ipv6 "the compressed run of all-zero fields is smaller than the largest such run"
        return 1
      elif (( largest_run == compressed_run )) && (( largest_run_i < compressed_i )); then
        log_invalid_ipv6 "only the leftmost largest run of all-zero fields should be compressed"
        return 1
      fi
    fi
  fi

  for segment in "${tokenized_segments[@]}"; do
    if [[ "${segment:0:1}" == "$nonzero_prefix" ]]; then
      printf -- '%04x\n' "${segment#${nonzero_prefix}}"
    else
      for (( n = 0 ; n < segment ; n++ )); do
        echo 0000
      done
    fi
  done
}

process_dns_ipv6() {
  local address="$1"
  shift

  info "Adding IPv6 DNS Server ${address}"

  local -a segments=()
  segments=($(parse_ipv6 "$address")) || return $?

  # Add AF_INET6 and byte count
  dns_servers+=(10 16)
  for segment in "${segments[@]}"; do
    dns_servers+=("$((16#${segment:0:2}))" "$((16#${segment:2:2}))")
  done

  (( dns_server_count += 1 ))
}

process_domain() {
  local domain="$1"
  shift

  info "Setting DNS Domain ${domain}"
  (( dns_domain_count = 1 ))
  dns_domain=("${domain}" false)
}

process_adapter_domain_suffix() {
  # This enables support for ADAPTER_DOMAIN_SUFFIX which is a Microsoft standard
  # which works in the same way as DOMAIN to set the primary search domain on
  # this specific link.
  process_domain "$@"
}

process_domain_search() {
  local domain="$1"
  shift

  info "Adding DNS Search Domain ${domain}"
  (( dns_search_count += 1 ))
  dns_search+=("${domain}" false)
}

process_domain_route() {
  local domain="$1"
  shift

  info "Adding DNS Routed Domain ${domain}"
  (( dns_routed_count += 1 ))
  dns_routed+=("${domain}" true)
}

process_dnssec() {
  local option="$1" setting=""
  shift

  case "${option,,}" in
    yes|true)
      setting="yes" ;;
    no|false)
      setting="no" ;;
    default)
      setting="default" ;;
    allow-downgrade)
      setting="allow-downgrade" ;;
    *)
      local message="'$option' is not a valid DNSSEC option"
      emerg "${message}"
      return 1 ;;
  esac

  info "Setting DNSSEC to ${setting}"
  dns_sec="${setting}"
}

main() {
  local script_type="$1"
  shift
  local dev="$1"
  shift

  if [[ -z "$script_type" ]]; then
    usage 'No script type specified'
    return 1
  elif [[ -z "$dev" ]]; then
    usage 'No device name specified'
    return 1
  elif ! declare -f "${script_type}" &>/dev/null; then
    usage "Invalid script type: '${script_type}'"
    return 1
  else
    if ! read -r link if_index _ < <(get_link_info "$dev"); then
      usage "Invalid device name: '$dev'"
      return 1
    fi

    "$script_type" "$link" "$if_index" "$@"
  fi
}

if [[ "${BASH_SOURCE[0]}" == "$0" ]] || [[ "$AUTOMATED_TESTING" == 1 ]]; then
  set -o nounset

  main "${script_type:-}" "${dev:-}" "$@"
fi


 

As a result of the above procedure, ipleak.net shows that I'm leaking my mobile broadband DNS (1.1.1.1) Cloudfare servers and I'm not using the AirVPN DNS at all. In the /etc/resolv.conf there is

 

cat /etc/resolv.conf 
# Dynamic resolv.conf(5) file for glibc resolver(3) generated by resolvconf(8)
#     DO NOT EDIT THIS FILE BY HAND -- YOUR CHANGES WILL BE OVERWRITTEN
# 127.0.0.53 is the systemd-resolved stub resolver.
# run "systemd-resolve --status" to see details about the actual nameservers.

nameserver 127.0.0.53

 

And what really looks to cause the leak is the systemd-resolve. There is no AirVPN entry or any other entries at the Global section. My normal DNS IP is at the ppp0 section, as I use an USB Huawei mobile broadband stick.

sudo systemd-resolve --status
.
.
.
Link 87 (tun0)
      Current Scopes: none
       LLMNR setting: yes
MulticastDNS setting: no
      DNSSEC setting: no
    DNSSEC supported: no
Link 69 (ppp0)
      Current Scopes: DNS
       LLMNR setting: yes
MulticastDNS setting: no
      DNSSEC setting: no
    DNSSEC supported: no
         DNS Servers: 1.1.1.1

 

 

The second test.

 

DNS switch mode set to Automatic.

Eddie directives:

client
dev tun
auth-nocache
resolv-retry infinite
nobind
persist-key
persist-tun
verb 3
connect-retry-max 1
ping 10
ping-exit 32
explicit-exit-notify 5

 

/etc/resolv.conf:

cat /etc/resolv.conf 
# Generated by Eddie v2.17.2 | https://eddie.website

nameserver 10.13.144.1
nameserver fde6:7a:7d20:990::1

systemd-resolved:

sudo systemd-resolve --status

Global
         DNS Servers: 10.13.144.1
                      fde6:7a:7d20:990::1

.
.
.
Link 86 (tun0)
      Current Scopes: none
       LLMNR setting: yes
MulticastDNS setting: no
      DNSSEC setting: no
    DNSSEC supported: no

Link 69 (ppp0)
      Current Scopes: DNS
       LLMNR setting: yes
MulticastDNS setting: no
      DNSSEC setting: no
    DNSSEC supported: no
         DNS Servers: 1.1.1.1

So it seems that my normal DNS IP 1.1.1.1 is not removed the configuration. Ipleak.net shows that now I use the AirVPN DNS server, but also a bunch of 1.1.1.1 Cloudfare servers. At least it's a bit better than the first test.

 

Update-systemd-resolved script

 

It's also odd that Eddie 2.17.2 doesn't seem to trigger the update-systemd-resolved script. This is the log at the first test:

I 2018.09.26 17.05.25 - Checking authorization ...
! 2018.09.26 17.05.26 - Connecting to Cepheus (Norway, Oslo)
. 2018.09.26 17.05.26 - OpenVPN > OpenVPN 2.4.6 x86_64-pc-linux-gnu [SSL (OpenSSL)] [LZO] [LZ4] [EPOLL] [PKCS11] [MH/PKTINFO] [AEAD] built on Apr 24 2018
. 2018.09.26 17.05.26 - OpenVPN > library versions: OpenSSL 1.0.2n  7 Dec 2017, LZO 2.08
. 2018.09.26 17.05.26 - Connection to OpenVPN Management Interface
. 2018.09.26 17.05.26 - OpenVPN > MANAGEMENT: TCP Socket listening on [AF_INET]127.0.0.1:3100
. 2018.09.26 17.05.26 - OpenVPN > Outgoing Control Channel Authentication: Using 160 bit message hash 'SHA1' for HMAC authentication
. 2018.09.26 17.05.26 - OpenVPN > Incoming Control Channel Authentication: Using 160 bit message hash 'SHA1' for HMAC authentication
. 2018.09.26 17.05.26 - OpenVPN > TCP/UDP: Preserving recently used remote address: [AF_INET]82.102.27.170:443
. 2018.09.26 17.05.26 - OpenVPN > Socket Buffers: R=[212992->212992] S=[212992->212992]
. 2018.09.26 17.05.26 - OpenVPN > UDP link local: (not bound)
. 2018.09.26 17.05.26 - OpenVPN > UDP link remote: [AF_INET]82.102.27.170:443
. 2018.09.26 17.05.26 - OpenVPN > TLS: Initial packet from [AF_INET]82.102.27.170:443, sid=75532ad7 97e1cb91
. 2018.09.26 17.05.26 - OpenVPN > MANAGEMENT: Client connected from [AF_INET]127.0.0.1:3100
. 2018.09.26 17.05.26 - OpenVPN > VERIFY OK: depth=1, C=IT, ST=IT, L=Perugia, O=airvpn.org, CN=airvpn.org CA, emailAddress=info@airvpn.org
. 2018.09.26 17.05.26 - OpenVPN > VERIFY KU OK
. 2018.09.26 17.05.26 - OpenVPN > Validating certificate extended key usage
. 2018.09.26 17.05.26 - OpenVPN > ++ Certificate has EKU (str) TLS Web Server Authentication, expects TLS Web Server Authentication
. 2018.09.26 17.05.26 - OpenVPN > VERIFY EKU OK
. 2018.09.26 17.05.26 - OpenVPN > VERIFY OK: depth=0, C=IT, ST=IT, L=Perugia, O=airvpn.org, CN=Cepheus, emailAddress=info@airvpn.org
. 2018.09.26 17.05.26 - OpenVPN > Control Channel: TLSv1.2, cipher TLSv1/SSLv3 DHE-RSA-AES256-GCM-SHA384, 4096 bit RSA
. 2018.09.26 17.05.26 - OpenVPN > [Cepheus] Peer Connection Initiated with [AF_INET]82.102.27.170:443
. 2018.09.26 17.05.27 - OpenVPN > SENT CONTROL [Cepheus]: 'PUSH_REQUEST' (status=1)
. 2018.09.26 17.05.27 - OpenVPN > PUSH: Received control message: 'PUSH_REPLY,comp-lzo no,redirect-gateway ipv6 def1 bypass-dhcp,dhcp-option DNS 10.13.144.1,dhcp-option DNS6 fde6:7a:7d20:990::1,tun-ipv6,route-gateway 10.13.144.1,topology subnet,ping 10,ping-restart 60,ifconfig-ipv6 fde6:7a:7d20:990::101d/64 fde6:7a:7d20:990::1,ifconfig 10.13.144.31 255.255.255.0,peer-id 2,cipher AES-256-GCM'
. 2018.09.26 17.05.27 - OpenVPN > Pushed option removed by filter: 'redirect-gateway ipv6 def1 bypass-dhcp'
. 2018.09.26 17.05.27 - OpenVPN > OPTIONS IMPORT: timers and/or timeouts modified
. 2018.09.26 17.05.27 - OpenVPN > OPTIONS IMPORT: compression parms modified
. 2018.09.26 17.05.27 - OpenVPN > OPTIONS IMPORT: --ifconfig/up options modified
. 2018.09.26 17.05.27 - OpenVPN > OPTIONS IMPORT: route-related options modified
. 2018.09.26 17.05.27 - OpenVPN > OPTIONS IMPORT: --ip-win32 and/or --dhcp-option options modified
. 2018.09.26 17.05.27 - OpenVPN > OPTIONS IMPORT: peer-id set
. 2018.09.26 17.05.27 - OpenVPN > OPTIONS IMPORT: adjusting link_mtu to 1625
. 2018.09.26 17.05.27 - OpenVPN > OPTIONS IMPORT: data channel crypto options modified
. 2018.09.26 17.05.27 - OpenVPN > Data Channel: using negotiated cipher 'AES-256-GCM'
. 2018.09.26 17.05.27 - OpenVPN > Outgoing Data Channel: Cipher 'AES-256-GCM' initialized with 256 bit key
. 2018.09.26 17.05.27 - OpenVPN > Incoming Data Channel: Cipher 'AES-256-GCM' initialized with 256 bit key
. 2018.09.26 17.05.27 - OpenVPN > ROUTE_GATEWAY ON_LINK IFACE=ppp0 HWADDR=00:00:00:00:00:00
. 2018.09.26 17.05.27 - OpenVPN > GDG6: remote_host_ipv6=n/a
. 2018.09.26 17.05.27 - OpenVPN > ROUTE6: default_gateway=UNDEF
. 2018.09.26 17.05.27 - OpenVPN > TUN/TAP device tun0 opened
. 2018.09.26 17.05.27 - OpenVPN > TUN/TAP TX queue length set to 100
. 2018.09.26 17.05.27 - OpenVPN > do_ifconfig, tt->did_ifconfig_ipv6_setup=1
. 2018.09.26 17.05.27 - OpenVPN > /sbin/ip link set dev tun0 up mtu 1500
. 2018.09.26 17.05.27 - OpenVPN > /sbin/ip addr add dev tun0 10.13.144.31/24 broadcast 10.13.144.255
. 2018.09.26 17.05.27 - OpenVPN > /sbin/ip -6 addr add fde6:7a:7d20:990::101d/64 dev tun0
. 2018.09.26 17.05.32 - OpenVPN > /sbin/ip route add 82.102.27.170/32 dev ppp0
. 2018.09.26 17.05.32 - OpenVPN > /sbin/ip route add 0.0.0.0/1 via 10.13.144.1
. 2018.09.26 17.05.32 - OpenVPN > /sbin/ip route add 128.0.0.0/1 via 10.13.144.1
. 2018.09.26 17.05.32 - OpenVPN > add_route_ipv6(::/3 -> fde6:7a:7d20:990::1 metric -1) dev tun0
. 2018.09.26 17.05.32 - OpenVPN > /sbin/ip -6 route add ::/3 dev tun0
. 2018.09.26 17.05.32 - OpenVPN > add_route_ipv6(2000::/4 -> fde6:7a:7d20:990::1 metric -1) dev tun0
. 2018.09.26 17.05.32 - OpenVPN > /sbin/ip -6 route add 2000::/4 dev tun0
. 2018.09.26 17.05.32 - OpenVPN > add_route_ipv6(3000::/4 -> fde6:7a:7d20:990::1 metric -1) dev tun0
. 2018.09.26 17.05.32 - OpenVPN > /sbin/ip -6 route add 3000::/4 dev tun0
. 2018.09.26 17.05.32 - OpenVPN > add_route_ipv6(fc00::/7 -> fde6:7a:7d20:990::1 metric -1) dev tun0
. 2018.09.26 17.05.32 - OpenVPN > /sbin/ip -6 route add fc00::/7 dev tun0
. 2018.09.26 17.05.32 - Shell(52) of '/sbin/ip', 7 args: 'route';'add';'82.102.27.171';'via';'10.13.144.1';'dev';'tun0';
. 2018.09.26 17.05.32 - Shell(52) done in 8 ms, exit: 0
. 2018.09.26 17.05.32 - Routes, added a new route, 82.102.27.171 for gateway 10.13.144.1
. 2018.09.26 17.05.32 - Shell(53) of '/sbin/ip', 8 args: '-6';'route';'add';'2001:ac8:38:22:7d4c:b9b3:86a8:fb0d';'via';'fde6:7a:7d20:990::1';'dev';'tun0';
. 2018.09.26 17.05.33 - Shell(53) done in 9 ms, exit: 0
. 2018.09.26 17.05.33 - Routes, added a new route, 2001:ac8:38:22:7d4c:b9b3:86a8:fb0d for gateway fde6:7a:7d20:990::1
. 2018.09.26 17.05.33 - Flushing DNS
I 2018.09.26 17.05.33 - Checking route IPv4
I 2018.09.26 17.05.33 - Checking route IPv6
! 2018.09.26 17.05.33 - Connected.
. 2018.09.26 17.05.33 - OpenVPN > Initialization Sequence Completed

 

If the script is triggered, there should be a log entry which looks like

.
.
Wed Sep 26 17:11:23 2018 /sbin/ip link set dev tun0 up mtu 1500
Wed Sep 26 17:11:23 2018 /sbin/ip addr add dev tun0 10.23.160.225/24 broadcast 10.23.160.255
Wed Sep 26 17:11:23 2018 /sbin/ip -6 addr add fde6:7a:7d20:13a0::10df/64 dev tun0
Wed Sep 26 17:11:23 2018 /etc/openvpn/update-systemd-resolved tun0 1500 1553 10.23.160.225 255.255.255.0 init
Wed Sep 26 17:11:23 2018 /etc/openvpn/update-systemd-resolved tun0 1500 1553 10.23.160.225 255.255.255.0 init
<14>Sep 26 17:11:23 update-systemd-resolved: Link 'tun0' coming up
<14>Sep 26 17:11:23 update-systemd-resolved: Adding DNS Routed Domain .
<14>Sep 26 17:11:23 update-systemd-resolved: Adding IPv4 DNS Server 10.23.160.1
<14>Sep 26 17:11:23 update-systemd-resolved: Adding IPv6 DNS Server fde6:7a:7d20:13a0::1
<14>Sep 26 17:11:23 update-systemd-resolved: SetLinkDNS(84 2 2 4 10 23 160 1 10 16 253 230 0 122 125 32 19 160 0 0 0 0 0 0 0 1)
<14>Sep 26 17:11:23 update-systemd-resolved: SetLinkDomains(84 1 . true)
Wed Sep 26 17:11:28 2018 /sbin/ip route add 128.127.105.183/32 dev ppp0
Wed Sep 26 17:11:28 2018 /sbin/ip route add 0.0.0.0/1 via 10.23.160.1
Wed Sep 26 17:11:28 2018 /sbin/ip route add 128.0.0.0/1 via 10.23.160.1
Wed Sep 26 17:11:28 2018 add_route_ipv6(::/3 -> fde6:7a:7d20:13a0::1 metric -1) dev tun0
.
.
.

 

The above log entry is generated when I connect to AirVPN using openvpn from the command line directly without Eddie and use the same directives as in the first test. In Eddie 2.16, there were indeed log entries like that. But not in Eddie 2.17.2. And when the script is triggered, no DNS "leak" happens. So using either Eddie 2.16 or Openvpn from the commandline ipleak.net shows only AirVPN servers.

 

Edit: Using Openvpn from command line

 

When I connect to an AirVPN server directly from command line, here are my DNS settings, which are generated by Openvpn itself (update-systemd-resolved script is used):

cat /etc/resolv.conf
# Dynamic resolv.conf(5) file for glibc resolver(3) generated by resolvconf(8)
#     DO NOT EDIT THIS FILE BY HAND -- YOUR CHANGES WILL BE OVERWRITTEN
# 127.0.0.53 is the systemd-resolved stub resolver.
# run "systemd-resolve --status" to see details about the actual nameservers.

nameserver 127.0.0.53

 

sudo systemd-resolve --status
.
.
.
Link 85 (tun0)
      Current Scopes: DNS
       LLMNR setting: yes
MulticastDNS setting: no
      DNSSEC setting: no
    DNSSEC supported: no
         DNS Servers: 10.23.160.1
                      fde6:7a:7d20:13a0::1
          DNS Domain: ~.

Link 92 (ppp0)
      Current Scopes: DNS
       LLMNR setting: yes
MulticastDNS setting: no
      DNSSEC setting: no
    DNSSEC supported: no
         DNS Servers: 1.1.1.1
.
.
.

Edit2: In September 27th. Small, but very important addition to the vanilla Openvpn test. There is indeed a DNS entry of 1.1.1.1 in ppp0 section, but unfortunately I didn't notice it earlier (I had to scroll results of systemd-resolve --status by one more line). So the only difference between Eddie 2.17.2 DNS and vanilla OpenVPN DNS entries is the location of the VPN servers. In other words, if they are in the global or in the tun0 section.

Share this post


Link to post

@rohko
 
The first test
 
Here the scripts are not executed: Eddie 2.17.2, for intended security purposes, sets script-security to 1. Your custom directive:

script-security 2

ensures that your "up" and "down" scripts will be executed by OpenVPN but they are not. The fact that in Eddie 2.16.3 you did not experience this issue might be related to a wrong bypass of the aforementioned directive. We will investigate with Eddie devs.
 
 
The second test
 
Here things become interesting. As you can see in the status printout, systemd-resolve acknowledges the DNS set by Eddie in resolv.conf and considers them as global DNS, according to the usual global DNS paradigm, as you correctly point out.
 
However, you/we can see that 1.1.1.1 remains set for "ppp0" link.  This implies that systemd-resolved works with "per-interface domain names".. Additionally, the Current Scopes of ppp0 are "DNS", while in tun0 they are set to "None". This cause a priority of names resolution toward the DNS specified in the ppp0 link:
 
According to https://www.freedesktop.org/software/systemd/man/resolved.conf.html :
DNS requests are sent to one of the listed DNS servers in parallel to suitable per-link DNS servers acquired from systemd-networkd.service(8) or set at runtime by external applications. For compatibility reasons, if this setting is not specified, the DNS servers listed in /etc/resolv.conf are used instead, if that file exists and any servers are configured in it. This setting defaults to the empty list.
 
Again, you considerations are correct.
 
This is an important "paradigm shift" from the global DNS (uniquely specified in resolv.conf) which allows to mimic the dangerous Windows DNS implementation (where there is no global DNS at all): since systemd 229, systemd-networkd has exposed an API through DBus allowing management of DNS configuration on a per-link basis.
 
We will carefully consider this behavior with our techies. It appears (according to your last test, when OpenVPN is run directly) that the script handles correctly this case (no DNS for ppp0, from the output you pasted, and tun0 scope set to DNS) while Eddie doesn't.
 
Thank you for the invaluable report, it will be thoroughly investigated to improve Eddie. In the meantime, can you please check the "DNS=" option in your [Resolve] section of your resolved.conf file in each of the tests (before and after each test) you performed and report back? Can you also test with DNS= option empty (remember to restart the service after you have saved the file) and check whether the problem is resolved with Eddie (leaving to Eddie the resolv.conf handling, without scripts of course)? With DNS setting left to empty, systemd will use nameservers specified in resolv.conf
 
Kind regards

Share this post


Link to post

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.
Note: Your post will require moderator approval before it will be visible.

Guest
Reply to this topic...

×   Pasted as rich text.   Paste as plain text instead

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

Loading...
  • Security Check
    Play CAPTCHA Audio
    Refresh Image

×
×
  • Create New...