<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Quinn</title>
    <description>The latest articles on DEV Community by Quinn (@antlossway).</description>
    <link>https://dev.to/antlossway</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F597277%2Fb9d412a8-a895-4ecb-a455-c6f53e518e39.png</url>
      <title>DEV Community: Quinn</title>
      <link>https://dev.to/antlossway</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/antlossway"/>
    <language>en</language>
    <item>
      <title>Site-to-site IPSec VPN between strongSwan(AWS) and Cisco Router(On-premise)</title>
      <dc:creator>Quinn</dc:creator>
      <pubDate>Thu, 28 Dec 2023 01:27:59 +0000</pubDate>
      <link>https://dev.to/antlossway/site-to-site-ipsec-vpn-between-strongswanaws-and-cisco-routeron-premise-j0e</link>
      <guid>https://dev.to/antlossway/site-to-site-ipsec-vpn-between-strongswanaws-and-cisco-routeron-premise-j0e</guid>
      <description>&lt;h2&gt;
  
  
  Introduction
&lt;/h2&gt;

&lt;p&gt;strongSwan is an open source project, which was launched in 2005 as a fork of the discontinued FreeS/WAN open source project.&lt;/p&gt;

&lt;p&gt;The strongSwan VPN suite uses the native IPsec stack in the standard Linux kernel. It supports both the IKEv1 and IKEv2 protocols.&lt;/p&gt;

&lt;p&gt;It is a comprehensive implementation of the Internet Key Exchange (IKE) protocols that allows securing IP traffic in policy- and route-based IPsec scenarios from simple to very complex.&lt;/p&gt;

&lt;p&gt;In this post, we connect strongSwan on AWS with on-premise Cisco router. I think it\'s an interesting scenario, because first, it applies to many companies who have their IT infrastructures on AWS; Second, there are very few tutorials cover this topic.&lt;/p&gt;

&lt;p&gt;As well, most existing strongSwan examples online are using the deprecated ipsec.conf method. We will use the recommended swanctl method.&lt;/p&gt;

&lt;p&gt;We use IKEv1 in this tutorial, because despite it is officially deprecated recently, it\'s still the de-facto set up nowadays.&lt;/p&gt;

&lt;p&gt;We will show IKEv2 examples in the future posts.&lt;/p&gt;

&lt;h2&gt;
  
  
  Network diagram
&lt;/h2&gt;

&lt;p&gt;The left side(mumbai) is using strongSwan hosted on AWS, and the right side(france) is using on-premise Cisco router. There is also NAT configured, because site-to-site VPN between different companies usually require the encryption domain to use public IP address.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--N66STgqJ--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://wp.hello-vpn.com/wp-content/uploads/2023/12/image-1024x441.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--N66STgqJ--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://wp.hello-vpn.com/wp-content/uploads/2023/12/image-1024x441.png" alt="network diagram" width="800" height="345"&gt;&lt;/a&gt; &lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;&lt;strong&gt;IP Info&lt;/strong&gt;&lt;/th&gt;
&lt;th&gt;&lt;strong&gt;Left side(mumbai)&lt;/strong&gt;&lt;/th&gt;
&lt;th&gt;&lt;strong&gt;Right side(france)&lt;/strong&gt;&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;VPN device/sw&lt;/td&gt;
&lt;td&gt;strongSwan 5.9.8 /Debian 12&lt;/td&gt;
&lt;td&gt;Cisco C931-4P&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;VPN GW IP&lt;/td&gt;
&lt;td&gt;35.154.207.104&lt;/td&gt;
&lt;td&gt;31.xxx.xxx.48&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Encryption Domain (VPN host or subnet)&lt;/td&gt;
&lt;td&gt;3.6.74.40 (NAT to 192.168.0.88)&lt;/td&gt;
&lt;td&gt;31.xxx.xxx.89 (NAT to 192.168.1.2)&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;h2&gt;
  
  
  IPSec parameters
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;&lt;strong&gt;Phase I Settings&lt;/strong&gt;&lt;/th&gt;
&lt;th&gt;﻿&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Authentication Method&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;Pre-Shared&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Diffie-Helman Group&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;2 (Mod1024)&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Encryption Algorithm&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;AES256&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Hash Algorithm&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;SHA-1&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;SA Timeout&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;28800&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;NAT-T&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;Enabled&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Phase II Settings&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;﻿&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Encapsulation&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;ESP (encrypted)&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Perfect Forward Secrecy (PFS)&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;NO PFS&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Encryption Algorithm&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;AES256&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Hash Algorithm&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;SHA-1&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Lifetime (In Seconds)&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;3600 (Default)&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;h2&gt;
  
  
  Notes for AWS
