Jex’s Note

設定無線網路

安裝 wpa client

sudo apt-get install wireless-tools wpasupplicant

掃描無線網路

sudo iwlist wlan0 scan | grep SSID
                    ESSID:"hinet-net4690695"
                    ESSID:"BUFFALO-E05EE0"
                    ESSID:"BUFFALO-E05EE0-1"
                    ESSID:"kking22"
                    ESSID:"TP-LINK_5499B2"
                    ESSID:"HTC ONE X - Jex"
                    ESSID:"P880"

等等要將 SSID 填入 /etc/network/interfaces wpa-ssid 的值

新增 /etc/network/interfaces :

auto lo
iface lo inet loopback

auto eth0
iface eth0 inet dhcp


auto wlan0
allow-hotplug wlan0
iface wlan0 inet dhcp
wpa-ssid My-Hone-Wireless
wpa-psk My-Password
  • SSID 就是無線網路的名稱
  • WPA-PSK金鑰 就是無線網路的密碼

重新啟動無線網路介面

sudo ifdown wlan0
sudo ifup wlan0

成功連線的結果 :

pi@raspbmc:~$ sudo ifdown wlan0
ifdown: interface wlan0 not configured
pi@raspbmc:~$ sudo ifup wlan0
ioctl[SIOCSIWAP]: Operation not permitted
ioctl[SIOCSIWENCODEEXT]: Invalid argument
ioctl[SIOCSIWENCODEEXT]: Invalid argument
Internet Systems Consortium DHCP Client 4.2.2
Copyright 2004-2011 Internet Systems Consortium.
All rights reserved.
For info, please visit https://www.isc.org/software/dhcp/

Listening on LPF/wlan0/00:0b:81:84:7a:17
Sending on   LPF/wlan0/00:0b:81:84:7a:17
Sending on   Socket/fallback
DHCPDISCOVER on wlan0 to 255.255.255.255 port 67 interval 4
DHCPDISCOVER on wlan0 to 255.255.255.255 port 67 interval 11
DHCPREQUEST on wlan0 to 255.255.255.255 port 67
DHCPOFFER from 192.168.1.1
DHCPACK from 192.168.1.1
Reloading /etc/samba/smb.conf: smbd only.
bound to 192.168.1.10 -- renewal in 38644 seconds.

以下是我實體網路線及無線網路都有連線的結果

pi@raspbmc:~$ ifconfig
eth0      Link encap:Ethernet  HWaddr b8:27:eb:7e:6e:3f
          inet addr:192.168.1.236  Bcast:192.168.1.255  Mask:255.255.255.0
          inet6 addr: fe80::ba27:ebff:fe7e:6e3f/64 Scope:Link
          UP BROADCAST RUNNING MULTICAST  MTU:1500  Metric:1
          RX packets:3168 errors:0 dropped:0 overruns:0 frame:0
          TX packets:2190 errors:0 dropped:0 overruns:0 carrier:0
          collisions:0 txqueuelen:1000
          RX bytes:443833 (433.4 KiB)  TX bytes:375591 (366.7 KiB)

lo        Link encap:Local Loopback
          inet addr:127.0.0.1  Mask:255.0.0.0
          inet6 addr: ::1/128 Scope:Host
          UP LOOPBACK RUNNING  MTU:65536  Metric:1
          RX packets:8 errors:0 dropped:0 overruns:0 frame:0
          TX packets:8 errors:0 dropped:0 overruns:0 carrier:0
          collisions:0 txqueuelen:0
          RX bytes:480 (480.0 B)  TX bytes:480 (480.0 B)

wlan0     Link encap:Ethernet  HWaddr 00:0b:81:84:7a:17
          inet addr:192.168.1.10  Bcast:192.168.1.255  Mask:255.255.255.0
          inet6 addr: fe80::20b:81ff:fe84:7a17/64 Scope:Link
          UP BROADCAST RUNNING MULTICAST  MTU:1500  Metric:1
          RX packets:28 errors:0 dropped:2179 overruns:0 frame:0
          TX packets:51 errors:0 dropped:3 overruns:0 carrier:0
          collisions:0 txqueuelen:1000
          RX bytes:31439 (30.7 KiB)  TX bytes:36803 (35.9 KiB)

其他

如果將無線網路登入設定寫在 interfaces 裡面的一些設定寫法

/etc/network/interfaces 的寫法 :

wpa-scan-ssid 1
wpa-ap-scan 1
wpa-key-mgmt WPA-PSK
wpa-proto RSN WPA
wpa-pairwise CCMP TKIP
wpa-group CCMP TKIP
wpa-ssid "My Secret SSID"
wpa-psk "My SSID PSK"

另外一種連線設定, 使用 wpa_supplicant

/etc/network/interfaces :

auto lo

iface lo inet loopback
iface eth0 inet dhcp

allow-hotplug wlan0
iface wlan0 inet manual
wpa-roam /etc/wpa_supplicant/wpa_supplicant.conf
iface default inet dhcp

/etc/wpa_supplicant/wpa_supplicant.conf 新增(沒有的話建立)

完整寫法 :

ctrl_interface=DIR=/var/run/wpa_supplicant GROUP=netdev
update_config=1

network={
  ssid="wireless_1"                                                     // 無線網路的名稱
  #scan_ssid=1
  proto=WPA RSN
  key_mgmt=WPA-PSK
  pairwise=CCMP TKIP
  group=CCMP TKIP
  psk=ec8cdd1c0aa2ebcc6564ee81587ebad81e4a39ebf6c4265e3f931175e3926c5b  // 無線網路的密碼(加密後) 寫法1
  # psk="my_password"   // 無線網路的密碼(未加密) 寫法2
}

偷懶寫法 :

network={
  ssid="TP-LINK_34403E"
  psk="2734403E"
  id_str="home"
}
network={
  ssid="jx"
  psk="00000000"
  id_str="my mobile"
}

不將明碼打在設定檔上, 使用加密後的密碼在設定檔裡較為安全

$ wpa_passphrase jex_ssid jex_password
network={
        ssid="jex_ssid"
        #psk="jex_password"
        psk=fce88e792dea2299472529eea209012a812cda28cbbf540e2a55d45be98988d0
}

加密協定

  • TKIP 與 CCMP 為安全加密協定
  • 有些無線網路設備以 AES 或 AES-CCMP 來表示 CCMP
  • AES 效能更好, 主流, 安全, 美國主推, 在 wifi 上用來取代 TKIP, 雙向加密解密

監聽封包

Tcpdump

監聽封包

