0%

使用ssh Reverse Tunnel 突破防火牆或NAT限制

  • 架構圖
  • 背景說明
  • 實作說明
  • 參考資料

    架構圖

    試想一個情況,公司區網有一部A主機可以對外連線上網都沒問題,可是這部A主機是在防火牆或NAT後端裡面,外部B主機是無法連到這部A主機。若不想在防火牆設定由外部 mapping A主機的話,就可以利用 SSH Reverse Tunnel。

SSh Reverse Tunnel架構圖

背景說明

- 區域網的 A主機(windows ) 192.168.88.8 , 有開啟RDP(有開啟遠端桌面服務,僅在區域網路使用) - 外部B主機(Linux,在Google GCP 租用的),35.221.139.139 (Public IP, 配合演示使用的),有開啟SSHD服務 - 本篇主要目的,要從 Google GCP 租用的外部B主機連到區域網路A主機RDP服務

實作說明

如上圖顯示紫色那一段為第1步,綠色為第2步。

第1步: 先在A主機建立與B主機的Reverse Tunnel連線

A主機是Windows,用putty ssh 外部B主機

填上外部B主機ip位址
填上外部B主機ip位址

填上Login帳號
填上Login帳號
此步驟非必要的,此篇登入外部B主機是使用憑證方式
此步驟非必要的,此篇登入外部B主機是使用憑證方式
最重要!!,設定reverse Tunnel

  • Source port:3389 表示給外部連線用的
  • Destination : 127.0.0.1:3389 表示連線A主機內部服務
    此步驟非必要的,此篇登入外部B主機是使用憑證方式

完成連線

  • 表示已連線登入到外部B主機
  • 紅色圈起來表示 上圖Source port部份
    完成連線

第2步: 從B主機連線到內網A主機

使用freerdp這個套件連線 內網A主機rdp服務
freerdp_connection
rdp Login
rdp Login
用RDP 進入內網A主機
RDP A

參考資料

基礎:Flask Jinja2 模板引擎

本範例程式的目錄結構 (使用python3.x)

1
2
3
4
5
6
7
8
.
├── hello.py
└── templates
├── base.html
├── test2.html
├── test.html
└── user.html

在Jinja2 變數的表示

  • hello.py
    1
    2
    3
    4
    5
    from flask import Flask, render_template
    app = Flask(__name__)
    @app.route('/user/<name>')
    def user(name):
    return render_template('user.html', name=name)
  • user.html
    1
    <h1>Hello, {{ name }}!</h1>

    在Jinja2 變數過濾器

  • [Jinja2 官方的過濾清單]
  • 呈上一的變數的表示, hello.py不變;只更改 templates/user.html
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    <h1>第一個字元大寫,其餘小寫: {{ name|capitalize }}!</h1>
    <h1>第一個字元大寫: {{ name|title }}!</h1>
    <h1>全部字元小寫: {{ name|lower }}!</h1>
    <h1>全部字元大寫: {{ name|upper }}!</h1>
    <h1>變數name2 未定義,顯示預定字串: {{ name2|default('the name2 is not defined') }}!</h1>
    <h1>變數為空值時,顯示預定字串: {{ ''|default('the string was empty',true) }}!</h1>
    <h1>刪除前後空白字元: {{ ' Hello~~~ '|trim }}!</h1>

    <h1>未移除HTML標籤: {{ '<ul><li>Hello ha</li></ul>' }}!</h1>
    <h1>轉譯前移除HTML標籤: {{ '<ul><li>Hello ha</li></ul>'|striptags }}!</h1>
    <h1>轉譯前移除HTML標籤,並再轉大寫字元: {{ '<ul><li>Hello ha</li></ul>'|striptags|upper }}!</h1>

    在Jinja2 控制結構

  • 只更改 templates/user.html,並刪除之前的內容。判斷name 變數的值是否為andy,正確返回 hello andy ; 反之,返回 Hello EveryBody
    1
    2
    3
    4
    5
    {% if name=="andy" %}
    <h1> Hello {{ name }} !!!</h1>
    {% else %}
    <h1> Hello EveryBody !!!</h1>
    {% endif %}
  • 迴圈控制。修改hello.pytemplates/test.html, 在hello.py 製造一個串列,將它帶往模板的迴圈來處理。

hello.py

