How to test if a gateway is online from a bash script? (Script Included)



  • Can someone please tell me how I can test if a VPN gateway is online and has connectivity from a bash script?

    I tried:

    [2.4.4-RELEASE][root@pfsense]/root: ping -c 3 -I ovpnc1 8.8.8.8
    ping: invalid multicast interface: `ovpnc1'
    

    which didn't work, so just as a test I also tried to ping on the main WAN gateway interface:

    [2.4.4-RELEASE][root@pfsense]/root: ping -c 3 -I em0 8.8.8.8
    ping: invalid multicast interface: `em0'
    

    and that didn't work either. (see relevent ifconfig output for those interfaces)

    What I'm missing? (My plan is to test $? from the ping command.)

    [2.4.4-RELEASE][root@pfsense]/root: ifconfig
    em0: flags=8943<UP,BROADCAST,RUNNING,PROMISC,SIMPLEX,MULTICAST> metric 0 mtu 1500
    options=219b<RXCSUM,TXCSUM,VLAN_MTU,VLAN_HWTAGGING,VLAN_HWCSUM,TSO4,WOL_MAGIC>
    	ether 00:28:1a:e0:10:04
    	hwaddr 00:28:1a:e0:10:04
    	inet6 fe80::228:1aff:fee0:1004%em0 prefixlen 64 scopeid 0x1 
    	inet 99.254.36.133 netmask 0xfffffe00 broadcast 255.255.255.255 
    	nd6 options=21<PERFORMNUD,AUTO_LINKLOCAL>
    	media: Ethernet autoselect (1000baseT <full-duplex>)
    	status: active
    
    ovpnc1: flags=8051<UP,POINTOPOINT,RUNNING,MULTICAST> metric 0 mtu 1500
    	options=80000<LINKSTATE>
    	inet6 fe80::228:1aff:fee0:1004%ovpnc1 prefixlen 64 scopeid 0x28 
    	inet 10.62.10.6 --> 10.62.10.5 netmask 0xffffffff 
    	nd6 options=21<PERFORMNUD,AUTO_LINKLOCAL>
    	groups: tun openvpn 
    	Opened by PID 96995
    
    


  • parse this

    root@pfsense.lan]/root: pfSsh.php playback gatewaystatus
    


  • Thanks @heper -- I guess that could work. BTW, are these calls documented somewhere?

    Is there any way I can directly communicate through the VPN interface?

    @heper said in How to test if a gateway is online from a bash script?:

    parse this

    root@pfsense.lan]/root: pfSsh.php playback gatewaystatus
    

  • LAYER 8 Rebel Alliance

    From the FreeBSD manpage:

         -I interface
    	     Source multicast packets with the given interface address.  This
    	     flag only applies if the ping destination is a multicast address.
    

    Try -S instead with your Interface address.

    -Rico



  • @Rico said in How to test if a gateway is online from a bash script?:

    From the FreeBSD manpage:

         -I interface
    	     Source multicast packets with the given interface address.  This
    	     flag only applies if the ping destination is a multicast address.
    

    Try -S instead with your Interface address.

    -Rico

    Thanks @Rico that worked.... only problem is that it turns out that ICMP is firewalled off on the VPN.

    So I tred to do something with curl, and I'm wondering why this doesn't work:

    ovpnc1: flags=8051<UP,POINTOPOINT,RUNNING,MULTICAST> metric 0 mtu 1500
    	options=80000<LINKSTATE>
    	inet6 fe80::228:1aff:fee0:1004%ovpnc1 prefixlen 64 scopeid 0x28 
    	inet 10.62.10.6 --> 10.62.10.5 netmask 0xffffffff 
    	nd6 options=21<PERFORMNUD,AUTO_LINKLOCAL>
    	groups: tun openvpn 
    	Opened by PID 96995
    
    
    curl -v -4 --interface 10.62.10.6 http://google.com
    * Expire in 0 ms for 6 (transfer 0x803a94000)
    * Expire in 1 ms for 1 (transfer 0x803a94000)
      [Similar lines removed]
    * Expire in 0 ms for 1 (transfer 0x803a94000)
    * Expire in 0 ms for 1 (transfer 0x803a94000)
    *   Trying 172.217.1.174...
    * TCP_NODELAY set
    * Name '10.62.10.6' family 2 resolved to '10.62.10.6' family 2
    * Local port: 0
    * Expire in 200 ms for 4 (transfer 0x803a94000)
    * connect to 172.217.1.174 port 80 failed: Operation timed out
    * Failed to connect to google.com port 80: Operation timed out
    * Closing connection 0
    curl: (7) Failed to connect to google.com port 80: Operation timed out
    
    
     curl -v -4 --interface 10.62.10.5 http://google.com
    * Expire in 0 ms for 6 (transfer 0x803a94000)
    * Expire in 1 ms for 1 (transfer 0x803a94000)
      [Similar lines removed]
    * Expire in 50 ms for 1 (transfer 0x803a94000)
    *   Trying 172.217.1.174...
    * TCP_NODELAY set
    * Name '10.62.10.5' family 2 resolved to '10.62.10.5' family 2
    * bind failed with errno 49: Can't assign requested address
    * Closing connection 0
    curl: (45) bind failed with errno 49: Can't assign requested address
    

    The curl statement does work when I don't specify an interface:

    curl -v -4  http://google.com
    * Expire in 0 ms for 6 (transfer 0x803a94000)
    * Expire in 1 ms for 1 (transfer 0x803a94000)
      [Similar lines removed]
    * Expire in 200 ms for 1 (transfer 0x803a94000)
    * Expire in 200 ms for 1 (transfer 0x803a94000)
    *   Trying 172.217.1.174...
    * TCP_NODELAY set
    * Expire in 200 ms for 4 (transfer 0x803a94000)
    * Connected to google.com (172.217.1.174) port 80 (#0)
    > GET / HTTP/1.1
    > Host: google.com
    > User-Agent: curl/7.64.0
    > Accept: */*
    > 
    < HTTP/1.1 301 Moved Permanently
    < Location: http://www.google.com/
    < Content-Type: text/html; charset=UTF-8
    < Date: Fri, 06 Mar 2020 07:39:36 GMT
    < Expires: Sun, 05 Apr 2020 07:39:36 GMT
    < Cache-Control: public, max-age=2592000
    < Server: gws
    < Content-Length: 219
    < X-XSS-Protection: 0
    < X-Frame-Options: SAMEORIGIN
    < 
    <HTML><HEAD><meta http-equiv="content-type" content="text/html;charset=utf-8">
    <TITLE>301 Moved</TITLE></HEAD><BODY>
    <H1>301 Moved</H1>
    The document has moved
    <A HREF="http://www.google.com/">here</A>.
    </BODY></HTML>
    * Connection #0 to host google.com left intact
    [2.4.4-RELEASE][root@guardian.pvt]/root: 
    

    Alternatively is there any other way I might route out the OpenVPN interface to test connectivity to a site that is very unlikely to be down, and hence a reliable way to determine if the interface is working.



  • @guardian

    Here's a script I wrote a few years ago. It's for bash on LInux, but it should work with FreeBSD.

    #! /bin/sh
    while [ 1 ]
    do
    ping <destination> -4 -c 1 || date >> ~/log;sleep 50
    done

    Replace <destination> with the gateway address and you will have a log file of when it failed. You can adjust the sleep time to taste.



  • @JKnott said in How to test if a gateway is online from a bash script?:

    @guardian

    Here's a script I wrote a few years ago. It's for bash on LInux, but it should work with FreeBSD.

    #! /bin/sh
    while [ 1 ]
    do
    ping <destination> -4 -c 1 || date >> ~/log;sleep 50
    done

    Replace <destination> with the gateway address and you will have a log file of when it failed. You can adjust the sleep time to taste.

    @JKnott unfortunately that won't work... a couple of problmes

    • FreeBSD doesn't have a -4 option (I wish FreeBSD would get their utilities on par with GNU linux)
    • The ping doesn't route through the OpenVPN interface. AFAICR connectivity can go down but the interface address doesn't disappear
    • ping -S does work, but on testing it, I found out that the VPN Tunnel firewall blocks ICMP, so I can't use ping at all.

    Since ping is blocked, I need to use something like curl (not attached to curl) that uses a common protocol to a site like google.

    I tried

    curl --interface ovpnc1 http://ifconfig.me
    and
    curl --interface 10.62.10.6 http://ifconfig.me
    

    and neither of them worked - the connection timed out., but once I removed --interface the command:

    curl  http://ifconfig.me
    

    correctly returns the IP address of the main WAN interface. How can I make curl use the VPN?

    Alternatively this dig command looks interesting as well, but I can't route it through the VPN.

    dig TXT +short o-o.myaddr.l.google.com @ns1.google.com
    

    Th above command correctly returns the main WAN IP address, but this command:

    dig -b10.62.10.5 TXT +short o-o.myaddr.l.google.com @ns1.google.com
    dig: isc_socket_bind: address not available
    

    fails as shown.

    Any suggestions would be much appreciated.



  • @guardian said in How to test if a gateway is online from a bash script?:

    FreeBSD doesn't have a -4 option

    All that does is force IPv4, when a host name returns both IPv4 and IPv6 addresses. If you specify an actual IPv4 address, rather than host name, IPv4 will be used. You used. 8.8.8.8, so the -4 option is irrelevant.


  • LAYER 8 Netgate

    @guardian said in How to test if a gateway is online from a bash script?:

    I wish FreeBSD would get their utilities on par with GNU linux

    There is zero reason for ping -4 on FreeBSD since there is ping and ping6



  • @Derelict said in How to test if a gateway is online from a bash script?:

    There is zero reason for ping -4 on FreeBSD since there is ping and ping6

    Linux used to work that way. Now, ping works with both IPv4 and IPv6. If both addresses are returned for a host name, it prefers IPv6. However, there is still a ping6 command, which is linked to ping.



  • This is for tcsh but I understand that should be very similar and easy to apply to bash

    #!/bin/tcsh
    set gw = `/usr/local/bin/php /usr/local/sbin/pfSsh.php playback gatewaystatus | grep WAN `
    set gwping = `echo $gw | awk '{ ORS="  "; print $6 }' `
    set gwstatus = `echo $gw | awk '{ ORS="  "; print $7 }' `
    


  • @Derelict said in How to test if a gateway is online from a bash script?:

    @guardian said in How to test if a gateway is online from a bash script?:

    I wish FreeBSD would get their utilities on par with GNU linux

    There is zero reason for ping -4 on FreeBSD since there is ping and ping6

    @JKnott said in How to test if a gateway is online from a bash script?:

    @Derelict said in How to test if a gateway is online from a bash script?:

    There is zero reason for ping -4 on FreeBSD since there is ping and ping6

    Linux used to work that way. Now, ping works with both IPv4 and IPv6. If both addresses are returned for a host name, it prefers IPv6. However, there is still a ping6 command, which is linked to ping.

    @JKnott @Derelict Thanks very much for this - I'm struggling with FreeBSD, after 2 years, I'm just beginning to get comfotable with Linux

    @hectorspc said in How to test if a gateway is online from a bash script?:

    This is for tcsh but I understand that should be very similar and easy to apply to bash

    #!/bin/tcsh
    set gw = `/usr/local/bin/php /usr/local/sbin/pfSsh.php playback gatewaystatus | grep WAN `
    set gwping = `echo $gw | awk '{ ORS="  "; print $6 }' `
    set gwstatus = `echo $gw | awk '{ ORS="  "; print $7 }' `
    

    @hectorspc - I decided to just use the gateway status.

    For the benefit of anyone who may wish to do something similar, here's the script I came up with;
    (Code review's welcome - goal was clarity/ease if maintenace/self-documenting not conciseness)

    #!/bin/sh 
    #
    # restartvpn: Restart the OpenVPN client if it is down.  The restart is supressed
    #             if the WAN is down.
    #
    #   -f / -F : Force: Force reset even if VPN is not down
    #   -q / -Q : Quiet: Supress printed output
    #
    
    WAN_ID='WAN_DHCP'                    # WAN Gateway ID String
    VPN_IDs='VPN_UDP_TOS_VPNV4'          # VPN Gateway ID Strings (Separate with a space)
    VPN_GWs='1'                          # VPN Client ID of gateway
    GW_DOWN='down'                       # Gateway down status string
    
    # -q / -Q : Quiet: Supress printed output
    silent=$(echo $@- | awk '{print (/-[qQ]/ ? 1 : 0)}')
    
    # -f / -F : Force: Force reset even if VPN is not down
    force=$(echo $@ | awk '{print (/-[fF]/ ? 1 : 0)}')
    
    restartvpn(){
       #
       #  Restart VPN client $VPN_GW  
       #
       WD=$([ "$WAN_STAT" = "$GW_DOWN" ] && echo "WAN DOWN:" || echo "")
       FC=$([ $force -eq 1 ] && echo "FORCED:" || echo "")
       echo $(date +%y/%m/%d-%H:%M:%S-)${ID}-${WD}${FC}$(/usr/local/sbin/pfSsh.php playback svc restart openvpn client $VPN_GW)
    }
    
    gwstat=$(pfSsh.php playback gatewaystatus)
    WAN_STAT=$(echo "$gwstat" | awk '/'$WAN_ID'/{print $NF}')
    PUBLIC_IP=$(echo "$gwstat" | awk '/'$WAN_ID'/{print $3}')
    
    if [ $silent -eq 0 ];then 
       echo -e "$(basename $0) - Public IP: $PUBLIC_IP - $(date)\n\n$gwstat\n"
    fi
    
    if [ "$WAN_STAT" = "$GW_DOWN" -a $force -eq 0 ];then
       echo "$(date +%y/%m/%d-%H:%M:%S-)WAN is down-VPN restart not attempted."
       return 1
    fi
    
    gw=1
    for ID in $VPN_IDs;do
       VPN_STAT=$(echo "$gwstat" | awk '/'$ID'/{print $NF}')
       VPN_GW=$(echo $VPN_GWs|cut -w -f $gw)
       if [ -n "$VPN_STAT" ];then
          [ $silent -eq 0 ] && echo VPN Gateway: $ID - $([ "$VPN_STAT" = "$GW_DOWN" ] && echo "DOWN" || echo "UP") 
           if [ "$VPN_STAT" = "$GW_DOWN" -o $force -eq 1 ];then
             restartvpn
             return 1
           fi
       else
          [ $silent -eq 0 ] && echo No active gateway $ID
       fi
    gw=gw+1
    done
    

    When run from the command line the output looks like this:

    # restartvpn 
    restartvpn - Public IP: 99.254.36.133 - Sun Mar  8 17:15:45 EDT 2020
    
    Name               Monitor  Source              Delay    StdDev  Loss  Status
    VPN_UDP_TOS_VPNV4  8.8.4.4  10.12.11.6       29.443ms  10.624ms   27%    down
    WAN_DHCP           8.8.8.8  99.254.36.133    11.329ms   6.142ms  0.0%    none
    
    VPN Gateway: VPN_UDP_TOS_VPNV4 - DOWN
    20/03/08-17:15:45-VPN_UDP_TOS_VPNV4-Attempting to issue restart to openvpn service... openvpn has been restarted.
    

    I have set it up to run as a cron job:

    */3	*	*	*	*	root	/root/bin/restartvpn -q
    

    Hopefully someone will find this helpful.


Log in to reply