sudo tcpdump -i lo -nn port 8080
13:45:48.703124 IP 127.0.0.1.42893 > 127.0.0.1.8080: Flags [S], seq 2569649818, win 43690, options [mss 65495,sackOK,TS val 2431608 ecr 0,nop,wscale 6], length 0
13:45:48.703130 IP 127.0.0.1.8080 > 127.0.0.1.42893: Flags [S.], seq 986657362, ack 2569649819, win 43690, options [mss 65495,sackOK,TS val 2431608 ecr 2431608,nop,wscale 6], length 0
13:45:48.703137 IP 127.0.0.1.42893 > 127.0.0.1.8080: Flags [.], ack 1, win 683, options [nop,nop,TS val 2431608 ecr 2431608], length 0
13:45:48.703572 IP 127.0.0.1.42893 > 127.0.0.1.8080: Flags [P.], seq 1:29, ack 1, win 683, options [nop,nop,TS val 2431608 ecr 2431608], length 28
13:45:48.703580 IP 127.0.0.1.8080 > 127.0.0.1.42893: Flags [.], ack 29, win 683, options [nop,nop,TS val 2431608 ecr 2431608], length 0
13:45:48.703824 IP 127.0.0.1.42893 > 127.0.0.1.8080: Flags [P.], seq 29:39, ack 1, win 683, options [nop,nop,TS val 2431608 ecr 2431608], length 10
13:45:48.703830 IP 127.0.0.1.8080 > 127.0.0.1.42893: Flags [.], ack 39, win 683, options [nop,nop,TS val 2431608 ecr 2431608], length 0
13:45:48.704009 IP 127.0.0.1.42893 > 127.0.0.1.8080: Flags [F.], seq 39, ack 1, win 683, options [nop,nop,TS val 2431609 ecr 2431608], length 0
13:45:48.743612 IP 127.0.0.1.8080 > 127.0.0.1.42893: Flags [.], ack 40, win 683, options [nop,nop,TS val 2431619 ecr 2431609], length 0
  • -i :後面接要『監聽』的網路介面,例如 eth0, lo, ppp0 等等的介面;
  • -nn:直接以 IP 及 port number 顯示,而非主機名與服務名稱

監聽封包內容