1
2
3
4
@app.route('/array/')
def arrayt():
commit=[ 'test'+str(xx) for xx in range(1,10)]
return render_template('test.html',commit=commit)

templates/test.html

1
2
3
4
5
<ul>
{% for item in commit %}
<li>Hello, {{ item }}!</li>
{% endfor %}
</ul>
  • Jinja2 模板引擎也有函數結構,稱為 macro。增加以下內容到 templates/test.html
    1
    2
    3
    4
    5
    6
    7
    8
    9
    {% macro tempf(item) %}
    <li>from macro : {{ item }}!!!</li!>
    {% endmacro %}

    <ul>
    {% for item in commit %}
    {{ tempf(item) }}
    {% endfor %}
    </ul>
  • 呈上一個macro 範例,使用像是 python import用法,將macro 函數寫在 template/test2.html, 修改template/test.html在匯入 test2.html。

增加以下 到 template/test2.html

1
2
3
{% macro tempf(item) %}
<li>from macro with import : {{ item }}!!!</li!>
{% endmacro %}

修改 template/test.html

1
2
3
4
5
6
7
{% import "test2.html" as testmacro %}

<ul>
{% for item in commit %}
{{ testmacro.tempf(item) }}
{% endfor %}
</ul>

Jinja2 模板繼承

網頁是由html head ,body 等標籤兩兩成對構成,通常程式回應結果只在body 區塊有所變更,沒有必要重新將相同內容放置同一個模板中,因此可以使用模板繼承方式將基礎的模板匯進來。

  • 基礎模板: template/base.html ; 在 template/user.html繼承基礎模板。基礎模板劃分 , head 區塊(),head 裡面 title 區塊, 及 body 區塊,現在只要改變body區塊

增加以下內容 至 template/base.html

1
2
3
4
5
6
7
8
9
10
11
12
<!DOCTYPE HTML>
<html>
<head>
{% block head %}
<title> {% block title %}who 123{% endblock %} </title>
{% endblock %}
</head>
<body>
{% block body %}
{% endblock %}
</body>
</html>

修正內容 template/user.html,使用extends 繼承 base.html

1
2
3
4
{% extends "base.html" %}
{% block body %}
<h1>Hello, {{ name }}!</h1>
{% endblock %}
  • 若要在head區塊增加 一個 meta 標籤,及改變一個tile 區塊內容

修正內容 template/user.html

1
2
3
4
5
6
7
8
{% extends "base.html" %}
{% block title %}Title Change {{ name }}{% endblock %}
{% block head %}
<meta charset="utf-8" />
{% endblock %}
{% block body %}
<h1>Hello, {{ name }}!</h1>
{% endblock %}

瀏覽結果發現,網頁title 標題不見。這是因為 title 區塊位於 head 區塊內,也就是說title 是head區塊的內容;當增加meta 標籤就會覆蓋掉原本的title 的內容。要解決此問題,只要 head 區塊在增加一個 super();表示再次引用 base.html 基礎模板中的 head 區塊內容。

1
2
3
4
5
6
7
8
9
{% extends "base.html" %}
{% block title %}Title Change {{ name }}{% endblock %}
{% block head %}
<meta charset="utf-8" />
{{super()}}
{% endblock %}
{% block body %}
<h1>Hello, {{ name }}!</h1>
{% endblock %}

參考資料:

基礎:Flask URL 傳值

url 傳值範例

demo2.py

1
2
3
4
5
6
7
8
9
#!/usr/bin/env python3
from flask import Flask
app = Flask(__name__)
@app.route('/home/<id>')
def index2(id):
return 'My Home in ' + id

if __name__ == '__main__':
app.run(host='127.0.0.1',port=8099,debug=True)

測試執行

參數類型

標記的 ,可以指定參數類型

  • 語法:
    <類型:id>
  • 類型:
    • string:沒有接受 斜線的文字(預設)
    • int
    • float
    • path: 和預設一樣 ,但接受斜線
    • uuid
    • any: 指定多種路徑

指定類型範例

demo2-1.py

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
#!/usr/bin/env python3
from flask import Flask
app = Flask(__name__)
@app.route('/home/<int:id>')
def index2(id):
test=100 + id
test=str(test)
return 'Google Number: ' + test

@app.route('/<any(Taichung,Taipei,AAA,BBB):lo>/')
def index3(lo):
return 'My Home is in ' + lo

if __name__ == '__main__':
app.run(host='127.0.0.1',port=8099,debug=True)