&lt;/h2&gt;

&lt;h3&gt;
  
  
  IP address
&lt;/h3&gt;

&lt;p&gt;We need to keep in mind that an AWS instance does not know the Elastic IP associated with its network interface. It only knows the internal IP inside the subnet that the network interface belongs to.&lt;/p&gt;

&lt;p&gt;Therefore, in our example, strongSwan instance is only aware of IP 192.168.0.33.&lt;/p&gt;

&lt;h3&gt;
  
  
  Disable Src/Dest check
&lt;/h3&gt;

&lt;p&gt;For strongSwan instance, disable src/dest check on it\'s main network interface.&lt;/p&gt;

&lt;p&gt;The reason? Check below quote from AWS doc:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;You can enable or disable source/destination checks, which ensure that the instance is either the source or the destination of any traffic that it receives. Source/destination checks are enabled by default.&lt;/p&gt;

&lt;p&gt;You must disable source/destination checks if the instance runs services such as network address translation, routing, or firewalls.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h3&gt;
  
  
  Security group
&lt;/h3&gt;

&lt;p&gt;The security group of strongSwan instance need to have below 2 rules enabled:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;allow incoming from 0.0.0.0 to UDP port 4500&lt;/li&gt;
&lt;li&gt;allow incoming from 0.0.0.0 to UDP port 500&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Installation(mumbai site)
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;
apt install strongswan charon-systemd
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Set linux kernel parameters(mumbai site)
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Edit /etc/sysctl.conf
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;# /etc/sysctl.conf

# Uncomment the next line to enable packet forwarding for IPv4
net.ipv4.ip_forward=1

# Do not accept ICMP redirects (prevent MITM attacks)
net.ipv4.conf.all.accept_redirects = 0

# Do not send ICMP redirects (we are not a router)
#net.ipv4.conf.all.send_redirects = 0

### also add below two lines, otherwise ping test will not work, replace enX0 with your own interface
net.ipv4.conf.default.send_redirects = 0
net.ipv4.conf.enX0.send_redirects = 0
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Disable the send_redirect on the affected network interface is important, because without it, the ping test will not work.&lt;/p&gt;

&lt;p&gt;Below is the explanation from strongSwan doc:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;If the VPN gateway is not the default gateway of the LAN, ICMP redirects might get returned to hosts if they send traffic destined for the remote hosts/subnets to the VPN gateway, directing them to the default gateway of the LAN (which probably doesn’t work and otherwise might get that traffic out unencrypted). To avoid this, disable sending such ICMP messages by setting&lt;/p&gt;

&lt;p&gt;&lt;code&gt;net.ipv4.conf.all.send_redirects=0 net.ipv4.conf.default.send_redirects=0&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;If the latter option is not set before the network interface comes up, also set the option for the individual interface&lt;/p&gt;

&lt;p&gt;&lt;code&gt;net.ipv4.conf.&amp;lt;iface&amp;gt;.send_redirects=0&lt;/code&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h3&gt;
  
  
  load the new setting
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;root@ip-192-168-0-33:~# sysctl -p
net.ipv4.ip_forward = 1
net.ipv4.conf.all.accept_redirects = 0
net.ipv4.conf.all.send_redirects = 0
net.ipv4.conf.default.send_redirects = 0
net.ipv4.conf.enX0.send_redirects = 0
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Configure NAT (Network Address Translation)
&lt;/h3&gt;

&lt;p&gt;First, create the file to define network rules.&lt;br&gt;
&lt;/p&gt;

&lt;p&gt;&lt;code&gt;iptables-save &amp;gt; /etc/iptables.rules&lt;/code&gt;&lt;br&gt;
&lt;/p&gt;

&lt;p&gt;Then add below rules in /etc/iptables.rules&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;*nat
:PREROUTING ACCEPT [0:0]
:INPUT ACCEPT [0:0]
:OUTPUT ACCEPT [0:0]
:POSTROUTING ACCEPT [0:0]
-A PREROUTING -d 3.6.74.40/32 -m comment --comment incoming-from-remote-host -j DNAT --to-destination 192.168.0.88
-A POSTROUTING -s 192.168.0.88/32 -d 31.xxx.xxx.89/32 -m comment --comment outgoing-to-remote-host -j SNAT --to-source 3.6.74.40
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Run below command to update iptables&lt;br&gt;
&lt;/p&gt;

&lt;p&gt;&lt;code&gt;iptables-restore &amp;lt; /etc/iptables.rules&lt;/code&gt;&lt;br&gt;
&lt;/p&gt;