sudo tcpdump -i lo -nn port 8080 -X
(...略...)
13:42:53.139609 IP 127.0.0.1.8080 > 127.0.0.1.42892: Flags [.], ack 40, win 683, options [nop,nop,TS val 2387718 ecr 2387708], length 0
        0x0000:  4500 0034 f30e 4000 4006 49b3 7f00 0001  E..4..@.@.I.....
        0x0010:  7f00 0001 1f90 a78c 0cc5 9df7 37a2 5c73  ............7.\s
        0x0020:  8010 02ab fe28 0000 0101 080a 0024 6f06  .....(.......$o.
        0x0030:  0024 6efc                                .$n.

-X :可以列出十六進位 (hex) 以及 ASCII 的封包內容,對於監聽封包內容很有用

監聽 post, 並且輸出成好閱讀模式

sudo tcpdump -s 0 -A 'tcp dst port 80 and (tcp[((tcp[12:1] & 0xf0) >> 2):4] = 0x504f5354)' -i eth0
(...略...)
E....   @.@..8..Of6......P.N$.Y...P..:....POST /oauth/authorize?client_id=a216481c HTTP/1.1
User-Agent: curl/7.22.0 (x86_64-pc-linux-gnu) libcurl/7.22.0 OpenSSL/1.0.1 zlib/1.2.3.4 libidn/1.23 librtmp/2.3
Host: example.com
Accept: */*
Content-Length: 8
Content-Type: application/x-www-form-urlencoded

(tcp[((tcp[12:1] & 0xf0) >> 2):4] = 0x504f5354) 是監聽 post 的意思

如何使用 tcpdump 監聽 (1)來自 eth0 介面卡且 (2)通訊協定為 port 22 ,(3)封包來源為 192.168.1.101 的封包資料?

tcpdump -i eth0 -nn 'port 22 and src host 192.168.1.101'

Ngrep

聽 GET/POST/PUT 80 port

sudo ngrep -W byline -d eth0 -t '^(GET|POST|PUT)' 'port 80'

聽 GET/POST/PUT 特定 host 的 80 port

sudo ngrep -d eht0 -t '^(GET|POST|PUT)' "src host example.com and port 80"

聽 GET/POST/PUT 特定 host 的 80 port, TCP 協定

sudo ngrep -t '^(GET|POST|PUT)' "src host example.com and tcp and dst port 80"

其他

ref: ngrep cheat sheet

Print udp packets

ngrep '' udp

Print packets passing eth0 device. Without -d ngrep listens to a default interface. ngrep -d eth0 Print packets for port 80 regardless of device

ngrep -d any port 80

Only print packets that contain “interesting-domain.com”

ngrep -d any “interesting-domain.com” port 80

You can use regex such as ‘.*’ in the search string

ngrep -d any “domain-.*.com” port 80

Or use regex to search for ‘pass’ or ‘USER’

ngrep -d any “pass|USER” port 80

And ignore case with -i to match for ‘user’ as well

ngrep -d any -i “pass|USER” port 80

If you’re logged in via SSH you might want to ignore your own traffic

ngrep -d any port not 22

Only print packet headers and payload (if relevant)

ngrep -q -d any “needle” port 80

Use -W byline for more readable output

ngrep -d any -W byline “needle” port 80

Limit the number of results with -n

ngrep -d any “needle” -n 3 port 80

Print empty packets with -e

ngrep -e -d any “needle” port 80

Xargs 指令

介紹

build and execute command lines from standard input

用法

假設有個檔案結構如下 :

$ tree test
test
├── c1
│   ├── ii.del
│   └── pp.ext
├── c2
│   ├── gg.del
│   └── hh.ext
└── c3
    ├── c3-1
    │   ├── qq.del
    │   └── xx.ext
    ├── cc.ext
    └── ff.del

4 directories, 8 files

如果我要刪除 test 下所有 *.del 的檔案

找出 *.del

$ find test -name "*.del"
test/c3/ff.del
test/c3/c3-1/qq.del
test/c2/gg.del
test/c1/ii.del

加上 xargs 指令, 可以一次幫你把找到的結果刪除

$ find test -name "*.del" | xargs rm

如果前面 find 那邊沒有任何結果輸出會出現錯誤訊息

rm: missing operand
Try 'rm --help' for more information.

可加上 --no-run-if-empty 來避免 :

$ find test -name "*.del" | xargs --no-run-if-empty rm

--no-run-if-empty or -r : If the standard input does not contain any nonblanks, do not run the command. Normally, the command is run once even if there is no input. This option is a GNU extension.

將筆對到的字串暫存成符號供取代使用, linux supports -i, mac supports -I

mac

redis-cli KEYS "user:???" | xargs -I@ redis-cli HSET @ field1 1

linux

redis-cli KEYS "user:???" | xargs -i@ redis-cli HSET i field1 1

Add file extension

$ tree .
.
├── cc
└── qq

$ ls | xargs -I file mv file file.txt && ls
cc.txt  qq.txt

不用 xargs 且達到一樣效果 :

$ for i in `ls`;do mv $i ${i}.txt; done && ls
cc.txt  qq.txt
  • xargs :
  • -I replace-str
  •  Replace occurrences of replace-str in the initial-arguments with names read from  standard  input.
    
  •  Also,  unquoted  blanks  do  not  terminate  input  items;  instead  the  separator is the newline
    
  •  character.  Implies -x and -L 1.
    

Change file extension

change xxx.thml -> xxx.txt

ls | grep html | sed 's/.html//g' | xargs -I file mv file.html file.txt

Add prefix

ls | xargs -I {FILE} mv {FILE} prefix_{FILE}

{FILE} 是自訂讓 xargs 辨識用的變數名稱

Example

將指到的檔都刪除

find -name "*.bak" | xargs rm

如果沒有找到也不要噴出錯誤訊息

find -name "*.bak" | xargs --no-run-if-empty rm

ref : http://blog.yam.com/ddy1280/article/13941218

Nmap 指令

介紹

有時候你想知道該網域下有哪些 ip 正在使用或有哪些 port 是開放的, 就可以使用 nmap 來檢查

安裝

ubuntu :

sudo apt-get install nmap

使用

假如已經有確定的 port 想知道是否開放可直接用 telnet nc

telnet xxx.oo 8010

$ nc -zv test-db.c6c8mn7tsdgv0.us-west-2.rds.amazonaws.com 3306
Connection to test-db.c6c8mn7tsdgv0.us-west-2.rds.amazonaws.com 3306 port [tcp/mysql] succeeded!
  • -z: Specifies that nc should just scan for listening daemons, without sending any data to them. It is an error to use this option in conjunction with the -l option.
  • -v: Have nc give more verbose output.

-sP 掃網段下有使用的 ip

nmap -sP 192.168.1.0/24

or

nmap -sP 192.168.1.1-254

-sT : TCP connect 掃描(Port Scanning)

這是對 TCP 的最基本形式的偵測,直接連到目標主機進行埠掃描並完成一個完整的三次交握過程 (SYN, SYN/ACK, ACK),但因為服務器接受了一個連接但它卻馬上斷開,於是其記錄會顯示出一連串的連接及錯誤資訊很容易被目標主電腦察覺並記錄下來,因此缺點是容易被目標系統檢測到。

$ nmap -sT 10.0.2.15

Starting Nmap 6.00 ( http://nmap.org ) at 2013-12-15 18:12 CST
Nmap scan report for 10.0.2.15
Host is up (0.00024s latency).
Not shown: 996 closed ports
PORT     STATE SERVICE
80/tcp   open  http
139/tcp  open  netbios-ssn
445/tcp  open  microsoft-ds
2222/tcp open  EtherNet/IP-1

Nmap done: 1 IP address (1 host up) scanned in 0.12 seconds

-sU : UDP掃描 (UDP Scanning)

可用來確定遠端主機開放哪些 UDP Port 原理為送出零位元組的 UDP 封包到目標主機的各連接埠,如果我們收到一個 ICMP port unreachable 無法到達的回應則可確定連接埠是關閉的,否則我們可認為該埠是打開的。

$ sudo nmap -sU 10.0.2.15

Starting Nmap 6.00 ( http://nmap.org ) at 2013-12-15 18:24 CST
Nmap scan report for 10.0.2.15
Host is up (0.0000060s latency).
Not shown: 997 closed ports
PORT    STATE         SERVICE
68/udp  open|filtered dhcpc
137/udp open          netbios-ns
138/udp open|filtered netbios-dgm

Nmap done: 1 IP address (1 host up) scanned in 1.28 seconds

-sS : TCP SYN(半公開)掃描

這種掃描技術也叫半公開式掃描 (half-open scanning),因為它沒有完成一個完整的 TCP 連接三次交握過程。此方法為向目標 Port 發送一個 SYN 封包,如果目標 Port 回應 SYN / ACK 封包則表示該 Port 處於打開狀態;若回應的是 RST / ACK 封包則表示該 Port 為關閉狀態。這種掃描方法比 TCP Connect Scan 更具隱蔽性,只有極少數的網站會對它作出記錄因此比較不會在目標系統中留下掃描痕跡。

sudo nmap -sS 10.0.2.15

Starting Nmap 6.00 ( http://nmap.org ) at 2013-12-15 18:16 CST
Nmap scan report for 10.0.2.15
Host is up (0.0000060s latency).
Not shown: 996 closed ports
PORT     STATE SERVICE
80/tcp   open  http
139/tcp  open  netbios-ssn
445/tcp  open  microsoft-ds
2222/tcp open  EtherNet/IP-1

Nmap done: 1 IP address (1 host up) scanned in 0.08 seconds

-sF -sX -sN : Stealth FIN、Xmas Tree或 NULL秘密掃描(Stealth Scanning)

一些防火墻及 Packet 過濾裝置會在重要連接 Port 守護,半公開的 SYN 封包掃描會在此時會被截獲因此要有更秘密的進行掃描;而 FIN、Xmas、NULL 掃描方法則是關閉的連接埠會對你送出的探測資訊包返回一個 RST,而打開的連接埠則對其忽略不理可參考 [RFC793],其中 FIN 掃瞄使用空的 FIN 資訊包作為探針、Xmas tree 使用 FIN、URG、PUSH 標記、Null 掃描則不用任何標記,但微軟不支援此一標準,所以 -sF,-sX,-sN 的掃瞄顯示所有連接埠都是關閉的但一個 SYN(-sS) 掃瞄卻顯示有打開連接埠,那你就能大致推斷它是 WINDOWS 平台。

$ sudo nmap -sF 10.0.2.15

Starting Nmap 6.00 ( http://nmap.org ) at 2013-12-15 18:19 CST
Nmap scan report for 10.0.2.15
Host is up (0.0000060s latency).
Not shown: 996 closed ports
PORT     STATE         SERVICE
80/tcp   open|filtered http
139/tcp  open|filtered netbios-ssn
445/tcp  open|filtered microsoft-ds
2222/tcp open|filtered EtherNet/IP-1

Nmap done: 1 IP address (1 host up) scanned in 1.27 seconds

-sF -sX -sN 三個指令的結果一樣

-sP ICMP 掃描 (Ping Sweeping)

若僅想了解網路上有哪些主電腦是開放的,你可對你指定的IP地址送出一個 ICMP 的 Echo Request 封包來偵測。但有些站台會把 ICMP 的 Echo Request 封包給關掉 (例如Microsoft.com)。在這種情況下可利用發送 TCP Ping 送一個 ACK 到目標網路上的每個主機。網路上的主機如果在線,則會返回一個 TCP RST 響應。使用帶有 Ping 掃描的 TCP Ping 選項,也就是 -PT 選項可以對網絡上指定 Port 進行掃描,它將可能通過目標邊界路由器甚至是防火牆。注意,被探測的主機上的目標 Port 無須打開,關鍵取決於是否在網路上。

$ sudo nmap -sP 10.0.2.15

Starting Nmap 6.00 ( http://nmap.org ) at 2013-12-15 18:23 CST
Nmap scan report for 10.0.2.15
Host is up.
Nmap done: 1 IP address (1 host up) scanned in 0.02 seconds

-sL : 列出子網路所有IP及對應的主機名稱

$ sudo nmap -sL 10.0.2.15

Starting Nmap 6.00 ( http://nmap.org ) at 2013-12-15 18:29 CST
Nmap scan report for 10.0.2.15
Nmap done: 1 IP address (0 hosts up) scanned in 0.03 seconds

-PS : 偵測遠端主機已開啟的通訊埠

$ sudo nmap -PS 10.0.2.15

Starting Nmap 6.00 ( http://nmap.org ) at 2013-12-15 18:34 CST
Nmap scan report for 10.0.2.15
Host is up (0.0000060s latency).
Not shown: 996 closed ports
PORT     STATE SERVICE
80/tcp   open  http
139/tcp  open  netbios-ssn
445/tcp  open  microsoft-ds
2222/tcp open  EtherNet/IP-1

Nmap done: 1 IP address (1 host up) scanned in 0.10 seconds

-sT 結果一樣

-PU : 使用UDP協定 ping 遠端的主機

$ sudo nmap -PU 10.0.2.15

Starting Nmap 6.00 ( http://nmap.org ) at 2013-12-15 18:35 CST
Nmap scan report for 10.0.2.15
Host is up (0.0000050s latency).
Not shown: 996 closed ports
PORT     STATE SERVICE
80/tcp   open  http
139/tcp  open  netbios-ssn
445/tcp  open  microsoft-ds
2222/tcp open  EtherNet/IP-1

Nmap done: 1 IP address (1 host up) scanned in 0.09 seconds

-sO : 偵測遠端主機已開啟哪些通訊協定 TCP,UDP,ICMP,…

$ sudo nmap -sO 10.0.2.15

Starting Nmap 6.00 ( http://nmap.org ) at 2013-12-15 18:36 CST
Nmap scan report for 10.0.2.15
Host is up (0.0000080s latency).
Not shown: 249 closed protocols
PROTOCOL STATE         SERVICE
1        open          icmp
2        open|filtered igmp
6        open          tcp
17       open          udp
103      open|filtered pim
136      open|filtered udplite
255      open|filtered unknown

Nmap done: 1 IP address (1 host up) scanned in 1.23 seconds

-p80 : 指定 port 掃描是否開啟, ex: 80 port

80 port 是 open 的 :

    $ sudo nmap -p80 10.0.2.15

Starting Nmap 6.00 ( http://nmap.org ) at 2013-12-15 18:33 CST
Nmap scan report for 10.0.2.15
Host is up (0.00020s latency).
PORT   STATE SERVICE
80/tcp open  http

Nmap done: 1 IP address (1 host up) scanned in 0.06 seconds

81 port 是 closed 的 :

$ sudo nmap -p81 10.0.2.15

Starting Nmap 6.00 ( http://nmap.org ) at 2013-12-15 18:33 CST
Nmap scan report for 10.0.2.15
Host is up (0.000048s latency).
PORT   STATE  SERVICE
81/tcp closed hosts2-ns

掃描網段內有開啟 80 port 的 IP

$ sudo nmap -p80 10.0.2.0/24

Starting Nmap 6.00 ( http://nmap.org ) at 2013-12-15 18:38 CST
Nmap scan report for 10.0.2.2
Host is up (0.00051s latency).
PORT   STATE SERVICE
80/tcp open  http
MAC Address: 52:54:00:12:35:02 (QEMU Virtual NIC)

Nmap scan report for 10.0.2.3
Host is up (0.00074s latency).
PORT   STATE SERVICE
80/tcp open  http
MAC Address: 52:54:00:12:35:03 (QEMU Virtual NIC)

Nmap scan report for 10.0.2.4
Host is up (0.00071s latency).
PORT   STATE SERVICE
80/tcp open  http
MAC Address: 52:54:00:12:35:04 (QEMU Virtual NIC)

Nmap scan report for 10.0.2.15
Host is up (0.00027s latency).
PORT   STATE SERVICE
80/tcp open  http

Nmap done: 256 IP addresses (4 hosts up) scanned in 10.09 seconds

掃網段指定 port

nmap comes with a nice output parameter -oG (grepable output) which makes parsing more easy.

Also it is not necessary to iterate through all IP addresses you want to scan. nmap is netmask aware.

nmap -p80 192.168.0.0/24 -oG - | grep 80/open

The -oG enables the grepable output, and - specifies the file to output to (in this case stdout). The pipe symbol redirects the output of nmap (stdout) to grep, which only returns lines containing 80/open in this case.

  • -oG filespec (grepable output) .
  • This output format is covered last because it is deprecated. The XML output format is
  • far more powerful, and is nearly as convenient for experienced users. XML is a standard
  • for which dozens of excellent parsers are available, while grepable output is my own
  • simple hack. XML is extensible to support new Nmap features as they are released, while
  • I often must omit those features from grepable output for lack of a place to put them.
  • (…略…)

ref: http://stackoverflow.com/questions/3773183/how-to-determine-which-ips-in-a-given-range-have-port-80-using-nmap 不自量力 http://idobest.pixnet.net/blog/post/22040775-%5B%E8%BD%89%E8%B2%BC%5D-linux-%E7%B6%B2%E8%B7%AF%E6%AA%A2%E6%B8%AC%E5%B7%A5%E5%85%B7-nmap-%E7%9A%84%E7%94%A8%E6%B3%95

Ruby 建立自己的 Gem 套件

建立 gem 的基本結構

jex@virtualBox:/tmp$ bundle gem exgem
      create  exgem/Gemfile                    <= 描述 dependency
      create  exgem/Rakefile                   <= 發佈和打包的 rake tasks
      create  exgem/LICENSE.txt                <= 註明 License
      create  exgem/README.md                  <= 簡單說明如何使用它
      create  exgem/.gitignore                 <= 不要進 Git 的檔案在這定義
      create  exgem/exgem.gemspec             <= gem 的 spec
      create  exgem/lib/exgem.rb              <= gem 裡的 library
      create  exgem/lib/exgem/version.rb      <= 版本紀錄
Initializating git repo in /tmp/exgem

首先看一下 Gemfile

exgem/Gemfile :

source 'https://rubygems.org'

# Specify your gem's dependencies in exgem.gemspec
gemspec

最後一行要你定義相依套件在 exgem.gemspec

開啟 GemSpec

exgem/exgem.gemspec :

裡面的內容大部份都已填好了, 所以我們改一點使它有變化

spec.description   = %q{Description : This is my gem for example.}
spec.summary       = %q{Summary : This is my gem for example.}

撰寫你的 lib

exgem/lib/exgem.rb :

加上 hi 這個 method :

require "exgem/version"

module Exgem
  # Your code goes here...
  def self.hi
    puts "Hello, world!"
  end
end

寫完之後 build

gem build exgem.gemspec
WARNING:  no homepage specified
  Successfully built RubyGem
  Name: exgem
  Version: 0.0.1
  File: exgem-0.0.1.gem
  • 出現提示 WARNING: no homepage specified 可以忽略它,
  • 因為在 exgem.gemspec 裡我們沒有定義 spec.homepage, 它是一個 URI
  • 目錄底下會多出此檔 exgem-0.0.1.gem

install 這個 package

在安裝之前你都還不能 require 它, 會噴錯誤

$ irb
2.0.0-p247 :001 > require 'exgem'
LoadError: cannot load such file -- exgem
        from /Users/apple/.rvm/rubies/ruby-2.0.0-p247/lib/ruby/site_ruby/2.0.0/rubygems/core_ext/kernel_require.rb:55:in `require'
        from /Users/apple/.rvm/rubies/ruby-2.0.0-p247/lib/ruby/site_ruby/2.0.0/rubygems/core_ext/kernel_require.rb:55:in `require'
        from (irb):1
        from /Users/apple/.rvm/rubies/ruby-2.0.0-p247/bin/irb:13:in `<main>'

所以要先安裝(需要 sudo 權限)

$ sudo gem install exgem-0.0.1.gem
Password:
Successfully installed exgem-0.0.1
1 gem installed

就可以 require 了

$ irb
2.0.0p247 :001 > require 'exgem'
 => true
2.0.0p247 :002 > Exgem.hi
Hello, world!
 => nil
  • 像我習慣用 tmux 分頁切來切去, 如果一 TAB 執行 gem install exgem-0.0.1.gem, 另一 TAB 執行 irb 可能會造成 require exgem 失敗
  • 最好是 irb 離開再重進一次, 才抓得到新的 gem package

發佈在 RubyGems.org

[1] 更新

gem update --system

[2] 申請一組帳號

handle 是 username 的意思

[3] 發佈到 RubyGems.org

執行

$ gem push exgem-0.0.1.gem
Pushing gem to https://rubygems.org...
Successfully registered gem: exgem (0.0.1)

官網就可以看到剛剛發佈的 gem 了 gem.JPG

gem 的相關指令

刪除

$ sudo gem uninstall exgem
Successfully uninstalled exgem-0.0.1

Q & A


如果發生錯誤

ERROR:  While executing gem ... (RuntimeError)
    Can't find 'rubygems-update' in any repo. Check `gem source list`.

解決方法

sudo gem sources -a http://s3.amazonaws.com/production.s3.rubygems.org/
http://s3.amazonaws.com/production.s3.rubygems.org/ added to sources

如果發生

gem push exgem-0.0.1.gem
Pushing gem to https://rubygems.org...
Repushing of gem versions is not allowed.
Please use `gem yank` to remove bad gem releases.

修改你的 lib/exgem/version.rb, 將版本從 0.0.1 改成 0.0.2

$ gem build exgem.gemspec
WARNING:  no homepage specified
  Successfully built RubyGem
  Name: exgem
  Version: 0.0.2
  File: exgem-0.0.2.gem

會生成 exgem-0.0.2.gem, 而舊的 exgem-0.0.1.gem 不會消失


如果發佈發生此錯誤的話表示 gem 的名稱跟別人重覆了

$ sudo gem push exgem-0.0.2.gem
Password:
Pushing gem to https://rubygems.org...
You do not have permission to push to this gem.

ref : http://blog.xdite.net/posts/2012/01/04/how-to-pack-a-gem http://weblog.rubyonrails.org/2009/9/1/gem-packaging-best-practices/ http://guides.rubygems.org/make-your-own-gem/#first-gem http://net.tutsplus.com/tutorials/ruby/gem-creation-with-bundler/ http://i3zhe.github.io/blog/2012/10/29/ru-he-zhi-zuo-zi-ji-de-gem/

PHP Yahoo Oauth 及取得基本資料

申請

[1] 到Yahoo! Developer Network登入後 -> 右上角 My Projects -> Create a Project

[2] 申請好會有一組 Application ID, Consumer Key, Consumer Secret

[3] 填入 domain 後記得驗證它, 才能用於線上

登入 Oauth, 並透過 yql 取得使用者資料 (使用 Codeigniter)

Oauth

原先 Oauth 那邊打算使用官方的 SDK, 但是怎麼試都會有 ERROR, 於是參考網路的資源重刻了一個輪子

YQL

原以為做登入 Oauth 取得的 GUID 再透過 YQL Console 的結果網址就可以取得使用者資料, 而不透過 YQL 的 SDK

例如我想取得使用者資料 YQL Console 執行

select * from social.profile where guid = "{我的GUID}"

完成後頁面下面有 url : http://query.yahooapis.com/v1/public/yql?q=select%20*%20from%20social.profile%20where%20guid%20%3D%20%22{我的GUID}%22&format=json&diagnostics=true&callback=

果然事情不是憨人想得這麼簡單, 直接拿來用會得到 ERROR 頁面

{
    error: {
        lang: "en-US",
        diagnostics: null,
        description: "Authentication Error. The table social.profile requires a higher security level than is provided, you provided ANY but at least APP is expected"
    }
}

YQL Console 頁面應該是塞了 Token, 所以只好使用正統的方法來取得了

我們要使用 Yahoo! Social SDK 請將 yos-social-php 下載到 /application/third_party, 稍後的 Library 會引入它

此練習只是取得使用者資料為例子, 取得 YQL 其它資料應該也是差不多

Oauth Library :

<?php defined('BASEPATH') OR exit('No direct script access allowed');

class Oauth {

    const CONSUMER_KEY    = "(填你自己的)";
    const CONSUMER_SECRET = "(填你自己的)";
    const APP_ID          = "(填你自己的)";
    const CALLBACK_URL    = "http://{你的 domain}/{你的 controller}/get_access_token";
    private $TOKEN;

    public function curl_post($url, $post = NULL, $options = array()) {
        $defaults = array(
            CURLOPT_POST           => 1,
            CURLOPT_HEADER         => 0,
            CURLOPT_URL            => $url,
            CURLOPT_FRESH_CONNECT  => 1,
            CURLOPT_RETURNTRANSFER => 1,
            CURLOPT_FORBID_REUSE   => 1,
            CURLOPT_TIMEOUT        => 4,
            CURLOPT_POSTFIELDS     => http_build_query($post),
        );

        $ch = curl_init();
        curl_setopt_array($ch, $defaults);
        if( ! $result = curl_exec($ch))
        {
            trigger_error(curl_error($ch));
        }
        curl_close($ch);
        return $result;
    }

    public function get_request_token()
    {
        $post = array(
            "oauth_nonce"            => md5(uniqid(rand(), true)),
            "oauth_timestamp"        => time(),
            "oauth_consumer_key"     => OAUTH::CONSUMER_KEY,
            "oauth_signature_method" => "PLAINTEXT",
            "oauth_signature"        => OAUTH::CONSUMER_SECRET."&",
            "oauth_version"          => "1.0",
            "oauth_callback"         => OAUTH::CALLBACK_URL,
        );

        $r = $this->curl_post("https://api.login.yahoo.com/oauth/v2/get_request_token", $post);
        parse_str($r, $output);
        return $output;
    }

    public function get_access_token($data)
    {
        if ( ! isset($data) || ! is_array($data))
        {
            return FALSE;
        }
        $post = array(
            "oauth_nonce"            => md5(uniqid(rand(), true)),
            "oauth_timestamp"        => time(),
            "oauth_consumer_key"     => OAUTH::CONSUMER_KEY,
            "oauth_signature_method" => "PLAINTEXT",
            "oauth_version"          => "1.0",
            "oauth_signature"        => OAUTH::CONSUMER_SECRET."&". $data["oauth_token_secret"],
            "oauth_token"            => $data['oauth_token'],
            "oauth_verifier"         => $data['oauth_verifier'],
        );

        $r = $this->curl_post("https://api.login.yahoo.com/oauth/v2/get_token", $post);
        parse_str($r, $output);
        return $output;
    }

    public function refresh_access_token($data)
    {
        if ( ! isset($data) || ! is_array($data))
        {
            return FALSE;
        }
        $cookie = get_object_vars(http_parse_cookie(getenv("HTTP_COOKIE")));
        $_COOKIE = $cookie["cookies"];
        $post = array(
            "oauth_nonce"            => md5(uniqid(rand(), true)),
            "oauth_timestamp"        => time(),
            "oauth_consumer_key"     => OAUTH::CONSUMER_KEY,
            "oauth_signature_method" => "PLAINTEXT",
            "oauth_version"          => "1.0",
            "oauth_signature"        => OAUTH::CONSUMER_SECRET."&".$data["oauth_token_secret"],
            "oauth_token"            => $data["oauth_token"],
            "oauth_session_handle"   => $data["oauth_session_handle"],
        );

        $r = $this->curl_post("https://api.login.yahoo.com/oauth/v2/get_token", $post);
        parse_str($r, $output);
        return $output;
    }

    /*
     * api : [yos-social-php github](https://github.com/yahoo/yos-social-php)
     */
    public function get_user_profile($guid = "")
    {
        if (empty($guid))
        {
            return FALSE;
        }
        require_once (APPPATH.'third_party/yos-social-php/lib/Yahoo.inc');
        $session = YahooSession::requireSession(OAUTH::CONSUMER_KEY, OAUTH::CONSUMER_SECRET, OAUTH::APP_ID);
        $user = $session->getSessionedUser();
        return $session->query("select * from social.profile where guid ='{$guid}'");
    }
}