指定類型執行

基礎:Flask 建立一個app

簡單範例 Hello World

demo.py

1
2
3
4
5
6
7
8
9
10
11
12
13
#!/usr/bin/env python3
from flask import Flask
app = Flask(__name__)
@app.route('/')
def index():
return "<h1>Hello World</h1>"

@app.route('/home')
def index2():
return 'My Home'

if __name__ == '__main__':
app.run(host='127.0.0.1',port=8099,debug=True)

啟動

啟動一個 web 服務, listen 127.0.0.1:8099

1
2
./demo.py
或是 python3 demo.py

測試

在Browser 測試兩個網址,看看會回應什麼變化。

說明

  • Flask 類 傳入的參數 ‘name‘ ,表示 程式的根目錄
  • @app.route 裝飾器 將 url 與 視圖函數(View) def index() 關聯到 app.url_map 屬性上 。處理 url 與 視圖函數的過程稱為路由(route)
  • app.run 使用 Python 標準函數 BaseHTTPServer.HTTPServer 啟動一個 web 服務。有 host , port , debug 等諸多參數
  • Flask 使用 唯一URL 。 使用 curl http://127.0.0.1:8099/home (回 http stat code 200) 與 curl http://127.0.0.1:8099/home/ (回http stat code 404) 回應結果不同。

Python - multiprocessing

大部分程式都是由上到下依序執行,若一個程式花費需要5秒,批示執行8次,理論是應該須40秒時間。現在CPU都是多核心,假設有一個8 core的CPU,將執行8次花費5秒的程式,分配到每個核心並行執行,理論上應該只要5秒就可完成工作。Python 標準函式庫 就有 multiprocessing 可達到此目的。

Python Demo 1

1.ping 5次 (循序方式,於雙核CPU) ;測出約8秒

1
2
3
4
5
6
7
8
9
10
#!/usr/bin/env python                                                                                                                 
import os

def job1(url):
tmpstr="ping -c 5 "+str(url)
os.system(tmpstr)

if __name__=='__main__':
job1("8.8.8.8")
job1("8.8.4.4")

2.ping 5次 (並行方式,於雙核CPU);測出約4秒

1
2
3
4
5
6
7
8
9
10
11
12
13
#!/usr/bin/env python                                                                                                                 
import multiprocessing as mp
import os

def job1(url):
tmpstr="ping -c 5 "+str(url)
os.system(tmpstr)

if __name__=='__main__':
p1=mp.Process(target=job1,args=("8.8.8.8",))
p1.start()
p2=mp.Process(target=job1,args=("8.8.4.4",))
p2.start()

Python Demo 2 ,另一種Pool寫法

1.一個工作睡3秒,執行5次。(循序方式,於雙核CPU) ;測出約15秒

1
2
3
4
5
6
7
8
9
10
11
#!/usr/bin/env python                                                                                                                 
from multiprocessing import Pool
from time import sleep

def task(argss):
print(str(argss) +" start ... sleep")
sleep(3)

if __name__ == '__main__':
for i in range(5):
task(i)

2.一個工作睡3秒,執行5次。(並行方式,於雙核CPU) ;測出約9秒

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
#!/usr/bin/env python
from multiprocessing import Pool
from time import sleep

def task(argss):
print(str(argss) +" start ... sleep")
sleep(3)

if __name__ == '__main__':
p=Pool(2)
for i in range(5):
p.apply_async(task, args=(i,))

print('Waiting for all subprocesses..')
p.close()
p.join()
print('All Subprocess done ..')

參考資料

安裝

開始部屬APP (deployment)

1
2
3
4
kubectl.exe run mynginx --image=nginx --port=80
kubectl.exe get pods
kubectl get node -o wide
kubectl.exe get deployments

發布APP (services)

1
2
kubectl.exe expose deployment mynginx --type="NodePort"
kubectl.exe get services

測試存取APP

  • kubectl.exe get services

    1
    2
    3
    NAME         TYPE        CLUSTER-IP      EXTERNAL-IP   PORT(S)        AGE
    kubernetes ClusterIP 10.96.0.1 <none> 443/TCP 54m
    mynginx NodePort 10.100.18.218 <none> 80:30213/TCP 7m
  • 看 k8s Master 的 IP 為何

    1
    minikube service mynginx --url
  • curl http://192.168.99.100:30213