&lt;h2&gt;
  
  
  strongSwan VPN configuration(mumbai site)
&lt;/h2&gt;

&lt;p&gt;/etc/swanctl/swanctl.conf&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;# default settings for all conns (e.g cert, IP pools)
conn-defaults {
      version = 1
      reauth_time = 28800
      proposals = aes256-sha1-modp1024
}

# default settings for all child configs (e.g. traffic selectors)
child-defaults {
      mode = tunnel
      start_action = trap|start
      rekey_time = 3600
}

connections {
   mumbai-france : conn-defaults {
      local_addrs  = 192.168.0.33
      remote_addrs = 31.xxx.xxx.48
      proposals = aes256-sha1-modp1024

      local {
         auth = psk
         id = 35.154.207.104
      }
      remote {
         auth = psk
         id = 31.xxx.xxx.48
      }
      children {
         mumbai-france1 : child-defaults {
            local_ts  = 3.6.74.40/32
            remote_ts = 31.xxx.xxx.89/32
        start_action = trap|start
            esp_proposals = aes256-sha1
         }
      }
   }

}

secrets {
   ike-1 {
      # a - local, b - remote
      id-1b = 31.xxx.xxx.48
      secret = ANsvU5WIwmQ6
   }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Note:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;local_addrs = 192.168.0.33, remember AWS instance does not know it\'s own Elastic IP address, therefore here we put the internal IP&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Cisco VPN configuration (france on-premise)
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;crypto isakmp policy 100
 encr aes 256
 authentication pre-share
 group 2
crypto isakmp key ANsvU5WIwmQ6
!
crypto ipsec transform-set vpn-sha1-aes256 esp-aes 256 esp-sha-hmac
 mode tunnel
!
crypto map francemap 2 ipsec-isakmp
 set peer 35.154.207.104
 set transform-set vpn-sha1-aes256
 match address TEST-MUMBAI-SS
!
ip nat inside source static 192.168.1.2 31.xxx.xxx.89
!
ip access-list extended TEST-MUMBAI-SS
 permit ip host 31.xxx.xxx.89 host 3.6.74.40
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  strongSwan start daemon
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;systemctl start strongswan

# for each modification on the connection, run below two command
swanctl --load-all #load preshared key and conn
swanctl --initiate --child mumbai-france1
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The output of --initiate command is something like below if it\'s successful:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;swanctl --initiate --child mumbai-france1
[ENC] generating QUICK_MODE request 2568099685 [ HASH SA No ID ID ]
[NET] sending packet: from 192.168.0.33[4500] to 31.xxx.xxx.48[4500] (172 bytes)
[NET] received packet: from 31.xxx.xxx.48[4500] to 192.168.0.33[4500] (204 bytes)
[ENC] parsed QUICK_MODE response 2568099685 [ HASH SA No ID ID N((24576)) ]
[CFG] selected proposal: ESP:AES_CBC_256/HMAC_SHA1_96/NO_EXT_SEQ
[IKE] CHILD_SA mumbai-france1{54} established with SPIs c21634ca_i 8dbd1a12_o and TS 3.6.74.40/32 === 31.xxx.xxx.89/32
[ENC] generating QUICK_MODE request 2568099685 [ HASH ]
[NET] sending packet: from 192.168.0.33[4500] to 31.xxx.xxx.48[4500] (60 bytes)
initiate completed successfully
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Verify VPN Status
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Verify strongSwan config
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;swanctl --list-conns

mumbai-france: IKEv1, reauthentication every 28800s
  local:  192.168.0.33
  remote: 31.xxx.xxx.48
  local pre-shared key authentication:
    id: 35.154.207.104
  remote pre-shared key authentication:
    id: 31.xxx.xxx.48
  mumbai-france1: TUNNEL, rekeying every 3600s
    local:  3.6.74.40/32
    remote: 31.xxx.xxx.89/32
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Verify strongSwan VPN status
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;&amp;lt;pre class="wp-block-code" has-small-font-size=""&amp;gt;```


swanctl --list-sas
mumbai-france: #53, ESTABLISHED, IKEv1, 99405922d34109cd_i b9f401ec6e3f603c_r*
  local  '35.154.207.104' @ 192.168.0.33[4500]
  remote '31.xxx.xxx.48' @ 31.xxx.xxx.48[4500]
  AES_CBC-256/HMAC_SHA1_96/PRF_HMAC_SHA1/MODP_1024
  established 8915s ago, reauth in 18254s
  mumbai-france1: #54, reqid 2, INSTALLED, TUNNEL-in-UDP, ESP:AES_CBC-256/HMAC_SHA1_96
    installed 984s ago, rekeying in 2412s, expires in 2976s
    in  c21634ca,   2940 bytes,    35 packets,    34s ago
    out 8dbd1a12,   2940 bytes,    35 packets,    34s ago
    local  3.6.74.40/32
    remote 31.xxx.xxx.89/32


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;We can also use below command to request detailed information about the IPsec SAs and policies installed in the kernel.&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;

ip -s xfrm state
ip -s xfrm policy


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;h3&gt;
  
  
  Verify Cisco VPN status
&lt;/h3&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;

# show crypto isakmp sa
IPv4 Crypto ISAKMP SA
dst             src             state          conn-id status
35.154.207.104  31.xxx.xxx.48     QM_IDLE           1223 ACTIVE
31.xxx.xxx.48     35.154.207.104  QM_IDLE           1224 ACTIVE


# show crypto session brief
Status: A- Active, U - Up, D - Down, I - Idle, S - Standby, N - Negotiating
        K - No IKE
ivrf = (none)
Peer            I/F          Username        Group/Phase1_id          Uptime   Status
35.154.207.104  Gi4                          35.154.207.104           00:22:41 UA
35.154.207.104  Gi4                          35.154.207.104           00:22:41 UA


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;h2&gt;
  
  
  Routing
&lt;/h2&gt;

&lt;p&gt;The hosts behind the VPN GW need to route remote host\'s IP via the VPN GW.&lt;/p&gt;

&lt;p&gt;On the left side (mumbai), the host app-L will add route like this:&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;

ip route add 31.xxx.xxx.89 via 192.168.0.33


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;And on the right side (france), host app-R has route like this:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;

ip route add 3.6.74.40 via 192.168.1.1


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;h2&gt;
  
  
  Test
&lt;/h2&gt;

&lt;p&gt;We will ping from app-L (192.168.0.88) to app-R (192.168.1.2)&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;

ping 31.xxx.xxx.89
PING 31.xxx.xxx.89 (31.xxx.xxx.89) 56(84) bytes of data.
64 bytes from 31.xxx.xxx.89: icmp_seq=1 ttl=62 time=152 ms
64 bytes from 31.xxx.xxx.89: icmp_seq=2 ttl=62 time=152 ms
64 bytes from 31.xxx.xxx.89: icmp_seq=3 ttl=62 time=152 ms
64 bytes from 31.xxx.xxx.89: icmp_seq=4 ttl=62 time=152 ms
64 bytes from 31.xxx.xxx.89: icmp_seq=5 ttl=62 time=152 ms
64 bytes from 31.xxx.xxx.89: icmp_seq=6 ttl=62 time=153 ms
64 bytes from 31.xxx.xxx.89: icmp_seq=7 ttl=62 time=152 ms


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;To verify that those traffic are indeed getting encrypted and decrypted via the VPN tunnel, we can check the counter on both strongSwan and Cisco.&lt;/p&gt;

&lt;p&gt;on strongSwan instance, run swanctl --list-sas, and observe the number of in and out packets, it should increase while doing the ping test.&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;

swanctl --list-sas
mumbai-france: #53, ESTABLISHED, IKEv1, 99405922d34109cd_i b9f401ec6e3f603c_r*
  local  '35.154.207.104' @ 192.168.0.33[4500]
  remote '31.xxx.xxx.48' @ 31.xxx.xxx.48[4500]
  AES_CBC-256/HMAC_SHA1_96/PRF_HMAC_SHA1/MODP_1024
  established 8915s ago, reauth in 18254s
  mumbai-france1: #54, reqid 2, INSTALLED, TUNNEL-in-UDP, ESP:AES_CBC-256/HMAC_SHA1_96
    installed 984s ago, rekeying in 2412s, expires in 2976s
    in  c21634ca,   2940 bytes,    35 packets,    34s ago
    out 8dbd1a12,   2940 bytes,    35 packets,    34s ago
    local  3.6.74.40/32
    remote 31.xxx.xxx.89/32


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;On Cisco side, observe as well the Inbound and Outbound packets increase.&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;

# show crypto session detail

Interface: GigabitEthernet4
Uptime: 00:19:19
Session status: UP-ACTIVE
Peer: 35.154.207.104 port 4500 fvrf: (none) ivrf: (none)
      Phase1_id: 35.154.207.104
      Desc: (none)
  Session ID: 0
  IKEv1 SA: local 31.xxx.xxx.48/4500 remote 35.154.207.104/4500 Active
          Capabilities:N connid:1223 lifetime:21:28:43
  Session ID: 0
  IKEv1 SA: local 31.xxx.xxx.48/4500 remote 35.154.207.104/4500 Active
          Capabilities:N connid:1224 lifetime:06:17:20
  IPSEC FLOW: permit ip host 31.xxx.xxx.89 host 3.6.74.40
        Active SAs: 4, origin: crypto map
       &amp;lt;strong&amp;gt; Inbound:  #pkts dec'ed 2121 drop 0 life (KB/Sec) 4344779/2452
        Outbound: #pkts enc'ed 2121 drop 0 life (KB/Sec) 4344779/2452&amp;lt;/strong&amp;gt;


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;It\'s relatively easy to create a standard site-to-site IPSec VPN using strongSwan if you check documentation carefully.&lt;/p&gt;

&lt;p&gt;Cost-wise, this is a very interesting option for small companies who only require VPN connection occasionally for some projects.&lt;/p&gt;

&lt;h2&gt;
  
  
  References
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://www.cisco.com/c/en/us/support/docs/ip/internet-key-exchange-ike/117258-config-l2l.html"&gt;Cisco document: example config between strongSwan and Cisco router (IKEv1 and IKEv2)&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://www.strongswan.org/testing/testresults/ikev1/net2net-psk/"&gt;strongSwan official doc example of site-to-site IKEv1&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://wiki.strongswan.org/projects/strongswan/wiki/Fromipsecconf"&gt;Migrate from ipsec.conf to swanctl.conf&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://techtalksecurity.blogspot.com/2022/12/configure-ipsec-site-to-site-vpn-in.html?m=1"&gt;https://techtalksecurity.blogspot.com/2022/12/configure-ipsec-site-to-site-vpn-in.html?m=1&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://www.tecmint.com/setup-ipsec-vpn-with-strongswan-on-debian-ubuntu/"&gt;https://www.tecmint.com/setup-ipsec-vpn-with-strongswan-on-debian-ubuntu/&lt;/a&gt;&lt;/p&gt;

</description>
    </item>
    <item>
      <title>How to run a Cisco router on AWS</title>
      <dc:creator>Quinn</dc:creator>
      <pubDate>Wed, 20 Dec 2023 02:00:52 +0000</pubDate>
      <link>https://dev.to/antlossway/how-to-run-a-cisco-router-on-aws-21k</link>
      <guid>https://dev.to/antlossway/how-to-run-a-cisco-router-on-aws-21k</guid>
      <description>&lt;p&gt;&lt;em&gt;&lt;strong&gt;Warning&lt;/strong&gt;: Cisco software usage cost will be incurred, as well as EC2 usage, although the latter is only a tiny portion comparing to Cisco software price. Make sure to terminate the instance after testing to avoid unexpected bill.&lt;/em&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Running a cloud router
&lt;/h2&gt;

&lt;p&gt;Don't want to bother with hardware procurement and maintenance? There are plenty of cloud solutions nowadays.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Today let's dive in the steps to run a Cisco router on AWS.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://aws.amazon.com/marketplace/pp/prodview-4mrybq6krrw3g#pdp-usage"&gt;Cisco Cloud Services Router (CSR) 1000V&lt;/a&gt; is an Enterprise-class VPN solution in AWS for many years. &lt;/p&gt;

&lt;p&gt;Below graph shows that CSR 1000V typically requires two network interfaces, one facing public subnet, the other one facing private subnet. &lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--I0CT9lVA--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://wp.hello-vpn.com/wp-content/uploads/2023/12/Screenshot-2023-12-14-at-15.31.04.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--I0CT9lVA--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://wp.hello-vpn.com/wp-content/uploads/2023/12/Screenshot-2023-12-14-at-15.31.04.png" alt="Cisco CSR on AWS" width="588" height="182"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;We will associate an Elastic IP with the public-facing network interface, which will be the endpoint for peer.&lt;/p&gt;

&lt;p&gt;The private-facing network interface will receive traffic routed by other internal servers, then the traffic will be encrypted in the Cisco router and routed out to the peer's VPN gateway.&lt;/p&gt;

&lt;h2&gt;
  
  
  Prerequisites
&lt;/h2&gt;

&lt;p&gt;First, let's have a look at the prerequisites. &lt;/p&gt;

&lt;p&gt;We need to have a VPC and two subnet. If you are starting from zero, then it's time to create those and come back for the next steps.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--9s8eOMby--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://wp.hello-vpn.com/wp-content/uploads/2023/12/cisco-aws-1024x452.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--9s8eOMby--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://wp.hello-vpn.com/wp-content/uploads/2023/12/cisco-aws-1024x452.png" alt="network diagram" width="800" height="353"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Steps to add a CSR instance
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;go to AWS marketplace and search for "Cisco CSR 1000V"&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;On the CSR 1000V product page, click the 'Continue' button. &lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Complete the deployment of a CSR 1000V AMI: Select the correct version and region, and click the 'Continue to launch through EC2' button. &lt;br&gt;
&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--xMyY8QTu--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/http://wp.hello-vpn.com/wp-content/uploads/2023/12/marketplace-configure.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--xMyY8QTu--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/http://wp.hello-vpn.com/wp-content/uploads/2023/12/marketplace-configure.png" alt="launch new instance" width="800" height="499"&gt;&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;The Launch Instances Wizard will open. Select the desired instance type: by default a bigger instance is selected, for testing purpose, we choose the smallest instance available, which is t2.medium at the moment.&lt;br&gt;
Select an existing key pair to use for authentication, or create a new key pair. If you create a key pair, make sure to download and save the private key.&lt;br&gt;
&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--AxIgpSMd--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/http://wp.hello-vpn.com/wp-content/uploads/2023/12/launch-instance-type.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--AxIgpSMd--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/http://wp.hello-vpn.com/wp-content/uploads/2023/12/launch-instance-type.png" alt="instance type" width="800" height="479"&gt;&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Select VPC environment in the 'Network' pull-down menu. &lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Select an IP subnet for the first CSR 1000V network interface in the 'Subnet' pull-down menu. &lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Select an Security group.&lt;br&gt;
&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--bTiZyLgy--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/http://wp.hello-vpn.com/wp-content/uploads/2023/12/launch-network-masked.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--bTiZyLgy--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/http://wp.hello-vpn.com/wp-content/uploads/2023/12/launch-network-masked.png" alt="select a security group" width="766" height="649"&gt;&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Add any additional network interfaces, and select the appropriate subnet for each to connect to. &lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Click 'Review and Launch', if the information is correct, click 'Launch'.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;From the AWS Console, wait for your instance to indicate a state of 'running'. It may take a few moments after that point, before you can connect to your CSR 1000V instance. Connect to your instance using an SSH client, and the private SSH key selected or created earlier in these steps. Example: ssh -i mykeypair.pem &lt;a href="mailto:ec2-user@myhostname.compute-1.amazonaws.com"&gt;ec2-user@myhostname.compute-1.amazonaws.com&lt;/a&gt; &lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Allocate an Elastic IP and associate it with the first (default) network interface of the CSR 1000V. &lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Once SSH has connected, you should be at the IOS XE command prompt on the CSR 1000V. Now we can configure this instance.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  Configure CSR instance
&lt;/h2&gt;

&lt;p&gt;By default, the "show running-config" displays interfaces like below:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;interface GigabitEthernet1
 ip address dhcp
 ip nat outside
 negotiation auto
!
interface GigabitEthernet2
 no ip address
 shutdown
 negotiation auto
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Note that we will not see the EIP(Elastic IP) we associated to the first interface(interface GigabitEthernet1), nor will we see the local IP 192.168.1.100. This is something we need to keep in mind, although the configuration does not show those IPs, they still exists.&lt;/p&gt;

&lt;p&gt;We can see local IP 192.168.1.100 when using command to display the details of the first interface.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;ip-192-168-1-100#show interfaces gigabitEthernet 1
GigabitEthernet1 is up, line protocol is up
  Hardware is CSR vNIC, address is 02c5.fde2.baec (bia 02c5.fde2.baec)
  Internet address is 192.168.1.100/24
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;As for the 2nd interface (interface GigabitEthernet2), no IP is configured and interface is down.&lt;/p&gt;

&lt;p&gt;Let's configure IP for GigabitEthernet2&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;ip-192-168-1-100#conf t
Enter configuration commands, one per line.  End with CNTL/Z.
ip-192-168-1-100(config)#interface gigabitEthernet 2
ip-192-168-1-100(config-if)#ip address 192.168.0.100 255.255.255.0
ip-192-168-1-100(config-if)#ip nat inside
ip-192-168-1-100(config-if)#no shutdown
ip-192-168-1-100(config-if)#end
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then we check again the status of GigabitEthernet2 :&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;ip-192-168-1-100#sho run interface  GigabitEthernet2
 ip address 192.168.0.100 255.255.255.0
 ip nat inside
 negotiation auto
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We can also test the connection from Cisco router to private host&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;ip-192-168-1-100#ping 192.168.0.88
Type escape sequence to abort.
Sending 5, 100-byte ICMP Echos to 192.168.0.88, timeout is 2 seconds:
!!!!!
Success rate is 100 percent (5/5), round-trip min/avg/max = 2/2/3 ms
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Voila! We have a running Cisco router on the cloud.&lt;/p&gt;

&lt;h2&gt;
  
  
  Cost Saving
&lt;/h2&gt;

&lt;p&gt;Always purchase a yearly software contract if it's available.&lt;/p&gt;

&lt;p&gt;With contract, the yearly cost is $2,285.73.&lt;/p&gt;

&lt;p&gt;Without contract, the price is $0.64 Software/hour +  $0.046 EC2/hour, which makes $5,928 per year (2.5 times of the price with contract!)&lt;/p&gt;

&lt;p&gt;Below is a screenshot of what the interface may looks like. &lt;br&gt;
&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--xHsvjGle--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://wp.hello-vpn.com/wp-content/uploads/2023/12/CSR-software-contract-1024x681.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--xHsvjGle--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://wp.hello-vpn.com/wp-content/uploads/2023/12/CSR-software-contract-1024x681.png" alt="AWS market place CSR subscription page" width="800" height="532"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Caveat
&lt;/h2&gt;

&lt;p&gt;According to a Cisco Community post and an End-of-Sale and End-of-Life announcement on the Cisco website, Cisco will no longer offer the "Cisco Cloud Services Router (CSR) 1000V" product line. The End-of-Sale date was December 16, 2022, and the End-of-Life date is December 16, 2025. This means that the product is no longer for sale and will not be supported beyond the End-of-Life date. Customers who have already purchased the product will continue to receive support until the End-of-Life date, and Cisco may offer replacement or alternative products.&lt;/p&gt;

&lt;p&gt;From AWS market place, the latest version is 17.03.08a and they still offer yearly software contract, which will cost $2k+ for one year. However, in the future, AWS may stop offering yearly contract and only offer hourly charging model. This all depends on Cisco's decision.&lt;/p&gt;

&lt;p&gt;Cisco is advocating for the next generation Catalyst 8000V to replace CSR 1000V. Yes, maybe the new one is more powerful and all better and shining, but the cost will be $8K+ yearly even with yearly contract!&lt;/p&gt;

&lt;p&gt;Does it worth it? This is not a light decision to make. &lt;/p&gt;

&lt;h2&gt;
  
  
  References
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://aws.amazon.com/marketplace/pp/prodview-4mrybq6krrw3g#pdp-usage"&gt;https://aws.amazon.com/marketplace/pp/prodview-4mrybq6krrw3g#pdp-usage&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://community.cisco.com/t5/other-cloud-subjects/cisco-will-no-longer-offer-quot-cisco-cloud-services-router-csr/td-p/4627861"&gt;https://community.cisco.com/t5/other-cloud-subjects/cisco-will-no-longer-offer-quot-cisco-cloud-services-router-csr/td-p/4627861&lt;/a&gt;&lt;/p&gt;

</description>
      <category>cisco</category>
      <category>vpn</category>
      <category>aws</category>
      <category>network</category>
    </item>
    <item>
      <title>python: compare dates</title>
      <dc:creator>Quinn</dc:creator>
      <pubDate>Wed, 01 Sep 2021 01:40:13 +0000</pubDate>
      <link>https://dev.to/antlossway/python-compare-dates-285f</link>
      <guid>https://dev.to/antlossway/python-compare-dates-285f</guid>
      <description>&lt;p&gt;An easy way to compare dates is to use comparison operators like &amp;lt;, &amp;gt;, &amp;lt;=, &amp;gt;=, != etc. &lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Case study:&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;I have a configuration file (text) including effective_date, and I need to compare if today is later than effective_date, if yes, then I need to perform some checking;&lt;br&gt;
otherwise nothing need to be done.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;""" extract effective_date from configuration file 
    line is obtained from readline() after open the 
    configuration file
"""
(param1,param2,effective_date) = line.strip().split(',')

"" use list comprehension to extract year,month,day
 to build a datetime.date type, """
year,month,day = [int(x) for x in effective_date.split('-')]
date_obj = datetime.date(year,month,day) #datetime.date type

today = datetime.date.today()

if today &amp;gt;= date_obj:
    """ do something here """
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;datetime.datetime type can also be compared in the same way, just make sure the compared objects have the same type.&lt;/p&gt;

</description>
      <category>python</category>
    </item>
    <item>
      <title>python: module has no attribute error</title>
      <dc:creator>Quinn</dc:creator>
      <pubDate>Sun, 29 Aug 2021 02:42:12 +0000</pubDate>
      <link>https://dev.to/antlossway/python-module-has-no-attribute-error-4753</link>
      <guid>https://dev.to/antlossway/python-module-has-no-attribute-error-4753</guid>
      <description>&lt;h1&gt;
  
  
  Problem
&lt;/h1&gt;

&lt;p&gt;I have a directory ~/dev/python3/pylib, which contains handy small modules. One of them is DB.py, which defines functions to connect to different databases.&lt;/p&gt;

&lt;p&gt;If a script requires connection to a database, I can simply do&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import site
site.addsitedir('/home/xqy/dev/python3/pylib')
import DB

db = DB.connectlocaldb()
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;But why I got error like below?&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;AttributeError: module 'DB' has no attribute 'connectlocaldb'&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;I checked several times to make sure the lib dir is correct and the file DB.py includes function "connectlocaldb()", but the error still persists.&lt;/p&gt;

&lt;h1&gt;
  
  
  Reason:
&lt;/h1&gt;

&lt;p&gt;When importing a module, python will go through a list of directories included in &lt;strong&gt;sys.path&lt;/strong&gt;, and searching for the specified module, the first one found will be used.&lt;/p&gt;

&lt;p&gt;xqy@voyager:~/dev/python3$ python&lt;br&gt;
Python 3.7.3 (default, Jan 22 2021, 20:04:44) &lt;br&gt;
[GCC 8.3.0] on linux&lt;br&gt;
Type "help", "copyright", "credits" or "license" for more information.&lt;/p&gt;

&lt;blockquote&gt;
&lt;blockquote&gt;
&lt;blockquote&gt;
&lt;p&gt;import sys&lt;br&gt;
print("\n".join(sys.path))&lt;br&gt;
''&lt;br&gt;
/usr/lib/python37.zip&lt;br&gt;
/usr/lib/python3.7&lt;br&gt;
/usr/lib/python3.7/lib-dynload&lt;br&gt;
/home/xqy/.local/lib/python3.7/site-packages&lt;br&gt;
/usr/local/lib/python3.7/dist-packages&lt;br&gt;
/usr/lib/python3/dist-packages&lt;/p&gt;
&lt;/blockquote&gt;


&lt;/blockquote&gt;
&lt;br&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;strong&gt;the empty entry '' means the current directory&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;There is another DB.py under ~/dev/python3/, as my current directory is ~/dev/python3, the module file ~/dev/python3/DB.py is used instead of /home/xqy/dev/python3/pylib/DB.py&lt;/p&gt;

&lt;p&gt;And there is no "connectlocaldb" function in ~/dev/python3/DB.py&lt;/p&gt;

&lt;p&gt;We can also find out sys.path using below command&lt;/p&gt;

&lt;p&gt;xqy@voyager:~/dev/python3$ python3 -m site&lt;br&gt;
sys.path = [&lt;br&gt;
    '/home/xqy/dev/python3',&lt;br&gt;
    '/usr/lib/python37.zip',&lt;br&gt;
    '/usr/lib/python3.7',&lt;br&gt;
    '/usr/lib/python3.7/lib-dynload',&lt;br&gt;
    '/home/xqy/.local/lib/python3.7/site-packages',&lt;br&gt;
    '/usr/local/lib/python3.7/dist-packages',&lt;br&gt;
    '/usr/lib/python3/dist-packages',&lt;br&gt;
]&lt;br&gt;
USER_BASE: '/home/xqy/.local' (exists)&lt;br&gt;
USER_SITE: '/home/xqy/.local/lib/python3.7/site-packages' (exists)&lt;br&gt;
ENABLE_USER_SITE: True&lt;/p&gt;

&lt;p&gt;xqy@voyager:~/dev/python3$ cd ~&lt;br&gt;
xqy@voyager:~$ python3 -m site&lt;br&gt;
sys.path = [&lt;br&gt;
    '/home/xqy',&lt;br&gt;
    '/usr/lib/python37.zip',&lt;br&gt;
    '/usr/lib/python3.7',&lt;br&gt;
    '/usr/lib/python3.7/lib-dynload',&lt;br&gt;
    '/home/xqy/.local/lib/python3.7/site-packages',&lt;br&gt;
    '/usr/local/lib/python3.7/dist-packages',&lt;br&gt;
    '/usr/lib/python3/dist-packages',&lt;br&gt;
]&lt;br&gt;
USER_BASE: '/home/xqy/.local' (exists)&lt;br&gt;
USER_SITE: '/home/xqy/.local/lib/python3.7/site-packages' (exists)&lt;br&gt;
ENABLE_USER_SITE: True`&lt;/p&gt;

&lt;p&gt;Therefore, by deleting file ~/dev/python3/DB.py or changing current directory, the error will not appear any more.&lt;/p&gt;

</description>
      <category>python</category>
    </item>
  </channel>
</rss>