Controller :

public function __construct()
{
    parent::__construct();
    header("Content-type: text/html; charset=utf-8");
    $this->load->library('Oauth');
    error_reporting(E_ALL ^ E_STRICT);    // ignore php notice
}

public function get_request_token()
{
    $output = $this->oauth->get_request_token();
    if ($output)
    {
        setcookie('oauth_token_secret', $output['oauth_token_secret']);
        header('Location: '. $output['xoauth_request_auth_url']);
        exit;
    }
    $this->_output_JSON(FALSE);
}

public function get_access_token()
{
    $data['oauth_token_secret'] = $_COOKIE['oauth_token_secret'];
    $data['oauth_token'] = $this->input->get_post('oauth_token');
    $data['oauth_verifier'] = $this->input->get_post('oauth_verifier');
    $output = $this->oauth->get_access_token($data);
    if ($output)
    {
        $this->get_user_profile($output['xoauth_yahoo_guid']);
    }
    $this->_output_JSON(FALSE);
}

public function get_user_profile($guid)
{
    $result = $this->oauth->get_user_profile($guid);
    $this->_output_JSON($result);
    exit;
}

private function _output_JSON_raw($result)
{
    echo json_encode(
        array(
            'status'    => (($result) ? 'ok' : 'fail'),
            'data'      => (($result) ? $result : ''),
        ),
        JSON_UNESCAPED_UNICODE
    );
}