探索APP

  • list pods 詳細資訊

    1
    kubectl.exe  describe pods
  • 依上述所列的Name即是pod的名稱,看 pod 裡 log 相關資訊

    1
    kubectl.exe  logs pod-Name
  • 到 pods container 執行命令列

    1
    kubectl.exe exec -it pod-Name bash
  • 刪除 pods , servies

    1
    kubectl.exe  delete  deployment mynginx
    1
    kubectl.exe  delete service mynginx

參考資料

架構說明

sito2sitel2
本實驗使用 vsphere Esxi 建立的LAB。此實驗目的要讓分屬在不同的廣域網路透過SoftEther VPN 將兩者串接在一起,形成邏輯上的區域網路。換言之,假設圖中 Site B 是位於台中辦公室; Site A 位於台北辦公室,透過SoftEther VPN串接起來,台中與台北辦公室彼此就可透過區域網路的方式互傳資料,或是台中有架一台DHCP Server(假設是 192.168.11.110-150);台北辦公室的Client端就可以分配到一個私有IP(192.168.11.x)。

上面架構圖中右邊 顯示 vSwitch5 應改成 vSwitch4

因為只是模擬的實驗,192.168.88.62 與 192.168.88.63當作是網域網路的Public IP。vSwitch0 , vSwitch 3及vSwitch 4是 Vsphere Esxi 模擬出來的。像是如下
vswitch0
vswitch3_4

安裝SoftEther VPN Server 及配置

- 安裝SoftEther VPN Server 及 啟動 vpnserver 執行到 make 就依照 它提問進行即可。
1
2
3
4
5
6
7
8
9
10
11
12
13
# cd /usr/local/src/
# wget http://www.softether-download.com/files/softether/v4.24-9651-beta-2017.10.23-tree/Linux/SoftEther_VPN_Server/64bit_-_Intel_x64_or_AMD64/softether-vpnserver-v4.24-9651-beta-2017.10.23-linux-x64-64bit.tar.gz
# tar zxf softether-vpnserver-v4.24-9651-beta-2017.10.23-linux-x64-64bit.tar.gz
# cd vpnserver/
# make

cd ..
mv vpnserver/ /usr/local/
cd /usr/local/vpnserver

chmod 600 *
chmod 700 vpnserver
chmod 700 vpncmd
vpnserver 啟動腳本; /etc/init.d/vpnserver
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
#!/bin/sh
# chkconfig: 2345 99 01
# description: SoftEther VPN Server
DAEMON=/usr/local/vpnserver/vpnserver
LOCK=/var/lock/subsys/vpnserver
test -x $DAEMON || exit 0
case "$1" in
start)
$DAEMON start
touch $LOCK
;;
stop)
$DAEMON stop
rm $LOCK
;;
restart)
$DAEMON stop
sleep 3
$DAEMON start
;;
*)
echo "Usage: $0 {start|stop|restart}"
exit 1
esac
exit 0
- 在啟動 vpnserver 之前 ,先使用vpncmd check 系統狀態 選擇 3 , 打上 check 指令。
1
2
3
4
cd /usr/local/vpnserver
./vpncmd

VPN Tools>check
- 更改權限,設定開機啟動及啟動 vpnserver
1
2
3
chmod a+x /etc/init.d/vpnserver
chkconfig --add vpnserver
/etc/init.d/vpnserver start
- 建立一個 Virtual Hub 名為 Taichung , 並切換到該 Virtual Hub
1
2
VPN Server>hubcreate Taichung
VPN Server>hub Taichung
- 設定使用者帳號及密碼 ; VPN Server 與 bridge 建立聯結(Cascade)時需要的
1
2
VPN Server/Taichung>usercreate amy
VPN Server/Taichung>userpasswordset amy
- show virtual hub list
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
VPN Server/Taichung>hublist
HubList 命令 - 获取一个虚拟 HUB 列表
项目 |价值
------------+-------------------
虚拟 HUB 名 |DEFAULT
状态 |在线
类型 |独立
用户 |0
组 |0
会话 |0
MAC 表 |0
IP 表 |0
登录次数 |0
最后登录时间|2017-12-16 15:45:32
最后通信时间|2017-12-16 15:45:32
传输字节 |0
传输数据包 |0
------------+-------------------
虚拟 HUB 名 |Taichung
状态 |在线
类型 |独立
用户 |1
组 |0
会话 |0
MAC 表 |0
IP 表 |0
登录次数 |0
最后登录时间|2017-12-16 15:51:59
最后通信时间|2017-12-16 15:51:59
传输字节 |0
传输数据包 |0
命令成功完成。
- 建立 local bridge 。 將 此Lab的 eth1 加入 local bridge , 再將 local bridge 加入到 virtual hub 使用 bridgecreate 指令。
1
2
3
VPN Server/Taichung>bridgecreate Taichung
BridgeCreate 命令 - 创建本地的网桥连接
目标网桥的设备名称: eth1
- 看local bridge 狀態
1
2
3
4
5
VPN Server/Taichung>bridgelist
BridgeList 命令 - 获得当地网桥连接列表
编号|虚拟 HUB 名称|网络适配器或 tap 设备名称|状态
----+-------------+-------------------------+------
1 |Taichung |eth1 |运行中

架設DHCP Server

架構圖中有一台DHCP Server,主要驗證整個環境的應用;DHCP Server 發出的廣播封包是否可到達廣域網路的另一端。
  • 此台機器 先忽略 防火牆防護
    1
    iptables -F
  • 安裝 dnsmasq
    1
    # yum instal dnsmasq
  • 設定 dnsmasq ; /etc/dnsmasq.conf
    1
    2
    3
    4
    5
    6
    7
    8
    port=
    dhcp-leasefile=/tmp/dnsmasq.leases
    interface=eth1
    dhcp-range=192.168.11.101,192.168.11.115,12h
    dhcp-option=1,255.255.255.0 #subnet mask
    dhcp-option=28,192.168.11.255 #broadcast
    dhcp-option=3,192.168.11.250 #default gateway
    dhcp-option=6,192.168.11.251 #DNS
  • 啟動 dnsmasq
    1
    /etc/init.d/dnsmasq start

安裝SoftEther VPN bridge及配

- 安裝SoftEther VPN bridge
1
2
3
4
5
6
7
8
9
10
11
# cd /usr/local/src/
# wget http://www.softether-download.com/files/softether/v4.24-9651-beta-2017.10.23-tree/Linux/SoftEther_VPN_Bridge/32bit_-_Intel_x86/softether-vpnbridge-v4.24-9651-beta-2017.10.23-linux-x86-32bit.tar.gz
# tar zxf softether-vpnbridge-v4.24-9651-beta-2017.10.23-linux-x86-32bit.tar.gz
# cd vpnbridge
# make
# cd ..
# mv vpnbridge/ /usr/local/
# cd /usr/local/vpnbridge/
# chmod 600 *
# chmod 700 vpnserver
# chmod 700 vpncmd
- 建立 vpn bridge 啟動檔; /etc/init.d/vpnbridge
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
#!/bin/sh
# chkconfig: 2345 99 01
# description: SoftEther VPN Server
DAEMON=/usr/local/vpnbridge/vpnbridge
LOCK=/var/lock/subsys/vpnbridge
test -x $DAEMON || exit 0
case "$1" in
start)
$DAEMON start
touch $LOCK
;;
stop)
$DAEMON stop
rm $LOCK
;;
restart)
$DAEMON stop
sleep 3
$DAEMON start
;;
*)
echo "Usage: $0 {start|stop|restart}"
exit 1
esac
exit 0
- 在啟動 vpnbridge 之前 ,先使用vpncmd check 系統狀態 選擇 3 , 打上 check 指令。 與上一節vpnserver 一樣。 - 更改權限,設定開機啟動及啟動 vpnbridge
1
2
3
chmod a+x /etc/init.d/vpnbridge  
chkconfig --add vpnbridge
/etc/init.d/vpnbridge start
- 開始配置設定。 執行 /usr/local/vpnbridge/vpncmd
1
2
3
# /usr/local/vpnbridge/vpncmd
選擇1
不用填寫 目标 IP 地址的主機名 , 指定虚擬 HUB 名稱 ,按 Enter 直接略過。
- SoftEther bridge 預設已 建立 名為 bridge 的 virtual hub ,直接建立 local bridge - show virtual hub list
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
VPN Server>hublist
HubList 命令 - 获取一个虚拟 HUB 列表
项目 |价值
------------+-------------------
虚拟 HUB 名 |BRIDGE
状态 |在线
类型 |独立
用户 |0
组 |0
会话 |2
MAC 表 |5
IP 表 |4
登录次数 |0
最后登录时间|2017-12-16 16:24:36
最后通信时间|2017-12-16 18:05:06
传输字节 |3,665,196
传输数据包 |39,112
命令成功完成。
- 建立 local bridge 。 將 此Lab的 eth1 加入 local bridge , 再將 local bridge 加入到 virtual hub
1
2
3
4
5
VPN Server>bridgecreate 
BridgeCreate 命令 - 创建本地的网桥连接
网桥虚拟 HUB 名称: bridge