瀏覽器執行 http://{你的 domain}/{你的 controller}/get_request_token, 輸出結果如下 :

yahoo-oauth.jpg

ref : http://code.gunblues.com/2011/02/yahoo-api-oauth.html

Du, Df 指令

du

目錄下每一個檔案/資料夾的所佔空間

du -smh *

計算資料夾容量(total)

cd /test
du -s
441800  .

-s, –summarize : display only a total for each argument

資料夾下每個資料夾的大小

cd /test
du -h

-h : 單位為 mb

列出佔用空間前 5 名

du -s /var/* | sort -rn | head -5

xargs du -s:列出資料夾大小 (單位是 K)

df

  • / : 找出你系統中的根目錄所在磁碟,並顯示相關資訊
  • -a : 全部檔案系統和各分割區的磁碟用情形
  • -h : 容量 (G / M / K)
  • -T : 列出檔案型態

只列出sd磁碟

ls /dev/sd*

列出所有磁碟(hd及sd)

ls /dev/[sh]d*

顯示磁碟資訊

$ df -h | grep /dev/sda1 | awk '{print $0"=>"$1" "$2" "$3}'
/dev/sda1       226G  2.1G  212G   1% /=>/dev/sda1 226G 2.1G

Grep 指令

一般用法

grep -R '時間' *
  • -r, –recursive like –directories=recurse
  • -R, –dereference-recursive likewise, but follow all symlinks
  • –include=FILE_PATTERN search only files that match FILE_PATTERN
  • –exclude=FILE_PATTERN skip files and directories matching FILE_PATTERN
  • –exclude-from=FILE skip files matching any file pattern from FILE
  • –exclude-dir=PATTERN directories that match PATTERN will be skipped.
  • -i, –ignore-case ignore case distinctions
  • -P, –perl-regexp
  • -o, –only-matching

grep ^d:過濾出資料夾

OR

沒有任何 option, 必須使用 \| 來分隔 pattern :

grep 'pattern1\|pattern2' filename
grep 'Tech\|Sales' employee.txt

使用 option -E (extended regexp), 使用 | 分隔 pattern :

grep -E 'pattern1|pattern2' filename
grep -E 'Tech|Sales' employee.txt

使用 egrep 指令, 相當於使用 grep -E :

egrep 'pattern1|pattern2' filename
egrep 'Tech|Sales' employee.txt

使用 option -e, 但 pattern 必須分開寫

grep -e pattern1 -e pattern2 filename
grep -e Tech -e Sales employee.txt

AND

AND 在 grep 沒有操作符, 可以使用 -E 達成 :

grep -E 'pattern1.*pattern2' filename
grep -E 'pattern1.*pattern2|pattern2.*pattern1' filename
grep -E 'Dev.*Tech' employee.txt
grep -E 'Manager.*Sales|Sales.*Manager' employee.txt

使用 linux 原生指令 | 來達成 :

grep -E 'pattern1' filename | grep -E 'pattern2'
grep Manager employee.txt | grep Sales

NOT

使用 -v (invert match) 達成, 它會顯示除了符合 pattern 以外的搜尋結果

grep -v 'pattern1' filename
grep -v Sales employee.txt
egrep 'Manager|Developer' employee.txt | grep -v Sales

Others

只過濾出符合的部份

echo 'hello world' | grep -oP 'hello \K(world)'

ref : http://www.thegeekstuff.com/2011/10/grep-or-and-not-operators/

PHP 微博登入 Oauth

申請

  • 微博申請非常的麻煩, 需要負責人的身份證件等等, 過關後才可以申請網站服務

  • 在申請前最好先了解 “我的應用” 及 “我的網站” 的差異, 再申請適合你網站的服務

1) 如果你的網站純粹只是要串接微博登入, 就選擇我的網站 2) 我的應用是給如手機登入或是如 facebook app 那樣的去申請

申請我的網站

[1] 申請

  • 開發平台頁面 點擊 管理中心 -> 我的網站 -> 添加網站 (接下來審核的步驟可以先略過)
  • 網站名稱可以先隨便寫,而網站域名必須為已經註冊的域名 (EX : www.example.com 以下均用此 domain 當例子)
  • 添加網站成功後,會得到 App Key 和 App Secret ,這兩個程式裡所需要的參數

[2] 網站信息 -> 高級信息, 在安全設置裡面,填寫網站的域名: www.example.com 及 IP: 127.0.0.1

[3] 網站信息 -> 測試賬號, 設置一個管理賬號

[4] 將域名綁定到 127.0.0.1

  • 因為在做 Oauth 回來後會導向你自己設定的 callback_url, 而這個 callback_url 的域名也是你在步驟 [1] 所申請的, 如果你沒有將這個域名在本機導向 127.0.0.1 的話, 就沒辦法完成剩下的步驟

  • 在本機的 C:\Windows\System32\Drivers\etc\host 檔案加上 127.0.0.1 www.example.com

[5] 審核

  • 如果網站還在開發階段, 可以先不用認證, 在本機開發不會有問題
  • 如果你的網站準備要開始上線了, 就可以送出認證了, 大概要3天左右

申請我的應用

在開發階段要記得在 管理中心 -> 應用信息 -> 測試帳號 新增帳號, 否則在 Oauth 時會得到 applications over the unaudited use restrictions 這樣的錯誤

注意:修改後約半小時左右時間生效

管理中心->應用信息->高級信息設置好授權回調頁(連結要與 callback_url 一樣)

否則會得到 error:redirect_uri_mismatch 這樣的錯誤訊息

補充申請手機 app

  • 資料可先隨便填
  • 記得加回調頁 (高級信息) : https://api.weibo.com/oauth2/default.html
  • 測試帳號也要加上自已的微博帳號
  • 手機只需用 APP Key 就可以從 weibo login 取得 token, 然後可以傳給 server, 而 server 可以直接使用網站的 App Key 及 Secret 做登入判別, 也就是說從 weibo 建立 app 不管是網站還是手機, 取得的 token 是可以相通的

在做之前先了解登入 Oauth 流程

[1] 在頁面上放置一個登入按鈕, 而按鈕的 link 導向你自己的某一隻程式 [2] 判斷是否己登入過 (檢查 token), 如果未登入就導向微博 Oauth 頁面, 成功後即可取得 token [3] 就可以利用 token 拿你想拿的使用者資料

開始動手做 (程式碼部份)

首先下載微博 php sdk github

設定好 config 方便開發 :

$config['app_id']           = (填上 app_id)
$config['secret']           = (填上 secret)
$config['callback_url']     = (填上 callback_url)

此頁檢查 token 是否存在, 如果沒有代表未登入

引入微博 PHP SDK, 並建立物件:

require 'saetv2.ex.class.php';
$weiboOauth = new SaeTOAuthV2($config["app_id"], $config["secret"]);

取得登入及授權 url, 並且導向過去:

$weiboOauth->getAuthorizeURL($config["callback_url"])

User 會被要求登入及授權, 如果通過的話, 會導向 callback_url, 並且網址後面會帶 GET : code=一串亂數

callback_url 網址的那一隻程式

取得 token :

require 'saetv2.ex.class.php';
$weiboOauth = new SaeTOAuthV2($config["app_id"], $config["secret"]);

$code = $_GET['code'];
if ($code)
{
    $keys = array();
    $keys['code'] = $code;
    $keys['redirect_uri'] = $config["callback_url"];
    try
    {
        $token = $weiboOauth->getAccessToken('code', $keys);
    }
    catch (OAuthException $e)
    {
        log_message('info', $e->getMessage());
    }
}

建議將 token 存到 SESSION, 方便下次判斷是否已登入及授權

取得 user 資料 (將 token 帶入):

if (is_array($token))
{
    $weiboClient = new saeTClientV2($config["app_id"], $config["secret"], $token['access_token']);
    $user_data = $weiboClient->show_user_by_id($token['uid']);
    if ( ! empty($user_data['error']))
    {
        log_message('info', "Weibo Error: {$user_data['error']}");
    }
}

User data 的值如下 :

array (
  'id' => 3865801255,                    #用戶UID
  'idstr' => '3865801255',
  'class' => 1,
  'screen_name' => 'jex_lin',            #微博暱稱
  'name' => 'jex_lin',                   #友好顯示名稱,同微博暱稱
  'province' => '400',                   #省份編碼(參考省份編​​碼表)
  'city' => '4',                         #城市編碼(參考城市編碼表)
  'location' => '海外 俄罗斯',            #所在地
  'description' => '',                   #個人描述
  'url' => '',                           #用戶博客地址
  'profile_image_url' => 'http://tp4.sinaimg.cn/3865801255/50/0/1',      #自定義圖像
  'profile_url' => 'u/3865801255',
  'domain' => '',                        #用戶個性化URL
  'weihao' => '',
  'gender' => 'm',                       #性別,m--男,f--女,n--未知
  'followers_count' => 15,               #粉絲數
  'friends_count' => 23,                 #關注數
  'statuses_count' => 0,                 #微博數
  'favourites_count' => 0,               #收藏數
  'created_at' => 'Mon Oct 21 11:48:34 +0800 2013',                      #創建時間
  'following' => false,                  #是否已關注(此特性暫不支持)
  'allow_all_act_msg' => false,
  'geo_enabled' => true,
  'verified' => false,                   #加V標示,是否微博認證用戶
  'verified_type' => -1,
  'remark' => '',
  'ptype' => 0,
  'allow_all_comment' => true,
  'avatar_large' => 'http://tp4.sinaimg.cn/3865801255/180/0/1',
  'avatar_hd' => 'http://tp4.sinaimg.cn/3865801255/180/0/1',
  'verified_reason' => '',
  'follow_me' => false,
  'online_status' => 1,
  'bi_followers_count' => 1,
  'lang' => 'zh-cn',
  'star' => 0,
  'mbtype' => 0,
  'mbrank' => 0,
  'block_word' => 0,
)
  • Fb 帳號若沒有 active, 會直接在 fb 頁面顯示錯誤訊息, 微博則無法判斷
  • 如果你的基本資料所在地填國外(Ex: 俄羅斯), 但返回的 lang 並不是 ru-ru, 因為 lang 並不是指你的所在地, 而是你微博頁面顯示的語言, 例如調成繁體中文, 帶回來的 ‘lang’ => ‘zh-tw’
  • 注意!! 選擇英文, ‘lang’ => ‘en’, 並不是我們熟悉的 en-us
  • FB 在這方面也一樣, 會依照網頁上顯示的語言帶不同的語言碼回來, ex : 語言選日語 ‘locale’ => ‘ja_JP’

登出微博 :

以下連結加上 token ($token[‘access_token’])

https://api.weibo.com/2/account/end_session.json?access_token=2.00JVVcNE0O_NXn3b7d524c0cl3ekeD

會返回同 get_user_data 的基本資料

使用不同帳號登入

如果使用者已登入過微博並且也已經 Oauth 過了, 程式將使用者導到登入 Oauth 的頁面, 如果 token 沒過期, 微博並不會再次要求登入 Oauth, 因為它會當你已經認證過了, 而直接導到帶入的 callback_url, 這是正常的, 但是有時候需要讓使用者直接切換帳號登入 Oauth 的話, 如果要求使用者先到微博登出, 那不就太不方便了嗎?

微博提供的作法是只要在授權連結上添加forcelogin參數,將forcelogin參數設置為true, 就可以達到強制再次做登入 Oauth

$weiboOauth->getAuthorizeURL($config["callback_url"]) . '&forcelogin=true';

ref : http://open.weibo.com/wiki/Direct_messages/new 官方 Q&A - 接口問題 http://www.oooink.com/blog/find/c/47 http://open.weibo.com/qa/index.php?qa=1457&qa_1=%E8%AF%B7%E9%97%AE%EF%BC%8C%E5%A6%82%E4%BD%95%E5%9C%A8%E6%9C%AC%E5%9C%B0%E6%B5%8B%E8%AF%95%E6%96%B0%E6%B5%AA%E7%9A%84%E7%99%BB%E5%BD%95%E6%8C%89%E9%92%AE%E7%99%BB%E5%BD%95%E7%AC%AC%E4%B8%89%E6%96%B9%E7%BD%91%E7%AB%99%EF%BC%9F

NFS (Network FileSystem)

分享目錄的 server 安裝及設定

server 安裝:

sudo apt-get update
sudo apt-get install nfs-kernel-server

設定 /etc/exports :

建議直接設定*, 在防火牆再限 ip, 不然因為 nfs port 是浮動的不好設定

/my_ugc *(rw,sync,all_squash,anonuid=1000,anongid=1000,insecure,subtree_check)
/home/me/test *(ro)
/my_ugc 10.170.189.142(rw,sync,all_squash,anonuid=1000,anongid=1000,insecure,subtree_check)
/my_ugc 10.170.189.0/24(rw,sync,all_squash,anonuid=1000,anongid=1000,insecure,subtree_check)
  • * : 代表任意主機
  • ro : 唯讀,是預設值
  • rw : 允許讀、寫
  • sync : 預設值。同步 I/O,也就是在資料異動時,會同步寫入記憶體與磁碟之中
  • all_squash : 所有client 端的user 都對應成 nobody(一般設定)
  • anonuid : 為 nobody 帳號設 uid
  • anongid : 為 nobody 帳號設 gid
  • insecure : 允許主機不需認證即可存取
  • subtree_check (或 no_subtree_check, 不加上會有 error) : If a subdirectory of a filesystem is exported, but the whole filesystem isn’t then whenever a NFS request arrives, the server must check not only that the accessed file is in the appropriate filesystem (which is easy) but also that it is in the exported tree (which is harder)
  • 更多官方文件參數說明

啟動

啟動 server

sudo service nfs-kernel-server start

查看是否成功啟動

$ showmount -e localhost
Export list for localhost:
/my_ugc/cms-me/doc *

-e or –exports : Show the NFS server’s export list.

開啟 nfs port

-A INPUT -p tcp -s 10.161.132.121   -m state --state NEW --dport 111  -j ACCEP    // nfs
-A INPUT -p tcp -s 10.161.132.121   -m state --state NEW --dport 2049  -j ACCEP   // nfs

測試 port 是否如預期

$ rpcinfo -p
   program vers proto   port  service
    100000    4   tcp    111  portmapper
    100000    3   tcp    111  portmapper
    100000    2   udp    111  portmapper
    100003    2   tcp   2049  nfs
    100003    4   tcp   2049  nfs
    100227    2   tcp   2049
    100227    3   tcp   2049
    100021    1   udp  51575  nlockmgr
    100021    3   udp  51575  nlockmgr
    100021    4   tcp  55701  nlockmgr
    100005    1   udp  35019  mountd
    100005    1   tcp  37799  mountd

server 開機自動 mount, /etc/fstab:

/dev/xvdb /my_ugc ext4  defaults       0 0

client 掛載遠端目錄

client 安裝:

sudo apt-get install nfs-common

mount :

sudo mount devm3:/my_ugc /my_ugc

df 查看 :

devm3:/my_ugc 236058624  48626176 175434752  22% /my_ugc

client 開機自動掛載, /etc/fstab:

base:/my_ugc /my_ugc nfs rw,soft,nosuid,noexec,nodev,bg,rsize=32768,wsize=32768     0 0
  • timeo : specifies the number of seconds to pass before the error is reported.
  • intr : Allows NFS requests to be interrupted if the server goes down or cannot be reached.
  • rsize=num and wsize=num — These settings speed up NFS communication for reads (rsize) and writes (wsize) by setting a larger data block size, in bytes, to be transferred at one time. Be careful when changing these values; some older Linux kernels and network cards do not work well with larger block sizes. For NFSv2 or NFSv3, the default values for both parameters is set to 8192. For NFSv4, the default values for both parameters is set to 32768.

ref : 固定 nfs server port