目标网桥的设备名称: eth1
1
2
3
4
5
6
VPN Server>bridgelist
BridgeList 命令 - 获得当地网桥连接列表
编号|虚拟 HUB 名称|网络适配器或 tap 设备名称|状态
----+-------------+-------------------------+------
1 |bridge |eth1 |运行中
命令成功完成。

串接

上面SoftEther VPN Server 與 Bridge 各自已安裝完成及設定好,現在要執行將 softEther Bridge 與 SoftEther Server 做串接(Cascade)。 - 在SoftEther Bridge那一台 執行 vpncmd
1
2
# /usr/local/vpnbridge/vpncmd
選擇1
- 交換到 virtual hub 為 bridge
1
VPN Server>hub bridge
- 建立聯結名稱為 VPN , 設定 VPN Server 為 192.168.88.62:443 , VPN Server 的 虛擬 HUB 為 Taichung, 及 設定聯結的使用者為 amy (在VPN server 階段建立的)
1
2
3
4
5
6
7
VPN Server/BRIDGE>cascadecreate
CascadeCreate 命令 - 创建一个新的级联接续
级联接续的名称: VPN
目标 VPN Server 的主机名和端口号: 192.168.88.62:443
目标虚拟 HUB 名称: Taichung
连接使用的用户名: amy
命令成功完成。
- 指令為「cascadepasswordset」,並輸入串接連結名稱為「VPN」,接著輸入之前在VPN Server設定的使用者密碼,最後選擇使用「standard」
1
2
3
4
5
6
7
8
9
VPN Server/BRIDGE>cascadepasswordset VPN
CascadePasswordSet 命令 - 将级联连接时所需的用户验证设置为密码验证
请输入密码。要取消,请按下 Ctrl + D 键。

密码 : **********
确认输入: **********

指定 standard 或者 radius: standard
命令成功完成。
- 執行 cascadeonline 指令 進行串接
1
2
3
VPN Server/BRIDGE>cascadeonline VPN
CascadeOnline 命令 - 设置级联接续的在线状态
命令成功完成。
- 執行 cascadestatusget 指令獲取串接狀態
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
VPN Server/BRIDGE>cascadestatusget
CascadeStatusGet 命令 - 获取级联的当前状态
级联接续的名称: VPN

项目 |价值
-------------------+----------------------------------------
VPN 连接设置名称 |VPN
会话状态 |连接完成 (会话建立)
VLAN ID |-
服务器名 |192.168.88.62
端口号 |TCP 端口 443
服务端产品名称 |SoftEther VPN Server (32 bit)
服务端版本 |4.24
服务端内部标号 |Build 9651
连接开始时间 |2017年12月16日(星期六) 16点41分 7秒
首次会话建立时间 |2017年12月16日(星期六) 16点41分 7秒
当前会话建立时间 |2017年12月16日(星期六) 16点41分 7秒
已建立的会话数 |1 次
半双工 TCP 连接模式|否 (全双工模式)
VoIP / QoS 功能 |已启用
TCP 连接数 |8
TCP 连接数最大值 |8
加密 |已启用 (算法: AES128-SHA)
使用压缩 |否 (不压缩)
物理底层协议 |Standard TCP/IP (IPv4)
支持 UDP 加速 |是
UDP 加速已激活 |是
会话名 |SID-AMY-2
连接名 |CID-4
会话密钥 (160 位) |DDA3FED7FFCAC795C104C4CFC2982876AAE506E7
网桥 / 路由模式 |是
监测模式 |否
输出数据量 |4,947 字节
输入数据量 |4,998 字节
传出单播数据包 |3 数据包
传出单播总量 |180 字节
传出广播数据包 |6 数据包
传出广播总量 |502 字节
传入单播数据包 |3 数据包
传入单播总量 |126 字节
传入广播数据包 |0 数据包
传入广播总量 |0 字节
命令成功完成。

Client端驗證

開啟client 端, 將網路設定DHCP 。重新整理網路,看是否有抓到192.168.11.x 這個網段的IP

參考資料

KVM install

KVM 全名為 Kernel-Based Virtual Machine,是一個用於Linux核心中的虛擬化基礎設施。
本單元主要演示安裝KVM過程,主要利用VMware Esxi 平台建立Netsed hypervisors環境,即是 在 Esxi 平台建立一個 虛擬機 ,在此虛擬機安裝KVM ,再由kvm 建立一台虛擬機。

環境需求

  • 實體機的 CPU 需支持 Intel (Intel Virtualization Technology, Intel VT-x); AMD (AMD Secure Virtual Machine, AMD)
  • VMware ESXi 5 或 6
  • Ubuntu 16.04 Desktop LTS ,下載點

步驟

  1. 在esxi 平台上建立虛擬機,主要關鍵,勾選硬體虛擬化項目向Guest OS 公開硬體協助虛擬化,此操作可以在 ESXi Web Client or ESXi Host Client下完成。
    如圖示說明
  2. 網路部分,需要將VSS Security Policies的Promiscuous mode 設為允許。此功能相當於HUB,將port 收到的封包,會廣播向其它的Port傳送
    Promiscuous mode

3.之後,虛擬機安裝OS ,Ubuntu 16.04 Desktop LTS
4.之後,安裝完OS。先確定以下項目,每項都必須確認無誤後,才能做下一步

  • VM是否支援CPU虛擬化
    1
    grep -E -i 'vmx|svm' /etc/cpuinfo
  • 確認kvm是否安奘
    1
    2
    apt-get install cpu-checker
    kvm-ok
  • 確認是否有載入KVM 相關模組
    1
    lsmod|grep kvm
  1. 安裝 libvirt,及看使用者(這邊以 andy)是否在指定群組
    1
    2
    apt-get install qemu-kvm libvirt-bin
    grep andy /etc/group
    1
    2
    3
    4
    5
    6
    7
    8
    9
    adm:x:4:syslog,andy
    cdrom:x:24:andy
    sudo:x:27:andy
    dip:x:30:andy
    plugdev:x:46:andy
    lpadmin:x:113:andy
    andy:x:1000:
    sambashare:x:128:andy
    libvirtd:x:130:andy
  2. 安裝 virt-manager , bridge-utils
    1
    apt-get install virt-manager bridge-utils
  3. 開始執行virt-manager 建立虛擬機,會跳出以下圖示
    1
    $ sudo virt-manager
    virt-manager

    參考資料

Flask Config 載入方式

Flask config 內建變數很多,可以參考 官方Builtin Configuration Values,中文翻譯可以參考內置的配置值,這裡用DEBUG這個變數說明Config載入方。

以簡單程式碼為範例說明

預設沒有指定DEBUG是表False,不開啟程式debug模式。

1
2
3
4
5
6
7
8
from flask import Flask
app=Flask(__name__)
@app.route('/')
def index():
return '<center><h1>Hello World</h1></center>'

if __name__ == '__main__':
app.run()

執行之後可以看到 ,預設沒有debug模式。
Flask_NO_Debug

若有開啟debug模式,如下:
Flask_Debug

  • 以陣列方式(寫在code裡)
    1
    2
    3
    4
    5
    from flask import Flask
    app=Flask(__name__)
    ...略...
    app.config["DEBUG"]=True
    ...略...
  • 加入參數到app.run() (寫在code裡)
    1
    2
    3
    4
    5
    from flask import Flask
    app=Flask(__name__)
    ..略..
    if __name__ == '__main__':
    app.run(debug=True)
  • 以傳入模組物件方式 (寫在code裡)
    1
    2
    3
    4
    5
    6
    from flask import Flask
    app=Flask(__name__)
    ...略...
    DEBUG=True
    app.config.from_object(__name__)
    ...略...
  • 以傳入模組物件方式 (寫在另一個檔案裡;config.py)
    config.py
    1
    DEBUG=True
    1
    2
    3
    4
    5
    from flask import Flask
    app=Flask(__name__)
    ...略...
    app.config.from_object('config')
    ...略...
    或是也可這樣表示
    1
    2
    3
    4
    5
    6
    from flask import Flask
    import config
    app=Flask(__name__)
    ...略...
    app.config.from_object('config')
    ...略...
  • 透過檔案名稱方式載入
    1
    2
    3
    4
    5
    from flask import Flask
    app=Flask(__name__)
    ...略...
    app.config.from_pyfile('config.py')
    ...略...
  • 透過系統的環境變數載入
    1
    # export tt='config.py'
1
2
3
4
5
from flask import Flask
app=Flask(__name__)
...略...
app.config.from_envvar('tt')
...略...

參考資料

Browser自動化測試工具Selenium - Selenium 初體驗

前言

前幾天與Software部門在進行測試網站某個功能性(每秒瀏灠一次網頁,共進行100次,查看第幾次開始得到http status code:403),因為我們部門長期都是使用Command-Line工作,因此為了方便用Shell Script簡單寫一個測試程式,測試結果與software部們不相同,了解之後,才知道他們是使用Browser 用手點方式測試。為了雙方測試環境一致性及客觀地顯示測試數據,本人有一個想法是否有支援程序化工具來控制Firefox或Chrome,經Google之後,很多網路上都推薦使用 Selenium,這項自動化測試工具。

建置selenium環境

  • 這邊範例使用 Windows 系統(win7 或 Win10 都可)
  • 這邊範例使用Python語言,Windows 預設沒有安裝Python,需要下載Python,選擇對應平台(x86 或 x86_64),下載後,執行下一步下一步的安裝方式,這邊就不展示。
  • 開啟命令提示字元, 打上 py 或 python,有跑出類似以下畫面表示python 安裝成功。
    py_windows
  • 安裝selenium。預設python 3 已有pip安裝python 第三方套件管理程式。
    1
    pip install selenium
  • 分別下載Firefox及Chrome的webdriver,為了方便使用,下載完放置在c:\

簡單執行自動執行Chrome

  • chromeDemo.py
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    from selenium import webdriver
    import time
    chrome_path="c:\chromedriver.exe"
    web=webdriver.Chrome(chrome_path)
    web.set_window_position(0,0)
    web.set_window_size(700,700)
    web.get('http://www.google.com')
    print(web.current_url)
    time.sleep(15)
    web.close()
  • 在命令提示字元 執行 chromeDemo.py
    1
    c:\>py chromeDemo.py

    簡單執行自動執Firefox

  • firefoxdemo.py
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    from selenium import webdriver
    from selenium.webdriver.common.keys import Keys
    from selenium.webdriver.common.action_chains import ActionChains
    import time
    Firefox_path="c:\geckodriver.exe"
    web=webdriver.Firefox(executable_path=Firefox_path)
    web.set_window_position(0,0)
    web.set_window_size(700,700)
    ActionChains(web).key_down(Keys.F12).key_up(Keys.F12).perform()
    web.get('http://www.google.com')
    print(web.current_url)
    time.sleep(15)
    web.close()
  • 在命令提示字元 執行 firefoxdemo.py
    1
    c:\>py firefoxdemo.py

    範例 - 持續點擊某個網址

    以下使用chrome drive 來開啟Chrome Browser,並設定 Proxy相關設定(這邊我的內網有一台proxy: http://192.168.160.17:8082)之後,每隔1秒持續點擊 ifconfig.io
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    from selenium import webdriver
    import time
    PROXY='http://192.168.160.17:8082'

    webdriver.DesiredCapabilities.CHROME['proxy']={
    "httpProxy": PROXY,
    "ftpProxy": PROXY,
    "sslProxy": PROXY,
    "proxyType": "MANUAL",
    }
    chrome_path="./chromedriver.exe"
    with webdriver.Chrome(chrome_path) as web:
    web.set_window_position(0,0)
    web.set_window_size(700,700)
    for i in range(1,11):
    web.get('http://ifconfig.io')
    print('{}, URL: {}'.format(i,web.current_url))
    time.sleep(1)

    影片展示自動執行Firefox及Chrome

  • for Firefox
  • for Chrome

    參考資料

  • 英文-SeleniumHQ-官方
  • 英文-Selenium_Http proxies
  • Selenium with Python中文翻譯文檔
  • Python Selenium 常用方法總結
  • [Python] 使用Selenium在Google Chrome瀏覽器
  • [Python] Selenium 教學
  • 在Chrome上面使用Selenium WebDriver
  • Python爬蟲新手筆記